/** * Loads updates from the implemented classes */ protected function loadUpdates() { $this->fetchStatusBefore(); foreach (new UpdatesIterator(self::getPathToUpdates()) as $fileInfo) { /* @var $fileInfo \SplFileInfo */ $updateClass = __NAMESPACE__ . '\\Updates\\' . substr($fileInfo->getFilename(), 0, 20); try { /* @var $update \Scalr\Upgrade\AbstractUpdate */ $update = new $updateClass($fileInfo, $this->stateBefore); $this->updates[$update->getUuidHex()] = $update; } catch (\Exception $e) { $this->console->error("Cound not load update %s. %s", $fileInfo->getPathname(), $e->getMessage()); } } }
/** * Applies update * * @param AbstractUpdate $upd Update to apply * * @return bool Returns true if update is successful, false otherwise * * @throws Exception\UpgradeException */ protected function applyUpdate(AbstractUpdate $upd) { if (!isset($this->attempts[$upd->getUuidHex()])) { $this->attempts[$upd->getUuidHex()] = 1; } else { $this->attempts[$upd->getUuidHex()]++; } if ($this->attempts[$upd->getUuidHex()] > self::MAX_ATTEMPTS) { throw new Exception\UpgradeException(sprintf('"%s" Failed due to infinity loop. Max number of attempts (%d) reached!', $upd->getName(), self::MAX_ATTEMPTS)); } $refuseReason = $upd->isRefused(); if (false !== $refuseReason) { if ($this->opt->verbosity) { $this->console->notice('%s is ignored. %s', $upd->getName(), (string) $refuseReason); } return true; } if ($upd->getStatus() == AbstractUpgradeEntity::STATUS_OK) { //Upgrade file is updated. $upd->updateAppears(); if (isset($this->opt->cmd) && $this->opt->cmd == self::CMD_RUN_SPECIFIC && $this->opt->uuid == $upd->getUuidHex()) { //User has requested re-execution of update $upd->setStatus(AbstractUpgradeEntity::STATUS_PENDING); $upd->updateHash(); $upd->getEntity()->save(); } else { //Compare checksum if ($upd->getEntity()->hash == $upd->getHash()) { //file modified time could be the issue $upd->updateApplied(); $upd->getEntity()->save(); if (!empty($this->opt->verbosity) || isset($this->opt->cmd) && $this->opt->cmd == self::CMD_RUN_SPECIFIC && $this->opt->uuid == $upd->getUuidHex()) { $this->console->warning('Ingnoring %s because of having complete status.', $upd->getName()); } return true; } else { //We should ignore changes in the script and update hash $upd->updateHash(); $upd->getEntity()->save(); return true; } } } $this->console->success('%s...', $upd->description ?: $upd->getName()); //Checks updates this upgrade depends upon if (!empty($upd->depends)) { foreach ($upd->depends as $uuid) { $uuidhex = AbstractUpdate::castUuid($uuid); if (!empty($this->updates[$uuidhex])) { $update = $this->updates[$uuidhex]; if ($update->getStatus() == AbstractUpgradeEntity::STATUS_OK) { //Relative update has already been successfully applied. continue; } } else { if (isset($this->stateBefore[$uuidhex])) { /* @var $upgradeEntity \Scalr\Upgrade\Entity\AbstractUpgradeEntity */ $upgradeEntity = $this->stateBefore[$uuidhex]; if ($upgradeEntity->status == AbstractUpgradeEntity::STATUS_OK) { //Relative update has already been applied continue; } else { //Relative update needs to be applied before dependant. $this->console->warning('"%s" has been declined as it depends on incomplete update "%s" which has status "%s". ' . 'Desired class "%s" does not exist in the expected folder.', $upd->getName(), $uuid, $upgradeEntity->getStatusName(), $upgradeEntity->getUpdateClassName()); return false; } } else { //Relative update has not been delivered yet. $this->console->warning('"%s" has been postponed as it depends on "%s" which has not been delivered yet.', $upd->getName(), $uuid); return false; } } if ($update->getStatus() == AbstractUpgradeEntity::STATUS_FAILED && isset($this->recurrences[$update->getUuidHex()])) { //Recurrence of the failed status. We don't need to report about it again. $this->console->warning('"%s" has been declined because of failure dependent update "%s".', $upd->getName(), $uuid); return false; } //Relative update has not been applied or it has incomplete status. //We need to apply it first. if ($this->applyUpdate($update) === false) { $this->console->warning('"%s" has been declined. Could not apply related update "%s".', $upd->getName(), $update->getName()); return false; } } } //Checks if update class implements SequenceInterface $stages = $upd instanceof SequenceInterface ? range(1, $upd->getNumberStages()) : array(1); $skip = 0; foreach ($stages as $stage) { //Checks if update is applied if ($upd->isApplied($stage)) { $upd->console->warning('Skips over the stage %d of update %s because it has already been applied.', $stage, $upd->getName()); $skip++; continue; } //Validates environment before applying if (!$upd->validateBefore($stage)) { $this->console->error('Error. Stage %d of update %s could not be applied because of invalid environment! validateBefore(%d) returned false.', $stage, $upd->getName(), $stage); return false; } //Applies the update try { $upd->run($stage); } catch (\Exception $e) { //We should avoid repetition when another update depends on failed. $this->recurrences[$upd->getUuidHex()] = true; $upd->setStatus(AbstractUpgradeEntity::STATUS_FAILED); $upd->console->error('Error. Stage %d of update %s failed! %s', $stage, $upd->getName(), $e->getMessage()); $upd->getEntity()->save(); $upd->getEntity()->createFailureMessage($upd->console->getLog()); return false; } } $this->console->success("%s - OK", $upd->description ?: $upd->getName()); $upd->setStatus(AbstractUpgradeEntity::STATUS_OK); $upd->updateHash(); $upd->updateApplied(); $upd->getEntity()->save(); return true; }
$console->out(""); $console->out("Usage: upgrade [OPTIONS]"); $console->out(" -h, --help Display this help end exit."); $console->out(" -n, --new Generate a new update class to implement."); $console->out(" -r uuid Run only specified update. UUID is unique identifier."); $console->out(" -v Turn on verbosity."); $console->out(" -i Turn on interactive mode for upgrades which rely on it."); $console->out(" --force Run forcefully ignoring pid."); $console->out(""); exit; }; $options = new \stdClass(); //validates options if (isset($opt['r'])) { if (!preg_match('/^[\\da-f]{32}$/i', $opt['r']) && !preg_match('/^[\\da-f]{8}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{4}-[\\da-f]{12}$/i', $opt['r'])) { $console->error("Error usage. UUID should be 32 hexadecimal digit number"); $showusage(); } $options->cmd = UpgradeHandler::CMD_RUN_SPECIFIC; $options->uuid = strtolower(str_replace('-', '', $opt['r'])); } $options->verbosity = isset($opt['v']); $options->interactive = isset($opt['i']); if (isset($opt['help']) || isset($opt['h'])) { $showusage(); } if (isset($opt['n']) || isset($opt['new'])) { $template = UpgradeHandler::getPathToUpdates() . '/Template.php'; if (!is_readable($template)) { $console->error('Could not open template file for reading ' . $template); exit;
/** * {@inheritdoc} * @see \Scalr\System\Pcntl\ProcessInterface::OnStartForking() */ public function OnStartForking() { $db = \Scalr::getDb(); $sevenDaysAgo = date('Y-m-d H:i:s', strtotime('-7 days')); $tenDaysAgo = date('Y-m-d H:i:s', strtotime('-10 days')); $twentyDaysAgo = date('Y-m-d H:i:s', strtotime('-20 days')); $monthAgo = date('Y-m-d H:i:s', strtotime('-1 months')); $twoMonthAgo = date('Y-m-d H:i:s', strtotime('-2 months')); $twoWeeksAgo = date('Y-m-d H:i:s', strtotime('-14 days')); $this->console->out("%s (UTC) Start RotateLogsProcess", gmdate('Y-m-d')); $this->console->out("Rotating logentries table"); $this->rotateTable("DELETE FROM `logentries` WHERE `time` < ?", [strtotime('-10 days')]); $this->console->out("Rotating scripting_log table"); $this->rotateTable("DELETE FROM `scripting_log` WHERE `dtadded` < ?", array($sevenDaysAgo)); $this->console->out("Rotating events table"); $this->rotateTable("DELETE FROM `events` WHERE `dtadded` < ?", array($twoMonthAgo)); $this->console->out("Rotating messages table"); $this->rotateTable("DELETE FROM messages WHERE type='out' AND status='1' AND `dtlasthandleattempt` < ?", array($tenDaysAgo)); $this->rotateTable("DELETE FROM messages WHERE type='out' AND status='3' AND `dtlasthandleattempt` < ?", array($tenDaysAgo)); $this->rotateTable("DELETE FROM messages WHERE type='in' AND status='1' AND `dtlasthandleattempt` < ?", array($tenDaysAgo)); $this->console->out('Rotating webhook_history table'); $this->rotateTable("DELETE FROM webhook_history WHERE `created` < ?", array($twoWeeksAgo)); $this->console->out("Rotating farm_role_scripts table"); $year = date('Y'); $month = date('m', strtotime('-1 months')); $this->rotateTable("\n DELETE FROM `farm_role_scripts`\n WHERE ismenuitem='0' AND event_name LIKE 'CustomEvent-{$year}{$month}%'\n "); $this->rotateTable("\n DELETE FROM `farm_role_scripts`\n WHERE ismenuitem='0' AND event_name LIKE 'APIEvent-{$year}{$month}%'\n "); $this->console->out('Calculating number of the records in the syslog table'); if ($db->GetOne("SELECT COUNT(*) FROM `syslog`") > 1000000) { $this->console->out("Rotating syslog table"); $dtstamp = date("HdmY"); try { if ($db->GetOne("SHOW TABLES LIKE ?", ['syslog_tmp'])) { $db->Execute("DROP TABLE `syslog_tmp`"); } $db->Execute("CREATE TABLE `syslog_tmp` LIKE `syslog`"); $db->Execute("RENAME TABLE `syslog` TO `syslog_" . $dtstamp . "`, `syslog_tmp` TO `syslog`"); $db->Execute("TRUNCATE TABLE syslog_metadata"); $db->Execute("OPTIMIZE TABLE syslog"); $db->Execute("OPTIMIZE TABLE syslog_metadata"); } catch (Exception $e) { $this->console->error($e->getMessage()); } $this->Logger->debug("Log rotated. New table 'syslog_{$dtstamp}' created."); $this->rotateBackup('^syslog_[0-9]{8,10}$'); } //Rotate aws_statistics $this->console->out("Rotating AWS Statistics"); StatisticsPlugin::rotate(); //Rotate cost analytics data if (Scalr::getContainer()->analytics->enabled) { $this->console->out("Rotating analytics.poller_sessions table"); $before = (new DateTime('-7 days', new DateTimeZone('UTC')))->format('Y-m-d H:i:s'); $this->rotateTable("DELETE FROM `poller_sessions` WHERE `dtime` < ?", [$before], 'cadb'); $this->console->out("Rotating analytics.usage_h table"); $before = (new DateTime('-14 days', new DateTimeZone('UTC')))->format('Y-m-d H:i:s'); $this->rotateTable("DELETE FROM `usage_h` WHERE `dtime` < ?", [$before], 'cadb'); $this->console->out("Rotating analytics.nm_usage_h table"); $this->rotateTable("DELETE FROM `nm_usage_h` WHERE `dtime` < ?", [$before], 'cadb'); } $this->console->out('Done'); }