diff --git a/library/Icinga/Protocol/Statusdat/ObjectContainer.php b/library/Icinga/Protocol/Statusdat/ObjectContainer.php new file mode 100644 index 000000000..42b1b6cdb --- /dev/null +++ b/library/Icinga/Protocol/Statusdat/ObjectContainer.php @@ -0,0 +1,71 @@ + + * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2 + * @author Icinga Development Team + */ +// {{{ICINGA_LICENSE_HEADER}}} + +namespace Icinga\Protocol\Statusdat; + +/** + * Class ObjectContainer + * @package Icinga\Protocol\Statusdat + */ +class ObjectContainer extends \stdClass +{ + /** + * @var \stdClass + */ + public $ref; + + /** + * @var IReader + */ + public $reader; + + /** + * @param \stdClass $obj + * @param IReader $reader + */ + public function __construct(\stdClass &$obj, IReader &$reader) + { + $this->ref = & $obj; + $this->reader = & $reader; + } + + /** + * @param $attribute + * @return \stdClass + */ + public function __get($attribute) + { + $exploded = explode(".", $attribute); + $result = $this->ref; + foreach ($exploded as $elem) { + + $result = $result->$elem; + } + return $result; + } +} diff --git a/library/Icinga/Protocol/Statusdat/Query.php b/library/Icinga/Protocol/Statusdat/Query.php index 1d91cd096..a0b320b4a 100755 --- a/library/Icinga/Protocol/Statusdat/Query.php +++ b/library/Icinga/Protocol/Statusdat/Query.php @@ -49,10 +49,10 @@ class Query extends AbstractQuery "servicegroups" => array("servicegroup"), "comments" => array("servicecomment", "hostcomment"), "hostcomments" => array("hostcomment"), - "servicecomments" => array("servicecomment"), - "status" => array("host", "service") + "servicecomments" => array("servicecomment") ); + /** * @var IReader|null */ @@ -63,11 +63,6 @@ class Query extends AbstractQuery */ private $source = ""; - /** - * @var array - */ - protected $columns = array(); - /** * @var null */ @@ -165,13 +160,7 @@ class Query extends AbstractQuery return $this->offset; } - /** - * @param IReader $reader - */ - public function __construct(IReader $reader) - { - $this->ds = $reader; - } + /** * @param $key @@ -248,7 +237,6 @@ class Query extends AbstractQuery } else { throw new \Exception("Unknown from target for status.dat :" . $table); } - $this->columns = $columns; return $this; } @@ -269,7 +257,8 @@ class Query extends AbstractQuery $state = $this->ds->getObjects(); $result = array(); - foreach (self::$VALID_TARGETS[$this->source] as $target) { + $source = self::$VALID_TARGETS[$this->source]; + foreach ($source as $target) { $indexes = & array_keys($state[$target]); if ($baseGroup) { $indexes = & $baseGroup->filter($state[$target]); @@ -307,7 +296,6 @@ class Query extends AbstractQuery $o2 = & $this->ds->getObjectByName($this->currentType, $b); $result = 0; foreach ($this->order_columns as $col) { - $result += $col[1] * strnatcasecmp($o1->{$col[0]}, $o2->{$col[0]}); } if ($result > 0) { @@ -410,4 +398,5 @@ class Query extends AbstractQuery } return $result; } + } diff --git a/library/Icinga/Protocol/Statusdat/Reader.php b/library/Icinga/Protocol/Statusdat/Reader.php index d20ade975..e7c369fa2 100755 --- a/library/Icinga/Protocol/Statusdat/Reader.php +++ b/library/Icinga/Protocol/Statusdat/Reader.php @@ -29,6 +29,7 @@ namespace Icinga\Protocol\Statusdat; +use Icinga\Data\DatasourceInterface; use Icinga\Exception as Exception; use Icinga\Benchmark as Benchmark; use Icinga\Protocol\Statusdat\View\MonitoringObjectList; @@ -36,7 +37,7 @@ use Icinga\Protocol\Statusdat\View\MonitoringObjectList; * Class Reader * @package Icinga\Protocol\Statusdat */ -class Reader implements IReader +class Reader implements IReader, DatasourceInterface { /** * diff --git a/library/Icinga/Protocol/Statusdat/View/AbstractAccessorStrategy.php b/library/Icinga/Protocol/Statusdat/View/AccessorStrategy.php similarity index 87% rename from library/Icinga/Protocol/Statusdat/View/AbstractAccessorStrategy.php rename to library/Icinga/Protocol/Statusdat/View/AccessorStrategy.php index e61ef12e6..db3082b5f 100644 --- a/library/Icinga/Protocol/Statusdat/View/AbstractAccessorStrategy.php +++ b/library/Icinga/Protocol/Statusdat/View/AccessorStrategy.php @@ -29,11 +29,11 @@ namespace Icinga\Protocol\Statusdat\View; /** - * Class AbstractAccessorStrategy - * Basic interface for views. - * The name sound weirder than it is: Views define special get and exists operations for fields - * that are not directly available in a resultset, but exist under another name or can be - * accessed by loading an additional object during runtime. + * Interface for statusdat classes that provide a specific view on the dataset + * + * Views define special get and exists operations for fields that are not directly available + * in a resultset, but exist under another name or can be accessed by loading an additional object + * during runtime. * * @see Icinga\Backend\DataView\ObjectRemappingView For an implementation of mapping field names * to storage specific names, e.g. service_state being status.current_state in status.dat views. @@ -41,9 +41,8 @@ namespace Icinga\Protocol\Statusdat\View; * @see Icinga\Backend\MonitoringObjectList For the typical usage of this class. It is not wrapped * around the monitoring object, so we don't use __get() or __set() and always have to give the * item we'd like to access. - * @package Icinga\Backend\DataView */ -interface AbstractAccessorStrategy +interface AccessorStrategy { /** * Returns a field for the item, or throws an Exception if the field doesn't exist diff --git a/library/Icinga/Protocol/Statusdat/View/MonitoringObjectList.php b/library/Icinga/Protocol/Statusdat/View/MonitoringObjectList.php index 3ae1d6e6a..7ddf86fe2 100755 --- a/library/Icinga/Protocol/Statusdat/View/MonitoringObjectList.php +++ b/library/Icinga/Protocol/Statusdat/View/MonitoringObjectList.php @@ -2,7 +2,7 @@ /** * Wrapper around an array of monitoring objects that can be enhanced with an optional - * object that extends AbstractAccessorStrategy. This will act as a dataview and provide + * object that extends AccessorStrategy. This will act as a dataview and provide * normalized access to the underlying data (mapping properties, retrieving additional data) * * If not Accessor is set, this class just behaves like a normal Iterator and returns @@ -19,7 +19,7 @@ class MonitoringObjectList implements \Iterator, \Countable, \ArrayAccess private $position = 0; private $dataView = null; - function __construct(array &$dataset, AbstractAccessorStrategy $dataView = null) + function __construct(array &$dataset, AccessorStrategy $dataView = null) { $this->dataSet = $dataset; $this->position = 0; diff --git a/library/Icinga/Protocol/Statusdat/View/ObjectRemappingView.php b/library/Icinga/Protocol/Statusdat/View/ObjectRemappingView.php index b9e5be6f0..44e6f81c6 100755 --- a/library/Icinga/Protocol/Statusdat/View/ObjectRemappingView.php +++ b/library/Icinga/Protocol/Statusdat/View/ObjectRemappingView.php @@ -46,16 +46,16 @@ namespace Icinga\Protocol\Statusdat\View; */ -class ObjectRemappingView implements AbstractAccessorStrategy +class ObjectRemappingView implements AccessorStrategy { /** * When implementing your own Mapper, this contains the static mapping rules. - * @see Icinga\Backend\Statusdat\DataView\StatusdatServiceView for an example + * @see Monitoring\Backend\Statusdat\DataView\StatusdatServiceView for an example * * @var array */ - protected $mappedParameters = array(); + public static $mappedParameters = array(); private $functionMap = array( "TO_DATE" => "toDateFormat" @@ -73,7 +73,7 @@ class ObjectRemappingView implements AbstractAccessorStrategy /** * - * @see Icinga\Backend\DataView\AbstractAccessorStrategy + * @see Icinga\Backend\DataView\AccessorStrategy * * @param The $item * @param The $field @@ -86,7 +86,7 @@ class ObjectRemappingView implements AbstractAccessorStrategy if (isset($item->$field)) { return $item->$field; } - if (isset($this->mappedParameters[$field])) { + if (isset(static::$mappedParameters[$field])) { return $this->getMappedParameter($item, $field); } @@ -118,7 +118,7 @@ class ObjectRemappingView implements AbstractAccessorStrategy private function getMappedParameter(&$item, $field) { $matches = array(); - $fieldDef = $this->mappedParameters[$field]; + $fieldDef = static::$mappedParameters[$field]; $function = false; if (preg_match_all('/(?P\w+)\((?P.*)\)/', $fieldDef, $matches)) { $function = $matches["FUNCTION"][0]; @@ -141,22 +141,22 @@ class ObjectRemappingView implements AbstractAccessorStrategy /** * - * @see Icinga\Backend\DataView\AbstractAccessorStrategy + * @see Icinga\Backend\DataView\AccessorStrategy * * @param The $field * @return The|string */ public function getNormalizedFieldName($field) { - if (isset($this->mappedParameters[$field])) { - return $this->mappedParameters[$field]; + if (isset(static::$mappedParameters[$field])) { + return static::$mappedParameters[$field]; } return $field; } /** * - * @see Icinga\Backend\DataView\AbstractAccessorStrategy + * @see Icinga\Backend\DataView\AccessorStrategy * * @param The $item * @param The $field @@ -165,7 +165,7 @@ class ObjectRemappingView implements AbstractAccessorStrategy public function exists(&$item, $field) { return (isset($item->$field) - || isset($this->mappedParameters[$field]) + || isset(static::$mappedParameters[$field]) || isset($this->handlerParameters[$field]) ); } diff --git a/modules/monitoring/application/controllers/ListController.php b/modules/monitoring/application/controllers/ListController.php index 0c5341b9d..8a5cd1489 100644 --- a/modules/monitoring/application/controllers/ListController.php +++ b/modules/monitoring/application/controllers/ListController.php @@ -83,22 +83,36 @@ class Monitoring_ListController extends ModuleActionController $this->view->services = $this->query('status', array( 'host_name', - 'host_problems', + 'host_state', + 'host_state_type', + 'host_last_state_change', + 'host_address', + 'host_handled', 'service_description', + 'service_display_name', 'service_state' => $state_column, 'service_in_downtime', 'service_acknowledged', 'service_handled', 'service_output', - 'service_last_state_change' => $state_change_column + 'service_last_state_change' => $state_change_column, + 'service_icon_image', + 'service_long_output', + 'service_is_flapping', + 'service_state_type', + 'service_handled', + 'service_severity', + 'service_last_check', + 'service_notifications_enabled', + 'service_action_url', + 'service_notes_url', + 'service_last_comment' )); - $this->preserve('sort') - ->preserve('backend') - ->preserve('extracolumns'); - $this->view->sort = $this->_getParam('sort'); - if ($this->view->compact) { - $this->_helper->viewRenderer('services-compact'); + if ($this->_getParam('sort')) { + $this->view->sort = $this->_getParam('sort'); } + + } public function hostgroupsAction() diff --git a/modules/monitoring/application/views/helpers/MonitoringState.php b/modules/monitoring/application/views/helpers/MonitoringState.php index de09eebe1..67f473e4a 100644 --- a/modules/monitoring/application/views/helpers/MonitoringState.php +++ b/modules/monitoring/application/views/helpers/MonitoringState.php @@ -27,6 +27,14 @@ class Zend_View_Helper_MonitoringState extends Zend_View_Helper_Abstract if ($object->host_last_state_change > (time() - 600)) { $state_classes[] = 'new'; } + } else { + $state_classes[] = $this->monitoringState($object, "service"); + if ($object->service_acknowledged || $object->service_in_downtime) { + $state_classes[] = 'handled'; + } + if ($object->service_last_state_change > (time() - 600)) { + $state_classes[] = 'new'; + } } return $state_classes; diff --git a/modules/monitoring/application/views/scripts/list/services-bak.phtml b/modules/monitoring/application/views/scripts/list/services-bak.phtml new file mode 100644 index 000000000..3af9b2173 --- /dev/null +++ b/modules/monitoring/application/views/scripts/list/services-bak.phtml @@ -0,0 +1,171 @@ +tabs ?> +paginate(); + +function getRowProperties(&$service, &$last_host, $scope) { + if ($last_host !== $service->host_name) { + $host_col = '' . $scope->qlink( + $service->host_name, + 'monitoring/show/host', + array('host' => $service->host_name) + ) . ':' + . (isset($service->host->address) ? ' ( ' . $scope->escape($service->host->address) . ')' : '') + . ''; + $last_host = $service->host_name; + } else { + $host_col = '  '; + } + $icons = array(); + if ($service->service_acknowledged) { + $icons['ack.gif'] = 'Problem has been acknowledged'; + } + + if ($service->service_in_downtime) { + $icons['downtime.gif'] = 'Service is in a scheduled downtime'; + } + + if ($service->host_problems) { + $icons['server.png'] = 'This services host has a problem'; + } + + $state_classes = array($scope->monitoringState($service)); + + if ($service->service_handled) { + $state_classes[] = 'handled'; + } + if ($service->service_last_state_change > (time() - 600)) { + $state_classes[] = 'new'; + } + $state_title = strtoupper($scope->monitoringState($service)) + . ' since ' + . date('Y-m-d H:i:s', $service->service_last_state_change); + if ($scope->grapher && $scope->grapher->hasGraph($service->host_name, $service->service_description)) { + $graph = $scope->grapher->getSmallPreviewImage( + $service->host_name, + $service->service_description + ); + } else { + $graph = ''; + } + return array($host_col,$icons,$state_classes,$state_title,$graph); +} + +$fparams = $this->services->getAppliedFilter()->toParams(); +if ($this->preserve === null) { + $this->preserve = $fparams; +} else { + $this->preserve += $fparams; +} + $last_host = null; +$always = array(); +if (isset($_GET['sort'])) { + $always['sort'] = $_GET['sort']; +} +if (isset($_GET['dir'])) { + $always['dir'] = $_GET['dir']; +} +?> +
+ +
Filters
+ $v): ?> +qlink( + 'x', + 'monitoring/list/services', + $this->services->getAppliedFilter()->without($k)->toParams() + $always, + array( + 'style' => array('color' => 'red') + ) +) ?> escape("$k = $v") ?>
+ +
+ +
+Sort by formSelect( + 'sort', + $this->sort, + array( + 'class' => 'autosubmit', + ), + array( + 'severity' => 'Severity', + 'service_last_state_change' => 'Last state change', + 'service_last_time_unknown' => 'Last UNKNOWN', + 'service_last_time_critical' => 'Last CRITICAL', + 'service_last_time_warning' => 'Last WARNING', + 'service_last_time_ok' => 'Last OK', + 'host_name' => 'Host', + 'service_description' => 'Service', + ) +) ?> +formText( + 'search', + $this->search, + array( + 'placeholder' => 'Add filllter...', + ) +) ?> +
+
+ + +
+ Sorry, no services found for this search +
+ + +paginationControl($paginator, null, null, array('preserve' => $this->preserve )); ?> + + +fetchAll() as $service): + list($host_col,$icons,$state_classes,$state_title,$graph) = getRowProperties($service,$last_host,$this); ?> + + + + +extraColumns as $col): ?> + + + + + +
+ qlink( + + $service->service_state == 99 ? 'PENDING' : + substr(strtoupper($this->monitoringState($service)), 0, 4) + . ' since
' + . $this->timeSince($service->service_last_state_change), + 'monitoring/show/history', array( + 'host' => $service->host_name, + 'service' => $service->service_description + ), array('quote' => false)) ?> +
+ $alt) { + echo $this->img('img/classic/' . $icon, array( + 'class' => 'icon', + 'title' => $alt + )); + } ?> + + qlink($service->service_description, 'monitoring/show/service', array( + 'host' => $service->host_name, + 'service' => $service->service_description + ), array('class' => 'row-action') + ) + ?> + +
+     + escape(substr(strip_tags($service->service_output), 0, 900)) ?> + + +
escape($service->$col) ?>
diff --git a/modules/monitoring/application/views/scripts/list/services.phtml b/modules/monitoring/application/views/scripts/list/services.phtml index 3af9b2173..19f5f4152 100644 --- a/modules/monitoring/application/views/scripts/list/services.phtml +++ b/modules/monitoring/application/views/scripts/list/services.phtml @@ -1,171 +1,180 @@ tabs ?> -paginate(); -function getRowProperties(&$service, &$last_host, $scope) { - if ($last_host !== $service->host_name) { - $host_col = '' . $scope->qlink( - $service->host_name, - 'monitoring/show/host', - array('host' => $service->host_name) - ) . ':' - . (isset($service->host->address) ? ' ( ' . $scope->escape($service->host->address) . ')' : '') - . ''; - $last_host = $service->host_name; - } else { - $host_col = '  '; - } - $icons = array(); - if ($service->service_acknowledged) { - $icons['ack.gif'] = 'Problem has been acknowledged'; - } - - if ($service->service_in_downtime) { - $icons['downtime.gif'] = 'Service is in a scheduled downtime'; - } - - if ($service->host_problems) { - $icons['server.png'] = 'This services host has a problem'; - } - - $state_classes = array($scope->monitoringState($service)); - - if ($service->service_handled) { - $state_classes[] = 'handled'; - } - if ($service->service_last_state_change > (time() - 600)) { - $state_classes[] = 'new'; - } - $state_title = strtoupper($scope->monitoringState($service)) - . ' since ' - . date('Y-m-d H:i:s', $service->service_last_state_change); - if ($scope->grapher && $scope->grapher->hasGraph($service->host_name, $service->service_description)) { - $graph = $scope->grapher->getSmallPreviewImage( - $service->host_name, - $service->service_description - ); - } else { - $graph = ''; - } - return array($host_col,$icons,$state_classes,$state_title,$graph); -} - -$fparams = $this->services->getAppliedFilter()->toParams(); -if ($this->preserve === null) { - $this->preserve = $fparams; -} else { - $this->preserve += $fparams; -} - $last_host = null; -$always = array(); -if (isset($_GET['sort'])) { - $always['sort'] = $_GET['sort']; -} -if (isset($_GET['dir'])) { - $always['dir'] = $_GET['dir']; -} +$viewHelper = $this->getHelper('MonitoringState'); +$trimArea = $this->getHelper('Trim'); ?> -
- -
Filters
- $v): ?> -qlink( - 'x', - 'monitoring/list/services', - $this->services->getAppliedFilter()->without($k)->toParams() + $always, - array( - 'style' => array('color' => 'red') - ) -) ?> escape("$k = $v") ?>
- -
- -
-Sort by formSelect( - 'sort', - $this->sort, - array( - 'class' => 'autosubmit', - ), - array( - 'severity' => 'Severity', - 'service_last_state_change' => 'Last state change', - 'service_last_time_unknown' => 'Last UNKNOWN', - 'service_last_time_critical' => 'Last CRITICAL', - 'service_last_time_warning' => 'Last WARNING', - 'service_last_time_ok' => 'Last OK', - 'host_name' => 'Host', - 'service_description' => 'Service', - ) -) ?> -formText( - 'search', - $this->search, - array( - 'placeholder' => 'Add filllter...', - ) -) ?> -
-
+ - -
- Sorry, no services found for this search -
- +
+ Sorry, no services found for this search +
-paginationControl($paginator, null, null, array('preserve' => $this->preserve )); ?> - - -fetchAll() as $service): - list($host_col,$icons,$state_classes,$state_title,$graph) = getRowProperties($service,$last_host,$this); ?> - - - -extraColumns as $col): ?> - - - - + + Sort by formSelect( + 'sort', + $this->sort, + array('class' => 'autosubmit'), + array( + 'service_severity' => 'Severity', + 'service_last_state_change' => 'Last state change', + 'service_last_time_unknown' => 'Last UNKNOWN', + 'service_last_time_critical' => 'Last CRITICAL', + 'service_last_time_warning' => 'Last WARNING', + 'service_last_time_ok' => 'Last OK', + 'service_description' => 'Service', + ) + ) ?> + + + +paginationControl($paginator, null, null, array('preserve' => $this->preserve)) ?> + +
- qlink( - - $service->service_state == 99 ? 'PENDING' : - substr(strtoupper($this->monitoringState($service)), 0, 4) - . ' since
' - . $this->timeSince($service->service_last_state_change), - 'monitoring/show/history', array( - 'host' => $service->host_name, - 'service' => $service->service_description - ), array('quote' => false)) ?> -
- $alt) { - echo $this->img('img/classic/' . $icon, array( - 'class' => 'icon', - 'title' => $alt - )); - } ?> - - qlink($service->service_description, 'monitoring/show/service', array( - 'host' => $service->host_name, - 'service' => $service->service_description - ), array('class' => 'row-action') - ) - ?> -
-     - escape(substr(strip_tags($service->service_output), 0, 900)) ?> - - -
escape($service->$col) ?>
+ + + + + + + + + + + + fetchAll() as $service): ?> + + + + + + + + + + + + + + + + +
StatusServiceHostOutput
+
start(); ?> + service_icon_image) : ?> + + + end(); ?>
+
+
start(); ?> + service_handled && $service->service_state > 0): ?> + + + + + service_acknowledged && !$service->service_in_downtime): ?> + + + + + service_is_flapping): ?> + + + + + service_notifications_enabled): ?> + + + + + service_in_downtime): ?> + + + + + end(); ?>
+
+
+ qlink( + "".ucfirst($viewHelper->monitoringState($service, 'service'))."". + '
since '. + $this->timeSince($service->service_last_state_change), + 'monitoring/show/history', array( + 'host' => $service->host_name, + 'service' => $service->service_description + ), + array('quote' => false) + );?> + service_state_type == 0): ?> + + + + +
+
+ service_last_comment !== null): ?> + + + + + qlink( + "".$service->service_display_name."
", + 'monitoring/show/service', array( + 'host' => $service->host_name, + 'service' => $service->service_description + ), array( + 'class' => 'row-action', + 'quote' => false + ) + ); ?> + + + service_action_url != ""): ?> + Action + + + service_notes_url != ""): ?> + Notes + + service_state_type == 0): ?> + + + + +
+ qlink( + $service->host_name, + 'monitoring/show/host', array( + 'host' => $service->host_name + ), array( + 'class' => 'row-action', + 'quote' => false + ) + ); ?> + +
+ qlink( + "(".ucfirst($viewHelper->monitoringState($service, 'host')).")", + 'monitoring/show/history', array( + 'host' => $service->host_name, + 'service' => $service->service_description + ), + array('quote' => false) + );?> +
+ + host_address ?> + +
+ escape(substr(strip_tags($service->service_output), 0, 10000)); ?> +
diff --git a/modules/monitoring/library/Monitoring/Backend/AbstractBackend.php b/modules/monitoring/library/Monitoring/Backend/AbstractBackend.php index 5f2719478..2f5a984b6 100644 --- a/modules/monitoring/library/Monitoring/Backend/AbstractBackend.php +++ b/modules/monitoring/library/Monitoring/Backend/AbstractBackend.php @@ -54,6 +54,7 @@ class AbstractBackend implements DatasourceInterface ) ); } + $query = new $classname($this, $fields); return $query; } diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/AbstractQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/AbstractQuery.php index 9f057d455..872db3dcb 100644 --- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/AbstractQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/AbstractQuery.php @@ -153,11 +153,10 @@ abstract class AbstractQuery extends Query } elseif ($this->hasAliasName($col)) { $col = $this->aliasToColumnName($col); } else { - die('SHIT'); + throw new \InvalidArgumentException('Can\'t order by column '.$col); } $this->order_columns[] = array($col, $dir); return $this; - return parent::order($col, $dir); } public function setRealColumns() diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/StatusQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/StatusQuery.php index 8dd52e61f..608369c2d 100644 --- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/StatusQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/StatusQuery.php @@ -113,6 +113,8 @@ class StatusQuery extends AbstractQuery 'service_description' => 'so.name2 COLLATE latin1_general_ci', 'service_display_name' => 's.display_name', 'service_icon_image' => 's.icon_image', + 'service_action_url' => 's.action_url', + 'service_notes_url' => 's.notes_url' ), 'servicestatus' => array( @@ -123,9 +125,10 @@ class StatusQuery extends AbstractQuery 'service_output' => 'ss.output', 'service_long_output' => 'ss.long_output', 'service_perfdata' => 'ss.perfdata', + 'service_is_flapping' => 'ss.is_flapping', 'service_acknowledged' => 'ss.problem_has_been_acknowledged', 'service_in_downtime' => 'CASE WHEN (ss.scheduled_downtime_depth = 0) THEN 0 ELSE 1 END', - 'service_handled' => 'CASE WHEN (ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth + COALESCE(hs.current_state, 0)) > 0 THEN 1 ELSE 0 END', + 'service_handled' => 'CASE WHEN (COALESCE(ss.current_state, 0) * ss.problem_has_been_acknowledged + ss.scheduled_downtime_depth + COALESCE(hs.current_state, 0)) > 0 THEN 1 ELSE 0 END', 'service_does_active_checks' => 'ss.active_checks_enabled', 'service_accepts_passive_checks' => 'ss.passive_checks_enabled', 'service_last_state_change' => 'UNIX_TIMESTAMP(ss.last_state_change)', @@ -152,9 +155,9 @@ class StatusQuery extends AbstractQuery 'service_last_comment' => 'slc.comment_id' ), 'status' => array( - 'problems' => 'CASE WHEN ss.current_state = 0 THEN 0 ELSE 1 END', - 'handled' => 'CASE WHEN ss.problem_has_been_acknowledged = 1 OR ss.scheduled_downtime_depth > 0 THEN 1 ELSE 0 END', - 'severity' => 'CASE WHEN ss.current_state = 0 + 'service_problems' => 'CASE WHEN ss.current_state = 0 THEN 0 ELSE 1 END', + 'service_handled' => 'CASE WHEN ss.problem_has_been_acknowledged = 1 OR ss.scheduled_downtime_depth > 0 THEN 1 ELSE 0 END', + 'service_severity' => 'CASE WHEN ss.current_state = 0 THEN CASE WHEN ss.has_been_checked = 0 OR ss.has_been_checked IS NULL THEN 16 @@ -345,4 +348,16 @@ class StatusQuery extends AbstractQuery array() ); } + + protected function joinLastservicecomment() + { + $this->baseQuery->joinleft( + array ('slc' => new \Zend_Db_Expr( + '(SELECT MAX(c.comment_id) as comment_id, c.object_id '. + 'FROM icinga_comments c GROUP BY c.object_id)') + ), + 'slc.object_id = ss.service_object_id', + array() + ); + } } diff --git a/modules/monitoring/library/Monitoring/Backend/Statusdat/DataView/StatusdatHostView.php b/modules/monitoring/library/Monitoring/Backend/Statusdat/DataView/HostStatusView.php similarity index 90% rename from modules/monitoring/library/Monitoring/Backend/Statusdat/DataView/StatusdatHostView.php rename to modules/monitoring/library/Monitoring/Backend/Statusdat/DataView/HostStatusView.php index 27441b3c0..f204e7d94 100644 --- a/modules/monitoring/library/Monitoring/Backend/Statusdat/DataView/StatusdatHostView.php +++ b/modules/monitoring/library/Monitoring/Backend/Statusdat/DataView/HostStatusView.php @@ -35,7 +35,7 @@ use Icinga\Protocol\Statusdat\IReader; * Class StatusdatHostView * @package Icinga\Backend\Statusdat\DataView */ -class StatusdatHostView extends ObjectRemappingView +class HostStatusView extends ObjectRemappingView { /** * @var mixed @@ -49,7 +49,8 @@ class StatusdatHostView extends ObjectRemappingView "host" => "getHost", "host_unhandled_service_count" => "getNrOfUnhandledServices", "host_last_comment" => "getLastComment", - 'host_handled' => "checkIfHandled" + 'host_handled' => "checkIfHandled", + ); public function checkIfHandled(&$host) @@ -83,20 +84,21 @@ class StatusdatHostView extends ObjectRemappingView /** * @var array */ - protected $mappedParameters = array( + public static $mappedParameters = array( "host_address" => "address", "host_name" => "host_name", + "host" => "host_name", "host_state" => "status.current_state", "host_output" => "status.plugin_output", "host_long_output" => "status.long_plugin_output", - "host_perfdata" => "status.pluign", + "host_perfdata" => "status.performance_data", "host_last_state_change" => "status.last_state_change", "host_check_command" => "check_command", "host_last_check" => "TO_DATE(status.last_check)", "host_next_check" => "status.next_check", "host_check_latency" => "status.check_latency", "host_check_execution_time" => "status.check_execution_time", - "active_checks_enabled" => "status.active_checks_enabled", + "host_active_checks_enabled" => "status.active_checks_enabled", "host_in_downtime" => "status.scheduled_downtime_depth", "host_is_flapping" => "status.is_flapping", "host_notifications_enabled"=> "status.notifications_enabled", @@ -104,7 +106,7 @@ class StatusdatHostView extends ObjectRemappingView "host_icon_image" => "icon_image", "host_action_url" => "action_url", "host_notes_url" => "notes_url", - "host_acknowledged" => "status.problem_has_been_acknowledged", + "host_acknowledged" => "status.problem_has_been_acknowledged" // "state" => "current_state" ); @@ -114,7 +116,7 @@ class StatusdatHostView extends ObjectRemappingView */ public function getHost(&$item) { - if (!isset($this->state["host"][$item->host_name])) { + if (!isset($this->state["service"][$item->host_name])) { return null; } if (!isset($this->state["host"][$item->host_name])) { diff --git a/modules/monitoring/library/Monitoring/Backend/Statusdat/DataView/ServiceStatusView.php b/modules/monitoring/library/Monitoring/Backend/Statusdat/DataView/ServiceStatusView.php new file mode 100644 index 000000000..a79214be2 --- /dev/null +++ b/modules/monitoring/library/Monitoring/Backend/Statusdat/DataView/ServiceStatusView.php @@ -0,0 +1,163 @@ + + * @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2 + * @author Icinga Development Team + */ +// {{{ICINGA_LICENSE_HEADER}}} + +namespace Monitoring\Backend\Statusdat\DataView; + +use Icinga\Protocol\Statusdat\View\ObjectRemappingView; +use Icinga\Protocol\Statusdat\IReader; + +/** + * Class StatusdatHostView + * @package Icinga\Backend\Statusdat\DataView + */ +class ServiceStatusView extends ObjectRemappingView +{ + /** + * @var mixed + */ + private $state; + + /** + * @var array + */ + protected $handlerParameters = array( + "host" => "getHost", + "host_last_comment" => "getLastHostComment", + 'host_handled' => "checkIfHostHandled", + 'service_handled' => "checkIfHandled", + "service_last_comment" => "getLastComment" + ); + + public function checkIfHostHandled(&$service) + { + return $service->host->status->current_state == 0 || + $service->host->status->problem_has_been_acknowledged || + $service->host->status->scheduled_downtime_depth; + } + + + public function checkIfHandled(&$service) + { + return $service->status->current_state == 0 || + $service->status->problem_has_been_acknowledged || + $service->status->scheduled_downtime_depth; + } + + public function getLastComment(&$service) + { + if (!isset($service->comment) || empty($service->comment)) { + return null; + } + $comment = end($service->comment); + return $comment->comment_id; + } + + public function getLastHostComment(&$service) + { + if (!isset($service->host->comment) || empty($service->host->comment)) { + return null; + } + $comment = end($service->host->comment); + return $comment->comment_id; + } + + /** + * @var array + */ + public static $mappedParameters = array( + "host_address" => "host.address", + "host_name" => "host.host_name", + "host" => "host.host_name", + "host_state" => "host.status.current_state", + "host_output" => "host.status.plugin_output", + "host_long_output" => "host.status.long_plugin_output", + "host_perfdata" => "host.status.performance_data", + "host_last_state_change" => "host.status.last_state_change", + "host_check_command" => "host.check_command", + "host_last_check" => "TO_DATE(host.status.last_check)", + "host_next_check" => "host.status.next_check", + "host_check_latency" => "host.status.check_latency", + "host_check_execution_time" => "host.status.check_execution_time", + "host_active_checks_enabled" => "host.status.active_checks_enabled", + "host_in_downtime" => "host.status.scheduled_downtime_depth", + "host_is_flapping" => "host.status.is_flapping", + "host_notifications_enabled" => "host.status.notifications_enabled", + "host_state_type" => "host.status.state_type", + "host_icon_image" => "host.icon_image", + "host_action_url" => "host.action_url", + "host_notes_url" => "host.notes_url", + "host_acknowledged" => "host.status.problem_has_been_acknowledged", + "service" => "service_description", + "service_display_name" => "service_description", + "service_description" => "service_description", + "service_state" => "status.current_state", + "service_icon_image" => "icon_image", + "service_output" => "status.plugin_output", + "service_long_output" => "status.long_plugin_output", + "service_perfdata" => "status.performance_data", + "service_last_state_change" => "status.last_state_change", + "service_check_command" => "check_command", + "service_last_check" => "TO_DATE(status.last_check)", + "service_next_check" => "status.next_check", + "service_check_latency" => "status.check_latency", + "service_check_execution_time" => "status.check_execution_time", + "service_active_checks_enabled" => "status.active_checks_enabled", + "service_in_downtime" => "status.scheduled_downtime_depth", + "service_is_flapping" => "status.is_flapping", + "service_notifications_enabled" => "status.notifications_enabled", + "service_state_type" => "status.state_type", + "service_icon_image" => "icon_image", + "service_action_url" => "action_url", + "service_notes_url" => "notes_url", + "service_acknowledged" => "status.problem_has_been_acknowledged", + // "state" => "current_state" + ); + + /** + * @param $item + * @return null + */ + public function getHost(&$item) + { + if (!isset($this->state["service"][$item->host_name])) { + return null; + } + if (!isset($this->state["host"][$item->host_name])) { + return null; + } + return $this->state["host"][$item->host_name]; + } + + /** + * @param IReader $reader + */ + public function __construct(IReader $reader) + { + $this->state = & $reader->getState(); + } +} diff --git a/modules/monitoring/library/Monitoring/Backend/Statusdat/DataView/StatusdatServiceView.php b/modules/monitoring/library/Monitoring/Backend/Statusdat/DataView/StatusdatServiceView.php index 27ab69966..f40c3c3eb 100644 --- a/modules/monitoring/library/Monitoring/Backend/Statusdat/DataView/StatusdatServiceView.php +++ b/modules/monitoring/library/Monitoring/Backend/Statusdat/DataView/StatusdatServiceView.php @@ -49,7 +49,7 @@ class StatusdatServiceView extends ObjectRemappingView /** * @var array */ - protected $mappedParameters = array( + public static $mappedParameters = array( "host_address" => "parenthost.address", "host_name" => "host_name", "active_checks_enabled" => "status.active_checks_enabled", diff --git a/modules/monitoring/library/Monitoring/Backend/Statusdat/Query/Query.php b/modules/monitoring/library/Monitoring/Backend/Statusdat/Query/Query.php index 1e551c846..d0d5fdd1e 100644 --- a/modules/monitoring/library/Monitoring/Backend/Statusdat/Query/Query.php +++ b/modules/monitoring/library/Monitoring/Backend/Statusdat/Query/Query.php @@ -33,6 +33,7 @@ use Icinga\Protocol\Statusdat; use Icinga\Exception; use Icinga\Data\AbstractQuery; use Icinga\Protocol\Statusdat\View\MonitoringObjectList as MList; +use Icinga\Protocol\Statusdat\Query as StatusdatQuery; /** * Class Query * @package Icinga\Backend\Statusdat @@ -42,24 +43,24 @@ abstract class Query extends AbstractQuery /** * @var null */ - protected $cursor = null; + private $cursor = null; /** * @var string */ - protected $view = 'Monitoring\Statusdat\DataView\StatusdatServiceView'; + private $viewClass = '\Monitoring\Backend\Statusdat\DataView\StatusdatServiceView'; + private $baseQuery = null; + + public function setBaseQuery(StatusdatQuery $query) + { + $this->baseQuery = $query; + } + + public function setResultViewClass($viewClass) + { + $this->viewClass = '\Monitoring\Backend\Statusdat\DataView\\'.$viewClass; + } - /** - * @var array Mapping of order to field names - * @todo Is not complete right now - */ - protected $orderColumns = array( - Order::SERVICE_STATE => "status.current_state", - Order::STATE_CHANGE => "status.last_state_change", - Order::HOST_STATE => "status.current_state", - Order::HOST_NAME => "host_name", - Order::SERVICE_NAME => "service_description" - ); /** * Calls the apply%Filtername%Filter() method for the given filter, or simply calls @@ -113,7 +114,7 @@ abstract class Query extends AbstractQuery $text = "%$value%"; $val = array($text, $text, $text); - $this->query->where("(host_name LIKE ? OR service_description LIKE ? OR status.plugin_output LIKE ?)", $val); + $this->baseQuery->where("(host_name LIKE ? OR service_description LIKE ? OR status.plugin_output LIKE ?)", $val); } @@ -126,7 +127,7 @@ abstract class Query extends AbstractQuery public function applyHostgroupsFilter($type, $value) { $filter = array($value); - $this->query->where("host.group IN ?", $filter); + $this->baseQuery->where("host.group IN ?", $filter); } /** @@ -138,7 +139,7 @@ abstract class Query extends AbstractQuery public function applyServicegroupsFilter($type, $value) { $filter = array($value); - $this->query->where("group IN ?", $filter); + $this->baseQuery->where("group IN ?", $filter); } /** @@ -151,7 +152,7 @@ abstract class Query extends AbstractQuery public function applyHandledFilter($type, $value) { $val = array($value, $value); - $this->query->where("(status.problem_has_been_acknowledged = ? )", $val); + $this->baseQuery->where("(status.problem_has_been_acknowledged = ? )", $val); } /** @@ -163,7 +164,7 @@ abstract class Query extends AbstractQuery if (!is_array($value)) { $value = array($value); } - $this->query->where("host_name LIKE ?", $value); + $this->baseQuery->where("host_name LIKE ?", $value); } /** @@ -172,7 +173,7 @@ abstract class Query extends AbstractQuery */ public function applyStateFilter($type, $value) { - $this->query->where("status.current_state = $value"); + $this->baseQuery->where("status.current_state = $value"); } /** @@ -181,7 +182,7 @@ abstract class Query extends AbstractQuery */ public function applyHoststateFilter($type, $value) { - $this->query->where("host.status.current_state = $value"); + $this->baseQuery->where("host.status.current_state = $value"); } /** @@ -193,7 +194,7 @@ abstract class Query extends AbstractQuery if (!is_array($value)) { $value = array($value); } - $this->query->where("service_description LIKE ?", $value); + $this->baseQuery->where("service_description LIKE ?", $value); } /** @@ -204,7 +205,7 @@ abstract class Query extends AbstractQuery */ public function limit($count = null, $offset = null) { - $this->query->limit($count, $offset); + $this->baseQuery->limit($count, $offset); return $this; } @@ -219,7 +220,8 @@ abstract class Query extends AbstractQuery { if ($column) { - $this->query->order($this->orderColumns[$column], strtolower($dir)); + $class = $this->viewClass; + $this->baseQuery->order($class::$mappedParameters[$column], strtolower($dir)); } return $this; } @@ -237,7 +239,7 @@ abstract class Query extends AbstractQuery if (!is_array($value)) { $value = array($value); } - $this->query->where($column, $value); + $this->baseQuery->where($column, $value); return $this; } @@ -246,9 +248,9 @@ abstract class Query extends AbstractQuery */ public function fetchAll() { - $view = $this->view; + $view = $this->viewClass; if (!$this->cursor) { - $this->cursor = new MList($this->query->getResult(), new $view($this->reader)); + $this->cursor = new MList($this->baseQuery->getResult(), new $view($this->reader)); } return $this->cursor; } @@ -283,6 +285,6 @@ abstract class Query extends AbstractQuery public function count() { - return count($this->query->getResult()); + return count($this->baseQuery->getResult()); } } diff --git a/modules/monitoring/library/Monitoring/Backend/Statusdat/Query/StatusQuery.php b/modules/monitoring/library/Monitoring/Backend/Statusdat/Query/StatusQuery.php index 20141b6db..08c2d738c 100644 --- a/modules/monitoring/library/Monitoring/Backend/Statusdat/Query/StatusQuery.php +++ b/modules/monitoring/library/Monitoring/Backend/Statusdat/Query/StatusQuery.php @@ -15,22 +15,24 @@ use Icinga\Exception; class StatusQuery extends Query { - /** - * @var \Icinga\Protocol\Statusdat\Query - */ - protected $query; - - /** - * @var string - */ - protected $view = 'Monitoring\Backend\Statusdat\DataView\StatusdatHostView'; + private function getTarget() + { + foreach($this->getColumns() as $column) { + if(preg_match("/^service/",$column)) + return "service"; + } + return "host"; + } public function init() { - + $target = $this->getTarget(); $this->reader = $this->ds->getReader(); - $this->query = $this->reader->select()->from("hosts", array()); + $this->setResultViewClass(ucfirst($target)."StatusView"); + $this->setBaseQuery($this->reader->select()->from($target."s", array())); + + } } \ No newline at end of file diff --git a/modules/monitoring/library/Monitoring/View/MonitoringView.php b/modules/monitoring/library/Monitoring/View/MonitoringView.php index 6e4766276..6777a895a 100644 --- a/modules/monitoring/library/Monitoring/View/MonitoringView.php +++ b/modules/monitoring/library/Monitoring/View/MonitoringView.php @@ -135,6 +135,7 @@ class MonitoringView extends AbstractQuery */ protected function applyRequestSorting($request) { + return $this->order( // TODO: Use first sortDefaults entry if available, fall back to // column if not @@ -238,12 +239,12 @@ class MonitoringView extends AbstractQuery -4 ) . 'Query'; $class = '\\' . get_class($this->ds) . '\\Query\\' . $class; - $query = new $class($this->ds, $this->columns); foreach ($this->filters as $f) { $query->where($f[0], $f[1]); } foreach ($this->order_columns as $col) { + if (isset($this->sortDefaults[$col[0]]['columns'])) { foreach ($this->sortDefaults[$col[0]]['columns'] as $c) { $query->order($c, $col[1]); @@ -252,11 +253,13 @@ class MonitoringView extends AbstractQuery $query->order($col[0], $col[1]); } } + $this->query = $query; } if ($this->hasLimit()) { $this->query->limit($this->getLimit(), $this->getOffset()); } + return $this->query; } diff --git a/modules/monitoring/test/php/application/controllers/ListControllerHostTest.php b/modules/monitoring/test/php/application/controllers/ListControllerHostTest.php index 316855e8d..5e65a5dc0 100644 --- a/modules/monitoring/test/php/application/controllers/ListControllerHostTest.php +++ b/modules/monitoring/test/php/application/controllers/ListControllerHostTest.php @@ -96,7 +96,6 @@ class ListControllerHostMySQLTest extends MonitoringControllerTest $this->assertEquals("note1.html", $hostToTest->host_notes_url, 'Testing for notes url (backend '.$backend.')'); $this->assertEquals("action.html", $hostToTest->host_action_url, 'Testing for action url (backend '.$backend.')'); $this->assertEquals(2, $hostToTest->host_unhandled_service_count, 'Testing correct open problems count (backend '.$backend.')'); - } } \ No newline at end of file diff --git a/modules/monitoring/test/php/application/controllers/ListControllerServiceTest.php b/modules/monitoring/test/php/application/controllers/ListControllerServiceTest.php new file mode 100644 index 000000000..39b73fda8 --- /dev/null +++ b/modules/monitoring/test/php/application/controllers/ListControllerServiceTest.php @@ -0,0 +1,69 @@ +executeServiceListTestFor("mysql"); + } + + public function testServiceListPgSQL() + { + $this->executeServiceListTestFor("pgsql"); + } + + public function testServiceListStatusdat() + { + $this->executeServiceListTestFor("statusdat"); + } + + public function executeServiceListTestFor($backend) + { + date_default_timezone_set('UTC'); + $checkTime = time()-2000; + $fixture = new TestFixture(); + $fixture->addHost('host1', 0)-> + addService("svc1", 0, new ObjectFlags(2000), array( + "notes_url" => "notes.url", + "action_url" => "action.url", + "icon_image" => "svcIcon.png" + ))-> + addService("svcDown", 2) -> addComment("author", "Comment text")-> + addService("svcFlapping", 1, ObjectFlags::FLAPPING())->addToServicegroup("Warning")-> + addService("svcNotifDisabled", 2, ObjectFlags::DISABLE_NOTIFICATIONS())-> + addService("svcPending", 0, ObjectFlags::PENDING()); + $fixture->addHost('host2', 1)-> + addService("svcPassive", 1, ObjectFlags::PASSIVE_ONLY())->addToServicegroup("Warning")-> + addService("svcDisabled", 1, ObjectFlags::DISABLED())->addToServicegroup("Warning")-> + addService("svcDowntime", 2, ObjectFlags::IN_DOWNTIME())-> + addService("svcAcknowledged", 1, ObjectFlags::ACKNOWLEDGED())->addToServicegroup("Warning"); + try { + $this->setupFixture($fixture, $backend); + } catch (\PDOException $e) { + echo $e->getMessage(); + $this->markTestSkipped('Could not setup fixture for backends '.$backend.' :'.$e->getMessage()); + return null; + } + + $controller = $this->requireController('ListController', $backend); + $controller->servicesAction(); + $result = $controller->view->services->fetchAll(); + + $this->assertEquals(9, count($result), "Testing for correct service count"); + $this->assertEquals("notes.url", $result[0]->service_notes_url, "Testing for correct notes_url"); + $this->assertEquals("action.url", $result[0]->service_action_url, "Testing for correct action_url"); + $this->assertEquals(0, $result[0]->service_state, "Testing for correct Service state"); + + } + + +} \ No newline at end of file diff --git a/modules/monitoring/test/php/testlib/MonitoringControllerTest.php b/modules/monitoring/test/php/testlib/MonitoringControllerTest.php index 6831fe85b..2077a5d32 100644 --- a/modules/monitoring/test/php/testlib/MonitoringControllerTest.php +++ b/modules/monitoring/test/php/testlib/MonitoringControllerTest.php @@ -16,6 +16,8 @@ namespace Icinga\Web */ public $view; + public $headers = array(); + /** * Parameters provided on call * @var array @@ -28,14 +30,29 @@ namespace Icinga\Web * @param string $param The parameter name to retrieve * @return mixed|bool The parameter $param or false if it doesn't exist */ - public function _getParam($param) + public function _getParam($param, $default = null) { if (!isset($this->params[$param])) { - return false; + return $default; } return $this->params[$param]; } + public function getParam($param, $default = null) + { + return $this->_getParam($param, $default); + } + + public function preserve() + { + return $this; + } + + public function getParams() + { + return $this->params; + } + /** * Sets the backend for this controller which will be used in the action * @@ -45,6 +62,17 @@ namespace Icinga\Web { $this->backend = $backend; } + + public function __get($param) { + return $this; + } + + public function getHeader($header) { + if (isset($this->headers[$header])) { + return $this->headers[$header]; + } + return null; + } } } diff --git a/modules/monitoring/test/php/testlib/datasource/strategies/PDOInsertionStrategy.php b/modules/monitoring/test/php/testlib/datasource/strategies/PDOInsertionStrategy.php index 2b9197ef0..4232a9a68 100644 --- a/modules/monitoring/test/php/testlib/datasource/strategies/PDOInsertionStrategy.php +++ b/modules/monitoring/test/php/testlib/datasource/strategies/PDOInsertionStrategy.php @@ -170,14 +170,14 @@ class PDOInsertionStrategy $insertObjectQuery->execute(array($this->objectId, $service["host"]["name"], $service["name"])); $insertServiceQuery->execute(array( $this->objectId, $service['host']['object_id'], $this->objectId, $service['name'], - $service["notes_url"], $service["action_url"], $service["icon_image"] + $service["icon_image"], $service["notes_url"], $service["action_url"] )); $insertServiceStatusQuery->execute(array( $this->objectId, $service["state"], date($this->datetimeFormat, $flags->time), date($this->datetimeFormat, $flags->time), $flags->notifications, $flags->active_checks, $flags->passive_checks, $flags->flapping, $flags->in_downtime, "Plugin output for service ".$service["name"], "Long plugin output for service ".$service["name"], $flags->acknowledged, - $flags->is_pending == 0 + $flags->is_pending == 0 ? '1' : '0' )); foreach($service["contacts"] as $contact) {