diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-14 13:15:40 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-14 13:15:40 +0000 |
commit | b7fd908d538ed19fe41f03c0a3f93351d8da64e9 (patch) | |
tree | 46e14f318948cd4f5d7e874f83e7dfcc5d42fc64 /library/Businessprocess/State | |
parent | Initial commit. (diff) | |
download | icingaweb2-module-businessprocess-upstream.tar.xz icingaweb2-module-businessprocess-upstream.zip |
Adding upstream version 2.5.0.upstream/2.5.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'library/Businessprocess/State')
-rw-r--r-- | library/Businessprocess/State/IcingaDbState.php | 191 | ||||
-rw-r--r-- | library/Businessprocess/State/MonitoringState.php | 151 |
2 files changed, 342 insertions, 0 deletions
diff --git a/library/Businessprocess/State/IcingaDbState.php b/library/Businessprocess/State/IcingaDbState.php new file mode 100644 index 0000000..1a66900 --- /dev/null +++ b/library/Businessprocess/State/IcingaDbState.php @@ -0,0 +1,191 @@ +<?php + +namespace Icinga\Module\Businessprocess\State; + +use Exception; +use Icinga\Application\Benchmark; +use Icinga\Module\Businessprocess\BpConfig; +use Icinga\Module\Businessprocess\IcingaDbObject; +use Icinga\Module\Businessprocess\ServiceNode; +use Icinga\Module\Icingadb\Common\IcingaRedis; +use Icinga\Module\Icingadb\Model\Host; +use Icinga\Module\Icingadb\Model\Service; +use ipl\Sql\Connection as IcingaDbConnection; +use ipl\Stdlib\Filter; + +class IcingaDbState +{ + /** @var BpConfig */ + protected $config; + + /** @var IcingaDbConnection */ + protected $backend; + + public function __construct(BpConfig $config) + { + $this->config = $config; + $this->backend = IcingaDbObject::fetchDb(); + } + + public static function apply(BpConfig $config) + { + $self = new static($config); + $self->retrieveStatesFromBackend(); + + return $config; + } + + public function retrieveStatesFromBackend() + { + $config = $this->config; + + try { + $this->reallyRetrieveStatesFromBackend(); + } catch (Exception $e) { + $config->addError( + $config->translate('Could not retrieve process state: %s'), + $e->getMessage() + ); + } + } + + public function reallyRetrieveStatesFromBackend() + { + $config = $this->config; + + $involvedHostNames = $config->listInvolvedHostNames(); + if (empty($involvedHostNames)) { + return $this; + } + + Benchmark::measure(sprintf( + 'Retrieving states for business process %s using Icinga DB backend', + $config->getName() + )); + + $hosts = Host::on($this->backend)->columns([ + 'id' => 'host.id', + 'name' => 'host.name', + 'display_name' => 'host.display_name', + 'hard_state' => 'host.state.hard_state', + 'soft_state' => 'host.state.soft_state', + 'last_state_change' => 'host.state.last_state_change', + 'in_downtime' => 'host.state.in_downtime', + 'is_acknowledged' => 'host.state.is_acknowledged' + ])->filter(Filter::equal('host.name', $involvedHostNames)); + + $services = Service::on($this->backend)->columns([ + 'id' => 'service.id', + 'name' => 'service.name', + 'display_name' => 'service.display_name', + 'host_name' => 'host.name', + 'host_display_name' => 'host.display_name', + 'hard_state' => 'service.state.hard_state', + 'soft_state' => 'service.state.soft_state', + 'last_state_change' => 'service.state.last_state_change', + 'in_downtime' => 'service.state.in_downtime', + 'is_acknowledged' => 'service.state.is_acknowledged' + ])->filter(Filter::equal('host.name', $involvedHostNames)); + + // All of this is ipl-sql now, for performance reasons + foreach ($config->listInvolvedConfigs() as $cfg) { + $serviceIds = []; + $serviceResults = []; + foreach ($this->backend->yieldAll($services->assembleSelect()) as $row) { + $row->hex_id = bin2hex(is_resource($row->id) ? stream_get_contents($row->id) : $row->id); + $serviceIds[] = $row->hex_id; + $serviceResults[] = $row; + } + + $redisServiceResults = iterator_to_array(IcingaRedis::fetchServiceState($serviceIds, [ + 'hard_state', + 'soft_state', + 'last_state_change', + 'in_downtime', + 'is_acknowledged' + ])); + foreach ($serviceResults as $row) { + if (isset($redisServiceResults[$row->hex_id])) { + $row = (object) array_merge( + (array) $row, + $redisServiceResults[$row->hex_id] + ); + } + + $this->handleDbRow($row, $cfg, 'service'); + } + + Benchmark::measure('Retrieved states for ' . count($serviceIds) . ' services in ' . $config->getName()); + + $hostIds = []; + $hostResults = []; + foreach ($this->backend->yieldAll($hosts->assembleSelect()) as $row) { + $row->hex_id = bin2hex(is_resource($row->id) ? stream_get_contents($row->id) : $row->id); + $hostIds[] = $row->hex_id; + $hostResults[] = $row; + } + + $redisHostResults = iterator_to_array(IcingaRedis::fetchHostState($hostIds, [ + 'hard_state', + 'soft_state', + 'last_state_change', + 'in_downtime', + 'is_acknowledged' + ])); + foreach ($hostResults as $row) { + if (isset($redisHostResults[$row->hex_id])) { + $row = (object) array_merge( + (array) $row, + $redisHostResults[$row->hex_id] + ); + } + + $this->handleDbRow($row, $cfg, 'host'); + } + + Benchmark::measure('Retrieved states for ' . count($hostIds) . ' hosts in ' . $config->getName()); + } + + Benchmark::measure('Got states for business process ' . $config->getName()); + + return $this; + } + + protected function handleDbRow($row, BpConfig $config, $type) + { + if ($type === 'service') { + $key = BpConfig::joinNodeName($row->host_name, $row->name); + } else { + $key = BpConfig::joinNodeName($row->name, 'Hoststatus'); + } + + // We fetch more states than we need, so skip unknown ones + if (! $config->hasNode($key)) { + return; + } + + $node = $config->getNode($key); + + if ($this->config->usesHardStates()) { + if ($row->hard_state !== null) { + $node->setState($row->hard_state)->setMissing(false); + } + } else { + if ($row->soft_state !== null) { + $node->setState($row->soft_state)->setMissing(false); + } + } + + if ($row->last_state_change !== null) { + $node->setLastStateChange($row->last_state_change / 1000.0); + } + + $node->setDowntime($row->in_downtime === 'y'); + $node->setAck($row->is_acknowledged === 'y'); + $node->setAlias($row->display_name); + + if ($node instanceof ServiceNode) { + $node->setHostAlias($row->host_display_name); + } + } +} diff --git a/library/Businessprocess/State/MonitoringState.php b/library/Businessprocess/State/MonitoringState.php new file mode 100644 index 0000000..b6a2391 --- /dev/null +++ b/library/Businessprocess/State/MonitoringState.php @@ -0,0 +1,151 @@ +<?php + +namespace Icinga\Module\Businessprocess\State; + +use Exception; +use Icinga\Application\Benchmark; +use Icinga\Data\Filter\Filter; +use Icinga\Module\Businessprocess\BpConfig; +use Icinga\Module\Businessprocess\ServiceNode; +use Icinga\Module\Monitoring\Backend\MonitoringBackend; + +class MonitoringState +{ + /** @var BpConfig */ + protected $config; + + /** @var MonitoringBackend */ + protected $backend; + + private function __construct(BpConfig $config) + { + $this->config = $config; + $this->backend = $config->getBackend(); + } + + public static function apply(BpConfig $config) + { + $self = new static($config); + $self->retrieveStatesFromBackend(); + return $config; + } + + public function retrieveStatesFromBackend() + { + $config = $this->config; + + try { + $this->reallyRetrieveStatesFromBackend(); + } catch (Exception $e) { + $config->addError( + $config->translate('Could not retrieve process state: %s'), + $e->getMessage() + ); + } + } + + public function reallyRetrieveStatesFromBackend() + { + $config = $this->config; + + Benchmark::measure('Retrieving states for business process ' . $config->getName()); + $backend = $this->backend; + + if ($config->usesHardStates()) { + $hostStateColumn = 'host_hard_state'; + $hostStateChangeColumn = 'host_last_hard_state_change'; + $serviceStateColumn = 'service_hard_state'; + $serviceStateChangeColumn = 'service_last_hard_state_change'; + } else { + $hostStateColumn = 'host_state'; + $hostStateChangeColumn = 'host_last_state_change'; + $serviceStateColumn = 'service_state'; + $serviceStateChangeColumn = 'service_last_state_change'; + } + + $hosts = $config->listInvolvedHostNames(); + if (empty($hosts)) { + return $this; + } + + $hostFilter = Filter::expression('host_name', '=', $hosts); + + $hostStatus = $backend->select()->from('hostStatus', array( + 'hostname' => 'host_name', + 'last_state_change' => $hostStateChangeColumn, + 'in_downtime' => 'host_in_downtime', + 'ack' => 'host_acknowledged', + 'state' => $hostStateColumn, + 'display_name' => 'host_display_name' + ))->applyFilter($hostFilter)->getQuery()->fetchAll(); + + Benchmark::measure('Retrieved states for ' . count($hostStatus) . ' hosts in ' . $config->getName()); + + // NOTE: we intentionally filter by host_name ONLY + // Tests with host IN ... AND service IN shows longer query times + // while retrieving 1635 (in 5ms) vs. 1388 (in ~430ms) services + $serviceStatus = $backend->select()->from('serviceStatus', array( + 'hostname' => 'host_name', + 'service' => 'service_description', + 'last_state_change' => $serviceStateChangeColumn, + 'in_downtime' => 'service_in_downtime', + 'ack' => 'service_acknowledged', + 'state' => $serviceStateColumn, + 'display_name' => 'service_display_name', + 'host_display_name' => 'host_display_name' + ))->applyFilter($hostFilter)->getQuery()->fetchAll(); + + Benchmark::measure('Retrieved states for ' . count($serviceStatus) . ' services in ' . $config->getName()); + + $configs = $config->listInvolvedConfigs(); + foreach ($configs as $cfg) { + foreach ($serviceStatus as $row) { + $this->handleDbRow($row, $cfg); + } + foreach ($hostStatus as $row) { + $this->handleDbRow($row, $cfg); + } + } + + // TODO: Union, single query? + Benchmark::measure('Got states for business process ' . $config->getName()); + + return $this; + } + + protected function handleDbRow($row, BpConfig $config) + { + $key = BpConfig::joinNodeName( + $row->hostname, + property_exists($row, 'service') + ? $row->service + : 'Hoststatus' + ); + + // We fetch more states than we need, so skip unknown ones + if (! $config->hasNode($key)) { + return; + } + + $node = $config->getNode($key); + + if ($row->state !== null) { + $node->setState($row->state)->setMissing(false); + } + if ($row->last_state_change !== null) { + $node->setLastStateChange($row->last_state_change); + } + if ((int) $row->in_downtime === 1) { + $node->setDowntime(true); + } + if ((int) $row->ack === 1) { + $node->setAck(true); + } + + $node->setAlias($row->display_name); + + if ($node instanceof ServiceNode) { + $node->setHostAlias($row->host_display_name); + } + } +} |