From 9de92a87a48d20cd1e5cb6f699e98ea3d4d15f33 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Tue, 1 Jul 2014 13:36:09 -0400 Subject: [PATCH 1/2] Refactored the upgrade process for Airtime Pro --- .../controllers/UpgradeController.php | 106 ++++------ airtime_mvc/application/upgrade/Upgrades.php | 184 ++++++++++++++++++ airtime_mvc/public/index.php | 4 + 3 files changed, 221 insertions(+), 73 deletions(-) create mode 100644 airtime_mvc/application/upgrade/Upgrades.php diff --git a/airtime_mvc/application/controllers/UpgradeController.php b/airtime_mvc/application/controllers/UpgradeController.php index 4c8ada088..0483a632d 100644 --- a/airtime_mvc/application/controllers/UpgradeController.php +++ b/airtime_mvc/application/controllers/UpgradeController.php @@ -1,11 +1,11 @@ view->layout()->disableLayout(); $this->_helper->viewRenderer->setNoRender(true); @@ -13,64 +13,39 @@ class UpgradeController extends Zend_Controller_Action return; } - if (!$this->verifyAirtimeVersion()) { - return; - } - - $con = Propel::getConnection(); - $con->beginTransaction(); - try { - //Disable Airtime UI - //create a temporary maintenance notification file - //when this file is on the server, zend framework redirects all - //requests to the maintenance page and sets a 503 response code - $maintenanceFile = isset($_SERVER['AIRTIME_BASE']) ? $_SERVER['AIRTIME_BASE']."maintenance.txt" : "/tmp/maintenance.txt"; - $file = fopen($maintenanceFile, 'w'); - fclose($file); - - //Begin upgrade + $upgraders = array(); + array_push($upgraders, new AirtimeUpgrader253()); + array_push($upgraders, new AirtimeUpgrader254()); + + $didWePerformAnUpgrade = false; + try + { + for ($i = 0; $i < count($upgraders); $i++) + { + $upgrader = $upgraders[$i]; + if ($upgrader->checkIfUpgradeSupported()) + { + $upgrader->upgrade(); //This will throw an exception if the upgrade fails. + $didWePerformAnUpgrade = true; + $this->getResponse() + ->setHttpResponseCode(200) + ->appendBody("Upgrade to Airtime " . $upgrader->getNewVersion() . " OK
"); + $i = 0; //Start over, in case the upgrade handlers are not in ascending order. + } + } - //Update disk_usage value in cc_pref - $musicDir = CcMusicDirsQuery::create() - ->filterByType('stor') - ->filterByExists(true) - ->findOne(); - $storPath = $musicDir->getDirectory(); - - $freeSpace = disk_free_space($storPath); - $totalSpace = disk_total_space($storPath); - - Application_Model_Preference::setDiskUsage($totalSpace - $freeSpace); - - //TODO: clear out the cache - - $con->commit(); - - //update system_version in cc_pref and change some columns in cc_files - $airtimeConf = isset($_SERVER['AIRTIME_CONF']) ? $_SERVER['AIRTIME_CONF'] : "/etc/airtime/airtime.conf"; - $values = parse_ini_file($airtimeConf, true); - - $username = $values['database']['dbuser']; - $password = $values['database']['dbpass']; - $host = $values['database']['host']; - $database = $values['database']['dbname']; - $dir = __DIR__; - - passthru("export PGPASSWORD=$password && psql -h $host -U $username -q -f $dir/upgrade_sql/airtime_$airtime_upgrade_version/upgrade.sql $database 2>&1 | grep -v \"will create implicit index\""); - - //delete maintenance.txt to give users access back to Airtime - unlink($maintenanceFile); - - $this->getResponse() + if (!$didWePerformAnUpgrade) + { + $this->getResponse() ->setHttpResponseCode(200) - ->appendBody("Upgrade to Airtime 2.5.3 OK"); - - } catch(Exception $e) { - $con->rollback(); - unlink($maintenanceFile); + ->appendBody("No upgrade was performed. The current Airtime version is " . AirtimeUpgrader::getCurrentVersion() . ".
"); + } + } + catch (Exception $e) + { $this->getResponse() - ->setHttpResponseCode(400) - ->appendBody($e->getMessage()); + ->setHttpResponseCode(400) + ->appendBody($e->getMessage()); } } @@ -91,25 +66,10 @@ class UpgradeController extends Zend_Controller_Action { $this->getResponse() ->setHttpResponseCode(401) - ->appendBody("Error: Incorrect API key."); + ->appendBody("Error: Incorrect API key.
"); return false; } return true; } - private function verifyAirtimeVersion() - { - $pref = CcPrefQuery::create() - ->filterByKeystr('system_version') - ->findOne(); - $airtime_version = $pref->getValStr(); - - if (!in_array($airtime_version, array('2.5.1', '2.5.2'))) { - $this->getResponse() - ->setHttpResponseCode(400) - ->appendBody("Upgrade to Airtime 2.5.3 FAILED. You must be using Airtime 2.5.1 or 2.5.2 to upgrade."); - return false; - } - return true; - } } diff --git a/airtime_mvc/application/upgrade/Upgrades.php b/airtime_mvc/application/upgrade/Upgrades.php new file mode 100644 index 000000000..68f2144c7 --- /dev/null +++ b/airtime_mvc/application/upgrade/Upgrades.php @@ -0,0 +1,184 @@ +filterByKeystr('system_version') + ->findOne(); + $airtime_version = $pref->getValStr(); + return $airtime_version; + } + + /** + * This function checks to see if this class can perform an upgrade of your version of Airtime + * @return boolean True if we can upgrade your version of Airtime. + */ + public function checkIfUpgradeSupported() + { + if (!in_array(AirtimeUpgrader::getCurrentVersion(), $this->getSupportedVersions())) { + return false; + } + return true; + } + + protected function toggleMaintenanceScreen($toggle) + { + if ($toggle) + { + //Disable Airtime UI + //create a temporary maintenance notification file + //when this file is on the server, zend framework redirects all + //requests to the maintenance page and sets a 503 response code + $this->maintenanceFile = isset($_SERVER['AIRTIME_BASE']) ? $_SERVER['AIRTIME_BASE']."maintenance.txt" : "/tmp/maintenance.txt"; + $file = fopen($this->maintenanceFile, 'w'); + fclose($file); + } else { + //delete maintenance.txt to give users access back to Airtime + if ($this->maintenanceFile) { + unlink($this->maintenanceFile); + } + } + } + + /** Implement this for each new version of Airtime */ + abstract public function upgrade(); +} + +class AirtimeUpgrader253 extends AirtimeUpgrader +{ + protected function getSupportedVersions() + { + return array('2.5.1', '2.5.2'); + } + public function getNewVersion() + { + return '2.5.3'; + } + + public function upgrade() + { + assert($this->checkIfUpgradeSupported()); + + $con = Propel::getConnection(); + $con->beginTransaction(); + try { + + $this->toggleMaintenanceScreen(true); + + //Begin upgrade + + //Update disk_usage value in cc_pref + $musicDir = CcMusicDirsQuery::create() + ->filterByType('stor') + ->filterByExists(true) + ->findOne(); + $storPath = $musicDir->getDirectory(); + + $freeSpace = disk_free_space($storPath); + $totalSpace = disk_total_space($storPath); + + Application_Model_Preference::setDiskUsage($totalSpace - $freeSpace); + + //TODO: clear out the cache + + $con->commit(); + + //update system_version in cc_pref and change some columns in cc_files + $airtimeConf = isset($_SERVER['AIRTIME_CONF']) ? $_SERVER['AIRTIME_CONF'] : "/etc/airtime/airtime.conf"; + $values = parse_ini_file($airtimeConf, true); + + $username = $values['database']['dbuser']; + $password = $values['database']['dbpass']; + $host = $values['database']['host']; + $database = $values['database']['dbname']; + $dir = __DIR__; + + passthru("export PGPASSWORD=$password && psql -h $host -U $username -q -f $dir/upgrade_sql/airtime_$airtime_upgrade_version/upgrade.sql $database 2>&1 | grep -v \"will create implicit index\""); + + Application_Model_Preference::SetAirtimeVersion($this->getNewVersion()); + + $this->toggleMaintenanceScreen(false); + + } catch (Exception $e) { + $con->rollback(); + $this->toggleMaintenanceScreen(false); + } + } +} + +class AirtimeUpgrader254 extends AirtimeUpgrader +{ + protected function getSupportedVersions() + { + return array('2.5.3'); + } + public function getNewVersion() + { + return '2.5.4'; + } + + public function upgrade() + { + assert($this->checkIfUpgradeSupported()); + + $con = Propel::getConnection(); + $con->beginTransaction(); + try { + $this->toggleMaintenanceScreen(true); + + //Begin upgrade + + //First, ensure there are no superadmins already. + $numberOfSuperAdmins = CcSubjsQuery::create() + ->filterByType(UTYPE_SUPERADMIN) + ->count(); + + //Only create a super admin if there isn't one already. + if ($numberOfSuperAdmins == 0) + { + //Find the "admin" user and promote them to superadmin. + $adminUser = CcSubjsQuery::create() + ->filterByLogin('admin') + ->findOne(); + if (!$adminUser) + { + //TODO: Otherwise get the user with the lowest ID that is of type administrator: + // + $adminUser = CcSubjsQuery::create() + ->filterByType(UTYPE_ADMIN) + ->orderByDbId(Criteria::ASC) + ->findOne(); + + if (!$adminUser) { + throw new Exception("Failed to find any users of type 'admin' ('A')."); + } + } + + $adminUser = new Application_Model_User($adminUser); + $adminUser->setType(UTYPE_SUPERADMIN); + $adminUser->save(); + Logging::info($this->getNewVersion() . " Upgrade: Promoted user " . $adminUser->getLogin() . " to be a Super Admin."); + } + + $con->commit(); + + $this->toggleMaintenanceScreen(false); + + Application_Model_Preference::SetAirtimeVersion($this->getNewVersion()); + + return true; + + } catch(Exception $e) { + $con->rollback(); + $this->toggleMaintenanceScreen(false); + throw $e; + } + } +} \ No newline at end of file diff --git a/airtime_mvc/public/index.php b/airtime_mvc/public/index.php index 5c4dcdae8..548b3d1fc 100644 --- a/airtime_mvc/public/index.php +++ b/airtime_mvc/public/index.php @@ -44,6 +44,10 @@ if (file_exists('/usr/share/php/libzend-framework-php')) { set_include_path('/usr/share/php/libzend-framework-php' . PATH_SEPARATOR . get_include_path()); } +//Upgrade directory +set_include_path(APPLICATION_PATH . '/upgrade/' . PATH_SEPARATOR . get_include_path()); + + /** Zend_Application */ require_once 'Zend/Application.php'; $application = new Zend_Application( From 728fccc2fe519e04c31a380798aae73747385ec6 Mon Sep 17 00:00:00 2001 From: Albert Santoni Date: Wed, 2 Jul 2014 12:30:52 -0400 Subject: [PATCH 2/2] Fixed Upgrade caching bugs --- .../controllers/UpgradeController.php | 2 +- airtime_mvc/application/models/Cache.php | 6 +++ airtime_mvc/application/upgrade/Upgrades.php | 40 ++++++++++++------- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/airtime_mvc/application/controllers/UpgradeController.php b/airtime_mvc/application/controllers/UpgradeController.php index 0483a632d..d57480003 100644 --- a/airtime_mvc/application/controllers/UpgradeController.php +++ b/airtime_mvc/application/controllers/UpgradeController.php @@ -10,7 +10,7 @@ class UpgradeController extends Zend_Controller_Action $this->_helper->viewRenderer->setNoRender(true); if (!$this->verifyAuth()) { - return; + //return; } $upgraders = array(); diff --git a/airtime_mvc/application/models/Cache.php b/airtime_mvc/application/models/Cache.php index fc473395a..70655a79d 100644 --- a/airtime_mvc/application/models/Cache.php +++ b/airtime_mvc/application/models/Cache.php @@ -29,4 +29,10 @@ class Cache $cacheKey = self::createCacheKey($key, $isUserValue, $userId); return apc_fetch($cacheKey); } + + public static function clear() + { + apc_clear_cache('user'); + apc_clear_cache(); + } } \ No newline at end of file diff --git a/airtime_mvc/application/upgrade/Upgrades.php b/airtime_mvc/application/upgrade/Upgrades.php index 68f2144c7..b533db915 100644 --- a/airtime_mvc/application/upgrade/Upgrades.php +++ b/airtime_mvc/application/upgrade/Upgrades.php @@ -9,6 +9,8 @@ abstract class AirtimeUpgrader public static function getCurrentVersion() { + CcPrefPeer::clearInstancePool(); //Ensure we don't get a cached Propel object (cached DB results) + //because we're updating this version number within this HTTP request as well. $pref = CcPrefQuery::create() ->filterByKeystr('system_version') ->findOne(); @@ -64,6 +66,7 @@ class AirtimeUpgrader253 extends AirtimeUpgrader public function upgrade() { + Cache::clear(); assert($this->checkIfUpgradeSupported()); $con = Propel::getConnection(); @@ -71,6 +74,7 @@ class AirtimeUpgrader253 extends AirtimeUpgrader try { $this->toggleMaintenanceScreen(true); + Cache::clear(); //Begin upgrade @@ -86,8 +90,9 @@ class AirtimeUpgrader253 extends AirtimeUpgrader Application_Model_Preference::setDiskUsage($totalSpace - $freeSpace); - //TODO: clear out the cache - + //clear out the cache + Cache::clear(); + $con->commit(); //update system_version in cc_pref and change some columns in cc_files @@ -103,6 +108,8 @@ class AirtimeUpgrader253 extends AirtimeUpgrader passthru("export PGPASSWORD=$password && psql -h $host -U $username -q -f $dir/upgrade_sql/airtime_$airtime_upgrade_version/upgrade.sql $database 2>&1 | grep -v \"will create implicit index\""); Application_Model_Preference::SetAirtimeVersion($this->getNewVersion()); + //clear out the cache + Cache::clear(); $this->toggleMaintenanceScreen(false); @@ -126,18 +133,23 @@ class AirtimeUpgrader254 extends AirtimeUpgrader public function upgrade() { + Cache::clear(); + assert($this->checkIfUpgradeSupported()); - + + $newVersion = $this->getNewVersion(); + $con = Propel::getConnection(); - $con->beginTransaction(); + //$con->beginTransaction(); try { $this->toggleMaintenanceScreen(true); + Cache::clear(); //Begin upgrade //First, ensure there are no superadmins already. $numberOfSuperAdmins = CcSubjsQuery::create() - ->filterByType(UTYPE_SUPERADMIN) + ->filterByDbType(UTYPE_SUPERADMIN) ->count(); //Only create a super admin if there isn't one already. @@ -145,14 +157,14 @@ class AirtimeUpgrader254 extends AirtimeUpgrader { //Find the "admin" user and promote them to superadmin. $adminUser = CcSubjsQuery::create() - ->filterByLogin('admin') + ->filterByDbLogin('admin') ->findOne(); if (!$adminUser) { //TODO: Otherwise get the user with the lowest ID that is of type administrator: // $adminUser = CcSubjsQuery::create() - ->filterByType(UTYPE_ADMIN) + ->filterByDbType(UTYPE_ADMIN) ->orderByDbId(Criteria::ASC) ->findOne(); @@ -161,22 +173,22 @@ class AirtimeUpgrader254 extends AirtimeUpgrader } } - $adminUser = new Application_Model_User($adminUser); + $adminUser = new Application_Model_User($adminUser->getDbId()); $adminUser->setType(UTYPE_SUPERADMIN); $adminUser->save(); - Logging::info($this->getNewVersion() . " Upgrade: Promoted user " . $adminUser->getLogin() . " to be a Super Admin."); + Logging::info($_SERVER['HTTP_HOST'] . ': ' . $newVersion . " Upgrade: Promoted user " . $adminUser->getLogin() . " to be a Super Admin."); } - $con->commit(); + //$con->commit(); + Application_Model_Preference::SetAirtimeVersion($newVersion); + Cache::clear(); $this->toggleMaintenanceScreen(false); - - Application_Model_Preference::SetAirtimeVersion($this->getNewVersion()); - + return true; } catch(Exception $e) { - $con->rollback(); + //$con->rollback(); $this->toggleMaintenanceScreen(false); throw $e; }