Fixed setup issues (improved modularity)

SVN:trunk[1982]
This commit is contained in:
Romain Quetiez
2012-05-10 09:30:48 +00:00
parent fb8d93319d
commit 39be3b449e
9 changed files with 457 additions and 340 deletions

View File

@@ -464,7 +464,15 @@ class utils
if (self::$oConfig == null)
{
$sConfigFile = self::GetConfigFilePath();
self::$oConfig = new Config($sConfigFile);
if (file_exists($sConfigFile))
{
self::$oConfig = new Config($sConfigFile);
}
else
{
// When executing the setup, the config file may be still missing
self::$oConfig = new Config();
}
}
return self::$oConfig;
}

View File

@@ -24,6 +24,7 @@
*/
require_once('MyHelpers.class.inc.php');
require_once(APPROOT.'core/kpi.class.inc.php');
class MySQLException extends CoreException
{

View File

@@ -1462,5 +1462,31 @@ class Config
}
}
/**
* Helper: for an array of string, change the prefix when found
*/
protected static function ChangePrefix(&$aStrings, $sSearchPrefix, $sNewPrefix)
{
foreach ($aStrings as &$sFile)
{
if (substr($sFile, 0, strlen($sSearchPrefix)) == $sSearchPrefix)
{
$sFile = $sNewPrefix.substr($sFile, strlen($sSearchPrefix));
}
}
}
/**
* Quick an dirty way to clone a config file into another environment
*/
public function ChangeModulesPath($sSourceEnv, $sTargetEnv)
{
$sSearchPrefix = 'env-'.$sSourceEnv.'/';
$sNewPrefix = 'env-'.$sTargetEnv.'/';
self::ChangePrefix($this->m_aDataModels, $sSearchPrefix, $sNewPrefix);
self::ChangePrefix($this->m_aWebServiceCategories, $sSearchPrefix, $sNewPrefix);
self::ChangePrefix($this->m_aDictionaries, $sSearchPrefix, $sNewPrefix);
}
}
?>

View File

@@ -227,10 +227,11 @@ try
$sModuleDir = Utils::ReadParam('modules_dir', '');
$oConfig->UpdateFromParams($aParamValues, $sModuleDir);
InitDataModel($oConfig, true); // load data model only
$oProductionEnv = new RunTimeEnvironment();
$oProductionEnv->InitDataModel($oConfig, true); // load data model only
$sMode = Utils::ReadParam('mode', 'install');
if(!CreateDatabaseStructure(MetaModel::GetConfig(), $sMode))
if(!$oProductionEnv->CreateDatabaseStructure(MetaModel::GetConfig(), $sMode))
{
throw(new Exception("Failed to create/upgrade the database structure"));
}
@@ -256,7 +257,8 @@ try
$sModuleDir = Utils::ReadParam('modules_dir', '');
$oConfig->UpdateFromParams($aParamValues, $sModuleDir);
InitDataModel($oConfig, false); // load data model and connect to the database
$oProductionEnv = new RunTimeEnvironment();
$oProductionEnv->InitDataModel($oConfig, false); // load data model and connect to the database
$sMode = Utils::ReadParam('mode', 'install');
$sSelectedModules = Utils::ReadParam('selected_modules', '', false, 'raw_data');
@@ -264,7 +266,7 @@ try
// Perform here additional DB setup... profiles, etc...
//
$aAvailableModules = AnalyzeInstallation(MetaModel::GetConfig(), $sModuleDir);
$aAvailableModules = $oProductionEnv->AnalyzeInstallation(MetaModel::GetConfig(), $sModuleDir);
foreach($aAvailableModules as $sModuleId => $aModule)
{
if (($sModuleId != ROOT_MODULE) && in_array($sModuleId, $aSelectedModules) &&
@@ -278,7 +280,7 @@ try
}
}
if (!RecordInstallation($oConfig, $aSelectedModules, $sModuleDir))
if (!$oProductionEnv->RecordInstallation($oConfig, $aSelectedModules, $sModuleDir))
{
throw(new Exception("Failed to record the installation information"));
}
@@ -326,7 +328,8 @@ try
$sModuleDir = Utils::ReadParam('modules_dir', '');
$oConfig->UpdateFromParams($aParamValues, $sModuleDir);
InitDataModel($oConfig, false); // load data model and connect to the database
$oProductionEnv = new RunTimeEnvironment();
$oProductionEnv->InitDataModel($oConfig, false); // load data model and connect to the database
$oDataLoader = new XMLDataLoader();
if ($sSessionStatus == 'start')

View File

@@ -398,7 +398,15 @@ EOF;
$aClassParams['reconc_keys'] = $sReconcKeys;
$aClassParams['db_table'] = "'".$oProperties->GetChildText('db_table')."'";
$aClassParams['db_key_field'] = "'".$oProperties->GetChildText('db_key_field')."'";
$sKeyField = $oProperties->GetChildText('db_key_field');
if ($sKeyField == '')
{
$sKeyField = 'id';
}
$aClassParams['db_key_field'] = "'".$sKeyField."'";
// TODO: faire automatiquement (pas dans le XML !!!)
$aClassParams['db_finalclass_field'] = "'".$oProperties->GetChildText('db_final_class_field')."'";
if (($sDisplayTemplate = $oProperties->GetChildText('display_template')) && (strlen($sDisplayTemplate) > 0))

View File

@@ -447,7 +447,8 @@ function PopulateDataFilesList(SetupPage $oP, $aParamValues, $oConfig)
$sScript .= "{\n";
$sScript .= "if (aFilesToLoad.length > 0) return;"; // Populate the list only once...
$aAvailableModules = AnalyzeInstallation($oConfig, $aParamValues['source_dir']);
$oProductionEnv = new RunTimeEnvironment();
$aAvailableModules = $oProductionEnv->AnalyzeInstallation($oConfig, $aParamValues['source_dir']);
$sMode = $aParamValues['mode'];
$aStructureDataFiles = array();
@@ -595,7 +596,8 @@ function WelcomeAndCheckPrerequisites(SetupPage $oP, $aParamValues, $iCurrentSte
{
$oConfig = new Config($sConfigFile);
$aVersion = AnalyzeInstallation($oConfig, 'datamodel');
$oProductionEnv = new RunTimeEnvironment();
$aVersion = $oProductionEnv->AnalyzeInstallation($oConfig, 'datamodel');
if (!empty($aVersion[ROOT_MODULE]['version_db']))
{
$aPreviousParams = array('mode', 'db_server', 'db_user', 'db_pwd','db_name', 'new_db_name', 'db_prefix', 'source_dir', 'target_dir');
@@ -826,7 +828,8 @@ function ModulesSelection(SetupPage $oP, $aParamValues, $iCurrentStep, $oConfig)
$sRedStar = '<span class="hilite">*</span>';
$oP->set_title("iTop modules selection");
$aAvailableModules = AnalyzeInstallation($oConfig, $aParamValues['source_dir']);
$oProductionEnv = new RunTimeEnvironment();
$aAvailableModules = $oProductionEnv->AnalyzeInstallation($oConfig, $aParamValues['source_dir']);
$sConfigFile = utils::GetConfigFilePath();
// Form goes here
@@ -1132,7 +1135,8 @@ function SampleDataSelection(SetupPage $oP, $aParamValues, $iCurrentStep, Config
function DisplaySummary(SetupPage $oP, $aParamValues, $iCurrentStep, Config $oConfig)
{
$sMode = $aParamValues['mode'];
$aAvailableModules = AnalyzeInstallation($oConfig, $aParamValues['source_dir']);
$oProductionEnv = new RunTimeEnvironment();
$aAvailableModules = $oProductionEnv->AnalyzeInstallation($oConfig, $aParamValues['source_dir']);
$aInstall = array();
$aUpgrade = array();
@@ -1388,7 +1392,8 @@ function SetupFinished(SetupPage $oP, $aParamValues, $iCurrentStep, Config $oCon
$oConfig->WriteToFile($sConfigFile);
// Start the application
InitDataModel($oConfig, false, true); // Load model, startup DB and load the cache
$oProductionEnv = new RunTimeEnvironment();
$oProductionEnv->InitDataModel($oConfig, false, true); // Load model, startup DB and load the cache
if ($aParamValues['mode'] == 'install')
{
if (UserRights::CheckCredentials($sAuthUser, $sAuthPwd))
@@ -1421,7 +1426,8 @@ function SetupFinished(SetupPage $oP, $aParamValues, $iCurrentStep, Config $oCon
$oP->add("<form id=\"theForm\" method=\"get\" action=\"../index.php\">\n");
// Check if there are some manual steps required:
$aAvailableModules = AnalyzeInstallation($oConfig, $aParamValues['target_dir']);
$oProductionEnv = new RunTimeEnvironment();
$aAvailableModules = $oProductionEnv->AnalyzeInstallation($oConfig, $aParamValues['target_dir']);
$aManualSteps = array();
$sRootUrl = utils::GetAbsoluteUrlAppRoot();
foreach($aParamValues['module'] as $sModuleId)

View File

@@ -124,6 +124,7 @@ class ModelFactory
$this->sRootDir = $sRootDir;
$this->oDOMDocument = new MFDocument();
$this->oRoot = $this->oDOMDocument->CreateElement('itop_design');
$this->oRoot->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
$this->oDOMDocument->AppendChild($this->oRoot);
$this->oModules = $this->oDOMDocument->CreateElement('loaded_modules');
$this->oRoot->AppendChild($this->oModules);
@@ -299,12 +300,18 @@ class ModelFactory
$oNodeList = $oXPath->query('/itop_design/classes//class');
foreach($oNodeList as $oNode)
{
$oNode->SetAttribute('_created_in', $sModuleName);
if ($oNode->getAttribute('_created_in') == '')
{
$oNode->SetAttribute('_created_in', $sModuleName);
}
}
$oNodeList = $oXPath->query('/itop_design/menus/menu');
foreach($oNodeList as $oNode)
{
$oNode->SetAttribute('_created_in', $sModuleName);
if ($oNode->getAttribute('_created_in') == '')
{
$oNode->SetAttribute('_created_in', $sModuleName);
}
}
$oDeltaRoot = $oDocument->childNodes->item(0);
@@ -1648,9 +1655,9 @@ class MFDocument extends DOMDocument
if (!$oRootNode)
{
$oRootNode = $this->createElement('itop_design'); // make sure that the document is not empty
$oRootNode->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
$this->appendChild($oRootNode);
}
$oRootNode->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
return parent::saveXML();
}
/**

View File

@@ -0,0 +1,380 @@
<?php
// Copyright (C) 2010 Combodo SARL
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; version 3 of the License.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
/**
* Web page used for displaying the login form
*
* @author Erwan Taloc <erwan.taloc@combodo.com>
* @author Romain Quetiez <romain.quetiez@combodo.com>
* @author Denis Flaven <denis.flaven@combodo.com>
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
*/
require_once(APPROOT."setup/modulediscovery.class.inc.php");
define ('MODULE_ACTION_OPTIONAL', 1);
define ('MODULE_ACTION_MANDATORY', 2);
define ('MODULE_ACTION_IMPOSSIBLE', 3);
define ('ROOT_MODULE', '_Root_'); // Convention to store IN MEMORY the name/version of the root module i.e. application
class RunTimeEnvironment
{
protected $sTargetEnv;
public function __construct($sEnvironment = 'production')
{
$this->sTargetEnv = $sEnvironment;
}
/**
* 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
* @return none
*/
public function InitDataModel($oConfig, $bModelOnly = true, $bUseCache = false)
{
require_once(APPROOT.'/core/log.class.inc.php');
require_once(APPROOT.'/core/kpi.class.inc.php');
require_once(APPROOT.'/core/coreexception.class.inc.php');
require_once(APPROOT.'/core/dict.class.inc.php');
require_once(APPROOT.'/core/attributedef.class.inc.php');
require_once(APPROOT.'/core/filterdef.class.inc.php');
require_once(APPROOT.'/core/stimulus.class.inc.php');
require_once(APPROOT.'/core/MyHelpers.class.inc.php');
require_once(APPROOT.'/core/expression.class.inc.php');
require_once(APPROOT.'/core/cmdbsource.class.inc.php');
require_once(APPROOT.'/core/sqlquery.class.inc.php');
require_once(APPROOT.'/core/dbobject.class.php');
require_once(APPROOT.'/core/dbobjectsearch.class.php');
require_once(APPROOT.'/core/dbobjectset.class.php');
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
require_once(APPROOT.'/core/userrights.class.inc.php');
require_once(APPROOT.'/setup/moduleinstallation.class.inc.php');
$sConfigFile = $oConfig->GetLoadedFile();
if (strlen($sConfigFile) > 0)
{
$this->log_info("MetaModel::Startup from $sConfigFile (ModelOnly = $bModelOnly)");
}
else
{
$this->log_info("MetaModel::Startup (ModelOnly = $bModelOnly)");
}
if (!$bUseCache)
{
// Reset the cache for the first use !
MetaModel::ResetCache($oConfig);
}
MetaModel::Startup($oConfig, $bModelOnly, $bUseCache);
}
/**
* Analyzes the current installation and the possibilities
*
* @param $oConfig Config Defines the target environment (DB)
* @return hash Array with the following format:
* array =>
* 'iTop' => array(
* 'version_db' => ... (could be empty in case of a fresh install)
* 'version_code => ...
* )
* <module_name> => array(
* 'version_db' => ...
* 'version_code' => ...
* 'install' => array(
* 'flag' => SETUP_NEVER | SETUP_OPTIONAL | SETUP_MANDATORY
* 'message' => ...
* )
* 'uninstall' => array(
* 'flag' => SETUP_NEVER | SETUP_OPTIONAL | SETUP_MANDATORY
* 'message' => ...
* )
* 'label' => ...
* 'dependencies' => array(<module1>, <module2>, ...)
* 'visible' => true | false
* )
* )
*/
public function AnalyzeInstallation($oConfig, $sModulesRelativePath)
{
$aRes = array(
ROOT_MODULE => array(
'version_db' => '',
'name_db' => '',
'version_code' => ITOP_VERSION.'.'.ITOP_REVISION,
'name_code' => ITOP_APPLICATION,
)
);
$aModules = ModuleDiscovery::GetAvailableModules(APPROOT, $sModulesRelativePath);
foreach($aModules as $sModuleId => $aModuleInfo)
{
list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId);
$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
$aModuleInfo['install'] = array(
'flag' => MODULE_ACTION_IMPOSSIBLE,
'message' => 'the module is not compatible with the current version of the application'
);
}
elseif ($aModuleInfo['mandatory'])
{
$aModuleInfo['install'] = array(
'flag' => MODULE_ACTION_MANDATORY,
'message' => 'the module is part of the application'
);
}
else
{
$aModuleInfo['install'] = array(
'flag' => MODULE_ACTION_OPTIONAL,
'message' => ''
);
}
$aRes[$sModuleName] = $aModuleInfo;
}
try
{
CMDBSource::Init($oConfig->GetDBHost(), $oConfig->GetDBUser(), $oConfig->GetDBPwd(), $oConfig->GetDBName());
$aSelectInstall = CMDBSource::QueryToArray("SELECT * FROM ".$oConfig->GetDBSubname()."priv_module_install");
}
catch (MySQLException $e)
{
// No database or eroneous information
$aSelectInstall = array();
}
// Build the list of installed module (get the latest installation)
//
$aInstallByModule = array(); // array of <module> => array ('installed' => timestamp, 'version' => <version>)
foreach ($aSelectInstall as $aInstall)
{
//$aInstall['comment']; // unsused
$iInstalled = strtotime($aInstall['installed']);
$sModuleName = $aInstall['name'];
$sModuleVersion = $aInstall['version'];
if ($aInstall['parent_id'] == 0)
{
$sModuleName = ROOT_MODULE;
}
if (array_key_exists($sModuleName, $aInstallByModule))
{
if ($iInstalled < $aInstallByModule[$sModuleName]['installed'])
{
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
continue;
}
$aRes[$sModuleName]['version_db'] = $aModuleDB['version'];
if ($aRes[$sModuleName]['install']['flag'] == MODULE_ACTION_MANDATORY)
{
$aRes[$sModuleName]['uninstall'] = array(
'flag' => MODULE_ACTION_IMPOSSIBLE,
'message' => 'the module is part of the application'
);
}
else
{
$aRes[$sModuleName]['uninstall'] = array(
'flag' => MODULE_ACTION_OPTIONAL,
'message' => ''
);
}
}
return $aRes;
}
/**
* Helper function to create the database structure
* @return boolean true on success, false otherwise
*/
public function CreateDatabaseStructure(Config $oConfig, $sMode)
{
if (strlen($oConfig->GetDBSubname()) > 0)
{
$this->log_info("Creating the structure in '".$oConfig->GetDBName()."' (table names prefixed by '".$oConfig->GetDBSubname()."').");
}
else
{
$this->log_info("Creating the structure in '".$oConfig->GetDBSubname()."'.");
}
//MetaModel::CheckDefinitions();
if ($sMode == 'install')
{
if (!MetaModel::DBExists(/* bMustBeComplete */ false))
{
MetaModel::DBCreate();
$this->log_ok("Database structure successfully created.");
}
else
{
if (strlen($oConfig->GetDBSubname()) > 0)
{
throw new Exception("Error: found iTop tables into the database '".$oConfig->GetDBName()."' (prefix: '".$oConfig->GetDBSubname()."'). Please, try selecting another database instance or specify another prefix to prevent conflicting table names.");
}
else
{
throw new Exception("Error: found iTop tables into the database '".$oConfig->GetDBName()."'. Please, try selecting another database instance or specify a prefix to prevent conflicting table names.");
}
}
}
else
{
if (MetaModel::DBExists(/* bMustBeComplete */ false))
{
MetaModel::DBCreate();
$this->log_ok("Database structure successfully updated.");
// Check (and update only if it seems needed) the hierarchical keys
ob_start();
MetaModel::CheckHKeys(false /* bDiagnosticsOnly */, true /* bVerbose*/, true /* bForceUpdate */); // Since in 1.2-beta the detection was buggy, let's force the rebuilding of HKeys
$sFeedback = ob_get_clean();
$this->log_ok("Hierchical keys rebuilt: $sFeedback");
// Check (and fix) data sync configuration
ob_start();
MetaModel::CheckDataSources(false /*$bDiagnostics*/, true/*$bVerbose*/);
$sFeedback = ob_get_clean();
$this->log_ok("Data sources checked: $sFeedback");
}
else
{
if (strlen($oConfig->GetDBSubname()) > 0)
{
throw new Exception("Error: No previous instance of iTop found into the database '".$oConfig->GetDBName()."' (prefix: '".$oConfig->GetDBSubname()."'). Please, try selecting another database instance.");
}
else
{
throw new Exception("Error: No previous instance of iTop found into the database '".$oConfig->GetDBName()."'. Please, try selecting another database instance.");
}
}
}
return true;
}
public function RecordInstallation(Config $oConfig, $aSelectedModules, $sModulesRelativePath)
{
// Record main installation
$oInstallRec = new ModuleInstallation();
$oInstallRec->Set('name', ITOP_APPLICATION);
$oInstallRec->Set('version', ITOP_VERSION.'.'.ITOP_REVISION);
$oInstallRec->Set('comment', "Done by the setup program\nBuilt on ".ITOP_BUILD_DATE);
$oInstallRec->Set('parent_id', 0); // root module
$iMainItopRecord = $oInstallRec->DBInsertNoReload();
// Record installed modules
//
$aAvailableModules = $this->AnalyzeInstallation($oConfig, $sModulesRelativePath);
foreach($aSelectedModules as $sModuleId)
{
$aModuleData = $aAvailableModules[$sModuleId];
$sName = $sModuleId;
$sVersion = $aModuleData['version_code'];
$aComments = array();
$aComments[] = 'Done by the setup program';
if ($aModuleData['mandatory'])
{
$aComments[] = 'Mandatory';
}
else
{
$aComments[] = 'Optional';
}
if ($aModuleData['visible'])
{
$aComments[] = 'Visible (during the setup)';
}
else
{
$aComments[] = 'Hidden (selected automatically)';
}
foreach ($aModuleData['dependencies'] as $sDependOn)
{
$aComments[] = "Depends on module: $sDependOn";
}
$sComment = implode("\n", $aComments);
$oInstallRec = new ModuleInstallation();
$oInstallRec->Set('name', $sName);
$oInstallRec->Set('version', $sVersion);
$oInstallRec->Set('comment', $sComment);
$oInstallRec->Set('parent_id', $iMainItopRecord);
$oInstallRec->DBInsertNoReload();
}
// Database is created, installation has been tracked into it
return true;
}
/**
* Wrappers for logging into the setup log files
*/
protected function log_error($sText)
{
SetupPage::log_error($sText);
}
protected function log_warning($sText)
{
SetupPage::log_warning($sText);
}
protected function log_info($sText)
{
SetupPage::log_info($sText);
}
protected function log_ok($sText)
{
SetupPage::log_ok($sText);
}
} // End of class
?>

View File

@@ -25,14 +25,10 @@
require_once(APPROOT."/application/nicewebpage.class.inc.php");
require_once(APPROOT."setup/modulediscovery.class.inc.php");
require_once(APPROOT."setup/runtimeenv.class.inc.php");
define('INSTALL_LOG_FILE', APPROOT.'/setup.log');
define ('MODULE_ACTION_OPTIONAL', 1);
define ('MODULE_ACTION_MANDATORY', 2);
define ('MODULE_ACTION_IMPOSSIBLE', 3);
define ('ROOT_MODULE', '_Root_'); // Convention to store IN MEMORY the name/version of the root module i.e. application
date_default_timezone_set('Europe/Paris');
class SetupPage extends NiceWebPage
{
@@ -309,322 +305,4 @@ h3.clickable.open {
}
} // End of class
/**
* 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
* @return none
*/
function InitDataModel($oConfig, $bModelOnly = true, $bUseCache = false)
{
require_once(APPROOT.'/core/log.class.inc.php');
require_once(APPROOT.'/core/kpi.class.inc.php');
require_once(APPROOT.'/core/coreexception.class.inc.php');
require_once(APPROOT.'/core/dict.class.inc.php');
require_once(APPROOT.'/core/attributedef.class.inc.php');
require_once(APPROOT.'/core/filterdef.class.inc.php');
require_once(APPROOT.'/core/stimulus.class.inc.php');
require_once(APPROOT.'/core/MyHelpers.class.inc.php');
require_once(APPROOT.'/core/expression.class.inc.php');
require_once(APPROOT.'/core/cmdbsource.class.inc.php');
require_once(APPROOT.'/core/sqlquery.class.inc.php');
require_once(APPROOT.'/core/dbobject.class.php');
require_once(APPROOT.'/core/dbobjectsearch.class.php');
require_once(APPROOT.'/core/dbobjectset.class.php');
require_once(APPROOT.'/application/cmdbabstract.class.inc.php');
require_once(APPROOT.'/core/userrights.class.inc.php');
require_once(APPROOT.'/setup/moduleinstallation.class.inc.php');
$sConfigFile = $oConfig->GetLoadedFile();
if (strlen($sConfigFile) > 0)
{
SetupPage::log_info("MetaModel::Startup from $sConfigFile (ModelOnly = $bModelOnly)");
}
else
{
SetupPage::log_info("MetaModel::Startup (ModelOnly = $bModelOnly)");
}
if (!$bUseCache)
{
// Reset the cache for the first use !
MetaModel::ResetCache($oConfig);
}
MetaModel::Startup($oConfig, $bModelOnly, $bUseCache);
}
/**
* Analyzes the current installation and the possibilities
*
* @param $oConfig Config Defines the target environment (DB)
* @return hash Array with the following format:
* array =>
* 'iTop' => array(
* 'version_db' => ... (could be empty in case of a fresh install)
* 'version_code => ...
* )
* <module_name> => array(
* 'version_db' => ...
* 'version_code' => ...
* 'install' => array(
* 'flag' => SETUP_NEVER | SETUP_OPTIONAL | SETUP_MANDATORY
* 'message' => ...
* )
* 'uninstall' => array(
* 'flag' => SETUP_NEVER | SETUP_OPTIONAL | SETUP_MANDATORY
* 'message' => ...
* )
* 'label' => ...
* 'dependencies' => array(<module1>, <module2>, ...)
* 'visible' => true | false
* )
* )
*/
function AnalyzeInstallation($oConfig, $sModulesRelativePath)
{
$aRes = array(
ROOT_MODULE => array(
'version_db' => '',
'name_db' => '',
'version_code' => ITOP_VERSION.'.'.ITOP_REVISION,
'name_code' => ITOP_APPLICATION,
)
);
$aModules = ModuleDiscovery::GetAvailableModules(APPROOT, $sModulesRelativePath);
foreach($aModules as $sModuleId => $aModuleInfo)
{
list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId);
$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
$aModuleInfo['install'] = array(
'flag' => MODULE_ACTION_IMPOSSIBLE,
'message' => 'the module is not compatible with the current version of the application'
);
}
elseif ($aModuleInfo['mandatory'])
{
$aModuleInfo['install'] = array(
'flag' => MODULE_ACTION_MANDATORY,
'message' => 'the module is part of the application'
);
}
else
{
$aModuleInfo['install'] = array(
'flag' => MODULE_ACTION_OPTIONAL,
'message' => ''
);
}
$aRes[$sModuleName] = $aModuleInfo;
}
try
{
CMDBSource::Init($oConfig->GetDBHost(), $oConfig->GetDBUser(), $oConfig->GetDBPwd(), $oConfig->GetDBName());
$aSelectInstall = CMDBSource::QueryToArray("SELECT * FROM ".$oConfig->GetDBSubname()."priv_module_install");
}
catch (MySQLException $e)
{
// No database or eroneous information
$aSelectInstall = array();
}
// Build the list of installed module (get the latest installation)
//
$aInstallByModule = array(); // array of <module> => array ('installed' => timestamp, 'version' => <version>)
foreach ($aSelectInstall as $aInstall)
{
//$aInstall['comment']; // unsused
$iInstalled = strtotime($aInstall['installed']);
$sModuleName = $aInstall['name'];
$sModuleVersion = $aInstall['version'];
if ($aInstall['parent_id'] == 0)
{
$sModuleName = ROOT_MODULE;
}
if (array_key_exists($sModuleName, $aInstallByModule))
{
if ($iInstalled < $aInstallByModule[$sModuleName]['installed'])
{
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
continue;
}
$aRes[$sModuleName]['version_db'] = $aModuleDB['version'];
if ($aRes[$sModuleName]['install']['flag'] == MODULE_ACTION_MANDATORY)
{
$aRes[$sModuleName]['uninstall'] = array(
'flag' => MODULE_ACTION_IMPOSSIBLE,
'message' => 'the module is part of the application'
);
}
else
{
$aRes[$sModuleName]['uninstall'] = array(
'flag' => MODULE_ACTION_OPTIONAL,
'message' => ''
);
}
}
return $aRes;
}
/**
* Helper function to create the database structure
* @return boolean true on success, false otherwise
*/
function CreateDatabaseStructure(Config $oConfig, $sMode)
{
if (strlen($oConfig->GetDBSubname()) > 0)
{
SetupPage::log_info("Creating the structure in '".$oConfig->GetDBName()."' (table names prefixed by '".$oConfig->GetDBSubname()."').");
}
else
{
SetupPage::log_info("Creating the structure in '".$oConfig->GetDBSubname()."'.");
}
//MetaModel::CheckDefinitions();
if ($sMode == 'install')
{
if (!MetaModel::DBExists(/* bMustBeComplete */ false))
{
MetaModel::DBCreate();
SetupPage::log_ok("Database structure successfully created.");
}
else
{
if (strlen($oConfig->GetDBSubname()) > 0)
{
throw new Exception("Error: found iTop tables into the database '".$oConfig->GetDBName()."' (prefix: '".$oConfig->GetDBSubname()."'). Please, try selecting another database instance or specify another prefix to prevent conflicting table names.");
}
else
{
throw new Exception("Error: found iTop tables into the database '".$oConfig->GetDBName()."'. Please, try selecting another database instance or specify a prefix to prevent conflicting table names.");
}
}
}
else
{
if (MetaModel::DBExists(/* bMustBeComplete */ false))
{
MetaModel::DBCreate();
SetupPage::log_ok("Database structure successfully updated.");
// Check (and update only if it seems needed) the hierarchical keys
ob_start();
MetaModel::CheckHKeys(false /* bDiagnosticsOnly */, true /* bVerbose*/, true /* bForceUpdate */); // Since in 1.2-beta the detection was buggy, let's force the rebuilding of HKeys
$sFeedback = ob_get_clean();
SetupPage::log_ok("Hierchical keys rebuilt: $sFeedback");
// Check (and fix) data sync configuration
ob_start();
MetaModel::CheckDataSources(false /*$bDiagnostics*/, true/*$bVerbose*/);
$sFeedback = ob_get_clean();
SetupPage::log_ok("Data sources checked: $sFeedback");
}
else
{
if (strlen($oConfig->GetDBSubname()) > 0)
{
throw new Exception("Error: No previous instance of iTop found into the database '".$oConfig->GetDBName()."' (prefix: '".$oConfig->GetDBSubname()."'). Please, try selecting another database instance.");
}
else
{
throw new Exception("Error: No previous instance of iTop found into the database '".$oConfig->GetDBName()."'. Please, try selecting another database instance.");
}
}
}
return true;
}
function RecordInstallation(Config $oConfig, $aSelectedModules, $sModulesRelativePath)
{
// Record main installation
$oInstallRec = new ModuleInstallation();
$oInstallRec->Set('name', ITOP_APPLICATION);
$oInstallRec->Set('version', ITOP_VERSION.'.'.ITOP_REVISION);
$oInstallRec->Set('comment', "Done by the setup program\nBuilt on ".ITOP_BUILD_DATE);
$oInstallRec->Set('parent_id', 0); // root module
$iMainItopRecord = $oInstallRec->DBInsertNoReload();
// Record installed modules
//
$aAvailableModules = AnalyzeInstallation($oConfig, $sModulesRelativePath);
foreach($aSelectedModules as $sModuleId)
{
$aModuleData = $aAvailableModules[$sModuleId];
$sName = $sModuleId;
$sVersion = $aModuleData['version_code'];
$aComments = array();
$aComments[] = 'Done by the setup program';
if ($aModuleData['mandatory'])
{
$aComments[] = 'Mandatory';
}
else
{
$aComments[] = 'Optional';
}
if ($aModuleData['visible'])
{
$aComments[] = 'Visible (during the setup)';
}
else
{
$aComments[] = 'Hidden (selected automatically)';
}
foreach ($aModuleData['dependencies'] as $sDependOn)
{
$aComments[] = "Depends on module: $sDependOn";
}
$sComment = implode("\n", $aComments);
$oInstallRec = new ModuleInstallation();
$oInstallRec->Set('name', $sName);
$oInstallRec->Set('version', $sVersion);
$oInstallRec->Set('comment', $sComment);
$oInstallRec->Set('parent_id', $iMainItopRecord);
$oInstallRec->DBInsertNoReload();
}
// Database is created, installation has been tracked into it
return true;
}
?>