mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
Merge branch 'feature/6133-add-extra-files-to-backup-and-restore' into develop
This commit is contained in:
@@ -187,6 +187,12 @@ class DBRestore extends DBBackup
|
|||||||
@chmod($sConfigFile, 0770); // Allow overwriting the file
|
@chmod($sConfigFile, 0770); // Allow overwriting the file
|
||||||
rename($sDataDir.'/config-itop.php', $sConfigFile);
|
rename($sDataDir.'/config-itop.php', $sConfigFile);
|
||||||
@chmod($sConfigFile, 0440); // Read-only
|
@chmod($sConfigFile, 0440); // Read-only
|
||||||
|
|
||||||
|
$aExtraFiles = $this->ListExtraFiles($sDataDir);
|
||||||
|
foreach($aExtraFiles as $sSourceFilePath => $sDestinationFilePath) {
|
||||||
|
SetupUtils::builddir(dirname($sDestinationFilePath));
|
||||||
|
rename($sSourceFilePath, $sDestinationFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
SetupUtils::rrmdir($sDataDir);
|
SetupUtils::rrmdir($sDataDir);
|
||||||
@@ -211,4 +217,31 @@ class DBRestore extends DBBackup
|
|||||||
$oRestoreMutex->Unlock();
|
$oRestoreMutex->Unlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List the 'extra files' found in the decompressed archive
|
||||||
|
* (i.e. files other than config-itop.php, delta.xml, itop-dump.sql or production-modules/*
|
||||||
|
* @param string $sDataDir
|
||||||
|
* @return string[]
|
||||||
|
*/
|
||||||
|
protected function ListExtraFiles(string $sDataDir)
|
||||||
|
{
|
||||||
|
$aExtraFiles = [];
|
||||||
|
$aStandardFiles = ['config-itop.php', 'itop-dump.sql', 'production-modules', 'delta.xml'];
|
||||||
|
$oDirectoryIterator = new RecursiveDirectoryIterator($sDataDir, FilesystemIterator::CURRENT_AS_FILEINFO|FilesystemIterator::SKIP_DOTS);
|
||||||
|
$oIterator = new RecursiveIteratorIterator($oDirectoryIterator);
|
||||||
|
foreach ($oIterator as $oFileInfo)
|
||||||
|
{
|
||||||
|
if (in_array($oFileInfo->getFilename(), $aStandardFiles)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strncmp($oFileInfo->getPathname(), $sDataDir.'/production-modules', strlen($sDataDir.'/production-modules')) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$aExtraFiles[$oFileInfo->getPathname()] = APPROOT.substr($oFileInfo->getPathname(), strlen($sDataDir));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $aExtraFiles;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -222,11 +222,12 @@ class DBBackup
|
|||||||
*
|
*
|
||||||
* @param string $sSourceConfigFile
|
* @param string $sSourceConfigFile
|
||||||
* @param string $sTmpFolder
|
* @param string $sTmpFolder
|
||||||
|
* @param bool $bSkipSQLDumpForTesting
|
||||||
*
|
*
|
||||||
* @return array list of files to archive
|
* @return array list of files to archive
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
protected function PrepareFilesToBackup($sSourceConfigFile, $sTmpFolder)
|
protected function PrepareFilesToBackup($sSourceConfigFile, $sTmpFolder, $bSkipSQLDumpForTesting = false)
|
||||||
{
|
{
|
||||||
$aRet = array();
|
$aRet = array();
|
||||||
if (is_dir($sTmpFolder))
|
if (is_dir($sTmpFolder))
|
||||||
@@ -243,7 +244,7 @@ class DBBackup
|
|||||||
{
|
{
|
||||||
$sFile = $sTmpFolder.'/config-itop.php';
|
$sFile = $sTmpFolder.'/config-itop.php';
|
||||||
$this->LogInfo("backup: adding resource '$sSourceConfigFile'");
|
$this->LogInfo("backup: adding resource '$sSourceConfigFile'");
|
||||||
copy($sSourceConfigFile, $sFile);
|
@copy($sSourceConfigFile, $sFile); // During unattended install config file may be absent
|
||||||
$aRet[] = $sFile;
|
$aRet[] = $sFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,9 +265,43 @@ class DBBackup
|
|||||||
SetupUtils::copydir($sExtraDir, $sFile);
|
SetupUtils::copydir($sExtraDir, $sFile);
|
||||||
$aRet[] = $sFile;
|
$aRet[] = $sFile;
|
||||||
}
|
}
|
||||||
$sDataFile = $sTmpFolder.'/itop-dump.sql';
|
if (MetaModel::GetConfig() !== null) // During unattended install config file may be absent
|
||||||
$this->DoBackup($sDataFile);
|
{
|
||||||
$aRet[] = $sDataFile;
|
$aExtraFiles = MetaModel::GetModuleSetting('itop-backup', 'extra_files', []);
|
||||||
|
foreach($aExtraFiles as $sExtraFileOrDir)
|
||||||
|
{
|
||||||
|
if(!file_exists(APPROOT.'/'.$sExtraFileOrDir)) {
|
||||||
|
continue; // Ignore non-existing files
|
||||||
|
}
|
||||||
|
|
||||||
|
$sExtraFullPath = utils::RealPath(APPROOT.'/'.$sExtraFileOrDir, APPROOT);
|
||||||
|
if ($sExtraFullPath === false)
|
||||||
|
{
|
||||||
|
throw new Exception("Backup: Aborting, resource '$sExtraFileOrDir'. Considered as UNSAFE because not inside the iTop directory.");
|
||||||
|
}
|
||||||
|
if (is_dir($sExtraFullPath))
|
||||||
|
{
|
||||||
|
$sFile = $sTmpFolder.'/'.$sExtraFileOrDir;
|
||||||
|
$this->LogInfo("backup: adding directory '$sExtraFileOrDir'");
|
||||||
|
SetupUtils::copydir($sExtraFullPath, $sFile);
|
||||||
|
$aRet[] = $sFile;
|
||||||
|
}
|
||||||
|
elseif (file_exists($sExtraFullPath))
|
||||||
|
{
|
||||||
|
$sFile = $sTmpFolder.'/'.$sExtraFileOrDir;
|
||||||
|
$this->LogInfo("backup: adding file '$sExtraFileOrDir'");
|
||||||
|
@mkdir(dirname($sFile), 0755, true);
|
||||||
|
copy($sExtraFullPath, $sFile);
|
||||||
|
$aRet[] = $sFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!$bSkipSQLDumpForTesting)
|
||||||
|
{
|
||||||
|
$sDataFile = $sTmpFolder.'/itop-dump.sql';
|
||||||
|
$this->DoBackup($sDataFile);
|
||||||
|
$aRet[] = $sDataFile;
|
||||||
|
}
|
||||||
|
|
||||||
return $aRet;
|
return $aRet;
|
||||||
}
|
}
|
||||||
|
|||||||
119
tests/php-unit-tests/unitary-tests/setup/DBBackupDataTest.php
Normal file
119
tests/php-unit-tests/unitary-tests/setup/DBBackupDataTest.php
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Combodo\iTop\Test\UnitTest\Core;
|
||||||
|
|
||||||
|
use Combodo\iTop\Test\UnitTest\ItopDataTestCase;
|
||||||
|
use DBBackup;
|
||||||
|
use DBRestore;
|
||||||
|
use MetaModel;
|
||||||
|
use SetupUtils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @runTestsInSeparateProcesses
|
||||||
|
* @preserveGlobalState disabled
|
||||||
|
* @backupGlobals disabled
|
||||||
|
*/
|
||||||
|
class DBBackupDataTest extends ItopDataTestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @dataProvider prepareFilesToBackupProvider
|
||||||
|
*/
|
||||||
|
public function testPrepareFilesToBackup(array $aExtraFiles, bool $bUnsafeFileException)
|
||||||
|
{
|
||||||
|
$sTmpDir = sys_get_temp_dir().'/testPrepareFilesToBackup-'.time();
|
||||||
|
$oBackup = new DBBackup(MetaModel::GetConfig());
|
||||||
|
MetaModel::GetConfig()->SetModuleSetting('itop-backup', 'extra_files', array_keys($aExtraFiles));
|
||||||
|
|
||||||
|
foreach($aExtraFiles as $sExtraFile => $bExists)
|
||||||
|
{
|
||||||
|
if ($bExists)
|
||||||
|
{
|
||||||
|
@mkdir(dirname(APPROOT.'/'.$sExtraFile), 0755, true);
|
||||||
|
file_put_contents(APPROOT.'/'.$sExtraFile, 'Hello World!');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($bUnsafeFileException)
|
||||||
|
{
|
||||||
|
$this->expectExceptionMessage("Backup: Aborting, resource '$sExtraFile'. Considered as UNSAFE because not inside the iTop directory.");
|
||||||
|
}
|
||||||
|
$aFiles = $this->InvokeNonPublicMethod('DBBackup', 'PrepareFilesToBackup', $oBackup, [APPROOT.'/conf/production/config-itop.php', $sTmpDir, true]);
|
||||||
|
SetupUtils::rrmdir($sTmpDir);
|
||||||
|
$aExpectedFiles = [
|
||||||
|
$sTmpDir.'/config-itop.php',
|
||||||
|
];
|
||||||
|
foreach($aExtraFiles as $sRelFile => $bExists)
|
||||||
|
{
|
||||||
|
if ($bExists)
|
||||||
|
{
|
||||||
|
$aExpectedFiles[] = $sTmpDir.'/'.$sRelFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort($aFiles);
|
||||||
|
sort($aExpectedFiles);
|
||||||
|
$this->assertEquals($aFiles, $aExpectedFiles);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
foreach($aExtraFiles as $sExtraFile => $bExists)
|
||||||
|
{
|
||||||
|
if ($bExists)
|
||||||
|
{
|
||||||
|
unlink(APPROOT.'/'.$sExtraFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareFilesToBackupProvider()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'no_extra_file' => ['aExtraFiles' => [], false],
|
||||||
|
'one_extra_file' => ['aExtraFiles' => ['foo.txt' => true], false],
|
||||||
|
'three_extra_file_and_dir' => ['aExtraFiles' => ['foo.txt' => true, 'gabu/zomeu.xml' => true, 'meuh.html' => true], false],
|
||||||
|
'two_extra_file_but_only_one_exists' => ['aExtraFiles' => ['foo.txt' => true, 'meuh.html' => false], false],
|
||||||
|
'one_unsafe_file' => ['aExtraFiles' => ['../foo.txt' => true], true],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider restoreListExtraFilesProvider
|
||||||
|
*/
|
||||||
|
function testRestoreListExtraFiles($aFilesToCreate, $aExpectedRelativeExtraFiles)
|
||||||
|
{
|
||||||
|
require_once(APPROOT.'/env-production/itop-backup/dbrestore.class.inc.php');
|
||||||
|
|
||||||
|
$sTmpDir = sys_get_temp_dir().'/testRestoreListExtraFiles-'.time();
|
||||||
|
|
||||||
|
foreach($aFilesToCreate as $sRelativeName)
|
||||||
|
{
|
||||||
|
$sDir = $sTmpDir.'/'.dirname($sRelativeName);
|
||||||
|
if(!is_dir($sDir))
|
||||||
|
{
|
||||||
|
mkdir($sDir, 0755, true);
|
||||||
|
}
|
||||||
|
file_put_contents($sTmpDir.'/'.$sRelativeName, 'Hello world.');
|
||||||
|
}
|
||||||
|
$aExpectedExtraFiles = [];
|
||||||
|
foreach($aExpectedRelativeExtraFiles as $sRelativeName)
|
||||||
|
{
|
||||||
|
$aExpectedExtraFiles[$sTmpDir.'/'.$sRelativeName] = APPROOT.'/'.$sRelativeName;
|
||||||
|
}
|
||||||
|
|
||||||
|
$oRestore = new DBRestore(MetaModel::GetConfig());
|
||||||
|
$aExtraFiles = $this->InvokeNonPublicMethod('DBRestore', 'ListExtraFiles', $oRestore, [$sTmpDir]);
|
||||||
|
|
||||||
|
asort($aExtraFiles);
|
||||||
|
asort($aExpectedExtraFiles);
|
||||||
|
$this->assertEquals($aExpectedExtraFiles, $aExtraFiles);
|
||||||
|
SetupUtils::rrmdir($sTmpDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreListExtraFilesProvider()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'no extra file' => ['aFilesToCreate' => ['config-itop.php', 'itop-dump.sql', 'delta.xml'], 'aExpectedExtraFiles' => []],
|
||||||
|
'no extra file (2)' => ['aFilesToCreate' => ['config-itop.php', 'itop-dump.sql', 'delta.xml', 'production-modules/test/module.test.php'], 'aExpectedExtraFiles' => []],
|
||||||
|
'one extra file' => ['aFilesToCreate' => ['config-itop.php', 'itop-dump.sql', 'delta.xml', 'production-modules/test/module.test.php', 'collectors/ldap/conf/params.local.xml'], 'aExpectedExtraFiles' => ['collectors/ldap/conf/params.local.xml']],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user