0, 'CRITICAL-HANDLED' => 0, 'WARNING' => 0, 'WARNING-HANDLED' => 0, 'UNKNOWN' => 0, 'UNKNOWN-HANDLED' => 0, 'OK' => 0, 'PENDING' => 0, 'MISSING' => 0, ); protected static $sortStateInversionMap = array( 4 => 0, 3 => 0, 2 => 2, 1 => 1, 0 => 4 ); protected $className = 'process'; public function __construct($object) { $this->name = $object->name; $this->operator = $object->operator; $this->childNames = $object->child_names; } public function getStateSummary() { if ($this->counters === null) { $this->getState(); $this->counters = self::$emptyStateSummary; foreach ($this->getChildren() as $child) { if ($child->isMissing()) { $this->counters['MISSING']++; } else { $state = $child->getStateName($this->getChildState($child)); if ($child->isHandled() && ($state !== 'UP' && $state !== 'OK')) { $state = $state . '-HANDLED'; } if ($state === 'DOWN') { $this->counters['CRITICAL']++; } elseif ($state === 'DOWN-HANDLED') { $this->counters['CRITICAL-HANDLED']++; } elseif ($state === 'UNREACHABLE') { $this->counters['UNKNOWN']++; } elseif ($state === 'UNREACHABLE-HANDLED') { $this->counters['UNKNOWN-HANDLED']++; } elseif ($state === 'UP') { $this->counters['OK']++; } else { $this->counters[$state]++; } } } } return $this->counters; } public function hasProblems() { if ($this->isProblem()) { return true; } $okStates = array('OK', 'UP', 'PENDING', 'MISSING'); foreach ($this->getStateSummary() as $state => $cnt) { if ($cnt !== 0 && ! in_array($state, $okStates)) { return true; } } return false; } /** * @param Node $node * @return $this * @throws ConfigurationError */ public function addChild(Node $node) { if ($this->children === null) { $this->getChildren(); } $name = $node->getName(); if (array_key_exists($name, $this->children)) { throw new ConfigurationError( 'Node "%s" has been defined more than once', $name ); } $this->children[$name] = $node; $this->childNames[] = $name; $this->reorderChildren(); $node->addParent($this); return $this; } public function getProblematicChildren() { $problems = array(); foreach ($this->getChildren() as $child) { if (isset($this->stateOverrides[$child->getName()])) { $problem = $this->getChildState($child) > 0; } else { $problem = $child->isProblem() || ($child instanceof BpNode && $child->hasProblems()); } if ($problem) { $problems[] = $child; } } return $problems; } public function hasChild($name) { return in_array($name, $this->getChildNames()); } public function removeChild($name) { if (($key = array_search($name, $this->getChildNames())) !== false) { unset($this->childNames[$key]); if (! empty($this->children)) { unset($this->children[$name]); } } return $this; } public function getProblemTree() { $tree = array(); foreach ($this->getProblematicChildren() as $child) { $name = $child->getName(); $tree[$name] = array( 'node' => $child, 'children' => array() ); if ($child instanceof BpNode) { $tree[$name]['children'] = $child->getProblemTree(); } } return $tree; } /** * Get the problem nodes as tree reduced to the nodes which have the same state as the business process * * @param bool $rootCause Reduce nodes to the nodes which are responsible for the state of the business process * * @return array */ public function getProblemTreeBlame($rootCause = false) { $tree = []; $nodeState = $this->getState(); if ($nodeState !== 0) { foreach ($this->getChildren() as $child) { $childState = $this->getChildState($child); $childState = $rootCause ? $child->getSortingState($childState) : $childState; if (($rootCause ? $this->getSortingState() : $nodeState) === $childState) { $name = $child->getName(); $tree[$name] = [ 'children' => [], 'node' => $child ]; if ($child instanceof BpNode) { $tree[$name]['children'] = $child->getProblemTreeBlame($rootCause); } } } } return $tree; } public function isMissing() { if ($this->missing === null) { $exists = false; $bp = $this->getBpConfig(); $bp->beginLoopDetection($this->name); foreach ($this->getChildren() as $child) { if (! $child->isMissing()) { $exists = true; } } $bp->endLoopDetection($this->name); $this->missing = ! $exists && ! empty($this->getChildren()); } return $this->missing; } public function isEmpty() { $bp = $this->getBpConfig(); $empty = true; if ($this->countChildren()) { $bp->beginLoopDetection($this->name); foreach ($this->getChildren() as $child) { if ($child instanceof MonitoredNode) { $empty = false; break; } elseif (!$child->isEmpty()) { $empty = false; } } $bp->endLoopDetection($this->name); } $this->empty = $empty; return $this->empty; } public function getMissingChildren() { if ($this->missingChildren === null) { $missing = array(); foreach ($this->getChildren() as $child) { if ($child->isMissing()) { $missing[$child->getName()] = $child; } foreach ($child->getMissingChildren() as $m) { $missing[$m->getName()] = $m; } } $this->missingChildren = $missing; } return $this->missingChildren; } public function getOperator() { return $this->operator; } public function setOperator($operator) { $this->assertValidOperator($operator); $this->operator = $operator; return $this; } protected function assertValidOperator($operator) { switch ($operator) { case self::OP_AND: case self::OP_OR: case self::OP_NOT: case self::OP_DEGRADED: return; default: if (is_numeric($operator)) { return; } } throw new ConfigurationError( 'Got invalid operator: %s', $operator ); } public function setInfoUrl($url) { $this->url = $url; return $this; } public function hasInfoUrl() { return ! empty($this->url); } public function getInfoUrl() { return $this->url; } public function setInfoCommand($cmd) { $this->info_command = $cmd; } public function hasInfoCommand() { return $this->info_command !== null; } public function getInfoCommand() { return $this->info_command; } public function setStateOverrides(array $overrides, $name = null) { if ($name === null) { $this->stateOverrides = $overrides; } else { $this->stateOverrides[$name] = $overrides; } return $this; } public function getStateOverrides($name = null) { $overrides = null; if ($name !== null) { if (isset($this->stateOverrides[$name])) { $overrides = $this->stateOverrides[$name]; } } else { $overrides = $this->stateOverrides; } return $overrides; } public function getAlias() { return $this->alias ? preg_replace('~_~', ' ', $this->alias) : $this->name; } /** * @return int */ public function getState() { if ($this->state === null) { try { $this->reCalculateState(); } catch (NestingError $e) { $this->getBpConfig()->addError( $this->getBpConfig()->translate('Nesting error detected: %s'), $e->getMessage() ); // Failing nodes are unknown $this->state = 3; } } return $this->state; } /** * Get the given child's state, possibly adjusted by override rules * * @param Node|string $child * @return int */ public function getChildState($child) { if (! $child instanceof Node) { $child = $this->getChildByName($child); } $childName = $child->getName(); $childState = $child->getState(); if (! isset($this->stateOverrides[$childName][$childState])) { return $childState; } return $this->stateOverrides[$childName][$childState]; } public function getHtmlId() { return 'businessprocess-' . preg_replace('/[\r\n\t\s]/', '_', $this->getName()); } protected function invertSortingState($state) { return self::$sortStateInversionMap[$state >> self::SHIFT_FLAGS] << self::SHIFT_FLAGS; } /** * @return $this */ public function reCalculateState() { $bp = $this->getBpConfig(); $sort_states = array(); $lastStateChange = 0; if ($this->isEmpty()) { // TODO: delegate this to operators, should mostly fail $this->setState(self::NODE_EMPTY); return $this; } foreach ($this->getChildren() as $child) { $bp->beginLoopDetection($this->name); if ($child instanceof MonitoredNode && $child->isMissing()) { if ($child instanceof HostNode) { $child->setState(self::ICINGA_UNREACHABLE); } else { $child->setState(self::ICINGA_UNKNOWN); } $child->setMissing(); } $sort_states[] = $child->getSortingState($this->getChildState($child)); $lastStateChange = max($lastStateChange, $child->getLastStateChange()); $bp->endLoopDetection($this->name); } $this->setLastStateChange($lastStateChange); switch ($this->getOperator()) { case self::OP_AND: $sort_state = max($sort_states); break; case self::OP_NOT: $sort_state = $this->invertSortingState(max($sort_states)); break; case self::OP_OR: $sort_state = min($sort_states); break; case self::OP_DEGRADED: $maxState = max($sort_states); $flags = $maxState & 0xf; $maxIcingaState = $this->sortStateTostate($maxState); $warningState = ($this->stateToSortState(self::ICINGA_WARNING) << self::SHIFT_FLAGS) + $flags; $sort_state = ($maxIcingaState === self::ICINGA_CRITICAL) ? $warningState : $maxState; break; default: // MIN: $sort_state = 3 << self::SHIFT_FLAGS; if (count($sort_states) >= $this->operator) { $actualGood = 0; foreach ($sort_states as $s) { if (($s >> self::SHIFT_FLAGS) === self::ICINGA_OK) { $actualGood++; } } if ($actualGood >= $this->operator) { // condition is fulfilled $sort_state = self::ICINGA_OK; } else { // worst state if not fulfilled $sort_state = max($sort_states); } } } if ($sort_state & self::FLAG_DOWNTIME) { $this->setDowntime(true); } if ($sort_state & self::FLAG_ACK) { $this->setAck(true); } $this->state = $this->sortStateTostate($sort_state); return $this; } public function checkForLoops() { $bp = $this->getBpConfig(); foreach ($this->getChildren() as $child) { $bp->beginLoopDetection($this->name); if ($child instanceof BpNode) { $child->checkForLoops(); } $bp->endLoopDetection($this->name); } return $this; } public function setDisplay($display) { $this->display = (int) $display; return $this; } public function getDisplay() { return $this->display; } public function setChildNames($names) { $this->childNames = $names; $this->children = null; $this->reorderChildren(); return $this; } public function hasChildren($filter = null) { $childNames = $this->getChildNames(); return !empty($childNames); } public function getChildNames() { return $this->childNames; } public function getChildren($filter = null) { if ($this->children === null) { $this->children = []; $this->reorderChildren(); foreach ($this->getChildNames() as $name) { $this->children[$name] = $this->getBpConfig()->getNode($name); $this->children[$name]->addParent($this); } } return $this->children; } /** * Reorder this node's children, in case manual order is not applied */ protected function reorderChildren() { if ($this->getBpConfig()->getMetadata()->isManuallyOrdered()) { return; } $childNames = $this->getChildNames(); natcasesort($childNames); $this->childNames = array_values($childNames); if (! empty($this->children)) { $children = []; foreach ($this->childNames as $name) { $children[$name] = $this->children[$name]; } $this->children = $children; } } /** * return BpNode[] */ public function getChildBpNodes() { $children = array(); foreach ($this->getChildren() as $name => $child) { if ($child instanceof BpNode) { $children[$name] = $child; } } return $children; } /** * @param $childName * @return Node * @throws NotFoundError */ public function getChildByName($childName) { foreach ($this->getChildren() as $name => $child) { if ($name === $childName) { return $child; } } throw new NotFoundError('Trying to get missing child %s', $childName); } protected function assertNumericOperator() { if (! is_numeric($this->getOperator())) { throw new ConfigurationError('Got invalid operator: %s', $this->operator); } } public function operatorHtml() { switch ($this->getOperator()) { case self::OP_AND: return 'AND'; break; case self::OP_OR: return 'OR'; break; case self::OP_NOT: return 'NOT'; break; case self::OP_DEGRADED: return 'DEG'; break; default: // MIN $this->assertNumericOperator(); return 'min:' . $this->operator; } } public function getIcon() { $this->icon = $this->hasParents() ? 'cubes' : 'sitemap'; return parent::getIcon(); } }