From 5d8081ad09b21cc436bb98f7c94aa83ae218b84a Mon Sep 17 00:00:00 2001 From: Matthias Jentsch Date: Wed, 22 Jan 2014 18:21:05 +0100 Subject: [PATCH] Add support for multiple module installation paths Read the module paths from the configuration file and add form fields to edit the path from the web interface. refs #4607 --- application/forms/Config/GeneralForm.php | 19 ++++++++-- config/config.ini.in | 12 +++--- .../Application/ApplicationBootstrap.php | 6 ++- .../Icinga/Application/Modules/Manager.php | 38 +++++++++++++++---- 4 files changed, 57 insertions(+), 18 deletions(-) diff --git a/application/forms/Config/GeneralForm.php b/application/forms/Config/GeneralForm.php index 61d86d920..376e0dbc0 100644 --- a/application/forms/Config/GeneralForm.php +++ b/application/forms/Config/GeneralForm.php @@ -203,13 +203,22 @@ class GeneralForm extends Form array( 'label' => 'Module Folder', 'required' => true, - 'helptext' => 'The moduleFolder directive is currently not used anywhere but ' - . 'configureable via the frontend and INI. With feature #4607 moduleFolder ' - . 'will be replaced with a configuration directive for locations of ' - . 'installed modules', + 'helptext' => 'The directory that contains the symlink to all enabled directories.', 'value' => $cfg->get('moduleFolder', $this->getConfigDir() . '/config/enabledModules') ) ); + $this->addElement( + 'text', + 'module_path', + array( + 'label' => 'Module Path', + 'required' => true, + 'helptext' => 'Contains the directories that will be searched for available modules, separated by ' . + ' colons. Modules that don\'t exist in these directories can still be symlinked in the module ' . + ' folder, but won\'t show up in the list of disabled modules.', + 'value' => $cfg->get('modulePath', realpath(ICINGA_APPDIR . '/../modules')) + ) + ); } /** @@ -382,9 +391,11 @@ class GeneralForm extends Form $cfg->global->environment = ($values['environment'] == 1) ? 'development' : 'production'; $cfg->global->timezone = $values['timezone']; $cfg->global->moduleFolder = $values['module_folder']; + $cfg->global->modulePath = $values['module_path']; $cfg->global->dateFormat = $values['date_format']; $cfg->global->timeFormat = $values['time_format']; + $cfg->preferences->type = $values['preferences_type']; if ($cfg->preferences->type === 'ini') { $cfg->preferences->configPath = $values['preferences_ini_path']; diff --git a/config/config.ini.in b/config/config.ini.in index 3868e5ca2..73324e865 100755 --- a/config/config.ini.in +++ b/config/config.ini.in @@ -3,14 +3,16 @@ environment = "development" timezone = "Europe/Berlin" indexModule = "monitoring" indexController = "dashboard" -; The moduleFolder directive is currently not used anywhere but configureable -; via the frontend and this file. With feature #4607 moduleFolder will -; be replaced with a configuration directive for locations of -; installed modules -moduleFolder = "@icingaweb_config_path@/enabledModules" dateFormat = "d/m/Y" timeFormat = "g:i A" +; The directory that contains the symlinks to all enabled directories. +moduleFolder = "@icingaweb_config_path@/enabledModules" + +; Contains the directories that will be searched for available modules. Modules that +; don't exist in these directories can still be symlinked in the module folder, but +; won't show up in the list of disabled modules. +; modulePath = "/vagrant/modules:/usr/share/icingaweb/modules" [logging] ; General log diff --git a/library/Icinga/Application/ApplicationBootstrap.php b/library/Icinga/Application/ApplicationBootstrap.php index 64485841e..95b218e80 100755 --- a/library/Icinga/Application/ApplicationBootstrap.php +++ b/library/Icinga/Application/ApplicationBootstrap.php @@ -354,6 +354,11 @@ abstract class ApplicationBootstrap */ protected function loadEnabledModules() { + $this->moduleManager = new ModuleManager( + $this, + $this->config->global->get('moduleFolder', $this->getConfigDir() . '/enabledModules'), + explode(':', $this->config->global->get('modulePath', ICINGA_APPDIR . '/../modules')) + ); try { $this->moduleManager->loadEnabledModules(); } catch (Exception $e) { @@ -362,7 +367,6 @@ abstract class ApplicationBootstrap $e->getMessage() ); } - return $this; } diff --git a/library/Icinga/Application/Modules/Manager.php b/library/Icinga/Application/Modules/Manager.php index 0583305e0..757772d7d 100644 --- a/library/Icinga/Application/Modules/Manager.php +++ b/library/Icinga/Application/Modules/Manager.php @@ -104,11 +104,16 @@ class Manager $this->app = $app; if (empty($availableDirs)) { $availableDirs = array(realpath(ICINGA_APPDIR . '/../modules')); + } else { + foreach($availableDirs as $key => $dir) { + $dir[$key] = realpath($dir); + } } $this->modulePaths = $availableDirs; if ($enabledDir === null) { $enabledDir = $this->app->getConfigDir() . '/enabledModules'; } + $enabledDir = realpath($enabledDir); $this->enableDir = $enabledDir; } @@ -293,7 +298,7 @@ class Manager 'Could not disable module. The module "' . $name . '" is not a symlink. ' . 'It looks like you have installed this module manually and moved it to your module folder. ' . 'In order to dynamically enable and disable modules, you have to create a symlink to ' - . 'the enabled_modules folder' + . 'the enabled_modules folder.' ); } @@ -424,15 +429,21 @@ class Manager */ public function getModuleInfo() { - $installed = $this->listInstalledModules(); - $info = array(); - if ($installed === null) { - return $info; + + $enabled = $this->listEnabledModules(); + foreach ($enabled as $name) { + $info[$name] = (object) array( + 'name' => $name, + 'path' => $this->enabledDirs[$name], + 'enabled' => true, + 'loaded' => $this->hasLoaded($name) + ); } + $installed = $this->listInstalledModules(); foreach ($installed as $name) { - $info[] = (object) array( + $info[$name] = (object) array( 'name' => $name, 'path' => $this->installedBaseDirs[$name], 'enabled' => $this->hasEnabled($name), @@ -496,17 +507,28 @@ class Manager public function detectInstalledModules() { foreach ($this->modulePaths as $basedir) { + if (!file_exists($basedir)) { + Logger::warn('Module path "%s" does not exist.', $basedir); + continue; + } $fh = opendir($basedir); if ($fh === false) { return $this; } - while ($name = readdir($fh)) { if ($name[0] === '.') { continue; } if (is_dir($basedir . '/' . $name)) { - $this->installedBaseDirs[$name] = $basedir . '/' . $name; + if (!array_key_exists($name, $this->installedBaseDirs)) { + $this->installedBaseDirs[$name] = $basedir . '/' . $name; + } else { + Logger::warn( + 'Module "%s" already exists in installation path "%s" and is ignored.', + $basedir . '/' . $name, + $this->installedBaseDirs[$name] + ); + } } } }