Merge branch 'bugfix/make-host-customvars-accessible-from-service-objects-10304'
fixes #10304
This commit is contained in:
commit
883608b09b
|
@ -239,7 +239,9 @@ class Logger
|
||||||
array_shift($arguments),
|
array_shift($arguments),
|
||||||
array_map(
|
array_map(
|
||||||
function ($a) {
|
function ($a) {
|
||||||
return is_string($a) ? $a : ($a instanceof Exception ? $a->getMessage() : json_encode($a));
|
return is_string($a) ? $a : ($a instanceof Exception
|
||||||
|
? IcingaException::describe($a)
|
||||||
|
: json_encode($a));
|
||||||
},
|
},
|
||||||
$arguments
|
$arguments
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,6 +3,8 @@
|
||||||
|
|
||||||
namespace Icinga\Data\Filter;
|
namespace Icinga\Data\Filter;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
|
||||||
class FilterExpression extends Filter
|
class FilterExpression extends Filter
|
||||||
{
|
{
|
||||||
protected $column;
|
protected $column;
|
||||||
|
@ -97,22 +99,24 @@ class FilterExpression extends Filter
|
||||||
|
|
||||||
public function matches($row)
|
public function matches($row)
|
||||||
{
|
{
|
||||||
if (! isset($row->{$this->column})) {
|
try {
|
||||||
|
$rowValue = $row->{$this->column};
|
||||||
|
} catch (Exception $e) {
|
||||||
// TODO: REALLY? Exception?
|
// TODO: REALLY? Exception?
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_array($this->expression)) {
|
if (is_array($this->expression)) {
|
||||||
return in_array($row->{$this->column}, $this->expression);
|
return in_array($rowValue, $this->expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
$expression = (string) $this->expression;
|
$expression = (string) $this->expression;
|
||||||
if (strpos($expression, '*') === false) {
|
if (strpos($expression, '*') === false) {
|
||||||
if (is_array($row->{$this->column})) {
|
if (is_array($rowValue)) {
|
||||||
return in_array($expression, $row->{$this->column});
|
return in_array($expression, $rowValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (string) $row->{$this->column} === $expression;
|
return (string) $rowValue === $expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
$parts = array();
|
$parts = array();
|
||||||
|
@ -121,8 +125,8 @@ class FilterExpression extends Filter
|
||||||
}
|
}
|
||||||
$pattern = '/^' . implode('.*', $parts) . '$/';
|
$pattern = '/^' . implode('.*', $parts) . '$/';
|
||||||
|
|
||||||
if (is_array($row->{$this->column})) {
|
if (is_array($rowValue)) {
|
||||||
foreach ($row->{$this->column} as $candidate) {
|
foreach ($rowValue as $candidate) {
|
||||||
if (preg_match($pattern, $candidate)) {
|
if (preg_match($pattern, $candidate)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -131,7 +135,7 @@ class FilterExpression extends Filter
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (bool) preg_match($pattern, $row->{$this->column});
|
return (bool) preg_match($pattern, $rowValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function andFilter(Filter $filter)
|
public function andFilter(Filter $filter)
|
||||||
|
|
|
@ -47,6 +47,8 @@ class ActionForm extends NavigationItemForm
|
||||||
'instance_name',
|
'instance_name',
|
||||||
'service_description',
|
'service_description',
|
||||||
'servicegroup_name',
|
'servicegroup_name',
|
||||||
|
'contact_name',
|
||||||
|
'contactgroup_name',
|
||||||
function ($c) {
|
function ($c) {
|
||||||
return preg_match('/^_(?:host|service)_/', $c);
|
return preg_match('/^_(?:host|service)_/', $c);
|
||||||
}
|
}
|
||||||
|
@ -63,6 +65,8 @@ class ActionForm extends NavigationItemForm
|
||||||
'hostgroup_name',
|
'hostgroup_name',
|
||||||
'service_description',
|
'service_description',
|
||||||
'servicegroup_name',
|
'servicegroup_name',
|
||||||
|
'contact_name',
|
||||||
|
'contactgroup_name',
|
||||||
'_(host|service)_<customvar-name>'
|
'_(host|service)_<customvar-name>'
|
||||||
))
|
))
|
||||||
));
|
));
|
||||||
|
|
|
@ -3,6 +3,9 @@
|
||||||
|
|
||||||
namespace Icinga\Module\Monitoring\Object;
|
namespace Icinga\Module\Monitoring\Object;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
|
use Icinga\Application\Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expand macros in string in the context of MonitoredObjects
|
* Expand macros in string in the context of MonitoredObjects
|
||||||
*/
|
*/
|
||||||
|
@ -60,11 +63,14 @@ class Macro
|
||||||
if (isset(self::$icingaMacros[$macro]) && isset($object->{self::$icingaMacros[$macro]})) {
|
if (isset(self::$icingaMacros[$macro]) && isset($object->{self::$icingaMacros[$macro]})) {
|
||||||
return $object->{self::$icingaMacros[$macro]};
|
return $object->{self::$icingaMacros[$macro]};
|
||||||
}
|
}
|
||||||
$customVar = strtolower($macro);
|
|
||||||
if (isset($object->customvars[$customVar])) {
|
try {
|
||||||
return $object->customvars[$customVar];
|
$value = $object->$macro;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$value = null;
|
||||||
|
Logger::debug('Unable to resolve macro "%s". An error occured: %s', $macro, $e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $macro;
|
return $value !== null ? $value : $macro;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@ namespace Icinga\Module\Monitoring\Object;
|
||||||
|
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use Icinga\Application\Config;
|
use Icinga\Application\Config;
|
||||||
use Icinga\Application\Logger;
|
|
||||||
use Icinga\Data\Filter\Filter;
|
use Icinga\Data\Filter\Filter;
|
||||||
use Icinga\Data\Filterable;
|
use Icinga\Data\Filterable;
|
||||||
use Icinga\Exception\InvalidPropertyException;
|
use Icinga\Exception\InvalidPropertyException;
|
||||||
|
@ -50,12 +49,26 @@ abstract class MonitoredObject implements Filterable
|
||||||
protected $comments;
|
protected $comments;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom variables
|
* This object's obfuscated custom variables
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $customvars;
|
protected $customvars;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The host custom variables
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $hostVariables;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The service custom variables
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $serviceVariables;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contact groups
|
* Contact groups
|
||||||
*
|
*
|
||||||
|
@ -218,6 +231,8 @@ abstract class MonitoredObject implements Filterable
|
||||||
* @return bool
|
* @return bool
|
||||||
*
|
*
|
||||||
* @throws ProgrammingError In case the object cannot be found
|
* @throws ProgrammingError In case the object cannot be found
|
||||||
|
*
|
||||||
|
* @deprecated Use $filter->matches($object) instead
|
||||||
*/
|
*/
|
||||||
public function matches(Filter $filter)
|
public function matches(Filter $filter)
|
||||||
{
|
{
|
||||||
|
@ -229,38 +244,7 @@ abstract class MonitoredObject implements Filterable
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
$queryString = $filter->toQueryString();
|
return $filter->matches($this);
|
||||||
$row = clone $this->properties;
|
|
||||||
|
|
||||||
if (strpos($queryString, '_host_') !== false || strpos($queryString, '_service_') !== false) {
|
|
||||||
if ($this->customvars === null) {
|
|
||||||
$this->fetchCustomvars();
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($this->customvars as $name => $value) {
|
|
||||||
if (! is_object($value)) {
|
|
||||||
$row->{'_' . $this->getType() . '_' . $name} = $value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strpos($queryString, 'hostgroup_name') !== false) {
|
|
||||||
if ($this->hostgroups === null) {
|
|
||||||
$this->fetchHostgroups();
|
|
||||||
}
|
|
||||||
|
|
||||||
$row->hostgroup_name = array_keys($this->hostgroups);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (strpos($queryString, 'servicegroup_name') !== false) {
|
|
||||||
if ($this->servicegroups === null) {
|
|
||||||
$this->fetchServicegroups();
|
|
||||||
}
|
|
||||||
|
|
||||||
$row->servicegroup_name = array_keys($this->servicegroups);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $filter->matches($row);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -438,9 +422,9 @@ abstract class MonitoredObject implements Filterable
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch the object's custom variables
|
* Fetch this object's obfuscated custom variables
|
||||||
*
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function fetchCustomvars()
|
public function fetchCustomvars()
|
||||||
{
|
{
|
||||||
|
@ -463,28 +447,81 @@ abstract class MonitoredObject implements Filterable
|
||||||
$blacklistPattern = '/^(' . implode('|', $blacklist) . ')$/i';
|
$blacklistPattern = '/^(' . implode('|', $blacklist) . ')$/i';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->type === self::TYPE_SERVICE) {
|
||||||
|
$this->fetchServiceVariables();
|
||||||
|
$customvars = $this->serviceVariables;
|
||||||
|
} else {
|
||||||
|
$this->fetchHostVariables();
|
||||||
|
$customvars = $this->hostVariables;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->customvars = array();
|
||||||
|
foreach ($customvars as $name => $value) {
|
||||||
|
if ($blacklistPattern && preg_match($blacklistPattern, $name)) {
|
||||||
|
$this->customvars[$name] = '***';
|
||||||
|
} else {
|
||||||
|
$this->customvars[$name] = $value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch the host custom variables related to this object
|
||||||
|
*
|
||||||
|
* @return $this
|
||||||
|
*/
|
||||||
|
public function fetchHostVariables()
|
||||||
|
{
|
||||||
$query = $this->backend->select()->from('customvar', array(
|
$query = $this->backend->select()->from('customvar', array(
|
||||||
'varname',
|
'varname',
|
||||||
'varvalue',
|
'varvalue',
|
||||||
'is_json'
|
'is_json'
|
||||||
))
|
))
|
||||||
->where('object_type', $this->type)
|
->where('object_type', static::TYPE_HOST)
|
||||||
->where('host_name', $this->host_name);
|
->where('host_name', $this->host_name);
|
||||||
if ($this->type === self::TYPE_SERVICE) {
|
|
||||||
$query->where('service_description', $this->service_description);
|
$this->hostVariables = array();
|
||||||
|
foreach ($query as $row) {
|
||||||
|
if ($row->is_json) {
|
||||||
|
$this->hostVariables[strtolower($row->varname)] = json_decode($row->varvalue);
|
||||||
|
} else {
|
||||||
|
$this->hostVariables[strtolower($row->varname)] = $row->varvalue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->customvars = array();
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
$customvars = $query->getQuery()->fetchAll();
|
/**
|
||||||
foreach ($customvars as $cv) {
|
* Fetch the service custom variables related to this object
|
||||||
$name = strtolower($cv->varname);
|
*
|
||||||
if ($blacklistPattern && preg_match($blacklistPattern, $cv->varname)) {
|
* @return $this
|
||||||
$this->customvars[$name] = '***';
|
*
|
||||||
} elseif ($cv->is_json) {
|
* @throws ProgrammingError In case this object is not a service
|
||||||
$this->customvars[$name] = json_decode($cv->varvalue);
|
*/
|
||||||
|
public function fetchServiceVariables()
|
||||||
|
{
|
||||||
|
if ($this->type !== static::TYPE_SERVICE) {
|
||||||
|
throw new ProgrammingError('Cannot fetch service custom variables for non-service objects');
|
||||||
|
}
|
||||||
|
|
||||||
|
$query = $this->backend->select()->from('customvar', array(
|
||||||
|
'varname',
|
||||||
|
'varvalue',
|
||||||
|
'is_json'
|
||||||
|
))
|
||||||
|
->where('object_type', static::TYPE_SERVICE)
|
||||||
|
->where('host_name', $this->host_name)
|
||||||
|
->where('service_description', $this->service_description);
|
||||||
|
|
||||||
|
$this->serviceVariables = array();
|
||||||
|
foreach ($query as $row) {
|
||||||
|
if ($row->is_json) {
|
||||||
|
$this->serviceVariables[strtolower($row->varname)] = json_decode($row->varvalue);
|
||||||
} else {
|
} else {
|
||||||
$this->customvars[$name] = $cv->varvalue;
|
$this->serviceVariables[strtolower($row->varname)] = $row->varvalue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -754,19 +791,86 @@ abstract class MonitoredObject implements Filterable
|
||||||
{
|
{
|
||||||
if (property_exists($this->properties, $name)) {
|
if (property_exists($this->properties, $name)) {
|
||||||
return $this->properties->$name;
|
return $this->properties->$name;
|
||||||
} elseif (property_exists($this, $name) && $this->$name !== null) {
|
|
||||||
return $this->$name;
|
|
||||||
} elseif (property_exists($this, $name)) {
|
} elseif (property_exists($this, $name)) {
|
||||||
$fetchMethod = 'fetch' . ucfirst($name);
|
if ($this->$name === null) {
|
||||||
$this->$fetchMethod();
|
$fetchMethod = 'fetch' . ucfirst($name);
|
||||||
|
$this->$fetchMethod();
|
||||||
|
}
|
||||||
|
|
||||||
return $this->$name;
|
return $this->$name;
|
||||||
}
|
} elseif (preg_match('/^_(host|service)_(.+)/i', $name, $matches)) {
|
||||||
if (substr($name, 0, strlen($this->prefix)) !== $this->prefix) {
|
if (strtolower($matches[1]) === static::TYPE_HOST) {
|
||||||
$prefixedName = $this->prefix . strtolower($name);
|
if ($this->hostVariables === null) {
|
||||||
|
$this->fetchHostVariables();
|
||||||
|
}
|
||||||
|
|
||||||
|
$customvars = $this->hostVariables;
|
||||||
|
} else {
|
||||||
|
if ($this->serviceVariables === null) {
|
||||||
|
$this->fetchServiceVariables();
|
||||||
|
}
|
||||||
|
|
||||||
|
$customvars = $this->serviceVariables;
|
||||||
|
}
|
||||||
|
|
||||||
|
$variableName = strtolower($matches[2]);
|
||||||
|
if (isset($customvars[$variableName])) {
|
||||||
|
return $customvars[$variableName];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null; // Unknown custom variables MUST NOT throw an error
|
||||||
|
} elseif (in_array($name, array('contact_name', 'contactgroup_name', 'hostgroup_name', 'servicegroup_name'))) {
|
||||||
|
if ($name === 'contact_name') {
|
||||||
|
if ($this->contacts === null) {
|
||||||
|
$this->fetchContacts();
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_map(function ($el) { return $el->contact_name; }, $this->contacts);
|
||||||
|
} elseif ($name === 'contactgroup_name') {
|
||||||
|
if ($this->contactgroups === null) {
|
||||||
|
$this->fetchContactgroups();
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_map(function ($el) { return $el->contactgroup_name; }, $this->contactgroups);
|
||||||
|
} elseif ($name === 'hostgroup_name') {
|
||||||
|
if ($this->hostgroups === null) {
|
||||||
|
$this->fetchHostgroups();
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_keys($this->hostgroups);
|
||||||
|
} else { // $name === 'servicegroup_name'
|
||||||
|
if ($this->servicegroups === null) {
|
||||||
|
$this->fetchServicegroups();
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_keys($this->servicegroups);
|
||||||
|
}
|
||||||
|
} elseif (strpos($name, $this->prefix) !== 0) {
|
||||||
|
$propertyName = strtolower($name);
|
||||||
|
$prefixedName = $this->prefix . $propertyName;
|
||||||
if (property_exists($this->properties, $prefixedName)) {
|
if (property_exists($this->properties, $prefixedName)) {
|
||||||
return $this->properties->$prefixedName;
|
return $this->properties->$prefixedName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->type === static::TYPE_HOST) {
|
||||||
|
if ($this->hostVariables === null) {
|
||||||
|
$this->fetchHostVariables();
|
||||||
|
}
|
||||||
|
|
||||||
|
$customvars = $this->hostVariables;
|
||||||
|
} else { // $this->type === static::TYPE_SERVICE
|
||||||
|
if ($this->serviceVariables === null) {
|
||||||
|
$this->fetchServiceVariables();
|
||||||
|
}
|
||||||
|
|
||||||
|
$customvars = $this->serviceVariables;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($customvars[$propertyName])) {
|
||||||
|
return $customvars[$propertyName];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new InvalidPropertyException('Can\'t access property \'%s\'. Property does not exist.', $name);
|
throw new InvalidPropertyException('Can\'t access property \'%s\'. Property does not exist.', $name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,7 +101,7 @@ class Action extends NavigationItem
|
||||||
{
|
{
|
||||||
if ($this->render === null) {
|
if ($this->render === null) {
|
||||||
$filter = $this->getFilter();
|
$filter = $this->getFilter();
|
||||||
$this->render = $filter ? $this->getObject()->matches(Filter::fromQueryString($filter)) : true;
|
$this->render = $filter ? Filter::fromQueryString($filter)->matches($this->getObject()) : true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->render;
|
return $this->render;
|
||||||
|
|
Loading…
Reference in New Issue