mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
N°2240 - Supportability - Maintenance mode
This commit is contained in:
@@ -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;
|
||||
}
|
||||
@@ -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
74
maintenancemsg.php
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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 == '')
|
||||
{
|
||||
|
||||
@@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user