Add Service Override

This commit is contained in:
Christian Menapace 2019-05-20 12:08:06 +02:00 committed by Johannes Meyer
parent 8f868d79c9
commit 98b6b2c6d0
13 changed files with 424 additions and 43 deletions

View file

@ -207,6 +207,11 @@ class AddNodeForm extends QuickForm
$this->addHostElement();
if ($host = $this->getSentValue('host')) {
$this->addServicesElement($host);
$this->addServiceOverrideCheckbox();
if ($this->getSentValue('service_override') === '1') {
$this->addServiceOverrideElements();
}
} else {
$this->setSubmitLabel($this->translate('Next'));
}
@ -253,6 +258,36 @@ class AddNodeForm extends QuickForm
]);
}
protected function addServiceOverrideCheckbox()
{
$this->addElement('checkbox', 'service_override', [
'ignore' => true,
'class' => 'autosubmit',
'label' => $this->translate('Override Service State'),
'description' => $this->translate('Enable service state overrides')
]);
}
protected function addServiceOverrideElements()
{
$elements = [];
foreach ($this->enumServiceStateList() as $state => $stateName) {
if ($state === 0) {
continue;
}
$this->addElement('select', $stateName, [
'label' => $this->translate($stateName),
'ignore' => true,
'multiOptions' => $this->optionalEnum($this->enumServiceStateList()),
]);
$elements[] = $stateName;
}
$this->addSimpleDisplayGroup($elements, 'override_group', [
'legend' => $this->translate('State Overrides')
]);
}
protected function selectProcess()
{
if ($this->hasParentNode()) {
@ -391,6 +426,34 @@ class AddNodeForm extends QuickForm
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 statesToString()
{
$stateString = null;
foreach ($this->enumServiceStateList() as $state => $stateName) {
if ($this->getValue($stateName) !== null && $this->getValue($stateName) !== '') {
if ($stateString !== null) {
$stateString .= ',';
}
$stateString .= $state . '-' . $this->getValue($stateName);
}
}
return $stateString;
}
protected function hasProcesses()
{
return count($this->enumProcesses()) > 0;
@ -464,8 +527,18 @@ class AddNodeForm extends QuickForm
{
$changes = ProcessChanges::construct($this->bp, $this->session);
switch ($this->getValue('node_type')) {
case 'host':
case 'service':
if ($this->statesToString() !== null) {
$services = [];
foreach ($this->getValue('children') as $service) {
$services[] = $service . ':' . $this->statesToString();
}
$changes->addChildrenToNode($services, $this->parent);
} else {
$changes->addChildrenToNode($this->getValue('children'), $this->parent);
}
break;
case 'host':
case 'process':
if ($this->hasParentNode()) {
$changes->addChildrenToNode($this->getValue('children'), $this->parent);

View file

@ -36,6 +36,8 @@ class EditNodeForm extends QuickForm
protected $host;
protected $statesOverride = [];
/** @var SessionNamespace */
protected $session;
@ -43,7 +45,8 @@ class EditNodeForm extends QuickForm
{
$this->host = substr($this->getNode()->getName(), 0, strpos($this->getNode()->getName(), ';'));
if ($this->isService()) {
$this->service = substr($this->getNode()->getName(), strpos($this->getNode()->getName(), ';') + 1);
$this->service = $this->getNode()->getShortName();
$this->statesOverride = $this->getNode()->getStatesOverride();
}
$view = $this->getView();
@ -190,8 +193,16 @@ class EditNodeForm extends QuickForm
if ($this->getSentValue('hosts') === null) {
$this->addServicesElement($this->host);
$this->addServiceOverrideCheckbox();
if (!empty($this->statesOverride) || $this->getSentValue('service_override') === '1') {
$this->addServiceOverrideElements();
}
} elseif ($host = $this->getSentValue('hosts')) {
$this->addServicesElement($host);
$this->addServiceOverrideCheckbox();
if ($this->getSentValue('service_override') === '1') {
$this->addServiceOverrideElements();
}
} else {
$this->setSubmitLabel($this->translate('Next'));
}
@ -214,14 +225,58 @@ class EditNodeForm extends QuickForm
{
$this->addElement('select', 'children', array(
'required' => true,
'value' => $this->getNode()->getName(),
'value' => $this->service,
'multiOptions' => $this->enumServiceList($host),
'label' => $this->translate('Service'),
'description' => $this->translate('The service for this business process node'),
'validators' => [[new NoDuplicateChildrenValidator($this, $this->bp, $this->parent), true]]
'validators' => [
['Callback', true, [
'callback' => function ($value) {
if ($this->node->getShortName() === $value) {
return true;
}
return ! $this->parent->hasMatchingChild($value);
},
'messages' => [
'callbackValue' => $this->translate('%value% is already defined in this process')
]
]]
]
));
}
protected function addServiceOverrideCheckbox()
{
$this->addElement('checkbox', 'service_override', [
'ignore' => true,
'class' => 'autosubmit',
'value' => ! empty($this->statesOverride) ? '1' : null,
'label' => $this->translate('Override Service State'),
'description' => $this->translate('Enable service state overrides')
]);
}
protected function addServiceOverrideElements()
{
$elements = [];
foreach ($this->enumServiceStateList() as $state => $stateName) {
if ($state == 0) {
continue;
}
$this->addElement('select', $stateName, [
'label' => $this->translate($stateName),
'value' => isset($this->statesOverride[$state]) ? $this->statesOverride[$state] : null,
'ignore' => true,
'multiOptions' => $this->optionalEnum($this->enumServiceStateList()),
]);
$elements[] = $stateName;
}
$this->addSimpleDisplayGroup($elements, 'override_group', [
'legend' => $this->translate('State Overrides')
]);
}
protected function selectProcess()
{
$this->addElement('multiselect', 'children', array(
@ -341,6 +396,34 @@ class EditNodeForm extends QuickForm
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 statesToString()
{
$stateString = null;
foreach ($this->enumServiceStateList() as $state => $stateName) {
if ($this->getValue($stateName) !== null && $this->getValue($stateName) !== '') {
if ($stateString !== null) {
$stateString .= ',';
}
$stateString .= $state . '-' . $this->getValue($stateName);
}
}
return $stateString;
}
protected function hasProcesses()
{
return count($this->enumProcesses()) > 0;
@ -405,8 +488,17 @@ class EditNodeForm extends QuickForm
$changes->deleteNode($this->node, $this->parent->getName());
switch ($this->getValue('node_type')) {
case 'host':
case 'service':
if ($this->statesToString() !== null) {
$changes->addChildrenToNode(
$this->getValue('children') . ':' . $this->statesToString(),
$this->parent
);
} else {
$changes->addChildrenToNode($this->getValue('children'), $this->parent);
}
break;
case 'host':
case 'process':
$changes->addChildrenToNode($this->getValue('children'), $this->parent);
break;

View file

@ -460,16 +460,21 @@ class BpConfig
return array_key_exists($name, $this->root_nodes);
}
public function createService($host, $service)
public function createService($host, $service, $statesOverride = null)
{
$node = new ServiceNode(
(object) array(
'hostname' => $host,
'service' => $service
'service' => $service,
'statesOverride'=> $statesOverride
)
);
$node->setBpConfig($this);
if (isset($statesOverride)) {
$this->nodes[$host . ';' . $service . ':' . $statesOverride] = $node;
} else {
$this->nodes[$host . ';' . $service] = $node;
}
$this->hosts[$host] = true;
return $node;
}
@ -657,6 +662,19 @@ class BpConfig
);
}
public function getMatchingNodeNams($name)
{
$matching = [];
foreach ($this->nodes as $nodeName => $node) {
if ($name === $node->getShortName()) {
$matching[] = $nodeName;
}
}
return $matching;
}
/**
* @return BpNode
*/

View file

@ -142,6 +142,11 @@ class BpNode extends Node
return in_array($name, $this->getChildNames());
}
public function hasMatchingChild($name)
{
return in_array($name, $this->getChildShortNames());
}
public function removeChild($name)
{
if (($key = array_search($name, $this->getChildNames())) !== false) {
@ -498,6 +503,20 @@ class BpNode extends Node
return $this->children;
}
protected function getChildShortNames()
{
$ChidrenShortNames = array();
foreach ($this->getChildren() as $child) {
$name = $child->getShortName();
array_push($ChidrenShortNames, $name);
}
return $ChidrenShortNames;
}
/**
* Reorder this node's children, in case manual order is not applied
*/

View file

@ -34,6 +34,10 @@ class NodeAddChildrenAction extends NodeAction
foreach ($this->children as $name) {
if (! $config->hasNode($name) || $config->getNode($name)->getBpConfig()->getName() !== $config->getName()) {
if (strpos($name, ';') !== false) {
if (strpos($name, ':') !== false) {
list($host, $service, $statesOverride) = preg_split('~[;:]~', $name, 3);
$config->createService($host, $service, $statesOverride);
} else {
list($host, $service) = preg_split('/;/', $name, 2);
if ($service === 'Hoststatus') {
@ -41,6 +45,7 @@ class NodeAddChildrenAction extends NodeAction
} else {
$config->createService($host, $service);
}
}
} elseif ($name[0] === '@' && strpos($name, ':') !== false) {
list($configName, $nodeName) = preg_split('~:\s*~', substr($name, 1), 2);
$config->createImportedNode($configName, $nodeName);

View file

@ -46,6 +46,8 @@ abstract class Node
self::NODE_EMPTY => 0
);
protected $stateOverride = [];
/** @var string Alias of the node */
protected $alias;
@ -197,6 +199,28 @@ abstract class Node
return $this;
}
protected function setStateOverride($state, $oveRrideState)
{
$this->stateOverride[(int) $state] = (int) $oveRrideState;
}
public function setStatesOverride($statesOverrideString)
{
$overrides = explode(',', $statesOverrideString);
foreach ($overrides as $overrideState) {
if (strpos($overrideState, '-') !== false) {
list($key, $value) = explode('-', $overrideState);
$this->setStateOverride($key, $value);
}
}
}
public function getStatesOverride()
{
return $this->stateOverride;
}
/**
* Forget my state
*
@ -246,6 +270,24 @@ abstract class Node
);
}
if (isset($this->stateOverride[$this->state])) {
return $this->stateOverride[$this->state];
} else {
return $this->state;
}
}
public function getRealState()
{
if ($this->state === null) {
throw new ProgrammingError(
sprintf(
'Node %s is unable to retrieve it\'s state',
$this->name
)
);
}
return $this->state;
}
@ -364,6 +406,11 @@ abstract class Node
return $this;
}
public function getShortName()
{
return $this->name;
}
public function hasParents()
{
return count($this->parents) > 0;

View file

@ -113,6 +113,15 @@ class NodeTile extends BaseHtmlElement
));
}
if ($node instanceof ServiceNode && $node->getRealState() !== $node->getState()) {
$this->add((new StateBall(strtolower($node->getStateName($node->getRealState()))))->addAttributes([
'title' => sprintf(
'%s',
$node->getStateName($node->getRealState())
)
]));
}
if ($node instanceof BpNode && !$renderer->isBreadcrumb()) {
$this->add(Html::tag(
'p',

View file

@ -136,6 +136,45 @@ class TreeRenderer extends Renderer
return $icons;
}
public function getNodeRealState(Node $node)
{
$realState = [];
$realState[] = Html::tag('i', ['class' => 'icon icon-flash']);
$realState[] = (new StateBall(strtolower($node->getStateName($node->getRealState()))))->addAttributes([
'title' => sprintf(
'%s',
$node->getStateName($node->getRealState())
)
]);
return $realState;
}
public function getNodeStateOverride(Node $node)
{
$statesOverrights = [];
$states = $node->getStatesOverride();
foreach ($states as $originalState => $overrideState) {
$statesOverrights[] = (new StateBall(strtolower($node->getStateName($originalState))))->addAttributes([
'title' => sprintf(
'%s',
$node->getStateName($originalState)
)
]);
$statesOverrights[] = Html::tag('i', ['class' => 'icon icon-right-small']);
$statesOverrights[] = (new StateBall(strtolower($node->getStateName($overrideState))))->addAttributes([
'title' => sprintf(
'%s',
$node->getStateName($overrideState)
),
'class' => 'last'
]);
}
return $statesOverrights;
}
/**
* @param BpConfig $bp
* @param Node $node
@ -243,10 +282,24 @@ class TreeRenderer extends Renderer
$link->getAttributes()->set('data-base-target', '_next');
$li->add($link);
if (! $this->isLocked() && $node->getBpConfig()->getName() === $this->getBusinessProcess()->getName()) {
$li->add($this->getActionIcons($bp, $node));
if ($node->getRealState() !== $node->getState()) {
$li->add($this->getNodeRealState($node));
}
$leftAlign = Html::tag('div', [
'class' => 'left-side',
]);
if (!empty($node->getStatesOverride())) {
$leftAlign->add($this->getNodeStateOverride($node));
}
if (! $this->isLocked() && $node->getBpConfig()->getName() === $this->getBusinessProcess()->getName()) {
$leftAlign->add($this->getActionIcons($bp, $node));
}
$li->add($leftAlign);
return $li;
}

View file

@ -19,7 +19,12 @@ class ServiceNode extends MonitoredNode
public function __construct($object)
{
if (isset($object->statesOverride)) {
$this->name = $object->hostname . ';' . $object->service . ':' . $object->statesOverride;
$this->setStatesOverride($object->statesOverride);
} else {
$this->name = $object->hostname . ';' . $object->service;
}
$this->hostname = $object->hostname;
$this->service = $object->service;
if (isset($object->state)) {
@ -68,6 +73,11 @@ class ServiceNode extends MonitoredNode
return $this->getHostAlias() . ': ' . $this->alias;
}
public function getShortName()
{
return $this->hostname . ';' . $this->service;
}
public function getUrl()
{
$params = array(

View file

@ -122,12 +122,14 @@ class MonitoringState
$key .= ';Hoststatus';
}
$nodesNames = $config->getMatchingNodeNams($key);
foreach ($nodesNames as $nodeName) {
// We fetch more states than we need, so skip unknown ones
if (! $config->hasNode($key)) {
if (! $config->hasNode($nodeName)) {
return;
}
$node = $config->getNode($key);
$node = $config->getNode($nodeName);
if ($row->state !== null) {
$node->setState($row->state)->setMissing(false);
@ -141,6 +143,7 @@ class MonitoringState
if ((int) $row->ack === 1) {
$node->setAck(true);
}
}
$node->setAlias($row->display_name);

View file

@ -334,14 +334,20 @@ class LegacyConfigParser
if (strpos($val, ';') !== false) {
if ($bp->hasNode($val)) {
$node->addChild($bp->getNode($val));
} else {
if (strpos($val, ':') !== false) {
list($host, $service, $statesOverride) = preg_split('~[;:]~', $val, 3);
$node->addChild($bp->createService($host, $service, $statesOverride));
} else {
list($host, $service) = preg_split('~;~', $val, 2);
if ($service === 'Hoststatus') {
$node->addChild($bp->createHost($host));
} else {
$node->addChild($bp->createService($host, $service));
}
}
}
} elseif ($val[0] === '@') {
if (strpos($val, ':') === false) {
throw new ConfigurationError(

View file

@ -43,7 +43,7 @@ class NoDuplicateChildrenValidator extends Zend_Validate_Abstract
} elseif ($this->form instanceof EditNodeForm && $this->form->getNode()->getName() === $value) {
$found = false;
} else {
$found = $this->parent->hasChild($value);
$found = $this->parent->hasMatchingChild($value);
}
if (! $found) {

View file

@ -214,12 +214,12 @@ ul.bp {
margin-right: .5em;
}
> a.action-link {
margin-left: auto; // Let the first action link move everything to the right
& + a.action-link {
margin-left: 0; // But really only the first one
a.action-link {
margin-left: 20px;
}
> .left-side {
margin-left: auto; // Left alligned Icons
}
}
@ -260,13 +260,18 @@ ul.bp {
}
li.process > div > .state-ball,
li:not(.process) > .state-ball {
li:not(.process) > .state-ball,
div.left-side > .state-ball {
border: .15em solid white;
&.size-s {
width: 7em/6em;
height: 7em/6em;
line-height: 7em/6em;
&.last {
margin-right: 10px;
}
}
}
}
@ -416,6 +421,14 @@ td > a > .badges {
font-size: 0.5em;
}
.state-ball {
position: absolute;
right: 0px;
bottom: 0px;
margin: 5px 5px 5px 5px;
border: 1px solid white;
}
> a {
display: block;
text-decoration: none;
@ -949,6 +962,39 @@ form dt label {
}
}
fieldset.collapsed {
dd, dt, ul, div {
display: none;
}
}
fieldset {
margin-top: 15px;
padding: 0 0 1.5em 0;
border: none;
legend {
margin: 0em 0 0.5em 0;
font-size: 1em;
box-shadow: 0 3px 4px -4px rgba(0,0,0,0.2);
font-weight: bold;
width: 100%;
padding-left: 0.5em;
line-height: 2em;
user-select: none;
&:hover {
border-color: @text-color;
}
}
dd, dt, ul, div {
display: none;
}
margin-bottom: 0.2em;
padding-bottom: 0;
}
form fieldset {
min-width: 36em;
}