Files
iTop/setup/unattended-install/InstallationFileService.php
odain-cbd 85c576a986 N°7407 - N°7306 - Ease iTop installation via unattended CLI by using installation.xml choices (#641)
* N°7306 - Use iTop configuration settings to run unattended installation (instead of XML file settings)

* 7306 - fix infinite loop with db_tls.ca null

* 7306 - complete fields to use from itop configuration instead of XML setup

* fix using default language from conf

* 6365 - temp work

* 6365 - add option to select modules from installation.xml

* 6365-select modules option in unattended install

* 6365 - pass env to service + debug failed test

* 6365 - debug ci again + separate process annotation

* 6365 - fix test + cleanup

* 6365 - ci using use_installation_xml mode

* 6365 - ci using use_installation_xml mode

* 6365 - pass selected_modules to unattended

* N°6365 - Compute selected modules based on selected extensions coming from XML setup

* switch constr parameters and fix call from unattended cli

* 6365 - use use_installation_xml for unattended install only when no selected modules already provided

* test ci XML setup including selected extensions but no modules

* test ci installing iTop without selected modules/extenesions: guess via installation.xml

* same but without even providing XML setup - comment it in ci_description.ini

* 7306 - cleanup requires

* use infra master

* N°6365 - make current unattended CLI work with any iTop version (CLIPage compatibility)

* N°6365 - log which modules will be installed during setup

* N°6365 - unattended documentation + bash helper

* 6365- fix warning due to copies index access

* 6365 - enhance traces feedback to understant which and how modules are computes

* 6365 - enhance bash CLI + doc

* 6365 - fix require clipage compatibility

* 6365 - add return for better cli ouput

* 6365 - enhance ouput messages

* Document the usage and harmonize argument names (still not perfect)

* 6365 - fix use of new param param-file

* 6365 - fix test + vardump cleanup

* N°6365 - use underscore for unattended install options as advices in the PR

* 6365 -enhance test by using PHP_BINARY

---------

Co-authored-by: Romain Quetiez <romain.quetiez@combodo.com>
2024-04-09 10:00:58 +02:00

253 lines
7.8 KiB
PHP

<?php
require_once(APPROOT.'/application/utils.inc.php');
require_once(APPROOT.'/setup/setuppage.class.inc.php');
require_once(APPROOT.'/setup/wizardcontroller.class.inc.php');
require_once(APPROOT.'/setup/wizardsteps.class.inc.php');
if (version_compare(ITOP_DESIGN_LATEST_VERSION, '2.7', '<=')) {
require_once(APPROOT.'/core/config.class.inc.php');
require_once(APPROOT.'/core/log.class.inc.php');
require_once(APPROOT.'/core/kpi.class.inc.php');
require_once(APPROOT.'/core/cmdbsource.class.inc.php');
require_once(APPROOT.'/application/clipage.class.inc.php');
}
class InstallationFileService {
private $sTargetEnvironment;
private $sInstallationPath;
private $aSelectedModules;
private $aSelectedExtensions;
private $aUnSelectedModules;
private $aAutoSelectModules;
private $bInstallationOptionalChoicesChecked;
/**
* @param string $sInstallationPath
* @param string $sTargetEnvironment
* @param array $aSelectedExtensions
* @param bool $bInstallationOptionalChoicesChecked : this option is used only when no extensions are selected (ie empty $aSelectedExtensions)
*/
public function __construct(string $sInstallationPath, string $sTargetEnvironment='production', array $aSelectedExtensions = [], bool $bInstallationOptionalChoicesChecked=true) {
$this->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) {
}
}
}
}