Add clearstatcache and tests for ModuleManager
Added the clearstatcache call before enabling or disabling modules, as this prevents a 'File exists' error that occurs sometimes on symlink creation (even when the folder is empty). Also added tests for teh moduleManager refs #4092
This commit is contained in:
parent
fd489484e1
commit
c72fa101ed
|
@ -2,33 +2,39 @@
|
||||||
|
|
||||||
namespace Icinga\Application\Modules;
|
namespace Icinga\Application\Modules;
|
||||||
|
|
||||||
use Icinga\Application\ApplicationBootstrap;
|
|
||||||
use Icinga\Data\ArrayDatasource;
|
|
||||||
use Icinga\Web\Notification;
|
|
||||||
use Icinga\Exception\ConfigurationError;
|
use Icinga\Exception\ConfigurationError;
|
||||||
use Icinga\Exception\SystemPermissionException;
|
use Icinga\Exception\SystemPermissionException;
|
||||||
|
use Icinga\Exception\ProgrammingError;
|
||||||
|
|
||||||
// TODO: show whether enabling/disabling modules is allowed by checking enableDir
|
// TODO: show whether enabling/disabling modules is allowed by checking enableDir
|
||||||
// perms
|
// perms
|
||||||
|
|
||||||
class Manager
|
class Manager
|
||||||
{
|
{
|
||||||
protected $installedBaseDirs;
|
protected $installedBaseDirs = null;
|
||||||
protected $enabledDirs = array();
|
protected $enabledDirs = array();
|
||||||
protected $loadedModules = array();
|
protected $loadedModules = array();
|
||||||
protected $index;
|
protected $index;
|
||||||
protected $app;
|
protected $app;
|
||||||
|
|
||||||
protected $enableDir;
|
protected $enableDir;
|
||||||
|
protected $modulePaths = array();
|
||||||
public function __construct(ApplicationBootstrap $app, $dir = null)
|
/**
|
||||||
|
* @param $app : The applicaiton bootstrap. This one needs a properly defined interface
|
||||||
|
* In order to test it correctly, the application now only requires a stdClass
|
||||||
|
* @param $dir :
|
||||||
|
**/
|
||||||
|
public function __construct($app, $enabledDir = null, array $availableDirs = array())
|
||||||
{
|
{
|
||||||
$this->app = $app;
|
$this->app = $app;
|
||||||
if ($dir === null) {
|
if (empty($availableDirs)) {
|
||||||
$dir = $this->app->getConfig()->getConfigDir()
|
$availableDirs = array(ICINGA_APPDIR."/../modules");
|
||||||
|
}
|
||||||
|
$this->modulePaths = $availableDirs;
|
||||||
|
if ($enabledDir === null) {
|
||||||
|
$enabledDir = $this->app->getConfig()->getConfigDir()
|
||||||
. '/enabledModules';
|
. '/enabledModules';
|
||||||
}
|
}
|
||||||
$this->prepareEssentials($dir);
|
$this->prepareEssentials($enabledDir);
|
||||||
$this->detectEnabledModules();
|
$this->detectEnabledModules();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,10 +52,17 @@ class Manager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function select()
|
||||||
|
{
|
||||||
|
$source = new \Icinga\Data\ArrayDataSource($this->getModuleInfo());
|
||||||
|
return $source->select();
|
||||||
|
}
|
||||||
|
|
||||||
protected function detectEnabledModules()
|
protected function detectEnabledModules()
|
||||||
{
|
{
|
||||||
$fh = opendir($this->enableDir);
|
$fh = opendir($this->enableDir);
|
||||||
|
|
||||||
|
$this->enabledDirs = array();
|
||||||
while (false !== ($file = readdir($fh))) {
|
while (false !== ($file = readdir($fh))) {
|
||||||
|
|
||||||
if ($file[0] === '.') {
|
if ($file[0] === '.') {
|
||||||
|
@ -78,12 +91,18 @@ class Manager
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function loadModule($name)
|
public function loadModule($name, $moduleBase = null)
|
||||||
{
|
{
|
||||||
if ($this->hasLoaded($name)) {
|
if ($this->hasLoaded($name)) {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
$module = new Module($this->app, $name, $this->getModuleDir($name));
|
|
||||||
|
$module = null;
|
||||||
|
if ($moduleBase === null) {
|
||||||
|
$module = new Module($this->app, $name, $this->getModuleDir($name));
|
||||||
|
} else {
|
||||||
|
$module = new $moduleBase($this->app, $name, $this->getModuleDir($name));
|
||||||
|
}
|
||||||
$module->register();
|
$module->register();
|
||||||
$this->loadedModules[$name] = $module;
|
$this->loadedModules[$name] = $module;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -100,6 +119,7 @@ class Manager
|
||||||
);
|
);
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
clearstatcache(true);
|
||||||
$target = $this->installedBaseDirs[$name];
|
$target = $this->installedBaseDirs[$name];
|
||||||
$link = $this->enableDir . '/' . $name;
|
$link = $this->enableDir . '/' . $name;
|
||||||
if (! is_writable($this->enableDir)) {
|
if (! is_writable($this->enableDir)) {
|
||||||
|
@ -118,6 +138,7 @@ class Manager
|
||||||
throw new SystemPermissionException($error["message"], "symlink", $link);
|
throw new SystemPermissionException($error["message"], "symlink", $link);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
$this->enabledDirs[$name] = $link;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -151,6 +172,7 @@ class Manager
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
unset($this->enabledDirs[$name]);
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,12 +250,6 @@ class Manager
|
||||||
return $info;
|
return $info;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function select()
|
|
||||||
{
|
|
||||||
$ds = new ArrayDatasource($this->getModuleInfo());
|
|
||||||
return $ds->select();
|
|
||||||
}
|
|
||||||
|
|
||||||
public function listEnabledModules()
|
public function listEnabledModules()
|
||||||
{
|
{
|
||||||
return array_keys($this->enabledDirs);
|
return array_keys($this->enabledDirs);
|
||||||
|
@ -254,19 +270,19 @@ class Manager
|
||||||
|
|
||||||
public function detectInstalledModules()
|
public function detectInstalledModules()
|
||||||
{
|
{
|
||||||
// TODO: Allow multiple paths for installed modules (e.g. web vs pkg)
|
foreach ($this->modulePaths as $basedir) {
|
||||||
$basedir = realpath(ICINGA_APPDIR . '/../modules');
|
$fh = opendir($basedir);
|
||||||
$fh = @opendir($basedir);
|
if ($fh === false) {
|
||||||
if ($fh === false) {
|
return $this;
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
while ($name = readdir($fh)) {
|
|
||||||
if ($name[0] === '.') {
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
if (is_dir($basedir . '/' . $name)) {
|
|
||||||
$this->installedBaseDirs[$name] = $basedir . '/' . $name;
|
while ($name = readdir($fh)) {
|
||||||
|
if ($name[0] === '.') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (is_dir($basedir . '/' . $name)) {
|
||||||
|
$this->installedBaseDirs[$name] = $basedir . '/' . $name;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Tests\Icinga\Application\Module\Manager;
|
||||||
|
|
||||||
|
require_once("../../library/Icinga/Application/Modules/Manager.php");
|
||||||
|
require_once("../../library/Icinga/Exception/ProgrammingError.php");
|
||||||
|
require_once("../../library/Icinga/Exception/ConfigurationError.php");
|
||||||
|
require_once("../../library/Icinga/Exception/SystemPermissionException.php");
|
||||||
|
|
||||||
|
use Icinga\Application\Modules\Manager as ModuleManager;
|
||||||
|
|
||||||
|
class ModuleMock
|
||||||
|
{
|
||||||
|
|
||||||
|
public $name = "";
|
||||||
|
public $dir = "";
|
||||||
|
|
||||||
|
public function __construct($app, $name, $dir)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
$this->dir = $dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function register()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ManagerTest extends \PHPUnit_Framework_TestCase
|
||||||
|
{
|
||||||
|
const MODULE_TARGET = "/tmp";
|
||||||
|
|
||||||
|
protected function setUp()
|
||||||
|
{
|
||||||
|
$moduleDir = self::MODULE_TARGET;
|
||||||
|
if (!is_writable($moduleDir)) {
|
||||||
|
$this->markTestSkipped("Temporary folder not writable for this user");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (is_dir($moduleDir."/enabledModules")) {
|
||||||
|
exec("rm -r $moduleDir/enabledModules");
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir($moduleDir."/enabledModules");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDetectEnabledModules()
|
||||||
|
{
|
||||||
|
$manager = new ModuleManager(null, "/tmp/enabledModules", array("none"));
|
||||||
|
$this->assertEmpty($manager->listEnabledModules());
|
||||||
|
|
||||||
|
symlink(getcwd()."/res/testModules/module1", "/tmp/enabledModules/module1");
|
||||||
|
$manager = new ModuleManager(null, "/tmp/enabledModules", array("none"));
|
||||||
|
$this->assertEquals(array("module1"), $manager->listEnabledModules());
|
||||||
|
symlink(getcwd()."/res/testModules/module2", "/tmp/enabledModules/module2");
|
||||||
|
symlink(getcwd()."/res/???", "/tmp/enabledModules/module3");
|
||||||
|
$manager = new ModuleManager(null, "/tmp/enabledModules", array("none"));
|
||||||
|
$this->assertEquals(array("module1", "module2"), $manager->listEnabledModules());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLoadModule()
|
||||||
|
{
|
||||||
|
$manager = new ModuleManager(null, "/tmp/enabledModules", array("./res/testModules"));
|
||||||
|
$this->assertEmpty($manager->getLoadedModules());
|
||||||
|
$manager->loadModule("module1", "Tests\Icinga\Application\Module\Manager\ModuleMock");
|
||||||
|
$elems = $manager->getLoadedModules();
|
||||||
|
$this->assertNotEmpty($elems);
|
||||||
|
$this->assertTrue(isset($elems["module1"]));
|
||||||
|
// assert the changes not to be permanent:
|
||||||
|
$manager = new ModuleManager(null, "/tmp/enabledModules", array("./res/testModules"));
|
||||||
|
$this->assertEmpty($manager->getLoadedModules());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testEnableModule()
|
||||||
|
{
|
||||||
|
$manager = new ModuleManager(null, "/tmp/enabledModules", array(getcwd()."/res/testModules"));
|
||||||
|
$this->assertEmpty($manager->listEnabledModules());
|
||||||
|
$manager->enableModule("module1");
|
||||||
|
$elems = $manager->listEnabledModules();
|
||||||
|
$this->assertNotEmpty($elems);
|
||||||
|
$this->assertEquals($elems[0], "module1");
|
||||||
|
$this->assertTrue(is_link("/tmp/enabledModules/module1"));
|
||||||
|
// assert the changes to be permanent:
|
||||||
|
$manager = new ModuleManager(null, "/tmp/enabledModules", array("./res/testModules"));
|
||||||
|
$this->assertNotEmpty($manager->listEnabledModules());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDisableModule()
|
||||||
|
{
|
||||||
|
clearstatcache(true);
|
||||||
|
symlink(getcwd()."/res/testModules/module1", "/tmp/enabledModules/module1");
|
||||||
|
$manager = new ModuleManager(null, "/tmp/enabledModules", array(getcwd()."/res/testModules"));
|
||||||
|
$elems = $manager->listEnabledModules();
|
||||||
|
$this->assertNotEmpty($elems);
|
||||||
|
$this->assertEquals($elems[0], "module1");
|
||||||
|
$manager->disableModule("module1");
|
||||||
|
$this->assertFalse(file_exists("/tmp/enabledModules/module1"));
|
||||||
|
$this->assertEmpty($manager->listEnabledModules());
|
||||||
|
// assert the changes to be permanent:
|
||||||
|
$manager = new ModuleManager(null, "/tmp/enabledModules", array("./res/testModules"));
|
||||||
|
$this->assertEmpty($manager->listEnabledModules());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function tearDown()
|
||||||
|
{
|
||||||
|
$moduleDir = self::MODULE_TARGET;
|
||||||
|
exec("rm -r $moduleDir/enabledModules");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue