monitoring: Fetch Icinga object properties lazily

This commit is contained in:
Eric Lippmann 2014-09-12 10:16:31 +02:00
parent b6ac31d10f
commit aca5a2e466
1 changed files with 288 additions and 173 deletions

View File

@ -2,127 +2,249 @@
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
// {{{ICINGA_LICENSE_HEADER}}} // {{{ICINGA_LICENSE_HEADER}}}
/*
CREATE INDEX tgelf_comments ON icinga_comments (object_id, comment_type, comment_time);
CREATE INDEX tgelf_scheduleddowntime ON icinga_scheduleddowntime (object_id, is_in_effect, scheduled_start_time);
*/
namespace Icinga\Module\Monitoring\Object; namespace Icinga\Module\Monitoring\Object;
use Icinga\Module\Monitoring\DataView\Contact; use InvalidArgumentException;
use Icinga\Module\Monitoring\DataView\Contactgroup;
use Icinga\Module\Monitoring\DataView\Downtime;
use Icinga\Module\Monitoring\DataView\EventHistory;
use Icinga\Module\Monitoring\DataView\Hostgroup;
use Icinga\Module\Monitoring\DataView\Comment;
use Icinga\Module\Monitoring\DataView\Servicegroup;
use Icinga\Module\Monitoring\DataView\Customvar;
use Icinga\Web\UrlParams;
use Icinga\Application\Config; use Icinga\Application\Config;
use Icinga\Exception\InvalidPropertyException;
use Icinga\Module\Monitoring\Backend;
/**
* A monitored Icinga object, i.e. host or service
*/
abstract class MonitoredObject abstract class MonitoredObject
{ {
public $type; /**
public $prefix; * Type host
*/
const TYPE_HOST = 'host';
public $comments = array(); /**
public $downtimes = array(); * Type service
public $hostgroups = array(); */
public $servicegroups = array(); const TYPE_SERVICE = 'service';
public $contacts = array();
public $contactgroups = array();
public $customvars = array();
public $events = array();
protected $view; /**
private $properties = array(); * Backend to fetch object information from
protected $params; *
* @var Backend
*/
protected $backend;
// TODO: Fetching parent states if any would be nice /**
// Same goes for host/service dependencies * Type of the Icinga object, i.e. 'host' or 'service'
*
* @var string
*/
protected $type;
public function __construct(UrlParams $params) /**
* Prefix of the Icinga object, i.e. 'host_' or 'service_'
*
* @var string
*/
protected $prefix;
/**
* Properties
*
* @var object
*/
protected $properties;
/**
* Comments
*
* @var array
*/
protected $comments;
/**
* Downtimes
*
* @var array
*/
protected $downtimes;
/**
* Host groups
*
* @var array
*/
protected $hostgroups;
/**
* Service groups
*
* @var array
*/
protected $servicegroups;
/**
* Contacts
*
* @var array
*/
protected $contacts;
/**
* Contact groups
*
* @var array
*/
protected $contactgroups;
/**
* Custom variables
*
* @var array
*/
protected $customvars;
/**
* Event history
*
* @var \Icinga\Module\Monitoring\DataView\EventHistory
*/
protected $eventhistory;
/**
* Create a monitored object, i.e. host or service
*
* @param Backend $backend Backend to fetch object information from
*/
public function __construct(Backend $backend)
{ {
$this->params = $params; $this->backend = $backend;
$this->properties = $this->getProperties();
} }
abstract protected function getProperties(); /**
* Get the object's data view
*
* @return \Icinga\Module\Monitoring\DataView\DataView
*/
abstract protected function getDataView();
/**
* Fetch the object's properties
*
* @return bool
*/
public function fetch()
{
$this->properties = $this->getDataView()->getQuery()->fetchRow();
return $this->properties !== false;
}
/**
* Get the type of the object
*
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* Require the object's type to be one of the given types
*
* @param array $oneOf
*
* @return bool
* @throws InvalidArgumentException If the object's type is not one of the given types.
*/
public function assertOneOf(array $oneOf)
{
if (! in_array($this->type, $oneOf)) {
throw new InvalidArgumentException;
}
return true;
}
/**
* Fetch the object's comments
*
* @return $this
*/
public function fetchComments() public function fetchComments()
{ {
// WTF??? $comments = $this->backend->select()->from('comment', array(
$query = Comment::fromParams(array('backend' => null), array(
'id' => 'comment_internal_id', 'id' => 'comment_internal_id',
'timestamp' => 'comment_timestamp', 'timestamp' => 'comment_timestamp',
'author' => 'comment_author', 'author' => 'comment_author',
'comment' => 'comment_data', 'comment' => 'comment_data',
'type' => 'comment_type', 'type' => 'comment_type',
)); ))
$query->where('comment_type', array('comment', 'ack')); ->where('comment_type', array('comment', 'ack'))
$query->where('comment_objecttype', $this->type); ->where('comment_objecttype', $this->type)
$query->where('comment_host', $this->host_name); ->where('comment_host', $this->host);
if ($this->type === 'service') { if ($this->type === self::TYPE_SERVICE) {
$query->where('comment_service', $this->service_description); $comments->where('comment_service', $this->service);
} }
$this->comments = $query->getQuery()->fetchAll(); $this->comments = $comments->getQuery()->fetchAll();
return $this; return $this;
} }
/**
* Fetch the object's downtimes
*
* @return $this
*/
public function fetchDowntimes() public function fetchDowntimes()
{ {
// TODO: We want to check for objecttype = 'host', not type_id = 1 $downtimes = $this->backend->select()->from('downtime', array(
'id' => 'downtime_internal_id',
// WTF??? 'objecttype' => 'downtime_objecttype',
$query = Downtime::fromParams(array('backend' => null), array( 'comment' => 'downtime_comment',
'id' => 'downtime_internal_id', 'author' => 'downtime_author',
'objecttype' => 'downtime_objecttype', 'start' => 'downtime_start',
'comment' => 'downtime_comment', 'scheduled_start' => 'downtime_scheduled_start',
'author' => 'downtime_author', 'end' => 'downtime_end',
'start' => 'downtime_start', 'duration' => 'downtime_duration',
'scheduled_start' => 'downtime_scheduled_start', 'is_flexible' => 'downtime_is_flexible',
'end' => 'downtime_end', 'is_fixed' => 'downtime_is_fixed',
'duration' => 'downtime_duration', 'is_in_effect' => 'downtime_is_in_effect',
'is_flexible' => 'downtime_is_flexible', 'entry_time' => 'downtime_entry_time',
'is_fixed' => 'downtime_is_fixed', 'host' => 'downtime_host',
'is_in_effect' => 'downtime_is_in_effect', 'service' => 'downtime_service'
'entry_time' => 'downtime_entry_time', ))
'host' => 'downtime_host', ->where('downtime_objecttype', $this->type)
'service' => 'downtime_service' ->where('downtime_host', $this->host)
)); ->order('downtime_is_in_effect', 'DESC')
->order('downtime_scheduled_start', 'ASC');
$query->where('downtime_objecttype', $this->type); if ($this->type === self::TYPE_SERVICE) {
$query->where('downtime_host', $this->host_name); $downtimes->where('downtime_service', $this->service);
if ($this->type === 'service') {
$query->where('downtime_service', $this->service_description);
} }
$query->order('downtime_is_in_effect', 'DESC')->order('downtime_scheduled_start', 'ASC'); $this->downtimes = $downtimes->getQuery()->fetchAll();
$this->downtimes = $query->getQuery()->fetchAll();
return $this;
$this->downtimes = Downtime::fromRequest($this->request)->getQuery()->fetchAll();
return $this; return $this;
} }
/**
* Fetch the object's host groups
*
* @return $this
*/
public function fetchHostgroups() public function fetchHostgroups()
{ {
$query = HostGroup::fromParams(array('backend' => null), array( $hostGroups = $this->backend->select()->from('hostGroup', array(
'hostgroup_name', 'hostgroup_name',
'hostgroup_alias' 'hostgroup_alias'
))->where('host_name', $this->host_name); ))
->where('host_name', $this->host);
$this->hostgroups = $query->getQuery()->fetchPairs(); $this->hostgroups = $hostGroups->getQuery()->fetchPairs();
return $this; return $this;
} }
/**
* Fetch the object's custom variables
*
* @return $this
*/
public function fetchCustomvars() public function fetchCustomvars()
{ {
$blacklist = array(); $blacklist = array();
$blacklistPattern = '/^(.*pw.*|.*pass.*|community)$/'; $blacklistPattern = '/^(.*pw.*|.*pass.*|community)$/i';
if ($security = Config::module('monitoring')->get('security')) { if ($security = Config::module('monitoring')->get('security')) {
@ -138,23 +260,20 @@ abstract class MonitoredObject
$blacklistPattern = '/^(' . implode('|', $blacklist) . ')$/i'; $blacklistPattern = '/^(' . implode('|', $blacklist) . ')$/i';
} }
$query = Customvar::fromParams(array('backend' => null), array( $query = $this->backend->select()->from('customvar', array(
'varname', 'varname',
'varvalue' 'varvalue'
) ))
); ->where('object_type', $this->type)
->where('host_name', $this->host);
if ($this->type === 'host') { if ($this->type === self::TYPE_SERVICE) {
$query->where('host_name', $this->host_name) $query->where('service_description', $this->service);
->where('object_type', 'host');
} else {
$query->where('host_name', $this->host_name)
->where('object_type', 'service')
->where('service_description', $this->service_description);
} }
$this->customvars = array();
$customvars = $query->getQuery()->fetchPairs(); $customvars = $query->getQuery()->fetchPairs();
foreach ($customvars as $name => &$value) { foreach ($customvars as $name => $value) {
$name = ucwords(str_replace('_', ' ', strtolower($name))); $name = ucwords(str_replace('_', ' ', strtolower($name)));
if ($blacklistPattern && preg_match($blacklistPattern, $name)) { if ($blacklistPattern && preg_match($blacklistPattern, $name)) {
$value = '***'; $value = '***';
@ -165,83 +284,71 @@ abstract class MonitoredObject
return $this; return $this;
} }
/**
* Fetch the object's contacts
*
* @return $this
*/
public function fetchContacts() public function fetchContacts()
{ {
/* $contacts = $this->backend->select()->from('contact', array(
$query = Contact::fromRequest(
$this->request,
array(
'contact_name', 'contact_name',
'contact_alias', 'contact_alias',
'contact_email', 'contact_email',
'contact_pager', 'contact_pager',
) ))
)->getQuery()
->where('host_name', $this->host_name); ->where('host_name', $this->host_name);
*/ if ($this->type === self::TYPE_SERVICE) {
$contacts->where('service_description', $this->service);
$query = Contact::fromParams(array('backend' => null), array(
'contact_name',
'contact_alias',
'contact_email',
'contact_pager',
));
if ($this->type === 'service') {
$query->where('service_host_name', $this->host_name);
$query->where('service_description', $this->service_description);
} else {
$query->where('host_name', $this->host_name);
} }
$this->contacts = $contacts->getQuery()->fetchAll();
$this->contacts = $query->getQuery()->fetchAll();
return $this; return $this;
} }
/**
* Fetch the object's service groups
*
* @return $this
*/
public function fetchServicegroups() public function fetchServicegroups()
{ {
$query = Servicegroup::fromParams(array('backend' => null), array( $serviceGroups = $this->backend->select()->from('serviceGroup', array(
'servicegroup_name', 'servicegroup_name',
'servicegroup_alias', 'servicegroup_alias'
) ))
); ->where('service_host_name', $this->host)
$query->where('service_host_name', $this->host_name); ->where('service_description', $this->service);
$query->where('service_description', $this->service_description); $this->servicegroups = $serviceGroups->getQuery()->fetchPairs();
$this->servicegroups = $query->getQuery()->fetchPairs();
return $this; return $this;
} }
/**
* Fetch the object's contact groups
*
* @return $this
*/
public function fetchContactgroups() public function fetchContactgroups()
{ {
$contactsGroups = $this->backend->select()->from('contactGroup', array(
$query = Contactgroup::fromParams(array('backend' => null), array(
'contactgroup_name', 'contactgroup_name',
'contactgroup_alias' 'contactgroup_alias'
)); ))
->where('host_name', $this->host);
if ($this->type === 'service') { if ($this->type === self::TYPE_SERVICE) {
$query->where('service_host_name', $this->host_name); $contactsGroups->where('service_description', $this->service);
$query->where('service_description', $this->service_description);
} else {
$query->where('host_name', $this->host_name);
} }
/* $this->contactgroups = $contactsGroups->getQuery()->fetchAll();
$query = Contactgroup::fromRequest(
$this->request,
array(
'contactgroup_name',
'contactgroup_alias'
)
)->getQuery();
*/
$this->contactgroups = $query->getQuery()->fetchAll();
return $this; return $this;
} }
public function fetchEventHistory() /**
* Fetch the object's event history
*
* @return $this
*/
public function fetchEventhistory()
{ {
$query = EventHistory::fromParams(array('backend' => null), array( $eventHistory = $this->backend->select()->from('eventHistory', array(
'object_type', 'object_type',
'host_name', 'host_name',
'service_description', 'service_description',
@ -251,42 +358,50 @@ abstract class MonitoredObject
'max_attempts', 'max_attempts',
'output', 'output',
'type' 'type'
) ))
)->sort('timestamp', 'DESC'); ->order('timestamp', 'DESC')
if ($this->type === 'service') { ->where('host_name', $this->host);
$query->where('service_host_name', $this->host_name); if ($this->type === self::TYPE_SERVICE) {
$query->where('service_description', $this->service_description); $eventHistory->where('service_description', $this->service);
} else {
$query->where('host_name', $this->host_name);
} }
$this->eventhistory = $eventHistory->getQuery();
$this->eventhistory = $query->getQuery();
return $this; return $this;
} }
public function __get($param) /**
* Fetch all available data of the object
*
* @return $this
*/
public function populate()
{ {
$this
if (isset($this->properties->$param)) { ->fetchComments()
return $this->properties->$param; ->fetchContacts()
} elseif (isset($this->$param)) { ->fetchContactgroups()
return $this->$param; ->fetchCustomvars()
} ->fetchDowntimes();
if (substr($param, 0, strlen($this->prefix)) === $this->prefix) { // Call fetchHostgroups or fetchServicegroups depending on the object's type
return false; $fetchGroups = 'fetch' . ucfirst($this->type) . 'groups';
} $this->$fetchGroups();
$expandedName = $this->prefix . strtolower($param); return $this;
return $this->$expandedName;
} }
public static function fromParams(UrlParams $params) public function __get($name)
{ {
if ($params->has('service') && $params->has('host')) { if (property_exists($this->properties, $name)) {
return new Service($params); return $this->properties->$name;
} elseif ($params->has('host')) { } elseif (isset($this->$name)) {
return new Host($params); return $this->$name;
} elseif (property_exists($this, $name)) {
$fetchMethod = 'fetch' . ucfirst($name);
$this->$fetchMethod();
return $this->$name;
} }
if (substr($name, 0, strlen($this->prefix)) === $this->prefix) {
throw new InvalidPropertyException('Can\'t access property \'%s\'. Property does not exist.', $name);
}
$prefixedName = $this->prefix . strtolower($name);
return $this->$prefixedName;
} }
abstract public function populate();
} }