diff --git a/library/Icinga/Application/Cli.php b/library/Icinga/Application/Cli.php
index c6e64905b8..9f14b6c206 100644
--- a/library/Icinga/Application/Cli.php
+++ b/library/Icinga/Application/Cli.php
@@ -53,8 +53,7 @@ protected function setupLogging()
new Config(
array(
'level' => Logger::INFO,
- 'log' => 'file',
- 'file' => 'php://stderr'
+ 'log' => 'stdout',
)
)
);
diff --git a/library/Icinga/Application/Config.php b/library/Icinga/Application/Config.php
index aa3765d86e..6a08eb93eb 100644
--- a/library/Icinga/Application/Config.php
+++ b/library/Icinga/Application/Config.php
@@ -378,7 +378,7 @@ public function fromSection($section, $key, $default = null)
);
}
- if ($default !== null) {
+ if ($value === null && $default !== null) {
$value = $default;
}
diff --git a/library/Icinga/Application/Logger/LogWriter.php b/library/Icinga/Application/Logger/LogWriter.php
index c18e512578..831c96fe8a 100644
--- a/library/Icinga/Application/Logger/LogWriter.php
+++ b/library/Icinga/Application/Logger/LogWriter.php
@@ -11,10 +11,18 @@
*/
abstract class LogWriter
{
+ /**
+ * @var Zend_Config
+ */
+ protected $config;
+
/**
* Create a new log writer initialized with the given configuration
*/
- abstract public function __construct(Config $config);
+ public function __construct(Config $config)
+ {
+ $this->config = $config;
+ }
/**
* Log a message with the given severity
diff --git a/library/Icinga/Application/Logger/Writer/StdoutWriter.php b/library/Icinga/Application/Logger/Writer/StdoutWriter.php
new file mode 100644
index 0000000000..1fe929d92d
--- /dev/null
+++ b/library/Icinga/Application/Logger/Writer/StdoutWriter.php
@@ -0,0 +1,50 @@
+screen === null) {
+ $this->screen = Screen::instance();
+ }
+ return $this->screen;
+ }
+
+ /**
+ * Log a message with the given severity
+ *
+ * @param int $severity The severity to use
+ * @param string $message The message to log
+ */
+ public function log($severity, $message)
+ {
+ $color = 'black';
+ switch ($severity) {
+ case Logger::$ERROR:
+ $color = 'red';
+ break;
+ case Logger::$WARNING:
+ $color = 'orange';
+ break;
+ case Logger::$INFO:
+ $color = 'green';
+ break;
+ case Logger::$DEBUG:
+ $color = 'blue';
+ break;
+ }
+ file_put_contents('php://stderr', $this->screen()->colorize($message, $color) . "\n");
+ }
+}
diff --git a/library/Icinga/Data/Db/DbConnection.php b/library/Icinga/Data/Db/DbConnection.php
index 5fb08730e2..82686893da 100644
--- a/library/Icinga/Data/Db/DbConnection.php
+++ b/library/Icinga/Data/Db/DbConnection.php
@@ -216,7 +216,10 @@ public function fetchAll(DbQuery $query)
*/
public function fetchRow(DbQuery $query)
{
- return $this->dbAdapter->fetchRow($query->getSelectQuery());
+ Benchmark::measure('DB is fetching row');
+ $result = $this->dbAdapter->fetchRow($query->getSelectQuery());
+ Benchmark::measure('DB row done');
+ return $result;
}
/**
diff --git a/library/Icinga/File/Ini/IniEditor.php b/library/Icinga/File/Ini/IniEditor.php
index 6ee19fa749..e1a7984d80 100644
--- a/library/Icinga/File/Ini/IniEditor.php
+++ b/library/Icinga/File/Ini/IniEditor.php
@@ -433,6 +433,9 @@ private function formatKeyValuePair(array $key, $value)
*/
private function formatKey(array $key)
{
+ foreach ($key as $i => $separator) {
+ $key[$i] = $this->sanitize($separator);
+ }
return implode($this->nestSeparator, $key);
}
@@ -599,7 +602,7 @@ private function removeFromArray($array, $pos)
}
/**
- * Prepare a value for INe
+ * Prepare a value for INI
*
* @param $value The value of the string
*
@@ -613,10 +616,12 @@ private function formatValue($value)
return $value;
} elseif (is_bool($value)) {
return ($value ? 'true' : 'false');
- } elseif (strpos($value, '"') === false) {
- return '"' . $value . '"';
- } else {
- return '"' . str_replace('"', '\"', $value) . '"';
}
+ return '"' . str_replace('"', '\"', $this->sanitize($value)) . '"';
+ }
+
+ private function sanitize($value)
+ {
+ return str_replace('\n', '', $value);
}
}
diff --git a/library/Icinga/File/Ini/IniWriter.php b/library/Icinga/File/Ini/IniWriter.php
index af11742b91..cf9355b56e 100644
--- a/library/Icinga/File/Ini/IniWriter.php
+++ b/library/Icinga/File/Ini/IniWriter.php
@@ -52,45 +52,6 @@ public function __construct(array $options = null)
parent::__construct($options);
}
- /**
- * Find all keys containing dots and convert it to a nested configuration
- *
- * Ensure that configurations with the same ini representation the have
- * similarly nested Zend_Config objects. The configuration may be altered
- * during that process.
- *
- * @param Zend_Config $config The configuration to normalize
- * @return Zend_Config The normalized config
- */
- private function normalizeKeys(Zend_Config $config)
- {
- foreach ($config as $key => $value) {
- if (preg_match('/\./', $key) > 0) {
- // remove old key
- unset ($config->$key);
-
- // insert new key
- $nests = explode('.', $key);
- $current = $config;
- $i = 0;
- for (; $i < count($nests) - 1; $i++) {
- if (! isset($current->{$nests[$i]})) {
- // configuration key doesn't exist, create a new nesting level
- $current->{$nests[$i]} = new Zend_Config (array(), true);
- }
- // move to next nesting level
- $current = $current->{$nests[$i]};
- }
- // reached last nesting level, insert value
- $current->{$nests[$i]} = $value;
- }
- if ($value instanceof Zend_Config) {
- $config->$key = $this->normalizeKeys ($value);
- }
- }
- return $config;
- }
-
/**
* Render the Zend_Config into a config file string
*
@@ -104,16 +65,6 @@ public function render()
$oldconfig = new Zend_Config(array());
}
- // create an internal copy of the given configuration, since the user of this class
- // won't expect that a configuration will ever be altered during
- // the rendering process.
- $extends = $this->_config->getExtends();
- $this->_config = new Zend_Config ($this->_config->toArray(), true);
- foreach ($extends as $extending => $extended) {
- $this->_config->setExtend($extending, $extended);
- }
- $this->_config = $this->normalizeKeys($this->_config);
-
$newconfig = $this->_config;
$editor = new IniEditor(@file_get_contents($this->_filename), $this->options);
$this->diffConfigs($oldconfig, $newconfig, $editor);
diff --git a/library/Icinga/Util/Translator.php b/library/Icinga/Util/Translator.php
index 7552034744..52a84bd629 100644
--- a/library/Icinga/Util/Translator.php
+++ b/library/Icinga/Util/Translator.php
@@ -224,6 +224,7 @@ public static function getAvailableLocaleCodes()
}
}
}
+ sort($codes);
return $codes;
}
diff --git a/library/Icinga/Web/Menu/MonitoringMenuItemRenderer.php b/library/Icinga/Web/Menu/MonitoringMenuItemRenderer.php
new file mode 100644
index 0000000000..63e819d1b9
--- /dev/null
+++ b/library/Icinga/Web/Menu/MonitoringMenuItemRenderer.php
@@ -0,0 +1,90 @@
+select()->from(
+ 'statusSummary',
+ array(
+ 'hosts_down_unhandled',
+ 'services_critical_unhandled'
+ )
+ )->getQuery()->fetchRow();
+ }
+
+ if ($column === null) {
+ return self::$summary;
+ } elseif (isset(self::$summary->$column)) {
+ return self::$summary->$column;
+ } else {
+ return null;
+ }
+ }
+
+ protected function getBadgeTitle()
+ {
+ $translations = array(
+ 'hosts_down_unhandled' => mt('monitoring', '%d unhandled hosts down'),
+ 'services_critical_unhandled' => mt('monitoring', '%d unhandled services critical')
+ );
+
+ $titles = array();
+ $sum = $this->summary();
+
+ foreach ($this->columns as $col) {
+ if (isset($sum->$col) && $sum->$col > 0) {
+ $titles[] = sprintf($translations[$col], $sum->$col);
+ }
+ }
+
+ return implode(', ', $titles);
+ }
+
+ protected function countItems()
+ {
+ $sum = self::summary();
+ $count = 0;
+
+ foreach ($this->columns as $col) {
+ if (isset($sum->$col)) {
+ $count += $sum->$col;
+ }
+ }
+
+ return $count;
+ }
+
+ public function render(Menu $menu)
+ {
+ $count = $this->countItems();
+ $badge = '';
+ if ($count) {
+ $badge = sprintf(
+ '
%s
',
+ $this->getBadgeTitle(),
+ $count
+ );
+ }
+ return sprintf(
+ '%s%s%s',
+ $menu->getUrl() ?: '#',
+ $menu->getIcon() ? ' ' : '',
+ htmlspecialchars($menu->getTitle()),
+ $badge
+ );
+ }
+}
diff --git a/library/Icinga/Web/Menu/ProblemMenuItemRenderer.php b/library/Icinga/Web/Menu/ProblemMenuItemRenderer.php
index 1254033ae0..58689547fd 100644
--- a/library/Icinga/Web/Menu/ProblemMenuItemRenderer.php
+++ b/library/Icinga/Web/Menu/ProblemMenuItemRenderer.php
@@ -1,39 +1,11 @@
select()->from(
- 'statusSummary',
- array(
- 'hosts_down_unhandled',
- 'services_critical_unhandled'
- )
- )->getQuery()->fetchRow();
- $unhandled = $statusSummary->hosts_down_unhandled + $statusSummary->services_critical_unhandled;
- $badge = '';
- if ($unhandled) {
- $badge = sprintf(
- '%s
',
- $unhandled
- );
- }
- return sprintf(
- '%s%s %s',
- $menu->getUrl() ?: '#',
- $menu->getIcon() ? ' ' : '',
- htmlspecialchars($menu->getTitle()),
- $badge
- );
- }
+class ProblemMenuItemRenderer extends MonitoringMenuItemRenderer
+{
+ protected $columns = array(
+ 'hosts_down_unhandled',
+ 'services_critical_unhandled'
+ );
}
diff --git a/library/Icinga/Web/Menu/UnhandledHostMenuItemRenderer.php b/library/Icinga/Web/Menu/UnhandledHostMenuItemRenderer.php
index c7e6036fb3..10a75c00f5 100644
--- a/library/Icinga/Web/Menu/UnhandledHostMenuItemRenderer.php
+++ b/library/Icinga/Web/Menu/UnhandledHostMenuItemRenderer.php
@@ -1,38 +1,12 @@
select()->from(
- 'statusSummary',
- array(
- 'hosts_down_unhandled'
- )
- )->getQuery()->fetchRow();
- $badge = '';
- if ($statusSummary->hosts_down_unhandled) {
- $badge = sprintf(
- '%s
',
- t(sprintf('%d unhandled host problems', $statusSummary->hosts_down_unhandled)),
- $statusSummary->hosts_down_unhandled
- );
- }
- return sprintf(
- '%s%s %s',
- $menu->getUrl() ?: '#',
- $menu->getIcon() ? ' ' : '',
- htmlspecialchars($menu->getTitle()),
- $badge
- );
- }
+class UnhandledHostMenuItemRenderer extends MonitoringMenuItemRenderer
+{
+ protected $columns = array(
+ 'hosts_down_unhandled',
+ );
}
diff --git a/library/Icinga/Web/Menu/UnhandledServiceMenuItemRenderer.php b/library/Icinga/Web/Menu/UnhandledServiceMenuItemRenderer.php
index b677a49352..8a59e9baac 100644
--- a/library/Icinga/Web/Menu/UnhandledServiceMenuItemRenderer.php
+++ b/library/Icinga/Web/Menu/UnhandledServiceMenuItemRenderer.php
@@ -1,38 +1,12 @@
select()->from(
- 'statusSummary',
- array(
- 'services_critical_unhandled'
- )
- )->getQuery()->fetchRow();
- $badge = '';
- if ($statusSummary->services_critical_unhandled) {
- $badge = sprintf(
- '%s
',
- t(sprintf('%d unhandled service problems', $statusSummary->services_critical_unhandled)),
- $statusSummary->services_critical_unhandled
- );
- }
- return sprintf(
- '%s%s %s',
- $menu->getUrl() ?: '#',
- $menu->getIcon() ? ' ' : '',
- htmlspecialchars($menu->getTitle()),
- $badge
- );
- }
+class UnhandledServiceMenuItemRenderer extends MonitoringMenuItemRenderer
+{
+ protected $columns = array(
+ 'services_critical_unhandled'
+ );
}
diff --git a/modules/monitoring/application/forms/Command/CommandForm.php b/modules/monitoring/application/forms/Command/CommandForm.php
index 0a7cd19f9e..da797e60cf 100644
--- a/modules/monitoring/application/forms/Command/CommandForm.php
+++ b/modules/monitoring/application/forms/Command/CommandForm.php
@@ -4,7 +4,7 @@
namespace Icinga\Module\Monitoring\Form\Command;
-use Icinga\Module\Monitoring\Backend;
+use Icinga\Module\Monitoring\Backend\MonitoringBackend;
use Icinga\Module\Monitoring\Command\Transport\CommandTransport;
use Icinga\Web\Form;
use Icinga\Web\Request;
@@ -24,11 +24,11 @@ abstract class CommandForm extends Form
/**
* Set the monitoring backend
*
- * @param Backend $backend
+ * @param MonitoringBackend $backend
*
* @return $this
*/
- public function setBackend(Backend $backend)
+ public function setBackend(MonitoringBackend $backend)
{
$this->backend = $backend;
return $this;
diff --git a/modules/monitoring/application/views/helpers/MonitoringState.php b/modules/monitoring/application/views/helpers/MonitoringState.php
index 871e8ad08f..4db1a7a91d 100644
--- a/modules/monitoring/application/views/helpers/MonitoringState.php
+++ b/modules/monitoring/application/views/helpers/MonitoringState.php
@@ -95,8 +95,11 @@ public function getStateFlags($object, $type = 'service')
*/
public function getStateTitle($object, $type)
{
- return strtoupper($this->monitoringState($object, $type))
- . ' since '
- . date('Y-m-d H:i:s', $object->{$type.'_last_state_change'});
+ return sprintf(
+ '%s %s %s',
+ $this->view->translate(strtoupper($this->monitoringState($object, $type))),
+ $this->view->translate('since'),
+ date('Y-m-d H:i:s', $object->{$type.'_last_state_change'})
+ );
}
}
diff --git a/modules/monitoring/bin/action/list.inc.php b/modules/monitoring/bin/action/list.inc.php
deleted file mode 100644
index 01fd351316..0000000000
--- a/modules/monitoring/bin/action/list.inc.php
+++ /dev/null
@@ -1,123 +0,0 @@
-shift('backend'));
-
-$query = $backend->select()->from('status', array(
- 'host_name',
- 'host_state',
- 'host_output',
- 'host_acknowledged',
- 'host_in_downtime',
- 'service_description',
- 'service_state',
- 'service_acknowledged',
- 'service_in_downtime',
- 'service_handled',
- 'service_output',
- 'service_last_state_change'
-))->order('service_last_state_change ASC');
-
-$endless = $params->shift('endless');
-$query->applyFilters($params->getParams());
-$host_colors = array(
- 0 => '2', // UP
- 1 => '1', // DOWN
- 2 => '3', // UNREACH (brown)
- 99 => '0', // PEND
-);
-$host_states = array(
- 0 => 'UP', // UP
- 1 => 'DOWN', // DOWN
- 2 => 'UNREACHABLE', // UNREACH (brown)
- 99 => 'PENDING', // PEND
-);
-$service_colors = array(
- 0 => '2', // OK
- 1 => '3', // WARN
- 2 => '1', // CRIT
- 3 => '5', // UNKN
- 99 => '0', // PEND
-);
-$service_states = array(
- 0 => 'OK', // OK
- 1 => 'WARNING', // WARN
- 2 => 'CRITICAL', // CRIT
- 3 => 'UNKNOWN', // UNKN
- 99 => 'PENDING', // PEND
-);
-
-$finished = false;
-while (! $finished) {
-$out = '';
-$last_host = null;
-
-foreach ($query->fetchAll() as $key => $row) {
- $host_extra = array();
- if ($row->host_in_downtime) {
- $host_extra[] = 'DOWNTIME';
- }
- if ($row->host_acknowledged) {
- $host_extra[] = 'ACK';
- }
- if (empty($host_extra)) {
- $host_extra = '';
- } else {
- $host_extra = " \033[34;1m[" . implode(',', $host_extra) . "]\033[0m";
- }
-
- $service_extra = array();
- if ($row->service_in_downtime) {
- $service_extra[] = 'DOWNTIME';
- }
- if ($row->service_acknowledged) {
- $service_extra[] = 'ACK';
- }
- if (empty($service_extra)) {
- $service_extra = '';
- } else {
- $service_extra = " \033[34;52;1m[" . implode(',', $service_extra) . "]\033[0m";
- }
-
- if ($row->host_name !== $last_host) {
- $out .= sprintf(
- "\n\033[01;37;4%dm %-5s \033[0m \033[30;1m%s\033[0m%s: %s\n",
- $host_colors[$row->host_state],
- substr($host_states[$row->host_state], 0, 5),
- $row->host_name,
- $host_extra,
- $row->host_output
- );
- }
- $last_host = $row->host_name;
- $out .= sprintf(
- "\033[01;37;4%dm \033[01;37;4%dm %4s \033[0m %s%s since %s: %s\n",
- $host_colors[$row->host_state],
- $service_colors[$row->service_state],
- substr($service_states[$row->service_state] . ' ', 0, 4),
- $row->service_description,
- $service_extra,
- Format::timeSince($row->service_last_state_change),
- preg_replace('/\n/', sprintf(
- "\n\033[01;37;4%dm \033[01;37;4%dm \033[0m ",
- $host_colors[$row->host_state],
- $service_colors[$row->service_state]
-
- ), substr(wordwrap(str_repeat(' ', 30) . preg_replace('~\@{3,}~', '@@@', $row->service_output), 72), 30))
- );
-}
-
-$out .= "\n";
-
- if ($endless) {
- echo "\033[2J\033[1;1H\033[1S" . $out;
- sleep(3);
- } else {
- echo $out;
- $finished = true;
- }
-}
diff --git a/modules/monitoring/library/Monitoring/Backend.php b/modules/monitoring/library/Monitoring/Backend.php
index 3af728860d..e3672dcd50 100644
--- a/modules/monitoring/library/Monitoring/Backend.php
+++ b/modules/monitoring/library/Monitoring/Backend.php
@@ -1,186 +1,11 @@
resource = $resource;
- $this->type = $type;
- }
+// TODO: obsolete, remove once MonitoringBackend is in use everywhere
- // Temporary workaround, we have no way to know our name
- protected function setName($name)
- {
- $this->name = $name;
- }
-
- public function getName()
- {
- return $this->name;
- }
+namespace Icinga\Module\Monitoring;
- /**
- * Create a backend
- *
- * @param string $backendName Name of the backend or null for creating the default backend which is the first INI
- * configuration entry not being disabled
- *
- * @return Backend
- * @throws ConfigurationError When no backend has been configured or all backends are disabled or the
- * configuration for the requested backend does either not exist or it's disabled
- */
- public static function createBackend($backendName = null)
- {
- $config = Config::module('monitoring', 'backends');
- if ($config->count() === 0) {
- throw new ConfigurationError(mt('monitoring', 'No backend has been configured'));
- }
- if ($backendName !== null) {
- $backendConfig = $config->get($backendName);
- if ($backendConfig === null) {
- throw new ConfigurationError('No configuration for backend %s', $backendName);
- }
- if ((bool) $backendConfig->get('disabled', false) === true) {
- throw new ConfigurationError(
- mt('monitoring', 'Configuration for backend %s available but backend is disabled'),
- $backendName
- );
- }
- } else {
- foreach ($config as $name => $backendConfig) {
- if ((bool) $backendConfig->get('disabled', false) === false) {
- $backendName = $name;
- break;
- }
- }
- if ($backendName === null) {
- throw new ConfigurationError(mt('monitoring', 'All backends are disabled'));
- }
- }
- $resource = ResourceFactory::create($backendConfig->resource);
- if ($backendConfig->type === 'ido' && $resource->getDbType() !== 'oracle') {
- // TODO(el): The resource should set the table prefix
- $resource->setTablePrefix('icinga_');
- }
- $backend = new Backend($resource, $backendConfig->type);
- $backend->setName($backendName);
- return $backend;
- }
+use Icinga\Module\Monitoring\Backend\MonitoringBackend;
-public function getResource()
+class Backend extends MonitoringBackend
{
- return $this->resource;
-}
-
- /**
- * Backend entry point
- *
- * @return self
- */
- public function select()
- {
- return $this;
- }
-
- /**
- * Create a data view to fetch data from
- *
- * @param string $viewName
- * @param array $columns
- *
- * @return DataView
- */
- public function from($viewName, array $columns = null)
- {
- $viewClass = $this->resolveDataViewName($viewName);
- return new $viewClass($this, $columns);
- }
-
- /**
- * View name to class name resolution
- *
- * @param string $viewName
- *
- * @return string
- * @throws ProgrammingError When the view does not exist
- */
- protected function resolveDataViewName($viewName)
- {
- $viewClass = '\\Icinga\\Module\\Monitoring\\DataView\\' . ucfirst($viewName);
- if (!class_exists($viewClass)) {
- throw new ProgrammingError(
- 'DataView %s does not exist',
- ucfirst($viewName)
- );
- }
- return $viewClass;
- }
-
- public function getQueryClass($name)
- {
- return $this->resolveQueryName($name);
- }
-
- /**
- * Query name to class name resolution
- *
- * @param string $queryName
- *
- * @return string
- * @throws ProgrammingError When the query does not exist for this backend
- */
- protected function resolveQueryName($queryName)
- {
- $queryClass = '\\Icinga\\Module\\Monitoring\\Backend\\'
- . ucfirst($this->type)
- . '\\Query\\'
- . ucfirst($queryName)
- . 'Query';
- if (!class_exists($queryClass)) {
- throw new ProgrammingError(
- 'Query "%s" does not exist for backend %s',
- ucfirst($queryName),
- ucfirst($this->type)
- );
- }
- return $queryClass;
- }
}
diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/IdoBackend.php b/modules/monitoring/library/Monitoring/Backend/Ido/IdoBackend.php
new file mode 100644
index 0000000000..17bfb9f6ad
--- /dev/null
+++ b/modules/monitoring/library/Monitoring/Backend/Ido/IdoBackend.php
@@ -0,0 +1,9 @@
+name = $name;
+ $this->config = $config;
+ }
+
+ /**
+ * Get a backend instance
+ *
+ * You may ask for a specific backend name or get the default one otherwise
+ *
+ * @param string $name Backend name
+ *
+ * @return MonitoringBackend
+ */
+ public static function instance($name = null)
+ {
+ if (! array_key_exists($name, self::$instances)) {
+
+ list($foundName, $config) = static::loadConfig($name);
+ $type = $config->get('type');
+ $class = implode(
+ '\\',
+ array(
+ __NAMESPACE__,
+ ucfirst($type),
+ ucfirst($type) . 'Backend'
+ )
+ );
+
+ if (!class_exists($class)) {
+ throw new ConfigurationError(
+ mt('monitoring', 'There is no "%s" monitoring backend'),
+ $class
+ );
+ }
+
+ self::$instances[$name] = new $class($foundName, $config);
+ if ($name === null) {
+ self::$instances[$foundName] = self::$instances[$name];
+ }
+ }
+
+ return self::$instances[$name];
+ }
+
+ /**
+ * Clear all cached instances. Mostly for testing purposes.
+ */
+ public static function clearInstances()
+ {
+ self::$instances = array();
+ }
+
+ /**
+ * Whether this backend is of a specific type
+ *
+ * @param string $type Backend type
+ *
+ * @return boolean
+ */
+ public function is($type)
+ {
+ return $this->getType() === $type;
+ }
+
+ /**
+ * Get the configured name of this backend
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Get the backend type name
+ *
+ * @return string
+ */
+ public function getType()
+ {
+ if ($this->type === null) {
+ $parts = preg_split('~\\\~', get_class($this));
+ $class = array_pop($parts);
+ if (substr($class, -7) === 'Backend') {
+ $this->type = lcfirst(substr($class, 0, -7));
+ } else {
+ throw new ProgrammingError(
+ '%s is not a valid monitoring backend class name',
+ $class
+ );
+ }
+ }
+ return $this->type;
+ }
+
+ /**
+ * Return the configuration for the first enabled or the given backend
+ */
+ protected static function loadConfig($name = null)
+ {
+ $backends = Config::module('monitoring', 'backends');
+
+ if ($name === null) {
+
+ $count = 0;
+
+ foreach ($backends as $name => $config) {
+ $count++;
+ if ((bool) $config->get('disabled', false) === false) {
+ return array($name, $config);
+ }
+ }
+
+ if ($count === 0) {
+ $message = mt('monitoring', 'No backend has been configured');
+ } else {
+ $message = mt('monitoring', 'All backends are disabled');
+ }
+
+ throw new ConfigurationError($message);
+
+ } else {
+
+ $config = $backends->get($name);
+
+ if ($config === null) {
+ throw new ConfigurationError(
+ mt('monitoring', 'No configuration for backend %s'),
+ $name
+ );
+ }
+
+ if ((bool) $config->get('disabled', false) === true) {
+ throw new ConfigurationError(
+ mt('monitoring', 'Configuration for backend %s is disabled'),
+ $name
+ );
+ }
+
+ return array($name, $config);
+ }
+ }
+
+ /**
+ * Create a backend
+ *
+ * @deprecated
+ *
+ * @param string $backendName Name of the backend or null for creating the default backend which is the first INI
+ * configuration entry not being disabled
+ *
+ * @return Backend
+ * @throws ConfigurationError When no backend has been configured or all backends are disabled or the
+ * configuration for the requested backend does either not exist or it's disabled
+ */
+ public static function createBackend($name = null)
+ {
+ return self::instance($name);
+ }
+
+ /**
+ * Get this backend's internal resource
+ *
+ * @return mixed
+ */
+ public function getResource()
+ {
+ if ($this->resource === null) {
+ $this->resource = ResourceFactory::create($this->config->get('resource'));
+ if ($this->is('ido') && $this->resource->getDbType() !== 'oracle') {
+ // TODO(el): The resource should set the table prefix
+ $this->resource->setTablePrefix('icinga_');
+ }
+ }
+ return $this->resource;
+ }
+
+ /**
+ * Backend entry point
+ *
+ * @return self
+ */
+ public function select()
+ {
+ return $this;
+ }
+
+ /**
+ * Create a data view to fetch data from
+ *
+ * @param string $name
+ * @param array $columns
+ *
+ * @return DataView
+ */
+ public function from($name, array $columns = null)
+ {
+ $class = $this->buildViewClassName($name);
+ return new $class($this, $columns);
+ }
+
+ /**
+ * View name to class name resolution
+ *
+ * @param string $viewName
+ *
+ * @return string
+ * @throws ProgrammingError When the view does not exist
+ */
+ protected function buildViewClassName($view)
+ {
+ $class = '\\Icinga\\Module\\Monitoring\\DataView\\' . ucfirst($view);
+ if (!class_exists($class)) {
+ throw new ProgrammingError(
+ 'DataView %s does not exist',
+ ucfirst($view)
+ );
+ }
+ return $class;
+ }
+
+ /**
+ * Get a specific query class instance
+ *
+ * @param string $name Query name
+ * @param array $columns Optional column list
+ *
+ * @return Icinga\Data\QueryInterface
+ */
+ public function query($name, $columns = null)
+ {
+ $class = $this->buildQueryClassName($name);
+
+ if (!class_exists($class)) {
+ throw new ProgrammingError(
+ 'Query "%s" does not exist for backend %s',
+ $name,
+ $this->getType()
+ );
+ }
+
+ return new $class($this->getResource(), $columns);
+ }
+
+ /**
+ * Whether this backend supports the given query
+ *
+ * @param string $name Query name to check for
+ *
+ * @return bool
+ */
+ public function hasQuery($name)
+ {
+ return class_exists($this->buildQueryClassName($name));
+ }
+
+ /**
+ * Query name to class name resolution
+ *
+ * @param string $query
+ *
+ * @return string
+ * @throws ProgrammingError When the query does not exist for this backend
+ */
+ protected function buildQueryClassName($query)
+ {
+ $parts = preg_split('~\\\~', get_class($this));
+ array_pop($parts);
+ array_push($parts, 'Query', ucfirst($query) . 'Query');
+ return implode('\\', $parts);
+ }
+}
diff --git a/modules/monitoring/library/Monitoring/DataView/DataView.php b/modules/monitoring/library/Monitoring/DataView/DataView.php
index 2c4ec53800..1fdd8b4f94 100644
--- a/modules/monitoring/library/Monitoring/DataView/DataView.php
+++ b/modules/monitoring/library/Monitoring/DataView/DataView.php
@@ -15,7 +15,7 @@
use Icinga\Exception\QueryException;
use Icinga\Web\Request;
use Icinga\Web\Url;
-use Icinga\Module\Monitoring\Backend;
+use Icinga\Module\Monitoring\Backend\MonitoringBackend;
/**
* A read-only view of an underlying query
@@ -44,8 +44,7 @@ abstract class DataView implements Browsable, Countable, Filterable, Sortable
public function __construct(ConnectionInterface $connection, array $columns = null)
{
$this->connection = $connection;
- $queryClass = $connection->getQueryClass($this->getQueryName());
- $this->query = new $queryClass($this->connection->getResource(), $columns);
+ $this->query = $connection->query($this->getQueryName(), $columns);
$this->filter = Filter::matchAll();
$this->init();
}
@@ -105,7 +104,7 @@ abstract public function getColumns();
*/
public static function fromRequest($request, array $columns = null)
{
- $view = new static(Backend::createBackend($request->getParam('backend')), $columns);
+ $view = new static(MonitoringBackend::instance($request->getParam('backend')), $columns);
$view->applyUrlFilter($request);
return $view;
@@ -141,7 +140,7 @@ protected function applyUrlFilter($request = null)
*/
public static function fromParams(array $params, array $columns = null)
{
- $view = new static(Backend::createBackend($params['backend']), $columns);
+ $view = new static(MonitoringBackend::instance($params['backend']), $columns);
foreach ($params as $key => $value) {
if ($view->isValidFilterTarget($key)) {
diff --git a/modules/monitoring/library/Monitoring/Object/Host.php b/modules/monitoring/library/Monitoring/Object/Host.php
index 483cb2baed..831579a571 100644
--- a/modules/monitoring/library/Monitoring/Object/Host.php
+++ b/modules/monitoring/library/Monitoring/Object/Host.php
@@ -5,7 +5,7 @@
namespace Icinga\Module\Monitoring\Object;
use InvalidArgumentException;
-use Icinga\Module\Monitoring\Backend;
+use Icinga\Module\Monitoring\Backend\MonitoringBackend;
/**
* A Icinga host
@@ -63,10 +63,10 @@ class Host extends MonitoredObject
/**
* Create a new host
*
- * @param Backend $backend Backend to fetch host information from
+ * @param MonitoringBackend $backend Backend to fetch host information from
* @param string $host Host name
*/
- public function __construct(Backend $backend, $host)
+ public function __construct(MonitoringBackend $backend, $host)
{
parent::__construct($backend);
$this->host = $host;
diff --git a/modules/monitoring/library/Monitoring/Object/MonitoredObject.php b/modules/monitoring/library/Monitoring/Object/MonitoredObject.php
index ecd1a9cf6a..8e88b861be 100644
--- a/modules/monitoring/library/Monitoring/Object/MonitoredObject.php
+++ b/modules/monitoring/library/Monitoring/Object/MonitoredObject.php
@@ -7,7 +7,7 @@
use InvalidArgumentException;
use Icinga\Application\Config;
use Icinga\Exception\InvalidPropertyException;
-use Icinga\Module\Monitoring\Backend;
+use Icinga\Module\Monitoring\Backend\MonitoringBackend;
use Icinga\Web\UrlParams;
/**
@@ -28,7 +28,7 @@ abstract class MonitoredObject
/**
* Backend to fetch object information from
*
- * @var Backend
+ * @var MonitoringBackend
*/
protected $backend;
@@ -119,9 +119,9 @@ abstract class MonitoredObject
/**
* Create a monitored object, i.e. host or service
*
- * @param Backend $backend Backend to fetch object information from
+ * @param MonitoringBackend $backend Backend to fetch object information from
*/
- public function __construct(Backend $backend)
+ public function __construct(MonitoringBackend $backend)
{
$this->backend = $backend;
}
@@ -480,9 +480,9 @@ public function __isset($name)
public static function fromParams(UrlParams $params)
{
if ($params->has('service') && $params->has('host')) {
- return new Service(Backend::createBackend(), $params->get('host'), $params->get('service'));
+ return new Service(MonitoringBackend::instance(), $params->get('host'), $params->get('service'));
} elseif ($params->has('host')) {
- return new Host(Backend::createBackend(), $params->get('host'));
+ return new Host(MonitoringBackend::instance(), $params->get('host'));
}
return null;
}
diff --git a/modules/monitoring/library/Monitoring/Object/ObjectList.php b/modules/monitoring/library/Monitoring/Object/ObjectList.php
index 1e5595d587..6eb1e4db3d 100644
--- a/modules/monitoring/library/Monitoring/Object/ObjectList.php
+++ b/modules/monitoring/library/Monitoring/Object/ObjectList.php
@@ -5,7 +5,7 @@
use ArrayIterator;
use Countable;
use IteratorAggregate;
-use Icinga\Module\Monitoring\Backend;
+use Icinga\Module\Monitoring\Backend\MonitoringBackend;
abstract class ObjectList implements Countable, IteratorAggregate
{
@@ -21,7 +21,7 @@ abstract class ObjectList implements Countable, IteratorAggregate
protected $count;
- public function __construct(Backend $backend)
+ public function __construct(MonitoringBackend $backend)
{
$this->backend = $backend;
}
diff --git a/modules/monitoring/library/Monitoring/Object/Service.php b/modules/monitoring/library/Monitoring/Object/Service.php
index 28d0338f20..6d5245f0d1 100644
--- a/modules/monitoring/library/Monitoring/Object/Service.php
+++ b/modules/monitoring/library/Monitoring/Object/Service.php
@@ -5,7 +5,7 @@
namespace Icinga\Module\Monitoring\Object;
use InvalidArgumentException;
-use Icinga\Module\Monitoring\Backend;
+use Icinga\Module\Monitoring\Backend\MonitoringBackend;
/**
* A Icinga service
@@ -68,11 +68,11 @@ class Service extends MonitoredObject
/**
* Create a new service
*
- * @param Backend $backend Backend to fetch service information from
+ * @param MonitoringBackend $backend Backend to fetch service information from
* @param string $host Host name the service is running on
* @param string $service Service name
*/
- public function __construct(Backend $backend, $host, $service)
+ public function __construct(MonitoringBackend $backend, $host, $service)
{
parent::__construct($backend);
$this->host = new Host($backend, $host);
diff --git a/modules/monitoring/public/css/module.less b/modules/monitoring/public/css/module.less
index 0138e0573f..6e0124ccd3 100644
--- a/modules/monitoring/public/css/module.less
+++ b/modules/monitoring/public/css/module.less
@@ -135,34 +135,9 @@ form.instance-features span.description, form.object-features span.description {
display: inline;
}
-.alertsummary-flex-container {
- display: -ms-Flexbox;
- -ms-box-orient: horizontal;
-
- display: -webkit-flex;
- display: -moz-flex;
- display: -ms-flex;
- display: flex;
-
- -webkit-flex-flow: row wrap;
- -moz-flex-flow: row wrap;
- -ms-flex-flow: row wrap;
- flex-flow: row wrap;
-}
-
-.alertsummary-flex {
- flex: 1 1 auto;
- overflow: auto;
- border: 1px #333 solid;
- padding: 5px;
- margin: 0 10px 0 0;
- border-spacing: 10px 10px;
-}
-
table.avp .customvar ul {
list-style-type: none;
margin: 0;
padding: 0;
padding-left: 1.5em;
}
-
diff --git a/modules/test/application/clicommands/PhpCommand.php b/modules/test/application/clicommands/PhpCommand.php
index 126e0c4626..dbcb58f05e 100644
--- a/modules/test/application/clicommands/PhpCommand.php
+++ b/modules/test/application/clicommands/PhpCommand.php
@@ -56,7 +56,7 @@ public function unitAction()
$options = array();
if ($this->isVerbose) {
- $options[] = '--verbose';
+ $options[] = '--verbose --testdox';
}
if ($build) {
$reportPath = $this->setupAndReturnReportDirectory();
@@ -71,7 +71,23 @@ public function unitAction()
}
chdir(realpath(__DIR__ . '/../..'));
- passthru($phpUnit . ' ' . join(' ', array_merge($options, $this->params->getAllStandalone())));
+ $command = $phpUnit . ' ' . join(' ', array_merge($options, $this->params->getAllStandalone()));
+ if ($this->isVerbose) {
+ $res = `$command`;
+ foreach (preg_split('/\n/', $res) as $line) {
+ if (preg_match('~\s+\[([x\s])\]\s~', $line, $m)) {
+ if ($m[1] === 'x') {
+ echo $this->screen->colorize($line, 'green') . "\n";
+ } else {
+ echo $this->screen->colorize($line, 'red') . "\n";
+ }
+ } else {
+ echo $line . "\n";
+ }
+ }
+ } else {
+ passthru($command);
+ }
}
/**
diff --git a/packages/debian/control b/packages/debian/control
index ab3162d469..48383839a0 100644
--- a/packages/debian/control
+++ b/packages/debian/control
@@ -1,5 +1,5 @@
Source: icingaweb
-Section: upstream
+Section: admin
Maintainer: Icinga Development Team
Priority: optional
Build-Depends: debhelper (>=9)
@@ -28,7 +28,7 @@ Description: Icinga PHP common libraries
Package: icingacli
Architecture: any
-Depends: libicinga-common-php (>= 2.0.0~alpha1)
+Depends: libicinga-common-php (>= 2.0.0~alpha1), php5-cli (>= 5.3.2)
Description: Icinga CLI tool
The Icinga CLI allows one to access it's Icinga monitoring
system from a terminal.
diff --git a/public/css/icinga/forms.less b/public/css/icinga/forms.less
index 10ef3aa45d..e3cf1f6856 100644
--- a/public/css/icinga/forms.less
+++ b/public/css/icinga/forms.less
@@ -189,22 +189,3 @@ textarea {
input, select, textarea {
display: inline;
}
-
-.control-group {
- display: -webkit-flex;
- display: flex;
- -webkit-flex-flow: row wrap;
- flex-flow: row wrap;
-}
-
-.control-group > div {
- width: 100%;
- height: 100%;
- overflow: auto;
-}
-
-@media (min-width: 480px) {
- .control-group > div {
- width: auto;
- }
-}
diff --git a/test/php/library/Icinga/Application/ConfigTest.php b/test/php/library/Icinga/Application/ConfigTest.php
index e74eb06a50..4f4f772199 100644
--- a/test/php/library/Icinga/Application/ConfigTest.php
+++ b/test/php/library/Icinga/Application/ConfigTest.php
@@ -266,6 +266,11 @@ public function testWhetherItIsPossibleToDirectlyRetrieveASectionProperty()
$config->fromSection('a', 'c', 'test'),
'Config::fromSection does not return the given default value for non-existent section properties'
);
+ $this->assertEquals(
+ 'c',
+ $config->fromSection('a', 'b', 'test'),
+ 'Config::fromSection does not return the actual value of a section\'s property in case a default is given'
+ );
}
/**
diff --git a/test/php/library/Icinga/File/Ini/IniWriterTest.php b/test/php/library/Icinga/File/Ini/IniWriterTest.php
index 53bd750d80..1b9580fb39 100644
--- a/test/php/library/Icinga/File/Ini/IniWriterTest.php
+++ b/test/php/library/Icinga/File/Ini/IniWriterTest.php
@@ -29,6 +29,30 @@ public function tearDown()
unlink($this->tempFile2);
}
+ public function testWhetherPointInSectionIsNotNormalized()
+ {
+ $writer = new IniWriter(
+ array(
+ 'config' => new Config(
+ array(
+ 'section' => array(
+ 'foo.bar' => 1337
+ ),
+ 'section.with.multiple.dots' => array(
+ 'some more' => array(
+ 'nested stuff' => 'With more values'
+ )
+ )
+ )
+ ),
+ 'filename' => $this->tempFile
+ )
+ );
+ $writer->write();
+ $config = Config::fromIni($this->tempFile)->toArray();
+ $this->assertTrue(array_key_exists('section.with.multiple.dots', $config), 'Section names not normalized');
+ }
+
public function testWhetherSimplePropertiesAreInsertedInEmptyFiles()
{
$this->markTestSkipped('Implementation has changed. Section-less properties are not supported anymore');
@@ -702,44 +726,6 @@ public function testWhetherCommentsOnSectionPropertyLinesArePreserved()
);
}
- public function testKeyNormalization()
- {
- $normalKeys = new IniWriter(
- array (
- 'config' => new Config(array (
- 'foo' => 'bar',
- 'nest' => array (
- 'nested' => array (
- 'stuff' => 'nested configuration element'
- )
- ),
- 'preserving' => array (
- 'ini' => array(
- 'writer' => 'n'
- ),
- 'foo' => 'this should not be overwritten'
- )
- )),
- 'filename' => $this->tempFile
- )
-
- );
-
- $nestedKeys = new IniWriter(
- array (
- 'config' => new Config(array (
- 'foo' => 'bar',
- 'nest.nested.stuff' => 'nested configuration element',
- 'preserving.ini.writer' => 'n',
- 'preserving.foo' => 'this should not be overwritten'
- )),
- 'filename' => $this->tempFile2
- )
-
- );
- $this->assertEquals($normalKeys->render(), $nestedKeys->render());
- }
-
/**
* Write a INI-configuration string to a temporary file and return it's path
*