diff options
Diffstat (limited to 'application/clicommands')
-rw-r--r-- | application/clicommands/CheckCommand.php | 23 | ||||
-rw-r--r-- | application/clicommands/CleanupCommand.php | 106 | ||||
-rw-r--r-- | application/clicommands/ProcessCommand.php | 227 |
3 files changed, 356 insertions, 0 deletions
diff --git a/application/clicommands/CheckCommand.php b/application/clicommands/CheckCommand.php new file mode 100644 index 0000000..d1c561f --- /dev/null +++ b/application/clicommands/CheckCommand.php @@ -0,0 +1,23 @@ +<?php + +namespace Icinga\Module\Businessprocess\Clicommands; + +class CheckCommand extends ProcessCommand +{ + public function listActions() + { + return array('process'); + } + + /** + * 'check process' is DEPRECATED, please use 'process check' instead + * + * USAGE + * + * icingacli businessprocess check process [--config <name>] <process> + */ + public function processAction() + { + $this->checkAction(); + } +} diff --git a/application/clicommands/CleanupCommand.php b/application/clicommands/CleanupCommand.php new file mode 100644 index 0000000..f0041c8 --- /dev/null +++ b/application/clicommands/CleanupCommand.php @@ -0,0 +1,106 @@ +<?php + +namespace Icinga\Module\Businessprocess\Clicommands; + +use Exception; +use Icinga\Application\Logger; +use Icinga\Application\Modules\Module; +use Icinga\Cli\Command; +use Icinga\Module\Businessprocess\Modification\NodeRemoveAction; +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; + +class CleanupCommand extends Command +{ + /** + * @var LegacyStorage + */ + protected $storage; + + protected $defaultActionName = 'cleanup'; + + public function init() + { + $this->storage = LegacyStorage::getInstance(); + } + + /** + * Cleanup all missing monitoring nodes from the specified config name + * If no config name is specified, the missing nodes are cleaned from all available configs. + * Invalid config files and file names are ignored + * + * USAGE + * + * icingacli businessprocess cleanup [<config-name>] + * + * OPTIONS + * + * <config-name> + */ + public function cleanupAction(): void + { + $configNames = (array) $this->params->shift() ?: $this->storage->listAllProcessNames(); + $foundMissingNode = false; + foreach ($configNames as $configName) { + if (! $this->storage->hasProcess($configName)) { + continue; + } + + try { + $bp = $this->storage->loadProcess($configName); + } catch (Exception $e) { + Logger::error( + 'Failed to scan the %s.conf file for missing nodes. Faulty config found.', + $configName + ); + + continue; + } + + if (Module::exists('icingadb') + && (! $bp->hasBackendName() && IcingadbSupport::useIcingaDbAsBackend()) + ) { + IcingaDbState::apply($bp); + } else { + MonitoringState::apply($bp); + } + + $removedNodes = []; + foreach (array_keys($bp->getMissingChildren()) as $missingNode) { + $node = $bp->getNode($missingNode); + $remove = new NodeRemoveAction($node); + + try { + if ($remove->appliesTo($bp)) { + $remove->applyTo($bp); + $removedNodes[] = $node->getName(); + $this->storage->storeProcess($bp); + $bp->clearAppliedChanges(); + + $foundMissingNode = true; + } + } catch (Exception $e) { + Logger::error(sprintf('(%s.conf) %s', $configName, $e->getMessage())); + + continue; + } + } + + if (! empty($removedNodes)) { + echo sprintf( + 'Removed following %d missing node(s) from %s.conf successfully:', + count($removedNodes), + $configName + ); + + echo "\n" . implode("\n", $removedNodes) . "\n\n"; + } + } + + if (! $foundMissingNode) { + echo "No missing node found.\n"; + } + } +} diff --git a/application/clicommands/ProcessCommand.php b/application/clicommands/ProcessCommand.php new file mode 100644 index 0000000..018c1e3 --- /dev/null +++ b/application/clicommands/ProcessCommand.php @@ -0,0 +1,227 @@ +<?php + +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; + +class ProcessCommand extends Command +{ + /** + * @var LegacyStorage + */ + protected $storage; + + protected $hostColors = array( + 0 => array('black', 'lightgreen'), + 1 => array('lightgray', 'lightred'), + 2 => array('black', 'brown'), + 99 => array('black', 'lightgray'), + ); + + protected $serviceColors = array( + 0 => array('black', 'lightgreen'), + 1 => array('black', 'yellow'), + 2 => array('lightgray', 'lightred'), + 3 => array('black', 'lightpurple'), + 99 => array('black', 'lightgray'), + ); + + public function init() + { + $this->storage = LegacyStorage::getInstance(); + } + + /** + * List all available Business Process Configurations + * + * ...or their BusinessProcess Nodes in case a Configuration name is given + * + * USAGE + * + * icingacli businessprocess list processes [<config-name>] [options] + * + * OPTIONS + * + * <config-name> + * --no-title Show only names and no related title + */ + public function listAction() + { + if ($config = $this->params->shift()) { + $this->listBpNames($this->storage->loadProcess($config)); + } else { + $this->listConfigNames(! (bool) $this->params->shift('no-title')); + } + } + + protected function listConfigNames($withTitle) + { + foreach ($this->storage->listProcesses() as $key => $title) { + if ($withTitle) { + echo $title . "\n"; + } else { + echo $key . "\n"; + } + } + } + + /** + * Check a specific process + * + * USAGE + * + * icingacli businessprocess process check <process> [options] + * + * OPTIONS + * + * --config <configname> Name of the config that contains <process> + * --details Show problem details as a tree + * --colors Show colored output + * --state-type <type> Define which state type to look at. Could be + * either soft or hard, overrides an eventually + * configured default + * --blame Show problem details as a tree reduced to the + * nodes which have the same state as the business + * process + * --root-cause Used in combination with --blame. Only shows + * the path of the nodes which are responsible for + * the state of the business process + * --downtime-is-ok Treat hosts/services in downtime always as + * UP/OK. + * --ack-is-ok Treat acknowledged hosts/services always as + * UP/OK. + */ + public function checkAction() + { + $nodeName = $this->params->shift(); + if (! $nodeName) { + Logger::error('A process name is required'); + exit(1); + } + + $name = $this->params->get('config'); + try { + if ($name === null) { + $name = $this->getFirstProcessName(); + } + + $bp = $this->storage->loadProcess($name); + } catch (Exception $err) { + Logger::error("Can't access configuration '%s': %s", $name, $err->getMessage()); + + exit(3); + } + + if (null !== ($stateType = $this->params->get('state-type'))) { + if ($stateType === 'soft') { + $bp->useSoftStates(); + } + if ($stateType === 'hard') { + $bp->useHardStates(); + } + } + + try { + /** @var BpNode $node */ + $node = $bp->getNode($nodeName); + 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()); + + exit(3); + } + } catch (Exception $err) { + Logger::error("Checking Business Process '%s' failed: %s", $name, $err); + + exit(3); + } + + if ($this->params->shift('ack-is-ok')) { + Node::setAckIsOk(); + } + + if ($this->params->shift('downtime-is-ok')) { + Node::setDowntimeIsOk(); + } + + printf("Business Process %s: %s\n", $node->getStateName(), $node->getAlias()); + if ($this->params->shift('details')) { + echo $this->renderProblemTree($node->getProblemTree(), $this->params->shift('colors')); + } + if ($this->params->shift('blame')) { + echo $this->renderProblemTree( + $node->getProblemTreeBlame($this->params->shift('root-cause')), + $this->params->shift('colors') + ); + } + + exit($node->getState()); + } + + protected function listBpNames(BpConfig $config) + { + foreach ($config->listBpNodes() as $title) { + echo $title . "\n"; + } + } + + protected function renderProblemTree($tree, $useColors = false, $depth = 0, BpNode $parent = null) + { + $output = ''; + + foreach ($tree as $name => $subtree) { + /** @var Node $node */ + $node = $subtree['node']; + $state = $parent !== null ? $parent->getChildState($node) : $node->getState(); + + if ($node instanceof HostNode) { + $colors = $this->hostColors[$state]; + } else { + $colors = $this->serviceColors[$state]; + } + + $state = sprintf('[%s]', $node->getStateName($state)); + if ($useColors) { + $state = $this->screen->colorize($state, $colors[0], $colors[1]); + } + + $output .= sprintf( + "%s%s %s %s\n", + str_repeat(' ', $depth), + $node instanceof BpNode ? $node->getOperator() : '-', + $state, + $node->getAlias() + ); + + if ($node instanceof BpNode) { + $output .= $this->renderProblemTree($subtree['children'], $useColors, $depth + 1, $node); + } + } + + return $output; + } + + protected function getFirstProcessName() + { + $list = $this->storage->listProcessNames(); + return key($list); + } +} |