diff --git a/.puppet/manifests/site.pp b/.puppet/manifests/site.pp
index 77ebfa0a7..08120d911 100644
--- a/.puppet/manifests/site.pp
+++ b/.puppet/manifests/site.pp
@@ -12,4 +12,6 @@ node default {
file { '/etc/profile.d/env.sh':
source => 'puppet:////vagrant/.puppet/files/etc/profile.d/env.sh'
}
+ @user { vagrant: ensure => present }
+ User <| title == vagrant |> { groups +> icingaweb }
}
diff --git a/.puppet/modules/icingacli/manifests/init.pp b/.puppet/modules/icingacli/manifests/init.pp
index 7eef7833a..701cb6e14 100644
--- a/.puppet/modules/icingacli/manifests/init.pp
+++ b/.puppet/modules/icingacli/manifests/init.pp
@@ -1,3 +1,4 @@
+# TODO(el): This module is not reuseable because it relies on vagrant paths
class icingacli {
file { '/usr/local/bin/icingacli':
ensure => link,
diff --git a/application/forms/Security/RoleForm.php b/application/forms/Security/RoleForm.php
index 0fb53e858..b27a4ec8b 100644
--- a/application/forms/Security/RoleForm.php
+++ b/application/forms/Security/RoleForm.php
@@ -6,6 +6,7 @@ namespace Icinga\Forms\Security;
use InvalidArgumentException;
use LogicException;
+use Zend_Form_Element;
use Icinga\Application\Icinga;
use Icinga\Forms\ConfigForm;
use Icinga\Util\String;
@@ -18,14 +19,14 @@ class RoleForm extends ConfigForm
/**
* Provided permissions by currently loaded modules
*
- * @var array
+ * @type array
*/
- protected $providedPermissions = array();
+ protected $providedPermissions = array('*' => '*');
/**
* Provided restrictions by currently loaded modules
*
- * @var array
+ * @type array
*/
protected $providedRestrictions = array();
@@ -35,14 +36,26 @@ class RoleForm extends ConfigForm
*/
public function init()
{
+ $helper = new Zend_Form_Element('bogus');
foreach (Icinga::app()->getModuleManager()->getLoadedModules() as $module) {
foreach ($module->getProvidedPermissions() as $permission) {
- /** @var object $permission */
+ /** @type object $permission */
$this->providedPermissions[$permission->name] = $permission->name . ': ' . $permission->description;
}
foreach ($module->getProvidedRestrictions() as $restriction) {
- /** @var object $restriction */
- $this->providedRestrictions[$restriction->name] = $restriction->description;
+ /** @type object $restriction */
+ $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(
'text',
$name,
array(
- 'label' => $name,
- 'description' => $description
+ 'label' => $spec['name'],
+ 'description' => $spec['description']
)
);
}
@@ -129,6 +142,15 @@ class RoleForm extends ConfigForm
? String::trimSplit($role['permissions'])
: null;
$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);
return $this;
}
@@ -230,6 +252,15 @@ class RoleForm extends ConfigForm
if (isset($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;
}
}
diff --git a/application/views/scripts/authentication/login.phtml b/application/views/scripts/authentication/login.phtml
index 584d8ad16..416e651d1 100644
--- a/application/views/scripts/authentication/login.phtml
+++ b/application/views/scripts/authentication/login.phtml
@@ -18,7 +18,7 @@
= sprintf(
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'
. ' %1$sdocumentation%3$s or by using our %2$sweb-based setup-wizard%3$s.'
),
diff --git a/application/views/scripts/roles/index.phtml b/application/views/scripts/roles/index.phtml
index 0f40f8279..79eda5dac 100644
--- a/application/views/scripts/roles/index.phtml
+++ b/application/views/scripts/roles/index.phtml
@@ -30,7 +30,7 @@
without(...) or $role->shift(...) would be nice!
- $restrictions = $role;
+ $restrictions = clone $role;
unset($restrictions['users']);
unset($restrictions['groups']);
unset($restrictions['permissions']);
diff --git a/doc/authentication.md b/doc/authentication.md
index 994d44e48..d36051e8f 100644
--- a/doc/authentication.md
+++ b/doc/authentication.md
@@ -2,21 +2,23 @@
**Choosing the Authentication Method**
-With Icinga Web 2 you can authenticate against Active Directory, LDAP, a MySQL or PostgreSQL database or delegate
-authentication to the web server. Authentication methods can be chained to set up fallback authentication methods
+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
or if users are spread over multiple places.
-## Configuration
+## Configuration
Authentication methods are configured in the INI file **config/authentication.ini**.
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.
-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.
-## External Authentication
+### External Authentication
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.
-## Active Directory or LDAP Authentication
+### Active Directory or LDAP Authentication
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.
-### LDAP
+#### LDAP
Directive | Description
------------------------|------------
@@ -52,7 +54,7 @@ user_class = inetOrgPerson
user_name_attribute = uid
```
-### Active Directory
+#### Active Directory
Directive | Description
------------------------|------------
@@ -67,10 +69,10 @@ backend = ad
resource = my_ad
```
-## Database Authentication
+### Database Authentication
-If you want to authenticate against a MySQL or PostgreSQL database, you have to define a
-[database resource](#resources-configuration-database) first which will be referenced as data source for the database
+If you want to authenticate against a MySQL or a PostgreSQL database, you have to define a
+[database resource](#resources-configuration-database) which will be referenced as data source for the database
authentication method.
Directive | Description
@@ -83,13 +85,31 @@ Directive | Description
```
[auth_ad]
backend = ad
-resource = my_db
+resource = icingaweb-mysql
```
+#### 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**
+Icinga Web 2 uses the MD5 based BSD password algorithm. For generating a password hash, please use the following
+command:
+
````
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');
````
diff --git a/doc/installation.md b/doc/installation.md
index 88c9c3650..6eb6737ec 100644
--- a/doc/installation.md
+++ b/doc/installation.md
@@ -26,7 +26,7 @@ repository either via git or http protocol using the following URLs:
* http://git.icinga.org/icingaweb2.git
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.
````
diff --git a/doc/preferences.md b/doc/preferences.md
index 0ac15034e..4ece5edf6 100644
--- a/doc/preferences.md
+++ b/doc/preferences.md
@@ -1,101 +1,53 @@
-# Preferences
+# Preferences
-Preferences are user based configuration for Icinga Web 2. For example max page
-items, languages or date time settings can controlled by users.
+Preferences are settings a user can set for his account only, for example his language and time zone.
-# Architecture
+**Choosing Where to Store Preferences**
-Preferences are initially loaded from a provider (ini files or database) and
-stored into session at login time. After this step preferences are only
-persisted to the configured backend, but never reloaded from them.
+Preferences can be stored either in INI files or in a MySQL or in a PostgreSQL database. By default, Icinga Web 2 stores
+preferences in INI files beneath Icinga Web 2's configuration directory.
-# Configuration
+## Configuration
-Preferences can be configured in config.ini in **preferences** section, default
-settings are this:
+Where to store preferences is defined in the INI file **config/config.ini** in the *preferences* section.
- [preferences]
- type=ini
+### Store Preferences in INI Files
-The ini provider uses the directory **config/preferences** to create one ini
-file per user and persists the data into a single file. If you want to drop your
-preferences just drop the file from disk and you'll start with a new profile.
+If preferences are stored in INI Files, Icinga Web 2 automatically creates one file per user using the username as
+file name for storing preferences. A INI file is created once a user saves changed preferences the first time.
+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
-example:
+```
+[preferences]
+type = ini
+````
- [preferences]
- type=db
- resource=icingaweb-pgsql
+### Store Preferences in a Database
-## 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
-created (due to permission errors, database outtakes, etc.).
+Directive | Description
+------------------------|------------
+**type** | `db`
+**resource** | The name of the database resource defined in [resources.ini](resources).
- [preferences]
- type=null
+**Example:**
-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
+#### Database Setup
-* **resource**: A reference to a database declared in *resources.ini*. Please read the chapter about
- resources for a detailed description about how to set up resources.
+For storing preferences in a database, you have to import one of the following database schemas:
-### 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
-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)
+After that you have to define the [database resource](#resources-configuration-database).
diff --git a/etc/license_header.txt b/etc/license_header.txt
deleted file mode 100644
index db19a8436..000000000
--- a/etc/license_header.txt
+++ /dev/null
@@ -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
\ No newline at end of file
diff --git a/library/Icinga/Util/String.php b/library/Icinga/Util/String.php
index 0bebb06e7..248ab0d34 100644
--- a/library/Icinga/Util/String.php
+++ b/library/Icinga/Util/String.php
@@ -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.
*
* @param string $name
+ * @param string $separator Word separator
*
* @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))));
}
}
diff --git a/library/Icinga/Util/Translator.php b/library/Icinga/Util/Translator.php
index 52a84bd62..87d9e4c88 100644
--- a/library/Icinga/Util/Translator.php
+++ b/library/Icinga/Util/Translator.php
@@ -4,7 +4,6 @@
namespace Icinga\Util;
-use Exception;
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
*
- * @param string $text The string to translate
- * @param string $domain The primary domain to use
+ * @param string $text The string to translate
+ * @param string $domain The primary domain to use
* @param string|null $context Optional parameter for context based translation
*
* @return string The translated string
@@ -64,7 +63,7 @@ class Translator
*
* @param string $textSingular The string in singular 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|null $context Optional parameter for context based translation
*
diff --git a/library/Icinga/Web/Form.php b/library/Icinga/Web/Form.php
index 37d8789fe..850285baa 100644
--- a/library/Icinga/Web/Form.php
+++ b/library/Icinga/Web/Form.php
@@ -9,6 +9,7 @@ use Zend_Config;
use Zend_Form;
use Zend_View_Interface;
use Icinga\Application\Icinga;
+use Icinga\Util\Translator;
use Icinga\Web\Form\Decorator\NoScriptApply;
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
*
- * It is called using the following signature: (Request $request, Form $form).
+ * It is called using the following signature: (Form $this).
*
* @param callable $onSuccess Callback
*
@@ -804,6 +805,57 @@ class Form extends Zend_Form
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
*
diff --git a/library/Icinga/Web/Session/PhpSession.php b/library/Icinga/Web/Session/PhpSession.php
old mode 100644
new mode 100755
index bef978c0b..fa545fd8d
--- a/library/Icinga/Web/Session/PhpSession.php
+++ b/library/Icinga/Web/Session/PhpSession.php
@@ -78,8 +78,9 @@ class PhpSession extends Session
}
}
- if (!is_writable(session_save_path())) {
- throw new ConfigurationError('Can\'t save session');
+ $sessionSavePath = session_save_path();
+ if (session_module_name() === 'files' && !is_writable($sessionSavePath)) {
+ throw new ConfigurationError("Can't save session, path '$sessionSavePath' is not writable.");
}
if ($this->exists()) {
diff --git a/library/Icinga/Web/Widget/Chart/InlinePie.php b/library/Icinga/Web/Widget/Chart/InlinePie.php
index 618d2903b..04e3e7318 100644
--- a/library/Icinga/Web/Widget/Chart/InlinePie.php
+++ b/library/Icinga/Web/Widget/Chart/InlinePie.php
@@ -5,6 +5,7 @@
namespace Icinga\Web\Widget\Chart;
use Icinga\Chart\PieChart;
+use Icinga\Module\Monitoring\Plugin\PerfdataSet;
use Icinga\Web\Widget\AbstractWidget;
use Icinga\Web\Url;
use Icinga\Util\Format;
@@ -28,36 +29,23 @@ class InlinePie extends AbstractWidget
const NUMBER_FORMAT_RATIO = 'ratio';
/**
- * The template string used for rendering this widget
* The template string used for rendering this widget
*
* @var string
*/
private $template =<<<'EOD'
-
-
+
+
+{noscript}
EOD;
+ private $noscript =<<<'EOD'
+
+EOD;
+
+
/**
* @var Url
*/
@@ -68,35 +56,7 @@ EOD;
*
* @var array
*/
- private $colors = array('#44bb77', '#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';
+ private $colors = array('#049BAF', '#ffaa44', '#ff5566', '#ddccdd');
/**
* The title of the chart
@@ -106,11 +66,9 @@ EOD;
private $title;
/**
- * The style for the HtmlElement
- *
- * @var string
+ * @var
*/
- private $style = '';
+ private $size;
/**
* The data displayed by the pie-chart
@@ -120,45 +78,9 @@ EOD;
private $data;
/**
- * The labels to display for each data set
- *
- * @var array
+ * @var
*/
- private $labels = array();
-
- /**
- * 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 = '{{title}} {{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;
- }
+ private $class = '';
/**
* 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->url->setParam('labels', implode(',', array_keys($label)));
- } elseif ($label != null) {
- $labelArr = array($label, $label, $label, '');
- $this->url->setParam('labels', implode(',', $labelArr));
- $label = $labelArr;
- } else {
- $this->url->removeKey('labels');
- }
- $this->labels = $label;
+ $this->size = $size;
+ return $this;
+ }
+
+ /**
+ * Do not display the NoScript fallback html
+ */
+ public function disableNoScript()
+ {
+ $this->noscript = '';
+ }
+
+ /**
+ * Set the class to define the
+ *
+ * @param $class
+ *
+ * @return $this
+ */
+ public function setSparklineClass($class)
+ {
+ $this->class = $class;
return $this;
}
@@ -214,105 +148,6 @@ EOD;
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:
- *
- *
label: The description for the current value
- *
formatted: A string representing the formatted value
- *
value: The raw (non-formatted) value used to render the piechart
- *
percent: The percentage of the current value
- *
- * 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
*
@@ -322,7 +157,7 @@ EOD;
*/
public function setTitle($title)
{
- $this->title = $title;
+ $this->title = 'title="' . htmlspecialchars($title) . '"';
return $this;
}
@@ -335,13 +170,10 @@ EOD;
*/
public function __construct(array $data, $title, $colors = null)
{
- $this->title = $title;
+ $this->setTitle($title);
$this->url = Url::fromPath('svg/chart.php');
if (array_key_exists('data', $data)) {
$this->data = $data['data'];
- if (array_key_exists('labels', $data)) {
- $this->labels = $data['labels'];
- }
if (array_key_exists('colors', $data)) {
$this->colors = $data['colors'];
}
@@ -354,21 +186,6 @@ EOD;
$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
* HTML as a string
@@ -382,11 +199,11 @@ EOD;
$pie->alignTopLeft();
$pie->disableLegend();
$pie->drawPie(array(
- 'data' => $this->data, 'colors' => $this->colors, 'labels' => $this->labels
+ 'data' => $this->data, 'colors' => $this->colors
));
try {
- $png = $pie->toPng($this->width, $this->height);
+ $png = $pie->toPng($this->size, $this->size);
return '';
} catch (IcingaException $_) {
return '';
@@ -394,17 +211,17 @@ EOD;
}
$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('{class}', $this->class, $template);
// style
- $template = str_replace('{width}', $this->width, $template);
- $template = str_replace('{height}', $this->height, $template);
- $template = str_replace('{title}', htmlspecialchars($this->title), $template);
- $template = str_replace('{style}', $this->style, $template);
+ $template = str_replace('{size}',
+ isset($this->size) ? 'sparkWidth="' . $this->size . '" sparkHeight="' . $this->size . '" ' : '', $template);
+ $template = str_replace('{title}', $this->title, $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.
// Problem is that implode respects locales when casting floats. This means
@@ -414,38 +231,7 @@ EOD;
$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('{formatted}', htmlspecialchars(implode('|', $formatted)), $template);
- $template = str_replace('{labels}', htmlspecialchars($this->createLabelString()), $template);
- $template = str_replace('{tooltipFormat}', $this->tooltipFormat, $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;
- }
- }
}
diff --git a/library/Icinga/Web/Widget/Tabextension/OutputFormat.php b/library/Icinga/Web/Widget/Tabextension/OutputFormat.php
index b5426ea47..0b533fd82 100644
--- a/library/Icinga/Web/Widget/Tabextension/OutputFormat.php
+++ b/library/Icinga/Web/Widget/Tabextension/OutputFormat.php
@@ -4,6 +4,7 @@
namespace Icinga\Web\Widget\Tabextension;
+use Icinga\Application\Platform;
use Icinga\Web\Url;
use Icinga\Web\Widget\Tab;
use Icinga\Web\Widget\Tabs;
@@ -28,35 +29,6 @@ class OutputFormat implements Tabextension
*/
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
*
@@ -74,7 +46,7 @@ class OutputFormat implements Tabextension
*/
public function __construct(array $disabled = array())
{
- foreach ($this->supportedTypes as $type => $tabConfig) {
+ foreach ($this->getSupportedTypes() as $type => $tabConfig) {
if (!in_array($type, $disabled)) {
$tabConfig['url'] = Url::fromRequest();
$tabConfig['tagParams'] = array(
@@ -98,4 +70,44 @@ class OutputFormat implements Tabextension
$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;
+ }
}
diff --git a/modules/monitoring/application/controllers/HostsController.php b/modules/monitoring/application/controllers/HostsController.php
index 4944cc237..09957a4a0 100644
--- a/modules/monitoring/application/controllers/HostsController.php
+++ b/modules/monitoring/application/controllers/HostsController.php
@@ -72,8 +72,10 @@ class Monitoring_HostsController extends Controller
'host_obsessing'*/
));
$unhandledObjects = array();
+ $unhandledFilterExpressions = array();
$acknowledgedObjects = array();
$objectsInDowntime = array();
+ $downtimeFilterExpressions = array();
$hostStates = array(
Host::getStateText(Host::STATE_UP) => 0,
Host::getStateText(Host::STATE_DOWN) => 0,
@@ -81,15 +83,17 @@ class Monitoring_HostsController extends Controller
Host::getStateText(Host::STATE_PENDING) => 0,
);
foreach ($this->hostList as $host) {
- /** @var Service $host */
+ /** @var Host $host */
if ((bool) $host->problem === true && (bool) $host->handled === false) {
$unhandledObjects[] = $host;
+ $unhandledFilterExpressions[] = Filter::where('host', $host->getName());
}
if ((bool) $host->acknowledged === true) {
$acknowledgedObjects[] = $host;
}
if ((bool) $host->in_downtime === true) {
$objectsInDowntime[] = $host;
+ $downtimeFilterExpressions[] = Filter::where('downtime_host', $host->getName());
}
++$hostStates[$host::getStateText($host->state)];
}
@@ -108,16 +112,15 @@ class Monitoring_HostsController extends Controller
$this->view->hostStates = $hostStates;
$this->view->objects = $this->hostList;
$this->view->unhandledObjects = $unhandledObjects;
- $this->view->acknowledgeUnhandledLink = Url::fromRequest()
- ->setPath('monitoring/hosts/acknowledge-problem')
- ->addParams(array('host_problem' => 1, 'host_handled' => 0));
- $this->view->downtimeUnhandledLink = Url::fromRequest()
- ->setPath('monitoring/hosts/schedule-downtime')
- ->addParams(array('host_problem' => 1, 'host_handled' => 0));
+ $unhandledFilterQueryString = Filter::matchAny($unhandledFilterExpressions)->toQueryString();
+ $this->view->acknowledgeUnhandledLink = Url::fromPath('monitoring/hosts/acknowledge-problem')
+ ->setQueryString($unhandledFilterQueryString);
+ $this->view->downtimeUnhandledLink = Url::fromPath('monitoring/hosts/schedule-downtime')
+ ->setQueryString($unhandledFilterQueryString);
$this->view->acknowledgedObjects = $acknowledgedObjects;
$this->view->objectsInDowntime = $objectsInDowntime;
- $this->view->inDowntimeLink = Url::fromRequest()
- ->setPath('monitoring/list/downtimes');
+ $this->view->inDowntimeLink = Url::fromPath('monitoring/list/downtimes')
+ ->setQueryString(Filter::matchAny($downtimeFilterExpressions)->toQueryString());
$this->view->havingCommentsLink = Url::fromRequest()
->setPath('monitoring/list/comments');
$this->view->hostStatesPieChart = $this->createPieChart(
@@ -131,9 +134,6 @@ class Monitoring_HostsController extends Controller
{
$chart = new InlinePie(array_values($states), $title, $colors);
return $chart
- ->setLabel(array_map('strtoupper', array_keys($states)))
- ->setHeight(100)
- ->setWidth(100)
->setTitle($title);
}
diff --git a/modules/monitoring/application/controllers/MultiController.php b/modules/monitoring/application/controllers/MultiController.php
index 52d927ffb..6deff2fc3 100644
--- a/modules/monitoring/application/controllers/MultiController.php
+++ b/modules/monitoring/application/controllers/MultiController.php
@@ -221,7 +221,7 @@ class Monitoring_MultiController extends Controller
private function createPie($states, $colors, $title)
{
$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);
return $chart;
}
diff --git a/modules/monitoring/application/controllers/ServicesController.php b/modules/monitoring/application/controllers/ServicesController.php
index cdf86f460..4d08622c2 100644
--- a/modules/monitoring/application/controllers/ServicesController.php
+++ b/modules/monitoring/application/controllers/ServicesController.php
@@ -74,8 +74,10 @@ class Monitoring_ServicesController extends Controller
'service_obsessing'*/
));
$unhandledObjects = array();
+ $unhandledFilterExpressions = array();
$acknowledgedObjects = array();
$objectsInDowntime = array();
+ $downtimeFilterExpressions = array();
$serviceStates = array(
Service::getStateText(Service::STATE_OK) => 0,
Service::getStateText(Service::STATE_WARNING) => 0,
@@ -94,12 +96,20 @@ class Monitoring_ServicesController extends Controller
/** @var Service $service */
if ((bool) $service->problem === true && (bool) $service->handled === false) {
$unhandledObjects[] = $service;
+ $unhandledFilterExpressions[] = Filter::matchAll(
+ Filter::where('host', $service->getHost()->getName()),
+ Filter::where('service', $service->getName())
+ );
}
if ((bool) $service->acknowledged === true) {
$acknowledgedObjects[] = $service;
}
if ((bool) $service->in_downtime === true) {
$objectsInDowntime[] = $service;
+ $downtimeFilterExpressions[] = Filter::matchAll(
+ Filter::where('downtime_host', $service->getHost()->getName()),
+ Filter::where('downtime_service', $service->getName())
+ );
}
++$serviceStates[$service::getStateText($service->state)];
if (! isset($knownHostStates[$service->getHost()->getName()])) {
@@ -125,16 +135,15 @@ class Monitoring_ServicesController extends Controller
$this->view->serviceStates = $serviceStates;
$this->view->objects = $this->serviceList;
$this->view->unhandledObjects = $unhandledObjects;
- $this->view->acknowledgeUnhandledLink = Url::fromRequest()
- ->setPath('monitoring/services/acknowledge-problem')
- ->addParams(array('service_problem' => 1, 'service_handled' => 0));
- $this->view->downtimeUnhandledLink = Url::fromRequest()
- ->setPath('monitoring/services/schedule-downtime')
- ->addParams(array('service_problem' => 1, 'service_handled' => 0));
+ $unhandledFilterQueryString = Filter::matchAny($unhandledFilterExpressions)->toQueryString();
+ $this->view->acknowledgeUnhandledLink = Url::fromPath('monitoring/services/acknowledge-problem')
+ ->setQueryString($unhandledFilterQueryString);
+ $this->view->downtimeUnhandledLink = Url::fromPath('monitoring/services/schedule-downtime')
+ ->setQueryString($unhandledFilterQueryString);
$this->view->acknowledgedObjects = $acknowledgedObjects;
$this->view->objectsInDowntime = $objectsInDowntime;
- $this->view->inDowntimeLink = Url::fromRequest()
- ->setPath('monitoring/list/downtimes');
+ $this->view->inDowntimeLink = Url::fromPath('monitoring/list/downtimes')
+ ->setQueryString(Filter::matchAny($downtimeFilterExpressions)->toQueryString());
$this->view->havingCommentsLink = Url::fromRequest()
->setPath('monitoring/list/comments');
$this->view->serviceStatesPieChart = $this->createPieChart(
@@ -153,10 +162,10 @@ class Monitoring_ServicesController extends Controller
{
$chart = new InlinePie(array_values($states), $title, $colors);
return $chart
- ->setLabel(array_map('strtoupper', array_keys($states)))
- ->setHeight(100)
- ->setWidth(100)
- ->setTitle($title);
+ // ->setLabel(array_map('strtoupper', array_keys($states)))
+ ->setSize(50)
+ ->setTitle($title)
+ ->setSparklineClass('sparkline-multi');
}
/**
diff --git a/modules/monitoring/application/forms/Command/Object/AcknowledgeProblemCommandForm.php b/modules/monitoring/application/forms/Command/Object/AcknowledgeProblemCommandForm.php
index 3456e1bfb..25ac76c25 100644
--- a/modules/monitoring/application/forms/Command/Object/AcknowledgeProblemCommandForm.php
+++ b/modules/monitoring/application/forms/Command/Object/AcknowledgeProblemCommandForm.php
@@ -104,7 +104,7 @@ class AcknowledgeProblemCommandForm extends ObjectsCommandForm
array(
'decorators' => array(
'FormElements',
- array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
+ array('HtmlTag', array('tag' => 'div'))
)
)
);
diff --git a/modules/monitoring/application/forms/Command/Object/ScheduleServiceDowntimeCommandForm.php b/modules/monitoring/application/forms/Command/Object/ScheduleServiceDowntimeCommandForm.php
index 9fd86a82b..9961d4b65 100644
--- a/modules/monitoring/application/forms/Command/Object/ScheduleServiceDowntimeCommandForm.php
+++ b/modules/monitoring/application/forms/Command/Object/ScheduleServiceDowntimeCommandForm.php
@@ -130,7 +130,7 @@ class ScheduleServiceDowntimeCommandForm extends ObjectsCommandForm
array(
'decorators' => array(
'FormElements',
- array('HtmlTag', array('tag' => 'div', 'class' => 'control-group'))
+ array('HtmlTag', array('tag' => 'div'))
)
)
);
@@ -169,7 +169,7 @@ class ScheduleServiceDowntimeCommandForm extends ObjectsCommandForm
),
'decorators' => array(
'FormElements',
- array('HtmlTag', array('tag' => 'div', 'class' => 'control-group')),
+ array('HtmlTag', array('tag' => 'div')),
array(
'Description',
array('tag' => 'span', 'class' => 'description', 'placement' => 'prepend')
diff --git a/modules/monitoring/application/views/helpers/Perfdata.php b/modules/monitoring/application/views/helpers/Perfdata.php
index eb649e77d..47c34d156 100644
--- a/modules/monitoring/application/views/helpers/Perfdata.php
+++ b/modules/monitoring/application/views/helpers/Perfdata.php
@@ -9,33 +9,36 @@ use Icinga\Module\Monitoring\Plugin\PerfdataSet;
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();
- $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; });
- }
+ $pieChartData = PerfdataSet::fromString($perfdataStr)->asArray();
$result = '';
$table = array();
- foreach ($onlyPieChartData as $perfdata) {
- $pieChart = $this->createInlinePie($perfdata);
- if ($compact) {
- $result .= $pieChart->render();
- } else {
- if (! $perfdata->isPercentage()) {
- // TODO: Should we trust sprintf-style placeholders in perfdata titles?
- $pieChart->setTooltipFormat('{{label}}: {{formatted}} ({{percent}}%)');
+ foreach ($pieChartData as $perfdata) {
+ if ($perfdata->isVisualizable()) {
+ $pieChart = $perfdata->asInlinePie($color);
+ if ($compact) {
+ $result .= $pieChart->render();
+ } else {
+ $table[] = '