mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
New implementation of the setup:
- All actions are performed asynchronously at the end of the setup - Supports upgrading and reinstalling (to add modules) SVN:trunk[1157]
This commit is contained in:
@@ -3549,9 +3549,9 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
public static function Startup($sConfigFile, $bModelOnly = false)
|
||||
public static function Startup($sConfigFile, $bModelOnly = false, $bUseCache = true)
|
||||
{
|
||||
self::LoadConfig($sConfigFile);
|
||||
self::LoadConfig($sConfigFile, $bUseCache);
|
||||
|
||||
if ($bModelOnly) return;
|
||||
|
||||
@@ -3573,10 +3573,10 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
public static function LoadConfig($sConfigFile)
|
||||
public static function LoadConfig($sConfigFile, $bUseCache = false)
|
||||
{
|
||||
self::$m_oConfig = new Config($sConfigFile);
|
||||
|
||||
|
||||
// Set log ASAP
|
||||
if (self::$m_oConfig->GetLogGlobal())
|
||||
{
|
||||
@@ -3655,7 +3655,7 @@ abstract class MetaModel
|
||||
$sCharacterSet = self::$m_oConfig->GetDBCharacterSet();
|
||||
$sCollation = self::$m_oConfig->GetDBCollation();
|
||||
|
||||
if (function_exists('apc_fetch'))
|
||||
if ($bUseCache && function_exists('apc_fetch'))
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
// Note: For versions of APC older than 3.0.17, fetch() accepts only one parameter
|
||||
@@ -3698,7 +3698,7 @@ abstract class MetaModel
|
||||
self::InitClasses($sTablePrefix);
|
||||
|
||||
$oKPI->ComputeAndReport('Initialization of Data model structures');
|
||||
if (function_exists('apc_store'))
|
||||
if ($bUseCache && function_exists('apc_store'))
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
|
||||
@@ -4123,12 +4123,11 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
public static function GetCacheEntries()
|
||||
public static function GetCacheEntries($sAppIdentity)
|
||||
{
|
||||
if (!function_exists('apc_cache_info')) return array();
|
||||
|
||||
$aCacheUserData = apc_cache_info('user');
|
||||
$sAppIdentity = MetaModel::GetConfig()->Get('session_name');
|
||||
$sPrefix = $sAppIdentity.'-';
|
||||
|
||||
$aEntries = array();
|
||||
@@ -4144,14 +4143,14 @@ abstract class MetaModel
|
||||
return $aEntries;
|
||||
}
|
||||
|
||||
public static function ResetCache()
|
||||
public static function ResetCache(Config $oConfig)
|
||||
{
|
||||
if (!function_exists('apc_delete')) return;
|
||||
|
||||
$sAppIdentity = MetaModel::GetConfig()->Get('session_name');
|
||||
$sAppIdentity = $oConfig->Get('session_name');
|
||||
Dict::ResetCache($sAppIdentity);
|
||||
|
||||
foreach(self::GetCacheEntries() as $sKey => $aAPCInfo)
|
||||
foreach(self::GetCacheEntries($sAppIdentity) as $sKey => $aAPCInfo)
|
||||
{
|
||||
$sAPCKey = $aAPCInfo['info'];
|
||||
apc_delete($sAPCKey);
|
||||
|
||||
@@ -75,11 +75,12 @@ class CreateITILProfilesInstaller extends ModuleInstallerAPI
|
||||
return $oConfiguration;
|
||||
}
|
||||
|
||||
public static function AfterDatabaseCreation(Config $oConfiguration)
|
||||
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
self::ComputeITILProfiles();
|
||||
//self::ComputeBasicProfiles();
|
||||
self::DoCreateProfiles();
|
||||
$bFirstInstall = empty($sPreviousVersion);
|
||||
self::DoCreateProfiles($bFirstInstall);
|
||||
UserRights::FlushPrivileges(true /* reset admin cache */);
|
||||
}
|
||||
|
||||
@@ -298,10 +299,14 @@ class CreateITILProfilesInstaller extends ModuleInstallerAPI
|
||||
DBObject::BulkInsertFlush();
|
||||
}
|
||||
|
||||
public static function DoCreateProfiles()
|
||||
public static function DoCreateProfiles($bFirstInstall = true)
|
||||
{
|
||||
URP_Profiles::DoCreateAdminProfile();
|
||||
URP_Profiles::DoCreateUserPortalProfile();
|
||||
if ($bFirstInstall)
|
||||
{
|
||||
// Makae sure we create these special profiles only once
|
||||
URP_Profiles::DoCreateAdminProfile();
|
||||
URP_Profiles::DoCreateUserPortalProfile();
|
||||
}
|
||||
|
||||
foreach(self::$m_aProfiles as $sName => $aProfileData)
|
||||
{
|
||||
|
||||
@@ -24,16 +24,26 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* This page is called to load "asynchronously" some xml file into the database
|
||||
* This page is called to perform "asynchronously" the setup actions
|
||||
* parameters
|
||||
* 'file' string Name of the file to load
|
||||
* 'session_status' string 'start', 'continue' or 'end'
|
||||
* 'percent' integer 0..100 the percentage of completion once the file has been loaded
|
||||
* 'operation': one of 'update_db_schema', 'after_db_creation', 'file'
|
||||
*
|
||||
* if 'operation' == 'update_db_schema':
|
||||
* 'mode': install | upgrade
|
||||
*
|
||||
* if 'operation' == 'after_db_creation':
|
||||
* 'mode': install | upgrade
|
||||
*
|
||||
* if 'operation' == 'file':
|
||||
* 'file': string Name of the file to load
|
||||
* 'session_status': string 'start', 'continue' or 'end'
|
||||
* 'percent': integer 0..100 the percentage of completion once the file has been loaded
|
||||
*/
|
||||
define('SAFE_MINIMUM_MEMORY', 32*1024*1024);
|
||||
require_once('../approot.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/setup/setuppage.class.inc.php');
|
||||
require_once(APPROOT.'/setup/moduleinstaller.class.inc.php');
|
||||
|
||||
$sMemoryLimit = trim(ini_get('memory_limit'));
|
||||
if (empty($sMemoryLimit))
|
||||
@@ -78,7 +88,24 @@ function FatalErrorCatcher($sOutput)
|
||||
}
|
||||
return $sOutput;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Helper function to create and administrator account for iTop
|
||||
* @return boolean true on success, false otherwise
|
||||
*/
|
||||
function CreateAdminAccount(Config $oConfig, $sAdminUser, $sAdminPwd, $sLanguage)
|
||||
{
|
||||
SetupWebPage::log_info('CreateAdminAccount');
|
||||
|
||||
if (UserRights::CreateAdministrator($sAdminUser, $sAdminPwd, $sLanguage))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//Define some bogus, invalid HTML tags that no sane
|
||||
//person would ever put in an actual document and tell
|
||||
//PHP to delimit fatal error warnings with them.
|
||||
@@ -104,50 +131,128 @@ header("Expires: Fri, 17 Jul 1970 05:00:00 GMT"); // Date in the past
|
||||
/**
|
||||
* Main program
|
||||
*/
|
||||
$sFileName = Utils::ReadParam('file', '');
|
||||
$sSessionStatus = Utils::ReadParam('session_status', '');
|
||||
$iPercent = (integer)Utils::ReadParam('percent', 0);
|
||||
SetupWebPage::log_info("Loading file: $sFileName");
|
||||
|
||||
$sOperation = Utils::ReadParam('operation', '');
|
||||
try
|
||||
{
|
||||
if (empty($sFileName) || !file_exists($sFileName))
|
||||
switch($sOperation)
|
||||
{
|
||||
throw(new Exception("File $sFileName does not exist"));
|
||||
}
|
||||
|
||||
case 'update_db_schema':
|
||||
SetupWebPage::log_info("Update Database Schema.");
|
||||
InitDataModel(TMP_CONFIG_FILE, true); // load data model and connect to the database
|
||||
$sMode = Utils::ReadParam('mode', 'install');
|
||||
$sSelectedModules = Utils::ReadParam('selected_modules', '');
|
||||
$aSelectedModules = explode(',', $sSelectedModules);
|
||||
if(!CreateDatabaseStructure(MetaModel::GetConfig(), $aSelectedModules, $sMode))
|
||||
{
|
||||
throw(new Exception("Failed to create/upgrade the database structure"));
|
||||
}
|
||||
SetupWebPage::log_info("Database Schema Successfully Updated.");
|
||||
break;
|
||||
|
||||
case 'after_db_create':
|
||||
SetupWebPage::log_info('After Database Creation');
|
||||
$sMode = Utils::ReadParam('mode', 'install');
|
||||
$sSelectedModules = Utils::ReadParam('selected_modules', '');
|
||||
$aSelectedModules = explode(',', $sSelectedModules);
|
||||
InitDataModel(TMP_CONFIG_FILE, true); // load data model and connect to the database
|
||||
|
||||
// Perform here additional DB setup... profiles, etc...
|
||||
|
||||
$aAvailableModules = AnalyzeInstallation(MetaModel::GetConfig());
|
||||
|
||||
$oDataLoader = new XMLDataLoader(TMP_CONFIG_FILE); // When called by the wizard, the final config is not yet there
|
||||
if ($sSessionStatus == 'start')
|
||||
{
|
||||
$oChange = MetaModel::NewObject("CMDBChange");
|
||||
$oChange->Set("date", time());
|
||||
$oChange->Set("userinfo", "Initialization");
|
||||
$iChangeId = $oChange->DBInsert();
|
||||
SetupWebPage::log_info("starting data load session");
|
||||
$oDataLoader->StartSession($oChange);
|
||||
}
|
||||
$aStructureDataFiles = array();
|
||||
$aSampleDataFiles = array();
|
||||
|
||||
foreach($aAvailableModules as $sModuleId => $aModule)
|
||||
{
|
||||
if (($sModuleId != 'iTop') && in_array($sModuleId, $aSelectedModules) &&
|
||||
isset($aAvailableModules[$sModuleId]['installer']) )
|
||||
{
|
||||
$sModuleInstallerClass = $aAvailableModules[$sModuleId]['installer'];
|
||||
SetupWebPage::log_info("Calling Module Handler: $sModuleInstallerClass::AfterDatabaseCreation(oConfig, {$aModule['version_db']}, {$aModule['version_code']})");
|
||||
// The validity of the sModuleInstallerClass has been established in BuildConfig()
|
||||
$aCallSpec = array($sModuleInstallerClass, 'AfterDatabaseCreation');
|
||||
call_user_func_array($aCallSpec, array(MetaModel::GetConfig(), $aModule['version_db'], $aModule['version_code']));
|
||||
}
|
||||
}
|
||||
|
||||
$oDataLoader->LoadFile($sFileName);
|
||||
$sResult = sprintf("loading of %s done. (Overall %d %% completed).", basename($sFileName), $iPercent);
|
||||
//echo $sResult;
|
||||
SetupWebPage::log_info($sResult);
|
||||
|
||||
if ($sSessionStatus == 'end')
|
||||
{
|
||||
$oDataLoader->EndSession();
|
||||
SetupWebPage::log_info("ending data load session");
|
||||
if (!RecordInstallation(MetaModel::GetConfig(), $aSelectedModules))
|
||||
{
|
||||
throw(new Exception("Failed to record the installation information"));
|
||||
}
|
||||
|
||||
if($sMode == 'install')
|
||||
{
|
||||
// Create the admin user only in case of installation
|
||||
$sAdminUser = Utils::ReadParam('auth_user', '');
|
||||
$sAdminPwd = Utils::ReadParam('auth_pwd', '');
|
||||
$sLanguage = Utils::ReadParam('language', '');
|
||||
if (!CreateAdminAccount(MetaModel::GetConfig(), $sAdminUser, $sAdminPwd, $sLanguage))
|
||||
{
|
||||
throw(new Exception("Failed to create the administrator account '$sAdminUser'"));
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupWebPage::log_info("Administrator account '$sAdminUser' created.");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'load_data': // Load data files
|
||||
$sFileName = Utils::ReadParam('file', '');
|
||||
$sSessionStatus = Utils::ReadParam('session_status', '');
|
||||
$iPercent = (integer)Utils::ReadParam('percent', 0);
|
||||
SetupWebPage::log_info("Loading file: $sFileName");
|
||||
if (empty($sFileName) || !file_exists($sFileName))
|
||||
{
|
||||
throw(new Exception("File $sFileName does not exist"));
|
||||
}
|
||||
|
||||
$oDataLoader = new XMLDataLoader(TMP_CONFIG_FILE); // When called by the wizard, the final config is not yet there
|
||||
if ($sSessionStatus == 'start')
|
||||
{
|
||||
$oChange = MetaModel::NewObject("CMDBChange");
|
||||
$oChange->Set("date", time());
|
||||
$oChange->Set("userinfo", "Initialization");
|
||||
$iChangeId = $oChange->DBInsert();
|
||||
SetupWebPage::log_info("starting data load session");
|
||||
$oDataLoader->StartSession($oChange);
|
||||
}
|
||||
|
||||
$oDataLoader->LoadFile($sFileName);
|
||||
$sResult = sprintf("loading of %s done. (Overall %d %% completed).", basename($sFileName), $iPercent);
|
||||
SetupWebPage::log_info($sResult);
|
||||
|
||||
if ($sSessionStatus == 'end')
|
||||
{
|
||||
$oDataLoader->EndSession();
|
||||
SetupWebPage::log_info("ending data load session");
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw(new Exception("Error unsupported operation '$sOperation'"));
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
header("HTTP/1.0 500 Internal server error.");
|
||||
echo "<p>An error happened while loading the data</p>\n";
|
||||
echo "<p>An error happened while processing the installation:</p>\n";
|
||||
echo '<p>'.$e."</p>\n";
|
||||
SetupWebPage::log_error("An error happened while loading the data. ".$e);
|
||||
SetupWebPage::log_error("An error happened while processing the installation: ".$e);
|
||||
}
|
||||
|
||||
if (function_exists('memory_get_peak_usage'))
|
||||
{
|
||||
SetupWebPage::log_info("loading file '$sFileName', peak memory usage. ".memory_get_peak_usage());
|
||||
if ($sOperation == 'file')
|
||||
{
|
||||
SetupWebPage::log_info("loading file '$sFileName', peak memory usage. ".memory_get_peak_usage());
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupWebPage::log_info("operation '$sOperation', peak memory usage. ".memory_get_peak_usage());
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
2843
setup/index.php
2843
setup/index.php
File diff suppressed because it is too large
Load Diff
@@ -31,7 +31,11 @@ abstract class ModuleInstallerAPI
|
||||
return $oConfiguration;
|
||||
}
|
||||
|
||||
public static function AfterDatabaseCreation(Config $oConfiguration)
|
||||
public static function BeforeDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
}
|
||||
|
||||
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
132
setup/setup.js
132
setup/setup.js
@@ -7,7 +7,7 @@ function NameIsValid(name)
|
||||
|
||||
function DoGoBack(iStep)
|
||||
{
|
||||
$('input[name=operation]').val('step'+(iStep-1));
|
||||
$('input[name=operation]').val('step'+iStep);
|
||||
$('#theForm').submit(); // Submit the form
|
||||
return true;
|
||||
}
|
||||
@@ -17,6 +17,14 @@ function DoSubmit(sMsg, iStep)
|
||||
var bResult = true;
|
||||
switch(iStep)
|
||||
{
|
||||
case 0: // Select either install or upgrade or nothing to select...
|
||||
if ( ($("input:radio").length > 0) && ($("input:radio:checked").length < 1))
|
||||
{
|
||||
alert('Please select either install or upgrade');
|
||||
bResult = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1: // Licence agreement
|
||||
if ($('#licence_ok:checked').length < 1)
|
||||
{
|
||||
@@ -94,8 +102,11 @@ function DoSubmit(sMsg, iStep)
|
||||
}
|
||||
break;
|
||||
|
||||
case 6: // Asynchronous load of data
|
||||
bResult = DoLoadDataAsynchronous();
|
||||
case 6: // Sample data selection
|
||||
break;
|
||||
|
||||
case 7: // Display Summary: launch DoUpdateDBSchema to start the asynchronous update
|
||||
bResult = DoUpdateDBSchema();
|
||||
break;
|
||||
|
||||
// Email test page
|
||||
@@ -113,33 +124,108 @@ function DoSubmit(sMsg, iStep)
|
||||
return bResult;
|
||||
}
|
||||
|
||||
function DoUpdateDBSchema()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Call the asynchronous page that performs the creation/update of the DB Schema
|
||||
$('#log').html('');
|
||||
$('#setup').block({message: '<p>Updating DB schema...<br/><div id=\"progress\">0%</div></p>'});
|
||||
$('#progress').progression( {Current:5, Maximum: 100, aBackgroundImg: 'orange-progress.gif', aTextColor: '#000000'} );
|
||||
$('#log').load( 'ajax.dataloader.php',
|
||||
{
|
||||
'operation': 'update_db_schema',
|
||||
'selected_modules': GetSelectedModules(),
|
||||
'mode': $(':input[name=mode]').val()
|
||||
},
|
||||
DoUpdateProfiles, 'html');
|
||||
}
|
||||
catch(err)
|
||||
{
|
||||
alert('An exception occured: '+err);
|
||||
}
|
||||
return false; // Do NOT submit the form yet
|
||||
}
|
||||
|
||||
function DoUpdateProfiles(response, status, xhr)
|
||||
{
|
||||
if (status == 'error')
|
||||
{
|
||||
$('#setup').unblock();
|
||||
return; // An error occurred !
|
||||
}
|
||||
try
|
||||
{
|
||||
// Call the asynchronous page that performs the creation/update of the DB Schema
|
||||
$('#log').html('');
|
||||
$('#setup').block({message: '<p>Updating Profiles...<br/><div id=\"progress\">0%</div></p>'});
|
||||
$('#progress').progression( {Current:40, Maximum: 100, aBackgroundImg: 'orange-progress.gif', aTextColor: '#000000'} );
|
||||
$('#log').load( 'ajax.dataloader.php',
|
||||
{
|
||||
'operation': 'after_db_create',
|
||||
'selected_modules': GetSelectedModules(),
|
||||
'mode': $(':input[name=mode]').val(),
|
||||
'auth_user': $(':input[name=auth_user]').val(),
|
||||
'auth_pwd': $(':input[name=auth_pwd]').val(),
|
||||
'language': $(':input[name=language]').val()
|
||||
},
|
||||
DoLoadDataAsynchronous, 'html');
|
||||
// $('#log').ajaxError(
|
||||
// function(e, xhr, settings, exception)
|
||||
// {
|
||||
// bStopAysncProcess = true;
|
||||
// alert('Fatal error detected: '+ xhr.responseText);
|
||||
// $('#log').append(xhr.responseText);
|
||||
// $('#setup').unblock();
|
||||
// } );
|
||||
}
|
||||
catch(err)
|
||||
{
|
||||
alert('An exception occured: '+err);
|
||||
}
|
||||
return true; // Continue loading the data
|
||||
}
|
||||
|
||||
var aFilesToLoad = new Array();
|
||||
var iCounter = 0;
|
||||
|
||||
function DoLoadDataAsynchronous()
|
||||
function DoLoadDataAsynchronous(response, status, xhr)
|
||||
{
|
||||
if (status == 'error')
|
||||
{
|
||||
$('#setup').unblock();
|
||||
return; // An error occurred !
|
||||
}
|
||||
try
|
||||
{
|
||||
// The array aFilesToLoad is populated by this function dynamically written on the server
|
||||
PopulateDataFilesList();
|
||||
iCounter = 0;
|
||||
$('#log').html('');
|
||||
$('#setup').block({message: '<p>Loading data...<br/><div id=\"progress\">0%</div></p>'});
|
||||
$('#progress').progression( {Current:0, Maximum: 100, aBackgroundImg: 'orange-progress.gif', aTextColor: '#000000'} );
|
||||
$('#log').ajaxError(
|
||||
function(e, xhr, settings, exception)
|
||||
{
|
||||
alert('Fatal error detected: '+ xhr.responseText);
|
||||
$('#log').append(xhr.responseText);
|
||||
$('#setup').unblock();
|
||||
} );
|
||||
iCurrent = 60;
|
||||
if (aFilesToLoad.length == 0)
|
||||
{
|
||||
$('#progress').progression( {Current: 100} );
|
||||
}
|
||||
else
|
||||
{
|
||||
$('#log').html('');
|
||||
$('#setup').block({message: '<p>Loading data...<br/><div id=\"progress\">0%</div></p>'});
|
||||
$('#progress').progression( {Current: 60, Maximum: 100, aBackgroundImg: 'orange-progress.gif', aTextColor: '#000000'} );
|
||||
// $('#log').ajaxError(
|
||||
// function(e, xhr, settings, exception)
|
||||
// {
|
||||
// bStopAysncProcess = true;
|
||||
// alert('Fatal error detected: '+ xhr.responseText);
|
||||
// $('#log').append(xhr.responseText);
|
||||
// $('#setup').unblock();
|
||||
// } );
|
||||
}
|
||||
LoadNextDataFile('', '', '');
|
||||
}
|
||||
catch(err)
|
||||
{
|
||||
alert('An exception occured: '+err);
|
||||
}
|
||||
return false; // Stop here for now
|
||||
return true; // Continue
|
||||
}
|
||||
|
||||
function LoadNextDataFile(response, status, xhr)
|
||||
@@ -168,16 +254,17 @@ function LoadNextDataFile(response, status, xhr)
|
||||
{
|
||||
sSessionStatus = 'continue';
|
||||
}
|
||||
iPercent = Math.round((100.0 * (1+iCounter)) / aFilesToLoad.length);
|
||||
iPercent = 60+Math.round((40.0 * (1+iCounter)) / aFilesToLoad.length);
|
||||
sFileName = aFilesToLoad[iCounter];
|
||||
//alert('Loading file '+sFileName+' ('+iPercent+' %) - '+sSessionStatus);
|
||||
$("#progress").progression({ Current: iPercent });
|
||||
$("#progress").progression({ Current: iPercent, Maximum: 100, aBackgroundImg: 'orange-progress.gif', aTextColor: '#000000' });
|
||||
iCounter++;
|
||||
$('#log').load( 'ajax.dataloader.php', { 'file': sFileName, 'percent': iPercent, 'session_status': sSessionStatus }, LoadNextDataFile, 'html');
|
||||
$('#log').load( 'ajax.dataloader.php', { 'operation': 'load_data', 'file': sFileName, 'percent': iPercent, 'session_status': sSessionStatus }, LoadNextDataFile, 'html');
|
||||
}
|
||||
else
|
||||
{
|
||||
// We're done
|
||||
$("#progress").progression({ Current: 100, Maximum: 100, aBackgroundImg: 'orange-progress.gif', aTextColor: '#000000' });
|
||||
$('#setup').unblock();
|
||||
$('#GoToNextStep').submit(); // Use the hidden form to navigate to the next step
|
||||
}
|
||||
@@ -187,3 +274,10 @@ function LoadNextDataFile(response, status, xhr)
|
||||
alert('An exception occurred: '+err);
|
||||
}
|
||||
}
|
||||
|
||||
function GetSelectedModules()
|
||||
{
|
||||
var aModules = new Array();
|
||||
$(':input[name^=module]').each(function() { aModules.push($(this).val()); } );
|
||||
return aModules.join(',');
|
||||
}
|
||||
@@ -25,6 +25,11 @@
|
||||
|
||||
require_once(APPROOT."/application/nicewebpage.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);
|
||||
|
||||
date_default_timezone_set('Europe/Paris');
|
||||
class SetupWebPage extends NiceWebPage
|
||||
{
|
||||
@@ -86,6 +91,11 @@ h2 {
|
||||
color: #000;
|
||||
font-size: 14pt;
|
||||
}
|
||||
h3 {
|
||||
color: #1C94C4;
|
||||
font-size: 12pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
.next {
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
@@ -262,7 +272,7 @@ table.formTable {
|
||||
static $m_aFilesList = array('datamodel', 'webservice', 'dictionary', 'data.struct', 'data.sample');
|
||||
|
||||
static $m_sModulePath = null;
|
||||
public function SetModulePath($sModulePath)
|
||||
public static function SetModulePath($sModulePath)
|
||||
{
|
||||
self::$m_sModulePath = $sModulePath;
|
||||
}
|
||||
@@ -297,7 +307,7 @@ table.formTable {
|
||||
}
|
||||
}
|
||||
}
|
||||
public function GetModules()
|
||||
public static function GetModules($oP = null)
|
||||
{
|
||||
// Order the modules to take into account their inter-dependencies
|
||||
$aDependencies = array();
|
||||
@@ -336,7 +346,14 @@ table.formTable {
|
||||
$sHtml.= "<li>{$aModule['label']} (id: $sId), depends on: ".implode(', ', $aDeps)."</li>";
|
||||
}
|
||||
$sHtml .= "</ul>\n";
|
||||
$this->warning($sHtml);
|
||||
if (is_object($oP))
|
||||
{
|
||||
$oP->warning($sHtml);
|
||||
}
|
||||
else
|
||||
{
|
||||
self::log_warning($sHtml);
|
||||
}
|
||||
}
|
||||
// Return the ordered list, so that the dependencies are met...
|
||||
$aResult = array();
|
||||
@@ -346,6 +363,370 @@ table.formTable {
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
} // End of class
|
||||
|
||||
/**
|
||||
* Helper function to initialize the ORM and load the data model
|
||||
* from the given file
|
||||
* @param $sConfigFileName string The name of the configuration file to load
|
||||
* @param $bModelOnly boolean Whether or not to allow loading a data model with no corresponding DB
|
||||
* @return none
|
||||
*/
|
||||
function InitDataModel($sConfigFileName, $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');
|
||||
SetupWebPage::log_info("MetaModel::Startup from file '$sConfigFileName' (ModelOnly = $bModelOnly)");
|
||||
|
||||
if ($bUseCache)
|
||||
{
|
||||
// Reset the cache for the first use !
|
||||
$oConfig = new Config($sConfigFileName, false);
|
||||
MetaModel::ResetCache($oConfig);
|
||||
}
|
||||
|
||||
MetaModel::Startup($sConfigFileName, $bModelOnly, $bUseCache);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search (on the disk) for all defined iTop modules, load them and returns the list (as an array)
|
||||
* of the possible iTop modules to install
|
||||
* @param none
|
||||
* @return Hash A big array moduleID => ModuleData
|
||||
*/
|
||||
function GetAvailableModules($oP = null)
|
||||
{
|
||||
clearstatcache();
|
||||
ListModuleFiles('modules');
|
||||
return SetupWebPage::GetModules($oP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Analyzes the current installation and the possibilities
|
||||
*
|
||||
* @param $oP SetupWebPage For accessing the list of loaded modules
|
||||
* @param $sDBServer string Name/IP of the DB server
|
||||
* @param $sDBUser username for the DB server connection
|
||||
* @param $sDBPwd password for the DB server connection
|
||||
* @param $sDBName Name of the database instance
|
||||
* @param $sDBPrefix Prefix for the iTop tables in the DB instance
|
||||
* @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)
|
||||
{
|
||||
$aRes = array(
|
||||
'iTop' => array(
|
||||
'version_db' => '',
|
||||
'version_code' => ITOP_VERSION.'.'.ITOP_REVISION,
|
||||
)
|
||||
);
|
||||
|
||||
$aModules = GetAvailableModules();
|
||||
foreach($aModules as $sModuleId => $aModuleInfo)
|
||||
{
|
||||
list($sModuleName, $sModuleVersion) = 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
|
||||
//$aInstall['parent_id']; // unsused
|
||||
$iInstalled = strtotime($aInstall['installed']);
|
||||
$sModuleName = $aInstall['name'];
|
||||
$sModuleVersion = $aInstall['version'];
|
||||
|
||||
if ($sModuleName == 'itop')
|
||||
{
|
||||
$aRes['iTop']['version_db'] = $sModuleVersion;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (array_key_exists($sModuleName, $aInstallByModule))
|
||||
{
|
||||
if ($iInstalled < $aInstallByModule[$sModuleName]['installed'])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
$aInstallByModule[$sModuleName]['installed'] = $iInstalled;
|
||||
$aInstallByModule[$sModuleName]['version'] = $sModuleVersion;
|
||||
}
|
||||
|
||||
// Adjust the list of proposed modules
|
||||
//
|
||||
foreach ($aInstallByModule as $sModuleName => $aModuleDB)
|
||||
{
|
||||
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 interpret the name of a module
|
||||
* @param $sModuleId string Identifier of the module, in the form 'name/version'
|
||||
* @return array(name, version)
|
||||
*/
|
||||
function GetModuleName($sModuleId)
|
||||
{
|
||||
if (preg_match('!^(.*)/(.*)$!', $sModuleId, $aMatches))
|
||||
{
|
||||
$sName = $aMatches[1];
|
||||
$sVersion = $aMatches[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sName = $sModuleId;
|
||||
$sVersion = "";
|
||||
}
|
||||
return array($sName, $sVersion);
|
||||
}
|
||||
/**
|
||||
* Helper function to create the database structure
|
||||
* @return boolean true on success, false otherwise
|
||||
*/
|
||||
function CreateDatabaseStructure(Config $oConfig, $aSelectedModules, $sMode)
|
||||
{
|
||||
if (strlen($oConfig->GetDBSubname()) > 0)
|
||||
{
|
||||
SetupWebPage::log_info("Creating the structure in '".$oConfig->GetDBName()."' (table names prefixed by '".$oConfig->GetDBSubname()."').");
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupWebPage::log_info("Creating the structure in '".$oConfig->GetDBSubname()."'.");
|
||||
}
|
||||
|
||||
//MetaModel::CheckDefinitions();
|
||||
if ($sMode == 'install')
|
||||
{
|
||||
if (!MetaModel::DBExists(/* bMustBeComplete */ false))
|
||||
{
|
||||
MetaModel::DBCreate();
|
||||
SetupWebPage::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();
|
||||
SetupWebPage::log_ok("Database structure successfully created.");
|
||||
}
|
||||
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)
|
||||
{
|
||||
// Record main installation
|
||||
$oInstallRec = new ModuleInstallation();
|
||||
$oInstallRec->Set('name', 'itop');
|
||||
$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);
|
||||
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;
|
||||
}
|
||||
|
||||
function ListModuleFiles($sRelDir)
|
||||
{
|
||||
$sDirectory = APPROOT.'/'.$sRelDir;
|
||||
//echo "<p>$sDirectory</p>\n";
|
||||
if ($hDir = opendir($sDirectory))
|
||||
{
|
||||
// This is the correct way to loop over the directory. (according to the documentation)
|
||||
while (($sFile = readdir($hDir)) !== false)
|
||||
{
|
||||
$aMatches = array();
|
||||
if (is_dir($sDirectory.'/'.$sFile))
|
||||
{
|
||||
if (($sFile != '.') && ($sFile != '..') && ($sFile != '.svn'))
|
||||
{
|
||||
ListModuleFiles($sRelDir.'/'.$sFile);
|
||||
}
|
||||
}
|
||||
else if (preg_match('/^module\.(.*).php$/i', $sFile, $aMatches))
|
||||
{
|
||||
SetupWebPage::SetModulePath($sRelDir);
|
||||
try
|
||||
{
|
||||
//echo "<p>Loading: $sDirectory/$sFile...</p>\n";
|
||||
require_once($sDirectory.'/'.$sFile);
|
||||
//echo "<p>Done.</p>\n";
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
// Continue...
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($hDir);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Data directory (".$sDirectory.") not found or not readable.");
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
Reference in New Issue
Block a user