/** * Reverts a series of SQL patches by looking up their down_sql code and executing it. */ public function rollback() { $this->logger->log('Database rollback: ' . implode(', ', $this->sql_revert_patches), LOG_DEBUG); if (!count($this->sql_revert_patches)) { return; } foreach ($this->sql_revert_patches as $patch_name) { // get the code to revert the patch $result = $this->driver->query("\n SELECT id, down_sql\n FROM db_patches\n WHERE patch_name = '" . $this->driver->escape($patch_name) . "'\n ORDER BY applied_at DESC, id DESC;\n "); if (!($patch_info = $this->driver->fetchAssoc($result))) { return; } if ($patch_info['down_sql'] != '') { // mark the patch as being reverted $this->driver->query("\n UPDATE db_patches\n SET reverted_at = '" . $this->driver->escape($this->timestamp) . "'\n WHERE patch_timestamp = '" . $this->driver->escape($patch_name) . "';\n "); // revert the patch $this->driver->startTransaction(); $this->driver->multiQuery($patch_info['down_sql']); if (false === $result) { throw new DatabaseException('Error reverting patch ' . $patch_name . ': ' . $this->driver->getLastError(), 1); } $this->driver->doCommit(); } // remove the patch from the db_patches table $this->driver->query("\n DELETE FROM db_patches\n WHERE id = " . $this->driver->escape($patch_info['id']) . ";\n "); $this->logger->log("Patch '{$patch_name}' reverted."); } }
/** * Stub methode voor extra uitbreidingen die *na* rollback worden uitgevoerd * * @param string $remote_host * @param string $remote_dir * @param string $target_dir */ protected function postRollback($remote_host, $remote_dir, $target_dir) { $this->logger->log("postRollback({$remote_host}, {$remote_dir}, {$target_dir})", LOG_DEBUG); if ($this->gearman_handler) { $this->gearman_handler->restartWorkers($remote_host, $remote_dir, $target_dir); } }
/** * Makes a list of all SQL update files, in the order the action implies: * 'update': the updates are ordered chronologically (old to new). * 'rollback': the updates are ordered in reverse (new to old). * * @param string $action 'update' or 'rollback' * @param boolean $quiet * @return array */ public function findSQLFiles($action, $quiet = false) { $this->logger->log("findSQLFiles({$action}, " . var_export($quiet, true) . ")", LOG_DEBUG); $update_files = array(); if (!empty($this->database_dirs)) { foreach ($this->database_dirs as $database_dir) { foreach (new FilterIterator(new \DirectoryIterator($this->basedir . '/' . ltrim($database_dir, '/'))) as $patch_name => $entry) { /** @var \SplFileInfo|\DirectoryIterator $entry */ $update_files[$patch_name] = $database_dir . '/' . $entry->getFilename(); } } if (!empty($update_files)) { $count_files = count($update_files); if (Deploy::UPDATE == $action) { ksort($update_files, SORT_STRING); $this->logger->log($count_files . ' SQL update patch' . ($count_files > 1 ? 'es' : '') . ' found:'); } elseif (Deploy::ROLLBACK == $action) { krsort($update_files, SORT_STRING); $this->logger->log($count_files . ' SQL rollback patch' . ($count_files > 1 ? 'es' : '') . ' found:'); } $this->logger->log($update_files, LOG_INFO, true); } else { $this->logger->log('No SQL patches found.'); } } return $update_files; }
/** * Gearman workers herstarten * * @param string $remote_host * @param string $remote_dir * @param string $target_dir */ public function restartWorkers($remote_host, $remote_dir, $target_dir) { $this->logger->log("restartGearmanWorkers({$remote_host}, {$remote_dir}, {$target_dir})", LOG_DEBUG); if (!isset($this->gearman['workers']) || empty($this->gearman['workers'])) { return; } $cmd = "cd {$remote_dir}/{$target_dir}; "; foreach ($this->gearman['servers'] as $server) { foreach ($this->gearman['workers'] as $worker) { $worker = sprintf($worker, $this->target); $cmd .= "php {$this->gearman_restarter} --ip={$server['ip']} --port={$server['port']} --function={$worker}; "; } } $output = array(); $this->remote_shell->exec($cmd, $remote_host, $output); $this->logger->log($output); }
/** * Wrapper for SSH commands * * @param string $command * @param string $remote_host * @param array $output * @param int $return * @param string $hide_pattern Regexp to clean up output (eg. passwords) * @param string $hide_replacement * @param int $ouput_loglevel */ public function exec($command, $remote_host = null, &$output = array(), &$return = 0, $hide_pattern = '', $hide_replacement = '', $ouput_loglevel = LOG_INFO) { if (null === $remote_host) { $remote_host = $this->remote_host; } if ('localhost' == $remote_host) { $cmd = $command; } else { $cmd = $this->ssh_path . ' ' . $this->remote_user . '@' . $remote_host . ' "' . str_replace('"', '\\"', $command) . '"'; } if ($hide_pattern != '') { $show_cmd = preg_replace($hide_pattern, $hide_replacement, $cmd); } else { $show_cmd = $cmd; } $this->logger->log('Remote: ' . $show_cmd, LOG_DEBUG); exec($cmd, $output, $return); $this->logger->log($output, $ouput_loglevel); }