Make Icinga Web 2 work without any config file

refs #5638
fixes #5523
This commit is contained in:
Eric Lippmann 2014-02-20 13:53:28 +01:00
parent 76769865da
commit 7fa6668b64
11 changed files with 181 additions and 153 deletions

View File

@ -25,7 +25,7 @@ ICINGA_MYSQL_CMD=${ICINGA_MYSQL_CMD:-"/usr/local/icinga-mysql/var/rw/icinga.cmd"
ICINGA_PGSQL_CMD=${ICINGA_PGSQL_CMD:-"/usr/local/icinga-pgsql/var/rw/icinga.cmd"}
LOCKFILE=${LOCKFILE:-/var/lock/subsys/$PROG}
PIDFILE=${PIDFILE:-/var/lock/subsys/$PROG/$PROD.pid}
PIDFILE=${PIDFILE:-/var/lock/subsys/$PROG/$PROG.pid}
RETVAL=0

View File

@ -1,17 +1,16 @@
______ ___
/\__ _\ __ /'___`\
\/_/\ \/ ___ /\_\ ___ __ __ /\_\ /\ \
\ \ \ /'___\/\ \ /' _ `\ /'_ `\ /'__`\ \/_/// /__
______ ___
/\__ _\ __ /'___`\
\/_/\ \/ ___ /\_\ ___ __ __ /\_\ /\ \
\ \ \ /'___\/\ \ /' _ `\ /'_ `\ /'__`\ \/_/// /__
\_\ \__/\ \__/\ \ \/\ \/\ \/\ \L\ \/\ \L\.\_ // /_\ \
/\_____\ \____\\ \_\ \_\ \_\ \____ \ \__/.\_\ /\______/
\/_____/\/____/ \/_/\/_/\/_/\/___L\ \/__/\/_/ \/_____/
/\____/
\_/__/
__ __ __
/\ \ __/\ \ /\ \
\ \ \/\ \ \ \ __\ \ \____
\ \ \ \ \ \ \ /'__`\ \ '__`\
\/_____/\/____/ \/_/\/_/\/_/\/___L\ \/__/\/_/ \/_____/
/\____/
\_/__/
__ __ __
/\ \ __/\ \ /\ \
\ \ \/\ \ \ \ __\ \ \____
\ \ \ \ \ \ \ /'__`\ \ '__`\
\ \ \_/ \_\ \/\ __/\ \ \L\ \
\ `\___x___/\ \____\\ \_,__/
'\/__//__/ \/____/ \/___/
'\/__//__/ \/____/ \/___/

View File

@ -6,9 +6,6 @@ indexController = "dashboard"
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

View File

@ -31,9 +31,12 @@ namespace Icinga\Application;
use DateTimeZone;
use Exception;
use Zend_Config;
use Icinga\Application\Logger;
use Icinga\Application\Modules\Manager as ModuleManager;
use Icinga\Data\ResourceFactory;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\NotReadableError;
use Icinga\Util\DateTimeFactory;
use Icinga\Util\Translator;
@ -78,7 +81,7 @@ abstract class ApplicationBootstrap
/**
* Config object
*
* @var Config
* @var Zend_Config
*/
protected $config;
@ -256,6 +259,13 @@ abstract class ApplicationBootstrap
public static function start($configDir)
{
$application = new static($configDir);
// TODO(el): This is subject to change (Feature #5683)
date_default_timezone_set('UTC');
// Log to the System Log
Logger::create(new Zend_Config(array(
'type' => 'syslog',
'application' => 'Icinga Web'
)));
$application->bootstrap();
return $application;
}
@ -309,7 +319,12 @@ abstract class ApplicationBootstrap
$this->moduleManager = new ModuleManager(
$this,
$this->configDir . '/enabledModules',
explode(':', $this->config->global->get('modulePath', ICINGA_APPDIR . '/../modules'))
explode(
':',
$this->config->global !== null
? $this->config->global->get('modulePath', ICINGA_APPDIR . '/../modules')
: ICINGA_APPDIR . '/../modules'
)
);
return $this;
}
@ -323,21 +338,26 @@ abstract class ApplicationBootstrap
{
try {
$this->moduleManager->loadEnabledModules();
} catch (Exception $e) {
} catch (NotReadableError $e) {
Logger::exception(new Exception('Cannot load enabled modules. An exception was thrown:', 0, $e));
}
return $this;
}
/**
* Load configuration
* Load application configuration
*
* @return self
*/
protected function loadConfig()
{
Config::$configDir = $this->configDir;
$this->config = Config::app();
try {
$this->config = Config::app();
} catch (NotReadableError $e) {
Logger::exception(new Exception('Cannot load application configuration. An exception was thrown:', 0, $e));
$this->config = new Zend_Config(array());
}
return $this;
}
@ -361,19 +381,28 @@ abstract class ApplicationBootstrap
*/
protected function setupLogger()
{
Logger::create($this->config->logging);
if ($this->config->logging !== null) {
Logger::create($this->config->logging);
}
return $this;
}
/**
* Setup factories that provide access to the resources
* Set up the resource factory
*
* @return self
*/
protected function setupResourceFactory()
{
$config = Config::app('resources');
ResourceFactory::setConfig($config);
try {
$config = Config::app('resources');
ResourceFactory::setConfig($config);
} catch (NotReadableError $e) {
Logger::exception(
new Exception('Cannot load resource configuration. An exception was thrown:', 0, $e)
);
}
return $this;
}
@ -385,7 +414,7 @@ abstract class ApplicationBootstrap
*/
protected function setupTimezone()
{
$timeZoneString = $this->config->global->get('timezone', 'UTC');
$timeZoneString = $this->config->global !== null ? $this->config->global->get('timezone', 'UTC') : 'UTC';
try {
$tz = new DateTimeZone($timeZoneString);
} catch (Exception $e) {
@ -406,7 +435,10 @@ abstract class ApplicationBootstrap
protected function setupInternationalization()
{
try {
Translator::setupLocale($this->config->global->get('language', Translator::DEFAULT_LOCALE));
Translator::setupLocale(
$this->config->global !== null ? $this->config->global->get('language', Translator::DEFAULT_LOCALE)
: Translator::DEFAULT_LOCALE
);
} catch (Exception $error) {
Logger::info($error->getMessage());
}

View File

@ -29,8 +29,9 @@
namespace Icinga\Application;
use \Icinga\Exception\ProgrammingError;
use \Zend_Config_Ini;
use Zend_Config_Ini;
use Icinga\Exception\NotReadableError;
use Icinga\Exception\ProgrammingError;
/**
* Global registry of application and module configuration.
@ -68,22 +69,25 @@ class Config extends Zend_Config_Ini
/**
* Load configuration from the config file $filename
*
* @param string $filename The filename to parse
* @param string $filename The filename to parse
* @see Zend_Config_Ini::__construct
* @throws Exception When the file can't be read
* @throws NotReadableError When the file does not exist or cannot be read
*/
public function __construct($filename)
{
if (!@is_readable($filename)) {
throw new \Exception('Cannot read config file: ' . $filename);
$canonical = realpath($filename);
if ($canonical === false) {
throw new NotReadableError('Cannot read config file "' . $filename . '". Config file does not exist');
}
if (!is_readable($canonical)) {
throw new NotReadableError('Cannot read config file "' . $filename . '". Permission denied');
};
$this->configFile = $filename;
$this->configFile = $canonical;
$section = null;
$options = array(
'allowModifications' => true
);
parent::__construct($filename, $section, $options);
parent::__construct($canonical, $section, $options);
}
/**
@ -99,7 +103,7 @@ class Config extends Zend_Config_Ini
{
if (!isset(self::$app[$configname]) || $fromDisk) {
$filename = self::$configDir . '/' . $configname . '.ini';
self::$app[$configname] = new Config(realpath($filename));
self::$app[$configname] = new Config($filename);
}
return self::$app[$configname];
}

View File

@ -40,6 +40,8 @@ use Icinga\Util\File;
/**
* Zend_Log wrapper
*
* TODO(el): This is subject to change (Feature #5683)
*/
class Logger
{
@ -64,17 +66,6 @@ class Logger
*/
private static $instance;
/**
* Format for logging exceptions
*/
const LOG_EXCEPTION_FORMAT = <<<'EOD'
%s: %s
Stacktrace
----------
%s
EOD;
/**
* Create a new Logger
*
@ -135,17 +126,17 @@ EOD;
default:
throw new ConfigurationError('Logger configuration defines an invalid log type "' . $type . '"');
}
if (($priority = $config->priority) === null) {
if ($config->priority === null) {
$priority = Zend_Log::WARN;
} else {
$priority = (int) $priority;
$priority = (int) $config->priority;
}
$writer->addFilter(new Zend_Log_Filter_Priority($priority));
$this->logger->addWriter($writer);
$this->writers[] = $writer;
} catch (Zend_Log_Exception $e) {
throw new ConfigurationError(
'Cannot not add log writer of type "' . $type . '". An exception was thrown: '. $e->getMessage()
'Cannot not add log writer of type "' . $type . '". An exception was thrown: ', 0, $e
);
}
}
@ -235,19 +226,19 @@ EOD;
/**
* Log a exception at a priority
*
* @param Exception $e Exception to log
* @param int $priority Priority of message
* @param Exception $e Exception to log
* @param int $priority Priority of message
*/
public static function exception(Exception $e, $priority = Zend_Log::ERR)
{
$message = array();
do {
$message[] = self::formatMessage(
array(self::LOG_EXCEPTION_FORMAT, get_class($e), $e->getMessage(), $e->getTraceAsString())
array('%s in %s:%d %s', get_class($e), $e->getFile(), $e->getLine(), $e->getMessage())
);
} while($e = $e->getPrevious());
self::log(
implode(PHP_EOL, $message),
implode(' ', $message),
$priority
);
}

View File

@ -37,6 +37,7 @@ use Icinga\Data\DataArray\Query as ArrayQuery;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\SystemPermissionException;
use Icinga\Exception\ProgrammingError;
use Icinga\Exception\NotReadableError;
/**
* Module manager that handles detecting, enabling and disabling of modules
@ -99,22 +100,10 @@ class Manager
* the given path
* @param array $availableDirs Installed modules location
**/
public function __construct($app, $enabledDir = null, array $availableDirs = array())
public function __construct($app, $enabledDir, array $availableDirs)
{
$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;
}
@ -134,54 +123,59 @@ class Manager
*
* Update the internal $enabledDirs property with the enabled modules.
*
* @throws ConfigurationError If module dir is not a directory or not readable
* @throws ConfigurationError If module dir does not exist, is not a directory or not readable
*/
private function detectEnabledModules()
{
$canonical = $this->enableDir;
if ($canonical === false) {
throw new NotReadableError(
'Cannot read enabled modules. Module directory "' . $this->enableDir . '" does not exist'
);
}
if (!is_dir($this->enableDir)) {
throw new ConfigurationError(
'Could not read enabled modules: Module directory is not a directory: ' . $this->enableDir
throw new NotReadableError(
'Cannot read enabled modules. Module directory "' . $this->enableDir . '" is not a directory'
);
}
if (!is_readable($this->enableDir)) {
throw new ConfigurationError(
'Could not read enabled modules: Module directory is not readable: ' . $this->enableDir
throw new NotReadableError(
'Cannot read enabled modules. Module directory "' . $this->enableDir . '" is not readable'
);
}
if (($dh = opendir($canonical)) !== false) {
$this->enabledDirs = array();
while (($file = readdir($dh)) !== false) {
$fh = opendir($this->enableDir);
if ($file[0] === '.' || $file === 'README') {
continue;
}
$this->enabledDirs = array();
while (false !== ($file = readdir($fh))) {
$link = $this->enableDir . '/' . $file;
if (! is_link($link)) {
Logger::warn(
'Found invalid module in enabledModule directory "%s": "%s" is not a symlink',
$this->enableDir,
$link
);
continue;
}
if ($file[0] === '.' || $file === 'README') {
continue;
$dir = realpath($link);
if (!file_exists($dir) || !is_dir($dir)) {
Logger::warn(
'Found invalid module in enabledModule directory "%s": "%s" points to non existing path "%s"',
$this->enableDir,
$link,
$dir
);
continue;
}
$this->enabledDirs[$file] = $dir;
ksort($this->enabledDirs);
}
$link = $this->enableDir . '/' . $file;
if (! is_link($link)) {
Logger::warn(
'Found invalid module in enabledModule directory "%s": "%s" is not a symlink',
$this->enableDir,
$link
);
continue;
}
$dir = realpath($link);
if (!file_exists($dir) || !is_dir($dir)) {
Logger::warn(
'Found invalid module in enabledModule directory "%s": "%s" points to non existing path "%s"',
$this->enableDir,
$link,
$dir
);
continue;
}
$this->enabledDirs[$file] = $dir;
ksort($this->enabledDirs);
closedir($dh);
}
}
@ -517,29 +511,37 @@ class Manager
public function detectInstalledModules()
{
foreach ($this->modulePaths as $basedir) {
if (!file_exists($basedir)) {
Logger::warn('Module path "%s" does not exist.', $basedir);
$canonical = realpath($basedir);
if ($canonical === false) {
Logger::warn('Module path "%s" does not exist', $basedir);
continue;
}
$fh = opendir($basedir);
if ($fh === false) {
return $this;
if (!is_dir($canonical)) {
Logger::err('Module path "%s" is not a directory', $canonical);
continue;
}
while ($name = readdir($fh)) {
if ($name[0] === '.') {
continue;
}
if (is_dir($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]
);
if (!is_readable($canonical)) {
Logger::err('Module path "%s" is not readable', $canonical);
continue;
}
if (($dh = opendir($canonical)) !== false) {
while (($file = readdir($dh)) !== false) {
if ($file[0] === '.') {
continue;
}
if (is_dir($canonical . '/' . $file)) {
if (! array_key_exists($file, $this->installedBaseDirs)) {
$this->installedBaseDirs[$file] = $canonical . '/' . $file;
} else {
Logger::warn(
'Module "%s" already exists in installation path "%s" and is ignored.',
$canonical . '/' . $file,
$this->installedBaseDirs[$file]
);
}
}
}
closedir($dh);
}
}
ksort($this->installedBaseDirs);

View File

@ -457,25 +457,7 @@ class Module
}
$this->registerLocales()
->registerRoutes()
->registerMenuEntries();
return $this;
}
/**
* Register menu entries
*
* @return self
*/
protected function registerMenuEntries()
{
$cfg = $this->app
->getConfig()
->module($this->name, 'menu');
$view = $this->app->getViewRenderer();
if ($cfg) {
$view->view->navigation = $cfg->merge($view->view->navigation);
}
->registerRoutes();
return $this;
}

View File

@ -44,6 +44,7 @@ use \Zend_Controller_Front;
use Icinga\Application\Logger;
use Icinga\Authentication\Manager as AuthenticationManager;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\NotReadableError;
use Icinga\User;
use Icinga\Web\Request;
use Icinga\Web\View;
@ -208,7 +209,15 @@ class Web extends ApplicationBootstrap
*/
private function setupUser()
{
$authenticationManager = AuthenticationManager::getInstance();
try {
$config = Config::app('authentication');
} catch (NotReadableError $e) {
Logger::exception(
new Exception('Cannot load authentication configuration. An exception was thrown:', 0, $e)
);
$config = null;
}
$authenticationManager = AuthenticationManager::getInstance($config);
if ($authenticationManager->isAuthenticated() === true) {
$this->user = $authenticationManager->getUser();
}
@ -279,11 +288,10 @@ class Web extends ApplicationBootstrap
$view->view->setEncoding('UTF-8');
$view->view->headTitle()->prepend(
$this->getConfig()->{'global'}->get('project', 'Icinga')
$this->config->global !== null ? $this->config->global->get('project', 'Icinga') : 'Icinga'
);
$view->view->headTitle()->setSeparator(' :: ');
$view->view->navigation = $this->getConfig()->app('menu');
$this->viewRenderer = $view;

View File

@ -36,12 +36,12 @@ use Icinga\Web\Session;
use Icinga\Data\ResourceFactory;
use Icinga\Application\Logger;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\NotReadableError;
use Icinga\Application\Config as IcingaConfig;
use Icinga\Authentication\Backend\DbUserBackend;
use Icinga\Authentication\Backend\LdapUserBackend;
use Icinga\User\Preferences;
use Icinga\User\Preferences\PreferencesStore;
use Icinga\Exception\NotReadableError;
/**
* The authentication manager allows to identify users and
@ -90,8 +90,10 @@ class Manager
**/
private function __construct(Zend_Config $config = null)
{
$this->config = $config === null ? IcingaConfig::app('authentication') : $config;
$this->setupBackends($this->config);
if ($config !== null) {
$this->setupBackends($config);
$this->config = $config;
}
}
/**

View File

@ -31,7 +31,8 @@ namespace Icinga\Web;
use Icinga\Application\Config;
use Icinga\Application\Icinga;
use Icinga\Web\MenuItem;
use Icinga\Application\Logger;
use Icinga\Exception\NotReadableError;
class Menu extends MenuItem
{
@ -43,12 +44,22 @@ class Menu extends MenuItem
public static function fromConfig() {
$menu = new static('menu');
$manager = Icinga::app()->getModuleManager();
$menuConfigs = array(Config::app('menu'));
foreach ($manager->listEnabledModules() as $moduleName) {
$moduleMenuConfig = Config::module($moduleName, 'menu');
if ($moduleMenuConfig) {
$menuConfigs[] = $moduleMenuConfig;
try {
$menuConfigs = array(Config::app('menu'));
} catch (NotReadableError $e) {
Logger::exception($e);
$menuConfigs = array();
}
try {
foreach ($manager->listEnabledModules() as $moduleName) {
$moduleMenuConfig = Config::module($moduleName, 'menu');
if ($moduleMenuConfig) {
$menuConfigs[] = $moduleMenuConfig;
}
}
} catch (NotReadableError $e) {
Logger::exception($e);
}
return $menu->loadMenuItems($menu->flattenConfigs($menuConfigs));
}