N°9144 - fix both UI setup wizard and CLI unattended + replace production by ITOP_DEFAULT_ENV

This commit is contained in:
odain
2026-04-03 16:17:44 +02:00
parent d36f68e3b0
commit 82a20c54a9
25 changed files with 58 additions and 78 deletions

View File

@@ -961,7 +961,7 @@ class utils
return self::$oConfig;
}
$sProductionEnvConfigPath = self::GetConfigFilePath('production');
$sProductionEnvConfigPath = self::GetConfigFilePath(ITOP_DEFAULT_ENV);
if (file_exists($sProductionEnvConfigPath)) {
$oProductionEnvDiskConfig = new Config($sProductionEnvConfigPath);
self::SetConfig($oProductionEnvDiskConfig);

View File

@@ -130,7 +130,7 @@ abstract class MetaModel
/** @var array */
private static $m_aClassToFile = [];
/** @var string */
protected static $m_sEnvironment = 'production';
protected static $m_sEnvironment = ITOP_DEFAULT_ENV;
/**
* Objects currently created/updated.
@@ -5748,7 +5748,7 @@ abstract class MetaModel
* @throws \DictExceptionUnknownLanguage
* @throws \Exception
*/
public static function Startup($config, $bModelOnly = false, $bAllowCache = true, $bTraceSourceFiles = false, $sEnvironment = 'production')
public static function Startup($config, $bModelOnly = false, $bAllowCache = true, $bTraceSourceFiles = false, $sEnvironment = ITOP_DEFAULT_ENV)
{
// Startup on a new environment is not supported
static $bStarted = false;

View File

@@ -131,7 +131,7 @@ try {
$oPage = new JsonPage();
$oPage->SetOutputDataOnly(true);
$sEnvironment = utils::ReadParam('environment', 'production', false, 'raw_data');
$sEnvironment = utils::ReadParam('environment', ITOP_DEFAULT_ENV, false, 'raw_data');
$oRestoreMutex = new iTopMutex('restore.'.$sEnvironment);
if ($oRestoreMutex->IsLocked()) {
DisplayErrorAndDie($oPage, '<p>'.Dict::S('bkp-restore-running').'</p>');
@@ -156,7 +156,7 @@ try {
require_once(APPROOT.'/setup/backup.class.inc.php');
require_once(__DIR__.'/dbrestore.class.inc.php');
$sEnvironment = utils::ReadParam('environment', 'production', false, 'raw_data');
$sEnvironment = utils::ReadParam('environment', ITOP_DEFAULT_ENV, false, 'raw_data');
try {
set_time_limit(0);

View File

@@ -97,7 +97,7 @@ class DBRestore extends DBBackup
*
* @uses \RunTimeEnvironment::CompileFrom()
*/
public function RestoreFromCompressedBackup($sFile, $sEnvironment = 'production')
public function RestoreFromCompressedBackup($sFile, $sEnvironment = ITOP_DEFAULT_ENV)
{
$oRestoreMutex = new iTopMutex('restore.'.$sEnvironment);
IssueLog::Info("Backup Restore - Acquiring the LOCK 'restore.$sEnvironment'");

View File

@@ -126,7 +126,7 @@ function ExecuteMainOperation($oP)
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');
$sEnvironment = utils::ReadParam('environment', ITOP_DEFAULT_ENV, false, 'raw_data');
$oRestore->RestoreFromCompressedBackup($sBackupFile, $sEnvironment);
}
}

View File

@@ -246,10 +246,10 @@ class AjaxController extends Controller
$iResponseCode = 200;
try {
$aParams['sAjaxURL'] = utils::GetAbsoluteUrlAppRoot().'/pages/UI.php';
$oConfig = new Config(APPCONF.'production'.'/'.ITOP_CONFIG_FILE);
$oEnvironment = new RunTimeEnvironment('production');
$oConfig = new Config(APPCONF.ITOP_DEFAULT_ENV.'/'.ITOP_CONFIG_FILE);
$oEnvironment = new RunTimeEnvironment(ITOP_DEFAULT_ENV);
$oEnvironment->WriteConfigFileSafe($oConfig);
$oEnvironment->CompileFrom('production');
$oEnvironment->CompileFrom(ITOP_DEFAULT_ENV);
} catch (Exception $e) {
IssueLog::Error('RebuildToolkitEnvironment: '.$e->getMessage());
$aParams['sError'] = $e->getMessage();

View File

@@ -89,7 +89,7 @@ final class CoreUpdater
// Compile code
SetupLog::Info('itop-core-update: Start checking compilation');
$sFinalEnv = 'production';
$sFinalEnv = ITOP_DEFAULT_ENV;
$oRuntimeEnv = new RunTimeEnvironmentCoreUpdater($sFinalEnv, false);
$oRuntimeEnv->CheckDirectories($sFinalEnv);
$oRuntimeEnv->CompileFrom($sFinalEnv);
@@ -117,10 +117,10 @@ final class CoreUpdater
// Compile code
SetupLog::Info('itop-core-update: Start compilation');
$sFinalEnv = 'production';
$sFinalEnv = ITOP_DEFAULT_ENV;
$oRuntimeEnv = new RunTimeEnvironmentCoreUpdater($sFinalEnv, true);
$oRuntimeEnv->CheckDirectories($sFinalEnv);
$oRuntimeEnv->CompileFrom('production');
$oRuntimeEnv->CompileFrom(ITOP_DEFAULT_ENV);
SetupLog::Info('itop-core-update: Compilation done');
} catch (Exception $e) {
@@ -142,7 +142,7 @@ final class CoreUpdater
try {
SetupLog::Info('itop-core-update: Start Update database');
$sFinalEnv = 'production';
$sFinalEnv = ITOP_DEFAULT_ENV;
$oRuntimeEnv = new RunTimeEnvironmentCoreUpdater($sFinalEnv, true);
$oConfig = $oRuntimeEnv->MakeConfigFile($sFinalEnv.' (built on '.date('Y-m-d').')');
$oConfig->Set('access_mode', ACCESS_FULL);

View File

@@ -25,7 +25,7 @@ class RunTimeEnvironmentCoreUpdater extends RunTimeEnvironment
*
* @throws \Exception
*/
public function __construct($sEnvironment = 'production', $bAutoCommit = true)
public function __construct($sEnvironment = ITOP_DEFAULT_ENV, $bAutoCommit = true)
{
parent::__construct($sEnvironment, $bAutoCommit);
@@ -83,7 +83,7 @@ class RunTimeEnvironmentCoreUpdater extends RunTimeEnvironment
{
// Clone the default 'production' config file
//
$oConfig = clone($this->GetConfig('production'));
$oConfig = clone($this->GetConfig(ITOP_DEFAULT_ENV));
$oConfig->UpdateIncludes('env-'.$this->sBuildEnv);

View File

@@ -20,7 +20,7 @@ function DisplayStatus(WebPage $oPage)
if (is_dir($sPath)) {
$aExtraDirs[] = $sPath; // Also read the extra downloaded-modules directory
}
$oExtensionsMap = new iTopExtensionsMap('production', $aExtraDirs);
$oExtensionsMap = new iTopExtensionsMap(ITOP_DEFAULT_ENV, $aExtraDirs);
$oExtensionsMap->LoadChoicesFromDatabase(MetaModel::GetConfig());
foreach ($oExtensionsMap->GetAllExtensions() as $oExtension) {
@@ -154,7 +154,7 @@ function DoInstall(WebPage $oPage)
if (is_dir($sPath)) {
$aExtraDirs[] = $sPath; // Also read the extra downloaded-modules directory
}
$oExtensionsMap = new iTopExtensionsMap('production', $aExtraDirs);
$oExtensionsMap = new iTopExtensionsMap(ITOP_DEFAULT_ENV, $aExtraDirs);
$oExtensionsMap->LoadChoicesFromDatabase(MetaModel::GetConfig());
foreach ($oExtensionsMap->GetAllExtensions() as $oExtension) {

View File

@@ -149,9 +149,9 @@ try {
if (is_subclass_of($sClass, 'WizardStep')) {
/** @var WizardStep $oStep */
$oStep = new $sClass($oDummyController, $sState);
$sConfigFile = utils::GetConfigFilePath();
$sConfigFile = utils::GetConfigFilePath(ITOP_DEFAULT_ENV);
if (file_exists($sConfigFile) && !is_writable($sConfigFile) && $oStep->RequiresWritableConfig()) {
$sRelativePath = utils::GetConfigFilePathRelative();
$sRelativePath = utils::GetConfigFilePathRelative(ITOP_DEFAULT_ENV);
$oPage->error("<b>Error:</b> the configuration file '".$sRelativePath."' already exists and cannot be overwritten.");
$oPage->p("The wizard cannot modify the configuration file for you. If you want to upgrade ".ITOP_APPLICATION.", make sure that the file '<b>".$sRelativePath."</b>' can be modified by the web server.");
$oPage->output();

View File

@@ -290,7 +290,7 @@ class MFCompiler
} else {
$oConfig = null;
}
if (($this->sEnvironment == 'production') && !$bIsAlreadyInMaintenanceMode && $bEnterMaintenanceMode) {
if (($this->sEnvironment == ITOP_DEFAULT_ENV) && !$bIsAlreadyInMaintenanceMode && $bEnterMaintenanceMode) {
SetupUtils::EnterMaintenanceMode($oConfig);
}
if ($bUseSymbolicLinks || $bSkipTempDir) {
@@ -313,7 +313,7 @@ class MFCompiler
// Cleanup the temporary directory
SetupUtils::rrmdir($sTempTargetDir);
}
if (($this->sEnvironment == 'production') && !$bIsAlreadyInMaintenanceMode && $bEnterMaintenanceMode) {
if (($this->sEnvironment == ITOP_DEFAULT_ENV) && !$bIsAlreadyInMaintenanceMode && $bEnterMaintenanceMode) {
SetupUtils::ExitMaintenanceMode();
}
throw $e;
@@ -323,7 +323,7 @@ class MFCompiler
// Move the results to the target directory
SetupUtils::movedir($sTempTargetDir, $sFinalTargetDir);
}
if (($this->sEnvironment == 'production') && !$bIsAlreadyInMaintenanceMode && $bEnterMaintenanceMode) {
if (($this->sEnvironment == ITOP_DEFAULT_ENV) && !$bIsAlreadyInMaintenanceMode && $bEnterMaintenanceMode) {
SetupUtils::ExitMaintenanceMode();
}

View File

@@ -41,7 +41,7 @@ class iTopExtensionsMap
* @param bool $bNormailizeOldExtension true to "magically" convert some well-known old extensions (i.e. a set of modules) to the new iTopExtension format
* @return void
*/
public function __construct($sFromEnvironment = 'production', $aExtraDirs = [])
public function __construct($sFromEnvironment = ITOP_DEFAULT_ENV, $aExtraDirs = [])
{
$this->aExtensions = [];
$this->aExtensionsByCode = [];

View File

@@ -92,7 +92,7 @@ class RunTimeEnvironment
* @param string $sEnvironment (e.g. 'test')
* @param bool $bAutoCommit (make the final environment directly, or build a temporary one)
*/
public function __construct($sEnvironment = 'production', $bAutoCommit = true)
public function __construct($sEnvironment = ITOP_DEFAULT_ENV, $bAutoCommit = true)
{
$this->sFinalEnv = $sEnvironment;
if ($bAutoCommit) {
@@ -167,10 +167,10 @@ class RunTimeEnvironment
}
if (! isset($_SESSION)) {
Session::$bAllowCLI = true;
Session::Start();
//used in all UI setups (not unattended)
session_start();
}
Session::Set('itop_env', $this->sBuildEnv);
$_SESSION['itop_env'] = $this->sBuildEnv;
MetaModel::Startup($oConfig, $bModelOnly, $bUseCache, false, $this->sBuildEnv);
self::$bMetamodelStarted = true;
@@ -1024,12 +1024,11 @@ class RunTimeEnvironment
@chmod($sFinalConfig, 0440); // Read-only for owner and group, nothing for others
@rmdir(dirname($sBuildConfig)); // Cleanup the temporary build dir if empty
MetaModel::ResetAllCaches($this->sFinalEnv);
if (! isset($_SESSION)) {
Session::$bAllowCLI = true;
Session::Start();
//used in all UI setups (not unattended)
session_start();
}
Session::Set('itop_env', $this->sFinalEnv);
$_SESSION['itop_env'] = $this->sFinalEnv;
}
}
@@ -1318,7 +1317,7 @@ class RunTimeEnvironment
public function DataToCleanupAudit()
{
$oSetupAudit = new SetupAudit('production', $this->sBuildEnv);
$oSetupAudit = new SetupAudit(ITOP_DEFAULT_ENV, $this->sBuildEnv);
//Make sure the MetaModel is started before analysing for issues
$sConfFile = utils::GetConfigFilePath($this->sBuildEnv);
@@ -1333,7 +1332,7 @@ class RunTimeEnvironment
public function CopySetupFiles(): void
{
$sSourceEnv = 'production';
$sSourceEnv = ITOP_DEFAULT_ENV;
$sDestinationEnv = $this->sBuildEnv;
if ($sDestinationEnv != $sSourceEnv) {
@@ -1347,10 +1346,6 @@ class RunTimeEnvironment
chmod($sFinalConfig, 0770); // In case it exists: RWX for owner and group, nothing for others
}
SetupUtils::copydir(APPCONF.$sSourceEnv, APPCONF.$sDestinationEnv);
if (is_file($sFinalConfig)) {
chmod($sFinalConfig, 0440); // Read-only for owner and group, nothing for others
}
MetaModel::ResetAllCaches($sDestinationEnv);
}
}
@@ -1456,7 +1451,7 @@ class RunTimeEnvironment
SetupUtils::tidydir($sBuildPath);
}
$oExtensionsMap = new iTopExtensionsMap('production', $aDirsToScan);
$oExtensionsMap = new iTopExtensionsMap(ITOP_DEFAULT_ENV, $aDirsToScan);
// Removed modules are stored as static for FindModules()
$oExtensionsMap->DeclareExtensionAsRemoved($aRemovedExtensionCodes);

View File

@@ -67,7 +67,6 @@ class ApplicationInstallSequencer extends StepSequencer
case 'backup':
if (array_key_exists('backup', $this->oParams->Get('optional_steps', []))) {
$aBackupOptions = $this->oParams->Get('optional_steps')['backup'];
// __DB__-%Y-%m-%d
$sDestination = $aBackupOptions['destination'];
@@ -136,7 +135,7 @@ class ApplicationInstallSequencer extends StepSequencer
return $this->GetNextStep('', "Unknown setup step '$sStep'.", 100, '', self::ERROR);
}
} catch (Exception $e) {
$this->ReportException($e);
SetupLog::Exception("$sStep failed", $e);
$aResult = $this->GetNextStep('', '', 100, $e->getMessage(), self::ERROR);
$aResult['error_code'] = $e->getCode();
return $aResult;

View File

@@ -64,20 +64,19 @@ class DataAuditSequencer extends StepSequencer
$sExtensionDir,
$bUseSymbolicLinks
);
if ($this->IsDataAuditRequired()) {
return $this->GetNextStep('setup-audit', 'Checking data consistency with the new data model', 70, $sMessage);
}
return $this->GetNextStep('', 'Completed', 100);
return $this->GetNextStep('setup-audit', 'Checking data consistency with the new data model', 70, $sMessage);
case 'setup-audit':
$this->oRunTimeEnvironment->DataToCleanupAudit();
if ($this->IsDataAuditRequired()) {
$this->oRunTimeEnvironment->DataToCleanupAudit();
}
return $this->GetNextStep('', 'Completed', 100);
default:
return $this->GetNextStep('', "Unknown setup step '$sStep'.", 100, '', self::ERROR);
}
} catch (Exception $e) {
$this->ReportException($e);
SetupLog::Exception("$sStep failed", $e);
$aResult = $this->GetNextStep('', '', 100, $e->getMessage(), self::ERROR);
$aResult['error_code'] = $e->getCode();
return $aResult;

View File

@@ -159,24 +159,6 @@ abstract class StepSequencer
file_put_contents(APPROOT.'log/'.$sFileName.'.xml', $sSafeXml);
}
protected function ReportException(Exception $e)
{
SetupLog::Error('An exception occurred: '.$e->getMessage().' at line '.$e->getLine().' in file '.$e->getFile());
$idx = 0;
// Log the call stack, but not the parameters since they may contain passwords or other sensitive data
SetupLog::Ok('Call stack:');
foreach ($e->getTrace() as $aTrace) {
$sLine = empty($aTrace['line']) ? '' : $aTrace['line'];
$sFile = empty($aTrace['file']) ? '' : $aTrace['file'];
$sClass = empty($aTrace['class']) ? '' : $aTrace['class'];
$sType = empty($aTrace['type']) ? '' : $aTrace['type'];
$sFunction = empty($aTrace['function']) ? '' : $aTrace['function'];
$sVerb = empty($sClass) ? $sFunction : "$sClass{$sType}$sFunction";
SetupLog::Ok("#$idx $sFile($sLine): $sVerb(...)");
$idx++;
}
}
protected function GetConfig()
{
$sTargetEnvironment = $this->oRunTimeEnvironment->GetBuildEnv();

View File

@@ -915,7 +915,7 @@ class SetupUtils
$aResult['found'] = true;
} elseif (file_exists($sDir.'/conf/production/config-itop.php')) {
$sSourceDir = $sDir;
$sSourceEnvironment = 'production';
$sSourceEnvironment = ITOP_DEFAULT_ENV;
$sConfigFile = $sDir.'/conf/production/config-itop.php';
$aResult['found'] = true;
}
@@ -1586,7 +1586,7 @@ JS
}
$oProductionEnv = new RunTimeEnvironment();
$aRemovedExtensionCodes = json_decode($oWizard->GetParameter('removed_extensions'), true) ?? [];
$oExtensionsMap = new iTopExtensionsMap('production', $aDirsToScan);
$oExtensionsMap = new iTopExtensionsMap(ITOP_DEFAULT_ENV, $aDirsToScan);
$oExtensionsMap->DeclareExtensionAsRemoved($aRemovedExtensionCodes);
$aAvailableModules = $oProductionEnv->AnalyzeInstallation($oConfig, $aDirsToScan, $bAbortOnMissingDependency, $aModulesToLoad);

View File

@@ -31,7 +31,7 @@ class InstallationFileService
* @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)
public function __construct(string $sInstallationPath, string $sTargetEnvironment = ITOP_DEFAULT_ENV, array $aSelectedExtensions = [], bool $bInstallationOptionalChoicesChecked = true)
{
$this->sInstallationPath = $sInstallationPath;
$this->aSelectedModules = [];

View File

@@ -56,7 +56,7 @@ $sMode = $oParams->Get('mode');
$sTargetEnvironment = $oParams->Get('target_env', '');
if ($sTargetEnvironment == '') {
$sTargetEnvironment = 'production';
$sTargetEnvironment = ITOP_DEFAULT_ENV;
}
$sXmlSetupBaseName = basename($sParamFile);
@@ -218,7 +218,7 @@ if ($sMode == 'install') {
//use settings from itop conf
$sTargetEnvironment = $oParams->Get('target_env', '');
if ($sTargetEnvironment == '') {
$sTargetEnvironment = 'production';
$sTargetEnvironment = ITOP_DEFAULT_ENV;
}
$sTargetDir = APPROOT.'env-'.$sTargetEnvironment;
}
@@ -271,6 +271,10 @@ $bFoundIssues = false;
$bInstall = utils::ReadParam('install', true, true /* CLI allowed */);
if ($bInstall) {
if (! isset($_SESSION)) {
$_SESSION = [];
}
echo "Starting the unattended installation...\n";
$oWizard = new DataAuditSequencer($oParams);
$bRes = $oWizard->ExecuteAllSteps();

View File

@@ -190,15 +190,16 @@ class WizardController
*/
protected function DisplayStep(WizardStep $oStep)
{
SetupLog::Info("=== Setup screen: ".$oStep->GetTitle().' ('.get_class($oStep).')');
$oPage = new SetupPage($oStep->GetTitle());
if ($oStep->RequiresWritableConfig()) {
$sConfigFile = utils::GetConfigFilePath();
$sConfigFile = utils::GetConfigFilePath(ITOP_DEFAULT_ENV);
if (file_exists($sConfigFile)) {
// The configuration file already exists
if (!is_writable($sConfigFile)) {
SetupUtils::ExitReadOnlyMode(false); // Reset readonly mode in case of problem
SetupUtils::EraseSetupToken();
$sRelativePath = utils::GetConfigFilePathRelative();
$sRelativePath = utils::GetConfigFilePathRelative(ITOP_DEFAULT_ENV);
$oP = new SetupPage('Installation Cannot Continue');
$oP->add("<h2>Fatal error</h2>\n");
$oP->error("<b>Error:</b> the configuration file '".$sRelativePath."' already exists and cannot be overwritten.");

View File

@@ -95,7 +95,7 @@ class WizStepDone extends WizardStep
// Load the data model only, in order to load env-production/core/main.php to get the XML parameters (needed by GetModuleSettings below)
// But main.php may also contain classes (defined without any module), and thus requiring the full data model
// to be loaded to prevent "class not found" errors...
$oProductionEnv = new RunTimeEnvironment('production');
$oProductionEnv = new RunTimeEnvironment(ITOP_DEFAULT_ENV);
$oProductionEnv->InitDataModel($oConfig, true);
$sIframeUrl = $oConfig->GetModuleSetting('itop-hub-connector', 'setup_url', '');

View File

@@ -60,8 +60,8 @@ class WizStepModulesChoice extends WizardStep
$sConfigPath = null;
if (($sPreviousSourceDir !== '') && is_readable($sPreviousSourceDir.'/conf/production/config-itop.php')) {
$sConfigPath = $sPreviousSourceDir.'/conf/production/config-itop.php';
} elseif (is_readable(utils::GetConfigFilePath('production'))) {
$sConfigPath = utils::GetConfigFilePath('production');
} elseif (is_readable(utils::GetConfigFilePath(ITOP_DEFAULT_ENV))) {
$sConfigPath = utils::GetConfigFilePath(ITOP_DEFAULT_ENV);
}
// only called if the config file exists : we are updating a previous installation !

View File

@@ -88,7 +88,7 @@ abstract class ItopCustomDatamodelTestCase extends ItopDataTestCase
*/
protected function GetSourceEnvironment(): string
{
return 'production';
return ITOP_DEFAULT_ENV;
}
/**

View File

@@ -86,7 +86,7 @@ abstract class ItopDataTestCase extends ItopTestCase
/**
* @var string Default environment to use for test cases
*/
public const DEFAULT_TEST_ENVIRONMENT = 'production';
public const DEFAULT_TEST_ENVIRONMENT = ITOP_DEFAULT_ENV;
public const USE_TRANSACTION = true;
public const CREATE_TEST_ORG = false;

View File

@@ -31,7 +31,7 @@ class TransactionsTest extends ItopTestCase
parent::setUp();
require_once('DeadLockInjection.php');
$this->RequireOnceItopFile('/core/cmdbsource.class.inc.php');
$sEnv = 'production';
$sEnv = ITOP_DEFAULT_ENV;
$sConfigFile = APPCONF.$sEnv.'/config-itop.php';
MetaModel::Startup($sConfigFile, false, true, false, $sEnv);