diff --git a/doc/authentication.md b/doc/authentication.md index 604c85a2e..13a821441 100644 --- a/doc/authentication.md +++ b/doc/authentication.md @@ -107,7 +107,7 @@ Icinga Web 2 uses the MD5 based BSD password algorithm. For generating a passwor command: ```` -openssl passwd -1 "password" +openssl passwd -1 password ```` > Note: The switch to `openssl passwd` is the **number one** (`-1`) for using the MD5 based BSD password algorithm. diff --git a/doc/installation.md b/doc/installation.md index ef968974a..133f6cb98 100644 --- a/doc/installation.md +++ b/doc/installation.md @@ -3,21 +3,133 @@ The preferred way of installing Icinga Web 2 is to use the official package repositories depending on which operating system and distribution you are running. But it is also possible to install Icinga Web 2 directly from source. -## Installing Requirements +## Installing Requirements * A web server, e.g. Apache or nginx -* PHP >= 5.3.0 w/ gettext and OpenSSL support -* MySQL or PostgreSQL PHP libraries when using a database for authentication or storing user preferences into a database +* PHP >= 5.3.0 w/ gettext, intl and OpenSSL support +* MySQL or PostgreSQL PHP libraries when using a database for authentication or for storing preferences into a database * LDAP PHP library when using Active Directory or LDAP for authentication -* Icinga 1.x w/ Livestatus or IDO, Icinga 2 w/ Livestatus or IDO feature enabled +* Icinga 1.x w/ Livestatus or IDO; Icinga 2.x w/ Livestatus or IDO feature enabled +* MySQL or PostgreSQL PHP libraries when using IDO -## Installing Icinga Web 2 from Package +## Installing Icinga Web 2 from Package -A guide on how to install Icinga Web 2 from package will follow shortly. +Below is a list of official package repositories for installing Icinga Web 2 for various operating systems. -## Installing Icinga Web 2 from Source +Distribution | Repository +------------------------|--------------------------- +Debian | [debmon](http://debmon.org/packages/debmon-wheezy/icingaweb2), [Icinga Repository](http://packages.icinga.org/debian/) +Ubuntu | [Icinga Repository](http://packages.icinga.org/ubuntu/) +RHEL/CentOS | [Icinga Repository](http://packages.icinga.org/epel/) +openSUSE | [Icinga Repository](http://packages.icinga.org/openSUSE/) +SLES | [Icinga Repository](http://packages.icinga.org/SUSE/) +Gentoo | - +FreeBSD | - +ArchLinux | [Upstream](https://aur.archlinux.org/packages/icingaweb2) -**Step 1: Getting the Source** +Packages for distributions other than the ones listed above may also be available. +Please contact your distribution packagers. + +### Setting up Package Repositories + +You need to add the Icinga repository to your package management configuration for installing Icinga Web 2. +Below is a list with examples for various distributions. + +Debian (debmon): +```` +wget -O - http://debmon.org/debmon/repo.key 2>/dev/null | apt-key add - +echo 'deb http://debmon.org/debmon debmon-wheezy main' >/etc/apt/sources.list.d/debmon.list +apt-get update +```` + +Ubuntu Trusty: +```` +wget -O - http://packages.icinga.org/icinga.key | apt-key add - +add-apt-repository 'deb http://packages.icinga.org/ubuntu icinga-trusty main' +apt-get update +```` + +For other Ubuntu versions just replace trusty with your distribution's code name. + +RHEL and CentOS: +```` +rpm --import http://packages.icinga.org/icinga.key +curl -o /etc/yum.repos.d/ICINGA-release.repo http://packages.icinga.org/epel/ICINGA-release.repo +yum makecache +```` + +Fedora: +```` +rpm --import http://packages.icinga.org/icinga.key +curl -o /etc/yum.repos.d/ICINGA-release.repo http://packages.icinga.org/fedora/ICINGA-release.repo +yum makecache +```` + +SLES 11: +```` +zypper ar http://packages.icinga.org/SUSE/ICINGA-release-11.repo +zypper ref +```` + +SLES 12: +```` +zypper ar http://packages.icinga.org/SUSE/ICINGA-release.repo +zypper ref +```` + +openSUSE: +```` +zypper ar http://packages.icinga.org/openSUSE/ICINGA-release.repo +zypper ref +```` + +The packages for RHEL/CentOS depend on other packages which are distributed as part of the +[EPEL repository](http://fedoraproject.org/wiki/EPEL). Please make sure to enable this repository by following +[these instructions](http://fedoraproject.org/wiki/EPEL#How_can_I_use_these_extra_packages.3F). + +### Installing Icinga Web 2 + +You can install Icinga Web 2 by using your distribution's package manager to install the `icingaweb2` package. +Below is a list with examples for various distributions. + +Debian and Ubuntu: +```` +apt-get install icingaweb2 +```` + +RHEL, CentOS and Fedora: +```` +yum install icingaweb2 +```` + +SLES and openSUSE: +```` +zypper install icingaweb2 +```` + +### Preparing Web Setup + +You can set up Icinga Web 2 quickly and easily with the Icinga Web 2 setup wizard which is available the first time +you visit Icinga Web 2 in your browser. When using the web setup you are required to authenticate using a token. +In order to generate a token use the `icingacli`: +```` +icingacli setup token create +```` + +In case you do not remember the token you can show it using the `icingacli`: +```` +icingacli setup token show +```` + +Finally visit Icinga Web 2 in your browser to access the setup wizard and complete the installation: +`/icingaweb2/setup`. + +## Installing Icinga Web 2 from Source + +Although the preferred way of installing Icinga Web 2 is to use packages, it is also possible to install Icinga Web 2 +directly from source. + +### Getting the Source First of all, you need to download the sources. Icinga Web 2 is available through a Git repository. You can clone this repository either via git or http protocol using the following URLs: @@ -33,7 +145,7 @@ This version also offers snapshots for easy download which you can use if you do git clone git://git.icinga.org/icingaweb2.git ```` -**Step 2: Install the Source** +### Installing Icinga Web 2 Choose a target directory and move Icinga Web 2 there. @@ -41,7 +153,7 @@ Choose a target directory and move Icinga Web 2 there. mv icingaweb2 /usr/share/icingaweb2 ```` -**Step 3: Configuring the Web Server** +### Configuring the Web Server Use `icingacli` to generate web server configuration for either Apache or nginx. @@ -57,13 +169,15 @@ nginx: Save the output as new file in your webserver's configuration directory. -Example for Apache on RHEL/CentOS: +Example for Apache on RHEL or CentOS: ```` ./bin/icingacli setup config webserver apache --document-root /usr/share/icingaweb2/public > /etc/httpd/conf.d/icingaweb2.conf ```` +### Preparing Web Setup -**Step 4: Preparing Web Setup** +You can set up Icinga Web 2 quickly and easily with the Icinga Web 2 setup wizard which is available the first time +you visit Icinga Web 2 in your browser. Please follow the steps listed below for preparing the web setup. Because both web and CLI must have access to configuration and logs, permissions will be managed using a special system group. The web server user and CLI user have to be added to this system group. @@ -102,6 +216,7 @@ Use `icingacli` to create the configuration directory which defaults to **/etc/i ./bin/icingacli setup config directory ```` + When using the web setup you are required to authenticate using a token. In order to generate a token use the `icingacli`: ```` @@ -113,11 +228,10 @@ In case you do not remember the token you can show it using the `icingacli`: ./bin/icingacli setup token show ```` -**Step 5: Web Setup** +Finally visit Icinga Web 2 in your browser to access the setup wizard and complete the installation: +`/icingaweb2/setup`. -Visit Icinga Web 2 in your browser and complete installation using the web setup: /icingaweb2/setup - -## Upgrading to Icinga Web 2 Beta 2 +## Upgrading to Icinga Web 2 Beta 2 Icinga Web 2 Beta 2 introduces access control based on roles for secured actions. If you've already set up Icinga Web 2, you are required to create the file **roles.ini** beneath Icinga Web 2's configuration directory with the following @@ -134,7 +248,7 @@ If you delegated authentication to your web server using the `autologin` backend authentication backend to be able to log in again. The new name better reflects what’s going on. A similar change affects environments that opted for not storing preferences, your new backend is `none`. -## Upgrading to Icinga Web 2 Beta 3 +## Upgrading to Icinga Web 2 Beta 3 Because Icinga Web 2 Beta 3 does not introduce any backward incompatible change you don't have to change your configuration files after upgrading to Icinga Web 2 Beta 3. diff --git a/library/Icinga/Application/Modules/Manager.php b/library/Icinga/Application/Modules/Manager.php index 8f48d7b77..90e55f0b4 100644 --- a/library/Icinga/Application/Modules/Manager.php +++ b/library/Icinga/Application/Modules/Manager.php @@ -12,7 +12,6 @@ use Icinga\Exception\ConfigurationError; use Icinga\Exception\SystemPermissionException; use Icinga\Exception\ProgrammingError; use Icinga\Exception\NotReadableError; -use Icinga\Exception\NotFoundError; /** * Module manager that handles detecting, enabling and disabling of modules @@ -199,7 +198,6 @@ class Manager * * @return $this * @throws ConfigurationError When trying to enable a module that is not installed - * @throws NotFoundError In case the "enabledModules" directory does not exist * @throws SystemPermissionException When insufficient permissions for the application exist */ public function enableModule($name) @@ -218,14 +216,15 @@ class Manager if (! is_dir($this->enableDir) && !@mkdir($this->enableDir, 02770, true)) { $error = error_get_last(); throw new SystemPermissionException( - 'Failed to create enabledModule directory "%s" (%s)', + 'Failed to create enabledModules directory "%s" (%s)', $this->enableDir, $error['message'] ); } elseif (! is_writable($this->enableDir)) { throw new SystemPermissionException( - 'Cannot enable module "%s". Insufficient system permissions for enabling modules.', - $name + 'Cannot enable module "%s". Check the permissions for the enabledModules directory: %s', + $name, + $this->enableDir ); } @@ -237,10 +236,11 @@ class Manager $error = error_get_last(); if (strstr($error["message"], "File exists") === false) { throw new SystemPermissionException( - 'Could not enable module "%s" due to file system errors. ' + 'Cannot enable module "%s" at %s due to file system errors. ' . 'Please check path and mounting points because this is not a permission error. ' . 'Primary error was: %s', $name, + $this->enableDir, $error['message'] ); } @@ -259,32 +259,37 @@ class Manager * @return $this * * @throws ConfigurationError When the module is not installed or it's not a symlink - * @throws SystemPermissionException When the module can't be disabled + * @throws SystemPermissionException When insufficient permissions for the application exist */ public function disableModule($name) { if (! $this->hasEnabled($name)) { return $this; } + if (! is_writable($this->enableDir)) { throw new SystemPermissionException( - 'Could not disable module. Module path is not writable.' + 'Cannot disable module "%s". Check the permissions for the enabledModules directory: %s', + $name, + $this->enableDir ); } + $link = $this->enableDir . DIRECTORY_SEPARATOR . $name; if (! file_exists($link)) { throw new ConfigurationError( - 'Could not disable module. The module %s was not found.', + 'Cannot disable module "%s". Module is not installed.', $name ); } if (! is_link($link)) { throw new ConfigurationError( - 'Could not disable module. The module "%s" is not a symlink. ' + 'Cannot disable module %s at %s. ' . '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.', - $name + . 'the enabledModules folder.', + $name, + $this->enableDir ); } @@ -292,10 +297,11 @@ class Manager if (! @unlink($link)) { $error = error_get_last(); throw new SystemPermissionException( - 'Could not disable module "%s" due to file system errors. ' + 'Cannot enable module "%s" at %s due to file system errors. ' . 'Please check path and mounting points because this is not a permission error. ' . 'Primary error was: %s', $name, + $this->enableDir, $error['message'] ); } diff --git a/library/Icinga/Web/Widget/Chart/HistoryColorGrid.php b/library/Icinga/Web/Widget/Chart/HistoryColorGrid.php index d1c9a677f..8ffd3ea00 100644 --- a/library/Icinga/Web/Widget/Chart/HistoryColorGrid.php +++ b/library/Icinga/Web/Widget/Chart/HistoryColorGrid.php @@ -127,7 +127,8 @@ class HistoryColorGrid extends AbstractWidget { . ' opacity: ' . $this->opacity . ';" ' . 'aria-label="' . $entry['caption'] . '" ' . 'title="' . $entry['caption'] . '" ' . - 'href="' . $entry['url'] . '"' . + 'href="' . $entry['url'] . '" ' . + 'data-tooltip-delay="0"' . '>'; } else { return ' - X + EOT; diff --git a/modules/monitoring/application/forms/Command/Object/SendCustomNotificationCommandForm.php b/modules/monitoring/application/forms/Command/Object/SendCustomNotificationCommandForm.php index 068f85e1b..b9ab60065 100644 --- a/modules/monitoring/application/forms/Command/Object/SendCustomNotificationCommandForm.php +++ b/modules/monitoring/application/forms/Command/Object/SendCustomNotificationCommandForm.php @@ -17,29 +17,20 @@ class SendCustomNotificationCommandForm extends ObjectsCommandForm public function init() { $this->addDescription( - $this->translate( - 'This command is used to send custom notifications for hosts or' - . ' services.' - ) + $this->translate('This command is used to send custom notifications about hosts or services.') ); } /** - * (non-PHPDoc) - * @see \Icinga\Web\Form::getSubmitLabel() For the method documentation. + * {@inheritdoc} */ public function getSubmitLabel() { - return $this->translatePlural( - 'Send custom notification', - 'Send custom notifications', - count($this->objects) - ); + return $this->translatePlural('Send custom notification', 'Send custom notifications', count($this->objects)); } /** - * (non-PHPDoc) - * @see \Icinga\Web\Form::createElements() For the method documentation. + * {@inheritdoc} */ public function createElements(array $formData = array()) { @@ -64,9 +55,8 @@ class SendCustomNotificationCommandForm extends ObjectsCommandForm 'label' => $this->translate('Forced'), 'value' => false, 'description' => $this->translate( - 'If you check this option, a notification is sent' - . 'regardless of the current time and whether' - . ' notifications are enabled.' + 'If you check this option, the notification is sent out regardless of time restrictions and' + . ' whether or not notifications are enabled.' ) ) ), @@ -77,8 +67,7 @@ class SendCustomNotificationCommandForm extends ObjectsCommandForm 'label' => $this->translate('Broadcast'), 'value' => false, 'description' => $this->translate( - 'If you check this option, a notification is sent to' - . ' all normal and escalated contacts.' + 'If you check this option, the notification is sent out to all normal and escalated contacts.' ) ) ) @@ -87,24 +76,24 @@ class SendCustomNotificationCommandForm extends ObjectsCommandForm } /** - * (non-PHPDoc) - * @see \Icinga\Web\Form::onSuccess() For the method documentation. + * {@inheritdoc} */ public function onSuccess() { foreach ($this->objects as $object) { /** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */ - $comment = new SendCustomNotificationCommand(); - $comment->setObject($object); - $comment->setComment($this->getElement('comment')->getValue()); - $comment->setAuthor($this->request->getUser()->getUsername()); - $comment->setForced($this->getElement('forced')->isChecked()); - $comment->setBroadcast($this->getElement('broadcast')->isChecked()); - $this->getTransport($this->request)->send($comment); + $notification = new SendCustomNotificationCommand(); + $notification + ->setObject($object) + ->setComment($this->getElement('comment')->getValue()) + ->setAuthor($this->request->getUser()->getUsername()) + ->setForced($this->getElement('forced')->isChecked()) + ->setBroadcast($this->getElement('broadcast')->isChecked()); + $this->getTransport($this->request)->send($notification); } Notification::success($this->translatePlural( - 'Send custom notification..', - 'Send custom notifications..', + 'Sending custom notification..', + 'Sending custom notifications..', count($this->objects) )); return true; diff --git a/modules/monitoring/application/views/scripts/list/comments.phtml b/modules/monitoring/application/views/scripts/list/comments.phtml index ee752b037..53a00835a 100644 --- a/modules/monitoring/application/views/scripts/list/comments.phtml +++ b/modules/monitoring/application/views/scripts/list/comments.phtml @@ -34,10 +34,12 @@ if (count($comments) === 0) { $icon = 'plug'; $title = $this->translate('Downtime'); $tooltip = $this->translate('Comment was caused by a downtime.'); + break; case 'ack': $icon = 'ok'; $title = $this->translate('Acknowledgement'); $tooltip = $this->translate('Comment was caused by an acknowledgement.'); + break; } ?> diff --git a/modules/monitoring/application/views/scripts/list/servicegrid.phtml b/modules/monitoring/application/views/scripts/list/servicegrid.phtml index 6fb6db63e..069a60619 100644 --- a/modules/monitoring/application/views/scripts/list/servicegrid.phtml +++ b/modules/monitoring/application/views/scripts/list/servicegrid.phtml @@ -50,7 +50,8 @@ foreach ($serviceDescriptions as $service_description): ?> 'service_description' => $service_description ), array( - 'title' => sprintf($this->translate('List all services with the name "%s" on all reported hosts'), $service_description) + 'title' => sprintf($this->translate('List all services with the name "%s" on all reported hosts'), $service_description), + 'data-tooltip-gravity' => 's' ), false ); ?> diff --git a/modules/monitoring/library/Monitoring/Command/Object/ScheduleServiceCheckCommand.php b/modules/monitoring/library/Monitoring/Command/Object/ScheduleServiceCheckCommand.php index ac5e4be61..192bae850 100644 --- a/modules/monitoring/library/Monitoring/Command/Object/ScheduleServiceCheckCommand.php +++ b/modules/monitoring/library/Monitoring/Command/Object/ScheduleServiceCheckCommand.php @@ -9,8 +9,7 @@ namespace Icinga\Module\Monitoring\Command\Object; class ScheduleServiceCheckCommand extends ObjectCommand { /** - * (non-PHPDoc) - * @see \Icinga\Module\Monitoring\Command\Object\ObjectCommand::$allowedObjects For the property documentation. + * {@inheritdoc} */ protected $allowedObjects = array( self::TYPE_SERVICE @@ -74,7 +73,7 @@ class ScheduleServiceCheckCommand extends ObjectCommand } /** - * Is the check forced? + * Get whether the check is forced * * @return bool */ @@ -84,8 +83,7 @@ class ScheduleServiceCheckCommand extends ObjectCommand } /** - * (non-PHPDoc) - * @see \Icinga\Module\Monitoring\Command\Object\IcingaCommand::getName() For the method documentation. + * {@inheritdoc} */ public function getName() { diff --git a/modules/monitoring/library/Monitoring/Command/Object/SendCustomNotificationCommand.php b/modules/monitoring/library/Monitoring/Command/Object/SendCustomNotificationCommand.php index 83f054295..647804310 100644 --- a/modules/monitoring/library/Monitoring/Command/Object/SendCustomNotificationCommand.php +++ b/modules/monitoring/library/Monitoring/Command/Object/SendCustomNotificationCommand.php @@ -15,29 +15,27 @@ class SendCustomNotificationCommand extends WithCommentCommand self::TYPE_HOST, self::TYPE_SERVICE ); - + /** - * Whether a notification is forced to send + * Whether the notification is forced * - * Forced notifications are send regardless of time and if notifications - * are enabled. + * Forced notifications are sent out regardless of time restrictions and whether or not notifications are enabled. * * @var bool */ protected $forced; /** - * Broadcast the notification + * Whether to broadcast the notification * - * If broadcast is true, the notification is send to all normal and - * escalated contacts for the object + * Broadcast notifications are sent out to all normal and escalated contacts. * * @var bool */ protected $broadcast; /** - * Get notification force flag + * Get whether to force the notification * * @return bool */ @@ -47,17 +45,20 @@ class SendCustomNotificationCommand extends WithCommentCommand } /** - * Set whether notification should be forced + * Set whether to force the notification * - * @param bool $forced + * @param bool $forced + * + * @return $this */ public function setForced($forced = true) { $this->forced = $forced; + return $this; } /** - * Get notification broadcast flag + * Get whether to broadcast the notification * * @return bool */ @@ -67,12 +68,15 @@ class SendCustomNotificationCommand extends WithCommentCommand } /** - * Set notification to broadcast + * Set whether to broadcast the notification * - * @param bool $broadcast + * @param bool $broadcast + * + * @return $this */ public function setBroadcast($broadcast = true) { $this->broadcast = $broadcast; + return $this; } } diff --git a/public/js/icinga/behavior/tooltip.js b/public/js/icinga/behavior/tooltip.js index c9a64257f..d3dc6c539 100644 --- a/public/js/icinga/behavior/tooltip.js +++ b/public/js/icinga/behavior/tooltip.js @@ -28,9 +28,19 @@ $el.attr('title', $el.data('title-rich') || $el.attr('title')); }); $('svg .chart-data', el).tipsy({ gravity: 'se', html: true }); - $('.historycolorgrid a[title]', el).tipsy({ gravity: 's', offset: 2 }); - $('img.icon[title]', el).tipsy({ gravity: $.fn.tipsy.autoNS, offset: 2 }); - $('[title]', el).tipsy({ gravity: $.fn.tipsy.autoNS, delayIn: 500 }); + $('i[title]', el).tipsy({ gravity: $.fn.tipsy.autoNS, offset: 2 }); + $('[title]', el).each(function (i, el) { + var $el = $(el); + var delay = 500; + if ($el.data('tooltip-delay') !== undefined) { + delay = $el.data('tooltip-delay'); + } + var gravity = $.fn.tipsy.autoNS; + if ($el.data('tooltip-gravity')) { + gravity = $el.data('tooltip-gravity'); + } + $el.tipsy({ gravity: gravity, delayIn: delay }); + }); // migrate or remove all orphaned tooltips $('.tipsy').each(function () { diff --git a/public/js/icinga/events.js b/public/js/icinga/events.js index 491ca82f2..7e87a8fb6 100644 --- a/public/js/icinga/events.js +++ b/public/js/icinga/events.js @@ -100,6 +100,7 @@ // Destroy Icinga, clean up and interrupt pending requests on unload $( window ).on('unload', { self: this }, this.onUnload); + $( window ).on('beforeunload', { self: this }, this.onUnload); // We catch scroll events in our containers $('.container').on('scroll', { self: this }, this.icinga.events.onContainerScroll); @@ -555,6 +556,7 @@ $(window).off('resize', this.onWindowResize); $(window).off('load', this.onLoad); $(window).off('unload', this.onUnload); + $(window).off('beforeunload', this.onUnload); $(document).off('scroll', '.container', this.onContainerScroll); $(document).off('click', 'a', this.linkClicked); $(document).off('click', 'table.action tr[href]', this.rowSelected); diff --git a/public/js/icinga/loader.js b/public/js/icinga/loader.js index e63125a4d..99667ac1c 100644 --- a/public/js/icinga/loader.js +++ b/public/js/icinga/loader.js @@ -640,7 +640,7 @@ this.icinga.logger.error( req.status, errorThrown + ':', - $(req.responseText).text().slice(0, 100) + $(req.responseText).text().replace(/\s+/g, ' ').slice(0, 100) ); this.renderContentToContainer( req.responseText,