Merge branch 'master' into feature/deduplicate-puppet-code-6842

Conflicts:
	.vagrant-puppet/manifests/default.pp
This commit is contained in:
Alexander Klimov 2014-09-11 11:39:37 +02:00
commit b82ed3d2a4
275 changed files with 7526 additions and 3781 deletions

2
.gitignore vendored
View File

@ -11,6 +11,8 @@
build/
development/
# ./configure output
config.log
autom4te.cache

View File

@ -5,7 +5,7 @@
namespace Icinga\Clicommands;
use Icinga\Cli\Command;
use Exception;
use Icinga\Exception\IcingaException;
class WebCommand extends Command
{
@ -13,11 +13,11 @@ class WebCommand extends Command
{
$minVersion = '5.4.0';
if (version_compare(PHP_VERSION, $minVersion) < 0) {
throw new Exception(sprintf(
throw new IcingaException(
'You are running PHP %s, internal webserver requires %s.',
PHP_VERSION,
$minVersion
));
);
}
$fork = $this->params->get('daemonize');
@ -27,12 +27,12 @@ class WebCommand extends Command
// TODO: Sanity check!!
if ($socket === null) {
$socket = '0.0.0.0:80';
// throw new Exception('Socket is required');
// throw new IcingaException('Socket is required');
}
if ($basedir === null) {
$basedir = dirname(ICINGAWEB_APPDIR) . '/public';
if (! file_exists($basedir) || ! is_dir($basedir)) {
throw new Exception('Basedir is required');
throw new IcingaException('Basedir is required');
}
}
$basedir = realpath($basedir);
@ -68,7 +68,7 @@ class WebCommand extends Command
{
$pid = pcntl_fork();
if ($pid == -1) {
throw new Exception('Could not fork');
throw new IcingaException('Could not fork');
} else if ($pid) {
echo $this->screen->colorize('[OK]')
. " Icinga Web server forked successfully\n";

View File

@ -2,7 +2,6 @@
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
use \Zend_Config;
use Icinga\Web\Url;
use Icinga\Logger\Logger;
use Icinga\Config\PreservingIniWriter;
@ -12,6 +11,7 @@ use Icinga\Form\Dashboard\AddUrlForm;
use Icinga\Exception\NotReadableError;
use Icinga\Exception\ConfigurationError;
use Icinga\Web\Controller\ActionController;
use Icinga\Exception\IcingaException;
/**
* Handle creation, removal and displaying of dashboards, panes and components
@ -42,7 +42,7 @@ class DashboardController extends ActionController
}
$dashboard->readConfig($dashboardConfig);
} catch (NotReadableError $e) {
Logger::error(new Exception('Cannot load dashboard configuration. An exception was thrown:', 0, $e));
Logger::error(new IcingaException('Cannot load dashboard configuration. An exception was thrown:', $e));
return null;
}
return $dashboard;
@ -111,7 +111,11 @@ class DashboardController extends ActionController
*/
public function indexAction()
{
$dashboard = $this->getDashboard();
$dashboard = Dashboard::load();
if (! $dashboard->hasPanes()) {
$this->view->title = 'Dashboard';
} else {
if ($this->_getParam('pane')) {
$pane = $this->_getParam('pane');
$dashboard->activate($pane);
@ -136,7 +140,7 @@ class DashboardController extends ActionController
*/
$this->view->dashboard = $dashboard;
}
}
}

View File

@ -4,6 +4,7 @@
// namespace Icinga\Application\Controllers;
use Icinga\Logger\Logger;
use Icinga\Web\Controller\ActionController;
use Icinga\Application\Icinga;
@ -21,6 +22,10 @@ class ErrorController extends ActionController
{
$error = $this->_getParam('error_handler');
$exception = $error->exception;
Logger::error($exception);
Logger::error('Stacktrace: %s', $exception->getTraceAsString());
switch ($error->type) {
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ROUTE:
case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:

View File

@ -18,9 +18,12 @@ class LayoutController extends ActionController
*/
public function menuAction()
{
$this->view->menuRenderer = new MenuRenderer(
Menu::fromConfig()->order(), Url::fromRequest()->without('renderLayout')->getRelativeUrl()
);
$this->setAutorefreshInterval(15);
$this->_helper->layout()->disableLayout();
$url = Url::fromRequest();
$menu = new MenuRenderer(Menu::load(), $url->getRelativeUrl());
$this->view->menuRenderer = $menu->useCustomRenderer();
}
/**
@ -30,11 +33,11 @@ class LayoutController extends ActionController
{
$topbarHtmlParts = array();
/** @var Hook\Layout\TopBar $hook */
/** @var Hook\TopBarHook $hook */
$hook = null;
foreach (Hook::all('TopBar') as $hook) {
$topbarHtmlParts[] = $hook->getHtml($this->getRequest(), $this->view);
$topbarHtmlParts[] = $hook->getHtml($this->getRequest());
}
$this->view->topbarHtmlParts = $topbarHtmlParts;

View File

@ -4,9 +4,12 @@
use Icinga\Module\Monitoring\Controller;
use Icinga\Web\Hook;
use Icinga\Application\Config as IcingaConfig;
use Icinga\Web\Url;
use Icinga\Data\ResourceFactory;
use Icinga\Logger\Logger;
use Icinga\Logger\Writer\FileWriter;
use Icinga\Protocol\File\FileReader;
use \Zend_Controller_Action_Exception as ActionError;
/**
* Class ListController
@ -36,20 +39,21 @@ class ListController extends Controller
*/
public function applicationlogAction()
{
$this->addTitleTab('application log');
$config_ini = IcingaConfig::app()->toArray();
if (!in_array('logging', $config_ini) || (
in_array('type', $config_ini['logging']) &&
$config_ini['logging']['type'] === 'file' &&
in_array('target', $config_ini['logging']) &&
file_exists($config_ini['logging']['target'])
)
) {
$config = ResourceFactory::getResourceConfig('logfile');
$resource = ResourceFactory::createResource($config);
$this->view->logData = $resource->select()->order('DESC')->paginate();
} else {
$this->view->logData = null;
if (! Logger::writesToFile()) {
throw new ActionError('Site not found', 404);
}
$this->addTitleTab('application log');
$pattern = '/^(?<datetime>[0-9]{4}(-[0-9]{2}){2}' // date
. 'T[0-9]{2}(:[0-9]{2}){2}([\\+\\-][0-9]{2}:[0-9]{2})?)' // time
. ' - (?<loglevel>[A-Za-z]+)' // loglevel
. ' - (?<message>.*)$/'; // message
$loggerWriter = Logger::getInstance()->getWriter();
$resource = new FileReader(new Zend_Config(array(
'filename' => $loggerWriter->getPath(),
'fields' => $pattern
)));
$this->view->logData = $resource->select()->order('DESC')->paginate();
}
}

View File

@ -3,9 +3,8 @@
// {{{ICINGA_LICENSE_HEADER}}}
use Icinga\Web\Controller\ActionController;
use Icinga\Application\Icinga;
use Icinga\Web\Widget;
use Icinga\Web\Url;
use Icinga\Web\Widget\SearchDashboard;
/**
* Search controller
@ -14,47 +13,13 @@ class SearchController extends ActionController
{
public function indexAction()
{
$search = $this->_request->getParam('q');
if (! $search) {
$this->view->tabs = Widget::create('tabs')->add(
'search',
array(
'title' => $this->translate('Search'),
'url' => '/search',
)
)->activate('search');
$this->render('hint');
return;
$this->view->dashboard = SearchDashboard::search($this->params->get('q'));
// NOTE: This renders the dashboard twice. Remove this once we can catch exceptions thrown in view scripts.
$this->view->dashboard->render();
}
$dashboard = Widget::create('dashboard')->createPane($this->translate('Search'));
$pane = $dashboard->getPane($this->translate('Search'));
$suffix = strlen($search) ? ': ' . rtrim($search, '*') . '*' : '';
$pane->addComponent(
$this->translate('Hosts') . $suffix,
Url::fromPath('monitoring/list/hosts', array(
'host_name' => $search . '*',
'sort' => 'host_severity',
'limit' => 10,
)
));
$pane->addComponent(
$this->translate('Services') . $suffix,
Url::fromPath('monitoring/list/services', array(
'service_description' => $search . '*',
'sort' => 'service_severity',
'limit' => 10,
)
));
$pane->addComponent('Hostgroups' . $suffix, Url::fromPath('monitoring/list/hostgroups', array(
'hostgroup' => $search . '*',
'limit' => 10,
)));
$pane->addComponent('Servicegroups' . $suffix, Url::fromPath('monitoring/list/servicegroups', array(
'servicegroup' => $search . '*',
'limit' => 10,
)));
$dashboard->activate($this->translate('Search'));
$this->view->dashboard = $dashboard;
$this->view->tabs = $dashboard->getTabs();
public function hintAction()
{
}
}

View File

@ -2,10 +2,11 @@
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
use \Zend_Controller_Action_Exception as ActionException;
use Icinga\Web\Controller\ActionController;
use Icinga\Application\Icinga;
use Icinga\Logger\Logger;
use Icinga\Web\FileCache;
use Zend_Controller_Action_Exception as ActionException;
/**
* Delivery static content to clients
@ -30,8 +31,25 @@ class StaticController extends ActionController
public function gravatarAction()
{
$cache = FileCache::instance();
$filename = md5(strtolower(trim($this->_request->getParam('email'))));
$cacheFile = 'gravatar-' . $filename;
header('Cache-Control: public');
header('Pragma: cache');
if ($etag = $cache->etagMatchesCachedFile($cacheFile)) {
header("HTTP/1.1 304 Not Modified");
return;
}
header('Content-Type: image/jpg');
$img = file_get_contents('http://www.gravatar.com/avatar/' . md5(strtolower(trim($this->_request->getParam('email')))) . '?s=200&d=mm');
if ($cache->has($cacheFile)) {
header('ETag: "' . $cache->etagForCachedFile($cacheFile) . '"');
$cache->send($cacheFile);
return;
}
$img = file_get_contents('http://www.gravatar.com/avatar/' . $filename . '?s=120&d=mm');
$cache->store($cacheFile, $img);
header('ETag: "' . $cache->etagForCachedFile($cacheFile) . '"');
echo $img;
}
@ -41,13 +59,12 @@ class StaticController extends ActionController
public function imgAction()
{
$module = $this->_getParam('module_name');
// TODO: This is more than dangerous, must be fixed!!
$file = $this->_getParam('file');
$basedir = Icinga::app()->getModuleManager()->getModule($module)->getBaseDir();
$filePath = $basedir . '/public/img/' . $file;
if (! file_exists($filePath)) {
$filePath = realpath($basedir . '/public/img/' . $file);
if (! $filePath || strpos($filePath, $basedir) !== 0) {
throw new ActionException(sprintf(
'%s does not exist',
$filePath

View File

@ -4,8 +4,8 @@
namespace Icinga\Form\Config\Authentication;
use \Zend_Config;
use \Zend_Form_Element_Checkbox;
use Zend_Config;
use Zend_Form_Element_Checkbox;
use Icinga\Web\Form;
use Icinga\Data\ResourceFactory;
use Icinga\Web\Form\Decorator\HelpText;

View File

@ -4,8 +4,8 @@
namespace Icinga\Form\Config\Authentication;
use \Exception;
use \Zend_Config;
use Exception;
use Zend_Config;
use Icinga\Data\ResourceFactory;
use Icinga\Authentication\DbConnection;
use Icinga\Authentication\Backend\DbUserBackend;
@ -111,10 +111,9 @@ class DbBackendForm extends BaseBackendForm
public function isValidAuthenticationBackend()
{
try {
$testConnection = ResourceFactory::createResource(ResourceFactory::getResourceConfig(
$dbUserBackend = new DbUserBackend(ResourceFactory::create(
$this->getValue('backend_' . $this->filterName($this->getBackendName()) . '_resource')
));
$dbUserBackend = new DbUserBackend($testConnection);
if ($dbUserBackend->count() < 1) {
$this->addErrorMessage(t("No users found under the specified database backend"));
return false;

View File

@ -4,8 +4,9 @@
namespace Icinga\Form\Config\Authentication;
use \Exception;
use \Zend_Config;
use Exception;
use Icinga\Application\Platform;
use Zend_Config;
use Icinga\Web\Form;
use Icinga\Data\ResourceFactory;
use Icinga\Authentication\Backend\LdapUserBackend;
@ -135,7 +136,7 @@ class LdapBackendForm extends BaseBackendForm
*/
public function isValidAuthenticationBackend()
{
if (! ResourceFactory::ldapAvailable()) {
if (! Platform::extensionLoaded('ldap')) {
/*
* It should be possible to run icingaweb without the php ldap extension, when
* no ldap backends are needed. When the user tries to create an ldap backend
@ -148,7 +149,7 @@ class LdapBackendForm extends BaseBackendForm
$cfg = $this->getConfig();
$backendName = 'backend_' . $this->filterName($this->getBackendName()) . '_name';
$backendConfig = new Zend_Config($cfg[$this->getValue($backendName)]);
$backend = ResourceFactory::createResource(ResourceFactory::getResourceConfig($backendConfig->resource));
$backend = ResourceFactory::create($backendConfig->resource);
$testConn = new LdapUserBackend(
$backend,
$backendConfig->user_class,
@ -157,7 +158,7 @@ class LdapBackendForm extends BaseBackendForm
$testConn->assertAuthenticationPossible();
/*
if ($testConn->count() === 0) {
throw new Exception('No Users Found On Directory Server');
throw new IcingaException('No Users Found On Directory Server');
}
*/
} catch (Exception $exc) {

View File

@ -4,7 +4,7 @@
namespace Icinga\Form\Config\Authentication;
use \Zend_Config;
use Zend_Config;
use Icinga\Web\Form;
/**

View File

@ -4,7 +4,7 @@
namespace Icinga\Form\Config;
use \Zend_Config;
use Zend_Config;
use Icinga\Web\Form;
use Icinga\Application\Icinga;
use Icinga\Web\Form\Validator\WritablePathValidator;

View File

@ -5,6 +5,7 @@
namespace Icinga\Form\Config;
use Exception;
use Icinga\Application\Platform;
use Zend_Config;
use Zend_Form_Element_Checkbox;
use Icinga\Web\Form;
@ -405,14 +406,14 @@ class ResourceForm extends Form
* in case they aren't actually used. When the user tries to create a resource that depends on an
* uninstalled extension, an error should be displayed.
*/
if ($config->db === 'mysql' && !ResourceFactory::mysqlAvailable()) {
if ($config->db === 'mysql' && ! Platform::extensionLoaded('mysql')) {
$this->addErrorMessage(
t('You need to install the php extension "mysql" and the ' .
'Zend_Pdo_Mysql classes to use MySQL database resources.')
);
return false;
}
if ($config->db === 'pgsql' && !ResourceFactory::pgsqlAvailable()) {
if ($config->db === 'pgsql' && ! Platform::extensionLoaded('pgsql')) {
$this->addErrorMessage(
t('You need to install the php extension "pgsql" and the ' .
'Zend_Pdo_Pgsql classes to use PostgreSQL database resources.')

View File

@ -4,15 +4,16 @@
namespace Icinga\Form\Preference;
use \DateTimeZone;
use \Zend_Config;
use \Zend_Form_Element_Text;
use \Zend_Form_Element_Select;
use \Zend_View_Helper_DateFormat;
use \Icinga\Web\Form;
use \Icinga\Web\Form\Validator\TimeFormatValidator;
use \Icinga\Web\Form\Validator\DateFormatValidator;
use \Icinga\Util\Translator;
use DateTimeZone;
use Icinga\Util\TimezoneDetect;
use Zend_Config;
use Zend_Form_Element_Text;
use Zend_Form_Element_Select;
use Zend_View_Helper_DateFormat;
use Icinga\Web\Form;
use Icinga\Web\Form\Validator\TimeFormatValidator;
use Icinga\Web\Form\Validator\DateFormatValidator;
use Icinga\Util\Translator;
/**
* General user preferences
@ -69,13 +70,22 @@ class GeneralForm extends Form
*/
private function addTimezoneSelection(Zend_Config $cfg)
{
$prefs = $this->getUserPreferences();
$useGlobalTimezone = $this->getRequest()->getParam('default_timezone', !$prefs->has('app.timezone'));
$detect = new TimezoneDetect();
$tzList = array();
foreach (DateTimeZone::listIdentifiers() as $tz) {
$tzList[$tz] = $tz;
}
$helptext = 'Use the following timezone for dates and times';
$prefs = $this->getUserPreferences();
$useGlobalTimezone = $this->getRequest()->getParam('default_timezone', !$prefs->has('app.timezone'));
if ($useGlobalTimezone && $detect->success() === true) {
$helptext .= '<br />' . t('Currently your time was detected to be')
. ': '
. '<strong>' . $detect->getTimezoneName() . '</strong>';
}
$selectTimezone = new Zend_Form_Element_Select(
array(
@ -87,6 +97,7 @@ class GeneralForm extends Form
'value' => $prefs->get('app.timezone', $cfg->get('timezone', date_default_timezone_get()))
)
);
$this->addElement(
'checkbox',
'default_timezone',
@ -99,7 +110,9 @@ class GeneralForm extends Form
if ($useGlobalTimezone) {
$selectTimezone->setAttrib('disabled', 1);
}
$this->addElement($selectTimezone);
$this->enableAutoSubmit(array('default_timezone'));
}

View File

@ -29,17 +29,17 @@ $iframeClass = $isIframe ? ' iframe' : '';
<title><?= $this->title ? $this->escape($this->title) : 'Icinga Web' ?></title>
<!-- TODO: viewport and scale settings make no sense for us, fix this -->
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<link rel="stylesheet" href="<?= $this->href($cssfile) ?>" media="screen" type="text/css" />
<? if ($isIframe): ?>
<? if ($isIframe): ?>
<base target="_parent"/>
<?php else: ?>
<?php else: ?>
<script type="text/javascript">
(function() {
var html = document.getElementsByTagName('html')[0];
html.className = html.className.replace(/no-js/, 'js');
}());
</script>
<?php endif ?>
<?php endif ?>
<link rel="stylesheet" href="<?= $this->href($cssfile) ?>" media="screen" type="text/css" />
<!-- Respond.js IE8 support of media queries -->
<!--[if lt IE 9]>
<script src="<?= $this->baseUrl('js/vendor/respond.min.js');?>"></script>

View File

@ -3,6 +3,7 @@
use Icinga\Web\Url;
use Icinga\Web\Menu;
use Icinga\Web\MenuRenderer;
use Icinga\Web\Widget\SearchDashboard;
// Don't render a menu for unauthenticated users unless menu is auth aware
if (! $this->auth()->isAuthenticated()) {
@ -10,9 +11,15 @@ if (! $this->auth()->isAuthenticated()) {
}
?>
<div id="menu" data-base-target="_main">
<div
id="menu" data-last-update="<?= (time() - 14) ?>000" data-base-target="_main" class="container" data-icinga-url="<?=$this->href('layout/menu');?>"
data-icinga-refresh="15"
>
<? if (SearchDashboard::search('dummy')->getPane('search')->hasComponents()): ?>
<form action="<?= $this->href('search') ?>" method="get" role="search">
<input type="text" name="q" class="search autofocus" placeholder="<?= $this->translate('Search...') ?>" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
<input type="text" name="q" class="search autofocus" placeholder="<?= $this->translate('Search...') ?>"
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />
</form>
<?= new MenuRenderer(Menu::fromConfig()->order(), Url::fromRequest()->without('renderLayout')->getRelativeUrl()); ?>
<? endif; ?>
<?= new MenuRenderer(Menu::load(), Url::fromRequest()->without('renderLayout')->getRelativeUrl()); ?>
</div>

View File

@ -5,121 +5,191 @@
#
msgid ""
msgstr ""
"Project-Id-Version: Icinga Web 2 (0.1)\n"
"Project-Id-Version: Icinga Web 2 (None)\n"
"Report-Msgid-Bugs-To: dev@icinga.org\n"
"POT-Creation-Date: 2014-05-29 11:12+0000\n"
"PO-Revision-Date: 2014-05-29 13:19+0100\n"
"POT-Creation-Date: 2014-08-22 17:30+0200\n"
"PO-Revision-Date: 2014-08-22 17:52+0100\n"
"Last-Translator: Thomas Gelf <thomas@gelf.net>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
#: /usr/local/src/bugfix.master/application/views/scripts/mixedPagination.phtml:15
#, php-format
msgid "%d to %d of %d"
msgstr "%d bis %d von %d"
#: /usr/local/src/bugfix.master/application/views/scripts/pivottablePagination.phtml:9
#, php-format
msgid "%s: %d to %d of %d"
msgstr "%s: %d bis %d von %d"
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:117
#: /usr/local/src/bugfix.master/application/forms/Authentication/LoginForm.php:36
msgid "...and your password"
msgstr "...und dein Kennwort ein"
#: /usr/local/src/bugfix.master/library/Icinga/Web/Widget/FilterEditor.php:132
msgid "Add"
msgstr "Hinzufügen"
#: /usr/local/src/bugfix.master/library/Icinga/Web/Widget/FilterWidget.php:81
msgid "Add filter..."
msgstr "Filter hinzufügen..."
#: /usr/local/src/bugfix.master/application/controllers/AuthenticationController.php:118
msgid "All configured authentication methods failed. Please check the system log or Icinga Web 2 log for more information."
msgstr "Alle konfigurierten Authentifizierungsmethoden sind fehlgeschlagen. Bitte überprüfe das Systemlog oder jenes von Icinga Web 2 für weitere Details."
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:91
msgid "Application Prefix"
msgstr "Anwendungspräfix"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/DbBackendForm.php:78
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:80
#: /usr/local/src/bugfix.master/library/Icinga/Web/Menu.php:197
msgid "ApplicationLog"
msgstr "Anwendungslog"
#: /usr/local/src/bugfix.master/library/Icinga/Web/Form/notyet_FormWizard.php:31
msgid "Back"
msgstr "Zurück"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/DbBackendForm.php:53
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:55
msgid "Backend Name"
msgstr "Backend-Name"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:282
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:257
msgid "Bind DN"
msgstr "Bind DN"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:294
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:269
msgid "Bind Password"
msgstr "Bind Kennwort"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:358
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/BaseBackendForm.php:139
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:333
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/BaseBackendForm.php:114
msgid "Check this box to enforce changes without connectivity validation"
msgstr "Aktiviere dieses Häkchen um die Änderungen ohne Validierung der Verbindung zu speichern"
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:73
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:47
msgid "Check this to enable logging."
msgstr "Aktiviere dieses Häkchen um das Logging zu aktivieren."
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:187
#: /usr/local/src/bugfix.master/library/Icinga/Web/Widget/FilterEditor.php:108
msgid "Click to add a filter expression to this operator"
msgstr "Hier klicken, um einen Filter-Ausdruck zu diesem Operator hinzuzufügen"
#: /usr/local/src/bugfix.master/library/Icinga/Web/Widget/FilterEditor.php:105
msgid "Click to add another operator below this one"
msgstr "Hier klicken, um unterhalb dieses Operators einen weiteren hinzuzufügen"
#: /usr/local/src/bugfix.master/library/Icinga/Web/Widget/FilterEditor.php:97
#: /usr/local/src/bugfix.master/library/Icinga/Web/Widget/FilterWidget.php:69
msgid "Click to remove this part of your filter"
msgstr "Klicken, um diesen Teil des Filters zu löschen"
#: /usr/local/src/bugfix.master/library/Icinga/Web/Menu.php:189
msgid "Configuration"
msgstr "Konfiguration"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:165
msgid "Connection Validation Failed: "
msgstr "Überprüfung der Verbindung fehlgeschlagen: "
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:477
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:452
msgid "Connectivity validation failed, connection to the given resource not possible."
msgstr "Überprüfung fehlgeschlagen, konnte keine Verbindung zu der angegebenen Ressource herstellen."
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:454
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:470
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:429
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:445
msgid "Connectivity validation failed, the provided file does not exist."
msgstr "Überprüfung fehlgeschlagen, die angegebene Datei existiert nicht."
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/DbBackendForm.php:90
#: /usr/local/src/bugfix.master/application/controllers/AuthenticationController.php:59
msgid "Could not read your authentiction.ini, no authentication methods are available."
msgstr "Deine authentication.ini konnte nicht gelesen werden, darum sind keine Authentifizierungsmethoden verfügbar."
#: /usr/local/src/bugfix.master/application/layouts/scripts/body.phtml:31
#: /usr/local/src/bugfix.master/library/Icinga/Web/Menu.php:175
msgid "Dashboard"
msgstr "Dashboard"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/DbBackendForm.php:65
msgid "Database Connection"
msgstr "Datenbankverbindung"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:183
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:158
msgid "Database Name"
msgstr "Datenbankname"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:144
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:119
msgid "Database Type"
msgstr "Datenbanktyp"
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:89
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:63
msgid "Debug"
msgstr "Debug"
#: /usr/local/src/bugfix.master/application/forms/Config/GeneralForm.php:185
#: /usr/local/src/bugfix.master/application/forms/Config/GeneralForm.php:101
msgid "Default Language"
msgstr "Standardsprache"
#: /usr/local/src/bugfix.master/application/controllers/ErrorController.php:62
#: /usr/local/src/bugfix.master/application/controllers/ErrorController.php:36
#, php-format
msgid "Enabling the \"%s\" module might help!"
msgstr "Das Modul \"%s\" zu aktivieren könnte helfen!"
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:86
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:60
msgid "Error"
msgstr "Fehler"
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:139
#: /usr/local/src/bugfix.master/library/Icinga/Web/Widget/FilterEditor.php:109
msgid "Expression"
msgstr "Ausdruck"
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:113
msgid "Facility"
msgstr "Facility"
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:102
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:383
#: /usr/local/src/bugfix.master/application/controllers/PreferenceController.php:55
#, php-format
msgid "Failed to persist preferences. (%s)"
msgstr "Persistierung der Einstellungen fehlgeschlagen. (%s)"
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:76
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:358
msgid "File"
msgstr "Datei"
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:155
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:220
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:231
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:308
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:129
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:195
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:206
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:283
msgid "Filepath"
msgstr "Dateipfad"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:357
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/BaseBackendForm.php:138
#: /usr/local/src/bugfix.master/library/Icinga/Web/Widget/FilterWidget.php:90
msgid "Filter this list"
msgstr "Diese Liste filtern"
#: /usr/local/src/bugfix.master/library/Icinga/Web/Widget/FilterWidget.php:94
msgid "Filtered"
msgstr "Gefiltert"
#: /usr/local/src/bugfix.master/library/Icinga/Web/Form/notyet_FormWizard.php:32
msgid "Finish"
msgstr "Fertigstellen"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:332
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/BaseBackendForm.php:113
msgid "Force Changes"
msgstr "Änderungen erzwingen"
#: /usr/local/src/bugfix.master/library/Icinga/Web/Form/notyet_QuickForm.php:147
msgid "Form has successfully been sent"
msgstr "Das Formular wurde erfolgreich versendet"
#: /usr/local/src/bugfix.master/application/views/scripts/search/hint.phtml:7
msgid "Hint"
msgstr "Hinweis"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:160
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:260
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:135
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:235
msgid "Host"
msgstr "Host"
@ -132,165 +202,183 @@ msgstr "Hosts"
msgid "I'm ready to search, waiting for your input"
msgstr "Ich bin bereit zur Suche, warte auf deine Eingabe"
#: /usr/local/src/bugfix.master/application/controllers/AuthenticationController.php:63
#: /usr/local/src/bugfix.master/application/controllers/AuthenticationController.php:40
#: /usr/local/src/bugfix.master/application/views/scripts/authentication/login.phtml:8
msgid "Icingaweb Login"
msgstr "Icingaweb Anmeldung"
#: /usr/local/src/bugfix.master/application/views/scripts/authentication/logout.phtml:17
#: /usr/local/src/bugfix.master/application/views/scripts/authentication/logout.phtml:14
msgid "If this message does not disappear, it might be necessary to quit the current session manually by clearing the cache, or by closing the current browser session."
msgstr "Wenn diese Nachricht nicht verschwindet könnte es nötig sein die aktuelle Sitzung manuell zu beenden indem der Cache gelöscht order die Browsersitzung geschlossen wird."
#: /usr/local/src/bugfix.master/application/controllers/AuthenticationController.php:118
#: /usr/local/src/bugfix.master/application/controllers/AuthenticationController.php:131
msgid "Incorrect username or password"
msgstr "Benutzername oder Kennwort ungültig"
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:88
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:62
msgid "Information"
msgstr "Information"
#: /usr/local/src/bugfix.master/library/Icinga/Web/Wizard/Wizard.php:337
#: /usr/local/src/bugfix.master/library/Icinga/Web/Wizard/Wizard.php:380
msgid "Install"
msgstr "Installieren"
#: /usr/local/src/bugfix.master/application/views/scripts/install/index.phtml:29
msgid "Installation"
msgstr "Installation"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:92
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:67
msgid "LDAP Resource"
msgstr "LDAP Ressource"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:115
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:90
msgid "LDAP User Name Attribute"
msgstr "LDAP-Attribut für Benutzername"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:104
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:79
msgid "LDAP User Object Class"
msgstr "LDAP Objektklasse für Benutzer"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:232
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:207
msgid "Location of your icinga objects.cache file"
msgstr "Pfad zur Datei objects.cache von Icinga"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:221
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:196
msgid "Location of your icinga status.dat file"
msgstr "Pfad zur Datei status.dat von Icinga"
#: /usr/local/src/bugfix.master/application/controllers/InstallController.php:69
msgid "Logging"
msgstr "Logging"
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:72
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:46
msgid "Logging Enabled"
msgstr "Logging aktiv"
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:82
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:56
msgid "Logging Level"
msgstr "Log-Level"
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:98
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:72
msgid "Logging Type"
msgstr "Logging-Typ"
#: /usr/local/src/bugfix.master/application/views/scripts/authentication/logout.phtml:15
#: /usr/local/src/bugfix.master/application/views/scripts/authentication/logout.phtml:12
msgid "Logging out..."
msgstr "Abmelden..."
#: /usr/local/src/bugfix.master/application/views/scripts/authentication/logout.phtml:28
#: /usr/local/src/bugfix.master/application/views/scripts/authentication/logout.phtml:21
msgid "Login"
msgstr "Anmelden"
#: /usr/local/src/bugfix.master/application/layouts/scripts/body.phtml:39
#: /usr/local/src/bugfix.master/application/layouts/scripts/parts/topbar.phtml:35
#: /usr/local/src/bugfix.master/library/Icinga/Web/Menu.php:202
msgid "Logout"
msgstr "Abmelden"
#: /usr/local/src/bugfix.master/application/views/scripts/authentication/logout.phtml:64
msgid "Logout not possible, it may be necessary to quit the session manually by clearing the cache, or closing the current browser session. Error: "
msgstr ""
#: /usr/local/src/bugfix.master/application/views/scripts/authentication/logout.phtml:69
#: /usr/local/src/bugfix.master/application/views/scripts/authentication/logout.phtml:43
msgid "Logout successful!"
msgstr "Abmelden erfolgreich!"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/ReorderForm.php:137
msgid "Move down in authentication order"
msgstr ""
#: /usr/local/src/bugfix.master/library/Icinga/Web/Widget/FilterEditor.php:235
#: /usr/local/src/bugfix.master/library/Icinga/Web/Widget/FilterWidget.php:95
msgid "Modify this filter"
msgstr "Diesen Filter bearbeiten"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/ReorderForm.php:111
#: /usr/local/src/bugfix.master/library/Icinga/Web/Menu.php:193
msgid "Modules"
msgstr "Module"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/ReorderForm.php:112
msgid "Move down in authentication order"
msgstr "In der Authentifizierungsreihenfolge nach unten schieben"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/ReorderForm.php:86
msgid "Move up in authentication order"
msgstr ""
msgstr "In der Authentifizierungsreihenfolge nach oben schieben"
#: /usr/local/src/bugfix.master/application/views/scripts/pivottablePagination.phtml:16
msgid "Navigation"
msgstr "Navigation"
#: /usr/local/src/bugfix.master/application/views/scripts/mixedPagination.phtml:83
#: /usr/local/src/bugfix.master/application/views/scripts/mixedPagination.phtml:86
#: /usr/local/src/bugfix.master/library/Icinga/Web/Wizard/Wizard.php:337
#: /usr/local/src/bugfix.master/library/Icinga/Web/Wizard/Wizard.php:380
#: /usr/local/src/bugfix.master/application/views/scripts/mixedPagination.phtml:89
#: /usr/local/src/bugfix.master/library/Icinga/Web/Form/notyet_FormWizard.php:30
msgid "Next"
msgstr "Weiter"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/DbBackendForm.php:144
msgid "No users found under the specified database backend"
msgstr ""
#: /usr/local/src/bugfix.master/application/controllers/AuthenticationController.php:110
msgid "No authentication methods available. Did you create authentication.ini when installing Icinga Web 2?"
msgstr "Keine Authentifizierungsmethode verfügbar. Hast du beim Installieren von Icinga Web 2 eine authentication.ini erstellt?"
#: /usr/local/src/bugfix.master/application/controllers/ErrorController.php:59
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/DbBackendForm.php:119
msgid "No users found under the specified database backend"
msgstr "Im konfigurierten Datenbankbackend wurden keine Benutzer gefunden"
#: /usr/local/src/bugfix.master/library/Icinga/Web/Widget/FilterEditor.php:106
msgid "Operator"
msgstr "Operator"
#: /usr/local/src/bugfix.master/application/views/scripts/mixedPagination.phtml:33
msgid "Page"
msgstr "Seite"
#: /usr/local/src/bugfix.master/application/controllers/ErrorController.php:33
msgid "Page not found."
msgstr "Seite nicht gefunden."
#: /usr/local/src/bugfix.master/application/forms/Authentication/LoginForm.php:65
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:206
#: /usr/local/src/bugfix.master/application/views/scripts/mixedPagination.phtml:12
msgid "Pagination"
msgstr "Seitennavigation"
#: /usr/local/src/bugfix.master/application/forms/Authentication/LoginForm.php:35
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:181
msgid "Password"
msgstr "Kennwort"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:319
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:294
msgid "Pattern"
msgstr "Muster"
#: /usr/local/src/bugfix.master/library/Icinga/Web/Form/Element/Number.php:61
#: /usr/local/src/bugfix.master/library/Icinga/Web/Form/Element/Number.php:36
msgid "Please enter a number."
msgstr "Bitte eine Nummer eingeben."
#: /usr/local/src/bugfix.master/application/forms/Authentication/LoginForm.php:25
msgid "Please enter your username..."
msgstr "Bitte gib deinen Benutzernamen..."
#: /usr/local/src/bugfix.master/application/controllers/AuthenticationController.php:126
msgid "Please note that not all authentication methods where available. Check the system log or Icinga Web 2 log for more information."
msgstr "Beachte bitte dass nicht alle Authentifizierungsmethoden verfügbar waren. Überprüfe das Systemlog oder jenes von Icinga Web 2 für weitere Informationen."
#: /usr/local/src/bugfix.master/application/views/scripts/search/hint.phtml:8
msgid "Please use the asterisk (*) as a placeholder for wildcard searches. For convenience I'll always add a wildcard after the last character you typed."
msgstr "Bitte benutze das Sternchen (*) als Jokerzeichen für eine Suche mit Platzhaltern. Der Einfachheit halber hänge ich immer einen Platzhalter hinter das letzte von dir getippte Zeichen."
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:171
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:146
msgid "Port"
msgstr "Port"
#: /usr/local/src/bugfix.master/application/layouts/scripts/body.phtml:38
#: /usr/local/src/bugfix.master/application/layouts/scripts/parts/topbar.phtml:32
#: /usr/local/src/bugfix.master/library/Icinga/Web/Menu.php:185
msgid "Preferences"
msgstr "Einstellungen"
#: /usr/local/src/bugfix.master/application/views/scripts/mixedPagination.phtml:45
#: /usr/local/src/bugfix.master/application/controllers/PreferenceController.php:48
msgid "Preferences updated successfully"
msgstr "Einstellungen erfolgreich aktualisiert"
#: /usr/local/src/bugfix.master/application/views/scripts/mixedPagination.phtml:48
#: /usr/local/src/bugfix.master/application/views/scripts/mixedPagination.phtml:51
msgid "Prev"
msgstr "Zurück"
#: /usr/local/src/bugfix.master/library/Icinga/Web/Wizard/Wizard.php:326
#: /usr/local/src/bugfix.master/library/Icinga/Web/Wizard/Wizard.php:367
msgid "Previous"
msgstr "Vorheriges"
#: /usr/local/src/bugfix.master/library/Icinga/Web/Widget/FilterWidget.php:99
msgid "Remove this filter"
msgstr "Diesen Filter entfernen"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:333
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:308
msgid "Resource Name"
msgstr ""
msgstr "Ressourcename"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:375
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:350
msgid "Resource Type"
msgstr ""
msgstr "Ressourcetyp"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:271
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:246
msgid "Root DN"
msgstr "Wurzel-DN"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:379
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:354
msgid "SQL Database"
msgstr "SQL Datenbank"
@ -301,187 +389,241 @@ msgstr "SQL Datenbank"
msgid "Search"
msgstr "Suche"
#: /usr/local/src/bugfix.master/application/layouts/scripts/parts/navigation.phtml:17
#: /usr/local/src/bugfix.master/application/layouts/scripts/parts/navigation.phtml:15
msgid "Search..."
msgstr "Suche..."
#: /usr/local/src/bugfix.master/application/forms/Config/GeneralForm.php:189
#: /usr/local/src/bugfix.master/library/Icinga/Web/Form/Validator/notyet_CsrfTokenValidator.php:20
msgid "Security check failed, please submit your form again"
msgstr "Sicherheitscheck fehlgeschlagen, bitte sende das Formular erneut ab"
#: /usr/local/src/bugfix.master/application/forms/Config/GeneralForm.php:105
msgid "Select the language to use by default. Can be overwritten by a user in his preferences."
msgstr ""
msgstr "Die zu benutzende Standard-Sprache. Kann von Benutzern in deren Einstellungen überschrieben werden."
#: /usr/local/src/bugfix.master/application/controllers/SearchController.php:41
#: /usr/local/src/bugfix.master/application/views/scripts/pivottablePagination.phtml:34
msgid "Services"
msgstr "Services"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:245
#: /usr/local/src/bugfix.master/library/Icinga/Web/Widget/Limiter.php:84
#, php-format
msgid "Show %s rows on one page"
msgstr "Zeige %s Zeilen pro Seite"
#: /usr/local/src/bugfix.master/application/views/scripts/mixedPagination.phtml:16
#, php-format
msgid "Show rows %d to %d of %d"
msgstr "Zeige die Zeilen %d bis %d von %d"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:220
msgid "Socket"
msgstr ""
msgstr "Socket"
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:140
#: /usr/local/src/bugfix.master/application/views/scripts/config/module.phtml:22
msgid "State"
msgstr "Status"
#: /usr/local/src/bugfix.master/library/Icinga/Web/Menu.php:181
msgid "System"
msgstr "System"
#: /usr/local/src/bugfix.master/application/views/scripts/authentication/login.phtml:4
msgid "The Icinga logo"
msgstr "Das Icinga Logo"
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:114
msgid "The Syslog facility to utilize."
msgstr ""
msgstr "Die zu benutzende Syslog-Facility"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:116
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:91
msgid "The attribute name used for storing the user name on the ldap server"
msgstr ""
msgstr "Der Attributname welcher benutzt wird, um Benutzernamen auf dem LDAP-Server abzulegen"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/DbBackendForm.php:91
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/DbBackendForm.php:66
msgid "The database connection to use for authenticating with this provider"
msgstr ""
msgstr "Die Datenbankverbindung, welche zur Authentifizierung mit diesem Provider genutzt werden soll"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:309
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:284
msgid "The filename to fetch information from"
msgstr ""
msgstr "Die Datei aus welcher Informationen gelesen werden sollen"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:161
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:136
msgid "The hostname of the database."
msgstr ""
msgstr "Der Hostname der Datenbank."
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:261
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:236
msgid "The hostname or address of the LDAP server to use for authentication"
msgstr ""
msgstr "Der Hostname oder die IP-Adresse des LDAP-Servers der zur Authentifizierung genutzt werden soll"
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:156
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:130
msgid "The logfile to write messages to."
msgstr ""
msgstr "Das Logfile in welches Nachrichten geschrieben werden sollen."
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:83
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:57
msgid "The maximum loglevel to emit."
msgstr ""
msgstr "Loglevel bis zu welchem Nachrichten ausgegeben werden sollen."
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:118
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:92
msgid "The name of the application by which to prefix syslog messages."
msgstr ""
msgstr "Der Anwendungsname welcher Syslog-Nachrichten vorangestellt werden soll."
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:184
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:159
msgid "The name of the database to use"
msgstr ""
msgstr "Der Name der zu benutzenden Datenbank"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:81
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:56
msgid "The name of this authentication backend"
msgstr ""
msgstr "Der Name dieses Authentifizierungsbackends"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/DbBackendForm.php:79
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/DbBackendForm.php:54
msgid "The name of this authentication provider"
msgstr ""
msgstr "Der Name dieses Authentifizierungsproviders"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:105
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:80
msgid "The object class used for storing users on the ldap server"
msgstr ""
msgstr "Die Objekt-Klasse welche benutzt wird, um Benutzer auf diesem LDAP-Server abzulegen"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:207
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:182
msgid "The password to use for authentication"
msgstr ""
msgstr "Das Kennwort welche zur Authentifizierung benutzt werden soll"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:270
msgid "The password to use for querying the ldap server"
msgstr "Das Kennwort welches zum Abfragen des LDAP-Servers benutzt werden soll"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:221
msgid "The path to your livestatus socket used for querying monitoring data"
msgstr "Der Pfad zu deinem Live-Status Socket, über welchen Monitoring-Daten abgefragt werden sollen"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:247
msgid "The path where users can be found on the ldap server"
msgstr "Der Pfad unter welchem Benutzer auf diesem LDAP-Server gefunden werden können."
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:147
msgid "The port to use."
msgstr "Der zu benutzende Port."
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:295
msgid "The password to use for querying the ldap server"
msgstr ""
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:246
msgid "The path to your livestatus socket used for querying monitoring data"
msgstr ""
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:272
msgid "The path where users can be found on the ldap server"
msgstr ""
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:172
msgid "The port to use."
msgstr ""
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:320
msgid "The regular expression by which to identify columns"
msgstr ""
msgstr "Der zu benutzende reguläre Ausdruck, mit welchem Spalten identifiziert werden können"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:93
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:68
msgid "The resource to use for authenticating with this provider"
msgstr ""
msgstr "Die Resource die zum Authentifizieren mit diesem Provider genutzt werden soll"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:145
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:120
msgid "The type of SQL database you want to create."
msgstr ""
msgstr "Der Typ der zu benutzenden SQL Datenbank."
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:99
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:73
msgid "The type of logging to utilize."
msgstr ""
msgstr "Der Typ des zu benutzenden Loggings."
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:376
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:351
msgid "The type of resource"
msgstr ""
msgstr "Der Typ der Ressource"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:334
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:309
msgid "The unique name of this resource"
msgstr ""
msgstr "Der eindeutige Name dieser Resource"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:283
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:258
msgid "The user dn to use for querying the ldap server"
msgstr ""
msgstr "Die DN des Benutzers mit welchem dieser LDAP-Server befragt werden soll"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:195
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:170
msgid "The user name to use for authentication."
msgstr ""
msgstr "Der zur Authentifizierung zu benutzende Benutzername."
#: /usr/local/src/bugfix.master/application/views/scripts/config/module.phtml:6
msgid "There is no such module installed."
msgstr "Gegenwärtig ist kein solches Modul installiert."
#: /usr/local/src/bugfix.master/application/views/scripts/config/module.phtml:32
#: /usr/local/src/bugfix.master/application/views/scripts/config/module.phtml:46
msgid "This module has no dependencies"
msgstr "Dieses Modul hat keine Abhängigkeiten"
#: /usr/local/src/bugfix.master/library/Icinga/Application/Modules/Module.php:383
#: /usr/local/src/bugfix.master/library/Icinga/Application/Modules/Module.php:435
msgid "This module has no description"
msgstr "Dieses Modul hat keine Beschreibung"
#: /usr/local/src/bugfix.master/application/forms/Preference/GeneralForm.php:100
#: /usr/local/src/bugfix.master/application/views/scripts/config/devtools.phtml:5
msgid "UI Debug"
msgstr "UI Debug"
#: /usr/local/src/bugfix.master/application/forms/Preference/GeneralForm.php:43
msgid "Use Default Language"
msgstr "Standardsprache verwenden"
#: /usr/local/src/bugfix.master/application/forms/Preference/GeneralForm.php:109
#: /usr/local/src/bugfix.master/application/forms/Preference/GeneralForm.php:52
msgid "Use the following language to display texts and messages"
msgstr ""
msgstr "Die folgende Sprache benutzen, um Texte und Nachrichten anzuzeigen"
#: /usr/local/src/bugfix.master/application/forms/Authentication/LoginForm.php:57
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:194
#: /usr/local/src/bugfix.master/application/forms/Authentication/LoginForm.php:24
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:169
msgid "Username"
msgstr "Benutzername"
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:169
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/LdapBackendForm.php:144
msgid "Using ldap is not possible, the php extension \"ldap\" is not installed."
msgstr ""
msgstr "Es ist nicht möglich, LDAP zu benutzen, da die PHP-Erweiterung \"LDAP\" nicht installiert ist."
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/DbBackendForm.php:148
#: /usr/local/src/bugfix.master/application/forms/Config/Authentication/DbBackendForm.php:123
#, php-format
msgid "Using the specified backend failed: %s"
msgstr ""
msgstr "Die angegebene Datenbank zu benutzen war nicht möglich: %s"
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:87
#: /usr/local/src/bugfix.master/application/forms/Config/LoggingForm.php:61
msgid "Warning"
msgstr "Warnung"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:435
#: /usr/local/src/bugfix.master/application/views/scripts/dashboard/index.phtml:13
msgid "We tried to load a dashboard configuration with no success. Please have look that the configuration does exist:"
msgstr "Der Versuch die Dashboard-Konfiguration zu laden war nicht erfolgreich. Bitte stelle sicher, dass die folgende Konfigurationsdatei existiert:"
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:410
msgid "You need to install the php extension \"mysql\" and the Zend_Pdo_Mysql classes to use MySQL database resources."
msgstr ""
msgstr "Um MySQL Datenbank-Ressourcen nutzen zu können müssen die PHP-Erweiterung \"mysql\" sowie die Zend_Pdo_Mysql Klassen installiert sein."
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:442
#: /usr/local/src/bugfix.master/application/forms/Config/ResourceForm.php:417
msgid "You need to install the php extension \"pgsql\" and the Zend_Pdo_Pgsql classes to use PostgreSQL database resources."
msgstr ""
msgstr "Um PostgreSQL Datenbank-Ressourcen nutzen zu können müssen die PHP-Erweiterung \"pqsql\" sowie die Zend_Pdo_Pgsql Klassen installiert sein."
#: /usr/local/src/bugfix.master/application/forms/Preference/GeneralForm.php:106
#: /usr/local/src/bugfix.master/application/forms/Preference/GeneralForm.php:49
msgid "Your Current Language"
msgstr "Deine aktuelle Sprache"
#: /usr/local/src/bugfix.master/library/Icinga/Util/Format.php:108
#: /usr/local/src/bugfix.master/library/Icinga/Util/Format.php:114
#: /usr/local/src/bugfix.master/library/Icinga/Web/Widget/Limiter.php:58
msgid "all"
msgstr "alle"
#: /usr/local/src/bugfix.master/library/Icinga/Util/Format.php:83
#: /usr/local/src/bugfix.master/library/Icinga/Util/Format.php:89
msgid "for"
msgstr "für"
#: /usr/local/src/bugfix.master/library/Icinga/Util/Format.php:112
#: /usr/local/src/bugfix.master/library/Icinga/Util/Format.php:131
#: /usr/local/src/bugfix.master/library/Icinga/Util/Format.php:133
#: /usr/local/src/bugfix.master/library/Icinga/Util/Format.php:87
#: /usr/local/src/bugfix.master/library/Icinga/Util/Format.php:106
#: /usr/local/src/bugfix.master/library/Icinga/Util/Format.php:108
msgid "since"
msgstr "seit"
#: /usr/local/src/bugfix.master/application/views/scripts/config/devtools.phtml:5
msgid "toggle"
msgstr "umschalten"
#~ msgid "%d to %d of %d"
#~ msgstr "%d bis %d von %d"
#~ msgid "Installation"
#~ msgstr "Installation"
#~ msgid "Logging"
#~ msgstr "Logging"
#~ msgid "Previous"
#~ msgstr "Vorheriges"
#~ msgid "Icinga Users Login"
#~ msgstr "Icinga Benutzeranmeldung"

View File

@ -3,7 +3,6 @@
// {{{ICINGA_LICENSE_HEADER}}}
use Icinga\Application\Icinga;
use Icinga\Application\Config;
use Icinga\Util\DateTimeFactory;
use Icinga\Web\Form\Validator\DateTimeValidator;
@ -109,10 +108,8 @@ class Zend_View_Helper_DateFormat extends Zend_View_Helper_Abstract
*/
public function getDateFormat()
{
return $this->request->getUser()->getPreferences()->get(
'app.dateFormat',
Config::app()->global !== null ? Config::app()->global->get('dateFormat', 'd/m/Y') : 'd/m/Y'
);
// TODO(mh): Missing localized format (#6077)
return 'd/m/Y';
}
/**
@ -122,10 +119,8 @@ class Zend_View_Helper_DateFormat extends Zend_View_Helper_Abstract
*/
public function getTimeFormat()
{
return $this->request->getUser()->getPreferences()->get(
'app.timeFormat',
Config::app()->global !== null ? Config::app()->global->get('timeFormat', 'g:i A') : 'g:i A'
);
// TODO(mh): Missing localized format (#6077)
return 'g:i A';
}
/**

View File

@ -2,6 +2,11 @@
<?= $this->tabs ?>
</div>
<div class="content" >
<?= $this->form ?>
<div class="content">
<h1><?= $this->escape($this->translate('This feature is deactivated at the moment.')); ?></h1>
<p>
<?=
$this->escape($this->translate('Please have a little patience, we are hard working on it, take a look at icingaweb2 issues.'));
?>
</p>
</div>

View File

@ -7,16 +7,10 @@
</div>
<?php else: ?>
<div class="content">
<h1>No dashboard configuration found!</h1>
<p>
<?=
$this->translate('We tried to load a dashboard configuration with no success.'
. ' Please have look that the configuration does exist:');
?>
<code>
<?= $this->escape($this->configPath) ?>.ini
</code>
</p>
<h1><?= $this->escape($this->translate('Welcome to Icinga Web!')) ?></h1>
<p><?= sprintf(
$this->escape($this->translate('Currently there is no dashlet available. This might change once you enabled some of the available %s.')),
$this->qlink($this->translate('modules'), 'config/modules')
) ?></p>
</div>
<?php endif; ?>
<?php endif ?>

View File

@ -1 +1,13 @@
<?php
use Icinga\Web\Widget\SearchDashboard;
?>
<? if (SearchDashboard::search('dummy')->getPane('search')->hasComponents()): ?>
<form action="<?= $this->href('search') ?>" method="get" role="search">
<input
type="text" name="q" class="search autofocus" placeholder="<?= $this->translate('Search...') ?>"
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"
/>
</form>
<? endif; ?>
<?= $menuRenderer; ?>

View File

@ -5,6 +5,7 @@
</div>
<div class="content">
<?php if ($this->logData !== null): ?>
<table class="action">
<tbody>
<?php foreach ($this->logData as $value): ?>
@ -21,4 +22,5 @@
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>

View File

@ -1,12 +1,8 @@
<div class="controls">
<?= $this->tabs ?>
</div>
<div class="content">
<h1><?= $this->translate("I'm ready to search, waiting for your input") ?></h1>
<p><strong><?= $this->translate('Hint') ?>: </strong><?= $this->translate(
'Please use the asterisk (*) as a placeholder for wildcard searches.'
. " For convenience I'll always add a wildcard after the last character"
. ' you typed.'
. " For convenience I'll always add a wildcard in front and after your"
. ' search string.'
) ?></p>
</div>

View File

@ -1,5 +1,5 @@
<div class="controls">
<?= $this->tabs ?>
<?= $this->dashboard->getTabs() ?>
</div>
<div class="content dashboard">

View File

@ -1,7 +1,5 @@
[global]
timezone = "Europe/Berlin"
dateFormat = "d/m/Y"
timeFormat = "g:i A"
; 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

View File

@ -1,39 +0,0 @@
[Incidents]
title = "Current incidents"
[Incidents.Service Problems]
url = "monitoring/list/services"
service_problem = 1
limit = 10
sort = service_severity
[Incidents.Recently Recovered Services]
url = "monitoring/list/services"
sort = "service_last_state_change"
service_state = 0
limit = 10
dir = "desc"
[Incidents.Host Problems]
url = "monitoring/list/hosts"
host_problem = 1
sort = host_severity
[Landing]
title = "Landing page"
[Landing.Hostgroups]
url = "monitoring/chart/hostgroup"
[Landing.Servicegroups]
url = "monitoring/chart/servicegroup"
[Landing.Unhandled Problem Services]
url = "monitoring/list/services"
service_handled = 0
service_problem = 1
[Landing.Unhandled Problem Hosts]
url = "monitoring/list/hosts"
host_handled = 0
host_problem = 1

View File

@ -1,34 +0,0 @@
[Dashboard]
title = "Dashboard"
url = "dashboard"
icon = "img/icons/dashboard.png"
priority = 10
[System]
icon = img/icons/configuration.png
priority = 200
[System.Preferences]
title = "Preferences"
url = "preference"
priority = 200
[System.Configuration]
title = "Configuration"
url = "config"
priority = 300
[System.Modules]
title = "Modules"
url = "config/modules"
priority = 400
[System.ApplicationLog]
title = "Application log"
url = "list/applicationlog"
priority = 500
[Logout]
url = "authentication/logout"
icon = img/icons/logout.png
priority = 300

View File

@ -1,5 +0,0 @@
[Documentation]
title = "Documentation"
icon = "img/icons/comment.png"
url = "doc"
priority = 80

View File

@ -1,109 +0,0 @@
[Problems]
priority = 20
icon = "img/icons/error.png"
[Problems.Unhandled Hosts]
priority = 40
url = "monitoring/list/hosts?host_problem=1&host_handled=0"
[Problems.Unhandled Services]
priority = 40
url = "monitoring/list/services?service_problem=1&service_handled=0&sort=service_severity"
[Problems.Host Problems]
priority = 50
url = "monitoring/list/hosts?host_problem=1&sort=host_severity"
[Problems.Service Problems]
priority = 50
url = "monitoring/list/services?service_problem=1&sort=service_severity&dir=desc"
[Problems.Current Downtimes]
url = "monitoring/list/downtimes?downtime_is_in_effect=1"
[Overview]
priority = 30
icon = "img/icons/hostgroup.png"
[Overview.Tactical Overview]
title = "Tactical Overview"
url = "monitoring/tactical"
priority = 40
[Overview.Hosts]
title = "Hosts"
url = "monitoring/list/hosts"
priority = 50
[Overview.Services]
title = "Services"
url = "monitoring/list/services"
priority = 50
[Overview.Servicematrix]
title = "Servicematrix"
url = "monitoring/list/servicematrix?service_problem=1"
priority = 51
[Overview.Servicegroups]
title = "Servicegroups"
url = "monitoring/list/servicegroups"
priority = 60
[Overview.Hostgroups]
title = "Hostgroups"
url = "monitoring/list/hostgroups"
priority = 60
[Overview.Contactgroups]
title = "Contactgroups"
url = "monitoring/list/contactgroups"
priority = 61
[Overview.Downtimes]
title = "Downtimes"
url = "monitoring/list/downtimes"
priority = 70
[Overview.Comments]
title = "Comments"
url = "monitoring/list/comments?comment_type=(comment|ack)"
priority = 70
[Overview.Contacts]
title = "Contacts"
url = "monitoring/list/contacts"
priority = 70
[History]
icon = "img/icons/history.png"
[History.Critical Events]
title = "Critical Events"
url = "monitoring/list/statehistorysummary"
priority = 50
[History.Notifications]
title = "Notifications"
url = "monitoring/list/notifications"
[History.Events]
title = "All Events"
url = "monitoring/list/eventhistory?timestamp>=-7%20days"
[History.Timeline]
title = "Timeline"
url = "monitoring/timeline"
[System.Process Info]
title = "Process Info"
url = "monitoring/process/info"
priority = 120
[System.Performance Info]
title = "Performance Info"
url = "monitoring/process/performance"
priority = 130

0
doc/api/.gitkeep Normal file
View File

View File

@ -1,130 +0,0 @@
# Frontend components
Frontend components are JavaScript modules that can be required directly through the HTML markup of
your view, to provide additional functionality for the user. Although its best practice to
make all features available without JavaScript, these components can be used to provide a richer
and more comfortable user experience in case JavaScript is available.
There is a certain set of frontend components which come directly with the Icinga2-Web core application,
but it is also possible to define new components directly in Icinga2-Web modules.
## How do components work?
Components are defined in JavaScript files that provide a set of functionality that will be added to the
targeted HTML node. Icinga2-Web uses [RequireJS](http://requirejs.org) to load
all frontend components, so each frontend component is in fact
[defined exactly like a RequireJS-Module](http://requirejs.org/docs/api.html#define) .
The important difference to plain RequireJS is, that the loading and execution of these components is
done automatically through the HTML markup. The attribute *data-icinga-component* in a DIV
element will indicate that this element is a container for a frontend component and will trigger
the component loader to create a component instance for this HTML node. The component loader
keeps track of all available components and makes it possible to retrieve this instance when needed.
### Component names
A component name consists of two parts: the namespace and the name of the component itself. The component
is named exactly like its JavaScript file, while the namespace is the name of the Icinga2-Web module that contains
the component. Each Icinga2-Web module can contain its own components in the folder *public/js*.
<module>/<component>
NOTE: The namespace used for modules defined in the Icinga2-Web core application is "app". In opposition to
the modules the core application keeps its modules located in *public/js/icinga/components*
instead of *public/js*.
#### Example Names
The full name for the component *modules/monitoring/public/js/someComponent.js* in the module "monitoring" would be:
"monitoring/someComponent"
The full component name for the component *public/js/icinga/components/datetime.js* in the Icinga2-Web core application
would:
"app/datetime"
## Creating a component
As described in the chapters above, components are defined exactly like RequireJS modules, but
with the additional requirement that they must always return a class constructor. The component below will
search all date pickers, set the time format and create a JavaScript date picker when there is no native one
available.
/**
* Ensures that our date/time controls will work on every browser (natively or javascript based)
*/
define(['jquery', 'datetimepicker'], function($) {
"use strict";
var DateTimePicker = function(target) {
$(target).find('.datetime input')
.attr('data-format', 'yyyy-MM-dd hh:mm:ss');
$(target).find('.datetime')
.addClass('input-append')
.append('<span class="add-on">' +
'<i data-time-icon="icon-time" data-date-icon="icon-calendar"></i></span>')
.datetimepicker();
};
return DateTimePicker;
});
## Loading a component
The following code will load the module *datetime*, which will ensure that there is always a datetime-picker
with right time-format available.
<div id="date-time-picker" data-icinga-component="app/datetime">
<div class="datetime">
<input data-format="dd/MM/yyyy hh:mm:ss" type="text"/>
</div>
</div>
### Component ids
When an ID is assigned to the HTML element, it will be used by the component loader to reference this
component. Otherwise an ID in the form "icinga-component-&lt;ID&gt;" will be created and the ID attribute in the
HTML Element will be updated accordingly.
### Component "target"
The div-element with the *data-icinga-component* will be used as the "target" for the loaded component,
which means that the component will perform its actions on this HTML node.
# Retrieving a component
Sometimes it can be necessary to retrieve the instances of the components itself, for example when they implement
additional functions that can be called. The component loader is available in the Icinga object and can be used
to retrieve component instances using their ID or their full component name.
## By component id
var component = Icinga.components.getById("component-id");
component.doSomething();
## By full component name
var components = Icinga.components.getByType("app/datetime");
// ... do something with every component of the type app/datetime
## All components
var components = Icinga.components.getComponents();
// ... do something with every component

View File

@ -14,30 +14,4 @@ the objects you're interested in and can add and remove elements.
* The dashboard itself is just the view containing the panes
## Configuration files
By default, the config/dashboard/dashboard.ini is used for storing dashboards in the following format:
[PaneName] ; Define a new Pane
title = "PaneTitle" ; The title of the pane as displayed in the tabls
[PaneName.Component1] ; Define a new component 'Component 1' underneat the pane
url = "/url/for/component1" ; the url that will be displayed, with view=compact as URL parameter appended
height = "500px" ; optional height setting
width = "400px" ; optional width setting
[test.My hosts] ; Another component, here with host
url = "monitoring/list/hosts" ; the url of the component
; Notice the missing height/width definition
[test.My services] ; And another pane
url = "monitoring/list/services" ; With service url
[test2] ; Define a second pane
title = "test2" ; with the title
[test2.test] ; Add a component to the second pane
url = "/monitoring/show/host/host1" ; ...and define it's url
[dashboards1]: res/Dashboard.png

View File

@ -238,6 +238,77 @@ the labels to show you can use the 'disableLegend()' call on the GridChart objec
![Various Line Graph Options][graph7]
### Tooltips
It is possible to specify custom tooltip format strings when creating bar charts.
Tooltips provide information about the points of each bar chart column, by aggregating
the values of all data sets with the same x-coordinate.
When no custom format string is given, a sane default format string is used, but its usually
clearer for the user to describe the data of each chart more accurately with a custom one.
**Example #9.1: Bar Charts with custom tooltips**
$this->chart->drawBars(
array(
'label' => 'Hosts critical',
'palette' => Palette::PROBLEM,
'stack' => 'stack1',
'data' => $data2,
'tooltip' => '{title}<br/> {value} of {sum} hosts are ok.'
),
array(
'label' => 'Hosts warning',
'stack' => 'stack1',
'palette' => Palette::WARNING,
'data' => $data,
'tooltip' => '{title}<br/> Oh no, {value} of {sum} hosts are down!'
)
);
As you can see, you can specify a format string for each data set, which allows you to
pass a custom message for all "down" hosts, one custom message for all "Ok" hosts and so on.
In contrast to that, the aggregation of values works on a column basis and will give you the
sum of all y-values with the same x-coordinate and not the aggregation of all values of the data set.
#### Rich Tooltips
It is also possible to use HTML in the tooltip strings to create rich tooltip markups, which can
be useful to provide extended output that spans over multiple lines. Please keep in mind that
users without JavaScript will see the tooltip with all of its html-tags stripped.
![Various Line Graph Options][graph7.1]
#### Available replacements
The available replacements depend on the used chart type, since the tooltip data is
instantiated and populated by the chart. All bar graphs have the following replacements available:
Aggregated values, are calculated from the data points of each column:
- sum: The amount of all Y-values of the current column
- max: The biggest occurring Y-value of the current column
- min: The smallest occurring Y-value of the current column
Column values are also defined by the current column, but are not
the product of any aggregation
- title: The x-value of the current column
Row values are defined by the properties the current data set, and are only useful for rendering the
generic tooltip correctly, since you could also just directly write
those values into your custom tooltip.
- label: The name of the current data set
- color: The color of this data set
## Pie Charts
### The PieChart Object
@ -317,5 +388,6 @@ Rendering is straightforward, assuming $svg is the PieChart/GridChart object, yo
[graph5]: res/GraphExample#5.png
[graph6]: res/GraphExample#6.png
[graph7]: res/GraphExample#7.png
[graph7.1]: res/GraphExample#7.1.png
[graph8]: res/GraphExample#8.png
[graph9]: res/GraphExample#9.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

View File

@ -83,7 +83,7 @@ BuildArch: noarch
AutoReqProv: Off
%endif
Source0: icingaweb2-%{version}.tar.gz
Source: icingaweb2-%{version}.tar.gz
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root
@ -181,15 +181,10 @@ install -D -m0644 packages/rpm/etc/httpd/conf.d/icingaweb.conf %{buildroot}/%{ap
%{__cp} -r application library modules public %{buildroot}/%{sharedir}/
## config
# use the default menu.ini for application and monitoring mobule
install -D -m0644 config/menu.ini %{buildroot}/%{_sysconfdir}/icingaweb/menu.ini
install -D -m0644 config/modules/monitoring/menu.ini %{buildroot}/%{_sysconfdir}/icingaweb/modules/monitoring/menu.ini
# authentication is db only
install -D -m0644 packages/rpm/etc/icingaweb/authentication.ini %{buildroot}/%{_sysconfdir}/icingaweb/authentication.ini
# custom resource paths
install -D -m0644 packages/rpm/etc/icingaweb/resources.ini %{buildroot}/%{_sysconfdir}/icingaweb/resources.ini
# dashboard
install -D -m0644 config/dashboard/dashboard.ini %{buildroot}/%{_sysconfdir}/icingaweb/dashboard/dashboard.ini
# monitoring module (icinga2)
install -D -m0644 packages/rpm/etc/icingaweb/modules/monitoring/backends.ini %{buildroot}/%{_sysconfdir}/icingaweb/modules/monitoring/backends.ini
install -D -m0644 packages/rpm/etc/icingaweb/modules/monitoring/instances.ini %{buildroot}/%{_sysconfdir}/icingaweb/modules/monitoring/instances.ini

View File

@ -14,6 +14,7 @@ use Icinga\Exception\NotReadableError;
use Icinga\Logger\Logger;
use Icinga\Util\DateTimeFactory;
use Icinga\Util\Translator;
use Icinga\Exception\IcingaException;
/**
* This class bootstraps a thin Icinga application layer
@ -332,7 +333,7 @@ abstract class ApplicationBootstrap
try {
$this->moduleManager->loadEnabledModules();
} catch (NotReadableError $e) {
Logger::error(new Exception('Cannot load enabled modules. An exception was thrown:', 0, $e));
Logger::error(new IcingaException('Cannot load enabled modules. An exception was thrown:', $e));
}
return $this;
}
@ -369,7 +370,7 @@ abstract class ApplicationBootstrap
try {
$this->config = Config::app();
} catch (NotReadableError $e) {
Logger::error(new Exception('Cannot load application configuration. An exception was thrown:', 0, $e));
Logger::error(new IcingaException('Cannot load application configuration. An exception was thrown:', $e));
$this->config = new Zend_Config(array());
}
return $this;
@ -417,7 +418,7 @@ abstract class ApplicationBootstrap
ResourceFactory::setConfig($config);
} catch (NotReadableError $e) {
Logger::error(
new Exception('Cannot load resource configuration. An exception was thrown:', 0, $e)
new IcingaException('Cannot load resource configuration. An exception was thrown:', $e)
);
}
@ -451,9 +452,8 @@ abstract class ApplicationBootstrap
*/
protected function setupInternationalization()
{
$localeDir = $this->getApplicationDir('locale');
if (file_exists($localeDir) && is_dir($localeDir)) {
Translator::registerDomain(Translator::DEFAULT_DOMAIN, $localeDir);
if ($this->hasLocales()) {
Translator::registerDomain(Translator::DEFAULT_DOMAIN, $this->getLocaleDir());
}
try {
@ -468,4 +468,48 @@ abstract class ApplicationBootstrap
return $this;
}
/**
* @return string Our locale directory
*/
public function getLocaleDir()
{
return $this->getApplicationDir('locale');
}
/**
* return bool Whether Icinga Web has translations
*/
public function hasLocales()
{
$localedir = $this->getLocaleDir();
return file_exists($localedir) && is_dir($localedir);
}
/**
* List all available locales
*
* NOTE: Might be a candidate for a static function in Translator
*
* return array Locale list
*/
public function listLocales()
{
$locales = array();
if (! $this->hasLocales()) {
return $locales;
}
$localedir = $this->getLocaleDir();
$dh = opendir($localedir);
while (false !== ($file = readdir($dh))) {
$filename = $localedir . DIRECTORY_SEPARATOR . $file;
if (preg_match('/^[a-z]{2}_[A-Z]{2}$/', $file) && is_dir($filename)) {
$locales[] = $file;
}
}
closedir($dh);
sort($locales);
return $locales;
}
}

View File

@ -61,7 +61,10 @@ class Config extends Zend_Config
$this->configFile = $filepath;
$this->merge(new Zend_Config_Ini($filepath));
} else {
throw new NotReadableError('Cannot read config file "' . $filename . '". Permission denied');
throw new NotReadableError(
'Cannot read config file "%s". Permission denied',
$filename
);
}
}
@ -82,6 +85,18 @@ class Config extends Zend_Config
return self::$app[$configname];
}
/**
* Set module config
*
* @param string $moduleName
* @param string $configName
* @param Zend_Config $config
*/
public static function setModuleConfig($moduleName, $configName, Zend_Config $config)
{
self::$modules[$moduleName][$configName] = $config;
}
/**
* Retrieve a module config instance
*

View File

@ -39,11 +39,11 @@ class Loader
public function registerNamespace($namespace, $directory)
{
if (!is_dir($directory)) {
throw new ProgrammingError(sprintf(
throw new ProgrammingError(
'Directory "%s" for namespace "%s" does not exist',
$directory,
$namespace
));
);
}
$this->namespaces[$namespace] = $directory;

View File

@ -110,12 +110,14 @@ class Manager
}
if (!is_dir($this->enableDir)) {
throw new NotReadableError(
'Cannot read enabled modules. Module directory "' . $this->enableDir . '" is not a directory'
'Cannot read enabled modules. Module directory "%s" is not a directory',
$this->enableDir
);
}
if (!is_readable($this->enableDir)) {
throw new NotReadableError(
'Cannot read enabled modules. Module directory "' . $this->enableDir . '" is not readable'
'Cannot read enabled modules. Module directory "%s" is not readable',
$this->enableDir
);
}
if (($dh = opendir($canonical)) !== false) {
@ -206,10 +208,8 @@ class Manager
{
if (!$this->hasInstalled($name)) {
throw new ConfigurationError(
sprintf(
'Cannot enable module "%s". Module is not installed.',
$name
)
);
}
@ -219,8 +219,8 @@ class Manager
if (!is_writable($this->enableDir)) {
throw new SystemPermissionException(
'Can not enable module "' . $name . '". '
. 'Insufficient system permissions for enabling modules.'
'Can not enable module "%s". Insufficient system permissions for enabling modules.',
$name
);
}
@ -232,9 +232,11 @@ class Manager
$error = error_get_last();
if (strstr($error["message"], "File exists") === false) {
throw new SystemPermissionException(
'Could not enable module "' . $name . '" due to file system errors. '
'Could not enable module "%s" due to file system errors. '
. 'Please check path and mounting points because this is not a permission error. '
. 'Primary error was: ' . $error['message']
. 'Primary error was: %s',
$name,
$error['message']
);
}
}
@ -268,14 +270,18 @@ class Manager
}
$link = $this->enableDir . '/' . $name;
if (!file_exists($link)) {
throw new ConfigurationError('Could not disable module. The module ' . $name . ' was not found.');
throw new ConfigurationError(
'Could not disable module. The module %s was not found.',
$name
);
}
if (!is_link($link)) {
throw new ConfigurationError(
'Could not disable module. The module "' . $name . '" is not a symlink. '
'Could not disable module. The module "%s" 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.',
$name
);
}
@ -283,9 +289,11 @@ class Manager
if (!@unlink($link)) {
$error = error_get_last();
throw new SystemPermissionException(
'Could not disable module "' . $name . '" due to file system errors. '
'Could not disable module "%s" due to file system errors. '
. 'Please check path and mounting points because this is not a permission error. '
. 'Primary error was: ' . $error['message']
. 'Primary error was: %s',
$name,
$error['message']
);
}
}
@ -319,10 +327,8 @@ class Manager
}
throw new ProgrammingError(
sprintf(
'Trying to access uninstalled module dir: %s',
$name
)
);
}
@ -388,10 +394,8 @@ class Manager
{
if (!$this->hasLoaded($name)) {
throw new ProgrammingError(
sprintf(
'Cannot access module %s as it hasn\'t been loaded',
$name
)
);
}
return $this->loadedModules[$name];

View File

@ -5,17 +5,22 @@
namespace Icinga\Application\Modules;
use Exception;
use Zend_Config;
use Zend_Controller_Router_Route_Abstract;
use Zend_Controller_Router_Route as Route;
use Zend_Controller_Router_Route_Regex as RegexRoute;
use Icinga\Application\ApplicationBootstrap;
use Icinga\Application\Config;
use Icinga\Application\Icinga;
use Icinga\Logger\Logger;
use Icinga\Util\Translator;
use Icinga\Web\Hook;
use Icinga\Web\Menu;
use Icinga\Web\Widget;
use Icinga\Web\Widget\Dashboard\Pane;
use Icinga\Util\File;
use Icinga\Exception\ProgrammingError;
use Icinga\Exception\IcingaException;
/**
* Module handling
@ -136,7 +141,6 @@ class Module
*/
private $app;
/**
* Routes to add to the route chain
*
@ -146,6 +150,97 @@ class Module
*/
protected $routes = array();
/**
* A set of menu elements
*
* @var array
*/
protected $menuItems = array();
/**
* A set of Pane elements
*
* @var array
*/
protected $paneItems = array();
/**
* @var array
*/
protected $searchUrls = array();
/**
* @param string $title
* @param string $url
*/
public function provideSearchUrl($title, $url)
{
$searchUrl = (object) array(
'title' => $title,
'url' => $url
);
$this->searchUrls[] = $searchUrl;
}
public function getSearchUrls()
{
$this->launchConfigScript();
return $this->searchUrls;
}
/**
* Get all Menu Items
*
* @return array
*/
public function getPaneItems()
{
$this->launchConfigScript();
return $this->paneItems;
}
/**
* Add a pane to dashboard
*
* @param $name
* @return Pane
*/
protected function dashboard($name)
{
$this->paneItems[$name] = new Pane($name);
return $this->paneItems[$name];
}
/**
* Get all Menu Items
*
* @return array
*/
public function getMenuItems()
{
$this->launchConfigScript();
return $this->menuItems;
}
/**
* Add a menu Section to the Sidebar menu
*
* @param $name
* @param array $properties
* @return mixed
*/
protected function menuSection($name, array $properties = array())
{
if (array_key_exists($name, $this->menuItems)) {
$this->menuItems[$name]->setProperties($properties);
} else {
$this->menuItems[$name] = new Menu($name, new Zend_Config($properties));
}
return $this->menuItems[$name];
}
/**
* Create a new module object
*
@ -559,8 +654,9 @@ class Module
protected function providePermission($name, $description)
{
if ($this->providesPermission($name)) {
throw new Exception(
sprintf('Cannot provide permission "%s" twice', $name)
throw new IcingaException(
'Cannot provide permission "%s" twice',
$name
);
}
$this->permissionList[$name] = (object) array(
@ -580,8 +676,9 @@ class Module
protected function provideRestriction($name, $description)
{
if ($this->providesRestriction($name)) {
throw new Exception(
sprintf('Cannot provide restriction "%s" twice', $name)
throw new IcingaException(
'Cannot provide restriction "%s" twice',
$name
);
}
$this->restrictionList[$name] = (object) array(
@ -637,12 +734,44 @@ class Module
*/
protected function registerLocales()
{
if (file_exists($this->localedir) && is_dir($this->localedir)) {
if ($this->hasLocales()) {
Translator::registerDomain($this->name, $this->localedir);
}
return $this;
}
/**
* return bool Whether this module has translations
*/
public function hasLocales()
{
return file_exists($this->localedir) && is_dir($this->localedir);
}
/**
* List all available locales
*
* return array Locale list
*/
public function listLocales()
{
$locales = array();
if (! $this->hasLocales()) {
return $locales;
}
$dh = opendir($this->localedir);
while (false !== ($file = readdir($dh))) {
$filename = $this->localedir . DIRECTORY_SEPARATOR . $file;
if (preg_match('/^[a-z]{2}_[A-Z]{2}$/', $file) && is_dir($filename)) {
$locales[] = $file;
}
}
closedir($dh);
sort($locales);
return $locales;
}
/**
* Register web integration
*
@ -693,12 +822,15 @@ class Module
);
$router->addRoute(
$this->name . '_img',
new Route(
'img/' . $this->name . '/:file',
new RegexRoute(
'img/' . $this->name . '/(.+)',
array(
'controller' => 'static',
'action' => 'img',
'module_name' => $this->name
),
array(
1 => 'file'
)
)
);
@ -781,4 +913,15 @@ class Module
$this->routes[$name] = $route;
return $this;
}
/**
* Translate a string with the global mt()
*
* @param $string
* @return mixed|string
*/
protected function translate($string)
{
return mt($this->name, $string);
}
}

View File

@ -4,22 +4,57 @@
namespace Icinga\Application;
/**
* Platform tests for icingaweb
*/
class Platform
{
/**
* Domain name
*
* @var string
*/
protected static $domain;
/**
* Host name
*
* @var string
*/
protected static $hostname;
/**
* Fully qualified domain name
*
* @var string
*/
protected static $fqdn;
/**
* Test of windows
*
* @return bool
*/
public static function isWindows()
{
return strtoupper(substr(PHP_OS, 0, 3)) === 'WIN';
}
/**
* Test of linux
*
* @return bool
*/
public static function isLinux()
{
return strtoupper(substr(PHP_OS, 0, 5)) === 'LINUX';
}
/**
* Test of CLI environment
*
* @return bool
*/
public static function isCli()
{
if (PHP_SAPI == 'cli') {
@ -31,6 +66,11 @@ class Platform
return false;
}
/**
* Get the hostname
*
* @return string
*/
public static function getHostname()
{
if (self::$hostname === null) {
@ -39,6 +79,11 @@ class Platform
return self::$hostname;
}
/**
* Get the domain name
*
* @return string
*/
public static function getDomain()
{
if (self::$domain === null) {
@ -47,6 +92,11 @@ class Platform
return self::$domain;
}
/**
* Get the fully qualified domain name
*
* @return string
*/
public static function getFqdn()
{
if (self::$fqdn === null) {
@ -55,6 +105,9 @@ class Platform
return self::$fqdn;
}
/**
* Initialize domain and host strings
*/
protected static function discoverHostname()
{
self::$hostname = gethostname();
@ -66,4 +119,16 @@ class Platform
self::$domain = array_shift(preg_split('~\.~', self::$hostname, 2));
}
}
/**
* Test for php extension
*
* @param string $extensionName E.g. mysql, ldap
*
* @return bool
*/
public static function extensionLoaded($extensionName)
{
return extension_loaded($extensionName);
}
}

View File

@ -10,11 +10,10 @@ use Icinga\Authentication\Manager as AuthenticationManager;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\NotReadableError;
use Icinga\Logger\Logger;
use Icinga\Util\TimezoneDetect;
use Icinga\Web\Request;
use Icinga\Web\Response;
use Icinga\Web\View;
use Icinga\Web\Session\Session as BaseSession;
use Icinga\Web\Session;
use Icinga\User;
use Icinga\Util\Translator;
use Icinga\Util\DateTimeFactory;
@ -59,13 +58,6 @@ class Web extends ApplicationBootstrap
*/
private $request;
/**
* Session object
*
* @var BaseSession
*/
private $session;
/**
* User object
*
@ -92,7 +84,6 @@ class Web extends ApplicationBootstrap
->setupErrorHandling()
->loadConfig()
->setupResourceFactory()
->setupSession()
->setupUser()
->setupTimezone()
->setupLogger()
@ -172,7 +163,6 @@ class Web extends ApplicationBootstrap
$this->setupFrontController();
$this->setupViewRenderer();
return $this;
}
@ -192,17 +182,6 @@ class Web extends ApplicationBootstrap
return $this;
}
/**
* Initialize a session provider
*
* @return self
*/
private function setupSession()
{
$this->session = Session::create();
return $this;
}
/**
* Inject dependencies into request
*
@ -295,10 +274,11 @@ class Web extends ApplicationBootstrap
*/
protected function setupTimezone()
{
if ($this->user !== null && $this->user->getPreferences() !== null) {
$userTimezone = $this->user->getPreferences()->get('app.timezone');
} else {
$userTimezone = null;
if ($this->user !== null && $this->user->getPreferences() !== null) {
$detect = new TimezoneDetect();
$userTimezone = $this->user->getPreferences()->get('app.timezone', $detect->getTimezoneName());
}
try {

View File

@ -2,7 +2,7 @@
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
use \Icinga\Util\Translator;
use Icinga\Util\Translator;
if (extension_loaded('gettext')) {
function t($messageId)

View File

@ -97,7 +97,9 @@ class AuthChain implements Iterator
} catch (ConfigurationError $e) {
Logger::error(
new ConfigurationError(
'Cannot create authentication backend "' . $name . '". An exception was thrown:', 0, $e
'Cannot create authentication backend "%s". An exception was thrown:',
$name,
$e
)
);
$this->next();

View File

@ -11,6 +11,7 @@ use Icinga\Exception\AuthenticationException;
use Exception;
use Zend_Db_Expr;
use Zend_Db_Select;
use Icinga\Exception\IcingaException;
class DbUserBackend extends UserBackend
{
@ -60,7 +61,10 @@ class DbUserBackend extends UserBackend
return false;
}
if ($salt === '') {
throw new Exception('Cannot find salt for user ' . $user->getUsername());
throw new IcingaException(
'Cannot find salt for user %s',
$user->getUsername()
);
}
$select = new Zend_Db_Select($this->conn->getConnection());
@ -73,12 +77,9 @@ class DbUserBackend extends UserBackend
return ($row !== false) ? true : false;
} catch (Exception $e) {
throw new AuthenticationException(
sprintf(
'Failed to authenticate user "%s" against backend "%s". An exception was thrown:',
$user->getUsername(),
$this->getName()
),
0,
$this->getName(),
$e
);
}

View File

@ -68,21 +68,17 @@ class LdapUserBackend extends UserBackend
$result = $q->fetchRow();
if (! isset($result)) {
throw new AuthenticationException(
sprintf(
'No objects with objectClass="%s" in DN="%s" found.',
$this->userClass,
$this->conn->getDN()
)
);
}
if (! isset($result->{$this->userNameAttribute})) {
throw new AuthenticationException(
sprintf(
'UserNameAttribute "%s" not existing in objectClass="%s"',
$this->userNameAttribute,
$this->userClass
)
);
}
}
@ -121,11 +117,8 @@ class LdapUserBackend extends UserBackend
} catch (AuthenticationException $e) {
// Authentication not possible
throw new AuthenticationException(
sprintf(
'Authentication against backend "%s" not possible: ',
$this->getName()
),
0,
$this->getName(),
$e
);
}
@ -141,12 +134,9 @@ class LdapUserBackend extends UserBackend
} catch (LdapException $e) {
// Error during authentication of this specific user
throw new AuthenticationException(
sprintf(
'Failed to authenticate user "%s" against backend "%s". An exception was thrown:',
$user->getUsername(),
$this->getName()
),
0,
$this->getName(),
$e
);
}

View File

@ -13,6 +13,7 @@ use Icinga\Exception\NotReadableError;
use Icinga\Application\Config as IcingaConfig;
use Icinga\User\Preferences;
use Icinga\User\Preferences\PreferencesStore;
use Icinga\Exception\IcingaException;
class Manager
{
@ -55,7 +56,11 @@ class Manager
$config = IcingaConfig::app();
} catch (NotReadableError $e) {
Logger::error(
new Exception('Cannot load preferences for user "' . $username . '". An exception was thrown', 0, $e)
new IcingaException(
'Cannot load preferences for user "%s". An exception was thrown',
$username,
$e
)
);
$config = new Zend_Config(array());
}
@ -68,8 +73,10 @@ class Manager
$preferences = new Preferences($preferencesStore->load());
} catch (NotReadableError $e) {
Logger::error(
new Exception(
'Cannot load preferences for user "' . $username . '". An exception was thrown', 0, $e
new IcingaException(
'Cannot load preferences for user "%s". An exception was thrown',
$username,
$e
)
);
$preferences = new Preferences();

View File

@ -54,16 +54,18 @@ abstract class UserBackend implements Countable
// Use a custom backend class, this is only useful for testing
if (!class_exists($backendConfig->class)) {
throw new ConfigurationError(
'Authentication configuration for backend "' . $name . '" defines an invalid backend'
. ' class. Backend class "' . $backendConfig->class. '" not found'
'Authentication configuration for backend "%s" defines an invalid backend class.'
. ' Backend class "%s" not found',
$name,
$backendConfig->class
);
}
return new $backendConfig->class($backendConfig);
}
if (($backendType = $backendConfig->backend) === null) {
throw new ConfigurationError(
'Authentication configuration for backend "' . $name
. '" is missing the backend directive'
'Authentication configuration for backend "%s" is missing the backend directive',
$name
);
}
$backendType = strtolower($backendType);
@ -74,8 +76,8 @@ abstract class UserBackend implements Countable
}
if ($backendConfig->resource === null) {
throw new ConfigurationError(
'Authentication configuration for backend "' . $name
. '" is missing the resource directive'
'Authentication configuration for backend "%s" is missing the resource directive',
$name
);
}
try {
@ -100,22 +102,24 @@ abstract class UserBackend implements Countable
case 'ldap':
if (($userClass = $backendConfig->user_class) === null) {
throw new ConfigurationError(
'Authentication configuration for backend "' . $name
. '" is missing the user_class directive'
'Authentication configuration for backend "%s" is missing the user_class directive',
$name
);
}
if (($userNameAttribute = $backendConfig->user_name_attribute) === null) {
throw new ConfigurationError(
'Authentication configuration for backend "' . $name
. '" is missing the user_name_attribute directive'
'Authentication configuration for backend "%s" is missing the user_name_attribute directive',
$name
);
}
$backend = new LdapUserBackend($resource, $userClass, $userNameAttribute);
break;
default:
throw new ConfigurationError(
'Authentication configuration for backend "' . $name. '" defines an invalid backend'
. ' type. Backend type "' . $backendType . '" is not supported'
'Authentication configuration for backend "%s" defines an invalid backend type.'
. ' Backend type "%s" is not supported',
$name,
$backendType
);
}
$backend->setName($name);

View File

@ -9,12 +9,15 @@ use Icinga\Chart\Legend;
use Icinga\Chart\Palette;
use Icinga\Chart\Primitive\Drawable;
use Icinga\Chart\SVGRenderer;
use Icinga\Exception\IcingaException;
/**
* Base class for charts, extended by all other Chart classes.
*/
abstract class Chart implements Drawable
{
protected $align = false;
/**
* SVG renderer that handles
*
@ -89,17 +92,31 @@ abstract class Chart implements Drawable
*
* @return string The SVG created by the SvgRenderer
*
* @throws Exception Thrown wen the dataset is not valid for this graph
* @throws IcingaException Thrown wen the dataset is not valid for this graph
* @see SVGRenderer::render
*/
public function render()
{
if (!$this->isValidDataFormat()) {
throw new Exception('Dataset for graph doesn\'t have the proper structure');
throw new IcingaException('Dataset for graph doesn\'t have the proper structure');
}
$this->build();
if ($this->align) {
$this->renderer->preserveAspectRatio();
$this->renderer->setXAspectRatioAlignment(SVGRenderer::X_ASPECT_RATIO_MIN);
$this->renderer->setYAspectRatioAlignment(SVGRenderer::Y_ASPECT_RATIO_MIN);
}
$this->renderer->getCanvas()->addElement($this);
return $this->renderer->render();
}
/**
* Align the chart to the top left corner instead of centering it
*
* @param bool $align
*/
public function alignTopLeft ($align = true)
{
$this->align = $align;
}
}

View File

@ -16,6 +16,13 @@ use Icinga\Chart\Render\RenderContext;
*/
class BarGraph extends Styleable implements Drawable
{
/**
* The dataset order
*
* @var int
*/
private $order = 0;
/**
* The width of the bars.
*
@ -30,14 +37,37 @@ class BarGraph extends Styleable implements Drawable
*/
private $dataSet;
/**
* The tooltips
*
* @var
*/
private $tooltips;
/**
* All graphs
*
* @var
*/
private $graphs;
/**
* Create a new BarGraph with the given dataset
*
* @param array $dataSet An array of datapoints
* @param array $dataSet An array of data points
* @param int $order The graph number displayed by this BarGraph
* @param array $tooltips The tooltips to display for each value
*/
public function __construct(array $dataSet)
{
public function __construct(
array $dataSet,
array &$graphs,
$order,
array $tooltips = null
) {
$this->order = $order;
$this->dataSet = $dataSet;
$this->tooltips = $tooltips;
$this->graphs = $graphs;
}
/**
@ -56,6 +86,30 @@ class BarGraph extends Styleable implements Drawable
}
}
/**
* Draw a single rectangle
*
* @param array $point The
* @param null $index
* @param string $fill The fill color to use
* @param $strokeWidth
*
* @return Rect
*/
private function drawSingleBar($point, $index = null, $fill, $strokeWidth)
{
$rect = new Rect($point[0] - ($this->barWidth / 2), $point[1], $this->barWidth, 100 - $point[1]);
$rect->setFill($fill);
$rect->setStrokeWidth($strokeWidth);
$rect->setStrokeColor('black');
if (isset($index)) {
$rect->setAttribute('data-icinga-graph-index', $index);
}
$rect->setAttribute('data-icinga-graph-type', 'bar');
$rect->setAdditionalStyle('clip-path: url(#clip);');
return $rect;
}
/**
* Render this BarChart
*
@ -68,23 +122,33 @@ class BarGraph extends Styleable implements Drawable
$doc = $ctx->getDocument();
$group = $doc->createElement('g');
$idx = 0;
foreach ($this->dataSet as $point) {
$rect = new Rect($point[0] - 2, $point[1], 4, 100 - $point[1]);
$rect->setFill($this->fill);
$rect->setStrokeWidth($this->strokeWidth);
$rect->setStrokeColor('black');
$rect->setAttribute('data-icinga-graph-index', $idx++);
$rect->setAttribute('data-icinga-graph-type', 'bar');
$rect->setAdditionalStyle('clip-path: url(#clip);');
/*$rect->setAnimation(
new Animation(
'y',
$ctx->yToAbsolute(100),
$ctx->yToAbsolute($point[1]),
rand(1, 1.5)/2
)
);*/
$group->appendChild($rect->toSvg($ctx));
foreach ($this->dataSet as $x => $point) {
// add white background bar, to prevent other bars from altering transparency effects
$bar = $this->drawSingleBar($point, $idx++, 'white', $this->strokeWidth, $idx)->toSvg($ctx);
$group->appendChild($bar);
// draw actual bar
$bar = $this->drawSingleBar($point, null, $this->fill, $this->strokeWidth, $idx)->toSvg($ctx);
$bar->setAttribute('class', 'chart-data');
if (isset($this->tooltips[$x])) {
$data = array(
'label' => isset($this->graphs[$this->order]['label']) ?
strtolower($this->graphs[$this->order]['label']) : '',
'color' => isset($this->graphs[$this->order]['color']) ?
strtolower($this->graphs[$this->order]['color']) : '#fff'
);
$format = isset($this->graphs[$this->order]['tooltip'])
? $this->graphs[$this->order]['tooltip'] : null;
$bar->setAttribute(
'title',
$this->tooltips[$x]->renderNoHtml($this->order, $data, $format)
);
$bar->setAttribute(
'data-title-rich',
$this->tooltips[$x]->render($this->order, $data, $format)
);
}
$group->appendChild($bar);
}
return $group;
}

View File

@ -41,6 +41,10 @@ class StackedGraph implements Drawable
if (!isset($this->points[$x])) {
$this->points[$x] = 0;
}
// store old y-value for displaying the actual (non-aggregated)
// value in the tooltip
$point[2] = $point[1];
$this->points[$x] += $point[1];
$point[1] = $this->points[$x];
}

View File

@ -0,0 +1,144 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Chart\Graph;
/**
* A tooltip that stores and aggregates information about displayed data
* points of a graph and replaces them in a format string to render the description
* for specific data points of the graph.
*
* When render() is called, placeholders for the keys for each data entry will be replaced by
* the current value of this data set and the formatted string will be returned.
* The content of the replaced keys can change for each data set and depends on how the data
* is passed to this class. There are several types of properties:
*
* <ul>
* <li>Global properties</li>: Key-value pairs that stay the same every time render is called, and are
* passed to an instance in the constructor.
* <li>Aggregated properties</li>: Global properties that are created automatically from
* all attached data points.
* <li>Local properties</li>: Key-value pairs that only apply to a single data point and
* are passed to the render-function.
* </ul>
*/
class Tooltip
{
/**
* The default format string used
* when no other format is specified
*
* @var string
*/
private $defaultFormat;
/**
* All aggregated points
*
* @var array
*/
private $points = array();
/**
* Contains all static replacements
*
* @var array
*/
private $data = array(
'sum' => 0
);
/**
* Used to format the displayed tooltip.
*
* @var string
*/
protected $tooltipFormat;
/**
* Create a new tooltip with the specified default format string
*
* Allows you to set the global data for this tooltip, that is displayed every
* time render is called.
*
* @param array $data Map of global properties
* @param string $format The default format string
*/
public function __construct (
$data = array(),
$format = '<b>{title}</b></b><br/> {value} of {sum} {label}'
) {
$this->data = array_merge($this->data, $data);
$this->defaultFormat = $format;
}
/**
* Add a single data point to update the aggregated properties for this tooltip
*
* @param $point array Contains the (x,y) values of the data set
*/
public function addDataPoint($point)
{
// set x-value
if (!isset($this->data['title'])) {
$this->data['title'] = $point[0];
}
// aggregate y-values
$y = (int)$point[1];
if (isset($point[2])) {
// load original value in case value already aggregated
$y = (int)$point[2];
}
if (!isset($this->data['min']) || $this->data['min'] > $y) {
$this->data['min'] = $y;
}
if (!isset($this->data['max']) || $this->data['max'] < $y) {
$this->data['max'] = $y;
}
$this->data['sum'] += $y;
$this->points[] = $y;
}
/**
* Format the tooltip for a certain data point
*
* @param array $order Which data set to render
* @param array $data The local data for this tooltip
* @param string $format Use a custom format string for this data set
*
* @return mixed|string The tooltip value
*/
public function render($order, $data = array(), $format = null)
{
if (isset($format)) {
$str = $format;
} else {
$str = $this->defaultFormat;
}
$data['value'] = $this->points[$order];
foreach (array_merge($this->data, $data) as $key => $value) {
$str = str_replace('{' . $key . '}', $value, $str);
}
return $str;
}
/**
* Format the tooltip for a certain data point but remove all
* occurring html tags
*
* This is useful for rendering clean tooltips on client without JavaScript
*
* @param array $order Which data set to render
* @param array $data The local data for this tooltip
* @param string $format Use a custom format string for this data set
*
* @return mixed|string The tooltip value, without any HTML tags
*/
public function renderNoHtml($order, $data, $format)
{
return strip_tags($this->render($order, $data, $format));
}
}

View File

@ -10,6 +10,7 @@ use Icinga\Chart\Axis;
use Icinga\Chart\Graph\BarGraph;
use Icinga\Chart\Graph\LineGraph;
use Icinga\Chart\Graph\StackedGraph;
use Icinga\Chart\Graph\Tooltip;
use Icinga\Chart\Primitive\Canvas;
use Icinga\Chart\Primitive\Rect;
use Icinga\Chart\Primitive\Path;
@ -74,6 +75,16 @@ class GridChart extends Chart
*/
private $stacks = array();
/**
* An associative array containing all Tooltips used to render the titles
*
* Each tooltip represents the summary for all y-values of a certain x-value
* in the grid chart
*
* @var Tooltip
*/
private $tooltips = array();
/**
* Check if the current dataset has the proper structure for this chart.
*
@ -169,6 +180,26 @@ class GridChart extends Chart
$this->legend->addDataset($graph);
}
}
$this->initTooltips($data);
}
private function initTooltips($data)
{
foreach ($data as &$graph) {
foreach ($graph['data'] as $x => $point) {
if (!array_key_exists($x, $this->tooltips)) {
$this->tooltips[$x] = new Tooltip(
array(
'color' => $graph['color'],
)
);
}
$this->tooltips[$x]->addDataPoint($point);
}
}
}
/**
@ -353,11 +384,16 @@ class GridChart extends Chart
foreach ($this->graphs as $axisName => $graphs) {
$axis = $this->axis[$axisName];
$graphObj = null;
foreach ($graphs as $graph) {
foreach ($graphs as $dataset => $graph) {
// determine the type and create a graph object for it
switch ($graph['graphType']) {
case self::TYPE_BAR:
$graphObj = new BarGraph($axis->transform($graph['data']));
$graphObj = new BarGraph(
$axis->transform($graph['data']),
$graphs,
$dataset,
$this->tooltips
);
break;
case self::TYPE_LINE:
$graphObj = new LineGraph($axis->transform($graph['data']));

View File

@ -7,6 +7,7 @@ namespace Icinga\Chart\Inline;
use Icinga\Chart\PieChart as PieChartRenderer;
use Imagick;
use Exception;
use Icinga\Exception\IcingaException;
/**
* Draw an inline pie-chart directly from the available request parameters.
@ -17,11 +18,11 @@ class PieChart extends Inline
public function render($output = true)
{
$pie = new PieChartRenderer();
$pie->alignTopLeft();
$pie->disableLegend();
$pie->drawPie(array(
'data' => $this->data, 'colors' => $this->colors, 'labels' => $this->labels
));
$pie->setWidth($this->width)->setHeight($this->height);
if ($output) {
echo $pie->render();
} else {
@ -33,7 +34,7 @@ class PieChart extends Inline
{
if (! class_exists('Imagick')) {
// TODO: This is quick & dirty. 404?
throw new Exception('Cannot render PNGs without Imagick');
throw new IcingaException('Cannot render PNGs without Imagick');
}
$image = new Imagick();
$image->readImageBlob($this->render(false));

View File

@ -16,7 +16,7 @@ use Icinga\Chart\Render\LayoutBox;
/**
* Graphing component for rendering Pie Charts.
*
* See the graphs.md documentation for futher information about how to use this component
* See the graphs.md documentation for further information about how to use this component
*/
class PieChart extends Chart
{
@ -51,46 +51,6 @@ class PieChart extends Chart
*/
private $noCaption = false;
/**
* Scaling level of the rendered svgs width in percent.
*
* @var float
*/
private $width = 100;
/**
* Scaling level of the rendered svgs height in percent.
*
* @var int
*/
private $height = 100;
/**
* Set the size of the rendered pie-chart svg.
*
* @param $width int The width in percent.
*
* @return self Fluent interface
*/
public function setWidth($width)
{
$this->width = $width;
return $this;
}
/**
* Set the size of the rendered pie-chart svg.
*
* @param $height int The height in percent.
*
* @return self Fluent interface
*/
public function setHeight($height)
{
$this->height = $height;
return $this;
}
/**
* Test if the given pies have the correct format
*
@ -111,10 +71,7 @@ class PieChart extends Chart
*/
protected function build()
{
$this->renderer = new SVGRenderer(
$this->type === self::STACKED ? $this->width : count($this->pies) * $this->width,
$this->width
);
$this->renderer = new SVGRenderer(($this->type === self::STACKED) ? 1 : count($this->pies), 1);
foreach ($this->pies as &$pie) {
$this->normalizeDataSet($pie);
}
@ -165,11 +122,16 @@ class PieChart extends Chart
*/
public function toSvg(RenderContext $ctx)
{
$outerBox = new Canvas('outerGraph', new LayoutBox(0, 0, 100, 100));
$innerBox = new Canvas('graph', new LayoutBox(0, 0, 100, 100));
$labelBox = $ctx->getDocument()->createElement('g');
if (!$this->noCaption) {
// Scale SVG to make room for captions
$outerBox = new Canvas('outerGraph', new LayoutBox(33, -5, 40, 40));
$innerBox = new Canvas('graph', new LayoutBox(0, 0, 100, 100));
$innerBox->getLayout()->setPadding(10, 10, 10, 10);
} else {
$outerBox = new Canvas('outerGraph', new LayoutBox(1.5, -10, 124, 124));
$innerBox = new Canvas('graph', new LayoutBox(0, 0, 100, 100));
$innerBox->getLayout()->setPadding(0, 0, 0, 0);
}
$this->createContentClipBox($innerBox);
$this->renderPies($innerBox, $labelBox);
@ -274,9 +236,6 @@ class PieChart extends Chart
$lastRadius = 0;
foreach ($pie['data'] as $idx => $dataset) {
$color = $this->getColorForPieSlice($pie, $idx);
if ($dataset === 100) {
$dataset = 99.9;
}
if ($dataset == 0) {
$labelPos++;
continue;
@ -340,3 +299,4 @@ class PieChart extends Chart
$clipBox->addElement($rect);
}
}

View File

@ -32,7 +32,7 @@ class PieSlice extends Animatable implements Drawable
*
* @var float
*/
private $endRadian= 0;
private $endRadian = 0;
/**
* The x position of the pie slice's center
@ -104,17 +104,21 @@ class PieSlice extends Animatable implements Drawable
*/
private function getPieSlicePath($x, $y, $r)
{
// start at the center of the pieslice
$pathString = 'M ' . $x . ' ' . $y . ' ';
// The coordinate system is mirrored on the Y axis, so we have to flip cos and sin
$xStart = $x + ($r * sin($this->startRadian));
$yStart = $y - ($r * cos($this->startRadian));
$xEnd = $x + ($r * sin($this->endRadian));
$yEnd = $y - ($r * cos($this->endRadian));
if ($this->endRadian - $this->startRadian == 2*M_PI) {
// To draw a full circle, adjust arc endpoint by a small (unvisible) value
$this->endRadian -= 0.001;
$pathString = 'M ' . Format::formatSVGNumber($xStart) . ' ' . Format::formatSVGNumber($yStart);
} else {
// Start at the center of the pieslice
$pathString = 'M ' . $x . ' ' . $y;
// Draw a straight line to the upper part of the arc
$pathString .= 'L ' . Format::formatSVGNumber($xStart) . ' ' . Format::formatSVGNumber($yStart);
$pathString .= ' L ' . Format::formatSVGNumber($xStart) . ' ' . Format::formatSVGNumber($yStart);
}
// Instead of directly connecting the upper part of the arc (leaving a triangle), draw a bow with the radius
$pathString .= ' A ' . Format::formatSVGNumber($r) . ' ' . Format::formatSVGNumber($r);
// These are the flags for the bow, see the SVG path documentation for details
@ -122,7 +126,10 @@ class PieSlice extends Animatable implements Drawable
$pathString .= ' 0 ' . (($this->endRadian - $this->startRadian > M_PI) ? '1' : '0 ') . ' 1';
// xEnd and yEnd are the lower point of the arc
$xEnd = $x + ($r * sin($this->endRadian));
$yEnd = $y - ($r * cos($this->endRadian));
$pathString .= ' ' . Format::formatSVGNumber($xEnd) . ' ' . Format::formatSVGNumber($yEnd);
return $pathString;
}
@ -152,7 +159,7 @@ class PieSlice extends Animatable implements Drawable
// Draw the handle
$path = new Path(array($midX, $midY));
$midX += ($addOffset + $r/1.8) * ($midRadius > M_PI ? -1 : 1);
$midX += ($addOffset + $r/3) * ($midRadius > M_PI ? -1 : 1);
$path->append(array($midX, $midY))->toAbsolute();
$midX += intval($r/2 * sin(M_PI/9)) * ($midRadius > M_PI ? -1 : 1);
@ -169,7 +176,7 @@ class PieSlice extends Animatable implements Drawable
// Draw the text box
$text = new Text($rel[0]+1.5, $rel[1], $this->caption);
$text->setFontSize('2.5em');
$text->setFontSize('5em');
$text->setAlignment(($midRadius > M_PI ? Text::ALIGN_END : Text::ALIGN_START));
$group->appendChild($path->toSvg($ctx));

View File

@ -4,8 +4,8 @@
namespace Icinga\Chart\Primitive;
use \DomElement;
use \Icinga\Chart\Render\RenderContext;
use DomElement;
use Icinga\Chart\Render\RenderContext;
use Icinga\Chart\Format;
/**

View File

@ -132,7 +132,7 @@ class RenderContext
* @param int $x The relative x coordinate
* @param int $y The relative y coordinate
*
* @return array An x,y tupel containing absolute coordinates
* @return array An x,y tuple containing absolute coordinates
* @see RenderContext::toRelative
*/
public function toAbsolute($x, $y)

View File

@ -1,10 +1,7 @@
<?php
/**
* Created by PhpStorm.
* User: mjentsch
* Date: 22.07.14
* Time: 10:17
*/
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Chart\Render;

View File

@ -19,6 +19,22 @@ use Icinga\Chart\Primitive\Canvas;
*/
class SVGRenderer
{
const X_ASPECT_RATIO_MIN = 'xMin';
const X_ASPECT_RATIO_MID = 'xMid';
const X_ASPECT_RATIO_MAX = 'xMax';
const Y_ASPECT_RATIO_MIN = 'YMin';
const Y_ASPECT_RATIO_MID = 'YMid';
const Y_ASPECT_RATIO_MAX = 'YMax';
const ASPECT_RATIO_PAD = 'meet';
const ASPECT_RATIO_CUTOFF = 'slice';
/**
* The XML-document
*
@ -54,6 +70,35 @@ class SVGRenderer
*/
private $height = 100;
/**
* Whether the aspect ratio is preversed
*
* @var bool
*/
private $preserveAspectRatio = false;
/**
* Horizontal alignment of SVG element
*
* @var string
*/
private $xAspectRatio = self::X_ASPECT_RATIO_MID;
/**
* Vertical alignment of SVG element
*
* @var string
*/
private $yAspectRatio = self::Y_ASPECT_RATIO_MID;
/**
* Define whether aspect differences should be handled using padding (default) or cutoff
*
* @var string
*/
private $xFillMode = "meet";
/**
* Create the root document and the SVG root node
*/
@ -82,8 +127,8 @@ class SVGRenderer
$svg = $this->document->createElement('svg');
$svg->setAttribute('xmlns', 'http://www.w3.org/2000/svg');
$svg->setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
$svg->setAttribute('width', $this->width . '%');
$svg->setAttribute('height', $this->height . '%');
$svg->setAttribute('width', '100%');
$svg->setAttribute('height', '100%');
$svg->setAttribute(
'viewBox',
sprintf(
@ -92,6 +137,17 @@ class SVGRenderer
$ctx->getNrOfUnitsY()
)
);
if ($this->preserveAspectRatio) {
$svg->setAttribute(
'preserveAspectRatio',
sprintf (
'%s%s %s',
$this->xAspectRatio,
$this->yAspectRatio,
$this->xFillMode
)
);
}
return $svg;
}
@ -141,4 +197,40 @@ class SVGRenderer
{
return $this->rootCanvas;
}
/**
* Preserve the aspect ratio of the rendered object
*
* Do not deform the content of the SVG when the aspect ratio of the viewBox
* differs from the aspect ratio of the SVG element, but add padding or cutoff
* instead
*
* @param bool $preserve Whether the aspect ratio should be preserved
*/
public function preserveAspectRatio($preserve = true)
{
$this->preserveAspectRatio = $preserve;
}
/**
* Change the horizontal alignment of the SVG element
*
* Change the horizontal alignment of the svg, when preserveAspectRatio is used and
* padding is present. Defaults to
*/
public function setXAspectRatioAlignment($alignment)
{
$this->xAspectRatio = $alignment;
}
/**
* Change the vertical alignment of the SVG element
*
* Change the vertical alignment of the svg, when preserveAspectRatio is used and
* padding is present.
*/
public function setYAspectRatioAlignment($alignment)
{
$this->yAspectRatio = $alignment;
}
}

View File

@ -5,6 +5,7 @@
namespace Icinga\Cli;
use Icinga\Cli\Screen;
use Icinga\Exception\IcingaException;
// @see http://en.wikipedia.org/wiki/ANSI_escape_code
@ -74,7 +75,10 @@ class AnsiScreen extends Screen
protected function fgColor($color)
{
if (! array_key_exists($color, $this->fgColors)) {
throw new \Exception(sprintf('There is no such foreground color: %s', $color));
throw new IcingaException(
'There is no such foreground color: %s',
$color
);
}
return $this->fgColors[$color];
}
@ -82,7 +86,10 @@ class AnsiScreen extends Screen
protected function bgColor($color)
{
if (! array_key_exists($color, $this->bgColors)) {
throw new \Exception(sprintf('There is no such background color: %s', $color));
throw new IcingaException(
'There is no such background color: %s',
$color
);
}
return $this->bgColors[$color];
}

View File

@ -10,6 +10,7 @@ use Icinga\Cli\Params;
use Icinga\Application\Config;
use Icinga\Application\ApplicationBootstrap as App;
use Exception;
use Icinga\Exception\IcingaException;
abstract class Command
{
@ -123,7 +124,7 @@ abstract class Command
public function fail($msg)
{
throw new Exception($msg);
throw new IcingaException('%s', $msg);
}
public function getDefaultActionName()

View File

@ -332,7 +332,8 @@ class Loader
{
if (! $this->hasModule($module)) {
throw new ProgrammingError(
sprintf('There is no such module: %s', $module)
'There is no such module: %s',
$module
);
}
}
@ -341,7 +342,8 @@ class Loader
{
if (! $this->hasCommand($command)) {
throw new ProgrammingError(
sprintf('There is no such command: %s', $command)
'There is no such command: %s',
$command
);
}
}
@ -351,7 +353,9 @@ class Loader
$this->assertModuleExists($module);
if (! $this->hasModuleCommand($module, $command)) {
throw new ProgrammingError(
sprintf("The module '%s' has no such command: %s", $module, $command)
'The module \'%s\' has no such command: %s',
$module,
$command
);
}
}

View File

@ -38,6 +38,45 @@ class PreservingIniWriter extends Zend_Config_Writer_FileAbstract
parent::__construct($options);
}
/**
* Find all keys containing dots and convert it to a nested configuration
*
* Ensure that configurations with the same ini representation the have
* similarly nested Zend_Config objects. The configuration may be altered
* during that process.
*
* @param Zend_Config $config The configuration to normalize
* @return Zend_Config The normalized config
*/
private function normalizeKeys(Zend_Config $config)
{
foreach ($config as $key => $value) {
if (preg_match('/\./', $key) > 0) {
// remove old key
unset ($config->$key);
// insert new key
$nests = explode('.', $key);
$current = $config;
$i = 0;
for (; $i < count($nests) - 1; $i++) {
if (! isset($current->{$nests[$i]})) {
// configuration key doesn't exist, create a new nesting level
$current->{$nests[$i]} = new Zend_Config (array(), true);
}
// move to next nesting level
$current = $current->{$nests[$i]};
}
// reached last nesting level, insert value
$current->{$nests[$i]} = $value;
}
if ($value instanceof Zend_Config) {
$config->$key = $this->normalizeKeys ($value);
}
}
return $config;
}
/**
* Render the Zend_Config into a config file string
*
@ -50,6 +89,17 @@ class PreservingIniWriter extends Zend_Config_Writer_FileAbstract
} else {
$oldconfig = new Zend_Config(array());
}
// create an internal copy of the given configuration, since the user of this class
// won't expect that a configuration will ever be altered during
// the rendering process.
$extends = $this->_config->getExtends();
$this->_config = new Zend_Config ($this->_config->toArray(), true);
foreach ($extends as $extending => $extended) {
$this->_config->setExtend($extending, $extended);
}
$this->_config = $this->normalizeKeys($this->_config);
$newconfig = $this->_config;
$editor = new IniEditor(file_get_contents($this->_filename), $this->options);
$this->diffConfigs($oldconfig, $newconfig, $editor);

View File

@ -142,7 +142,10 @@ class DbConnection implements Selectable
}
break;*/
default:
throw new ConfigurationError(sprintf('Backend "%s" is not supported', $this->dbType));
throw new ConfigurationError(
'Backend "%s" is not supported',
$this->dbType
);
}
$this->dbAdapter = Zend_Db::factory($adapter, $adapterParamaters);
$this->dbAdapter->setFetchMode(Zend_Db::FETCH_OBJ);

View File

@ -11,6 +11,7 @@ use Icinga\Data\Filter\FilterExpression;
use Icinga\Data\Filter\FilterOr;
use Icinga\Data\Filter\FilterAnd;
use Icinga\Data\Filter\FilterNot;
use Icinga\Exception\IcingaException;
use Zend_Db_Select;
/**
@ -88,6 +89,17 @@ class DbQuery extends SimpleQuery
public function getSelectQuery()
{
$select = $this->dbSelect();
// Add order fields to select for postgres distinct queries (#6351)
if ($this->hasOrder()
&& $this->getDatasource()->getDbType() === 'pgsql'
&& $select->getPart(Zend_Db_Select::DISTINCT) === true) {
foreach ($this->getOrder() as $fieldAndDirection) {
list($alias, $field) = explode('.', $fieldAndDirection[0]);
$this->columns[$field] = $fieldAndDirection[0];
}
}
$select->columns($this->columns);
$this->applyFilterSql($select);
@ -101,6 +113,7 @@ class DbQuery extends SimpleQuery
);
}
}
return $select;
}
@ -124,7 +137,10 @@ class DbQuery extends SimpleQuery
$op = ' AND ';
$str .= ' NOT ';
} else {
throw new \Exception('Cannot render filter: ' . $filter);
throw new IcingaException(
'Cannot render filter: %s',
$filter
);
}
$parts = array();
if (! $filter->isEmpty()) {
@ -177,7 +193,7 @@ class DbQuery extends SimpleQuery
if (! $value) {
/*
NOTE: It's too late to throw exceptions, we might finish in __toString
throw new \Exception(sprintf(
throw new IcingaException(sprintf(
'"%s" is not a valid time expression',
$value
));

View File

@ -34,9 +34,12 @@ abstract class Filter
if ((string) $id === $this->getId()) {
return $this;
}
throw new ProgrammingError(sprintf(
'Trying to get invalid filter index "%s" from "%s" ("%s")', $id, $this, $this->id
));
throw new ProgrammingError(
'Trying to get invalid filter index "%s" from "%s" ("%s")',
$id,
$this,
$this->id
);
}
public function getId()
@ -129,14 +132,15 @@ abstract class Filter
public static function expression($col, $op, $expression)
{
switch ($op) {
case '=': return new FilterEqual($col, $op, $expression);
case '=': return new FilterMatch($col, $op, $expression);
case '<': return new FilterLessThan($col, $op, $expression);
case '>': return new FilterGreaterThan($col, $op, $expression);
case '>=': return new FilterEqualOrGreaterThan($col, $op, $expression);
case '<=': return new FilterEqualOrLessThan($col, $op, $expression);
case '!=': return new FilterNotEqual($col, $op, $expression);
case '!=': return new FilterMatchNot($col, $op, $expression);
default: throw new ProgrammingError(
sprintf('There is no such filter sign: %s', $op)
'There is no such filter sign: %s',
$op
);
}
}
@ -203,7 +207,8 @@ abstract class Filter
case 'NOT': return self::not($filters);
}
throw new ProgrammingError(
sprintf('"%s" is not a valid filter chain operator', $operator)
'"%s" is not a valid filter chain operator',
$operator
);
}

View File

@ -4,11 +4,11 @@
namespace Icinga\Data\Filter;
use Exception;
use Icinga\Exception\IcingaException;
/**
* Filter Exception Class
*
* Filter Exceptions should be thrown on filter parse errors or similar
*/
class FilterException extends Exception {}
class FilterException extends IcingaException {}

View File

@ -0,0 +1,22 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Data\Filter;
class FilterMatch extends FilterExpression
{
public function matches($row)
{
$expression = (string) $this->expression;
if (strpos($expression, '*') === false) {
return (string) $row->{$this->column} === $expression;
} else {
$parts = array();
foreach (preg_split('/\*/', $expression) as $part) {
$parts[] = preg_quote($part);
}
return preg_match('/^' . implode('.*', $parts) . '$/', $row->{$this->column});
}
}
}

View File

@ -0,0 +1,22 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Data\Filter;
class FilterMatchNot extends FilterExpression
{
public function matches($row)
{
$expression = (string) $this->expression;
if (strpos($expression, '*') === false) {
return (string) $row->{$this->column} !== $expression;
} else {
$parts = array();
foreach (preg_split('/\*/', $expression) as $part) {
$parts[] = preg_quote($part);
}
return ! preg_match('/^' . implode('.*', $parts) . '$/', $row->{$this->column});
}
}
}

View File

@ -0,0 +1,13 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Data\Filter;
class FilterNotEqual extends FilterExpression
{
public function matches($row)
{
return (string) $row->{$this->column} !== (string) $this->expression;
}
}

View File

@ -4,8 +4,8 @@
namespace Icinga\Data\Filter;
use Exception;
use Icinga\Exception\IcingaException;
class FilterParseException extends Exception
class FilterParseException extends IcingaException
{
}

View File

@ -111,13 +111,13 @@ class FilterQueryString
$extra .= "\n" . implode("\n", $this->debug);
}
throw new FilterParseException(sprintf(
throw new FilterParseException(
'Invalid filter "%s", unexpected %s at pos %d%s',
$this->string,
$char,
$this->pos,
$extra
));
);
}
protected function readFilters($nestingLevel = 0, $op = null)

View File

@ -12,15 +12,25 @@ use Icinga\Data\Db\DbConnection;
use Icinga\Protocol\Livestatus\Connection as LivestatusConnection;
use Icinga\Protocol\Statusdat\Reader as StatusdatReader;
use Icinga\Protocol\Ldap\Connection as LdapConnection;
use Icinga\Protocol\File\Reader as FileReader;
use Icinga\Protocol\File\FileReader;
/**
* Create resources from names or resource configuration
*/
class ResourceFactory implements ConfigAwareFactory
{
/**
* Resource configuration
*
* @var Zend_Config
*/
private static $resources;
/**
* Set resource configurations
*
* @param Zend_Config $config
*/
public static function setConfig($config)
{
self::$resources = $config;
@ -32,14 +42,16 @@ class ResourceFactory implements ConfigAwareFactory
* @param $resourceName String The resource's name
*
* @return Zend_Config The configuration of the resource
* @throws \Icinga\Exception\ConfigurationError
*
* @throws ConfigurationError
*/
public static function getResourceConfig($resourceName)
{
self::assertResourcesExist();
if (($resourceConfig = self::$resources->get($resourceName)) === null) {
throw new ConfigurationError(
'Cannot load resource config "' . $resourceName . '". Resource does not exist'
'Cannot load resource config "%s". Resource does not exist',
$resourceName
);
}
return $resourceConfig;
@ -71,13 +83,13 @@ class ResourceFactory implements ConfigAwareFactory
/**
* Check if the existing resources are set. If not, throw an error.
*
* @throws \Icinga\Exception\ProgrammingError
* @throws ProgrammingError
*/
private static function assertResourcesExist()
{
if (!isset(self::$resources)) {
throw new ProgrammingError(
"The ResourceFactory must be initialised by setting a config, before it can be used"
'The ResourceFactory must be initialised by setting a config, before it can be used'
);
}
}
@ -92,7 +104,7 @@ class ResourceFactory implements ConfigAwareFactory
*
* @return DbConnection|LdapConnection|LivestatusConnection|StatusdatReader An objects that can be used to access
* the given resource. The returned class depends on the configuration property 'type'.
* @throws \Icinga\Exception\ConfigurationError When an unsupported type is given
* @throws ConfigurationError When an unsupported type is given
*/
public static function createResource(Zend_Config $config)
{
@ -113,23 +125,22 @@ class ResourceFactory implements ConfigAwareFactory
$resource = new FileReader($config);
break;
default:
throw new ConfigurationError('Unsupported resource type "' . $config->type . '"');
throw new ConfigurationError(
'Unsupported resource type "%s"',
$config->type
);
}
return $resource;
}
public static function ldapAvailable()
/**
* Create a resource from name
*
* @param string $resourceName
* @return DbConnection|LdapConnection|LivestatusConnection|StatusdatReader
*/
public static function create($resourceName)
{
return extension_loaded('ldap');
}
public static function pgsqlAvailable()
{
return extension_loaded('pgsql');
}
public static function mysqlAvailable()
{
return extension_loaded('mysql');
return self::createResource(self::getResourceConfig($resourceName));
}
}

View File

@ -9,6 +9,7 @@ use Icinga\Data\Filter\Filter;
use Icinga\Web\Paginator\Adapter\QueryAdapter;
use Zend_Paginator;
use Exception;
use Icinga\Exception\IcingaException;
class SimpleQuery implements QueryInterface, Queryable
{
@ -158,7 +159,7 @@ class SimpleQuery implements QueryInterface, Queryable
public function setOrderColumns(array $orderColumns)
{
throw new Exception('This function does nothing and will be removed');
throw new IcingaException('This function does nothing and will be removed');
}
/**

View File

@ -4,11 +4,9 @@
namespace Icinga\Exception;
use RuntimeException;
/**
* Exception thrown if an error occurs during authentication
*/
class AuthenticationException extends RuntimeException
class AuthenticationException extends IcingaException
{
}

View File

@ -8,6 +8,6 @@ namespace Icinga\Exception;
* Class ConfigurationError
* @package Icinga\Exception
*/
class ConfigurationError extends \RuntimeException
class ConfigurationError extends IcingaException
{
}

View File

@ -0,0 +1,29 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Exception;
use Exception;
class IcingaException extends Exception
{
/**
* @param string $message format string for vsprintf()
* Any futher args: args for vsprintf()
* @see vsprintf
*
* If there is at least one exception, the last one will be also used for the exception chaining.
*/
public function __construct($message = '')
{
$args = array_slice(func_get_args(), 1);
$exc = null;
foreach ($args as &$arg) {
if ($arg instanceof Exception) {
$exc = $arg;
}
}
parent::__construct(vsprintf($message, $args), 0, $exc);
}
}

View File

@ -4,12 +4,10 @@
namespace Icinga\Exception;
use RuntimeException;
/**
* Class MissingParameterException
* @package Icinga\Exception
*/
class MissingParameterException extends RuntimeException
class MissingParameterException extends IcingaException
{
}

View File

@ -8,6 +8,6 @@ namespace Icinga\Exception;
* Class NotImplementedError
* @package Icinga\Exception
*/
class NotImplementedError extends \Exception
class NotImplementedError extends IcingaException
{
}

View File

@ -4,8 +4,6 @@
namespace Icinga\Exception;
use RuntimeException;
class NotReadableError extends RuntimeException
class NotReadableError extends IcingaException
{
}

View File

@ -4,8 +4,6 @@
namespace Icinga\Exception;
use RuntimeException;
class NotWritableError extends RuntimeException
class NotWritableError extends IcingaException
{
}

View File

@ -8,6 +8,6 @@ namespace Icinga\Exception;
* Class ProgrammingError
* @package Icinga\Exception
*/
class ProgrammingError extends \Exception
class ProgrammingError extends IcingaException
{
}

View File

@ -4,11 +4,9 @@
namespace Icinga\Exception;
use \Exception;
/**
* Handle problems according to file system permissions
*/
class SystemPermissionException extends Exception
class SystemPermissionException extends IcingaException
{
}

View File

@ -23,10 +23,17 @@ class Logger
/**
* The log writer to use
*
* @var LogWriter
* @var \Icinga\Logger\LogWriter
*/
protected $writer;
/**
* The configured type
*
* @string Type (syslog, file)
*/
protected $type = 'none';
/**
* The maximum severity to emit
*
@ -52,7 +59,7 @@ class Logger
$this->verbosity = $config->level;
if ($config->enable) {
$this->writer = $this->getWriter($config);
$this->writer = $this->createWriter($config);
}
}
@ -71,16 +78,19 @@ class Logger
*
* @param Zend_Config $config The configuration to initialize the writer with
*
* @return LogWriter The requested log writer
*
* @throws ConfigurationError In case the requested writer cannot be found
* @return \Icinga\Logger\LogWriter The requested log writer
* @throws ConfigurationError If the requested writer cannot be found
*/
protected function getWriter(Zend_Config $config)
protected function createWriter(Zend_Config $config)
{
$class = 'Icinga\\Logger\\Writer\\' . ucfirst(strtolower($config->type)) . 'Writer';
if (!class_exists($class)) {
throw new ConfigurationError('Cannot find log writer of type "' . $config->type . '"');
throw new ConfigurationError(
'Cannot find log writer of type "%s"',
$config->type
);
}
$this->type = $config->type;
return new $class($config);
}
@ -191,4 +201,34 @@ class Logger
static::$instance->log(static::formatMessage(func_get_args()), static::$DEBUG);
}
}
/**
* Get the log writer to use
*
* @return \Icinga\Logger\LogWriter
*/
public function getWriter()
{
return $this->writer;
}
public static function writesToSyslog()
{
return static::$instance && static::$instance->type === 'syslog';
}
public static function writesToFile()
{
return static::$instance && static::$instance->type === 'file';
}
/**
* Get this' instance
*
* @return Logger
*/
public static function getInstance()
{
return static::$instance;
}
}

View File

@ -5,6 +5,7 @@
namespace Icinga\Logger\Writer;
use Exception;
use Icinga\Exception\IcingaException;
use Zend_Config;
use Icinga\Util\File;
use Icinga\Logger\Logger;
@ -33,13 +34,20 @@ class FileWriter extends LogWriter
$this->path = $config->target;
if (substr($this->path, 0, 6) !== 'php://' && false === file_exists(dirname($this->path))) {
throw new ConfigurationError('Log path "' . dirname($this->path) . '" does not exist');
throw new ConfigurationError(
'Log path "%s" does not exist',
dirname($this->path)
);
}
try {
$this->write(''); // Avoid to handle such errors on every write access
} catch (Exception $e) {
throw new ConfigurationError('Cannot write to log file "' . $this->path . '" (' . $e->getMessage() . ')');
throw new ConfigurationError(
'Cannot write to log file "%s" (%s)',
$this->path,
$e->getMessage()
);
}
}
@ -61,7 +69,7 @@ class FileWriter extends LogWriter
*
* @return string The string representation of the severity
*
* @throws Exception In case the given severity is unknown
* @throws IcingaException In case the given severity is unknown
*/
protected function getSeverityString($severity)
{
@ -75,7 +83,10 @@ class FileWriter extends LogWriter
case Logger::$DEBUG:
return '- DEBUG -';
default:
throw new Exception('Unknown severity "' . $severity . '"');
throw new IcingaException(
'Unknown severity "%s"',
$severity
);
}
}
@ -92,4 +103,12 @@ class FileWriter extends LogWriter
$file->fwrite($text);
$file->fflush();
}
/**
* @return string
*/
public function getPath()
{
return $this->path;
}
}

View File

@ -9,6 +9,7 @@ use Zend_Config;
use Icinga\Logger\Logger;
use Icinga\Logger\LogWriter;
use Icinga\Exception\ConfigurationError;
use Icinga\Exception\IcingaException;
/**
* Class to write messages to syslog
@ -45,7 +46,8 @@ class SyslogWriter extends LogWriter
{
if (!array_key_exists($config->facility, $this->facilities)) {
throw new ConfigurationError(
'Cannot create syslog writer with unknown facility "' . $config->facility . '"'
'Cannot create syslog writer with unknown facility "%s"',
$config->facility
);
}
@ -71,7 +73,10 @@ class SyslogWriter extends LogWriter
);
if (!array_key_exists($severity, $priorities)) {
throw new Exception('Severity "' . $severity . '" cannot be mapped to a valid syslog priority');
throw new IcingaException(
'Severity "%s" cannot be mapped to a valid syslog priority',
$severity
);
}
$this->open();

View File

@ -138,7 +138,10 @@ abstract class Command
*/
public function getHostgroupCommand($hostgroup)
{
throw new ProgrammingError(get_class($this) . ' does not provide a hostgroup command');
throw new ProgrammingError(
'%s does not provide a hostgroup command',
get_class($this)
);
}
/**
@ -150,7 +153,10 @@ abstract class Command
*/
public function getServicegroupCommand($servicegroup)
{
throw new ProgrammingError(get_class($this) . ' does not provide a servicegroup command');
throw new ProgrammingError(
'%s does not provide a servicegroup command',
get_class($this)
);
}
/**
@ -163,6 +169,9 @@ abstract class Command
*/
public function getGlobalCommand($instance = null)
{
throw new ProgrammingError(getclass($this) . ' does not provide a global command');
throw new ProgrammingError(
'%s does not provide a global command',
getclass($this)
);
}
}

View File

@ -49,11 +49,9 @@ class LocalPipe implements Transport
$file->fflush();
} catch (Exception $e) {
throw new ConfigurationError(
sprintf(
'Could not open icinga command pipe at "%s" (%s)',
$this->path,
$e->getMessage()
)
);
}

View File

@ -4,7 +4,7 @@
namespace Icinga\Protocol\Commandpipe\Transport;
use \Zend_Config;
use Zend_Config;
/**
* Interface for Transport classes handling the concrete access to the command pipe

View File

@ -2,9 +2,9 @@
namespace Icinga\Protocol\File;
use RuntimeException;
use Icinga\Exception\IcingaException;
/**
* Exception thrown if a file reader specific error occurs
*/
class FileReaderException extends RuntimeException {}
class FileReaderException extends IcingaException {}

View File

@ -0,0 +1,82 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}}
namespace Icinga\Protocol\File;
use FilterIterator;
use Icinga\Util\File;
/**
* Class FileIterator
*
* Iterate over a file, yielding only fields of non-empty lines which match a PCRE expression
*/
class FileIterator extends FilterIterator
{
/**
* A PCRE string with the fields to extract from the file's lines as named subpatterns
*
* @var string
*/
protected $fields;
/**
* An associative array of the current line's fields ($field => $value)
*
* @var array
*/
protected $currentData;
public function __construct($filename, $fields)
{
$this->fields = $fields;
$f = new File($filename);
$f->setFlags(
File::DROP_NEW_LINE |
File::READ_AHEAD |
File::SKIP_EMPTY
);
parent::__construct($f);
}
/**
* Return the current data
*
* @return array
*/
public function current()
{
return $this->currentData;
}
/**
* Accept lines matching the given PCRE pattern
*
* @return bool
*
* @throws FileReaderException If PHP failed parsing the PCRE pattern
*/
public function accept()
{
$data = array();
$matched = preg_match(
$this->fields,
$this->getInnerIterator()->current(),
$data
);
if ($matched === false) {
throw new FileReaderException('Failed parsing regular expression!');
} else if ($matched === 1) {
foreach ($data as $key => $value) {
if (is_int($key)) {
unset($data[$key]);
}
}
$this->currentData = $data;
return true;
}
return false;
}
}

View File

@ -8,13 +8,13 @@ use Icinga\Data\SimpleQuery;
use Icinga\Data\Filter\Filter;
/**
* Class Query
* Class FileQuery
*
* Query for Datasource Icinga\Protocol\File\Reader
* Query for Datasource Icinga\Protocol\File\FileReader
*
* @package Icinga\Protocol\File
*/
class Query extends SimpleQuery
class FileQuery extends SimpleQuery
{
/**
* Sort direction
@ -41,7 +41,7 @@ class Query extends SimpleQuery
*
* @param string $dir Sort direction, 'ASC' or 'DESC' (default)
*
* @return Query
* @return FileQuery
*/
public function order($field, $direction = null)
{
@ -66,7 +66,7 @@ class Query extends SimpleQuery
*
* @param string $expression the filter expression to be applied
*
* @return Query
* @return FileQuery
*/
public function andWhere($expression)
{

View File

@ -4,16 +4,15 @@
namespace Icinga\Protocol\File;
use FilterIterator;
use Iterator;
use Icinga\Data\Selectable;
use Countable;
use Icinga\Util\Enumerate;
use Zend_Config;
use Icinga\Protocol\File\FileReaderException;
use Icinga\Util\File;
/**
* Read file line by line
*/
class Reader extends FilterIterator
class FileReader implements Selectable, Countable
{
/**
* A PCRE string with the fields to extract from the file's lines as named subpatterns
@ -23,11 +22,11 @@ class Reader extends FilterIterator
protected $fields;
/**
* An associative array of the current line's fields ($field => $value)
* Name of the target file
*
* @var array
* @var string
*/
protected $currentData;
protected $filename;
/**
* Create a new reader
@ -39,67 +38,34 @@ class Reader extends FilterIterator
public function __construct(Zend_Config $config)
{
foreach (array('filename', 'fields') as $key) {
if (! isset($config->{$key})) {
throw new FileReaderException('The directive `' . $key . '\' is required');
if (isset($config->{$key})) {
$this->{$key} = $config->{$key};
} else {
throw new FileReaderException('The directive `%s\' is required', $key);
}
}
$this->fields = $config->fields;
$f = new File($config->filename);
$f->setFlags(
File::DROP_NEW_LINE |
File::READ_AHEAD |
File::SKIP_EMPTY
);
parent::__construct($f);
}
/**
* Return the current data
* Instantiate a FileIterator object with the target file
*
* @return array
* @return FileIterator
*/
public function current()
public function iterate()
{
return $this->currentData;
}
/**
* Accept lines matching the given PCRE pattern
*
* @return bool
*
* @throws FileReaderException If PHP failed parsing the PCRE pattern
*/
public function accept()
{
$data = array();
$matched = @preg_match(
$this->fields,
$this->getInnerIterator()->current(),
$data
return new Enumerate(
new FileIterator($this->filename, $this->fields)
);
if ($matched === false) {
throw new FileReaderException('Failed parsing regular expression!');
} else if ($matched === 1) {
foreach ($data as $key) {
if (is_int($key)) {
unset($data[$key]);
}
}
$this->currentData = $data;
return true;
}
return false;
}
/**
* Instantiate a Query object
* Instantiate a FileQuery object
*
* @return Query
* @return FileQuery
*/
public function select()
{
return new Query($this);
return new FileQuery($this);
}
/**
@ -109,17 +75,17 @@ class Reader extends FilterIterator
*/
public function count()
{
return iterator_count($this);
return iterator_count($this->iterate());
}
/**
* Fetch result as an array of objects
*
* @param Query $query
* @param FileQuery $query
*
* @return array
*/
public function fetchAll(Query $query)
public function fetchAll(FileQuery $query)
{
$all = array();
foreach ($this->fetchPairs($query) as $index => $value) {
@ -131,32 +97,32 @@ class Reader extends FilterIterator
/**
* Fetch result as a key/value pair array
*
* @param Query $query
* @param FileQuery $query
*
* @return array
*/
public function fetchPairs(Query $query)
public function fetchPairs(FileQuery $query)
{
$skipLines = $query->getOffset();
$readLines = $query->getLimit();
if ($skipLines === null) {
$skipLines = 0;
$skip = $query->getOffset();
$read = $query->getLimit();
if ($skip === null) {
$skip = 0;
}
$lines = array();
if ($query->sortDesc()) {
$count = $this->count($query);
if ($count <= $skipLines) {
if ($count <= $skip) {
return $lines;
} else if ($count < ($skipLines + $readLines)) {
$readLines = $count - $skipLines;
$skipLines = 0;
} else if ($count < ($skip + $read)) {
$read = $count - $skip;
$skip = 0;
} else {
$skipLines = $count - ($skipLines + $readLines);
$skip = $count - ($skip + $read);
}
}
foreach ($this as $index => $line) {
if ($index >= $skipLines) {
if ($index >= $skipLines + $readLines) {
foreach ($this->iterate() as $index => $line) {
if ($index >= $skip) {
if ($index >= $skip + $read) {
break;
}
$lines[] = $line;
@ -171,11 +137,11 @@ class Reader extends FilterIterator
/**
* Fetch first result row
*
* @param Query $query
* @param FileQuery $query
*
* @return object
*/
public function fetchRow(Query $query)
public function fetchRow(FileQuery $query)
{
$all = $this->fetchAll($query);
if (isset($all[0])) {
@ -187,11 +153,11 @@ class Reader extends FilterIterator
/**
* Fetch first result column
*
* @param Query $query
* @param FileQuery $query
*
* @return array
*/
public function fetchColumn(Query $query)
public function fetchColumn(FileQuery $query)
{
$column = array();
foreach ($this->fetchPairs($query) as $pair) {
@ -206,11 +172,11 @@ class Reader extends FilterIterator
/**
* Fetch first column value from first result row
*
* @param Query $query
* @param FileQuery $query
*
* @return mixed
*/
public function fetchOne(Query $query)
public function fetchOne(FileQuery $query)
{
$pairs = $this->fetchPairs($query);
if (isset($pairs[0])) {

View File

@ -8,7 +8,7 @@ use Icinga\Protocol\Ldap\Exception as LdapException;
use Icinga\Application\Platform;
use Icinga\Application\Config;
use Icinga\Logger\Logger;
use \Zend_Config;
use Zend_Config;
/**
* Backend class managing all the LDAP stuff for you.
@ -307,7 +307,7 @@ class Connection
$results = @ldap_search(
$this->ds,
$base,
(string) $query,
$query->create(),
$fields,
0, // Attributes and values
0 // No limit - at least where possible
@ -619,7 +619,7 @@ class Connection
$result = @ldap_read(
$ds,
'',
(string) $query,
$query->create(),
$query->listFields()
);

View File

@ -83,11 +83,9 @@ class Query
{
if (! preg_match('~^\d+~', $count . $offset)) {
throw new Exception(
sprintf(
'Got invalid limit: %s, %s',
$count,
$offset
)
);
}
$this->limit_count = (int) $count;
@ -302,21 +300,11 @@ class Query
*
* @string
*/
public function __toString()
{
return $this->render();
}
/**
* Returns the LDAP filter that will be applied
*
* @string
*/
protected function render()
public function create()
{
$parts = array();
if (! isset($this->filters['objectClass']) || $this->filters['objectClass'] === null) {
// throw new Exception('Object class is mandatory');
throw new Exception('Object class is mandatory');
}
foreach ($this->filters as $key => $value) {
$parts[] = sprintf(

View File

@ -4,6 +4,8 @@
namespace Icinga\Protocol\Ldap;
use Icinga\Exception\IcingaException;
/**
* This class is a special node object, representing your connections root node
*
@ -95,16 +97,14 @@ class Root
/**
* @param $rdn
* @return mixed
* @throws Exception
* @throws IcingaException
*/
public function getChildByRDN($rdn)
{
if (!$this->hasChildRDN($rdn)) {
throw new Exception(
sprintf(
throw new IcingaException(
'The child RDN "%s" is not available',
$rdn
)
);
}
return $this->children[strtolower($rdn)];
@ -154,28 +154,24 @@ class Root
/**
* @param $dn
* @return $this
* @throws Exception
* @throws IcingaException
*/
protected function assertSubDN($dn)
{
$mydn = $this->getDN();
$end = substr($dn, -1 * strlen($mydn));
if (strtolower($end) !== strtolower($mydn)) {
throw new Exception(
sprintf(
throw new IcingaException(
'"%s" is not a child of "%s"',
$dn,
$mydn
)
);
}
if (strlen($dn) === strlen($mydn)) {
throw new Exception(
sprintf(
throw new IcingaException(
'"%s" is not a child of "%s", they are equal',
$dn,
$mydn
)
);
}
return $this;

View File

@ -6,6 +6,7 @@ namespace Icinga\Protocol\Livestatus;
use Icinga\Application\Benchmark;
use Exception;
use Icinga\Exception\IcingaException;
/**
* Backend class managing handling MKI Livestatus connections
@ -73,22 +74,18 @@ class Connection
$this->assertPhpExtensionLoaded('sockets');
if ($socket[0] === '/') {
if (! is_writable($socket)) {
throw new \Exception(
sprintf(
throw new IcingaException(
'Cannot write to livestatus socket "%s"',
$socket
)
);
}
$this->socket_type = self::TYPE_UNIX;
$this->socket_path = $socket;
} else {
if (! preg_match('~^tcp://([^:]+):(\d+)~', $socket, $m)) {
throw new \Exception(
sprintf(
throw new IcingaException(
'Invalid TCP socket syntax: "%s"',
$socket
)
);
}
// TODO: Better syntax checks
@ -156,17 +153,15 @@ class Connection
$length = (int) trim(substr($header, 4));
$body = $this->readFromSocket($length);
if ($status !== 200) {
throw new Exception(
sprintf(
throw new IcingaException(
'Problem while reading %d bytes from livestatus: %s',
$length,
$body
)
);
}
$result = json_decode($body);
if ($result === null) {
throw new Exception('Got invalid response body from livestatus');
throw new IcingaException('Got invalid response body from livestatus');
}
return $result;
@ -180,11 +175,9 @@ class Connection
while ($offset < $length) {
$data = socket_read($this->connection, $length - $offset);
if ($data === false) {
throw new Exception(
sprintf(
throw new IcingaException(
'Failed to read from livestatus socket: %s',
socket_strerror(socket_last_error($this->connection))
)
);
}
$size = strlen($data);
@ -196,12 +189,10 @@ class Connection
}
}
if ($offset !== $length) {
throw new \Exception(
sprintf(
throw new IcingaException(
'Got only %d instead of %d bytes from livestatus socket',
$offset,
$length
)
);
}
@ -212,7 +203,7 @@ class Connection
{
$res = socket_write($this->connection, $data);
if ($res === false) {
throw new \Exception('Writing to livestatus socket failed');
throw new IcingaException('Writing to livestatus socket failed');
}
return true;
}
@ -220,11 +211,9 @@ class Connection
protected function assertPhpExtensionLoaded($name)
{
if (! extension_loaded($name)) {
throw new \Exception(
sprintf(
throw new IcingaException(
'The extension "%s" is not loaded',
$name
)
);
}
}
@ -250,13 +239,11 @@ class Connection
$this->connection = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if (! @socket_connect($this->connection, $this->socket_host, $this->socket_port)) {
throw new \Exception(
sprintf(
throw new IcingaException(
'Cannot connect to livestatus TCP socket "%s:%d": %s',
$this->socket_host,
$this->socket_port,
socket_strerror(socket_last_error($this->connection))
)
);
}
socket_set_option($this->connection, SOL_TCP, TCP_NODELAY, 1);
@ -266,11 +253,9 @@ class Connection
{
$this->connection = socket_create(AF_UNIX, SOCK_STREAM, 0);
if (! socket_connect($this->connection, $this->socket_path)) {
throw new \Exception(
sprintf(
throw new IcingaException(
'Cannot connect to livestatus local socket "%s"',
$this->socket_path
)
);
}
}

Some files were not shown because too many files have changed in this diff Show More