Merge branch 'bugfix/monitoring-ack-comments-display-9674'

fixes #9674
This commit is contained in:
Eric Lippmann 2015-09-04 13:04:39 +02:00
commit b28f1c4038
19 changed files with 681 additions and 328 deletions

View File

@ -672,6 +672,12 @@
"code": 59492,
"src": "entypo"
},
{
"uid": "p57wgnf4glngbchbucdi029iptu8oxb8",
"css": "pin",
"code": 59513,
"src": "typicons"
},
{
"uid": "c16a63e911bc47b46dc2a7129d2f0c46",
"css": "down-small",

View File

@ -119,4 +119,5 @@
.icon-down-small:before { content: '\e875'; } /* '' */
.icon-left-small:before { content: '\e876'; } /* '' */
.icon-right-small:before { content: '\e877'; } /* '' */
.icon-up-small:before { content: '\e878'; } /* '' */
.icon-up-small:before { content: '\e878'; } /* '' */
.icon-pin:before { content: '\e879'; } /* '' */

File diff suppressed because one or more lines are too long

View File

@ -119,4 +119,5 @@
.icon-down-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-left-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-right-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-up-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-up-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-pin { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }

View File

@ -130,4 +130,5 @@
.icon-down-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-left-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-right-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-up-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-up-small { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }
.icon-pin { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); }

View File

@ -1,10 +1,10 @@
@font-face {
font-family: 'ifont';
src: url('../font/ifont.eot?54745533');
src: url('../font/ifont.eot?54745533#iefix') format('embedded-opentype'),
url('../font/ifont.woff?54745533') format('woff'),
url('../font/ifont.ttf?54745533') format('truetype'),
url('../font/ifont.svg?54745533#ifont') format('svg');
src: url('../font/ifont.eot?612849');
src: url('../font/ifont.eot?612849#iefix') format('embedded-opentype'),
url('../font/ifont.woff?612849') format('woff'),
url('../font/ifont.ttf?612849') format('truetype'),
url('../font/ifont.svg?612849#ifont') format('svg');
font-weight: normal;
font-style: normal;
}
@ -14,7 +14,7 @@
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: 'ifont';
src: url('../font/ifont.svg?54745533#ifont') format('svg');
src: url('../font/ifont.svg?612849#ifont') format('svg');
}
}
*/
@ -174,4 +174,5 @@
.icon-down-small:before { content: '\e875'; } /* '' */
.icon-left-small:before { content: '\e876'; } /* '' */
.icon-right-small:before { content: '\e877'; } /* '' */
.icon-up-small:before { content: '\e878'; } /* '' */
.icon-up-small:before { content: '\e878'; } /* '' */
.icon-pin:before { content: '\e879'; } /* '' */

View File

@ -229,11 +229,11 @@ body {
}
@font-face {
font-family: 'ifont';
src: url('./font/ifont.eot?11424534');
src: url('./font/ifont.eot?11424534#iefix') format('embedded-opentype'),
url('./font/ifont.woff?11424534') format('woff'),
url('./font/ifont.ttf?11424534') format('truetype'),
url('./font/ifont.svg?11424534#ifont') format('svg');
src: url('./font/ifont.eot?91269362');
src: url('./font/ifont.eot?91269362#iefix') format('embedded-opentype'),
url('./font/ifont.woff?91269362') format('woff'),
url('./font/ifont.ttf?91269362') format('truetype'),
url('./font/ifont.svg?91269362#ifont') format('svg');
font-weight: normal;
font-style: normal;
}
@ -482,6 +482,7 @@ body {
</div>
<div class="row">
<div title="Code: 0xe878" class="the-icons span3"><i class="demo-icon icon-up-small">&#xe878;</i> <span class="i-name">icon-up-small</span><span class="i-code">0xe878</span></div>
<div title="Code: 0xe879" class="the-icons span3"><i class="demo-icon icon-pin">&#xe879;</i> <span class="i-name">icon-pin</span><span class="i-code">0xe879</span></div>
</div>
</div>
<div class="container footer">Generated by <a href="http://fontello.com">fontello.com</a></div>

View File

@ -112,7 +112,7 @@ class DbConnection implements Selectable, Extensible, Updatable, Reducible, Insp
/**
* Getter for the Zend_Db_Adapter
*
* @return Zend_Db_Adapter_Abstract
* @return \Zend_Db_Adapter_Abstract
*/
public function getDbAdapter()
{

View File

@ -111,8 +111,8 @@ class AcknowledgeProblemCommandForm extends ObjectsCommandForm
'label' => $this->translate('Sticky Acknowledgement'),
'value' => true,
'description' => $this->translate(
'If you want the acknowledgement to disable notifications until the host or service recovers,'
. ' check this option.'
'If you want the acknowledgement to remain until the host or service recovers even if the host'
. ' or service changes state, check this option.'
)
)
),

View File

@ -8,14 +8,43 @@ if (in_array((int) $object->state, array(0, 99))) {
}
if ($object->acknowledged): ?>
<?php
$acknowledgement = $object->acknowledgement;
/** @var \Icinga\Module\Monitoring\Object\Acknowledgement $acknowledgement */
?>
<tr>
<th><?= $this->translate('Acknowledged') ?></th>
<td data-base-target="_self">
<?php if (isset($removeAckForm)) { // Form is unset if the current user lacks the respective permission
echo $removeAckForm;
} else {
echo '&#45;';
} ?>
<ul class="inline-comments">
<li class="comment-item">
<h3>
<?= sprintf(
$this->translate('%s acknowledged %s'),
'<span class="author">' . $this->escape($acknowledgement->getAuthor()) . '</span>',
$this->timeAgo($acknowledgement->getEntryTime())
) ?>
<?php
if ($acknowledgement->getSticky()) {
echo $this->icon('pin', sprintf(
$this->translate(
'Acknowledgement remains until the %1$s recovers even if the %1$s changes state'
),
$object->getType(true)
));
}
if (isset($removeAckForm)) {
// Form is unset if the current user lacks the respective permission
// Form is unset if the current user lacks the respective permission
echo $removeAckForm;
}
?>
</h3>
<p>
<span class="sr-only">(<?= $this->translate('Comment') ?>): </span>
<?= nl2br($this->createTicketLinks($acknowledgement->getComment()), false) ?>
</p>
</li>
</ul>
</td>
</tr>
<?php else: ?>

View File

@ -25,8 +25,8 @@ class CommentQuery extends IdoQuery
'comment_is_persistent' => 'c.comment_is_persistent',
'comment_timestamp' => 'c.comment_timestamp',
'comment_type' => 'c.comment_type',
'object_type' => 'c.object_type',
'instance_name' => 'c.instance_name'
'instance_name' => 'c.instance_name',
'object_type' => 'c.object_type'
),
'hosts' => array(
'host_display_name' => 'c.host_display_name',

View File

@ -0,0 +1,215 @@
<?php
/* Icinga Web 2 | (c) 2013-2015 Icinga Development Team | GPLv2+ */
namespace Icinga\Module\Monitoring\Object;
use InvalidArgumentException;
use Traversable;
use Icinga\Util\String;
/**
* Acknowledgement of a host or service incident
*/
class Acknowledgement
{
/**
* Author of the acknowledgement
*
* @var string
*/
protected $author;
/**
* Comment of the acknowledgement
*
* @var string
*/
protected $comment;
/**
* Entry time of the acknowledgement
*
* @var int
*/
protected $entryTime;
/**
* Expiration time of the acknowledgment
*
* @var int|null
*/
protected $expirationTime;
/**
* Whether the acknowledgement is sticky
*
* Sticky acknowledgements suppress notifications until the host or service recovers
*
* @var bool
*/
protected $sticky = false;
/**
* Create a new acknowledgement of a host or service incident
*
* @param array|object|Traversable $properties
*
* @throws InvalidArgumentException If the type of the given properties is invalid
*/
public function __construct($properties = null)
{
if ($properties !== null) {
$this->setProperties($properties);
}
}
/**
* Get the author of the acknowledgement
*
* @return string
*/
public function getAuthor()
{
return $this->author;
}
/**
* Set the author of the acknowledgement
*
* @param string $author
*
* @return $this
*/
public function setAuthor($author)
{
$this->author = (string) $author;
return $this;
}
/**
* Get the comment of the acknowledgement
*
* @return string
*/
public function getComment()
{
return $this->comment;
}
/**
* Set the comment of the acknowledgement
*
* @param string $comment
*
* @return $this
*/
public function setComment($comment)
{
$this->comment = (string) $comment;
return $this;
}
/**
* Get the entry time of the acknowledgement
*
* @return int
*/
public function getEntryTime()
{
return $this->entryTime;
}
/**
* Set the entry time of the acknowledgement
*
* @param int $entryTime
*
* @return $this
*/
public function setEntryTime($entryTime)
{
$this->entryTime = (int) $entryTime;
return $this;
}
/**
* Get the expiration time of the acknowledgement
*
* @return int|null
*/
public function getExpirationTime()
{
return $this->expirationTime;
}
/**
* Set the expiration time of the acknowledgement
*
* @param int|null $expirationTime Unix timestamp
*
* @return $this
*/
public function setExpirationTime($expirationTime = null)
{
$this->expirationTime = $expirationTime !== null ? (int) $expirationTime : null;
return $this;
}
/**
* Get whether the acknowledgement is sticky
*
* @return bool
*/
public function getSticky()
{
return $this->sticky;
}
/**
* Set whether the acknowledgement is sticky
*
* @param bool $sticky
*
* @return $this
*/
public function setSticky($sticky = true)
{
$this->sticky = (bool) $sticky;
return $this;
}
/**
* Get whether the acknowledgement expires
*
* @return bool
*/
public function expires()
{
return $this->expirationTime !== null;
}
/**
* Set the properties of the acknowledgement
*
* @param array|object|Traversable $properties
*
* @return $this
* @throws InvalidArgumentException If the type of the given properties is invalid
*/
public function setProperties($properties)
{
if (! is_array($properties) && ! is_object($properties) && ! $properties instanceof Traversable) {
throw new InvalidArgumentException('Properties must be either an array or an instance of Traversable');
}
foreach ($properties as $name => $value) {
$setter = 'set' . ucfirst(String::cname($name));
if (method_exists($this, $setter)) {
$this->$setter($value);
}
}
return $this;
}
}

View File

@ -93,6 +93,7 @@ class Host extends MonitoredObject
'host_icon_image',
'host_icon_image_alt',
'host_acknowledged',
'host_acknowledgement_type',
'host_action_url',
'host_active_checks_enabled',
'host_active_checks_enabled_changed',

View File

@ -5,9 +5,9 @@ namespace Icinga\Module\Monitoring\Object;
use InvalidArgumentException;
use Icinga\Application\Config;
use Icinga\Exception\InvalidPropertyException;
use Icinga\Data\Filter\Filter;
use Icinga\Data\Filterable;
use Icinga\Exception\InvalidPropertyException;
use Icinga\Module\Monitoring\Backend\MonitoringBackend;
use Icinga\Web\UrlParams;
@ -26,6 +26,13 @@ abstract class MonitoredObject implements Filterable
*/
const TYPE_SERVICE = 'service';
/**
* Acknowledgement of the host or service if any
*
* @var object
*/
protected $acknowledgement;
/**
* Backend to fetch object information from
*
@ -34,11 +41,60 @@ abstract class MonitoredObject implements Filterable
protected $backend;
/**
* Type of the Icinga object, i.e. 'host' or 'service'
* Comments
*
* @var string
* @var array
*/
protected $type;
protected $comments;
/**
* Custom variables
*
* @var array
*/
protected $customvars;
/**
* Contact groups
*
* @var array
*/
protected $contactgroups;
/**
* Contacts
*
* @var array
*/
protected $contacts;
/**
* Downtimes
*
* @var array
*/
protected $downtimes;
/**
* Event history
*
* @var \Icinga\Module\Monitoring\DataView\EventHistory
*/
protected $eventhistory;
/**
* Filter
*
* @var Filter
*/
protected $filter;
/**
* Host groups
*
* @var array
*/
protected $hostgroups;
/**
* Prefix of the Icinga object, i.e. 'host_' or 'service_'
@ -54,27 +110,6 @@ abstract class MonitoredObject implements Filterable
*/
protected $properties;
/**
* Comments
*
* @var array
*/
protected $comments;
/**
* Downtimes
*
* @var array
*/
protected $downtimes;
/**
* Host groups
*
* @var array
*/
protected $hostgroups;
/**
* Service groups
*
@ -83,32 +118,11 @@ abstract class MonitoredObject implements Filterable
protected $servicegroups;
/**
* Contacts
* Type of the Icinga object, i.e. 'host' or 'service'
*
* @var array
* @var string
*/
protected $contacts;
/**
* Contact groups
*
* @var array
*/
protected $contactgroups;
/**
* Custom variables
*
* @var array
*/
protected $customvars;
/**
* Event history
*
* @var \Icinga\Module\Monitoring\DataView\EventHistory
*/
protected $eventhistory;
protected $type;
/**
* Stats
@ -117,13 +131,6 @@ abstract class MonitoredObject implements Filterable
*/
protected $stats;
/**
* Filter
*
* @var Filter
*/
protected $filter;
/**
* Create a monitored object, i.e. host or service
*
@ -141,68 +148,64 @@ abstract class MonitoredObject implements Filterable
*/
abstract protected function getDataView();
public function applyFilter(Filter $filter)
{
$this->getFilter()->addFilter($filter);
return $this;
}
/**
* Get the notes for this monitored object
*
* @return string The notes as a string
*/
public abstract function getNotes();
public function setFilter(Filter $filter)
{
// Left out on purpose. Interface is deprecated.
}
public function getFilter()
{
if ($this->filter === null) {
$this->filter = Filter::matchAll();
}
return $this->filter;
}
/**
* Get all note urls configured for this monitored object
*
* @return array All note urls as a string
*/
public abstract function getNotesUrls();
/**
* {@inheritdoc}
*/
public function addFilter(Filter $filter)
{
// Left out on purpose. Interface is deprecated.
}
public function where($condition, $value = null)
/**
* {@inheritdoc}
*/
public function applyFilter(Filter $filter)
{
$this->getFilter()->addFilter($filter);
return $this;
}
/**
* {@inheritdoc}
*/
public function getFilter()
{
if ($this->filter === null) {
$this->filter = Filter::matchAll();
}
return $this->filter;
}
/**
* {@inheritdoc}
*/
public function setFilter(Filter $filter)
{
// Left out on purpose. Interface is deprecated.
}
/**
* Fetch the object's properties
*
* @return bool
* {@inheritdoc}
*/
public function fetch()
public function where($condition, $value = null)
{
$this->properties = $this->getDataView()->applyFilter($this->getFilter())->getQuery()->fetchRow();
if ($this->properties === false) {
return false;
}
if (isset($this->properties->host_contacts)) {
$this->contacts = array();
foreach (preg_split('~,~', $this->properties->host_contacts) as $contact) {
$this->contacts[] = (object) array(
'contact_name' => $contact,
'contact_alias' => $contact,
'contact_email' => null,
'contact_pager' => null,
);
}
}
return true;
}
/**
* Get the type of the object
*
* @return string
*/
public function getType()
{
return $this->type;
// Left out on purpose. Interface is deprecated.
}
/**
@ -222,15 +225,44 @@ abstract class MonitoredObject implements Filterable
}
/**
* Set the object's properties
* Fetch the object's properties
*
* @param object $properties
*
* @return $this
* @return bool
*/
public function setProperties($properties)
public function fetch()
{
$this->properties = (object) $properties;
$properties = $this->getDataView()->applyFilter($this->getFilter())->getQuery()->fetchRow();
if ($properties === false) {
return false;
}
if (isset($properties->host_contacts)) {
$this->contacts = array();
foreach (preg_split('~,~', $properties->host_contacts) as $contact) {
$this->contacts[] = (object) array(
'contact_name' => $contact,
'contact_alias' => $contact,
'contact_email' => null,
'contact_pager' => null,
);
}
}
$this->properties = $properties;
return true;
}
/**
* Fetch the object's acknowledgement
*/
public function fetchAcknowledgement()
{
if ($this->comments === null) {
$this->fetchComments();
}
return $this;
}
@ -245,75 +277,108 @@ abstract class MonitoredObject implements Filterable
$this->comments = array();
return $this;
}
$comments = $this->backend->select()->from('comment', array(
'id' => 'comment_internal_id',
'timestamp' => 'comment_timestamp',
'author' => 'comment_author_name',
'comment' => 'comment_data',
'type' => 'comment_type',
))
->where('comment_type', array('comment', 'ack'))
$commentsView = $this->backend->select()->from('comment', array(
'author' => 'comment_author_name',
'comment' => 'comment_data',
'expiration' => 'comment_expiration',
'id' => 'comment_internal_id',
'timestamp' => 'comment_timestamp',
'type' => 'comment_type'
));
if ($this->type === self::TYPE_SERVICE) {
$commentsView
->where('service_host_name', $this->host_name)
->where('service_description', $this->service_description);
} else {
$commentsView->where('host_name', $this->host_name);
}
$commentsView
->where('comment_type', array('ack', 'comment'))
->where('object_type', $this->type);
if ($this->type === self::TYPE_SERVICE) {
$comments
->where('service_host_name', $this->host_name)
->where('service_description', $this->service_description);
} else {
$comments->where('host_name', $this->host_name);
$comments = $commentsView->fetchAll();
if ((bool) $this->properties->{$this->prefix . 'acknowledged'}) {
$ackCommentIdx = null;
foreach ($comments as $i => $comment) {
if ($comment->type === 'ack') {
$this->acknowledgement = new Acknowledgement(array(
'author' => $comment->author,
'comment' => $comment->comment,
'entry_time' => $comment->timestamp,
'expiration_time' => $comment->expiration,
'sticky' => (int) $this->properties->{$this->prefix . 'acknowledgement_type'} === 2
));
$ackCommentIdx = $i;
break;
}
}
if ($ackCommentIdx !== null) {
unset($comments[$ackCommentIdx]);
}
}
$this->comments = $comments->getQuery()->fetchAll();
$this->comments = $comments;
return $this;
}
/**
* Fetch the object's downtimes
* Fetch the object's contact groups
*
* @return $this
*/
public function fetchDowntimes()
public function fetchContactgroups()
{
$downtimes = $this->backend->select()->from('downtime', array(
'id' => 'downtime_internal_id',
'objecttype' => 'object_type',
'comment' => 'downtime_comment',
'author_name' => 'downtime_author_name',
'start' => 'downtime_start',
'scheduled_start' => 'downtime_scheduled_start',
'scheduled_end' => 'downtime_scheduled_end',
'end' => 'downtime_end',
'duration' => 'downtime_duration',
'is_flexible' => 'downtime_is_flexible',
'is_fixed' => 'downtime_is_fixed',
'is_in_effect' => 'downtime_is_in_effect',
'entry_time' => 'downtime_entry_time'
))
->where('object_type', $this->type)
->order('downtime_is_in_effect', 'DESC')
->order('downtime_scheduled_start', 'ASC');
if ($this->backend->is('livestatus')) {
$this->contactgroups = array();
return $this;
}
$contactsGroups = $this->backend->select()->from('contactgroup', array(
'contactgroup_name',
'contactgroup_alias'
));
if ($this->type === self::TYPE_SERVICE) {
$downtimes
$contactsGroups
->where('service_host_name', $this->host_name)
->where('service_description', $this->service_description);
} else {
$downtimes
->where('host_name', $this->host_name);
$contactsGroups->where('host_name', $this->host_name);
}
$this->downtimes = $downtimes->getQuery()->fetchAll();
$this->contactgroups = $contactsGroups->applyFilter($this->getFilter())->getQuery()->fetchAll();
return $this;
}
/**
* Fetch the object's host groups
* Fetch the object's contacts
*
* @return $this
*/
public function fetchHostgroups()
public function fetchContacts()
{
$this->hostgroups = $this->backend->select()
->from('hostgroup', array('hostgroup_name', 'hostgroup_alias'))
->where('host_name', $this->host_name)
->applyFilter($this->getFilter())
->fetchPairs();
if ($this->backend->is('livestatus')) {
$this->contacts = array();
return $this;
}
$contacts = $this->backend->select()->from('contact', array(
'contact_name',
'contact_alias',
'contact_email',
'contact_pager',
));
if ($this->type === self::TYPE_SERVICE) {
$contacts
->where('service_host_name', $this->host_name)
->where('service_description', $this->service_description);
} else {
$contacts->where('host_name', $this->host_name);
}
$this->contacts = $contacts->applyFilter($this->getFilter())->getQuery()->fetchAll();
return $this;
}
@ -372,74 +437,39 @@ abstract class MonitoredObject implements Filterable
}
/**
* Fetch the object's contacts
* Fetch the object's downtimes
*
* @return $this
*/
public function fetchContacts()
public function fetchDowntimes()
{
if ($this->backend->is('livestatus')) {
$this->contacts = array();
return $this;
}
$contacts = $this->backend->select()->from('contact', array(
'contact_name',
'contact_alias',
'contact_email',
'contact_pager',
));
$downtimes = $this->backend->select()->from('downtime', array(
'id' => 'downtime_internal_id',
'objecttype' => 'object_type',
'comment' => 'downtime_comment',
'author_name' => 'downtime_author_name',
'start' => 'downtime_start',
'scheduled_start' => 'downtime_scheduled_start',
'scheduled_end' => 'downtime_scheduled_end',
'end' => 'downtime_end',
'duration' => 'downtime_duration',
'is_flexible' => 'downtime_is_flexible',
'is_fixed' => 'downtime_is_fixed',
'is_in_effect' => 'downtime_is_in_effect',
'entry_time' => 'downtime_entry_time'
))
->where('object_type', $this->type)
->order('downtime_is_in_effect', 'DESC')
->order('downtime_scheduled_start', 'ASC');
if ($this->type === self::TYPE_SERVICE) {
$contacts
$downtimes
->where('service_host_name', $this->host_name)
->where('service_description', $this->service_description);
} else {
$contacts->where('host_name', $this->host_name);
$downtimes
->where('host_name', $this->host_name);
}
$this->contacts = $contacts->applyFilter($this->getFilter())->getQuery()->fetchAll();
return $this;
}
/**
* Fetch the object's service groups
*
* @return $this
*/
public function fetchServicegroups()
{
$this->servicegroups = $this->backend->select()
->from('servicegroup', array('servicegroup_name', 'servicegroup_alias'))
->where('host_name', $this->host_name)
->where('service_description', $this->service_description)
->applyFilter($this->getFilter())
->fetchPairs();
return $this;
}
/**
* Fetch the object's contact groups
*
* @return $this
*/
public function fetchContactgroups()
{
if ($this->backend->is('livestatus')) {
$this->contactgroups = array();
return $this;
}
$contactsGroups = $this->backend->select()->from('contactgroup', array(
'contactgroup_name',
'contactgroup_alias'
));
if ($this->type === self::TYPE_SERVICE) {
$contactsGroups
->where('service_host_name', $this->host_name)
->where('service_description', $this->service_description);
} else {
$contactsGroups->where('host_name', $this->host_name);
}
$this->contactgroups = $contactsGroups->applyFilter($this->getFilter())->getQuery()->fetchAll();
$this->downtimes = $downtimes->getQuery()->fetchAll();
return $this;
}
@ -477,6 +507,37 @@ abstract class MonitoredObject implements Filterable
return $this;
}
/**
* Fetch the object's host groups
*
* @return $this
*/
public function fetchHostgroups()
{
$this->hostgroups = $this->backend->select()
->from('hostgroup', array('hostgroup_name', 'hostgroup_alias'))
->where('host_name', $this->host_name)
->applyFilter($this->getFilter())
->fetchPairs();
return $this;
}
/**
* Fetch the object's service groups
*
* @return $this
*/
public function fetchServicegroups()
{
$this->servicegroups = $this->backend->select()
->from('servicegroup', array('servicegroup_name', 'servicegroup_alias'))
->where('host_name', $this->host_name)
->where('service_description', $this->service_description)
->applyFilter($this->getFilter())
->fetchPairs();
return $this;
}
/**
* Fetch stats
*
@ -504,6 +565,74 @@ abstract class MonitoredObject implements Filterable
return $this;
}
/**
* Get all action urls configured for this monitored object
*
* @return array All note urls as a string
*/
public function getActionUrls()
{
return $this->resolveAllStrings(
MonitoredObject::parseAttributeUrls($this->action_url)
);
}
/**
* Get the type of the object
*
* @param bool $translate
*
* @return string
*/
public function getType($translate = false)
{
if ($translate !== false) {
switch ($this->type) {
case self::TYPE_HOST:
$type = mt('montiroing', 'host');
break;
case self::TYPE_SERVICE:
$type = mt('monitoring', 'service');
break;
default:
throw new InvalidArgumentException('Invalid type ' . $this->type);
}
} else {
$type = $this->type;
}
return $type;
}
/**
* Parse the content of the action_url or notes_url attributes
*
* Find all occurences of http links, separated by whitespaces and quoted
* by single or double-ticks.
*
* @link http://docs.icinga.org/latest/de/objectdefinitions.html
*
* @param string $urlString A string containing one or more urls
* @return array Array of urls as strings
*/
public static function parseAttributeUrls($urlString)
{
if (empty($urlString)) {
return array();
}
$links = array();
if (strpos($urlString, "' ") === false) {
$links[] = $urlString;
} else {
// parse notes-url format
foreach (explode("' ", $urlString) as $url) {
$url = strpos($url, "'") === 0 ? substr($url, 1) : $url;
$url = strrpos($url, "'") === strlen($url) - 1 ? substr($url, 0, strlen($url) - 1) : $url;
$links[] = $url;
}
}
return $links;
}
/**
* Fetch all available data of the object
*
@ -513,16 +642,56 @@ abstract class MonitoredObject implements Filterable
{
$this
->fetchComments()
->fetchContacts()
->fetchContactgroups()
->fetchContacts()
->fetchCustomvars()
->fetchDowntimes();
// Call fetchHostgroups or fetchServicegroups depending on the object's type
$fetchGroups = 'fetch' . ucfirst($this->type) . 'groups';
$this->$fetchGroups();
return $this;
}
/**
* Resolve macros in all given strings in the current object context
*
* @param array $strs An array of urls as string
*
* @return array
*/
protected function resolveAllStrings(array $strs)
{
foreach ($strs as $i => $str) {
$strs[$i] = Macro::resolveMacros($str, $this);
}
return $strs;
}
/**
* Set the object's properties
*
* @param object $properties
*
* @return $this
*/
public function setProperties($properties)
{
$this->properties = (object) $properties;
return $this;
}
public function __isset($name)
{
if (property_exists($this->properties, $name)) {
return isset($this->properties->$name);
} elseif (property_exists($this, $name)) {
return isset($this->$name);
}
return false;
}
public function __get($name)
{
if (property_exists($this->properties, $name)) {
@ -543,16 +712,6 @@ abstract class MonitoredObject implements Filterable
throw new InvalidPropertyException('Can\'t access property \'%s\'. Property does not exist.', $name);
}
public function __isset($name)
{
if (property_exists($this->properties, $name)) {
return isset($this->properties->$name);
} elseif (property_exists($this, $name)) {
return isset($this->$name);
}
return false;
}
/**
* @deprecated
*/
@ -565,73 +724,4 @@ abstract class MonitoredObject implements Filterable
}
return null;
}
/**
* The notes for this monitored object
*
* @return string The notes as a string
*/
public abstract function getNotes();
/**
* Get all note urls configured for this monitored object
*
* @return array All note urls as a string
*/
public abstract function getNotesUrls();
/**
* Get all action urls configured for this monitored object
*
* @return array All note urls as a string
*/
public function getActionUrls()
{
return $this->resolveAllStrings(
MonitoredObject::parseAttributeUrls($this->action_url)
);
}
/**
* Resolve macros in all given strings in the current object context
*
* @param array $strs An array of urls as string
* @return type
*/
protected function resolveAllStrings(array $strs)
{
foreach ($strs as $i => $str) {
$strs[$i] = Macro::resolveMacros($str, $this);
}
return $strs;
}
/**
* Parse the content of the action_url or notes_url attributes
*
* Find all occurences of http links, separated by whitespaces and quoted
* by single or double-ticks.
*
* @link http://docs.icinga.org/latest/de/objectdefinitions.html
*
* @param string $urlString A string containing one or more urls
* @return array Array of urls as strings
*/
public static function parseAttributeUrls($urlString)
{
if (empty($urlString)) {
return array();
}
if (strpos($urlString, "' ") === false) {
$links[] = $urlString;
} else {
// parse notes-url format
foreach (explode("' ", $urlString) as $url) {
$url = strpos($url, "'") === 0 ? substr($url, 1) : $url;
$url = strrpos($url, "'") === strlen($url) - 1 ? substr($url, 0, strlen($url) - 1) : $url;
$links[] = $url;
}
}
return $links;
}
}

View File

@ -124,6 +124,7 @@ class Service extends MonitoredObject
'service_icon_image',
'service_icon_image_alt',
'service_acknowledged',
'service_acknowledgement_type',
'service_action_url',
'service_active_checks_enabled',
'service_active_checks_enabled_changed',

Binary file not shown.

View File

@ -111,7 +111,7 @@
<glyph glyph-name="host" unicode="&#xe866;" d="m232 136q-37 0-63 26t-26 63v393q0 37 26 63t63 26h607q37 0 63-26t27-63v-393q0-37-27-63t-63-26h-607z m-18 482v-393q0-7 6-13t12-5h607q8 0 13 5t5 13v393q0 7-5 12t-13 6h-607q-7 0-12-6t-6-12z m768-518h89v-54q0-22-26-37t-63-16h-893q-36 0-63 16t-26 37v54h982z m-402-54q9 0 9 9t-9 9h-89q-9 0-9-9t9-9h89z" horiz-adv-x="1071.4" />
<glyph glyph-name="thumbs-up" unicode="&#xe867;" d="m143 100q0 15-11 25t-25 11-25-11-11-25 11-25 25-11 25 11 11 25z m643 321q0 29-22 50t-50 22h-196q0 32 27 89t26 89q0 55-17 81t-72 27q-14-15-21-48t-17-70-33-61q-13-13-43-51-2-3-13-17t-18-22-19-24-22-25-22-19-22-16-20-5h-18v-357h18q7 0 18-1t18-4 21-6 20-7 20-7 16-5q118-41 191-41h67q107 0 107 93 0 15-2 31 16 9 26 30t10 41-10 38q29 28 29 67 0 13-5 31t-14 26q18 1 30 26t12 45z m71 1q0-50-27-91 5-18 5-38 0-43-21-81 1-12 1-24 0-56-33-99 0-78-48-123t-126-45h-72q-54 0-106 13t-121 36q-65 23-77 23h-161q-29 0-50 21t-21 50v357q0 30 21 51t50 21h153q20 13 77 86 32 42 60 72 13 14 19 47t17 71 35 60q22 21 50 21 47 0 84-18t57-57 20-104q0-51-27-107h98q58 0 101-42t42-100z" horiz-adv-x="857.1" />
<glyph glyph-name="thumbs-down" unicode="&#xe868;" d="m143 600q0 15-11 25t-25 11-25-11-11-25 11-25 25-11 25 11 11 25z m643-321q0 19-12 45t-30 26q8 10 14 27t5 30q0 39-29 67 10 18 10 38t-10 41-26 30q2 16 2 31 0 47-27 70t-76 23h-71q-73 0-191-41-3-1-16-6t-20-7-20-6-21-6-18-4-18-1h-18v-358h18q9 0 20-5t22-15 22-19 22-25 19-24 18-23 13-16q30-38 43-51 23-24 33-61t17-70 21-48q54 0 72 27t17 81q0 32-26 89t-27 89h196q28 0 50 22t22 49z m71-1q0-57-42-100t-101-42h-98q27-55 27-107 0-66-20-104-19-39-57-57t-84-18q-28 0-50 21-19 18-30 45t-14 51-10 47-17 36q-27 28-60 71-57 73-77 86h-153q-29 0-50 21t-21 51v357q0 29 21 50t50 21h161q12 0 77 22 72 25 125 37t111 13h63q78 0 126-45t48-120v-3q33-43 33-99 0-13-1-24 21-38 21-81 0-20-5-38 27-41 27-91z" horiz-adv-x="857.1" />
<glyph glyph-name="spinner" unicode="&#xe869;" d="m277 100q0-33-24-57t-57-23q-33 0-56 23t-24 57 24 57 56 23q33 0 57-23t24-57z m241-107q0-30-21-51t-51-21-50 21-21 51 21 50 50 21 51-21 21-50z m-339 357q0-37-27-63t-63-26-63 26-26 63 26 63 63 26 63-26 27-63z m580-250q0-26-18-44t-45-18-44 18-18 44 18 44 44 19 45-19 18-44z m-464 500q0-41-29-69t-70-29-69 29-29 69 29 69 69 29 70-29 29-69z m259 107q0-45-32-76t-76-31-75 31-32 76 32 76 75 31 76-31 32-76z m303-357q0-22-15-38t-38-16-38 16-16 38 16 38 38 16 38-16 15-38z m-116 250q0-18-13-32t-32-13-31 13-13 32 13 31 31 14 32-14 13-31z" horiz-adv-x="875" />
<glyph glyph-name="spinner" unicode="&#xe869;" d="m294 72q0-29-21-50t-51-21q-29 0-50 21t-21 50q0 30 21 51t50 21 51-21 21-51z m277-115q0-29-20-50t-51-21-50 21-21 50 21 51 50 21 51-21 20-51z m-392 393q0-30-21-50t-51-21-50 21-21 50 21 51 50 20 51-20 21-51z m670-278q0-29-21-50t-50-21q-30 0-51 21t-21 50 21 51 51 21 50-21 21-51z m-538 556q0-37-26-63t-63-26-63 26-26 63 26 63 63 26 63-26 26-63z m653-278q0-30-21-50t-50-21-51 21-21 50 21 51 51 20 50-20 21-51z m-357 393q0-45-31-76t-76-31-76 31-31 76 31 76 76 31 76-31 31-76z m296-115q0-52-37-89t-88-36q-52 0-89 36t-36 89q0 51 36 88t89 37q51 0 88-37t37-88z" horiz-adv-x="1000" />
<glyph glyph-name="attach" unicode="&#xe86a;" d="m783 77q0-65-44-109t-109-44q-75 0-131 55l-434 434q-63 64-63 151 0 88 62 150t150 62q88 0 152-63l338-338q5-5 5-12 0-9-17-26t-26-17q-7 0-13 5l-338 339q-44 43-101 43-59 0-100-42t-40-101q0-58 42-101l433-433q35-35 81-35 36 0 59 23t24 59q0 46-36 81l-324 324q-14 14-33 14-16 0-27-11t-11-27q0-18 14-33l229-228q6-6 6-13 0-9-18-26t-26-17q-7 0-12 5l-229 229q-35 34-35 83 0 46 32 78t77 32q49 0 83-36l325-324q55-54 55-131z" horiz-adv-x="785.7" />
<glyph glyph-name="keyboard" unicode="&#xe86b;" d="m214 198v-53q0-9-9-9h-53q-9 0-9 9v53q0 9 9 9h53q9 0 9-9z m72 143v-53q0-9-9-9h-125q-9 0-9 9v53q0 9 9 9h125q9 0 9-9z m-72 143v-54q0-9-9-9h-53q-9 0-9 9v54q0 9 9 9h53q9 0 9-9z m572-286v-53q0-9-9-9h-482q-9 0-9 9v53q0 9 9 9h482q9 0 9-9z m-357 143v-53q0-9-9-9h-54q-9 0-9 9v53q0 9 9 9h54q9 0 9-9z m-72 143v-54q0-9-9-9h-53q-9 0-9 9v54q0 9 9 9h53q9 0 9-9z m214-143v-53q0-9-8-9h-54q-9 0-9 9v53q0 9 9 9h54q8 0 8-9z m-71 143v-54q0-9-9-9h-53q-9 0-9 9v54q0 9 9 9h53q9 0 9-9z m214-143v-53q0-9-9-9h-53q-9 0-9 9v53q0 9 9 9h53q9 0 9-9z m215-143v-53q0-9-9-9h-54q-9 0-9 9v53q0 9 9 9h54q9 0 9-9z m-286 286v-54q0-9-9-9h-54q-9 0-9 9v54q0 9 9 9h54q9 0 9-9z m143 0v-54q0-9-9-9h-54q-9 0-9 9v54q0 9 9 9h54q9 0 9-9z m143 0v-196q0-9-9-9h-125q-9 0-9 9v53q0 9 9 9h62v134q0 9 9 9h54q9 0 9-9z m71-420v500h-929v-500h929z m71 500v-500q0-29-21-50t-50-21h-929q-29 0-50 21t-21 50v500q0 30 21 51t50 21h929q30 0 50-21t21-51z" horiz-adv-x="1071.4" />
<glyph glyph-name="menu" unicode="&#xe86c;" d="m857 100v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 25t25 11h785q15 0 26-11t10-25z m0 286v-72q0-14-10-25t-26-10h-785q-15 0-25 10t-11 25v72q0 14 11 25t25 10h785q15 0 26-10t10-25z m0 285v-71q0-15-10-25t-26-11h-785q-15 0-25 11t-11 25v71q0 15 11 26t25 10h785q15 0 26-10t10-26z" horiz-adv-x="857.1" />
@ -123,6 +123,11 @@
<glyph glyph-name="beaker" unicode="&#xe872;" d="m852 42q31-50 12-85t-78-36h-643q-59 0-79 36t12 85l281 442v223h-36q-14 0-25 11t-10 25 10 25 25 11h286q15 0 25-11t11-25-11-25-25-11h-36v-223z m-435 405l-151-240h397l-152 240-11 17v243h-71v-243z" horiz-adv-x="928.6" />
<glyph glyph-name="magic" unicode="&#xe873;" d="m664 526l164 163-60 60-164-164z m249 163q0-15-10-25l-717-718q-10-10-25-10t-25 10l-111 111q-10 10-10 25t10 25l718 718q10 10 25 10t25-10l110-111q10-10 10-25z m-753 106l54-16-54-17-17-55-17 55-55 17 55 16 17 55z m195-90l109-34-109-33-34-109-33 109-109 33 109 34 33 109z m519-267l55-17-55-16-17-55-17 55-54 16 54 17 17 55z m-357 357l54-16-54-17-17-55-17 55-54 17 54 16 17 55z" horiz-adv-x="928.6" />
<glyph glyph-name="spin6" unicode="&#xe874;" d="m855 9c-189-190-520-172-705 13-190 190-200 494-28 695 11 13 21 26 35 34 36 23 85 18 117-13 30-31 35-76 16-112-5-9-9-15-16-22-140-151-145-379-8-516 153-153 407-121 542 34 106 122 142 297 77 451-83 198-305 291-510 222l0 1c236 82 492-24 588-252 71-167 37-355-72-493-11-15-23-29-36-42z" horiz-adv-x="1000" />
<glyph glyph-name="down-small" unicode="&#xe875;" d="m505 346q15-15 15-37t-15-37l-245-245-245 245q-15 15-15 37t15 37 37 15 37-15l120-119 0 395q0 21 15 36t36 15 37-15 16-36l0-395 120 119q15 15 36 15t36-15z" horiz-adv-x="520" />
<glyph glyph-name="left-small" unicode="&#xe876;" d="m595 403q21 0 36-16t15-37-15-37-36-15l-395 0 119-119q15-15 15-37t-15-37-36-15q-23 0-38 15l-245 245 245 245q15 15 37 15t37-15 15-37-15-37l-119-118 395 0z" horiz-adv-x="646" />
<glyph glyph-name="right-small" unicode="&#xe877;" d="m328 595q15 15 36 15t37-15l245-245-245-245q-15-15-36-15-22 0-37 15t-15 37 15 37l120 119-395 0q-22 0-37 15t-16 37 16 37 37 16l395 0-120 118q-15 15-15 37t15 37z" horiz-adv-x="646" />
<glyph glyph-name="up-small" unicode="&#xe878;" d="m260 673l245-245q15-15 15-37t-15-37-36-15-36 15l-120 120 0-395q0-21-16-37t-37-15-36 15-15 37l0 395-120-120q-15-15-37-15t-37 15-15 37 15 37z" horiz-adv-x="520" />
<glyph glyph-name="pin" unicode="&#xe879;" d="m573 37q0-23-15-38t-37-15q-21 0-37 16l-169 169-315-236 236 315-168 169q-24 23-12 56 14 32 48 32 157 0 270 57 90 45 151 171 9 24 36 32t50-13l208-209q21-23 14-50t-32-36q-127-63-172-152-56-110-56-268z" horiz-adv-x="834" />
</font>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Binary file not shown.