Merge branch 'master' into feature/restrict-custom-variables-10965

This commit is contained in:
Eric Lippmann 2016-03-21 14:50:13 +01:00
commit 5bc52a2801
103 changed files with 2364 additions and 1680 deletions

View File

@ -35,6 +35,11 @@ class apache {
require => Package['apache'], require => Package['apache'],
} }
package { 'mod_ssl':
ensure => latest,
notify => Service[$apache],
}
@user { $user: @user { $user:
alias => 'apache', alias => 'apache',
} }

View File

@ -17,6 +17,7 @@
class php { class php {
include apache include apache
include epel
package { 'php': package { 'php':
ensure => latest, ensure => latest,
@ -24,5 +25,11 @@ class php {
require => Package['apache'], require => Package['apache'],
} }
package { 'php-pecl-xdebug':
ensure => latest,
notify => Service['apache'],
require => Class['epel'],
}
php::phpd { ['error_reporting', 'timezone', 'xdebug_settings' ]: } php::phpd { ['error_reporting', 'timezone', 'xdebug_settings' ]: }
} }

View File

@ -14,10 +14,12 @@ Daniel Shirley <aditaa@ig2ad.com>
Davide Demuru <davide.demuru@buongiorno.com> Davide Demuru <davide.demuru@buongiorno.com>
Emil Vikström <emil@pixelstore.se> Emil Vikström <emil@pixelstore.se>
Eric Lippmann <eric.lippmann@netways.de> Eric Lippmann <eric.lippmann@netways.de>
Florian Strohmaier <hello@florianstrohmaier.com>
Goran Rakic <grakic@devbase.net> Goran Rakic <grakic@devbase.net>
Gunnar Beutner <gunnar.beutner@netways.de> Gunnar Beutner <gunnar.beutner@netways.de>
Jannis Moßhammer <jannis.mosshammer@netways.de> Jannis Moßhammer <jannis.mosshammer@netways.de>
Jo Rhett <jo@chegg.com> Jo Rhett <jo@chegg.com>
Joe Doherty <git@pjuu.com>
Johannes Meyer <johannes.meyer@netways.de> Johannes Meyer <johannes.meyer@netways.de>
Louis Sautier <sautier.louis@gmail.com> Louis Sautier <sautier.louis@gmail.com>
Marcus Cobden <marcus@marcuscobden.co.uk> Marcus Cobden <marcus@marcuscobden.co.uk>

View File

@ -1,5 +1,66 @@
# Icinga Web 2 Changelog # Icinga Web 2 Changelog
## What's New in Version 2.2.0
#### Features
* Feature 8487: Number headings in the documentation module
* Feature 8963: Feature commands in the multi select views
* Feature 10654: Render links in acknowledgements, comments and downtimes
* Feature 11062: Allow style classes in plugin output
* Feature 11238: Puppet/Vagrant: Install mod_ssl and forward port 443
#### Bugfixes
* Bug 7350: Tabs are missing if JS is disabled
* Bug 9800: Debian packaging: Ship translation module w/ the icingaweb2 package and install its config.ini
* Bug 10173: Failed commands give no useful error any more
* Bug 10251: Icinga Web 2 fails to run with PHP7
* Bug 10277: Special characters are incorrectly escaped for tooltips in the service grid
* Bug 10289: Doc module: Headers are cut off when clicking on TOC links
* Bug 10309: Move auth backend configuration to app config
* Bug 10310: Monitoring details: information/action ordering
* Bug 10362: Debian packaging: Separate package for CLI missing
* Bug 10366: Text plugin output treated as HTML in too many occasions
* Bug 10369: Accessibility: Focus not visible and lost after refresh
* Bug 10397: Users with no permissions can check multiple services
* Bug 10442: Edit user control should be more prominent
* Bug 10469: "Remove Acknowledgement" text missing in multi-select views
* Bug 10506: HTTP basic auth request is sent when using Kerberos authentication with Apache2 and mod_php
* Bug 10625: Return local date and time when lost connection to the web server
* Bug 10640: Respect protected_variables in nested custom variables too
* Bug 10778: Filters in the host group and service group overview not applied to state links
* Bug 10786: Whitespace characters are ignored in the plugin output in list views
* Bug 10805: Setup Wizard: Obsolete PHP sockets requirement
* Bug 10856: Benchmark is not rendered on many pages
* Bug 10871: Get rid of padding in controls
* Bug 10878: Dashboards different depending on username casing
* Bug 10881: Move iframe from modules to framework
* Bug 10917: Event grid tiles: The filter column "from" is not allowed here
* Bug 10918: Error on logout when using external authentication
* Bug 10921: icingacli monitoring list --format=csv throws error
* Bug 11000: Change license header to only reflect a file's year of creation/initial commit
* Bug 11008: Wobbling spinners
* Bug 11021: Global default theme is not applied while not authenticated
* Bug 11032: Fix icon_image size and provide a CSS class for theming
* Bug 11039: Misleading tooltip in Tactical Overview
* Bug 11051: Preferences and navigation items stored in INI files rely on case sensitive usernames
* Bug 11073: Active row is flickering on refresh
* Bug 11091: Custom navigation items: URL is not escaped/encoded
* Bug 11100: Comments are always persistent
* Bug 11114: Validate that a proper root DN is set for LDAP resources
* Bug 11117: Vendor: Update dompdf to version 0.6.2
* Bug 11119: icingacli shows ugly exception when unable to access the config directory
* Bug 11120: icingacli: command and action shortcuts have been broken
* Bug 11126: Invalid cookie value in cookie icingaweb2-tzo
* Bug 11142: LDAP User Groups backend group_filter
* Bug 11143: Layout: Tabs should be left-aligned
* Bug 11151: Having basic authentication on the webserver but not in Icinga Web 2 causes Web 2 to require basic auth
* Bug 11168: Debian packaging: Don't patch HTMLPurifier loading and install HTMLPurifier*.php files from the library/vendor root
* Bug 11187: Session cookie: Path too broad and unset secure flag on HTTPS
* Bug 11197: Menu items without url should ignore the target configuration
* Bug 11260: Scheduling downtimes through the API not working
## What's New in Version 2.1.1 ## What's New in Version 2.1.1
#### Features #### Features

View File

@ -10,7 +10,7 @@
**Icinga Web 2** is the next generation open source monitoring web interface, framework **Icinga Web 2** is the next generation open source monitoring web interface, framework
and command-line interface developed by the [Icinga Project](https://www.icinga.org/), supporting Icinga 2, and command-line interface developed by the [Icinga Project](https://www.icinga.org/), supporting Icinga 2,
Icinga Core and any other monitoring backend compatible with the Livestatus Protocol. Icinga Core and any other monitoring backend compatible with the IDO database.
![Icinga Web 2](https://www.icinga.org/wp-content/uploads/2015/10/Screen-Shot-2015-10-02-at-00.12.26.png "Icinga Web 2") ![Icinga Web 2](https://www.icinga.org/wp-content/uploads/2015/10/Screen-Shot-2015-10-02-at-00.12.26.png "Icinga Web 2")

View File

@ -1 +1 @@
v2.1.2 v2.2.0

2
Vagrantfile vendored
View File

@ -18,6 +18,8 @@ end
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
config.vm.network "forwarded_port", guest: 80, host: 8080, config.vm.network "forwarded_port", guest: 80, host: 8080,
auto_correct: true auto_correct: true
config.vm.network "forwarded_port", guest: 443, host: 8443,
auto_correct: true
config.vm.provision :shell, :path => ".puppet/manifests/puppet.sh" config.vm.provision :shell, :path => ".puppet/manifests/puppet.sh"

View File

@ -45,27 +45,12 @@ class ConfigController extends Controller
'url' => 'config/resource', 'url' => 'config/resource',
'baseTarget' => '_main' 'baseTarget' => '_main'
)); ));
return $tabs; $tabs->add('authentication', array(
} 'title' => $this->translate('Configure the user and group backends'),
'label' => $this->translate('Authentication'),
/**
* Create and return the tabs to display when showing authentication configuration
*/
public function createAuthenticationTabs()
{
$tabs = $this->getTabs();
$tabs->add('userbackend', array(
'title' => $this->translate('Configure how users authenticate with and log into Icinga Web 2'),
'label' => $this->translate('Users'),
'url' => 'config/userbackend', 'url' => 'config/userbackend',
'baseTarget' => '_main' 'baseTarget' => '_main'
)); ));
$tabs->add('usergroupbackend', array(
'title' => $this->translate('Configure how users are associated with groups by Icinga Web 2'),
'label' => $this->translate('User Groups'),
'url' => 'usergroupbackend/list',
'baseTarget' => '_main'
));
return $tabs; return $tabs;
} }
@ -184,17 +169,19 @@ class ConfigController extends Controller
} }
/** /**
* Action for listing and reordering user backends * Action for listing user and group backends
*/ */
public function userbackendAction() public function userbackendAction()
{ {
$this->assertPermission('config/application/userbackend'); $this->assertPermission('config/application/userbackend');
$this->assertPermission('config/application/usergroupbackend');
$form = new UserBackendReorderForm(); $form = new UserBackendReorderForm();
$form->setIniConfig(Config::app('authentication')); $form->setIniConfig(Config::app('authentication'));
$form->handleRequest(); $form->handleRequest();
$this->view->form = $form; $this->view->form = $form;
$this->createAuthenticationTabs()->activate('userbackend'); $this->view->backendNames = Config::app('groups');
$this->createApplicationTabs()->activate('authentication');
$this->render('userbackend/reorder'); $this->render('userbackend/reorder');
} }

View File

@ -39,6 +39,8 @@ class ListController extends Controller
*/ */
public function applicationlogAction() public function applicationlogAction()
{ {
$this->assertPermission('application/log');
if (! Logger::writesToFile()) { if (! Logger::writesToFile()) {
$this->httpNotFound('Page not found'); $this->httpNotFound('Page not found');
} }

View File

@ -29,16 +29,7 @@ class UsergroupbackendController extends Controller
*/ */
public function indexAction() public function indexAction()
{ {
$this->redirectNow('usergroupbackend/list'); $this->redirectNow('config/userbackend');
}
/**
* Show a list of all user group backends
*/
public function listAction()
{
$this->view->backendNames = Config::app('groups');
$this->createListTabs()->activate('usergroupbackend');
} }
/** /**
@ -47,7 +38,7 @@ class UsergroupbackendController extends Controller
public function createAction() public function createAction()
{ {
$form = new UserGroupBackendForm(); $form = new UserGroupBackendForm();
$form->setRedirectUrl('usergroupbackend/list'); $form->setRedirectUrl('config/userbackend');
$form->addDescription($this->translate('Create a new backend to associate users and groups with.')); $form->addDescription($this->translate('Create a new backend to associate users and groups with.'));
$form->setIniConfig(Config::app('groups')); $form->setIniConfig(Config::app('groups'));
$form->setOnSuccess(function (UserGroupBackendForm $form) { $form->setOnSuccess(function (UserGroupBackendForm $form) {
@ -78,7 +69,7 @@ class UsergroupbackendController extends Controller
$backendName = $this->params->getRequired('backend'); $backendName = $this->params->getRequired('backend');
$form = new UserGroupBackendForm(); $form = new UserGroupBackendForm();
$form->setRedirectUrl('usergroupbackend/list'); $form->setRedirectUrl('config/userbackend');
$form->setIniConfig(Config::app('groups')); $form->setIniConfig(Config::app('groups'));
$form->setOnSuccess(function (UserGroupBackendForm $form) use ($backendName) { $form->setOnSuccess(function (UserGroupBackendForm $form) use ($backendName) {
try { try {
@ -121,7 +112,7 @@ class UsergroupbackendController extends Controller
$backendForm = new UserGroupBackendForm(); $backendForm = new UserGroupBackendForm();
$backendForm->setIniConfig(Config::app('groups')); $backendForm->setIniConfig(Config::app('groups'));
$form = new ConfirmRemovalForm(); $form = new ConfirmRemovalForm();
$form->setRedirectUrl('usergroupbackend/list'); $form->setRedirectUrl('config/userbackend');
$form->setOnSuccess(function (ConfirmRemovalForm $form) use ($backendName, $backendForm) { $form->setOnSuccess(function (ConfirmRemovalForm $form) use ($backendName, $backendForm) {
try { try {
$backendForm->delete($backendName); $backendForm->delete($backendName);
@ -141,23 +132,4 @@ class UsergroupbackendController extends Controller
$this->renderForm($form, $this->translate('Remove User Group Backend')); $this->renderForm($form, $this->translate('Remove User Group Backend'));
} }
/**
* Create the tabs for the application configuration
*/
protected function createListTabs()
{
$tabs = $this->getTabs();
$tabs->add('userbackend', array(
'title' => $this->translate('Configure how users authenticate with and log into Icinga Web 2'),
'label' => $this->translate('Users'),
'url' => 'config/userbackend'
));
$tabs->add('usergroupbackend', array(
'title' => $this->translate('Configure how users are associated with groups by Icinga Web 2'),
'label' => $this->translate('User Groups'),
'url' => 'usergroupbackend/list'
));
return $tabs;
}
} }

View File

@ -5,6 +5,7 @@ namespace Icinga\Forms\Dashboard;
use Icinga\Web\Widget\Dashboard; use Icinga\Web\Widget\Dashboard;
use Icinga\Web\Form; use Icinga\Web\Form;
use Icinga\Web\Form\Validator\UrlValidator;
use Icinga\Web\Url; use Icinga\Web\Url;
use Icinga\Web\Widget\Dashboard\Dashlet; use Icinga\Web\Widget\Dashboard\Dashlet;
@ -27,7 +28,7 @@ class DashletForm extends Form
if (! $this->getSubmitLabel()) { if (! $this->getSubmitLabel()) {
$this->setSubmitLabel($this->translate('Add To Dashboard')); $this->setSubmitLabel($this->translate('Add To Dashboard'));
} }
$this->setAction(URL::fromRequest()); $this->setAction(Url::fromRequest());
} }
/** /**
@ -68,7 +69,8 @@ class DashletForm extends Form
'label' => $this->translate('Url'), 'label' => $this->translate('Url'),
'description' => $this->translate( 'description' => $this->translate(
'Enter url being loaded in the dashlet. You can paste the full URL, including filters.' 'Enter url being loaded in the dashlet. You can paste the full URL, including filters.'
) ),
'validators' => array(new UrlValidator())
) )
); );
$this->addElement( $this->addElement(

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
<?= $tabs ?> <?= $tabs ?>
</div> </div>
<div class="content"> <div class="content">
<h1><?= $this->translate('User Backends') ?></h1>
<?= $this->qlink( <?= $this->qlink(
$this->translate('Create a New User Backend') , $this->translate('Create a New User Backend') ,
'config/createuserbackend', 'config/createuserbackend',
@ -14,4 +15,57 @@
) )
) ?> ) ?>
<?= $form ?> <?= $form ?>
<h1><?= $this->translate('User Group Backends') ?></h1>
<?= $this->qlink(
$this->translate('Create a New User Group Backend') ,
'usergroupbackend/create',
null,
array(
'class' => 'button-link',
'data-base-target' => '_next',
'icon' => 'plus',
'title' => $this->translate('Create a new user group backend')
)
) ?>
<?php if (! count($backendNames)) { return; } ?>
<table class="table-row-selectable common-table" data-base-target="_next">
<thead>
<tr>
<th><?= $this->translate('Backend') ?></th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($backendNames as $backendName => $config):
$type = $config->get('backend');
?>
<tr>
<td>
<?= $this->qlink(
$backendName,
'usergroupbackend/edit',
array('backend' => $backendName),
array(
'icon' => $type === 'external' ? 'magic' : ($type === 'ldap' || $type === 'msldap' ? 'sitemap' : 'database'),
'title' => sprintf($this->translate('Edit user group backend %s'), $backendName)
)
); ?>
</td>
<td class="icon-col text-right">
<?= $this->qlink(
null,
'usergroupbackend/remove',
array('backend' => $backendName),
array(
'class' => 'action-link',
'icon' => 'cancel',
'title' => sprintf($this->translate('Remove user group backend %s'), $backendName)
)
) ?>
</td>
</tr>
<?php endforeach ?>
</tbody>
</table>
</div> </div>

View File

@ -20,7 +20,7 @@
<?php foreach ($this->dashboard->getPanes() as $pane): ?> <?php foreach ($this->dashboard->getPanes() as $pane): ?>
<tr style="background-color: #f1f1f1;"> <tr style="background-color: #f1f1f1;">
<th colspan="2" style="text-align: left; padding: 0.5em;"> <th colspan="2" style="text-align: left; padding: 0.5em;">
<?= $pane->getName(); ?> <?= $this->escape($pane->getName()) ?>
</th> </th>
<th> <th>
<?= $this->qlink( <?= $this->qlink(

View File

@ -40,30 +40,26 @@
</td> </td>
<td class="icon-col text-right" data-base-target="_self"> <td class="icon-col text-right" data-base-target="_self">
<?php if ($i > 0): ?> <?php if ($i > 0): ?>
<button type="submit" name="backend_newpos" class="link-button icon-only animated move-up" value="<?= sprintf( <button type="submit" name="backend_newpos" class="link-button icon-only animated move-up" value="<?= $this->escape(
'%s|%s', $backendNames[$i] . '|' . ($i - 1)
$backendNames[$i],
$i - 1
) ?>" title="<?= $this->translate( ) ?>" title="<?= $this->translate(
'Move up in authentication order' 'Move up in authentication order'
) ?>" aria-label="<?= sprintf( ) ?>" aria-label="<?= $this->escape(sprintf(
$this->translate('Move user backend %s upwards'), $this->translate('Move user backend %s upwards'),
$backendNames[$i] $backendNames[$i]
) ?>"> )) ?>">
<?= $this->icon('up-small') ?> <?= $this->icon('up-small') ?>
</button> </button>
<?php endif ?> <?php endif ?>
<?php if ($i + 1 < count($backendNames)): ?> <?php if ($i + 1 < count($backendNames)): ?>
<button type="submit" name="backend_newpos" class="link-button icon-only animated move-down" value="<?= sprintf( <button type="submit" name="backend_newpos" class="link-button icon-only animated move-down" value="<?= $this->escape(
'%s|%s', $backendNames[$i] . '|' . ($i + 1)
$backendNames[$i],
$i + 1
) ?>" title="<?= $this->translate( ) ?>" title="<?= $this->translate(
'Move down in authentication order' 'Move down in authentication order'
) ?>" aria-label="<?= sprintf( ) ?>" aria-label="<?= $this->escape(sprintf(
$this->translate('Move user backend %s downwards'), $this->translate('Move user backend %s downwards'),
$backendNames[$i] $backendNames[$i]
) ?>"> )) ?>">
<?= $this->icon('down-small') ?> <?= $this->icon('down-small') ?>
</button> </button>
<?php endif ?> <?php endif ?>

View File

@ -4,29 +4,29 @@ use Icinga\Data\Updatable;
use Icinga\Data\Reducible; use Icinga\Data\Reducible;
use Icinga\Data\Selectable; use Icinga\Data\Selectable;
$editLink = null;
if ($this->hasPermission('config/authentication/users/edit') && $backend instanceof Updatable) {
$editLink = $this->qlink(
null,
'user/edit',
array(
'backend' => $backend->getName(),
'user' => $user->user_name
),
array(
'title' => sprintf($this->translate('Edit user %s'), $user->user_name),
'class' => 'user-edit',
'icon' => 'edit'
)
);
}
?> ?>
<div class="controls separated"> <div class="controls separated">
<?php if (! $this->compact): ?> <?php if (! $this->compact): ?>
<?= $tabs; ?> <?= $tabs; ?>
<?php endif ?> <?php endif ?>
<h2 class="clearfix"><?= $this->escape($user->user_name) ?><span class="pull-right"><?= $editLink ?></span></h2> <h2><?= $this->escape($user->user_name) ?></h2>
<?php
if ($this->hasPermission('config/authentication/users/edit') && $backend instanceof Updatable) {
echo $this->qlink(
$this->translate('Edit User'),
'user/edit',
array(
'backend' => $backend->getName(),
'user' => $user->user_name
),
array(
'class' => 'button-link',
'icon' => 'edit',
'title' => sprintf($this->translate('Edit user %s'), $user->user_name)
)
);
}
?>
<table class="name-value-table"> <table class="name-value-table">
<tr> <tr>
<th><?= $this->translate('State'); ?></th> <th><?= $this->translate('State'); ?></th>

View File

@ -1,56 +0,0 @@
<div class="controls">
<?= $tabs ?>
</div>
<div class="content">
<?= $this->qlink(
$this->translate('Create a New User Group Backend') ,
'usergroupbackend/create',
null,
array(
'class' => 'button-link',
'data-base-target' => '_next',
'icon' => 'plus',
'title' => $this->translate('Create a new user group backend')
)
) ?>
<?php if (! count($backendNames)) { return; } ?>
<table class="table-row-selectable common-table" data-base-target="_next">
<thead>
<tr>
<th><?= $this->translate('Backend') ?></th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($backendNames as $backendName => $config):
$type = $config->get('backend');
?>
<tr>
<td>
<?= $this->qlink(
$backendName,
'usergroupbackend/edit',
array('backend' => $backendName),
array(
'icon' => $type === 'external' ? 'magic' : ($type === 'ldap' || $type === 'msldap' ? 'sitemap' : 'database'),
'title' => sprintf($this->translate('Edit user group backend %s'), $backendName)
)
); ?>
</td>
<td class="icon-col text-right">
<?= $this->qlink(
null,
'usergroupbackend/remove',
array('backend' => $backendName),
array(
'class' => 'action-link',
'icon' => 'cancel',
'title' => sprintf($this->translate('Remove user group backend %s'), $backendName)
)
) ?>
</td>
</tr>
<?php endforeach ?>
</tbody>
</table>
</div>

View File

@ -11,10 +11,10 @@ thoroughly.
* A web server, e.g. Apache or nginx * A web server, e.g. Apache or nginx
* PHP >= 5.3.0 w/ gettext, intl and OpenSSL support * 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 * LDAP PHP library when using Active Directory or LDAP for authentication
* Icinga 1.x w/ Livestatus or IDO; Icinga 2.x w/ Livestatus or IDO feature enabled * Icinga 1.x w/ IDO; Icinga 2.x w/ IDO feature enabled
* MySQL or PostgreSQL PHP libraries when using IDO * The IDO table prefix must be icinga_ which is the default
* MySQL or PostgreSQL PHP libraries
### <a id="pagespeed-incompatibility"></a> PageSpeed Module Incompatibility ### <a id="pagespeed-incompatibility"></a> PageSpeed Module Incompatibility
@ -22,14 +22,14 @@ It seems that Web 2 is not compatible with the PageSpeed module. Please disable
following methods. following methods.
**Apache**: **Apache**:
```` ```
ModPagespeedDisallow "*/icingaweb2/*" ModPagespeedDisallow "*/icingaweb2/*"
```` ```
**Nginx**: **Nginx**:
```` ```
pagespeed Disallow "*/icingaweb2/*"; pagespeed Disallow "*/icingaweb2/*";
```` ```
## <a id="installing-from-package"></a> Installing Icinga Web 2 from Package ## <a id="installing-from-package"></a> Installing Icinga Web 2 from Package
@ -55,52 +55,52 @@ You need to add the Icinga repository to your package management configuration f
Below is a list with examples for various distributions. Below is a list with examples for various distributions.
**Debian (debmon)**: **Debian (debmon)**:
```` ```
wget -O - http://debmon.org/debmon/repo.key 2>/dev/null | apt-key add - 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 echo 'deb http://debmon.org/debmon debmon-wheezy main' >/etc/apt/sources.list.d/debmon.list
apt-get update apt-get update
```` ```
**Ubuntu Trusty**: **Ubuntu Trusty**:
```` ```
wget -O - http://packages.icinga.org/icinga.key | apt-key add - wget -O - http://packages.icinga.org/icinga.key | apt-key add -
add-apt-repository 'deb http://packages.icinga.org/ubuntu icinga-trusty main' add-apt-repository 'deb http://packages.icinga.org/ubuntu icinga-trusty main'
apt-get update apt-get update
```` ```
For other Ubuntu versions just replace trusty with your distribution\'s code name. For other Ubuntu versions just replace trusty with your distribution\'s code name.
**RHEL and CentOS**: **RHEL and CentOS**:
```` ```
rpm --import http://packages.icinga.org/icinga.key 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 curl -o /etc/yum.repos.d/ICINGA-release.repo http://packages.icinga.org/epel/ICINGA-release.repo
yum makecache yum makecache
```` ```
**Fedora**: **Fedora**:
```` ```
rpm --import http://packages.icinga.org/icinga.key 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 curl -o /etc/yum.repos.d/ICINGA-release.repo http://packages.icinga.org/fedora/ICINGA-release.repo
yum makecache yum makecache
```` ```
**SLES 11**: **SLES 11**:
```` ```
zypper ar http://packages.icinga.org/SUSE/ICINGA-release-11.repo zypper ar http://packages.icinga.org/SUSE/ICINGA-release-11.repo
zypper ref zypper ref
```` ```
**SLES 12**: **SLES 12**:
```` ```
zypper ar http://packages.icinga.org/SUSE/ICINGA-release.repo zypper ar http://packages.icinga.org/SUSE/ICINGA-release.repo
zypper ref zypper ref
```` ```
**openSUSE**: **openSUSE**:
```` ```
zypper ar http://packages.icinga.org/openSUSE/ICINGA-release.repo zypper ar http://packages.icinga.org/openSUSE/ICINGA-release.repo
zypper ref zypper ref
```` ```
#### <a id="package-repositories-rhel-notes"></a> RHEL/CentOS Notes #### <a id="package-repositories-rhel-notes"></a> RHEL/CentOS Notes
@ -114,7 +114,7 @@ The packages for RHEL/CentOS depend on other packages which are distributed as p
#### <a id="package-repositories-wheezy-notes"></a> Debian wheezy Notes #### <a id="package-repositories-wheezy-notes"></a> Debian wheezy Notes
The packages for Debian wheezy depend on other packages which are distributed as part of the The packages for Debian wheezy depend on other packages which are distributed as part of the
[wheezy-packports](http://backports.debian.org/) repository. Please make sure to enable this repository by following [wheezy-backports](http://backports.debian.org/) repository. Please make sure to enable this repository by following
[these instructions](http://backports.debian.org/Instructions/). [these instructions](http://backports.debian.org/Instructions/).
### <a id="installing-from-package-example"></a> Installing Icinga Web 2 ### <a id="installing-from-package-example"></a> Installing Icinga Web 2
@ -123,35 +123,35 @@ You can install Icinga Web 2 by using your distribution's package manager to ins
Below is a list with examples for various distributions. The additional package `icingacli` is necessary on RPM based systems for being able to follow further steps in this guide. In DEB based systems, the icingacli binary is included in the icingaweb2 package. Below is a list with examples for various distributions. The additional package `icingacli` is necessary on RPM based systems for being able to follow further steps in this guide. In DEB based systems, the icingacli binary is included in the icingaweb2 package.
**Debian and Ubuntu**: **Debian and Ubuntu**:
```` ```
apt-get install icingaweb2 apt-get install icingaweb2
```` ```
For Debian wheezy please read the [package repositories notes](#package-repositories-wheezy-notes). For Debian wheezy please read the [package repositories notes](#package-repositories-wheezy-notes).
**RHEL, CentOS and Fedora**: **RHEL, CentOS and Fedora**:
```` ```
yum install icingaweb2 icingacli yum install icingaweb2 icingacli
```` ```
For RHEL/CentOS please read the [package repositories notes](#package-repositories-rhel-notes). For RHEL/CentOS please read the [package repositories notes](#package-repositories-rhel-notes).
**SLES and openSUSE**: **SLES and openSUSE**:
```` ```
zypper install icingaweb2 icingacli zypper install icingaweb2 icingacli
```` ```
### <a id="preparing-web-setup-from-package"></a> Preparing Web Setup ### <a id="preparing-web-setup-from-package"></a> 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 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. 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`: In order to generate a token use the `icingacli`:
```` ```
icingacli setup token create icingacli setup token create
```` ```
In case you do not remember the token you can show it using the `icingacli`: In case you do not remember the token you can show it using the `icingacli`:
```` ```
icingacli setup token show icingacli setup token show
```` ```
Finally visit Icinga Web 2 in your browser to access the setup wizard and complete the installation: Finally visit Icinga Web 2 in your browser to access the setup wizard and complete the installation:
`/icingaweb2/setup`. `/icingaweb2/setup`.
@ -173,9 +173,9 @@ There is also a browsable version available at
[git.icinga.org](https://git.icinga.org/?p=icingaweb2.git;a=summary "Icinga Web 2 Git Repository"). [git.icinga.org](https://git.icinga.org/?p=icingaweb2.git;a=summary "Icinga Web 2 Git Repository").
This version also offers snapshots for easy download which you can use if you do not have git present on your system. This version also offers snapshots for easy download which you can use if you do not have git present on your system.
```` ```
git clone git://git.icinga.org/icingaweb2.git git clone git://git.icinga.org/icingaweb2.git
```` ```
### <a id="installing-from-source-requirements"></a> Installing Requirements from Source ### <a id="installing-from-source-requirements"></a> Installing Requirements from Source
@ -198,41 +198,41 @@ The setup wizard will check the pre-requisites later on.
Choose a target directory and move Icinga Web 2 there. Choose a target directory and move Icinga Web 2 there.
```` ```
mv icingaweb2 /usr/share/icingaweb2 mv icingaweb2 /usr/share/icingaweb2
```` ```
### <a id="configuring-web-server"></a> Configuring the Web Server ### <a id="configuring-web-server"></a> Configuring the Web Server
Use `icingacli` to generate web server configuration for either Apache or nginx. Use `icingacli` to generate web server configuration for either Apache or nginx.
**Apache**: **Apache**:
```` ```
./bin/icingacli setup config webserver apache --document-root /usr/share/icingaweb2/public ./bin/icingacli setup config webserver apache --document-root /usr/share/icingaweb2/public
```` ```
**nginx**: **nginx**:
```` ```
./bin/icingacli setup config webserver nginx --document-root /usr/share/icingaweb2/public ./bin/icingacli setup config webserver nginx --document-root /usr/share/icingaweb2/public
```` ```
Save the output as new file in your webserver's configuration directory. Save the output as new file in your webserver's configuration directory.
Example for Apache on RHEL or 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 ./bin/icingacli setup config webserver apache --document-root /usr/share/icingaweb2/public > /etc/httpd/conf.d/icingaweb2.conf
```` ```
Example for Apache on SUSE: Example for Apache on SUSE:
```` ```
./bin/icingacli setup config webserver apache --document-root /usr/share/icingaweb2/public > /etc/apache2/conf.d/icingaweb2.conf ./bin/icingacli setup config webserver apache --document-root /usr/share/icingaweb2/public > /etc/apache2/conf.d/icingaweb2.conf
```` ```
Example for Apache on Debian Jessie: Example for Apache on Debian Jessie:
```` ```
./bin/icingacli setup config webserver apache --document-root /usr/share/icingaweb2/public > /etc/apache2/conf-available/icingaweb2.conf ./bin/icingacli setup config webserver apache --document-root /usr/share/icingaweb2/public > /etc/apache2/conf-available/icingaweb2.conf
a2enconf icingaweb2 a2enconf icingaweb2
```` ```
### <a id="preparing-web-setup-from-source"></a> Preparing Icinga Web 2 Setup ### <a id="preparing-web-setup-from-source"></a> Preparing Icinga Web 2 Setup
@ -245,53 +245,53 @@ system group. The web server user and CLI user have to be added to this system g
Add the system group `icingaweb2` in the first place. Add the system group `icingaweb2` in the first place.
**Fedora, RHEL, CentOS, SLES and OpenSUSE**: **Fedora, RHEL, CentOS, SLES and OpenSUSE**:
```` ```
groupadd -r icingaweb2 groupadd -r icingaweb2
```` ```
**Debian and Ubuntu**: **Debian and Ubuntu**:
```` ```
addgroup --system icingaweb2 addgroup --system icingaweb2
```` ```
Add your web server's user to the system group `icingaweb2` Add your web server's user to the system group `icingaweb2`
and restart the web server: and restart the web server:
**Fedora, RHEL and CentOS**: **Fedora, RHEL and CentOS**:
```` ```
usermod -a -G icingaweb2 apache usermod -a -G icingaweb2 apache
service httpd restart service httpd restart
```` ```
**SLES and OpenSUSE**: **SLES and OpenSUSE**:
```` ```
usermod -A icingaweb2 wwwrun usermod -A icingaweb2 wwwrun
service apache2 restart service apache2 restart
```` ```
**Debian and Ubuntu**: **Debian and Ubuntu**:
```` ```
usermod -a -G icingaweb2 www-data usermod -a -G icingaweb2 www-data
service apache2 restart service apache2 restart
```` ```
Use `icingacli` to create the configuration directory which defaults to **/etc/icingaweb2**: Use `icingacli` to create the configuration directory which defaults to **/etc/icingaweb2**:
```` ```
./bin/icingacli setup config directory ./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 When using the web setup you are required to authenticate using a token. In order to generate a token use the
`icingacli`: `icingacli`:
```` ```
./bin/icingacli setup token create ./bin/icingacli setup token create
```` ```
In case you do not remember the token you can show it using the `icingacli`: In case you do not remember the token you can show it using the `icingacli`:
```` ```
./bin/icingacli setup token show ./bin/icingacli setup token show
```` ```
### <a id="web-setup-from-source-wizard"></a> Icinga Web 2 Setup Wizard ### <a id="web-setup-from-source-wizard"></a> Icinga Web 2 Setup Wizard
@ -325,7 +325,7 @@ Puppet, Ansible, Chef, etc. modules.
Create the database and add a new user as shown below for MySQL: Create the database and add a new user as shown below for MySQL:
```` ```
sudo mysql -p sudo mysql -p
CREATE DATABASE icingaweb2; CREATE DATABASE icingaweb2;
@ -333,18 +333,18 @@ GRANT SELECT, INSERT, UPDATE, DELETE, DROP, CREATE VIEW, INDEX, EXECUTE ON icing
quit quit
mysql -p icingaweb2 < /usr/share/icingaweb2/etc/schema/mysql.schema.sql mysql -p icingaweb2 < /usr/share/icingaweb2/etc/schema/mysql.schema.sql
```` ```
Then generate a new password hash as described in the [authentication docs](authentication.md#authentication-configuration-db-setup) Then generate a new password hash as described in the [authentication docs](authentication.md#authentication-configuration-db-setup)
and use it to insert a new user called `icingaadmin` into the database. and use it to insert a new user called `icingaadmin` into the database.
```` ```
mysql -p icingaweb2 mysql -p icingaweb2
INSERT INTO icingaweb_user (name, active, password_hash) VALUES ('icingaadmin', 1, '$1$EzxLOFDr$giVx3bGhVm4lDUAw6srGX1'); INSERT INTO icingaweb_user (name, active, password_hash) VALUES ('icingaadmin', 1, '$1$EzxLOFDr$giVx3bGhVm4lDUAw6srGX1');
quit quit
```` ```
#### <a id="web-setup-manual-from-source-config"></a> Icinga Web 2 Manual Configuration #### <a id="web-setup-manual-from-source-config"></a> Icinga Web 2 Manual Configuration
@ -352,7 +352,7 @@ quit
[resources.ini](resources.md#resources) providing the details for the Icinga Web 2 and [resources.ini](resources.md#resources) providing the details for the Icinga Web 2 and
Icinga 2 IDO database configuration. Example for MySQL: Icinga 2 IDO database configuration. Example for MySQL:
```` ```
vim /etc/icingaweb2/resources.ini vim /etc/icingaweb2/resources.ini
[icingaweb2] [icingaweb2]
@ -373,11 +373,11 @@ port = "3306"
dbname = "icinga" dbname = "icinga"
username = "icinga" username = "icinga"
password = "icinga" password = "icinga"
```` ```
[config.ini](configuration.md#configuration) defining general application settings. [config.ini](configuration.md#configuration) defining general application settings.
```` ```
vim /etc/icingaweb2/config.ini vim /etc/icingaweb2/config.ini
[logging] [logging]
@ -389,60 +389,60 @@ application = "icingaweb2"
[preferences] [preferences]
type = "db" type = "db"
resource = "icingaweb2" resource = "icingaweb2"
```` ```
[authentication.ini](authentication.md#authentication) for e.g. using the previously created database. [authentication.ini](authentication.md#authentication) for e.g. using the previously created database.
```` ```
vim /etc/icingaweb2/authentication.ini vim /etc/icingaweb2/authentication.ini
[icingaweb2] [icingaweb2]
backend = "db" backend = "db"
resource = "icingaweb2" resource = "icingaweb2"
```` ```
[roles.ini](security.md#security) granting the previously added `icingaadmin` user all permissions. [roles.ini](security.md#security) granting the previously added `icingaadmin` user all permissions.
```` ```
vim /etc/icingaweb2/roles.ini vim /etc/icingaweb2/roles.ini
[admins] [admins]
users = "icingaadmin" users = "icingaadmin"
permissions = "*" permissions = "*"
```` ```
#### <a id="web-setup-manual-from-source-config-monitoring-module"></a> Icinga Web 2 Manual Configuration Monitoring Module #### <a id="web-setup-manual-from-source-config-monitoring-module"></a> Icinga Web 2 Manual Configuration Monitoring Module
[config.ini](../modules/monitoring/doc/configuration.md#configuration) defining additional security settings. [config.ini](../modules/monitoring/doc/configuration.md#configuration) defining additional security settings.
```` ```
vim /etc/icingaweb2/modules/monitoring/config.ini vim /etc/icingaweb2/modules/monitoring/config.ini
[security] [security]
protected_customvars = "*pw*,*pass*,community" protected_customvars = "*pw*,*pass*,community"
```` ```
[backends.ini](../modules/monitoring/doc/configuration.md#configuration) referencing the Icinga 2 DB IDO resource. [backends.ini](../modules/monitoring/doc/configuration.md#configuration) referencing the Icinga 2 DB IDO resource.
```` ```
vim /etc/icingaweb2/modules/monitoring/backends.ini vim /etc/icingaweb2/modules/monitoring/backends.ini
[icinga2] [icinga2]
type = "ido" type = "ido"
resource = "icinga2" resource = "icinga2"
```` ```
[commandtransports.ini](../modules/monitoring/doc/commandtransports.md#commandtransports) defining the Icinga 2 command pipe. [commandtransports.ini](../modules/monitoring/doc/commandtransports.md#commandtransports) defining the Icinga 2 command pipe.
```` ```
vim /etc/icingaweb2/modules/monitoring/commandtransports.ini vim /etc/icingaweb2/modules/monitoring/commandtransports.ini
[icinga2] [icinga2]
transport = "local" transport = "local"
path = "/var/run/icinga2/cmd/icinga2.cmd" path = "/var/run/icinga2/cmd/icinga2.cmd"
```` ```
#### <a id="web-setup-manual-from-source-login"></a> Icinga Web 2 Manual Setup Login #### <a id="web-setup-manual-from-source-login"></a> Icinga Web 2 Manual Setup Login
@ -456,11 +456,11 @@ Finally visit Icinga Web 2 in your browser to login as `icingaadmin` user: `/ici
Icinga Web 2 Beta 2 introduces access control based on roles for secured actions. If you've already set up Icinga Web 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 you are required to create the file **roles.ini** beneath Icinga Web 2's configuration directory with the following
content: content:
```` ```
[administrators] [administrators]
users = "your_user_name, another_user_name" users = "your_user_name, another_user_name"
permissions = "*" permissions = "*"
```` ```
After please log out from Icinga Web 2 and log in again for having all permissions granted. After please log out from Icinga Web 2 and log in again for having all permissions granted.
@ -519,3 +519,8 @@ The first release candidate of Icinga Web 2 introduces the following non-backwar
* Since Icinga Web 2 version 2.1.3 LDAP user group backends respect the configuration option `group_filter`. * Since Icinga Web 2 version 2.1.3 LDAP user group backends respect the configuration option `group_filter`.
Users who changed the configuration manually and used the option `filter` instead Users who changed the configuration manually and used the option `filter` instead
have to change it back to `group_filter`. have to change it back to `group_filter`.
## <a id="upgrading-to-2.2.0"></a> Upgrading to Icinga Web 2 2.2.0
* The menu entry `Authorization` beneath `Config` has been renamed to `Authentication`. The role, user backend and user
group backend configuration which was previously found beneath `Authentication` has been moved to `Application`.

View File

@ -1,9 +1,9 @@
# Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ # Icinga Web 2 | (c) 2013-2016 Icinga Development Team | GPLv2+
%define revision 1 %define revision 1
Name: icingaweb2 Name: icingaweb2
Version: 2.1.2 Version: 2.2.0
Release: %{revision}%{?dist} Release: %{revision}%{?dist}
Summary: Icinga Web 2 Summary: Icinga Web 2
Group: Applications/System Group: Applications/System
@ -165,6 +165,18 @@ Requires: %{php} >= 5.3.0
Icinga Web 2 vendor library Parsedown Icinga Web 2 vendor library Parsedown
%package vendor-Zend
Version: 1.12.15
Release: 1%{?dist}
Summary: Icinga Web 2 vendor library Zend Framework
Group: Development/Libraries
License: BSD
Requires: %{php} >= 5.3.0
%description vendor-Zend
Icinga Web 2 vendor library Zend
%prep %prep
%setup -q %setup -q
@ -177,7 +189,7 @@ cp -prv application doc %{buildroot}/%{basedir}
cp -pv etc/bash_completion.d/icingacli %{buildroot}/%{_sysconfdir}/bash_completion.d/icingacli cp -pv etc/bash_completion.d/icingacli %{buildroot}/%{_sysconfdir}/bash_completion.d/icingacli
cp -prv modules/{monitoring,setup,doc,translation} %{buildroot}/%{basedir}/modules cp -prv modules/{monitoring,setup,doc,translation} %{buildroot}/%{basedir}/modules
cp -prv library/Icinga %{buildroot}/%{phpdir} cp -prv library/Icinga %{buildroot}/%{phpdir}
cp -prv library/vendor/{dompdf,HTMLPurifier*,JShrink,lessphp,Parsedown} %{buildroot}/%{basedir}/library/vendor cp -prv library/vendor/{dompdf,HTMLPurifier*,JShrink,lessphp,Parsedown,Zend} %{buildroot}/%{basedir}/library/vendor
cp -prv public/{css,img,js,error_norewrite.html} %{buildroot}/%{basedir}/public cp -prv public/{css,img,js,error_norewrite.html} %{buildroot}/%{basedir}/public
cp -pv packages/files/apache/icingaweb2.conf %{buildroot}/%{wwwconfigdir}/icingaweb2.conf cp -pv packages/files/apache/icingaweb2.conf %{buildroot}/%{wwwconfigdir}/icingaweb2.conf
cp -pv packages/files/bin/icingacli %{buildroot}/%{bindir} cp -pv packages/files/bin/icingacli %{buildroot}/%{bindir}
@ -267,3 +279,8 @@ exit 0
%files vendor-Parsedown %files vendor-Parsedown
%defattr(-,root,root) %defattr(-,root,root)
%{basedir}/library/vendor/Parsedown %{basedir}/library/vendor/Parsedown
%files vendor-Zend
%defattr(-,root,root)
%{basedir}/library/vendor/Zend

View File

@ -520,25 +520,6 @@ abstract class ApplicationBootstrap
return $this; return $this;
} }
/**
* Set up the resource factory
*
* @return $this
*/
protected function setupResourceFactory()
{
try {
$config = Config::app('resources');
ResourceFactory::setConfig($config);
} catch (NotReadableError $e) {
Logger::error(
new IcingaException('Cannot load resource configuration. An exception was thrown:', $e)
);
}
return $this;
}
/** /**
* Set up the user backend factory * Set up the user backend factory
* *

View File

@ -41,7 +41,6 @@ class Cli extends ApplicationBootstrap
->setupInternationalization() ->setupInternationalization()
->parseBasicParams() ->parseBasicParams()
->setupLogger() ->setupLogger()
->setupResourceFactory()
->setupModuleManager() ->setupModuleManager()
->setupUserBackendFactory() ->setupUserBackendFactory()
->loadSetupModuleIfNecessary(); ->loadSetupModuleIfNecessary();

View File

@ -120,7 +120,7 @@ class Manager
} }
if (! is_readable($parent)) { if (! is_readable($parent)) {
throw new NotReadableError( throw new NotReadableError(
'Cannot read enabled modules. Module directory\'s parent directory "%s" is not readable', 'Cannot read enabled modules. Config directory "%s" is not readable',
$parent $parent
); );
} }

View File

@ -1289,7 +1289,7 @@ class Module
$class = $implementation; $class = $implementation;
} }
Hook::register($name, $implementation, $class); Hook::register($name, $class, $class);
return $this; return $this;
} }

View File

@ -8,7 +8,7 @@ namespace Icinga\Application;
*/ */
class Version class Version
{ {
const VERSION = '2.1.2'; const VERSION = '2.2.0';
/** /**
* Get the version of this instance of Icinga Web 2 * Get the version of this instance of Icinga Web 2

View File

@ -82,22 +82,21 @@ class Web extends EmbeddedWeb
->setupLogging() ->setupLogging()
->setupErrorHandling() ->setupErrorHandling()
->loadConfig() ->loadConfig()
->setupResourceFactory() ->setupRequest()
->setupSession() ->setupSession()
->setupNotifications() ->setupNotifications()
->setupRequest()
->setupResponse() ->setupResponse()
->setupUserBackendFactory()
->setupUser()
->setupTimezone()
->setupLogger()
->setupInternationalization()
->setupZendMvc() ->setupZendMvc()
->setupModuleManager() ->setupModuleManager()
->loadSetupModuleIfNecessary() ->loadSetupModuleIfNecessary()
->loadEnabledModules() ->loadEnabledModules()
->setupRoute() ->setupRoute()
->setupPagination(); ->setupPagination()
->setupUserBackendFactory()
->setupUser()
->setupTimezone()
->setupLogger()
->setupInternationalization();
} }
/** /**
@ -322,13 +321,7 @@ class Web extends EmbeddedWeb
'priority' => 810 'priority' => 810
), ),
'authentication' => array( 'authentication' => array(
'label' => t('Authentication'), 'label' => t('Authentication'),
'url' => 'config/userbackend',
'permission' => 'config/application/*',
'priority' => 820
),
'authorization' => array(
'label' => t('Authorization'),
'permission' => 'config/authentication/*', 'permission' => 'config/authentication/*',
'priority' => 830, 'priority' => 830,
'url' => 'role/list' 'url' => 'role/list'
@ -370,9 +363,10 @@ class Web extends EmbeddedWeb
if (Logger::writesToFile()) { if (Logger::writesToFile()) {
$menu['system']['children']['application_log'] = array( $menu['system']['children']['application_log'] = array(
'label' => t('Application Log'), 'label' => t('Application Log'),
'url' => 'list/applicationlog', 'url' => 'list/applicationlog',
'priority' => 710 'permission' => 'application/log',
'priority' => 710
); );
} }
} else { } else {

View File

@ -3,7 +3,6 @@
use Icinga\Util\Translator; use Icinga\Util\Translator;
/** /**
* No-op translate * No-op translate
* *
@ -19,6 +18,11 @@ function N_($messageId)
return $messageId; return $messageId;
} }
// Workaround for test issues, this is required unless our tests are able to
// accomplish "real" bootstrapping
if (function_exists('t')) {
return;
}
if (extension_loaded('gettext')) { if (extension_loaded('gettext')) {

View File

@ -244,7 +244,8 @@ class Auth
$this->user = Session::getSession()->get('user'); $this->user = Session::getSession()->get('user');
if ($this->user !== null && $this->user->isExternalUser() === true) { if ($this->user !== null && $this->user->isExternalUser() === true) {
list($originUsername, $field) = $this->user->getExternalUserInformation(); list($originUsername, $field) = $this->user->getExternalUserInformation();
if (! array_key_exists($field, $_SERVER) || $_SERVER[$field] !== $originUsername) { $username = getenv($field); // usually REMOTE_USER here
if ( !$username || $username !== $originUsername) {
$this->removeAuthorization(); $this->removeAuthorization();
} }
} }

View File

@ -1,143 +0,0 @@
<?php
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
namespace Icinga\Authentication\UserGroup;
use Icinga\Exception\StatementException;
use Icinga\Data\Filter\Filter;
use Icinga\Repository\IniRepository;
use Icinga\User;
use Icinga\Util\StringHelper;
class IniUserGroupBackend extends IniRepository implements UserGroupBackendInterface
{
/**
* The query columns being provided
*
* @var array
*/
protected $queryColumns = array(
'groups' => array(
'group' => 'name',
'group_name' => 'name',
'parent' => 'parent',
'created_at' => 'ctime',
'last_modified' => 'mtime',
'users'
)
);
/**
* The columns which are not permitted to be queried
*
* @var array
*/
protected $blacklistedQueryColumns = array('group');
/**
* The search columns being provided
*
* @var array
*/
protected $searchColumns = array('group');
/**
* The value conversion rules to apply on a query or statement
*
* @var array
*/
protected $conversionRules = array(
'groups' => array(
'created_at' => 'date_time',
'last_modified' => 'date_time',
'users' => 'comma_separated_string'
)
);
/**
* Initialize this ini user group backend
*/
protected function init()
{
$this->ds->getConfigObject()->setKeyColumn('name');
}
/**
* Initialize this repository's filter columns
*
* @return array
*/
protected function initializeFilterColumns()
{
return array(
t('User Group') => 'group',
t('Parent') => 'parent',
t('Created At') => 'created_at',
t('Last Modified') => 'last_modified'
);
}
/**
* Add a new group to this backend
*
* @param string $target
* @param array $data
*
* @throws StatementException In case the operation has failed
*/
public function insert($target, array $data)
{
$data['created_at'] = time();
parent::insert($target, $data);
}
/**
* Update groups of this backend, optionally limited using a filter
*
* @param string $target
* @param array $data
* @param Filter $filter
*
* @throws StatementException In case the operation has failed
*/
public function update($target, array $data, Filter $filter = null)
{
$data['last_modified'] = time();
parent::update($target, $data, $filter);
}
/**
* Return the groups the given user is a member of
*
* @param User $user
*
* @return array
*/
public function getMemberships(User $user)
{
$result = $this->select()->fetchAll();
$groups = array();
foreach ($result as $group) {
$groups[$group->group_name] = $group->parent;
}
$username = strtolower($user->getUsername());
$memberships = array();
foreach ($result as $group) {
if ($group->users && !in_array($group->group_name, $memberships)) {
$users = array_map('strtolower', StringHelper::trimSplit($group->users));
if (in_array($username, $users)) {
$memberships[] = $group->group_name;
$parent = $groups[$group->group_name];
while ($parent !== null) {
$memberships[] = $parent;
$parent = isset($groups[$parent]) ? $groups[$parent] : null;
}
}
}
}
return $memberships;
}
}

View File

@ -22,8 +22,7 @@ class UserGroupBackend
protected static $defaultBackends = array( protected static $defaultBackends = array(
'db', 'db',
'ldap', 'ldap',
'msldap', 'msldap'
//'ini'
); );
/** /**
@ -155,9 +154,6 @@ class UserGroupBackend
case 'db': case 'db':
$backend = new DbUserGroupBackend($resource); $backend = new DbUserGroupBackend($resource);
break; break;
case 'ini':
$backend = new IniUserGroupBackend($resource);
break;
case 'ldap': case 'ldap':
case 'msldap': case 'msldap':
$backend = new LdapUserGroupBackend($resource); $backend = new LdapUserGroupBackend($resource);

View File

@ -5,6 +5,7 @@ namespace Icinga\Cli;
use Icinga\Application\ApplicationBootstrap as App; use Icinga\Application\ApplicationBootstrap as App;
use Icinga\Exception\IcingaException; use Icinga\Exception\IcingaException;
use Icinga\Exception\NotReadableError;
use Icinga\Exception\ProgrammingError; use Icinga\Exception\ProgrammingError;
use Icinga\Cli\Params; use Icinga\Cli\Params;
use Icinga\Cli\Screen; use Icinga\Cli\Screen;
@ -421,10 +422,14 @@ class Loader
{ {
if ($this->modules === null) { if ($this->modules === null) {
$this->modules = array(); $this->modules = array();
$this->modules = array_unique(array_merge( try {
$this->app->getModuleManager()->listEnabledModules(), $this->modules = array_unique(array_merge(
$this->app->getModuleManager()->listLoadedModules() $this->app->getModuleManager()->listEnabledModules(),
)); $this->app->getModuleManager()->listLoadedModules()
));
} catch (NotReadableError $e) {
$this->fail($e->getMessage());
}
} }
return $this->modules; return $this->modules;
} }

View File

@ -153,6 +153,11 @@ class DbConnection implements Selectable, Extensible, Updatable, Reducible, Insp
$driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] = $driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] =
'SET SESSION SQL_MODE=\'STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,' 'SET SESSION SQL_MODE=\'STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,'
. 'NO_AUTO_CREATE_USER,ANSI_QUOTES,PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION\';'; . 'NO_AUTO_CREATE_USER,ANSI_QUOTES,PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION\';';
if (array_key_exists('charset', $adapterParamaters) && $adapterParamaters['charset']) {
$driverOptions[PDO::MYSQL_ATTR_INIT_COMMAND] .= 'SET NAMES ' . $adapterParamaters['charset']. ';';
unset($adapterParamaters['charset']);
}
$adapterParamaters['port'] = $this->config->get('port', 3306); $adapterParamaters['port'] = $this->config->get('port', 3306);
break; break;
case 'oci': case 'oci':

View File

@ -67,16 +67,14 @@ class ResourceFactory implements ConfigAwareFactory
} }
/** /**
* Check if the existing resources are set. If not, throw an error. * Check if the existing resources are set. If not, load them from resources.ini
* *
* @throws ConfigurationError * @throws ConfigurationError
*/ */
private static function assertResourcesExist() private static function assertResourcesExist()
{ {
if (self::$resources === null) { if (self::$resources === null) {
throw new ConfigurationError( self::$resources = Config::app('resources');
'Resources not set up. Please contact your Icinga Web administrator'
);
} }
} }

View File

@ -53,7 +53,11 @@ class TimezoneDetect
} }
if (Platform::isCli() === false && array_key_exists(self::$cookieName, $_COOKIE)) { if (Platform::isCli() === false && array_key_exists(self::$cookieName, $_COOKIE)) {
list($offset, $dst) = explode(',', $_COOKIE[self::$cookieName]); $cookieValue = $_COOKIE[self::$cookieName];
list($offset, $dst) = explode(
strpos($cookieValue, ',') === false ? '-' : ',',
$cookieValue
);
$timezoneName = timezone_name_from_abbr('', (int)$offset, (int)$dst); $timezoneName = timezone_name_from_abbr('', (int)$offset, (int)$dst);
self::$success = (bool)$timezoneName; self::$success = (bool)$timezoneName;

View File

@ -209,6 +209,7 @@ class Controller extends ModuleActionController
); );
$editor = Widget::create('filterEditor'); $editor = Widget::create('filterEditor');
/** @var \Icinga\Web\Widget\FilterEditor $editor */
call_user_func_array( call_user_func_array(
array($editor, 'preserveParams'), array($editor, 'preserveParams'),
array_merge($defaultPreservedParams, $preserveParams ?: array()) array_merge($defaultPreservedParams, $preserveParams ?: array())
@ -221,10 +222,12 @@ class Controller extends ModuleActionController
->setSearchColumns($searchColumns) ->setSearchColumns($searchColumns)
->handleRequest($this->getRequest()); ->handleRequest($this->getRequest());
if (! $this->view->compact) { if ($this->view->compact) {
$this->view->filterEditor = $editor; $editor->setVisible(false);
} }
$this->view->filterEditor = $editor;
return $this; return $this;
} }
} }

View File

@ -459,15 +459,13 @@ class ActionController extends Zend_Controller_Action
$layout->innerLayout = $this->innerLayout; $layout->innerLayout = $this->innerLayout;
if ($user = $req->getUser()) { if ($user = $req->getUser()) {
// Cast preference app.show_benchmark to bool because preferences loaded from a preferences storage are if ((bool) $user->getPreferences()->getValue('icingaweb', 'show_benchmark', false)) {
// always strings if ($this->_helper->layout()->isEnabled()) {
if ((bool) $user->getPreferences()->getValue('icingaweb', 'show_benchmark', false) === true) {
if (!$this->_helper->viewRenderer->getNoRender()) {
$layout->benchmark = $this->renderBenchmark(); $layout->benchmark = $this->renderBenchmark();
} }
} }
if ((bool) $user->getPreferences()->getValue('icingaweb', 'auto_refresh', true) === false) { if (! (bool) $user->getPreferences()->getValue('icingaweb', 'auto_refresh', true)) {
$this->disableAutoRefresh(); $this->disableAutoRefresh();
} }
} }

View File

@ -96,6 +96,9 @@ class Cookie
*/ */
public function getDomain() public function getDomain()
{ {
if ($this->domain === null) {
$this->domain = Config::app()->get('cookie', 'domain');
}
return $this->domain; return $this->domain;
} }
@ -182,9 +185,9 @@ class Cookie
if ($path === null) { if ($path === null) {
// The following call could be used as default for ConfigObject::get(), but we prevent unnecessary // The following call could be used as default for ConfigObject::get(), but we prevent unnecessary
// function calls here, if the path is set in the config // function calls here, if the path is set in the config
$path = Icinga::app()->getRequest()->getBaseUrl(); $path = Icinga::app()->getRequest()->getBaseUrl() . '/'; // Zend has rtrim($baseUrl, '/')
} }
return $path; $this->path = $path;
} }
return $this->path; return $this->path;
} }
@ -219,7 +222,7 @@ class Cookie
// function calls here, if the secure flag is set in the config // function calls here, if the secure flag is set in the config
$secure = Icinga::app()->getRequest()->isSecure(); $secure = Icinga::app()->getRequest()->isSecure();
} }
return $secure; $this->secure = $secure;
} }
return $this->secure; return $this->secure;
} }

View File

@ -0,0 +1,41 @@
<?php
/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
namespace Icinga\Web\Form\Validator;
use Zend_Validate_Abstract;
/**
* Validator that checks whether a textfield doesn't contain raw double quotes
*/
class UrlValidator extends Zend_Validate_Abstract
{
/**
* Error templates
*
* @var array
*
* @see Zend_Validate_Abstract::$_messageTemplates
*/
protected $_messageTemplates = array(
'HAS_QUOTES' => 'The url must not contain raw double quotes. If you really need double quotes, use %22 instead.'
);
/**
* Validate the input value
*
* @param string $value The string to validate
*
* @return bool true if and only if the input is valid, otherwise false
*
* @see Zend_Validate_Abstract::isValid()
*/
public function isValid($value)
{
$hasQuotes = false === strpos($value, '"');
if (! $hasQuotes) {
$this->_error('HAS_QUOTES');
}
return $hasQuotes;
}
}

View File

@ -155,18 +155,16 @@ class LessCompiler
$moduleCss .= '}'; $moduleCss .= '}';
} }
$moduleCss = preg_replace(
'/(\.icinga-module\.module-[^\s]+) (#layout\.[^\s]+)/m',
'\2 \1',
$moduleCss
);
$this->source .= $moduleCss; $this->source .= $moduleCss;
if ($this->theme !== null) { if ($this->theme !== null) {
$this->source .= file_get_contents($this->theme); $this->source .= file_get_contents($this->theme);
} }
return $this->lessc->compile($this->source); return preg_replace(
'/(\.icinga-module\.module-[^\s]+) (#layout\.[^\s]+)/m',
'\2 \1',
$this->lessc->compile($this->source)
);
} }
} }

View File

@ -260,8 +260,9 @@ class Menu implements RecursiveIterator
)); ));
if (Logger::writesToFile()) { if (Logger::writesToFile()) {
$section->add(t('Application Log'), array( $section->add(t('Application Log'), array(
'url' => 'list/applicationlog', 'url' => 'list/applicationlog',
'priority' => 710 'permission' => 'application/log',
'priority' => 710
)); ));
} }

View File

@ -192,7 +192,7 @@ class NavigationItemRenderer
$content = sprintf( $content = sprintf(
'<a%s href="%s"%s>%s</a>', '<a%s href="%s"%s>%s</a>',
$this->view()->propertiesToString($item->getAttributes()), $this->view()->propertiesToString($item->getAttributes()),
$url, $this->view()->escape($url->getAbsoluteUrl('&')),
$this->renderTargetAttribute(), $this->renderTargetAttribute(),
$label $label
); );
@ -218,7 +218,7 @@ class NavigationItemRenderer
protected function renderTargetAttribute() protected function renderTargetAttribute()
{ {
$target = $this->getItem()->getTarget(); $target = $this->getItem()->getTarget();
if ($target === null) { if ($target === null || $this->getItem()->getUrl()->getAbsoluteUrl() == '#') {
return ''; return '';
} }

View File

@ -5,6 +5,7 @@ namespace Icinga\Web\Session;
use Icinga\Application\Logger; use Icinga\Application\Logger;
use Icinga\Exception\ConfigurationError; use Icinga\Exception\ConfigurationError;
use Icinga\Web\Cookie;
/** /**
* Session implementation in PHP * Session implementation in PHP
@ -102,11 +103,21 @@ class PhpSession extends Session
ini_set('session.cache_limiter', null); ini_set('session.cache_limiter', null);
} }
$cookie = new Cookie('bogus');
session_set_cookie_params(
0,
$cookie->getPath(),
$cookie->getDomain(),
$cookie->isSecure(),
true
);
session_start(); session_start();
if ($this->hasBeenTouched) { if ($this->hasBeenTouched) {
ini_set('session.use_cookies', true); ini_set('session.use_cookies', true);
ini_set('session.use_only_cookies', true); ini_set('session.use_only_cookies', true);
/** @noinspection PhpUndefinedVariableInspection */
ini_set('session.cache_limiter', $cacheLimiter); ini_set('session.cache_limiter', $cacheLimiter);
} }
} }

View File

@ -212,17 +212,18 @@ class Url
} }
/** /**
* Set the new Filter of the url to be the current filter and the given filter * Add the given filter to the current filter of the URL
* *
* @param Filter $and * @param Filter $and
*
* @return $this
*/ */
public function addFilter($and) public function addFilter($and)
{ {
$this->setQueryString( $this->setQueryString(
Filter::matchAll( Filter::fromQueryString($this->getQueryString())
$and, ->andFilter($and)
Filter::fromQueryString($this->getQueryString()) ->toQueryString()
)->toQueryString()
); );
return $this; return $this;
} }

View File

@ -55,6 +55,13 @@ class FilterEditor extends AbstractWidget
*/ */
private $selectedIdx; private $selectedIdx;
/**
* Whether the filter control is visible
*
* @var bool
*/
protected $visible = true;
/** /**
* Create a new FilterWidget * Create a new FilterWidget
* *
@ -144,6 +151,30 @@ class FilterEditor extends AbstractWidget
return $this; return $this;
} }
/**
* Get whether the filter control is visible
*
* @return bool
*/
public function isVisible()
{
return $this->visible;
}
/**
* Set whether the filter control is visible
*
* @param bool $visible
*
* @return $this
*/
public function setVisible($visible)
{
$this->visible = (bool) $visible;
return $this;
}
protected function redirectNow($url) protected function redirectNow($url)
{ {
$response = Icinga::app()->getFrontController()->getResponse(); $response = Icinga::app()->getFrontController()->getResponse();
@ -714,7 +745,7 @@ class FilterEditor extends AbstractWidget
} else { } else {
$title = t('Modify this filter'); $title = t('Modify this filter');
if (! $this->filter->isEmpty()) { if (! $this->filter->isEmpty()) {
$title .= ': ' . $this->filter; $title .= ': ' . $this->view()->escape($this->filter);
} }
} }
return $html return $html
@ -731,8 +762,11 @@ class FilterEditor extends AbstractWidget
public function render() public function render()
{ {
if (! $this->visible) {
return '';
}
if (! $this->preservedUrl()->getParam('modifyFilter')) { if (! $this->preservedUrl()->getParam('modifyFilter')) {
return '<div class="filter">' . $this->renderSearch() . $this->shorten($this->filter, 50) . '</div>'; return '<div class="filter">' . $this->renderSearch() . $this->view()->escape($this->shorten($this->filter, 50)) . '</div>';
} }
return '<div class="filter">' return '<div class="filter">'
. $this->renderSearch() . $this->renderSearch()

View File

@ -1,4 +1,4 @@
Module: doc Module: doc
Version: 2.1.2 Version: 2.2.0
Description: Documentation module Description: Documentation module
Extracts, shows and exports documentation for Icinga Web 2 and its modules. Extracts, shows and exports documentation for Icinga Web 2 and its modules.

View File

@ -48,6 +48,7 @@ class Monitoring_ActionsController extends Controller
$form = new ScheduleHostDowntimeCommandForm(); $form = new ScheduleHostDowntimeCommandForm();
$form $form
->setIsApiTarget(true) ->setIsApiTarget(true)
->setBackend($this->backend)
->setObjects($hostList->fetch()) ->setObjects($hostList->fetch())
->handleRequest($this->getRequest()); ->handleRequest($this->getRequest());
} }
@ -96,6 +97,7 @@ class Monitoring_ActionsController extends Controller
$form = new ScheduleServiceDowntimeCommandForm(); $form = new ScheduleServiceDowntimeCommandForm();
$form $form
->setIsApiTarget(true) ->setIsApiTarget(true)
->setBackend($this->backend)
->setObjects($serviceList->fetch()) ->setObjects($serviceList->fetch())
->handleRequest($this->getRequest()); ->handleRequest($this->getRequest());
} }

View File

@ -93,6 +93,7 @@ class HealthController extends Controller
$this->view->programStatus = $programStatus; $this->view->programStatus = $programStatus;
$toggleFeaturesForm = new ToggleInstanceFeaturesCommandForm(); $toggleFeaturesForm = new ToggleInstanceFeaturesCommandForm();
$toggleFeaturesForm $toggleFeaturesForm
->setBackend($this->backend)
->setStatus($programStatus) ->setStatus($programStatus)
->load($programStatus) ->load($programStatus)
->handleRequest(); ->handleRequest();

View File

@ -151,7 +151,6 @@ class HostController extends MonitoredObjectController
$this->assertPermission('monitoring/command/downtime/schedule'); $this->assertPermission('monitoring/command/downtime/schedule');
$form = new ScheduleHostDowntimeCommandForm(); $form = new ScheduleHostDowntimeCommandForm();
$form->setBackend($this->backend);
$form->setTitle($this->translate('Schedule Host Downtime')); $form->setTitle($this->translate('Schedule Host Downtime'));
$this->handleCommandForm($form); $this->handleCommandForm($form);
} }
@ -164,7 +163,6 @@ class HostController extends MonitoredObjectController
$this->assertPermission('monitoring/command/process-check-result'); $this->assertPermission('monitoring/command/process-check-result');
$form = new ProcessCheckResultCommandForm(); $form = new ProcessCheckResultCommandForm();
$form->setBackend($this->backend);
$form->setTitle($this->translate('Submit Passive Host Check Result')); $form->setTitle($this->translate('Submit Passive Host Check Result'));
$this->handleCommandForm($form); $this->handleCommandForm($form);
} }

View File

@ -69,6 +69,7 @@ class HostsController extends Controller
protected function handleCommandForm(ObjectsCommandForm $form) protected function handleCommandForm(ObjectsCommandForm $form)
{ {
$form $form
->setBackend($this->backend)
->setObjects($this->hostList) ->setObjects($this->hostList)
->setRedirectUrl(Url::fromPath('monitoring/hosts/show')->setParams($this->params)) ->setRedirectUrl(Url::fromPath('monitoring/hosts/show')->setParams($this->params))
->handleRequest(); ->handleRequest();
@ -83,11 +84,13 @@ class HostsController extends Controller
public function showAction() public function showAction()
{ {
$this->setAutorefreshInterval(15); $this->setAutorefreshInterval(15);
$checkNowForm = new CheckNowCommandForm(); if ($this->Auth()->hasPermission('monitoring/command/schedule-check')) {
$checkNowForm $checkNowForm = new CheckNowCommandForm();
->setObjects($this->hostList) $checkNowForm
->handleRequest(); ->setObjects($this->hostList)
$this->view->checkNowForm = $checkNowForm; ->handleRequest();
$this->view->checkNowForm = $checkNowForm;
}
$acknowledgedObjects = $this->hostList->getAcknowledgedObjects(); $acknowledgedObjects = $this->hostList->getAcknowledgedObjects();
if (! empty($acknowledgedObjects)) { if (! empty($acknowledgedObjects)) {
@ -192,7 +195,6 @@ class HostsController extends Controller
$this->assertPermission('monitoring/command/downtime/schedule'); $this->assertPermission('monitoring/command/downtime/schedule');
$form = new ScheduleHostDowntimeCommandForm(); $form = new ScheduleHostDowntimeCommandForm();
$form->setBackend($this->backend);
$form->setTitle($this->translate('Schedule Host Downtimes')); $form->setTitle($this->translate('Schedule Host Downtimes'));
$this->handleCommandForm($form); $this->handleCommandForm($form);
} }
@ -205,7 +207,6 @@ class HostsController extends Controller
$this->assertPermission('monitoring/command/process-check-result'); $this->assertPermission('monitoring/command/process-check-result');
$form = new ProcessCheckResultCommandForm(); $form = new ProcessCheckResultCommandForm();
$form->setBackend($this->backend);
$form->setTitle($this->translate('Submit Passive Host Check Results')); $form->setTitle($this->translate('Submit Passive Host Check Results'));
$this->handleCommandForm($form); $this->handleCommandForm($form);
} }

View File

@ -121,7 +121,6 @@ class ServiceController extends MonitoredObjectController
$this->assertPermission('monitoring/command/process-check-result'); $this->assertPermission('monitoring/command/process-check-result');
$form = new ProcessCheckResultCommandForm(); $form = new ProcessCheckResultCommandForm();
$form->setBackend($this->backend);
$form->setTitle($this->translate('Submit Passive Service Check Result')); $form->setTitle($this->translate('Submit Passive Service Check Result'));
$this->handleCommandForm($form); $this->handleCommandForm($form);
} }

View File

@ -75,6 +75,7 @@ class ServicesController extends Controller
protected function handleCommandForm(ObjectsCommandForm $form) protected function handleCommandForm(ObjectsCommandForm $form)
{ {
$form $form
->setBackend($this->backend)
->setObjects($this->serviceList) ->setObjects($this->serviceList)
->setRedirectUrl(Url::fromPath('monitoring/services/show')->setParams($this->params)) ->setRedirectUrl(Url::fromPath('monitoring/services/show')->setParams($this->params))
->handleRequest(); ->handleRequest();
@ -90,11 +91,13 @@ class ServicesController extends Controller
public function showAction() public function showAction()
{ {
$this->setAutorefreshInterval(15); $this->setAutorefreshInterval(15);
$checkNowForm = new CheckNowCommandForm(); if ($this->Auth()->hasPermission('monitoring/command/schedule-check')) {
$checkNowForm $checkNowForm = new CheckNowCommandForm();
->setObjects($this->serviceList) $checkNowForm
->handleRequest(); ->setObjects($this->serviceList)
$this->view->checkNowForm = $checkNowForm; ->handleRequest();
$this->view->checkNowForm = $checkNowForm;
}
$acknowledgedObjects = $this->serviceList->getAcknowledgedObjects(); $acknowledgedObjects = $this->serviceList->getAcknowledgedObjects();
if (! empty($acknowledgedObjects)) { if (! empty($acknowledgedObjects)) {
@ -207,7 +210,6 @@ class ServicesController extends Controller
$this->assertPermission('monitoring/command/process-check-result'); $this->assertPermission('monitoring/command/process-check-result');
$form = new ProcessCheckResultCommandForm(); $form = new ProcessCheckResultCommandForm();
$form->setBackend($this->backend);
$form->setTitle($this->translate('Submit Passive Service Check Results')); $form->setTitle($this->translate('Submit Passive Service Check Results'));
$this->handleCommandForm($form); $this->handleCommandForm($form);
} }

View File

@ -138,7 +138,7 @@ class ToggleInstanceFeaturesCommandForm extends CommandForm
) )
); );
if (! preg_match('~^v2\.\d+\.\d+.*$~', $this->status->program_version)) { if (! $this->getBackend()->isIcinga2($this->status->program_version)) {
$this->addElement( $this->addElement(
'checkbox', 'checkbox',
ToggleInstanceFeatureCommand::FEATURE_HOST_OBSESSING, ToggleInstanceFeatureCommand::FEATURE_HOST_OBSESSING,

View File

@ -34,21 +34,21 @@ class AddCommentCommandForm extends ObjectsCommandForm
*/ */
public function createElements(array $formData = array()) public function createElements(array $formData = array())
{ {
$this->addElements(array( $this->addElement(
'textarea',
'comment',
array( array(
'textarea', 'required' => true,
'comment', 'label' => $this->translate('Comment'),
array( 'description' => $this->translate(
'required' => true, 'If you work with other administrators, you may find it useful to share information about the'
'label' => $this->translate('Comment'), . ' the host or service that is having problems. Make sure you enter a brief description of'
'description' => $this->translate( . ' what you are doing.'
'If you work with other administrators, you may find it useful to share information about the'
. ' the host or service that is having problems. Make sure you enter a brief description of'
. ' what you are doing.'
)
) )
), )
array( );
if (! $this->getBackend()->isIcinga2()) {
$this->addElement(
'checkbox', 'checkbox',
'persistent', 'persistent',
array( array(
@ -59,8 +59,8 @@ class AddCommentCommandForm extends ObjectsCommandForm
. ' restarted.' . ' restarted.'
) )
) )
) );
)); }
return $this; return $this;
} }
@ -76,7 +76,9 @@ class AddCommentCommandForm extends ObjectsCommandForm
$comment->setObject($object); $comment->setObject($object);
$comment->setComment($this->getElement('comment')->getValue()); $comment->setComment($this->getElement('comment')->getValue());
$comment->setAuthor($this->request->getUser()->getUsername()); $comment->setAuthor($this->request->getUser()->getUsername());
$comment->setPersistent($this->getElement('persistent')->isChecked()); if (($persistent = $this->getElement('persistent')) !== null) {
$comment->setPersistent($persistent->isChecked());
}
$this->getTransport($this->request)->send($comment); $this->getTransport($this->request)->send($comment);
} }
Notification::success($this->translatePlural( Notification::success($this->translatePlural(

View File

@ -124,7 +124,7 @@ class ProcessCheckResultCommandForm extends ObjectsCommandForm
ProcessCheckResultCommand::HOST_DOWN => $this->translate('DOWN', 'icinga.state') ProcessCheckResultCommand::HOST_DOWN => $this->translate('DOWN', 'icinga.state')
); );
if (substr($this->getBackend()->getProgramVersion(), 0, 2) !== 'v2') { if (! $this->getBackend()->isIcinga2()) {
$options[ProcessCheckResultCommand::HOST_UNREACHABLE] = $this->translate('UNREACHABLE', 'icinga.state'); $options[ProcessCheckResultCommand::HOST_UNREACHABLE] = $this->translate('UNREACHABLE', 'icinga.state');
} }

View File

@ -12,8 +12,40 @@ use Icinga\Web\Notification;
class RemoveAcknowledgementCommandForm extends ObjectsCommandForm class RemoveAcknowledgementCommandForm extends ObjectsCommandForm
{ {
/** /**
* (non-PHPDoc) * Whether to show the submit label next to the remove icon
* @see \Zend_Form::init() For the method documentation. *
* The submit label is disabled in detail views but should be enabled in multi-select views.
*
* @var bool
*/
protected $labelEnabled = false;
/**
* Whether to show the submit label next to the remove icon
*
* @return bool
*/
public function isLabelEnabled()
{
return $this->labelEnabled;
}
/**
* Set whether to show the submit label next to the remove icon
*
* @param bool $labelEnabled
*
* @return $this
*/
public function setLabelEnabled($labelEnabled)
{
$this->labelEnabled = (bool) $labelEnabled;
return $this;
}
/**
* {@inheritdoc}
*/ */
public function init() public function init()
{ {
@ -36,7 +68,7 @@ class RemoveAcknowledgementCommandForm extends ObjectsCommandForm
), ),
'escape' => false, 'escape' => false,
'ignore' => true, 'ignore' => true,
'label' => $this->getView()->icon('cancel'), 'label' => $this->getSubmitLabel(),
'title' => $this->translatePlural( 'title' => $this->translatePlural(
'Remove problem acknowledgement', 'Remove problem acknowledgement',
'Remove problem acknowledgements', 'Remove problem acknowledgements',
@ -45,12 +77,29 @@ class RemoveAcknowledgementCommandForm extends ObjectsCommandForm
'type' => 'submit' 'type' => 'submit'
) )
); );
return $this; return $this;
} }
/** /**
* (non-PHPDoc) * {@inheritdoc}
* @see \Icinga\Web\Form::onSuccess() For the method documentation. */
public function getSubmitLabel()
{
$label = $this->getView()->icon('cancel');
if ($this->isLabelEnabled()) {
$label .= $this->translatePlural(
'Remove problem acknowledgement',
'Remove problem acknowledgements',
count($this->objects)
);
}
return $label;
}
/**
* {@inheritdoc}
*/ */
public function onSuccess() public function onSuccess()
{ {
@ -66,6 +115,7 @@ class RemoveAcknowledgementCommandForm extends ObjectsCommandForm
'Removing problem acknowledgements..', 'Removing problem acknowledgements..',
count($this->objects) count($this->objects)
)); ));
return true; return true;
} }
} }

View File

@ -33,7 +33,7 @@ class ScheduleHostDowntimeCommandForm extends ScheduleServiceDowntimeCommandForm
) )
); );
if (substr($this->getBackend()->getProgramVersion(), 0, 2) !== 'v2') { if (! $this->getBackend()->isIcinga2()) {
$this->addElement( $this->addElement(
'select', 'select',
'child_hosts', 'child_hosts',

View File

@ -59,7 +59,7 @@ class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm
'permission' => 'monitoring/command/feature/object/flap-detection' 'permission' => 'monitoring/command/feature/object/flap-detection'
) )
); );
if (preg_match('~^[vr]2\.\d+\.\d+.*$~', $this->getIcingaVersion())) { if ($this->getBackend()->isIcinga2()) {
unset($features[ToggleObjectFeatureCommand::FEATURE_OBSESSING]); unset($features[ToggleObjectFeatureCommand::FEATURE_OBSESSING]);
} }
$this->features = $features; $this->features = $features;
@ -176,14 +176,4 @@ class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm
return true; return true;
} }
/**
* Fetch and return the program version of the current instance
*
* @return string
*/
protected function getIcingaVersion()
{
return $this->getBackend()->select()->from('programstatus', array('program_version'))->fetchOne();
}
} }

View File

@ -0,0 +1,38 @@
<?php
/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
/**
* Helper for escaping comments, but preserving links
*/
class Zend_View_Helper_EscapeComment extends Zend_View_Helper_Abstract
{
/**
* The purifier to use for escaping
*
* @var HTMLPurifier
*/
protected static $purifier;
/**
* Escape any comment for being placed inside HTML, but preserve simple links (<a href="...">).
*
* @param string $comment
*
* @return string
*/
public function escapeComment($comment)
{
if (self::$purifier === null) {
require_once 'HTMLPurifier/Bootstrap.php';
require_once 'HTMLPurifier.php';
require_once 'HTMLPurifier.autoload.php';
$config = HTMLPurifier_Config::createDefault();
$config->set('Core.EscapeNonASCIICharacters', true);
$config->set('HTML.Allowed', 'a[href]');
$config->set('Cache.DefinitionImpl', null);
self::$purifier = new HTMLPurifier($config);
}
return self::$purifier->purify($comment);
}
}

View File

@ -27,13 +27,14 @@ class Zend_View_Helper_IconImage extends Zend_View_Helper_Abstract
public function host($object) public function host($object)
{ {
if ($object->host_icon_image && ! preg_match('/[\'"]/', $object->host_icon_image)) { if ($object->host_icon_image && ! preg_match('/[\'"]/', $object->host_icon_image)) {
return $this->view->icon( return $this->view->img(
Macro::resolveMacros($object->host_icon_image, $object), Macro::resolveMacros($object->host_icon_image, $object),
null, null,
array( array(
'alt' => $object->host_icon_image_alt, 'alt' => $object->host_icon_image_alt,
'title' => $object->host_icon_image_alt, 'data-tooltip-delay' => 0,
'data-tooltip-delay' => 0 'class' => 'host-icon-image',
'title' => $object->host_icon_image_alt
) )
); );
} }
@ -49,13 +50,14 @@ class Zend_View_Helper_IconImage extends Zend_View_Helper_Abstract
public function service($object) public function service($object)
{ {
if ($object->service_icon_image && ! preg_match('/[\'"]/', $object->service_icon_image)) { if ($object->service_icon_image && ! preg_match('/[\'"]/', $object->service_icon_image)) {
return $this->view->icon( return $this->view->img(
Macro::resolveMacros($object->service_icon_image, $object), Macro::resolveMacros($object->service_icon_image, $object),
null, null,
array( array(
'alt' => $object->service_icon_image_alt, 'alt' => $object->service_icon_image_alt,
'title' => $object->service_icon_image_alt, 'class' => 'service-icon-image',
'data-tooltip-delay' => 0 'data-tooltip-delay' => 0,
'title' => $object->service_icon_image_alt
) )
); );
} }

View File

@ -33,7 +33,7 @@ class Zend_View_Helper_PluginOutput extends Zend_View_Helper_Abstract
return ''; return '';
} }
$output = preg_replace('~<br[^>]*>~', "\n", $output); $output = preg_replace('~<br[^>]*>~', "\n", $output);
if (strlen($output) > strlen(strip_tags($output))) { if (preg_match('~<[^>]*["/\'][^>]*>~', $output)) {
// HTML // HTML
$output = preg_replace( $output = preg_replace(
'~<table~', '~<table~',
@ -97,7 +97,7 @@ class Zend_View_Helper_PluginOutput extends Zend_View_Helper_Abstract
$config = HTMLPurifier_Config::createDefault(); $config = HTMLPurifier_Config::createDefault();
$config->set('Core.EscapeNonASCIICharacters', true); $config->set('Core.EscapeNonASCIICharacters', true);
$config->set('HTML.Allowed', 'p,br,b,a[href],i,table,tr,td[colspan],div[class]'); $config->set('HTML.Allowed', 'p,br,b,a[href],i,table,tr,td[colspan],div,*[class]');
// This avoids permission problems: // This avoids permission problems:
// $config->set('Core.DefinitionCache', null); // $config->set('Core.DefinitionCache', null);
$config->set('Cache.DefinitionImpl', null); $config->set('Cache.DefinitionImpl', null);

View File

@ -45,7 +45,7 @@
</tr> </tr>
<tr title="<?= $this->translate('A comment, as entered by the author, associated with the scheduled downtime'); ?>"> <tr title="<?= $this->translate('A comment, as entered by the author, associated with the scheduled downtime'); ?>">
<th><?= $this->translate('Comment') ?></th> <th><?= $this->translate('Comment') ?></th>
<td class="comment-text"><?= $this->nl2br($this->escape($this->downtime->comment)) ?></td> <td class="comment-text"><?= $this->nl2br($this->escapeComment($this->downtime->comment)) ?></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>

View File

@ -50,7 +50,7 @@
'<b>' . $acknowledgedCount . '</b>' '<b>' . $acknowledgedCount . '</b>'
); ?> </th> ); ?> </th>
<td> <td>
<?= $removeAckForm ?> <?= $removeAckForm->setLabelEnabled(true) ?>
</td> </td>
</tr> </tr>
<?php endif ?> <?php endif ?>
@ -174,10 +174,12 @@
</td> </td>
</tr> </tr>
<tr> <?php if (isset($checkNowForm)): // Form is unset if the current user lacks the respective permission ?>
<th> <?= $this->translate('Schedule Check') ?> </th> <tr>
<td> <?= $checkNowForm ?> </td> <th> <?= $this->translate('Schedule Check') ?> </th>
</tr> <td> <?= $checkNowForm ?> </td>
</tr>
<?php endif ?>
<tr> <tr>
<th></th> <th></th>

View File

@ -50,6 +50,7 @@ if (! $this->compact): ?>
$stateBadges = new StateBadges(); $stateBadges = new StateBadges();
$stateBadges $stateBadges
->setUrl('monitoring/list/hosts') ->setUrl('monitoring/list/hosts')
->setBaseFilter($this->filterEditor->getFilter())
->add( ->add(
StateBadges::STATE_UP, StateBadges::STATE_UP,
$hostgroup->hosts_up, $hostgroup->hosts_up,

View File

@ -86,9 +86,7 @@ if (! $this->compact): ?>
<?php endif ?> <?php endif ?>
<span class="state-icons"><?= implode(' ', $this->hostFlags($host)) ?></span> <span class="state-icons"><?= implode(' ', $this->hostFlags($host)) ?></span>
</div> </div>
<p class="overview-plugin-output"> <p class="overview-plugin-output"><?= $this->pluginOutput($this->ellipsis($host->host_output, 10000), true) ?></p>
<?= $this->pluginOutput($this->ellipsis($host->host_output, 10000), true) ?>
</p>
</td> </td>
<?php foreach($this->addColumns as $col): ?> <?php foreach($this->addColumns as $col): ?>
<td><?= $this->escape($host->$col) ?></td> <td><?= $this->escape($host->$col) ?></td>

View File

@ -65,14 +65,12 @@ if (! $this->compact): ?>
) )
) ?> ) ?>
<?php else: ?> <?php else: ?>
<?= $this->translate('Sent out to any contact') ?> <?= $this->translate('Not sent out to any contact') ?>
<?php endif ?> <?php endif ?>
</div> </div>
<?php endif ?> <?php endif ?>
</div> </div>
<p class="overview-plugin-output"> <p class="overview-plugin-output"><?= $this->pluginOutput($this->ellipsis($notification->notification_output, 10000), true) ?></p>
<?= $this->pluginOutput($this->ellipsis($notification->notification_output, 10000), true) ?>
</p>
</td> </td>
</tr> </tr>
<?php endforeach ?> <?php endforeach ?>

View File

@ -82,7 +82,7 @@ $hostFilter = '(host_name=' . implode('|host_name=', array_keys($pivotData)) . '
$service->host_display_name $service->host_display_name
), ),
'class' => 'bg-color-' . Service::getStateText($service->service_state) . ($service->service_handled ? ' handled' : ''), 'class' => 'bg-color-' . Service::getStateText($service->service_state) . ($service->service_handled ? ' handled' : ''),
'title' => $this->escape($service->service_output) 'title' => $service->service_output
) )
) ?> ) ?>
</td> </td>

View File

@ -43,6 +43,7 @@ if (! $this->compact): ?>
$stateBadges = new StateBadges(); $stateBadges = new StateBadges();
$stateBadges $stateBadges
->setUrl('monitoring/list/services') ->setUrl('monitoring/list/services')
->setBaseFilter($this->filterEditor->getFilter())
->add( ->add(
StateBadges::STATE_OK, StateBadges::STATE_OK,
$serviceGroup->services_ok, $serviceGroup->services_ok,

View File

@ -90,9 +90,7 @@ if (! $this->compact): ?>
<div class="overview-performance-data"> <div class="overview-performance-data">
<?= $this->perfdata($service->service_perfdata, true, 5) ?> <?= $this->perfdata($service->service_perfdata, true, 5) ?>
</div> </div>
<p class="overview-plugin-output"> <p class="overview-plugin-output"><?= $this->pluginOutput($this->ellipsis($service->service_output, 10000), true) ?></p>
<?= $this->pluginOutput($this->ellipsis($service->service_output, 10000), true) ?>
</p>
</div> </div>
</td> </td>
<?php foreach($this->addColumns as $col): ?> <?php foreach($this->addColumns as $col): ?>

View File

@ -36,10 +36,11 @@
<?= $this->timeAgo($comment->timestamp) ?> <?= $this->timeAgo($comment->timestamp) ?>
</span> </span>
<span class="comment-icons" data-base-target="_self"> <span class="comment-icons" data-base-target="_self">
<?= $comment->persistent ? $this->icon('attach', 'This comment is persistent.') : '' ?> <?= $comment->persistent ? $this->icon('attach', 'This comment is persistent') : '' ?>
<?= $comment->expiration ? $this->icon('clock', sprintf( <?= $comment->expiration ? $this->icon('clock', sprintf(
$this->translate('This comment expires %s.'), $this->translate('This comment expires on %s at %s'),
$this->timeUntil($comment->expiration) $this->formatDate($comment->expiration),
$this->formatTime($comment->expiration)
)) : '' ?> )) : '' ?>
<?php if (isset($delCommentForm)) { <?php if (isset($delCommentForm)) {
$deleteButton = clone $delCommentForm; $deleteButton = clone $delCommentForm;
@ -56,5 +57,5 @@
</span> </span>
</div> </div>
<p class="comment-text"> <p class="comment-text">
<?= $this->nl2br($this->escape($comment->comment)) ?> <?= $this->nl2br($this->escapeComment($comment->comment)) ?>
</p> </p>

View File

@ -67,6 +67,6 @@
</span> </span>
</div> </div>
<p class="comment-text"> <p class="comment-text">
<?= $this->nl2br($this->escape($downtime->comment)) ?> <?= $this->nl2br($this->escapeComment($downtime->comment)) ?>
</p> </p>
</td> </td>

View File

@ -143,12 +143,11 @@ $history->limit($limit * $page);
) ?> ) ?>
<?php endif ?> <?php endif ?>
<?php endif ?> <?php endif ?>
<p class="overview-plugin-output"> <p class="overview-plugin-output"><?php if ($icon) {
<?php if ($icon) { echo $this->icon($icon, null, $iconCssClass ? array('class' => $iconCssClass) : array());
echo $this->icon($icon, null, $iconCssClass ? array('class' => $iconCssClass) : array()); } ?><?= $this->nl2br($this->createTicketLinks($this->escapeComment($msg)))
} ?> // TODO(ak): this allows only a[href] in messages, but plugin output allows more
<?= nl2br($this->createTicketLinks($this->escape($msg)), false) ?> ?></p>
</p>
</td> </td>
</tr> </tr>
<?php endforeach ?> <?php endforeach ?>

View File

@ -49,7 +49,7 @@
) ?> ) ?>
</th> </th>
<td> <td>
<?= $removeAckForm ?> <?= $removeAckForm->setLabelEnabled(true) ?>
</td> </td>
</tr> </tr>
<?php endif ?> <?php endif ?>
@ -176,10 +176,12 @@
</td> </td>
</tr> </tr>
<tr> <?php if (isset($checkNowForm)): // Form is unset if the current user lacks the respective permission ?>
<th> <?= $this->translate('Schedule Check') ?> </th> <tr>
<td> <?= $checkNowForm ?> </td> <th> <?= $this->translate('Schedule Check') ?> </th>
</tr> <td> <?= $checkNowForm ?> </td>
</tr>
<?php endif ?>
<tr> <tr>
<th></th> <th></th>

View File

@ -44,7 +44,7 @@ $acknowledgement = $object->acknowledgement;
} ?> } ?>
</dt> </dt>
<dd> <dd>
<?= $this->nl2br($this->createTicketLinks($this->escape($acknowledgement->getComment()))) ?> <?= $this->nl2br($this->createTicketLinks($this->escapeComment($acknowledgement->getComment()))) ?>
</dd> </dd>
</dl> </dl>
<?php elseif (isset($removeAckForm)): ?> <?php elseif (isset($removeAckForm)): ?>

View File

@ -4,16 +4,14 @@
<?= $this->translate('Check Source') ?> <?= $this->translate('Check Source') ?>
</th> </th>
<td> <td>
<?php if ($object->is_reachable !== null) {
if ((bool) $object->is_reachable) {
echo $this->icon('circle', $this->translate('Is reachable'), array('class' => 'fg-color-ok'));
} else {
echo $this->icon('circle', $this->translate('Not reachable'), array('class' => 'fg-color-critical'));
}
} ?>
<?= $this->escape($object->check_source) ?> <?= $this->escape($object->check_source) ?>
<?php if ($object->is_reachable !== null): ?> <?php if ($object->is_reachable !== null): ?>
<span class="check-source-meta"><?= (bool) $object->is_reachable ? $this->translate('is reachable') : $this->translate('is not reachable') ?></span> <span class="check-source-meta"><?= (bool) $object->is_reachable ? $this->translate('is reachable') : $this->translate('is not reachable') ?></span>
<?php if ((bool) $object->is_reachable) {
echo $this->icon('circle', $this->translate('Is reachable'), array('class' => 'check-source-reachable'));
} else {
echo $this->icon('circle', $this->translate('Not reachable'), array('class' => 'check-source-not-reachable'));
} ?>
<?php endif ?> <?php endif ?>
</td> </td>
</tr> </tr>

View File

@ -6,18 +6,28 @@ $activeChecksEnabled = (bool) $object->active_checks_enabled;
<tr> <tr>
<th><?= $activeChecksEnabled ? $this->translate('Last check') : $this->translate('Last update') ?></th> <th><?= $activeChecksEnabled ? $this->translate('Last check') : $this->translate('Last update') ?></th>
<td data-base-target="_self"> <td data-base-target="_self">
<?php if ((int) $object->state !== 99): ?>
<?= $this->timeAgo($object->last_check) ?>
<?php if ($object->next_update < time()): ?>
<?= $this->icon('circle', $this->translate('Check result is late'), array('class' => 'check-result-late')) ?>
<?php endif ?>
<?php endif ?>
<?php if (isset($checkNowForm)) { // Form is unset if the current user lacks the respective permission <?php if (isset($checkNowForm)) { // Form is unset if the current user lacks the respective permission
echo $checkNowForm; echo $checkNowForm;
} ?> } ?>
<?php if ((int) $object->state !== 99) {
echo $this->timeAgo($object->last_check);
} ?>
</td> </td>
</tr> </tr>
<tr> <tr>
<th><?= $activeChecksEnabled ? $this->translate('Next check') : $this->translate('Next update') ?></th> <th><?= $activeChecksEnabled ? $this->translate('Next check') : $this->translate('Next update') ?></th>
<td> <td>
<?php if ((int) $object->state !== 99) {
if ($activeChecksEnabled) {
echo $this->timeUntil($object->next_check);
} else {
echo sprintf($this->translate('expected %s'), $this->timeUntil($object->next_update));
}
} ?>
<?php if ($activeChecksEnabled && $this->hasPermission('monitoring/command/schedule-check')) { <?php if ($activeChecksEnabled && $this->hasPermission('monitoring/command/schedule-check')) {
if ($object->getType() === $object::TYPE_SERVICE) { if ($object->getType() === $object::TYPE_SERVICE) {
echo $this->qlink( echo $this->qlink(
@ -49,16 +59,6 @@ $activeChecksEnabled = (bool) $object->active_checks_enabled;
); );
} }
} ?> } ?>
<?php if ((int) $object->state !== 99) {
if ($activeChecksEnabled) {
echo $this->timeUntil($object->next_check);
} else {
echo sprintf($this->translate('expected %s'), $this->timeUntil($object->next_update));
}
} ?>
<?php if ($object->next_update < time()) {
echo $this->icon('circle', $this->translate('Check result is late'), array('class' => 'fg-color-critical'));
} ?>
</td> </td>
</tr> </tr>

View File

@ -67,7 +67,7 @@ if (empty($object->comments) && ! $addLink) {
} ?> } ?>
</dt> </dt>
<dd> <dd>
<?= $this->nl2br($this->createTicketLinks($this->escape($comment->comment))) ?> <?= $this->nl2br($this->createTicketLinks($this->escapeComment($comment->comment))) ?>
</dd> </dd>
<?php endforeach ?> <?php endforeach ?>
</dl> </dl>

View File

@ -96,7 +96,7 @@ if (empty($object->comments) && ! $addLink) {
} ?> } ?>
</dt> </dt>
<dd> <dd>
<?= $this->nl2br($this->createTicketLinks($this->escape($downtime->comment))) ?> <?= $this->nl2br($this->createTicketLinks($this->escapeComment($downtime->comment))) ?>
</dd> </dd>
<?php endforeach ?> <?php endforeach ?>
</dl> </dl>

View File

@ -28,7 +28,7 @@ use Icinga\Module\Monitoring\Object\Service;
<?php if ($services_critical_handled): ?> <?php if ($services_critical_handled): ?>
<?= $this->qlink( <?= $this->qlink(
$services_critical_handled . ' ' . ( $services_critical_handled . ' ' . (
$services_critical_unhandled ? $this->translate('Acknowledged') : Service::getStateText(2, true) $services_critical_unhandled ? $this->translate('Handled') : Service::getStateText(2, true)
), ),
'monitoring/list/services', 'monitoring/list/services',
array( array(
@ -38,8 +38,8 @@ use Icinga\Module\Monitoring\Object\Service;
), ),
array('title' => sprintf( array('title' => sprintf(
$this->translatePlural( $this->translatePlural(
'List %u service that is currently in state CRITICAL (Acknowledged)', 'List %u service that is currently in state CRITICAL (Handled)',
'List %u services which are currently in state CRITICAL (Acknowledged)', 'List %u services which are currently in state CRITICAL (Handled)',
$services_critical_handled $services_critical_handled
), ),
$services_critical_handled $services_critical_handled
@ -127,7 +127,7 @@ use Icinga\Module\Monitoring\Object\Service;
<?php if ($services_warning_handled): ?> <?php if ($services_warning_handled): ?>
<?= $this->qlink( <?= $this->qlink(
$services_warning_handled . ' ' . ( $services_warning_handled . ' ' . (
$services_warning_unhandled ? $this->translate('Acknowledged') : Service::getStateText(1, true) $services_warning_unhandled ? $this->translate('Handled') : Service::getStateText(1, true)
), ),
'monitoring/list/services', 'monitoring/list/services',
array( array(
@ -137,8 +137,8 @@ use Icinga\Module\Monitoring\Object\Service;
), ),
array('title' => sprintf( array('title' => sprintf(
$this->translatePlural( $this->translatePlural(
'List %u service that is currently in state WARNING (Acknowledged)', 'List %u service that is currently in state WARNING (Handled)',
'List %u services which are currently in state WARNING (Acknowledged)', 'List %u services which are currently in state WARNING (Handled)',
$services_warning_handled $services_warning_handled
), ),
$services_warning_handled $services_warning_handled
@ -226,7 +226,7 @@ use Icinga\Module\Monitoring\Object\Service;
<?php if ($services_unknown_handled): ?> <?php if ($services_unknown_handled): ?>
<?= $this->qlink( <?= $this->qlink(
$services_unknown_handled . ' ' . ( $services_unknown_handled . ' ' . (
$services_unknown_unhandled ? $this->translate('Acknowledged') : Service::getStateText(3, true) $services_unknown_unhandled ? $this->translate('Handled') : Service::getStateText(3, true)
), ),
'monitoring/list/services', 'monitoring/list/services',
array( array(
@ -236,8 +236,8 @@ use Icinga\Module\Monitoring\Object\Service;
), ),
array('title' => sprintf( array('title' => sprintf(
$this->translatePlural( $this->translatePlural(
'List %u service that is currently in state UNKNOWN (Acknowledged)', 'List %u service that is currently in state UNKNOWN (Handled)',
'List %u services which are currently in state UNKNOWN (Acknowledged)', 'List %u services which are currently in state UNKNOWN (Handled)',
$services_unknown_handled $services_unknown_handled
), ),
$services_unknown_handled $services_unknown_handled

View File

@ -341,4 +341,22 @@ class MonitoringBackend implements Selectable, Queryable, ConnectionInterface
{ {
return $this->select()->from('programstatus', array('program_version'))->fetchOne(); return $this->select()->from('programstatus', array('program_version'))->fetchOne();
} }
/**
* Get whether the backend is Icinga 2
*
* @param string $programVersion
*
* @return bool
*/
public function isIcinga2($programVersion = null)
{
if ($programVersion === null) {
$programVersion = $this->select()->from('programstatus', array('program_version'))->fetchOne();
}
return (bool) preg_match(
'/^[vr]2\.\d+\.\d+.*$/',
$programVersion
);
}
} }

View File

@ -111,16 +111,16 @@ class CommandTransport implements CommandTransportInterface
*/ */
public function send(IcingaCommand $command, $now = null) public function send(IcingaCommand $command, $now = null)
{ {
$tries = 0; $errors = array();
foreach (static::getConfig() as $transportConfig) {
$transport = static::createTransport($transportConfig);
foreach (static::getConfig() as $name => $transportConfig) {
$transport = static::createTransport($transportConfig);
if ($this->transferPossible($command, $transport)) { if ($this->transferPossible($command, $transport)) {
try { try {
$transport->send($command, $now); $transport->send($command, $now);
} catch (CommandTransportException $e) { } catch (CommandTransportException $e) {
Logger::error($e); Logger::error($e);
$tries += 1; $errors[] = sprintf('%s: %s.', $name, rtrim($e->getMessage(), '.'));
continue; // Try the next transport continue; // Try the next transport
} }
@ -128,14 +128,8 @@ class CommandTransport implements CommandTransportInterface
} }
} }
if ($tries > 0) { if (! empty($errors)) {
throw new CommandTransportException( throw new CommandTransportException(implode("\n", $errors));
mt(
'monitoring',
'Failed to send external Icinga command. None of the configured transports'
. ' was able to transfer the command. Please see the log for more details.'
)
);
} }
throw new CommandTransportException( throw new CommandTransportException(

View File

@ -95,7 +95,9 @@ abstract class DataView implements QueryInterface, SortRules, FilterColumns, Ite
public function dump() public function dump()
{ {
$this->order(); if (! $this->isSorted) {
$this->order();
}
return $this->query->dump(); return $this->query->dump();
} }

View File

@ -89,7 +89,11 @@ class HostStatus extends DataView
) { ) {
return array('host', 'host_address', 'host_address6'); return array('host', 'host_address', 'host_address6');
} else { } else {
return array('host', 'host_display_name'); if ($this->connection->isIcinga2()) {
return array('host', 'host_display_name');
} else {
return array('host', 'host_display_name', 'host_alias');
}
} }
} }

View File

@ -3,6 +3,7 @@
namespace Icinga\Module\Monitoring\Object; namespace Icinga\Module\Monitoring\Object;
use stdClass;
use InvalidArgumentException; use InvalidArgumentException;
use Icinga\Application\Config; use Icinga\Application\Config;
use Icinga\Data\Filter\Filter; use Icinga\Data\Filter\Filter;
@ -456,18 +457,34 @@ abstract class MonitoredObject implements Filterable
$customvars = $this->hostVariables; $customvars = $this->hostVariables;
} }
$this->customvars = array(); $this->customvars = $this->obfuscateCustomVars($customvars, $blacklistPattern);
foreach ($customvars as $name => $value) {
if ($blacklistPattern && preg_match($blacklistPattern, $name)) {
$this->customvars[$name] = '***';
} else {
$this->customvars[$name] = $value;
}
}
return $this; return $this;
} }
/**
* Obfuscate custom variables recursively
*
* @param stdClass|array $customvars The custom variables to obfuscate
* @param string $blacklistPattern Which custom variables to obfuscate
*
* @return stdClass|array The obfuscated custom variables
*/
protected function obfuscateCustomVars($customvars, $blacklistPattern)
{
$obfuscatedCustomVars = array();
foreach ($customvars as $name => $value) {
if ($blacklistPattern && preg_match($blacklistPattern, $name)) {
$obfuscatedCustomVars[$name] = '***';
} else {
$obfuscatedCustomVars[$name] = $value instanceof stdClass || is_array($value)
? $this->obfuscateCustomVars($value, $blacklistPattern)
: $value;
}
}
return $customvars instanceof stdClass ? (object) $obfuscatedCustomVars : $obfuscatedCustomVars;
}
/** /**
* Fetch the host custom variables related to this object * Fetch the host custom variables related to this object
* *

View File

@ -122,6 +122,7 @@ abstract class MonitoredObjectController extends Controller
protected function handleCommandForm(ObjectsCommandForm $form) protected function handleCommandForm(ObjectsCommandForm $form)
{ {
$form $form
->setBackend($this->backend)
->setObjects($this->object) ->setObjects($this->object)
->setRedirectUrl(Url::fromPath($this->commandRedirectUrl)->setParams($this->params)) ->setRedirectUrl(Url::fromPath($this->commandRedirectUrl)->setParams($this->params))
->handleRequest(); ->handleRequest();

View File

@ -1,5 +1,5 @@
Module: monitoring Module: monitoring
Version: 2.1.2 Version: 2.2.0
Description: Icinga monitoring module Description: Icinga monitoring module
This is the core module for most Icingaweb users. It provides an This is the core module for most Icingaweb users. It provides an
abstraction layer for various Icinga data backends. abstraction layer for various Icinga data backends.

View File

@ -1,5 +1,26 @@
/*! Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */ /*! Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
// Styles for the icon displayed if a check source is reachable
.check-source-reachable {
color: @color-ok;
}
// Styles for the icon displayed if a check source is not reachable
.check-source-not-reachable {
color: @color-critical;
}
// Styles for the icon displayed if a check result is late
.check-result-late {
color: @color-critical;
&:before {
// Remove right margin because the check now form may be displayed right next to the icon and we already have a gap
// because of inline-blocks
margin-right: 0;
}
}
// Show more and load more links in overviews // Show more and load more links in overviews
.action-links { .action-links {
text-align: right; text-align: right;

View File

@ -2,6 +2,13 @@
@border-left-width: 6px; @border-left-width: 6px;
// Icon images in list and detail views
.host-icon-image,
.service-icon-image {
max-width: 2em;
vertical-align: middle;
}
// Check source reachable information in the host and service detail views // Check source reachable information in the host and service detail views
.check-source-meta { .check-source-meta {
font-size: @font-size-small; font-size: @font-size-small;
@ -77,6 +84,7 @@
font-family: @font-family-fixed; font-family: @font-family-fixed;
font-size: @font-size-small; font-size: @font-size-small;
margin: 0; margin: 0;
white-space: pre-wrap;
} }
// Table for performance data in detail views // Table for performance data in detail views
@ -201,16 +209,12 @@
border-spacing: 0 1px; border-spacing: 0 1px;
width: 100%; width: 100%;
tr[href] { tr[href].active {
.transition(background 0.2s ease); background-color: @tr-active-color;
}
&.active { tr[href]:hover {
background-color: @tr-active-color; background-color: @tr-hover-color;
} cursor: pointer;
&:hover {
background-color: @tr-hover-color;
cursor: pointer;
}
} }
} }

View File

@ -1,5 +1,5 @@
Module: setup Module: setup
Version: 2.1.2 Version: 2.2.0
Description: Setup module Description: Setup module
Web based wizard for setting up Icinga Web 2 and its modules. Web based wizard for setting up Icinga Web 2 and its modules.
This includes the data backends (e.g. relational database, LDAP), This includes the data backends (e.g. relational database, LDAP),

View File

@ -1,5 +1,5 @@
Module: test Module: test
Version: 2.1.2 Version: 2.2.0
Description: Translation module Description: Translation module
This module allows developers to run (unit) tests against Icinga Web 2 and This module allows developers to run (unit) tests against Icinga Web 2 and
any of its modules. Usually you do not need to enable this. any of its modules. Usually you do not need to enable this.

View File

@ -1,5 +1,5 @@
Module: translation Module: translation
Version: 2.1.2 Version: 2.2.0
Description: Translation module Description: Translation module
This module allows developers and translators to translate Icinga Web 2 and This module allows developers and translators to translate Icinga Web 2 and
its modules for multiple languages. You do not need this module to run an its modules for multiple languages. You do not need this module to run an

View File

@ -163,10 +163,11 @@ td, th {
// Styles for when containers are loading. JS will remove this once the containers are ready // Styles for when containers are loading. JS will remove this once the containers are ready
.impact { .impact {
.active > a, // Remove > a once .tabs layout has been fixed
.controls,
.content {
.transition(background-color 2s 1s linear !important); .transition(background-color 2s 1s linear !important);
background-color: @gray-lighter !important; background-color: @gray-lighter !important;
} }
.impact > .controls, .impact li.active a {
.transition(background-color 2s 1s linear !important);
background-color: @gray-lighter !important;
} }

View File

@ -127,6 +127,8 @@ label {
border: none; border: none;
padding: 0; padding: 0;
text-align: left;
&:hover { &:hover {
text-decoration: underline; text-decoration: underline;
} }

View File

@ -97,15 +97,15 @@
& > .controls { & > .controls {
z-index: 3; z-index: 3;
> * { padding-left: @gutter;
margin-left: @gutter !important; padding-right: @gutter;
margin-right: @gutter !important;
> .tabs {
// Remove gutter for tabs
margin-left: -1 * @gutter;
margin-right: -1 * @gutter;
} }
} }
// 1em gutter of containers is maintained by padding of content and margin of every element in controls. We're not
// setting padding to .container because else horizontally scrolled .content may overflow .controls when scrolled
// vertically
} }
} }

View File

@ -68,23 +68,6 @@ a:hover > .icon-cancel {
.button-link { .button-link {
.action-link(); .action-link();
.button();
display: inline-block;
height: 35px;
line-height: 20px;
min-width: 175px;
&:hover {
text-decoration: none;
}
* {
line-height: inherit;
}
i {
font-size: 16px;
}
} }
// List styles // List styles
@ -162,26 +145,21 @@ a:hover > .icon-cancel {
} }
} }
tr[href] { tr[href].active {
.transition(background 0.2s ease); background-color: @tr-active-color;
border-left-color: @icinga-blue;
}
&.active { tr[href]:hover {
background-color: @tr-active-color; background-color: @tr-hover-color;
border-left-color: @icinga-blue; cursor: pointer;
transition: none;
}
&:hover {
background-color: @tr-hover-color;
cursor: pointer;
}
} }
caption { caption {
border-top: 1px solid @gray-light; border-top: 1px solid @gray-light;
caption-side: bottom; caption-side: bottom;
text-align: right;
font-style: italic; font-style: italic;
text-align: right;
} }
} }

View File

@ -100,3 +100,11 @@
.dropdown-nav-item > ul > li:hover > a > .display-on-hover { .dropdown-nav-item > ul > li:hover > a > .display-on-hover {
position: static; position: static;
} }
.tabs > li > .close-container-control {
display: none;
}
#layout.twocols .tabs > li > .close-container-control {
display: block;
}

View File

@ -217,7 +217,7 @@
$ = undefined; $ = undefined;
oldjQuery.getScript( oldjQuery.getScript(
oldConfig.baseUrl + 'js/icinga.min.js' oldConfig.baseUrl.replace(/\/$/, '') + '/js/icinga.min.js'
).done(function () { ).done(function () {
var jQuery = window.jQuery; var jQuery = window.jQuery;
window.icinga = new window.Icinga(oldConfig); window.icinga = new window.Icinga(oldConfig);

View File

@ -243,7 +243,6 @@
*/ */
Navigation.prototype.onPopState = function (url, data) { Navigation.prototype.onPopState = function (url, data) {
// 1. get selection data and set active menu // 1. get selection data and set active menu
console.log('popstate:', data);
if (data) { if (data) {
var active = this.icinga.utils.getElementByDomPath(data); var active = this.icinga.utils.getElementByDomPath(data);
if (!active) { if (!active) {

View File

@ -36,6 +36,12 @@
var self = event.data.self; var self = event.data.self;
var icinga = self.icinga; var icinga = self.icinga;
if (! icinga) {
// Attempt to catch a rare error, race condition, whatever
console.log('Got no icinga in applyHandlers');
return;
}
if (self.initializeModules) { if (self.initializeModules) {
var loaded = false; var loaded = false;
var moduleName = $target.data('icingaModule'); var moduleName = $target.data('icingaModule');
@ -89,12 +95,6 @@
if ($searchField.length && $searchField.val().length) { if ($searchField.length && $searchField.val().length) {
self.searchValue = $searchField.val(); self.searchValue = $searchField.val();
} }
if (icinga.ui.isOneColLayout()) {
icinga.ui.disableCloseButtons();
} else {
icinga.ui.enableCloseButtons();
}
}, },
/** /**

View File

@ -681,11 +681,17 @@
req.addToHistory = false; req.addToHistory = false;
} else { } else {
if (this.failureNotice === null) { if (this.failureNotice === null) {
var now = new Date();
var padString = this.icinga.utils.padString;
this.failureNotice = this.createNotice( this.failureNotice = this.createNotice(
'error', 'error',
'The connection to the Icinga web server was lost at ' + 'The connection to the Icinga web server was lost at '
this.icinga.utils.timeShort() + + now.getFullYear()
'.', + '-' + padString(now.getMonth() + 1, 0, 2)
+ '-' + padString(now.getDate(), 0, 2)
+ ' ' + padString(now.getHours(), 0, 2)
+ ':' + padString(now.getMinutes(), 0, 2)
+ '.',
true true
); );
@ -711,7 +717,7 @@
c += ' persist'; c += ' persist';
} }
var $notice = $( var $notice = $(
'<li class="' + c + '">' + message + '</li>' '<li class="' + c + '">' + this.icinga.utils.escape(message) + '</li>'
).appendTo($('#notifications')); ).appendTo($('#notifications'));
this.icinga.ui.fixControls(); this.icinga.ui.fixControls();
@ -737,7 +743,7 @@
if (forceFocus && forceFocus.length) { if (forceFocus && forceFocus.length) {
activeElementPath = this.icinga.utils.getCSSPath($(forceFocus)); activeElementPath = this.icinga.utils.getCSSPath($(forceFocus));
} else if (document.activeElement.id === 'search') { } else if (document.activeElement && document.activeElement.id === 'search') {
activeElementPath = '#search'; activeElementPath = '#search';
} else if (document.activeElement } else if (document.activeElement
&& document.activeElement !== document.body && document.activeElement !== document.body

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