Add Service overview and fixes for Statusdat

The service overview required a few fixes for issues that
occured because the StatusDat Query class now inherits from
Data/AbstractQuery.

refs #4178
This commit is contained in:
Jannis Moßhammer 2013-07-19 17:45:51 +02:00
parent 340554a58c
commit 5e4adcfea2
23 changed files with 809 additions and 264 deletions

View File

@ -0,0 +1,71 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* Icinga 2 Web - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*/
// {{{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;
}
}

View File

@ -49,10 +49,10 @@ class Query extends AbstractQuery
"servicegroups" => array("servicegroup"), "servicegroups" => array("servicegroup"),
"comments" => array("servicecomment", "hostcomment"), "comments" => array("servicecomment", "hostcomment"),
"hostcomments" => array("hostcomment"), "hostcomments" => array("hostcomment"),
"servicecomments" => array("servicecomment"), "servicecomments" => array("servicecomment")
"status" => array("host", "service")
); );
/** /**
* @var IReader|null * @var IReader|null
*/ */
@ -63,11 +63,6 @@ class Query extends AbstractQuery
*/ */
private $source = ""; private $source = "";
/**
* @var array
*/
protected $columns = array();
/** /**
* @var null * @var null
*/ */
@ -165,13 +160,7 @@ class Query extends AbstractQuery
return $this->offset; return $this->offset;
} }
/**
* @param IReader $reader
*/
public function __construct(IReader $reader)
{
$this->ds = $reader;
}
/** /**
* @param $key * @param $key
@ -248,7 +237,6 @@ class Query extends AbstractQuery
} else { } else {
throw new \Exception("Unknown from target for status.dat :" . $table); throw new \Exception("Unknown from target for status.dat :" . $table);
} }
$this->columns = $columns;
return $this; return $this;
} }
@ -269,7 +257,8 @@ class Query extends AbstractQuery
$state = $this->ds->getObjects(); $state = $this->ds->getObjects();
$result = array(); $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]); $indexes = & array_keys($state[$target]);
if ($baseGroup) { if ($baseGroup) {
$indexes = & $baseGroup->filter($state[$target]); $indexes = & $baseGroup->filter($state[$target]);
@ -307,7 +296,6 @@ class Query extends AbstractQuery
$o2 = & $this->ds->getObjectByName($this->currentType, $b); $o2 = & $this->ds->getObjectByName($this->currentType, $b);
$result = 0; $result = 0;
foreach ($this->order_columns as $col) { foreach ($this->order_columns as $col) {
$result += $col[1] * strnatcasecmp($o1->{$col[0]}, $o2->{$col[0]}); $result += $col[1] * strnatcasecmp($o1->{$col[0]}, $o2->{$col[0]});
} }
if ($result > 0) { if ($result > 0) {
@ -410,4 +398,5 @@ class Query extends AbstractQuery
} }
return $result; return $result;
} }
} }

View File

@ -29,6 +29,7 @@
namespace Icinga\Protocol\Statusdat; namespace Icinga\Protocol\Statusdat;
use Icinga\Data\DatasourceInterface;
use Icinga\Exception as Exception; use Icinga\Exception as Exception;
use Icinga\Benchmark as Benchmark; use Icinga\Benchmark as Benchmark;
use Icinga\Protocol\Statusdat\View\MonitoringObjectList; use Icinga\Protocol\Statusdat\View\MonitoringObjectList;
@ -36,7 +37,7 @@ use Icinga\Protocol\Statusdat\View\MonitoringObjectList;
* Class Reader * Class Reader
* @package Icinga\Protocol\Statusdat * @package Icinga\Protocol\Statusdat
*/ */
class Reader implements IReader class Reader implements IReader, DatasourceInterface
{ {
/** /**
* *

View File

@ -29,11 +29,11 @@
namespace Icinga\Protocol\Statusdat\View; namespace Icinga\Protocol\Statusdat\View;
/** /**
* Class AbstractAccessorStrategy * Interface for statusdat classes that provide a specific view on the dataset
* Basic interface for views. *
* The name sound weirder than it is: Views define special get and exists operations for fields * Views define special get and exists operations for fields that are not directly available
* that are not directly available in a resultset, but exist under another name or can be * in a resultset, but exist under another name or can be accessed by loading an additional object
* accessed by loading an additional object during runtime. * during runtime.
* *
* @see Icinga\Backend\DataView\ObjectRemappingView For an implementation of mapping field names * @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. * 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 * @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 * around the monitoring object, so we don't use __get() or __set() and always have to give the
* item we'd like to access. * 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 * Returns a field for the item, or throws an Exception if the field doesn't exist

View File

@ -2,7 +2,7 @@
/** /**
* Wrapper around an array of monitoring objects that can be enhanced with an optional * 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) * 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 * 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 $position = 0;
private $dataView = null; private $dataView = null;
function __construct(array &$dataset, AbstractAccessorStrategy $dataView = null) function __construct(array &$dataset, AccessorStrategy $dataView = null)
{ {
$this->dataSet = $dataset; $this->dataSet = $dataset;
$this->position = 0; $this->position = 0;

View File

@ -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. * 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 * @var array
*/ */
protected $mappedParameters = array(); public static $mappedParameters = array();
private $functionMap = array( private $functionMap = array(
"TO_DATE" => "toDateFormat" "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 $item
* @param The $field * @param The $field
@ -86,7 +86,7 @@ class ObjectRemappingView implements AbstractAccessorStrategy
if (isset($item->$field)) { if (isset($item->$field)) {
return $item->$field; return $item->$field;
} }
if (isset($this->mappedParameters[$field])) { if (isset(static::$mappedParameters[$field])) {
return $this->getMappedParameter($item, $field); return $this->getMappedParameter($item, $field);
} }
@ -118,7 +118,7 @@ class ObjectRemappingView implements AbstractAccessorStrategy
private function getMappedParameter(&$item, $field) private function getMappedParameter(&$item, $field)
{ {
$matches = array(); $matches = array();
$fieldDef = $this->mappedParameters[$field]; $fieldDef = static::$mappedParameters[$field];
$function = false; $function = false;
if (preg_match_all('/(?P<FUNCTION>\w+)\((?P<PARAMETER>.*)\)/', $fieldDef, $matches)) { if (preg_match_all('/(?P<FUNCTION>\w+)\((?P<PARAMETER>.*)\)/', $fieldDef, $matches)) {
$function = $matches["FUNCTION"][0]; $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 * @param The $field
* @return The|string * @return The|string
*/ */
public function getNormalizedFieldName($field) public function getNormalizedFieldName($field)
{ {
if (isset($this->mappedParameters[$field])) { if (isset(static::$mappedParameters[$field])) {
return $this->mappedParameters[$field]; return static::$mappedParameters[$field];
} }
return $field; return $field;
} }
/** /**
* *
* @see Icinga\Backend\DataView\AbstractAccessorStrategy * @see Icinga\Backend\DataView\AccessorStrategy
* *
* @param The $item * @param The $item
* @param The $field * @param The $field
@ -165,7 +165,7 @@ class ObjectRemappingView implements AbstractAccessorStrategy
public function exists(&$item, $field) public function exists(&$item, $field)
{ {
return (isset($item->$field) return (isset($item->$field)
|| isset($this->mappedParameters[$field]) || isset(static::$mappedParameters[$field])
|| isset($this->handlerParameters[$field]) || isset($this->handlerParameters[$field])
); );
} }

View File

@ -83,22 +83,36 @@ class Monitoring_ListController extends ModuleActionController
$this->view->services = $this->query('status', array( $this->view->services = $this->query('status', array(
'host_name', 'host_name',
'host_problems', 'host_state',
'host_state_type',
'host_last_state_change',
'host_address',
'host_handled',
'service_description', 'service_description',
'service_display_name',
'service_state' => $state_column, 'service_state' => $state_column,
'service_in_downtime', 'service_in_downtime',
'service_acknowledged', 'service_acknowledged',
'service_handled', 'service_handled',
'service_output', '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') if ($this->_getParam('sort')) {
->preserve('backend') $this->view->sort = $this->_getParam('sort');
->preserve('extracolumns');
$this->view->sort = $this->_getParam('sort');
if ($this->view->compact) {
$this->_helper->viewRenderer('services-compact');
} }
} }
public function hostgroupsAction() public function hostgroupsAction()

View File

@ -27,6 +27,14 @@ class Zend_View_Helper_MonitoringState extends Zend_View_Helper_Abstract
if ($object->host_last_state_change > (time() - 600)) { if ($object->host_last_state_change > (time() - 600)) {
$state_classes[] = 'new'; $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; return $state_classes;

View File

@ -0,0 +1,171 @@
<?= $this->tabs ?>
<?php
$paginator = $services->paginate();
function getRowProperties(&$service, &$last_host, $scope) {
if ($last_host !== $service->host_name) {
$host_col = '<b>' . $scope->qlink(
$service->host_name,
'monitoring/show/host',
array('host' => $service->host_name)
) . ':</b><span style="font-size: 0.7em">'
. (isset($service->host->address) ? ' ( ' . $scope->escape($service->host->address) . ')' : '')
. '</span>';
$last_host = $service->host_name;
} else {
$host_col = '&nbsp; ';
}
$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'];
}
?>
<div class="dontprint">
<? if (! empty($fparams)): ?>
<div style="float: right; width: 20em; font-size: 0.8em;"><b>Filters</b><br>
<? foreach ($fparams as $k => $v): ?>
<?= $this->qlink(
'x',
'monitoring/list/services',
$this->services->getAppliedFilter()->without($k)->toParams() + $always,
array(
'style' => array('color' => 'red')
)
) ?> <?= $this->escape("$k = $v") ?></br>
<? endforeach ?>
</div>
<? endif ?>
<form method="get" action="<?= $this->qUrl(
'monitoring/list/services?' . http_build_query(
$this->services->getAppliedFilter()->toParams()
),
array()
)
?>">
Sort by <?= $this->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',
)
) ?>
<?= $this->formText(
'search',
$this->search,
array(
'placeholder' => 'Add filllter...',
)
) ?>
</form>
</div>
<?php if (empty($services)): ?>
<div class="alert alert-info fullpage_infobox">
Sorry, no services found for this search
</div>
<?php return; endif ?>
<?= $this->paginationControl($paginator, null, null, array('preserve' => $this->preserve )); ?>
<table class="action">
<tbody>
<?php foreach ($services->fetchAll() as $service):
list($host_col,$icons,$state_classes,$state_title,$graph) = getRowProperties($service,$last_host,$this); ?>
<tr class="<?= implode(' ', $state_classes) ?>">
<td class="state" title="<?= $state_title ?>">
<?= $this->qlink(
$service->service_state == 99 ? 'PENDING' :
substr(strtoupper($this->monitoringState($service)), 0, 4)
. '&nbsp;since<br /> '
. $this->timeSince($service->service_last_state_change),
'monitoring/show/history', array(
'host' => $service->host_name,
'service' => $service->service_description
), array('quote' => false)) ?>
</td>
<td>
<?php
foreach ($icons as $icon => $alt) {
echo $this->img('img/classic/' . $icon, array(
'class' => 'icon',
'title' => $alt
));
} ?>
<?= $host_col ?>
<?= $this->qlink($service->service_description, 'monitoring/show/service', array(
'host' => $service->host_name,
'service' => $service->service_description
), array('class' => 'row-action')
)
?>
<br />
&nbsp; &nbsp; <span style="font-size: 0.7em">
<?= $this->escape(substr(strip_tags($service->service_output), 0, 900)) ?>
</span>
<?= $graph ?>
</td>
<? foreach ($this->extraColumns as $col): ?>
<td><?= $this->escape($service->$col) ?></td>
<? endforeach ?>
</tr>
<?php endforeach; ?>
</tbody>
</table>

View File

@ -1,171 +1,180 @@
<?= $this->tabs ?> <?= $this->tabs ?>
<?php
<?php
$paginator = $services->paginate(); $paginator = $services->paginate();
function getRowProperties(&$service, &$last_host, $scope) { $viewHelper = $this->getHelper('MonitoringState');
if ($last_host !== $service->host_name) { $trimArea = $this->getHelper('Trim');
$host_col = '<b>' . $scope->qlink(
$service->host_name,
'monitoring/show/host',
array('host' => $service->host_name)
) . ':</b><span style="font-size: 0.7em">'
. (isset($service->host->address) ? ' ( ' . $scope->escape($service->host->address) . ')' : '')
. '</span>';
$last_host = $service->host_name;
} else {
$host_col = '&nbsp; ';
}
$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'];
}
?> ?>
<div class="dontprint">
<? if (! empty($fparams)): ?>
<div style="float: right; width: 20em; font-size: 0.8em;"><b>Filters</b><br>
<? foreach ($fparams as $k => $v): ?>
<?= $this->qlink(
'x',
'monitoring/list/services',
$this->services->getAppliedFilter()->without($k)->toParams() + $always,
array(
'style' => array('color' => 'red')
)
) ?> <?= $this->escape("$k = $v") ?></br>
<? endforeach ?>
</div>
<? endif ?>
<form method="get" action="<?= $this->qUrl(
'monitoring/list/services?' . http_build_query(
$this->services->getAppliedFilter()->toParams()
),
array()
)
?>">
Sort by <?= $this->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',
)
) ?>
<?= $this->formText(
'search',
$this->search,
array(
'placeholder' => 'Add filllter...',
)
) ?>
</form>
</div>
<?php if (empty($services)): ?> <?php if (empty($services)): ?>
<div class="alert alert-info fullpage_infobox">
<div class="alert alert-info fullpage_infobox"> Sorry, no services found for this search
Sorry, no services found for this search </div>
</div>
<?php return; endif ?> <?php return; endif ?>
<?= $this->paginationControl($paginator, null, null, array('preserve' => $this->preserve )); ?>
<table class="action">
<tbody>
<?php foreach ($services->fetchAll() as $service):
list($host_col,$icons,$state_classes,$state_title,$graph) = getRowProperties($service,$last_host,$this); ?>
<tr class="<?= implode(' ', $state_classes) ?>">
<td class="state" title="<?= $state_title ?>">
<?= $this->qlink(
$service->service_state == 99 ? 'PENDING' :
substr(strtoupper($this->monitoringState($service)), 0, 4)
. '&nbsp;since<br /> '
. $this->timeSince($service->service_last_state_change),
'monitoring/show/history', array(
'host' => $service->host_name,
'service' => $service->service_description
), array('quote' => false)) ?>
</td>
<td>
<?php
foreach ($icons as $icon => $alt) {
echo $this->img('img/classic/' . $icon, array(
'class' => 'icon',
'title' => $alt
));
} ?>
<?= $host_col ?>
<?= $this->qlink($service->service_description, 'monitoring/show/service', array(
'host' => $service->host_name,
'service' => $service->service_description
), array('class' => 'row-action')
)
?>
<br /> <form method="get" action="<?= $this->qUrl(
&nbsp; &nbsp; <span style="font-size: 0.7em"> 'monitoring/list/services?' . http_build_query($this->services->getAppliedFilter()->toParams()),
<?= $this->escape(substr(strip_tags($service->service_output), 0, 900)) ?> array()
</span> );
<?= $graph ?> ?>">
</td> Sort by <?= $this->formSelect(
<? foreach ($this->extraColumns as $col): ?> 'sort',
<td><?= $this->escape($service->$col) ?></td> $this->sort,
<? endforeach ?> array('class' => 'autosubmit'),
</tr> array(
<?php endforeach; ?> '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',
)
) ?>
<input type="search" name="filter" placeholder="Type to filter" />
<button class="btn btn-small"><i class="icon-refresh"></i></button>
</form>
<?= $this->paginationControl($paginator, null, null, array('preserve' => $this->preserve)) ?>
<table class="statustable action services">
<thead>
<tr>
<th colspan="3">Status</th>
<th>Service</th>
<th>Host</th>
<th>Output</th>
<th></th>
</tr>
</thead>
<tbody>
<?php foreach ($services->fetchAll() as $service): ?>
<tr class="<?= implode(' ', $viewHelper->getStateFlags($service, 'service')); ?>">
<td class="icons indicator">
<div class="img-box"><?php $trimArea->start(); ?>
<?php if ($service->service_icon_image) : ?>
<img src="<?= $service->service_icon_image; ?>"/>
<?php endif; ?>
<?php $trimArea->end(); ?></div>
</td>
<td class="icons indicator">
<div class="icon-box"><?php $trimArea->start(); ?>
<?php if (!$service->service_handled && $service->service_state > 0): ?>
<a href="#" title="<?= 'Unhandled service' ?>">
<i class="icon-warning-sign"></i>
</a>
<?php endif; ?>
<?php if ($service->service_acknowledged && !$service->service_in_downtime): ?>
<a href="#" title="<?= 'Acknowledged' ?>">
<i class="icon-ok-sign"></i>
</a>
<?php endif; ?>
<?php if ($service->service_is_flapping): ?>
<a href="#" title="<?= 'Flapping' ?>">
<i class="icon-random"></i>
</a>
<?php endif; ?>
<?php if (!$service->service_notifications_enabled): ?>
<a href="#" title="<?= 'Notifications disabled' ?>">
<i class="icon-volume-off"></i>
</a>
<?php endif; ?>
<?php if ($service->service_in_downtime): ?>
<a href="#" title="<?= 'In downtime' ?>">
<i class="icon-wrench"></i>
</a>
<?php endif; ?>
<?php $trimArea->end(); ?></div>
</td>
<td class="indicator state" title="<?= $viewHelper->getStateTitle($service, 'service'); ?>">
<div class="statetext">
<?= $this->qlink(
"<b>".ucfirst($viewHelper->monitoringState($service, 'service'))."</b>".
'<div class="nowrap"> since&nbsp;'.
$this->timeSince($service->service_last_state_change),
'monitoring/show/history', array(
'host' => $service->host_name,
'service' => $service->service_description
),
array('quote' => false)
);?>
<?php if ($service->service_state_type == 0): ?>
<a href="#" title="<?= 'Soft state' ?>">
<i class="icon-gears"></i>
</a>
<?php endif; ?>
</div>
</td>
<td class="servicename">
<?php if ($service->service_last_comment !== null): ?>
<a href="#" title="<?= 'Comments' ?>">
<i class="icon-comment"> </i>
</a>
<?php endif; ?>
<?= $this->qlink(
"<b>".$service->service_display_name."</b><br/>",
'monitoring/show/service', array(
'host' => $service->host_name,
'service' => $service->service_description
), array(
'class' => 'row-action',
'quote' => false
)
); ?>
<?php if ($service->service_action_url != ""): ?>
<a href="<?= $service->service_action_url; ?>">Action</a>
<?php endif; ?>
<?php if ($service->service_notes_url != ""): ?>
<a href="<?= $service->service_notes_url; ?>">Notes</a>
<?php endif; ?>
<?php if ($service->service_state_type == 0): ?>
<a href="#" title="<?= 'Soft state' ?>">
<i class="icon-gears"></i>
</a>
<?php endif; ?>
</td>
<td class="hostname" title="<?= $viewHelper->getStateTitle($service, 'host'); ?>">
<?= $this->qlink(
$service->host_name,
'monitoring/show/host', array(
'host' => $service->host_name
), array(
'class' => 'row-action',
'quote' => false
)
); ?>
<div class="statetext">
<?= $this->qlink(
"(".ucfirst($viewHelper->monitoringState($service, 'host')).")",
'monitoring/show/history', array(
'host' => $service->host_name,
'service' => $service->service_description
),
array('quote' => false)
);?>
</div>
<span class="host_address">
<?= $service->host_address ?>
</span>
</td>
<td class="expand-full">
<?= $this->escape(substr(strip_tags($service->service_output), 0, 10000)); ?>
</td>
</tr>
<?php endforeach; ?>
</tbody> </tbody>
</table> </table>

View File

@ -54,6 +54,7 @@ class AbstractBackend implements DatasourceInterface
) )
); );
} }
$query = new $classname($this, $fields); $query = new $classname($this, $fields);
return $query; return $query;
} }

View File

@ -153,11 +153,10 @@ abstract class AbstractQuery extends Query
} elseif ($this->hasAliasName($col)) { } elseif ($this->hasAliasName($col)) {
$col = $this->aliasToColumnName($col); $col = $this->aliasToColumnName($col);
} else { } else {
die('SHIT'); throw new \InvalidArgumentException('Can\'t order by column '.$col);
} }
$this->order_columns[] = array($col, $dir); $this->order_columns[] = array($col, $dir);
return $this; return $this;
return parent::order($col, $dir);
} }
public function setRealColumns() public function setRealColumns()

View File

@ -113,6 +113,8 @@ class StatusQuery extends AbstractQuery
'service_description' => 'so.name2 COLLATE latin1_general_ci', 'service_description' => 'so.name2 COLLATE latin1_general_ci',
'service_display_name' => 's.display_name', 'service_display_name' => 's.display_name',
'service_icon_image' => 's.icon_image', 'service_icon_image' => 's.icon_image',
'service_action_url' => 's.action_url',
'service_notes_url' => 's.notes_url'
), ),
'servicestatus' => array( 'servicestatus' => array(
@ -123,9 +125,10 @@ class StatusQuery extends AbstractQuery
'service_output' => 'ss.output', 'service_output' => 'ss.output',
'service_long_output' => 'ss.long_output', 'service_long_output' => 'ss.long_output',
'service_perfdata' => 'ss.perfdata', 'service_perfdata' => 'ss.perfdata',
'service_is_flapping' => 'ss.is_flapping',
'service_acknowledged' => 'ss.problem_has_been_acknowledged', 'service_acknowledged' => 'ss.problem_has_been_acknowledged',
'service_in_downtime' => 'CASE WHEN (ss.scheduled_downtime_depth = 0) THEN 0 ELSE 1 END', '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_does_active_checks' => 'ss.active_checks_enabled',
'service_accepts_passive_checks' => 'ss.passive_checks_enabled', 'service_accepts_passive_checks' => 'ss.passive_checks_enabled',
'service_last_state_change' => 'UNIX_TIMESTAMP(ss.last_state_change)', 'service_last_state_change' => 'UNIX_TIMESTAMP(ss.last_state_change)',
@ -152,9 +155,9 @@ class StatusQuery extends AbstractQuery
'service_last_comment' => 'slc.comment_id' 'service_last_comment' => 'slc.comment_id'
), ),
'status' => array( 'status' => array(
'problems' => 'CASE WHEN ss.current_state = 0 THEN 0 ELSE 1 END', 'service_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', 'service_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_severity' => 'CASE WHEN ss.current_state = 0
THEN THEN
CASE WHEN ss.has_been_checked = 0 OR ss.has_been_checked IS NULL CASE WHEN ss.has_been_checked = 0 OR ss.has_been_checked IS NULL
THEN 16 THEN 16
@ -345,4 +348,16 @@ class StatusQuery extends AbstractQuery
array() 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()
);
}
} }

View File

@ -35,7 +35,7 @@ use Icinga\Protocol\Statusdat\IReader;
* Class StatusdatHostView * Class StatusdatHostView
* @package Icinga\Backend\Statusdat\DataView * @package Icinga\Backend\Statusdat\DataView
*/ */
class StatusdatHostView extends ObjectRemappingView class HostStatusView extends ObjectRemappingView
{ {
/** /**
* @var mixed * @var mixed
@ -49,7 +49,8 @@ class StatusdatHostView extends ObjectRemappingView
"host" => "getHost", "host" => "getHost",
"host_unhandled_service_count" => "getNrOfUnhandledServices", "host_unhandled_service_count" => "getNrOfUnhandledServices",
"host_last_comment" => "getLastComment", "host_last_comment" => "getLastComment",
'host_handled' => "checkIfHandled" 'host_handled' => "checkIfHandled",
); );
public function checkIfHandled(&$host) public function checkIfHandled(&$host)
@ -83,20 +84,21 @@ class StatusdatHostView extends ObjectRemappingView
/** /**
* @var array * @var array
*/ */
protected $mappedParameters = array( public static $mappedParameters = array(
"host_address" => "address", "host_address" => "address",
"host_name" => "host_name", "host_name" => "host_name",
"host" => "host_name",
"host_state" => "status.current_state", "host_state" => "status.current_state",
"host_output" => "status.plugin_output", "host_output" => "status.plugin_output",
"host_long_output" => "status.long_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_last_state_change" => "status.last_state_change",
"host_check_command" => "check_command", "host_check_command" => "check_command",
"host_last_check" => "TO_DATE(status.last_check)", "host_last_check" => "TO_DATE(status.last_check)",
"host_next_check" => "status.next_check", "host_next_check" => "status.next_check",
"host_check_latency" => "status.check_latency", "host_check_latency" => "status.check_latency",
"host_check_execution_time" => "status.check_execution_time", "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_in_downtime" => "status.scheduled_downtime_depth",
"host_is_flapping" => "status.is_flapping", "host_is_flapping" => "status.is_flapping",
"host_notifications_enabled"=> "status.notifications_enabled", "host_notifications_enabled"=> "status.notifications_enabled",
@ -104,7 +106,7 @@ class StatusdatHostView extends ObjectRemappingView
"host_icon_image" => "icon_image", "host_icon_image" => "icon_image",
"host_action_url" => "action_url", "host_action_url" => "action_url",
"host_notes_url" => "notes_url", "host_notes_url" => "notes_url",
"host_acknowledged" => "status.problem_has_been_acknowledged", "host_acknowledged" => "status.problem_has_been_acknowledged"
// "state" => "current_state" // "state" => "current_state"
); );
@ -114,7 +116,7 @@ class StatusdatHostView extends ObjectRemappingView
*/ */
public function getHost(&$item) public function getHost(&$item)
{ {
if (!isset($this->state["host"][$item->host_name])) { if (!isset($this->state["service"][$item->host_name])) {
return null; return null;
} }
if (!isset($this->state["host"][$item->host_name])) { if (!isset($this->state["host"][$item->host_name])) {

View File

@ -0,0 +1,163 @@
<?php
// {{{ICINGA_LICENSE_HEADER}}}
/**
* This file is part of Icinga 2 Web.
*
* Icinga 2 Web - Head for multiple monitoring backends.
* Copyright (C) 2013 Icinga Development Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* @copyright 2013 Icinga Development Team <info@icinga.org>
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
* @author Icinga Development Team <info@icinga.org>
*/
// {{{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();
}
}

View File

@ -49,7 +49,7 @@ class StatusdatServiceView extends ObjectRemappingView
/** /**
* @var array * @var array
*/ */
protected $mappedParameters = array( public static $mappedParameters = array(
"host_address" => "parenthost.address", "host_address" => "parenthost.address",
"host_name" => "host_name", "host_name" => "host_name",
"active_checks_enabled" => "status.active_checks_enabled", "active_checks_enabled" => "status.active_checks_enabled",

View File

@ -33,6 +33,7 @@ use Icinga\Protocol\Statusdat;
use Icinga\Exception; use Icinga\Exception;
use Icinga\Data\AbstractQuery; use Icinga\Data\AbstractQuery;
use Icinga\Protocol\Statusdat\View\MonitoringObjectList as MList; use Icinga\Protocol\Statusdat\View\MonitoringObjectList as MList;
use Icinga\Protocol\Statusdat\Query as StatusdatQuery;
/** /**
* Class Query * Class Query
* @package Icinga\Backend\Statusdat * @package Icinga\Backend\Statusdat
@ -42,24 +43,24 @@ abstract class Query extends AbstractQuery
/** /**
* @var null * @var null
*/ */
protected $cursor = null; private $cursor = null;
/** /**
* @var string * @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 * Calls the apply%Filtername%Filter() method for the given filter, or simply calls
@ -113,7 +114,7 @@ abstract class Query extends AbstractQuery
$text = "%$value%"; $text = "%$value%";
$val = array($text, $text, $text); $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) public function applyHostgroupsFilter($type, $value)
{ {
$filter = array($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) public function applyServicegroupsFilter($type, $value)
{ {
$filter = array($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) public function applyHandledFilter($type, $value)
{ {
$val = array($value, $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)) { if (!is_array($value)) {
$value = 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) 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) 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)) { if (!is_array($value)) {
$value = 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) public function limit($count = null, $offset = null)
{ {
$this->query->limit($count, $offset); $this->baseQuery->limit($count, $offset);
return $this; return $this;
} }
@ -219,7 +220,8 @@ abstract class Query extends AbstractQuery
{ {
if ($column) { if ($column) {
$this->query->order($this->orderColumns[$column], strtolower($dir)); $class = $this->viewClass;
$this->baseQuery->order($class::$mappedParameters[$column], strtolower($dir));
} }
return $this; return $this;
} }
@ -237,7 +239,7 @@ abstract class Query extends AbstractQuery
if (!is_array($value)) { if (!is_array($value)) {
$value = array($value); $value = array($value);
} }
$this->query->where($column, $value); $this->baseQuery->where($column, $value);
return $this; return $this;
} }
@ -246,9 +248,9 @@ abstract class Query extends AbstractQuery
*/ */
public function fetchAll() public function fetchAll()
{ {
$view = $this->view; $view = $this->viewClass;
if (!$this->cursor) { 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; return $this->cursor;
} }
@ -283,6 +285,6 @@ abstract class Query extends AbstractQuery
public function count() public function count()
{ {
return count($this->query->getResult()); return count($this->baseQuery->getResult());
} }
} }

View File

@ -15,22 +15,24 @@ use Icinga\Exception;
class StatusQuery extends Query 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() public function init()
{ {
$target = $this->getTarget();
$this->reader = $this->ds->getReader(); $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()));
} }
} }

View File

@ -135,6 +135,7 @@ class MonitoringView extends AbstractQuery
*/ */
protected function applyRequestSorting($request) protected function applyRequestSorting($request)
{ {
return $this->order( return $this->order(
// TODO: Use first sortDefaults entry if available, fall back to // TODO: Use first sortDefaults entry if available, fall back to
// column if not // column if not
@ -238,12 +239,12 @@ class MonitoringView extends AbstractQuery
-4 -4
) . 'Query'; ) . 'Query';
$class = '\\' . get_class($this->ds) . '\\Query\\' . $class; $class = '\\' . get_class($this->ds) . '\\Query\\' . $class;
$query = new $class($this->ds, $this->columns); $query = new $class($this->ds, $this->columns);
foreach ($this->filters as $f) { foreach ($this->filters as $f) {
$query->where($f[0], $f[1]); $query->where($f[0], $f[1]);
} }
foreach ($this->order_columns as $col) { foreach ($this->order_columns as $col) {
if (isset($this->sortDefaults[$col[0]]['columns'])) { if (isset($this->sortDefaults[$col[0]]['columns'])) {
foreach ($this->sortDefaults[$col[0]]['columns'] as $c) { foreach ($this->sortDefaults[$col[0]]['columns'] as $c) {
$query->order($c, $col[1]); $query->order($c, $col[1]);
@ -252,11 +253,13 @@ class MonitoringView extends AbstractQuery
$query->order($col[0], $col[1]); $query->order($col[0], $col[1]);
} }
} }
$this->query = $query; $this->query = $query;
} }
if ($this->hasLimit()) { if ($this->hasLimit()) {
$this->query->limit($this->getLimit(), $this->getOffset()); $this->query->limit($this->getLimit(), $this->getOffset());
} }
return $this->query; return $this->query;
} }

View File

@ -96,7 +96,6 @@ class ListControllerHostMySQLTest extends MonitoringControllerTest
$this->assertEquals("note1.html", $hostToTest->host_notes_url, 'Testing for notes url (backend '.$backend.')'); $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("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.')'); $this->assertEquals(2, $hostToTest->host_unhandled_service_count, 'Testing correct open problems count (backend '.$backend.')');
} }
} }

View File

@ -0,0 +1,69 @@
<?php
namespace Test\Monitoring\Application\Controllers\ListController;
require_once(dirname(__FILE__).'/../../testlib/MonitoringControllerTest.php');
use Test\Monitoring\Testlib\MonitoringControllerTest;
use Test\Monitoring\Testlib\Datasource\TestFixture;
use Test\Monitoring\Testlib\Datasource\ObjectFlags;
class ListControllerServiceMySQLTest extends MonitoringControllerTest
{
public function testServiceListMySQL()
{
$this->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");
}
}

View File

@ -16,6 +16,8 @@ namespace Icinga\Web
*/ */
public $view; public $view;
public $headers = array();
/** /**
* Parameters provided on call * Parameters provided on call
* @var array * @var array
@ -28,14 +30,29 @@ namespace Icinga\Web
* @param string $param The parameter name to retrieve * @param string $param The parameter name to retrieve
* @return mixed|bool The parameter $param or false if it doesn't exist * @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])) { if (!isset($this->params[$param])) {
return false; return $default;
} }
return $this->params[$param]; 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 * Sets the backend for this controller which will be used in the action
* *
@ -45,6 +62,17 @@ namespace Icinga\Web
{ {
$this->backend = $backend; $this->backend = $backend;
} }
public function __get($param) {
return $this;
}
public function getHeader($header) {
if (isset($this->headers[$header])) {
return $this->headers[$header];
}
return null;
}
} }
} }

View File

@ -170,14 +170,14 @@ class PDOInsertionStrategy
$insertObjectQuery->execute(array($this->objectId, $service["host"]["name"], $service["name"])); $insertObjectQuery->execute(array($this->objectId, $service["host"]["name"], $service["name"]));
$insertServiceQuery->execute(array( $insertServiceQuery->execute(array(
$this->objectId, $service['host']['object_id'], $this->objectId, $service['name'], $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( $insertServiceStatusQuery->execute(array(
$this->objectId, $service["state"], date($this->datetimeFormat, $flags->time), $this->objectId, $service["state"], date($this->datetimeFormat, $flags->time),
date($this->datetimeFormat, $flags->time), $flags->notifications, $flags->active_checks, date($this->datetimeFormat, $flags->time), $flags->notifications, $flags->active_checks,
$flags->passive_checks, $flags->flapping, $flags->in_downtime, "Plugin output for service ".$service["name"], $flags->passive_checks, $flags->flapping, $flags->in_downtime, "Plugin output for service ".$service["name"],
"Long plugin output for service ".$service["name"], $flags->acknowledged, "Long plugin output for service ".$service["name"], $flags->acknowledged,
$flags->is_pending == 0 $flags->is_pending == 0 ? '1' : '0'
)); ));
foreach($service["contacts"] as $contact) { foreach($service["contacts"] as $contact) {