mirror of
https://github.com/Icinga/icingaweb2.git
synced 2025-07-24 22:34:24 +02:00
Add tested Statusdat Protocol
In order to run the tests, phpunit must be called in the tests/php folder refs #4212
This commit is contained in:
parent
66b8f70e3e
commit
ba38c89755
152
library/Icinga/Application/Logger.php
Executable file
152
library/Icinga/Application/Logger.php
Executable file
@ -0,0 +1,152 @@
|
||||
<?php
|
||||
namespace Icinga\Application;
|
||||
|
||||
class Logger
|
||||
{
|
||||
const DEFAULT_LOG_TYPE = "stream";
|
||||
const DEFAULT_LOG_TARGET = "./var/log/icinga.log";
|
||||
const DEFAULT_DEBUG_TARGET = "./var/log/icinga.debug.log";
|
||||
|
||||
private $writers = array();
|
||||
private $logger = null;
|
||||
private static $instance;
|
||||
private static $queue = array();
|
||||
|
||||
public function __construct(\Zend_Config $config)
|
||||
{
|
||||
$this->overwrite($config);
|
||||
}
|
||||
|
||||
public function getWriters() {
|
||||
return $this->writers;
|
||||
}
|
||||
|
||||
public function overwrite(\Zend_Config $config)
|
||||
{
|
||||
$this->clearLog();
|
||||
try {
|
||||
if ($config->debug && $config->debug->enable == 1)
|
||||
$this->setupDebugLog($config);
|
||||
} catch (\Icinga\Exception\ConfigurationError $e) {
|
||||
$this->warn("Could not create debug log: {$e->getMessage()}");
|
||||
}
|
||||
|
||||
$this->setupLog($config);
|
||||
$this->flushQueue();
|
||||
}
|
||||
|
||||
private function setupDebugLog(\Zend_Config $config)
|
||||
{
|
||||
$type = $config->debug->get("type", self::DEFAULT_LOG_TYPE);
|
||||
$target = $config->debug->get("target", self::DEFAULT_LOG_TARGET);
|
||||
if ($target == self::DEFAULT_LOG_TARGET)
|
||||
$type == self::DEFAULT_LOG_TYPE;
|
||||
|
||||
$this->addWriter($type, $target, \Zend_Log::DEBUG);
|
||||
}
|
||||
|
||||
private function setupLog(\Zend_Config $config)
|
||||
{
|
||||
$type = $config->get("type", self::DEFAULT_LOG_TYPE);
|
||||
$target = $config->get("target", self::DEFAULT_DEBUG_TARGET);
|
||||
if ($target == self::DEFAULT_DEBUG_TARGET)
|
||||
$type == self::DEFAULT_LOG_TYPE;
|
||||
$level = \Zend_Log::WARN;
|
||||
if ($config->get("verbose", 0) == 1)
|
||||
$level = \Zend_Log::INFO;
|
||||
$this->addWriter($type, $target, $level);
|
||||
}
|
||||
|
||||
private function addWriter($type, $target , $priority)
|
||||
{
|
||||
$type[0] = strtoupper($type[0]);
|
||||
$writerClass = "\Zend_Log_Writer_" . $type;
|
||||
if (!class_exists($writerClass))
|
||||
throw new \Icinga\Exception\ConfigurationError("Could not create log: Unknown type " . $type);
|
||||
|
||||
$writer = new $writerClass($target);
|
||||
|
||||
$writer->addFilter(new \Zend_Log_Filter_Priority($priority));
|
||||
$this->logger->addWriter($writer);
|
||||
$this->writers[] = $writer;
|
||||
}
|
||||
|
||||
public function flushQueue()
|
||||
{
|
||||
foreach(self::$queue as $msgTypePair) {
|
||||
$this->logger->log($msgTypePair[0],$msgTypePair[1]);
|
||||
}
|
||||
}
|
||||
|
||||
public static function formatMessage(array $argv)
|
||||
{
|
||||
|
||||
if (count($argv) == 1) {
|
||||
$format = $argv[0];
|
||||
} else {
|
||||
$format = array_shift($argv);
|
||||
}
|
||||
if (!is_string($format)) {
|
||||
$format = json_encode($format);
|
||||
}
|
||||
foreach ($argv as &$arg) {
|
||||
if (!is_string($arg))
|
||||
$arg = json_encode($arg);
|
||||
}
|
||||
|
||||
return @vsprintf($format, $argv);
|
||||
}
|
||||
|
||||
|
||||
public function clearLog()
|
||||
{
|
||||
$this->logger = null;
|
||||
$this->writers = array();
|
||||
$this->logger = new \Zend_Log();
|
||||
}
|
||||
|
||||
public static function create(\Zend_Config $config)
|
||||
{
|
||||
if (self::$instance)
|
||||
return self::$instance->overwrite($config);
|
||||
return self::$instance = new Logger($config);
|
||||
}
|
||||
|
||||
public static function debug()
|
||||
{
|
||||
self::log(self::formatMessage(func_get_args()),\Zend_Log::DEBUG);
|
||||
}
|
||||
|
||||
public static function warn() {
|
||||
self::log(self::formatMessage(func_get_args()),\Zend_Log::WARN);
|
||||
}
|
||||
|
||||
public static function info() {
|
||||
self::log(self::formatMessage(func_get_args()),\Zend_Log::INFO);
|
||||
}
|
||||
|
||||
public static function error() {
|
||||
self::log(self::formatMessage(func_get_args()),\Zend_Log::ERR);
|
||||
}
|
||||
|
||||
public static function fatal() {
|
||||
self::log(self::formatMessage(func_get_args()),\Zend_Log::EMERG);
|
||||
}
|
||||
|
||||
private static function log($msg,$level = \Zend_Log::INFO) {
|
||||
$logger = self::$instance;
|
||||
|
||||
if(!$logger) {
|
||||
array_push(self::$queue, array($msg,$level));
|
||||
return;
|
||||
}
|
||||
|
||||
$logger->logger->log($msg,$level);
|
||||
}
|
||||
|
||||
|
||||
public static function reset() {
|
||||
self::$queue = array();
|
||||
self::$instance = null;
|
||||
}
|
||||
}
|
8
library/Icinga/Exception/ConfigurationError.php
Normal file
8
library/Icinga/Exception/ConfigurationError.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Icinga\Exception;
|
||||
|
||||
class ConfigurationError extends \RuntimeException
|
||||
{
|
||||
|
||||
}
|
9
library/Icinga/Exception/MissingParameterException.php
Normal file
9
library/Icinga/Exception/MissingParameterException.php
Normal file
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Icinga\Exception;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class MissingParameterException extends RuntimeException
|
||||
{
|
||||
}
|
8
library/Icinga/Exception/NotImplementedError.php
Normal file
8
library/Icinga/Exception/NotImplementedError.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Icinga\Exception;
|
||||
|
||||
class NotImplementedError extends \Exception
|
||||
{
|
||||
|
||||
}
|
8
library/Icinga/Exception/ProgrammingError.php
Normal file
8
library/Icinga/Exception/ProgrammingError.php
Normal file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Icinga\Exception;
|
||||
|
||||
class ProgrammingError extends \Exception
|
||||
{
|
||||
|
||||
}
|
50
library/Icinga/Protocol/AbstractQuery.php
Executable file
50
library/Icinga/Protocol/AbstractQuery.php
Executable file
@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace Icinga\Protocol;
|
||||
abstract class AbstractQuery
|
||||
{
|
||||
const SORT_ASC = 1;
|
||||
const SORT_DESC = -1;
|
||||
|
||||
abstract public function where($key, $val = null);
|
||||
abstract public function order($col);
|
||||
abstract public function limit($count = null, $offset = null);
|
||||
abstract public function from($table, $columns = null);
|
||||
|
||||
public function hasOrder()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function hasColumns()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getColumns()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
|
||||
public function hasLimit()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function hasOffset()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getLimit()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getOffset()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
8
library/Icinga/Protocol/Statusdat/Exception/ParsingException.php
Executable file
8
library/Icinga/Protocol/Statusdat/Exception/ParsingException.php
Executable file
@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Icinga\Protocol\Statusdat\Exception;
|
||||
|
||||
class ParsingException extends \RuntimeException
|
||||
{
|
||||
|
||||
}
|
18
library/Icinga/Protocol/Statusdat/IReader.php
Executable file
18
library/Icinga/Protocol/Statusdat/IReader.php
Executable file
@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* Created by JetBrains PhpStorm.
|
||||
* User: moja
|
||||
* Date: 1/17/13
|
||||
* Time: 10:21 AM
|
||||
* To change this template use File | Settings | File Templates.
|
||||
*/
|
||||
namespace Icinga\Protocol\Statusdat;
|
||||
interface IReader
|
||||
{
|
||||
|
||||
public function getState();
|
||||
public function getObjects();
|
||||
|
||||
public function getObjectByName($type,$name);
|
||||
|
||||
}
|
264
library/Icinga/Protocol/Statusdat/Parser.php
Executable file
264
library/Icinga/Protocol/Statusdat/Parser.php
Executable file
@ -0,0 +1,264 @@
|
||||
<?php
|
||||
|
||||
namespace Icinga\Protocol\Statusdat;
|
||||
use Icinga\Protocol\Statusdat\Exception\ParsingException as ParsingException;
|
||||
|
||||
class Parser
|
||||
{
|
||||
private $deferred = array();
|
||||
private $filehandle = null;
|
||||
private $currentObjectType = null;
|
||||
private $currentStateType = null;
|
||||
private $icingaState = null;
|
||||
private $lineCtr = 0;
|
||||
|
||||
|
||||
public function __construct($filehandle = null, $baseState = null)
|
||||
{
|
||||
if (!is_resource($filehandle))
|
||||
throw new \Icinga\Exception\ConfigurationError("Statusdat parser can't find $filehandle");
|
||||
|
||||
$this->filehandle = $filehandle;
|
||||
$this->icingaState = $baseState;
|
||||
}
|
||||
|
||||
public function parseObjectsFile()
|
||||
{
|
||||
\Icinga\Application\Logger::debug("Reading new objects file");
|
||||
$DEFINE = strlen("define ");
|
||||
$filehandle = $this->filehandle;
|
||||
$this->icingaState = array();
|
||||
while (!feof($filehandle)) {
|
||||
|
||||
$line = trim(fgets($filehandle));
|
||||
|
||||
$this->lineCtr++;
|
||||
if ($line === "" || $line[0] === "#")
|
||||
continue;
|
||||
$this->currentObjectType = trim(substr($line,$DEFINE,-1));
|
||||
if (!isset($this->icingaState[$this->currentObjectType])) {
|
||||
$this->icingaState[$this->currentObjectType] = array();
|
||||
}
|
||||
$this->readCurrentObject();
|
||||
}
|
||||
$this->processDeferred();
|
||||
}
|
||||
|
||||
public function parseRuntimeState($filehandle = null)
|
||||
{
|
||||
if($filehandle != null)
|
||||
$this->filehandle = $filehandle;
|
||||
else
|
||||
$filehandle = $this->filehandle;
|
||||
|
||||
if(!$this->icingaState)
|
||||
throw new \Icinga\Exception\ProgrammingError("Tried to read runtime state without existing objects data");
|
||||
$this->overwrites = array();
|
||||
while (!feof($filehandle)) {
|
||||
|
||||
$line = trim(fgets($filehandle));
|
||||
|
||||
$this->lineCtr++;
|
||||
if ($line === "" || $line[0] === "#")
|
||||
continue;
|
||||
|
||||
$this->currentStateType = trim(substr($line,0,-1));
|
||||
$this->readCurrentState();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private function readCurrentObject()
|
||||
{
|
||||
$filehandle = $this->filehandle;
|
||||
$monitoringObject = new \stdClass();
|
||||
while (!feof($filehandle)) {
|
||||
$line = explode("\t",trim(fgets($filehandle)),2);
|
||||
$this->lineCtr++;
|
||||
if (!$line)
|
||||
continue;
|
||||
|
||||
// End of object
|
||||
if ($line[0] === "}") {
|
||||
$this->registerObject($monitoringObject);
|
||||
return;
|
||||
}
|
||||
if(!isset($line[1]))
|
||||
$line[1] = "";
|
||||
$monitoringObject->{$line[0]} = trim($line[1]);
|
||||
}
|
||||
throw new ParsingException("Unexpected EOF in objects.cache, line ".$this->lineCtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Discard old runtime data
|
||||
* @throws Exception\ParsingException
|
||||
*/
|
||||
private function readCurrentState()
|
||||
{
|
||||
$filehandle = $this->filehandle;
|
||||
$statusdatObject = new RuntimeStateContainer();
|
||||
|
||||
$objectType = $this->getObjectTypeForState();
|
||||
|
||||
if($objectType != "host" && $objectType != "service") {
|
||||
$this->skipObject(); // ignore unknown objects
|
||||
return;
|
||||
}
|
||||
if(!isset($this->icingaState[$this->currentObjectType]))
|
||||
throw new ParsingException("No $this->currentObjectType objects registered in objects.cache");
|
||||
$base = &$this->icingaState[$this->currentObjectType];
|
||||
$state = &$this->skipObject(true);
|
||||
$statusdatObject->runtimeState = &$state;
|
||||
$name = $this->getObjectIdentifier($statusdatObject);
|
||||
|
||||
if(!isset($base[$name]))
|
||||
throw new ParsingException("Unknown object $name ".$this->currentObjectType." - ".print_r($statusdatObject,true)."\n".print_r($base,true));
|
||||
$type = substr($this->currentStateType,strlen($objectType));
|
||||
|
||||
if($type == "status") {
|
||||
$base[$name]->status = &$statusdatObject;
|
||||
} else {
|
||||
if(!isset($base[$name]->$type) || !in_array($base[$name]->$type,$this->overwrites)) {
|
||||
$base[$name]->$type = array();
|
||||
$this->overwrites[] = &$base[$name]->$type;
|
||||
}
|
||||
array_push($base[$name]->$type,$statusdatObject);
|
||||
}
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
private function getObjectTypeForState()
|
||||
{
|
||||
$pos = strpos($this->currentStateType,"service");
|
||||
|
||||
if($pos === False) {
|
||||
$pos = strpos($this->currentStateType,"host");
|
||||
} else {
|
||||
$this->currentObjectType = "service";
|
||||
return "service";
|
||||
}
|
||||
|
||||
if($pos === False)
|
||||
return $this->currentStateType;
|
||||
else {
|
||||
$this->currentObjectType = "host";
|
||||
return "host";
|
||||
}
|
||||
|
||||
return $this->currentObjectType;
|
||||
}
|
||||
|
||||
protected function skipObject($returnString = false)
|
||||
{
|
||||
if(!$returnString) {
|
||||
while(trim(fgets($this->filehandle)) !== "}") {
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
$str = "";
|
||||
while(($val = trim(fgets($this->filehandle))) !== "}") {
|
||||
$str .= $val."\n";
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
}
|
||||
|
||||
protected function registerObject(&$object) {
|
||||
|
||||
$name = $this->getObjectIdentifier($object);
|
||||
|
||||
if($name !== false) {
|
||||
$this->icingaState[$this->currentObjectType][$name] = &$object;
|
||||
}
|
||||
$this->registerObjectAsProperty($object);
|
||||
}
|
||||
|
||||
protected function registerObjectAsProperty(&$object)
|
||||
{
|
||||
if($this->currentObjectType == "service" || $this->currentObjectType == "host") {
|
||||
return;
|
||||
}
|
||||
$isService = strpos($this->currentObjectType,"service") !== False;
|
||||
$isHost = strpos($this->currentObjectType,"host") !== False;
|
||||
|
||||
$name = $this->getObjectIdentifier($object);
|
||||
if($isService === false && $isHost === false) // this would be error in the parser implementation
|
||||
return;
|
||||
$property = $this->currentObjectType;
|
||||
if($isService) {
|
||||
$this->currentObjectType = "service";
|
||||
$property = substr($property,strlen("service"));
|
||||
} else {
|
||||
$this->currentObjectType = "host";
|
||||
$property = substr($property,strlen("host"));
|
||||
}
|
||||
if(!isset($this->icingaState[$this->currentObjectType]))
|
||||
return $this->deferRegistration($object,$this->currentObjectType.$property);
|
||||
|
||||
// @TODO: Clean up, this differates between 1:n and 1:1 references
|
||||
if(strpos($property ,"group") !== False) {
|
||||
$sourceIdentifier = $this->getMembers($object);
|
||||
foreach($sourceIdentifier as $id) {
|
||||
$source = $this->icingaState[$this->currentObjectType][$id];
|
||||
if(!isset($source->$property))
|
||||
$source->$property = array();
|
||||
array_push($source->$property, $name);
|
||||
}
|
||||
} else {
|
||||
$source = $this->icingaState[$this->currentObjectType][$this->getObjectIdentifier($object)];
|
||||
if(!isset($source->$property))
|
||||
$source->$property = array();
|
||||
array_push($source->$property, $object);
|
||||
}
|
||||
}
|
||||
|
||||
protected function deferRegistration($object,$objType)
|
||||
{
|
||||
$this->deferred[] = array($object,$objType);
|
||||
}
|
||||
|
||||
protected function processDeferred() {
|
||||
foreach($this->deferred as $obj) {
|
||||
$this->currentObjectType = $obj[1];
|
||||
$this->registerObjectAsProperty($obj[0]);
|
||||
}
|
||||
}
|
||||
|
||||
protected function getMembers(&$object)
|
||||
{
|
||||
$members = explode(",",$object->members);
|
||||
if($this->currentObjectType == "service") {
|
||||
$res = array();
|
||||
for($i=0;$i<count($members);$i+=2) {
|
||||
$res[] = $members[$i].";".$members[$i+1];
|
||||
}
|
||||
return $res;
|
||||
} else {
|
||||
return $members;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected function getObjectIdentifier(&$object)
|
||||
{
|
||||
if ($this->currentObjectType == "service") {
|
||||
return $object->host_name.";".$object->service_description;
|
||||
}
|
||||
$name = $this->currentObjectType."_name";
|
||||
if(isset($object->{$name}))
|
||||
return $object->{$name};
|
||||
return false;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function getRuntimeState()
|
||||
{
|
||||
return $this->icingaState;
|
||||
}
|
||||
|
||||
}
|
256
library/Icinga/Protocol/Statusdat/Query.php
Executable file
256
library/Icinga/Protocol/Statusdat/Query.php
Executable file
@ -0,0 +1,256 @@
|
||||
<?php
|
||||
|
||||
namespace Icinga\Protocol\Statusdat;
|
||||
use Icinga\Protocol;
|
||||
|
||||
class Query extends Protocol\AbstractQuery
|
||||
{
|
||||
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"),
|
||||
"servicecomments" => array("servicecomment")
|
||||
);
|
||||
|
||||
private $reader = null;
|
||||
private $source = "";
|
||||
private $columns = array();
|
||||
private $limit = null;
|
||||
private $offset = 0;
|
||||
private $order_columns = array();
|
||||
private $groupColumns = array();
|
||||
private $groupByFn = null;
|
||||
private $filter = array();
|
||||
|
||||
// Magic indexes
|
||||
const FN_SCOPE = 0;
|
||||
const FN_NAME = 1;
|
||||
|
||||
public function hasOrder()
|
||||
{
|
||||
return !empty($this->order_columns);
|
||||
}
|
||||
|
||||
public function hasColumns()
|
||||
{
|
||||
return !empty($this->columns);
|
||||
}
|
||||
|
||||
public function getColumns()
|
||||
{
|
||||
return $this->columns;
|
||||
|
||||
}
|
||||
|
||||
public function hasLimit()
|
||||
{
|
||||
return $this->limit !== false;
|
||||
}
|
||||
|
||||
public function hasOffset()
|
||||
{
|
||||
return $this->offset !== false;
|
||||
}
|
||||
|
||||
public function getLimit()
|
||||
{
|
||||
return $this->limit;
|
||||
}
|
||||
|
||||
public function getOffset()
|
||||
{
|
||||
return $this->offset;
|
||||
}
|
||||
|
||||
public function __construct(IReader $reader)
|
||||
{
|
||||
$this->reader = $reader;
|
||||
}
|
||||
|
||||
public function where($key, $val = null)
|
||||
{
|
||||
$this->filter[] = array($key, $val);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function order($columns, $dir = null)
|
||||
{
|
||||
if($dir && strtolower($dir) == "desc")
|
||||
$dir = self::SORT_DESC;
|
||||
else
|
||||
$dir = self::SORT_ASC;
|
||||
if(!is_array($columns))
|
||||
$columns = array($columns);
|
||||
foreach($columns as $col) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
public function from($table, $columns = null)
|
||||
{
|
||||
if (isset(self::$VALID_TARGETS[$table]))
|
||||
$this->source = $table;
|
||||
else
|
||||
throw new \Exception("Unknown from target for status.dat :". $table);
|
||||
$this->columns = $columns;
|
||||
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]));
|
||||
}
|
||||
}
|
||||
|
||||
$state = $this->reader->getObjects();
|
||||
$result = array();
|
||||
foreach (self::$VALID_TARGETS[$this->source] as $target) {
|
||||
$indexes = & array_keys($state[$target]);
|
||||
if ($baseGroup) {
|
||||
$indexes = & $baseGroup->filter($state[$target]);
|
||||
}
|
||||
if (!isset($result[$target])) {
|
||||
$result[$target] = $indexes;
|
||||
} else {
|
||||
array_merge($result[$target], $indexes);
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function orderIndices(array &$indices) {
|
||||
if(!empty($this->order_columns)) {
|
||||
foreach($indices as $type=>&$subindices) {
|
||||
$this->currentType = $type; // we're singlethreaded, so let's do it a bit dirty
|
||||
usort($subindices,array($this,"orderResult"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function orderResult($a,$b) {
|
||||
$o1 = &$this->reader->getObjectByName($this->currentType,$a);
|
||||
$o2 = &$this->reader->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)
|
||||
return 1;
|
||||
if($result < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function limitIndices(array &$indices)
|
||||
{
|
||||
foreach($indices as $type=>$subindices){
|
||||
$indices[$type] = array_slice($subindices,$this->offset,$this->limit);
|
||||
}
|
||||
}
|
||||
|
||||
public function groupByFunction($fn,$scope=null)
|
||||
{
|
||||
$this->groupByFn = array($scope ? $scope : $this,$fn);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function groupByColumns($columns)
|
||||
{
|
||||
if(!is_array($columns))
|
||||
$columns = array($columns);
|
||||
$this->groupColumns = $columns;
|
||||
$this->groupByFn = array($this,"columnGroupFn");
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function columnGroupFn(array &$indices)
|
||||
{
|
||||
$cols = $this->groupColumns;
|
||||
$result = array();
|
||||
foreach($indices as $type=>$subindices) {
|
||||
foreach($subindices as $objectIndex) {
|
||||
$r = &$this->reader->getObjectByName($type,$objectIndex);
|
||||
$hash = "";
|
||||
$cols = array();
|
||||
foreach($this->groupColumns as $col) {
|
||||
$hash = md5($hash.$r->$col);
|
||||
$cols[$col] = $r->$col;
|
||||
}
|
||||
if(!isset($result[$hash]))
|
||||
$result[$hash] = (object) array(
|
||||
"columns" => (object) $cols,
|
||||
"count" => 0
|
||||
);
|
||||
$result[$hash]->count++;
|
||||
}
|
||||
}
|
||||
return array_values($result);
|
||||
}
|
||||
|
||||
public function getResult()
|
||||
{
|
||||
|
||||
$indices = &$this->getFilteredIndices();
|
||||
$this->orderIndices($indices);
|
||||
if($this->groupByFn) {
|
||||
$scope = $this->groupByFn[self::FN_SCOPE];
|
||||
$fn = $this->groupByFn[self::FN_NAME];
|
||||
|
||||
return $scope->$fn($indices);
|
||||
}
|
||||
|
||||
$this->limitIndices($indices);
|
||||
|
||||
$result = array();
|
||||
$state = &$this->reader->getObjects();
|
||||
foreach ($indices as $type=>$subindices) {
|
||||
|
||||
foreach($subindices as $index) {
|
||||
$result[] = &$state[$type][$index];
|
||||
}
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
}
|
216
library/Icinga/Protocol/Statusdat/Query/Expression.php
Executable file
216
library/Icinga/Protocol/Statusdat/Query/Expression.php
Executable file
@ -0,0 +1,216 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Icinga\Protocol\Statusdat\Query;
|
||||
|
||||
class Expression implements IQueryPart
|
||||
{
|
||||
const ENC_NUMERIC = 0;
|
||||
const ENC_SET = 0;
|
||||
const ENC_STRING = 0;
|
||||
|
||||
private $expression;
|
||||
private $field = null;
|
||||
private $basedata = array();
|
||||
private $function = null;
|
||||
private $value = "";
|
||||
private $operator = null;
|
||||
private $name = null;
|
||||
public $CB = null;
|
||||
|
||||
private function getOperatorType($token)
|
||||
{
|
||||
switch (strtoupper($token)) {
|
||||
case ">":
|
||||
$this->CB = "IS_GREATER";
|
||||
break;
|
||||
case "<":
|
||||
$this->CB = "IS_LESS";
|
||||
break;
|
||||
case ">=":
|
||||
$this->CB = "IS_GREATER_EQ";
|
||||
break;
|
||||
case "<=":
|
||||
$this->CB = "IS_LESS_EQ";
|
||||
break;
|
||||
case "=":
|
||||
$this->CB = "IS_EQUAL";
|
||||
break;
|
||||
case "LIKE":
|
||||
$this->CB = "IS_LIKE";
|
||||
break;
|
||||
case "!=":
|
||||
$this->CB = "IS_NOT_EQUAL";
|
||||
break;
|
||||
case "IN":
|
||||
$this->CB = "IS_IN";
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \Exception("Unknown operator $token in expression $this->expression !");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private function extractAggregationFunction(&$tokens) {
|
||||
$token = $tokens[0];
|
||||
$value = array();
|
||||
if(preg_match("/COUNT\{(.*)\}/",$token,$value) == false)
|
||||
return $token;
|
||||
$this->function = "count";
|
||||
$tokens[0] = $value[1];
|
||||
}
|
||||
|
||||
private function parseExpression(&$values)
|
||||
{
|
||||
$tokenized = preg_split("/ +/", trim($this->expression), 3);
|
||||
$this->extractAggregationFunction($tokenized);
|
||||
if (count($tokenized) != 3)
|
||||
echo ("Currently statusdat query expressions must be in the format FIELD OPERATOR ? or FIELD OPERATOR :value_name");
|
||||
|
||||
$this->fields = explode(".",trim($tokenized[0]));
|
||||
$this->field = $this->fields[count($this->fields)-1];
|
||||
$this->getOperatorType(trim($tokenized[1]));
|
||||
$tokenized[2] = trim($tokenized[2]);
|
||||
|
||||
if ($tokenized[2][0] === ":") {
|
||||
$this->name = substr($tokenized, 1);
|
||||
$this->value = $values[$this->name];
|
||||
} else if ($tokenized[2] === "?") {
|
||||
$this->value = array_shift($values);
|
||||
} else {
|
||||
$this->value = trim($tokenized[2]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function fromString($expression, &$values)
|
||||
{
|
||||
$this->expression = $expression;
|
||||
$this->parseExpression($values);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function __construct($expression = null, &$values = array())
|
||||
{
|
||||
if ($expression)
|
||||
$this->fromString($expression, $values);
|
||||
|
||||
}
|
||||
|
||||
public function filter(array &$base, &$idx = array())
|
||||
{
|
||||
if (!$idx)
|
||||
$idx = array_keys($base);
|
||||
$this->basedata = $base;
|
||||
return array_filter($idx, array($this,"filterFn"));
|
||||
}
|
||||
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function getField()
|
||||
{
|
||||
return $this->field;
|
||||
}
|
||||
|
||||
protected function filterFn($idx) {
|
||||
$values = $this->getFieldValues($idx);
|
||||
|
||||
if($values === False)
|
||||
return false;
|
||||
|
||||
if($this->CB == "IS_IN" ) {
|
||||
return count(array_intersect($values,$this->value)) > 0;
|
||||
}
|
||||
if($this->CB == "IS_NOT_IN" )
|
||||
return count(array_intersect($values,$this->value)) == 0;
|
||||
if($this->function) {
|
||||
$values = call_user_func($this->function,$values);
|
||||
if(!is_array($values))
|
||||
$values = array($values);
|
||||
}
|
||||
foreach($values as $val)
|
||||
if($this->{$this->CB}($val))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private function getFieldValues($idx) {
|
||||
$res = $this->basedata[$idx];
|
||||
foreach($this->fields as $field) {
|
||||
if(!is_array($res)) {
|
||||
if(!isset($res->$field)) {
|
||||
$res = array();
|
||||
break;
|
||||
}
|
||||
$res = $res->$field;
|
||||
continue;
|
||||
}
|
||||
|
||||
// it can be that an element contains more than one value, like it
|
||||
// happens when using comments, in this case we have to create a new
|
||||
// array that contains the values/objects we're searching
|
||||
$swap = array();
|
||||
foreach($res as $sub) {
|
||||
if(!isset($sub->$field))
|
||||
continue;
|
||||
if(!is_array($sub->$field))
|
||||
$swap[] = $sub->$field;
|
||||
else {
|
||||
$swap = array_merge($swap,$sub->$field);
|
||||
}
|
||||
}
|
||||
$res = $swap;
|
||||
}
|
||||
if(!is_array($res))
|
||||
return array($res);
|
||||
return $res;
|
||||
}
|
||||
|
||||
public function IS_GREATER($value)
|
||||
{
|
||||
return $value > $this->value;
|
||||
}
|
||||
|
||||
public function IS_LESS($value)
|
||||
{
|
||||
return $value < $this->value;
|
||||
}
|
||||
|
||||
public function IS_LIKE($value)
|
||||
{
|
||||
|
||||
return preg_match("/^".str_replace("%", ".*", $this->value)."$/", $value) ? true : false;
|
||||
}
|
||||
|
||||
public function IS_EQUAL($value)
|
||||
{
|
||||
if(!is_numeric($value))
|
||||
return strtolower($value) ==strtolower($this->value);
|
||||
return $value == $this->value;
|
||||
}
|
||||
|
||||
public function IS_NOT_EQUAL($value)
|
||||
{
|
||||
return $value != $this->value;
|
||||
}
|
||||
|
||||
public function IS_GREATER_EQ($value)
|
||||
{
|
||||
return $value >= $this->value;
|
||||
}
|
||||
|
||||
public function IS_LESS_EQ($value)
|
||||
{
|
||||
return $value <= $this->value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
226
library/Icinga/Protocol/Statusdat/Query/Group.php
Executable file
226
library/Icinga/Protocol/Statusdat/Query/Group.php
Executable file
@ -0,0 +1,226 @@
|
||||
<?php
|
||||
|
||||
namespace Icinga\Protocol\Statusdat\Query;
|
||||
|
||||
class Group implements IQueryPart
|
||||
{
|
||||
const GROUP_BEGIN = "(";
|
||||
const GROUP_END = ")";
|
||||
const CONJUNCTION_AND = "AND ";
|
||||
const CONJUNCTION_OR = "OR ";
|
||||
|
||||
const EXPRESSION = 0;
|
||||
const EOF = -1;
|
||||
|
||||
const TYPE_AND = "AND";
|
||||
const TYPE_OR = "OR";
|
||||
|
||||
private $items = array();
|
||||
private $parsePos = 0;
|
||||
private $expression = "";
|
||||
private $expressionClass = null;
|
||||
private $type = "";
|
||||
private $subExpressionStart = 0;
|
||||
private $subExpressionLength = 0;
|
||||
private $value;
|
||||
|
||||
public function setValue($value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function getItems()
|
||||
{
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
public function getType()
|
||||
{
|
||||
return $this->type ? $this->type : self::TYPE_AND;
|
||||
}
|
||||
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
private function tokenize()
|
||||
{
|
||||
$token = 0;
|
||||
$subgroupCount = 0;
|
||||
while ($token != self::EOF) {
|
||||
|
||||
$token = $this->getNextToken();
|
||||
|
||||
if ($token === self::GROUP_BEGIN) {
|
||||
|
||||
if ($subgroupCount == 0) // check if this is a nested group, if so then it's considered part of the subexpression
|
||||
$this->startNewSubExpression();
|
||||
$subgroupCount++;
|
||||
continue;
|
||||
}
|
||||
if ($token === self::GROUP_END) {
|
||||
if ($subgroupCount < 1)
|
||||
throw new \Exception("Invalid Query: unexpected ')' at pos " . $this->parsePos);
|
||||
$subgroupCount--;
|
||||
if ($subgroupCount == 0) // check if this is a nested group, if so then it's considered part of the subexpression
|
||||
$this->addSubgroupFromExpression();
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($token === self::CONJUNCTION_AND && $subgroupCount == 0) {
|
||||
$this->startNewSubExpression();
|
||||
if ($this->type != self::TYPE_AND && $this->type != "") {
|
||||
$this->createImplicitGroup(self::TYPE_AND);
|
||||
break;
|
||||
} else {
|
||||
$this->type = self::TYPE_AND;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if ($token === self::CONJUNCTION_OR && $subgroupCount == 0) {
|
||||
$this->startNewSubExpression();
|
||||
if ($this->type != self::TYPE_OR && $this->type != "") {
|
||||
$this->createImplicitGroup(self::TYPE_OR);
|
||||
break;
|
||||
} else {
|
||||
|
||||
$this->type = self::TYPE_OR;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->subExpressionLength = $this->parsePos - $this->subExpressionStart;
|
||||
}
|
||||
if ($subgroupCount > 0)
|
||||
throw new \Exception("Unexpected end of query, are you missing a parenthesis?");
|
||||
|
||||
$this->startNewSubExpression();
|
||||
}
|
||||
|
||||
private function createImplicitGroup($type)
|
||||
{
|
||||
$group = new Group();
|
||||
$group->setType($type);
|
||||
$group->addItem(array_pop($this->items));
|
||||
|
||||
$group->fromString(substr($this->expression, $this->parsePos), $this->value, $this->expressionClass);
|
||||
$this->items[] = $group;
|
||||
$this->parsePos = strlen($this->expression);
|
||||
|
||||
}
|
||||
|
||||
private function startNewSubExpression()
|
||||
{
|
||||
if ($this->getCurrentSubExpression() != "") {
|
||||
if (!$this->expressionClass)
|
||||
$this->items[] = new Expression($this->getCurrentSubExpression(), $this->value);
|
||||
else
|
||||
$this->items[] = new $this->expressionClass($this->getCurrentSubExpression(), $this->value);
|
||||
}
|
||||
|
||||
$this->subExpressionStart = $this->parsePos;
|
||||
$this->subExpressionLength = 0;
|
||||
}
|
||||
|
||||
private function getCurrentSubExpression()
|
||||
{
|
||||
|
||||
return substr($this->expression, $this->subExpressionStart, $this->subExpressionLength);
|
||||
}
|
||||
|
||||
private function addSubgroupFromExpression()
|
||||
{
|
||||
|
||||
if (!$this->expressionClass) {
|
||||
$this->items[] = new Group($this->getCurrentSubExpression(), $this->value);
|
||||
} else {
|
||||
$group = new Group();
|
||||
$group->fromString($this->getCurrentSubExpression(), $this->value, $this->expressionClass);
|
||||
$this->items[] = $group;
|
||||
}
|
||||
$this->subExpressionStart = $this->parsePos;
|
||||
$this->subExpressionLength = 0;
|
||||
}
|
||||
|
||||
private function isEOF()
|
||||
{
|
||||
if ($this->parsePos >= strlen($this->expression))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
private function getNextToken()
|
||||
{
|
||||
if ($this->isEOF())
|
||||
return self::EOF;
|
||||
|
||||
// skip whitespaces
|
||||
while ($this->expression[$this->parsePos] == " ") {
|
||||
$this->parsePos++;
|
||||
if ($this->isEOF())
|
||||
return self::EOF;
|
||||
}
|
||||
if ($this->expression[$this->parsePos] == self::GROUP_BEGIN) {
|
||||
$this->parsePos++;
|
||||
return self::GROUP_BEGIN;
|
||||
}
|
||||
if ($this->expression[$this->parsePos] == self::GROUP_END) {
|
||||
$this->parsePos++;
|
||||
return self::GROUP_END;
|
||||
}
|
||||
if (substr_compare($this->expression, self::CONJUNCTION_AND, $this->parsePos, strlen(self::CONJUNCTION_AND), true) === 0) {
|
||||
$this->parsePos += strlen(self::CONJUNCTION_AND);
|
||||
return self::CONJUNCTION_AND;
|
||||
}
|
||||
if (substr_compare($this->expression, self::CONJUNCTION_OR, $this->parsePos, strlen(self::CONJUNCTION_OR), true) === 0) {
|
||||
$this->parsePos += strlen(self::CONJUNCTION_OR);
|
||||
return self::CONJUNCTION_OR;
|
||||
}
|
||||
$this->parsePos++;
|
||||
return self::EXPRESSION;
|
||||
}
|
||||
|
||||
public function addItem($ex)
|
||||
{
|
||||
$this->items[] = $ex;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function fromString($expression, &$value = array(), $expressionClass = null)
|
||||
{
|
||||
$this->expression = $expression;
|
||||
$this->value = & $value;
|
||||
$this->expressionClass = $expressionClass;
|
||||
|
||||
$this->tokenize();
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function __construct($expression = null, &$value = array())
|
||||
{
|
||||
if ($expression)
|
||||
$this->fromString($expression, $value);
|
||||
}
|
||||
|
||||
public function filter(array &$base, &$idx = null)
|
||||
{
|
||||
|
||||
if ($this->type == self::TYPE_OR) {
|
||||
$idx = array();
|
||||
foreach ($this->items as &$subFilter) {
|
||||
$idx += $subFilter->filter($base, array_keys($base));
|
||||
}
|
||||
} else {
|
||||
if (!$idx)
|
||||
$idx = array_keys($base);
|
||||
foreach ($this->items as $subFilter) {
|
||||
$idx = array_intersect($idx, $subFilter->filter($base, $idx));
|
||||
}
|
||||
}
|
||||
|
||||
return $idx;
|
||||
}
|
||||
}
|
||||
|
10
library/Icinga/Protocol/Statusdat/Query/IQueryPart.php
Executable file
10
library/Icinga/Protocol/Statusdat/Query/IQueryPart.php
Executable file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace Icinga\Protocol\Statusdat\Query;
|
||||
|
||||
|
||||
interface IQueryPart
|
||||
{
|
||||
public function __construct($expression = null,&$value = array());
|
||||
public function filter(array &$base, &$idx=null);
|
||||
}
|
194
library/Icinga/Protocol/Statusdat/Reader.php
Executable file
194
library/Icinga/Protocol/Statusdat/Reader.php
Executable file
@ -0,0 +1,194 @@
|
||||
<?php
|
||||
namespace Icinga\Protocol\Statusdat;
|
||||
|
||||
use Icinga\Exception as Exception;
|
||||
use Icinga\Benchmark as Benchmark;
|
||||
|
||||
class ObjectContainer extends \stdClass {
|
||||
public $ref;
|
||||
public $reader;
|
||||
|
||||
public function __construct(\stdClass &$obj,IReader &$reader) {
|
||||
$this->ref = &$obj;
|
||||
$this->reader = &$reader;
|
||||
|
||||
}
|
||||
public function __get($attribute) {
|
||||
$exploded = explode(".",$attribute);
|
||||
$result = $this->ref;
|
||||
foreach($exploded as $elem) {
|
||||
|
||||
$result = $result->$elem;
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
class Reader implements IReader
|
||||
{
|
||||
const DEFAULT_CACHE_LIFETIME = 300;
|
||||
const STATUSDAT_DEFAULT_CACHE_PATH = "/cache";
|
||||
|
||||
|
||||
private $lastState = null;
|
||||
private $hasRuntimeState = false;
|
||||
private $objectCache = null;
|
||||
private $statusCache = null;
|
||||
private $newState = false;
|
||||
private $parser = null;
|
||||
private $noCache = false;
|
||||
public function __construct($config = \Zend_Config, $parser = null, $noCache = false)
|
||||
{
|
||||
$this->noCache = $noCache;
|
||||
$this->config = $config;
|
||||
$this->parser = $parser;
|
||||
if(!$noCache) {
|
||||
$this->cache = $this->initializeCaches($config);
|
||||
if($this->fromCache()) {
|
||||
$this->createHostServiceConnections();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if(!$this->lastState)
|
||||
$this->parseObjectsCacheFile();
|
||||
if(!$this->hasRuntimeState);
|
||||
$this->parseStatusDatFile();
|
||||
if(!$noCache && $this->newState)
|
||||
$this->statusCache->save($this->parser->getRuntimeState(),'objects'.md5($this->config->objects_file));
|
||||
$this->createHostServiceConnections();
|
||||
|
||||
}
|
||||
|
||||
private function createHostServiceConnections()
|
||||
{
|
||||
if (!isset($this->lastState["service"])) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->lastState["service"] as &$service) {
|
||||
$host = &$this->lastState["host"][$service->host_name];
|
||||
if(!isset($host->services))
|
||||
$host->services = array();
|
||||
$host->services[$service->service_description] = &$service;
|
||||
$service->host = &$host;
|
||||
}
|
||||
}
|
||||
|
||||
public function select()
|
||||
{
|
||||
return new Query($this);
|
||||
}
|
||||
|
||||
public function fetchAll(Query $query)
|
||||
{
|
||||
return new \Icinga\Backend\MonitoringObjectList(
|
||||
$query->getResult(),
|
||||
$query->getView()
|
||||
);
|
||||
}
|
||||
|
||||
public function getState()
|
||||
{
|
||||
return $this->lastState;
|
||||
}
|
||||
|
||||
public function getObjects()
|
||||
{
|
||||
return $this->lastState;
|
||||
}
|
||||
|
||||
|
||||
public function getObjectByName($type, $name)
|
||||
{
|
||||
if (isset($this->lastState[$type]) && isset($this->lastState[$type][$name]))
|
||||
return new ObjectContainer($this->lastState[$type][$name],$this);
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getObjectNames($type) {
|
||||
return isset($this->lastState[$type]) ? array_keys($this->lastState[$type]) : null;
|
||||
}
|
||||
|
||||
private function fromCache()
|
||||
{
|
||||
if(!$this->readObjectsCache()) {
|
||||
$this->newState = true;
|
||||
return false;
|
||||
}
|
||||
if(!$this->readStatusCache()){
|
||||
$this->newState = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function readObjectsCache()
|
||||
{
|
||||
$this->lastState = $this->objectCache->load('objects'.md5($this->config->objects_file));
|
||||
if($this->lastState == false)
|
||||
return false;
|
||||
}
|
||||
|
||||
private function readStatusCache()
|
||||
{
|
||||
$statusInfo = $this->stateCache->load('state'.md5($this->config->status_file));
|
||||
if($statusInfo == false)
|
||||
return false;
|
||||
$this->hasRuntimeState = true;
|
||||
}
|
||||
|
||||
private function initializeCaches()
|
||||
{
|
||||
$defaultCachePath = "/tmp/".self::STATUSDAT_DEFAULT_CACHE_PATH;
|
||||
|
||||
$cachePath = $this->config->get('cache_path',$defaultCachePath);
|
||||
$maxCacheLifetime = intval($this->config->get('cache_path',self::DEFAULT_CACHE_LIFETIME));
|
||||
if(!is_writeable($cachePath))
|
||||
throw new \Icinga\Exception\ConfigurationError("Cache path $cachePath is not writable, check your configuration");
|
||||
|
||||
|
||||
$backendOptions = array(
|
||||
'cache_dir' => $cachePath
|
||||
);
|
||||
// the objects cache might exist for months and is still valid
|
||||
$this->objectCache = $this->initCache($this->config->objects_file,$backendOptions,NULL);
|
||||
$this->statusCache = $this->initCache($this->config->status_file,$backendOptions,$maxCacheLifetime);
|
||||
|
||||
}
|
||||
|
||||
private function initCache($file, $backend, $lifetime)
|
||||
{
|
||||
$frontendOptions = array(
|
||||
'lifetime' => $lifetime,
|
||||
'automatic_serialization' => true,
|
||||
'master_files' => array($file)
|
||||
);
|
||||
return \Zend_Cache::factory('Core','File',$frontendOptions,$backend);
|
||||
}
|
||||
|
||||
private function parseObjectsCacheFile()
|
||||
{
|
||||
if(!is_readable($this->config->objects_file))
|
||||
throw new \Icinga\Exception\ConfigurationError("Can't read objects-file {$this->config->objects_file}, check your configuration");
|
||||
if(!$this->parser)
|
||||
$this->parser = new Parser(fopen($this->config->objects_file,"r"));
|
||||
$this->parser->parseObjectsFile();
|
||||
$this->lastState = &$this->parser->getRuntimeState();
|
||||
}
|
||||
|
||||
private function parseStatusDatFile()
|
||||
{
|
||||
if(!is_readable($this->config->status_file))
|
||||
throw new \Icinga\Exception\ConfigurationError("Can't read status-file {$this->config->status_file}, check your configuration");
|
||||
if(!$this->parser)
|
||||
$this->parser = new Parser(fopen($this->config->status_file,"r"),$this->lastState);
|
||||
$this->parser->parseRuntimeState(fopen($this->config->status_file,"r"));
|
||||
$this->lastState = &$this->parser->getRuntimeState();
|
||||
if(!$this->noCache)
|
||||
$this->statusCache->save(array("true" => true),"state".md5($this->config->objects_file));
|
||||
}
|
||||
|
||||
|
||||
}
|
35
library/Icinga/Protocol/Statusdat/RuntimeStateContainer.php
Executable file
35
library/Icinga/Protocol/Statusdat/RuntimeStateContainer.php
Executable file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Icinga\Protocol\Statusdat;
|
||||
|
||||
class RuntimeStateContainer extends \stdClass
|
||||
{
|
||||
public $runtimeState = "";
|
||||
public function __construct($str = "") {
|
||||
$this->runtimeState = $str;
|
||||
}
|
||||
|
||||
public function __isset($attr)
|
||||
{
|
||||
try {
|
||||
$this->__get($attr);
|
||||
return true;
|
||||
} catch(\InvalidArgumentException $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function __get($attr)
|
||||
{
|
||||
|
||||
$start = strpos($this->runtimeState,$attr."=");
|
||||
if($start === False)
|
||||
throw new \InvalidArgumentException("Unknown property $attr");
|
||||
|
||||
$start += strlen($attr."=");
|
||||
$len = strpos($this->runtimeState,"\n",$start) - $start;
|
||||
$this->$attr = trim(substr($this->runtimeState,$start,$len));
|
||||
|
||||
return $this->$attr;
|
||||
}
|
||||
}
|
Binary file not shown.
@ -1,19 +1,21 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Icinga\Protocol\Statusdat;
|
||||
|
||||
require_once("../library/Icinga/Protocol/Statusdat/IReader.php");
|
||||
require_once("../library/Icinga/Protocol/Statusdat/Reader.php");
|
||||
require_once("../library/Icinga/Protocol/Statusdat/Exception/ParsingException.php");
|
||||
require_once("../library/Icinga/Exception/ProgrammingError.php");
|
||||
require_once("../library/Icinga/Protocol/Statusdat/Parser.php");
|
||||
require_once("../library/Icinga/Protocol/AbstractQuery.php");
|
||||
require_once("../library/Icinga/Protocol/Statusdat/Query.php");
|
||||
require_once("../library/Icinga/Protocol/Statusdat/Query/IQueryPart.php");
|
||||
require_once("../library/Icinga/Protocol/Statusdat/Query/Group.php");
|
||||
require_once("../library/Icinga/Protocol/Statusdat/Query/Expression.php");
|
||||
require_once("../library/Icinga/Exception/ConfigurationError.php");
|
||||
require_once("Zend/Config.php");
|
||||
require_once("Zend/Log.php");
|
||||
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/IReader.php");
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/Reader.php");
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/Exception/ParsingException.php");
|
||||
require_once("../../library/Icinga/Exception/ProgrammingError.php");
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/Parser.php");
|
||||
require_once("../../library/Icinga/Protocol/AbstractQuery.php");
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/Query.php");
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/Query/IQueryPart.php");
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/Query/Group.php");
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/Query/Expression.php");
|
||||
require_once("../../library/Icinga/Exception/ConfigurationError.php");
|
||||
require_once("../../library/Icinga/Application/Logger.php");
|
||||
use \Icinga\Protocol\Statusdat as SD;
|
||||
|
||||
/**
|
||||
|
@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Icinga\Protocol\Statusdat;
|
||||
require_once("../library/Icinga/Protocol/Statusdat/Exception/ParsingException.php");
|
||||
require_once("../library/Icinga/Exception/ProgrammingError.php");
|
||||
require_once("../library/Icinga/Protocol/Statusdat/Parser.php");
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/Exception/ParsingException.php");
|
||||
require_once("../../library/Icinga/Exception/ProgrammingError.php");
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/Parser.php");
|
||||
use Icinga\Protocol\Statusdat\Parser;
|
||||
/**
|
||||
*
|
||||
|
@ -2,8 +2,8 @@
|
||||
|
||||
namespace Tests\Icinga\Protocol\Statusdat\Query;
|
||||
|
||||
require_once("../library/Icinga/Protocol/Statusdat/Query/IQueryPart.php");
|
||||
require_once("../library/Icinga/Protocol/Statusdat/Query/Expression.php");
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/Query/IQueryPart.php");
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/Query/Expression.php");
|
||||
|
||||
use Icinga\Protocol\Statusdat\Query\Expression;
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Icinga\Protocol\Statusdat\Query;
|
||||
require_once("../library/Icinga/Protocol/Statusdat/Query/IQueryPart.php");
|
||||
require_once("../library/Icinga/Protocol/Statusdat/Query/Group.php");
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/Query/IQueryPart.php");
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/Query/Group.php");
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Icinga\Protocol\Statusdat;
|
||||
require_once("../library/Icinga/Protocol/AbstractQuery.php");
|
||||
require_once("../library/Icinga/Protocol/Statusdat/Query.php");
|
||||
require_once("../../library/Icinga/Protocol/AbstractQuery.php");
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/Query.php");
|
||||
require_once(dirname(__FILE__)."/ReaderMock.php");
|
||||
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?php
|
||||
namespace Tests\Icinga\Protocol\Statusdat;
|
||||
require_once("../library/Icinga/Protocol/Statusdat/IReader.php");
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/IReader.php");
|
||||
|
||||
use Icinga\Protocol\Statusdat\IReader;
|
||||
|
||||
@ -39,4 +39,4 @@ class ReaderMock implements IReader
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Icinga\Protocol\Statusdat;
|
||||
require_once("../library/Icinga/Protocol/Statusdat/IReader.php");
|
||||
require_once("../library/Icinga/Protocol/Statusdat/Reader.php");
|
||||
require_once("../library/Icinga/Exception/ConfigurationError.php");
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/IReader.php");
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/Reader.php");
|
||||
require_once("../../library/Icinga/Exception/ConfigurationError.php");
|
||||
|
||||
use Icinga\Protocol\Statusdat\Reader as Reader;
|
||||
define("APPLICATION_PATH","./"); // TODO: test boostrap
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Tests\Icinga\Protocol\Statusdat;
|
||||
|
||||
require_once("../library/Icinga/Protocol/Statusdat/RuntimeStateContainer.php");
|
||||
require_once("../../library/Icinga/Protocol/Statusdat/RuntimeStateContainer.php");
|
||||
|
||||
class RuntimestatecontainerTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
Loading…
x
Reference in New Issue
Block a user