BpApp: initial import of legacy version
87
application/clicommands/CheckCommand.php
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Bpapp\Clicommands;
|
||||
|
||||
use Icinga\Cli\Command;
|
||||
use Icinga\Module\Bpapp\BusinessProcess;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Module\Monitoring\Backend;
|
||||
|
||||
class CheckCommand extends Command
|
||||
{
|
||||
protected $config;
|
||||
protected $bpconf;
|
||||
protected $bpname;
|
||||
protected $views;
|
||||
protected $filename;
|
||||
protected $backend;
|
||||
|
||||
public function init()
|
||||
{
|
||||
$this->app->getModuleManager()->loadModule('monitoring');
|
||||
$this->config = Config::module($this->moduleName);
|
||||
$this->readConfig();
|
||||
$this->prepareBackend();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check a specific process
|
||||
*
|
||||
* Blabla
|
||||
*/
|
||||
public function processAction()
|
||||
{
|
||||
$bp = BusinessProcess::parse($this->filename);
|
||||
$node = $bp->getNode($this->params->shift());
|
||||
if ($this->params->get('soft-states')) {
|
||||
$bp->useSoftStates();
|
||||
}
|
||||
$bp->retrieveStatesFromBackend($this->backend);
|
||||
printf("Business Process %s: %s\n", $node->getStateName(), $node->getAlias());
|
||||
exit($node->getState());
|
||||
|
||||
}
|
||||
|
||||
// TODO: Remove this
|
||||
protected function prepareBackend()
|
||||
{
|
||||
if ($this->backend === null) {
|
||||
$name = $this->config->{'global'}->get('default_backend');
|
||||
if (isset($this->bpconf->backend)) {
|
||||
$name = $this->bpconf->backend;
|
||||
}
|
||||
$this->backend = Backend::createBackend($name);
|
||||
}
|
||||
return $this->backend;
|
||||
}
|
||||
|
||||
// TODO: Remove this
|
||||
protected function readConfig()
|
||||
{
|
||||
$this->views = array();
|
||||
$this->aliases = array();
|
||||
foreach ($this->config as $key => $val) {
|
||||
if (! preg_match('~^view-(.+)$~', $key, $match)) continue;
|
||||
$this->views[$match[1]] = (object) $val->toArray();
|
||||
$this->aliases[(string) $val->title] = $match[1];
|
||||
if ($val->aliases) {
|
||||
foreach (preg_split('~\s*,\s*~', $val->aliases, -1, PREG_SPLIT_NO_EMPTY) as $alias) {
|
||||
$this->aliases[$alias] = $match[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
$bpname = $this->params->get('bp', key($this->views));
|
||||
|
||||
if (array_key_exists($bpname, $this->aliases)) {
|
||||
$bpname = $this->aliases[$bpname];
|
||||
}
|
||||
if (! array_key_exists($bpname, $this->views)) {
|
||||
throw new Exception('Got invalid bp name: ' . $bpname);
|
||||
}
|
||||
$this->bpconf = $this->views[$bpname];
|
||||
$this->bpname = $bpname;
|
||||
|
||||
$this->filename = $this->config->global->bp_config_dir
|
||||
. '/' . $this->bpconf->file . '.conf';
|
||||
}
|
||||
}
|
||||
140
application/controllers/ProcessController.php
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
<?php
|
||||
|
||||
use Icinga\Module\Monitoring\Backend;
|
||||
use Icinga\Web\Controller\ModuleActionController;
|
||||
use Icinga\Module\Bpapp\BusinessProcess;
|
||||
use Icinga\Application\Config;
|
||||
use Icinga\Web\Widget;
|
||||
|
||||
class Bpapp_ProcessController extends ModuleActionController
|
||||
{
|
||||
protected $backend;
|
||||
protected $views;
|
||||
protected $aliases;
|
||||
protected $bpname;
|
||||
protected $bpconf;
|
||||
protected $filename;
|
||||
|
||||
public function init()
|
||||
{
|
||||
// $this->requireJs('bpaddon.js');
|
||||
$this->config = Config::module('bpapp');
|
||||
$this->readConfig();
|
||||
$this->prepareBackend();
|
||||
$this->view->showMenu = $this->_getParam('menu', 'enabled') === 'enabled';
|
||||
$this->view->tabs = $this->createTabs();
|
||||
}
|
||||
|
||||
protected function prepareBackend()
|
||||
{
|
||||
if ($this->backend === null) {
|
||||
$name = $this->config->{'global'}->default_backend;
|
||||
if (isset($this->bpconf->backend)) {
|
||||
$name = $this->bpconf->backend;
|
||||
}
|
||||
$this->view->backend = $name;
|
||||
$this->backend = Backend::createBackend($name);
|
||||
}
|
||||
return $this->backend;
|
||||
}
|
||||
|
||||
protected function createTabs()
|
||||
{
|
||||
// $tabs = $this->widget('tabs');
|
||||
$tabs = Widget::create('tabs');
|
||||
$action = $this->_request->getActionName();
|
||||
foreach ($this->views as $bpname => $bpconf) {
|
||||
$tabs->add($bpname, array(
|
||||
'url' => 'bpapp/process/' . $action,
|
||||
'urlParams' => array('bp' => $bpname),
|
||||
'title' => $bpconf->title,
|
||||
));
|
||||
}
|
||||
$tabs->activate($this->bpname);
|
||||
return $tabs;
|
||||
}
|
||||
|
||||
protected function readConfig()
|
||||
{
|
||||
$this->views = array();
|
||||
$this->aliases = array();
|
||||
foreach ($this->config as $key => $val) {
|
||||
if (! preg_match('~^view-(.+)$~', $key, $match)) continue;
|
||||
$this->views[$match[1]] = (object) $val->toArray();
|
||||
$this->aliases[(string) $val->title] = $match[1];
|
||||
if ($val->aliases) {
|
||||
foreach (preg_split('~\s*,\s*~', $val->aliases, -1, PREG_SPLIT_NO_EMPTY) as $alias) {
|
||||
$this->aliases[$alias] = $match[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->view->views = $this->views;
|
||||
$bpname = $this->_getParam('bp', key($this->views));
|
||||
|
||||
if (array_key_exists($bpname, $this->aliases)) {
|
||||
$bpname = $this->aliases[$bpname];
|
||||
}
|
||||
if (! array_key_exists($bpname, $this->views)) {
|
||||
throw new Exception('Got invalid bp name: ' . $bpname);
|
||||
}
|
||||
$this->bpconf = $this->views[$bpname];
|
||||
$this->view->bpname = $bpname;
|
||||
$this->bpname = $bpname;
|
||||
|
||||
$this->filename = $this->config->global->bp_config_dir
|
||||
. '/' . $this->bpconf->file . '.conf';
|
||||
}
|
||||
|
||||
public function sourceAction()
|
||||
{
|
||||
$this->view->title = 'Source: ' . $this->bpconf->title;
|
||||
$this->view->source = file_get_contents($this->filename);
|
||||
}
|
||||
|
||||
|
||||
public function historyAction()
|
||||
{
|
||||
$bp = BusinessProcess::parse($this->filename);
|
||||
echo '<pre>' . print_r($bp, 1) . '</pre>';
|
||||
exit;
|
||||
}
|
||||
|
||||
public function showAction()
|
||||
{
|
||||
$this->setAutoRefreshInterval(10);
|
||||
|
||||
$this->view->opened = $this->_getParam('opened');
|
||||
$this->view->compact = $this->_getParam('view') === 'compact';
|
||||
$bpconf = $this->bpconf;
|
||||
$this->view->title = 'Process: ' . $bpconf->title;
|
||||
|
||||
$bp = BusinessProcess::parse($this->filename);
|
||||
if ($this->_getParam('state_type') === 'soft'
|
||||
|| (isset($bpconf->states) && $bpconf->states === 'soft')) {
|
||||
$bp->useSoftStates();
|
||||
}
|
||||
$bp->retrieveStatesFromBackend($this->backend);
|
||||
$this->view->bp = $bp;
|
||||
|
||||
if (isset($bpconf->slahosts)) {
|
||||
$sla_hosts = preg_split('~\s*,s*~', $bpconf->slahosts, -1, PREG_SPLIT_NO_EMPTY);
|
||||
if (isset($bpconf->sla_year)) {
|
||||
$start = mktime(0, 0, 0, 1, 1, $bpconf->sla_year);
|
||||
$end = mktime(23, 59, 59, 1, 0, $bpconf->sla_year + 1);
|
||||
} else {
|
||||
$start = mktime(0, 0, 0, 1, 1, (int) date('Y'));
|
||||
$end = null;
|
||||
// Bis zum Jahresende hochrechnen:
|
||||
// $end = mktime(23, 59, 59, 1, 0, (int) date('Y') + 1);
|
||||
}
|
||||
$this->view->slas = $this->backend
|
||||
->module('BpAddon')
|
||||
->getBpSlaValues($sla_hosts, $start, $end);
|
||||
} else {
|
||||
$this->view->slas = array();
|
||||
}
|
||||
|
||||
$this->view->available_bps = $this->views;
|
||||
}
|
||||
}
|
||||
|
||||
94
application/views/scripts/process/history.phtml
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
$months = array(
|
||||
'Jänner',
|
||||
'Februar',
|
||||
'März',
|
||||
'April',
|
||||
'Mai',
|
||||
'Juni',
|
||||
'Juli',
|
||||
'August',
|
||||
'September',
|
||||
'Oktober',
|
||||
'November',
|
||||
'Dezember',
|
||||
);
|
||||
?><table style="width: 100%;">
|
||||
<tr>
|
||||
<th style="width: 10%;"> </th>
|
||||
<? for ($i = 1; $i <= 12; $i++): ?>
|
||||
<th style="width: 7.5%; border: 1px solid black;"><?= $months[$i - 1] ?></th>
|
||||
<? endfor ?>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div style="overflow: auto">
|
||||
<table>
|
||||
<tr>
|
||||
<? for ($i = 1; $i <= 12; $i++): ?>
|
||||
<td style="border-right: 1px solid black;"><div style="width: 600px; height: 1px; overflow: hidden;"> </div><?= $months[$i - 1] ?></td>
|
||||
<? endfor ?>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div style="overflow: auto; ">
|
||||
<?php
|
||||
|
||||
function stateColor($state)
|
||||
{
|
||||
switch($state) {
|
||||
case 0:
|
||||
$color = '#0f0';
|
||||
break;
|
||||
case 1:
|
||||
$color = 'orange';
|
||||
break;
|
||||
case 2:
|
||||
$color = '#f00';
|
||||
break;
|
||||
default: // und case 3
|
||||
$color = '#ccc';
|
||||
}
|
||||
return $color;
|
||||
}
|
||||
|
||||
$next_color = null;
|
||||
$color = null;
|
||||
|
||||
$start = mktime(0, 0, 0, 0, 0, (int) date('Y'));
|
||||
$current_offset = $start;
|
||||
$htm = '';
|
||||
$cnt = 0;
|
||||
$last_host = null;
|
||||
$last_service = null;
|
||||
foreach ($this->history as $entry) {
|
||||
if ($entry->hostname !== $last_host || $entry->service !== $last_service) {
|
||||
|
||||
echo '<span style="clear: both;" />' . "\n";
|
||||
}
|
||||
$cnt++;
|
||||
if ($cnt > 10000) break;
|
||||
$duration = $entry->timestamp - $current_offset;
|
||||
if ($next_color === null) {
|
||||
$color = stateColor($entry->last_state);
|
||||
} else {
|
||||
$color = $next_color;
|
||||
}
|
||||
$next_color = stateColor($entry->state);
|
||||
|
||||
if ($entry->state == 0) {
|
||||
$offset = ceil($duration / 3600 / 6);
|
||||
} else {
|
||||
$offset = floor($duration / 3600 / 6);
|
||||
}
|
||||
echo '<div style="overflow: hidden; height: 10px; float: left; width: ' . $offset . 'px; background-color:' . $color . ';"> </div>';
|
||||
$current_offset += $duration;
|
||||
|
||||
$last_host = $entry->hostname;
|
||||
$last_service = $entry->service;
|
||||
|
||||
}
|
||||
|
||||
|
||||
?></div>
|
||||
239
application/views/scripts/process/show.phtml
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
<?php
|
||||
|
||||
// TODO: This view script is pretty ugly. Clean the mess up, use existing
|
||||
// view helpers and create new ones (or Widgets) where needed
|
||||
|
||||
use Icinga\Module\Bpapp\BpNode;
|
||||
use Icinga\Module\Bpapp\ServiceNode;
|
||||
|
||||
if ($this->showMenu) {
|
||||
|
||||
if ($this->compact) {
|
||||
|
||||
} else {
|
||||
|
||||
?>
|
||||
<div class="controls">
|
||||
<?= $this->tabs ?>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
function stateName($state)
|
||||
{
|
||||
$names = array('ok', 'warning', 'critical', 'unknown');
|
||||
return $names[$state];
|
||||
}
|
||||
|
||||
function showNode($self, $node, & $slas = array(), $opened_param, $id_prefix = '', $level = 0, $hidden = false)
|
||||
{
|
||||
$opened = true;
|
||||
$htm = '';
|
||||
|
||||
$opened_list = array();
|
||||
foreach ($opened_param as $opened_cmps) {
|
||||
if (strstr($opened_cmps, '_') === false) {
|
||||
$key = $opened_cmps;
|
||||
$opened_cmps = false;
|
||||
} else {
|
||||
list($key, $opened_cmps) = preg_split('/_/', $opened_cmps, 2);
|
||||
}
|
||||
|
||||
if (! array_key_exists($key, $opened_list)) {
|
||||
$opened_list[$key] = array();
|
||||
}
|
||||
if ($opened_cmps) {
|
||||
$opened_list[$key][] = $opened_cmps;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ($node instanceof BpNode && $node->getState() == 0) {
|
||||
$opened = false;
|
||||
}
|
||||
if ($level > 0) $opened = false;
|
||||
$opened = false;
|
||||
|
||||
|
||||
// Example "open three problem levels"
|
||||
if ($node instanceof BpNode && $node->getState() > 0 && $level < 2) {
|
||||
// $opened = true;
|
||||
}
|
||||
|
||||
if ($hidden) {
|
||||
$opened = false;
|
||||
}
|
||||
|
||||
$id = $id_prefix . $node->getAlias();
|
||||
|
||||
if (array_key_exists(md5($id), $opened_list)) {
|
||||
$opened_list = $opened_list[md5($id)];
|
||||
$opened = true;
|
||||
} else {
|
||||
$opened_list = array();
|
||||
}
|
||||
if (! $opened) {
|
||||
$extra = ' collapsed';
|
||||
} else {
|
||||
$extra = '';
|
||||
}
|
||||
|
||||
$htm .= '<table class="'
|
||||
. ($level === 0 ? 'businessprocess' : '')
|
||||
. $extra
|
||||
. '" id="' . md5($id) . '" data-base-target="col2">';
|
||||
|
||||
|
||||
|
||||
if ($node->isMissing()) {
|
||||
$state_classes = 'state missing';
|
||||
} else {
|
||||
$state_classes = 'state ' . stateName($node->getState());
|
||||
}
|
||||
if ($node->isInDowntime() || $node->isAcknowledged()) {
|
||||
$state_classes .= ' handled';
|
||||
}
|
||||
|
||||
if ($node instanceof BpNode) {
|
||||
$htm .= '<tr><th colspan="2" class="' . $state_classes . ' bptitle">'
|
||||
. '<span class="collapsible"> </span>'
|
||||
. preg_replace('~^\d{2}\.\s*~', '', $node->getAlias());
|
||||
/* . ': '
|
||||
. $node->getState()
|
||||
. '/'
|
||||
. $node->getSortingState();
|
||||
*/
|
||||
if ($node->isInDowntime()) $htm .= ' <img src="' . $self->baseUrl('/img/bpapp/downtime.gif') . '" alt="" title="' . mt('bpapp', 'Downtime') . '" class="icon" />';
|
||||
if ($node->isAcknowledged()) $htm .= ' <img src="' . $self->baseUrl('/img/bpapp/ack.gif') . '" alt="" title="' . mt('bpapp', 'Acknowledged') . '" class="icon" />';
|
||||
|
||||
if ($node->hasUrl()) {
|
||||
$htm .= ' <a href="' . $node->getUrl() . '" title="'
|
||||
. mt('bpapp', 'More information') . ': ' . $node->getUrl()
|
||||
. '"><img src="'
|
||||
. $self->baseUrl('/img/bpapp/help.gif')
|
||||
. '" alt="" class="icon" /></a>';
|
||||
}
|
||||
|
||||
// Summaries, PIE
|
||||
if (! $self->compact) {
|
||||
$summary = $node->getStateSummary();
|
||||
$sumtxt = array();
|
||||
foreach ($summary as $k => $v) {
|
||||
if ($v > 0) {
|
||||
$sumtxt[] = $v . 'x ' . stateName($k);
|
||||
}
|
||||
}
|
||||
$sumtxt = implode(', ', $sumtxt);
|
||||
if ($sumtxt === '') $sumtxt = '-';
|
||||
if ($level === 0) {
|
||||
$htm .= '<span class="inlinepie" title="'
|
||||
. $sumtxt
|
||||
. '">'
|
||||
. implode(',', $node->getStateSummary())
|
||||
. '</span>';
|
||||
}
|
||||
}
|
||||
// END of PIE
|
||||
$alias = $node->getAlias();
|
||||
if (array_key_exists($alias, $slas)) {
|
||||
$sla = $slas[$alias];
|
||||
$sla_style = '';
|
||||
if ($sla->level === null) $sla->level = 0;
|
||||
if ($sla->value < $sla->level) {
|
||||
$sla_style = ' color: red; font-weight: bold;';
|
||||
} elseif ($sla->value < $sla->level * 1.002) {
|
||||
$sla_style = ' color: orange;';
|
||||
}
|
||||
$htm .= sprintf(' <span style="float: right; font-weight: normal;">[SLA] <span style="' . $sla_style . '">%0.3f%%</span> (Soll: %0.2f%%)</span>', $sla->value, $sla->level);
|
||||
}
|
||||
|
||||
|
||||
// Problem info:
|
||||
if ($node->getState() > 0) {
|
||||
$problems = array();
|
||||
foreach ($node->getChildren() as $child) {
|
||||
if ($child->getState() > 0) {
|
||||
$problems[] = '<span class="state ' . stateName($child->getState()) . '">' . htmlspecialchars($child->getAlias()) . '</span>';
|
||||
}
|
||||
}
|
||||
$htm .= ': <p class="problems">' . implode(', ', $problems) . '</p>';
|
||||
}
|
||||
// END of Problem Info
|
||||
|
||||
$htm .= "</th></tr>\n";
|
||||
|
||||
if ($node->hasChildren()) {
|
||||
$htm .= '<tr class="children">'
|
||||
. '<th class="' . $state_classes . ' operator"' . ($node->hasInfoCommand() ? ' rowspan="2"' : '') . '>'
|
||||
. $node->getOperator()
|
||||
. '</th><td>';
|
||||
//$htm .= '<!--';
|
||||
|
||||
if ($node->hasInfoCommand()) {
|
||||
$htm .= ' <b><i>' . nl2br(htmlspecialchars(strip_tags(
|
||||
|
||||
preg_replace('~(?:echo\s+(["\']))+(.+?)\1+~s', '$2',
|
||||
|
||||
preg_replace('~\<br\s*/?\>~', "\n", $node->getInfoCommand()
|
||||
|
||||
)
|
||||
)))) . '</i></b></td></tr><tr class="children"><td>';
|
||||
}
|
||||
//$htm .= '-->';
|
||||
|
||||
foreach ($node->getChildren() as $name => $child) {
|
||||
$htm .= showNode($self, $child, $slas, $opened_list, $id_prefix . $id . '_', $level + 1, ! $opened);
|
||||
}
|
||||
$htm .= "</td></tr>\n";
|
||||
}
|
||||
} else {
|
||||
$htm .= '<tr><td class="service ' . $state_classes . '">';
|
||||
if ($node->isInDowntime()) $htm .= ' <img src="' . $self->baseUrl('/img/bpapp/downtime.gif') . '" class="icon" alt="" />';
|
||||
if ($node->isAcknowledged()) $htm .= ' <img src="' . $self->baseUrl('/img/bpapp/ack.gif') . '" class="icon" alt="" />';
|
||||
$htm .= stateName($node->getState())
|
||||
. '</td><td><a href="'
|
||||
. $self->href('monitoring/show/host', array(
|
||||
'host' => $node->getHostname(),
|
||||
'backend' => $self->backend
|
||||
))
|
||||
. '">'
|
||||
. $node->getHostname()
|
||||
. '</a>'
|
||||
. ($node instanceof ServiceNode
|
||||
? ' / <a href="' . $self->href('monitoring/show/service', array(
|
||||
'host' => $node->getHostname(),
|
||||
'service' => $node->getServiceDescription(),
|
||||
'backend' => $self->backend
|
||||
)) . '">' . $node->getServiceDescription() . '</a>'
|
||||
: '')
|
||||
/* DEBUG
|
||||
. ': '
|
||||
. $node->getState()
|
||||
. '/'
|
||||
. $node->getSortingState()*/
|
||||
;
|
||||
$htm .= "</td></tr>\n";
|
||||
}
|
||||
|
||||
$htm .= '</table>';
|
||||
$htm .= "\n";
|
||||
return $htm;
|
||||
}
|
||||
|
||||
echo '<div class="content">';
|
||||
|
||||
if (! is_array($this->opened)) { $this->opened = array(); }
|
||||
|
||||
?><? foreach ($this->bp->getRootNodes() as $name => $node): ?>
|
||||
<?= showNode($this, $node, $this->slas, $this->opened, 'bp_') ?>
|
||||
<? endforeach ?>
|
||||
<? if ($this->bp->hasWarnings()): ?>
|
||||
<h2>Warnings</h2>
|
||||
<? foreach ($this->bp->getWarnings() as $warning): ?>
|
||||
<?= $this->escape($warning) ?><br />
|
||||
<? endforeach ?>
|
||||
<? endif ?>
|
||||
</div>
|
||||
22
application/views/scripts/process/source.phtml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
<div class="controls">
|
||||
<span style="float:right; margin-right: 1em; margin-top: 0.5em;">
|
||||
<a href="<?= $this->href('bpapp/process/show', array(
|
||||
'bp' => $this->bpname
|
||||
)) ?>">Render</a>
|
||||
</span>
|
||||
<?= $this->tabs ?>
|
||||
</div>
|
||||
<pre>
|
||||
<?php
|
||||
|
||||
$cnt = 0;
|
||||
$lines = preg_split('~\r?\n~', $this->source);
|
||||
$len = ceil(log(count($lines), 10));
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$cnt++;
|
||||
printf("%0" . $len . "d: %s\n", $cnt, $this->escape($line));
|
||||
}
|
||||
|
||||
?>
|
||||
</pre>
|
||||
8
configuration.php
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
|
||||
$section = $this->menuSection($this->translate('Availability'), array(
|
||||
'icon' => 'img/icons/servicegroup.png',
|
||||
'priority' => 40
|
||||
));
|
||||
$section->add($this->translate('Business Processes'))->setUrl('bpapp/process/show');
|
||||
|
||||
187
library/Bpapp/BpNode.php
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Bpapp;
|
||||
|
||||
use Exception;
|
||||
|
||||
class BpNode extends Node
|
||||
{
|
||||
const OP_AND = '&';
|
||||
const OP_OR = '|';
|
||||
protected $operator = '&';
|
||||
protected $url;
|
||||
protected $info_command;
|
||||
protected $display = 0;
|
||||
protected $children;
|
||||
protected $child_names = array();
|
||||
protected $alias;
|
||||
protected $counters;
|
||||
|
||||
public function __construct(
|
||||
BusinessProcess $bp,
|
||||
$object
|
||||
/*
|
||||
$name,
|
||||
$operator,
|
||||
$child_names
|
||||
*/
|
||||
) {
|
||||
$this->bp = $bp;
|
||||
$this->name = $object->name;
|
||||
$this->operator = $object->operator;
|
||||
$this->setChildNames($object->child_names);
|
||||
}
|
||||
|
||||
public function getStateSummary()
|
||||
{
|
||||
if ($this->counters === null) {
|
||||
$this->getState();
|
||||
$this->counters = array(0, 0, 0, 0);
|
||||
foreach ($this->children as $child) {
|
||||
if ($child instanceof BpNode) {
|
||||
$counters = $child->getStateSummary();
|
||||
foreach ($counters as $k => $v) {
|
||||
$this->counters[$k] += $v;
|
||||
}
|
||||
} else {
|
||||
$state = $child->getState();
|
||||
$this->counters[$state]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $this->counters;
|
||||
}
|
||||
|
||||
public function getOperator()
|
||||
{
|
||||
return $this->operator;
|
||||
}
|
||||
|
||||
public function setUrl($url)
|
||||
{
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
public function hasUrl()
|
||||
{
|
||||
return $this->url !== null;
|
||||
}
|
||||
|
||||
public function setInfoCommand($cmd)
|
||||
{
|
||||
$this->info_command = $cmd;
|
||||
}
|
||||
|
||||
public function hasInfoCommand()
|
||||
{
|
||||
return $this->info_command !== null;
|
||||
}
|
||||
|
||||
public function getUrl()
|
||||
{
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
public function getInfoCommand()
|
||||
{
|
||||
return $this->info_command;
|
||||
}
|
||||
|
||||
public function getAlias()
|
||||
{
|
||||
return $this->alias;
|
||||
}
|
||||
|
||||
public function setAlias($name)
|
||||
{
|
||||
$this->alias = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getState()
|
||||
{
|
||||
if ($this->state === null) {
|
||||
$this->calculateState();
|
||||
}
|
||||
return $this->state;
|
||||
}
|
||||
|
||||
protected function calculateState()
|
||||
{
|
||||
$sort_states = array();
|
||||
foreach ($this->getChildren() as $child) {
|
||||
$sort_states[] = $child->getSortingState();
|
||||
}
|
||||
switch ($this->operator) {
|
||||
case self::OP_AND:
|
||||
$state = max($sort_states);
|
||||
break;
|
||||
case self::OP_OR:
|
||||
$state = min($sort_states);
|
||||
break;
|
||||
default:
|
||||
// MIN:
|
||||
if (! is_numeric($this->operator)) {
|
||||
throw new Exception(
|
||||
sprintf(
|
||||
'Got invalid operator: %s',
|
||||
$this->operator
|
||||
)
|
||||
);
|
||||
}
|
||||
sort($sort_states);
|
||||
|
||||
// default -> unknown
|
||||
$state = 2 << self::SHIFT_FLAGS;
|
||||
|
||||
for ($i = 1; $i <= $this->operator; $i++) {
|
||||
$state = array_shift($sort_states);
|
||||
}
|
||||
}
|
||||
if ($state & self::FLAG_DOWNTIME) {
|
||||
$this->setDowntime(true);
|
||||
}
|
||||
if ($state & self::FLAG_ACK) {
|
||||
$this->setAck(true);
|
||||
}
|
||||
$state = $state >> self::SHIFT_FLAGS;
|
||||
|
||||
if ($state === 3) {
|
||||
$this->state = 2;
|
||||
} elseif ($state === 2) {
|
||||
$this->state = 3;
|
||||
} else {
|
||||
$this->state = $state;
|
||||
}
|
||||
}
|
||||
|
||||
public function hasChildren()
|
||||
{
|
||||
return count($this->children) > 0;
|
||||
}
|
||||
|
||||
public function setDisplay($display)
|
||||
{
|
||||
$this->display = $display;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setChildNames($names)
|
||||
{
|
||||
$this->child_names = $names;
|
||||
$this->children = null;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getChildren()
|
||||
{
|
||||
if ($this->children === null) {
|
||||
$this->children = array();
|
||||
natsort($this->child_names);
|
||||
foreach ($this->child_names as $name) {
|
||||
$this->children[$name] = $this->bp->getNode($name);
|
||||
}
|
||||
}
|
||||
return $this->children;
|
||||
}
|
||||
}
|
||||
309
library/Bpapp/BusinessProcess.php
Normal file
|
|
@ -0,0 +1,309 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Bpapp;
|
||||
|
||||
use Exception;
|
||||
|
||||
class BusinessProcess
|
||||
{
|
||||
const SOFT_STATE = 0;
|
||||
const HARD_STATE = 1;
|
||||
protected $ido;
|
||||
protected $filename;
|
||||
protected $parsing_line_number;
|
||||
protected $bps;
|
||||
protected $state_type = self::HARD_STATE;
|
||||
protected $warnings = array();
|
||||
protected $nodes = array();
|
||||
// protected $object_ids = array();
|
||||
protected $root_nodes = array();
|
||||
protected $all_checks = array();
|
||||
protected $hosts = array();
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
}
|
||||
/*
|
||||
public function getObjectIds()
|
||||
{
|
||||
return array_keys($this->object_ids);
|
||||
}
|
||||
*/
|
||||
|
||||
public static function parse($filename)
|
||||
{
|
||||
$bp = new BusinessProcess();
|
||||
$bp->filename = $filename;
|
||||
$bp->doParse();
|
||||
return $bp;
|
||||
}
|
||||
|
||||
public function useSoftStates()
|
||||
{
|
||||
$this->state_type = self::SOFT_STATE;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function useHardStates()
|
||||
{
|
||||
$this->state_type = self::HARD_STATE;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function doParse()
|
||||
{
|
||||
$fh = @fopen($this->filename, 'r');
|
||||
if (! $fh) {
|
||||
throw new Exception('Could not open ' . $this->filename);
|
||||
}
|
||||
|
||||
$this->parsing_line_number = 0;
|
||||
while ($line = fgets($fh)) {
|
||||
$line = trim($line);
|
||||
|
||||
$this->parsing_line_number++;
|
||||
|
||||
if (preg_match('~^#~', $line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (preg_match('~^$~', $line)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (preg_match('~^display~', $line)) {
|
||||
list($display, $name, $desc) = preg_split('~\s*;\s*~', substr($line, 8), 3);
|
||||
$node = $this->getNode($name)->setAlias($desc)->setDisplay($display);
|
||||
if ($display > 0) {
|
||||
$this->root_nodes[$name] = $node;
|
||||
}
|
||||
}
|
||||
|
||||
if (preg_match('~^external_info~', $line)) {
|
||||
list($name, $script) = preg_split('~\s*;\s*~', substr($line, 14), 2);
|
||||
$node = $this->getNode($name)->setInfoCommand($script);
|
||||
}
|
||||
|
||||
if (preg_match('~^info_url~', $line)) {
|
||||
list($name, $url) = preg_split('~\s*;\s*~', substr($line, 9), 2);
|
||||
$node = $this->getNode($name)->setUrl($url);
|
||||
}
|
||||
|
||||
if (strpos($line, '=') === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list($name, $value) = preg_split('~\s*=\s*~', $line, 2);
|
||||
|
||||
if (strpos($name, ';') !== false) {
|
||||
$this->parseError('No semicolon allowed in varname');
|
||||
}
|
||||
|
||||
$op = '&';
|
||||
if (preg_match_all('~([\|\+&])~', $value, $m)) {
|
||||
$op = implode('', $m[1]);
|
||||
for ($i = 1; $i < strlen($op); $i++) {
|
||||
if ($op[$i] !== $op[$i - 1]) {
|
||||
$this->parseError('Mixing operators is not allowed');
|
||||
}
|
||||
}
|
||||
}
|
||||
$op = $op[0];
|
||||
$op_name = $op;
|
||||
|
||||
if ($op === '+') {
|
||||
if (! preg_match('~^(\d+)\s*of:\s*(.+?)$~', $value, $m)) {
|
||||
$this->parseError('syntax: <var> = <num> of: <var1> + <var2> [+ <varn>]*');
|
||||
}
|
||||
$op_name = $m[1];
|
||||
$value = $m[2];
|
||||
}
|
||||
$cmps = preg_split('~\s*\\' . $op . '\s*~', $value);
|
||||
|
||||
foreach ($cmps as & $val) {
|
||||
if (strpos($val, ';') !== false) {
|
||||
list($host, $service) = preg_split('~;~', $val, 2);
|
||||
$this->all_checks[$val] = 1;
|
||||
$this->hosts[$host] = 1;
|
||||
}
|
||||
}
|
||||
$node = new BpNode($this, (object) array(
|
||||
'name' => $name,
|
||||
'operator' => $op_name,
|
||||
'child_names' => $cmps
|
||||
));
|
||||
$this->addNode($name, $node);
|
||||
}
|
||||
|
||||
fclose($fh);
|
||||
unset($this->parsing_line_number);
|
||||
}
|
||||
|
||||
public function retrieveStatesFromBackend($backend)
|
||||
{
|
||||
$this->backend = $backend;
|
||||
// TODO: Split apart, create a dedicated function.
|
||||
// Separate "parse-logic" from "retrieve-state-logic"
|
||||
// Allow DB-based backend
|
||||
// Use IcingaWeb2 Multi-Backend-Support
|
||||
$check_results = array();
|
||||
$hostFilter = array_keys($this->hosts);
|
||||
if ($this->state_type === self::HARD_STATE) {
|
||||
$db_states = $this->backend/*->module('Bpapp')*/
|
||||
->fetchHardStatesForBpHosts(array_keys($this->hosts));
|
||||
} else {
|
||||
// TOM 2014
|
||||
// $db_states = $this->backend/*->module('Bpapp')*/
|
||||
// ->fetchSoftStatesForBpHosts(array_keys($this->hosts));
|
||||
$hostStatus = $backend->select()->from(
|
||||
'hostStatus',
|
||||
array(
|
||||
'hostname' => 'host_name',
|
||||
'in_downtime' => 'host_in_downtime',
|
||||
'ack' => 'host_acknowledged',
|
||||
'state' => 'host_state'
|
||||
)
|
||||
)->where('host_name', $hostFilter)->getQuery()->fetchAll();
|
||||
$serviceStatus = $backend->select()->from(
|
||||
'serviceStatus',
|
||||
array(
|
||||
'hostname' => 'host_name',
|
||||
'service' => 'service_description',
|
||||
'in_downtime' => 'service_in_downtime',
|
||||
'ack' => 'service_acknowledged',
|
||||
'state' => 'service_state'
|
||||
)
|
||||
)->where('host_name', $hostFilter)->getQuery()->fetchAll();
|
||||
|
||||
}
|
||||
|
||||
foreach ($serviceStatus + $hostStatus as $row) {
|
||||
$key = $row->hostname;
|
||||
if ($row->service) {
|
||||
$key .= ';' . $row->service;
|
||||
// Ignore unused services, we are fetching more than we need
|
||||
if (! array_key_exists($key, $this->all_checks)) {
|
||||
continue;
|
||||
}
|
||||
$node = new ServiceNode($this, $row);
|
||||
// $this->object_ids[$row->object_id] = 1;
|
||||
} else {
|
||||
$key .= ';Hoststatus';
|
||||
if (! array_key_exists($key, $this->all_checks)) {
|
||||
continue;
|
||||
}
|
||||
$node = new HostNode($this, $row);
|
||||
// $this->object_ids[$row->object_id] = 1;
|
||||
}
|
||||
if ($row->state === null) {
|
||||
$node = new ServiceNode(
|
||||
$this,
|
||||
(object) array(
|
||||
'hostname' => $row->hostname,
|
||||
'service' => $row->service,
|
||||
'state' => 0
|
||||
)
|
||||
);
|
||||
$node->setMissing();
|
||||
}
|
||||
if ((int) $row->in_downtime === 1) {
|
||||
$node->setDowntime(true);
|
||||
}
|
||||
if ((int) $row->ack === 1) {
|
||||
$node->setAck(true);
|
||||
}
|
||||
$this->addNode($key, $node);
|
||||
}
|
||||
ksort($this->root_nodes);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getRootNodes()
|
||||
{
|
||||
return $this->root_nodes;
|
||||
}
|
||||
|
||||
public function hasNode($name)
|
||||
{
|
||||
return array_key_exists($name, $this->nodes);
|
||||
}
|
||||
|
||||
public function getNode($name)
|
||||
{
|
||||
if (array_key_exists($name, $this->nodes)) {
|
||||
return $this->nodes[$name];
|
||||
}
|
||||
|
||||
// Fallback: if it is a service, create an empty one:
|
||||
$this->warn(sprintf('The node "%s" doesn\'t exist', $name));
|
||||
$pos = strpos($name, ';');
|
||||
if ($pos !== false) {
|
||||
$host = substr($name, 0, $pos);
|
||||
$service = substr($name, $pos + 1);
|
||||
$node = new ServiceNode(
|
||||
$this,
|
||||
(object) array(
|
||||
'hostname' => $host,
|
||||
'service' => $service,
|
||||
'state' => 0
|
||||
)
|
||||
);
|
||||
$node->setMissing();
|
||||
return $node;
|
||||
}
|
||||
|
||||
throw new Exception(
|
||||
sprintf('The node "%s" doesn\'t exist', $name)
|
||||
);
|
||||
}
|
||||
|
||||
protected function addNode($name, Node $node)
|
||||
{
|
||||
if (array_key_exists($name, $this->nodes)) {
|
||||
$this->warn(
|
||||
sprintf(
|
||||
'Node "%s" has been defined twice',
|
||||
$name
|
||||
)
|
||||
);
|
||||
}
|
||||
$this->nodes[$name] = $node;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasWarnings()
|
||||
{
|
||||
return ! empty($this->warnings);
|
||||
}
|
||||
|
||||
public function getWarnings()
|
||||
{
|
||||
return $this->warnings;
|
||||
}
|
||||
|
||||
protected function warn($msg)
|
||||
{
|
||||
if (isset($this->parsing_line_number)) {
|
||||
$this->warnings[] = sprintf(
|
||||
'Parser waring on %s:%s: %s',
|
||||
$this->filename,
|
||||
$this->parsing_line_number,
|
||||
$msg
|
||||
);
|
||||
} else {
|
||||
$this->warnings[] = $msg;
|
||||
}
|
||||
}
|
||||
|
||||
protected function parseError($msg)
|
||||
{
|
||||
throw new Exception(
|
||||
sprintf(
|
||||
'Parse error on %s:%s: %s',
|
||||
$this->filename,
|
||||
$this->parsing_line_number,
|
||||
$msg
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
21
library/Bpapp/HostNode.php
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Bpapp;
|
||||
|
||||
class HostNode extends Node
|
||||
{
|
||||
protected $hostname;
|
||||
|
||||
public function __construct(BusinessProcess $bp, $object)
|
||||
{
|
||||
$this->name = $object->hostname . ';Hoststate';
|
||||
$this->hostname = $object->hostname;
|
||||
$this->bp = $bp;
|
||||
$this->setState($object->state);
|
||||
}
|
||||
|
||||
public function getHostname()
|
||||
{
|
||||
return $this->hostname;
|
||||
}
|
||||
}
|
||||
158
library/Bpapp/Node.php
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Bpapp;
|
||||
|
||||
use Exception;
|
||||
|
||||
abstract class Node
|
||||
{
|
||||
const FLAG_DOWNTIME = 1;
|
||||
const FLAG_ACK = 2;
|
||||
const FLAG_MISSING = 4;
|
||||
const FLAG_NONE = 8;
|
||||
const SHIFT_FLAGS = 4;
|
||||
|
||||
protected $bp;
|
||||
protected $parent;
|
||||
protected $name;
|
||||
protected $state;
|
||||
protected $description;
|
||||
# protected $flags = 0;
|
||||
protected $ack;
|
||||
protected $downtime;
|
||||
protected $recent_problems = array();
|
||||
protected $duration;
|
||||
protected $missing = false;
|
||||
|
||||
protected static $state_names = array(
|
||||
'OK',
|
||||
'WARNING',
|
||||
'CRITICAL',
|
||||
'UNKNOWN'
|
||||
);
|
||||
|
||||
abstract public function __construct(BusinessProcess $bp, $object);
|
||||
|
||||
public function setMissing($missing = true)
|
||||
{
|
||||
$this->missing = $missing;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isMissing()
|
||||
{
|
||||
return $this->missing;
|
||||
}
|
||||
|
||||
public function addChild(Node $node)
|
||||
{
|
||||
if (array_key_exists((string) $node, $this->children)) {
|
||||
throw new Exception(
|
||||
sprintf(
|
||||
'Node "%s" has been defined more than once',
|
||||
$node
|
||||
)
|
||||
);
|
||||
}
|
||||
$this->childs[(string) $node] = $node;
|
||||
$node->setParent($this);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setState($state)
|
||||
{
|
||||
$this->state = (int) $state;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setAck($ack = true)
|
||||
{
|
||||
$this->ack = $ack;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setDowntime($downtime = true)
|
||||
{
|
||||
$this->downtime = $downtime;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStateName()
|
||||
{
|
||||
return self::$state_names[ $this->getState() ];
|
||||
}
|
||||
|
||||
public function getState()
|
||||
{
|
||||
if ($this->state === null) {
|
||||
throw new Exception(
|
||||
sprintf(
|
||||
'Node %s is unable to retrieve it\'s state',
|
||||
$this->name
|
||||
)
|
||||
);
|
||||
}
|
||||
return $this->state;
|
||||
}
|
||||
|
||||
public function getSortingState()
|
||||
{
|
||||
$state = $this->getState();
|
||||
if ($state === 3) {
|
||||
$state = 2;
|
||||
} elseif ($state === 2) {
|
||||
$state = 3;
|
||||
}
|
||||
$state = ($state << self::SHIFT_FLAGS)
|
||||
+ ($this->isInDowntime() ? self::FLAG_DOWNTIME : 0)
|
||||
+ ($this->isAcknowledged() ? self::FLAG_ACK : 0);
|
||||
if (! ($state & (self::FLAG_DOWNTIME | self::FLAG_ACK))) {
|
||||
$state |= self::FLAG_NONE;
|
||||
}
|
||||
return $state;
|
||||
}
|
||||
|
||||
public function setParent(Node $parent)
|
||||
{
|
||||
$this->parent = $parent;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDuration()
|
||||
{
|
||||
return $this->duration;
|
||||
}
|
||||
|
||||
public function isInDowntime()
|
||||
{
|
||||
if ($this->downtime === null) {
|
||||
$this->getState();
|
||||
}
|
||||
return $this->downtime;
|
||||
}
|
||||
|
||||
public function isAcknowledged()
|
||||
{
|
||||
if ($this->ack === null) {
|
||||
$this->getState();
|
||||
}
|
||||
return $this->ack;
|
||||
}
|
||||
|
||||
public function hasChildren()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
// required to avoid memleeks in PHP < 5.3:
|
||||
$this->parent = null;
|
||||
$this->children = array();
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
33
library/Bpapp/ServiceNode.php
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
|
||||
namespace Icinga\Module\Bpapp;
|
||||
|
||||
class ServiceNode extends Node
|
||||
{
|
||||
protected $hostname;
|
||||
protected $service;
|
||||
|
||||
public function __construct(BusinessProcess $bp, $object)
|
||||
{
|
||||
$this->name = $object->hostname . ';' . $object->service;
|
||||
$this->hostname = $object->hostname;
|
||||
$this->service = $object->service;
|
||||
$this->bp = $bp;
|
||||
$this->setState($object->state);
|
||||
}
|
||||
|
||||
public function getHostname()
|
||||
{
|
||||
return $this->hostname;
|
||||
}
|
||||
|
||||
public function getServiceDescription()
|
||||
{
|
||||
return $this->service;
|
||||
}
|
||||
|
||||
public function getAlias()
|
||||
{
|
||||
return $this->hostname . ': ' . $this->service;
|
||||
}
|
||||
}
|
||||
5
module.info
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
Name: BPapp
|
||||
Version: 0.0.1
|
||||
Depends: monitoring
|
||||
Description: BPapp is a viewer for BPaddon business process config files
|
||||
That's it
|
||||
192
public/css/module.less
Normal file
|
|
@ -0,0 +1,192 @@
|
|||
|
||||
.content a {
|
||||
color: #333;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.content a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
table.businessprocess, table.businessprocess table {
|
||||
border-collapse: collapse;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table.businessprocess {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
table.businessprocess tr {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: Verdana, Helvetica, Arial, sans-serif;
|
||||
font-size: 0.97em;
|
||||
}
|
||||
|
||||
table.businessprocess tr tr tr tr {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
table.businessprocess th, table.businessprocess td {
|
||||
margin: 0;
|
||||
padding: 0.3em 0 0 0.3em;
|
||||
text-align: left;
|
||||
vertical-align: middle;
|
||||
line-height: 1.7em;
|
||||
}
|
||||
|
||||
table.businessprocess th {
|
||||
/* IE? */
|
||||
padding: 0.2em 1em 0.2em 1em;
|
||||
cursor: pointer;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
table.businessprocess th.hovered.state {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
table.businessprocess th.bptitle {
|
||||
border-radius: 0.5em 0.5em 0.5em 0;
|
||||
-moz-border-radius: 0.5em 0.5em 0.5em 0;
|
||||
}
|
||||
|
||||
table.collapsed > tbody > tr > th.bptitle {
|
||||
border-radius: 0.5em;
|
||||
-moz-border-radius: 0.5em;
|
||||
}
|
||||
|
||||
table.businessprocess th.operator {
|
||||
width: 1em;
|
||||
padding: 0.5em;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
border-radius: 0 0 0.5em 0.5em;
|
||||
-moz-border-radius: 0 0 0.5em 0.5em;
|
||||
|
||||
}
|
||||
|
||||
table.businessprocess td.service {
|
||||
border-radius: 0.5em;
|
||||
-moz-border-radius: 0.5;
|
||||
width: 6em;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
table.businessprocess td.service img {
|
||||
float: left;
|
||||
}
|
||||
|
||||
table.businessprocess, table.businessprocess table {
|
||||
border-top: 2px solid transparent;
|
||||
border-left: 2px solid transparent;
|
||||
}
|
||||
|
||||
table.businessprocess .state {
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.state.unknown {
|
||||
background-color: @colorUnknown;
|
||||
}
|
||||
|
||||
.state.critical {
|
||||
background-color: @colorCritical;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.state.critical.handled {
|
||||
background-color: @colorCriticalHandled;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.state.warning {
|
||||
background-color: @colorWarning;
|
||||
}
|
||||
|
||||
.state.unknown.handled {
|
||||
background-color: @colorUnknownHandled;
|
||||
}
|
||||
|
||||
.state.pending {
|
||||
background-color: @colorPending;
|
||||
}
|
||||
|
||||
.state.warning.handled {
|
||||
background-color: @colorWarningHandled;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.state.ok {
|
||||
background-color: @colorOk;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
th.hovered.state.unknown {
|
||||
background-color: #aac;
|
||||
}
|
||||
|
||||
table.businessprocess th p.problems {
|
||||
font-weight: normal;
|
||||
font-size: 0.7em;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.collapsed > tbody > tr > th > p.problems {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
table.businessprocess th p.problems span {
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
table.businessprocess th.hovered p.problems > .state {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
span.collapsible {
|
||||
background-image: url("../img/bpapp/icon_collapse.png");
|
||||
background-repeat: no-repeat;
|
||||
width: 1.7em;
|
||||
height: 1.7em;
|
||||
background-position: left center;
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.collapsed span.collapsible {
|
||||
background: url("../img/bpapp/icon_expand.png");
|
||||
background-repeat: no-repeat;
|
||||
background-position: left center;
|
||||
}
|
||||
|
||||
.collapsed tr.children {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.inlinepie {
|
||||
display: none;
|
||||
width: 2em;
|
||||
float: right;
|
||||
margin-top: 0.1em;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
BIN
public/img/ack.gif
Normal file
|
After Width: | Height: | Size: 564 B |
BIN
public/img/downtime.gif
Normal file
|
After Width: | Height: | Size: 601 B |
BIN
public/img/help.gif
Normal file
|
After Width: | Height: | Size: 1 KiB |
BIN
public/img/icon_collapse.png
Normal file
|
After Width: | Height: | Size: 178 B |
BIN
public/img/icon_expand.png
Normal file
|
After Width: | Height: | Size: 177 B |
BIN
public/img/op_and.png
Normal file
|
After Width: | Height: | Size: 680 B |
BIN
public/img/op_min1.png
Normal file
|
After Width: | Height: | Size: 574 B |
BIN
public/img/op_min2.png
Normal file
|
After Width: | Height: | Size: 626 B |
BIN
public/img/op_min3.png
Normal file
|
After Width: | Height: | Size: 652 B |
BIN
public/img/op_min4.png
Normal file
|
After Width: | Height: | Size: 606 B |
BIN
public/img/op_min5.png
Normal file
|
After Width: | Height: | Size: 633 B |
BIN
public/img/op_min6.png
Normal file
|
After Width: | Height: | Size: 664 B |
BIN
public/img/op_min7.png
Normal file
|
After Width: | Height: | Size: 631 B |
BIN
public/img/op_min8.png
Normal file
|
After Width: | Height: | Size: 660 B |
BIN
public/img/op_min9.png
Normal file
|
After Width: | Height: | Size: 647 B |
BIN
public/img/op_or.png
Normal file
|
After Width: | Height: | Size: 591 B |
144
public/js/module.js
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
|
||||
(function(Icinga) {
|
||||
|
||||
var Bp = function(module) {
|
||||
/**
|
||||
* YES, we need Icinga
|
||||
*/
|
||||
this.module = module;
|
||||
|
||||
this.initialize();
|
||||
|
||||
this.module.icinga.logger.debug('BP module loaded');
|
||||
};
|
||||
|
||||
Bp.prototype = {
|
||||
|
||||
initialize: function()
|
||||
{
|
||||
/**
|
||||
* Tell Icinga about our event handlers
|
||||
*/
|
||||
this.module.on('mouseenter', 'table.businessprocess th.bptitle', this.titleMouseOver);
|
||||
this.module.on('mouseleave', 'table.businessprocess th.bptitle', this.titleMouseOut);
|
||||
this.module.on('click', 'table.businessprocess th', this.titleClicked);
|
||||
this.module.on('rendered', this.fixOpenedBps);
|
||||
|
||||
this.module.icinga.logger.debug('BP module loaded');
|
||||
},
|
||||
|
||||
/**
|
||||
* Add 'hovered' class to hovered title elements
|
||||
*
|
||||
* TODO: Skip on tablets
|
||||
*/
|
||||
titleMouseOver: function (event) {
|
||||
event.stopPropagation();
|
||||
var el = $(event.currentTarget);
|
||||
el.addClass('hovered');
|
||||
},
|
||||
|
||||
/**
|
||||
* Remove 'hovered' class from hovered title elements
|
||||
*
|
||||
* TODO: Skip on tablets
|
||||
*/
|
||||
titleMouseOut: function (event) {
|
||||
event.stopPropagation();
|
||||
var el = $(event.currentTarget);
|
||||
el.removeClass('hovered');
|
||||
},
|
||||
|
||||
/**
|
||||
* Handle clicks on operator or title element
|
||||
*
|
||||
* Title shows subelement, operator unfolds all subelements
|
||||
*/
|
||||
titleClicked: function (event) {
|
||||
var self = this;
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
var $el = $(event.currentTarget),
|
||||
affected = []
|
||||
$container = $el.closest('.container');
|
||||
if ($el.hasClass('operator')) {
|
||||
$affected = $el.closest('table').children('tbody')
|
||||
.children('tr.children').children('td').children('table');
|
||||
|
||||
// Only if there are child BPs
|
||||
if ($affected.find('th.operator').length < 1) {
|
||||
$affected = $el.closest('table');
|
||||
}
|
||||
} else {
|
||||
$affected = $el.closest('table');
|
||||
}
|
||||
$affected.each(function (key, el) {
|
||||
var $bptable = $(el).closest('table');
|
||||
$bptable.toggleClass('collapsed');
|
||||
if ($bptable.hasClass('collapsed')) {
|
||||
$bptable.find('table').addClass('collapsed');
|
||||
}
|
||||
});
|
||||
|
||||
$container.data('refreshParams', {
|
||||
opened: self.listOpenedBps($container)
|
||||
});
|
||||
},
|
||||
|
||||
fixOpenedBps: function(event) {
|
||||
var $container = $(event.currentTarget);
|
||||
var opened = $container.data('refreshParams');
|
||||
if (typeof opened === 'undefined' || typeof opened.opened === 'undefined') {
|
||||
return;
|
||||
}
|
||||
|
||||
opened = opened.opened;
|
||||
$.each(opened, function(idx, ids) {
|
||||
$.each(ids.split('_'), function(idx, id) {
|
||||
$('#' + id, $container).removeClass('collapsed');
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Get a list of all currently opened BPs.
|
||||
*
|
||||
* Only get the deepest nodes to keep requests as small as possible
|
||||
*/
|
||||
listOpenedBps: function ($container) {
|
||||
var ids = [];
|
||||
|
||||
$('.businessprocess', $container).add('.businessprocess table', $container)
|
||||
.not('.collapsed').each(function (key, el) {
|
||||
var $el = $(el);
|
||||
if ($el.find('table').not('.collapsed').length === 0) {
|
||||
var search = true,
|
||||
this_id = $el.attr('id'),
|
||||
cnt = 0,
|
||||
current = el,
|
||||
parent;
|
||||
while (search && cnt < 40) {
|
||||
cnt++;
|
||||
parent = $(current).parent().closest('table')[0];
|
||||
if (!parent || $(parent).hasClass('bps')) {
|
||||
search = false;
|
||||
} else {
|
||||
current = parent;
|
||||
this_id = parent.id + '_' + this_id;
|
||||
}
|
||||
}
|
||||
|
||||
if (this_id) {
|
||||
ids.push(this_id);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return ids;
|
||||
}
|
||||
};
|
||||
|
||||
Icinga.availableModules.bpapp = Bp;
|
||||
|
||||
}(Icinga));
|
||||
|
||||