diff --git a/application/controllers/ModulesController.php b/application/controllers/ModulesController.php
new file mode 100755
index 000000000..f8f40a3b3
--- /dev/null
+++ b/application/controllers/ModulesController.php
@@ -0,0 +1,47 @@
+manager = Icinga::app()->moduleManager();
+ }
+
+ public function indexAction()
+ {
+ $this->view->modules = $this->manager->select()
+ ->from('modules')
+ ->order('name');
+ $this->render('overview');
+ }
+
+ public function overviewAction()
+ {
+ $this->indexAction();
+
+ }
+
+ public function enableAction()
+ {
+ $this->manager->enableModule($this->_getParam('name'));
+ $this->redirectNow('modules/overview?_render=body');
+ }
+
+ public function disableAction()
+ {
+ $this->manager->disableModule($this->_getParam('name'));
+ $this->redirectNow('modules/overview?_render=body');
+ }
+
+}
diff --git a/application/views/scripts/inline.phtml b/application/views/scripts/inline.phtml
new file mode 100644
index 000000000..24e5f00ce
--- /dev/null
+++ b/application/views/scripts/inline.phtml
@@ -0,0 +1,3 @@
+= $this->layout()->moduleStart ?>
+= $this->layout()->content ?>
+= $this->layout()->moduleEnd ?>
diff --git a/application/views/scripts/mixedPagination.phtml b/application/views/scripts/mixedPagination.phtml
new file mode 100755
index 000000000..7b2b23570
--- /dev/null
+++ b/application/views/scripts/mixedPagination.phtml
@@ -0,0 +1,61 @@
+ if ($this->pageCount > 1): ?>
+preserve)) {
+ $preserve = $this->preserve;
+} else {
+ $preserve = array();
+}
+
+$fromto = t('%d to %d of %d');
+$total = $this->totalItemCount;
+?>
+
+ endif ?>
diff --git a/application/views/scripts/modules/overview.phtml b/application/views/scripts/modules/overview.phtml
new file mode 100644
index 000000000..cc651c78f
--- /dev/null
+++ b/application/views/scripts/modules/overview.phtml
@@ -0,0 +1,38 @@
+modules->limit(10);
+$modules = $this->modules->paginate();
+
+?>
+Installed Modules
+= $this->paginationControl($modules, null, null, array(
+ 'preserve' => $this->preserve
+)); ?>
+
+
+ foreach ($modules as $module): ?>
+
+
+ if ($module->enabled): ?>
+ = $this->qlink(
+ $module->name,
+ 'modules/disable',
+ array('name' => $module->name),
+ array('target'=>'body')
+ ) ?>
+ else: ?>
+ = $this->qlink(
+ $module->name,
+ 'modules/enable',
+ array('name' => $module->name),
+ array('target'=>'body')
+ ) ?>
+ endif ?>
+ (=
+ $module->enabled
+ ? ($module->loaded ? 'enabled' : 'failed')
+ : 'disabled'
+ ?>) |
+
+ endforeach ?>
+
+
diff --git a/application/views/scripts/modules/show.phtml b/application/views/scripts/modules/show.phtml
new file mode 100644
index 000000000..38d5cf050
--- /dev/null
+++ b/application/views/scripts/modules/show.phtml
@@ -0,0 +1,24 @@
+container('modules-container',array(
+ "class" => "expanded_absolute"
+))->beginContent() ?>
+
+
+
+ Module |
+ Type |
+ Active |
+
+
+
+ modules as $module): ?>
+
+ = $module["name"] ?> |
+ = $module["type"] ?> |
+ = $module["active"] ?> |
+
+
+
+
+
+
+= $container; ?>
\ No newline at end of file
diff --git a/library/Icinga/Application/ApplicationBootstrap.php b/library/Icinga/Application/ApplicationBootstrap.php
index dc40cb646..715850ee5 100755
--- a/library/Icinga/Application/ApplicationBootstrap.php
+++ b/library/Icinga/Application/ApplicationBootstrap.php
@@ -18,6 +18,7 @@ use Icinga\Exception\ConfigurationError;
* Usage example for CLI:
*
* use Icinga\Application\Cli;
+
* Cli::start();
*
*
@@ -99,7 +100,7 @@ abstract class ApplicationBootstrap
public function moduleManager()
{
if ($this->moduleManager === null) {
- $this->moduleManager = new ModuleManager($this);
+ $this->moduleManager = new ModuleManager($this, "/etc/icinga2/modules_enabled");
}
return $this->moduleManager;
}
diff --git a/library/Icinga/Application/Modules/Manager.php b/library/Icinga/Application/Modules/Manager.php
index 45f4c89aa..4061a2421 100644
--- a/library/Icinga/Application/Modules/Manager.php
+++ b/library/Icinga/Application/Modules/Manager.php
@@ -6,6 +6,7 @@ use Icinga\Application\ApplicationBootstrap;
use Icinga\Data\ArrayDatasource;
use Icinga\Web\Notification;
use Icinga\Exception\ConfigurationError;
+use Icinga\Exception\SystemPermissionException;
// TODO: show whether enabling/disabling modules is allowed by checking enableDir
// perms
@@ -20,17 +21,20 @@ class Manager
protected $enableDir;
- public function __construct(ApplicationBootstrap $app)
+ public function __construct(ApplicationBootstrap $app, $dir = null)
{
$this->app = $app;
- $this->prepareEssentials();
+ if ($dir === null) {
+ $dir = $this->app->getConfig()->getConfigDir()
+ . '/enabledModules';
+ }
+ $this->prepareEssentials($dir);
$this->detectEnabledModules();
}
- protected function prepareEssentials()
+ protected function prepareEssentials($moduleDir)
{
- $this->enableDir = $this->app->getConfig()->getConfigDir()
- . '/enabledModules';
+ $this->enableDir = $moduleDir;
if (! file_exists($this->enableDir) || ! is_dir($this->enableDir)) {
throw new ProgrammingError(
@@ -99,13 +103,20 @@ class Manager
$target = $this->installedBaseDirs[$name];
$link = $this->enableDir . '/' . $name;
if (! is_writable($this->enableDir)) {
- Notification::error("I do not have permissions to enable modules");
+ throw new SystemPermissionException(
+ "Insufficient system permissions for enabling modules",
+ "write",
+ $this->enableDir
+ );
+ }
+ if (file_exists($link) && is_link($link)) {
return $this;
}
- if (@symlink($target, $link)) {
- Notification::success("The module $name has been enabled");
- } else {
- Notification::error("Enabling module $name failed");
+ if (!@symlink($target, $link)) {
+ $error = error_get_last();
+ if (strstr($error["message"], "File exists") === false) {
+ throw new SystemPermissionException($error["message"], "symlink", $link);
+ }
}
return $this;
}
@@ -116,16 +127,29 @@ class Manager
return $this;
}
if (! is_writable($this->enableDir)) {
- Notification::error("I do not have permissions to disable modules");
+ throw new SystemPermissionException("Can't write the module directory", "write", $this->enableDir);
return $this;
}
$link = $this->enableDir . '/' . $name;
+ if (!file_exists($link)) {
+ throw new ConfigurationError("The module $name could not be found, can't disable it");
+ }
+ if (!is_link($link)) {
+ throw new ConfigurationError(
+ "The module $name can't be disabled as this would delete the whole module. ".
+ "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"
+ );
+ }
+
if (file_exists($link) && is_link($link)) {
- if (@unlink($link)) {
- Notification::success("The module $name has been disabled");
- } else {
- Notification::error("Disabling module $name failed");
+ if (!@unlink($link)) {
+ $error = error_get_last();
+ throw new SystemPermissionException($error["message"], "unlink", $link);
}
+ } else {
+
}
return $this;
}
diff --git a/public/js/icinga/container.js b/public/js/icinga/container.js
index a64075b94..08d60f047 100755
--- a/public/js/icinga/container.js
+++ b/public/js/icinga/container.js
@@ -24,7 +24,7 @@
this.updateContainer = function(id,content,req) {
var target = id;
if (typeof id === "string") {
- target = $('div[container-id='+id+']');
+ target = this.getContainer(id);
}
var ctrl = $('.container-controls',target);
target.html(content);
@@ -100,6 +100,9 @@
};
this.getContainer = function(id) {
+ if(id == 'body') {
+ return $(document.body);
+ }
return $('div[container-id='+id+']');
};
@@ -111,4 +114,4 @@
return containerMgrInstance;
});
-})();
\ No newline at end of file
+})();
diff --git a/public/js/icinga/util/async.js b/public/js/icinga/util/async.js
index 8e015b45a..15a6be7df 100644
--- a/public/js/icinga/util/async.js
+++ b/public/js/icinga/util/async.js
@@ -10,7 +10,7 @@
};
var getDOMForDestination = function(destination) {
var target = destination;
- if(typeof destination === "string") {
+ if (typeof destination === "string") {
target = containerMgr.getContainer(destination)[0];
} else if(typeof destination.context !== "undefined") {
target = destination[0];
@@ -89,7 +89,7 @@
if(destination) {
pending.push({
request: req,
- DOM: getDOMForDestination(destination)
+ DOM: getDOMForDestination(destination)
});
req.destination = destination;
}