mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
Revert "N°4225 - Protect manual backups from cron (and vice versa) - minimal work ie protect manual backup from cron only"
This reverts commit e3dc1b77cc.
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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 => <env>.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 => <env>.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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,203 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2013-2021 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
if (!defined('__DIR__')) define('__DIR__', dirname(__FILE__));
|
||||
if (!defined('APPROOT'))
|
||||
{
|
||||
if (file_exists(__DIR__.'/../../approot.inc.php'))
|
||||
{
|
||||
require_once __DIR__.'/../../approot.inc.php'; // When in env-xxxx folder
|
||||
}
|
||||
else
|
||||
{
|
||||
require_once __DIR__.'/../../../approot.inc.php'; // When in datamodels/x.x folder
|
||||
}
|
||||
}
|
||||
require_once(APPROOT.'application/application.inc.php');
|
||||
require_once(APPROOT.'application/ajaxwebpage.class.inc.php');
|
||||
require_once(APPROOT.'core/log.class.inc.php');
|
||||
require_once(APPROOT.'application/startup.inc.php');
|
||||
require_once(dirname(__FILE__).'/dbrestore.class.inc.php');
|
||||
|
||||
class MyDBRestore extends DBRestore
|
||||
{
|
||||
/** @var Page used to send log */
|
||||
protected $oPage;
|
||||
|
||||
protected function LogInfo($sMsg)
|
||||
{
|
||||
$this->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();
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user