diff --git a/application/clicommands/ProcessCommand.php b/application/clicommands/ProcessCommand.php index a6d1dac..3b470b8 100644 --- a/application/clicommands/ProcessCommand.php +++ b/application/clicommands/ProcessCommand.php @@ -4,11 +4,14 @@ namespace Icinga\Module\Businessprocess\Clicommands; use Exception; use Icinga\Application\Logger; +use Icinga\Application\Modules\Module; use Icinga\Cli\Command; use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\BpNode; use Icinga\Module\Businessprocess\HostNode; use Icinga\Module\Businessprocess\Node; +use Icinga\Module\Businessprocess\ProvidedHook\Icingadb\IcingadbSupport; +use Icinga\Module\Businessprocess\State\IcingaDbState; use Icinga\Module\Businessprocess\State\MonitoringState; use Icinga\Module\Businessprocess\Storage\LegacyStorage; @@ -132,7 +135,14 @@ class ProcessCommand extends Command /** @var BpNode $node */ try { $node = $bp->getNode($nodeName); - MonitoringState::apply($bp); + if (Module::exists('icingadb') + && (! $bp->hasBackendName() && IcingadbSupport::useIcingaDbAsBackend()) + ) { + IcingaDbState::apply($bp); + } else { + MonitoringState::apply($bp); + } + if ($bp->hasErrors()) { Logger::error("Checking Business Process '%s' failed: %s\n", $name, $bp->getErrors()); diff --git a/application/controllers/HostController.php b/application/controllers/HostController.php index 134ab5b..6b306b3 100644 --- a/application/controllers/HostController.php +++ b/application/controllers/HostController.php @@ -2,23 +2,63 @@ namespace Icinga\Module\Businessprocess\Controllers; +use Icinga\Application\Modules\Module; +use Icinga\Module\Businessprocess\IcingaDbObject; +use Icinga\Module\Businessprocess\ProvidedHook\Icingadb\IcingadbSupport; +use Icinga\Module\Icingadb\Model\Host; use Icinga\Module\Monitoring\Controller; use Icinga\Web\Url; +use ipl\Stdlib\Filter; class HostController extends Controller { + /** + * True if business process prefers to use icingadb as backend for it's nodes + * + * @var bool + */ + protected $isIcingadbPreferred; + + protected function moduleInit() + { + $this->isIcingadbPreferred = Module::exists('icingadb') + && ! $this->params->has('backend') + && IcingadbSupport::useIcingaDbAsBackend(); + + if (! $this->isIcingadbPreferred) { + parent::moduleInit(); + } + } + public function showAction() { - $host = $this->params->getRequired('host'); + if ($this->isIcingadbPreferred) { + $hostName = $this->params->shift('host'); - $query = $this->backend->select() - ->from('hoststatus', array('host_name')) - ->where('host_name', $host); + $query = Host::on(IcingaDbObject::fetchDb()); + IcingaDbObject::applyIcingaDbRestrictions($query); - if ($this->applyRestriction('monitoring/filter/objects', $query)->fetchRow() !== false) { - $this->redirectNow(Url::fromPath('monitoring/host/show')->setParams($this->params)); + $query->filter(Filter::equal('host.name', $hostName)); + + $host = $query->first(); + + $this->params->add('name', $hostName); + + if ($host !== false) { + $this->redirectNow(Url::fromPath('icingadb/host')->setParams($this->params)); + } + } else { + $hostName = $this->params->get('host'); + + $query = $this->backend->select() + ->from('hoststatus', array('host_name')) + ->where('host_name', $hostName); + + if ($this->applyRestriction('monitoring/filter/objects', $query)->fetchRow() !== false) { + $this->redirectNow(Url::fromPath('monitoring/host/show')->setParams($this->params)); + } } - $this->view->host = $host; + $this->view->host = $hostName; } } diff --git a/application/controllers/NodeController.php b/application/controllers/NodeController.php index dc6c5fc..8addc07 100644 --- a/application/controllers/NodeController.php +++ b/application/controllers/NodeController.php @@ -2,9 +2,12 @@ namespace Icinga\Module\Businessprocess\Controllers; +use Icinga\Application\Modules\Module; +use Icinga\Module\Businessprocess\ProvidedHook\Icingadb\IcingadbSupport; use Icinga\Module\Businessprocess\Renderer\Breadcrumb; use Icinga\Module\Businessprocess\Renderer\TileRenderer; use Icinga\Module\Businessprocess\Simulation; +use Icinga\Module\Businessprocess\State\IcingaDbState; use Icinga\Module\Businessprocess\State\MonitoringState; use Icinga\Module\Businessprocess\Web\Controller; use Icinga\Module\Businessprocess\Web\Url; @@ -82,7 +85,13 @@ class NodeController extends Controller continue; } - MonitoringState::apply($config); + if (Module::exists('icingadb') && + (! $config->getBackendName() && IcingadbSupport::useIcingaDbAsBackend()) + ) { + IcingaDbState::apply($config); + } else { + MonitoringState::apply($config); + } $config->applySimulation($simulation); foreach ($parents as $parentAndPath) { diff --git a/application/controllers/ProcessController.php b/application/controllers/ProcessController.php index b4fb3ef..475826f 100644 --- a/application/controllers/ProcessController.php +++ b/application/controllers/ProcessController.php @@ -2,15 +2,18 @@ namespace Icinga\Module\Businessprocess\Controllers; +use Icinga\Application\Modules\Module; use Icinga\Date\DateFormatter; use Icinga\Module\Businessprocess\BpConfig; use Icinga\Module\Businessprocess\BpNode; use Icinga\Module\Businessprocess\Node; +use Icinga\Module\Businessprocess\ProvidedHook\Icingadb\IcingadbSupport; use Icinga\Module\Businessprocess\Renderer\Breadcrumb; use Icinga\Module\Businessprocess\Renderer\Renderer; use Icinga\Module\Businessprocess\Renderer\TileRenderer; use Icinga\Module\Businessprocess\Renderer\TreeRenderer; use Icinga\Module\Businessprocess\Simulation; +use Icinga\Module\Businessprocess\State\IcingaDbState; use Icinga\Module\Businessprocess\State\MonitoringState; use Icinga\Module\Businessprocess\Storage\ConfigDiff; use Icinga\Module\Businessprocess\Storage\LegacyConfigRenderer; @@ -81,7 +84,14 @@ class ProcessController extends Controller $bp = $this->loadModifiedBpConfig(); $node = $this->getNode($bp); - MonitoringState::apply($bp); + if (Module::exists('icingadb') && + (! $bp->hasBackendName() && IcingadbSupport::useIcingaDbAsBackend()) + ) { + IcingaDbState::apply($bp); + } else { + MonitoringState::apply($bp); + } + $this->handleSimulations($bp); $this->setTitle($this->translate('Business Process "%s"'), $bp->getTitle()); diff --git a/application/controllers/ServiceController.php b/application/controllers/ServiceController.php index 17bb474..29d40ce 100644 --- a/application/controllers/ServiceController.php +++ b/application/controllers/ServiceController.php @@ -2,26 +2,71 @@ namespace Icinga\Module\Businessprocess\Controllers; +use Icinga\Application\Modules\Module; +use Icinga\Module\Businessprocess\IcingaDbObject; +use Icinga\Module\Businessprocess\ProvidedHook\Icingadb\IcingadbSupport; +use Icinga\Module\Icingadb\Model\Service; use Icinga\Module\Monitoring\Controller; use Icinga\Web\Url; +use ipl\Stdlib\Filter; class ServiceController extends Controller { + /** + * True if business process prefers to use icingadb as backend for it's nodes + * + * @var bool + */ + protected $isIcingadbPreferred; + + protected function moduleInit() + { + $this->isIcingadbPreferred = Module::exists('icingadb') + && ! $this->params->has('backend') + && IcingadbSupport::useIcingaDbAsBackend(); + + if (! $this->isIcingadbPreferred) { + parent::moduleInit(); + } + } + public function showAction() { - $host = $this->params->getRequired('host'); - $service = $this->params->getRequired('service'); + if ($this->isIcingadbPreferred) { + $hostName = $this->params->shift('host'); + $serviceName = $this->params->shift('service'); - $query = $this->backend->select() - ->from('servicestatus', array('service_description')) - ->where('host_name', $host) - ->where('service_description', $service); + $query = Service::on(IcingaDbObject::fetchDb()); + IcingaDbObject::applyIcingaDbRestrictions($query); - if ($this->applyRestriction('monitoring/filter/objects', $query)->fetchRow() !== false) { - $this->redirectNow(Url::fromPath('monitoring/service/show')->setParams($this->params)); + $query->filter(Filter::all( + Filter::equal('service.name', $serviceName), + Filter::equal('host.name', $hostName) + )); + + $service = $query->first(); + + $this->params->add('name', $serviceName); + $this->params->add('host.name', $hostName); + + if ($service !== false) { + $this->redirectNow(Url::fromPath('icingadb/service')->setParams($this->params)); + } + } else { + $hostName = $this->params->get('host'); + $serviceName = $this->params->get('service'); + + $query = $this->backend->select() + ->from('servicestatus', array('service_description')) + ->where('host_name', $hostName) + ->where('service_description', $serviceName); + + if ($this->applyRestriction('monitoring/filter/objects', $query)->fetchRow() !== false) { + $this->redirectNow(Url::fromPath('monitoring/service/show')->setParams($this->params)); + } } - $this->view->host = $host; - $this->view->service = $service; + $this->view->host = $hostName; + $this->view->service = $serviceName; } } diff --git a/application/forms/AddNodeForm.php b/application/forms/AddNodeForm.php index 6bfe392..43afa4c 100644 --- a/application/forms/AddNodeForm.php +++ b/application/forms/AddNodeForm.php @@ -2,23 +2,23 @@ namespace Icinga\Module\Businessprocess\Forms; -use Icinga\Data\Filter\Filter; use Icinga\Module\Businessprocess\BpNode; use Icinga\Module\Businessprocess\BpConfig; +use Icinga\Module\Businessprocess\Common\EnumList; use Icinga\Module\Businessprocess\ImportedNode; use Icinga\Module\Businessprocess\Modification\ProcessChanges; -use Icinga\Module\Businessprocess\MonitoringRestrictions; use Icinga\Module\Businessprocess\Storage\Storage; use Icinga\Module\Businessprocess\Web\Form\QuickForm; use Icinga\Module\Businessprocess\Web\Form\Validator\NoDuplicateChildrenValidator; use Icinga\Module\Monitoring\Backend\MonitoringBackend; use Icinga\Web\Session\SessionNamespace; +use ipl\Sql\Connection as IcingaDbConnection; class AddNodeForm extends QuickForm { - use MonitoringRestrictions; + use EnumList; - /** @var MonitoringBackend */ + /** @var MonitoringBackend|IcingaDbConnection*/ protected $backend; /** @var Storage */ @@ -402,10 +402,10 @@ class AddNodeForm extends QuickForm } /** - * @param MonitoringBackend $backend + * @param MonitoringBackend|IcingaDbConnection $backend * @return $this */ - public function setBackend(MonitoringBackend $backend) + public function setBackend($backend) { $this->backend = $backend; return $this; @@ -460,127 +460,6 @@ class AddNodeForm extends QuickForm return $this; } - protected function enumHostForServiceList() - { - $names = $this->backend - ->select() - ->from('hostStatus', ['hostname' => 'host_name']) - ->applyFilter($this->getRestriction('monitoring/filter/objects')) - ->order('host_name') - ->getQuery() - ->fetchColumn(); - - // fetchPairs doesn't seem to work when using the same column with - // different aliases twice - - return array_combine((array) $names, (array) $names); - } - - protected function enumHostList() - { - $names = $this->backend - ->select() - ->from('hostStatus', ['hostname' => 'host_name']) - ->applyFilter($this->getRestriction('monitoring/filter/objects')) - ->order('host_name') - ->getQuery() - ->fetchColumn(); - - // fetchPairs doesn't seem to work when using the same column with - // different aliases twice - $res = array(); - $suffix = ';Hoststatus'; - foreach ($names as $name) { - $res[$name . $suffix] = $name; - } - - return $res; - } - - protected function enumHostStateList() - { - $hostStateList = [ - 0 => $this->translate('UP'), - 1 => $this->translate('DOWN'), - 99 => $this->translate('PENDING') - ]; - - return $hostStateList; - } - - protected function enumServiceList($host) - { - $names = $this->backend - ->select() - ->from('serviceStatus', ['service' => 'service_description']) - ->where('host_name', $host) - ->applyFilter($this->getRestriction('monitoring/filter/objects')) - ->order('service_description') - ->getQuery() - ->fetchColumn(); - - $services = array(); - foreach ($names as $name) { - $services[$host . ';' . $name] = $name; - } - - return $services; - } - - protected function enumServiceStateList() - { - $serviceStateList = [ - 0 => $this->translate('OK'), - 1 => $this->translate('WARNING'), - 2 => $this->translate('CRITICAL'), - 3 => $this->translate('UNKNOWN'), - 99 => $this->translate('PENDING'), - ]; - - return $serviceStateList; - } - - protected function enumHostListByFilter($filter) - { - $names = $this->backend - ->select() - ->from('hostStatus', ['hostname' => 'host_name']) - ->applyFilter(Filter::fromQueryString($filter)) - ->applyFilter($this->getRestriction('monitoring/filter/objects')) - ->order('host_name') - ->getQuery() - ->fetchColumn(); - - // fetchPairs doesn't seem to work when using the same column with - // different aliases twice - $res = array(); - $suffix = ';Hoststatus'; - foreach ($names as $name) { - $res[$name . $suffix] = $name; - } - - return $res; - } - - protected function enumServiceListByFilter($filter) - { - $objects = $this->backend - ->select() - ->from('serviceStatus', ['host' => 'host_name', 'service' => 'service_description']) - ->applyFilter(Filter::fromQueryString($filter)) - ->applyFilter($this->getRestriction('monitoring/filter/objects')) - ->order('service_description') - ->getQuery() - ->fetchAll(); - - $services = array(); - foreach ($objects as $object) { - $services[$object->host . ';' . $object->service] = $object->host . ':' . $object->service; - } - - return $services; - } - protected function hasProcesses() { return count($this->enumProcesses()) > 0; diff --git a/application/forms/BpConfigForm.php b/application/forms/BpConfigForm.php index 7895d00..2de98e3 100644 --- a/application/forms/BpConfigForm.php +++ b/application/forms/BpConfigForm.php @@ -51,16 +51,18 @@ class BpConfigForm extends BpConfigBaseForm 'rows' => 4, )); - $this->addElement('select', 'Backend', array( - 'label' => $this->translate('Backend'), - 'description' => $this->translate( - 'Icinga Web Monitoring Backend where current object states for' - . ' this process should be retrieved from' - ), - 'multiOptions' => array( - null => $this->translate('Use the configured default backend'), - ) + $this->listAvailableBackends() - )); + if (! empty($this->listAvailableBackends())) { + $this->addElement('select', 'Backend', array( + 'label' => $this->translate('Backend'), + 'description' => $this->translate( + 'Icinga Web Monitoring Backend where current object states for' + . ' this process should be retrieved from' + ), + 'multiOptions' => array( + null => $this->translate('Use the configured default backend'), + ) + $this->listAvailableBackends() + )); + } $this->addElement('select', 'Statetype', array( 'label' => $this->translate('State Type'), @@ -167,9 +169,11 @@ class BpConfigForm extends BpConfigBaseForm } $meta = $config->getMetadata(); foreach ($this->getValues() as $key => $value) { - if ($value === null || $value === '') { + if (! in_array($key, ['Title', 'Description', 'Backend'], true) + && ($value === null || $value === '')) { continue; } + if ($meta->hasKey($key)) { $meta->set($key, $value); } diff --git a/application/forms/DeleteNodeForm.php b/application/forms/DeleteNodeForm.php index d06f8df..dada9d3 100644 --- a/application/forms/DeleteNodeForm.php +++ b/application/forms/DeleteNodeForm.php @@ -9,10 +9,11 @@ use Icinga\Module\Businessprocess\Node; use Icinga\Module\Businessprocess\Web\Form\QuickForm; use Icinga\Module\Monitoring\Backend\MonitoringBackend; use Icinga\Web\Session\SessionNamespace; +use ipl\Sql\Connection as IcingaDbConnection; class DeleteNodeForm extends QuickForm { - /** @var MonitoringBackend */ + /** @var MonitoringBackend|IcingaDbConnection */ protected $backend; /** @var BpConfig */ @@ -79,10 +80,10 @@ class DeleteNodeForm extends QuickForm } /** - * @param MonitoringBackend $backend + * @param MonitoringBackend|IcingaDbConnection $backend * @return $this */ - public function setBackend(MonitoringBackend $backend) + public function setBackend($backend) { $this->backend = $backend; return $this; diff --git a/application/forms/EditNodeForm.php b/application/forms/EditNodeForm.php index e97ae59..eceb065 100644 --- a/application/forms/EditNodeForm.php +++ b/application/forms/EditNodeForm.php @@ -4,19 +4,20 @@ namespace Icinga\Module\Businessprocess\Forms; use Icinga\Module\Businessprocess\BpNode; use Icinga\Module\Businessprocess\BpConfig; +use Icinga\Module\Businessprocess\Common\EnumList; use Icinga\Module\Businessprocess\Modification\ProcessChanges; -use Icinga\Module\Businessprocess\MonitoringRestrictions; use Icinga\Module\Businessprocess\Node; use Icinga\Module\Businessprocess\Web\Form\QuickForm; use Icinga\Module\Businessprocess\Web\Form\Validator\NoDuplicateChildrenValidator; use Icinga\Module\Monitoring\Backend\MonitoringBackend; use Icinga\Web\Session\SessionNamespace; +use ipl\Sql\Connection as IcingaDbConnection; class EditNodeForm extends QuickForm { - use MonitoringRestrictions; + use EnumList; - /** @var MonitoringBackend */ + /** @var MonitoringBackend|IcingaDbConnection */ protected $backend; /** @var BpConfig */ @@ -296,10 +297,10 @@ class EditNodeForm extends QuickForm } /** - * @param MonitoringBackend $backend + * @param MonitoringBackend|IcingaDbConnection $backend * @return $this */ - public function setBackend(MonitoringBackend $backend) + public function setBackend($backend) { $this->backend = $backend; return $this; @@ -344,86 +345,6 @@ class EditNodeForm extends QuickForm return $this; } - protected function enumHostForServiceList() - { - $names = $this->backend - ->select() - ->from('hostStatus', ['hostname' => 'host_name']) - ->applyFilter($this->getRestriction('monitoring/filter/objects')) - ->order('host_name') - ->getQuery() - ->fetchColumn(); - - // fetchPairs doesn't seem to work when using the same column with - // different aliases twice - - return array_combine((array) $names, (array) $names); - } - - protected function enumHostList() - { - $names = $this->backend - ->select() - ->from('hostStatus', ['hostname' => 'host_name']) - ->applyFilter($this->getRestriction('monitoring/filter/objects')) - ->order('host_name') - ->getQuery() - ->fetchColumn(); - - // fetchPairs doesn't seem to work when using the same column with - // different aliases twice - $res = array(); - $suffix = ';Hoststatus'; - foreach ($names as $name) { - $res[$name . $suffix] = $name; - } - - return $res; - } - - protected function enumHostStateList() - { - $hostStateList = [ - 0 => $this->translate('UP'), - 1 => $this->translate('DOWN'), - 99 => $this->translate('PENDING') - ]; - - return $hostStateList; - } - - protected function enumServiceList($host) - { - $names = $this->backend - ->select() - ->from('serviceStatus', ['service' => 'service_description']) - ->where('host_name', $host) - ->applyFilter($this->getRestriction('monitoring/filter/objects')) - ->order('service_description') - ->getQuery() - ->fetchColumn(); - - $services = array(); - foreach ($names as $name) { - $services[$host . ';' . $name] = $name; - } - - return $services; - } - - protected function enumServiceStateList() - { - $serviceStateList = [ - 0 => $this->translate('OK'), - 1 => $this->translate('WARNING'), - 2 => $this->translate('CRITICAL'), - 3 => $this->translate('UNKNOWN'), - 99 => $this->translate('PENDING'), - ]; - - return $serviceStateList; - } - protected function hasProcesses() { return count($this->enumProcesses()) > 0; diff --git a/application/forms/ProcessForm.php b/application/forms/ProcessForm.php index 0e0b853..be1abbf 100644 --- a/application/forms/ProcessForm.php +++ b/application/forms/ProcessForm.php @@ -9,10 +9,11 @@ use Icinga\Module\Businessprocess\Web\Form\QuickForm; use Icinga\Module\Monitoring\Backend\MonitoringBackend; use Icinga\Web\Notification; use Icinga\Web\Session\SessionNamespace; +use ipl\Sql\Connection as IcingaDbConnection; class ProcessForm extends QuickForm { - /** @var MonitoringBackend */ + /** @var MonitoringBackend|IcingaDbConnection */ protected $backend; /** @var BpConfig */ @@ -111,10 +112,10 @@ class ProcessForm extends QuickForm } /** - * @param MonitoringBackend $backend + * @param MonitoringBackend|IcingaDbConnection $backend * @return $this */ - public function setBackend(MonitoringBackend $backend) + public function setBackend($backend) { $this->backend = $backend; return $this; diff --git a/doc/02-Installation.md b/doc/02-Installation.md index 3be623e..5f8c417 100644 --- a/doc/02-Installation.md +++ b/doc/02-Installation.md @@ -7,7 +7,7 @@ Requirements * Icinga Web 2 (>= 2.9) * PHP (>= 7.2) * Icinga Web 2 modules: - * The `monitoring` module needs to be configured and enabled. + * The `monitoring` or `icingadb` module needs to be configured and enabled. Installation from .tar.gz ------------------------- diff --git a/library/Businessprocess/BpConfig.php b/library/Businessprocess/BpConfig.php index c49d262..1e3f119 100644 --- a/library/Businessprocess/BpConfig.php +++ b/library/Businessprocess/BpConfig.php @@ -3,13 +3,15 @@ namespace Icinga\Module\Businessprocess; use Exception; -use Icinga\Application\Config; +use Icinga\Application\Modules\Module; use Icinga\Exception\IcingaException; use Icinga\Exception\NotFoundError; use Icinga\Module\Businessprocess\Exception\NestingError; use Icinga\Module\Businessprocess\Modification\ProcessChanges; +use Icinga\Module\Businessprocess\ProvidedHook\Icingadb\IcingadbSupport; use Icinga\Module\Businessprocess\Storage\LegacyStorage; use Icinga\Module\Monitoring\Backend\MonitoringBackend; +use ipl\Sql\Connection as IcingaDbConnection; class BpConfig { @@ -25,9 +27,9 @@ class BpConfig protected $backendName; /** - * Monitoring backend to retrieve states from + * Backend to retrieve states from * - * @var MonitoringBackend + * @var MonitoringBackend|IcingaDbConnection */ protected $backend; @@ -281,7 +283,7 @@ class BpConfig return $this->getMetadata()->has('Backend'); } - public function setBackend(MonitoringBackend $backend) + public function setBackend($backend) { $this->backend = $backend; return $this; @@ -290,9 +292,14 @@ class BpConfig public function getBackend() { if ($this->backend === null) { - $this->backend = MonitoringBackend::instance( - $this->getBackendName() - ); + if (Module::exists('icingadb') + && (! $this->hasBackendName() && IcingadbSupport::useIcingaDbAsBackend())) { + $this->backend = IcingaDbObject::fetchDb(); + } else { + $this->backend = MonitoringBackend::instance( + $this->getBackendName() + ); + } } return $this->backend; diff --git a/library/Businessprocess/Common/EnumList.php b/library/Businessprocess/Common/EnumList.php new file mode 100644 index 0000000..a1e5b56 --- /dev/null +++ b/library/Businessprocess/Common/EnumList.php @@ -0,0 +1,168 @@ +useIcingaDbBackend()) { + $names = (new IcingaDbObject())->yieldHostnames(); + } else { + $names = $this->backend + ->select() + ->from('hostStatus', ['hostname' => 'host_name']) + ->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects')) + ->order('host_name') + ->getQuery() + ->fetchColumn(); + } + + // fetchPairs doesn't seem to work when using the same column with + // different aliases twice + $res = array(); + foreach ($names as $name) { + $res[$name] = $name; + } + + return $res; + } + + protected function enumHostList() + { + if ($this->useIcingaDbBackend()) { + $names = (new IcingaDbObject())->yieldHostnames(); + } else { + $names = $this->backend + ->select() + ->from('hostStatus', ['hostname' => 'host_name']) + ->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects')) + ->order('host_name') + ->getQuery() + ->fetchColumn(); + } + + // fetchPairs doesn't seem to work when using the same column with + // different aliases twice + $res = array(); + $suffix = ';Hoststatus'; + foreach ($names as $name) { + $res[$name . $suffix] = $name; + } + + return $res; + } + + protected function enumServiceList($host) + { + if ($this->useIcingaDbBackend()) { + $names = (new IcingaDbObject())->yieldServicenames($host); + } else { + $names = $this->backend + ->select() + ->from('serviceStatus', ['service' => 'service_description']) + ->where('host_name', $host) + ->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects')) + ->order('service_description') + ->getQuery() + ->fetchColumn(); + } + + $services = array(); + foreach ($names as $name) { + $services[$host . ';' . $name] = $name; + } + + return $services; + } + + protected function enumHostListByFilter($filter) + { + if ($this->useIcingaDbBackend()) { + $names = (new IcingaDbObject())->yieldHostnames($filter); + } else { + $names = $this->backend + ->select() + ->from('hostStatus', ['hostname' => 'host_name']) + ->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects')) + ->order('host_name') + ->getQuery() + ->fetchColumn(); + } + + // fetchPairs doesn't seem to work when using the same column with + // different aliases twice + $res = array(); + $suffix = ';Hoststatus'; + foreach ($names as $name) { + $res[$name . $suffix] = $name; + } + + return $res; + } + + protected function enumServiceListByFilter($filter) + { + $services = array(); + + if ($this->useIcingaDbBackend()) { + $objects = (new IcingaDbObject())->fetchServices($filter); + foreach ($objects as $object) { + $services[$object->host->name . ';' . $object->name] = $object->host->name . ':' . $object->name; + } + } else { + $objects = $this->backend + ->select() + ->from('serviceStatus', ['host' => 'host_name', 'service' => 'service_description']) + ->applyFilter(Filter::fromQueryString($filter)) + ->applyFilter(MonitoringRestrictions::getRestriction('monitoring/filter/objects')) + ->order('service_description') + ->getQuery() + ->fetchAll(); + foreach ($objects as $object) { + $services[$object->host . ';' . $object->service] = $object->host . ':' . $object->service; + } + } + + return $services; + } + + protected function enumHostStateList() + { + $hostStateList = [ + 0 => $this->translate('UP'), + 1 => $this->translate('DOWN'), + 99 => $this->translate('PENDING') + ]; + + return $hostStateList; + } + + protected function enumServiceStateList() + { + $serviceStateList = [ + 0 => $this->translate('OK'), + 1 => $this->translate('WARNING'), + 2 => $this->translate('CRITICAL'), + 3 => $this->translate('UNKNOWN'), + 99 => $this->translate('PENDING'), + ]; + + return $serviceStateList; + } + + protected function useIcingaDbBackend() + { + if (Module::exists('icingadb')) { + return ! $this->bp->hasBackendName() && IcingadbSupport::useIcingaDbAsBackend(); + } + + return false; + } +} diff --git a/library/Businessprocess/HostNode.php b/library/Businessprocess/HostNode.php index 8229e95..b66f66f 100644 --- a/library/Businessprocess/HostNode.php +++ b/library/Businessprocess/HostNode.php @@ -3,7 +3,6 @@ namespace Icinga\Module\Businessprocess; use Icinga\Module\Businessprocess\Web\Url; -use ipl\Html\Html; class HostNode extends MonitoredNode { diff --git a/library/Businessprocess/IcingaDbObject.php b/library/Businessprocess/IcingaDbObject.php new file mode 100644 index 0000000..cad459f --- /dev/null +++ b/library/Businessprocess/IcingaDbObject.php @@ -0,0 +1,94 @@ +conn = $this->getDb(); + } + + public function fetchHosts($filter = null) + { + + $hosts = Host::on($this->conn); + + if ($filter !== null) { + $filterQuery = QueryString::parse($filter); + + $hosts->filter($filterQuery); + } + + $hosts->orderBy('host.name'); + + $this->applyIcingaDbRestrictions($hosts); + + return $hosts; + } + + public function fetchServices($filter) + { + $services = Service::on($this->conn) + ->with('host'); + + if ($filter !== null) { + $filterQuery = QueryString::parse($filter); + + $services->filter($filterQuery); + } + + $services->orderBy('service.name'); + + $this->applyIcingaDbRestrictions($services); + + return $services; + } + + public function yieldHostnames($filter = null) + { + foreach ($this->fetchHosts($filter) as $host) { + yield $host->name; + } + } + + public function yieldServicenames($host) + { + $filter = "host.name=$host"; + + foreach ($this->fetchServices($filter) as $service) { + yield $service->name; + } + } + + public static function applyIcingaDbRestrictions($query) + { + $object = new self; + $object->applyRestrictions($query); + + return $object; + } + + public static function fetchDb() + { + $object = new self; + return $object->getDb(); + } +} diff --git a/library/Businessprocess/MonitoringRestrictions.php b/library/Businessprocess/MonitoringRestrictions.php index 4dd4caa..c7d2cef 100644 --- a/library/Businessprocess/MonitoringRestrictions.php +++ b/library/Businessprocess/MonitoringRestrictions.php @@ -7,7 +7,7 @@ use Icinga\Data\Filter\Filter; use Icinga\Exception\ConfigurationError; use Icinga\Exception\QueryException; -trait MonitoringRestrictions +class MonitoringRestrictions { /** * Return a filter for the given restriction @@ -17,7 +17,7 @@ trait MonitoringRestrictions * @return Filter|null Filter object or null if the authenticated user is not restricted * @throws ConfigurationError If the restriction contains invalid filter columns */ - protected function getRestriction($name) + public static function getRestriction($name) { // Borrowed from Icinga\Module\Monitoring\Controller $restriction = Filter::matchAny(); diff --git a/library/Businessprocess/ProvidedHook/Icingadb/HostActions.php b/library/Businessprocess/ProvidedHook/Icingadb/HostActions.php new file mode 100644 index 0000000..27f4551 --- /dev/null +++ b/library/Businessprocess/ProvidedHook/Icingadb/HostActions.php @@ -0,0 +1,22 @@ +name . ';Hoststatus') + ) + ); + } +} diff --git a/library/Businessprocess/ProvidedHook/Icingadb/IcingadbSupport.php b/library/Businessprocess/ProvidedHook/Icingadb/IcingadbSupport.php new file mode 100644 index 0000000..1ff37d3 --- /dev/null +++ b/library/Businessprocess/ProvidedHook/Icingadb/IcingadbSupport.php @@ -0,0 +1,10 @@ +host->name, $service->name) + ) + ) + ) + ); + } +} diff --git a/library/Businessprocess/State/IcingaDbState.php b/library/Businessprocess/State/IcingaDbState.php new file mode 100644 index 0000000..f33d4a4 --- /dev/null +++ b/library/Businessprocess/State/IcingaDbState.php @@ -0,0 +1,145 @@ +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; + + Benchmark::measure(sprintf( + 'Retrieving states for business process %s using Icinga DB backend', + $config->getName() + )); + + $hosts = $config->listInvolvedHostNames(); + if (empty($hosts)) { + return $this; + } + + $queryHost = Host::on($this->backend)->with('state'); + IcingaDbObject::applyIcingaDbRestrictions($queryHost); + + $queryHost->filter(Filter::equal('host.name', $hosts)); + + $hostObject = $queryHost->getModel()->getTableName(); + + Benchmark::measure('Retrieved states for ' . $queryHost->count() . ' hosts in ' . $config->getName()); + + $queryService = Service::on($this->backend)->with([ + 'state', + 'host', + 'host.state' + ]); + + $queryService->filter(Filter::equal('host.name', $hosts)); + + IcingaDbObject::applyIcingaDbRestrictions($queryService); + + Benchmark::measure('Retrieved states for ' . $queryService->count() . ' services in ' . $config->getName()); + + $configs = $config->listInvolvedConfigs(); + + $serviceObject = $queryService->getModel()->getTableName(); + + foreach ($configs as $cfg) { + foreach ($queryService as $row) { + $this->handleDbRow($row, $cfg, $serviceObject); + } + foreach ($queryHost as $row) { + $this->handleDbRow($row, $cfg, $hostObject); + } + } + + Benchmark::measure('Got states for business process ' . $config->getName()); + + return $this; + } + + protected function handleDbRow($row, BpConfig $config, $objectName) + { + if ($objectName === 'service') { + $key = $row->host->name . ';' . $row->name; + } else { + $key = $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->state->hard_state !== null) { + $node->setState($row->state->hard_state)->setMissing(false); + } + } else { + if ($row->state->soft_state !== null) { + $node->setState($row->state->soft_state)->setMissing(false); + } + } + + if ($row->state->last_state_change !== null) { + $node->setLastStateChange($row->state->last_state_change/1000); + } + if ($row->state->in_downtime) { + $node->setDowntime(true); + } + if ($row->state->is_acknowledged) { + $node->setAck(true); + } + + $node->setAlias($row->display_name); + + if ($node instanceof ServiceNode) { + $node->setHostAlias($row->host->display_name); + } + } +} diff --git a/library/Businessprocess/Web/Component/Dashboard.php b/library/Businessprocess/Web/Component/Dashboard.php index eb3b092..58506df 100644 --- a/library/Businessprocess/Web/Component/Dashboard.php +++ b/library/Businessprocess/Web/Component/Dashboard.php @@ -2,7 +2,10 @@ namespace Icinga\Module\Businessprocess\Web\Component; +use Icinga\Application\Modules\Module; use Icinga\Authentication\Auth; +use Icinga\Module\Businessprocess\ProvidedHook\Icingadb\IcingadbSupport; +use Icinga\Module\Businessprocess\State\IcingaDbState; use Icinga\Module\Businessprocess\State\MonitoringState; use Icinga\Module\Businessprocess\Storage\Storage; use ipl\Html\BaseHtmlElement; @@ -91,7 +94,14 @@ class Dashboard extends BaseHtmlElement } $bp = $storage->loadProcess($name); - MonitoringState::apply($bp); + + if (Module::exists('icingadb') && + (! $bp->hasBackendName() && IcingadbSupport::useIcingaDbAsBackend()) + ) { + IcingaDbState::apply($bp); + } else { + MonitoringState::apply($bp); + } $this->add(new BpDashboardTile( $bp, diff --git a/library/Businessprocess/Web/Form/BpConfigBaseForm.php b/library/Businessprocess/Web/Form/BpConfigBaseForm.php index b8bcbbd..ddfc851 100644 --- a/library/Businessprocess/Web/Form/BpConfigBaseForm.php +++ b/library/Businessprocess/Web/Form/BpConfigBaseForm.php @@ -3,6 +3,7 @@ namespace Icinga\Module\Businessprocess\Web\Form; use Icinga\Application\Config; +use Icinga\Application\Icinga; use Icinga\Authentication\Auth; use Icinga\Module\Businessprocess\Storage\LegacyStorage; use Icinga\Module\Businessprocess\BpConfig; @@ -17,8 +18,14 @@ abstract class BpConfigBaseForm extends QuickForm protected function listAvailableBackends() { - $keys = array_keys(Config::module('monitoring', 'backends')->toArray()); - return array_combine($keys, $keys); + $keys = []; + $moduleManager = Icinga::app()->getModuleManager(); + if ($moduleManager->hasEnabled('monitoring')) { + $keys = array_keys(Config::module('monitoring', 'backends')->toArray()); + $keys = array_combine($keys, $keys); + } + + return $keys; } public function setStorage(LegacyStorage $storage) diff --git a/module.info b/module.info index 1f80156..7484c03 100644 --- a/module.info +++ b/module.info @@ -1,14 +1,14 @@ Name: Businessprocess Version: 2.3.1 -Depends: monitoring (>= 2.4.1), ipl (>= 0.1.1) +Depends: monitoring (>= 2.4.1), icingadb (>= 1.0.0), ipl (>= 0.5.0) Description: A Business Process viewer and modeler Provides a web-based process modeler for. It integrates as a module into Icinga Web 2 and provides a plugin check command for Icinga. Tile and tree views can be shown inline, as dashlets or fullscreen. All of those for whole processes or just parts of them. - Hooks into the monitoring module to show Business Impact for a specific host - or service and provides a Business Impact Simulation mode to visualize the - influence of a potential outage. + Hooks into the monitoring or icingadb module to show Business Impact for a + specific host or service and provides a Business Impact Simulation mode to + visualize the influence of a potential outage. Supports legacy BPaddon config files. diff --git a/run.php b/run.php index 2cde2ee..3f05d06 100644 --- a/run.php +++ b/run.php @@ -2,4 +2,7 @@ $this->provideHook('monitoring/HostActions'); $this->provideHook('monitoring/ServiceActions'); +$this->provideHook('icingadb/HostActions'); +$this->provideHook('icingadb/ServiceActions'); +$this->provideHook('icingadb/icingadbSupport'); //$this->provideHook('director/shipConfigFiles');