2013-06-03 16:14:46 +02:00
|
|
|
<?php
|
2013-06-07 13:29:11 +02:00
|
|
|
// {{{ICINGA_LICENSE_HEADER}}}
|
2013-06-28 16:47:30 +02:00
|
|
|
/**
|
2013-07-15 12:26:10 +02:00
|
|
|
* This file is part of Icinga 2 Web.
|
|
|
|
*
|
|
|
|
* Icinga 2 Web - Head for multiple monitoring backends.
|
2013-06-28 16:47:30 +02:00
|
|
|
* 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>
|
2013-07-15 12:26:10 +02:00
|
|
|
* @license http://www.gnu.org/licenses/gpl-2.0.txt GPL, version 2
|
|
|
|
* @author Icinga Development Team <info@icinga.org>
|
2013-06-28 16:47:30 +02:00
|
|
|
*/
|
2013-06-07 13:29:11 +02:00
|
|
|
// {{{ICINGA_LICENSE_HEADER}}}
|
2013-06-03 16:14:46 +02:00
|
|
|
|
|
|
|
namespace Icinga\Protocol\Statusdat;
|
2013-06-07 13:29:11 +02:00
|
|
|
|
2013-06-03 16:14:46 +02:00
|
|
|
use Icinga\Protocol;
|
2013-07-19 11:29:51 +02:00
|
|
|
use Icinga\Data\AbstractQuery;
|
2013-09-02 17:33:12 +02:00
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* Class Query
|
|
|
|
* @package Icinga\Protocol\Statusdat
|
|
|
|
*/
|
2013-07-19 11:29:51 +02:00
|
|
|
class Query extends AbstractQuery
|
2013-06-03 16:14:46 +02:00
|
|
|
{
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
public static $VALID_TARGETS = array(
|
|
|
|
"hosts" => array("host"),
|
|
|
|
"services" => array("service"),
|
|
|
|
"downtimes" => array("hostdowntime", "servicedowntime"),
|
|
|
|
"hostdowntimes" => array("hostdowntime"),
|
|
|
|
"servicedowntimes" => array("servicedowntime"),
|
|
|
|
"hostgroups" => array("hostgroup"),
|
|
|
|
"servicegroups" => array("servicegroup"),
|
|
|
|
"comments" => array("servicecomment", "hostcomment"),
|
|
|
|
"hostcomments" => array("hostcomment"),
|
2013-07-19 17:45:51 +02:00
|
|
|
"servicecomments" => array("servicecomment")
|
2013-06-03 16:14:46 +02:00
|
|
|
);
|
|
|
|
|
2013-07-19 17:45:51 +02:00
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @var IReader|null
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
private $reader = null;
|
2013-06-07 13:29:11 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var string
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
private $source = "";
|
2013-06-07 13:29:11 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var null
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
private $limit = null;
|
2013-06-07 13:29:11 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var int
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
private $offset = 0;
|
2013-06-07 13:29:11 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
2013-07-19 11:29:51 +02:00
|
|
|
protected $order_columns = array();
|
2013-06-07 13:29:11 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
private $groupColumns = array();
|
2013-06-07 13:29:11 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var null
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
private $groupByFn = null;
|
2013-06-07 13:29:11 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @var array
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
private $filter = array();
|
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
const FN_SCOPE = 0;
|
2013-06-07 13:29:11 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
const FN_NAME = 1;
|
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @return bool
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
public function hasOrder()
|
|
|
|
{
|
|
|
|
return !empty($this->order_columns);
|
|
|
|
}
|
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @return bool
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
public function hasColumns()
|
|
|
|
{
|
|
|
|
return !empty($this->columns);
|
|
|
|
}
|
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @return array
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
public function getColumns()
|
|
|
|
{
|
|
|
|
return $this->columns;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @return bool
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
public function hasLimit()
|
|
|
|
{
|
|
|
|
return $this->limit !== false;
|
|
|
|
}
|
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @return bool
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
public function hasOffset()
|
|
|
|
{
|
|
|
|
return $this->offset !== false;
|
|
|
|
}
|
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @return null
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
public function getLimit()
|
|
|
|
{
|
|
|
|
return $this->limit;
|
|
|
|
}
|
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @return int|null
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
public function getOffset()
|
|
|
|
{
|
|
|
|
return $this->offset;
|
|
|
|
}
|
|
|
|
|
2013-07-19 17:45:51 +02:00
|
|
|
|
2013-06-03 16:14:46 +02:00
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @param $key
|
|
|
|
* @param null $val
|
|
|
|
* @return $this
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
public function where($key, $val = null)
|
|
|
|
{
|
|
|
|
$this->filter[] = array($key, $val);
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @param $columns
|
|
|
|
* @param null $dir
|
|
|
|
* @return $this
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
public function order($columns, $dir = null)
|
|
|
|
{
|
2013-06-07 13:29:11 +02:00
|
|
|
if ($dir && strtolower($dir) == "desc") {
|
2013-06-03 16:14:46 +02:00
|
|
|
$dir = self::SORT_DESC;
|
2013-06-07 13:29:11 +02:00
|
|
|
} else {
|
2013-06-03 16:14:46 +02:00
|
|
|
$dir = self::SORT_ASC;
|
2013-06-07 13:29:11 +02:00
|
|
|
}
|
|
|
|
if (!is_array($columns)) {
|
2013-06-03 16:14:46 +02:00
|
|
|
$columns = array($columns);
|
2013-06-07 13:29:11 +02:00
|
|
|
}
|
|
|
|
foreach ($columns as $col) {
|
2013-06-03 16:14:46 +02:00
|
|
|
|
|
|
|
if (($pos = strpos($col, ' ')) !== false) {
|
|
|
|
$dir = strtoupper(substr($col, $pos + 1));
|
|
|
|
if ($dir === 'DESC') {
|
|
|
|
$dir = self::SORT_DESC;
|
|
|
|
} else {
|
|
|
|
$dir = self::SORT_ASC;
|
|
|
|
}
|
|
|
|
$col = substr($col, 0, $pos);
|
|
|
|
} else {
|
|
|
|
$col = $col;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->order_columns[] = array($col, $dir);
|
|
|
|
}
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @param null $count
|
|
|
|
* @param int $offset
|
|
|
|
* @return $this
|
|
|
|
* @throws Exception
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
public function limit($count = null, $offset = 0)
|
|
|
|
{
|
|
|
|
if ((is_null($count) || is_integer($count)) && (is_null($offset) || is_integer($offset))) {
|
|
|
|
$this->offset = $offset;
|
|
|
|
$this->limit = $count;
|
|
|
|
} else {
|
|
|
|
throw new Exception("Got invalid limit $count, $offset");
|
|
|
|
}
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @param $table
|
|
|
|
* @param null $columns
|
|
|
|
* @return $this
|
|
|
|
* @throws \Exception
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
public function from($table, $columns = null)
|
|
|
|
{
|
2013-06-07 13:29:11 +02:00
|
|
|
if (isset(self::$VALID_TARGETS[$table])) {
|
2013-06-03 16:14:46 +02:00
|
|
|
$this->source = $table;
|
2013-06-07 13:29:11 +02:00
|
|
|
} else {
|
|
|
|
throw new \Exception("Unknown from target for status.dat :" . $table);
|
|
|
|
}
|
2013-06-03 16:14:46 +02:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* @throws Exception
|
|
|
|
*/
|
|
|
|
private function getFilteredIndices($classType = "\Icinga\Protocol\Statusdat\Query\Group")
|
|
|
|
{
|
|
|
|
$baseGroup = null;
|
|
|
|
if (!empty($this->filter)) {
|
|
|
|
$baseGroup = new $classType();
|
|
|
|
|
|
|
|
foreach ($this->filter as $values) {
|
|
|
|
$baseGroup->addItem(new $classType($values[0], $values[1]));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-19 11:29:51 +02:00
|
|
|
$state = $this->ds->getObjects();
|
2013-06-03 16:14:46 +02:00
|
|
|
$result = array();
|
2013-07-19 17:45:51 +02:00
|
|
|
$source = self::$VALID_TARGETS[$this->source];
|
|
|
|
foreach ($source as $target) {
|
2013-07-23 12:18:27 +02:00
|
|
|
$indexes = array_keys($state[$target]);
|
2013-06-03 16:14:46 +02:00
|
|
|
if ($baseGroup) {
|
2013-07-23 12:18:27 +02:00
|
|
|
$indexes = $baseGroup->filter($state[$target]);
|
2013-06-03 16:14:46 +02:00
|
|
|
}
|
|
|
|
if (!isset($result[$target])) {
|
|
|
|
$result[$target] = $indexes;
|
|
|
|
} else {
|
|
|
|
array_merge($result[$target], $indexes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @param array $indices
|
|
|
|
*/
|
|
|
|
private function orderIndices(array &$indices)
|
|
|
|
{
|
|
|
|
if (!empty($this->order_columns)) {
|
|
|
|
foreach ($indices as $type => &$subindices) {
|
2013-06-03 16:14:46 +02:00
|
|
|
$this->currentType = $type; // we're singlethreaded, so let's do it a bit dirty
|
2013-06-07 13:29:11 +02:00
|
|
|
usort($subindices, array($this, "orderResult"));
|
2013-06-03 16:14:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @param $a
|
|
|
|
* @param $b
|
|
|
|
* @return int
|
|
|
|
*/
|
|
|
|
private function orderResult($a, $b)
|
|
|
|
{
|
2013-07-23 12:18:27 +02:00
|
|
|
$o1 = $this->ds->getObjectByName($this->currentType, $a);
|
|
|
|
$o2 = $this->ds->getObjectByName($this->currentType, $b);
|
2013-06-03 16:14:46 +02:00
|
|
|
$result = 0;
|
2013-06-07 13:29:11 +02:00
|
|
|
foreach ($this->order_columns as $col) {
|
|
|
|
$result += $col[1] * strnatcasecmp($o1->{$col[0]}, $o2->{$col[0]});
|
2013-06-03 16:14:46 +02:00
|
|
|
}
|
2013-06-07 13:29:11 +02:00
|
|
|
if ($result > 0) {
|
2013-06-03 16:14:46 +02:00
|
|
|
return 1;
|
2013-06-07 13:29:11 +02:00
|
|
|
}
|
|
|
|
if ($result < 0) {
|
2013-06-03 16:14:46 +02:00
|
|
|
return -1;
|
2013-06-07 13:29:11 +02:00
|
|
|
}
|
2013-06-03 16:14:46 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @param array $indices
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
private function limitIndices(array &$indices)
|
|
|
|
{
|
2013-06-07 13:29:11 +02:00
|
|
|
foreach ($indices as $type => $subindices) {
|
|
|
|
$indices[$type] = array_slice($subindices, $this->offset, $this->limit);
|
2013-06-03 16:14:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @param $fn
|
|
|
|
* @param null $scope
|
|
|
|
* @return $this
|
|
|
|
*/
|
|
|
|
public function groupByFunction($fn, $scope = null)
|
2013-06-03 16:14:46 +02:00
|
|
|
{
|
2013-06-07 13:29:11 +02:00
|
|
|
$this->groupByFn = array($scope ? $scope : $this, $fn);
|
2013-06-03 16:14:46 +02:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @param $columns
|
|
|
|
* @return $this
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
public function groupByColumns($columns)
|
|
|
|
{
|
2013-06-07 13:29:11 +02:00
|
|
|
if (!is_array($columns)) {
|
2013-06-03 16:14:46 +02:00
|
|
|
$columns = array($columns);
|
2013-06-07 13:29:11 +02:00
|
|
|
}
|
2013-06-03 16:14:46 +02:00
|
|
|
$this->groupColumns = $columns;
|
2013-06-07 13:29:11 +02:00
|
|
|
$this->groupByFn = array($this, "columnGroupFn");
|
2013-06-03 16:14:46 +02:00
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @param array $indices
|
|
|
|
* @return array
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
private function columnGroupFn(array &$indices)
|
|
|
|
{
|
|
|
|
$cols = $this->groupColumns;
|
|
|
|
$result = array();
|
2013-06-07 13:29:11 +02:00
|
|
|
foreach ($indices as $type => $subindices) {
|
|
|
|
foreach ($subindices as $objectIndex) {
|
2013-07-23 12:18:27 +02:00
|
|
|
$r = $this->ds->getObjectByName($type, $objectIndex);
|
2013-06-03 16:14:46 +02:00
|
|
|
$hash = "";
|
|
|
|
$cols = array();
|
2013-06-07 13:29:11 +02:00
|
|
|
foreach ($this->groupColumns as $col) {
|
|
|
|
$hash = md5($hash . $r->$col);
|
2013-06-03 16:14:46 +02:00
|
|
|
$cols[$col] = $r->$col;
|
|
|
|
}
|
2013-06-07 13:29:11 +02:00
|
|
|
if (!isset($result[$hash])) {
|
|
|
|
$result[$hash] = (object)array(
|
|
|
|
"columns" => (object)$cols,
|
2013-06-03 16:14:46 +02:00
|
|
|
"count" => 0
|
|
|
|
);
|
2013-06-07 13:29:11 +02:00
|
|
|
}
|
2013-06-03 16:14:46 +02:00
|
|
|
$result[$hash]->count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return array_values($result);
|
|
|
|
}
|
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
/**
|
|
|
|
* @return array
|
|
|
|
*/
|
2013-06-03 16:14:46 +02:00
|
|
|
public function getResult()
|
|
|
|
{
|
|
|
|
|
2013-07-23 12:18:27 +02:00
|
|
|
$indices = $this->getFilteredIndices();
|
2013-06-03 16:14:46 +02:00
|
|
|
$this->orderIndices($indices);
|
2013-06-07 13:29:11 +02:00
|
|
|
if ($this->groupByFn) {
|
2013-06-03 16:14:46 +02:00
|
|
|
$scope = $this->groupByFn[self::FN_SCOPE];
|
2013-06-07 13:29:11 +02:00
|
|
|
$fn = $this->groupByFn[self::FN_NAME];
|
2013-06-03 16:14:46 +02:00
|
|
|
|
|
|
|
return $scope->$fn($indices);
|
2013-06-07 13:29:11 +02:00
|
|
|
}
|
2013-06-03 16:14:46 +02:00
|
|
|
|
|
|
|
$this->limitIndices($indices);
|
|
|
|
|
|
|
|
$result = array();
|
2013-07-23 12:18:27 +02:00
|
|
|
$state = $this->ds->getObjects();
|
2013-06-07 13:29:11 +02:00
|
|
|
foreach ($indices as $type => $subindices) {
|
2013-06-03 16:14:46 +02:00
|
|
|
|
2013-06-07 13:29:11 +02:00
|
|
|
foreach ($subindices as $index) {
|
|
|
|
$result[] = & $state[$type][$index];
|
2013-06-03 16:14:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
}
|