diff --git a/setup/applicationinstaller.class.inc.php b/setup/applicationinstaller.class.inc.php
index 8a57472f5..b298a085b 100644
--- a/setup/applicationinstaller.class.inc.php
+++ b/setup/applicationinstaller.class.inc.php
@@ -3,7 +3,7 @@
//
// This file is part of iTop.
//
-// iTop is free software; you can redistribute it and/or modify
+// 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.
@@ -25,7 +25,7 @@ require_once(APPROOT.'setup/backup.class.inc.php');
* The installation process is split into a sequence of unitary steps
* for performance reasons (i.e; timeout, memory usage) and also in order
* to provide some feedback about the progress of the installation.
- *
+ *
* This class can be used for a step by step interactive installation
* while displaying a progress bar, or in an unattended manner
* (for example from the command line), to run all the steps
@@ -157,7 +157,7 @@ class ApplicationInstaller
}
}
while(($aRes['status'] != self::ERROR) && ($aRes['next-step'] != ''));
-
+
return ($iOverallStatus == self::OK);
}
@@ -225,7 +225,7 @@ class ApplicationInstaller
case 'copy':
$aPreinstall = $this->oParams->Get('preinstall');
- $aCopies = $aPreinstall['copies'];
+ $aCopies = $aPreinstall['copies'] ?? [];
self::DoCopy($aCopies);
$sReport = "Copying...";
@@ -472,7 +472,7 @@ class ApplicationInstaller
{
$sSource = $aCopy['source'];
$sDestination = APPROOT.$aCopy['destination'];
-
+
SetupUtils::builddir($sDestination);
SetupUtils::tidydir($sDestination);
SetupUtils::copydir($sSource, $sDestination);
@@ -513,7 +513,7 @@ class ApplicationInstaller
$oBackup->CreateCompressedBackup($sTargetFile, $sSourceConfigFile);
}
-
+
protected static function DoCompile($aSelectedModules, $sSourceDir, $sExtensionDir, $sTargetDir, $sEnvironment, $bUseSymbolicLinks = false)
{
SetupPage::log_info("Compiling data model.");
@@ -525,7 +525,7 @@ class ApplicationInstaller
if (empty($sSourceDir) || empty($sTargetDir))
{
throw new Exception("missing parameter source_dir and/or target_dir");
- }
+ }
$sSourcePath = APPROOT.$sSourceDir;
$aDirsToScan = array($sSourcePath);
@@ -582,10 +582,10 @@ class ApplicationInstaller
}
$oFactory = new ModelFactory($aDirsToScan);
-
+
$oDictModule = new MFDictModule('dictionaries', 'iTop Dictionaries', APPROOT.'dictionaries');
$oFactory->LoadModule($oDictModule);
-
+
$sDeltaFile = APPROOT.'core/datamodel.core.xml';
if (file_exists($sDeltaFile))
{
@@ -598,7 +598,7 @@ class ApplicationInstaller
$oApplicationModule = new MFCoreModule('application', 'Application Module', $sDeltaFile);
$oFactory->LoadModule($oApplicationModule);
}
-
+
$aModules = $oFactory->FindModules();
foreach($aModules as $oModule)
@@ -611,7 +611,7 @@ class ApplicationInstaller
}
// Dump the "reference" model, just before loading any actual delta
$oFactory->SaveToFile(APPROOT.'data/datamodel-'.$sEnvironment.'.xml');
-
+
$sDeltaFile = APPROOT.'data/'.$sEnvironment.'.delta.xml';
if (file_exists($sDeltaFile))
{
@@ -635,12 +635,12 @@ class ApplicationInstaller
if (file_exists($sFileToPatch))
{
$sContent = file_get_contents($sFileToPatch);
-
+
$sContent = str_replace("require_once(APPROOT.'modules/itop-welcome-itil/model.itop-welcome-itil.php');", "//\n// The line below is no longer needed in iTop 2.0 -- patched by the setup program\n// require_once(APPROOT.'modules/itop-welcome-itil/model.itop-welcome-itil.php');", $sContent);
-
+
file_put_contents($sFileToPatch, $sContent);
}
-
+
// Set an "Instance UUID" identifying this machine based on a file located in the data directory
$sInstanceUUIDFile = APPROOT.'data/instance.txt';
SetupUtils::builddir(APPROOT.'data');
@@ -699,7 +699,7 @@ class ApplicationInstaller
// Starting 2.0, all table names must be lowercase
if ($sMode != 'install')
{
- SetupPage::log_info("Renaming '{$sDBPrefix}priv_internalUser' into '{$sDBPrefix}priv_internaluser' (lowercase)");
+ SetupPage::log_info("Renaming '{$sDBPrefix}priv_internalUser' into '{$sDBPrefix}priv_internaluser' (lowercase)");
// This command will have no effect under Windows...
// and it has been written in two steps so as to make it work under windows!
CMDBSource::SelectDB($sDBName);
@@ -710,18 +710,18 @@ class ApplicationInstaller
}
catch (Exception $e)
{
- SetupPage::log_info("Renaming '{$sDBPrefix}priv_internalUser' failed (already done in a previous upgrade?)");
+ SetupPage::log_info("Renaming '{$sDBPrefix}priv_internalUser' failed (already done in a previous upgrade?)");
}
-
+
// let's remove the records in priv_change which have no counterpart in priv_changeop
- SetupPage::log_info("Cleanup of '{$sDBPrefix}priv_change' to remove orphan records");
+ SetupPage::log_info("Cleanup of '{$sDBPrefix}priv_change' to remove orphan records");
CMDBSource::SelectDB($sDBName);
try
{
$sTotalCount = "SELECT COUNT(*) FROM `{$sDBPrefix}priv_change`";
$iTotalCount = (int)CMDBSource::QueryToScalar($sTotalCount);
SetupPage::log_info("There is a total of $iTotalCount records in {$sDBPrefix}priv_change.");
-
+
$sOrphanCount = "SELECT COUNT(c.id) FROM `{$sDBPrefix}priv_change` AS c left join `{$sDBPrefix}priv_changeop` AS o ON c.id = o.changeid WHERE o.id IS NULL";
$iOrphanCount = (int)CMDBSource::QueryToScalar($sOrphanCount);
SetupPage::log_info("There are $iOrphanCount useless records in {$sDBPrefix}priv_change (".sprintf('%.2f', ((100.0*$iOrphanCount)/$iTotalCount))."%)");
@@ -745,11 +745,11 @@ class ApplicationInstaller
}
catch (Exception $e)
{
- SetupPage::log_info("Cleanup of orphan records in `{$sDBPrefix}priv_change` failed: ".$e->getMessage());
+ SetupPage::log_info("Cleanup of orphan records in `{$sDBPrefix}priv_change` failed: ".$e->getMessage());
}
-
+
}
-
+
// Module specific actions (migrate the data)
//
$aAvailableModules = $oProductionEnv->AnalyzeInstallation(MetaModel::GetConfig(), APPROOT.$sModulesDir);
@@ -757,9 +757,9 @@ class ApplicationInstaller
if(!$oProductionEnv->CreateDatabaseStructure(MetaModel::GetConfig(), $sMode))
{
- throw new Exception("Failed to create/upgrade the database structure for environment '$sTargetEnvironment'");
+ throw new Exception("Failed to create/upgrade the database structure for environment '$sTargetEnvironment'");
}
-
+
// Set a DBProperty with a unique ID to identify this instance of iTop
$sUUID = DBProperty::GetProperty('database_uuid', '');
if ($sUUID === '')
@@ -767,10 +767,10 @@ class ApplicationInstaller
$sUUID = utils::CreateUUID('database');
DBProperty::SetProperty('database_uuid', $sUUID, 'Installation/upgrade of '.ITOP_APPLICATION, 'Unique ID of this '.ITOP_APPLICATION.' Database');
}
-
+
// priv_change now has an 'origin' field to distinguish between the various input sources
// Let's initialize the field with 'interactive' for all records were it's null
- // Then check if some records should hold a different value, based on a pattern matching in the userinfo field
+ // Then check if some records should hold a different value, based on a pattern matching in the userinfo field
CMDBSource::SelectDB($sDBName);
try
{
@@ -778,21 +778,21 @@ class ApplicationInstaller
$iCount = (int)CMDBSource::QueryToScalar($sCount);
if ($iCount > 0)
{
- SetupPage::log_info("Initializing '{$sDBPrefix}priv_change.origin' ($iCount records to update)");
-
+ SetupPage::log_info("Initializing '{$sDBPrefix}priv_change.origin' ($iCount records to update)");
+
// By default all uninitialized values are considered as 'interactive'
$sInit = "UPDATE `{$sDBPrefix}priv_change` SET `origin` = 'interactive' WHERE `origin` IS NULL";
CMDBSource::Query($sInit);
-
+
// CSV Import was identified by the comment at the end
$sInit = "UPDATE `{$sDBPrefix}priv_change` SET `origin` = 'csv-import.php' WHERE `userinfo` LIKE '%Web Service (CSV)'";
CMDBSource::Query($sInit);
-
+
// CSV Import was identified by the comment at the end
$sInit = "UPDATE `{$sDBPrefix}priv_change` SET `origin` = 'csv-interactive' WHERE `userinfo` LIKE '%(CSV)' AND origin = 'interactive'";
CMDBSource::Query($sInit);
-
-
+
+
// Syncho data sources were identified by the comment at the end
// Unfortunately the comment is localized, so we have to search for all possible patterns
$sCurrentLanguage = Dict::GetUserLanguage();
@@ -806,19 +806,19 @@ class ApplicationInstaller
Dict::SetUserLanguage($sCurrentLanguage);
$sCondition = "`userinfo` LIKE ".implode(" OR `userinfo` LIKE ", array_keys($aSuffixes));
- $sInit = "UPDATE `{$sDBPrefix}priv_change` SET `origin` = 'synchro-data-source' WHERE ($sCondition)";
+ $sInit = "UPDATE `{$sDBPrefix}priv_change` SET `origin` = 'synchro-data-source' WHERE ($sCondition)";
CMDBSource::Query($sInit);
-
- SetupPage::log_info("Initialization of '{$sDBPrefix}priv_change.origin' completed.");
+
+ SetupPage::log_info("Initialization of '{$sDBPrefix}priv_change.origin' completed.");
}
else
{
- SetupPage::log_info("'{$sDBPrefix}priv_change.origin' already initialized, nothing to do.");
+ SetupPage::log_info("'{$sDBPrefix}priv_change.origin' already initialized, nothing to do.");
}
}
catch (Exception $e)
{
- SetupPage::log_error("Initializing '{$sDBPrefix}priv_change.origin' failed: ".$e->getMessage());
+ SetupPage::log_error("Initializing '{$sDBPrefix}priv_change.origin' failed: ".$e->getMessage());
}
// priv_async_task now has a 'status' field to distinguish between the various statuses rather than just relying on the date columns
@@ -830,24 +830,24 @@ class ApplicationInstaller
$iCount = (int)CMDBSource::QueryToScalar($sCount);
if ($iCount > 0)
{
- SetupPage::log_info("Initializing '{$sDBPrefix}priv_async_task.status' ($iCount records to update)");
-
+ SetupPage::log_info("Initializing '{$sDBPrefix}priv_async_task.status' ($iCount records to update)");
+
$sInit = "UPDATE `{$sDBPrefix}priv_async_task` SET `status` = 'planned' WHERE (`status` IS NULL) AND (`started` IS NULL)";
CMDBSource::Query($sInit);
$sInit = "UPDATE `{$sDBPrefix}priv_async_task` SET `status` = 'error' WHERE (`status` IS NULL) AND (`started` IS NOT NULL)";
CMDBSource::Query($sInit);
-
- SetupPage::log_info("Initialization of '{$sDBPrefix}priv_async_task.status' completed.");
+
+ SetupPage::log_info("Initialization of '{$sDBPrefix}priv_async_task.status' completed.");
}
else
{
- SetupPage::log_info("'{$sDBPrefix}priv_async_task.status' already initialized, nothing to do.");
+ SetupPage::log_info("'{$sDBPrefix}priv_async_task.status' already initialized, nothing to do.");
}
}
catch (Exception $e)
{
- SetupPage::log_error("Initializing '{$sDBPrefix}priv_async_task.status' failed: ".$e->getMessage());
+ SetupPage::log_error("Initializing '{$sDBPrefix}priv_async_task.status' failed: ".$e->getMessage());
}
SetupPage::log_info("Database Schema Successfully Updated for environment '$sTargetEnvironment'.");
@@ -887,15 +887,15 @@ class ApplicationInstaller
$oProductionEnv = new RunTimeEnvironment($sTargetEnvironment);
$oProductionEnv->InitDataModel($oConfig, true); // load data model and connect to the database
$oContextTag = new ContextTag(ContextTag::TAG_SETUP);
- self::$bMetaModelStarted = true; // No need to reload the final MetaModel in case the installer runs synchronously
-
+ self::$bMetaModelStarted = true; // No need to reload the final MetaModel in case the installer runs synchronously
+
// Perform here additional DB setup... profiles, etc...
//
$aAvailableModules = $oProductionEnv->AnalyzeInstallation(MetaModel::GetConfig(), APPROOT.$sModulesDir);
$oProductionEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseCreation');
$oProductionEnv->UpdatePredefinedObjects();
-
+
if($sMode == 'install')
{
if (!self::CreateAdminAccount(MetaModel::GetConfig(), $sAdminUser, $sAdminPwd, $sAdminLanguage))
@@ -907,20 +907,20 @@ class ApplicationInstaller
SetupPage::log_info("Administrator account '$sAdminUser' created.");
}
}
-
+
// Perform final setup tasks here
//
$oProductionEnv->CallInstallerHandlers($aAvailableModules, $aSelectedModules, 'AfterDatabaseSetup');
}
-
+
/**
* Helper function to create and administrator account for iTop
- * @return boolean true on success, false otherwise
+ * @return boolean true on success, false otherwise
*/
protected static function CreateAdminAccount(Config $oConfig, $sAdminUser, $sAdminPwd, $sLanguage)
{
SetupPage::log_info('CreateAdminAccount');
-
+
if (UserRights::CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage))
{
return true;
@@ -946,9 +946,9 @@ class ApplicationInstaller
'user rights' => 'addons/userrights/userrightsprofile.db.class.inc.php',
));
}
-
+
$oProductionEnv = new RunTimeEnvironment($sTargetEnvironment);
-
+
//Load the MetaModel if needed (asynchronous mode)
if (!self::$bMetaModelStarted)
{
@@ -956,8 +956,8 @@ class ApplicationInstaller
$oContextTag = new ContextTag(ContextTag::TAG_SETUP);
self::$bMetaModelStarted = true; // No need to reload the final MetaModel in case the installer runs synchronously
- }
-
+ }
+
$aAvailableModules = $oProductionEnv->AnalyzeInstallation($oConfig, APPROOT.$sModulesDir);
$oProductionEnv->LoadData($aAvailableModules, $aSelectedModules, $bSampleData);
@@ -992,7 +992,7 @@ class ApplicationInstaller
$bPreserveModuleSettings = false;
if ($sMode == 'upgrade')
{
- try
+ try
{
$oOldConfig = new Config($sPreviousConfigFile);
$oConfig = clone($oOldConfig);
@@ -1038,7 +1038,7 @@ class ApplicationInstaller
{
mkdir(APPCONF);
chmod(APPCONF, 0770); // RWX for owner and group, nothing for others
- SetupPage::log_info("Created configuration directory: ".APPCONF);
+ SetupPage::log_info("Created configuration directory: ".APPCONF);
}
// Write the final configuration file
@@ -1048,7 +1048,7 @@ class ApplicationInstaller
@chmod($sConfigDir, 0770); // RWX for owner and group, nothing for others
$oConfig->WriteToFile($sConfigFile);
-
+
// try to make the final config file read-only
@chmod($sConfigFile, 0440); // Read-only for owner and group, nothing for others
diff --git a/setup/modulediscovery.class.inc.php b/setup/modulediscovery.class.inc.php
index 4dd2e281a..4a24f0bcc 100644
--- a/setup/modulediscovery.class.inc.php
+++ b/setup/modulediscovery.class.inc.php
@@ -76,7 +76,7 @@ class ModuleDiscovery
'doc.manual_setup' => 'url',
'doc.more_information' => 'url',
);
-
+
// Cache the results and the source directories
protected static $m_aSearchDirs = null;
@@ -148,7 +148,7 @@ class ModuleDiscovery
self::$m_aModuleVersionByName[$sModuleName]['version'] = $sModuleVersion;
self::$m_aModuleVersionByName[$sModuleName]['id'] = $sId;
}
-
+
self::$m_aModules[$sId] = $aArgs;
// Now keep the relative paths, as provided
@@ -250,7 +250,7 @@ class ModuleDiscovery
if ($bAbortOnMissingDependency && count($aDependencies) > 0)
{
$aModulesInfo = array();
- $aModuleDeps = array();
+ $aModuleDeps = array();
foreach($aDependencies as $sId => $aDeps)
{
$aModule = $aModules[$sId];
@@ -282,7 +282,7 @@ class ModuleDiscovery
// The de-duplication is now done directly by the AddModule method
return $aModules;
}
-
+
protected static function DependencyIsResolved($sDepString, $aOrderedModules, $aSelectedModules)
{
$bResult = false;
@@ -329,12 +329,12 @@ class ModuleDiscovery
if (version_compare($sCurrentVersion, $sExpectedVersion, $sOperator))
{
$aReplacements[$sModuleId] = '(true)'; // Add parentheses to protect against invalid condition causing
- // a function call that results in a runtime fatal error
+ // a function call that results in a runtime fatal error
}
else
{
$aReplacements[$sModuleId] = '(false)'; // Add parentheses to protect against invalid condition causing
- // a function call that results in a runtime fatal error
+ // a function call that results in a runtime fatal error
}
}
else
@@ -393,20 +393,20 @@ class ModuleDiscovery
{
self::ResetCache();
}
-
+
if (is_null(self::$m_aSearchDirs))
{
self::$m_aSearchDirs = $aSearchDirs;
-
+
// Not in cache, let's scan the disk
foreach($aSearchDirs as $sSearchDir)
{
- $sLookupDir = realpath($sSearchDir);
+ $sLookupDir = realpath($sSearchDir);
if ($sLookupDir == '')
{
throw new Exception("Invalid directory '$sSearchDir'");
}
-
+
clearstatcache();
self::ListModuleFiles(basename($sSearchDir), dirname($sSearchDir));
}
@@ -418,7 +418,7 @@ class ModuleDiscovery
return self::GetModules($bAbortOnMissingDependency, $aModulesToLoad);
}
}
-
+
public static function ResetCache()
{
self::$m_aSearchDirs = null;
@@ -430,7 +430,7 @@ class ModuleDiscovery
* Helper function to interpret the name of a module
* @param $sModuleId string Identifier of the module, in the form 'name/version'
* @return array(name, version)
- */
+ */
public static function GetModuleName($sModuleId)
{
$aMatches = array();
@@ -459,7 +459,7 @@ class ModuleDiscovery
{
static $iDummyClassIndex = 0;
$sDirectory = $sRootDir.'/'.$sRelDir;
-
+
if ($hDir = opendir($sDirectory))
{
// This is the correct way to loop over the directory. (according to the documentation)
@@ -495,12 +495,12 @@ class ModuleDiscovery
$idx++;
}
$bRet = eval($sModuleFileContents);
-
+
if ($bRet === false)
{
SetupPage::log_warning("Eval of $sRelDir/$sFile returned false");
}
-
+
//echo "
Done.
\n";
}
catch(ParseError $e)
@@ -528,7 +528,7 @@ class ModuleDiscovery
/** Alias for backward compatibility with old module files in which
* the declaration of a module invokes SetupWebPage::AddModule()
* whereas the new form is ModuleDiscovery::AddModule()
- */
+ */
class SetupWebPage extends ModuleDiscovery
{
// For backward compatibility with old modules...
@@ -555,9 +555,9 @@ class SetupWebPage extends ModuleDiscovery
public static function log($sText)
{
SetupPage::log($sText);
- }
+ }
}
-
+
/** Ugly patch !!!
* In order to be able to analyse / load several times
* the same module file, we rename the class (to avoid duplicate class definitions)
diff --git a/setup/runtimeenv.class.inc.php b/setup/runtimeenv.class.inc.php
index 3b92fa460..0d46c5ad3 100644
--- a/setup/runtimeenv.class.inc.php
+++ b/setup/runtimeenv.class.inc.php
@@ -3,7 +3,7 @@
//
// This file is part of iTop.
//
-// iTop is free software; you can redistribute it and/or modify
+// 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.
@@ -100,14 +100,14 @@ class RunTimeEnvironment
$this->log_info(sprintf('%.3fs - query: %s ', $fDuration, $sQuery));
$this->log_db_query($sQuery);
}
-
+
/**
* Helper function to initialize the ORM and load the data model
* from the given file
* @param $oConfig object The configuration (volatile, not necessarily already on disk)
- * @param $bModelOnly boolean Whether or not to allow loading a data model with no corresponding DB
+ * @param $bModelOnly boolean Whether or not to allow loading a data model with no corresponding DB
* @return none
- */
+ */
public function InitDataModel($oConfig, $bModelOnly = true, $bUseCache = false)
{
require_once APPROOT.'/setup/moduleinstallation.class.inc.php';
@@ -121,15 +121,15 @@ class RunTimeEnvironment
{
$this->log_info("MetaModel::Startup (ModelOnly = $bModelOnly)");
}
-
+
if (!$bUseCache)
{
// Reset the cache for the first use !
MetaModel::ResetCache(md5(APPROOT).'-'.$this->sTargetEnv);
}
-
+
MetaModel::Startup($oConfig, $bModelOnly, $bUseCache, false /* $bTraceSourceFiles */, $this->sTargetEnv);
-
+
if ($this->oExtensionsMap === null)
{
$this->oExtensionsMap = new iTopExtensionsMap($this->sTargetEnv);
@@ -139,7 +139,7 @@ class RunTimeEnvironment
/**
* Analyzes the current installation and the possibilities
*
- * @param Config $oConfig Defines the target environment (DB)
+ * @param null|Config $oConfig Defines the target environment (DB)
* @param mixed $modulesPath Either a single string or an array of absolute paths
* @param bool $bAbortOnMissingDependency ...
* @param array $aModulesToLoad List of modules to search for, defaults to all if omitted
@@ -178,7 +178,7 @@ class RunTimeEnvironment
'name_code' => ITOP_APPLICATION,
)
);
-
+
$aDirs = is_array($modulesPath) ? $modulesPath : array($modulesPath);
$aModules = ModuleDiscovery::GetAvailableModules($aDirs, $bAbortOnMissingDependency, $aModulesToLoad);
foreach($aModules as $sModuleId => $aModuleInfo)
@@ -194,11 +194,11 @@ class RunTimeEnvironment
//throw new Exception("Missing version for the module: '$sModuleId'");
$sModuleVersion = '1.0.0';
}
-
+
$sModuleAppVersion = $aModuleInfo['itop_version'];
$aModuleInfo['version_db'] = '';
$aModuleInfo['version_code'] = $sModuleVersion;
-
+
if (!in_array($sModuleAppVersion, array('1.0.0', '1.0.1', '1.0.2')))
{
// This module is NOT compatible with the current version
@@ -223,18 +223,20 @@ class RunTimeEnvironment
}
$aRes[$sModuleName] = $aModuleInfo;
}
-
+
try
{
- CMDBSource::InitFromConfig($oConfig);
- $aSelectInstall = CMDBSource::QueryToArray("SELECT * FROM ".$oConfig->Get('db_subname')."priv_module_install");
+ $aSelectInstall = array();
+ if (! is_null($oConfig)) {
+ CMDBSource::InitFromConfig($oConfig);
+ $aSelectInstall = CMDBSource::QueryToArray("SELECT * FROM ".$oConfig->Get('db_subname')."priv_module_install");
+ }
}
catch (MySQLException $e)
{
// No database or erroneous information
- $aSelectInstall = array();
}
-
+
// Build the list of installed module (get the latest installation)
//
$aInstallByModule = array(); // array of => array ('installed' => timestamp, 'version' => )
@@ -251,7 +253,7 @@ class RunTimeEnvironment
}
}
}
-
+
foreach ($aSelectInstall as $aInstall)
{
//$aInstall['comment']; // unsused
@@ -265,7 +267,7 @@ class RunTimeEnvironment
// as being installed
$sModuleVersion = '0.0.0';
}
-
+
if ($aInstall['parent_id'] == 0)
{
$sModuleName = ROOT_MODULE;
@@ -275,7 +277,7 @@ class RunTimeEnvironment
// Skip all modules belonging to previous installations
continue;
}
-
+
if (array_key_exists($sModuleName, $aInstallByModule))
{
if ($iInstalled < $aInstallByModule[$sModuleName]['installed'])
@@ -283,30 +285,30 @@ class RunTimeEnvironment
continue;
}
}
-
+
if ($aInstall['parent_id'] == 0)
{
$aRes[$sModuleName]['version_db'] = $sModuleVersion;
$aRes[$sModuleName]['name_db'] = $aInstall['name'];
}
-
+
$aInstallByModule[$sModuleName]['installed'] = $iInstalled;
$aInstallByModule[$sModuleName]['version'] = $sModuleVersion;
}
-
+
// Adjust the list of proposed modules
//
foreach ($aInstallByModule as $sModuleName => $aModuleDB)
{
if ($sModuleName == ROOT_MODULE) continue; // Skip the main module
-
+
if (!array_key_exists($sModuleName, $aRes))
{
- // A module was installed, it is not proposed in the new build... skip
+ // A module was installed, it is not proposed in the new build... skip
continue;
}
$aRes[$sModuleName]['version_db'] = $aModuleDB['version'];
-
+
if ($aRes[$sModuleName]['install']['flag'] == MODULE_ACTION_MANDATORY)
{
$aRes[$sModuleName]['uninstall'] = array(
@@ -322,7 +324,7 @@ class RunTimeEnvironment
);
}
}
-
+
return $aRes;
}
@@ -336,9 +338,9 @@ class RunTimeEnvironment
{
self::MakeDirSafe(APPCONF);
self::MakeDirSafe(APPCONF.$this->sTargetEnv);
-
+
$sTargetConfigFile = APPCONF.$this->sTargetEnv.'/'.ITOP_CONFIG_FILE;
-
+
// Write the config file
@chmod($sTargetConfigFile, 0770); // In case it exists: RWX for owner and group, nothing for others
$oConfig->WriteToFile($sTargetConfigFile);
@@ -354,7 +356,7 @@ class RunTimeEnvironment
// Do nothing, overload this method if needed
return array();
}
-
+
/**
* Decide whether or not the given extension is selected for installation
* @param iTopExtension $oExtension
@@ -364,10 +366,10 @@ class RunTimeEnvironment
{
return ($oExtension->sSource == iTopExtension::SOURCE_REMOTE);
}
-
+
/**
- * Get the installed modules (only the installed ones)
- */
+ * Get the installed modules (only the installed ones)
+ */
protected function GetMFModulesToCompile($sSourceEnv, $sSourceDir)
{
$sSourceDirFull = APPROOT.$sSourceDir;
@@ -388,7 +390,7 @@ class RunTimeEnvironment
$aExtraDirs = $this->GetExtraDirsToScan($aDirsToCompile);
$aDirsToCompile = array_merge($aDirsToCompile, $aExtraDirs);
-
+
$aRet = array();
// Determine the installed modules and extensions
@@ -396,7 +398,7 @@ class RunTimeEnvironment
$oSourceConfig = new Config(APPCONF.$sSourceEnv.'/'.ITOP_CONFIG_FILE);
$oSourceEnv = new RunTimeEnvironment($sSourceEnv);
$aAvailableModules = $oSourceEnv->AnalyzeInstallation($oSourceConfig, $aDirsToCompile);
-
+
// Actually read the modules available for the target environment,
// but get the selection from the source environment and finally
// mark as (automatically) chosen alll the "remote" modules present in the
@@ -416,7 +418,7 @@ class RunTimeEnvironment
//
$oDictModule = new MFDictModule('dictionaries', 'iTop Dictionaries', APPROOT.'dictionaries');
$aRet[$oDictModule->GetName()] = $oDictModule;
-
+
$oFactory = new ModelFactory($aDirsToCompile);
$sDeltaFile = APPROOT.'core/datamodel.core.xml';
if (file_exists($sDeltaFile))
@@ -430,14 +432,14 @@ class RunTimeEnvironment
$oApplicationModule = new MFCoreModule('application', 'Application Module', $sDeltaFile);
$aRet[$oApplicationModule->GetName()] = $oApplicationModule;
}
-
+
$aModules = $oFactory->FindModules();
foreach($aModules as $oModule)
{
$sModule = $oModule->GetName();
$sModuleRootDir = $oModule->GetRootDir();
$bIsExtra = $this->oExtensionsMap->ModuleIsChosenAsPartOfAnExtension($sModule, iTopExtension::SOURCE_REMOTE);
- if (array_key_exists($sModule, $aAvailableModules))
+ if (array_key_exists($sModule, $aAvailableModules))
{
if (($aAvailableModules[$sModule]['version_db'] != '') || $bIsExtra && !$oModule->IsAutoSelect()) //Extra modules are always unless they are 'AutoSelect'
{
@@ -445,7 +447,7 @@ class RunTimeEnvironment
}
}
}
-
+
// Now process the 'AutoSelect' modules
do
{
@@ -514,7 +516,7 @@ class RunTimeEnvironment
}
$oFactory->LoadModule($oModule);
}
-
+
if ($oModule instanceof MFDeltaModule)
{
@@ -565,7 +567,7 @@ class RunTimeEnvironment
{
$this->log_info("Creating the structure in '".$oConfig->Get('db_name')."'.");
}
-
+
//MetaModel::CheckDefinitions();
if ($sMode == 'install')
{
@@ -597,7 +599,7 @@ class RunTimeEnvironment
MetaModel::DBCreate(array($this, 'LogQueryCallback'));
$this->log_ok("Database structure successfully updated.");
-
+
// Check (and update only if it seems needed) the hierarchical keys
if (MFCompiler::SkipRebuildHKeys()) {
$this->log_ok("Hierchical keys are NOT rebuilt due to the presence of the \"data/.setup-rebuild-hkeys-never\" file");
@@ -657,7 +659,7 @@ class RunTimeEnvironment
if ($aPredefinedObjects != null)
{
$this->log_info("$sClass::GetPredefinedObjects() returned " . count($aPredefinedObjects) . " elements.");
-
+
// Create/Delete/Update objects of this class,
// according to the given constant values
//
@@ -699,7 +701,7 @@ class RunTimeEnvironment
// Restore the previous access mode
$oConfig->Set('access_mode', $iPrevAccessMode);
}
-
+
public function RecordInstallation(Config $oConfig, $sDataModelVersion, $aSelectedModuleCodes, $aSelectedExtensionCodes, $sShortComment = null)
{
// Have it work fine even if the DB has been set in read-only mode for the users
@@ -708,7 +710,7 @@ class RunTimeEnvironment
//$oConfig->Set('access_mode', ACCESS_FULL);
if (CMDBSource::DBName() == '')
- {
+ {
// In case this has not yet been done
CMDBSource::InitFromConfig($oConfig);
}
@@ -718,7 +720,7 @@ class RunTimeEnvironment
$sShortComment = 'Done by the setup program';
}
$sMainComment = $sShortComment."\nBuilt on ".ITOP_BUILD_DATE;
-
+
// Record datamodel version
$aData = array(
'source_dir' => $oConfig->Get('source_dir'),
@@ -731,7 +733,7 @@ class RunTimeEnvironment
$oInstallRec->Set('parent_id', 0); // root module
$oInstallRec->Set('installed', $iInstallationTime);
$iMainItopRecord = $oInstallRec->DBInsertNoReload();
-
+
// Record main installation
$oInstallRec = new ModuleInstallation();
$oInstallRec->Set('name', ITOP_APPLICATION);
@@ -740,8 +742,8 @@ class RunTimeEnvironment
$oInstallRec->Set('parent_id', 0); // root module
$oInstallRec->Set('installed', $iInstallationTime);
$iMainItopRecord = $oInstallRec->DBInsertNoReload();
-
-
+
+
// Record installed modules and extensions
//
$aAvailableExtensions = array();
@@ -775,7 +777,7 @@ class RunTimeEnvironment
$aComments[] = "Depends on module: $sDependOn";
}
$sComment = implode("\n", $aComments);
-
+
$oInstallRec = new ModuleInstallation();
$oInstallRec->Set('name', $sName);
$oInstallRec->Set('version', $sVersion);
@@ -784,7 +786,7 @@ class RunTimeEnvironment
$oInstallRec->Set('installed', $iInstallationTime);
$oInstallRec->DBInsertNoReload();
}
-
+
if ($this->oExtensionsMap)
{
// Mark as chosen the selected extensions code passed to us
@@ -796,7 +798,7 @@ class RunTimeEnvironment
$this->oExtensionsMap->MarkAsChosen($oExtension->sCode);
}
}
-
+
foreach($this->oExtensionsMap->GetChoices() as $oExtension)
{
$oInstallRec = new ExtensionInstallation();
@@ -813,9 +815,9 @@ class RunTimeEnvironment
MetaModel::GetConfig()->Set('access_mode', $iPrevAccessMode);
// Database is created, installation has been tracked into it
- return true;
+ return true;
}
-
+
public function GetApplicationVersion(Config $oConfig)
{
$aResult = false;
@@ -832,7 +834,7 @@ class RunTimeEnvironment
$this->log_error('Exception '.$e->getMessage());
return false;
}
-
+
// Scan the list of installed modules to get the version of the 'ROOT' module which holds the main application version
foreach ($aSelectInstall as $aInstall)
{
@@ -844,7 +846,7 @@ class RunTimeEnvironment
// as being installed
$sModuleVersion = '0.0.0';
}
-
+
if ($aInstall['parent_id'] == 0)
{
if ($aInstall['name'] == DATAMODEL_MODULE)
@@ -870,7 +872,7 @@ class RunTimeEnvironment
$aResult['datamodel_version'] = $aResult['product_version'];
}
$this->log_info("GetApplicationVersion returns: product_name: ".$aResult['product_name'].', product_version: '.$aResult['product_version']);
- return $aResult;
+ return $aResult;
}
public static function MakeDirSafe($sDir)
@@ -886,8 +888,8 @@ class RunTimeEnvironment
}
/**
- * Wrappers for logging into the setup log files
- */
+ * Wrappers for logging into the setup log files
+ */
protected function log_error($sText)
{
SetupPage::log_error($sText);
@@ -923,7 +925,7 @@ class RunTimeEnvironment
fclose($hSetupQueriesFile);
}
}
-
+
public function GetCurrentDataModelVersion()
{
$oSearch = DBObjectSearch::FromOQL("SELECT ModuleInstallation WHERE name='".DATAMODEL_MODULE."'");
@@ -1116,7 +1118,7 @@ class RunTimeEnvironment
}
}
}
-
+
/**
* Load data from XML files for the selected modules (structural data and/or sample data)
* @param array[] $aAvailableModules All available modules and their definition
@@ -1126,13 +1128,13 @@ class RunTimeEnvironment
public function LoadData($aAvailableModules, $aSelectedModules, $bSampleData)
{
$oDataLoader = new XMLDataLoader();
-
+
CMDBObject::SetTrackInfo("Initialization");
$oMyChange = CMDBObject::GetCurrentChange();
-
+
SetupPage::log_info("starting data load session");
$oDataLoader->StartSession($oMyChange);
-
+
$aFiles = array();
$aPreviouslyLoadedFiles = array();
foreach($aAvailableModules as $sModuleId => $aModule)
@@ -1173,7 +1175,7 @@ class RunTimeEnvironment
}
}
}
-
+
// Simulate the load of the previously loaded files, in order to initialize
// the mapping between the identifiers in the XML and the actual identifiers
// in the current database
@@ -1185,12 +1187,12 @@ class RunTimeEnvironment
{
throw(new Exception("File $sFileName does not exist"));
}
-
+
$oDataLoader->LoadFile($sFileName, true);
$sResult = sprintf("loading of %s done.", basename($sFileName));
SetupPage::log_info($sResult);
}
-
+
foreach($aFiles as $sFileRelativePath)
{
$sFileName = APPROOT.$sFileRelativePath;
@@ -1199,16 +1201,16 @@ class RunTimeEnvironment
{
throw(new Exception("File $sFileName does not exist"));
}
-
+
$oDataLoader->LoadFile($sFileName);
$sResult = sprintf("loading of %s done.", basename($sFileName));
SetupPage::log_info($sResult);
}
-
+
$oDataLoader->EndSession();
SetupPage::log_info("ending data load session");
}
-
+
/**
* Merge two arrays of file names, adding the relative path to the files provided in the array to merge
* @param string[] $aSourceArray
@@ -1225,7 +1227,7 @@ class RunTimeEnvironment
}
return array_merge($aSourceArray, $aToMerge);
}
-
+
/**
* Check the MetaModel for some common pitfall (class name too long, classes requiring too many joins...)
* The check takes about 900 ms for 200 classes
@@ -1265,7 +1267,7 @@ class RunTimeEnvironment
$iCount++;
}
$fDuration = microtime(true) - $fStart;
-
+
return sprintf("Checked %d classes in %.1f ms. No error found.\n", $iCount, $fDuration*1000.0);
}
} // End of class
diff --git a/setup/unattended-install/InstallationFileService.php b/setup/unattended-install/InstallationFileService.php
new file mode 100644
index 000000000..103080e59
--- /dev/null
+++ b/setup/unattended-install/InstallationFileService.php
@@ -0,0 +1,252 @@
+sInstallationPath = $sInstallationPath;
+ $this->aSelectedModules = [];
+ $this->aUnSelectedModules = [];
+ $this->sTargetEnvironment = $sTargetEnvironment;
+ $this->aSelectedExtensions = $aSelectedExtensions;
+ $this->bInstallationOptionalChoicesChecked = $bInstallationOptionalChoicesChecked;
+ }
+
+ public function GetSelectedModules(): array {
+ return $this->aSelectedModules;
+ }
+
+ public function GetUnSelectedModules(): array {
+ return $this->aUnSelectedModules;
+ }
+
+ public function Init(): void {
+ clearstatcache();
+
+ $this->ProcessDefaultModules();
+ $this->ProcessInstallationChoices();
+ $this->ProcessAutoSelectModules();
+ }
+
+ public function ProcessInstallationChoices(): void {
+ $oXMLParameters = new XMLParameters($this->sInstallationPath);
+ $aSteps = $oXMLParameters->Get('steps', []);
+ if (! is_array($aSteps)) {
+ return;
+ }
+
+ foreach ($aSteps as $aStepInfo) {
+ $aOptions = $aStepInfo["options"] ?? null;
+ if (! is_null($aOptions) && is_array($aOptions)) {
+ foreach ($aOptions as $aChoiceInfo) {
+ $this->ProcessSelectedChoice($aChoiceInfo, $this->bInstallationOptionalChoicesChecked);
+ }
+ }
+ $aOptions = $aStepInfo["alternatives"] ?? null;
+ if (! is_null($aOptions) && is_array($aOptions)) {
+ foreach ($aOptions as $aChoiceInfo) {
+ $this->ProcessSelectedChoice($aChoiceInfo, false);
+ }
+ }
+ }
+
+ foreach ($this->aSelectedModules as $sModuleId => $sVal){
+ if (array_key_exists($sModuleId, $this->aUnSelectedModules)){
+ unset($this->aUnSelectedModules[$sModuleId]);
+ }
+ }
+ }
+
+ private function ProcessUnSelectedChoice($aChoiceInfo) {
+ if (!is_array($aChoiceInfo)) {
+ return;
+ }
+
+ $aCurrentModules = $aChoiceInfo["modules"] ?? [];
+ foreach ($aCurrentModules as $sModuleId){
+ $this->aUnSelectedModules[$sModuleId] = true;
+ }
+
+ $aAlternatives = $aChoiceInfo["alternatives"] ?? null;
+ if (!is_null($aAlternatives) && is_array($aAlternatives)) {
+ foreach ($aAlternatives as $aSubChoiceInfo) {
+ $this->ProcessUnSelectedChoice($aSubChoiceInfo);
+ }
+ }
+
+ if (array_key_exists('sub_options', $aChoiceInfo)) {
+ if (array_key_exists('options', $aChoiceInfo['sub_options'])) {
+ $aSubOptions = $aChoiceInfo['sub_options']['options'];
+ if (!is_null($aSubOptions) && is_array($aSubOptions)) {
+ foreach ($aSubOptions as $aSubChoiceInfo) {
+ $this->ProcessUnSelectedChoice($aSubChoiceInfo);
+ }
+ }
+ }
+ if (array_key_exists('alternatives', $aChoiceInfo['sub_options'])) {
+ $aSubAlternatives = $aChoiceInfo['sub_options']['alternatives'];
+ if (!is_null($aSubAlternatives) && is_array($aSubAlternatives)) {
+ foreach ($aSubAlternatives as $aSubChoiceInfo) {
+ $this->ProcessUnSelectedChoice($aSubChoiceInfo);
+ }
+ }
+ }
+ }
+ }
+
+ private function ProcessSelectedChoice($aChoiceInfo, bool $bAllChecked) {
+ if (!is_array($aChoiceInfo)) {
+ return;
+ }
+
+ $sDefault = $aChoiceInfo["default"] ?? "false";
+ $sMandatory = $aChoiceInfo["mandatory"] ?? "false";
+
+ $aCurrentModules = $aChoiceInfo["modules"] ?? [];
+ if (0 === count($this->aSelectedExtensions)){
+ $bSelected = $bAllChecked || $sDefault === "true" || $sMandatory === "true";
+ } else {
+ $sExtensionCode = $aChoiceInfo["extension_code"] ?? null;
+ $bSelected = $sMandatory === "true" ||
+ (null !== $sExtensionCode && in_array($sExtensionCode, $this->aSelectedExtensions));
+ }
+
+ foreach ($aCurrentModules as $sModuleId){
+ if ($bSelected) {
+ $this->aSelectedModules[$sModuleId] = true;
+ } else {
+ $this->aUnSelectedModules[$sModuleId] = true;
+ }
+ }
+
+ $aAlternatives = $aChoiceInfo["alternatives"] ?? null;
+ if (!is_null($aAlternatives) && is_array($aAlternatives)) {
+ foreach ($aAlternatives as $aSubChoiceInfo) {
+ if ($bSelected) {
+ $this->ProcessSelectedChoice($aSubChoiceInfo, $bAllChecked);
+ } else {
+ $this->ProcessUnSelectedChoice($aSubChoiceInfo);
+ }
+ }
+ }
+
+ if (array_key_exists('sub_options', $aChoiceInfo)) {
+ if (array_key_exists('options', $aChoiceInfo['sub_options'])) {
+ $aSubOptions = $aChoiceInfo['sub_options']['options'];
+ if (!is_null($aSubOptions) && is_array($aSubOptions)) {
+ foreach ($aSubOptions as $aSubChoiceInfo) {
+ if ($bSelected) {
+ $this->ProcessSelectedChoice($aSubChoiceInfo, $bAllChecked);
+ } else {
+ $this->ProcessUnSelectedChoice($aSubChoiceInfo);
+ }
+ }
+ }
+ }
+ if (array_key_exists('alternatives', $aChoiceInfo['sub_options'])) {
+ $aSubAlternatives = $aChoiceInfo['sub_options']['alternatives'];
+ if (!is_null($aSubAlternatives) && is_array($aSubAlternatives)) {
+ foreach ($aSubAlternatives as $aSubChoiceInfo) {
+ if ($bSelected) {
+ $this->ProcessSelectedChoice($aSubChoiceInfo, false);
+ } else {
+ $this->ProcessUnSelectedChoice($aSubChoiceInfo);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ private function GetExtraDirs() : array {
+ $aSearchDirs = [];
+
+ $aDirs = [
+ '/datamodels/1.x',
+ '/datamodels/2.x',
+ 'data/' . $this->sTargetEnvironment . '-modules',
+ 'extensions',
+ ];
+ foreach ($aDirs as $sRelativeDir){
+ $sDirPath = APPROOT.$sRelativeDir;
+ if (is_dir($sDirPath))
+ {
+ $aSearchDirs[] = $sDirPath;
+ }
+ }
+
+ return $aSearchDirs;
+ }
+
+ public function ProcessDefaultModules() : void {
+ $sProductionModuleDir = APPROOT.'data/' . $this->sTargetEnvironment . '-modules/';
+
+ $oProductionEnv = new RunTimeEnvironment();
+ $aAvailableModules = $oProductionEnv->AnalyzeInstallation(MetaModel::GetConfig(), $this->GetExtraDirs(), false, null);
+
+ $this->aAutoSelectModules = [];
+ foreach ($aAvailableModules as $sModuleId => $aModule) {
+ if (($sModuleId != ROOT_MODULE)) {
+ if (isset($aModule['auto_select'])) {
+ $this->aAutoSelectModules[$sModuleId] = $aModule;
+ continue;
+ }
+
+ if (($aModule['category'] == 'authentication') || (!$aModule['visible'])) {
+ $this->aSelectedModules[$sModuleId] = true;
+ continue;
+ }
+
+ $bIsExtra = (array_key_exists('root_dir', $aModule) && (strpos($aModule['root_dir'],
+ $sProductionModuleDir) !== false)); // Some modules (root, datamodel) have no 'root_dir'
+ if ($bIsExtra) {
+ // Modules in data/production-modules/ are considered as mandatory and always installed
+ $this->aSelectedModules[$sModuleId] = true;
+ }
+ }
+ }
+ }
+
+ public function ProcessAutoSelectModules() : void {
+ foreach($this->aAutoSelectModules as $sModuleId => $aModule)
+ {
+ try {
+ $bSelected = false;
+ SetupInfo::SetSelectedModules($this->aSelectedModules);
+ eval('$bSelected = ('.$aModule['auto_select'].');');
+ if ($bSelected)
+ {
+ // Modules in data/production-modules/ are considered as mandatory and always installed
+ $this->aSelectedModules[$sModuleId] = true;
+ }
+ }
+ catch (Exception $e) {
+ }
+ }
+ }
+}
diff --git a/setup/unattended-install/README.md b/setup/unattended-install/README.md
index d4ca4249b..bb1a19ebc 100644
--- a/setup/unattended-install/README.md
+++ b/setup/unattended-install/README.md
@@ -3,3 +3,23 @@
This script allows to install and update iTop via CLI.
For more information, see the official Wiki : [Automated installation [iTop Documentation]](https://www.itophub.io/wiki/page?id=latest:advancedtopics:automatic_install)
+
+
+#install-itop.sh
+You can install your iTop by only using config-itop.php settings and run either
+
+- a non-ITIL iTop fresh installation (use itil-fresh-install.xml to have ITIL modules instead)
+```
+./install-itop.sh ./xml_setup/fresh-install.xml
+```
+
+- a non-ITIL iTop upgrade (use itil-upgrade.xml to have ITIL modules instead)
+```
+./install-itop.sh ./xml_setup/upgrade.xml
+```
+
+- a specific iTop installation by providing both xml setup file
+in below example file provided is the one generated by iTop during last setup.
+```
+./install-itop.sh ../../log/install-2024-04-03.xml
+```
diff --git a/setup/unattended-install/install-itop.sh b/setup/unattended-install/install-itop.sh
new file mode 100644
index 000000000..dc165c57f
--- /dev/null
+++ b/setup/unattended-install/install-itop.sh
@@ -0,0 +1,50 @@
+#! /bin/bash
+
+CLI_NAME=$(basename $0)
+DIR=$(dirname $0)
+ITOP_DIR="$DIR/../.."
+
+HELP="Syntax: $CLI_NAME XML_SETUP [INSTALLATION_XML]"
+
+function HELP {
+ echo $HELP
+ exit 1
+}
+
+if [ $# -lt 1 ]
+then
+ echo "Missing parameters passed."
+ HELP
+fi
+
+if [ $# -gt 2 ]
+then
+ echo "Too much parameters passed ($#) : $*."
+ HELP
+fi
+
+XML_SETUP=$1
+if [ ! -f $XML_SETUP ]
+then
+ echo "XML_SETUP file ($XML_SETUP) not found."
+ HELP
+fi
+
+if [ $# -eq 2 ]
+then
+ INSTALLATION_XML=$2
+ if [ ! -f $INSTALLATION_XML ]
+ then
+ echo "INSTALLATION_XML file ($INSTALLATION_XML) not found."
+ HELP
+ fi
+else
+ INSTALLATION_XML="$ITOP_DIR/datamodels/2.x/installation.xml"
+fi
+
+echo "$CLI_NAME: Using XML_SETUP ($XML_SETUP) and INSTALLATION_XML ($INSTALLATION_XML) files during unattended itop installation."
+
+rm -rf $ITOP_DIR/data/.maintenance;
+echo php $DIR/unattended-install.php --use_itop_config --installation_xml="$INSTALLATION_XML" --param-file="$XML_SETUP"
+
+php $DIR/unattended-install.php --use_itop_config --installation_xml="$INSTALLATION_XML" --param-file="$XML_SETUP"
diff --git a/setup/unattended-install/unattended-install.php b/setup/unattended-install/unattended-install.php
index 09af751ec..10dc03fc0 100644
--- a/setup/unattended-install/unattended-install.php
+++ b/setup/unattended-install/unattended-install.php
@@ -1,17 +1,29 @@
[--installation_xml=] [--use_itop_config]
+
+Options:
+ --param-file= Path to the file (XML) to use for the unattended installation. That file (generated by the setup into log directory) must contain the following sections:
+ - target_env: the target environment (production, test, dev)
+ - database: the database settings (server, user, pwd, name, prefix)
+ - selected_modules: the list of modules to install
+ --response_file DEPRECATED: use `--param-file` instead
+ --installation_xml= Use an installation.xml file to compute the modules to install depending on the selected extensions listed in the param file
+ --use_itop_config Use the iTop configuration file to get the database settings, otherwise use the database settings from the parameters file
+
+Advanced options:
+ --check-consistency=1 Check the data model consistency after the installation (default: 0)
+ --clean=1 In case of a first installation, cleanup the environment before proceeding: delete the configuration file, the cache directory, the target directory, the database (default: 0)
+ --install=0 Set to 0 to perform a dry-run (default: 1)
+EOF;
+ exit(-1);
+}
/////////////////////////////////////////////////
if (! utils::IsModeCLI())
{
@@ -19,17 +31,22 @@ if (! utils::IsModeCLI())
exit(-1);
}
-$sParamFile = utils::ReadParam('response_file', 'null', true /* CLI allowed */, 'raw_data');
-if ($sParamFile === 'null') {
- echo "No `--response_file` param specified, using default value !\n";
- $sParamFile = 'default-params.xml';
+if (in_array('--help', $argv)) {
+ PrintUsageAndExit();
}
-$bCheckConsistency = (utils::ReadParam('check_consistency', '0', true /* CLI allowed */) == '1');
+
+$sParamFile = utils::ReadParam('param-file', null, true /* CLI allowed */, 'raw_data') ?? utils::ReadParam('response_file', null, true /* CLI allowed */, 'raw_data');
+if (is_null($sParamFile)) {
+ echo "Missing mandatory argument `--param-file`.\n";
+ PrintUsageAndExit();
+}
+$bCheckConsistency = (utils::ReadParam('check-consistency', '0', true /* CLI allowed */) == '1');
if (false === file_exists($sParamFile)) {
- echo "Param file `$sParamFile` doesn't exist ! Exiting...";
+ echo "Param file `$sParamFile` doesn't exist! Exiting...\n";
exit(-1);
}
+
$oParams = new XMLParameters($sParamFile);
$sMode = $oParams->Get('mode');
@@ -40,8 +57,73 @@ if ($sTargetEnvironment == '')
$sTargetEnvironment = 'production';
}
-//unattended run based on db settings coming from response_file (XML file)
-$aDBXmlSettings = $oParams->Get('database', array());
+$sXmlSetupBaseName = basename($sParamFile);
+$sInstallationXmlPath = utils::ReadParam('installation_xml', null, true /* CLI allowed */, 'raw_data');
+if (! is_null($sInstallationXmlPath) && is_file($sInstallationXmlPath)) {
+ $sInstallationBaseName = basename($sInstallationXmlPath);
+
+ $aSelectedExtensionsFromXmlSetup = $oParams->Get('selected_extensions', []);
+ if (count($aSelectedExtensionsFromXmlSetup) !== 0) {
+ $sMsg = "Modules to install computed based on $sInstallationBaseName file and installation choices (listed in section `selected_extensions` of $sXmlSetupBaseName file)";
+ echo "$sMsg:\n".implode(',', $aSelectedExtensionsFromXmlSetup)."\n\n";
+ SetupLog::Info($sMsg, null, $aSelectedExtensionsFromXmlSetup);
+ } else {
+ $sMsg = "Modules to install computed based on default installation choices inside $sInstallationBaseName (no choice specified in section `selected_extensions` of $sXmlSetupBaseName file).";
+ echo "$sMsg\n\n";
+ SetupLog::Info($sMsg);
+ }
+
+ $oInstallationFileService = new InstallationFileService($sInstallationXmlPath, $sTargetEnvironment, $aSelectedExtensionsFromXmlSetup);
+ $oInstallationFileService->Init();
+ $aComputedModules = $oInstallationFileService->GetSelectedModules();
+ $aSelectedModules = array_keys($aComputedModules);
+ $oParams->Set('selected_modules', $aSelectedModules);
+
+ $sMsg = "Modules to install computed";
+} else {
+ $aSelectedModules = $oParams->Get('selected_modules', []);
+ $sMsg = "Modules to install listed in $sXmlSetupBaseName (selected_modules section)";
+}
+
+sort($aSelectedModules);
+echo "$sMsg:\n".implode(',', $aSelectedModules)."\n\n";
+SetupLog::Info($sMsg, null, $aSelectedModules);
+
+// Configuration file
+$sConfigFile = APPCONF.$sTargetEnvironment.'/'.ITOP_CONFIG_FILE;
+$bUseItopConfig = in_array('--use_itop_config', $argv);
+if ($bUseItopConfig && file_exists($sConfigFile)){
+ //unattended run based on db settings coming from itop configuration
+ copy($sConfigFile, "$sConfigFile.backup");
+
+ $oConfig = new Config($sConfigFile);
+ $aDBXmlSettings = $oParams->Get('database', array());
+ $aDBXmlSettings ['server'] = $oConfig->Get('db_host');
+ $aDBXmlSettings ['user'] = $oConfig->Get('db_user');
+ $aDBXmlSettings ['pwd'] = $oConfig->Get('db_pwd');
+ $aDBXmlSettings ['name'] = $oConfig->Get('db_name');
+ $aDBXmlSettings ['prefix'] = $oConfig->Get('db_subname');
+ $aDBXmlSettings ['db_tls_enabled'] = $oConfig->Get('db_tls.enabled');
+ //cannot be null or infinite loop triggered!
+ $aDBXmlSettings ['db_tls_ca'] = $oConfig->Get('db_tls.ca') ?? "";
+ $oParams->Set('database', $aDBXmlSettings);
+
+ $aFields = [
+ 'url' => 'app_root_url',
+ 'source_dir' => 'source_dir',
+ 'graphviz_path' => 'graphviz_path',
+ ];
+ foreach($aFields as $sSetupField => $sConfField){
+ $oParams->Set($sSetupField, $oConfig->Get($sConfField));
+ }
+
+ $oParams->Set('mysql_bindir', $oConfig->GetModuleSetting('itop-backup', 'mysql_bindir', ""));
+ $oParams->Set('language', $oConfig->GetDefaultLanguage());
+} else {
+ //unattended run based on db settings coming from response_file (XML file)
+ $aDBXmlSettings = $oParams->Get('database', array());
+}
+
$sDBServer = $aDBXmlSettings['server'];
$sDBUser = $aDBXmlSettings['user'];
$sDBPwd = $aDBXmlSettings['pwd'];
@@ -57,8 +139,6 @@ if ($sMode == 'install')
{
echo "Cleanup mode detected.\n";
- // Configuration file
- $sConfigFile = APPCONF.$sTargetEnvironment.'/'.ITOP_CONFIG_FILE;
if (file_exists($sConfigFile))
{
echo "Trying to delete the configuration file: '$sConfigFile'.\n";
@@ -200,7 +280,7 @@ if ($bHasErrors)
$sLogMsg = "Encountered stopper issues. Aborting...";
echo "$sLogMsg\n";
SetupLog::Error($sLogMsg);
- die;
+ exit(-1);
}
$bFoundIssues = false;
@@ -291,11 +371,18 @@ if (!$bFoundIssues && $bCheckConsistency)
}
}
-if (!$bFoundIssues)
+if (! $bFoundIssues)
{
// last line: used to check the install
// the only way to track issues in case of Fatal error or even parsing error!
$sLogMsg = "installed!";
+
+ if ($bUseItopConfig && is_file("$sConfigFile.backup"))
+ {
+ echo "\nuse config file provided by backup in $sConfigFile.";
+ copy("$sConfigFile.backup", $sConfigFile);
+ }
+
SetupLog::Info($sLogMsg);
echo "\n$sLogMsg";
exit(0);
@@ -303,5 +390,5 @@ if (!$bFoundIssues)
$sLogMsg = "installation failed!";
SetupLog::Error($sLogMsg);
-echo "\n$sLogMsg";
+echo "\n$sLogMsg\n";
exit(-1);
diff --git a/setup/unattended-install/xml_setup/fresh-install.xml b/setup/unattended-install/xml_setup/fresh-install.xml
new file mode 100644
index 000000000..db1311cf5
--- /dev/null
+++ b/setup/unattended-install/xml_setup/fresh-install.xml
@@ -0,0 +1,41 @@
+
+
+ install
+
+
+ datamodels/2.x/
+ 2.7.0
+ /var/www/html/iTop/conf/production/config-itop.php
+ extensions
+ production
+
+
+
+
+
+
+
+
+
+
+
+ /usr/bin/dot
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
diff --git a/setup/unattended-install/xml_setup/itil-fresh-install.xml b/setup/unattended-install/xml_setup/itil-fresh-install.xml
new file mode 100644
index 000000000..e1b1e594f
--- /dev/null
+++ b/setup/unattended-install/xml_setup/itil-fresh-install.xml
@@ -0,0 +1,53 @@
+
+
+ install
+
+
+ datamodels/2.x/
+ 2.7.0
+ /var/www/html/iTop/conf/production/config-itop.php
+ extensions
+ production
+
+
+
+
+
+
+
+
+
+
+
+ /usr/bin/dot
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+ - itop-config-mgmt-datacenter
+ - itop-config-mgmt-end-user
+ - itop-config-mgmt-storage
+ - itop-config-mgmt-virtualization
+ - itop-service-mgmt-enterprise
+ - itop-ticket-mgmt-itil
+ - itop-ticket-mgmt-itil-user-request
+ - itop-ticket-mgmt-itil-incident
+ - itop-ticket-mgmt-itil-enhanced-portal
+ - itop-change-mgmt-itil
+ - itop-config-mgmt-core
+ - itop-kown-error-mgmt
+
+
diff --git a/setup/unattended-install/xml_setup/itil-upgrade.xml b/setup/unattended-install/xml_setup/itil-upgrade.xml
new file mode 100644
index 000000000..eb0a63208
--- /dev/null
+++ b/setup/unattended-install/xml_setup/itil-upgrade.xml
@@ -0,0 +1,53 @@
+
+
+ upgrade
+
+
+ datamodels/2.x/
+ 2.7.0
+ /var/www/html/iTop/conf/production/config-itop.php
+ extensions
+ production
+
+
+
+
+
+
+
+
+
+
+
+ /usr/bin/dot
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+ - itop-config-mgmt-datacenter
+ - itop-config-mgmt-end-user
+ - itop-config-mgmt-storage
+ - itop-config-mgmt-virtualization
+ - itop-service-mgmt-enterprise
+ - itop-ticket-mgmt-itil
+ - itop-ticket-mgmt-itil-user-request
+ - itop-ticket-mgmt-itil-incident
+ - itop-ticket-mgmt-itil-enhanced-portal
+ - itop-change-mgmt-itil
+ - itop-config-mgmt-core
+ - itop-kown-error-mgmt
+
+
diff --git a/setup/unattended-install/xml_setup/upgrade.xml b/setup/unattended-install/xml_setup/upgrade.xml
new file mode 100644
index 000000000..ff0d153f1
--- /dev/null
+++ b/setup/unattended-install/xml_setup/upgrade.xml
@@ -0,0 +1,41 @@
+
+
+ upgrade
+
+
+ datamodels/2.x/
+ 2.7.0
+ /var/www/html/iTop/conf/production/config-itop.php
+ extensions
+ production
+
+
+
+
+
+
+
+
+
+
+
+ /usr/bin/dot
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/ci_description.ini b/tests/ci_description.ini
index b9f1cdd4c..e030bccc5 100644
--- a/tests/ci_description.ini
+++ b/tests/ci_description.ini
@@ -5,7 +5,7 @@ php_version=7.2-apache
db_version=5.7
[itop]
-itop_setup=tests/setup_params/default-params.xml
+;itop_setup=tests/setup_params/default-params.xml
itop_backup=tests/backups/backup-itop.tar.gz
[phpunit]
diff --git a/tests/php-unit-tests/unitary-tests/setup/unattended-install/InstallationFileServiceTest.php b/tests/php-unit-tests/unitary-tests/setup/unattended-install/InstallationFileServiceTest.php
new file mode 100644
index 000000000..768395ef0
--- /dev/null
+++ b/tests/php-unit-tests/unitary-tests/setup/unattended-install/InstallationFileServiceTest.php
@@ -0,0 +1,315 @@
+sFolderToCleanup = null;
+ \ModuleDiscovery::ResetCache();
+ }
+
+ protected function tearDown(): void {
+ parent::tearDown();
+
+ $sModuleId = "itop-problem-mgmt";
+ $this->RecurseMoveDir(APPROOT."data/production-modules/$sModuleId", APPROOT . "datamodels/2.x/$sModuleId");
+ }
+
+ public function GetDefaultModulesProvider() {
+ return [
+ 'all checked' => [ true ],
+ 'only defaut + mandatory' => [ false ],
+ ];
+ }
+
+ /**
+ * @dataProvider GetDefaultModulesProvider
+ */
+ public function testProcessInstallationChoices($bInstallationOptionalChoicesChecked=false) {
+ $sPath = realpath(dirname(__FILE__, 6)."/datamodels/2.x/installation.xml");
+ $this->assertTrue(is_file($sPath));
+ $oInstallationFileService = new \InstallationFileService($sPath, 'production', [], $bInstallationOptionalChoicesChecked);
+ $oInstallationFileService->ProcessInstallationChoices();
+ $aExpectedModules = [
+ "itop-config-mgmt",
+ "itop-attachments",
+ "itop-profiles-itil",
+ "itop-welcome-itil",
+ "itop-tickets",
+ "itop-files-information",
+ "combodo-db-tools",
+ "itop-core-update",
+ "itop-hub-connector",
+ "itop-oauth-client",
+ "itop-datacenter-mgmt",
+ "itop-endusers-devices",
+ "itop-storage-mgmt",
+ "itop-virtualization-mgmt",
+ "itop-service-mgmt",
+ "itop-request-mgmt",
+ "itop-portal",
+ "itop-portal-base",
+ "itop-change-mgmt",
+ ];
+
+ $aExpectedUnselectedModules = [
+ 'itop-change-mgmt-itil',
+ 'itop-incident-mgmt-itil',
+ 'itop-request-mgmt-itil',
+ 'itop-service-mgmt-provider',
+ ];
+
+ if ($bInstallationOptionalChoicesChecked){
+ $aExpectedModules []= "itop-problem-mgmt";
+ $aExpectedModules []= "itop-knownerror-mgmt";
+ } else {
+ $aExpectedUnselectedModules []= "itop-problem-mgmt";
+ $aExpectedUnselectedModules []= "itop-knownerror-mgmt";
+ }
+
+ sort($aExpectedModules);
+ $aModules = array_keys($oInstallationFileService->GetSelectedModules());
+ sort($aModules);
+
+ $this->assertEquals($aExpectedModules, $aModules);
+
+ $aUnselectedModules = array_keys($oInstallationFileService->GetUnSelectedModules());
+ sort($aExpectedUnselectedModules);
+ sort($aUnselectedModules);
+ $this->assertEquals($aExpectedUnselectedModules, $aUnselectedModules);
+ }
+
+ /**
+ * @dataProvider GetDefaultModulesProvider
+ */
+ public function testGetAllSelectedModules($bInstallationOptionalChoicesChecked=false) {
+ $sPath = realpath(dirname(__FILE__, 6)."/datamodels/2.x/installation.xml");
+ $oInstallationFileService = new \InstallationFileService($sPath, 'production', [], $bInstallationOptionalChoicesChecked);
+ $oInstallationFileService->Init();
+
+ $aSelectedModules = $oInstallationFileService->GetSelectedModules();
+ $aExpectedInstallationModules = [
+ "itop-config-mgmt",
+ "itop-attachments",
+ "itop-profiles-itil",
+ "itop-welcome-itil",
+ "itop-tickets",
+ "itop-files-information",
+ "combodo-db-tools",
+ "itop-core-update",
+ "itop-hub-connector",
+ "itop-oauth-client",
+ "itop-datacenter-mgmt",
+ "itop-endusers-devices",
+ "itop-storage-mgmt",
+ "itop-virtualization-mgmt",
+ "itop-service-mgmt",
+ "itop-request-mgmt",
+ "itop-portal",
+ "itop-portal-base",
+ "itop-change-mgmt",
+ ];
+ if ($bInstallationOptionalChoicesChecked){
+ $aExpectedInstallationModules []= "itop-problem-mgmt";
+ $aExpectedInstallationModules []= "itop-knownerror-mgmt";
+ }
+
+ $aExpectedAuthenticationModules = [
+ 'authent-cas',
+ 'authent-external',
+ 'authent-ldap',
+ 'authent-local',
+ ];
+
+ $aUnvisibleModules = [
+ 'itop-backup',
+ 'itop-config',
+ 'itop-sla-computation',
+ ];
+
+ $aAutoSelectedModules = [
+ 'itop-bridge-virtualization-storage',
+ ];
+
+ $this->checkModuleList("installation.xml choices", $aExpectedInstallationModules, $aSelectedModules);
+ $this->checkModuleList("authentication category", $aExpectedAuthenticationModules, $aSelectedModules);
+ $this->checkModuleList("unvisible", $aUnvisibleModules, $aSelectedModules);
+ $this->checkModuleList("auto-select", $aAutoSelectedModules, $aSelectedModules);
+ $this->assertEquals([], $aSelectedModules, "there should be no more modules remaining apart from below lists");
+ }
+
+ private function GetSelectedItilExtensions(bool $coreExtensionIncluded, bool $bKnownMgtIncluded) : array {
+ $aExtensions = [
+ 'itop-config-mgmt-datacenter',
+ 'itop-config-mgmt-end-user',
+ 'itop-config-mgmt-storage',
+ 'itop-config-mgmt-virtualization',
+ 'itop-service-mgmt-enterprise',
+ 'itop-ticket-mgmt-itil',
+ 'itop-ticket-mgmt-itil-user-request',
+ 'itop-ticket-mgmt-itil-incident',
+ 'itop-ticket-mgmt-itil-enhanced-portal',
+ 'itop-change-mgmt-itil',
+ ];
+
+ if ($coreExtensionIncluded){
+ $aExtensions[]= 'itop-config-mgmt-core';
+ }
+
+ if ($bKnownMgtIncluded){
+ $aExtensions[]= 'itop-kown-error-mgmt';
+ }
+
+ return $aExtensions;
+
+ }
+
+ public function ItilExtensionProvider() {
+ return [
+ 'all itil extensions + INCLUDING known-error-mgt' => [
+ 'aSelectedExtensions' => $this->GetSelectedItilExtensions(true, true),
+ 'bKnownMgtSelected' => true,
+ ],
+ 'all itil extensions WITHOUT known-error-mgt' => [
+ 'aSelectedExtensions' => $this->GetSelectedItilExtensions(true, false),
+ 'bKnownMgtSelected' => false,
+ ],
+ 'all itil extensions WITHOUT core mandatory ones + INCLUDING known-error-mgt' => [
+ 'aSelectedExtensions' => $this->GetSelectedItilExtensions(false, true),
+ 'bKnownMgtSelected' => true,
+ ],
+ 'all itil extensions WITHOUT core mandatory ones and WITHOUT known-error-mgt' => [
+ 'aSelectedExtensions' => $this->GetSelectedItilExtensions(false, false),
+ 'bKnownMgtSelected' => false,
+ ],
+ ];
+ }
+
+ /**
+ * @dataProvider ItilExtensionProvider
+ */
+ public function testGetAllSelectedModules_withItilExtensions(array $aSelectedExtensions, bool $bKnownMgtSelected) {
+ $sPath = realpath(dirname(__FILE__, 6)."/datamodels/2.x/installation.xml");
+ $oInstallationFileService = new \InstallationFileService($sPath, 'production', $aSelectedExtensions);
+ $oInstallationFileService->Init();
+
+ $aSelectedModules = $oInstallationFileService->GetSelectedModules();
+ $aExpectedInstallationModules = [
+ "itop-config-mgmt",
+ "itop-attachments",
+ "itop-profiles-itil",
+ "itop-welcome-itil",
+ "itop-tickets",
+ "itop-files-information",
+ "combodo-db-tools",
+ "itop-core-update",
+ "itop-hub-connector",
+ "itop-oauth-client",
+ "itop-datacenter-mgmt",
+ "itop-endusers-devices",
+ "itop-storage-mgmt",
+ "itop-virtualization-mgmt",
+ "itop-service-mgmt",
+ "itop-request-mgmt-itil",
+ "itop-incident-mgmt-itil",
+ "itop-portal",
+ "itop-portal-base",
+ "itop-change-mgmt-itil",
+ "itop-full-itil",
+ ];
+ if ($bKnownMgtSelected){
+ $aExpectedInstallationModules []= "itop-knownerror-mgmt";
+ }
+
+ $aExpectedAuthenticationModules = [
+ 'authent-cas',
+ 'authent-external',
+ 'authent-ldap',
+ 'authent-local',
+ ];
+
+ $aUnvisibleModules = [
+ 'itop-backup',
+ 'itop-config',
+ 'itop-sla-computation',
+ ];
+
+ $aAutoSelectedModules = [
+ 'itop-bridge-virtualization-storage',
+ ];
+
+ $this->checkModuleList("installation.xml choices", $aExpectedInstallationModules, $aSelectedModules);
+ $this->checkModuleList("authentication category", $aExpectedAuthenticationModules, $aSelectedModules);
+ $this->checkModuleList("unvisible", $aUnvisibleModules, $aSelectedModules);
+ $this->checkModuleList("auto-select", $aAutoSelectedModules, $aSelectedModules);
+ $this->assertEquals([], $aSelectedModules, "there should be no more modules remaining apart from below lists");
+ }
+
+ private function checkModuleList(string $sModuleCategory, array $aExpectedModuleList, array &$aSelectedModules) {
+ $aMissingModules = [];
+
+ foreach ($aExpectedModuleList as $sModuleId){
+ if (! array_key_exists($sModuleId, $aSelectedModules)){
+ $aMissingModules[]=$sModuleId;
+ } else {
+ unset($aSelectedModules[$sModuleId]);
+ }
+ }
+
+ $this->assertEquals([], $aMissingModules, "$sModuleCategory modules are missing");
+
+ }
+
+ public function ProductionModulesProvider() {
+ return [
+ 'module autoload as located in production-modules' => [ true ],
+ 'module not loaded' => [ false ],
+ ];
+ }
+
+ /**
+ * @dataProvider ProductionModulesProvider
+ */
+ public function testGetAllSelectedModules_ProductionModules(bool $bModuleInProductionModulesFolder) {
+ $sModuleId = "itop-problem-mgmt";
+ if ($bModuleInProductionModulesFolder){
+ if (! is_dir(APPROOT."data/production-modules")){
+ @mkdir(APPROOT."data/production-modules");
+ }
+
+ $this->RecurseMoveDir(APPROOT . "datamodels/2.x/$sModuleId", APPROOT."data/production-modules/$sModuleId");
+ }
+
+ $sPath = realpath(dirname(__FILE__, 6)."/datamodels/2.x/installation.xml");
+ $oInstallationFileService = new \InstallationFileService($sPath, 'production', [], false);
+ $oInstallationFileService->Init();
+
+ $aSelectedModules = $oInstallationFileService->GetSelectedModules();
+ $this->assertEquals($bModuleInProductionModulesFolder, array_key_exists($sModuleId, $aSelectedModules));
+ }
+
+ private function RecurseMoveDir($sFromDir, $sToDir) {
+ if (! is_dir($sFromDir)){
+ return;
+ }
+
+ if (! is_dir($sToDir)){
+ @mkdir($sToDir);
+ }
+
+ foreach (glob("$sFromDir/*") as $sPath){
+ $sToPath = $sToDir.'/'.basename($sPath);
+ if (is_file($sPath)){
+ @rename($sPath, $sToPath);
+ } else {
+ $this->RecurseMoveDir($sPath, $sToPath);
+ }
+ }
+
+ @rmdir($sFromDir);
+ }
+}
diff --git a/tests/php-unit-tests/unitary-tests/setup/unattended-install/UnattendedInstallTest.php b/tests/php-unit-tests/unitary-tests/setup/unattended-install/UnattendedInstallTest.php
index ee4bdd1d3..97fa971ee 100644
--- a/tests/php-unit-tests/unitary-tests/setup/unattended-install/UnattendedInstallTest.php
+++ b/tests/php-unit-tests/unitary-tests/setup/unattended-install/UnattendedInstallTest.php
@@ -63,9 +63,12 @@ class UnattendedInstallTest extends ItopDataTestCase
}
public function testCallUnattendedInstallFromCLI() {
- $cliPath = realpath(APPROOT."/setup/unattended-install/unattended-install.php");
- $res = exec("php ".$cliPath);
+ $sCliPath = realpath(APPROOT."/setup/unattended-install/unattended-install.php");
+ exec(sprintf("%s %s", PHP_BINARY . " ".$sCliPath), $aOutput, $iCode);
- $this->assertEquals("Param file `default-params.xml` doesn't exist ! Exiting...", $res);
+ $sOutput = implode('\n', $aOutput);
+ var_dump($sOutput);
+ $this->assertStringContainsString("Missing mandatory argument `--param-file`", $sOutput);
+ $this->assertEquals(255, $iCode);
}
}
diff --git a/tests/setup_params/default-params.xml b/tests/setup_params/default-params.xml
index 071916b9c..dcaf30986 100644
--- a/tests/setup_params/default-params.xml
+++ b/tests/setup_params/default-params.xml
@@ -29,40 +29,8 @@
EN US
- - authent-cas
- - authent-external
- - authent-local
- - itop-backup
- - itop-config
- - itop-profiles-itil
- - itop-sla-computation
- - itop-tickets
- - itop-welcome-itil
- - itop-config-mgmt
- - itop-attachments
- - itop-datacenter-mgmt
- - itop-endusers-devices
- - itop-storage-mgmt
- - itop-virtualization-mgmt
- - itop-bridge-virtualization-storage
- - itop-service-mgmt
- - itop-request-mgmt
- - itop-portal
- - itop-portal-base
- - itop-change-mgmt
- - itop-knownerror-mgmt
- - itop-config-mgmt-core
- - itop-config-mgmt-datacenter
- - itop-config-mgmt-end-user
- - itop-config-mgmt-storage
- - itop-config-mgmt-virtualization
- - itop-service-mgmt-enterprise
- - itop-ticket-mgmt-simple-ticket
- - itop-ticket-mgmt-simple-ticket-enhanced-portal
- - itop-change-mgmt-simple
- - itop-kown-error-mgmt
1