HostApplyMatches: resolve services and -sets...

...for Icinga v1.x

refs #13049
This commit is contained in:
Thomas Gelf 2016-11-04 19:56:56 +01:00
parent 87fe623d11
commit ba7d350a8c
3 changed files with 209 additions and 30 deletions

View File

@ -0,0 +1,109 @@
<?php
namespace Icinga\Module\Director\Objects;
use Icinga\Application\Benchmark;
use Icinga\Data\Filter\Filter;
use Icinga\Data\Filter\FilterExpression;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Db\Cache\PrefetchCache;
class HostApplyMatches
{
protected static $flatObjects;
protected static $columnMap = array(
'name' => 'object_name'
);
/**
* @param Filter $filter
* @param Db $db
*
* @return array
*/
public static function forFilter(Filter $filter, Db $db)
{
$result = array();
Benchmark::measure(sprintf('Starting Filter %s', $filter));
$filter = clone($filter);
static::fixFilterColumns($filter);
foreach (static::flatObjects($db) as $object) {
if ($filter->matches($object)) {
$name = $object->object_name;
$result[] = $name;
}
}
Benchmark::measure(sprintf('Got %d results for %s', count($result), $filter));
return array_values($result);
}
protected static function flatObjects(Db $db)
{
if (self::$flatObjects === null) {
self::$flatObjects = static::fetchFlatObjects($db);
}
return self::$flatObjects;
}
protected static function fetchFlatObjects(Db $db)
{
Benchmark::measure('HostApplyMatches: prefetching');
PrefetchCache::initialize($db);
$all = IcingaHost::prefetchAll($db);
IcingaZone::prefetchAll($db);
IcingaCommand::prefetchAll($db);
Benchmark::measure('HostApplyMatches: preparing flat objects');
$objects = array();
foreach ($all as $host) {
if ($host->isTemplate()) {
continue;
}
$object = $host->toPlainObject(true);
static::flattenVars($object);
$objects[$host->getObjectName()] = $object;
}
Benchmark::measure('HostApplyMatches: cache ready');
return $objects;
}
protected static function fixFilterColumns(Filter $filter)
{
if ($filter->isExpression()) {
/** @var FilterExpression $filter */
$col = $filter->getColumn();
if (substr($col, 0, 5) === 'host.') {
$filter->setColumn($col = substr($col, 5));
}
if (array_key_exists($col, self::$columnMap)) {
$filter->setColumn(self::$columnMap[$col]);
}
$filter->setExpression(json_decode($filter->getExpression()));
} else {
foreach ($filter->filters() as $sub) {
static::fixFilterColumns($sub);
}
}
}
protected static function flattenVars(& $object, $key = 'vars')
{
if (property_exists($object, 'vars')) {
foreach ($object->vars as $k => $v) {
if (is_object($v)) {
static::flattenVars($v, $k);
}
$object->{$key . '.' . $k} = $v;
}
unset($object->vars);
}
}
protected function __construct()
{
}
}

View File

@ -2,6 +2,7 @@
namespace Icinga\Module\Director\Objects;
use Icinga\Data\Filter\Filter;
use Icinga\Exception\ProgrammingError;
use Icinga\Module\Director\Db;
use Icinga\Module\Director\Data\PropertiesFilter;
@ -174,8 +175,47 @@ class IcingaService extends IcingaObject
return $this->renderRelationProperty('host', $this->host_id, 'host_name');
}
public function toLegacyConfigString()
{
if ($this->get('assign_filter')) {
return $this->renderLegacyResolvedAssignFilter();
}
$str = parent::toLegacyConfigString();
if (! $this->isDisabled() && $this->host_id && $this->getRelated('host')->isDisabled()) {
return
"# --- This services host has been disabled ---\n"
. preg_replace('~^~m', '# ', trim($str))
. "\n\n";
} else {
return $str;
}
}
protected function renderLegacyResolvedAssignFilter()
{
$str = '';
$hosts = HostApplyMatches::forFilter(
Filter::fromQueryString($this->get('assign_filter')),
$this->getConnection()
);
$this->object_type = 'object';
$this->assign_filter = null;
foreach ($hosts as $hostname) {
$this->host = $hostname;
$str .= $this->toLegacyConfigString();
}
return $str;
}
public function toConfigString()
{
if ($this->get('service_set_id')) {
return '';
}
$str = parent::toConfigString();
if (! $this->isDisabled() && $this->host_id && $this->getRelated('host')->isDisabled()) {
@ -282,6 +322,11 @@ class IcingaService extends IcingaObject
return '';
}
public function renderService_set()
{
return '';
}
public function renderUse_var_overrides()
{
return '';

View File

@ -2,6 +2,7 @@
namespace Icinga\Module\Director\Objects;
use Icinga\Data\Filter\Filter;
use Icinga\Exception\ProgrammingError;
use Icinga\Module\Director\IcingaConfig\IcingaConfig;
use Icinga\Module\Director\IcingaConfig\IcingaConfigHelper as c;
@ -45,11 +46,11 @@ class IcingaServiceSet extends IcingaObject
}
/**
* @return IcingaService
* @return IcingaService[]
*/
public function getServiceObjects()
{
if ($this->host_id) {
if ($this->get('host_id')) {
$imports = $this->imports()->getObjects();
if (empty($imports)) {
return array();
@ -62,7 +63,7 @@ class IcingaServiceSet extends IcingaObject
protected function getServiceObjectsForSet(IcingaServiceSet $set)
{
if ($set->id === null) {
if ($set->get('id') === null) {
return array();
}
@ -70,7 +71,7 @@ class IcingaServiceSet extends IcingaObject
$db = $this->getDb();
$ids = $db->fetchCol(
$db->select()->from('icinga_service', 'id')
->where('service_set_id = ?', $set->id)
->where('service_set_id = ?', $set->get('id'))
);
$services = array();
@ -80,7 +81,7 @@ class IcingaServiceSet extends IcingaObject
'object_type' => 'template'
), $connection);
$services[$service->object_name] = $service;
$services[$service->getObjectName()] = $service;
}
return $services;
@ -88,12 +89,13 @@ class IcingaServiceSet extends IcingaObject
public function renderToConfig(IcingaConfig $config)
{
if ($this->assign_filter === null && $this->isTemplate()) {
if ($this->get('assign_filter') === null && $this->isTemplate()) {
return;
}
if ($config->isLegacy()) {
return $this->renderToLegacyConfig($config);
$this->renderToLegacyConfig($config);
return;
}
$file = $this->getConfigFileWithHeader($config);
@ -103,19 +105,18 @@ class IcingaServiceSet extends IcingaObject
// eventually clone them beforehand to not get into trouble with caches
// figure out whether we might need a zone property
foreach ($this->getServiceObjects() as $service) {
// TODO: make them REAL applies
if ($this->assign_filter) {
$service->object_type = 'apply';
$service->assign_filter = $this->assign_filter;
if ($filter = $this->get('assign_filter')) {
$service->set('object_type', 'apply');
$service->set('assign_filter', $filter);
} elseif ($hostId = $this->get('host_id')) {
$service->set('object_type', 'object');
$service->host_id = $this->host_id;
} else {
$service->object_type = $this->object_type;
if ($this->isApplyRule()) {
$service->assign_filter = $this->assign_filter;
}
// Service set template without assign filter or host
continue;
}
$service->vars = $this->vars;
$service->host_id = $this->host_id;
$this->copyVarsToService($service);
$file->addObject($service);
}
}
@ -141,20 +142,26 @@ class IcingaServiceSet extends IcingaObject
return sprintf($comment, $this->object_name);
}
public function renderToLegacyConfig(IcingaConfig $config)
protected function copyVarsToService(IcingaService $service)
{
if ($this->isTemplate()) {
return;
$serviceVars = $service->vars();
foreach ($this->vars() as $k => $var) {
$serviceVars->$k = $var;
}
if ($this->isApplyRule()) {
// Not yet
return $this;
}
public function renderToLegacyConfig(IcingaConfig $config)
{
if ($this->assign_filter === null && $this->isTemplate()) {
return;
}
// evaluate my assign rules once, get related hosts
// Loop over all services belonging to this set
// generate every service with host_name host1,host2...
// generate every service with host_name host1,host2... -> not yet. And Zones?
$file = $config->configFile(
// TODO: zones.d?
@ -162,21 +169,39 @@ class IcingaServiceSet extends IcingaObject
);
$file->prepend($this->getConfigHeaderComment($config));
$conn = $this->getConnection();
foreach ($this->getServiceObjects() as $service) {
$service->object_type = 'object';
$service->host_id = $this->host_id;
$service->vars = $this->vars;
$file->addLegacyObject($service);
// Delegating this to the service would look, but this way it's faster
if ($filter = $this->get('assign_filter')) {
$filter = Filter::fromQueryString($filter);
$hosts = HostApplyMatches::forFilter($filter, $conn);
foreach ($this->getServiceObjects() as $service) {
$service->set('object_type', 'object');
$this->copyVarsToService($service);
foreach ($hosts as $hostname) {
$service->host = $hostname;
$file->addLegacyObject($service);
}
}
} else {
foreach ($this->getServiceObjects() as $service) {
$service->set('object_type', 'object');
$service->set('host_id', $this->get('host_id'));
foreach ($this->vars() as $k => $var) {
$service->$k = $var;
}
$file->addLegacyObject($service);
}
}
}
public function getRenderingZone(IcingaConfig $config = null)
{
if ($this->host_id === null) {
if ($this->get('host_id') === null) {
return $this->connection->getDefaultGlobalZoneName();
} else {
$host = $this->getRelatedObject('host', $this->host_id);
$host = $this->getRelatedObject('host', $this->get('host_id'));
return $host->getRenderingZone($config);
}
return $zone;