mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-12-13 16:04:02 +01:00
Compare commits
No commits in common. "main" and "v2.12.2" have entirely different histories.
6
.github/dependabot.yml
vendored
6
.github/dependabot.yml
vendored
@ -1,6 +0,0 @@
|
|||||||
version: 2
|
|
||||||
updates:
|
|
||||||
- package-ecosystem: composer
|
|
||||||
directory: /
|
|
||||||
schedule:
|
|
||||||
interval: daily
|
|
||||||
15
.github/workflows/L10n-update.yml
vendored
15
.github/workflows/L10n-update.yml
vendored
@ -6,6 +6,15 @@ on:
|
|||||||
- main
|
- main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
update:
|
trigger-update:
|
||||||
uses: icinga/github-actions/.github/workflows/L10n-update.yml@main
|
name: L10n Update Trigger
|
||||||
secrets: inherit
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Repository dispatch
|
||||||
|
uses: peter-evans/repository-dispatch@v1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.ICINGABOT_TOKEN }}
|
||||||
|
repository: Icinga/L10n
|
||||||
|
event-type: update
|
||||||
|
client-payload: '{"origin": "${{ github.repository }}", "commit": "${{ github.sha }}"}'
|
||||||
|
|||||||
120
.github/workflows/php.yml
vendored
120
.github/workflows/php.yml
vendored
@ -1,33 +1,111 @@
|
|||||||
name: CI
|
name: PHP Tests
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
- release/*
|
- release/*
|
||||||
- support/*
|
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
php:
|
lint:
|
||||||
name: PHP
|
name: Static analysis for php ${{ matrix.php }} on ${{ matrix.os }}
|
||||||
uses: Icinga/github-actions/.github/workflows/php.yml@main
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3']
|
||||||
|
os: ['ubuntu-latest']
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code base
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
with:
|
with:
|
||||||
databases: true
|
php-version: ${{ matrix.php }}
|
||||||
php-extensions: ldap
|
tools: phpcs
|
||||||
phpunit-version: 9.6
|
|
||||||
dependencies: |
|
- name: Setup dependencies
|
||||||
{
|
run: composer require -n --no-progress overtrue/phplint
|
||||||
"./icinga-php/ipl" : "https://github.com/Icinga/icinga-php-library.git#snapshot/nightly",
|
|
||||||
"./icinga-php/vendor" : "https://github.com/Icinga/icinga-php-thirdparty.git#snapshot/nightly",
|
- name: PHP Lint
|
||||||
"./icingaweb2-modules/icingadb" : "https://github.com/Icinga/icingadb-web.git",
|
if: ${{ ! cancelled() }}
|
||||||
"./icingaweb2-modules/pdfexport" : "https://github.com/Icinga/icingaweb2-module-pdfexport.git",
|
run: ./vendor/bin/phplint -n --exclude={^vendor/.*} --exclude=library/Icinga/Util/String.php ${{ matrix.phplint_options }} -- .
|
||||||
"./icingaweb2-modules/x509" : "https://github.com/Icinga/icingaweb2-module-x509.git"
|
|
||||||
}
|
- name: PHP CodeSniffer
|
||||||
env: |
|
if: ${{ ! cancelled() }}
|
||||||
{
|
run: phpcs
|
||||||
"ICINGAWEB_LIBDIR" : "./icinga-php",
|
|
||||||
"ICINGAWEB_MODULES_DIR" : "modules:./icingaweb2-modules"
|
test:
|
||||||
}
|
name: Unit tests with php ${{ matrix.php }} on ${{ matrix.os }}
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
env:
|
||||||
|
phpunit-version: 9.5
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
php: ['7.2', '7.3', '7.4', '8.0', '8.1', '8.2', '8.3']
|
||||||
|
os: ['ubuntu-latest']
|
||||||
|
include:
|
||||||
|
- php: '7.2'
|
||||||
|
phpunit-version: 8.5
|
||||||
|
|
||||||
|
services:
|
||||||
|
mysql:
|
||||||
|
image: mariadb
|
||||||
|
env:
|
||||||
|
MYSQL_ROOT_PASSWORD: root
|
||||||
|
MYSQL_DATABASE: icinga_unittest
|
||||||
|
MYSQL_USER: icinga_unittest
|
||||||
|
MYSQL_PASSWORD: icinga_unittest
|
||||||
|
options: >-
|
||||||
|
--health-cmd "mariadb -s -uroot -proot -e'SHOW DATABASES;' 2> /dev/null | grep icinga_unittest > test"
|
||||||
|
--health-interval 10s
|
||||||
|
--health-timeout 5s
|
||||||
|
--health-retries 5
|
||||||
|
ports:
|
||||||
|
- 3306/tcp
|
||||||
|
|
||||||
|
pgsql:
|
||||||
|
image: postgres
|
||||||
|
env:
|
||||||
|
POSTGRES_USER: icinga_unittest
|
||||||
|
POSTGRES_PASSWORD: icinga_unittest
|
||||||
|
POSTGRES_DB: icinga_unittest
|
||||||
|
options: >-
|
||||||
|
--health-cmd pg_isready
|
||||||
|
--health-interval 10s
|
||||||
|
--health-timeout 5s
|
||||||
|
--health-retries 5
|
||||||
|
ports:
|
||||||
|
- 5432/tcp
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout code base
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: ${{ matrix.php }}
|
||||||
|
tools: phpunit:${{ matrix.phpunit-version || env.phpunit-version }}
|
||||||
|
extensions: mysql, pgsql, ldap
|
||||||
|
|
||||||
|
- name: Setup dependencies
|
||||||
|
run: |
|
||||||
|
composer require -n --no-progress mockery/mockery ipl/i18n:@dev ipl/web:@dev
|
||||||
|
git clone --depth 1 --branch snapshot/nightly https://github.com/Icinga/icinga-php-thirdparty.git vendor/icinga-php-thirdparty
|
||||||
|
|
||||||
|
- name: PHPUnit
|
||||||
|
env:
|
||||||
|
ICINGAWEB_TEST_MYSQL_PORT: ${{ job.services.mysql.ports['3306'] }}
|
||||||
|
ICINGAWEB_TEST_PGSQL_PORT: ${{ job.services.pgsql.ports['5432'] }}
|
||||||
|
ICINGAWEB_LIBDIR: vendor/
|
||||||
|
run: phpunit -c modules/test/phpunit.xml --verbose
|
||||||
|
|||||||
18
.github/workflows/phpstan.yml
vendored
Normal file
18
.github/workflows/phpstan.yml
vendored
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
name: PHPStan
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
phpstan:
|
||||||
|
uses: icinga/github-actions/.github/workflows/phpstan.yml@main
|
||||||
|
with:
|
||||||
|
phpExtensions: ldap
|
||||||
|
dependencies: |
|
||||||
|
{
|
||||||
|
"/usr/share/icingaweb2-modules/x509" : "https://github.com/Icinga/icingaweb2-module-x509.git",
|
||||||
|
"/usr/share/icingaweb2-modules/icingadb" : "https://github.com/Icinga/icingadb-web.git",
|
||||||
|
"/usr/share/icingaweb2-modules/pdfexport" : "https://github.com/Icinga/icingaweb2-module-pdfexport.git"
|
||||||
|
}
|
||||||
8
.gitignore
vendored
8
.gitignore
vendored
@ -3,8 +3,12 @@
|
|||||||
|
|
||||||
# Except those related to git
|
# Except those related to git
|
||||||
!.git*
|
!.git*
|
||||||
|
!.travis.yml
|
||||||
!.mailmap
|
!.mailmap
|
||||||
|
|
||||||
|
# Testing - created by test/setup_vendor.sh
|
||||||
|
/vendor/
|
||||||
|
|
||||||
# Exclude application log files
|
# Exclude application log files
|
||||||
var/log/*
|
var/log/*
|
||||||
|
|
||||||
@ -16,7 +20,3 @@ build/*
|
|||||||
# Exclude dompdf font cache
|
# Exclude dompdf font cache
|
||||||
library/vendor/dompdf/lib/fonts/*.php
|
library/vendor/dompdf/lib/fonts/*.php
|
||||||
library/vendor/dompdf/lib/fonts/log.htm
|
library/vendor/dompdf/lib/fonts/log.htm
|
||||||
|
|
||||||
# Exclude files from composer install
|
|
||||||
vendor/
|
|
||||||
composer.lock
|
|
||||||
|
|||||||
3
.mailmap
3
.mailmap
@ -15,10 +15,8 @@ Eric Lippmann <eric.lippmann@icinga.com> <lippserd@googlemail.com>
|
|||||||
Florian Strohmaier <florian.strohmaier@icinga.com> <florian.strohmaier@netways.de>
|
Florian Strohmaier <florian.strohmaier@icinga.com> <florian.strohmaier@netways.de>
|
||||||
Florian Strohmaier <florian.strohmaier@icinga.com> <hello@florianstrohmaier.com>
|
Florian Strohmaier <florian.strohmaier@icinga.com> <hello@florianstrohmaier.com>
|
||||||
Florian Strohmaier <florian.strohmaier@icinga.com> <florian.strohmaier@me.com>
|
Florian Strohmaier <florian.strohmaier@icinga.com> <florian.strohmaier@me.com>
|
||||||
Gianluca Piccolo <gianluca.piccolo@wuerth-phoenix.com> <2795394+gianlucapiccolo@users.noreply.github.com>
|
|
||||||
Gunnar Beutner <gunnar.beutner@netways.de> <gunnar@beutner.name>
|
Gunnar Beutner <gunnar.beutner@netways.de> <gunnar@beutner.name>
|
||||||
Jannis Moßhammer <jannis.mosshammer@netways.de>
|
Jannis Moßhammer <jannis.mosshammer@netways.de>
|
||||||
Jan Schuppik <jan.schuppik@icinga.com> <114286749+Jan-Schuppik@users.noreply.github.com>
|
|
||||||
Johannes Meyer <johannes.meyer@icinga.com> <johannes.meyer@netways.de>
|
Johannes Meyer <johannes.meyer@icinga.com> <johannes.meyer@netways.de>
|
||||||
Jennifer Mourek <jennifer.mourek@icinga.com> <jennifer.mourek@netways.de>
|
Jennifer Mourek <jennifer.mourek@icinga.com> <jennifer.mourek@netways.de>
|
||||||
Marius Hein <marius.hein@netways.de> <mhein@itsocks.de>
|
Marius Hein <marius.hein@netways.de> <mhein@itsocks.de>
|
||||||
@ -44,6 +42,5 @@ Thomas Gelf <thomas.gelf@icinga.com> <thomas@gelf.net>
|
|||||||
Tobias Bauriedel <tobias.bauriedel@netways.de> <tobias@bauriedel.de>
|
Tobias Bauriedel <tobias.bauriedel@netways.de> <tobias@bauriedel.de>
|
||||||
Yonas Habteab <yonas.habteab@icinga.com> <yonas.habteab@netways.de>
|
Yonas Habteab <yonas.habteab@icinga.com> <yonas.habteab@netways.de>
|
||||||
Ravi Kumar Kempapura Srinivasa <ravi.srinivasa@icinga.com> <33730024+raviks789@users.noreply.github.com>
|
Ravi Kumar Kempapura Srinivasa <ravi.srinivasa@icinga.com> <33730024+raviks789@users.noreply.github.com>
|
||||||
Ravi Kumar Kempapura Srinivasa <ravi.srinivasa@icinga.com> <raviks789@gmail.com>
|
|
||||||
Sukhwinder Dhillon <sukhwinder.dhillon@icinga.com> <54990055+sukhwinder33445@users.noreply.github.com>
|
Sukhwinder Dhillon <sukhwinder.dhillon@icinga.com> <54990055+sukhwinder33445@users.noreply.github.com>
|
||||||
Sukhwinder Dhillon <sukhwinder.dhillon@icinga.com> <sukhwinder33445@gmail.com>
|
Sukhwinder Dhillon <sukhwinder.dhillon@icinga.com> <sukhwinder33445@gmail.com>
|
||||||
|
|||||||
6
AUTHORS
6
AUTHORS
@ -1,5 +1,4 @@
|
|||||||
Aaron Collins <acollins@chegg.com>
|
Aaron Collins <acollins@chegg.com>
|
||||||
Alex <alexander.noack@web.de>
|
|
||||||
Alexander A. Klimov <alexander.klimov@icinga.com>
|
Alexander A. Klimov <alexander.klimov@icinga.com>
|
||||||
Alexander Aleksandrovič Klimov <alexander.klimov@icinga.com>
|
Alexander Aleksandrovič Klimov <alexander.klimov@icinga.com>
|
||||||
Alexander Fuhr <alexander.fuhr@netways.de>
|
Alexander Fuhr <alexander.fuhr@netways.de>
|
||||||
@ -55,13 +54,10 @@ Ian Shearin <ishearin@womply.com>
|
|||||||
ignasr <ignas.linux@gmail.com>
|
ignasr <ignas.linux@gmail.com>
|
||||||
Janne Heß <janne@hess.ooo>
|
Janne Heß <janne@hess.ooo>
|
||||||
Jannis Moßhammer <jannis.mosshammer@netways.de>
|
Jannis Moßhammer <jannis.mosshammer@netways.de>
|
||||||
Jan Schuppik <jan.schuppik@icinga.com>
|
|
||||||
Jennifer Mourek <jennifer.mourek@icinga.com>
|
Jennifer Mourek <jennifer.mourek@icinga.com>
|
||||||
Jiri Pejchal <jiri.pejchal@gmail.com>
|
Jiri Pejchal <jiri.pejchal@gmail.com>
|
||||||
Joe Doherty <git@pjuu.com>
|
Joe Doherty <git@pjuu.com>
|
||||||
Johannes Meyer <johannes.meyer@icinga.com>
|
Johannes Meyer <johannes.meyer@icinga.com>
|
||||||
Johannes Rauh <johannes.rauh@icinga.com>
|
|
||||||
Jolien Trog <jolien.trog@icinga.com>
|
|
||||||
Joonas Kylmälä <joonas.kylmala@kirjastot.fi>
|
Joonas Kylmälä <joonas.kylmala@kirjastot.fi>
|
||||||
Jorge Vallecillo <jorgevallecilloc@gmail.com>
|
Jorge Vallecillo <jorgevallecilloc@gmail.com>
|
||||||
Jo Rhett <jo@chegg.com>
|
Jo Rhett <jo@chegg.com>
|
||||||
@ -77,7 +73,6 @@ Marc DeTrano <marc@gridshield.net>
|
|||||||
Marcel Weinberg <marcel.weinberg@secucloud.com>
|
Marcel Weinberg <marcel.weinberg@secucloud.com>
|
||||||
Marcus Cobden <marcus@marcuscobden.co.uk>
|
Marcus Cobden <marcus@marcuscobden.co.uk>
|
||||||
Marian Rainer-Harbach <marian@rainer-harbach.at>
|
Marian Rainer-Harbach <marian@rainer-harbach.at>
|
||||||
marianrh <19990392+marianrh@users.noreply.github.com>
|
|
||||||
Mario Rimann <mario@rimann.org>
|
Mario Rimann <mario@rimann.org>
|
||||||
Marius Hein <marius.hein@netways.de>
|
Marius Hein <marius.hein@netways.de>
|
||||||
Markus Frosch <markus.frosch@icinga.com>
|
Markus Frosch <markus.frosch@icinga.com>
|
||||||
@ -130,7 +125,6 @@ Rune Darrud <theflyingcorpse@gmail.com>
|
|||||||
Russell Kubik <russkubik@3d-p.com>
|
Russell Kubik <russkubik@3d-p.com>
|
||||||
Sander Ferdinand <sa.ferdinand@gmail.com>
|
Sander Ferdinand <sa.ferdinand@gmail.com>
|
||||||
sant-swedge <simon.wedge@sant.ox.ac.uk>
|
sant-swedge <simon.wedge@sant.ox.ac.uk>
|
||||||
Silas <67681686+Tqnsls@users.noreply.github.com>
|
|
||||||
Simone Orsi <simahawk@users.noreply.github.com>
|
Simone Orsi <simahawk@users.noreply.github.com>
|
||||||
ss23 <stephen@zxsecurity.co.nz>
|
ss23 <stephen@zxsecurity.co.nz>
|
||||||
Sukhwinder Dhillon <sukhwinder.dhillon@icinga.com>
|
Sukhwinder Dhillon <sukhwinder.dhillon@icinga.com>
|
||||||
|
|||||||
91
CHANGELOG.md
91
CHANGELOG.md
@ -4,96 +4,9 @@ Please make sure to always read our [Upgrading](doc/80-Upgrading.md) documentati
|
|||||||
|
|
||||||
## What's New
|
## What's New
|
||||||
|
|
||||||
### What's New in Version 2.12.6
|
|
||||||
|
|
||||||
You can find all issues related to this release on our [Roadmap](https://github.com/Icinga/icingaweb2/milestone/86?closed=1).
|
|
||||||
|
|
||||||
#### It's Like Fine Wine
|
|
||||||
|
|
||||||
Icinga Web 2.12 is now two years old. But like fine wine, it gets better with age. Each fix and improvement included
|
|
||||||
this time enhances your experience with Icinga Web. Even if just a little bit. Maybe a small annoyance is gone now, or
|
|
||||||
something you didn't even notice was broken is fixed.
|
|
||||||
|
|
||||||
But let's get to it, a small selection of fixes and improvements:
|
|
||||||
|
|
||||||
* Search box shows many magnifying glasses for some community themes #5395
|
|
||||||
* Authentication hooks are not called with external backends #5415
|
|
||||||
* Improve Minimal layout #5386
|
|
||||||
|
|
||||||
### What's New in Version 2.12.5
|
|
||||||
|
|
||||||
You can find all issues related to this release on our [Roadmap](https://github.com/Icinga/icingaweb2/milestone/85?closed=1).
|
|
||||||
|
|
||||||
#### PHP 8.4 Support
|
|
||||||
|
|
||||||
We're again a little behind schedule, but now we support PHP 8.4! This means that installations on Ubuntu 25.04 and
|
|
||||||
Fedora 42+ can now install Icinga Web without worrying about PHP related incompatibilities. Icinga packages will be
|
|
||||||
available in the next few days.
|
|
||||||
|
|
||||||
#### Good Things Take Time
|
|
||||||
|
|
||||||
There's only a single (notable) recent issue that is fixed with this release. All the others are a bit older.
|
|
||||||
|
|
||||||
* External URLs set up as dashlets are not *embedded* the same as navigation items [#5346](https://github.com/Icinga/icingaweb2/issues/5346)
|
|
||||||
|
|
||||||
But the team sat together a few weeks ago and fixed a bug here and there. And of course, also in Icinga Web!
|
|
||||||
|
|
||||||
* Users who are not allowed to change the theme, cannot change the theme mode either [#5385](https://github.com/Icinga/icingaweb2/issues/5385)
|
|
||||||
* Filtering for older-than events with relative time does not work [#5263](https://github.com/Icinga/icingaweb2/issues/5263)
|
|
||||||
* External logout not working from the navigation dashboard [#5000](https://github.com/Icinga/icingaweb2/issues/5000)
|
|
||||||
* Empty values are NULL in CSV exports [#5350](https://github.com/Icinga/icingaweb2/issues/5350)
|
|
||||||
|
|
||||||
#### Breaking, Somewhat
|
|
||||||
|
|
||||||
This is mainly for developers.
|
|
||||||
|
|
||||||
With the support of PHP 8.4, we introduced a new environment variable, `ICINGAWEB_ENVIRONMENT`. Unless set to `dev`,
|
|
||||||
Icinga Web will not show nor log deprecation notices anymore.
|
|
||||||
|
|
||||||
### What's New in Version 2.12.4
|
|
||||||
|
|
||||||
This is a hotfix release which fixes the following issue:
|
|
||||||
|
|
||||||
Database login broken after upgrade [#5343](https://github.com/Icinga/icingaweb2/issues/5343)
|
|
||||||
|
|
||||||
### What's New in Version 2.12.3
|
|
||||||
|
|
||||||
**Notice:** This is a security release. It is recommended to upgrade _immediately_.
|
|
||||||
|
|
||||||
You can find all issues related to this release on our [Roadmap](https://github.com/Icinga/icingaweb2/milestone/83?closed=1).
|
|
||||||
|
|
||||||
#### Vulnerabilities, Closed
|
|
||||||
|
|
||||||
Cross site scripting is one of the worst attacks on web based platforms. Especially, if carrying it out is as easy as
|
|
||||||
the first two mentioned here. You might recognize the open redirect on the login. You are correct, we attempted to fix
|
|
||||||
it already with v2.11.3 but underestimated PHP's quirks. The last is difficult to exploit, hence the lowest severity
|
|
||||||
of all, but don't be fooled by that!
|
|
||||||
|
|
||||||
All four of them are backported to v2.11.5.
|
|
||||||
|
|
||||||
* XSS in embedded content [CVE-2025-27405](https://github.com/Icinga/icingaweb2/security/advisories/GHSA-3x37-fjc3-ch8w)
|
|
||||||
* DOM-based XSS [CVE-2025-27404](https://github.com/Icinga/icingaweb2/security/advisories/GHSA-c6pg-h955-wf66)
|
|
||||||
* Open redirect on login page [CVE-2025-30164](https://github.com/Icinga/icingaweb2/security/advisories/GHSA-8r73-6686-wv8q)
|
|
||||||
* Reflected XSS [CVE-2025-27609](https://github.com/Icinga/icingaweb2/security/advisories/GHSA-5cjw-fwjc-8j38)
|
|
||||||
|
|
||||||
Big thanks to all finders / reporters! :+1:
|
|
||||||
|
|
||||||
#### Bugs, Exterminated
|
|
||||||
|
|
||||||
Did you know, that we started [Icinga Notifications](https://icinga.com/docs/icinga-notifications/latest/) with support
|
|
||||||
for PostgreSQL first? Reason for that is, we wanted to make sure we are fully compatible with it right away. To ensure
|
|
||||||
things like logging in with a PostgreSQL authentication/group backend is case-insensitive, like it was always the case
|
|
||||||
for MySQL. Now it **really** is case-insensitive! There are also two issues fixed, which many of you will probably have
|
|
||||||
noticed since v2.12.2, sorry that it took so long :)
|
|
||||||
|
|
||||||
* Login against Postgres DB is case-sensitive [#5223](https://github.com/Icinga/icingaweb2/issues/5223)
|
|
||||||
* Role list has no functioning quick search [#5300](https://github.com/Icinga/icingaweb2/issues/5300)
|
|
||||||
* After clicking on Check now, the page does not refresh itself [#5293](https://github.com/Icinga/icingaweb2/issues/5293)
|
|
||||||
* Service States display wrong since update to 2.12.2 [#5290](https://github.com/Icinga/icingaweb2/issues/5290)
|
|
||||||
|
|
||||||
### What's New in Version 2.12.2
|
### What's New in Version 2.12.2
|
||||||
|
|
||||||
You can find all issues related to this release on our [Roadmap](https://github.com/Icinga/icingaweb2/milestone/81?closed=1).
|
You can find all issues related to this release on our Roadmap.
|
||||||
|
|
||||||
#### General Fixes
|
#### General Fixes
|
||||||
|
|
||||||
@ -149,7 +62,7 @@ but it’s now slightly improved.
|
|||||||
|
|
||||||
### What's New in Version 2.12.1
|
### What's New in Version 2.12.1
|
||||||
|
|
||||||
You can find all issues related to this release on our [Roadmap](https://github.com/Icinga/icingaweb2/milestone/80?closed=1).
|
You can find all issues related to this release on our Roadmap.
|
||||||
|
|
||||||
#### PHP 8.3 Support
|
#### PHP 8.3 Support
|
||||||
|
|
||||||
|
|||||||
@ -3,108 +3,18 @@
|
|||||||
|
|
||||||
namespace Icinga\Controllers;
|
namespace Icinga\Controllers;
|
||||||
|
|
||||||
use Icinga\Web\Session;
|
use Icinga\Web\Controller;
|
||||||
use ipl\Html\BaseHtmlElement;
|
|
||||||
use ipl\Html\Html;
|
|
||||||
use ipl\Html\HtmlString;
|
|
||||||
use ipl\Html\Text;
|
|
||||||
use ipl\Web\Compat\CompatController;
|
|
||||||
use ipl\Web\Url;
|
|
||||||
use ipl\Web\Widget\Icon;
|
|
||||||
use ipl\Web\Widget\Tabs;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display external or internal links within an iframe
|
* Display external or internal links within an iframe
|
||||||
*/
|
*/
|
||||||
class IframeController extends CompatController
|
class IframeController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Display iframe w/ the given URL
|
* Display iframe w/ the given URL
|
||||||
*/
|
*/
|
||||||
public function indexAction(): void
|
public function indexAction()
|
||||||
{
|
{
|
||||||
$url = Url::fromPath($this->params->getRequired('url'));
|
$this->view->url = $this->params->getRequired('url');
|
||||||
$urlHash = $this->getRequest()->getHeader('X-Icinga-URLHash');
|
|
||||||
$expectedHash = hash('sha256', $url->getAbsoluteUrl() . Session::getSession()->getId());
|
|
||||||
$iframeUrl = Url::fromPath('iframe', ['url' => $url->getAbsoluteUrl()]);
|
|
||||||
|
|
||||||
if (! in_array($url->getScheme(), ['http', 'https'], true)) {
|
|
||||||
$this->httpBadRequest('Invalid URL scheme');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->injectTabs();
|
|
||||||
|
|
||||||
$this->getTabs()->setRefreshUrl($iframeUrl);
|
|
||||||
|
|
||||||
if ($urlHash) {
|
|
||||||
if ($urlHash !== $expectedHash) {
|
|
||||||
$this->httpBadRequest('Invalid URL hash');
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$this->addContent(Html::tag('div', ['class' => 'iframe-warning'], [
|
|
||||||
Html::tag('h2', $this->translate('Attention!')),
|
|
||||||
Html::tag('p', ['class' => 'note'], $this->translate(
|
|
||||||
'You are about to open untrusted content embedded in Icinga Web! Only proceed,'
|
|
||||||
.' by clicking the link below, if you recognize and trust the source!'
|
|
||||||
)),
|
|
||||||
Html::tag('a', ['data-url-hash' => $expectedHash, 'href' => Html::escape($iframeUrl)], $url),
|
|
||||||
Html::tag('p', ['class' => 'reason'], [
|
|
||||||
new Icon('circle-info'),
|
|
||||||
Text::create($this->translate(
|
|
||||||
'You see this warning because you do not seem to have followed a link in Icinga Web.'
|
|
||||||
. ' You can bypass this in the future by configuring a navigation item instead.'
|
|
||||||
))
|
|
||||||
])
|
|
||||||
]));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->getTabs()->setHash($expectedHash);
|
|
||||||
|
|
||||||
$this->addContent(Html::tag(
|
|
||||||
'div',
|
|
||||||
['class' => 'iframe-container'],
|
|
||||||
Html::tag('iframe', [
|
|
||||||
'src' => $url,
|
|
||||||
'sandbox' => 'allow-same-origin allow-scripts allow-popups allow-forms',
|
|
||||||
])
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
private function injectTabs(): void
|
|
||||||
{
|
|
||||||
$this->tabs = new class extends Tabs {
|
|
||||||
private $hash;
|
|
||||||
|
|
||||||
public function setHash($hash)
|
|
||||||
{
|
|
||||||
$this->hash = $hash;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function assemble()
|
|
||||||
{
|
|
||||||
$tabHtml = substr($this->tabs->render(), 34, -5);
|
|
||||||
if ($this->refreshUrl !== null) {
|
|
||||||
$tabHtml = preg_replace(
|
|
||||||
[
|
|
||||||
'/(?<=class="refresh-container-control spinner" href=")([^"]*)/',
|
|
||||||
'/(\s)(?=href)/'
|
|
||||||
],
|
|
||||||
[
|
|
||||||
$this->refreshUrl->getAbsoluteUrl(),
|
|
||||||
' data-url-hash="' . $this->hash . '" '
|
|
||||||
],
|
|
||||||
$tabHtml
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
BaseHtmlElement::add(HtmlString::create($tabHtml));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$this->controls->setTabs($this->tabs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -133,18 +133,6 @@ class MigrationForm extends CompatForm
|
|||||||
. ' that has the appropriate credentials to resolve this issue.'
|
. ' that has the appropriate credentials to resolve this issue.'
|
||||||
),
|
),
|
||||||
implode(', ', $mm->getRequiredDatabasePrivileges())
|
implode(', ', $mm->getRequiredDatabasePrivileges())
|
||||||
))),
|
|
||||||
new HtmlElement('br'),
|
|
||||||
new HtmlElement('br'),
|
|
||||||
new HtmlElement('span', null, Text::create(sprintf(
|
|
||||||
$this->translate(
|
|
||||||
'The database name may contain either an underscore or a percent sign.'
|
|
||||||
. ' In MySQL these characters represent a wildcard. If part of a database name,'
|
|
||||||
. ' they might not have been escaped when manually granting privileges.'
|
|
||||||
. ' Privileges might not be detected in this case. Check the documentation and'
|
|
||||||
. ' update your grants accordingly: %s'
|
|
||||||
),
|
|
||||||
'https://dev.mysql.com/doc/refman/8.0/en/grant.html#grant-quoting'
|
|
||||||
)))
|
)))
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|||||||
@ -184,6 +184,15 @@ use ipl\Web\Widget\StateBadge;
|
|||||||
</div>
|
</div>
|
||||||
<div class="about-social">
|
<div class="about-social">
|
||||||
<?= $this->qlink(
|
<?= $this->qlink(
|
||||||
|
null,
|
||||||
|
'https://www.twitter.com/icinga',
|
||||||
|
null,
|
||||||
|
array(
|
||||||
|
'target' => '_blank',
|
||||||
|
'icon' => 'twitter',
|
||||||
|
'title' => $this->translate('Icinga on Twitter')
|
||||||
|
)
|
||||||
|
) ?> <?= $this->qlink(
|
||||||
null,
|
null,
|
||||||
'https://www.facebook.com/icinga',
|
'https://www.facebook.com/icinga',
|
||||||
null,
|
null,
|
||||||
|
|||||||
@ -28,6 +28,18 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul id="social">
|
<ul id="social">
|
||||||
|
<li>
|
||||||
|
<?= $this->qlink(
|
||||||
|
null,
|
||||||
|
'https://twitter.com/icinga',
|
||||||
|
null,
|
||||||
|
array(
|
||||||
|
'target' => '_blank',
|
||||||
|
'icon' => 'twitter',
|
||||||
|
'title' => $this->translate('Icinga on Twitter')
|
||||||
|
)
|
||||||
|
) ?>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<?= $this->qlink(
|
<?= $this->qlink(
|
||||||
null,
|
null,
|
||||||
|
|||||||
@ -6,7 +6,7 @@
|
|||||||
<?= $this->tabs->render($this); ?>
|
<?= $this->tabs->render($this); ?>
|
||||||
<br/>
|
<br/>
|
||||||
<div>
|
<div>
|
||||||
<h1>Could not <?= $action; ?> module "<?= $this->escape($moduleName); ?>"</h1>
|
<h1>Could not <?= $action; ?> module "<?= $moduleName; ?>"</h1>
|
||||||
<p>
|
<p>
|
||||||
While operation the following error occurred:
|
While operation the following error occurred:
|
||||||
<br />
|
<br />
|
||||||
|
|||||||
@ -23,7 +23,7 @@ $modReason = [];
|
|||||||
|
|
||||||
if (isset($requiredVendor, $requiredProject) && $requiredVendor && $requiredProject) {
|
if (isset($requiredVendor, $requiredProject) && $requiredVendor && $requiredProject) {
|
||||||
// TODO: I don't like this, can we define requirements somewhere else?
|
// TODO: I don't like this, can we define requirements somewhere else?
|
||||||
$coreDeps = ['icinga-php-library' => '>= 0.14.2', 'icinga-php-thirdparty' => '>= 0.12'];
|
$coreDeps = ['icinga-php-library' => '>= 0.13.2', 'icinga-php-thirdparty' => '>= 0.12'];
|
||||||
|
|
||||||
foreach ($coreDeps as $libraryName => $requiredVersion) {
|
foreach ($coreDeps as $libraryName => $requiredVersion) {
|
||||||
if (! $libraries->has($libraryName)) {
|
if (! $libraries->has($libraryName)) {
|
||||||
|
|||||||
8
application/views/scripts/iframe/index.phtml
Normal file
8
application/views/scripts/iframe/index.phtml
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
<?php if (! $compact): ?>
|
||||||
|
<div class="controls">
|
||||||
|
<?= $tabs ?>
|
||||||
|
</div>
|
||||||
|
<?php endif ?>
|
||||||
|
<div class="iframe-container">
|
||||||
|
<iframe src="<?= $this->escape($url) ?>" frameborder="no"></iframe>
|
||||||
|
</div>
|
||||||
@ -8,7 +8,6 @@ $searchDashboard->setUser($this->Auth()->getUser());
|
|||||||
|
|
||||||
if ($searchDashboard->search('dummy')->getPane('search')->hasDashlets()): ?>
|
if ($searchDashboard->search('dummy')->getPane('search')->hasDashlets()): ?>
|
||||||
<form action="<?= $this->href('search') ?>" method="get" role="search" class="search-control">
|
<form action="<?= $this->href('search') ?>" method="get" role="search" class="search-control">
|
||||||
<i class="icon fa-search fa search-icon"></i>
|
|
||||||
<input type="text" name="q" id="search" class="search search-input" required
|
<input type="text" name="q" id="search" class="search search-input" required
|
||||||
placeholder="<?= $this->translate('Search') ?> …"
|
placeholder="<?= $this->translate('Search') ?> …"
|
||||||
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false">
|
autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false">
|
||||||
|
|||||||
@ -21,5 +21,7 @@
|
|||||||
<?= $this->translate('In case you can access the file by yourself, you can open it and insert the config manually:'); ?>
|
<?= $this->translate('In case you can access the file by yourself, you can open it and insert the config manually:'); ?>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<pre><code><?= $this->escape($configString); ?></code></pre>
|
<pre>
|
||||||
|
<code><?= $this->escape($configString); ?></code>
|
||||||
|
</pre>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@ -1,10 +0,0 @@
|
|||||||
{
|
|
||||||
"config": {
|
|
||||||
"platform": {
|
|
||||||
"php": "8.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"mockery/mockery": "^1.6"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -399,7 +399,7 @@ You will need to install certain dependencies depending on your setup:
|
|||||||
monitor your infrastructure
|
monitor your infrastructure
|
||||||
* A web server, e.g. Apache or Nginx
|
* A web server, e.g. Apache or Nginx
|
||||||
* PHP version ≥ 7.2
|
* PHP version ≥ 7.2
|
||||||
* [Icinga PHP Library (ipl)](https://github.com/Icinga/icinga-php-library) (≥ 0.14.2)
|
* [Icinga PHP Library (ipl)](https://github.com/Icinga/icinga-php-library) (≥ 0.13.2)
|
||||||
* [Icinga PHP Thirdparty](https://github.com/Icinga/icinga-php-thirdparty) (≥ 0.12)
|
* [Icinga PHP Thirdparty](https://github.com/Icinga/icinga-php-thirdparty) (≥ 0.12)
|
||||||
* The following PHP modules must be installed: cURL, json, gettext, fileinfo, intl, dom, OpenSSL and xml
|
* The following PHP modules must be installed: cURL, json, gettext, fileinfo, intl, dom, OpenSSL and xml
|
||||||
* The [pdfexport](https://github.com/Icinga/icingaweb2-module-pdfexport) module (≥0.10) is required for the
|
* The [pdfexport](https://github.com/Icinga/icingaweb2-module-pdfexport) module (≥0.10) is required for the
|
||||||
|
|||||||
@ -59,7 +59,7 @@ sudo htpasswd -c /etc/icingaweb2/.http-users icingaadmin
|
|||||||
|
|
||||||
#### Apache Configuration <a id="authentication-configuration-external-authentication-example-apache"></a>
|
#### Apache Configuration <a id="authentication-configuration-external-authentication-example-apache"></a>
|
||||||
|
|
||||||
Add the following configuration to the `<Directory>` directive in the `icingaweb2.conf` web server
|
Add the following configuration to the `<Directory>` directive in the `icingaweb2.conf` web server
|
||||||
configuration file.
|
configuration file.
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@ -157,7 +157,6 @@ Here is a list of all Icinga Web components that are capable of strict CSP.
|
|||||||
| Icinga Web GenericTTS Integration | [v2.1.0](https://github.com/Icinga/icingaweb2-module-generictts/releases/tag/v2.1.0) |
|
| Icinga Web GenericTTS Integration | [v2.1.0](https://github.com/Icinga/icingaweb2-module-generictts/releases/tag/v2.1.0) |
|
||||||
| Icinga Web Nagvis Integration | [v1.2.0](https://github.com/Icinga/icingaweb2-module-nagvis/releases/tag/v1.2.0) |
|
| Icinga Web Nagvis Integration | [v1.2.0](https://github.com/Icinga/icingaweb2-module-nagvis/releases/tag/v1.2.0) |
|
||||||
| Icinga Web AWS Integration | [v1.1.0](https://github.com/Icinga/icingaweb2-module-aws/releases/tag/v1.1.0) |
|
| Icinga Web AWS Integration | [v1.1.0](https://github.com/Icinga/icingaweb2-module-aws/releases/tag/v1.1.0) |
|
||||||
| Icinga Web vSphere Integration | [v1.8.0](https://github.com/Icinga/icingaweb2-module-vspheredb/releases/tag/v1.8.0) |
|
|
||||||
|
|
||||||
|
|
||||||
## Advanced Authentication Tips <a id="advanced-topics-authentication-tips"></a>
|
## Advanced Authentication Tips <a id="advanced-topics-authentication-tips"></a>
|
||||||
|
|||||||
@ -3,16 +3,6 @@
|
|||||||
Specific version upgrades are described below. Please note that upgrades are incremental. An upgrade from
|
Specific version upgrades are described below. Please note that upgrades are incremental. An upgrade from
|
||||||
v2.6 to v2.8 requires to follow the instructions for v2.7 too.
|
v2.6 to v2.8 requires to follow the instructions for v2.7 too.
|
||||||
|
|
||||||
## Upgrading to Icinga Web 2.13
|
|
||||||
|
|
||||||
**Breaking changes**
|
|
||||||
|
|
||||||
* The following columns of the `Servicestatus` table, which previously displayed the date time (string) as a fetched value, now display the unix timestamp to support relative time filters:
|
|
||||||
* `service_last_time_ok`
|
|
||||||
* `service_last_time_unknown`
|
|
||||||
* `service_last_time_warning`
|
|
||||||
* `service_last_time_critical`
|
|
||||||
|
|
||||||
## Upgrading to Icinga Web 2.12.2
|
## Upgrading to Icinga Web 2.12.2
|
||||||
|
|
||||||
**Framework changes affecting third-party code**
|
**Framework changes affecting third-party code**
|
||||||
|
|||||||
@ -58,8 +58,8 @@ Disabled by default.
|
|||||||
If you experience any problems while running SELinux in enforcing mode try to reproduce it in permissive mode. If the
|
If you experience any problems while running SELinux in enforcing mode try to reproduce it in permissive mode. If the
|
||||||
problem persists, it is not related to SELinux because in permissive mode SELinux will not deny anything.
|
problem persists, it is not related to SELinux because in permissive mode SELinux will not deny anything.
|
||||||
|
|
||||||
When filing a bug report please add the following information additionally to the common ones:
|
When filing a bug report please add the following information additionally to the
|
||||||
|
[common ones](https://icinga.com/icinga/faq/):
|
||||||
* Output of `semodule -l | grep -e icinga2 -e icingaweb2 -e nagios -e apache`
|
* Output of `semodule -l | grep -e icinga2 -e icingaweb2 -e nagios -e apache`
|
||||||
* Output of `semanage boolean -l | grep icinga`
|
* Output of `semanage boolean -l | grep icinga`
|
||||||
* Output of `ps -eZ | grep httpd`
|
* Output of `ps -eZ | grep httpd`
|
||||||
|
|||||||
@ -41,7 +41,7 @@
|
|||||||
<exclude-pattern>*/application/views/helpers/*</exclude-pattern>
|
<exclude-pattern>*/application/views/helpers/*</exclude-pattern>
|
||||||
<exclude-pattern>*/library/Icinga/Web/Paginator/ScrollingStyle/SlidingWithBorder.php</exclude-pattern>
|
<exclude-pattern>*/library/Icinga/Web/Paginator/ScrollingStyle/SlidingWithBorder.php</exclude-pattern>
|
||||||
</rule>
|
</rule>
|
||||||
<rule ref="Squiz.Classes.ValidClassName.NotPascalCase">
|
<rule ref="Squiz.Classes.ValidClassName.NotCamelCaps">
|
||||||
<exclude-pattern>*/application/views/helpers/*</exclude-pattern>
|
<exclude-pattern>*/application/views/helpers/*</exclude-pattern>
|
||||||
<exclude-pattern>*/library/Icinga/Web/Paginator/ScrollingStyle/SlidingWithBorder.php</exclude-pattern>
|
<exclude-pattern>*/library/Icinga/Web/Paginator/ScrollingStyle/SlidingWithBorder.php</exclude-pattern>
|
||||||
</rule>
|
</rule>
|
||||||
|
|||||||
@ -568,7 +568,7 @@ abstract class ApplicationBootstrap
|
|||||||
*/
|
*/
|
||||||
protected function setupErrorHandling()
|
protected function setupErrorHandling()
|
||||||
{
|
{
|
||||||
error_reporting(getenv('ICINGAWEB_ENVIRONMENT') === 'dev' ? E_ALL : E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
|
error_reporting(E_ALL | E_STRICT);
|
||||||
ini_set('display_startup_errors', 1);
|
ini_set('display_startup_errors', 1);
|
||||||
ini_set('display_errors', 1);
|
ini_set('display_errors', 1);
|
||||||
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
|
set_error_handler(function ($errno, $errstr, $errfile, $errline) {
|
||||||
@ -579,6 +579,7 @@ abstract class ApplicationBootstrap
|
|||||||
switch ($errno) {
|
switch ($errno) {
|
||||||
case E_NOTICE:
|
case E_NOTICE:
|
||||||
case E_WARNING:
|
case E_WARNING:
|
||||||
|
case E_STRICT:
|
||||||
case E_RECOVERABLE_ERROR:
|
case E_RECOVERABLE_ERROR:
|
||||||
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
|
throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ namespace Icinga\Application;
|
|||||||
*/
|
*/
|
||||||
class Version
|
class Version
|
||||||
{
|
{
|
||||||
const VERSION = '2.12.6';
|
const VERSION = '2.12.2';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the version of this instance of Icinga Web 2
|
* Get the version of this instance of Icinga Web 2
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use Icinga\Web\Controller\StaticController;
|
|||||||
use Icinga\Web\JavaScript;
|
use Icinga\Web\JavaScript;
|
||||||
use Icinga\Web\StyleSheet;
|
use Icinga\Web\StyleSheet;
|
||||||
|
|
||||||
error_reporting(E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED);
|
error_reporting(E_ALL | E_STRICT);
|
||||||
|
|
||||||
if (isset($_SERVER['REQUEST_URI'])) {
|
if (isset($_SERVER['REQUEST_URI'])) {
|
||||||
$ruri = $_SERVER['REQUEST_URI'];
|
$ruri = $_SERVER['REQUEST_URI'];
|
||||||
@ -17,8 +17,8 @@ if (isset($_SERVER['REQUEST_URI'])) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Workaround, PHPs internal Webserver seems to mess up SCRIPT_FILENAME
|
// Workaround, PHPs internal Webserver seems to mess up SCRIPT_FILENAME
|
||||||
// as it prefixes its absolute path with DOCUMENT_ROOT
|
// as it prefixes it's absolute path with DOCUMENT_ROOT
|
||||||
if (preg_match('/^PHP.*Development Server/', $_SERVER['SERVER_SOFTWARE'])) {
|
if (preg_match('/^PHP .* Development Server/', $_SERVER['SERVER_SOFTWARE'])) {
|
||||||
$script = basename($_SERVER['SCRIPT_FILENAME']);
|
$script = basename($_SERVER['SCRIPT_FILENAME']);
|
||||||
$_SERVER['PHP_SELF'] = $_SERVER['SCRIPT_NAME'] = '/' . $script;
|
$_SERVER['PHP_SELF'] = $_SERVER['SCRIPT_NAME'] = '/' . $script;
|
||||||
$_SERVER['SCRIPT_FILENAME'] = $_SERVER['DOCUMENT_ROOT']
|
$_SERVER['SCRIPT_FILENAME'] = $_SERVER['DOCUMENT_ROOT']
|
||||||
|
|||||||
@ -6,7 +6,6 @@ namespace Icinga\Authentication;
|
|||||||
use Exception;
|
use Exception;
|
||||||
use Icinga\Application\Config;
|
use Icinga\Application\Config;
|
||||||
use Icinga\Application\Hook\AuditHook;
|
use Icinga\Application\Hook\AuditHook;
|
||||||
use Icinga\Application\Hook\AuthenticationHook;
|
|
||||||
use Icinga\Application\Icinga;
|
use Icinga\Application\Icinga;
|
||||||
use Icinga\Application\Logger;
|
use Icinga\Application\Logger;
|
||||||
use Icinga\Authentication\User\ExternalBackend;
|
use Icinga\Authentication\User\ExternalBackend;
|
||||||
@ -247,8 +246,6 @@ class Auth
|
|||||||
$user->setDomain(Config::app()->get('authentication', 'default_domain'));
|
$user->setDomain(Config::app()->get('authentication', 'default_domain'));
|
||||||
}
|
}
|
||||||
$this->setAuthenticated($user);
|
$this->setAuthenticated($user);
|
||||||
AuthenticationHook::triggerLogin($user);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,9 +42,4 @@ class RolesConfig extends IniRepository
|
|||||||
|
|
||||||
return $columns;
|
return $columns;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function initializeSearchColumns(): array
|
|
||||||
{
|
|
||||||
return ['name'];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,6 @@ use Icinga\Exception\AuthenticationException;
|
|||||||
use Icinga\Repository\DbRepository;
|
use Icinga\Repository\DbRepository;
|
||||||
use Icinga\User;
|
use Icinga\User;
|
||||||
use PDO;
|
use PDO;
|
||||||
use Zend_Db_Expr;
|
|
||||||
|
|
||||||
class DbUserBackend extends DbRepository implements UserBackendInterface, Inspectable
|
class DbUserBackend extends DbRepository implements UserBackendInterface, Inspectable
|
||||||
{
|
{
|
||||||
@ -180,28 +179,23 @@ class DbUserBackend extends DbRepository implements UserBackendInterface, Inspec
|
|||||||
{
|
{
|
||||||
if ($this->ds->getDbType() === 'pgsql') {
|
if ($this->ds->getDbType() === 'pgsql') {
|
||||||
// Since PostgreSQL version 9.0 the default value for bytea_output is 'hex' instead of 'escape'
|
// Since PostgreSQL version 9.0 the default value for bytea_output is 'hex' instead of 'escape'
|
||||||
$columns = ['password_hash' => new Zend_Db_Expr('ENCODE(password_hash, \'escape\')')];
|
$columns = array('password_hash' => 'ENCODE(password_hash, \'escape\')');
|
||||||
} else {
|
} else {
|
||||||
// password_hash is intentionally not a valid query column,
|
$columns = array('password_hash');
|
||||||
// by wrapping it in an expression it is not validated
|
|
||||||
$columns = ['password_hash' => new Zend_Db_Expr('password_hash')];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = $this
|
$nameColumn = 'name';
|
||||||
->select()
|
|
||||||
->from('user', $columns)
|
|
||||||
->where('active', true);
|
|
||||||
|
|
||||||
if ($this->ds->getDbType() === 'mysql') {
|
if ($this->ds->getDbType() === 'mysql') {
|
||||||
$username = strtolower($username);
|
$username = strtolower($username);
|
||||||
$nameColumn = new Zend_Db_Expr('BINARY LOWER(name)');
|
$nameColumn = 'BINARY LOWER(name)';
|
||||||
|
|
||||||
$query->getQuery()->where($nameColumn, $username);
|
|
||||||
} else { // pgsql
|
|
||||||
$query->where('user', $username);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$statement = $this->ds->getDbAdapter()->prepare($query->getQuery()->getSelectQuery());
|
$query = $this->ds->select()
|
||||||
|
->from($this->prependTablePrefix('user'), $columns)
|
||||||
|
->where($nameColumn, $username)
|
||||||
|
->where('active', true);
|
||||||
|
|
||||||
|
$statement = $this->ds->getDbAdapter()->prepare($query->getSelectQuery());
|
||||||
$statement->execute();
|
$statement->execute();
|
||||||
$statement->bindColumn(1, $lob, PDO::PARAM_LOB);
|
$statement->bindColumn(1, $lob, PDO::PARAM_LOB);
|
||||||
$statement->fetch(PDO::FETCH_BOUND);
|
$statement->fetch(PDO::FETCH_BOUND);
|
||||||
|
|||||||
@ -204,7 +204,7 @@ class DbUserGroupBackend extends DbRepository implements Inspectable, UserGroupB
|
|||||||
$membershipQuery = $this
|
$membershipQuery = $this
|
||||||
->select()
|
->select()
|
||||||
->from('group_membership', array('group_name'))
|
->from('group_membership', array('group_name'))
|
||||||
->where('user', $user->getUsername());
|
->where('user_name', $user->getUsername());
|
||||||
|
|
||||||
$memberships = array();
|
$memberships = array();
|
||||||
foreach ($membershipQuery as $membership) {
|
foreach ($membershipQuery as $membership) {
|
||||||
|
|||||||
@ -37,7 +37,7 @@ class Csv
|
|||||||
}
|
}
|
||||||
$out = array();
|
$out = array();
|
||||||
foreach ($row as & $val) {
|
foreach ($row as & $val) {
|
||||||
$out[] = '"' . ($val == '0' ? '0' : ($val ? str_replace('"', '""', $val) : '')) . '"';
|
$out[] = '"' . ($val ? str_replace('"', '""', $val) : '') . '"';
|
||||||
}
|
}
|
||||||
$csv .= implode(',', $out) . "\r\n";
|
$csv .= implode(',', $out) . "\r\n";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,11 +5,9 @@ namespace Icinga\File;
|
|||||||
|
|
||||||
use Dompdf\Dompdf;
|
use Dompdf\Dompdf;
|
||||||
use Dompdf\Options;
|
use Dompdf\Options;
|
||||||
use Exception;
|
|
||||||
use Icinga\Application\Icinga;
|
use Icinga\Application\Icinga;
|
||||||
use Icinga\Exception\ProgrammingError;
|
use Icinga\Exception\ProgrammingError;
|
||||||
use Icinga\Util\Environment;
|
use Icinga\Util\Environment;
|
||||||
use Icinga\Web\FileCache;
|
|
||||||
use Icinga\Web\Hook;
|
use Icinga\Web\Hook;
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
|
|
||||||
@ -66,17 +64,8 @@ class Pdf
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
$tmpDir = FileCache::instance()->directory('legacy_pdf');
|
|
||||||
if ($tmpDir === false) {
|
|
||||||
throw new Exception('Could not create temporary directory for PDF rendering');
|
|
||||||
}
|
|
||||||
|
|
||||||
$options = new Options();
|
$options = new Options();
|
||||||
$options->set('defaultPaperSize', 'A4');
|
$options->set('defaultPaperSize', 'A4');
|
||||||
$options->set('fontDir', $tmpDir);
|
|
||||||
$options->set('fontCache', $tmpDir);
|
|
||||||
$options->set('tempDir', $tmpDir);
|
|
||||||
$options->set('chroot', $tmpDir);
|
|
||||||
$dompdf = new Dompdf($options);
|
$dompdf = new Dompdf($options);
|
||||||
$dompdf->loadHtml($html);
|
$dompdf->loadHtml($html);
|
||||||
$dompdf->render();
|
$dompdf->render();
|
||||||
|
|||||||
@ -292,5 +292,22 @@ namespace Icinga\Test {
|
|||||||
$adapter->exec('DROP TABLE ' . $table . ';');
|
$adapter->exec('DROP TABLE ' . $table . ';');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add assertMatchesRegularExpression() method for phpunit >= 8.0 < 9.0 for compatibility with PHP 7.2.
|
||||||
|
*
|
||||||
|
* @TODO Remove once PHP 7.2 support is not needed for testing anymore.
|
||||||
|
*/
|
||||||
|
public static function assertMatchesRegularExpression(
|
||||||
|
string $pattern,
|
||||||
|
string $string,
|
||||||
|
string $message = ''
|
||||||
|
): void {
|
||||||
|
if (method_exists(parent::class, 'assertMatchesRegularExpression')) {
|
||||||
|
parent::assertMatchesRegularExpression($pattern, $string, $message);
|
||||||
|
} else {
|
||||||
|
static::assertRegExp($pattern, $string, $message);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,8 +3,6 @@
|
|||||||
|
|
||||||
namespace Icinga\Util;
|
namespace Icinga\Util;
|
||||||
|
|
||||||
use DateTimeZone;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve timezone information from cookie
|
* Retrieve timezone information from cookie
|
||||||
*/
|
*/
|
||||||
@ -17,6 +15,13 @@ class TimezoneDetect
|
|||||||
*/
|
*/
|
||||||
private static $success;
|
private static $success;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timezone offset in minutes
|
||||||
|
*
|
||||||
|
* @var int
|
||||||
|
*/
|
||||||
|
private static $offset = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
@ -29,6 +34,13 @@ class TimezoneDetect
|
|||||||
*/
|
*/
|
||||||
public static $cookieName = 'icingaweb2-tzo';
|
public static $cookieName = 'icingaweb2-tzo';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timezone name
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
private static $timezone;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new object and try to identify the timezone
|
* Create new object and try to identify the timezone
|
||||||
*/
|
*/
|
||||||
@ -38,13 +50,30 @@ class TimezoneDetect
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (in_array($_COOKIE[self::$cookieName] ?? null, DateTimeZone::listIdentifiers(), true)) {
|
if (array_key_exists(self::$cookieName, $_COOKIE)) {
|
||||||
self::$timezoneName = $_COOKIE[self::$cookieName];
|
$matches = array();
|
||||||
self::$success = true;
|
if (preg_match('/\A(-?\d+)[\-,](\d+)\z/', $_COOKIE[self::$cookieName], $matches)) {
|
||||||
} else {
|
$offset = $matches[1];
|
||||||
self::$success = false;
|
$timezoneName = timezone_name_from_abbr('', (int) $offset, (int) $matches[2]);
|
||||||
|
|
||||||
|
self::$success = (bool) $timezoneName;
|
||||||
|
if (self::$success) {
|
||||||
|
self::$offset = $offset;
|
||||||
|
self::$timezoneName = $timezoneName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get offset
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getOffset()
|
||||||
|
{
|
||||||
|
return self::$offset;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get timezone name
|
* Get timezone name
|
||||||
@ -73,5 +102,6 @@ class TimezoneDetect
|
|||||||
{
|
{
|
||||||
self::$success = null;
|
self::$success = null;
|
||||||
self::$timezoneName = null;
|
self::$timezoneName = null;
|
||||||
|
self::$offset = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -352,7 +352,7 @@ class Form extends Zend_Form
|
|||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*
|
*
|
||||||
* @throws ProgrammingError In case $url is neither a string nor an instance of Icinga\Web\Url
|
* @throws ProgrammingError In case $url is neither a string nor a instance of Icinga\Web\Url
|
||||||
*/
|
*/
|
||||||
public function setRedirectUrl($url)
|
public function setRedirectUrl($url)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -6,7 +6,6 @@ namespace Icinga\Web;
|
|||||||
use Icinga\Application\Logger;
|
use Icinga\Application\Logger;
|
||||||
use Icinga\Authentication\Auth;
|
use Icinga\Authentication\Auth;
|
||||||
use Icinga\Web\Navigation\Navigation;
|
use Icinga\Web\Navigation\Navigation;
|
||||||
use Icinga\Web\Navigation\Renderer\RecursiveMenuNavigationRenderer;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main menu for Icinga Web 2
|
* Main menu for Icinga Web 2
|
||||||
@ -150,14 +149,4 @@ class Menu extends Navigation
|
|||||||
]));
|
]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create and return the renderer for this navigation
|
|
||||||
*
|
|
||||||
* @return RecursiveMenuNavigationRenderer
|
|
||||||
*/
|
|
||||||
public function getRenderer()
|
|
||||||
{
|
|
||||||
return new RecursiveMenuNavigationRenderer($this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,6 @@ use Icinga\Application\Icinga;
|
|||||||
use Icinga\Exception\ProgrammingError;
|
use Icinga\Exception\ProgrammingError;
|
||||||
use Icinga\Util\StringHelper;
|
use Icinga\Util\StringHelper;
|
||||||
use Icinga\Web\Navigation\NavigationItem;
|
use Icinga\Web\Navigation\NavigationItem;
|
||||||
use Icinga\Web\Session;
|
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
use Icinga\Web\View;
|
use Icinga\Web\View;
|
||||||
|
|
||||||
@ -191,10 +190,6 @@ class NavigationItemRenderer
|
|||||||
|
|
||||||
$target = $item->getTarget();
|
$target = $item->getTarget();
|
||||||
if ($url->isExternal() && (!$target || in_array($target, $this->internalLinkTargets, true))) {
|
if ($url->isExternal() && (!$target || in_array($target, $this->internalLinkTargets, true))) {
|
||||||
$item->setAttribute('data-url-hash', hash(
|
|
||||||
'sha256',
|
|
||||||
$url->getAbsoluteUrl() . Session::getSession()->getId()
|
|
||||||
));
|
|
||||||
$url = Url::fromPath('iframe', array('url' => $url));
|
$url = Url::fromPath('iframe', array('url' => $url));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,30 +0,0 @@
|
|||||||
<?php
|
|
||||||
/* Icinga Web 2 | (c) 2025 Icinga GmbH | GPLv2+ */
|
|
||||||
|
|
||||||
namespace Icinga\Web\Navigation\Renderer;
|
|
||||||
|
|
||||||
use Icinga\Web\Navigation\NavigationItem;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Renderer for the multi level navigation in the sidebar menu
|
|
||||||
*/
|
|
||||||
class RecursiveMenuNavigationRenderer extends RecursiveNavigationRenderer
|
|
||||||
{
|
|
||||||
public function beginChildren(): void
|
|
||||||
{
|
|
||||||
parent::beginChildren();
|
|
||||||
|
|
||||||
$parentItem = $this->getInnerIterator()->current()->getParent();
|
|
||||||
$item = new NavigationItem($parentItem->getName());
|
|
||||||
$item->setLabel($parentItem->getLabel());
|
|
||||||
$item->setCssClass('nav-item-header');
|
|
||||||
|
|
||||||
$renderer = new NavigationItemRenderer();
|
|
||||||
$renderer->setEscapeLabel(false);
|
|
||||||
$content = $renderer->render($item);
|
|
||||||
|
|
||||||
$this->content[] = $this->getInnerIterator()->beginItemMarkup($item);
|
|
||||||
$this->content[] = $content;
|
|
||||||
$this->content[] = $this->getInnerIterator()->endItemMarkup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -4,10 +4,11 @@
|
|||||||
namespace Icinga\Web\Navigation\Renderer;
|
namespace Icinga\Web\Navigation\Renderer;
|
||||||
|
|
||||||
use Exception;
|
use Exception;
|
||||||
|
use RecursiveIteratorIterator;
|
||||||
use Icinga\Exception\IcingaException;
|
use Icinga\Exception\IcingaException;
|
||||||
use Icinga\Web\Navigation\Navigation;
|
use Icinga\Web\Navigation\Navigation;
|
||||||
use Icinga\Web\Navigation\NavigationItem;
|
use Icinga\Web\Navigation\NavigationItem;
|
||||||
use RecursiveIteratorIterator;
|
use Icinga\Web\Navigation\Renderer\NavigationItemRenderer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renderer for multi level navigation
|
* Renderer for multi level navigation
|
||||||
|
|||||||
@ -139,7 +139,6 @@ class StyleSheet
|
|||||||
$this->lessCompiler->addLessFile($this->pubPath . '/' . $lessFile);
|
$this->lessCompiler->addLessFile($this->pubPath . '/' . $lessFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
$auth = Auth::getInstance();
|
|
||||||
$mm = $this->app->getModuleManager();
|
$mm = $this->app->getModuleManager();
|
||||||
|
|
||||||
foreach ($mm->getLoadedModules() as $moduleName => $module) {
|
foreach ($mm->getLoadedModules() as $moduleName => $module) {
|
||||||
@ -158,6 +157,7 @@ class StyleSheet
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (! (bool) $themingConfig->get('disabled', false)) {
|
if (! (bool) $themingConfig->get('disabled', false)) {
|
||||||
|
$auth = Auth::getInstance();
|
||||||
if ($auth->isAuthenticated()) {
|
if ($auth->isAuthenticated()) {
|
||||||
$userTheme = $auth->getUser()->getPreferences()->getValue('icingaweb', 'theme');
|
$userTheme = $auth->getUser()->getPreferences()->getValue('icingaweb', 'theme');
|
||||||
if ($userTheme !== null) {
|
if ($userTheme !== null) {
|
||||||
@ -174,7 +174,7 @@ class StyleSheet
|
|||||||
Logger::warning(sprintf(
|
Logger::warning(sprintf(
|
||||||
'Theme "%s" set by user "%s" has not been found.',
|
'Theme "%s" set by user "%s" has not been found.',
|
||||||
$theme,
|
$theme,
|
||||||
$auth->isAuthenticated() ? $auth->getUser()->getUsername() : 'anonymous'
|
($user = Auth::getInstance()->getUser()) !== null ? $user->getUsername() : 'anonymous'
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -184,10 +184,10 @@ class StyleSheet
|
|||||||
}
|
}
|
||||||
|
|
||||||
$mode = 'none';
|
$mode = 'none';
|
||||||
if ($auth->isAuthenticated()) {
|
if ($user = Auth::getInstance()->getUser()) {
|
||||||
$file = $themePath !== null ? @file_get_contents($themePath) : false;
|
$file = $themePath !== null ? @file_get_contents($themePath) : false;
|
||||||
if (! $file || strpos($file, self::LIGHT_MODE_IDENTIFIER) !== false) {
|
if (! $file || strpos($file, self::LIGHT_MODE_IDENTIFIER) !== false) {
|
||||||
$mode = $auth->getUser()->getPreferences()->getValue('icingaweb', 'theme_mode', self::DEFAULT_MODE);
|
$mode = $user->getPreferences()->getValue('icingaweb', 'theme_mode', self::DEFAULT_MODE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -179,9 +179,10 @@ class Url
|
|||||||
}
|
}
|
||||||
|
|
||||||
$urlParts = parse_url($url);
|
$urlParts = parse_url($url);
|
||||||
if ((isset($urlParts['scheme']) && $urlParts['scheme'] !== $request->getScheme())
|
if (isset($urlParts['scheme']) && (
|
||||||
|
$urlParts['scheme'] !== $request->getScheme()
|
||||||
|| (isset($urlParts['host']) && $urlParts['host'] !== $request->getServer('SERVER_NAME'))
|
|| (isset($urlParts['host']) && $urlParts['host'] !== $request->getServer('SERVER_NAME'))
|
||||||
|| (isset($urlParts['port']) && $urlParts['port'] != $request->getServer('SERVER_PORT'))
|
|| (isset($urlParts['port']) && $urlParts['port'] != $request->getServer('SERVER_PORT')))
|
||||||
) {
|
) {
|
||||||
$urlObject->setIsExternal();
|
$urlObject->setIsExternal();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -205,8 +205,7 @@ class View extends Zend_View_Abstract
|
|||||||
'th-thumb-empty' => true,
|
'th-thumb-empty' => true,
|
||||||
'github-circled' => true,
|
'github-circled' => true,
|
||||||
'history' => true,
|
'history' => true,
|
||||||
'binoculars' => true,
|
'binoculars' => true
|
||||||
'letter' => true
|
|
||||||
//</editor-fold>
|
//</editor-fold>
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -3,9 +3,9 @@
|
|||||||
|
|
||||||
namespace Icinga\Web\Widget\Dashboard;
|
namespace Icinga\Web\Widget\Dashboard;
|
||||||
|
|
||||||
use Icinga\Web\Session;
|
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
use Icinga\Data\ConfigObject;
|
use Icinga\Data\ConfigObject;
|
||||||
|
use Icinga\Exception\IcingaException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dashboard pane dashlet
|
* A dashboard pane dashlet
|
||||||
@ -57,15 +57,18 @@ class Dashlet extends UserWidget
|
|||||||
*/
|
*/
|
||||||
private $template =<<<'EOD'
|
private $template =<<<'EOD'
|
||||||
|
|
||||||
<div class="container" data-icinga-url="{URL}" data-url-hash="{URL_HASH}">
|
<div class="container" data-icinga-url="{URL}">
|
||||||
<h1><a
|
<h1><a href="{FULL_URL}" aria-label="{TOOLTIP}" title="{TOOLTIP}" data-base-target="col1">{TITLE}</a></h1>
|
||||||
href="{FULL_URL}"
|
|
||||||
aria-label="{TOOLTIP}"
|
|
||||||
title="{TOOLTIP}"
|
|
||||||
data-url-hash="{FULL_URL_HASH}"
|
|
||||||
data-base-target="col1"
|
|
||||||
>{TITLE}</a></h1>
|
|
||||||
<p class="progress-label">{PROGRESS_LABEL}<span>.</span><span>.</span><span>.</span></p>
|
<p class="progress-label">{PROGRESS_LABEL}<span>.</span><span>.</span><span>.</span></p>
|
||||||
|
<noscript>
|
||||||
|
<div class="iframe-container">
|
||||||
|
<iframe
|
||||||
|
src="{IFRAME_URL}"
|
||||||
|
frameborder="no"
|
||||||
|
title="{TITLE_PREFIX}{TITLE}">
|
||||||
|
</iframe>
|
||||||
|
</div>
|
||||||
|
</noscript>
|
||||||
</div>
|
</div>
|
||||||
EOD;
|
EOD;
|
||||||
|
|
||||||
@ -247,22 +250,13 @@ EOD;
|
|||||||
|
|
||||||
$url = $this->getUrl();
|
$url = $this->getUrl();
|
||||||
$url->setParam('showCompact', true);
|
$url->setParam('showCompact', true);
|
||||||
$fullUrl = $url->getUrlWithout(['showCompact', 'limit', 'view']);
|
$iframeUrl = clone $url;
|
||||||
|
$iframeUrl->setParam('isIframe');
|
||||||
$urlHash = '';
|
|
||||||
$fullUrlHash = '';
|
|
||||||
if ($url->getPath() === 'iframe') {
|
|
||||||
$urlHash = hash('sha256', Url::fromPath($url->getParam('url'))->getAbsoluteUrl()
|
|
||||||
. Session::getSession()->getId());
|
|
||||||
$fullUrlHash = hash('sha256', Url::fromPath($fullUrl->getParam('url'))->getAbsoluteUrl()
|
|
||||||
. Session::getSession()->getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
$searchTokens = array(
|
$searchTokens = array(
|
||||||
'{URL}',
|
'{URL}',
|
||||||
'{URL_HASH}',
|
'{IFRAME_URL}',
|
||||||
'{FULL_URL}',
|
'{FULL_URL}',
|
||||||
'{FULL_URL_HASH}',
|
|
||||||
'{TOOLTIP}',
|
'{TOOLTIP}',
|
||||||
'{TITLE}',
|
'{TITLE}',
|
||||||
'{TITLE_PREFIX}',
|
'{TITLE_PREFIX}',
|
||||||
@ -271,9 +265,8 @@ EOD;
|
|||||||
|
|
||||||
$replaceTokens = array(
|
$replaceTokens = array(
|
||||||
$url,
|
$url,
|
||||||
$urlHash,
|
$iframeUrl,
|
||||||
$fullUrl,
|
$url->getUrlWithout(['showCompact', 'limit', 'view']),
|
||||||
$fullUrlHash,
|
|
||||||
sprintf($view->translate('Show %s', 'dashboard.dashlet.tooltip'), $view->escape($this->getTitle())),
|
sprintf($view->translate('Show %s', 'dashboard.dashlet.tooltip'), $view->escape($this->getTitle())),
|
||||||
$view->escape($this->getTitle()),
|
$view->escape($this->getTitle()),
|
||||||
$view->translate('Dashlet') . ': ',
|
$view->translate('Dashlet') . ': ',
|
||||||
|
|||||||
@ -3,17 +3,17 @@
|
|||||||
|
|
||||||
namespace Icinga\Web\Widget;
|
namespace Icinga\Web\Widget;
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use Icinga\Application\Icinga;
|
|
||||||
use Icinga\Data\Filter\Filter;
|
|
||||||
use Icinga\Data\Filter\FilterChain;
|
|
||||||
use Icinga\Data\Filter\FilterExpression;
|
|
||||||
use Icinga\Data\Filter\FilterOr;
|
|
||||||
use Icinga\Data\Filterable;
|
use Icinga\Data\Filterable;
|
||||||
use Icinga\Data\FilterColumns;
|
use Icinga\Data\FilterColumns;
|
||||||
|
use Icinga\Data\Filter\Filter;
|
||||||
|
use Icinga\Data\Filter\FilterExpression;
|
||||||
|
use Icinga\Data\Filter\FilterChain;
|
||||||
|
use Icinga\Data\Filter\FilterOr;
|
||||||
|
use Icinga\Web\Url;
|
||||||
|
use Icinga\Application\Icinga;
|
||||||
use Icinga\Exception\ProgrammingError;
|
use Icinga\Exception\ProgrammingError;
|
||||||
use Icinga\Web\Notification;
|
use Icinga\Web\Notification;
|
||||||
use Icinga\Web\Url;
|
use Exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter
|
* Filter
|
||||||
@ -738,8 +738,7 @@ class FilterEditor extends AbstractWidget
|
|||||||
|
|
||||||
$html = ' <form method="post" class="search inline" action="'
|
$html = ' <form method="post" class="search inline" action="'
|
||||||
. $preservedUrl
|
. $preservedUrl
|
||||||
. '"><i class="icon fa-search fa search-icon"></i>'
|
. '"><input type="text" name="q" class="search search-input" value="" placeholder="'
|
||||||
. '<input type="text" name="q" class="search search-input" value="" placeholder="'
|
|
||||||
. t('Search...')
|
. t('Search...')
|
||||||
. '" /></form>';
|
. '" /></form>';
|
||||||
|
|
||||||
|
|||||||
@ -10,7 +10,6 @@ use ipl\Html\FormElement\InputElement;
|
|||||||
use ipl\Html\HtmlElement;
|
use ipl\Html\HtmlElement;
|
||||||
use ipl\Web\Control\SearchBar\Suggestions;
|
use ipl\Web\Control\SearchBar\Suggestions;
|
||||||
use ipl\Web\Url;
|
use ipl\Web\Url;
|
||||||
use ipl\Web\Widget\Icon;
|
|
||||||
|
|
||||||
class SingleValueSearchControl extends Form
|
class SingleValueSearchControl extends Form
|
||||||
{
|
{
|
||||||
@ -107,8 +106,6 @@ class SingleValueSearchControl extends Form
|
|||||||
{
|
{
|
||||||
$suggestionsId = Icinga::app()->getRequest()->protectId('single-value-suggestions');
|
$suggestionsId = Icinga::app()->getRequest()->protectId('single-value-suggestions');
|
||||||
|
|
||||||
$this->addHtml(new Icon('search', Attributes::create(['class' => 'search-icon'])));
|
|
||||||
|
|
||||||
$this->addElement(
|
$this->addElement(
|
||||||
'text',
|
'text',
|
||||||
$this->searchParameter,
|
$this->searchParameter,
|
||||||
|
|||||||
@ -112,7 +112,7 @@ class Window
|
|||||||
{
|
{
|
||||||
if (! isset(static::$window)) {
|
if (! isset(static::$window)) {
|
||||||
$id = Icinga::app()->getRequest()->getHeader('X-Icinga-WindowId');
|
$id = Icinga::app()->getRequest()->getHeader('X-Icinga-WindowId');
|
||||||
if (empty($id) || $id === static::UNDEFINED || ! preg_match('/^\w+$/', $id)) {
|
if (empty($id) || $id === static::UNDEFINED) {
|
||||||
Icinga::app()->getResponse()->setOverrideWindowId();
|
Icinga::app()->getResponse()->setOverrideWindowId();
|
||||||
$id = static::generateId();
|
$id = static::generateId();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
Module: doc
|
Module: doc
|
||||||
Version: 2.12.6
|
Version: 2.12.2
|
||||||
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.
|
||||||
|
|||||||
@ -1,5 +1,17 @@
|
|||||||
/*! Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
/*! Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
// Mixins
|
||||||
|
|
||||||
|
.gradient(@a: @gray-lighter; @b: @gray-lightest) {
|
||||||
|
background: @a;
|
||||||
|
background: -webkit-gradient(linear, left top, left bottom, from(@a), to(@b));
|
||||||
|
background: -webkit-linear-gradient(top, @a, @b);
|
||||||
|
background: -moz-linear-gradient(top, @a, @b);
|
||||||
|
background: -ms-linear-gradient(top, @a, @b);
|
||||||
|
background: -o-linear-gradient(top, @a, @b);
|
||||||
|
background: linear-gradient(to bottom, @a, @b);
|
||||||
|
}
|
||||||
|
|
||||||
// General styles
|
// General styles
|
||||||
|
|
||||||
code {
|
code {
|
||||||
@ -72,7 +84,7 @@ table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tbody > tr:nth-child(odd) {
|
tbody > tr:nth-child(odd) {
|
||||||
background: @gray-light;
|
.gradient()
|
||||||
}
|
}
|
||||||
|
|
||||||
tbody > tr:nth-child(even) {
|
tbody > tr:nth-child(even) {
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
Module: migrate
|
Module: migrate
|
||||||
Version: 2.12.6
|
Version: 2.12.2
|
||||||
Description: Migrate module
|
Description: Migrate module
|
||||||
This module was introduced with the domain-aware authentication feature in version 2.5.0.
|
This module was introduced with the domain-aware authentication feature in version 2.5.0.
|
||||||
It helps you migrating users and user configurations according to a given domain.
|
It helps you migrating users and user configurations according to a given domain.
|
||||||
|
|||||||
400
modules/monitoring/application/clicommands/ListCommand.php
Normal file
400
modules/monitoring/application/clicommands/ListCommand.php
Normal file
@ -0,0 +1,400 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2013 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Clicommands;
|
||||||
|
|
||||||
|
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||||
|
use Icinga\Module\Monitoring\Cli\CliUtils;
|
||||||
|
use Icinga\Date\DateFormatter;
|
||||||
|
use Icinga\Cli\Command;
|
||||||
|
use Icinga\File\Csv;
|
||||||
|
use Icinga\Module\Monitoring\Plugin\PerfdataSet;
|
||||||
|
use Exception;
|
||||||
|
use Icinga\Util\Json;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Icinga monitoring objects
|
||||||
|
*
|
||||||
|
* This module is your interface to the Icinga monitoring application.
|
||||||
|
*/
|
||||||
|
class ListCommand extends Command
|
||||||
|
{
|
||||||
|
protected $backend;
|
||||||
|
protected $dumpSql;
|
||||||
|
protected $defaultActionName = 'status';
|
||||||
|
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->backend = MonitoringBackend::instance($this->params->shift('backend'));
|
||||||
|
$this->dumpSql = $this->params->shift('showsql');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getQuery($table, $columns)
|
||||||
|
{
|
||||||
|
$limit = $this->params->shift('limit');
|
||||||
|
$format = $this->params->shift('format');
|
||||||
|
if ($format !== null) {
|
||||||
|
if ($this->params->has('columns')) {
|
||||||
|
$columnParams = preg_split(
|
||||||
|
'/,/',
|
||||||
|
$this->params->shift('columns')
|
||||||
|
);
|
||||||
|
$columns = array();
|
||||||
|
foreach ($columnParams as $col) {
|
||||||
|
if (false !== ($pos = strpos($col, '='))) {
|
||||||
|
$columns[substr($col, 0, $pos)] = substr($col, $pos + 1);
|
||||||
|
} else {
|
||||||
|
$columns[] = $col;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->backend->select()->from($table, $columns);
|
||||||
|
if ($limit) {
|
||||||
|
$query->limit($limit, $this->params->shift('offset'));
|
||||||
|
}
|
||||||
|
foreach ($this->params->getParams() as $col => $filter) {
|
||||||
|
$query->where($col, $filter);
|
||||||
|
}
|
||||||
|
// $query->applyFilters($this->params->getParams());
|
||||||
|
if ($this->dumpSql) {
|
||||||
|
echo wordwrap($query->dump(), 72);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($format !== null) {
|
||||||
|
$this->showFormatted($query, $format, $columns);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function showFormatted($query, $format, $columns)
|
||||||
|
{
|
||||||
|
$query = $query->getQuery();
|
||||||
|
switch ($format) {
|
||||||
|
case 'json':
|
||||||
|
echo Json::sanitize($query->fetchAll());
|
||||||
|
break;
|
||||||
|
case 'csv':
|
||||||
|
Csv::fromQuery($query)->dump();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
preg_match_all('~\$([a-z0-9_-]+)\$~', $format, $m);
|
||||||
|
$words = array();
|
||||||
|
foreach ($columns as $key => $col) {
|
||||||
|
if (is_numeric($key)) {
|
||||||
|
if (in_array($col, $m[1])) {
|
||||||
|
$words[] = $col;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (in_array($key, $m[1])) {
|
||||||
|
$words[] = $key;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ($query->fetchAll() as $row) {
|
||||||
|
$output = $format;
|
||||||
|
foreach ($words as $word) {
|
||||||
|
$output = preg_replace(
|
||||||
|
'~\$' . $word . '\$~',
|
||||||
|
$row->{$word},
|
||||||
|
$output
|
||||||
|
);
|
||||||
|
}
|
||||||
|
echo $output . "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List and filter hosts
|
||||||
|
*
|
||||||
|
* This command allows you to search and visualize your hosts in
|
||||||
|
* different ways.
|
||||||
|
*
|
||||||
|
* USAGE
|
||||||
|
*
|
||||||
|
* icingacli monitoring list hosts [options]
|
||||||
|
*
|
||||||
|
* OPTIONS
|
||||||
|
*
|
||||||
|
* --verbose Show detailled output
|
||||||
|
* --showsql Dump generated SQL query (DB backend only)
|
||||||
|
*
|
||||||
|
* --format=<csv|json|<custom>>
|
||||||
|
* Dump columns in the given format. <custom> format allows $column$
|
||||||
|
* placeholders, e.g. --format='$host$: $service$'. This requires
|
||||||
|
* that the columns are specified within the --columns parameter.
|
||||||
|
*
|
||||||
|
* --<column>[=filter]
|
||||||
|
* Filter given column by optional filter. Boolean (1/0) columns are
|
||||||
|
* true if no filter value is given.
|
||||||
|
*
|
||||||
|
* --problems
|
||||||
|
* Only show unhandled problems (HARD state and not acknowledged/in downtime).
|
||||||
|
*
|
||||||
|
* --columns='<comma separated list of host/service columns>'
|
||||||
|
* Add a limited set of columns to the output. The following host
|
||||||
|
* attributes can be fetched: state, handled, output, acknowledged, in_downtime, perfdata last_state_change
|
||||||
|
*
|
||||||
|
* EXAMPLES
|
||||||
|
*
|
||||||
|
* icingacli monitoring list hosts --problems
|
||||||
|
* icingacli monitoring list hosts --problems --host_state_type 0
|
||||||
|
* icingacli monitoring list hosts --host=local*
|
||||||
|
* icingacli monitoring list hosts --columns 'host,host_output' \
|
||||||
|
* --format='$host$ ($host_output$)'
|
||||||
|
*/
|
||||||
|
public function hostsAction()
|
||||||
|
{
|
||||||
|
$columns = array(
|
||||||
|
'host_name',
|
||||||
|
'host_state',
|
||||||
|
'host_output',
|
||||||
|
'host_handled',
|
||||||
|
'host_acknowledged',
|
||||||
|
'host_in_downtime'
|
||||||
|
);
|
||||||
|
$query = $this->getQuery('hoststatus', $columns)
|
||||||
|
->order('host_name');
|
||||||
|
echo $this->renderStatusQuery($query);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List and filter services
|
||||||
|
*
|
||||||
|
* This command allows you to search and visualize your services in
|
||||||
|
* different ways.
|
||||||
|
*
|
||||||
|
* USAGE
|
||||||
|
*
|
||||||
|
* icingacli monitoring list services [options]
|
||||||
|
*
|
||||||
|
* OPTIONS
|
||||||
|
*
|
||||||
|
* --verbose Show detailled output
|
||||||
|
* --showsql Dump generated SQL query (DB backend only)
|
||||||
|
*
|
||||||
|
* --format=<csv|json|<custom>>
|
||||||
|
* Dump columns in the given format. <custom> format allows $column$
|
||||||
|
* placeholders, e.g. --format='$host$: $service$'. This requires
|
||||||
|
* that the columns are specified within the --columns parameter.
|
||||||
|
*
|
||||||
|
* --<column>[=filter]
|
||||||
|
* Filter given column by optional filter. Boolean (1/0) columns are
|
||||||
|
* true if no filter value is given.
|
||||||
|
*
|
||||||
|
* --problems
|
||||||
|
* Only show unhandled problems (HARD state and not acknowledged/in downtime).
|
||||||
|
*
|
||||||
|
* --columns='<comma separated list of host/service columns>'
|
||||||
|
* Add a limited set of columns to the output. The following service
|
||||||
|
* attributes can be fetched: state, handled, output, acknowledged, in_downtime, perfdata last_state_change
|
||||||
|
*
|
||||||
|
* EXAMPLES
|
||||||
|
*
|
||||||
|
* icingacli monitoring list services --problems
|
||||||
|
* icingacli monitoring list services --problems --service_state_type 0
|
||||||
|
* icingacli monitoring list services --host=local* --service=*disk*
|
||||||
|
* icingacli monitoring list services --columns 'host,service,service_output' \
|
||||||
|
* --format='$host$: $service$ ($service_output$)'
|
||||||
|
*/
|
||||||
|
public function servicesAction()
|
||||||
|
{
|
||||||
|
$columns = array(
|
||||||
|
'host_name',
|
||||||
|
'host_state',
|
||||||
|
'host_output',
|
||||||
|
'host_handled',
|
||||||
|
'host_acknowledged',
|
||||||
|
'host_in_downtime',
|
||||||
|
'service_description',
|
||||||
|
'service_state',
|
||||||
|
'service_acknowledged',
|
||||||
|
'service_in_downtime',
|
||||||
|
'service_handled',
|
||||||
|
'service_output',
|
||||||
|
'service_perfdata',
|
||||||
|
'service_last_state_change'
|
||||||
|
);
|
||||||
|
$query = $this->getQuery('servicestatus', $columns)
|
||||||
|
->order('host_name');
|
||||||
|
echo $this->renderStatusQuery($query);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function renderStatusQuery($query)
|
||||||
|
{
|
||||||
|
$out = '';
|
||||||
|
$last_host = null;
|
||||||
|
$screen = $this->screen;
|
||||||
|
$utils = new CliUtils($screen);
|
||||||
|
$maxCols = $screen->getColumns();
|
||||||
|
$query = $query->getQuery();
|
||||||
|
$rows = $query->fetchAll();
|
||||||
|
$count = $query->count();
|
||||||
|
$count = count($rows);
|
||||||
|
|
||||||
|
for ($i = 0; $i < $count; $i++) {
|
||||||
|
$row = & $rows[$i];
|
||||||
|
|
||||||
|
$utils->setHostState($row->host_state);
|
||||||
|
if (! array_key_exists($i + 1, $rows)
|
||||||
|
|| $row->host_name !== $rows[$i + 1]->host_name
|
||||||
|
) {
|
||||||
|
$lastService = true;
|
||||||
|
} else {
|
||||||
|
$lastService = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hostUnhandled = ! ($row->host_state == 0 || $row->host_handled);
|
||||||
|
|
||||||
|
if ($row->host_name !== $last_host) {
|
||||||
|
if (isset($row->service_description)) {
|
||||||
|
$out .= "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$hostTxt = $utils->shortHostState();
|
||||||
|
if ($hostUnhandled) {
|
||||||
|
$out .= $utils->hostStateBackground(
|
||||||
|
sprintf(' %s ', $utils->shortHostState())
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$out .= sprintf(
|
||||||
|
'%s %s ',
|
||||||
|
$utils->hostStateBackground(' '),
|
||||||
|
$utils->shortHostState()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$out .= sprintf(
|
||||||
|
" %s%s: %s\n",
|
||||||
|
$screen->underline($row->host_name),
|
||||||
|
$screen->colorize($utils->objectStateFlags('host', $row), 'lightblue'),
|
||||||
|
$row->host_output
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isset($row->services_ok)) {
|
||||||
|
$out .= sprintf(
|
||||||
|
"%d services, %d problems (%d unhandled), %d OK\n",
|
||||||
|
$row->services_cnt,
|
||||||
|
$row->services_problem,
|
||||||
|
$row->services_problem_unhandled,
|
||||||
|
$row->services_ok
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$last_host = $row->host_name;
|
||||||
|
if (! isset($row->service_description)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$utils->setServiceState($row->service_state);
|
||||||
|
$serviceUnhandled = ! (
|
||||||
|
$row->service_state == 0 || $row->service_handled
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($lastService) {
|
||||||
|
$straight = ' ';
|
||||||
|
$leaf = '└';
|
||||||
|
} else {
|
||||||
|
$straight = '│';
|
||||||
|
$leaf = '├';
|
||||||
|
}
|
||||||
|
$out .= $utils->hostStateBackground(' ');
|
||||||
|
|
||||||
|
if ($serviceUnhandled) {
|
||||||
|
$out .= $utils->serviceStateBackground(
|
||||||
|
sprintf(' %s ', $utils->shortServiceState())
|
||||||
|
);
|
||||||
|
$emptyBg = ' ';
|
||||||
|
$emptySpace = '';
|
||||||
|
} else {
|
||||||
|
$out .= sprintf(
|
||||||
|
'%s %s ',
|
||||||
|
$utils->serviceStateBackground(' '),
|
||||||
|
$utils->shortServiceState()
|
||||||
|
);
|
||||||
|
$emptyBg = ' ';
|
||||||
|
$emptySpace = ' ';
|
||||||
|
}
|
||||||
|
|
||||||
|
$emptyLine = "\n"
|
||||||
|
. $utils->hostStateBackground(' ')
|
||||||
|
. $utils->serviceStateBackground($emptyBg)
|
||||||
|
. $emptySpace
|
||||||
|
. ' ' . $straight . ' ';
|
||||||
|
|
||||||
|
$perf = '';
|
||||||
|
try {
|
||||||
|
$pset = PerfdataSet::fromString($row->service_perfdata);
|
||||||
|
$perfs = array();
|
||||||
|
foreach ($pset as $p) {
|
||||||
|
if ($percent = $p->getPercentage()) {
|
||||||
|
if ($percent < 0 || $percent > 100) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$perfs[] = ' '
|
||||||
|
. $p->getLabel()
|
||||||
|
. ': '
|
||||||
|
. $this->getPercentageSign($percent)
|
||||||
|
. ' '
|
||||||
|
. number_format($percent, 2, ',', '.')
|
||||||
|
. '%';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (! empty($perfs)) {
|
||||||
|
$perf = ', ' . implode($perfs);
|
||||||
|
}
|
||||||
|
// TODO: fix wordwarp, then remove this line:
|
||||||
|
$perf = '';
|
||||||
|
} catch (Exception $e) {
|
||||||
|
// Ignoring perfdata errors right now, we could show some hint
|
||||||
|
}
|
||||||
|
|
||||||
|
$wrappedOutput = wordwrap(
|
||||||
|
preg_replace('~\@{3,}~', '@@@', $row->service_output),
|
||||||
|
$maxCols - 13
|
||||||
|
) . "\n";
|
||||||
|
$out .= sprintf(
|
||||||
|
" %1s─ %s%s (%s)",
|
||||||
|
$leaf,
|
||||||
|
$screen->underline($row->service_description),
|
||||||
|
$screen->colorize($utils->objectStateFlags('service', $row) . $perf, 'lightblue'),
|
||||||
|
ucfirst(DateFormatter::timeSince($row->service_last_state_change))
|
||||||
|
);
|
||||||
|
if ($this->isVerbose) {
|
||||||
|
$out .= $emptyLine . preg_replace(
|
||||||
|
'/\n/',
|
||||||
|
$emptyLine,
|
||||||
|
$wrappedOutput
|
||||||
|
) . "\n";
|
||||||
|
} else {
|
||||||
|
$out .= "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$out .= "\n";
|
||||||
|
return $out;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getPercentageSign($percent)
|
||||||
|
{
|
||||||
|
$circles = array(
|
||||||
|
0 => '○',
|
||||||
|
15 => '◔',
|
||||||
|
40 => '◑',
|
||||||
|
65 => '◕',
|
||||||
|
90 => '●',
|
||||||
|
);
|
||||||
|
$last = $circles[0];
|
||||||
|
foreach ($circles as $cur => $circle) {
|
||||||
|
if ($percent < $cur) {
|
||||||
|
return $last;
|
||||||
|
}
|
||||||
|
$last = $circle;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
58
modules/monitoring/application/clicommands/NrpeCommand.php
Normal file
58
modules/monitoring/application/clicommands/NrpeCommand.php
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2013 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Clicommands;
|
||||||
|
|
||||||
|
use Icinga\Protocol\Nrpe\Connection;
|
||||||
|
use Icinga\Cli\Command;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NRPE
|
||||||
|
*/
|
||||||
|
class NrpeCommand extends Command
|
||||||
|
{
|
||||||
|
protected $defaultActionName = 'check';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute an NRPE command
|
||||||
|
*
|
||||||
|
* This command will execute an NRPE check, fire it against the given host
|
||||||
|
* and also pass through all your parameters. Output will be shown, exit
|
||||||
|
* code respected.
|
||||||
|
*
|
||||||
|
* USAGE
|
||||||
|
*
|
||||||
|
* icingacli monitoring nrpe <host> <command> [--ssl] [nrpe options]
|
||||||
|
*
|
||||||
|
* EXAMPLE
|
||||||
|
*
|
||||||
|
* icingacli monitoring nrpe 127.0.0.1 CheckMEM --ssl --MaxWarn=80% \
|
||||||
|
* --MaxCrit=90% --type=physical
|
||||||
|
*/
|
||||||
|
public function checkAction()
|
||||||
|
{
|
||||||
|
$host = $this->params->shift();
|
||||||
|
if (! $host) {
|
||||||
|
echo $this->showUsage();
|
||||||
|
exit(3);
|
||||||
|
}
|
||||||
|
$command = $this->params->shift(null, '_NRPE_CHECK');
|
||||||
|
$port = $this->params->shift('port', 5666);
|
||||||
|
try {
|
||||||
|
$nrpe = new Connection($host, $port);
|
||||||
|
if ($this->params->shift('ssl')) {
|
||||||
|
$nrpe->useSsl();
|
||||||
|
}
|
||||||
|
$args = array();
|
||||||
|
foreach ($this->params->getParams() as $k => $v) {
|
||||||
|
$args[] = $k . '=' . $v;
|
||||||
|
}
|
||||||
|
echo $nrpe->sendCommand($command, $args) . "\n";
|
||||||
|
exit($nrpe->getLastReturnCode());
|
||||||
|
} catch (Exception $e) {
|
||||||
|
echo $e->getMessage() . "\n";
|
||||||
|
exit(3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
135
modules/monitoring/application/controllers/ActionsController.php
Normal file
135
modules/monitoring/application/controllers/ActionsController.php
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Controllers;
|
||||||
|
|
||||||
|
use Icinga\Data\Filter\Filter;
|
||||||
|
use Icinga\Module\Monitoring\Controller;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\DeleteDowntimesCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleHostDowntimeCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleServiceDowntimeCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Object\HostList;
|
||||||
|
use Icinga\Module\Monitoring\Object\ServiceList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Monitoring API
|
||||||
|
*/
|
||||||
|
class ActionsController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Get the filter from URL parameters or exit immediately if the filter is empty
|
||||||
|
*
|
||||||
|
* @return Filter
|
||||||
|
*/
|
||||||
|
protected function getFilterOrExitIfEmpty()
|
||||||
|
{
|
||||||
|
$filter = Filter::fromQueryString((string) $this->params);
|
||||||
|
if ($filter->isEmpty()) {
|
||||||
|
$this->getResponse()->json()
|
||||||
|
->setFailData(array('filter' => 'Filter is required and must not be empty'))
|
||||||
|
->sendResponse();
|
||||||
|
}
|
||||||
|
return $filter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule host downtimes
|
||||||
|
*/
|
||||||
|
public function scheduleHostDowntimeAction()
|
||||||
|
{
|
||||||
|
$filter = $this->getFilterOrExitIfEmpty();
|
||||||
|
$hostList = new HostList($this->backend);
|
||||||
|
$hostList
|
||||||
|
->applyFilter($this->getRestriction('monitoring/filter/objects'))
|
||||||
|
->applyFilter($filter);
|
||||||
|
if (! $hostList->count()) {
|
||||||
|
$this->getResponse()->json()
|
||||||
|
->setFailData(array('filter' => 'No hosts found matching the filter'))
|
||||||
|
->sendResponse();
|
||||||
|
}
|
||||||
|
$form = new ScheduleHostDowntimeCommandForm();
|
||||||
|
$form
|
||||||
|
->setIsApiTarget(true)
|
||||||
|
->setBackend($this->backend)
|
||||||
|
->setObjects($hostList->fetch())
|
||||||
|
->handleRequest($this->getRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove host downtimes
|
||||||
|
*/
|
||||||
|
public function removeHostDowntimeAction()
|
||||||
|
{
|
||||||
|
$filter = $this->getFilterOrExitIfEmpty();
|
||||||
|
$downtimes = $this->backend
|
||||||
|
->select()
|
||||||
|
->from('downtime', array('host_name', 'id' => 'downtime_internal_id', 'name' => 'downtime_name'))
|
||||||
|
->where('object_type', 'host')
|
||||||
|
->applyFilter($this->getRestriction('monitoring/filter/objects'))
|
||||||
|
->applyFilter($filter);
|
||||||
|
if (! $downtimes->count()) {
|
||||||
|
$this->getResponse()->json()
|
||||||
|
->setFailData(array('filter' => 'No downtimes found matching the filter'))
|
||||||
|
->sendResponse();
|
||||||
|
}
|
||||||
|
$form = new DeleteDowntimesCommandForm();
|
||||||
|
$form
|
||||||
|
->setIsApiTarget(true)
|
||||||
|
->setDowntimes($downtimes->fetchAll())
|
||||||
|
->handleRequest($this->getRequest());
|
||||||
|
// @TODO(el): Respond w/ the downtimes deleted instead of the notifiaction added by
|
||||||
|
// DeleteDowntimesCommandForm::onSuccess().
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule service downtimes
|
||||||
|
*/
|
||||||
|
public function scheduleServiceDowntimeAction()
|
||||||
|
{
|
||||||
|
$filter = $this->getFilterOrExitIfEmpty();
|
||||||
|
$serviceList = new ServiceList($this->backend);
|
||||||
|
$serviceList
|
||||||
|
->applyFilter($this->getRestriction('monitoring/filter/objects'))
|
||||||
|
->applyFilter($filter);
|
||||||
|
if (! $serviceList->count()) {
|
||||||
|
$this->getResponse()->json()
|
||||||
|
->setFailData(array('filter' => 'No services found matching the filter'))
|
||||||
|
->sendResponse();
|
||||||
|
}
|
||||||
|
$form = new ScheduleServiceDowntimeCommandForm();
|
||||||
|
$form
|
||||||
|
->setIsApiTarget(true)
|
||||||
|
->setBackend($this->backend)
|
||||||
|
->setObjects($serviceList->fetch())
|
||||||
|
->handleRequest($this->getRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove service downtimes
|
||||||
|
*/
|
||||||
|
public function removeServiceDowntimeAction()
|
||||||
|
{
|
||||||
|
$filter = $this->getFilterOrExitIfEmpty();
|
||||||
|
$downtimes = $this->backend
|
||||||
|
->select()
|
||||||
|
->from(
|
||||||
|
'downtime',
|
||||||
|
array('host_name', 'service_description', 'id' => 'downtime_internal_id', 'name' => 'downtime_name')
|
||||||
|
)
|
||||||
|
->where('object_type', 'service')
|
||||||
|
->applyFilter($this->getRestriction('monitoring/filter/objects'))
|
||||||
|
->applyFilter($filter);
|
||||||
|
if (! $downtimes->count()) {
|
||||||
|
$this->getResponse()->json()
|
||||||
|
->setFailData(array('filter' => 'No downtimes found matching the filter'))
|
||||||
|
->sendResponse();
|
||||||
|
}
|
||||||
|
$form = new DeleteDowntimesCommandForm();
|
||||||
|
$form
|
||||||
|
->setIsApiTarget(true)
|
||||||
|
->setDowntimes($downtimes->fetchAll())
|
||||||
|
->handleRequest($this->getRequest());
|
||||||
|
// @TODO(el): Respond w/ the downtimes deleted instead of the notifiaction added by
|
||||||
|
// DeleteDowntimesCommandForm::onSuccess().
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,91 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Controllers;
|
||||||
|
|
||||||
|
use Icinga\Application\Hook;
|
||||||
|
use Icinga\Module\Monitoring\Controller;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\DeleteCommentCommandForm;
|
||||||
|
use Icinga\Web\Url;
|
||||||
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display detailed information about a comment
|
||||||
|
*/
|
||||||
|
class CommentController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The fetched comment
|
||||||
|
*
|
||||||
|
* @var object
|
||||||
|
*/
|
||||||
|
protected $comment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the first comment with the given id and add tabs
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$commentId = $this->params->getRequired('comment_id');
|
||||||
|
|
||||||
|
$query = $this->backend->select()->from('comment', array(
|
||||||
|
'id' => 'comment_internal_id',
|
||||||
|
'objecttype' => 'object_type',
|
||||||
|
'comment' => 'comment_data',
|
||||||
|
'author' => 'comment_author_name',
|
||||||
|
'timestamp' => 'comment_timestamp',
|
||||||
|
'type' => 'comment_type',
|
||||||
|
'persistent' => 'comment_is_persistent',
|
||||||
|
'expiration' => 'comment_expiration',
|
||||||
|
'name' => 'comment_name',
|
||||||
|
'host_name',
|
||||||
|
'service_description',
|
||||||
|
'host_display_name',
|
||||||
|
'service_display_name'
|
||||||
|
))->where('comment_internal_id', $commentId);
|
||||||
|
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||||
|
|
||||||
|
if (false === $this->comment = $query->fetchRow()) {
|
||||||
|
$this->httpNotFound($this->translate('Comment not found'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->getTabs()->add(
|
||||||
|
'comment',
|
||||||
|
array(
|
||||||
|
'icon' => 'comment-empty',
|
||||||
|
'label' => $this->translate('Comment'),
|
||||||
|
'title' => $this->translate('Display detailed information about a comment.'),
|
||||||
|
'url' =>'monitoring/comments/show'
|
||||||
|
)
|
||||||
|
)->activate('comment')->extend(new DashboardAction())->extend(new MenuAction());
|
||||||
|
|
||||||
|
if (Hook::has('ticket')) {
|
||||||
|
$this->view->tickets = Hook::first('ticket');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display comment detail view
|
||||||
|
*/
|
||||||
|
public function showAction()
|
||||||
|
{
|
||||||
|
$this->view->comment = $this->comment;
|
||||||
|
$this->view->title = $this->translate('Comments');
|
||||||
|
|
||||||
|
if ($this->hasPermission('monitoring/command/comment/delete')) {
|
||||||
|
$listUrl = Url::fromPath('monitoring/list/comments')
|
||||||
|
->setQueryString('comment_type=comment|comment_type=ack');
|
||||||
|
$form = new DeleteCommentCommandForm();
|
||||||
|
$form
|
||||||
|
->populate(array(
|
||||||
|
'comment_id' => $this->comment->id,
|
||||||
|
'comment_is_service' => isset($this->comment->service_description),
|
||||||
|
'comment_name' => $this->comment->name,
|
||||||
|
'redirect' => $listUrl
|
||||||
|
))
|
||||||
|
->handleRequest();
|
||||||
|
$this->view->delCommentForm = $form;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Controllers;
|
||||||
|
|
||||||
|
use Icinga\Data\Filter\Filter;
|
||||||
|
use Icinga\Module\Monitoring\Controller;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\DeleteCommentsCommandForm;
|
||||||
|
use Icinga\Web\Url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display detailed information about comments
|
||||||
|
*/
|
||||||
|
class CommentsController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The comments view
|
||||||
|
*
|
||||||
|
* @var \Icinga\Module\Monitoring\DataView\Comment
|
||||||
|
*/
|
||||||
|
protected $comments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter from request
|
||||||
|
*
|
||||||
|
* @var Filter
|
||||||
|
*/
|
||||||
|
protected $filter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch all comments matching the current filter and add tabs
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->filter = Filter::fromQueryString(str_replace(
|
||||||
|
'comment_id',
|
||||||
|
'comment_internal_id',
|
||||||
|
(string) $this->params
|
||||||
|
));
|
||||||
|
$query = $this->backend->select()->from('comment', array(
|
||||||
|
'id' => 'comment_internal_id',
|
||||||
|
'objecttype' => 'object_type',
|
||||||
|
'comment' => 'comment_data',
|
||||||
|
'author' => 'comment_author_name',
|
||||||
|
'timestamp' => 'comment_timestamp',
|
||||||
|
'type' => 'comment_type',
|
||||||
|
'persistent' => 'comment_is_persistent',
|
||||||
|
'expiration' => 'comment_expiration',
|
||||||
|
'name' => 'comment_name',
|
||||||
|
'host_name',
|
||||||
|
'service_description',
|
||||||
|
'host_display_name',
|
||||||
|
'service_display_name'
|
||||||
|
))->addFilter($this->filter);
|
||||||
|
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||||
|
|
||||||
|
$this->comments = $query;
|
||||||
|
|
||||||
|
$this->view->title = $this->translate('Comments');
|
||||||
|
$this->getTabs()->add(
|
||||||
|
'comments',
|
||||||
|
array(
|
||||||
|
'icon' => 'comment-empty',
|
||||||
|
'label' => $this->translate('Comments') . sprintf(' (%d)', $query->count()),
|
||||||
|
'title' => $this->translate(
|
||||||
|
'Display detailed information about multiple comments.'
|
||||||
|
),
|
||||||
|
'url' =>'monitoring/comments/show'
|
||||||
|
)
|
||||||
|
)->activate('comments');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the detail view for a comment list
|
||||||
|
*/
|
||||||
|
public function showAction()
|
||||||
|
{
|
||||||
|
$this->view->comments = $this->comments;
|
||||||
|
$this->view->listAllLink = Url::fromPath('monitoring/list/comments')
|
||||||
|
->setQueryString($this->filter->toQueryString());
|
||||||
|
$this->view->removeAllLink = Url::fromPath('monitoring/comments/delete-all')
|
||||||
|
->setParams($this->params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the form for removing a comment list
|
||||||
|
*/
|
||||||
|
public function deleteAllAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/comment/delete');
|
||||||
|
|
||||||
|
$listCommentsLink = Url::fromPath('monitoring/list/comments')
|
||||||
|
->setQueryString('comment_type=(comment|ack)');
|
||||||
|
$delCommentForm = new DeleteCommentsCommandForm();
|
||||||
|
$delCommentForm->setTitle($this->view->translate('Remove all Comments'));
|
||||||
|
$delCommentForm->addDescription(sprintf(
|
||||||
|
$this->translate('Confirm removal of %d comments.'),
|
||||||
|
$this->comments->count()
|
||||||
|
));
|
||||||
|
$delCommentForm->setComments($this->comments->fetchAll())
|
||||||
|
->setRedirectUrl($listCommentsLink)
|
||||||
|
->handleRequest();
|
||||||
|
$this->view->delCommentForm = $delCommentForm;
|
||||||
|
$this->view->comments = $this->comments;
|
||||||
|
$this->view->listAllLink = Url::fromPath('monitoring/list/comments')
|
||||||
|
->setQueryString($this->filter->toQueryString());
|
||||||
|
}
|
||||||
|
}
|
||||||
298
modules/monitoring/application/controllers/ConfigController.php
Normal file
298
modules/monitoring/application/controllers/ConfigController.php
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2013 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Controllers;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Icinga\Data\ResourceFactory;
|
||||||
|
use Icinga\Exception\ConfigurationError;
|
||||||
|
use Icinga\Exception\NotFoundError;
|
||||||
|
use Icinga\Forms\ConfirmRemovalForm;
|
||||||
|
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Config\TransportReorderForm;
|
||||||
|
use Icinga\Web\Controller;
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Config\BackendConfigForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Config\SecurityConfigForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Config\TransportConfigForm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configuration controller for editing monitoring resources
|
||||||
|
*/
|
||||||
|
class ConfigController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->assertPermission('config/modules');
|
||||||
|
$this->view->title = $this->translate('Backends');
|
||||||
|
$this->view->defaultTitle = 'monitoring :: ' . $this->view->defaultTitle;
|
||||||
|
parent::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a list of available backends and command transports
|
||||||
|
*/
|
||||||
|
public function indexAction()
|
||||||
|
{
|
||||||
|
$this->view->commandTransportReorderForm = $form = new TransportReorderForm();
|
||||||
|
$form->handleRequest();
|
||||||
|
|
||||||
|
$this->view->backendsConfig = $this->Config('backends');
|
||||||
|
$this->view->tabs = $this->Module()->getConfigTabs()->activate('backends');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit a monitoring backend
|
||||||
|
*/
|
||||||
|
public function editbackendAction()
|
||||||
|
{
|
||||||
|
$backendName = $this->params->getRequired('backend-name');
|
||||||
|
|
||||||
|
$form = new BackendConfigForm();
|
||||||
|
$form->setRedirectUrl('monitoring/config');
|
||||||
|
$form->setTitle(sprintf($this->translate('Edit Monitoring Backend %s'), $backendName));
|
||||||
|
$form->setIniConfig($this->Config('backends'));
|
||||||
|
$form->setResourceConfig(ResourceFactory::getResourceConfigs());
|
||||||
|
$form->setOnSuccess(function (BackendConfigForm $form) use ($backendName) {
|
||||||
|
try {
|
||||||
|
$form->edit($backendName, array_map(
|
||||||
|
function ($v) {
|
||||||
|
return $v !== '' ? $v : null;
|
||||||
|
},
|
||||||
|
$form->getValues()
|
||||||
|
));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$form->error($e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($form->save()) {
|
||||||
|
Notification::success(sprintf(t('Monitoring backend "%s" successfully updated'), $backendName));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
$form->load($backendName);
|
||||||
|
$form->handleRequest();
|
||||||
|
} catch (NotFoundError $_) {
|
||||||
|
$this->httpNotFound(sprintf($this->translate('Monitoring backend "%s" not found'), $backendName));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->view->form = $form;
|
||||||
|
$this->render('form');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new monitoring backend
|
||||||
|
*/
|
||||||
|
public function createbackendAction()
|
||||||
|
{
|
||||||
|
$form = new BackendConfigForm();
|
||||||
|
$form->setRedirectUrl('monitoring/config');
|
||||||
|
$form->setTitle($this->translate('Create New Monitoring Backend'));
|
||||||
|
$form->setIniConfig($this->Config('backends'));
|
||||||
|
|
||||||
|
try {
|
||||||
|
$form->setResourceConfig(ResourceFactory::getResourceConfigs());
|
||||||
|
} catch (ConfigurationError $e) {
|
||||||
|
if ($this->hasPermission('config/resources')) {
|
||||||
|
Notification::error($e->getMessage());
|
||||||
|
$this->redirectNow('config/createresource');
|
||||||
|
}
|
||||||
|
|
||||||
|
throw $e; // No permission for resource configuration, show the error
|
||||||
|
}
|
||||||
|
|
||||||
|
$form->setOnSuccess(function (BackendConfigForm $form) {
|
||||||
|
try {
|
||||||
|
$form->add($form::transformEmptyValuesToNull($form->getValues()));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$form->error($e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($form->save()) {
|
||||||
|
Notification::success(t('Monitoring backend successfully created'));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
$form->handleRequest();
|
||||||
|
|
||||||
|
$this->view->form = $form;
|
||||||
|
$this->render('form');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a confirmation form to remove the backend identified by the 'backend' parameter
|
||||||
|
*/
|
||||||
|
public function removebackendAction()
|
||||||
|
{
|
||||||
|
$backendName = $this->params->getRequired('backend-name');
|
||||||
|
|
||||||
|
$backendForm = new BackendConfigForm();
|
||||||
|
$backendForm->setIniConfig($this->Config('backends'));
|
||||||
|
$form = new ConfirmRemovalForm();
|
||||||
|
$form->setRedirectUrl('monitoring/config');
|
||||||
|
$form->setTitle(sprintf($this->translate('Remove Monitoring Backend %s'), $backendName));
|
||||||
|
$form->setOnSuccess(function (ConfirmRemovalForm $form) use ($backendName, $backendForm) {
|
||||||
|
try {
|
||||||
|
$backendForm->delete($backendName);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$form->error($e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($backendForm->save()) {
|
||||||
|
Notification::success(sprintf(t('Monitoring backend "%s" successfully removed'), $backendName));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
$form->handleRequest();
|
||||||
|
|
||||||
|
$this->view->form = $form;
|
||||||
|
$this->render('form');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a command transport
|
||||||
|
*/
|
||||||
|
public function removetransportAction()
|
||||||
|
{
|
||||||
|
$transportName = $this->params->getRequired('transport');
|
||||||
|
|
||||||
|
$transportForm = new TransportConfigForm();
|
||||||
|
$transportForm->setIniConfig($this->Config('commandtransports'));
|
||||||
|
$form = new ConfirmRemovalForm();
|
||||||
|
$form->setRedirectUrl('monitoring/config');
|
||||||
|
$form->setTitle(sprintf($this->translate('Remove Command Transport %s'), $transportName));
|
||||||
|
$form->info(
|
||||||
|
$this->translate(
|
||||||
|
'If you still have any environments or views referring to this transport, '
|
||||||
|
. 'you won\'t be able to send commands anymore after deletion.'
|
||||||
|
),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
$form->setOnSuccess(function (ConfirmRemovalForm $form) use ($transportName, $transportForm) {
|
||||||
|
try {
|
||||||
|
$transportForm->delete($transportName);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$form->error($e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($transportForm->save()) {
|
||||||
|
Notification::success(sprintf(t('Command transport "%s" successfully removed'), $transportName));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
$form->handleRequest();
|
||||||
|
|
||||||
|
$this->view->form = $form;
|
||||||
|
$this->render('form');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit a command transport
|
||||||
|
*/
|
||||||
|
public function edittransportAction()
|
||||||
|
{
|
||||||
|
$transportName = $this->params->getRequired('transport');
|
||||||
|
|
||||||
|
$form = new TransportConfigForm();
|
||||||
|
$form->setRedirectUrl('monitoring/config');
|
||||||
|
$form->setTitle(sprintf($this->translate('Edit Command Transport %s'), $transportName));
|
||||||
|
$form->setIniConfig($this->Config('commandtransports'));
|
||||||
|
$form->setInstanceNames(
|
||||||
|
MonitoringBackend::instance()->select()->from('instance', array('instance_name'))->fetchColumn()
|
||||||
|
);
|
||||||
|
$form->setOnSuccess(function (TransportConfigForm $form) use ($transportName) {
|
||||||
|
try {
|
||||||
|
$form->edit($transportName, array_map(
|
||||||
|
function ($v) {
|
||||||
|
return $v !== '' ? $v : null;
|
||||||
|
},
|
||||||
|
$form->getValues()
|
||||||
|
));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$form->error($e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($form->save()) {
|
||||||
|
Notification::success(sprintf(t('Command transport "%s" successfully updated'), $transportName));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
$form->load($transportName);
|
||||||
|
$form->handleRequest();
|
||||||
|
} catch (NotFoundError $_) {
|
||||||
|
$this->httpNotFound(sprintf($this->translate('Command transport "%s" not found'), $transportName));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->view->form = $form;
|
||||||
|
$this->render('form');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new command transport
|
||||||
|
*/
|
||||||
|
public function createtransportAction()
|
||||||
|
{
|
||||||
|
$form = new TransportConfigForm();
|
||||||
|
$form->setRedirectUrl('monitoring/config');
|
||||||
|
$form->setTitle($this->translate('Create New Command Transport'));
|
||||||
|
$form->setIniConfig($this->Config('commandtransports'));
|
||||||
|
$form->setInstanceNames(
|
||||||
|
MonitoringBackend::instance()->select()->from('instance', array('instance_name'))->fetchColumn()
|
||||||
|
);
|
||||||
|
$form->setOnSuccess(function (TransportConfigForm $form) {
|
||||||
|
try {
|
||||||
|
$form->add($form::transformEmptyValuesToNull($form->getValues()));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$form->error($e->getMessage());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($form->save()) {
|
||||||
|
Notification::success(t('Command transport successfully created'));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
$form->handleRequest();
|
||||||
|
|
||||||
|
$this->view->form = $form;
|
||||||
|
$this->render('form');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display a form to adjust security relevant settings
|
||||||
|
*/
|
||||||
|
public function securityAction()
|
||||||
|
{
|
||||||
|
$form = new SecurityConfigForm();
|
||||||
|
$form->setIniConfig($this->Config());
|
||||||
|
$form->handleRequest();
|
||||||
|
|
||||||
|
$this->view->form = $form;
|
||||||
|
$this->view->title = $this->translate('Security');
|
||||||
|
$this->view->tabs = $this->Module()->getConfigTabs()->activate('security');
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Controllers;
|
||||||
|
|
||||||
|
use Icinga\Application\Hook;
|
||||||
|
use Icinga\Module\Monitoring\Controller;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\DeleteDowntimeCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Object\Host;
|
||||||
|
use Icinga\Module\Monitoring\Object\Service;
|
||||||
|
use Icinga\Web\Url;
|
||||||
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display detailed information about a downtime
|
||||||
|
*/
|
||||||
|
class DowntimeController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The fetched downtime
|
||||||
|
*
|
||||||
|
* @var object
|
||||||
|
*/
|
||||||
|
protected $downtime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the downtime matching the given id and add tabs
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$downtimeId = $this->params->getRequired('downtime_id');
|
||||||
|
|
||||||
|
$query = $this->backend->select()->from('downtime', array(
|
||||||
|
'id' => 'downtime_internal_id',
|
||||||
|
'objecttype' => 'object_type',
|
||||||
|
'comment' => 'downtime_comment',
|
||||||
|
'author_name' => 'downtime_author_name',
|
||||||
|
'start' => 'downtime_start',
|
||||||
|
'scheduled_start' => 'downtime_scheduled_start',
|
||||||
|
'scheduled_end' => 'downtime_scheduled_end',
|
||||||
|
'end' => 'downtime_end',
|
||||||
|
'duration' => 'downtime_duration',
|
||||||
|
'is_flexible' => 'downtime_is_flexible',
|
||||||
|
'is_fixed' => 'downtime_is_fixed',
|
||||||
|
'is_in_effect' => 'downtime_is_in_effect',
|
||||||
|
'entry_time' => 'downtime_entry_time',
|
||||||
|
'name' => 'downtime_name',
|
||||||
|
'host_state',
|
||||||
|
'service_state',
|
||||||
|
'host_name',
|
||||||
|
'service_description',
|
||||||
|
'host_display_name',
|
||||||
|
'service_display_name'
|
||||||
|
))->where('downtime_internal_id', $downtimeId);
|
||||||
|
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||||
|
|
||||||
|
if (false === $this->downtime = $query->fetchRow()) {
|
||||||
|
$this->httpNotFound($this->translate('Downtime not found'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->getTabs()->add(
|
||||||
|
'downtime',
|
||||||
|
array(
|
||||||
|
|
||||||
|
'icon' => 'plug',
|
||||||
|
'label' => $this->translate('Downtime'),
|
||||||
|
'title' => $this->translate('Display detailed information about a downtime.'),
|
||||||
|
'url' =>'monitoring/downtimes/show'
|
||||||
|
)
|
||||||
|
)->activate('downtime')->extend(new DashboardAction())->extend(new MenuAction());
|
||||||
|
|
||||||
|
if (Hook::has('ticket')) {
|
||||||
|
$this->view->tickets = Hook::first('ticket');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the detail view for a downtime
|
||||||
|
*/
|
||||||
|
public function showAction()
|
||||||
|
{
|
||||||
|
$isService = isset($this->downtime->service_description);
|
||||||
|
$this->view->downtime = $this->downtime;
|
||||||
|
$this->view->isService = $isService;
|
||||||
|
$this->view->listAllLink = Url::fromPath('monitoring/list/downtimes');
|
||||||
|
$this->view->showHostLink = Url::fromPath('monitoring/host/show')->setParam('host', $this->downtime->host_name);
|
||||||
|
$this->view->showServiceLink = Url::fromPath('monitoring/service/show')
|
||||||
|
->setParam('host', $this->downtime->host_name)
|
||||||
|
->setParam('service', $this->downtime->service_description);
|
||||||
|
$this->view->stateName = $isService ? Service::getStateText($this->downtime->service_state)
|
||||||
|
: Host::getStateText($this->downtime->host_state);
|
||||||
|
|
||||||
|
$this->view->title = $this->translate('Downtimes');
|
||||||
|
if ($this->hasPermission('monitoring/command/downtime/delete')) {
|
||||||
|
$form = new DeleteDowntimeCommandForm();
|
||||||
|
$form
|
||||||
|
->populate(array(
|
||||||
|
'downtime_id' => $this->downtime->id,
|
||||||
|
'downtime_is_service' => $isService,
|
||||||
|
'downtime_name' => $this->downtime->name,
|
||||||
|
'redirect' => Url::fromPath('monitoring/list/downtimes'),
|
||||||
|
))
|
||||||
|
->handleRequest();
|
||||||
|
$this->view->delDowntimeForm = $form;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,108 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Controllers;
|
||||||
|
|
||||||
|
use Icinga\Data\Filter\Filter;
|
||||||
|
use Icinga\Module\Monitoring\Controller;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\DeleteDowntimesCommandForm;
|
||||||
|
use Icinga\Web\Url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display detailed information about downtimes
|
||||||
|
*/
|
||||||
|
class DowntimesController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The downtimes view
|
||||||
|
*
|
||||||
|
* @var \Icinga\Module\Monitoring\DataView\Downtime
|
||||||
|
*/
|
||||||
|
protected $downtimes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter from request
|
||||||
|
*
|
||||||
|
* @var Filter
|
||||||
|
*/
|
||||||
|
protected $filter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch all downtimes matching the current filter and add tabs
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->filter = Filter::fromQueryString(str_replace(
|
||||||
|
'downtime_id',
|
||||||
|
'downtime_internal_id',
|
||||||
|
(string) $this->params
|
||||||
|
));
|
||||||
|
$query = $this->backend->select()->from('downtime', array(
|
||||||
|
'id' => 'downtime_internal_id',
|
||||||
|
'objecttype' => 'object_type',
|
||||||
|
'comment' => 'downtime_comment',
|
||||||
|
'author_name' => 'downtime_author_name',
|
||||||
|
'start' => 'downtime_start',
|
||||||
|
'scheduled_start' => 'downtime_scheduled_start',
|
||||||
|
'scheduled_end' => 'downtime_scheduled_end',
|
||||||
|
'end' => 'downtime_end',
|
||||||
|
'duration' => 'downtime_duration',
|
||||||
|
'is_flexible' => 'downtime_is_flexible',
|
||||||
|
'is_fixed' => 'downtime_is_fixed',
|
||||||
|
'is_in_effect' => 'downtime_is_in_effect',
|
||||||
|
'entry_time' => 'downtime_entry_time',
|
||||||
|
'name' => 'downtime_name',
|
||||||
|
'host_state',
|
||||||
|
'service_state',
|
||||||
|
'host_name',
|
||||||
|
'service_description',
|
||||||
|
'host_display_name',
|
||||||
|
'service_display_name'
|
||||||
|
))->addFilter($this->filter);
|
||||||
|
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||||
|
|
||||||
|
$this->downtimes = $query;
|
||||||
|
|
||||||
|
$this->view->title = $this->translate('Downtimes');
|
||||||
|
$this->getTabs()->add(
|
||||||
|
'downtimes',
|
||||||
|
array(
|
||||||
|
'icon' => 'plug',
|
||||||
|
'label' => $this->translate('Downtimes') . sprintf(' (%d)', $query->count()),
|
||||||
|
'title' => $this->translate('Display detailed information about multiple downtimes.'),
|
||||||
|
'url' =>'monitoring/downtimes/show'
|
||||||
|
)
|
||||||
|
)->activate('downtimes');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the detail view for a downtime list
|
||||||
|
*/
|
||||||
|
public function showAction()
|
||||||
|
{
|
||||||
|
$this->view->downtimes = $this->downtimes;
|
||||||
|
$this->view->listAllLink = Url::fromPath('monitoring/list/downtimes')
|
||||||
|
->setQueryString($this->filter->toQueryString());
|
||||||
|
$this->view->removeAllLink = Url::fromPath('monitoring/downtimes/delete-all')->setParams($this->params);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display the form for removing a downtime list
|
||||||
|
*/
|
||||||
|
public function deleteAllAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/downtime/delete');
|
||||||
|
$this->view->downtimes = $this->downtimes;
|
||||||
|
$this->view->listAllLink = Url::fromPath('monitoring/list/downtimes')
|
||||||
|
->setQueryString($this->filter->toQueryString());
|
||||||
|
$delDowntimeForm = new DeleteDowntimesCommandForm();
|
||||||
|
$delDowntimeForm->setTitle($this->view->translate('Remove all Downtimes'));
|
||||||
|
$delDowntimeForm->addDescription(sprintf(
|
||||||
|
$this->translate('Confirm removal of %d downtimes.'),
|
||||||
|
$this->downtimes->count()
|
||||||
|
));
|
||||||
|
$delDowntimeForm->setRedirectUrl(Url::fromPath('monitoring/list/downtimes'));
|
||||||
|
$delDowntimeForm->setDowntimes($this->downtimes->fetchAll())->handleRequest();
|
||||||
|
$this->view->delAllDowntimeForm = $delDowntimeForm;
|
||||||
|
}
|
||||||
|
}
|
||||||
551
modules/monitoring/application/controllers/EventController.php
Normal file
551
modules/monitoring/application/controllers/EventController.php
Normal file
@ -0,0 +1,551 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2017 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Controllers;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use DateTimeZone;
|
||||||
|
use Icinga\Module\Monitoring\Hook\EventDetailsExtensionHook;
|
||||||
|
use Icinga\Application\Hook;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use Icinga\Data\Queryable;
|
||||||
|
use Icinga\Date\DateFormatter;
|
||||||
|
use Icinga\Module\Monitoring\Controller;
|
||||||
|
use Icinga\Module\Monitoring\Object\Host;
|
||||||
|
use Icinga\Module\Monitoring\Object\Service;
|
||||||
|
use Icinga\Util\TimezoneDetect;
|
||||||
|
use Icinga\Web\Url;
|
||||||
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\OutputFormat;
|
||||||
|
|
||||||
|
class EventController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
protected $dataViewsByType = array(
|
||||||
|
'notify' => 'notificationevent',
|
||||||
|
'comment' => 'commentevent',
|
||||||
|
'comment_deleted' => 'commentevent',
|
||||||
|
'ack' => 'commentevent',
|
||||||
|
'ack_deleted' => 'commentevent',
|
||||||
|
'dt_comment' => 'commentevent',
|
||||||
|
'dt_comment_deleted' => 'commentevent',
|
||||||
|
'flapping' => 'flappingevent',
|
||||||
|
'flapping_deleted' => 'flappingevent',
|
||||||
|
'hard_state' => 'statechangeevent',
|
||||||
|
'soft_state' => 'statechangeevent',
|
||||||
|
'dt_start' => 'downtimeevent',
|
||||||
|
'dt_end' => 'downtimeevent'
|
||||||
|
);
|
||||||
|
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
if (Hook::has('ticket')) {
|
||||||
|
$this->view->tickets = Hook::first('ticket');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showAction()
|
||||||
|
{
|
||||||
|
$type = $this->params->shiftRequired('type');
|
||||||
|
$id = $this->params->shiftRequired('id');
|
||||||
|
|
||||||
|
if (! isset($this->dataViewsByType[$type])
|
||||||
|
|| $this->applyRestriction(
|
||||||
|
'monitoring/filter/objects',
|
||||||
|
$this->backend->select()->from('eventhistory', array('id'))->where('id', $id)
|
||||||
|
)->fetchRow() === false
|
||||||
|
) {
|
||||||
|
$this->httpNotFound($this->translate('Event not found'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$event = $this->query($type, $id)->fetchRow();
|
||||||
|
|
||||||
|
if ($event === false) {
|
||||||
|
$this->httpNotFound($this->translate('Event not found'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->view->object = $object = $event->service_description === null
|
||||||
|
? new Host($this->backend, $event->host_name)
|
||||||
|
: new Service($this->backend, $event->host_name, $event->service_description);
|
||||||
|
$object->fetch();
|
||||||
|
|
||||||
|
list($icon, $label) = $this->getIconAndLabel($type);
|
||||||
|
|
||||||
|
$this->view->details = array_merge(
|
||||||
|
array(array($this->view->escape($this->translate('Type')), $label)),
|
||||||
|
$this->getDetails($type, $event)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->view->extensionsHtml = array();
|
||||||
|
/** @var EventDetailsExtensionHook $hook */
|
||||||
|
foreach (Hook::all('Monitoring\\EventDetailsExtension') as $hook) {
|
||||||
|
try {
|
||||||
|
$html = $hook->getHtmlForEvent($event);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$html = $this->view->escape($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($html) {
|
||||||
|
$module = $this->view->escape($hook->getModule()->getName());
|
||||||
|
$this->view->extensionsHtml[] =
|
||||||
|
'<div class="icinga-module module-' . $module . '" data-icinga-module="' . $module . '">'
|
||||||
|
. $html
|
||||||
|
. '</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->view->title = $this->translate('Event Overview');
|
||||||
|
$this->getTabs()
|
||||||
|
->add('event', array(
|
||||||
|
'title' => $label,
|
||||||
|
'label' => $label,
|
||||||
|
'url' => Url::fromRequest(),
|
||||||
|
'active' => true
|
||||||
|
))
|
||||||
|
->extend(new OutputFormat())
|
||||||
|
->extend(new DashboardAction())
|
||||||
|
->extend(new MenuAction());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return translated and escaped 'Yes' if the given condition is true, 'No' otherwise, 'N/A' if NULL
|
||||||
|
*
|
||||||
|
* @param bool|null $condition
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function yesOrNo($condition)
|
||||||
|
{
|
||||||
|
if ($condition === null) {
|
||||||
|
return $this->view->escape($this->translate('N/A'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->view->escape($condition ? $this->translate('Yes') : $this->translate('No'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the given duration in seconds as human readable HTML or 'N/A' if NULL
|
||||||
|
*
|
||||||
|
* @param int|null $seconds
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function duration($seconds)
|
||||||
|
{
|
||||||
|
return $this->view->escape(
|
||||||
|
$seconds === null ? $this->translate('N/A') : DateFormatter::formatDuration($seconds)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the given percent number as human readable HTML or 'N/A' if NULL
|
||||||
|
*
|
||||||
|
* @param float|null $percent
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function percent($percent)
|
||||||
|
{
|
||||||
|
return $this->view->escape(
|
||||||
|
$percent === null ? $this->translate('N/A') : sprintf($this->translate('%.2f%%'), $percent)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the given comment message as HTML or 'N/A' if NULL
|
||||||
|
*
|
||||||
|
* @param string|null $message
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function comment($message)
|
||||||
|
{
|
||||||
|
return $this->view->nl2br($this->view->createTicketLinks($this->view->markdown($message)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render a link to the given contact or 'N/A' if NULL
|
||||||
|
*
|
||||||
|
* @param string|null $name
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function contact($name)
|
||||||
|
{
|
||||||
|
return $name === null
|
||||||
|
? $this->view->escape($this->translate('N/A'))
|
||||||
|
: $this->view->qlink($name, Url::fromPath('monitoring/show/contact', array('contact_name' => $name)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the given monitored object state as human readable HTML or 'N/A' if NULL
|
||||||
|
*
|
||||||
|
* @param bool $isService
|
||||||
|
* @param int|null $state
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function state($isService, $state)
|
||||||
|
{
|
||||||
|
if ($state === null) {
|
||||||
|
return $this->view->escape($this->translate('N/A'));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$stateText = $isService
|
||||||
|
? Service::getStateText($state, true)
|
||||||
|
: Host::getStateText($state, true);
|
||||||
|
} catch (InvalidArgumentException $e) {
|
||||||
|
return $this->view->escape($this->translate('N/A'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return '<span class="badge state-' . ($isService ? Service::getStateText($state) : Host::getStateText($state))
|
||||||
|
. '"> </span><span class="state-label">' . $this->view->escape($stateText) . '</span>';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the given plugin output as human readable HTML
|
||||||
|
*
|
||||||
|
* @param string $output
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function pluginOutput($output)
|
||||||
|
{
|
||||||
|
return $this->view->getHelper('PluginOutput')->pluginOutput($output);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the icon and the label for the given event type
|
||||||
|
*
|
||||||
|
* @param string $eventType
|
||||||
|
*
|
||||||
|
* @return ?string[]
|
||||||
|
*/
|
||||||
|
protected function getIconAndLabel($eventType)
|
||||||
|
{
|
||||||
|
switch ($eventType) {
|
||||||
|
case 'notify':
|
||||||
|
return array('bell', $this->translate('Notification', 'tooltip'));
|
||||||
|
case 'comment':
|
||||||
|
return array('comment-empty', $this->translate('Comment', 'tooltip'));
|
||||||
|
case 'comment_deleted':
|
||||||
|
return array('cancel', $this->translate('Comment removed', 'tooltip'));
|
||||||
|
case 'ack':
|
||||||
|
return array('ok', $this->translate('Acknowledged', 'tooltip'));
|
||||||
|
case 'ack_deleted':
|
||||||
|
return array('ok', $this->translate('Acknowledgement removed', 'tooltip'));
|
||||||
|
case 'dt_comment':
|
||||||
|
return array('plug', $this->translate('Downtime scheduled', 'tooltip'));
|
||||||
|
case 'dt_comment_deleted':
|
||||||
|
return array('plug', $this->translate('Downtime removed', 'tooltip'));
|
||||||
|
case 'flapping':
|
||||||
|
return array('flapping', $this->translate('Flapping started', 'tooltip'));
|
||||||
|
case 'flapping_deleted':
|
||||||
|
return array('flapping', $this->translate('Flapping stopped', 'tooltip'));
|
||||||
|
case 'hard_state':
|
||||||
|
return array('warning-empty', $this->translate('Hard state change'));
|
||||||
|
case 'soft_state':
|
||||||
|
return array('spinner', $this->translate('Soft state change'));
|
||||||
|
case 'dt_start':
|
||||||
|
return array('plug', $this->translate('Downtime started', 'tooltip'));
|
||||||
|
case 'dt_end':
|
||||||
|
return array('plug', $this->translate('Downtime ended', 'tooltip'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a query for the given event ID of the given type
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @param int $id
|
||||||
|
*
|
||||||
|
* @return ?Queryable
|
||||||
|
*/
|
||||||
|
protected function query($type, $id)
|
||||||
|
{
|
||||||
|
switch ($this->dataViewsByType[$type]) {
|
||||||
|
case 'downtimeevent':
|
||||||
|
return $this->backend->select()
|
||||||
|
->from('downtimeevent', array(
|
||||||
|
'entry_time' => 'downtimeevent_entry_time',
|
||||||
|
'author_name' => 'downtimeevent_author_name',
|
||||||
|
'comment_data' => 'downtimeevent_comment_data',
|
||||||
|
'is_fixed' => 'downtimeevent_is_fixed',
|
||||||
|
'scheduled_start_time' => 'downtimeevent_scheduled_start_time',
|
||||||
|
'scheduled_end_time' => 'downtimeevent_scheduled_end_time',
|
||||||
|
'was_started' => 'downtimeevent_was_started',
|
||||||
|
'actual_start_time' => 'downtimeevent_actual_start_time',
|
||||||
|
'actual_end_time' => 'downtimeevent_actual_end_time',
|
||||||
|
'was_cancelled' => 'downtimeevent_was_cancelled',
|
||||||
|
'is_in_effect' => 'downtimeevent_is_in_effect',
|
||||||
|
'trigger_time' => 'downtimeevent_trigger_time',
|
||||||
|
'host_name',
|
||||||
|
'service_description'
|
||||||
|
))
|
||||||
|
->where('downtimeevent_id', $id);
|
||||||
|
case 'commentevent':
|
||||||
|
return $this->backend->select()
|
||||||
|
->from('commentevent', array(
|
||||||
|
'entry_type' => 'commentevent_entry_type',
|
||||||
|
'comment_time' => 'commentevent_comment_time',
|
||||||
|
'author_name' => 'commentevent_author_name',
|
||||||
|
'comment_data' => 'commentevent_comment_data',
|
||||||
|
'is_persistent' => 'commentevent_is_persistent',
|
||||||
|
'comment_source' => 'commentevent_comment_source',
|
||||||
|
'expires' => 'commentevent_expires',
|
||||||
|
'expiration_time' => 'commentevent_expiration_time',
|
||||||
|
'deletion_time' => 'commentevent_deletion_time',
|
||||||
|
'host_name',
|
||||||
|
'service_description'
|
||||||
|
))
|
||||||
|
->where('commentevent_id', $id);
|
||||||
|
case 'flappingevent':
|
||||||
|
return $this->backend->select()
|
||||||
|
->from('flappingevent', array(
|
||||||
|
'event_time' => 'flappingevent_event_time',
|
||||||
|
'reason_type' => 'flappingevent_reason_type',
|
||||||
|
'percent_state_change' => 'flappingevent_percent_state_change',
|
||||||
|
'low_threshold' => 'flappingevent_low_threshold',
|
||||||
|
'high_threshold' => 'flappingevent_high_threshold',
|
||||||
|
'host_name',
|
||||||
|
'service_description'
|
||||||
|
))
|
||||||
|
->where('flappingevent_id', $id)
|
||||||
|
->where('flappingevent_event_type', $type);
|
||||||
|
case 'notificationevent':
|
||||||
|
return $this->backend->select()
|
||||||
|
->from('notificationevent', array(
|
||||||
|
'notification_reason' => 'notificationevent_reason',
|
||||||
|
'start_time' => 'notificationevent_start_time',
|
||||||
|
'end_time' => 'notificationevent_end_time',
|
||||||
|
'state' => 'notificationevent_state',
|
||||||
|
'output' => 'notificationevent_output',
|
||||||
|
'long_output' => 'notificationevent_long_output',
|
||||||
|
'escalated' => 'notificationevent_escalated',
|
||||||
|
'contacts_notified' => 'notificationevent_contacts_notified',
|
||||||
|
'host_name',
|
||||||
|
'service_description'
|
||||||
|
))
|
||||||
|
->where('notificationevent_id', $id);
|
||||||
|
case 'statechangeevent':
|
||||||
|
return $this->backend->select()
|
||||||
|
->from('statechangeevent', array(
|
||||||
|
'state_time' => 'statechangeevent_state_time',
|
||||||
|
'state' => 'statechangeevent_state',
|
||||||
|
'current_check_attempt' => 'statechangeevent_current_check_attempt',
|
||||||
|
'max_check_attempts' => 'statechangeevent_max_check_attempts',
|
||||||
|
'last_state' => 'statechangeevent_last_state',
|
||||||
|
'last_hard_state' => 'statechangeevent_last_hard_state',
|
||||||
|
'output' => 'statechangeevent_output',
|
||||||
|
'long_output' => 'statechangeevent_long_output',
|
||||||
|
'check_source' => 'statechangeevent_check_source',
|
||||||
|
'host_name',
|
||||||
|
'service_description'
|
||||||
|
))
|
||||||
|
->where('statechangeevent_id', $id)
|
||||||
|
->where('statechangeevent_state_change', 1)
|
||||||
|
->where('statechangeevent_state_type', $type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the given event's data prepared for a name-value table
|
||||||
|
*
|
||||||
|
* @param string $type
|
||||||
|
* @param \stdClass $event
|
||||||
|
*
|
||||||
|
* @return ?string[][]
|
||||||
|
*/
|
||||||
|
protected function getDetails($type, $event)
|
||||||
|
{
|
||||||
|
switch ($type) {
|
||||||
|
case 'dt_start':
|
||||||
|
case 'dt_end':
|
||||||
|
$details = array(array(
|
||||||
|
array($this->translate('Entry time'), DateFormatter::formatDateTime($event->entry_time)),
|
||||||
|
array($this->translate('Is fixed'), $this->yesOrNo($event->is_fixed)),
|
||||||
|
array($this->translate('Is in effect'), $this->yesOrNo($event->is_in_effect)),
|
||||||
|
array($this->translate('Was started'), $this->yesOrNo($event->was_started))
|
||||||
|
));
|
||||||
|
|
||||||
|
if ($type === 'dt_end') {
|
||||||
|
$details[] = array(
|
||||||
|
array($this->translate('Was cancelled'), $this->yesOrNo($event->was_cancelled))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$details[] = array(
|
||||||
|
array($this->translate('Trigger time'), DateFormatter::formatDateTime($event->trigger_time)),
|
||||||
|
array(
|
||||||
|
$this->translate('Scheduled start time'),
|
||||||
|
DateFormatter::formatDateTime($event->scheduled_start_time)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
$this->translate('Actual start time'),
|
||||||
|
DateFormatter::formatDateTime($event->actual_start_time)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
$this->translate('Scheduled end time'),
|
||||||
|
DateFormatter::formatDateTime($event->scheduled_end_time)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if ($type === 'dt_end') {
|
||||||
|
$details[] = array(
|
||||||
|
array(
|
||||||
|
$this->translate('Actual end time'),
|
||||||
|
DateFormatter::formatDateTime($event->actual_end_time)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$details[] = array(
|
||||||
|
array($this->translate('Author'), $this->contact($event->author_name)),
|
||||||
|
array($this->translate('Comment'), $this->comment($event->comment_data))
|
||||||
|
);
|
||||||
|
|
||||||
|
return call_user_func_array('array_merge', $details);
|
||||||
|
case 'comment':
|
||||||
|
case 'comment_deleted':
|
||||||
|
case 'ack':
|
||||||
|
case 'ack_deleted':
|
||||||
|
case 'dt_comment':
|
||||||
|
case 'dt_comment_deleted':
|
||||||
|
switch ($event->entry_type) {
|
||||||
|
case 'comment':
|
||||||
|
$entryType = $this->translate('User comment');
|
||||||
|
break;
|
||||||
|
case 'downtime':
|
||||||
|
$entryType = $this->translate('Scheduled downtime');
|
||||||
|
break;
|
||||||
|
case 'flapping':
|
||||||
|
$entryType = $this->translate('Flapping');
|
||||||
|
break;
|
||||||
|
case 'ack':
|
||||||
|
$entryType = $this->translate('Acknowledgement');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$entryType = $this->translate('N/A');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($event->comment_source) {
|
||||||
|
case 'icinga':
|
||||||
|
$commentSource = $this->translate('Icinga');
|
||||||
|
break;
|
||||||
|
case 'user':
|
||||||
|
$commentSource = $this->translate('User');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$commentSource = $this->translate('N/A');
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
array($this->translate('Time'), DateFormatter::formatDateTime($event->comment_time)),
|
||||||
|
array($this->translate('Source'), $this->view->escape($commentSource)),
|
||||||
|
array($this->translate('Entry type'), $this->view->escape($entryType)),
|
||||||
|
array($this->translate('Author'), $this->contact($event->author_name)),
|
||||||
|
array($this->translate('Is persistent'), $this->yesOrNo($event->is_persistent)),
|
||||||
|
array($this->translate('Expires'), $this->yesOrNo($event->expires)),
|
||||||
|
array($this->translate('Expiration time'), DateFormatter::formatDateTime($event->expiration_time)),
|
||||||
|
array($this->translate('Deletion time'), DateFormatter::formatDateTime($event->deletion_time)),
|
||||||
|
array($this->translate('Message'), $this->comment($event->comment_data))
|
||||||
|
);
|
||||||
|
case 'flapping':
|
||||||
|
case 'flapping_deleted':
|
||||||
|
switch ($event->reason_type) {
|
||||||
|
case 'stopped':
|
||||||
|
$reasonType = $this->translate('Flapping stopped normally');
|
||||||
|
break;
|
||||||
|
case 'disabled':
|
||||||
|
$reasonType = $this->translate('Flapping was disabled');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$reasonType = $this->translate('N/A');
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
array($this->translate('Event time'), DateFormatter::formatDateTime($event->event_time)),
|
||||||
|
array($this->translate('Reason'), $this->view->escape($reasonType)),
|
||||||
|
array($this->translate('State change'), $this->percent($event->percent_state_change)),
|
||||||
|
array($this->translate('Low threshold'), $this->percent($event->low_threshold)),
|
||||||
|
array($this->translate('High threshold'), $this->percent($event->high_threshold))
|
||||||
|
);
|
||||||
|
case 'notify':
|
||||||
|
switch ($event->notification_reason) {
|
||||||
|
case 'normal_notification':
|
||||||
|
$notificationReason = $this->translate('Normal notification');
|
||||||
|
break;
|
||||||
|
case 'ack':
|
||||||
|
$notificationReason = $this->translate('Problem acknowledgement');
|
||||||
|
break;
|
||||||
|
case 'flapping_started':
|
||||||
|
$notificationReason = $this->translate('Flapping started');
|
||||||
|
break;
|
||||||
|
case 'flapping_stopped':
|
||||||
|
$notificationReason = $this->translate('Flapping stopped');
|
||||||
|
break;
|
||||||
|
case 'flapping_disabled':
|
||||||
|
$notificationReason = $this->translate('Flapping was disabled');
|
||||||
|
break;
|
||||||
|
case 'dt_start':
|
||||||
|
$notificationReason = $this->translate('Downtime started');
|
||||||
|
break;
|
||||||
|
case 'dt_end':
|
||||||
|
$notificationReason = $this->translate('Downtime ended');
|
||||||
|
break;
|
||||||
|
case 'dt_cancel':
|
||||||
|
$notificationReason = $this->translate('Downtime was cancelled');
|
||||||
|
break;
|
||||||
|
case 'custom_notification':
|
||||||
|
$notificationReason = $this->translate('Custom notification');
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$notificationReason = $this->translate('N/A');
|
||||||
|
}
|
||||||
|
|
||||||
|
$details = array(
|
||||||
|
array($this->translate('Start time'), DateFormatter::formatDateTime($event->start_time)),
|
||||||
|
array($this->translate('End time'), DateFormatter::formatDateTime($event->end_time)),
|
||||||
|
array($this->translate('Reason'), $this->view->escape($notificationReason)),
|
||||||
|
array(
|
||||||
|
$this->translate('State'),
|
||||||
|
$this->state($event->service_description !== null, $event->state)
|
||||||
|
),
|
||||||
|
array($this->translate('Escalated'), $this->yesOrNo($event->escalated)),
|
||||||
|
array($this->translate('Contacts notified'), (int) $event->contacts_notified),
|
||||||
|
array(
|
||||||
|
$this->translate('Output'),
|
||||||
|
$this->pluginOutput($event->output) . $this->pluginOutput($event->long_output)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return $details;
|
||||||
|
case 'hard_state':
|
||||||
|
case 'soft_state':
|
||||||
|
$isService = $event->service_description !== null;
|
||||||
|
|
||||||
|
$details = array(
|
||||||
|
array($this->translate('State time'), DateFormatter::formatDateTime($event->state_time)),
|
||||||
|
array($this->translate('State'), $this->state($isService, $event->state)),
|
||||||
|
array($this->translate('Check source'), $event->check_source),
|
||||||
|
array($this->translate('Check attempt'), $this->view->escape(sprintf(
|
||||||
|
$this->translate('%d of %d'),
|
||||||
|
(int) $event->current_check_attempt,
|
||||||
|
(int) $event->max_check_attempts
|
||||||
|
))),
|
||||||
|
array($this->translate('Last state'), $this->state($isService, $event->last_state)),
|
||||||
|
array($this->translate('Last hard state'), $this->state($isService, $event->last_hard_state)),
|
||||||
|
array(
|
||||||
|
$this->translate('Output'),
|
||||||
|
$this->pluginOutput($event->output) . $this->pluginOutput($event->long_output)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return $details;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
197
modules/monitoring/application/controllers/HealthController.php
Normal file
197
modules/monitoring/application/controllers/HealthController.php
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2013 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Controllers;
|
||||||
|
|
||||||
|
use Icinga\Module\Monitoring\Controller;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Instance\DisableNotificationsExpireCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Instance\ToggleInstanceFeaturesCommandForm;
|
||||||
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display process and performance information of the monitoring host and program-wide commands
|
||||||
|
*/
|
||||||
|
class HealthController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Add tabs
|
||||||
|
*
|
||||||
|
* @see \Icinga\Web\Controller\ActionController::init()
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this
|
||||||
|
->getTabs()
|
||||||
|
->add(
|
||||||
|
'info',
|
||||||
|
array(
|
||||||
|
'title' => $this->translate(
|
||||||
|
'Show information about the current monitoring instance\'s process'
|
||||||
|
. ' and it\'s performance as well as available features'
|
||||||
|
),
|
||||||
|
'label' => $this->translate('Process Information'),
|
||||||
|
'url' =>'monitoring/health/info'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
->add(
|
||||||
|
'stats',
|
||||||
|
array(
|
||||||
|
'title' => $this->translate(
|
||||||
|
'Show statistics about the monitored objects'
|
||||||
|
),
|
||||||
|
'label' => $this->translate('Stats'),
|
||||||
|
'url' =>'monitoring/health/stats'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
->extend(new DashboardAction())->extend(new MenuAction());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display process information and program-wide commands
|
||||||
|
*/
|
||||||
|
public function infoAction()
|
||||||
|
{
|
||||||
|
$this->view->title = $this->translate('Process Information');
|
||||||
|
$this->getTabs()->activate('info');
|
||||||
|
$this->setAutorefreshInterval(10);
|
||||||
|
$this->view->backendName = $this->backend->getName();
|
||||||
|
$programStatus = $this->backend
|
||||||
|
->select()
|
||||||
|
->from(
|
||||||
|
'programstatus',
|
||||||
|
array(
|
||||||
|
'is_currently_running',
|
||||||
|
'process_id',
|
||||||
|
'endpoint_name',
|
||||||
|
'program_start_time',
|
||||||
|
'status_update_time',
|
||||||
|
'program_version',
|
||||||
|
'last_command_check',
|
||||||
|
'last_log_rotation',
|
||||||
|
'global_service_event_handler',
|
||||||
|
'global_host_event_handler',
|
||||||
|
'notifications_enabled',
|
||||||
|
'disable_notif_expire_time',
|
||||||
|
'active_service_checks_enabled',
|
||||||
|
'passive_service_checks_enabled',
|
||||||
|
'active_host_checks_enabled',
|
||||||
|
'passive_host_checks_enabled',
|
||||||
|
'event_handlers_enabled',
|
||||||
|
'obsess_over_services',
|
||||||
|
'obsess_over_hosts',
|
||||||
|
'flap_detection_enabled',
|
||||||
|
'process_performance_data'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
->getQuery();
|
||||||
|
$this->handleFormatRequest($programStatus);
|
||||||
|
$programStatus = $programStatus->fetchRow();
|
||||||
|
if ($programStatus === false) {
|
||||||
|
$this->render('not-running', true, null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$this->view->programStatus = $programStatus;
|
||||||
|
$toggleFeaturesForm = new ToggleInstanceFeaturesCommandForm();
|
||||||
|
$toggleFeaturesForm
|
||||||
|
->setBackend($this->backend)
|
||||||
|
->setStatus($programStatus)
|
||||||
|
->load($programStatus)
|
||||||
|
->handleRequest();
|
||||||
|
$this->view->toggleFeaturesForm = $toggleFeaturesForm;
|
||||||
|
|
||||||
|
$this->view->runtimevariables = (object) $this->backend->select()
|
||||||
|
->from('runtimevariables', array('varname', 'varvalue'))
|
||||||
|
->getQuery()->fetchPairs();
|
||||||
|
|
||||||
|
$this->view->checkperformance = $this->backend->select()
|
||||||
|
->from('runtimesummary')
|
||||||
|
->getQuery()->fetchAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display stats about current checks and monitored objects
|
||||||
|
*/
|
||||||
|
public function statsAction()
|
||||||
|
{
|
||||||
|
$this->view->title = $this->translate('Stats');
|
||||||
|
$this->getTabs()->activate('stats');
|
||||||
|
|
||||||
|
$servicestats = $this->backend->select()->from('servicestatussummary', array(
|
||||||
|
'services_critical',
|
||||||
|
'services_critical_handled',
|
||||||
|
'services_critical_unhandled',
|
||||||
|
'services_ok',
|
||||||
|
'services_pending',
|
||||||
|
'services_total',
|
||||||
|
'services_unknown',
|
||||||
|
'services_unknown_handled',
|
||||||
|
'services_unknown_unhandled',
|
||||||
|
'services_warning',
|
||||||
|
'services_warning_handled',
|
||||||
|
'services_warning_unhandled'
|
||||||
|
));
|
||||||
|
$this->applyRestriction('monitoring/filter/objects', $servicestats);
|
||||||
|
$this->view->servicestats = $servicestats->fetchRow();
|
||||||
|
$this->view->unhandledServiceProblems = $this->view->servicestats->services_critical_unhandled
|
||||||
|
+ $this->view->servicestats->services_unknown_unhandled
|
||||||
|
+ $this->view->servicestats->services_warning_unhandled;
|
||||||
|
|
||||||
|
$hoststats = $this->backend->select()->from('hoststatussummary', array(
|
||||||
|
'hosts_total',
|
||||||
|
'hosts_up',
|
||||||
|
'hosts_down',
|
||||||
|
'hosts_down_handled',
|
||||||
|
'hosts_down_unhandled',
|
||||||
|
'hosts_unreachable',
|
||||||
|
'hosts_unreachable_handled',
|
||||||
|
'hosts_unreachable_unhandled',
|
||||||
|
'hosts_pending',
|
||||||
|
));
|
||||||
|
$this->applyRestriction('monitoring/filter/objects', $hoststats);
|
||||||
|
$this->view->hoststats = $hoststats->fetchRow();
|
||||||
|
$this->view->unhandledhostProblems = $this->view->hoststats->hosts_down_unhandled
|
||||||
|
+ $this->view->hoststats->hosts_unreachable_unhandled;
|
||||||
|
|
||||||
|
$this->view->unhandledProblems = $this->view->unhandledhostProblems
|
||||||
|
+ $this->view->unhandledServiceProblems;
|
||||||
|
|
||||||
|
$this->view->runtimevariables = (object) $this->backend->select()
|
||||||
|
->from('runtimevariables', array('varname', 'varvalue'))
|
||||||
|
->getQuery()->fetchPairs();
|
||||||
|
|
||||||
|
$this->view->checkperformance = $this->backend->select()
|
||||||
|
->from('runtimesummary')
|
||||||
|
->getQuery()->fetchAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Disable notifications w/ an optional expire time
|
||||||
|
*/
|
||||||
|
public function disableNotificationsAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/feature/instance');
|
||||||
|
$this->view->title = $this->translate('Disable Notifications');
|
||||||
|
$programStatus = $this->backend
|
||||||
|
->select()
|
||||||
|
->from(
|
||||||
|
'programstatus',
|
||||||
|
array(
|
||||||
|
'notifications_enabled',
|
||||||
|
'disable_notif_expire_time'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
->getQuery()
|
||||||
|
->fetchRow();
|
||||||
|
$this->view->programStatus = $programStatus;
|
||||||
|
if ((bool) $programStatus->notifications_enabled === false) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
$form = new DisableNotificationsExpireCommandForm();
|
||||||
|
$form
|
||||||
|
->setRedirectUrl('monitoring/health/info')
|
||||||
|
->handleRequest();
|
||||||
|
$this->view->form = $form;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
185
modules/monitoring/application/controllers/HostController.php
Normal file
185
modules/monitoring/application/controllers/HostController.php
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Controllers;
|
||||||
|
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\AcknowledgeProblemCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\AddCommentCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\ProcessCheckResultCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleHostCheckCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleHostDowntimeCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\SendCustomNotificationCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Object\Host;
|
||||||
|
use Icinga\Module\Monitoring\Web\Controller\MonitoredObjectController;
|
||||||
|
use Icinga\Web\Hook;
|
||||||
|
use Icinga\Web\Navigation\Navigation;
|
||||||
|
|
||||||
|
class HostController extends MonitoredObjectController
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected $commandRedirectUrl = 'monitoring/host/show';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the requested host from the monitoring backend
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$host = new Host($this->backend, $this->params->getRequired('host'));
|
||||||
|
$this->applyRestriction('monitoring/filter/objects', $host);
|
||||||
|
if ($host->fetch() === false) {
|
||||||
|
$this->httpNotFound($this->translate('Host not found'));
|
||||||
|
}
|
||||||
|
$this->object = $host;
|
||||||
|
$this->createTabs();
|
||||||
|
$this->getTabs()->activate('host');
|
||||||
|
$this->view->title = $host->host_display_name;
|
||||||
|
$this->view->defaultTitle = $this->translate('Hosts') . ' :: ' . $this->view->defaultTitle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get host actions from hook
|
||||||
|
*
|
||||||
|
* @return Navigation
|
||||||
|
*/
|
||||||
|
protected function getHostActions()
|
||||||
|
{
|
||||||
|
$navigation = new Navigation();
|
||||||
|
foreach (Hook::all('Monitoring\\HostActions') as $hook) {
|
||||||
|
$navigation->merge($hook->getNavigation($this->object));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $navigation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a host
|
||||||
|
*/
|
||||||
|
public function showAction()
|
||||||
|
{
|
||||||
|
$this->view->actions = $this->getHostActions();
|
||||||
|
parent::showAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List a host's services
|
||||||
|
*/
|
||||||
|
public function servicesAction()
|
||||||
|
{
|
||||||
|
$this->setAutorefreshInterval(10);
|
||||||
|
$this->getTabs()->activate('services');
|
||||||
|
$query = $this->backend->select()->from('servicestatus', array(
|
||||||
|
'host_name',
|
||||||
|
'host_display_name',
|
||||||
|
'host_state',
|
||||||
|
'host_state_type',
|
||||||
|
'host_last_state_change',
|
||||||
|
'host_address',
|
||||||
|
'host_address6',
|
||||||
|
'host_handled',
|
||||||
|
'service_description',
|
||||||
|
'service_display_name',
|
||||||
|
'service_state',
|
||||||
|
'service_in_downtime',
|
||||||
|
'service_acknowledged',
|
||||||
|
'service_handled',
|
||||||
|
'service_output',
|
||||||
|
'service_perfdata',
|
||||||
|
'service_attempt',
|
||||||
|
'service_last_state_change',
|
||||||
|
'service_icon_image',
|
||||||
|
'service_icon_image_alt',
|
||||||
|
'service_is_flapping',
|
||||||
|
'service_state_type',
|
||||||
|
'service_handled',
|
||||||
|
'service_severity',
|
||||||
|
'service_last_check',
|
||||||
|
'service_notifications_enabled',
|
||||||
|
'service_action_url',
|
||||||
|
'service_notes_url',
|
||||||
|
'service_active_checks_enabled',
|
||||||
|
'service_passive_checks_enabled',
|
||||||
|
'current_check_attempt' => 'service_current_check_attempt',
|
||||||
|
'max_check_attempts' => 'service_max_check_attempts',
|
||||||
|
'service_check_command',
|
||||||
|
'service_next_update'
|
||||||
|
));
|
||||||
|
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||||
|
$this->view->services = $query->where('host_name', $this->object->getName());
|
||||||
|
$this->view->object = $this->object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acknowledge a host problem
|
||||||
|
*/
|
||||||
|
public function acknowledgeProblemAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/acknowledge-problem');
|
||||||
|
|
||||||
|
$form = new AcknowledgeProblemCommandForm();
|
||||||
|
$form->setTitle($this->translate('Acknowledge Host Problem'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a host comment
|
||||||
|
*/
|
||||||
|
public function addCommentAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/comment/add');
|
||||||
|
|
||||||
|
$form = new AddCommentCommandForm();
|
||||||
|
$form->setTitle($this->translate('Add Host Comment'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reschedule a host check
|
||||||
|
*/
|
||||||
|
public function rescheduleCheckAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/schedule-check');
|
||||||
|
|
||||||
|
$form = new ScheduleHostCheckCommandForm();
|
||||||
|
$form->setTitle($this->translate('Reschedule Host Check'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule a host downtime
|
||||||
|
*/
|
||||||
|
public function scheduleDowntimeAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/downtime/schedule');
|
||||||
|
|
||||||
|
$form = new ScheduleHostDowntimeCommandForm();
|
||||||
|
$form->setTitle($this->translate('Schedule Host Downtime'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit a passive host check result
|
||||||
|
*/
|
||||||
|
public function processCheckResultAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/process-check-result');
|
||||||
|
|
||||||
|
$form = new ProcessCheckResultCommandForm();
|
||||||
|
$form->setTitle($this->translate('Submit Passive Host Check Result'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a custom notification for host
|
||||||
|
*/
|
||||||
|
public function sendCustomNotificationAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/send-custom-notification');
|
||||||
|
|
||||||
|
$form = new SendCustomNotificationCommandForm();
|
||||||
|
$form->setTitle($this->translate('Send Custom Host Notification'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
}
|
||||||
260
modules/monitoring/application/controllers/HostsController.php
Normal file
260
modules/monitoring/application/controllers/HostsController.php
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Controllers;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Icinga\Data\Filter\Filter;
|
||||||
|
use Icinga\Data\Filter\FilterEqual;
|
||||||
|
use Icinga\Module\Monitoring\Controller;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\AcknowledgeProblemCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\AddCommentCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\CheckNowCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\ObjectsCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\ProcessCheckResultCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\RemoveAcknowledgementCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleHostCheckCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleHostDowntimeCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\SendCustomNotificationCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\ToggleObjectFeaturesCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Hook\DetailviewExtensionHook;
|
||||||
|
use Icinga\Module\Monitoring\Object\HostList;
|
||||||
|
use Icinga\Web\Hook;
|
||||||
|
use Icinga\Web\Url;
|
||||||
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
|
|
||||||
|
class HostsController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var HostList
|
||||||
|
*/
|
||||||
|
protected $hostList;
|
||||||
|
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$hostList = new HostList($this->backend);
|
||||||
|
$this->applyRestriction('monitoring/filter/objects', $hostList);
|
||||||
|
$hostList->addFilter(Filter::fromQueryString((string) $this->params));
|
||||||
|
$this->hostList = $hostList;
|
||||||
|
$this->hostList->setColumns(array(
|
||||||
|
'host_acknowledged',
|
||||||
|
'host_active_checks_enabled',
|
||||||
|
'host_display_name',
|
||||||
|
'host_event_handler_enabled',
|
||||||
|
'host_flap_detection_enabled',
|
||||||
|
'host_handled',
|
||||||
|
'host_in_downtime',
|
||||||
|
'host_is_flapping',
|
||||||
|
'host_last_state_change',
|
||||||
|
'host_name',
|
||||||
|
'host_notifications_enabled',
|
||||||
|
'host_obsessing',
|
||||||
|
'host_passive_checks_enabled',
|
||||||
|
'host_problem',
|
||||||
|
'host_state',
|
||||||
|
'instance_name'
|
||||||
|
));
|
||||||
|
$this->view->baseFilter = $this->hostList->getFilter();
|
||||||
|
$this->getTabs()->add(
|
||||||
|
'show',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Hosts') . sprintf(' (%d)', count($this->hostList)),
|
||||||
|
'title' => sprintf(
|
||||||
|
$this->translate('Show summarized information for %u hosts'),
|
||||||
|
count($this->hostList)
|
||||||
|
),
|
||||||
|
'url' => Url::fromRequest()
|
||||||
|
)
|
||||||
|
)->extend(new DashboardAction())->extend(new MenuAction())->activate('show');
|
||||||
|
$this->view->listAllLink = Url::fromRequest()->setPath('monitoring/list/hosts');
|
||||||
|
$this->view->title = $this->translate('Hosts');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleCommandForm(ObjectsCommandForm $form)
|
||||||
|
{
|
||||||
|
$form
|
||||||
|
->setBackend($this->backend)
|
||||||
|
->setObjects($this->hostList)
|
||||||
|
->setRedirectUrl(Url::fromPath('monitoring/hosts/show')->setParams(
|
||||||
|
$this->params->without('host_active_checks_enabled')
|
||||||
|
))
|
||||||
|
->handleRequest();
|
||||||
|
|
||||||
|
$this->view->form = $form;
|
||||||
|
$this->view->objects = $this->hostList;
|
||||||
|
$this->view->stats = $this->hostList->getStateSummary();
|
||||||
|
$this->_helper->viewRenderer('partials/command/objects-command-form', null, true);
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showAction()
|
||||||
|
{
|
||||||
|
$this->setAutorefreshInterval(15);
|
||||||
|
$activeChecksEnabled = $this->hostList->getFeatureStatus()['active_checks_enabled'] !== 0;
|
||||||
|
if ($this->Auth()->hasPermission('monitoring/command/schedule-check')
|
||||||
|
|| ($this->Auth()->hasPermission('monitoring/command/schedule-check/active-only')
|
||||||
|
&& $activeChecksEnabled
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
$checkNowForm = new CheckNowCommandForm();
|
||||||
|
$checkNowForm
|
||||||
|
->setObjects($this->hostList)
|
||||||
|
->handleRequest();
|
||||||
|
$this->view->checkNowForm = $checkNowForm;
|
||||||
|
}
|
||||||
|
|
||||||
|
$acknowledgedObjects = $this->hostList->getAcknowledgedObjects();
|
||||||
|
if ($acknowledgedObjects->count()) {
|
||||||
|
$removeAckForm = new RemoveAcknowledgementCommandForm();
|
||||||
|
$removeAckForm
|
||||||
|
->setObjects($acknowledgedObjects)
|
||||||
|
->handleRequest();
|
||||||
|
$this->view->removeAckForm = $removeAckForm;
|
||||||
|
}
|
||||||
|
|
||||||
|
$featureStatus = $this->hostList->getFeatureStatus();
|
||||||
|
$toggleFeaturesForm = new ToggleObjectFeaturesCommandForm(array(
|
||||||
|
'backend' => $this->backend,
|
||||||
|
'objects' => $this->hostList
|
||||||
|
));
|
||||||
|
$toggleFeaturesForm
|
||||||
|
->load((object) $featureStatus)
|
||||||
|
->handleRequest();
|
||||||
|
$this->view->toggleFeaturesForm = $toggleFeaturesForm;
|
||||||
|
|
||||||
|
$hostStates = $this->hostList->getStateSummary();
|
||||||
|
|
||||||
|
if ($activeChecksEnabled) {
|
||||||
|
$this->view->rescheduleAllLink = Url::fromRequest()
|
||||||
|
->setPath('monitoring/hosts/reschedule-check')
|
||||||
|
->addParams(['host_active_checks_enabled' => true]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->view->downtimeAllLink = Url::fromRequest()->setPath('monitoring/hosts/schedule-downtime');
|
||||||
|
$this->view->processCheckResultAllLink = Url::fromRequest()->setPath('monitoring/hosts/process-check-result');
|
||||||
|
$this->view->addCommentLink = Url::fromRequest()->setPath('monitoring/hosts/add-comment');
|
||||||
|
$this->view->stats = $hostStates;
|
||||||
|
$this->view->objects = $this->hostList;
|
||||||
|
$this->view->unhandledObjects = $this->hostList->getUnhandledObjects();
|
||||||
|
$this->view->problemObjects = $this->hostList->getProblemObjects();
|
||||||
|
$this->view->acknowledgeUnhandledLink = Url::fromPath('monitoring/hosts/acknowledge-problem')
|
||||||
|
->setQueryString($this->hostList->getUnhandledObjects()->objectsFilter()->toQueryString());
|
||||||
|
$this->view->downtimeUnhandledLink = Url::fromPath('monitoring/hosts/schedule-downtime')
|
||||||
|
->setQueryString($this->hostList->getUnhandledObjects()->objectsFilter()->toQueryString());
|
||||||
|
$this->view->downtimeLink = Url::fromPath('monitoring/hosts/schedule-downtime')
|
||||||
|
->setQueryString($this->hostList->getProblemObjects()->objectsFilter()->toQueryString());
|
||||||
|
$this->view->acknowledgedObjects = $this->hostList->getAcknowledgedObjects();
|
||||||
|
$this->view->acknowledgeLink = Url::fromPath('monitoring/hosts/acknowledge-problem')
|
||||||
|
->setQueryString($this->hostList->getUnacknowledgedObjects()->objectsFilter()->toQueryString());
|
||||||
|
$this->view->unacknowledgedObjects = $this->hostList->getUnacknowledgedObjects();
|
||||||
|
$this->view->objectsInDowntime = $this->hostList->getObjectsInDowntime();
|
||||||
|
$this->view->inDowntimeLink = Url::fromPath('monitoring/list/hosts')
|
||||||
|
->setQueryString(
|
||||||
|
$this->hostList
|
||||||
|
->getObjectsInDowntime()
|
||||||
|
->objectsFilter()
|
||||||
|
->toQueryString()
|
||||||
|
);
|
||||||
|
$this->view->showDowntimesLink = Url::fromPath('monitoring/list/downtimes')
|
||||||
|
->setQueryString(
|
||||||
|
$this->hostList
|
||||||
|
->objectsFilter()
|
||||||
|
->andFilter(FilterEqual::where('object_type', 'host'))
|
||||||
|
->toQueryString()
|
||||||
|
);
|
||||||
|
$this->view->commentsLink = Url::fromRequest()->setPath('monitoring/list/comments');
|
||||||
|
$this->view->sendCustomNotificationLink = Url::fromRequest()
|
||||||
|
->setPath('monitoring/hosts/send-custom-notification');
|
||||||
|
|
||||||
|
$this->view->extensionsHtml = array();
|
||||||
|
foreach (Hook::all('Monitoring\DetailviewExtension') as $hook) {
|
||||||
|
/** @var DetailviewExtensionHook $hook */
|
||||||
|
try {
|
||||||
|
$html = $hook->setView($this->view)->getHtmlForObjects($this->hostList);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$html = $this->view->escape($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($html) {
|
||||||
|
$module = $this->view->escape($hook->getModule()->getName());
|
||||||
|
$this->view->extensionsHtml[] =
|
||||||
|
'<div class="icinga-module module-' . $module . '" data-icinga-module="' . $module . '">'
|
||||||
|
. $html
|
||||||
|
. '</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a host comments
|
||||||
|
*/
|
||||||
|
public function addCommentAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/comment/add');
|
||||||
|
|
||||||
|
$form = new AddCommentCommandForm();
|
||||||
|
$form->setTitle($this->translate('Add Host Comments'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acknowledge host problems
|
||||||
|
*/
|
||||||
|
public function acknowledgeProblemAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/acknowledge-problem');
|
||||||
|
|
||||||
|
$form = new AcknowledgeProblemCommandForm();
|
||||||
|
$form->setTitle($this->translate('Acknowledge Host Problems'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reschedule host checks
|
||||||
|
*/
|
||||||
|
public function rescheduleCheckAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/schedule-check');
|
||||||
|
|
||||||
|
$form = new ScheduleHostCheckCommandForm();
|
||||||
|
$form->setTitle($this->translate('Reschedule Host Checks'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule host downtimes
|
||||||
|
*/
|
||||||
|
public function scheduleDowntimeAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/downtime/schedule');
|
||||||
|
|
||||||
|
$form = new ScheduleHostDowntimeCommandForm();
|
||||||
|
$form->setTitle($this->translate('Schedule Host Downtimes'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit passive host check results
|
||||||
|
*/
|
||||||
|
public function processCheckResultAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/process-check-result');
|
||||||
|
|
||||||
|
$form = new ProcessCheckResultCommandForm();
|
||||||
|
$form->setTitle($this->translate('Submit Passive Host Check Results'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a custom notification for hosts
|
||||||
|
*/
|
||||||
|
public function sendCustomNotificationAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/send-custom-notification');
|
||||||
|
|
||||||
|
$form = new SendCustomNotificationCommandForm();
|
||||||
|
$form->setTitle($this->translate('Send Custom Host Notification'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
}
|
||||||
808
modules/monitoring/application/controllers/ListController.php
Normal file
808
modules/monitoring/application/controllers/ListController.php
Normal file
@ -0,0 +1,808 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2013 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Controllers;
|
||||||
|
|
||||||
|
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||||
|
use Icinga\Security\SecurityException;
|
||||||
|
use Icinga\Util\GlobFilter;
|
||||||
|
use Icinga\Web\Form;
|
||||||
|
use Zend_Form;
|
||||||
|
use Icinga\Data\Filter\Filter;
|
||||||
|
use Icinga\Module\Monitoring\Controller;
|
||||||
|
use Icinga\Module\Monitoring\DataView\DataView;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\DeleteCommentCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\DeleteDowntimeCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\StatehistoryForm;
|
||||||
|
use Icinga\Web\Url;
|
||||||
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\OutputFormat;
|
||||||
|
use Icinga\Web\Widget\Tabs;
|
||||||
|
|
||||||
|
class ListController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @see ActionController::init
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
parent::init();
|
||||||
|
$this->createTabs();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Overwrite the backend to use (used for testing)
|
||||||
|
*
|
||||||
|
* @param MonitoringBackend $backend The Backend that should be used for querying
|
||||||
|
*/
|
||||||
|
public function setBackend($backend)
|
||||||
|
{
|
||||||
|
$this->backend = $backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List hosts
|
||||||
|
*/
|
||||||
|
public function hostsAction()
|
||||||
|
{
|
||||||
|
$this->addTitleTab(
|
||||||
|
'hosts',
|
||||||
|
$this->translate('Hosts'),
|
||||||
|
$this->translate('List hosts')
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->setAutorefreshInterval(10);
|
||||||
|
|
||||||
|
// Handle soft and hard states
|
||||||
|
if (strtolower($this->params->shift('stateType', 'soft')) === 'hard') {
|
||||||
|
$stateColumn = 'host_hard_state';
|
||||||
|
$stateChangeColumn = 'host_last_hard_state_change';
|
||||||
|
} else {
|
||||||
|
$stateColumn = 'host_state';
|
||||||
|
$stateChangeColumn = 'host_last_state_change';
|
||||||
|
}
|
||||||
|
|
||||||
|
$hosts = $this->backend->select()->from('hoststatus', array_merge(array(
|
||||||
|
'host_icon_image',
|
||||||
|
'host_icon_image_alt',
|
||||||
|
'host_name',
|
||||||
|
'host_display_name',
|
||||||
|
'host_state' => $stateColumn,
|
||||||
|
'host_acknowledged',
|
||||||
|
'host_output',
|
||||||
|
'host_attempt',
|
||||||
|
'host_in_downtime',
|
||||||
|
'host_is_flapping',
|
||||||
|
'host_state_type',
|
||||||
|
'host_handled',
|
||||||
|
'host_last_state_change' => $stateChangeColumn,
|
||||||
|
'host_notifications_enabled',
|
||||||
|
'host_active_checks_enabled',
|
||||||
|
'host_passive_checks_enabled',
|
||||||
|
'host_check_command',
|
||||||
|
'host_next_update'
|
||||||
|
), $this->addColumns()));
|
||||||
|
|
||||||
|
$this->setupPaginationControl($hosts);
|
||||||
|
$this->setupSortControl(array(
|
||||||
|
'host_severity' => $this->translate('Severity'),
|
||||||
|
'host_state' => $this->translate('Current State'),
|
||||||
|
'host_display_name' => $this->translate('Hostname'),
|
||||||
|
'host_address' => $this->translate('Address'),
|
||||||
|
'host_last_check' => $this->translate('Last Check'),
|
||||||
|
'host_last_state_change' => $this->translate('Last State Change')
|
||||||
|
), $hosts);
|
||||||
|
$this->filterQuery($hosts);
|
||||||
|
$this->setupLimitControl();
|
||||||
|
|
||||||
|
$stats = $this->backend->select()->from('hoststatussummary', array(
|
||||||
|
'hosts_total',
|
||||||
|
'hosts_up',
|
||||||
|
'hosts_down',
|
||||||
|
'hosts_down_handled',
|
||||||
|
'hosts_down_unhandled',
|
||||||
|
'hosts_unreachable',
|
||||||
|
'hosts_unreachable_handled',
|
||||||
|
'hosts_unreachable_unhandled',
|
||||||
|
'hosts_pending',
|
||||||
|
));
|
||||||
|
$this->applyRestriction('monitoring/filter/objects', $stats);
|
||||||
|
|
||||||
|
$this->view->hosts = $hosts;
|
||||||
|
$this->view->stats = $stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List services
|
||||||
|
*/
|
||||||
|
public function servicesAction()
|
||||||
|
{
|
||||||
|
$this->addTitleTab(
|
||||||
|
'services',
|
||||||
|
$this->translate('Services'),
|
||||||
|
$this->translate('List services')
|
||||||
|
);
|
||||||
|
|
||||||
|
// Handle soft and hard states
|
||||||
|
if (strtolower($this->params->shift('stateType', 'soft')) === 'hard') {
|
||||||
|
$stateColumn = 'service_hard_state';
|
||||||
|
$stateChangeColumn = 'service_last_hard_state_change';
|
||||||
|
} else {
|
||||||
|
$stateColumn = 'service_state';
|
||||||
|
$stateChangeColumn = 'service_last_state_change';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setAutorefreshInterval(10);
|
||||||
|
|
||||||
|
$services = $this->backend->select()->from('servicestatus', array_merge(array(
|
||||||
|
'host_name',
|
||||||
|
'host_display_name',
|
||||||
|
'host_state',
|
||||||
|
'service_description',
|
||||||
|
'service_display_name',
|
||||||
|
'service_state' => $stateColumn,
|
||||||
|
'service_in_downtime',
|
||||||
|
'service_acknowledged',
|
||||||
|
'service_handled',
|
||||||
|
'service_output',
|
||||||
|
'service_perfdata',
|
||||||
|
'service_attempt',
|
||||||
|
'service_last_state_change' => $stateChangeColumn,
|
||||||
|
'service_icon_image',
|
||||||
|
'service_icon_image_alt',
|
||||||
|
'service_is_flapping',
|
||||||
|
'service_state_type',
|
||||||
|
'service_handled',
|
||||||
|
'service_severity',
|
||||||
|
'service_notifications_enabled',
|
||||||
|
'service_active_checks_enabled',
|
||||||
|
'service_passive_checks_enabled',
|
||||||
|
'service_check_command',
|
||||||
|
'service_next_update'
|
||||||
|
), $this->addColumns()));
|
||||||
|
|
||||||
|
$this->setupPaginationControl($services);
|
||||||
|
$this->setupSortControl(array(
|
||||||
|
'service_severity' => $this->translate('Service Severity'),
|
||||||
|
'service_state' => $this->translate('Current Service State'),
|
||||||
|
'service_display_name' => $this->translate('Service Name'),
|
||||||
|
'service_last_check' => $this->translate('Last Service Check'),
|
||||||
|
'service_last_state_change' => $this->translate('Last State Change'),
|
||||||
|
'host_severity' => $this->translate('Host Severity'),
|
||||||
|
'host_state' => $this->translate('Current Host State'),
|
||||||
|
'host_display_name' => $this->translate('Hostname'),
|
||||||
|
'host_address' => $this->translate('Host Address'),
|
||||||
|
'host_last_check' => $this->translate('Last Host Check')
|
||||||
|
), $services);
|
||||||
|
$this->filterQuery($services);
|
||||||
|
$this->setupLimitControl();
|
||||||
|
|
||||||
|
$stats = $this->backend->select()->from('servicestatussummary', array(
|
||||||
|
'services_critical',
|
||||||
|
'services_critical_handled',
|
||||||
|
'services_critical_unhandled',
|
||||||
|
'services_ok',
|
||||||
|
'services_pending',
|
||||||
|
'services_total',
|
||||||
|
'services_unknown',
|
||||||
|
'services_unknown_handled',
|
||||||
|
'services_unknown_unhandled',
|
||||||
|
'services_warning',
|
||||||
|
'services_warning_handled',
|
||||||
|
'services_warning_unhandled'
|
||||||
|
));
|
||||||
|
$this->applyRestriction('monitoring/filter/objects', $stats);
|
||||||
|
|
||||||
|
$this->view->services = $services;
|
||||||
|
$this->view->stats = $stats;
|
||||||
|
if (strpos($this->params->get('host_name', '*'), '*') === false) {
|
||||||
|
$this->view->showHost = false;
|
||||||
|
} else {
|
||||||
|
$this->view->showHost = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List downtimes
|
||||||
|
*/
|
||||||
|
public function downtimesAction()
|
||||||
|
{
|
||||||
|
$this->addTitleTab(
|
||||||
|
'downtimes',
|
||||||
|
$this->translate('Downtimes'),
|
||||||
|
$this->translate('List downtimes')
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->setAutorefreshInterval(12);
|
||||||
|
|
||||||
|
$downtimes = $this->backend->select()->from('downtime', array(
|
||||||
|
'id' => 'downtime_internal_id',
|
||||||
|
'objecttype' => 'object_type',
|
||||||
|
'comment' => 'downtime_comment',
|
||||||
|
'author_name' => 'downtime_author_name',
|
||||||
|
'start' => 'downtime_start',
|
||||||
|
'scheduled_start' => 'downtime_scheduled_start',
|
||||||
|
'scheduled_end' => 'downtime_scheduled_end',
|
||||||
|
'end' => 'downtime_end',
|
||||||
|
'duration' => 'downtime_duration',
|
||||||
|
'is_flexible' => 'downtime_is_flexible',
|
||||||
|
'is_fixed' => 'downtime_is_fixed',
|
||||||
|
'is_in_effect' => 'downtime_is_in_effect',
|
||||||
|
'entry_time' => 'downtime_entry_time',
|
||||||
|
'name' => 'downtime_name',
|
||||||
|
'host_state',
|
||||||
|
'service_state',
|
||||||
|
'host_name',
|
||||||
|
'service_description',
|
||||||
|
'host_display_name',
|
||||||
|
'service_display_name'
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->setupPaginationControl($downtimes);
|
||||||
|
$this->setupSortControl(array(
|
||||||
|
'downtime_is_in_effect' => $this->translate('Is In Effect'),
|
||||||
|
'host_display_name' => $this->translate('Host'),
|
||||||
|
'service_display_name' => $this->translate('Service'),
|
||||||
|
'downtime_entry_time' => $this->translate('Entry Time'),
|
||||||
|
'downtime_author' => $this->translate('Author'),
|
||||||
|
'downtime_start' => $this->translate('Start Time'),
|
||||||
|
'downtime_end' => $this->translate('End Time'),
|
||||||
|
'downtime_scheduled_start' => $this->translate('Scheduled Start'),
|
||||||
|
'downtime_scheduled_end' => $this->translate('Scheduled End'),
|
||||||
|
'downtime_duration' => $this->translate('Duration')
|
||||||
|
), $downtimes);
|
||||||
|
$this->filterQuery($downtimes);
|
||||||
|
$this->setupLimitControl();
|
||||||
|
|
||||||
|
$this->view->downtimes = $downtimes;
|
||||||
|
|
||||||
|
if ($this->Auth()->hasPermission('monitoring/command/downtime/delete')) {
|
||||||
|
$this->view->delDowntimeForm = new DeleteDowntimeCommandForm();
|
||||||
|
$this->view->delDowntimeForm->handleRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List notifications
|
||||||
|
*/
|
||||||
|
public function notificationsAction()
|
||||||
|
{
|
||||||
|
$this->addTitleTab(
|
||||||
|
'notifications',
|
||||||
|
$this->translate('Notifications'),
|
||||||
|
$this->translate('List notifications')
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->setAutorefreshInterval(15);
|
||||||
|
|
||||||
|
$notifications = $this->backend->select()->from('notification', array(
|
||||||
|
'id',
|
||||||
|
'host_display_name',
|
||||||
|
'host_name',
|
||||||
|
'notification_contact_name',
|
||||||
|
'notification_output',
|
||||||
|
'notification_state',
|
||||||
|
'notification_timestamp',
|
||||||
|
'service_description',
|
||||||
|
'service_display_name'
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->setupPaginationControl($notifications);
|
||||||
|
$this->setupSortControl(array(
|
||||||
|
'notification_timestamp' => $this->translate('Notification Start')
|
||||||
|
), $notifications);
|
||||||
|
$this->filterQuery($notifications);
|
||||||
|
$this->setupLimitControl();
|
||||||
|
|
||||||
|
$this->view->notifications = $notifications;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List contacts
|
||||||
|
*/
|
||||||
|
public function contactsAction()
|
||||||
|
{
|
||||||
|
if (! $this->hasPermission('*') && $this->hasPermission('no-monitoring/contacts')) {
|
||||||
|
throw new SecurityException('No permission for %s', 'monitoring/contacts');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addTitleTab(
|
||||||
|
'contacts',
|
||||||
|
$this->translate('Contacts'),
|
||||||
|
$this->translate('List contacts')
|
||||||
|
);
|
||||||
|
|
||||||
|
$contacts = $this->backend->select()->from('contact', array(
|
||||||
|
'contact_name',
|
||||||
|
'contact_alias',
|
||||||
|
'contact_email',
|
||||||
|
'contact_pager',
|
||||||
|
'contact_notify_service_timeperiod',
|
||||||
|
'contact_notify_host_timeperiod'
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->setupPaginationControl($contacts);
|
||||||
|
$this->setupSortControl(array(
|
||||||
|
'contact_name' => $this->translate('Name'),
|
||||||
|
'contact_alias' => $this->translate('Alias'),
|
||||||
|
'contact_email' => $this->translate('Email'),
|
||||||
|
'contact_pager' => $this->translate('Pager Address / Number')
|
||||||
|
), $contacts);
|
||||||
|
$this->filterQuery($contacts);
|
||||||
|
$this->setupLimitControl();
|
||||||
|
|
||||||
|
$this->view->contacts = $contacts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function eventgridAction()
|
||||||
|
{
|
||||||
|
$this->addTitleTab('eventgrid', $this->translate('Event Grid'), $this->translate('Show the Event Grid'));
|
||||||
|
|
||||||
|
$form = new StatehistoryForm();
|
||||||
|
$form->setEnctype(Zend_Form::ENCTYPE_URLENCODED);
|
||||||
|
$form->setMethod('get');
|
||||||
|
$form->setTokenDisabled();
|
||||||
|
$form->setUidDisabled();
|
||||||
|
$form->render();
|
||||||
|
$this->view->form = $form;
|
||||||
|
|
||||||
|
$this->params
|
||||||
|
->remove('showCompact')
|
||||||
|
->remove('format');
|
||||||
|
$orientation = $this->params->shift('vertical', 0) ? 'vertical' : 'horizontal';
|
||||||
|
/*
|
||||||
|
$orientationBox = new SelectBox(
|
||||||
|
'orientation',
|
||||||
|
array(
|
||||||
|
'0' => mt('monitoring', 'Vertical'),
|
||||||
|
'1' => mt('monitoring', 'Horizontal')
|
||||||
|
),
|
||||||
|
mt('monitoring', 'Orientation'),
|
||||||
|
'horizontal'
|
||||||
|
);
|
||||||
|
$orientationBox->applyRequest($this->getRequest());
|
||||||
|
*/
|
||||||
|
$objectType = $form->getValue('objecttype');
|
||||||
|
$from = $form->getValue('from');
|
||||||
|
$query = $this->backend->select()->from(
|
||||||
|
'eventgrid' . $objectType,
|
||||||
|
array('day', $form->getValue('state'))
|
||||||
|
);
|
||||||
|
$this->params->remove(array('objecttype', 'from', 'to', 'state', 'btn_submit'));
|
||||||
|
$this->view->filter = Filter::fromQueryString((string) $this->params);
|
||||||
|
$query->applyFilter($this->view->filter);
|
||||||
|
$query->applyFilter(Filter::fromQueryString('timestamp>=' . $from));
|
||||||
|
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||||
|
$this->view->summary = $query;
|
||||||
|
$this->view->column = $form->getValue('state');
|
||||||
|
// $this->view->orientationBox = $orientationBox;
|
||||||
|
$this->view->orientation = $orientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List contact groups
|
||||||
|
*/
|
||||||
|
public function contactgroupsAction()
|
||||||
|
{
|
||||||
|
if (! $this->hasPermission('*') && $this->hasPermission('no-monitoring/contacts')) {
|
||||||
|
throw new SecurityException('No permission for %s', 'monitoring/contacts');
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addTitleTab(
|
||||||
|
'contactgroups',
|
||||||
|
$this->translate('Contact Groups'),
|
||||||
|
$this->translate('List contact groups')
|
||||||
|
);
|
||||||
|
|
||||||
|
$contactGroups = $this->backend->select()->from('contactgroup', array(
|
||||||
|
'contactgroup_name',
|
||||||
|
'contactgroup_alias',
|
||||||
|
'contact_count'
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->setupPaginationControl($contactGroups);
|
||||||
|
$this->setupSortControl(array(
|
||||||
|
'contactgroup_name' => $this->translate('Contactgroup Name'),
|
||||||
|
'contactgroup_alias' => $this->translate('Contactgroup Alias')
|
||||||
|
), $contactGroups);
|
||||||
|
$this->filterQuery($contactGroups);
|
||||||
|
$this->setupLimitControl();
|
||||||
|
|
||||||
|
$this->view->contactGroups = $contactGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all comments
|
||||||
|
*/
|
||||||
|
public function commentsAction()
|
||||||
|
{
|
||||||
|
$this->addTitleTab(
|
||||||
|
'comments',
|
||||||
|
$this->translate('Comments'),
|
||||||
|
$this->translate('List comments')
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->setAutorefreshInterval(12);
|
||||||
|
|
||||||
|
$comments = $this->backend->select()->from('comment', array(
|
||||||
|
'id' => 'comment_internal_id',
|
||||||
|
'objecttype' => 'object_type',
|
||||||
|
'comment' => 'comment_data',
|
||||||
|
'author' => 'comment_author_name',
|
||||||
|
'timestamp' => 'comment_timestamp',
|
||||||
|
'type' => 'comment_type',
|
||||||
|
'persistent' => 'comment_is_persistent',
|
||||||
|
'expiration' => 'comment_expiration',
|
||||||
|
'name' => 'comment_name',
|
||||||
|
'host_name',
|
||||||
|
'service_description',
|
||||||
|
'host_display_name',
|
||||||
|
'service_display_name'
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->setupPaginationControl($comments);
|
||||||
|
$this->setupSortControl(
|
||||||
|
array(
|
||||||
|
'comment_timestamp' => $this->translate('Comment Timestamp'),
|
||||||
|
'host_display_name' => $this->translate('Host'),
|
||||||
|
'service_display_name' => $this->translate('Service'),
|
||||||
|
'comment_type' => $this->translate('Comment Type'),
|
||||||
|
'comment_expiration' => $this->translate('Expiration')
|
||||||
|
),
|
||||||
|
$comments
|
||||||
|
);
|
||||||
|
$this->filterQuery($comments);
|
||||||
|
$this->setupLimitControl();
|
||||||
|
|
||||||
|
$this->view->comments = $comments;
|
||||||
|
|
||||||
|
if ($this->Auth()->hasPermission('monitoring/command/comment/delete')) {
|
||||||
|
$this->view->delCommentForm = new DeleteCommentCommandForm();
|
||||||
|
$this->view->delCommentForm->handleRequest();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List service groups
|
||||||
|
*/
|
||||||
|
public function servicegroupsAction()
|
||||||
|
{
|
||||||
|
$this->addTitleTab(
|
||||||
|
'servicegroups',
|
||||||
|
$this->translate('Service Groups'),
|
||||||
|
$this->translate('List service groups')
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->setAutorefreshInterval(12);
|
||||||
|
|
||||||
|
$serviceGroups = $this->backend->select()->from('servicegroupsummary', array(
|
||||||
|
'servicegroup_alias',
|
||||||
|
'servicegroup_name',
|
||||||
|
'services_critical_handled',
|
||||||
|
'services_critical_unhandled',
|
||||||
|
'services_ok',
|
||||||
|
'services_pending',
|
||||||
|
'services_total',
|
||||||
|
'services_unknown_handled',
|
||||||
|
'services_unknown_unhandled',
|
||||||
|
'services_warning_handled',
|
||||||
|
'services_warning_unhandled'
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->setupPaginationControl($serviceGroups);
|
||||||
|
$this->setupSortControl(array(
|
||||||
|
'servicegroup_alias' => $this->translate('Service Group Name'),
|
||||||
|
'services_severity' => $this->translate('Severity'),
|
||||||
|
'services_total' => $this->translate('Total Services')
|
||||||
|
), $serviceGroups);
|
||||||
|
$this->filterQuery($serviceGroups);
|
||||||
|
$this->setupLimitControl();
|
||||||
|
|
||||||
|
$this->view->serviceGroups = $serviceGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List service groups
|
||||||
|
*/
|
||||||
|
public function servicegroupGridAction()
|
||||||
|
{
|
||||||
|
$this->addTitleTab(
|
||||||
|
'servicegroup-grid',
|
||||||
|
$this->translate('Service Group Grid'),
|
||||||
|
$this->translate('Show the Service Group Grid')
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->setAutorefreshInterval(15);
|
||||||
|
|
||||||
|
$serviceGroups = $this->backend->select()->from('servicegroupsummary', array(
|
||||||
|
'servicegroup_alias',
|
||||||
|
'servicegroup_name',
|
||||||
|
'services_critical_handled',
|
||||||
|
'services_critical_unhandled',
|
||||||
|
'services_ok',
|
||||||
|
'services_pending',
|
||||||
|
'services_total',
|
||||||
|
'services_unknown_handled',
|
||||||
|
'services_unknown_unhandled',
|
||||||
|
'services_warning_handled',
|
||||||
|
'services_warning_unhandled'
|
||||||
|
));
|
||||||
|
$this->filterQuery($serviceGroups);
|
||||||
|
|
||||||
|
$this->setupSortControl(array(
|
||||||
|
'servicegroup_alias' => $this->translate('Service Group Name'),
|
||||||
|
'services_severity' => $this->translate('Severity'),
|
||||||
|
'services_total' => $this->translate('Total Services')
|
||||||
|
), $serviceGroups, ['services_severity' => 'desc']);
|
||||||
|
|
||||||
|
$this->view->serviceGroups = $serviceGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List host groups
|
||||||
|
*/
|
||||||
|
public function hostgroupsAction()
|
||||||
|
{
|
||||||
|
$this->addTitleTab(
|
||||||
|
'hostgroups',
|
||||||
|
$this->translate('Host Groups'),
|
||||||
|
$this->translate('List host groups')
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->setAutorefreshInterval(12);
|
||||||
|
|
||||||
|
$hostGroups = $this->backend->select()->from('hostgroupsummary', array(
|
||||||
|
'hostgroup_alias',
|
||||||
|
'hostgroup_name',
|
||||||
|
'hosts_down_handled',
|
||||||
|
'hosts_down_unhandled',
|
||||||
|
'hosts_pending',
|
||||||
|
'hosts_total',
|
||||||
|
'hosts_unreachable_handled',
|
||||||
|
'hosts_unreachable_unhandled',
|
||||||
|
'hosts_up',
|
||||||
|
'services_critical_handled',
|
||||||
|
'services_critical_unhandled',
|
||||||
|
'services_ok',
|
||||||
|
'services_pending',
|
||||||
|
'services_total',
|
||||||
|
'services_unknown_handled',
|
||||||
|
'services_unknown_unhandled',
|
||||||
|
'services_warning_handled',
|
||||||
|
'services_warning_unhandled'
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->setupPaginationControl($hostGroups);
|
||||||
|
$this->setupSortControl(array(
|
||||||
|
'hostgroup_alias' => $this->translate('Host Group Name'),
|
||||||
|
'hosts_severity' => $this->translate('Severity'),
|
||||||
|
'hosts_total' => $this->translate('Total Hosts'),
|
||||||
|
'services_total' => $this->translate('Total Services')
|
||||||
|
), $hostGroups);
|
||||||
|
$this->filterQuery($hostGroups);
|
||||||
|
$this->setupLimitControl();
|
||||||
|
|
||||||
|
$this->view->hostGroups = $hostGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List host groups
|
||||||
|
*/
|
||||||
|
public function hostgroupGridAction()
|
||||||
|
{
|
||||||
|
$this->addTitleTab(
|
||||||
|
'hostgroup-grid',
|
||||||
|
$this->translate('Host Group Grid'),
|
||||||
|
$this->translate('Show the Host Group Grid')
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->setAutorefreshInterval(15);
|
||||||
|
|
||||||
|
$hostGroups = $this->backend->select()->from('hostgroupsummary', [
|
||||||
|
'hostgroup_alias',
|
||||||
|
'hostgroup_name',
|
||||||
|
'hosts_down_handled',
|
||||||
|
'hosts_down_unhandled',
|
||||||
|
'hosts_pending',
|
||||||
|
'hosts_total',
|
||||||
|
'hosts_unreachable_handled',
|
||||||
|
'hosts_unreachable_unhandled',
|
||||||
|
'hosts_up'
|
||||||
|
]);
|
||||||
|
$this->filterQuery($hostGroups);
|
||||||
|
|
||||||
|
$this->setupSortControl([
|
||||||
|
'hosts_severity' => $this->translate('Severity'),
|
||||||
|
'hostgroup_alias' => $this->translate('Host Group Name'),
|
||||||
|
'hosts_total' => $this->translate('Total Hosts'),
|
||||||
|
'services_total' => $this->translate('Total Services')
|
||||||
|
], $hostGroups, ['hosts_severity' => 'desc']);
|
||||||
|
|
||||||
|
$this->view->hostGroups = $hostGroups;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function eventhistoryAction()
|
||||||
|
{
|
||||||
|
$this->addTitleTab(
|
||||||
|
'eventhistory',
|
||||||
|
$this->translate('Event Overview'),
|
||||||
|
$this->translate('List event records')
|
||||||
|
);
|
||||||
|
|
||||||
|
$query = $this->backend->select()->from('eventhistory', array(
|
||||||
|
'id',
|
||||||
|
'host_name',
|
||||||
|
'host_display_name',
|
||||||
|
'service_description',
|
||||||
|
'service_display_name',
|
||||||
|
'object_type',
|
||||||
|
'timestamp',
|
||||||
|
'state',
|
||||||
|
'output',
|
||||||
|
'type'
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->view->history = $query;
|
||||||
|
|
||||||
|
$this->setupSortControl(array(
|
||||||
|
'timestamp' => $this->translate('Occurence')
|
||||||
|
), $query);
|
||||||
|
$this->filterQuery($query);
|
||||||
|
$this->setupLimitControl();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function servicegridAction()
|
||||||
|
{
|
||||||
|
if ($this->params->has('noscript_apply')) {
|
||||||
|
$this->redirectNow($this->getRequest()->getUrl()->without('noscript_apply'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addTitleTab('servicegrid', $this->translate('Service Grid'), $this->translate('Show the Service Grid'));
|
||||||
|
$this->setAutorefreshInterval(15);
|
||||||
|
$query = $this->backend->select()->from('servicestatus', array(
|
||||||
|
'host_display_name',
|
||||||
|
'host_name',
|
||||||
|
'service_description',
|
||||||
|
'service_display_name',
|
||||||
|
'service_handled',
|
||||||
|
'service_output',
|
||||||
|
'service_state'
|
||||||
|
));
|
||||||
|
$this->filterQuery($query);
|
||||||
|
$filter = (bool) $this->params->shift('problems', false) ? Filter::where('service_problem', 1) : null;
|
||||||
|
|
||||||
|
$this->view->problemToggle = $problemToggle = new Form(['method' => 'GET']);
|
||||||
|
$problemToggle->setUidDisabled();
|
||||||
|
$problemToggle->setTokenDisabled();
|
||||||
|
$problemToggle->setAttrib('class', 'filter-toggle inline icinga-controls');
|
||||||
|
$problemToggle->addElement('checkbox', 'problems', [
|
||||||
|
'disableHidden' => true,
|
||||||
|
'autosubmit' => true,
|
||||||
|
'value' => $filter !== null,
|
||||||
|
'label' => $this->translate('Problems Only'),
|
||||||
|
'decorators' => ['ViewHelper', ['Label', ['placement' => 'APPEND']]]
|
||||||
|
]);
|
||||||
|
|
||||||
|
if ($this->params->get('flipped', false)) {
|
||||||
|
$pivot = $query
|
||||||
|
->pivot(
|
||||||
|
'host_name',
|
||||||
|
'service_description',
|
||||||
|
$filter,
|
||||||
|
$filter ? clone $filter : null
|
||||||
|
)
|
||||||
|
->setYAxisHeader('service_display_name')
|
||||||
|
->setXAxisHeader('host_display_name');
|
||||||
|
} else {
|
||||||
|
$pivot = $query
|
||||||
|
->pivot(
|
||||||
|
'service_description',
|
||||||
|
'host_name',
|
||||||
|
$filter,
|
||||||
|
$filter ? clone $filter : null
|
||||||
|
)
|
||||||
|
->setXAxisHeader('service_display_name')
|
||||||
|
->setYAxisHeader('host_display_name');
|
||||||
|
}
|
||||||
|
$this->setupSortControl(array(
|
||||||
|
'host_display_name' => $this->translate('Hostname'),
|
||||||
|
'service_display_name' => $this->translate('Service Name')
|
||||||
|
), $pivot);
|
||||||
|
$this->view->horizontalPaginator = $pivot->paginateXAxis();
|
||||||
|
$this->view->verticalPaginator = $pivot->paginateYAxis();
|
||||||
|
list($pivotData, $pivotHeader) = $pivot->toArray();
|
||||||
|
$this->view->pivotData = $pivotData;
|
||||||
|
$this->view->pivotHeader = $pivotHeader;
|
||||||
|
if ($this->params->get('flipped', false)) {
|
||||||
|
$this->render('servicegrid-flipped');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply filters on a DataView
|
||||||
|
*
|
||||||
|
* @param DataView $dataView The DataView to apply filters on
|
||||||
|
*
|
||||||
|
* @return DataView $dataView
|
||||||
|
*/
|
||||||
|
protected function filterQuery(DataView $dataView)
|
||||||
|
{
|
||||||
|
$this->setupFilterControl($dataView, null, null, array(
|
||||||
|
'format', // handleFormatRequest()
|
||||||
|
'stateType', // hostsAction() and servicesAction()
|
||||||
|
'addColumns', // addColumns()
|
||||||
|
'problems', // servicegridAction()
|
||||||
|
'flipped' // servicegridAction()
|
||||||
|
));
|
||||||
|
|
||||||
|
if ($this->params->get('format') !== 'sql' || $this->hasPermission('config/authentication/roles/show')) {
|
||||||
|
$this->applyRestriction('monitoring/filter/objects', $dataView);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->handleFormatRequest($dataView);
|
||||||
|
|
||||||
|
return $dataView;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get columns to be added from URL parameter 'addColumns'
|
||||||
|
* and assign to $this->view->addColumns (as array)
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function addColumns()
|
||||||
|
{
|
||||||
|
$columns = preg_split(
|
||||||
|
'~,~',
|
||||||
|
$this->params->shift('addColumns', ''),
|
||||||
|
-1,
|
||||||
|
PREG_SPLIT_NO_EMPTY
|
||||||
|
);
|
||||||
|
|
||||||
|
$customVars = [];
|
||||||
|
$additionalCols = [];
|
||||||
|
foreach ($columns as $column) {
|
||||||
|
if (preg_match('~^_(host|service)_([a-zA-Z0-9_]+)$~', $column, $m)) {
|
||||||
|
$customVars[$m[1]]['vars'][$m[2]] = null;
|
||||||
|
} else {
|
||||||
|
$additionalCols[] = $column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! empty($customVars)) {
|
||||||
|
$blacklistedProperties = new GlobFilter(
|
||||||
|
$this->getRestrictions('monitoring/blacklist/properties')
|
||||||
|
);
|
||||||
|
$customVars = $blacklistedProperties->removeMatching($customVars);
|
||||||
|
foreach ($customVars as $type => $vars) {
|
||||||
|
foreach ($vars['vars'] as $var => $_) {
|
||||||
|
$additionalCols[] = '_' . $type . '_' . $var;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->view->addColumns = $additionalCols;
|
||||||
|
return $additionalCols;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function addTitleTab($action, $title, $tip)
|
||||||
|
{
|
||||||
|
$this->getTabs()->add($action, array(
|
||||||
|
'title' => $tip,
|
||||||
|
'label' => $title,
|
||||||
|
'url' => Url::fromRequest()
|
||||||
|
))->activate($action);
|
||||||
|
$this->view->title = $title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return all tabs for this controller
|
||||||
|
*
|
||||||
|
* @return Tabs
|
||||||
|
*/
|
||||||
|
private function createTabs()
|
||||||
|
{
|
||||||
|
return $this->getTabs()->extend(new OutputFormat())->extend(new DashboardAction())->extend(new MenuAction());
|
||||||
|
}
|
||||||
|
}
|
||||||
147
modules/monitoring/application/controllers/ServiceController.php
Normal file
147
modules/monitoring/application/controllers/ServiceController.php
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Controllers;
|
||||||
|
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\AcknowledgeProblemCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\AddCommentCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\ProcessCheckResultCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleServiceCheckCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleServiceDowntimeCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\SendCustomNotificationCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Object\Service;
|
||||||
|
use Icinga\Module\Monitoring\Web\Controller\MonitoredObjectController;
|
||||||
|
use Icinga\Web\Hook;
|
||||||
|
use Icinga\Web\Navigation\Navigation;
|
||||||
|
|
||||||
|
class ServiceController extends MonitoredObjectController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
protected $commandRedirectUrl = 'monitoring/service/show';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the requested service from the monitoring backend
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$service = new Service(
|
||||||
|
$this->backend,
|
||||||
|
$this->params->getRequired('host'),
|
||||||
|
$this->params->getRequired('service')
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->applyRestriction('monitoring/filter/objects', $service);
|
||||||
|
|
||||||
|
if ($service->fetch() === false) {
|
||||||
|
$this->httpNotFound($this->translate('Service not found'));
|
||||||
|
}
|
||||||
|
$this->object = $service;
|
||||||
|
$this->createTabs();
|
||||||
|
$this->getTabs()->activate('service');
|
||||||
|
$this->view->title = $service->service_display_name;
|
||||||
|
$this->view->defaultTitle = join(' :: ', [
|
||||||
|
$service->host_display_name,
|
||||||
|
$this->translate('Services'),
|
||||||
|
$this->view->defaultTitle
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get service actions from hook
|
||||||
|
*
|
||||||
|
* @return Navigation
|
||||||
|
*/
|
||||||
|
protected function getServiceActions()
|
||||||
|
{
|
||||||
|
$navigation = new Navigation();
|
||||||
|
foreach (Hook::all('Monitoring\\ServiceActions') as $hook) {
|
||||||
|
$navigation->merge($hook->getNavigation($this->object));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $navigation;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show a service
|
||||||
|
*/
|
||||||
|
public function showAction()
|
||||||
|
{
|
||||||
|
$this->view->actions = $this->getServiceActions();
|
||||||
|
parent::showAction();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acknowledge a service problem
|
||||||
|
*/
|
||||||
|
public function acknowledgeProblemAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/acknowledge-problem');
|
||||||
|
|
||||||
|
$form = new AcknowledgeProblemCommandForm();
|
||||||
|
$form->setTitle($this->translate('Acknowledge Service Problem'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a service comment
|
||||||
|
*/
|
||||||
|
public function addCommentAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/comment/add');
|
||||||
|
|
||||||
|
$form = new AddCommentCommandForm();
|
||||||
|
$form->setTitle($this->translate('Add Service Comment'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reschedule a service check
|
||||||
|
*/
|
||||||
|
public function rescheduleCheckAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/schedule-check');
|
||||||
|
|
||||||
|
$form = new ScheduleServiceCheckCommandForm();
|
||||||
|
$form->setTitle($this->translate('Reschedule Service Check'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule a service downtime
|
||||||
|
*/
|
||||||
|
public function scheduleDowntimeAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/downtime/schedule');
|
||||||
|
|
||||||
|
$form = new ScheduleServiceDowntimeCommandForm();
|
||||||
|
$form->setTitle($this->translate('Schedule Service Downtime'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit a passive service check result
|
||||||
|
*/
|
||||||
|
public function processCheckResultAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/process-check-result');
|
||||||
|
|
||||||
|
$form = new ProcessCheckResultCommandForm();
|
||||||
|
$form->setTitle($this->translate('Submit Passive Service Check Result'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a custom notification for a service
|
||||||
|
*/
|
||||||
|
public function sendCustomNotificationAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/send-custom-notification');
|
||||||
|
|
||||||
|
$form = new SendCustomNotificationCommandForm();
|
||||||
|
$form->setTitle($this->translate('Send Custom Service Notification'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,262 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Controllers;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Icinga\Data\Filter\Filter;
|
||||||
|
use Icinga\Module\Monitoring\Controller;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\AcknowledgeProblemCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\AddCommentCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\CheckNowCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\ObjectsCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\ProcessCheckResultCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\RemoveAcknowledgementCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleServiceCheckCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\ScheduleServiceDowntimeCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\SendCustomNotificationCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\Object\ToggleObjectFeaturesCommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Hook\DetailviewExtensionHook;
|
||||||
|
use Icinga\Module\Monitoring\Object\ServiceList;
|
||||||
|
use Icinga\Web\Hook;
|
||||||
|
use Icinga\Web\Url;
|
||||||
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
|
|
||||||
|
class ServicesController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var ServiceList
|
||||||
|
*/
|
||||||
|
protected $serviceList;
|
||||||
|
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$serviceList = new ServiceList($this->backend);
|
||||||
|
$this->applyRestriction('monitoring/filter/objects', $serviceList);
|
||||||
|
$serviceList->addFilter(Filter::fromQueryString(
|
||||||
|
(string) $this->params->without(array('service_problem', 'service_handled', 'showCompact'))
|
||||||
|
));
|
||||||
|
$this->serviceList = $serviceList;
|
||||||
|
$this->serviceList->setColumns(array(
|
||||||
|
'host_display_name',
|
||||||
|
'host_handled',
|
||||||
|
'host_name',
|
||||||
|
'host_problem',
|
||||||
|
'host_state',
|
||||||
|
'instance_name',
|
||||||
|
'service_acknowledged',
|
||||||
|
'service_active_checks_enabled',
|
||||||
|
'service_description',
|
||||||
|
'service_display_name',
|
||||||
|
'service_event_handler_enabled',
|
||||||
|
'service_flap_detection_enabled',
|
||||||
|
'service_handled',
|
||||||
|
'service_in_downtime',
|
||||||
|
'service_is_flapping',
|
||||||
|
'service_last_state_change',
|
||||||
|
'service_notifications_enabled',
|
||||||
|
'service_obsessing',
|
||||||
|
'service_passive_checks_enabled',
|
||||||
|
'service_problem',
|
||||||
|
'service_state'
|
||||||
|
));
|
||||||
|
$this->view->baseFilter = $this->serviceList->getFilter();
|
||||||
|
$this->view->listAllLink = Url::fromRequest()->setPath('monitoring/list/services');
|
||||||
|
$this->getTabs()->add(
|
||||||
|
'show',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Services') . sprintf(' (%d)', count($this->serviceList)),
|
||||||
|
'title' => sprintf(
|
||||||
|
$this->translate('Show summarized information for %u services'),
|
||||||
|
count($this->serviceList)
|
||||||
|
),
|
||||||
|
'url' => Url::fromRequest()
|
||||||
|
)
|
||||||
|
)->extend(new DashboardAction())->extend(new MenuAction())->activate('show');
|
||||||
|
$this->view->title = $this->translate('Services');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function handleCommandForm(ObjectsCommandForm $form)
|
||||||
|
{
|
||||||
|
$form
|
||||||
|
->setBackend($this->backend)
|
||||||
|
->setObjects($this->serviceList)
|
||||||
|
->setRedirectUrl(Url::fromPath('monitoring/services/show')->setParams(
|
||||||
|
$this->params->without('service_active_checks_enabled')
|
||||||
|
))
|
||||||
|
->handleRequest();
|
||||||
|
|
||||||
|
$this->view->form = $form;
|
||||||
|
$this->view->objects = $this->serviceList;
|
||||||
|
$this->view->stats = $this->serviceList->getServiceStateSummary();
|
||||||
|
$this->view->serviceStates = true;
|
||||||
|
$this->_helper->viewRenderer('partials/command/objects-command-form', null, true);
|
||||||
|
return $form;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function showAction()
|
||||||
|
{
|
||||||
|
$this->setAutorefreshInterval(15);
|
||||||
|
$activeChecksEnabled = $this->serviceList->getFeatureStatus()['active_checks_enabled'] !== 0;
|
||||||
|
if ($this->Auth()->hasPermission('monitoring/command/schedule-check')
|
||||||
|
|| ($this->Auth()->hasPermission('monitoring/command/schedule-check/active-only')
|
||||||
|
&& $activeChecksEnabled
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
$checkNowForm = new CheckNowCommandForm();
|
||||||
|
$checkNowForm
|
||||||
|
->setObjects($this->serviceList)
|
||||||
|
->handleRequest();
|
||||||
|
$this->view->checkNowForm = $checkNowForm;
|
||||||
|
}
|
||||||
|
|
||||||
|
$acknowledgedObjects = $this->serviceList->getAcknowledgedObjects();
|
||||||
|
if ($acknowledgedObjects->count()) {
|
||||||
|
$removeAckForm = new RemoveAcknowledgementCommandForm();
|
||||||
|
$removeAckForm
|
||||||
|
->setObjects($acknowledgedObjects)
|
||||||
|
->handleRequest();
|
||||||
|
$this->view->removeAckForm = $removeAckForm;
|
||||||
|
}
|
||||||
|
|
||||||
|
$featureStatus = $this->serviceList->getFeatureStatus();
|
||||||
|
$toggleFeaturesForm = new ToggleObjectFeaturesCommandForm(array(
|
||||||
|
'backend' => $this->backend,
|
||||||
|
'objects' => $this->serviceList
|
||||||
|
));
|
||||||
|
$toggleFeaturesForm
|
||||||
|
->load((object) $featureStatus)
|
||||||
|
->handleRequest();
|
||||||
|
$this->view->toggleFeaturesForm = $toggleFeaturesForm;
|
||||||
|
|
||||||
|
if ($activeChecksEnabled) {
|
||||||
|
$this->view->rescheduleAllLink = Url::fromRequest()
|
||||||
|
->setPath('monitoring/services/reschedule-check')
|
||||||
|
->addParams(['service_active_checks_enabled' => true]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->view->downtimeAllLink = Url::fromRequest()->setPath('monitoring/services/schedule-downtime');
|
||||||
|
$this->view->processCheckResultAllLink = Url::fromRequest()->setPath(
|
||||||
|
'monitoring/services/process-check-result'
|
||||||
|
);
|
||||||
|
$this->view->addCommentLink = Url::fromRequest()->setPath('monitoring/services/add-comment');
|
||||||
|
$this->view->deleteCommentLink = Url::fromRequest()->setPath('monitoring/services/delete-comment');
|
||||||
|
$this->view->stats = $this->serviceList->getServiceStateSummary();
|
||||||
|
$this->view->objects = $this->serviceList;
|
||||||
|
$this->view->unhandledObjects = $this->serviceList->getUnhandledObjects();
|
||||||
|
$this->view->problemObjects = $this->serviceList->getProblemObjects();
|
||||||
|
$this->view->downtimeUnhandledLink = Url::fromPath('monitoring/services/schedule-downtime')
|
||||||
|
->setQueryString($this->serviceList->getUnhandledObjects()->objectsFilter()->toQueryString());
|
||||||
|
$this->view->downtimeLink = Url::fromPath('monitoring/services/schedule-downtime')
|
||||||
|
->setQueryString($this->serviceList->getProblemObjects()->objectsFilter()->toQueryString());
|
||||||
|
$this->view->acknowledgedObjects = $acknowledgedObjects;
|
||||||
|
$this->view->acknowledgeLink = Url::fromPath('monitoring/services/acknowledge-problem')
|
||||||
|
->setQueryString($this->serviceList->getUnacknowledgedObjects()->objectsFilter()->toQueryString());
|
||||||
|
$this->view->unacknowledgedObjects = $this->serviceList->getUnacknowledgedObjects();
|
||||||
|
$this->view->objectsInDowntime = $this->serviceList->getObjectsInDowntime();
|
||||||
|
$this->view->inDowntimeLink = Url::fromPath('monitoring/list/services')
|
||||||
|
->setQueryString($this->serviceList->getObjectsInDowntime()
|
||||||
|
->objectsFilter(array('host' => 'host_name', 'service' => 'service_description'))->toQueryString());
|
||||||
|
$this->view->showDowntimesLink = Url::fromPath('monitoring/downtimes/show')
|
||||||
|
->setQueryString(
|
||||||
|
$this->serviceList->getObjectsInDowntime()
|
||||||
|
->objectsFilter()->andFilter(Filter::where('object_type', 'service'))->toQueryString()
|
||||||
|
);
|
||||||
|
$this->view->commentsLink = Url::fromRequest()
|
||||||
|
->setPath('monitoring/list/comments');
|
||||||
|
$this->view->sendCustomNotificationLink = Url::fromRequest()->setPath(
|
||||||
|
'monitoring/services/send-custom-notification'
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->view->extensionsHtml = array();
|
||||||
|
foreach (Hook::all('Monitoring\DetailviewExtension') as $hook) {
|
||||||
|
/** @var DetailviewExtensionHook $hook */
|
||||||
|
try {
|
||||||
|
$html = $hook->setView($this->view)->getHtmlForObjects($this->serviceList);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$html = $this->view->escape($e->getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($html) {
|
||||||
|
$module = $this->view->escape($hook->getModule()->getName());
|
||||||
|
$this->view->extensionsHtml[] =
|
||||||
|
'<div class="icinga-module module-' . $module . '" data-icinga-module="' . $module . '">'
|
||||||
|
. $html
|
||||||
|
. '</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a service comment
|
||||||
|
*/
|
||||||
|
public function addCommentAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/comment/add');
|
||||||
|
|
||||||
|
$form = new AddCommentCommandForm();
|
||||||
|
$form->setTitle($this->translate('Add Service Comments'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acknowledge service problems
|
||||||
|
*/
|
||||||
|
public function acknowledgeProblemAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/acknowledge-problem');
|
||||||
|
|
||||||
|
$form = new AcknowledgeProblemCommandForm();
|
||||||
|
$form->setTitle($this->translate('Acknowledge Service Problems'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reschedule service checks
|
||||||
|
*/
|
||||||
|
public function rescheduleCheckAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/schedule-check');
|
||||||
|
|
||||||
|
$form = new ScheduleServiceCheckCommandForm();
|
||||||
|
$form->setTitle($this->translate('Reschedule Service Checks'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule service downtimes
|
||||||
|
*/
|
||||||
|
public function scheduleDowntimeAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/downtime/schedule');
|
||||||
|
|
||||||
|
$form = new ScheduleServiceDowntimeCommandForm();
|
||||||
|
$form->setTitle($this->translate('Schedule Service Downtimes'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Submit passive service check results
|
||||||
|
*/
|
||||||
|
public function processCheckResultAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/process-check-result');
|
||||||
|
|
||||||
|
$form = new ProcessCheckResultCommandForm();
|
||||||
|
$form->setTitle($this->translate('Submit Passive Service Check Results'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a custom notification for services
|
||||||
|
*/
|
||||||
|
public function sendCustomNotificationAction()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/send-custom-notification');
|
||||||
|
|
||||||
|
$form = new SendCustomNotificationCommandForm();
|
||||||
|
$form->setTitle($this->translate('Send Custom Service Notification'));
|
||||||
|
$this->handleCommandForm($form);
|
||||||
|
}
|
||||||
|
}
|
||||||
101
modules/monitoring/application/controllers/ShowController.php
Normal file
101
modules/monitoring/application/controllers/ShowController.php
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2013 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Controllers;
|
||||||
|
|
||||||
|
use Icinga\Data\Filter\FilterEqual;
|
||||||
|
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||||
|
use Icinga\Module\Monitoring\Controller;
|
||||||
|
use Icinga\Security\SecurityException;
|
||||||
|
use Icinga\Web\Url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Monitoring_ShowController
|
||||||
|
*
|
||||||
|
* Actions for show context
|
||||||
|
*/
|
||||||
|
class ShowController extends Controller
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var MonitoringBackend
|
||||||
|
*/
|
||||||
|
protected $backend;
|
||||||
|
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->view->defaultTitle = $this->translate('Contacts') . ' :: ' . $this->view->defaultTitle;
|
||||||
|
|
||||||
|
parent::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function contactAction()
|
||||||
|
{
|
||||||
|
if (! $this->hasPermission('*') && $this->hasPermission('no-monitoring/contacts')) {
|
||||||
|
throw new SecurityException('No permission for %s', 'monitoring/contacts');
|
||||||
|
}
|
||||||
|
|
||||||
|
$contactName = $this->params->getRequired('contact_name');
|
||||||
|
|
||||||
|
$this->getTabs()->add('contact-detail', [
|
||||||
|
'title' => $this->translate('Contact details'),
|
||||||
|
'label' => $this->translate('Contact'),
|
||||||
|
'url' => Url::fromRequest(),
|
||||||
|
'active' => true
|
||||||
|
]);
|
||||||
|
|
||||||
|
$query = $this->backend->select()->from('contact', array(
|
||||||
|
'contact_name',
|
||||||
|
'contact_id',
|
||||||
|
'contact_alias',
|
||||||
|
'contact_email',
|
||||||
|
'contact_pager',
|
||||||
|
'contact_notify_service_timeperiod',
|
||||||
|
'contact_notify_service_recovery',
|
||||||
|
'contact_notify_service_warning',
|
||||||
|
'contact_notify_service_critical',
|
||||||
|
'contact_notify_service_unknown',
|
||||||
|
'contact_notify_service_flapping',
|
||||||
|
'contact_notify_service_downtime',
|
||||||
|
'contact_notify_host_timeperiod',
|
||||||
|
'contact_notify_host_recovery',
|
||||||
|
'contact_notify_host_down',
|
||||||
|
'contact_notify_host_unreachable',
|
||||||
|
'contact_notify_host_flapping',
|
||||||
|
'contact_notify_host_downtime',
|
||||||
|
));
|
||||||
|
$this->applyRestriction('monitoring/filter/objects', $query);
|
||||||
|
$query->whereEx(new FilterEqual('contact_name', '=', $contactName));
|
||||||
|
$contact = $query->getQuery()->fetchRow();
|
||||||
|
|
||||||
|
if ($contact) {
|
||||||
|
$commands = $this->backend->select()->from('command', array(
|
||||||
|
'command_line',
|
||||||
|
'command_name'
|
||||||
|
))->where('contact_id', $contact->contact_id);
|
||||||
|
|
||||||
|
$this->view->commands = $commands;
|
||||||
|
|
||||||
|
$notifications = $this->backend->select()->from('notification', array(
|
||||||
|
'id',
|
||||||
|
'host_name',
|
||||||
|
'service_description',
|
||||||
|
'notification_output',
|
||||||
|
'notification_contact_name',
|
||||||
|
'notification_timestamp',
|
||||||
|
'notification_state',
|
||||||
|
'host_display_name',
|
||||||
|
'service_display_name'
|
||||||
|
));
|
||||||
|
|
||||||
|
$notifications->where('notification_contact_name', $contactName);
|
||||||
|
$this->applyRestriction('monitoring/filter/objects', $notifications);
|
||||||
|
$this->view->notifications = $notifications;
|
||||||
|
$this->setupLimitControl();
|
||||||
|
$this->setupPaginationControl($this->view->notifications);
|
||||||
|
$this->view->title = $contact->contact_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->view->contact = $contact;
|
||||||
|
$this->view->contactName = $contactName;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,128 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Controllers;
|
||||||
|
|
||||||
|
use Icinga\Chart\Donut;
|
||||||
|
use Icinga\Module\Monitoring\Controller;
|
||||||
|
use Icinga\Web\Url;
|
||||||
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
|
|
||||||
|
class TacticalController extends Controller
|
||||||
|
{
|
||||||
|
public function indexAction()
|
||||||
|
{
|
||||||
|
$this->setAutorefreshInterval(15);
|
||||||
|
|
||||||
|
$this->view->title = $this->translate('Tactical Overview');
|
||||||
|
$this->getTabs()->add(
|
||||||
|
'tactical_overview',
|
||||||
|
array(
|
||||||
|
'title' => $this->translate(
|
||||||
|
'Show an overview of all hosts and services, their current'
|
||||||
|
. ' states and monitoring feature utilisation'
|
||||||
|
),
|
||||||
|
'label' => $this->translate('Tactical Overview'),
|
||||||
|
'url' => Url::fromRequest()
|
||||||
|
)
|
||||||
|
)->extend(new DashboardAction())->extend(new MenuAction())->activate('tactical_overview');
|
||||||
|
|
||||||
|
$stats = $this->backend->select()->from(
|
||||||
|
'statussummary',
|
||||||
|
array(
|
||||||
|
'hosts_up',
|
||||||
|
'hosts_down_handled',
|
||||||
|
'hosts_down_unhandled',
|
||||||
|
'hosts_unreachable_handled',
|
||||||
|
'hosts_unreachable_unhandled',
|
||||||
|
'hosts_pending',
|
||||||
|
'hosts_pending_not_checked',
|
||||||
|
'hosts_not_checked',
|
||||||
|
|
||||||
|
'services_ok',
|
||||||
|
'services_warning_handled',
|
||||||
|
'services_warning_unhandled',
|
||||||
|
'services_critical_handled',
|
||||||
|
'services_critical_unhandled',
|
||||||
|
'services_unknown_handled',
|
||||||
|
'services_unknown_unhandled',
|
||||||
|
'services_pending',
|
||||||
|
'services_pending_not_checked',
|
||||||
|
'services_not_checked',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->applyRestriction('monitoring/filter/objects', $stats);
|
||||||
|
|
||||||
|
$this->setupFilterControl($stats, null, ['host', 'service'], ['format']);
|
||||||
|
$this->view->setHelperFunction('filteredUrl', function ($path, array $params) {
|
||||||
|
$filter = clone $this->view->filterEditor->getFilter();
|
||||||
|
|
||||||
|
return $this->view->url($path)->setParams($params)->addFilter($filter);
|
||||||
|
});
|
||||||
|
|
||||||
|
$this->handleFormatRequest($stats);
|
||||||
|
$summary = $stats->fetchRow();
|
||||||
|
|
||||||
|
// Correct pending counts. Done here instead of in the query for compatibility reasons.
|
||||||
|
$summary->hosts_pending -= $summary->hosts_pending_not_checked;
|
||||||
|
$summary->services_pending -= $summary->services_pending_not_checked;
|
||||||
|
|
||||||
|
$hostSummaryChart = new Donut();
|
||||||
|
$hostSummaryChart
|
||||||
|
->addSlice($summary->hosts_up, array('class' => 'slice-state-ok'))
|
||||||
|
->addSlice($summary->hosts_down_handled, array('class' => 'slice-state-critical-handled'))
|
||||||
|
->addSlice($summary->hosts_down_unhandled, array('class' => 'slice-state-critical'))
|
||||||
|
->addSlice($summary->hosts_unreachable_handled, array('class' => 'slice-state-unreachable-handled'))
|
||||||
|
->addSlice($summary->hosts_unreachable_unhandled, array('class' => 'slice-state-unreachable'))
|
||||||
|
->addSlice($summary->hosts_pending, array('class' => 'slice-state-pending'))
|
||||||
|
->addSlice($summary->hosts_pending_not_checked, array('class' => 'slice-state-not-checked'))
|
||||||
|
->setLabelBig($summary->hosts_down_unhandled)
|
||||||
|
->setLabelBigEyeCatching($summary->hosts_down_unhandled > 0)
|
||||||
|
->setLabelSmall($this->translate('Hosts Down'));
|
||||||
|
|
||||||
|
$serviceSummaryChart = new Donut();
|
||||||
|
$serviceSummaryChart
|
||||||
|
->addSlice($summary->services_ok, array('class' => 'slice-state-ok'))
|
||||||
|
->addSlice($summary->services_warning_handled, array('class' => 'slice-state-warning-handled'))
|
||||||
|
->addSlice($summary->services_warning_unhandled, array('class' => 'slice-state-warning'))
|
||||||
|
->addSlice($summary->services_critical_handled, array('class' => 'slice-state-critical-handled'))
|
||||||
|
->addSlice($summary->services_critical_unhandled, array('class' => 'slice-state-critical'))
|
||||||
|
->addSlice($summary->services_unknown_handled, array('class' => 'slice-state-unknown-handled'))
|
||||||
|
->addSlice($summary->services_unknown_unhandled, array('class' => 'slice-state-unknown'))
|
||||||
|
->addSlice($summary->services_pending, array('class' => 'slice-state-pending'))
|
||||||
|
->addSlice($summary->services_pending_not_checked, array('class' => 'slice-state-not-checked'))
|
||||||
|
->setLabelBig($summary->services_critical_unhandled ?: $summary->services_unknown_unhandled)
|
||||||
|
->setLabelBigState($summary->services_critical_unhandled > 0 ? 'critical' : (
|
||||||
|
$summary->services_unknown_unhandled > 0 ? 'unknown' : null
|
||||||
|
))
|
||||||
|
->setLabelSmall($summary->services_critical_unhandled > 0 || $summary->services_unknown_unhandled < 1
|
||||||
|
? $this->translate('Services Critical')
|
||||||
|
: $this->translate('Services Unknown'));
|
||||||
|
|
||||||
|
$this->view->hostStatusSummaryChart = $hostSummaryChart
|
||||||
|
->setLabelBigUrl($this->view->filteredUrl(
|
||||||
|
'monitoring/list/hosts',
|
||||||
|
array(
|
||||||
|
'host_state' => 1,
|
||||||
|
'host_handled' => 0,
|
||||||
|
'sort' => 'host_last_check',
|
||||||
|
'dir' => 'asc'
|
||||||
|
)
|
||||||
|
))
|
||||||
|
->render();
|
||||||
|
$this->view->serviceStatusSummaryChart = $serviceSummaryChart
|
||||||
|
->setLabelBigUrl($this->view->filteredUrl(
|
||||||
|
'monitoring/list/services',
|
||||||
|
array(
|
||||||
|
'service_state' => $summary->services_critical_unhandled > 0
|
||||||
|
|| ! $summary->services_unknown_unhandled ? 2 : 3,
|
||||||
|
'service_handled' => 0,
|
||||||
|
'sort' => 'service_last_check',
|
||||||
|
'dir' => 'asc'
|
||||||
|
)
|
||||||
|
))
|
||||||
|
->render();
|
||||||
|
$this->view->statusSummary = $summary;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,325 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2013 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Controllers;
|
||||||
|
|
||||||
|
use DateInterval;
|
||||||
|
use DateTime;
|
||||||
|
use Icinga\Module\Monitoring\Controller;
|
||||||
|
use Icinga\Module\Monitoring\Timeline\TimeLine;
|
||||||
|
use Icinga\Module\Monitoring\Timeline\TimeRange;
|
||||||
|
use Icinga\Module\Monitoring\Web\Widget\SelectBox;
|
||||||
|
use Icinga\Util\Format;
|
||||||
|
use Icinga\Web\Url;
|
||||||
|
use Icinga\Web\Widget\Tabextension\DashboardAction;
|
||||||
|
use Icinga\Web\Widget\Tabextension\MenuAction;
|
||||||
|
|
||||||
|
class TimelineController extends Controller
|
||||||
|
{
|
||||||
|
public function indexAction()
|
||||||
|
{
|
||||||
|
$this->getTabs()->add(
|
||||||
|
'timeline',
|
||||||
|
array(
|
||||||
|
'title' => $this->translate('Show the number of historical event records grouped by time and type'),
|
||||||
|
'label' => $this->translate('Timeline'),
|
||||||
|
'url' => Url::fromRequest()
|
||||||
|
)
|
||||||
|
)->extend(new DashboardAction())->extend(new MenuAction())->activate('timeline');
|
||||||
|
$this->view->title = $this->translate('Timeline');
|
||||||
|
|
||||||
|
// TODO: filter for hard_states (precedence adjustments necessary!)
|
||||||
|
$this->setupIntervalBox();
|
||||||
|
list($displayRange, $forecastRange) = $this->buildTimeRanges();
|
||||||
|
|
||||||
|
$detailUrl = Url::fromPath('monitoring/list/eventhistory');
|
||||||
|
|
||||||
|
$timeline = new TimeLine(
|
||||||
|
$this->applyRestriction(
|
||||||
|
'monitoring/filter/objects',
|
||||||
|
$this->backend->select()->from(
|
||||||
|
'eventhistory',
|
||||||
|
array(
|
||||||
|
'name' => 'type',
|
||||||
|
'time' => 'timestamp'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'notification_ack' => array(
|
||||||
|
'class' => 'timeline-notification',
|
||||||
|
'detailUrl' => $detailUrl,
|
||||||
|
'label' => mt('monitoring', 'Notifications'),
|
||||||
|
'groupBy' => 'notification_*'
|
||||||
|
),
|
||||||
|
'notification_flapping' => array(
|
||||||
|
'class' => 'timeline-notification',
|
||||||
|
'detailUrl' => $detailUrl,
|
||||||
|
'label' => mt('monitoring', 'Notifications'),
|
||||||
|
'groupBy' => 'notification_*'
|
||||||
|
),
|
||||||
|
'notification_flapping_end' => array(
|
||||||
|
'class' => 'timeline-notification',
|
||||||
|
'detailUrl' => $detailUrl,
|
||||||
|
'label' => mt('monitoring', 'Notifications'),
|
||||||
|
'groupBy' => 'notification_*'
|
||||||
|
),
|
||||||
|
'notification_dt_start' => array(
|
||||||
|
'class' => 'timeline-notification',
|
||||||
|
'detailUrl' => $detailUrl,
|
||||||
|
'label' => mt('monitoring', 'Notifications'),
|
||||||
|
'groupBy' => 'notification_*'
|
||||||
|
),
|
||||||
|
'notification_dt_end' => array(
|
||||||
|
'class' => 'timeline-notification',
|
||||||
|
'detailUrl' => $detailUrl,
|
||||||
|
'label' => mt('monitoring', 'Notifications'),
|
||||||
|
'groupBy' => 'notification_*'
|
||||||
|
),
|
||||||
|
'notification_custom' => array(
|
||||||
|
'class' => 'timeline-notification',
|
||||||
|
'detailUrl' => $detailUrl,
|
||||||
|
'label' => mt('monitoring', 'Notifications'),
|
||||||
|
'groupBy' => 'notification_*'
|
||||||
|
),
|
||||||
|
'notification_state' => array(
|
||||||
|
'class' => 'timeline-notification',
|
||||||
|
'detailUrl' => $detailUrl,
|
||||||
|
'label' => mt('monitoring', 'Notifications'),
|
||||||
|
'groupBy' => 'notification_*'
|
||||||
|
),
|
||||||
|
'hard_state' => array(
|
||||||
|
'class' => 'timeline-hard-state',
|
||||||
|
'detailUrl' => $detailUrl,
|
||||||
|
'label' => mt('monitoring', 'Hard state changes')
|
||||||
|
),
|
||||||
|
'comment' => array(
|
||||||
|
'class' => 'timeline-comment',
|
||||||
|
'detailUrl' => $detailUrl,
|
||||||
|
'label' => mt('monitoring', 'Comments')
|
||||||
|
),
|
||||||
|
'ack' => array(
|
||||||
|
'class' => 'timeline-ack',
|
||||||
|
'detailUrl' => $detailUrl,
|
||||||
|
'label' => mt('monitoring', 'Acknowledgements')
|
||||||
|
),
|
||||||
|
'dt_start' => array(
|
||||||
|
'class' => 'timeline-downtime-start',
|
||||||
|
'detailUrl' => $detailUrl,
|
||||||
|
'label' => mt('monitoring', 'Started downtimes')
|
||||||
|
),
|
||||||
|
'dt_end' => array(
|
||||||
|
'class' => 'timeline-downtime-end',
|
||||||
|
'detailUrl' => $detailUrl,
|
||||||
|
'label' => mt('monitoring', 'Ended downtimes')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$timeline->setMaximumCircleWidth('6em');
|
||||||
|
$timeline->setMinimumCircleWidth('0.3em');
|
||||||
|
$timeline->setDisplayRange($displayRange);
|
||||||
|
$timeline->setForecastRange($forecastRange);
|
||||||
|
$beingExtended = $this->getRequest()->getParam('extend') == 1;
|
||||||
|
$timeline->setSession($this->Window()->getSessionNamespace('timeline', !$beingExtended));
|
||||||
|
|
||||||
|
$this->view->timeline = $timeline;
|
||||||
|
$this->view->nextRange = $forecastRange;
|
||||||
|
$this->view->beingExtended = $beingExtended;
|
||||||
|
$this->view->intervalFormat = $this->getIntervalFormat();
|
||||||
|
$oldBase = $timeline->getCalculationBase(false);
|
||||||
|
$this->view->switchedContext = $oldBase !== null && $oldBase !== $timeline->getCalculationBase(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a select box the user can choose the timeline interval from
|
||||||
|
*/
|
||||||
|
private function setupIntervalBox()
|
||||||
|
{
|
||||||
|
$box = new SelectBox(
|
||||||
|
'intervalBox',
|
||||||
|
array(
|
||||||
|
'4h' => mt('monitoring', '4 Hours'),
|
||||||
|
'1d' => mt('monitoring', 'One day'),
|
||||||
|
'1w' => mt('monitoring', 'One week'),
|
||||||
|
'1m' => mt('monitoring', 'One month'),
|
||||||
|
'1y' => mt('monitoring', 'One year')
|
||||||
|
),
|
||||||
|
mt('monitoring', 'TimeLine interval'),
|
||||||
|
'interval'
|
||||||
|
);
|
||||||
|
$box->applyRequest($this->getRequest());
|
||||||
|
$this->view->intervalBox = $box;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the chosen interval
|
||||||
|
*
|
||||||
|
* @return DateInterval The chosen interval
|
||||||
|
*/
|
||||||
|
private function getTimelineInterval()
|
||||||
|
{
|
||||||
|
switch ($this->view->intervalBox->getInterval()) {
|
||||||
|
case '1d':
|
||||||
|
return new DateInterval('P1D');
|
||||||
|
case '1w':
|
||||||
|
return new DateInterval('P1W');
|
||||||
|
case '1m':
|
||||||
|
return new DateInterval('P1M');
|
||||||
|
case '1y':
|
||||||
|
return new DateInterval('P1Y');
|
||||||
|
default:
|
||||||
|
return new DateInterval('PT4H');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get an appropriate datetime format string for the chosen interval
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getIntervalFormat()
|
||||||
|
{
|
||||||
|
switch ($this->view->intervalBox->getInterval()) {
|
||||||
|
case '1d':
|
||||||
|
return $this->getDateFormat();
|
||||||
|
case '1w':
|
||||||
|
return '\W\e\ek W\<b\r\>\of Y';
|
||||||
|
case '1m':
|
||||||
|
return 'F Y';
|
||||||
|
case '1y':
|
||||||
|
return 'Y';
|
||||||
|
default:
|
||||||
|
return $this->getDateFormat() . '\<b\r\>' . $this->getTimeFormat();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a preload interval based on the chosen timeline interval and the given date and time
|
||||||
|
*
|
||||||
|
* @param DateTime $dateTime The date and time to use
|
||||||
|
*
|
||||||
|
* @return DateInterval The interval to pre-load
|
||||||
|
*/
|
||||||
|
private function getPreloadInterval(DateTime $dateTime)
|
||||||
|
{
|
||||||
|
switch ($this->view->intervalBox->getInterval()) {
|
||||||
|
case '1d':
|
||||||
|
return DateInterval::createFromDateString('1 week -1 second');
|
||||||
|
case '1w':
|
||||||
|
return DateInterval::createFromDateString('8 weeks -1 second');
|
||||||
|
case '1m':
|
||||||
|
$dateCopy = clone $dateTime;
|
||||||
|
for ($i = 0; $i < 6; $i++) {
|
||||||
|
$dateCopy->sub(new DateInterval('PT' . Format::secondsByMonth($dateCopy) . 'S'));
|
||||||
|
}
|
||||||
|
return $dateCopy->add(new DateInterval('PT1S'))->diff($dateTime);
|
||||||
|
case '1y':
|
||||||
|
$dateCopy = clone $dateTime;
|
||||||
|
for ($i = 0; $i < 4; $i++) {
|
||||||
|
$dateCopy->sub(new DateInterval('PT' . Format::secondsByYear($dateCopy) . 'S'));
|
||||||
|
}
|
||||||
|
return $dateCopy->add(new DateInterval('PT1S'))->diff($dateTime);
|
||||||
|
default:
|
||||||
|
return DateInterval::createFromDateString('1 day -1 second');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extrapolate the given datetime based on the chosen timeline interval
|
||||||
|
*
|
||||||
|
* @param DateTime $dateTime The datetime to extrapolate
|
||||||
|
*/
|
||||||
|
private function extrapolateDateTime(DateTime &$dateTime)
|
||||||
|
{
|
||||||
|
switch ($this->view->intervalBox->getInterval()) {
|
||||||
|
case '1d':
|
||||||
|
$dateTime->setTimestamp(strtotime('tomorrow', $dateTime->getTimestamp()) - 1);
|
||||||
|
break;
|
||||||
|
case '1w':
|
||||||
|
$dateTime->setTimestamp(strtotime('next monday', $dateTime->getTimestamp()) - 1);
|
||||||
|
break;
|
||||||
|
case '1m':
|
||||||
|
$dateTime->setTimestamp(
|
||||||
|
strtotime(
|
||||||
|
'last day of this month',
|
||||||
|
strtotime(
|
||||||
|
'tomorrow',
|
||||||
|
$dateTime->getTimestamp()
|
||||||
|
) - 1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
case '1y':
|
||||||
|
$dateTime->setTimestamp(strtotime('1 january next year', $dateTime->getTimestamp()) - 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$hour = $dateTime->format('G');
|
||||||
|
$end = $hour < 4 ? 4 : ($hour < 8 ? 8 : ($hour < 12 ? 12 : ($hour < 16 ? 16 : ($hour < 20 ? 20 : 24))));
|
||||||
|
$dateTime = DateTime::createFromFormat(
|
||||||
|
'd/m/y G:i:s',
|
||||||
|
$dateTime->format('d/m/y') . ($end - 1) . ':59:59'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a display- and forecast time range
|
||||||
|
*
|
||||||
|
* Assembles a time range each for display and forecast purposes based on the start- and
|
||||||
|
* end time if given in the current request otherwise based on the current time and a
|
||||||
|
* end time that is calculated based on the chosen timeline interval.
|
||||||
|
*
|
||||||
|
* @return array The resulting time ranges
|
||||||
|
*/
|
||||||
|
private function buildTimeRanges()
|
||||||
|
{
|
||||||
|
$startTime = new DateTime();
|
||||||
|
$startParam = $this->_request->getParam('start');
|
||||||
|
$startTimestamp = is_numeric($startParam) ? intval($startParam) : strtotime($startParam ?? '');
|
||||||
|
if ($startTimestamp !== false) {
|
||||||
|
$startTime->setTimestamp($startTimestamp);
|
||||||
|
} else {
|
||||||
|
$this->extrapolateDateTime($startTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
$endTime = clone $startTime;
|
||||||
|
$endParam = $this->_request->getParam('end');
|
||||||
|
$endTimestamp = is_numeric($endParam) ? intval($endParam) : strtotime($endParam ?? '');
|
||||||
|
if ($endTimestamp !== false) {
|
||||||
|
$endTime->setTimestamp($endTimestamp);
|
||||||
|
} else {
|
||||||
|
$endTime->sub($this->getPreloadInterval($startTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
$forecastStart = clone $endTime;
|
||||||
|
$forecastStart->sub(new DateInterval('PT1S'));
|
||||||
|
$forecastEnd = clone $forecastStart;
|
||||||
|
$forecastEnd->sub($this->getPreloadInterval($forecastStart));
|
||||||
|
|
||||||
|
$timelineInterval = $this->getTimelineInterval();
|
||||||
|
return array(
|
||||||
|
new TimeRange($startTime, $endTime, $timelineInterval),
|
||||||
|
new TimeRange($forecastStart, $forecastEnd, $timelineInterval)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the user's preferred time format or the application's default
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getTimeFormat()
|
||||||
|
{
|
||||||
|
return 'H:i';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the user's preferred date format or the application's default
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function getDateFormat()
|
||||||
|
{
|
||||||
|
return 'Y-m-d';
|
||||||
|
}
|
||||||
|
}
|
||||||
92
modules/monitoring/application/forms/Command/CommandForm.php
Normal file
92
modules/monitoring/application/forms/Command/CommandForm.php
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command;
|
||||||
|
|
||||||
|
use Icinga\Exception\ConfigurationError;
|
||||||
|
use Icinga\Web\Form;
|
||||||
|
use Icinga\Web\Request;
|
||||||
|
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
|
||||||
|
use Icinga\Module\Monitoring\Command\Transport\CommandTransport;
|
||||||
|
use Icinga\Module\Monitoring\Command\Transport\CommandTransportInterface;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for command forms
|
||||||
|
*/
|
||||||
|
abstract class CommandForm extends Form
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Monitoring backend
|
||||||
|
*
|
||||||
|
* @var MonitoringBackend
|
||||||
|
*/
|
||||||
|
protected $backend;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the monitoring backend
|
||||||
|
*
|
||||||
|
* @param MonitoringBackend $backend
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setBackend(MonitoringBackend $backend)
|
||||||
|
{
|
||||||
|
$this->backend = $backend;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the monitoring backend
|
||||||
|
*
|
||||||
|
* @return MonitoringBackend
|
||||||
|
*/
|
||||||
|
public function getBackend()
|
||||||
|
{
|
||||||
|
return $this->backend;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the transport used to send commands
|
||||||
|
*
|
||||||
|
* @param Request $request
|
||||||
|
*
|
||||||
|
* @return CommandTransportInterface
|
||||||
|
*
|
||||||
|
* @throws ConfigurationError
|
||||||
|
*/
|
||||||
|
public function getTransport(Request $request)
|
||||||
|
{
|
||||||
|
if (($transportName = $request->getParam('transport')) !== null) {
|
||||||
|
$config = CommandTransport::getConfig();
|
||||||
|
if ($config->hasSection($transportName)) {
|
||||||
|
$transport = CommandTransport::createTransport($config->getSection($transportName));
|
||||||
|
} else {
|
||||||
|
throw new ConfigurationError(sprintf(
|
||||||
|
mt('monitoring', 'Command transport "%s" not found.'),
|
||||||
|
$transportName
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$transport = new CommandTransport();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $transport;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getRedirectUrl()
|
||||||
|
{
|
||||||
|
$redirectUrl = parent::getRedirectUrl();
|
||||||
|
// TODO(el): Forms should provide event handling. This is quite hackish
|
||||||
|
$formData = $this->getRequestData();
|
||||||
|
if ($this->wasSent($formData)
|
||||||
|
&& (! $this->getSubmitLabel() || $this->isSubmitted())
|
||||||
|
&& $this->isValid($formData)
|
||||||
|
) {
|
||||||
|
$this->getResponse()->setAutoRefreshInterval(1);
|
||||||
|
}
|
||||||
|
return $redirectUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command\Instance;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use DateInterval;
|
||||||
|
use Icinga\Module\Monitoring\Command\Instance\DisableNotificationsExpireCommand;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\CommandForm;
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for disabling host and service notifications w/ an optional expire date and time on an Icinga instance
|
||||||
|
*/
|
||||||
|
class DisableNotificationsExpireCommandForm extends CommandForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Zend_Form::init() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setRequiredCue(null);
|
||||||
|
$this->setSubmitLabel($this->translate('Disable Notifications'));
|
||||||
|
$this->addDescription($this->translate(
|
||||||
|
'This command is used to disable host and service notifications for a specific time.'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::createElements() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData = array())
|
||||||
|
{
|
||||||
|
$expireTime = new DateTime();
|
||||||
|
$expireTime->add(new DateInterval('PT1H'));
|
||||||
|
$this->addElement(
|
||||||
|
'dateTimePicker',
|
||||||
|
'expire_time',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Expire Time'),
|
||||||
|
'description' => $this->translate('Set the expire time.'),
|
||||||
|
'value' => $expireTime
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
$disableNotifications = new DisableNotificationsExpireCommand();
|
||||||
|
$disableNotifications
|
||||||
|
->setExpireTime($this->getElement('expire_time')->getValue()->getTimestamp());
|
||||||
|
$this->getTransport($this->request)->send($disableNotifications);
|
||||||
|
Notification::success($this->translate('Disabling host and service notifications..'));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,279 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command\Instance;
|
||||||
|
|
||||||
|
use Icinga\Module\Monitoring\Command\Instance\ToggleInstanceFeatureCommand;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\CommandForm;
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for enabling or disabling features of Icinga instances
|
||||||
|
*/
|
||||||
|
class ToggleInstanceFeaturesCommandForm extends CommandForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Instance status
|
||||||
|
*
|
||||||
|
* @var object
|
||||||
|
*/
|
||||||
|
protected $status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Zend_Form::init() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setUseFormAutosubmit();
|
||||||
|
$this->setAttrib('class', self::DEFAULT_CLASSES . ' instance-features');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the instance status
|
||||||
|
*
|
||||||
|
* @param object $status
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setStatus($status)
|
||||||
|
{
|
||||||
|
$this->status = (object) $status;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the instance status
|
||||||
|
*
|
||||||
|
* @return object
|
||||||
|
*/
|
||||||
|
public function getStatus()
|
||||||
|
{
|
||||||
|
return $this->status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::createElements() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData = array())
|
||||||
|
{
|
||||||
|
$notificationDescription = null;
|
||||||
|
$isIcinga2 = $this->getBackend()->isIcinga2($this->status->program_version);
|
||||||
|
|
||||||
|
if (! $isIcinga2) {
|
||||||
|
if ((bool) $this->status->notifications_enabled) {
|
||||||
|
if ($this->hasPermission('monitoring/command/feature/instance')) {
|
||||||
|
$notificationDescription = sprintf(
|
||||||
|
'<a aria-label="%1$s" class="action-link" title="%1$s"'
|
||||||
|
. ' href="%2$s" data-base-target="_next">%3$s</a>',
|
||||||
|
$this->translate('Disable notifications for a specific time on a program-wide basis'),
|
||||||
|
$this->getView()->href('monitoring/health/disable-notifications'),
|
||||||
|
$this->translate('Disable temporarily')
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
$notificationDescription = null;
|
||||||
|
}
|
||||||
|
} elseif ($this->status->disable_notif_expire_time) {
|
||||||
|
$notificationDescription = sprintf(
|
||||||
|
$this->translate('Notifications will be re-enabled in <strong>%s</strong>'),
|
||||||
|
$this->getView()->timeUntil($this->status->disable_notif_expire_time)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$toggleDisabled = $this->hasPermission('monitoring/command/feature/instance') ? null : '';
|
||||||
|
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_ACTIVE_HOST_CHECKS,
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Active Host Checks'),
|
||||||
|
'autosubmit' => true,
|
||||||
|
'disabled' => $toggleDisabled
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_ACTIVE_SERVICE_CHECKS,
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Active Service Checks'),
|
||||||
|
'autosubmit' => true,
|
||||||
|
'disabled' => $toggleDisabled
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_EVENT_HANDLERS,
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Event Handlers'),
|
||||||
|
'autosubmit' => true,
|
||||||
|
'disabled' => $toggleDisabled
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_FLAP_DETECTION,
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Flap Detection'),
|
||||||
|
'autosubmit' => true,
|
||||||
|
'disabled' => $toggleDisabled
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_NOTIFICATIONS,
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Notifications'),
|
||||||
|
'autosubmit' => true,
|
||||||
|
'description' => $notificationDescription,
|
||||||
|
'decorators' => array(
|
||||||
|
array('Label', array('tag'=>'span', 'separator' => '', 'class' => 'control-label')),
|
||||||
|
array(
|
||||||
|
'Description',
|
||||||
|
array('tag' => 'span', 'class' => 'description', 'escape' => false)
|
||||||
|
),
|
||||||
|
array(array('labelWrap' => 'HtmlTag'), array('tag' => 'div', 'class' => 'control-label-group')),
|
||||||
|
array('ViewHelper', array('separator' => '')),
|
||||||
|
array('Errors', array('separator' => '')),
|
||||||
|
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
|
||||||
|
),
|
||||||
|
'disabled' => $toggleDisabled
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (! $isIcinga2) {
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_HOST_OBSESSING,
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Obsessing Over Hosts'),
|
||||||
|
'autosubmit' => true,
|
||||||
|
'disabled' => $toggleDisabled
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_SERVICE_OBSESSING,
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Obsessing Over Services'),
|
||||||
|
'autosubmit' => true,
|
||||||
|
'disabled' => $toggleDisabled
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_PASSIVE_HOST_CHECKS,
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Passive Host Checks'),
|
||||||
|
'autosubmit' => true,
|
||||||
|
'disabled' => $toggleDisabled
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_PASSIVE_SERVICE_CHECKS,
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Passive Service Checks'),
|
||||||
|
'autosubmit' => true,
|
||||||
|
'disabled' => $toggleDisabled
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_PERFORMANCE_DATA,
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Performance Data'),
|
||||||
|
'autosubmit' => true,
|
||||||
|
'disabled' => $toggleDisabled
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load feature status
|
||||||
|
*
|
||||||
|
* @param object $instanceStatus
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function load($instanceStatus)
|
||||||
|
{
|
||||||
|
$this->create();
|
||||||
|
foreach ($this->getValues() as $feature => $enabled) {
|
||||||
|
$this->getElement($feature)->setChecked($instanceStatus->{$feature});
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
$this->assertPermission('monitoring/command/feature/instance');
|
||||||
|
|
||||||
|
$notifications = array(
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_ACTIVE_HOST_CHECKS => array(
|
||||||
|
$this->translate('Enabling active host checks..'),
|
||||||
|
$this->translate('Disabling active host checks..')
|
||||||
|
),
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_ACTIVE_SERVICE_CHECKS => array(
|
||||||
|
$this->translate('Enabling active service checks..'),
|
||||||
|
$this->translate('Disabling active service checks..')
|
||||||
|
),
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_EVENT_HANDLERS => array(
|
||||||
|
$this->translate('Enabling event handlers..'),
|
||||||
|
$this->translate('Disabling event handlers..')
|
||||||
|
),
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_FLAP_DETECTION => array(
|
||||||
|
$this->translate('Enabling flap detection..'),
|
||||||
|
$this->translate('Disabling flap detection..')
|
||||||
|
),
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_NOTIFICATIONS => array(
|
||||||
|
$this->translate('Enabling notifications..'),
|
||||||
|
$this->translate('Disabling notifications..')
|
||||||
|
),
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_HOST_OBSESSING => array(
|
||||||
|
$this->translate('Enabling obsessing over hosts..'),
|
||||||
|
$this->translate('Disabling obsessing over hosts..')
|
||||||
|
),
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_SERVICE_OBSESSING => array(
|
||||||
|
$this->translate('Enabling obsessing over services..'),
|
||||||
|
$this->translate('Disabling obsessing over services..')
|
||||||
|
),
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_PASSIVE_HOST_CHECKS => array(
|
||||||
|
$this->translate('Enabling passive host checks..'),
|
||||||
|
$this->translate('Disabling passive host checks..')
|
||||||
|
),
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_PASSIVE_SERVICE_CHECKS => array(
|
||||||
|
$this->translate('Enabling passive service checks..'),
|
||||||
|
$this->translate('Disabling passive service checks..')
|
||||||
|
),
|
||||||
|
ToggleInstanceFeatureCommand::FEATURE_PERFORMANCE_DATA => array(
|
||||||
|
$this->translate('Enabling performance data..'),
|
||||||
|
$this->translate('Disabling performance data..')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($this->getValues() as $feature => $enabled) {
|
||||||
|
if ((bool) $this->status->{$feature} !== (bool) $enabled) {
|
||||||
|
$toggleFeature = new ToggleInstanceFeatureCommand();
|
||||||
|
$toggleFeature
|
||||||
|
->setFeature($feature)
|
||||||
|
->setEnabled($enabled);
|
||||||
|
$this->getTransport($this->request)->send($toggleFeature);
|
||||||
|
|
||||||
|
Notification::success(
|
||||||
|
$notifications[$feature][$enabled ? 0 : 1]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,172 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use DateInterval;
|
||||||
|
use Icinga\Application\Config;
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\AcknowledgeProblemCommand;
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for acknowledging host or service problems
|
||||||
|
*/
|
||||||
|
class AcknowledgeProblemCommandForm extends ObjectsCommandForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Initialize this form
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->addDescription($this->translate(
|
||||||
|
'This command is used to acknowledge host or service problems. When a problem is acknowledged,'
|
||||||
|
. ' future notifications about problems are temporarily disabled until the host or service'
|
||||||
|
. ' recovers.'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::getSubmitLabel() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function getSubmitLabel()
|
||||||
|
{
|
||||||
|
return $this->translatePlural('Acknowledge problem', 'Acknowledge problems', count($this->objects));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::createElements() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData = array())
|
||||||
|
{
|
||||||
|
$config = Config::module('monitoring');
|
||||||
|
|
||||||
|
$acknowledgeExpire = (bool) $config->get('settings', 'acknowledge_expire', false);
|
||||||
|
|
||||||
|
$this->addElements(array(
|
||||||
|
array(
|
||||||
|
'textarea',
|
||||||
|
'comment',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Comment'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'If you work with other administrators, you may find it useful to share information about'
|
||||||
|
. ' the host or service that is having problems. Make sure you enter a brief description of'
|
||||||
|
. ' what you are doing.'
|
||||||
|
),
|
||||||
|
'attribs' => array('class' => 'autofocus')
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'checkbox',
|
||||||
|
'persistent',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Persistent Comment'),
|
||||||
|
'value' => (bool) $config->get('settings', 'acknowledge_persistent', false),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'If you would like the comment to remain even when the acknowledgement is removed, check this'
|
||||||
|
. ' option.'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'checkbox',
|
||||||
|
'expire',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Use Expire Time'),
|
||||||
|
'value' => $acknowledgeExpire,
|
||||||
|
'description' => $this->translate(
|
||||||
|
'If the acknowledgement should expire, check this option.'
|
||||||
|
),
|
||||||
|
'autosubmit' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
$expire = isset($formData['expire']) ? $formData['expire'] : $acknowledgeExpire;
|
||||||
|
if ($expire) {
|
||||||
|
$expireTime = new DateTime();
|
||||||
|
$expireTime->add(new DateInterval($config->get('settings', 'acknowledge_expire_time', 'PT1H')));
|
||||||
|
$this->addElement(
|
||||||
|
'dateTimePicker',
|
||||||
|
'expire_time',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Expire Time'),
|
||||||
|
'value' => $expireTime,
|
||||||
|
'description' => $this->translate(
|
||||||
|
'Enter the expire date and time for this acknowledgement here. Icinga will delete the'
|
||||||
|
. ' acknowledgement after this time expired.'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->addDisplayGroup(
|
||||||
|
array('expire', 'expire_time'),
|
||||||
|
'expire-expire_time',
|
||||||
|
array(
|
||||||
|
'decorators' => array(
|
||||||
|
'FormElements',
|
||||||
|
array('HtmlTag', array('tag' => 'div'))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$this->addElements(array(
|
||||||
|
array(
|
||||||
|
'checkbox',
|
||||||
|
'sticky',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Sticky Acknowledgement'),
|
||||||
|
'value' => (bool) $config->get('settings', 'acknowledge_sticky', false),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'If you want the acknowledgement to remain until the host or service recovers even if the host'
|
||||||
|
. ' or service changes state, check this option.'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'checkbox',
|
||||||
|
'notify',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Send Notification'),
|
||||||
|
'value' => (bool) $config->get('settings', 'acknowledge_notify', true),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'If you do not want an acknowledgement notification to be sent out to the appropriate contacts,'
|
||||||
|
. ' uncheck this option.'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
foreach ($this->objects as $object) {
|
||||||
|
/** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
|
||||||
|
$ack = new AcknowledgeProblemCommand();
|
||||||
|
$ack
|
||||||
|
->setObject($object)
|
||||||
|
->setComment($this->getElement('comment')->getValue())
|
||||||
|
->setAuthor($this->request->getUser()->getUsername())
|
||||||
|
->setPersistent($this->getElement('persistent')->isChecked())
|
||||||
|
->setSticky($this->getElement('sticky')->isChecked())
|
||||||
|
->setNotify($this->getElement('notify')->isChecked());
|
||||||
|
if ($this->getElement('expire')->isChecked()) {
|
||||||
|
$ack->setExpireTime($this->getElement('expire_time')->getValue()->getTimestamp());
|
||||||
|
}
|
||||||
|
$this->getTransport($this->request)->send($ack);
|
||||||
|
}
|
||||||
|
Notification::success($this->translatePlural(
|
||||||
|
'Acknowledging problem..',
|
||||||
|
'Acknowledging problems..',
|
||||||
|
count($this->objects)
|
||||||
|
));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,148 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||||
|
|
||||||
|
use DateInterval;
|
||||||
|
use DateTime;
|
||||||
|
use Icinga\Application\Config;
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\AddCommentCommand;
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for adding host or service comments
|
||||||
|
*/
|
||||||
|
class AddCommentCommandForm extends ObjectsCommandForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Initialize this form
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->addDescription($this->translate('This command is used to add host or service comments.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::getSubmitLabel() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function getSubmitLabel()
|
||||||
|
{
|
||||||
|
return $this->translatePlural('Add comment', 'Add comments', count($this->objects));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::createElements() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData = array())
|
||||||
|
{
|
||||||
|
$this->addElement(
|
||||||
|
'textarea',
|
||||||
|
'comment',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Comment'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'If you work with other administrators, you may find it useful to share information about'
|
||||||
|
. ' the host or service that is having problems. Make sure you enter a brief description of'
|
||||||
|
. ' what you are doing.'
|
||||||
|
),
|
||||||
|
'attribs' => array('class' => 'autofocus')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (! $this->getBackend()->isIcinga2()) {
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
'persistent',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Persistent'),
|
||||||
|
'value' => (bool) Config::module('monitoring')->get('settings', 'comment_persistent', true),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'If you uncheck this option, the comment will automatically be deleted the next time Icinga is'
|
||||||
|
. ' restarted.'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (version_compare($this->getBackend()->getProgramVersion(), '2.13.0', '>=')) {
|
||||||
|
$config = Config::module('monitoring');
|
||||||
|
$commentExpire = (bool) $config->get('settings', 'comment_expire', false);
|
||||||
|
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
'expire',
|
||||||
|
[
|
||||||
|
'label' => $this->translate('Use Expire Time'),
|
||||||
|
'value' => $commentExpire,
|
||||||
|
'description' => $this->translate('If the comment should expire, check this option.'),
|
||||||
|
'autosubmit' => true
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isset($formData['expire']) ? $formData['expire'] : $commentExpire) {
|
||||||
|
$expireTime = new DateTime();
|
||||||
|
$expireTime->add(new DateInterval($config->get('settings', 'comment_expire_time', 'PT1H')));
|
||||||
|
|
||||||
|
$this->addElement(
|
||||||
|
'dateTimePicker',
|
||||||
|
'expire_time',
|
||||||
|
[
|
||||||
|
'label' => $this->translate('Expire Time'),
|
||||||
|
'value' => $expireTime,
|
||||||
|
'description' => $this->translate(
|
||||||
|
'Enter the expire date and time for this comment here. Icinga will delete the'
|
||||||
|
. ' comment after this time expired.'
|
||||||
|
)
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->addDisplayGroup(
|
||||||
|
['expire', 'expire_time'],
|
||||||
|
'expire-expire_time',
|
||||||
|
[
|
||||||
|
'decorators' => [
|
||||||
|
'FormElements',
|
||||||
|
['HtmlTag', ['tag' => 'div']]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
foreach ($this->objects as $object) {
|
||||||
|
/** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
|
||||||
|
$comment = new AddCommentCommand();
|
||||||
|
$comment->setObject($object);
|
||||||
|
$comment->setComment($this->getElement('comment')->getValue());
|
||||||
|
$comment->setAuthor($this->request->getUser()->getUsername());
|
||||||
|
if (($persistent = $this->getElement('persistent')) !== null) {
|
||||||
|
$comment->setPersistent($persistent->isChecked());
|
||||||
|
}
|
||||||
|
|
||||||
|
$expire = $this->getElement('expire');
|
||||||
|
|
||||||
|
if ($expire !== null && $expire->isChecked()) {
|
||||||
|
$comment->setExpireTime($this->getElement('expire_time')->getValue()->getTimestamp());
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->getTransport($this->request)->send($comment);
|
||||||
|
}
|
||||||
|
Notification::success($this->translatePlural(
|
||||||
|
'Adding comment..',
|
||||||
|
'Adding comments..',
|
||||||
|
count($this->objects)
|
||||||
|
));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||||
|
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\ScheduleHostCheckCommand;
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\ScheduleServiceCheckCommand;
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for immediately checking hosts or services
|
||||||
|
*/
|
||||||
|
class CheckNowCommandForm extends ObjectsCommandForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Zend_Form::init() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setAttrib('class', 'inline');
|
||||||
|
$this->setSubmitLabel($this->translate('Check now'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::addSubmitButton() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function addSubmitButton()
|
||||||
|
{
|
||||||
|
$this->addElements(array(
|
||||||
|
array(
|
||||||
|
'button',
|
||||||
|
'btn_submit',
|
||||||
|
array(
|
||||||
|
'class' => 'link-button spinner',
|
||||||
|
'decorators' => array(
|
||||||
|
'ViewHelper',
|
||||||
|
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group form-controls'))
|
||||||
|
),
|
||||||
|
'escape' => false,
|
||||||
|
'ignore' => true,
|
||||||
|
'label' => $this->getView()->icon('arrows-cw') . $this->translate('Check now'),
|
||||||
|
'type' => 'submit',
|
||||||
|
'title' => $this->translate('Schedule the next active check to run immediately'),
|
||||||
|
'value' => $this->translate('Check now')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
foreach ($this->objects as $object) {
|
||||||
|
/** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
|
||||||
|
if (! $object->active_checks_enabled
|
||||||
|
&& ! $this->Auth()->hasPermission('monitoring/command/schedule-check')
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($object->getType() === $object::TYPE_HOST) {
|
||||||
|
$check = new ScheduleHostCheckCommand();
|
||||||
|
} else {
|
||||||
|
$check = new ScheduleServiceCheckCommand();
|
||||||
|
}
|
||||||
|
$check
|
||||||
|
->setObject($object)
|
||||||
|
->setForced()
|
||||||
|
->setCheckTime(time());
|
||||||
|
$this->getTransport($this->request)->send($check);
|
||||||
|
}
|
||||||
|
Notification::success(mtp(
|
||||||
|
'monitoring',
|
||||||
|
'Scheduling check..',
|
||||||
|
'Scheduling checks..',
|
||||||
|
count($this->objects)
|
||||||
|
));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,109 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||||
|
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\DeleteCommentCommand;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\CommandForm;
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for deleting host or service comments
|
||||||
|
*/
|
||||||
|
class DeleteCommentCommandForm extends CommandForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setAttrib('class', 'inline');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function addSubmitButton()
|
||||||
|
{
|
||||||
|
$this->addElement(
|
||||||
|
'button',
|
||||||
|
'btn_submit',
|
||||||
|
array(
|
||||||
|
'class' => 'link-button spinner',
|
||||||
|
'decorators' => array(
|
||||||
|
'ViewHelper',
|
||||||
|
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group form-controls'))
|
||||||
|
),
|
||||||
|
'escape' => false,
|
||||||
|
'ignore' => true,
|
||||||
|
'label' => $this->getView()->icon('cancel'),
|
||||||
|
'title' => $this->translate('Delete this comment'),
|
||||||
|
'type' => 'submit'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData = array())
|
||||||
|
{
|
||||||
|
$this->addElements(
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'hidden',
|
||||||
|
'comment_id',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'validators' => array('NotEmpty'),
|
||||||
|
'decorators' => array('ViewHelper')
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'hidden',
|
||||||
|
'comment_is_service',
|
||||||
|
array(
|
||||||
|
'filters' => array('Boolean'),
|
||||||
|
'decorators' => array('ViewHelper')
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'hidden',
|
||||||
|
'comment_name',
|
||||||
|
array(
|
||||||
|
'decorators' => array('ViewHelper')
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'hidden',
|
||||||
|
'redirect',
|
||||||
|
array(
|
||||||
|
'decorators' => array('ViewHelper')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
$cmd = new DeleteCommentCommand();
|
||||||
|
$cmd
|
||||||
|
->setAuthor($this->Auth()->getUser()->getUsername())
|
||||||
|
->setCommentId($this->getElement('comment_id')->getValue())
|
||||||
|
->setCommentName($this->getElement('comment_name')->getValue())
|
||||||
|
->setIsService($this->getElement('comment_is_service')->getValue());
|
||||||
|
$this->getTransport($this->request)->send($cmd);
|
||||||
|
$redirect = $this->getElement('redirect')->getValue();
|
||||||
|
if (! empty($redirect)) {
|
||||||
|
$this->setRedirectUrl($redirect);
|
||||||
|
}
|
||||||
|
Notification::success($this->translate('Deleting comment..'));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||||
|
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\DeleteCommentCommand;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\CommandForm;
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for deleting host or service comments
|
||||||
|
*/
|
||||||
|
class DeleteCommentsCommandForm extends CommandForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The comments to delete
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $comments;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setAttrib('class', 'inline');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the comments to delete
|
||||||
|
*
|
||||||
|
* @param iterable $comments
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setComments($comments)
|
||||||
|
{
|
||||||
|
$this->comments = $comments;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData = array())
|
||||||
|
{
|
||||||
|
$this->addElements(array(
|
||||||
|
array(
|
||||||
|
'hidden',
|
||||||
|
'redirect',
|
||||||
|
array('decorators' => array('ViewHelper'))
|
||||||
|
)
|
||||||
|
));
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getSubmitLabel()
|
||||||
|
{
|
||||||
|
return $this->translatePlural('Remove', 'Remove All', count($this->comments));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
foreach ($this->comments as $comment) {
|
||||||
|
$cmd = new DeleteCommentCommand();
|
||||||
|
$cmd
|
||||||
|
->setCommentId($comment->id)
|
||||||
|
->setCommentName($comment->name)
|
||||||
|
->setAuthor($this->Auth()->getUser()->getUsername())
|
||||||
|
->setIsService(isset($comment->service_description));
|
||||||
|
$this->getTransport($this->request)->send($cmd);
|
||||||
|
}
|
||||||
|
$redirect = $this->getElement('redirect')->getValue();
|
||||||
|
if (! empty($redirect)) {
|
||||||
|
$this->setRedirectUrl($redirect);
|
||||||
|
}
|
||||||
|
Notification::success(
|
||||||
|
$this->translatePlural('Deleting comment..', 'Deleting comments..', count($this->comments))
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||||
|
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\DeleteDowntimeCommand;
|
||||||
|
use Icinga\Module\Monitoring\Exception\CommandTransportException;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\CommandForm;
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for deleting host or service downtimes
|
||||||
|
*/
|
||||||
|
class DeleteDowntimeCommandForm extends CommandForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setAttrib('class', 'inline');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function addSubmitButton()
|
||||||
|
{
|
||||||
|
$this->addElement(
|
||||||
|
'button',
|
||||||
|
'btn_submit',
|
||||||
|
array(
|
||||||
|
'class' => 'link-button spinner',
|
||||||
|
'decorators' => array(
|
||||||
|
'ViewHelper',
|
||||||
|
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group form-controls'))
|
||||||
|
),
|
||||||
|
'escape' => false,
|
||||||
|
'ignore' => true,
|
||||||
|
'label' => $this->getView()->icon('cancel'),
|
||||||
|
'title' => $this->translate('Delete this downtime'),
|
||||||
|
'type' => 'submit'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData = array())
|
||||||
|
{
|
||||||
|
$this->addElements(
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'hidden',
|
||||||
|
'downtime_id',
|
||||||
|
array(
|
||||||
|
'decorators' => array('ViewHelper'),
|
||||||
|
'required' => true,
|
||||||
|
'validators' => array('NotEmpty')
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'hidden',
|
||||||
|
'downtime_is_service',
|
||||||
|
array(
|
||||||
|
'decorators' => array('ViewHelper'),
|
||||||
|
'filters' => array('Boolean')
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'hidden',
|
||||||
|
'downtime_name',
|
||||||
|
array(
|
||||||
|
'decorators' => array('ViewHelper')
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'hidden',
|
||||||
|
'redirect',
|
||||||
|
array(
|
||||||
|
'decorators' => array('ViewHelper')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
$cmd = new DeleteDowntimeCommand();
|
||||||
|
$cmd
|
||||||
|
->setAuthor($this->Auth()->getUser()->getUsername())
|
||||||
|
->setDowntimeId($this->getElement('downtime_id')->getValue())
|
||||||
|
->setDowntimeName($this->getElement('downtime_name')->getValue())
|
||||||
|
->setIsService($this->getElement('downtime_is_service')->getValue());
|
||||||
|
|
||||||
|
$errorMsg = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->getTransport($this->request)->send($cmd);
|
||||||
|
} catch (CommandTransportException $e) {
|
||||||
|
$errorMsg = $e->getMessage();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $errorMsg) {
|
||||||
|
$redirect = $this->getElement('redirect')->getValue();
|
||||||
|
Notification::success($this->translate('Deleting downtime.'));
|
||||||
|
} else {
|
||||||
|
if (! $this->getIsApiTarget()) {
|
||||||
|
$redirect = $this->getRequest()->getUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
Notification::error($errorMsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! empty($redirect)) {
|
||||||
|
$this->setRedirectUrl($redirect);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||||
|
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\DeleteDowntimeCommand;
|
||||||
|
use Icinga\Module\Monitoring\Exception\CommandTransportException;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\CommandForm;
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for deleting host or service downtimes
|
||||||
|
*/
|
||||||
|
class DeleteDowntimesCommandForm extends CommandForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The downtimes to delete
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $downtimes;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setAttrib('class', 'inline');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the downtimes to delete
|
||||||
|
*
|
||||||
|
* @param iterable $downtimes
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setDowntimes($downtimes)
|
||||||
|
{
|
||||||
|
$this->downtimes = $downtimes;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData = array())
|
||||||
|
{
|
||||||
|
$this->addElements(array(
|
||||||
|
array(
|
||||||
|
'hidden',
|
||||||
|
'redirect',
|
||||||
|
array('decorators' => array('ViewHelper'))
|
||||||
|
)
|
||||||
|
));
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getSubmitLabel()
|
||||||
|
{
|
||||||
|
return $this->translatePlural('Remove', 'Remove All', count($this->downtimes));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
foreach ($this->downtimes as $downtime) {
|
||||||
|
$delDowntime = new DeleteDowntimeCommand();
|
||||||
|
$delDowntime
|
||||||
|
->setDowntimeId($downtime->id)
|
||||||
|
->setDowntimeName($downtime->name)
|
||||||
|
->setAuthor($this->Auth()->getUser()->getUsername())
|
||||||
|
->setIsService(isset($downtime->service_description));
|
||||||
|
|
||||||
|
try {
|
||||||
|
$this->getTransport($this->request)->send($delDowntime);
|
||||||
|
} catch (CommandTransportException $e) {
|
||||||
|
// Negative lookahead because there may be messages from other endpoints with different status codes
|
||||||
|
if (preg_match('/Can\'t send external Icinga command: (?!404)/', $e->getMessage())) {
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$redirect = $this->getElement('redirect')->getValue();
|
||||||
|
if (! empty($redirect)) {
|
||||||
|
$this->setRedirectUrl($redirect);
|
||||||
|
}
|
||||||
|
Notification::success(
|
||||||
|
$this->translatePlural('Deleting downtime..', 'Deleting downtimes..', count($this->downtimes))
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||||
|
|
||||||
|
use Icinga\Module\Monitoring\Forms\Command\CommandForm;
|
||||||
|
use Icinga\Module\Monitoring\Object\MonitoredObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for Icinga object command forms
|
||||||
|
*/
|
||||||
|
abstract class ObjectsCommandForm extends CommandForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Involved Icinga objects
|
||||||
|
*
|
||||||
|
* @var array|\Traversable|\ArrayAccess
|
||||||
|
*/
|
||||||
|
protected $objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the involved Icinga objects
|
||||||
|
*
|
||||||
|
* @param $objects MonitoredObject|array|\Traversable|\ArrayAccess
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setObjects($objects)
|
||||||
|
{
|
||||||
|
if ($objects instanceof MonitoredObject) {
|
||||||
|
$this->objects = array($objects);
|
||||||
|
} else {
|
||||||
|
$this->objects = $objects;
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the involved Icinga objects
|
||||||
|
*
|
||||||
|
* @return array|\ArrayAccess|\Traversable
|
||||||
|
*/
|
||||||
|
public function getObjects()
|
||||||
|
{
|
||||||
|
return $this->objects;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,140 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||||
|
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\ProcessCheckResultCommand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for submitting a passive host or service check result
|
||||||
|
*/
|
||||||
|
class ProcessCheckResultCommandForm extends ObjectsCommandForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Initialize this form
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->addDescription($this->translate(
|
||||||
|
'This command is used to submit passive host or service check results.'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::getSubmitLabel() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function getSubmitLabel()
|
||||||
|
{
|
||||||
|
return $this->translatePlural(
|
||||||
|
'Submit Passive Check Result',
|
||||||
|
'Submit Passive Check Results',
|
||||||
|
count($this->objects)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::createElements() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData)
|
||||||
|
{
|
||||||
|
$object = null;
|
||||||
|
foreach ($this->getObjects() as $object) {
|
||||||
|
/** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
|
||||||
|
// Nasty, but as getObjects() returns everything but an object with a real
|
||||||
|
// iterator interface this is the only way to fetch just the first element
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addElement(
|
||||||
|
'select',
|
||||||
|
'status',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Status'),
|
||||||
|
'description' => $this->translate('The state this check result should report'),
|
||||||
|
'multiOptions' => $object->getType() === $object::TYPE_HOST ? $this->getHostMultiOptions() : array(
|
||||||
|
ProcessCheckResultCommand::SERVICE_OK => $this->translate('OK', 'icinga.state'),
|
||||||
|
ProcessCheckResultCommand::SERVICE_WARNING => $this->translate('WARNING', 'icinga.state'),
|
||||||
|
ProcessCheckResultCommand::SERVICE_CRITICAL => $this->translate('CRITICAL', 'icinga.state'),
|
||||||
|
ProcessCheckResultCommand::SERVICE_UNKNOWN => $this->translate('UNKNOWN', 'icinga.state')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->addElement(
|
||||||
|
'text',
|
||||||
|
'output',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Output'),
|
||||||
|
'description' => $this->translate('The plugin output of this check result')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->addElement(
|
||||||
|
'text',
|
||||||
|
'perfdata',
|
||||||
|
array(
|
||||||
|
'allowEmpty' => true,
|
||||||
|
'label' => $this->translate('Performance Data'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'The performance data of this check result. Leave empty'
|
||||||
|
. ' if this check result has no performance data'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
foreach ($this->objects as $object) {
|
||||||
|
/** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
|
||||||
|
if (! $object->passive_checks_enabled) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$command = new ProcessCheckResultCommand();
|
||||||
|
$command->setObject($object);
|
||||||
|
$command->setStatus($this->getValue('status'));
|
||||||
|
$command->setOutput($this->getValue('output'));
|
||||||
|
|
||||||
|
if ($perfdata = $this->getValue('perfdata')) {
|
||||||
|
$command->setPerformanceData($perfdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->getTransport($this->request)->send($command);
|
||||||
|
}
|
||||||
|
|
||||||
|
Notification::success($this->translatePlural(
|
||||||
|
'Processing check result..',
|
||||||
|
'Processing check results..',
|
||||||
|
count($this->objects)
|
||||||
|
));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the available host options based on the program version
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function getHostMultiOptions()
|
||||||
|
{
|
||||||
|
$options = array(
|
||||||
|
ProcessCheckResultCommand::HOST_UP => $this->translate('UP', 'icinga.state'),
|
||||||
|
ProcessCheckResultCommand::HOST_DOWN => $this->translate('DOWN', 'icinga.state')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (! $this->getBackend()->isIcinga2()) {
|
||||||
|
$options[ProcessCheckResultCommand::HOST_UNREACHABLE] = $this->translate('UNREACHABLE', 'icinga.state');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $options;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,122 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||||
|
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\RemoveAcknowledgementCommand;
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for removing host or service problem acknowledgements
|
||||||
|
*/
|
||||||
|
class RemoveAcknowledgementCommandForm extends ObjectsCommandForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Whether to show the submit label next to the remove icon
|
||||||
|
*
|
||||||
|
* 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()
|
||||||
|
{
|
||||||
|
$this->setAttrib('class', 'inline');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function addSubmitButton()
|
||||||
|
{
|
||||||
|
$this->addElement(
|
||||||
|
'button',
|
||||||
|
'btn_submit',
|
||||||
|
array(
|
||||||
|
'class' => 'link-button spinner',
|
||||||
|
'decorators' => array(
|
||||||
|
'ViewHelper',
|
||||||
|
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group form-controls'))
|
||||||
|
),
|
||||||
|
'escape' => false,
|
||||||
|
'ignore' => true,
|
||||||
|
'label' => $this->getSubmitLabel(),
|
||||||
|
'title' => $this->translatePlural(
|
||||||
|
'Remove acknowledgement',
|
||||||
|
'Remove acknowledgements',
|
||||||
|
count($this->objects)
|
||||||
|
),
|
||||||
|
'type' => 'submit'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getSubmitLabel()
|
||||||
|
{
|
||||||
|
$label = $this->getView()->icon('cancel');
|
||||||
|
if ($this->isLabelEnabled()) {
|
||||||
|
$label .= $this->translatePlural(
|
||||||
|
'Remove acknowledgement',
|
||||||
|
'Remove acknowledgements',
|
||||||
|
count($this->objects)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $label;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
foreach ($this->objects as $object) {
|
||||||
|
/** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
|
||||||
|
$removeAck = new RemoveAcknowledgementCommand();
|
||||||
|
$removeAck->setObject($object);
|
||||||
|
$removeAck->setAuthor($this->Auth()->getUser()->getUsername());
|
||||||
|
$this->getTransport($this->request)->send($removeAck);
|
||||||
|
}
|
||||||
|
Notification::success(mtp(
|
||||||
|
'monitoring',
|
||||||
|
'Removing acknowledgement..',
|
||||||
|
'Removing acknowledgements..',
|
||||||
|
count($this->objects)
|
||||||
|
));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||||
|
|
||||||
|
use Icinga\Application\Config;
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\ScheduleHostCheckCommand;
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for scheduling host checks
|
||||||
|
*/
|
||||||
|
class ScheduleHostCheckCommandForm extends ScheduleServiceCheckCommandForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::createElements() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData = array())
|
||||||
|
{
|
||||||
|
$config = Config::module('monitoring');
|
||||||
|
|
||||||
|
parent::createElements($formData);
|
||||||
|
$this->addElements(array(
|
||||||
|
array(
|
||||||
|
'checkbox',
|
||||||
|
'all_services',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('All Services'),
|
||||||
|
'value' => (bool) $config->get('settings', 'hostcheck_all_services', false),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'Schedule check for all services on the hosts and the hosts themselves.'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
foreach ($this->objects as $object) {
|
||||||
|
/** @var \Icinga\Module\Monitoring\Object\Host $object */
|
||||||
|
if (! $object->active_checks_enabled
|
||||||
|
&& ! $this->Auth()->hasPermission('monitoring/command/schedule-check')
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$check = new ScheduleHostCheckCommand();
|
||||||
|
$check
|
||||||
|
->setObject($object)
|
||||||
|
->setOfAllServices($this->getElement('all_services')->isChecked());
|
||||||
|
$this->scheduleCheck($check, $this->request);
|
||||||
|
}
|
||||||
|
Notification::success($this->translatePlural(
|
||||||
|
'Scheduling host check..',
|
||||||
|
'Scheduling host checks..',
|
||||||
|
count($this->objects)
|
||||||
|
));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,178 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||||
|
|
||||||
|
use DateInterval;
|
||||||
|
use DateTime;
|
||||||
|
use Icinga\Application\Config;
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\ApiScheduleHostDowntimeCommand;
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\PropagateHostDowntimeCommand;
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\ScheduleHostDowntimeCommand;
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\ScheduleServiceDowntimeCommand;
|
||||||
|
use Icinga\Module\Monitoring\Command\Transport\ApiCommandTransport;
|
||||||
|
use Icinga\Module\Monitoring\Command\Transport\CommandTransport;
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for scheduling host downtimes
|
||||||
|
*/
|
||||||
|
class ScheduleHostDowntimeCommandForm extends ScheduleServiceDowntimeCommandForm
|
||||||
|
{
|
||||||
|
/** @var bool */
|
||||||
|
protected $hostDowntimeAllServices;
|
||||||
|
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->start = new DateTime();
|
||||||
|
$config = Config::module('monitoring');
|
||||||
|
$this->commentText = $config->get('settings', 'hostdowntime_comment_text');
|
||||||
|
|
||||||
|
$this->hostDowntimeAllServices = (bool) $config->get('settings', 'hostdowntime_all_services', false);
|
||||||
|
|
||||||
|
$fixedEnd = clone $this->start;
|
||||||
|
$fixed = $config->get('settings', 'hostdowntime_end_fixed', 'PT1H');
|
||||||
|
$this->fixedEnd = $fixedEnd->add(new DateInterval($fixed));
|
||||||
|
|
||||||
|
$flexibleEnd = clone $this->start;
|
||||||
|
$flexible = $config->get('settings', 'hostdowntime_end_flexible', 'PT1H');
|
||||||
|
$this->flexibleEnd = $flexibleEnd->add(new DateInterval($flexible));
|
||||||
|
|
||||||
|
$flexibleDuration = $config->get('settings', 'hostdowntime_flexible_duration', 'PT2H');
|
||||||
|
$this->flexibleDuration = new DateInterval($flexibleDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::createElements() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData = array())
|
||||||
|
{
|
||||||
|
parent::createElements($formData);
|
||||||
|
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
'all_services',
|
||||||
|
array(
|
||||||
|
'description' => $this->translate(
|
||||||
|
'Schedule downtime for all services on the hosts and the hosts themselves.'
|
||||||
|
),
|
||||||
|
'label' => $this->translate('All Services'),
|
||||||
|
'value' => $this->hostDowntimeAllServices
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (! $this->getBackend()->isIcinga2()
|
||||||
|
|| version_compare($this->getBackend()->getProgramVersion(), '2.6.0', '>=')
|
||||||
|
) {
|
||||||
|
$this->addElement(
|
||||||
|
'select',
|
||||||
|
'child_hosts',
|
||||||
|
array(
|
||||||
|
'description' => $this->translate(
|
||||||
|
'Define what should be done with the child hosts of the hosts.'
|
||||||
|
),
|
||||||
|
'label' => $this->translate('Child Hosts'),
|
||||||
|
'multiOptions' => array(
|
||||||
|
0 => $this->translate('Do nothing with child hosts'),
|
||||||
|
1 => $this->translate('Schedule triggered downtime for all child hosts'),
|
||||||
|
2 => $this->translate('Schedule non-triggered downtime for all child hosts')
|
||||||
|
),
|
||||||
|
'value' => 0
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
$end = $this->getValue('end')->getTimestamp();
|
||||||
|
if ($end <= $this->getValue('start')->getTimestamp()) {
|
||||||
|
$endElement = $this->_elements['end'];
|
||||||
|
$endElement->setValue($endElement->getValue()->format($endElement->getFormat()));
|
||||||
|
$endElement->addError($this->translate('The end time must be greater than the start time'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$now = new DateTime;
|
||||||
|
if ($end <= $now->getTimestamp()) {
|
||||||
|
$endElement = $this->_elements['end'];
|
||||||
|
$endElement->setValue($endElement->getValue()->format($endElement->getFormat()));
|
||||||
|
$endElement->addError($this->translate('A downtime must not be in the past'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send all_services API parameter if Icinga is equal to or greater than 2.11.0
|
||||||
|
$allServicesNative = version_compare($this->getBackend()->getProgramVersion(), '2.11.0', '>=');
|
||||||
|
// Use ApiScheduleHostDowntimeCommand only when Icinga is equal to or greater than 2.11.0 and
|
||||||
|
// when an API command transport is requested or only API command transports are configured:
|
||||||
|
$useApiDowntime = $allServicesNative;
|
||||||
|
if ($useApiDowntime) {
|
||||||
|
$transport = $this->getTransport($this->getRequest());
|
||||||
|
if ($transport instanceof CommandTransport) {
|
||||||
|
foreach ($transport::getConfig() as $config) {
|
||||||
|
if (strtolower($config->transport) !== 'api') {
|
||||||
|
$useApiDowntime = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif (! $transport instanceof ApiCommandTransport) {
|
||||||
|
$useApiDowntime = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->objects as $object) {
|
||||||
|
if ($useApiDowntime) {
|
||||||
|
$hostDowntime = (new ApiScheduleHostDowntimeCommand())
|
||||||
|
->setForAllServices($this->getElement('all_services')->isChecked())
|
||||||
|
->setChildOptions((int) $this->getElement('child_hosts')->getValue());
|
||||||
|
// Code duplicated for readability and scope
|
||||||
|
$hostDowntime->setObject($object);
|
||||||
|
$this->scheduleDowntime($hostDowntime, $this->request);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var \Icinga\Module\Monitoring\Object\Host $object */
|
||||||
|
if (($childHostsEl = $this->getElement('child_hosts')) !== null) {
|
||||||
|
$childHosts = (int) $childHostsEl->getValue();
|
||||||
|
} else {
|
||||||
|
$childHosts = 0;
|
||||||
|
}
|
||||||
|
$allServices = $this->getElement('all_services')->isChecked();
|
||||||
|
if ($childHosts === 0) {
|
||||||
|
$hostDowntime = (new ScheduleHostDowntimeCommand())
|
||||||
|
->setForAllServicesNative($allServicesNative);
|
||||||
|
if ($allServices === true) {
|
||||||
|
$hostDowntime->setForAllServices();
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
$hostDowntime = new PropagateHostDowntimeCommand();
|
||||||
|
if ($childHosts === 1) {
|
||||||
|
$hostDowntime->setTriggered();
|
||||||
|
}
|
||||||
|
if ($allServices === true) {
|
||||||
|
foreach ($object->services as $service) {
|
||||||
|
$serviceDowntime = new ScheduleServiceDowntimeCommand();
|
||||||
|
$serviceDowntime->setObject($service);
|
||||||
|
$this->scheduleDowntime($serviceDowntime, $this->request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$hostDowntime->setObject($object);
|
||||||
|
$this->scheduleDowntime($hostDowntime, $this->request);
|
||||||
|
}
|
||||||
|
Notification::success($this->translatePlural(
|
||||||
|
'Scheduling host downtime..',
|
||||||
|
'Scheduling host downtimes..',
|
||||||
|
count($this->objects)
|
||||||
|
));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,112 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use DateInterval;
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\ScheduleServiceCheckCommand;
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
use Icinga\Web\Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for scheduling service checks
|
||||||
|
*/
|
||||||
|
class ScheduleServiceCheckCommandForm extends ObjectsCommandForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Initialize this form
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->addDescription($this->translate(
|
||||||
|
'This command is used to schedule the next check of hosts or services. Icinga will re-queue the'
|
||||||
|
. ' hosts or services to be checked at the time you specify.'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::getSubmitLabel() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function getSubmitLabel()
|
||||||
|
{
|
||||||
|
return $this->translatePlural('Schedule check', 'Schedule checks', count($this->objects));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::createElements() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData = array())
|
||||||
|
{
|
||||||
|
$checkTime = new DateTime();
|
||||||
|
$checkTime->add(new DateInterval('PT1H'));
|
||||||
|
$this->addElements(array(
|
||||||
|
array(
|
||||||
|
'dateTimePicker',
|
||||||
|
'check_time',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Check Time'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'Set the date and time when the check should be scheduled.'
|
||||||
|
),
|
||||||
|
'value' => $checkTime
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'checkbox',
|
||||||
|
'force_check',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Force Check'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'If you select this option, Icinga will force a check regardless of both what time the'
|
||||||
|
. ' scheduled check occurs and whether or not checks are enabled.'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule a check
|
||||||
|
*
|
||||||
|
* @param ScheduleServiceCheckCommand $check
|
||||||
|
* @param Request $request
|
||||||
|
*/
|
||||||
|
public function scheduleCheck(ScheduleServiceCheckCommand $check, Request $request)
|
||||||
|
{
|
||||||
|
$check
|
||||||
|
->setForced($this->getElement('force_check')->isChecked())
|
||||||
|
->setCheckTime($this->getElement('check_time')->getValue()->getTimestamp());
|
||||||
|
$this->getTransport($request)->send($check);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
foreach ($this->objects as $object) {
|
||||||
|
/** @var \Icinga\Module\Monitoring\Object\Service $object */
|
||||||
|
if (! $object->active_checks_enabled
|
||||||
|
&& ! $this->Auth()->hasPermission('monitoring/command/schedule-check')
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$check = new ScheduleServiceCheckCommand();
|
||||||
|
$check->setObject($object);
|
||||||
|
$this->scheduleCheck($check, $this->request);
|
||||||
|
}
|
||||||
|
Notification::success($this->translatePlural(
|
||||||
|
'Scheduling service check..',
|
||||||
|
'Scheduling service checks..',
|
||||||
|
count($this->objects)
|
||||||
|
));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,263 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use DateInterval;
|
||||||
|
use Icinga\Application\Config;
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\ScheduleServiceDowntimeCommand;
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
use Icinga\Web\Request;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for scheduling service downtimes
|
||||||
|
*/
|
||||||
|
class ScheduleServiceDowntimeCommandForm extends ObjectsCommandForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Fixed downtime
|
||||||
|
*/
|
||||||
|
const FIXED = 'fixed';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flexible downtime
|
||||||
|
*/
|
||||||
|
const FLEXIBLE = 'flexible';
|
||||||
|
|
||||||
|
/** @var DateTime downtime start */
|
||||||
|
protected $start;
|
||||||
|
|
||||||
|
/** @var DateTime fixed downtime end */
|
||||||
|
protected $fixedEnd;
|
||||||
|
|
||||||
|
/** @var DateTime flexible downtime end */
|
||||||
|
protected $flexibleEnd;
|
||||||
|
|
||||||
|
/** @var DateInterval flexible downtime duration */
|
||||||
|
protected $flexibleDuration;
|
||||||
|
|
||||||
|
/** @var mixed Comment text */
|
||||||
|
protected $commentText;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize this form
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->start = new DateTime();
|
||||||
|
|
||||||
|
$config = Config::module('monitoring');
|
||||||
|
|
||||||
|
$this->commentText = $config->get('settings', 'servicedowntime_comment_text');
|
||||||
|
$fixedEnd = clone $this->start;
|
||||||
|
$fixed = $config->get('settings', 'servicedowntime_end_fixed', 'PT1H');
|
||||||
|
$this->fixedEnd = $fixedEnd->add(new DateInterval($fixed));
|
||||||
|
|
||||||
|
$flexibleEnd = clone $this->start;
|
||||||
|
$flexible = $config->get('settings', 'servicedowntime_end_flexible', 'PT1H');
|
||||||
|
$this->flexibleEnd = $flexibleEnd->add(new DateInterval($flexible));
|
||||||
|
|
||||||
|
$flexibleDuration = $config->get('settings', 'servicedowntime_flexible_duration', 'PT2H');
|
||||||
|
$this->flexibleDuration = new DateInterval($flexibleDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::getSubmitLabel() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function getSubmitLabel()
|
||||||
|
{
|
||||||
|
return $this->translatePlural('Schedule downtime', 'Schedule downtimes', count($this->objects));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::createElements() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData = array())
|
||||||
|
{
|
||||||
|
$this->addDescription($this->translate(
|
||||||
|
'This command is used to schedule host and service downtimes. During the specified downtime,'
|
||||||
|
. ' Icinga will not send notifications out about the hosts and services. When the scheduled'
|
||||||
|
. ' downtime expires, Icinga will send out notifications for the hosts and services as it'
|
||||||
|
. ' normally would. Scheduled downtimes are preserved across program shutdowns and'
|
||||||
|
. ' restarts.'
|
||||||
|
));
|
||||||
|
|
||||||
|
$isFlexible = (bool) isset($formData['type']) && $formData['type'] === self::FLEXIBLE;
|
||||||
|
|
||||||
|
$this->addElements(array(
|
||||||
|
array(
|
||||||
|
'textarea',
|
||||||
|
'comment',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Comment'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'If you work with other administrators, you may find it useful to share information about'
|
||||||
|
. ' the host or service that is having problems. Make sure you enter a brief description of'
|
||||||
|
. ' what you are doing.'
|
||||||
|
),
|
||||||
|
'attribs' => array('class' => 'autofocus'),
|
||||||
|
'value' => $this->commentText
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'dateTimePicker',
|
||||||
|
'start',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Start Time'),
|
||||||
|
'description' => $this->translate('Set the start date and time for the downtime.'),
|
||||||
|
'value' => $this->start
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'dateTimePicker',
|
||||||
|
'end',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('End Time'),
|
||||||
|
'description' => $this->translate('Set the end date and time for the downtime.'),
|
||||||
|
'preserveDefault' => true,
|
||||||
|
'value' => $isFlexible ? $this->flexibleEnd : $this->fixedEnd
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'select',
|
||||||
|
'type',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'autosubmit' => true,
|
||||||
|
'label' => $this->translate('Type'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'If you select the fixed option, the downtime will be in effect between the start and end'
|
||||||
|
. ' times you specify whereas a flexible downtime starts when the host or service enters a'
|
||||||
|
. ' problem state sometime between the start and end times you specified and lasts as long'
|
||||||
|
. ' as the duration time you enter. The duration fields do not apply for fixed downtimes.'
|
||||||
|
),
|
||||||
|
'multiOptions' => array(
|
||||||
|
self::FIXED => $this->translate('Fixed'),
|
||||||
|
self::FLEXIBLE => $this->translate('Flexible')
|
||||||
|
),
|
||||||
|
'validators' => array(
|
||||||
|
array(
|
||||||
|
'InArray',
|
||||||
|
true,
|
||||||
|
array(array(self::FIXED, self::FLEXIBLE))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
$this->addDisplayGroup(
|
||||||
|
array('start', 'end'),
|
||||||
|
'start-end',
|
||||||
|
array(
|
||||||
|
'decorators' => array(
|
||||||
|
'FormElements',
|
||||||
|
array('HtmlTag', array('tag' => 'div'))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if ($isFlexible) {
|
||||||
|
$this->addElements(array(
|
||||||
|
array(
|
||||||
|
'number',
|
||||||
|
'hours',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Hours'),
|
||||||
|
'value' => $this->flexibleDuration->h,
|
||||||
|
'min' => -1
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'number',
|
||||||
|
'minutes',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Minutes'),
|
||||||
|
'value' => $this->flexibleDuration->m,
|
||||||
|
'min' => -1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
$this->addDisplayGroup(
|
||||||
|
array('hours', 'minutes'),
|
||||||
|
'duration',
|
||||||
|
array(
|
||||||
|
'legend' => $this->translate('Flexible Duration'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'Enter here the duration of the downtime. The downtime will be automatically deleted after this'
|
||||||
|
. ' time expired.'
|
||||||
|
),
|
||||||
|
'decorators' => array(
|
||||||
|
'FormElements',
|
||||||
|
array('HtmlTag', array('tag' => 'div')),
|
||||||
|
array(
|
||||||
|
'Description',
|
||||||
|
array('tag' => 'span', 'class' => 'description', 'placement' => 'prepend')
|
||||||
|
),
|
||||||
|
'Fieldset'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function scheduleDowntime(ScheduleServiceDowntimeCommand $downtime, Request $request)
|
||||||
|
{
|
||||||
|
$downtime
|
||||||
|
->setComment($this->getElement('comment')->getValue())
|
||||||
|
->setAuthor($request->getUser()->getUsername())
|
||||||
|
->setStart($this->getElement('start')->getValue()->getTimestamp())
|
||||||
|
->setEnd($this->getElement('end')->getValue()->getTimestamp());
|
||||||
|
if ($this->getElement('type')->getValue() === self::FLEXIBLE) {
|
||||||
|
$downtime->setFixed(false);
|
||||||
|
$downtime->setDuration(
|
||||||
|
(float) $this->getElement('hours')->getValue() * 3600
|
||||||
|
+ (float) $this->getElement('minutes')->getValue() * 60
|
||||||
|
);
|
||||||
|
}
|
||||||
|
$this->getTransport($request)->send($downtime);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
$end = $this->getValue('end')->getTimestamp();
|
||||||
|
if ($end <= $this->getValue('start')->getTimestamp()) {
|
||||||
|
$endElement = $this->_elements['end'];
|
||||||
|
$endElement->setValue($endElement->getValue()->format($endElement->getFormat()));
|
||||||
|
$endElement->addError($this->translate('The end time must be greater than the start time'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$now = new DateTime;
|
||||||
|
if ($end <= $now->getTimestamp()) {
|
||||||
|
$endElement = $this->_elements['end'];
|
||||||
|
$endElement->setValue($endElement->getValue()->format($endElement->getFormat()));
|
||||||
|
$endElement->addError($this->translate('A downtime must not be in the past'));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->objects as $object) {
|
||||||
|
/** @var \Icinga\Module\Monitoring\Object\Service $object */
|
||||||
|
$downtime = new ScheduleServiceDowntimeCommand();
|
||||||
|
$downtime->setObject($object);
|
||||||
|
$this->scheduleDowntime($downtime, $this->request);
|
||||||
|
}
|
||||||
|
Notification::success($this->translatePlural(
|
||||||
|
'Scheduling service downtime..',
|
||||||
|
'Scheduling service downtimes..',
|
||||||
|
count($this->objects)
|
||||||
|
));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,110 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||||
|
|
||||||
|
use Icinga\Application\Config;
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\SendCustomNotificationCommand;
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form to send custom notifications
|
||||||
|
*/
|
||||||
|
class SendCustomNotificationCommandForm extends ObjectsCommandForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Initialize this form
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->addDescription(
|
||||||
|
$this->translate('This command is used to send custom notifications about hosts or services.')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getSubmitLabel()
|
||||||
|
{
|
||||||
|
return $this->translatePlural('Send custom notification', 'Send custom notifications', count($this->objects));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData = array())
|
||||||
|
{
|
||||||
|
$config = Config::module('monitoring');
|
||||||
|
|
||||||
|
$this->addElements(array(
|
||||||
|
array(
|
||||||
|
'textarea',
|
||||||
|
'comment',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Comment'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'If you work with other administrators, you may find it useful to share information about'
|
||||||
|
. ' the host or service that is having problems. Make sure you enter a brief description of'
|
||||||
|
. ' what you are doing.'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'checkbox',
|
||||||
|
'forced',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Forced'),
|
||||||
|
'value' => (bool) $config->get('settings', 'custom_notification_forced', false),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'If you check this option, the notification is sent out regardless of time restrictions and'
|
||||||
|
. ' whether or not notifications are enabled.'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
if (! $this->getBackend()->isIcinga2()) {
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
'broadcast',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Broadcast'),
|
||||||
|
'value' => (bool) $config->get('settings', 'custom_notification_broadcast', false),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'If you check this option, the notification is sent out to all normal and escalated contacts.'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
foreach ($this->objects as $object) {
|
||||||
|
/** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
|
||||||
|
$notification = new SendCustomNotificationCommand();
|
||||||
|
$notification
|
||||||
|
->setObject($object)
|
||||||
|
->setComment($this->getElement('comment')->getValue())
|
||||||
|
->setAuthor($this->request->getUser()->getUsername())
|
||||||
|
->setForced($this->getElement('forced')->isChecked());
|
||||||
|
if (($broadcast = $this->getElement('broadcast')) !== null) {
|
||||||
|
$notification->setBroadcast($broadcast->isChecked());
|
||||||
|
}
|
||||||
|
$this->getTransport($this->request)->send($notification);
|
||||||
|
}
|
||||||
|
Notification::success($this->translatePlural(
|
||||||
|
'Sending custom notification..',
|
||||||
|
'Sending custom notifications..',
|
||||||
|
count($this->objects)
|
||||||
|
));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,187 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Command\Object;
|
||||||
|
|
||||||
|
use Icinga\Module\Monitoring\Command\Object\ToggleObjectFeatureCommand;
|
||||||
|
use Icinga\Module\Monitoring\Object\MonitoredObject;
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for enabling or disabling features of Icinga objects, i.e. hosts or services
|
||||||
|
*/
|
||||||
|
class ToggleObjectFeaturesCommandForm extends ObjectsCommandForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Feature to feature spec map
|
||||||
|
*
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
protected $features;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Feature to feature status map
|
||||||
|
*
|
||||||
|
* @var int[]
|
||||||
|
*/
|
||||||
|
protected $featureStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setUseFormAutosubmit();
|
||||||
|
$this->setAttrib('class', self::DEFAULT_CLASSES . ' object-features');
|
||||||
|
$features = array(
|
||||||
|
ToggleObjectFeatureCommand::FEATURE_ACTIVE_CHECKS => array(
|
||||||
|
'label' => $this->translate('Active Checks'),
|
||||||
|
'permission' => 'monitoring/command/feature/object/active-checks'
|
||||||
|
),
|
||||||
|
ToggleObjectFeatureCommand::FEATURE_PASSIVE_CHECKS => array(
|
||||||
|
'label' => $this->translate('Passive Checks'),
|
||||||
|
'permission' => 'monitoring/command/feature/object/passive-checks'
|
||||||
|
),
|
||||||
|
ToggleObjectFeatureCommand::FEATURE_OBSESSING => array(
|
||||||
|
'label' => $this->translate('Obsessing'),
|
||||||
|
'permission' => 'monitoring/command/feature/object/obsessing'
|
||||||
|
),
|
||||||
|
ToggleObjectFeatureCommand::FEATURE_NOTIFICATIONS => array(
|
||||||
|
'label' => $this->translate('Notifications'),
|
||||||
|
'permission' => 'monitoring/command/feature/object/notifications'
|
||||||
|
),
|
||||||
|
ToggleObjectFeatureCommand::FEATURE_EVENT_HANDLER => array(
|
||||||
|
'label' => $this->translate('Event Handler'),
|
||||||
|
'permission' => 'monitoring/command/feature/object/event-handler'
|
||||||
|
),
|
||||||
|
ToggleObjectFeatureCommand::FEATURE_FLAP_DETECTION => array(
|
||||||
|
'label' => $this->translate('Flap Detection'),
|
||||||
|
'permission' => 'monitoring/command/feature/object/flap-detection'
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if ($this->getBackend()->isIcinga2()) {
|
||||||
|
unset($features[ToggleObjectFeatureCommand::FEATURE_OBSESSING]);
|
||||||
|
}
|
||||||
|
$this->features = $features;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData = array())
|
||||||
|
{
|
||||||
|
foreach ($this->features as $feature => $spec) {
|
||||||
|
$options = array(
|
||||||
|
'autosubmit' => true,
|
||||||
|
'disabled' => $this->hasPermission($spec['permission']) ? null : 'disabled',
|
||||||
|
'label' => $spec['label']
|
||||||
|
);
|
||||||
|
if ($formData[$feature . '_changed']) {
|
||||||
|
$options['description'] = $this->translate('changed');
|
||||||
|
}
|
||||||
|
if ($formData[$feature] === 2) {
|
||||||
|
$this->addElement('select', $feature, $options + [
|
||||||
|
'description' => $this->translate('Multiple Values'),
|
||||||
|
'filters' => [['Null', ['type' => \Zend_Filter_Null::STRING]]],
|
||||||
|
'multiOptions' => [
|
||||||
|
'' => $this->translate('Leave Unchanged'),
|
||||||
|
$this->translate('Disable All'),
|
||||||
|
$this->translate('Enable All')
|
||||||
|
],
|
||||||
|
'decorators' => array_merge(
|
||||||
|
array_slice(static::$defaultElementDecorators, 0, 3),
|
||||||
|
[['Description', ['tag' => 'span']]],
|
||||||
|
array_slice(static::$defaultElementDecorators, 4, 1),
|
||||||
|
[['HtmlTag', ['tag' => 'div', 'class' => 'control-group indeterminate']]]
|
||||||
|
)
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
$options['value'] = $formData[$feature];
|
||||||
|
$this->addElement('checkbox', $feature, $options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load feature status
|
||||||
|
*
|
||||||
|
* @param MonitoredObject|object $object
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function load($object)
|
||||||
|
{
|
||||||
|
$featureStatus = array();
|
||||||
|
foreach (array_keys($this->features) as $feature) {
|
||||||
|
$featureStatus[$feature] = $object->{$feature};
|
||||||
|
if (isset($object->{$feature . '_changed'})) {
|
||||||
|
$featureStatus[$feature . '_changed'] = (bool) $object->{$feature . '_changed'};
|
||||||
|
} else {
|
||||||
|
$featureStatus[$feature . '_changed'] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->create($featureStatus);
|
||||||
|
$this->featureStatus = $featureStatus;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see \Icinga\Web\Form::onSuccess() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
$notifications = array(
|
||||||
|
ToggleObjectFeatureCommand::FEATURE_ACTIVE_CHECKS => array(
|
||||||
|
$this->translate('Enabling active checks..'),
|
||||||
|
$this->translate('Disabling active checks..')
|
||||||
|
),
|
||||||
|
ToggleObjectFeatureCommand::FEATURE_PASSIVE_CHECKS => array(
|
||||||
|
$this->translate('Enabling passive checks..'),
|
||||||
|
$this->translate('Disabling passive checks..')
|
||||||
|
),
|
||||||
|
ToggleObjectFeatureCommand::FEATURE_OBSESSING => array(
|
||||||
|
$this->translate('Enabling obsessing..'),
|
||||||
|
$this->translate('Disabling obsessing..')
|
||||||
|
),
|
||||||
|
ToggleObjectFeatureCommand::FEATURE_NOTIFICATIONS => array(
|
||||||
|
$this->translate('Enabling notifications..'),
|
||||||
|
$this->translate('Disabling notifications..')
|
||||||
|
),
|
||||||
|
ToggleObjectFeatureCommand::FEATURE_EVENT_HANDLER => array(
|
||||||
|
$this->translate('Enabling event handler..'),
|
||||||
|
$this->translate('Disabling event handler..')
|
||||||
|
),
|
||||||
|
ToggleObjectFeatureCommand::FEATURE_FLAP_DETECTION => array(
|
||||||
|
$this->translate('Enabling flap detection..'),
|
||||||
|
$this->translate('Disabling flap detection..')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($this->getValues() as $feature => $enabled) {
|
||||||
|
if ($this->getElement($feature)->getAttrib('disabled') !== null
|
||||||
|
|| $enabled === null
|
||||||
|
|| (int) $enabled === (int) $this->featureStatus[$feature]
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
foreach ($this->objects as $object) {
|
||||||
|
/** @var \Icinga\Module\Monitoring\Object\MonitoredObject $object */
|
||||||
|
if ((bool) $object->{$feature} !== (bool) $enabled) {
|
||||||
|
$toggleFeature = new ToggleObjectFeatureCommand();
|
||||||
|
$toggleFeature
|
||||||
|
->setFeature($feature)
|
||||||
|
->setObject($object)
|
||||||
|
->setEnabled($enabled);
|
||||||
|
$this->getTransport($this->request)->send($toggleFeature);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Notification::success(
|
||||||
|
$notifications[$feature][$enabled ? 0 : 1]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,367 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Config;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use Icinga\Application\Config;
|
||||||
|
use Icinga\Data\ConfigObject;
|
||||||
|
use Icinga\Data\ResourceFactory;
|
||||||
|
use Icinga\Exception\ConfigurationError;
|
||||||
|
use Icinga\Exception\IcingaException;
|
||||||
|
use Icinga\Exception\NotFoundError;
|
||||||
|
use Icinga\Forms\ConfigForm;
|
||||||
|
use Icinga\Web\Form;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for managing monitoring backends
|
||||||
|
*/
|
||||||
|
class BackendConfigForm extends ConfigForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The available monitoring backend resources split by type
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $resources;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The backend to load when displaying the form for the first time
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $backendToLoad;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize this form
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setName('form_config_monitoring_backends');
|
||||||
|
$this->setSubmitLabel($this->translate('Save Changes'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the resource configuration to use
|
||||||
|
*
|
||||||
|
* @param Config $resourceConfig The resource configuration
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws ConfigurationError In case there are no valid monitoring backend resources
|
||||||
|
*/
|
||||||
|
public function setResourceConfig(Config $resourceConfig)
|
||||||
|
{
|
||||||
|
$resources = array();
|
||||||
|
foreach ($resourceConfig as $name => $resource) {
|
||||||
|
if ($resource->type === 'db') {
|
||||||
|
$resources['ido'][$name] = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($resources)) {
|
||||||
|
throw new ConfigurationError($this->translate(
|
||||||
|
'Could not find any valid monitoring backend resources. Please configure a database resource first.'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->resources = $resources;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate the form with the given backend's config
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws NotFoundError In case no backend with the given name is found
|
||||||
|
*/
|
||||||
|
public function load($name)
|
||||||
|
{
|
||||||
|
if (! $this->config->hasSection($name)) {
|
||||||
|
throw new NotFoundError('No monitoring backend called "%s" found', $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->backendToLoad = $name;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new monitoring backend
|
||||||
|
*
|
||||||
|
* The backend to add is identified by the array-key `name'.
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException In case $data does not contain a backend name
|
||||||
|
* @throws IcingaException In case a backend with the same name already exists
|
||||||
|
*/
|
||||||
|
public function add(array $data)
|
||||||
|
{
|
||||||
|
if (! isset($data['name'])) {
|
||||||
|
throw new InvalidArgumentException('Key \'name\' missing');
|
||||||
|
}
|
||||||
|
|
||||||
|
$backendName = $data['name'];
|
||||||
|
if ($this->config->hasSection($backendName)) {
|
||||||
|
throw new IcingaException(
|
||||||
|
$this->translate('A monitoring backend with the name "%s" does already exist'),
|
||||||
|
$backendName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($data['name']);
|
||||||
|
$this->config->setSection($backendName, $data);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit a monitoring backend
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws NotFoundError In case no backend with the given name is found
|
||||||
|
*/
|
||||||
|
public function edit($name, array $data)
|
||||||
|
{
|
||||||
|
if (! $this->config->hasSection($name)) {
|
||||||
|
throw new NotFoundError('No monitoring backend called "%s" found', $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
$backendConfig = $this->config->getSection($name);
|
||||||
|
if (isset($data['name'])) {
|
||||||
|
if ($data['name'] !== $name) {
|
||||||
|
$this->config->removeSection($name);
|
||||||
|
$name = $data['name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($data['name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$backendConfig->merge($data);
|
||||||
|
$this->config->setSection($name, $backendConfig);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a monitoring backend
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function delete($name)
|
||||||
|
{
|
||||||
|
$this->config->removeSection($name);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and add elements to this form
|
||||||
|
*
|
||||||
|
* @param array $formData
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData)
|
||||||
|
{
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
'disabled',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Disable This Backend')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->addElement(
|
||||||
|
'text',
|
||||||
|
'name',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Backend Name'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'The name of this monitoring backend that is used to differentiate it from others'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$resourceType = isset($formData['type']) ? $formData['type'] : null;
|
||||||
|
|
||||||
|
$resourceTypes = array();
|
||||||
|
if ($resourceType === 'ido' || array_key_exists('ido', $this->resources)) {
|
||||||
|
$resourceTypes['ido'] = 'IDO Backend';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($resourceType === null) {
|
||||||
|
$resourceType = key($resourceTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addElement(
|
||||||
|
'select',
|
||||||
|
'type',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'autosubmit' => true,
|
||||||
|
'label' => $this->translate('Backend Type'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'The type of data source used for retrieving monitoring information'
|
||||||
|
),
|
||||||
|
'multiOptions' => $resourceTypes
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->addElement(
|
||||||
|
'select',
|
||||||
|
'resource',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Resource'),
|
||||||
|
'description' => $this->translate('The resource to use'),
|
||||||
|
'multiOptions' => $this->resources[$resourceType],
|
||||||
|
'value' => current($this->resources[$resourceType]),
|
||||||
|
'autosubmit' => true
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$resourceName = isset($formData['resource']) ? $formData['resource'] : $this->getValue('resource');
|
||||||
|
$this->addElement(
|
||||||
|
'note',
|
||||||
|
'resource_note',
|
||||||
|
array(
|
||||||
|
'escape' => false,
|
||||||
|
'value' => sprintf(
|
||||||
|
'<a href="%1$s" data-base-target="_next" title="%2$s" aria-label="%2$s">%3$s</a>',
|
||||||
|
$this->getView()->url('config/editresource', array('resource' => $resourceName)),
|
||||||
|
sprintf($this->translate('Show the configuration of the %s resource'), $resourceName),
|
||||||
|
$this->translate('Show resource configuration')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isset($formData['skip_validation']) && $formData['skip_validation']) {
|
||||||
|
// In case another error occured and the checkbox was displayed before
|
||||||
|
$this->addSkipValidationCheckbox();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate the configuration of the backend to load
|
||||||
|
*/
|
||||||
|
public function onRequest()
|
||||||
|
{
|
||||||
|
if ($this->backendToLoad) {
|
||||||
|
$data = $this->config->getSection($this->backendToLoad)->toArray();
|
||||||
|
$data['name'] = $this->backendToLoad;
|
||||||
|
$this->populate($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the given values are valid
|
||||||
|
*
|
||||||
|
* @param array $formData The data to validate
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function isValid($formData)
|
||||||
|
{
|
||||||
|
if (! parent::isValid($formData)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($el = $this->getElement('skip_validation')) === null || false === $el->isChecked()) {
|
||||||
|
$resourceConfig = ResourceFactory::getResourceConfig($this->getValue('resource'));
|
||||||
|
if (! self::isValidIdoSchema($this, $resourceConfig)
|
||||||
|
|| (! $this->getElement('disabled')->isChecked()
|
||||||
|
&& ! self::isValidIdoInstance($this, $resourceConfig))
|
||||||
|
) {
|
||||||
|
if ($el === null) {
|
||||||
|
$this->addSkipValidationCheckbox();
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a checkbox to the form by which the user can skip the schema validation
|
||||||
|
*/
|
||||||
|
protected function addSkipValidationCheckbox()
|
||||||
|
{
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
'skip_validation',
|
||||||
|
array(
|
||||||
|
'order' => 0,
|
||||||
|
'ignore' => true,
|
||||||
|
'label' => $this->translate('Skip Validation'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'Check this to not to validate the IDO schema of the chosen resource.'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether the given resource contains a valid IDO schema
|
||||||
|
*
|
||||||
|
* @param Form $form
|
||||||
|
* @param ConfigObject $resourceConfig
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public static function isValidIdoSchema(Form $form, ConfigObject $resourceConfig)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$db = ResourceFactory::createResource($resourceConfig);
|
||||||
|
$db->select()->from('icinga_dbversion', array('version'))->fetchOne();
|
||||||
|
} catch (Exception $_) {
|
||||||
|
$form->error($form->translate(
|
||||||
|
'Cannot find the IDO schema. Please verify that the given database '
|
||||||
|
. 'contains the schema and that the configured user has access to it.'
|
||||||
|
));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return whether a single icinga instance is writing to the given resource
|
||||||
|
*
|
||||||
|
* @param Form $form
|
||||||
|
* @param ConfigObject $resourceConfig
|
||||||
|
*
|
||||||
|
* @return bool True if it's a single instance, false if none
|
||||||
|
* or multiple instances are writing to it
|
||||||
|
*/
|
||||||
|
public static function isValidIdoInstance(Form $form, ConfigObject $resourceConfig)
|
||||||
|
{
|
||||||
|
$db = ResourceFactory::createResource($resourceConfig);
|
||||||
|
$rowCount = $db->select()->from('icinga_instances')->count();
|
||||||
|
|
||||||
|
if ($rowCount === 0) {
|
||||||
|
$form->warning($form->translate(
|
||||||
|
'There is currently no icinga instance writing to the IDO. Make sure '
|
||||||
|
. 'that a icinga instance is configured and able to write to the IDO.'
|
||||||
|
));
|
||||||
|
return false;
|
||||||
|
} elseif ($rowCount > 1) {
|
||||||
|
$form->warning($form->translate(
|
||||||
|
'There is currently more than one icinga instance writing to the IDO. You\'ll see all objects from all'
|
||||||
|
. ' instances without any differentation. If this is not desired, consider setting up a separate IDO'
|
||||||
|
. ' for each instance.'
|
||||||
|
));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Config;
|
||||||
|
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
use Icinga\Forms\ConfigForm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for modifying security relevant settings
|
||||||
|
*/
|
||||||
|
class SecurityConfigForm extends ConfigForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Initialize this form
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setName('form_config_monitoring_security');
|
||||||
|
$this->setSubmitLabel($this->translate('Save Changes'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Form::onSuccess()
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
$this->config->setSection('security', $this->getValues());
|
||||||
|
|
||||||
|
if ($this->save()) {
|
||||||
|
Notification::success($this->translate('New security configuration has successfully been stored'));
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Form::onRequest()
|
||||||
|
*/
|
||||||
|
public function onRequest()
|
||||||
|
{
|
||||||
|
$this->populate($this->config->getSection('security')->toArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see Form::createElements()
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData)
|
||||||
|
{
|
||||||
|
$this->addElement(
|
||||||
|
'text',
|
||||||
|
'protected_customvars',
|
||||||
|
array(
|
||||||
|
'allowEmpty' => true,
|
||||||
|
'attribs' => array('placeholder' => $this->getDefaultProtectedCustomvars()),
|
||||||
|
'label' => $this->translate('Protected Custom Variables'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'Comma separated case insensitive list of protected custom variables.'
|
||||||
|
. ' Use * as a placeholder for zero or more wildcard characters.'
|
||||||
|
. ' Existence of those custom variables will be shown, but their values will be masked.'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the customvars to suggest to protect when none are protected
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function getDefaultProtectedCustomvars()
|
||||||
|
{
|
||||||
|
return '*pw*,*pass*,community';
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2016 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Config\Transport;
|
||||||
|
|
||||||
|
use Icinga\Web\Form;
|
||||||
|
|
||||||
|
class ApiTransportForm extends Form
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setName('form_config_command_transport_api');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData = array())
|
||||||
|
{
|
||||||
|
$this->addElements(array(
|
||||||
|
array(
|
||||||
|
'text',
|
||||||
|
'host',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Host'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'Hostname or address of the remote Icinga instance'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'number',
|
||||||
|
'port',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'preserveDefault' => true,
|
||||||
|
'label' => $this->translate('Port'),
|
||||||
|
'description' => $this->translate('SSH port to connect to on the remote Icinga instance'),
|
||||||
|
'value' => 5665
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'text',
|
||||||
|
'username',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('API Username'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'User to log in as on the remote Icinga instance. Please note that key-based SSH login must be'
|
||||||
|
. ' possible for this user'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'password',
|
||||||
|
'password',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('API Password'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'User to log in as on the remote Icinga instance. Please note that key-based SSH login must be'
|
||||||
|
. ' possible for this user'
|
||||||
|
),
|
||||||
|
'renderPassword' => true
|
||||||
|
)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Config\Transport;
|
||||||
|
|
||||||
|
use Icinga\Web\Form;
|
||||||
|
|
||||||
|
class LocalTransportForm extends Form
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see Form::init() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setName('form_config_command_transport_local');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see Form::createElements() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData = array())
|
||||||
|
{
|
||||||
|
$this->addElement(
|
||||||
|
'text',
|
||||||
|
'path',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Command File'),
|
||||||
|
'value' => '/var/run/icinga2/cmd/icinga2.cmd',
|
||||||
|
'description' => $this->translate('Path to the local Icinga command file')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,185 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Config\Transport;
|
||||||
|
|
||||||
|
use Icinga\Data\ResourceFactory;
|
||||||
|
use Icinga\Exception\ConfigurationError;
|
||||||
|
use Icinga\Web\Form;
|
||||||
|
|
||||||
|
class RemoteTransportForm extends Form
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The available resources split by type
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $resources;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see Form::init() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setName('form_config_command_transport_remote');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load all available ssh identity resources
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws \Icinga\Exception\ConfigurationError
|
||||||
|
*/
|
||||||
|
public function loadResources()
|
||||||
|
{
|
||||||
|
$resourceConfig = ResourceFactory::getResourceConfigs();
|
||||||
|
|
||||||
|
$resources = array();
|
||||||
|
foreach ($resourceConfig as $name => $resource) {
|
||||||
|
if ($resource->type === 'ssh') {
|
||||||
|
$resources['ssh'][$name] = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($resources)) {
|
||||||
|
throw new ConfigurationError($this->translate('Could not find any valid SSH resources'));
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->resources = $resources;
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether ssh identity resources exists or not
|
||||||
|
*
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public function hasResources()
|
||||||
|
{
|
||||||
|
$resourceConfig = ResourceFactory::getResourceConfigs();
|
||||||
|
|
||||||
|
foreach ($resourceConfig as $name => $resource) {
|
||||||
|
if ($resource->type === 'ssh') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (non-PHPDoc)
|
||||||
|
* @see Form::createElements() For the method documentation.
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData = array())
|
||||||
|
{
|
||||||
|
$useResource = false;
|
||||||
|
|
||||||
|
if ($this->hasResources()) {
|
||||||
|
$useResource = isset($formData['use_resource'])
|
||||||
|
? $formData['use_resource'] : $this->getValue('use_resource');
|
||||||
|
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
'use_resource',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Use SSH Identity'),
|
||||||
|
'description' => $this->translate('Make use of the ssh identity resource'),
|
||||||
|
'autosubmit' => true,
|
||||||
|
'ignore' => true
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($useResource) {
|
||||||
|
$this->loadResources();
|
||||||
|
|
||||||
|
$decorators = static::$defaultElementDecorators;
|
||||||
|
array_pop($decorators); // Removes the HtmlTag decorator
|
||||||
|
|
||||||
|
$this->addElement(
|
||||||
|
'select',
|
||||||
|
'resource',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('SSH Identity'),
|
||||||
|
'description' => $this->translate('The resource to use'),
|
||||||
|
'decorators' => $decorators,
|
||||||
|
'multiOptions' => $this->resources['ssh'],
|
||||||
|
'value' => current($this->resources['ssh']),
|
||||||
|
'autosubmit' => false
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$resourceName = isset($formData['resource']) ? $formData['resource'] : $this->getValue('resource');
|
||||||
|
$this->addElement(
|
||||||
|
'note',
|
||||||
|
'resource_note',
|
||||||
|
array(
|
||||||
|
'escape' => false,
|
||||||
|
'decorators' => $decorators,
|
||||||
|
'value' => sprintf(
|
||||||
|
'<a href="%1$s" data-base-target="_next" title="%2$s" aria-label="%2$s">%3$s</a>',
|
||||||
|
$this->getView()->url('config/editresource', array('resource' => $resourceName)),
|
||||||
|
sprintf($this->translate('Show the configuration of the %s resource'), $resourceName),
|
||||||
|
$this->translate('Show resource configuration')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addElements(array(
|
||||||
|
array(
|
||||||
|
'text',
|
||||||
|
'host',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Host'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'Hostname or address of the remote Icinga instance'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'number',
|
||||||
|
'port',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'preserveDefault' => true,
|
||||||
|
'label' => $this->translate('Port'),
|
||||||
|
'description' => $this->translate('SSH port to connect to on the remote Icinga instance'),
|
||||||
|
'value' => 22
|
||||||
|
)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
if (! $useResource) {
|
||||||
|
$this->addElement(
|
||||||
|
'text',
|
||||||
|
'user',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('User'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'User to log in as on the remote Icinga instance. Please note that key-based SSH login must be'
|
||||||
|
. ' possible for this user'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addElement(
|
||||||
|
'text',
|
||||||
|
'path',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Command File'),
|
||||||
|
'value' => '/var/run/icinga2/cmd/icinga2.cmd',
|
||||||
|
'description' => $this->translate('Path to the Icinga command file on the remote Icinga instance')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,392 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Config;
|
||||||
|
|
||||||
|
use Icinga\Data\ConfigObject;
|
||||||
|
use Icinga\Module\Monitoring\Command\Transport\CommandTransport;
|
||||||
|
use Icinga\Module\Monitoring\Exception\CommandTransportException;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use Icinga\Application\Platform;
|
||||||
|
use Icinga\Exception\IcingaException;
|
||||||
|
use Icinga\Exception\NotFoundError;
|
||||||
|
use Icinga\Forms\ConfigForm;
|
||||||
|
use Icinga\Module\Monitoring\Command\Transport\ApiCommandTransport;
|
||||||
|
use Icinga\Module\Monitoring\Command\Transport\LocalCommandFile;
|
||||||
|
use Icinga\Module\Monitoring\Command\Transport\RemoteCommandFile;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Config\Transport\ApiTransportForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Config\Transport\LocalTransportForm;
|
||||||
|
use Icinga\Module\Monitoring\Forms\Config\Transport\RemoteTransportForm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for managing command transports
|
||||||
|
*/
|
||||||
|
class TransportConfigForm extends ConfigForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The transport to load when displaying the form for the first time
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $transportToLoad;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The names of all available Icinga instances
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $instanceNames;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var bool
|
||||||
|
*/
|
||||||
|
protected $validatePartial = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize this form
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setName('form_config_command_transports');
|
||||||
|
$this->setSubmitLabel($this->translate('Save Changes'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the names of all available Icinga instances
|
||||||
|
*
|
||||||
|
* @param array $names
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setInstanceNames(array $names)
|
||||||
|
{
|
||||||
|
$this->instanceNames = $names;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the names of all available Icinga instances
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getInstanceNames()
|
||||||
|
{
|
||||||
|
return $this->instanceNames ?: array();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a form object for the given transport type
|
||||||
|
*
|
||||||
|
* @param string $type The transport type for which to return a form
|
||||||
|
*
|
||||||
|
* @return \Icinga\Web\Form
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException In case the given transport type is invalid
|
||||||
|
*/
|
||||||
|
public function getTransportForm($type)
|
||||||
|
{
|
||||||
|
switch (strtolower($type)) {
|
||||||
|
case LocalCommandFile::TRANSPORT:
|
||||||
|
return new LocalTransportForm();
|
||||||
|
case RemoteCommandFile::TRANSPORT:
|
||||||
|
return new RemoteTransportForm();
|
||||||
|
case ApiCommandTransport::TRANSPORT:
|
||||||
|
return new ApiTransportForm();
|
||||||
|
default:
|
||||||
|
throw new InvalidArgumentException(
|
||||||
|
sprintf($this->translate('Invalid command transport type "%s" given'), $type)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate the form with the given transport's config
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws NotFoundError In case no transport with the given name is found
|
||||||
|
*/
|
||||||
|
public function load($name)
|
||||||
|
{
|
||||||
|
if (! $this->config->hasSection($name)) {
|
||||||
|
throw new NotFoundError('No command transport called "%s" found', $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->transportToLoad = $name;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new command transport
|
||||||
|
*
|
||||||
|
* The transport to add is identified by the array-key `name'.
|
||||||
|
*
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws InvalidArgumentException In case $data does not contain a transport name
|
||||||
|
* @throws IcingaException In case a transport with the same name already exists
|
||||||
|
*/
|
||||||
|
public function add(array $data)
|
||||||
|
{
|
||||||
|
if (! isset($data['name'])) {
|
||||||
|
throw new InvalidArgumentException('Key \'name\' missing');
|
||||||
|
}
|
||||||
|
|
||||||
|
$transportName = $data['name'];
|
||||||
|
if ($this->config->hasSection($transportName)) {
|
||||||
|
throw new IcingaException(
|
||||||
|
$this->translate('A command transport with the name "%s" does already exist'),
|
||||||
|
$transportName
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($data['name']);
|
||||||
|
$this->config->setSection($transportName, $data);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit an existing command transport
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
* @param array $data
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*
|
||||||
|
* @throws NotFoundError In case no transport with the given name is found
|
||||||
|
*/
|
||||||
|
public function edit($name, array $data)
|
||||||
|
{
|
||||||
|
if (! $this->config->hasSection($name)) {
|
||||||
|
throw new NotFoundError('No command transport called "%s" found', $name);
|
||||||
|
}
|
||||||
|
|
||||||
|
$transportConfig = $this->config->getSection($name);
|
||||||
|
if (isset($data['name'])) {
|
||||||
|
if ($data['name'] !== $name) {
|
||||||
|
$this->config->removeSection($name);
|
||||||
|
$name = $data['name'];
|
||||||
|
}
|
||||||
|
|
||||||
|
unset($data['name']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$transportConfig->merge($data);
|
||||||
|
$this->config->setSection($name, $transportConfig);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove a command transport
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function delete($name)
|
||||||
|
{
|
||||||
|
$this->config->removeSection($name);
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create and add elements to this form
|
||||||
|
*
|
||||||
|
* @param array $formData
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData)
|
||||||
|
{
|
||||||
|
$instanceNames = $this->getInstanceNames();
|
||||||
|
if (count($instanceNames) > 1) {
|
||||||
|
$options = array('none' => $this->translate('None', 'command transport instance association'));
|
||||||
|
$this->addElement(
|
||||||
|
'select',
|
||||||
|
'instance',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Instance Link'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'The name of the Icinga instance this transport should exclusively transfer commands to.'
|
||||||
|
),
|
||||||
|
'multiOptions' => array_merge($options, array_combine($instanceNames, $instanceNames))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addElement(
|
||||||
|
'text',
|
||||||
|
'name',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Transport Name'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'The name of this command transport that is used to differentiate it from others'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$transportTypes = array(
|
||||||
|
ApiCommandTransport::TRANSPORT => $this->translate('Icinga 2 API'),
|
||||||
|
LocalCommandFile::TRANSPORT => $this->translate('Local Command File'),
|
||||||
|
RemoteCommandFile::TRANSPORT => $this->translate('Remote Command File')
|
||||||
|
);
|
||||||
|
if (! Platform::extensionLoaded('curl')) {
|
||||||
|
unset($transportTypes[ApiCommandTransport::TRANSPORT]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$transportType = isset($formData['transport']) ? $formData['transport'] : null;
|
||||||
|
if ($transportType === null) {
|
||||||
|
$transportType = key($transportTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addElements(array(
|
||||||
|
array(
|
||||||
|
'select',
|
||||||
|
'transport',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'autosubmit' => true,
|
||||||
|
'label' => $this->translate('Transport Type'),
|
||||||
|
'multiOptions' => $transportTypes
|
||||||
|
)
|
||||||
|
)
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->addSubForm($this->getTransportForm($transportType)->create($formData), 'transport_form');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a submit button to this form and one to manually validate the configuration
|
||||||
|
*
|
||||||
|
* Calls parent::addSubmitButton() to add the submit button.
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function addSubmitButton()
|
||||||
|
{
|
||||||
|
parent::addSubmitButton();
|
||||||
|
|
||||||
|
if ($this->getSubForm('transport_form') instanceof ApiTransportForm) {
|
||||||
|
$btnSubmit = $this->getElement('btn_submit');
|
||||||
|
|
||||||
|
if ($btnSubmit !== null) {
|
||||||
|
// In the setup wizard $this is being used as a subform which doesn't have a submit button.
|
||||||
|
$this->addElement(
|
||||||
|
'submit',
|
||||||
|
'transport_validation',
|
||||||
|
array(
|
||||||
|
'ignore' => true,
|
||||||
|
'label' => $this->translate('Validate Configuration'),
|
||||||
|
'data-progress-label' => $this->translate('Validation In Progress'),
|
||||||
|
'decorators' => array('ViewHelper')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->setAttrib('data-progress-element', 'transport-progress');
|
||||||
|
$this->addElement(
|
||||||
|
'note',
|
||||||
|
'transport-progress',
|
||||||
|
array(
|
||||||
|
'decorators' => array(
|
||||||
|
'ViewHelper',
|
||||||
|
array('Spinner', array('id' => 'transport-progress'))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$elements = array('transport_validation', 'transport-progress');
|
||||||
|
|
||||||
|
$btnSubmit->setDecorators(array('ViewHelper'));
|
||||||
|
array_unshift($elements, 'btn_submit');
|
||||||
|
|
||||||
|
$this->addDisplayGroup(
|
||||||
|
$elements,
|
||||||
|
'submit_validation',
|
||||||
|
array(
|
||||||
|
'decorators' => array(
|
||||||
|
'FormElements',
|
||||||
|
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group form-controls'))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populate the configuration of the transport to load
|
||||||
|
*/
|
||||||
|
public function onRequest()
|
||||||
|
{
|
||||||
|
if ($this->transportToLoad) {
|
||||||
|
$data = $this->config->getSection($this->transportToLoad)->toArray();
|
||||||
|
$data['name'] = $this->transportToLoad;
|
||||||
|
$this->populate($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function isValidPartial(array $formData)
|
||||||
|
{
|
||||||
|
$isValidPartial = parent::isValidPartial($formData);
|
||||||
|
|
||||||
|
$transportValidation = $this->getElement('transport_validation');
|
||||||
|
if ($transportValidation !== null && $transportValidation->isChecked() && $this->isValid($formData)) {
|
||||||
|
$this->info($this->translate('The configuration has been successfully validated.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $isValidPartial;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function isValid($formData)
|
||||||
|
{
|
||||||
|
if (! parent::isValid($formData)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->getSubForm('transport_form') instanceof ApiTransportForm) {
|
||||||
|
if (! isset($formData['transport_validation'])
|
||||||
|
&& isset($formData['force_creation']) && $formData['force_creation']
|
||||||
|
) {
|
||||||
|
// ignore any validation result
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
CommandTransport::createTransport(new ConfigObject($this->getValues()))->probe();
|
||||||
|
} catch (CommandTransportException $e) {
|
||||||
|
$this->error(sprintf(
|
||||||
|
$this->translate('Failed to successfully validate the configuration: %s'),
|
||||||
|
$e->getMessage()
|
||||||
|
));
|
||||||
|
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
'force_creation',
|
||||||
|
array(
|
||||||
|
'order' => 0,
|
||||||
|
'ignore' => true,
|
||||||
|
'label' => $this->translate('Force Changes'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'Check this box to enforce changes without connectivity validation'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,87 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2017 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Config;
|
||||||
|
|
||||||
|
use Icinga\Application\Config;
|
||||||
|
use Icinga\Web\Form;
|
||||||
|
use Icinga\Web\Notification;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Form for reordering command transports
|
||||||
|
*/
|
||||||
|
class TransportReorderForm extends Form
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Initialize this form
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setName('form_reorder_command_transports');
|
||||||
|
$this->setViewScript('form/reorder-command-transports.phtml');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData)
|
||||||
|
{
|
||||||
|
// This adds just a dummy element to be able to utilize Form::getValue as part of onSuccess()
|
||||||
|
$this->addElement(
|
||||||
|
'hidden',
|
||||||
|
'transport_newpos',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'validators' => array(
|
||||||
|
array(
|
||||||
|
'validator' => 'regex',
|
||||||
|
'options' => array(
|
||||||
|
'pattern' => '/\A\d+\|/'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the command transport order and save the configuration
|
||||||
|
*/
|
||||||
|
public function onSuccess()
|
||||||
|
{
|
||||||
|
list($position, $transportName) = explode('|', $this->getValue('transport_newpos'), 2);
|
||||||
|
$config = $this->getConfig();
|
||||||
|
if (! $config->hasSection($transportName)) {
|
||||||
|
Notification::error(sprintf($this->translate('Command transport "%s" not found'), $transportName));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($config->count() > 1) {
|
||||||
|
$sections = $config->keys();
|
||||||
|
array_splice($sections, array_search($transportName, $sections, true), 1);
|
||||||
|
array_splice($sections, $position, 0, array($transportName));
|
||||||
|
|
||||||
|
$sectionsInNewOrder = array();
|
||||||
|
foreach ($sections as $section) {
|
||||||
|
$sectionsInNewOrder[$section] = $config->getSection($section);
|
||||||
|
$config->removeSection($section);
|
||||||
|
}
|
||||||
|
foreach ($sectionsInNewOrder as $name => $options) {
|
||||||
|
$config->setSection($name, $options);
|
||||||
|
}
|
||||||
|
|
||||||
|
$config->saveIni();
|
||||||
|
Notification::success($this->translate('Command transport order updated'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the command transports config
|
||||||
|
*
|
||||||
|
* @return Config
|
||||||
|
*/
|
||||||
|
public function getConfig()
|
||||||
|
{
|
||||||
|
return Config::module('monitoring', 'commandtransports');
|
||||||
|
}
|
||||||
|
}
|
||||||
157
modules/monitoring/application/forms/EventOverviewForm.php
Normal file
157
modules/monitoring/application/forms/EventOverviewForm.php
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms;
|
||||||
|
|
||||||
|
use Icinga\Web\Url;
|
||||||
|
use Icinga\Web\Form;
|
||||||
|
use Icinga\Data\Filter\Filter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configure the filter for the event overview
|
||||||
|
*/
|
||||||
|
class EventOverviewForm extends Form
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setName('form_event_overview');
|
||||||
|
$this->setDecorators(array(
|
||||||
|
'FormElements',
|
||||||
|
array('HtmlTag', array('tag' => 'div', 'class' => 'hbox')),
|
||||||
|
'Form'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData)
|
||||||
|
{
|
||||||
|
$decorators = array(
|
||||||
|
array('Label', array('class' => 'optional')),
|
||||||
|
'ViewHelper',
|
||||||
|
array('HtmlTag', array('tag' => 'div', 'class' => 'hbox-item optionbox')),
|
||||||
|
);
|
||||||
|
|
||||||
|
$url = Url::fromRequest()->getAbsoluteUrl();
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
'statechange',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('State Changes'),
|
||||||
|
'class' => 'autosubmit',
|
||||||
|
'decorators' => $decorators,
|
||||||
|
'value' => strpos($url, $this->stateChangeFilter()->toQueryString()) === false ? 0 : 1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
'downtime',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Downtimes'),
|
||||||
|
'class' => 'autosubmit',
|
||||||
|
'decorators' => $decorators,
|
||||||
|
'value' => strpos($url, $this->downtimeFilter()->toQueryString()) === false ? 0 : 1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
'comment',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Comments'),
|
||||||
|
'class' => 'autosubmit',
|
||||||
|
'decorators' => $decorators,
|
||||||
|
'value' => strpos($url, $this->commentFilter()->toQueryString()) === false ? 0 : 1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
'notification',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Notifications'),
|
||||||
|
'class' => 'autosubmit',
|
||||||
|
'decorators' => $decorators,
|
||||||
|
'value' => strpos($url, $this->notificationFilter()->toQueryString()) === false ? 0 : 1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$this->addElement(
|
||||||
|
'checkbox',
|
||||||
|
'flapping',
|
||||||
|
array(
|
||||||
|
'label' => $this->translate('Flapping'),
|
||||||
|
'class' => 'autosubmit',
|
||||||
|
'decorators' => $decorators,
|
||||||
|
'value' => strpos($url, $this->flappingFilter()->toQueryString()) === false ? 0 : 1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the corresponding filter-object
|
||||||
|
*
|
||||||
|
* @returns Filter
|
||||||
|
*/
|
||||||
|
public function getFilter()
|
||||||
|
{
|
||||||
|
$filters = array();
|
||||||
|
if ($this->getValue('statechange')) {
|
||||||
|
$filters[] = $this->stateChangeFilter();
|
||||||
|
}
|
||||||
|
if ($this->getValue('comment')) {
|
||||||
|
$filters[] = $this->commentFilter();
|
||||||
|
}
|
||||||
|
if ($this->getValue('notification')) {
|
||||||
|
$filters[] = $this->notificationFilter();
|
||||||
|
}
|
||||||
|
if ($this->getValue('downtime')) {
|
||||||
|
$filters[] = $this->downtimeFilter();
|
||||||
|
}
|
||||||
|
if ($this->getValue('flapping')) {
|
||||||
|
$filters[] = $this->flappingFilter();
|
||||||
|
}
|
||||||
|
return Filter::matchAny($filters);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function stateChangeFilter()
|
||||||
|
{
|
||||||
|
return Filter::matchAny(
|
||||||
|
Filter::expression('type', '=', 'hard_state'),
|
||||||
|
Filter::expression('type', '=', 'soft_state')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function commentFilter()
|
||||||
|
{
|
||||||
|
return Filter::matchAny(
|
||||||
|
Filter::expression('type', '=', 'comment'),
|
||||||
|
Filter::expression('type', '=', 'comment_deleted'),
|
||||||
|
Filter::expression('type', '=', 'dt_comment'),
|
||||||
|
Filter::expression('type', '=', 'dt_comment_deleted'),
|
||||||
|
Filter::expression('type', '=', 'ack')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function notificationFilter()
|
||||||
|
{
|
||||||
|
return Filter::expression('type', '=', 'notify');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function downtimeFilter()
|
||||||
|
{
|
||||||
|
return Filter::matchAny(
|
||||||
|
Filter::expression('type', '=', 'downtime_start'),
|
||||||
|
Filter::expression('type', '=', 'downtime_end')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function flappingFilter()
|
||||||
|
{
|
||||||
|
return Filter::matchAny(
|
||||||
|
Filter::expression('type', '=', 'flapping'),
|
||||||
|
Filter::expression('type', '=', 'flapping_deleted')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,79 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Navigation;
|
||||||
|
|
||||||
|
use Icinga\Data\Filter\Filter;
|
||||||
|
use Icinga\Exception\QueryException;
|
||||||
|
use Icinga\Forms\Navigation\NavigationItemForm;
|
||||||
|
|
||||||
|
class ActionForm extends NavigationItemForm
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function createElements(array $formData)
|
||||||
|
{
|
||||||
|
parent::createElements($formData);
|
||||||
|
|
||||||
|
$this->addElement(
|
||||||
|
'text',
|
||||||
|
'filter',
|
||||||
|
array(
|
||||||
|
'allowEmpty' => true,
|
||||||
|
'label' => $this->translate('Filter'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'Display this action only for objects matching this filter. Leave it blank'
|
||||||
|
. ' if you want this action being displayed regardless of the object'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function isValid($formData)
|
||||||
|
{
|
||||||
|
if (! parent::isValid($formData)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($filterString = $this->getValue('filter')) !== null) {
|
||||||
|
$filter = Filter::matchAll();
|
||||||
|
$filter->setAllowedFilterColumns(array(
|
||||||
|
'host_name',
|
||||||
|
'hostgroup_name',
|
||||||
|
'instance_name',
|
||||||
|
'service_description',
|
||||||
|
'servicegroup_name',
|
||||||
|
'contact_name',
|
||||||
|
'contactgroup_name',
|
||||||
|
function ($c) {
|
||||||
|
return preg_match('/^_(?:host|service)_/', $c);
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
try {
|
||||||
|
$filter->addFilter(Filter::fromQueryString($filterString));
|
||||||
|
} catch (QueryException $_) {
|
||||||
|
$this->getElement('filter')->addError(sprintf(
|
||||||
|
$this->translate('Invalid filter provided. You can only use the following columns: %s'),
|
||||||
|
implode(', ', array(
|
||||||
|
'instance_name',
|
||||||
|
'host_name',
|
||||||
|
'hostgroup_name',
|
||||||
|
'service_description',
|
||||||
|
'servicegroup_name',
|
||||||
|
'contact_name',
|
||||||
|
'contactgroup_name',
|
||||||
|
'_(host|service)_<customvar-name>'
|
||||||
|
))
|
||||||
|
));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Navigation;
|
||||||
|
|
||||||
|
class HostActionForm extends ActionForm
|
||||||
|
{
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2015 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Navigation;
|
||||||
|
|
||||||
|
class ServiceActionForm extends ActionForm
|
||||||
|
{
|
||||||
|
}
|
||||||
51
modules/monitoring/application/forms/Setup/BackendPage.php
Normal file
51
modules/monitoring/application/forms/Setup/BackendPage.php
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
/* Icinga Web 2 | (c) 2014 Icinga Development Team | GPLv2+ */
|
||||||
|
|
||||||
|
namespace Icinga\Module\Monitoring\Forms\Setup;
|
||||||
|
|
||||||
|
use Icinga\Web\Form;
|
||||||
|
use Icinga\Application\Platform;
|
||||||
|
|
||||||
|
class BackendPage extends Form
|
||||||
|
{
|
||||||
|
public function init()
|
||||||
|
{
|
||||||
|
$this->setName('setup_monitoring_backend');
|
||||||
|
$this->setTitle($this->translate('Monitoring Backend', 'setup.page.title'));
|
||||||
|
$this->addDescription($this->translate(
|
||||||
|
'Please configure below how Icinga Web 2 should retrieve monitoring information.'
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createElements(array $formData)
|
||||||
|
{
|
||||||
|
$this->addElement(
|
||||||
|
'text',
|
||||||
|
'name',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'value' => 'icinga',
|
||||||
|
'label' => $this->translate('Backend Name'),
|
||||||
|
'description' => $this->translate('The identifier of this backend')
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$resourceTypes = array();
|
||||||
|
if (Platform::hasMysqlSupport() || Platform::hasPostgresqlSupport()) {
|
||||||
|
$resourceTypes['ido'] = 'IDO';
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addElement(
|
||||||
|
'select',
|
||||||
|
'type',
|
||||||
|
array(
|
||||||
|
'required' => true,
|
||||||
|
'label' => $this->translate('Backend Type'),
|
||||||
|
'description' => $this->translate(
|
||||||
|
'The data source used for retrieving monitoring information'
|
||||||
|
),
|
||||||
|
'multiOptions' => $resourceTypes
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user