mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-07-21 04:44:25 +02:00
Merge branch 'master' into feature/packages-4075
This commit is contained in:
commit
4ea52161a9
@ -12,4 +12,6 @@ node default {
|
|||||||
file { '/etc/profile.d/env.sh':
|
file { '/etc/profile.d/env.sh':
|
||||||
source => 'puppet:////vagrant/.puppet/files/etc/profile.d/env.sh'
|
source => 'puppet:////vagrant/.puppet/files/etc/profile.d/env.sh'
|
||||||
}
|
}
|
||||||
|
@user { vagrant: ensure => present }
|
||||||
|
User <| title == vagrant |> { groups +> icingaweb }
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
# TODO(el): This module is not reuseable because it relies on vagrant paths
|
||||||
class icingacli {
|
class icingacli {
|
||||||
file { '/usr/local/bin/icingacli':
|
file { '/usr/local/bin/icingacli':
|
||||||
ensure => link,
|
ensure => link,
|
||||||
|
@ -6,6 +6,7 @@ namespace Icinga\Forms\Security;
|
|||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use LogicException;
|
use LogicException;
|
||||||
|
use Zend_Form_Element;
|
||||||
use Icinga\Application\Icinga;
|
use Icinga\Application\Icinga;
|
||||||
use Icinga\Forms\ConfigForm;
|
use Icinga\Forms\ConfigForm;
|
||||||
use Icinga\Util\String;
|
use Icinga\Util\String;
|
||||||
@ -18,14 +19,14 @@ class RoleForm extends ConfigForm
|
|||||||
/**
|
/**
|
||||||
* Provided permissions by currently loaded modules
|
* Provided permissions by currently loaded modules
|
||||||
*
|
*
|
||||||
* @var array
|
* @type array
|
||||||
*/
|
*/
|
||||||
protected $providedPermissions = array();
|
protected $providedPermissions = array('*' => '*');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provided restrictions by currently loaded modules
|
* Provided restrictions by currently loaded modules
|
||||||
*
|
*
|
||||||
* @var array
|
* @type array
|
||||||
*/
|
*/
|
||||||
protected $providedRestrictions = array();
|
protected $providedRestrictions = array();
|
||||||
|
|
||||||
@ -35,14 +36,26 @@ class RoleForm extends ConfigForm
|
|||||||
*/
|
*/
|
||||||
public function init()
|
public function init()
|
||||||
{
|
{
|
||||||
|
$helper = new Zend_Form_Element('bogus');
|
||||||
foreach (Icinga::app()->getModuleManager()->getLoadedModules() as $module) {
|
foreach (Icinga::app()->getModuleManager()->getLoadedModules() as $module) {
|
||||||
foreach ($module->getProvidedPermissions() as $permission) {
|
foreach ($module->getProvidedPermissions() as $permission) {
|
||||||
/** @var object $permission */
|
/** @type object $permission */
|
||||||
$this->providedPermissions[$permission->name] = $permission->name . ': ' . $permission->description;
|
$this->providedPermissions[$permission->name] = $permission->name . ': ' . $permission->description;
|
||||||
}
|
}
|
||||||
foreach ($module->getProvidedRestrictions() as $restriction) {
|
foreach ($module->getProvidedRestrictions() as $restriction) {
|
||||||
/** @var object $restriction */
|
/** @type object $restriction */
|
||||||
$this->providedRestrictions[$restriction->name] = $restriction->description;
|
$name = $helper->filterName($restriction->name); // Zend only permits alphanumerics, the underscore,
|
||||||
|
// the circumflex and any ASCII character in range
|
||||||
|
// \x7f to \xff (127 to 255)
|
||||||
|
while (isset($this->providedRestrictions[$name])) {
|
||||||
|
// Because Zend_Form_Element::filterName() replaces any not permitted character with the empty
|
||||||
|
// string we may have duplicate names, e.g. 're/striction' and 'restriction'
|
||||||
|
$name .= '_';
|
||||||
|
}
|
||||||
|
$this->providedRestrictions[$name] = array(
|
||||||
|
'description' => $restriction->description,
|
||||||
|
'name' => $restriction->name
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,13 +103,13 @@ class RoleForm extends ConfigForm
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
));
|
));
|
||||||
foreach ($this->providedRestrictions as $name => $description) {
|
foreach ($this->providedRestrictions as $name => $spec) {
|
||||||
$this->addElement(
|
$this->addElement(
|
||||||
'text',
|
'text',
|
||||||
$name,
|
$name,
|
||||||
array(
|
array(
|
||||||
'label' => $name,
|
'label' => $spec['name'],
|
||||||
'description' => $description
|
'description' => $spec['description']
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -129,6 +142,15 @@ class RoleForm extends ConfigForm
|
|||||||
? String::trimSplit($role['permissions'])
|
? String::trimSplit($role['permissions'])
|
||||||
: null;
|
: null;
|
||||||
$role['name'] = $name;
|
$role['name'] = $name;
|
||||||
|
$restrictions = array();
|
||||||
|
foreach ($this->providedRestrictions as $name => $spec) {
|
||||||
|
if (isset($role[$spec['name']])) {
|
||||||
|
// Translate restriction names to filtered element names
|
||||||
|
$restrictions[$name] = $role[$spec['name']];
|
||||||
|
unset($role[$spec['name']]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$role = array_merge($role, $restrictions);
|
||||||
$this->populate($role);
|
$this->populate($role);
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
@ -230,6 +252,15 @@ class RoleForm extends ConfigForm
|
|||||||
if (isset($values['permissions'])) {
|
if (isset($values['permissions'])) {
|
||||||
$values['permissions'] = implode(', ', $values['permissions']);
|
$values['permissions'] = implode(', ', $values['permissions']);
|
||||||
}
|
}
|
||||||
|
$restrictions = array();
|
||||||
|
foreach ($this->providedRestrictions as $name => $spec) {
|
||||||
|
if (isset($values[$name])) {
|
||||||
|
// Translate filtered element names to restriction names
|
||||||
|
$restrictions[$spec['name']] = $values[$name];
|
||||||
|
unset($values[$name]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$values = array_merge($values, $restrictions);
|
||||||
return $values;
|
return $values;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
<?php if ($configMissing): ?>
|
<?php if ($configMissing): ?>
|
||||||
<div class="config-note"><?= sprintf(
|
<div class="config-note"><?= sprintf(
|
||||||
t(
|
t(
|
||||||
'You seem not to have Icinga Web 2 configured yet so it\'s not possible to log in without any defined '
|
'It appears that you did not configure Icinga Web 2 yet so it\'s not possible to log in without any defined '
|
||||||
. 'authentication method. Please define a authentication method by following the instructions in the'
|
. 'authentication method. Please define a authentication method by following the instructions in the'
|
||||||
. ' %1$sdocumentation%3$s or by using our %2$sweb-based setup-wizard%3$s.'
|
. ' %1$sdocumentation%3$s or by using our %2$sweb-based setup-wizard%3$s.'
|
||||||
),
|
),
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
<td>
|
<td>
|
||||||
<?php
|
<?php
|
||||||
// TODO(el): $role->without(...) or $role->shift(...) would be nice!
|
// TODO(el): $role->without(...) or $role->shift(...) would be nice!
|
||||||
$restrictions = $role;
|
$restrictions = clone $role;
|
||||||
unset($restrictions['users']);
|
unset($restrictions['users']);
|
||||||
unset($restrictions['groups']);
|
unset($restrictions['groups']);
|
||||||
unset($restrictions['permissions']);
|
unset($restrictions['permissions']);
|
||||||
|
@ -2,21 +2,23 @@
|
|||||||
|
|
||||||
**Choosing the Authentication Method**
|
**Choosing the Authentication Method**
|
||||||
|
|
||||||
With Icinga Web 2 you can authenticate against Active Directory, LDAP, a MySQL or PostgreSQL database or delegate
|
With Icinga Web 2 you can authenticate against Active Directory, LDAP, a MySQL or a PostgreSQL database or delegate
|
||||||
authentication to the web server. Authentication methods can be chained to set up fallback authentication methods
|
authentication to the web server.
|
||||||
|
|
||||||
|
Authentication methods can be chained to set up fallback authentication methods
|
||||||
or if users are spread over multiple places.
|
or if users are spread over multiple places.
|
||||||
|
|
||||||
## Configuration
|
## <a id="authentication-configuration"></a> Configuration
|
||||||
|
|
||||||
Authentication methods are configured in the INI file **config/authentication.ini**.
|
Authentication methods are configured in the INI file **config/authentication.ini**.
|
||||||
|
|
||||||
Each section in the authentication configuration represents a single authentication method.
|
Each section in the authentication configuration represents a single authentication method.
|
||||||
|
|
||||||
The order of entries in the authentication configuration determines the order of the authentication methods.
|
The order of entries in the authentication configuration determines the order of the authentication methods.
|
||||||
If the current authentication method errors or the current authentication method does not know the account being
|
If the current authentication method errors or if the current authentication method does not know the account being
|
||||||
authenticated, the next authentication method will be used.
|
authenticated, the next authentication method will be used.
|
||||||
|
|
||||||
## External Authentication
|
### <a id="authentication-configuration-external-authentication"></a> External Authentication
|
||||||
|
|
||||||
For delegating authentication to the web server simply add `autologin` to your authentication configuration:
|
For delegating authentication to the web server simply add `autologin` to your authentication configuration:
|
||||||
|
|
||||||
@ -27,13 +29,13 @@ backend = autologin
|
|||||||
|
|
||||||
If your web server is not configured for authentication though the `autologin` section has no effect.
|
If your web server is not configured for authentication though the `autologin` section has no effect.
|
||||||
|
|
||||||
## Active Directory or LDAP Authentication
|
### <a id="authentication-configuration-ad-or-ldap-authentication"></a> Active Directory or LDAP Authentication
|
||||||
|
|
||||||
If you want to authenticate against Active Directory or LDAP, you have to define a
|
If you want to authenticate against Active Directory or LDAP, you have to define a
|
||||||
[LDAP resource](#resources-configuration-ldap) first which will be referenced as data source for the Active Directory
|
[LDAP resource](#resources-configuration-ldap) which will be referenced as data source for the Active Directory
|
||||||
or LDAP configuration method.
|
or LDAP configuration method.
|
||||||
|
|
||||||
### LDAP
|
#### <a id="authentication-configuration-ldap-authentication"></a> LDAP
|
||||||
|
|
||||||
Directive | Description
|
Directive | Description
|
||||||
------------------------|------------
|
------------------------|------------
|
||||||
@ -52,7 +54,7 @@ user_class = inetOrgPerson
|
|||||||
user_name_attribute = uid
|
user_name_attribute = uid
|
||||||
```
|
```
|
||||||
|
|
||||||
### Active Directory
|
#### <a id="authentication-configuration-ad-authentication"></a> Active Directory
|
||||||
|
|
||||||
Directive | Description
|
Directive | Description
|
||||||
------------------------|------------
|
------------------------|------------
|
||||||
@ -67,10 +69,10 @@ backend = ad
|
|||||||
resource = my_ad
|
resource = my_ad
|
||||||
```
|
```
|
||||||
|
|
||||||
## Database Authentication
|
### <a id="authentication-configuration-db-authentication"></a> Database Authentication
|
||||||
|
|
||||||
If you want to authenticate against a MySQL or PostgreSQL database, you have to define a
|
If you want to authenticate against a MySQL or a PostgreSQL database, you have to define a
|
||||||
[database resource](#resources-configuration-database) first which will be referenced as data source for the database
|
[database resource](#resources-configuration-database) which will be referenced as data source for the database
|
||||||
authentication method.
|
authentication method.
|
||||||
|
|
||||||
Directive | Description
|
Directive | Description
|
||||||
@ -83,13 +85,31 @@ Directive | Description
|
|||||||
```
|
```
|
||||||
[auth_ad]
|
[auth_ad]
|
||||||
backend = ad
|
backend = ad
|
||||||
resource = my_db
|
resource = icingaweb-mysql
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### <a id="authentication-configuration-db-setup"></a> Database Setup
|
||||||
|
|
||||||
|
For authenticating against a database, you have to import one of the following database schemas:
|
||||||
|
|
||||||
|
* **etc/schema/preferences.mysql.sql** (for **MySQL** database)
|
||||||
|
* **etc/schema/preferences.pgsql.sql** (for **PostgreSQL** databases)
|
||||||
|
|
||||||
|
After that you have to define the [database resource](#resources-configuration-database).
|
||||||
|
|
||||||
**Manually Creating Users**
|
**Manually Creating Users**
|
||||||
|
|
||||||
|
Icinga Web 2 uses the MD5 based BSD password algorithm. For generating a password hash, please use the following
|
||||||
|
command:
|
||||||
|
|
||||||
````
|
````
|
||||||
openssl passwd -1 "password"
|
openssl passwd -1 "password"
|
||||||
|
````
|
||||||
|
|
||||||
|
> Note: The switch to `openssl passwd` is the **number one** (`-1`) for using the MD5 based BSD password algorithm.
|
||||||
|
|
||||||
|
Insert the user into the database using the generated password hash:
|
||||||
|
|
||||||
|
````
|
||||||
INSERT INTO icingaweb_user (name, active, password_hash) VALUES ('icingaadmin', 1, 'hash from openssl');
|
INSERT INTO icingaweb_user (name, active, password_hash) VALUES ('icingaadmin', 1, 'hash from openssl');
|
||||||
````
|
````
|
||||||
|
@ -26,7 +26,7 @@ repository either via git or http protocol using the following URLs:
|
|||||||
* http://git.icinga.org/icingaweb2.git
|
* http://git.icinga.org/icingaweb2.git
|
||||||
|
|
||||||
There is also a browsable version available at
|
There is also a browsable version available at
|
||||||
[gi.icinga.org](https://git.icinga.org/?p=icingaweb2.git;a=summary "Icinga Web 2 Git Repository").
|
[git.icinga.org](https://git.icinga.org/?p=icingaweb2.git;a=summary "Icinga Web 2 Git Repository").
|
||||||
This version also offers snapshots for easy download which you can use if you do not have git present on your system.
|
This version also offers snapshots for easy download which you can use if you do not have git present on your system.
|
||||||
|
|
||||||
````
|
````
|
||||||
|
@ -1,101 +1,53 @@
|
|||||||
# Preferences
|
# <a id="preferences"></a> Preferences
|
||||||
|
|
||||||
Preferences are user based configuration for Icinga Web 2. For example max page
|
Preferences are settings a user can set for his account only, for example his language and time zone.
|
||||||
items, languages or date time settings can controlled by users.
|
|
||||||
|
|
||||||
# Architecture
|
**Choosing Where to Store Preferences**
|
||||||
|
|
||||||
Preferences are initially loaded from a provider (ini files or database) and
|
Preferences can be stored either in INI files or in a MySQL or in a PostgreSQL database. By default, Icinga Web 2 stores
|
||||||
stored into session at login time. After this step preferences are only
|
preferences in INI files beneath Icinga Web 2's configuration directory.
|
||||||
persisted to the configured backend, but never reloaded from them.
|
|
||||||
|
|
||||||
# Configuration
|
## <a id="preferences-configuration"></a> Configuration
|
||||||
|
|
||||||
Preferences can be configured in config.ini in **preferences** section, default
|
Where to store preferences is defined in the INI file **config/config.ini** in the *preferences* section.
|
||||||
settings are this:
|
|
||||||
|
|
||||||
[preferences]
|
### <a id="preferences-configuration-ini"></a> Store Preferences in INI Files
|
||||||
type=ini
|
|
||||||
|
|
||||||
The ini provider uses the directory **config/preferences** to create one ini
|
If preferences are stored in INI Files, Icinga Web 2 automatically creates one file per user using the username as
|
||||||
file per user and persists the data into a single file. If you want to drop your
|
file name for storing preferences. A INI file is created once a user saves changed preferences the first time.
|
||||||
preferences just drop the file from disk and you'll start with a new profile.
|
The files are located beneath the `preferences` directory beneath Icinga Web 2's configuration directory.
|
||||||
|
|
||||||
## Database Provider
|
For storing preferences in INI files you have to add the following section to the INI file **config/config.ini**:
|
||||||
|
|
||||||
To be more flexible in distributed setups you can store preferences in a
|
```
|
||||||
database (pgsql or mysql), a typical configuration looks like the following
|
[preferences]
|
||||||
example:
|
type = ini
|
||||||
|
````
|
||||||
|
|
||||||
[preferences]
|
### <a id="preferences-configuration-db"></a> Store Preferences in a Database
|
||||||
type=db
|
|
||||||
resource=icingaweb-pgsql
|
|
||||||
|
|
||||||
## Null Provider
|
In order to be more flexible in distributed setups you can store preferences in a MySQL or in a PostgreSQL database.
|
||||||
|
For storing preferences in a database, you have to define a [database resource](#resources-configuration-database)
|
||||||
|
which will be referenced as resource for the preferences storage.
|
||||||
|
|
||||||
The Null Provider discards all preferences and is mainly used as a fallback when no provider could be
|
Directive | Description
|
||||||
created (due to permission errors, database outtakes, etc.).
|
------------------------|------------
|
||||||
|
**type** | `db`
|
||||||
|
**resource** | The name of the database resource defined in [resources.ini](resources).
|
||||||
|
|
||||||
[preferences]
|
**Example:**
|
||||||
type=null
|
|
||||||
|
|
||||||
If your preferences aren't stored it's best to take a look into the logfiles - errors during the preference setup
|
```
|
||||||
are displayed as warnings here.
|
[preferences]
|
||||||
|
type = db
|
||||||
|
resource = icingaweb-mysql
|
||||||
|
```
|
||||||
|
|
||||||
### Settings
|
#### <a id="preferences-configuration-db-setup"></a> Database Setup
|
||||||
|
|
||||||
* **resource**: A reference to a database declared in *resources.ini*. Please read the chapter about
|
For storing preferences in a database, you have to import one of the following database schemas:
|
||||||
resources for a detailed description about how to set up resources.
|
|
||||||
|
|
||||||
### Preparation
|
* **etc/schema/preferences.mysql.sql** (for **MySQL** database)
|
||||||
|
* **etc/schema/preferences.pgsql.sql** (for **PostgreSQL** databases)
|
||||||
|
|
||||||
To use this feature you need a running database environment. After creating a
|
After that you have to define the [database resource](#resources-configuration-database).
|
||||||
database and a writable user you need to import the initial table file:
|
|
||||||
|
|
||||||
* etc/schema/preferences.mysql.sql (for mysql database)
|
|
||||||
* etc/schema/preferemces.pgsql.sql (for postgres databases)
|
|
||||||
|
|
||||||
#### Example for mysql
|
|
||||||
|
|
||||||
# mysql -u root -p
|
|
||||||
mysql> create database icingaweb;
|
|
||||||
mysql> GRANT SELECT,INSERT,UPDATE,DELETE ON icingaweb.* TO \
|
|
||||||
'icingaweb'@'localhost' IDENTIFIED BY 'icingaweb';
|
|
||||||
mysql> exit
|
|
||||||
# mysql -u root -p icingaweb < /path/to/icingaweb/etc/schema/preferences.mysql.sql
|
|
||||||
|
|
||||||
After following these steps above you can configure your preferences provider.
|
|
||||||
|
|
||||||
## Coding API
|
|
||||||
|
|
||||||
You can set, update or remove preferences using the Preference data object
|
|
||||||
which is bound to the user. Here are some simple examples how to work with
|
|
||||||
that:
|
|
||||||
|
|
||||||
$preferences = $user->getPreferences();
|
|
||||||
// Get language with en_US as fallback
|
|
||||||
$preferences->get('app.language', 'en_US');
|
|
||||||
$preferences->set('app.language', 'de_DE');
|
|
||||||
$preferences->remove('app.language');
|
|
||||||
|
|
||||||
// Using transactional mode
|
|
||||||
$preferences->startTransaction();
|
|
||||||
$preferences->set('test.pref1', 'pref1');
|
|
||||||
$preferences->set('test.pref2', 'pref2');
|
|
||||||
$preferences->remove('test.pref3');
|
|
||||||
$preferemces->commit(); // Stores 3 changes in one operation
|
|
||||||
|
|
||||||
More information can be found in the api docs.
|
|
||||||
|
|
||||||
## Namespaces and behaviour
|
|
||||||
|
|
||||||
If you are using this API please obey the following rules:
|
|
||||||
|
|
||||||
* Use dotted notation for preferences
|
|
||||||
* Namespaces starting with one context identifier
|
|
||||||
* **app** as global identified (e.g. app.language)
|
|
||||||
* **mymodule** for your module
|
|
||||||
* **monitoring** for the monitoring module
|
|
||||||
* Use preferences wisely (set only when needed and write small settings)
|
|
||||||
* Use only simple data types, e.g. strings or numbers
|
|
||||||
* If you need complex types you have to do it your self (e.g. serialization)
|
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
Icinga Web 2
|
|
||||||
|
|
||||||
@link https://www.icinga.org/icingaweb2/
|
|
||||||
@copyright Copyright (c) 2013-%(YEAR)s Icinga Development Team (https://www.icinga.org)
|
|
||||||
@license http://www.gnu.org/licenses/gpl-2.0.txt, or any later version
|
|
@ -23,16 +23,17 @@ class String
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uppercase the first character of each word in a string assuming and removing the underscore as word separator
|
* Uppercase the first character of each word in a string
|
||||||
*
|
*
|
||||||
* Converts 'first_name' to 'firstName' for example.
|
* Converts 'first_name' to 'firstName' for example.
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
|
* @param string $separator Word separator
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public static function cname($name)
|
public static function cname($name, $separator = '_')
|
||||||
{
|
{
|
||||||
return str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($name))));
|
return str_replace(' ', '', ucwords(str_replace($separator, ' ', strtolower($name))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
namespace Icinga\Util;
|
namespace Icinga\Util;
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use Icinga\Exception\IcingaException;
|
use Icinga\Exception\IcingaException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,8 +33,8 @@ class Translator
|
|||||||
*
|
*
|
||||||
* Falls back to the default domain in case the string cannot be translated using the given domain
|
* Falls back to the default domain in case the string cannot be translated using the given domain
|
||||||
*
|
*
|
||||||
* @param string $text The string to translate
|
* @param string $text The string to translate
|
||||||
* @param string $domain The primary domain to use
|
* @param string $domain The primary domain to use
|
||||||
* @param string|null $context Optional parameter for context based translation
|
* @param string|null $context Optional parameter for context based translation
|
||||||
*
|
*
|
||||||
* @return string The translated string
|
* @return string The translated string
|
||||||
@ -64,7 +63,7 @@ class Translator
|
|||||||
*
|
*
|
||||||
* @param string $textSingular The string in singular form to translate
|
* @param string $textSingular The string in singular form to translate
|
||||||
* @param string $textPlural The string in plural form to translate
|
* @param string $textPlural The string in plural form to translate
|
||||||
* @param integer $number The number to get the plural or singular string
|
* @param integer $number The amount to determine from whether to return singular or plural
|
||||||
* @param string $domain The primary domain to use
|
* @param string $domain The primary domain to use
|
||||||
* @param string|null $context Optional parameter for context based translation
|
* @param string|null $context Optional parameter for context based translation
|
||||||
*
|
*
|
||||||
|
@ -9,6 +9,7 @@ use Zend_Config;
|
|||||||
use Zend_Form;
|
use Zend_Form;
|
||||||
use Zend_View_Interface;
|
use Zend_View_Interface;
|
||||||
use Icinga\Application\Icinga;
|
use Icinga\Application\Icinga;
|
||||||
|
use Icinga\Util\Translator;
|
||||||
use Icinga\Web\Form\Decorator\NoScriptApply;
|
use Icinga\Web\Form\Decorator\NoScriptApply;
|
||||||
use Icinga\Web\Form\Element\CsrfCounterMeasure;
|
use Icinga\Web\Form\Element\CsrfCounterMeasure;
|
||||||
|
|
||||||
@ -147,7 +148,7 @@ class Form extends Zend_Form
|
|||||||
/**
|
/**
|
||||||
* Set a callback that is called instead of this form's onSuccess method
|
* Set a callback that is called instead of this form's onSuccess method
|
||||||
*
|
*
|
||||||
* It is called using the following signature: (Request $request, Form $form).
|
* It is called using the following signature: (Form $this).
|
||||||
*
|
*
|
||||||
* @param callable $onSuccess Callback
|
* @param callable $onSuccess Callback
|
||||||
*
|
*
|
||||||
@ -804,6 +805,57 @@ class Form extends Zend_Form
|
|||||||
return array();
|
return array();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the translation domain for this form
|
||||||
|
*
|
||||||
|
* The returned translation domain is either determined based on
|
||||||
|
* this form's class path or it is the default `icinga' domain
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
protected function getTranslationDomain()
|
||||||
|
{
|
||||||
|
if (preg_match('@^Icinga\\\\Module\\\\([A-z]+)\\\\.*$@', get_called_class(), $matches) === 1) {
|
||||||
|
return strtolower($matches[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'icinga';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translate a string
|
||||||
|
*
|
||||||
|
* @param string $text The string to translate
|
||||||
|
* @param string|null $context Optional parameter for context based translation
|
||||||
|
*
|
||||||
|
* @return string The translated string
|
||||||
|
*/
|
||||||
|
protected function translate($text, $context = null)
|
||||||
|
{
|
||||||
|
return Translator::translate($text, $this->getTranslationDomain(), $context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Translate a plural string
|
||||||
|
*
|
||||||
|
* @param string $textSingular The string in singular form to translate
|
||||||
|
* @param string $textPlural The string in plural form to translate
|
||||||
|
* @param integer $number The amount to determine from whether to return singular or plural
|
||||||
|
* @param string|null $context Optional parameter for context based translation
|
||||||
|
*
|
||||||
|
* @return string The translated string
|
||||||
|
*/
|
||||||
|
protected function translatePlural($textSingular, $textPlural, $number, $context = null)
|
||||||
|
{
|
||||||
|
return Translator::translatePlural(
|
||||||
|
$textSingular,
|
||||||
|
$textPlural,
|
||||||
|
$number,
|
||||||
|
$this->getTranslationDomain(),
|
||||||
|
$context
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render this form
|
* Render this form
|
||||||
*
|
*
|
||||||
|
5
library/Icinga/Web/Session/PhpSession.php
Normal file → Executable file
5
library/Icinga/Web/Session/PhpSession.php
Normal file → Executable file
@ -78,8 +78,9 @@ class PhpSession extends Session
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!is_writable(session_save_path())) {
|
$sessionSavePath = session_save_path();
|
||||||
throw new ConfigurationError('Can\'t save session');
|
if (session_module_name() === 'files' && !is_writable($sessionSavePath)) {
|
||||||
|
throw new ConfigurationError("Can't save session, path '$sessionSavePath' is not writable.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->exists()) {
|
if ($this->exists()) {
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
namespace Icinga\Web\Widget\Chart;
|
namespace Icinga\Web\Widget\Chart;
|
||||||
|
|
||||||
use Icinga\Chart\PieChart;
|
use Icinga\Chart\PieChart;
|
||||||
|
use Icinga\Module\Monitoring\Plugin\PerfdataSet;
|
||||||
use Icinga\Web\Widget\AbstractWidget;
|
use Icinga\Web\Widget\AbstractWidget;
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
use Icinga\Util\Format;
|
use Icinga\Util\Format;
|
||||||
@ -28,36 +29,23 @@ class InlinePie extends AbstractWidget
|
|||||||
const NUMBER_FORMAT_RATIO = 'ratio';
|
const NUMBER_FORMAT_RATIO = 'ratio';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The template string used for rendering this widget
|
|
||||||
* The template string used for rendering this widget
|
* The template string used for rendering this widget
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
private $template =<<<'EOD'
|
private $template =<<<'EOD'
|
||||||
<span
|
<span sparkType="pie" class="sparkline {class}" {title} {size} sparkSliceColors="[{colors}]" values="{data}">
|
||||||
class="sparkline"
|
</span>
|
||||||
sparkTitle="{title}"
|
{noscript}
|
||||||
sparkWidth="{width}"
|
|
||||||
sparkHeight="{height}"
|
|
||||||
sparkBorderWidth="{borderWidth}"
|
|
||||||
sparkBorderColor="{borderColor}"
|
|
||||||
sparkTooltipChartTitle="{title}"
|
|
||||||
style="{style}"
|
|
||||||
labels="{labels}"
|
|
||||||
formatted="{formatted}"
|
|
||||||
hideEmptyLabel={hideEmptyLabel}
|
|
||||||
values="{data}"
|
|
||||||
tooltipFormat="{tooltipFormat}"
|
|
||||||
sparkSliceColors="[{colors}]"
|
|
||||||
sparkType="pie"></span>
|
|
||||||
<noscript>
|
|
||||||
<img class="inlinepie"
|
|
||||||
title="{title}" src="{url}" style="position: relative; top: 10px; width: {width}px; height: {height}px; {style}"
|
|
||||||
data-icinga-colors="{colors}" data-icinga-values="{data}"
|
|
||||||
/>
|
|
||||||
</noscript>
|
|
||||||
EOD;
|
EOD;
|
||||||
|
|
||||||
|
private $noscript =<<<'EOD'
|
||||||
|
<noscript>
|
||||||
|
<img class="inlinepie {class}" {title} src="{url}" data-icinga-colors="{colors}" data-icinga-values="{data}"/>
|
||||||
|
</noscript>
|
||||||
|
EOD;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Url
|
* @var Url
|
||||||
*/
|
*/
|
||||||
@ -68,35 +56,7 @@ EOD;
|
|||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
private $colors = array('#44bb77', '#ffaa44', '#ff5566', '#ddccdd');
|
private $colors = array('#049BAF', '#ffaa44', '#ff5566', '#ddccdd');
|
||||||
|
|
||||||
/**
|
|
||||||
* The width of the rendered chart
|
|
||||||
*
|
|
||||||
* @var int The value in px
|
|
||||||
*/
|
|
||||||
private $width = 16;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The height of the rendered chart
|
|
||||||
*
|
|
||||||
* @var int The value in px
|
|
||||||
*/
|
|
||||||
private $height = 16;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* PieChart border width
|
|
||||||
*
|
|
||||||
* @var float
|
|
||||||
*/
|
|
||||||
private $borderWidth = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The color of the border
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $borderColor = '#fff';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The title of the chart
|
* The title of the chart
|
||||||
@ -106,11 +66,9 @@ EOD;
|
|||||||
private $title;
|
private $title;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The style for the HtmlElement
|
* @var
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
*/
|
||||||
private $style = '';
|
private $size;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The data displayed by the pie-chart
|
* The data displayed by the pie-chart
|
||||||
@ -120,45 +78,9 @@ EOD;
|
|||||||
private $data;
|
private $data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The labels to display for each data set
|
* @var
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
*/
|
||||||
private $labels = array();
|
private $class = '';
|
||||||
|
|
||||||
/**
|
|
||||||
* If the tooltip for the "empty" area should be hidden
|
|
||||||
*
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
private $hideEmptyLabel = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The format string used to display tooltips
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $tooltipFormat = '<b>{{title}}</b></br> {{label}}: {{formatted}} ({{percent}}%)';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The number format used to render numeric values in tooltips
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private $format = self::NUMBER_FORMAT_NONE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set if the tooltip for the empty area should be hidden
|
|
||||||
*
|
|
||||||
* @param bool $hide Whether to hide the empty area
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setHideEmptyLabel($hide = true)
|
|
||||||
{
|
|
||||||
$this->hideEmptyLabel = $hide;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the data to be displayed.
|
* Set the data to be displayed.
|
||||||
@ -175,24 +97,36 @@ EOD;
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The labels to be displayed in the pie-chart
|
* Set the size of the inline pie
|
||||||
*
|
*
|
||||||
* @param mixed $label The label of the displayed value, or null for no labels
|
* @param int $size Sets both, the height and width
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setLabel($label)
|
public function setSize($size = null)
|
||||||
{
|
{
|
||||||
if (is_array($label)) {
|
$this->size = $size;
|
||||||
$this->url->setParam('labels', implode(',', array_keys($label)));
|
return $this;
|
||||||
} elseif ($label != null) {
|
}
|
||||||
$labelArr = array($label, $label, $label, '');
|
|
||||||
$this->url->setParam('labels', implode(',', $labelArr));
|
/**
|
||||||
$label = $labelArr;
|
* Do not display the NoScript fallback html
|
||||||
} else {
|
*/
|
||||||
$this->url->removeKey('labels');
|
public function disableNoScript()
|
||||||
}
|
{
|
||||||
$this->labels = $label;
|
$this->noscript = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the class to define the
|
||||||
|
*
|
||||||
|
* @param $class
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function setSparklineClass($class)
|
||||||
|
{
|
||||||
|
$this->class = $class;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,105 +148,6 @@ EOD;
|
|||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the used number format
|
|
||||||
*
|
|
||||||
* @param $format string 'bytes' or 'time'
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setNumberFormat($format)
|
|
||||||
{
|
|
||||||
$this->format = $format;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A format string used to render the content of the piechart tooltips
|
|
||||||
*
|
|
||||||
* Placeholders using curly braces '{FOO}' are replace with their specific values. The format
|
|
||||||
* String may contain HTML-Markup. The available replaceable values are:
|
|
||||||
* <ul>
|
|
||||||
* <li><b>label</b>: The description for the current value </li>
|
|
||||||
* <li><b>formatted</b>: A string representing the formatted value </li>
|
|
||||||
* <li><b>value</b>: The raw (non-formatted) value used to render the piechart </li>
|
|
||||||
* <li><b>percent</b>: The percentage of the current value </li>
|
|
||||||
* </ul>
|
|
||||||
* Note: Changes will only affect JavaScript sparklines and not the SVG charts used for fallback
|
|
||||||
*
|
|
||||||
* @param $format
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setTooltipFormat($format)
|
|
||||||
{
|
|
||||||
$this->tooltipFormat = $format;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the height
|
|
||||||
*
|
|
||||||
* @param $height
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setHeight($height)
|
|
||||||
{
|
|
||||||
$this->height = $height;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the border width of the pie chart
|
|
||||||
*
|
|
||||||
* @param float $width Width in px
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setBorderWidth($width)
|
|
||||||
{
|
|
||||||
$this->borderWidth = $width;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the color of the pie chart border
|
|
||||||
*
|
|
||||||
* @param string $col The color string
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setBorderColor($col)
|
|
||||||
{
|
|
||||||
$this->borderColor = $col;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the width
|
|
||||||
*
|
|
||||||
* @param $width
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setWidth($width)
|
|
||||||
{
|
|
||||||
$this->width = $width;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the styling of the created HtmlElement
|
|
||||||
*
|
|
||||||
* @param string $style
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setStyle($style)
|
|
||||||
{
|
|
||||||
$this->style = $style;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the title of the displayed Data
|
* Set the title of the displayed Data
|
||||||
*
|
*
|
||||||
@ -322,7 +157,7 @@ EOD;
|
|||||||
*/
|
*/
|
||||||
public function setTitle($title)
|
public function setTitle($title)
|
||||||
{
|
{
|
||||||
$this->title = $title;
|
$this->title = 'title="' . htmlspecialchars($title) . '"';
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -335,13 +170,10 @@ EOD;
|
|||||||
*/
|
*/
|
||||||
public function __construct(array $data, $title, $colors = null)
|
public function __construct(array $data, $title, $colors = null)
|
||||||
{
|
{
|
||||||
$this->title = $title;
|
$this->setTitle($title);
|
||||||
$this->url = Url::fromPath('svg/chart.php');
|
$this->url = Url::fromPath('svg/chart.php');
|
||||||
if (array_key_exists('data', $data)) {
|
if (array_key_exists('data', $data)) {
|
||||||
$this->data = $data['data'];
|
$this->data = $data['data'];
|
||||||
if (array_key_exists('labels', $data)) {
|
|
||||||
$this->labels = $data['labels'];
|
|
||||||
}
|
|
||||||
if (array_key_exists('colors', $data)) {
|
if (array_key_exists('colors', $data)) {
|
||||||
$this->colors = $data['colors'];
|
$this->colors = $data['colors'];
|
||||||
}
|
}
|
||||||
@ -354,21 +186,6 @@ EOD;
|
|||||||
$this->setColors($this->colors);
|
$this->setColors($this->colors);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a serialization containing the current label array
|
|
||||||
*
|
|
||||||
* @return string A serialized array of labels
|
|
||||||
*/
|
|
||||||
private function createLabelString ()
|
|
||||||
{
|
|
||||||
$labels = $this->labels;
|
|
||||||
foreach ($labels as $key => $label) {
|
|
||||||
$labels[$key] = str_replace('|', '', $label);
|
|
||||||
}
|
|
||||||
return isset($this->labels) && is_array($this->labels) ? implode('|', $this->labels) : '';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders this widget via the given view and returns the
|
* Renders this widget via the given view and returns the
|
||||||
* HTML as a string
|
* HTML as a string
|
||||||
@ -382,11 +199,11 @@ EOD;
|
|||||||
$pie->alignTopLeft();
|
$pie->alignTopLeft();
|
||||||
$pie->disableLegend();
|
$pie->disableLegend();
|
||||||
$pie->drawPie(array(
|
$pie->drawPie(array(
|
||||||
'data' => $this->data, 'colors' => $this->colors, 'labels' => $this->labels
|
'data' => $this->data, 'colors' => $this->colors
|
||||||
));
|
));
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$png = $pie->toPng($this->width, $this->height);
|
$png = $pie->toPng($this->size, $this->size);
|
||||||
return '<img class="inlinepie" src="data:image/png;base64,' . base64_encode($png) . '" />';
|
return '<img class="inlinepie" src="data:image/png;base64,' . base64_encode($png) . '" />';
|
||||||
} catch (IcingaException $_) {
|
} catch (IcingaException $_) {
|
||||||
return '';
|
return '';
|
||||||
@ -394,17 +211,17 @@ EOD;
|
|||||||
}
|
}
|
||||||
|
|
||||||
$template = $this->template;
|
$template = $this->template;
|
||||||
|
// TODO: Check whether we are XHR and don't send
|
||||||
|
$template = str_replace('{noscript}', $this->noscript, $template);
|
||||||
$template = str_replace('{url}', $this->url, $template);
|
$template = str_replace('{url}', $this->url, $template);
|
||||||
|
$template = str_replace('{class}', $this->class, $template);
|
||||||
|
|
||||||
// style
|
// style
|
||||||
$template = str_replace('{width}', $this->width, $template);
|
$template = str_replace('{size}',
|
||||||
$template = str_replace('{height}', $this->height, $template);
|
isset($this->size) ? 'sparkWidth="' . $this->size . '" sparkHeight="' . $this->size . '" ' : '', $template);
|
||||||
$template = str_replace('{title}', htmlspecialchars($this->title), $template);
|
$template = str_replace('{title}', $this->title, $template);
|
||||||
$template = str_replace('{style}', $this->style, $template);
|
|
||||||
$template = str_replace('{colors}', implode(',', $this->colors), $template);
|
$template = str_replace('{colors}', implode(',', $this->colors), $template);
|
||||||
$template = str_replace('{borderWidth}', $this->borderWidth, $template);
|
|
||||||
$template = str_replace('{borderColor}', $this->borderColor, $template);
|
|
||||||
$template = str_replace('{hideEmptyLabel}', $this->hideEmptyLabel ? 'true' : 'false', $template);
|
|
||||||
|
|
||||||
// Locale-ignorant string cast. Please. Do. NOT. Remove. This. Again.
|
// Locale-ignorant string cast. Please. Do. NOT. Remove. This. Again.
|
||||||
// Problem is that implode respects locales when casting floats. This means
|
// Problem is that implode respects locales when casting floats. This means
|
||||||
@ -414,38 +231,7 @@ EOD;
|
|||||||
$data[] = sprintf('%F', $dat);
|
$data[] = sprintf('%F', $dat);
|
||||||
}
|
}
|
||||||
|
|
||||||
// values
|
|
||||||
$formatted = array();
|
|
||||||
foreach ($this->data as $key => $value) {
|
|
||||||
$formatted[$key] = $this->formatValue($value);
|
|
||||||
}
|
|
||||||
$template = str_replace('{data}', htmlspecialchars(implode(',', $data)), $template);
|
$template = str_replace('{data}', htmlspecialchars(implode(',', $data)), $template);
|
||||||
$template = str_replace('{formatted}', htmlspecialchars(implode('|', $formatted)), $template);
|
|
||||||
$template = str_replace('{labels}', htmlspecialchars($this->createLabelString()), $template);
|
|
||||||
$template = str_replace('{tooltipFormat}', $this->tooltipFormat, $template);
|
|
||||||
return $template;
|
return $template;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Format the given value depending on the current value of numberFormat
|
|
||||||
*
|
|
||||||
* @param float $value The value to format
|
|
||||||
*
|
|
||||||
* @return string The formatted value
|
|
||||||
*/
|
|
||||||
private function formatValue($value)
|
|
||||||
{
|
|
||||||
if ($this->format === self::NUMBER_FORMAT_NONE) {
|
|
||||||
return (string)$value;
|
|
||||||
} elseif ($this->format === self::NUMBER_FORMAT_BYTES) {
|
|
||||||
return Format::bytes($value);
|
|
||||||
} elseif ($this->format === self::NUMBER_FORMAT_TIME) {
|
|
||||||
return Format::duration($value);
|
|
||||||
} elseif ($this->format === self::NUMBER_FORMAT_RATIO) {
|
|
||||||
return $value;
|
|
||||||
} else {
|
|
||||||
Logger::warning('Unknown format string "' . $this->format . '" for InlinePie, value not formatted.');
|
|
||||||
return $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
namespace Icinga\Web\Widget\Tabextension;
|
namespace Icinga\Web\Widget\Tabextension;
|
||||||
|
|
||||||
|
use Icinga\Application\Platform;
|
||||||
use Icinga\Web\Url;
|
use Icinga\Web\Url;
|
||||||
use Icinga\Web\Widget\Tab;
|
use Icinga\Web\Widget\Tab;
|
||||||
use Icinga\Web\Widget\Tabs;
|
use Icinga\Web\Widget\Tabs;
|
||||||
@ -28,35 +29,6 @@ class OutputFormat implements Tabextension
|
|||||||
*/
|
*/
|
||||||
const TYPE_CSV = 'csv';
|
const TYPE_CSV = 'csv';
|
||||||
|
|
||||||
/**
|
|
||||||
* An array containing the tab definitions for all supported types
|
|
||||||
*
|
|
||||||
* Using array_keys on this array or isset allows to check whether a
|
|
||||||
* requested type is supported
|
|
||||||
*
|
|
||||||
* @var array
|
|
||||||
*/
|
|
||||||
private $supportedTypes = array(
|
|
||||||
self::TYPE_PDF => array(
|
|
||||||
'name' => 'pdf',
|
|
||||||
'title' => 'PDF',
|
|
||||||
'icon' => 'file-pdf',
|
|
||||||
'urlParams' => array('format' => 'pdf'),
|
|
||||||
),
|
|
||||||
self::TYPE_CSV => array(
|
|
||||||
'name' => 'csv',
|
|
||||||
'title' => 'CSV',
|
|
||||||
'icon' => 'file-excel',
|
|
||||||
'urlParams' => array('format' => 'csv')
|
|
||||||
),
|
|
||||||
self::TYPE_JSON => array(
|
|
||||||
'name' => 'json',
|
|
||||||
'title' => 'JSON',
|
|
||||||
'icon' => 'img/icons/json.png',
|
|
||||||
'urlParams' => array('format' => 'json')
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of tabs to be added to the dropdown area
|
* An array of tabs to be added to the dropdown area
|
||||||
*
|
*
|
||||||
@ -74,7 +46,7 @@ class OutputFormat implements Tabextension
|
|||||||
*/
|
*/
|
||||||
public function __construct(array $disabled = array())
|
public function __construct(array $disabled = array())
|
||||||
{
|
{
|
||||||
foreach ($this->supportedTypes as $type => $tabConfig) {
|
foreach ($this->getSupportedTypes() as $type => $tabConfig) {
|
||||||
if (!in_array($type, $disabled)) {
|
if (!in_array($type, $disabled)) {
|
||||||
$tabConfig['url'] = Url::fromRequest();
|
$tabConfig['url'] = Url::fromRequest();
|
||||||
$tabConfig['tagParams'] = array(
|
$tabConfig['tagParams'] = array(
|
||||||
@ -98,4 +70,44 @@ class OutputFormat implements Tabextension
|
|||||||
$tabs->addAsDropdown($tab->getName(), $tab);
|
$tabs->addAsDropdown($tab->getName(), $tab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array containing the tab definitions for all supported types
|
||||||
|
*
|
||||||
|
* Using array_keys on this array or isset allows to check whether a
|
||||||
|
* requested type is supported
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getSupportedTypes()
|
||||||
|
{
|
||||||
|
$supportedTypes = array();
|
||||||
|
|
||||||
|
if (Platform::extensionLoaded('gd')) {
|
||||||
|
$supportedTypes[self::TYPE_PDF] = array(
|
||||||
|
'name' => 'pdf',
|
||||||
|
'title' => 'PDF',
|
||||||
|
'icon' => 'file-pdf',
|
||||||
|
'urlParams' => array('format' => 'pdf'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$supportedTypes[self::TYPE_CSV] = array(
|
||||||
|
'name' => 'csv',
|
||||||
|
'title' => 'CSV',
|
||||||
|
'icon' => 'file-excel',
|
||||||
|
'urlParams' => array('format' => 'csv')
|
||||||
|
);
|
||||||
|
|
||||||
|
if (Platform::extensionLoaded('json')) {
|
||||||
|
$supportedTypes[self::TYPE_JSON] = array(
|
||||||
|
'name' => 'json',
|
||||||
|
'title' => 'JSON',
|
||||||
|
'icon' => 'img/icons/json.png',
|
||||||
|
'urlParams' => array('format' => 'json')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $supportedTypes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,8 +72,10 @@ class Monitoring_HostsController extends Controller
|
|||||||
'host_obsessing'*/
|
'host_obsessing'*/
|
||||||
));
|
));
|
||||||
$unhandledObjects = array();
|
$unhandledObjects = array();
|
||||||
|
$unhandledFilterExpressions = array();
|
||||||
$acknowledgedObjects = array();
|
$acknowledgedObjects = array();
|
||||||
$objectsInDowntime = array();
|
$objectsInDowntime = array();
|
||||||
|
$downtimeFilterExpressions = array();
|
||||||
$hostStates = array(
|
$hostStates = array(
|
||||||
Host::getStateText(Host::STATE_UP) => 0,
|
Host::getStateText(Host::STATE_UP) => 0,
|
||||||
Host::getStateText(Host::STATE_DOWN) => 0,
|
Host::getStateText(Host::STATE_DOWN) => 0,
|
||||||
@ -81,15 +83,17 @@ class Monitoring_HostsController extends Controller
|
|||||||
Host::getStateText(Host::STATE_PENDING) => 0,
|
Host::getStateText(Host::STATE_PENDING) => 0,
|
||||||
);
|
);
|
||||||
foreach ($this->hostList as $host) {
|
foreach ($this->hostList as $host) {
|
||||||
/** @var Service $host */
|
/** @var Host $host */
|
||||||
if ((bool) $host->problem === true && (bool) $host->handled === false) {
|
if ((bool) $host->problem === true && (bool) $host->handled === false) {
|
||||||
$unhandledObjects[] = $host;
|
$unhandledObjects[] = $host;
|
||||||
|
$unhandledFilterExpressions[] = Filter::where('host', $host->getName());
|
||||||
}
|
}
|
||||||
if ((bool) $host->acknowledged === true) {
|
if ((bool) $host->acknowledged === true) {
|
||||||
$acknowledgedObjects[] = $host;
|
$acknowledgedObjects[] = $host;
|
||||||
}
|
}
|
||||||
if ((bool) $host->in_downtime === true) {
|
if ((bool) $host->in_downtime === true) {
|
||||||
$objectsInDowntime[] = $host;
|
$objectsInDowntime[] = $host;
|
||||||
|
$downtimeFilterExpressions[] = Filter::where('downtime_host', $host->getName());
|
||||||
}
|
}
|
||||||
++$hostStates[$host::getStateText($host->state)];
|
++$hostStates[$host::getStateText($host->state)];
|
||||||
}
|
}
|
||||||
@ -108,16 +112,15 @@ class Monitoring_HostsController extends Controller
|
|||||||
$this->view->hostStates = $hostStates;
|
$this->view->hostStates = $hostStates;
|
||||||
$this->view->objects = $this->hostList;
|
$this->view->objects = $this->hostList;
|
||||||
$this->view->unhandledObjects = $unhandledObjects;
|
$this->view->unhandledObjects = $unhandledObjects;
|
||||||
$this->view->acknowledgeUnhandledLink = Url::fromRequest()
|
$unhandledFilterQueryString = Filter::matchAny($unhandledFilterExpressions)->toQueryString();
|
||||||
->setPath('monitoring/hosts/acknowledge-problem')
|
$this->view->acknowledgeUnhandledLink = Url::fromPath('monitoring/hosts/acknowledge-problem')
|
||||||
->addParams(array('host_problem' => 1, 'host_handled' => 0));
|
->setQueryString($unhandledFilterQueryString);
|
||||||
$this->view->downtimeUnhandledLink = Url::fromRequest()
|
$this->view->downtimeUnhandledLink = Url::fromPath('monitoring/hosts/schedule-downtime')
|
||||||
->setPath('monitoring/hosts/schedule-downtime')
|
->setQueryString($unhandledFilterQueryString);
|
||||||
->addParams(array('host_problem' => 1, 'host_handled' => 0));
|
|
||||||
$this->view->acknowledgedObjects = $acknowledgedObjects;
|
$this->view->acknowledgedObjects = $acknowledgedObjects;
|
||||||
$this->view->objectsInDowntime = $objectsInDowntime;
|
$this->view->objectsInDowntime = $objectsInDowntime;
|
||||||
$this->view->inDowntimeLink = Url::fromRequest()
|
$this->view->inDowntimeLink = Url::fromPath('monitoring/list/downtimes')
|
||||||
->setPath('monitoring/list/downtimes');
|
->setQueryString(Filter::matchAny($downtimeFilterExpressions)->toQueryString());
|
||||||
$this->view->havingCommentsLink = Url::fromRequest()
|
$this->view->havingCommentsLink = Url::fromRequest()
|
||||||
->setPath('monitoring/list/comments');
|
->setPath('monitoring/list/comments');
|
||||||
$this->view->hostStatesPieChart = $this->createPieChart(
|
$this->view->hostStatesPieChart = $this->createPieChart(
|
||||||
@ -131,9 +134,6 @@ class Monitoring_HostsController extends Controller
|
|||||||
{
|
{
|
||||||
$chart = new InlinePie(array_values($states), $title, $colors);
|
$chart = new InlinePie(array_values($states), $title, $colors);
|
||||||
return $chart
|
return $chart
|
||||||
->setLabel(array_map('strtoupper', array_keys($states)))
|
|
||||||
->setHeight(100)
|
|
||||||
->setWidth(100)
|
|
||||||
->setTitle($title);
|
->setTitle($title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,7 +221,7 @@ class Monitoring_MultiController extends Controller
|
|||||||
private function createPie($states, $colors, $title)
|
private function createPie($states, $colors, $title)
|
||||||
{
|
{
|
||||||
$chart = new InlinePie(array_values($states), $title, $colors);
|
$chart = new InlinePie(array_values($states), $title, $colors);
|
||||||
$chart->setLabel(array_keys($states))->setHeight(100)->setWidth(100);
|
$chart->setLabel(array_keys($states))->setSize(100);
|
||||||
$chart->setTitle($title);
|
$chart->setTitle($title);
|
||||||
return $chart;
|
return $chart;
|
||||||
}
|
}
|
||||||
|
@ -74,8 +74,10 @@ class Monitoring_ServicesController extends Controller
|
|||||||
'service_obsessing'*/
|
'service_obsessing'*/
|
||||||
));
|
));
|
||||||
$unhandledObjects = array();
|
$unhandledObjects = array();
|
||||||
|
$unhandledFilterExpressions = array();
|
||||||
$acknowledgedObjects = array();
|
$acknowledgedObjects = array();
|
||||||
$objectsInDowntime = array();
|
$objectsInDowntime = array();
|
||||||
|
$downtimeFilterExpressions = array();
|
||||||
$serviceStates = array(
|
$serviceStates = array(
|
||||||
Service::getStateText(Service::STATE_OK) => 0,
|
Service::getStateText(Service::STATE_OK) => 0,
|
||||||
Service::getStateText(Service::STATE_WARNING) => 0,
|
Service::getStateText(Service::STATE_WARNING) => 0,
|
||||||
@ -94,12 +96,20 @@ class Monitoring_ServicesController extends Controller
|
|||||||
/** @var Service $service */
|
/** @var Service $service */
|
||||||
if ((bool) $service->problem === true && (bool) $service->handled === false) {
|
if ((bool) $service->problem === true && (bool) $service->handled === false) {
|
||||||
$unhandledObjects[] = $service;
|
$unhandledObjects[] = $service;
|
||||||
|
$unhandledFilterExpressions[] = Filter::matchAll(
|
||||||
|
Filter::where('host', $service->getHost()->getName()),
|
||||||
|
Filter::where('service', $service->getName())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if ((bool) $service->acknowledged === true) {
|
if ((bool) $service->acknowledged === true) {
|
||||||
$acknowledgedObjects[] = $service;
|
$acknowledgedObjects[] = $service;
|
||||||
}
|
}
|
||||||
if ((bool) $service->in_downtime === true) {
|
if ((bool) $service->in_downtime === true) {
|
||||||
$objectsInDowntime[] = $service;
|
$objectsInDowntime[] = $service;
|
||||||
|
$downtimeFilterExpressions[] = Filter::matchAll(
|
||||||
|
Filter::where('downtime_host', $service->getHost()->getName()),
|
||||||
|
Filter::where('downtime_service', $service->getName())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
++$serviceStates[$service::getStateText($service->state)];
|
++$serviceStates[$service::getStateText($service->state)];
|
||||||
if (! isset($knownHostStates[$service->getHost()->getName()])) {
|
if (! isset($knownHostStates[$service->getHost()->getName()])) {
|
||||||
@ -125,16 +135,15 @@ class Monitoring_ServicesController extends Controller
|
|||||||
$this->view->serviceStates = $serviceStates;
|
$this->view->serviceStates = $serviceStates;
|
||||||
$this->view->objects = $this->serviceList;
|
$this->view->objects = $this->serviceList;
|
||||||
$this->view->unhandledObjects = $unhandledObjects;
|
$this->view->unhandledObjects = $unhandledObjects;
|
||||||
$this->view->acknowledgeUnhandledLink = Url::fromRequest()
|
$unhandledFilterQueryString = Filter::matchAny($unhandledFilterExpressions)->toQueryString();
|
||||||
->setPath('monitoring/services/acknowledge-problem')
|
$this->view->acknowledgeUnhandledLink = Url::fromPath('monitoring/services/acknowledge-problem')
|
||||||
->addParams(array('service_problem' => 1, 'service_handled' => 0));
|
->setQueryString($unhandledFilterQueryString);
|
||||||
$this->view->downtimeUnhandledLink = Url::fromRequest()
|
$this->view->downtimeUnhandledLink = Url::fromPath('monitoring/services/schedule-downtime')
|
||||||
->setPath('monitoring/services/schedule-downtime')
|
->setQueryString($unhandledFilterQueryString);
|
||||||
->addParams(array('service_problem' => 1, 'service_handled' => 0));
|
|
||||||
$this->view->acknowledgedObjects = $acknowledgedObjects;
|
$this->view->acknowledgedObjects = $acknowledgedObjects;
|
||||||
$this->view->objectsInDowntime = $objectsInDowntime;
|
$this->view->objectsInDowntime = $objectsInDowntime;
|
||||||
$this->view->inDowntimeLink = Url::fromRequest()
|
$this->view->inDowntimeLink = Url::fromPath('monitoring/list/downtimes')
|
||||||
->setPath('monitoring/list/downtimes');
|
->setQueryString(Filter::matchAny($downtimeFilterExpressions)->toQueryString());
|
||||||
$this->view->havingCommentsLink = Url::fromRequest()
|
$this->view->havingCommentsLink = Url::fromRequest()
|
||||||
->setPath('monitoring/list/comments');
|
->setPath('monitoring/list/comments');
|
||||||
$this->view->serviceStatesPieChart = $this->createPieChart(
|
$this->view->serviceStatesPieChart = $this->createPieChart(
|
||||||
@ -153,10 +162,10 @@ class Monitoring_ServicesController extends Controller
|
|||||||
{
|
{
|
||||||
$chart = new InlinePie(array_values($states), $title, $colors);
|
$chart = new InlinePie(array_values($states), $title, $colors);
|
||||||
return $chart
|
return $chart
|
||||||
->setLabel(array_map('strtoupper', array_keys($states)))
|
// ->setLabel(array_map('strtoupper', array_keys($states)))
|
||||||
->setHeight(100)
|
->setSize(50)
|
||||||
->setWidth(100)
|
->setTitle($title)
|
||||||
->setTitle($title);
|
->setSparklineClass('sparkline-multi');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -104,7 +104,7 @@ class AcknowledgeProblemCommandForm extends ObjectsCommandForm
|
|||||||
array(
|
array(
|
||||||
'decorators' => array(
|
'decorators' => array(
|
||||||
'FormElements',
|
'FormElements',
|
||||||
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
|
array('HtmlTag', array('tag' => 'div'))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -130,7 +130,7 @@ class ScheduleServiceDowntimeCommandForm extends ObjectsCommandForm
|
|||||||
array(
|
array(
|
||||||
'decorators' => array(
|
'decorators' => array(
|
||||||
'FormElements',
|
'FormElements',
|
||||||
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
|
array('HtmlTag', array('tag' => 'div'))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -169,7 +169,7 @@ class ScheduleServiceDowntimeCommandForm extends ObjectsCommandForm
|
|||||||
),
|
),
|
||||||
'decorators' => array(
|
'decorators' => array(
|
||||||
'FormElements',
|
'FormElements',
|
||||||
array('HtmlTag', array('tag' => 'div', 'class' => 'control-group')),
|
array('HtmlTag', array('tag' => 'div')),
|
||||||
array(
|
array(
|
||||||
'Description',
|
'Description',
|
||||||
array('tag' => 'span', 'class' => 'description', 'placement' => 'prepend')
|
array('tag' => 'span', 'class' => 'description', 'placement' => 'prepend')
|
||||||
|
@ -9,33 +9,36 @@ use Icinga\Module\Monitoring\Plugin\PerfdataSet;
|
|||||||
|
|
||||||
class Zend_View_Helper_Perfdata extends Zend_View_Helper_Abstract
|
class Zend_View_Helper_Perfdata extends Zend_View_Helper_Abstract
|
||||||
{
|
{
|
||||||
public function perfdata($perfdataStr, $compact = false)
|
|
||||||
|
/**
|
||||||
|
* Display the given perfdata string to the user
|
||||||
|
*
|
||||||
|
* @param $perfdataStr The perfdata string
|
||||||
|
* @param bool $compact Whether to display the perfdata in compact mode
|
||||||
|
* @param $color The color indicating the perfdata state
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function perfdata($perfdataStr, $compact = false, $color = Perfdata::PERFDATA_DEFAULT)
|
||||||
{
|
{
|
||||||
$pset = PerfdataSet::fromString($perfdataStr)->asArray();
|
$pieChartData = PerfdataSet::fromString($perfdataStr)->asArray();
|
||||||
$onlyPieChartData = array_filter($pset, function ($e) { return $e->getPercentage() > 0; });
|
|
||||||
if ($compact) {
|
|
||||||
$onlyPieChartData = array_slice($onlyPieChartData, 0, 5);
|
|
||||||
} else {
|
|
||||||
$nonPieChartData = array_filter($pset, function ($e) { return $e->getPercentage() == 0; });
|
|
||||||
}
|
|
||||||
|
|
||||||
$result = '';
|
$result = '';
|
||||||
$table = array();
|
$table = array();
|
||||||
foreach ($onlyPieChartData as $perfdata) {
|
foreach ($pieChartData as $perfdata) {
|
||||||
$pieChart = $this->createInlinePie($perfdata);
|
if ($perfdata->isVisualizable()) {
|
||||||
if ($compact) {
|
$pieChart = $perfdata->asInlinePie($color);
|
||||||
$result .= $pieChart->render();
|
if ($compact) {
|
||||||
} else {
|
$result .= $pieChart->render();
|
||||||
if (! $perfdata->isPercentage()) {
|
} else {
|
||||||
// TODO: Should we trust sprintf-style placeholders in perfdata titles?
|
$table[] = '<tr><th>' . $pieChart->render()
|
||||||
$pieChart->setTooltipFormat('{{label}}: {{formatted}} ({{percent}}%)');
|
. htmlspecialchars($perfdata->getLabel())
|
||||||
|
. '</th><td> '
|
||||||
|
. htmlspecialchars($this->formatPerfdataValue($perfdata)) .
|
||||||
|
' </td></tr>';
|
||||||
}
|
}
|
||||||
// $pieChart->setStyle('margin: 0.2em 0.5em 0.2em 0.5em;');
|
} else {
|
||||||
$table[] = '<tr><th>' . $pieChart->render()
|
$table[] = (string)$perfdata;
|
||||||
. htmlspecialchars($perfdata->getLabel())
|
|
||||||
. '</th><td> '
|
|
||||||
. htmlspecialchars($this->formatPerfdataValue($perfdata)) .
|
|
||||||
' </td></tr>';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,32 +46,10 @@ class Zend_View_Helper_Perfdata extends Zend_View_Helper_Abstract
|
|||||||
return $result;
|
return $result;
|
||||||
} else {
|
} else {
|
||||||
$pieCharts = empty($table) ? '' : '<table class="perfdata">' . implode("\n", $table) . '</table>';
|
$pieCharts = empty($table) ? '' : '<table class="perfdata">' . implode("\n", $table) . '</table>';
|
||||||
return $pieCharts . "\n" . implode("<br>\n", $nonPieChartData);
|
return $pieCharts;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function calculatePieChartData(Perfdata $perfdata)
|
|
||||||
{
|
|
||||||
$rawValue = $perfdata->getValue();
|
|
||||||
$minValue = $perfdata->getMinimumValue() !== null ? $perfdata->getMinimumValue() : 0;
|
|
||||||
$maxValue = $perfdata->getMaximumValue();
|
|
||||||
$usedValue = ($rawValue - $minValue);
|
|
||||||
$unusedValue = ($maxValue - $minValue) - $usedValue;
|
|
||||||
|
|
||||||
$gray = $unusedValue;
|
|
||||||
$green = $orange = $red = 0;
|
|
||||||
// TODO(#6122): Add proper treshold parsing.
|
|
||||||
if ($perfdata->getCriticalThreshold() && $perfdata->getValue() > $perfdata->getCriticalThreshold()) {
|
|
||||||
$red = $usedValue;
|
|
||||||
} elseif ($perfdata->getWarningThreshold() && $perfdata->getValue() > $perfdata->getWarningThreshold()) {
|
|
||||||
$orange = $usedValue;
|
|
||||||
} else {
|
|
||||||
$green = $usedValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return array($green, $orange, $red, $gray);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function formatPerfdataValue(Perfdata $perfdata)
|
protected function formatPerfdataValue(Perfdata $perfdata)
|
||||||
{
|
{
|
||||||
if ($perfdata->isBytes()) {
|
if ($perfdata->isBytes()) {
|
||||||
@ -82,24 +63,4 @@ class Zend_View_Helper_Perfdata extends Zend_View_Helper_Abstract
|
|||||||
return $perfdata->getValue();
|
return $perfdata->getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function createInlinePie(Perfdata $perfdata)
|
|
||||||
{
|
|
||||||
$pieChart = new InlinePie($this->calculatePieChartData($perfdata), $perfdata->getLabel());
|
|
||||||
$pieChart->setLabel(htmlspecialchars($perfdata->getLabel()));
|
|
||||||
$pieChart->setHideEmptyLabel();
|
|
||||||
|
|
||||||
//$pieChart->setHeight(32)->setWidth(32);
|
|
||||||
if ($perfdata->isBytes()) {
|
|
||||||
$pieChart->setTooltipFormat('{{label}}: {{formatted}} ({{percent}}%)');
|
|
||||||
$pieChart->setNumberFormat(InlinePie::NUMBER_FORMAT_BYTES);
|
|
||||||
} else if ($perfdata->isSeconds()) {
|
|
||||||
$pieChart->setTooltipFormat('{{label}}: {{formatted}} ({{percent}}%)');
|
|
||||||
$pieChart->setNumberFormat(InlinePie::NUMBER_FORMAT_TIME);
|
|
||||||
} else {
|
|
||||||
$pieChart->setTooltipFormat('{{label}}: {{formatted}}%');
|
|
||||||
$pieChart->setNumberFormat(InlinePie::NUMBER_FORMAT_RATIO);
|
|
||||||
$pieChart->setHideEmptyLabel();
|
|
||||||
}
|
|
||||||
return $pieChart;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ use Icinga\Module\Monitoring\Object\Service;
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<?php if (isset($downtime->service)): ?>
|
<?php if (isset($downtime->service)): ?>
|
||||||
<a href="<?= $this->href('monitoring/service/show', array(
|
<?= $this->icon('service'); ?> <a href="<?= $this->href('monitoring/service/show', array(
|
||||||
'host' => $downtime->host,
|
'host' => $downtime->host,
|
||||||
'service' => $downtime->service
|
'service' => $downtime->service
|
||||||
)); ?>">
|
)); ?>">
|
||||||
@ -63,7 +63,7 @@ use Icinga\Module\Monitoring\Object\Service;
|
|||||||
<?= $this->translate('on'); ?> <?= $downtime->host; ?>
|
<?= $this->translate('on'); ?> <?= $downtime->host; ?>
|
||||||
</small>
|
</small>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<a href="<?= $this->href('monitoring/host/show', array(
|
<?= $this->icon('host'); ?> <a href="<?= $this->href('monitoring/host/show', array(
|
||||||
'host' => $downtime->host
|
'host' => $downtime->host
|
||||||
)); ?>">
|
)); ?>">
|
||||||
<?= $downtime->host; ?>
|
<?= $downtime->host; ?>
|
||||||
@ -76,7 +76,9 @@ use Icinga\Module\Monitoring\Object\Service;
|
|||||||
<?php if ($downtime->is_flexible): ?>
|
<?php if ($downtime->is_flexible): ?>
|
||||||
<?php if ($downtime->is_in_effect): ?>
|
<?php if ($downtime->is_in_effect): ?>
|
||||||
<?= sprintf(
|
<?= sprintf(
|
||||||
$this->translate('This flexible downtime was started on %s at %s and lasts for %s until %s at %s.'),
|
isset($downtime->service)
|
||||||
|
? $this->translate('This flexible service downtime was started on %s at %s and lasts for %s until %s at %s.')
|
||||||
|
: $this->translate('This flexible host downtime was started on %s at %s and lasts for %s until %s at %s.'),
|
||||||
date('d.m.y', $downtime->start),
|
date('d.m.y', $downtime->start),
|
||||||
date('H:i', $downtime->start),
|
date('H:i', $downtime->start),
|
||||||
$this->format()->duration($downtime->duration),
|
$this->format()->duration($downtime->duration),
|
||||||
@ -85,7 +87,9 @@ use Icinga\Module\Monitoring\Object\Service;
|
|||||||
); ?>
|
); ?>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<?= sprintf(
|
<?= sprintf(
|
||||||
$this->translate('This flexible downtime has been scheduled to start between %s - %s and to last for %s.'),
|
isset($downtime->service)
|
||||||
|
? $this->translate('This flexible service downtime has been scheduled to start between %s - %s and to last for %s.')
|
||||||
|
: $this->translate('This flexible host downtime has been scheduled to start between %s - %s and to last for %s.'),
|
||||||
date('d.m.y H:i', $downtime->scheduled_start),
|
date('d.m.y H:i', $downtime->scheduled_start),
|
||||||
date('d.m.y H:i', $downtime->scheduled_end),
|
date('d.m.y H:i', $downtime->scheduled_end),
|
||||||
$this->format()->duration($downtime->duration)
|
$this->format()->duration($downtime->duration)
|
||||||
@ -94,7 +98,9 @@ use Icinga\Module\Monitoring\Object\Service;
|
|||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<?php if ($downtime->is_in_effect): ?>
|
<?php if ($downtime->is_in_effect): ?>
|
||||||
<?= sprintf(
|
<?= sprintf(
|
||||||
$this->translate('This fixed downtime was started on %s at %s and expires on %s at %s.'),
|
isset($downtime->service)
|
||||||
|
? $this->translate('This fixed service downtime was started on %s at %s and expires on %s at %s.')
|
||||||
|
: $this->translate('This fixed host downtime was started on %s at %s and expires on %s at %s.'),
|
||||||
date('d.m.y', $downtime->start),
|
date('d.m.y', $downtime->start),
|
||||||
date('H:i', $downtime->start),
|
date('H:i', $downtime->start),
|
||||||
date('d.m.y', $downtime->end),
|
date('d.m.y', $downtime->end),
|
||||||
@ -102,7 +108,9 @@ use Icinga\Module\Monitoring\Object\Service;
|
|||||||
); ?>
|
); ?>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<?= sprintf(
|
<?= sprintf(
|
||||||
$this->translate('This fixed downtime has been scheduled to start on %s at %s and to end on %s at %s.'),
|
isset($downtime->service)
|
||||||
|
? $this->translate('This fixed service downtime has been scheduled to start on %s at %s and to end on %s at %s.')
|
||||||
|
: $this->translate('This fixed host downtime has been scheduled to start on %s at %s and to end on %s at %s.'),
|
||||||
date('d.m.y', $downtime->scheduled_start),
|
date('d.m.y', $downtime->scheduled_start),
|
||||||
date('H:i', $downtime->scheduled_start),
|
date('H:i', $downtime->scheduled_start),
|
||||||
date('d.m.y', $downtime->scheduled_end),
|
date('d.m.y', $downtime->scheduled_end),
|
||||||
|
@ -108,10 +108,9 @@ if ($hosts->count() === 0) {
|
|||||||
$host->host_unhandled_services),
|
$host->host_unhandled_services),
|
||||||
'monitoring/show/services',
|
'monitoring/show/services',
|
||||||
array(
|
array(
|
||||||
'host' => $host->host_name,
|
'host' => $host->host_name,
|
||||||
'service_problem' => 1,
|
'service_problem' => 1,
|
||||||
'service_acknowledged' => 0,
|
'service_handled' => 0
|
||||||
'service_in_downtime' => 0
|
|
||||||
),
|
),
|
||||||
array('style' => 'font-weight: normal')
|
array('style' => 'font-weight: normal')
|
||||||
) ?>)</span>
|
) ?>)</span>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
use Icinga\Module\Monitoring\Object\Host;
|
use Icinga\Module\Monitoring\Object\Host;
|
||||||
use Icinga\Module\Monitoring\Object\Service;
|
use Icinga\Module\Monitoring\Object\Service;
|
||||||
|
use Icinga\Module\Monitoring\Plugin\Perfdata;
|
||||||
|
|
||||||
$helper = $this->getHelper('MonitoringState');
|
$helper = $this->getHelper('MonitoringState');
|
||||||
|
|
||||||
|
@ -518,12 +518,14 @@ class StatusQuery extends IdoQuery
|
|||||||
protected function joinServiceproblemsummary()
|
protected function joinServiceproblemsummary()
|
||||||
{
|
{
|
||||||
$sub = new Zend_Db_Expr('(SELECT'
|
$sub = new Zend_Db_Expr('(SELECT'
|
||||||
. ' SUM(CASE WHEN (ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth) > 0 THEN 0 ELSE 1 END) AS unhandled_services_count,'
|
. ' SUM(CASE WHEN (ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth + COALESCE(hs.current_state, 0)) > 0 THEN 0 ELSE 1 END) AS unhandled_services_count,'
|
||||||
. ' SUM(CASE WHEN (ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth) > 0 THEN 1 ELSE 0 END) AS handled_services_count,'
|
. ' SUM(CASE WHEN (ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth + COALESCE(hs.current_state, 0)) > 0 THEN 1 ELSE 0 END) AS handled_services_count,'
|
||||||
. ' s.host_object_id FROM icinga_servicestatus ss'
|
. ' s.host_object_id FROM icinga_servicestatus ss'
|
||||||
. ' JOIN icinga_services s'
|
. ' JOIN icinga_services s'
|
||||||
. ' ON s.service_object_id = ss.service_object_id'
|
. ' ON s.service_object_id = ss.service_object_id'
|
||||||
. ' AND ss.current_state > 0'
|
. ' AND ss.current_state > 0'
|
||||||
|
. ' JOIN icinga_hoststatus hs'
|
||||||
|
. ' ON hs.host_object_id = s.host_object_id'
|
||||||
. ' GROUP BY s.host_object_id)');
|
. ' GROUP BY s.host_object_id)');
|
||||||
$this->select->joinLeft(
|
$this->select->joinLeft(
|
||||||
array('sps' => $sub),
|
array('sps' => $sub),
|
||||||
|
@ -30,7 +30,7 @@ class IcingaCommandFileCommandRenderer implements IcingaCommandRendererInterface
|
|||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function escape($commandString)
|
protected function escape($commandString)
|
||||||
{
|
{
|
||||||
return str_replace(array("\r", "\n"), array('\r', '\n'), $commandString);
|
return str_replace(array("\r", "\n"), array('\r', '\n'), $commandString);
|
||||||
}
|
}
|
||||||
@ -52,7 +52,7 @@ class IcingaCommandFileCommandRenderer implements IcingaCommandRendererInterface
|
|||||||
if ($now === null) {
|
if ($now === null) {
|
||||||
$now = time();
|
$now = time();
|
||||||
}
|
}
|
||||||
return sprintf('[%u] %s', $now, $this->$renderMethod($command));
|
return sprintf('[%u] %s', $now, $this->escape($this->$renderMethod($command)));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function renderAddComment(AddCommentCommand $command)
|
public function renderAddComment(AddCommentCommand $command)
|
||||||
|
@ -5,9 +5,15 @@
|
|||||||
namespace Icinga\Module\Monitoring\Plugin;
|
namespace Icinga\Module\Monitoring\Plugin;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
|
use Icinga\Exception\ProgrammingError;
|
||||||
|
use Icinga\Web\Widget\Chart\InlinePie;
|
||||||
|
use Zend_Controller_Front;
|
||||||
|
|
||||||
class Perfdata
|
class Perfdata
|
||||||
{
|
{
|
||||||
|
const PERFDATA_DEFAULT = 'green';
|
||||||
|
const PERFDATA_RED = 'red';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The performance data value being parsed
|
* The performance data value being parsed
|
||||||
*
|
*
|
||||||
@ -159,6 +165,16 @@ class Perfdata
|
|||||||
return $this->unit === 'c';
|
return $this->unit === 'c';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether it is possible to display a visual representation
|
||||||
|
*
|
||||||
|
* @return bool True when the perfdata is visualizable
|
||||||
|
*/
|
||||||
|
public function isVisualizable()
|
||||||
|
{
|
||||||
|
return isset($this->minValue) && isset($this->maxValue) && isset($this->value);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return this perfomance data's label
|
* Return this perfomance data's label
|
||||||
*/
|
*/
|
||||||
@ -316,4 +332,50 @@ class Perfdata
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function calculatePieChartData( $color)
|
||||||
|
{
|
||||||
|
$rawValue = $this->getValue();
|
||||||
|
$minValue = $this->getMinimumValue() !== null ? $this->getMinimumValue() : 0;
|
||||||
|
$maxValue = $this->getMaximumValue();
|
||||||
|
$usedValue = ($rawValue - $minValue);
|
||||||
|
$unusedValue = ($maxValue - $minValue) - $usedValue;
|
||||||
|
|
||||||
|
$gray = $unusedValue;
|
||||||
|
$green = $orange = $red = 0;
|
||||||
|
|
||||||
|
switch ($color) {
|
||||||
|
case self::PERFDATA_DEFAULT:
|
||||||
|
$green = $usedValue;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case self::PERFDATA_RED:
|
||||||
|
$red = $usedValue;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case self::PERFDATA_ORANGE:
|
||||||
|
$orange = $usedValue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// TODO(#6122): Add proper treshold parsing.
|
||||||
|
|
||||||
|
return array($green, $orange, $red, $gray);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function asInlinePie($color)
|
||||||
|
{
|
||||||
|
if (! $this->isVisualizable()) {
|
||||||
|
throw new ProgrammingError('Cannot calculate piechart data for unvisualizable perfdata entry.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $this->calculatePieChartData($color);
|
||||||
|
$pieChart = new InlinePie($data, $this->getLabel() . ' ' . number_format($this->getPercentage(), 2) . '%');
|
||||||
|
$pieChart->setSparklineClass('sparkline-perfdata');
|
||||||
|
|
||||||
|
if (Zend_Controller_Front::getInstance()->getRequest()->isXmlHttpRequest()) {
|
||||||
|
$pieChart->disableNoScript();
|
||||||
|
}
|
||||||
|
return $pieChart;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
63
modules/monitoring/test/php/regression/Bug6088Test.php
Normal file
63
modules/monitoring/test/php/regression/Bug6088Test.php
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
<?php
|
||||||
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
|
// {{{ICINGA_LICENSE_HEADER}}}
|
||||||
|
|
||||||
|
namespace Tests\Icinga\Regression;
|
||||||
|
|
||||||
|
use Icinga\Test\BaseTestCase;
|
||||||
|
use Icinga\Module\Monitoring\Command\IcingaCommand;
|
||||||
|
use Icinga\Module\Monitoring\Command\Renderer\IcingaCommandFileCommandRenderer;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A command that has a hardcoded parameter with newlines
|
||||||
|
*/
|
||||||
|
class Bug6088Command extends IcingaCommand
|
||||||
|
{
|
||||||
|
public function getParameterWithCarriageReturnAndLineFeed()
|
||||||
|
{
|
||||||
|
return "foo\r\nbar";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getBug()
|
||||||
|
{
|
||||||
|
return '6088';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A subclass of IcingaCommandFileCommandRenderer to utiliseIcingaCommandFileCommandRenderer
|
||||||
|
* to render an instance of Bug6088Command
|
||||||
|
*/
|
||||||
|
class Bug6088CommandFileCommandRenderer extends IcingaCommandFileCommandRenderer
|
||||||
|
{
|
||||||
|
public function renderBug6088(Bug6088Command $command)
|
||||||
|
{
|
||||||
|
return 'SOLVE_BUG;' . $command->getBug() . ';' . $command->getParameterWithCarriageReturnAndLineFeed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class Bug6088
|
||||||
|
*
|
||||||
|
* Multi-line comments don't work
|
||||||
|
*
|
||||||
|
* @see https://dev.icinga.org/issues/6088
|
||||||
|
*/
|
||||||
|
class Bug6088Test extends BaseTestCase
|
||||||
|
{
|
||||||
|
public function testWhetherCommandParametersWithMultipleLinesAreProperlyEscaped()
|
||||||
|
{
|
||||||
|
$command = new Bug6088Command();
|
||||||
|
$renderer = new Bug6088CommandFileCommandRenderer();
|
||||||
|
$commandString = $renderer->render($command);
|
||||||
|
|
||||||
|
$this->assertEquals(
|
||||||
|
'SOLVE_BUG;6088;foo\r\nbar',
|
||||||
|
substr($commandString, strpos($commandString, ' ') + 1),
|
||||||
|
'Command parameters with multiple lines are not properly escaped'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -51,9 +51,7 @@ $cliPath = realpath(Icinga::app()->getApplicationDir() . '/../bin/icingacli');
|
|||||||
</div>
|
</div>
|
||||||
<p><?= mt('setup', 'In case the IcingaCLI is missing you can create the token manually:'); ?></p>
|
<p><?= mt('setup', 'In case the IcingaCLI is missing you can create the token manually:'); ?></p>
|
||||||
<div class="code">
|
<div class="code">
|
||||||
<span>su <?= ($user = Platform::getPhpUser()) !== null ? $user : 'your_webserver_group'; ?> && mkdir -m 2770 <?= dirname($setupTokenPath); ?>;</span>
|
<span>su <?= ($user = Platform::getPhpUser()) !== null ? $user : 'your_webserver_user'; ?> -c "mkdir -m 2770 <?= dirname($setupTokenPath); ?>; head -c 12 /dev/urandom | base64 | tee <?= $setupTokenPath; ?>; chmod 0660 <?= $setupTokenPath; ?>;";</span>
|
||||||
<span>head -c 12 /dev/urandom | base64 | tee <?= $setupTokenPath; ?>;</span>
|
|
||||||
<span>chmod 0660 <?= $setupTokenPath; ?>;</span>
|
|
||||||
</div>
|
</div>
|
||||||
<p><?= sprintf(
|
<p><?= sprintf(
|
||||||
mt('setup', 'Please see the %s for an extensive description on how to access and use this wizard.'),
|
mt('setup', 'Please see the %s for an extensive description on how to access and use this wizard.'),
|
||||||
|
@ -461,8 +461,8 @@ class WebWizard extends Wizard implements SetupWizard
|
|||||||
mt('setup', 'PHP Module: GD'),
|
mt('setup', 'PHP Module: GD'),
|
||||||
mt(
|
mt(
|
||||||
'setup',
|
'setup',
|
||||||
'In case you want icons being exported to PDF as'
|
'In case you want views being exported to PDF,'
|
||||||
. ' well, you\'ll need the GD extension for PHP.'
|
. ' you\'ll need the GD extension for PHP.'
|
||||||
),
|
),
|
||||||
Platform::extensionLoaded('gd'),
|
Platform::extensionLoaded('gd'),
|
||||||
Platform::extensionLoaded('gd') ? mt('setup', 'The PHP module GD is available') : (
|
Platform::extensionLoaded('gd') ? mt('setup', 'The PHP module GD is available') : (
|
||||||
|
@ -285,3 +285,10 @@ li li .badge {
|
|||||||
.widgetFilter li.active {
|
.widgetFilter li.active {
|
||||||
background-color: #eee;
|
background-color: #eee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sparkline {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
position: relative;
|
||||||
|
top: 4px;
|
||||||
|
}
|
@ -18,34 +18,33 @@
|
|||||||
|
|
||||||
$('span.sparkline', el).each(function(i, element) {
|
$('span.sparkline', el).each(function(i, element) {
|
||||||
// read custom options
|
// read custom options
|
||||||
var $spark = $(element);
|
var $spark = $(element);
|
||||||
var labels = $spark.attr('labels').split('|');
|
var title = $spark.attr('title');
|
||||||
var formatted = $spark.attr('formatted').split('|');
|
|
||||||
var tooltipChartTitle = $spark.attr('sparkTooltipChartTitle') || '';
|
if ($spark.attr('labels')) {
|
||||||
var format = $spark.attr('tooltipformat');
|
$spark.removeAttr('original-title');
|
||||||
var hideEmpty = $spark.attr('hideEmptyLabel') === 'true';
|
}
|
||||||
$spark.sparkline(
|
|
||||||
'html',
|
var options;
|
||||||
{
|
if ($spark.hasClass('sparkline-perfdata')) {
|
||||||
|
options = {
|
||||||
enableTagOptions: true,
|
enableTagOptions: true,
|
||||||
tooltipFormatter: function (sparkline, options, fields) {
|
width: 12,
|
||||||
var out = format;
|
height: 12,
|
||||||
if (hideEmpty && fields.offset === 3) {
|
title: title,
|
||||||
return '';
|
disableTooltips: true
|
||||||
}
|
};
|
||||||
var replace = {
|
$spark.sparkline('html', options);
|
||||||
title: tooltipChartTitle,
|
} else if ($spark.hasClass('sparkline-multi')) {
|
||||||
label: labels[fields.offset] ? labels[fields.offset] : fields.offset,
|
options = {
|
||||||
formatted: formatted[fields.offset] ? formatted[fields.offset] : '',
|
width: 100,
|
||||||
value: fields.value,
|
height: 100,
|
||||||
percent: Math.round(fields.percent * 100) / 100
|
title: title,
|
||||||
};
|
enableTagOptions: true
|
||||||
$.each(replace, function(key, value) {
|
};
|
||||||
out = out.replace('{{' + key + '}}', value);
|
$spark.sparkline('html', options);
|
||||||
});
|
}
|
||||||
return out;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user