From 280feca8639d06c3c365513b8b773cf8b2a27c70 Mon Sep 17 00:00:00 2001 From: odain Date: Fri, 13 Aug 2021 11:16:48 +0200 Subject: [PATCH] =?UTF-8?q?Revert=20"N=C2=B04225=20-=20Protect=20manual=20?= =?UTF-8?q?backups=20from=20cron=20(and=20vice=20versa)=20-=20minimal=20wo?= =?UTF-8?q?rk=20ie=20protect=20manual=20backup=20from=20cron=20only"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit e3dc1b77ccb1191e25bdb96b7c5b9db7db6c24a9. --- datamodels/2.x/itop-backup/ajax.backup.php | 5 + datamodels/2.x/itop-backup/backup.php | 3 + .../2.x/itop-backup/dbrestore.class.inc.php | 142 ++++++------ datamodels/2.x/itop-backup/restore.php | 203 ------------------ setup/backup.class.inc.php | 62 +++--- 5 files changed, 100 insertions(+), 315 deletions(-) delete mode 100644 datamodels/2.x/itop-backup/restore.php diff --git a/datamodels/2.x/itop-backup/ajax.backup.php b/datamodels/2.x/itop-backup/ajax.backup.php index a43094a78..f94b3d703 100644 --- a/datamodels/2.x/itop-backup/ajax.backup.php +++ b/datamodels/2.x/itop-backup/ajax.backup.php @@ -170,6 +170,10 @@ JS require_once(dirname(__FILE__).'/dbrestore.class.inc.php'); $sEnvironment = utils::ReadParam('environment', 'production', false, 'raw_data'); + $oRestoreMutex = new iTopMutex('restore.'.$sEnvironment); + IssueLog::Info("Backup Restore - Acquiring the LOCK 'restore.$sEnvironment'"); + $oRestoreMutex->Lock(); + IssueLog::Info('Backup Restore - LOCK acquired, executing...'); try { set_time_limit(0); @@ -199,6 +203,7 @@ JS finally { unlink($tokenRealPath); + $oRestoreMutex->Unlock(); } $oPage->output(); diff --git a/datamodels/2.x/itop-backup/backup.php b/datamodels/2.x/itop-backup/backup.php index 9861bd0c8..edf7e4331 100644 --- a/datamodels/2.x/itop-backup/backup.php +++ b/datamodels/2.x/itop-backup/backup.php @@ -30,6 +30,9 @@ if (!defined('APPROOT')) } } require_once(APPROOT.'application/application.inc.php'); +require_once(APPROOT.'application/webpage.class.inc.php'); +require_once(APPROOT.'application/csvpage.class.inc.php'); +require_once(APPROOT.'application/clipage.class.inc.php'); require_once(APPROOT.'application/ajaxwebpage.class.inc.php'); require_once(APPROOT.'core/log.class.inc.php'); diff --git a/datamodels/2.x/itop-backup/dbrestore.class.inc.php b/datamodels/2.x/itop-backup/dbrestore.class.inc.php index f8d84f431..c591412a4 100644 --- a/datamodels/2.x/itop-backup/dbrestore.class.inc.php +++ b/datamodels/2.x/itop-backup/dbrestore.class.inc.php @@ -28,8 +28,8 @@ class DBRestore extends DBBackup { parent::__construct($oConfig); - $this->sDBUser = $this->oConfig->Get('db_user'); - $this->sDBPwd = $this->oConfig->Get('db_pwd'); + $this->sDBUser = $oConfig->Get('db_user'); + $this->sDBPwd = $oConfig->Get('db_pwd'); } protected function LogInfo($sMsg) @@ -127,89 +127,79 @@ class DBRestore extends DBBackup */ public function RestoreFromCompressedBackup($sFile, $sEnvironment = 'production') { - $oRestoreMutex = new iTopMutex('restore.'.$sEnvironment); - IssueLog::Info("Backup Restore - Acquiring the LOCK 'restore.$sEnvironment'"); - $oRestoreMutex->Lock(); + $this->LogInfo("Starting restore of ".basename($sFile)); - try { - IssueLog::Info('Backup Restore - LOCK acquired, executing...'); - $bReadonlyBefore = SetupUtils::IsInReadOnlyMode(); - SetupUtils::EnterReadOnlyMode(MetaModel::GetConfig()); + $sNormalizedFile = strtolower(basename($sFile)); + if (substr($sNormalizedFile, -4) == '.zip') + { + $this->LogInfo('zip file detected'); + $oArchive = new ZipArchiveEx(); + $oArchive->open($sFile); + } + elseif (substr($sNormalizedFile, -7) == '.tar.gz') + { + $this->LogInfo('tar.gz file detected'); + $oArchive = new TarGzArchive($sFile); + } + else + { + throw new BackupException('Unsupported format for a backup file: '.$sFile); + } - try { - //safe zone for db backup => cron is stopped/ itop in readonly - $this->LogInfo("Starting restore of ".basename($sFile)); + // Load the database + // + $sDataDir = APPROOT.'data/tmp-backup-'.rand(10000, getrandmax()); + SetupUtils::builddir($sDataDir); // Here is the directory + $oArchive->extractTo($sDataDir); - $sNormalizedFile = strtolower(basename($sFile)); - if (substr($sNormalizedFile, -4) == '.zip') { - $this->LogInfo('zip file detected'); - $oArchive = new ZipArchiveEx(); - $oArchive->open($sFile); - } elseif (substr($sNormalizedFile, -7) == '.tar.gz') { - $this->LogInfo('tar.gz file detected'); - $oArchive = new TarGzArchive($sFile); - } else { - throw new BackupException('Unsupported format for a backup file: '.$sFile); - } + $sDataFile = $sDataDir.'/itop-dump.sql'; + $this->LoadDatabase($sDataFile); - // Load the database - // - $sDataDir = APPROOT.'data/tmp-backup-'.rand(10000, getrandmax()); + // Update the code + // + $sDeltaFile = APPROOT.'data/'.$sEnvironment.'.delta.xml'; - SetupUtils::builddir($sDataDir); // Here is the directory - $oArchive->extractTo($sDataDir); - - $sDataFile = $sDataDir.'/itop-dump.sql'; - $this->LoadDatabase($sDataFile); - - // Update the code - // - $sDeltaFile = APPROOT.'data/'.$sEnvironment.'.delta.xml'; - - if (is_file($sDataDir.'/delta.xml')) { - // Extract and rename delta.xml => .delta.xml; - rename($sDataDir.'/delta.xml', $sDeltaFile); - } else { - @unlink($sDeltaFile); - } - if (is_dir(APPROOT.'data/production-modules/')) { - try { - SetupUtils::rrmdir(APPROOT.'data/production-modules/'); - } catch (Exception $e) { - throw new BackupException("Can't remove production-modules dir", 0, $e); - } - } - if (is_dir($sDataDir.'/production-modules')) { - rename($sDataDir.'/production-modules', APPROOT.'data/production-modules/'); - } - - $sConfigFile = APPROOT.'conf/'.$sEnvironment.'/config-itop.php'; - @chmod($sConfigFile, 0770); // Allow overwriting the file - rename($sDataDir.'/config-itop.php', $sConfigFile); - @chmod($sConfigFile, 0440); // Read-only - - try { - SetupUtils::rrmdir($sDataDir); - } catch (Exception $e) { - throw new BackupException("Can't remove data dir", 0, $e); - } - - $oEnvironment = new RunTimeEnvironment($sEnvironment); - $oEnvironment->CompileFrom($sEnvironment); - } finally { - if (! $bReadonlyBefore) { - SetupUtils::ExitReadOnlyMode(); - } else { - //we are in the scope of main process that needs to handle/keep readonly mode. - $this->LogInfo("Keep readonly mode after restore"); - } + if (is_file($sDataDir.'/delta.xml')) + { + // Extract and rename delta.xml => .delta.xml; + rename($sDataDir.'/delta.xml', $sDeltaFile); + } + else + { + @unlink($sDeltaFile); + } + if (is_dir(APPROOT.'data/production-modules/')) + { + try + { + SetupUtils::rrmdir(APPROOT.'data/production-modules/'); + } + catch (Exception $e) + { + throw new BackupException("Can't remove production-modules dir", 0, $e); } } - finally + if (is_dir($sDataDir.'/production-modules')) { - IssueLog::Info('Backup Restore - LOCK released.'); - $oRestoreMutex->Unlock(); + rename($sDataDir.'/production-modules', APPROOT.'data/production-modules/'); } + + $sConfigFile = APPROOT.'conf/'.$sEnvironment.'/config-itop.php'; + @chmod($sConfigFile, 0770); // Allow overwriting the file + rename($sDataDir.'/config-itop.php', $sConfigFile); + @chmod($sConfigFile, 0440); // Read-only + + try + { + SetupUtils::rrmdir($sDataDir); + } + catch (Exception $e) + { + throw new BackupException("Can't remove data dir", 0, $e); + } + + $oEnvironment = new RunTimeEnvironment($sEnvironment); + $oEnvironment->CompileFrom($sEnvironment); } } diff --git a/datamodels/2.x/itop-backup/restore.php b/datamodels/2.x/itop-backup/restore.php deleted file mode 100644 index 4d72e6172..000000000 --- a/datamodels/2.x/itop-backup/restore.php +++ /dev/null @@ -1,203 +0,0 @@ -oPage->p($sMsg); - } - - protected function LogError($sMsg) - { - $this->oPage->p('Error: '.$sMsg); - ToolsLog::Error($sMsg); - } - - public function __construct($oPage) - { - $this->oPage = $oPage; - parent::__construct(); - } -} - - -/** - * Checks if a parameter (possibly empty) was specified when calling this page - */ -function CheckParam($sParamName) -{ - global $argv; - - if (isset($_REQUEST[$sParamName])) return true; // HTTP parameter either GET or POST - if (!is_array($argv)) return false; - foreach($argv as $sArg) - { - if ($sArg == '--'.$sParamName) return true; // Empty command line parameter, long unix style - if ($sArg == $sParamName) return true; // Empty command line parameter, Windows style - if ($sArg == '-'.$sParamName) return true; // Empty command line parameter, short unix style - if (preg_match('/^--'.$sParamName.'=(.*)$/', $sArg, $aMatches)) return true; // Command parameter with a value - } - return false; -} - -function Usage($oP) -{ - $oP->p('Restore an iTop from a backup file'); - $oP->p('Parameters:'); - if (utils::IsModeCLI()) - { - $oP->p('auth_user: login, must be administrator'); - $oP->p('auth_pwd: ...'); - } - $oP->p('backup_file [optional]: name of the file to store the backup into. Follows the PHP strftime format spec. The following placeholders are available: __HOST__, __DB__, __SUBNAME__'); - $oP->p('mysql_bindir [optional]: specify the path for mysql executable'); - - if (utils::IsModeCLI()) - { - $oP->p('Example: php -q restore.php --auth_user=admin --auth_pwd=myPassw0rd --backup_file=/tmp/backup.zip'); - $oP->p('Known limitation: the current directory must be the directory of backup.php'); - } - else - { - $oP->p('Example: .../restore.php?backup_file=/tmp/backup.zip'); - } -} - -function ExitError($oP, $sMessage) -{ - ToolsLog::Error($sMessage); - $oP->p($sMessage); - $oP->output(); - exit; -} - - -function ReadMandatoryParam($oP, $sParam) -{ - $sValue = utils::ReadParam($sParam, null, true /* Allow CLI */, 'raw_data'); - if (is_null($sValue)) - { - ExitError($oP, "ERROR: Missing argument '$sParam'"); - } - return trim($sValue); -} - - -///////////////////////////////// -// Main program - -set_time_limit(0); - -if (utils::IsModeCLI()) -{ - $oP = new CLIPage("iTop - iTop Restore"); - - SetupUtils::CheckPhpAndExtensionsForCli($oP); -} -else -{ - $oP = new WebPage("iTop - iTop Restore"); -} - -try -{ - utils::UseParamFile(); -} -catch(Exception $e) -{ - ExitError($oP, $e->GetMessage()); -} - -if (utils::IsModeCLI()) -{ - $oP->p(date('Y-m-d H:i:s')." - running backup utility"); - $sAuthUser = ReadMandatoryParam($oP, 'auth_user'); - $sAuthPwd = ReadMandatoryParam($oP, 'auth_pwd'); - $sBackupFile = ReadMandatoryParam($oP, 'backup_file'); - $bDownloadBackup = false; - if (UserRights::CheckCredentials($sAuthUser, $sAuthPwd)) - { - UserRights::Login($sAuthUser); // Login & set the user's language - } - else - { - ExitError($oP, "Access restricted or wrong credentials ('$sAuthUser')"); - } - - if (!is_file($sBackupFile) && is_readable($sBackupFile)){ - ExitError($oP, "Cannot access backup file ('$sBackupFile')"); - } -} -else -{ - require_once(APPROOT.'application/loginwebpage.class.inc.php'); - LoginWebPage::DoLogin(); // Check user rights and prompt if needed -} - -if (!UserRights::IsAdministrator()) -{ - ExitError($oP, "Access restricted to administors"); -} - -if (CheckParam('?') || CheckParam('h') || CheckParam('help')) -{ - Usage($oP); - $oP->output(); - exit; -} - - -// Interpret strftime specifications (like %Y) and database placeholders -$oRestore = new MyDBRestore($oP); -$oRestore->SetMySQLBinDir(MetaModel::GetConfig()->GetModuleSetting('itop-backup', 'mysql_bindir', '')); - -$res = false; -if (MetaModel::GetConfig()->Get('demo_mode')) -{ - $oP->p("Sorry, iTop is in demonstration mode: the feature is disabled"); -} -else -{ - $sEnvironment = utils::ReadParam('environment', 'production', false, 'raw_data'); - $oRestore->RestoreFromCompressedBackup($sBackupFile, $sEnvironment); -} - -$oP->output(); diff --git a/setup/backup.class.inc.php b/setup/backup.class.inc.php index 0dd9f809a..a491247b1 100644 --- a/setup/backup.class.inc.php +++ b/setup/backup.class.inc.php @@ -172,43 +172,33 @@ class DBBackup */ public function CreateCompressedBackup($sTargetFile, $sSourceConfigFile = null) { - $bReadonlyBefore = SetupUtils::IsInReadOnlyMode(); - SetupUtils::EnterReadOnlyMode(MetaModel::GetConfig()); - try { - //safe zone for db backup => cron is stopped/ itop in readonly - $bIsCmdbSourceInitialized = CMDBSource::GetMysqli() instanceof mysqli; - if (!$bIsCmdbSourceInitialized) { - $sErrorMsg = 'Cannot backup : CMDBSource not initialized !'; - $this->LogError($sErrorMsg); - throw new CoreException($sErrorMsg); - } - - $this->LogInfo("Creating backup: '$sTargetFile.tar.gz'"); - - $oArchive = new ITopArchiveTar($sTargetFile.'.tar.gz'); - - $sTmpFolder = APPROOT.'data/tmp-backup-'.rand(10000, getrandmax()); - $aFiles = $this->PrepareFilesToBackup($sSourceConfigFile, $sTmpFolder); - - $sFilesList = var_export($aFiles, true); - $this->LogInfo("backup: adding to archive files '$sFilesList'"); - $bArchiveCreationResult = $oArchive->createModify($aFiles, '', $sTmpFolder); - if (!$bArchiveCreationResult) { - $sErrorMsg = 'Cannot backup : unable to create archive'; - $this->LogError($sErrorMsg); - throw new BackupException($sErrorMsg); - } - - $this->LogInfo("backup: removing tmp folder '$sTmpFolder'"); - SetupUtils::rrmdir($sTmpFolder); - } finally { - if (! $bReadonlyBefore) { - SetupUtils::ExitReadOnlyMode(); - } else { - //we are in the scope of main process that needs to handle/keep readonly mode (setup for example). - $this->LogInfo("Keep readonly mode after backup"); - } + $bIsCmdbSourceInitialized = CMDBSource::GetMysqli() instanceof mysqli; + if (!$bIsCmdbSourceInitialized) + { + $sErrorMsg = 'Cannot backup : CMDBSource not initialized !'; + $this->LogError($sErrorMsg); + throw new CoreException($sErrorMsg); } + + $this->LogInfo("Creating backup: '$sTargetFile.tar.gz'"); + + $oArchive = new ITopArchiveTar($sTargetFile.'.tar.gz'); + + $sTmpFolder = APPROOT.'data/tmp-backup-'.rand(10000, getrandmax()); + $aFiles = $this->PrepareFilesToBackup($sSourceConfigFile, $sTmpFolder); + + $sFilesList = var_export($aFiles, true); + $this->LogInfo("backup: adding to archive files '$sFilesList'"); + $bArchiveCreationResult = $oArchive->createModify($aFiles, '', $sTmpFolder); + if (!$bArchiveCreationResult) + { + $sErrorMsg = 'Cannot backup : unable to create archive'; + $this->LogError($sErrorMsg); + throw new BackupException($sErrorMsg); + } + + $this->LogInfo("backup: removing tmp folder '$sTmpFolder'"); + SetupUtils::rrmdir($sTmpFolder); } /**