N°2240 - Supportability - Maintenance mode

This commit is contained in:
Eric
2019-09-27 17:13:25 +02:00
parent a54695b2e0
commit 044623309c
8 changed files with 191 additions and 136 deletions

View File

@@ -53,40 +53,6 @@ register_shutdown_function(function()
}
});
// Use 'maintenance' parameter to bypass maintenance mode
$bBypassMaintenance = !is_null(Utils::ReadParam('maintenance', null));
// Maintenance mode
if (file_exists(APPROOT.'.maintenance') && !$bBypassMaintenance)
{
$sMessage = 'Application is currently in maintenance';
$sTitle = 'Maintenance';
http_response_code(503);
// Display message depending on the request
switch (true)
{
case isset($_SERVER['REQUEST_URI']) && EndsWith($_SERVER['REQUEST_URI'], '/pages/ajax.searchform.php'):
_MaintenanceHtmlMessage($sMessage);
break;
case array_key_exists('HTTP_X_COMBODO_AJAX', $_SERVER):
case isset($_SERVER['REQUEST_URI']) && EndsWith($_SERVER['REQUEST_URI'], '/webservices/soapserver.php'):
case isset($_SERVER['REQUEST_URI']) && EndsWith($_SERVER['REQUEST_URI'], '/webservices/rest.php'):
_MaintenanceTextMessage($sMessage);
break;
case isset($_SERVER['CONTENT_TYPE']) && ($_SERVER['CONTENT_TYPE'] == 'application/json'):
_MaintenanceJsonMessage($sTitle, $sMessage);
break;
default:
_MaintenanceSetupPageMessage($sTitle, $sMessage);
break;
}
exit();
}
session_name('itop-'.md5(APPROOT));
session_start();
$sSwitchEnv = utils::ReadParam('switch_env', null);
@@ -120,80 +86,3 @@ else
}
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
MetaModel::Startup($sConfigFile, false /* $bModelOnly */, $bAllowCache, false /* $bTraceSourceFiles */, $sEnv);
//
// Maintenance message display functions
//
/**
* Use a setup page to display the maintenance message
* @param $sTitle
* @param $sMessage
*/
function _MaintenanceSetupPageMessage($sTitle, $sMessage)
{
// Web Page
@include_once(APPROOT."/setup/setuppage.class.inc.php");
if (class_exists('SetupPage'))
{
$oP = new SetupPage($sTitle);
$oP->p("<h2>$sMessage</h2>");
$oP->output();
}
else
{
_MaintenanceTextMessage($sMessage);
}
}
/**
* Use simple text to display the maintenance message
* @param $sMessage
*/
function _MaintenanceTextMessage($sMessage)
{
echo $sMessage;
}
/**
* Use a simple HTML to display the maintenance message
* @param $sMessage
*/
function _MaintenanceHtmlMessage($sMessage)
{
echo '<html><body><div>'.$sMessage.'</div></body></html>';
}
/**
* Use a simple JSON to display the maintenance message
*
* @param $sTitle
* @param $sMessage
*/
function _MaintenanceJsonMessage($sTitle, $sMessage)
{
@include_once(APPROOT."/application/ajaxwebpage.class.inc.php");
if (class_exists('ajax_page'))
{
$oP = new ajax_page($sTitle);
$oP->add_header('Access-Control-Allow-Origin: *');
$oP->SetContentType('application/json');
$oP->add('{"code":100, "message":"'.$sMessage.'"}');
$oP->Output();
}
else
{
_MaintenanceTextMessage($sMessage);
}
}
/**
* helper to test if a string ends with another
* @param $haystack
* @param $needle
*
* @return bool
*/
function EndsWith($haystack, $needle) {
return substr_compare($haystack, $needle, -strlen($needle)) === 0;
}

View File

@@ -12,4 +12,56 @@ else
{
$fItopStarted = 1000 * time();
}
?>
//
// Maintenance mode
//
// Use 'maintenance' parameter to bypass maintenance mode
if (!isset($bBypassMaintenance))
{
$bBypassMaintenance = isset($_REQUEST['maintenance']) ? boolval($_REQUEST['maintenance']) : false;
}
if (file_exists(APPROOT.'.maintenance') && !$bBypassMaintenance)
{
$sMessage = 'Application is currently in maintenance';
$sTitle = 'Maintenance';
http_response_code(503);
// Display message depending on the request
include(APPROOT.'maintenancemsg.php');
switch (true)
{
case isset($_SERVER['REQUEST_URI']) && EndsWith($_SERVER['REQUEST_URI'], '/pages/ajax.searchform.php'):
_MaintenanceHtmlMessage($sMessage);
break;
case array_key_exists('HTTP_X_COMBODO_AJAX', $_SERVER):
case isset($_SERVER['REQUEST_URI']) && EndsWith($_SERVER['REQUEST_URI'], '/webservices/soapserver.php'):
case isset($_SERVER['REQUEST_URI']) && EndsWith($_SERVER['REQUEST_URI'], '/webservices/rest.php'):
_MaintenanceTextMessage($sMessage);
break;
case isset($_SERVER['CONTENT_TYPE']) && ($_SERVER['CONTENT_TYPE'] == 'application/json'):
_MaintenanceJsonMessage($sTitle, $sMessage);
break;
default:
_MaintenanceSetupPageMessage($sTitle, $sMessage);
break;
}
exit();
}
/**
* helper to test if a string ends with another
* @param $haystack
* @param $needle
*
* @return bool
*/
function EndsWith($haystack, $needle) {
return substr_compare($haystack, $needle, -strlen($needle)) === 0;
}

74
maintenancemsg.php Normal file
View File

@@ -0,0 +1,74 @@
<?php
/**
* @copyright Copyright (C) 2010-2019 Combodo SARL
* @license http://opensource.org/licenses/AGPL-3.0
*/
//
// Maintenance message display functions
//
/**
* Use a setup page to display the maintenance message
* @param $sTitle
* @param $sMessage
*/
function _MaintenanceSetupPageMessage($sTitle, $sMessage)
{
// Web Page
@include_once(APPROOT.'bootstrap.inc.php');
@include_once(APPROOT.'setup/setuppage.class.inc.php');
if (class_exists('SetupPage'))
{
$oP = new SetupPage($sTitle);
$oP->p("<h2>$sMessage</h2>");
$oP->output();
}
else
{
_MaintenanceTextMessage($sMessage);
}
}
/**
* Use simple text to display the maintenance message
* @param $sMessage
*/
function _MaintenanceTextMessage($sMessage)
{
echo $sMessage;
}
/**
* Use a simple HTML to display the maintenance message
* @param $sMessage
*/
function _MaintenanceHtmlMessage($sMessage)
{
echo '<html><body><div>'.$sMessage.'</div></body></html>';
}
/**
* Use a simple JSON to display the maintenance message
*
* @param $sTitle
* @param $sMessage
*/
function _MaintenanceJsonMessage($sTitle, $sMessage)
{
@include_once(APPROOT.'bootstrap.inc.php');
@include_once(APPROOT."/application/ajaxwebpage.class.inc.php");
if (class_exists('ajax_page'))
{
$oP = new ajax_page($sTitle);
$oP->add_header('Access-Control-Allow-Origin: *');
$oP->SetContentType('application/json');
$oP->add('{"code":100, "message":"'.$sMessage.'"}');
$oP->Output();
}
else
{
_MaintenanceTextMessage($sMessage);
}
}

View File

@@ -26,16 +26,6 @@ require_once(APPROOT.'core/metamodel.class.php');
utils::InitTimeZone();
// Maintenance mode
if (file_exists(APPROOT.'.maintenance'))
{
http_response_code(503);
require_once(APPROOT.'core/dict.class.inc.php');
$sMessage = Dict::S('UI:Error:MaintenanceMode', 'Application is currently in maintenance');
echo "$sMessage";
exit;
}
$sModule = utils::ReadParam('exec_module', '');
if ($sModule == '')
{

View File

@@ -137,7 +137,21 @@ class ApplicationInstaller
return ($iOverallStatus == self::OK);
}
private function GetConfig()
{
$sTargetEnvironment = $this->GetTargetEnv();
$sConfigFile = APPCONF.$sTargetEnvironment.'/'.ITOP_CONFIG_FILE;
try
{
return new Config($sConfigFile);
}
catch (Exception $e)
{
return null;
}
}
/**
* Executes the next step of the installation and reports about the progress
* and the next step to perform
@@ -151,7 +165,7 @@ class ApplicationInstaller
try
{
$fStart = microtime(true);
SetupUtils::EnterMaintenanceMode();
SetupUtils::EnterMaintenanceMode($this->GetConfig());
switch ($sStep)
{
case '':
@@ -356,15 +370,11 @@ class ApplicationInstaller
'next-step-label' => "Unknown setup step '$sStep'.",
'percentage-completed' => 100,
);
break;
}
SetupUtils::ExitMaintenanceMode();
$fDuration = round(microtime(true) - $fStart, 2);
SetupPage::log_info("##### STEP {$sStep} duration: {$fDuration}s");
}
catch (Exception $e)
{
SetupUtils::ExitMaintenanceMode();
$aResult = array(
'status' => self::ERROR,
'message' => $e->getMessage(),
@@ -389,6 +399,12 @@ class ApplicationInstaller
$idx++;
}
}
finally
{
SetupUtils::ExitMaintenanceMode();
$fDuration = round(microtime(true) - $fStart, 2);
SetupPage::log_info("##### STEP {$sStep} duration: {$fDuration}s");
}
return $aResult;
}
@@ -946,6 +962,11 @@ class ApplicationInstaller
// Ready to go !!
require_once(APPROOT.'core/dict.class.inc.php');
MetaModel::ResetCache();
// Perform final setup tasks here
//
$aAvailableModules = $oProductionEnv->AnalyzeInstallation(MetaModel::GetConfig(), APPROOT.$sModulesDir);
$oProductionEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModuleCodes, 'AfterCreateConfig');
}
}

View File

@@ -17,6 +17,7 @@
* You should have received a copy of the GNU Affero General Public License
*/
$bBypassMaintenance = true; // Reset maintenance mode in case of problem
require_once('../approot.inc.php');
require_once(APPROOT.'/bootstrap.inc.php');
require_once(APPROOT.'/application/utils.inc.php');
@@ -26,6 +27,7 @@ require_once(APPROOT.'/setup/wizardcontroller.class.inc.php');
require_once(APPROOT.'/setup/wizardsteps.class.inc.php');
clearstatcache(); // Make sure we know what we are doing !
SetupUtils::ExitMaintenanceMode(false); // Reset maintenance mode in case of problem
// Set a long (at least 4 minutes) execution time for the setup to avoid timeouts during this phase
ini_set('max_execution_time', max(240, ini_get('max_execution_time')));
// While running the setup it is desirable to see any error that may happen

View File

@@ -1836,20 +1836,47 @@ EOF
return APPROOT.'log/setup-queries-'.strftime('%Y-%m-%d_%H_%M').'.sql';
}
public final static function EnterMaintenanceMode($bCheckBackgroundTask = false)
public final static function EnterMaintenanceMode($oConfig)
{
@touch(APPROOT.'.maintenance');
if ($bCheckBackgroundTask)
SetupPage::log("----> Entering maintenance mode");
try
{
// Assume database is OK but datamodel is not usable
$iCount = CMDBSource::QueryToScalar('SELECT COUNT(*) FROM priv_backgroundtask WHERE running=1');
// Wait for cron to stop
if (is_null($oConfig))
{
return;
}
// Use mutex to check if cron is running
$oMutex = new iTopMutex(
'cron'.$oConfig->Get('db_name').$oConfig->Get('db_subname'),
$oConfig->Get('db_host'),
$oConfig->Get('db_user'),
$oConfig->Get('db_pwd'),
$oConfig->Get('db_tls.enabled'),
$oConfig->Get('db_tls.ca')
);
$iCount = 1;
while ($oMutex->IsLocked())
{
SetupPage::log("Waiting for cron to stop ($iCount)");
$iCount++;
sleep(10);
}
}
catch(Exception $e)
{
// Ignore errors
}
}
public final static function ExitMaintenanceMode()
public final static function ExitMaintenanceMode($bLog = true)
{
@unlink(APPROOT.'.maintenance');
if ($bLog)
{
SetupPage::log("<---- Exiting maintenance mode");
}
}
}

View File

@@ -566,7 +566,7 @@ try
{
// Note: testing this now in case some of the background processes forces the read-only mode for a while
// in that case it is better to exit with the check on reentrance (mutex)
if (!MetaModel::DBHasAccess(ACCESS_ADMIN_WRITE) || file_exists(APPROOT.'.maintenance'))
if (!MetaModel::DBHasAccess(ACCESS_ADMIN_WRITE))
{
$oP->p("A maintenance is ongoing");
$oP->Output();