HealthController: show Health Check in the UI

fixes #1669
This commit is contained in:
Thomas Gelf 2018-10-05 15:56:22 +02:00
parent 8fb2c26d7f
commit fda7acc855
6 changed files with 233 additions and 2 deletions

View File

@ -2,7 +2,10 @@
namespace Icinga\Module\Director\Controllers;
use dipl\Html\Html;
use Icinga\Module\Director\Web\Widget\HealthCheckPluginOutput;
use Icinga\Module\Director\Dashboard\Dashboard;
use Icinga\Module\Director\Health;
use Icinga\Module\Director\Web\Controller\ActionController;
use Icinga\Module\Director\Web\Form\DbSelectorForm;
@ -43,7 +46,19 @@ class DashboardController extends ActionController
$dashboard = Dashboard::loadByName($name, $this->db());
$this->tabs($dashboard->getTabs())->activate($name);
} else {
$this->addSingleTab($this->translate('Overview'));
$this->tabs()->add('main', [
'label' => $this->translate('Overview'),
'url' => 'director'
])->add('health', [
'label' => $this->translate('Health'),
'url' => 'director/health'
])->activate('main');
$state = $this->getHealthState();
if ($state->isProblem()) {
$this->tabs()->get('health')->setTagParams([
'class' => 'state-' . strtolower($state->getName())
]);
}
}
$cntDashboards = 0;
@ -66,4 +81,16 @@ class DashboardController extends ActionController
$this->content()->add($msg);
}
}
/**
* @return \Icinga\Module\Director\CheckPlugin\PluginState
*/
protected function getHealthState()
{
$health = new Health();
$health->setDbResourceName($this->getDbResourceName());
$output = new HealthCheckPluginOutput($health);
return $output->getState();
}
}

View File

@ -0,0 +1,37 @@
<?php
namespace Icinga\Module\Director\Controllers;
use dipl\Html\Html;
use dipl\Html\Icon;
use Icinga\Module\Director\Web\Widget\HealthCheckPluginOutput;
use Icinga\Module\Director\Health;
use Icinga\Module\Director\Web\Controller\ActionController;
class HealthController extends ActionController
{
public function indexAction()
{
$this->tabs()->add('main', [
'label' => $this->translate('Overview'),
'url' => 'director'
])->add('health', [
'label' => $this->translate('Health'),
'url' => 'director/health'
])->activate('health');
$this->addTitle($this->translate('Director Health'));
$health = new Health();
$health->setDbResourceName($this->getDbResourceName());
$output = new HealthCheckPluginOutput($health);
$this->content()->add($output);
$this->content()->add([
Html::tag('h1', ['class' => 'icon-pin'], $this->translate('Hint: Check Plugin')),
Html::tag('p', $this->translate(
'Did you know that you can run this entire Health Check'
. ' (or just some sections) as an Icinga Check on a regular'
. ' base?'
))
]);
}
}

View File

@ -28,6 +28,11 @@ class CheckResults
$this->state = new PluginState(0);
}
public function getName()
{
return $this->name;
}
public function add(CheckResult $result)
{
$this->results[] = $result;
@ -37,7 +42,26 @@ class CheckResults
return $this;
}
protected function getStateSummaryString()
public function getStateCounters()
{
return $this->stateCounters;
}
public function getProblemSummary()
{
$summary = [];
for ($i = 1; $i <= 3; $i++) {
$count = $this->stateCounters[$i];
if ($count === 0) {
continue;
}
$summary[PluginState::create($i)->getName()] = $count;
}
return $summary;
}
public function getStateSummaryString()
{
$summary = [sprintf(
'%d tests OK',

View File

@ -30,6 +30,11 @@ class PluginState
$this->set($state);
}
public function isProblem()
{
return $this->state > 0;
}
public function set($state)
{
$this->state = $this->getNumericStateFor($state);

View File

@ -0,0 +1,98 @@
<?php
namespace Icinga\Module\Director\Web\Widget;
use dipl\Html\Html;
use dipl\Html\HtmlDocument;
use dipl\Html\HtmlString;
use dipl\Translation\TranslationHelper;
use Icinga\Module\Director\CheckPlugin\PluginState;
use Icinga\Module\Director\Health;
class HealthCheckPluginOutput extends HtmlDocument
{
use TranslationHelper;
/** @var Health */
protected $health;
/** @var PluginState */
protected $state;
public function __construct(Health $health)
{
$this->state = new PluginState('OK');
$this->health = $health;
$this->process();
}
protected function process()
{
$checks = $this->health->getAllChecks();
foreach ($checks as $check) {
$this->add([
$title = Html::tag('h2', $check->getName()),
$ul = Html::tag('ul', ['class' => 'health-check-result'])
]);
$problems = $check->getProblemSummary();
if (! empty($problems)) {
$badges = Html::tag('span', ['class' => 'title-badges']);
foreach ($problems as $state => $count) {
$badges->add(Html::tag('span', [
'class' => ['badge', 'state-' . strtolower($state)],
'title' => $this->translate('Critical Checks'),
], $count));
}
$title->add($badges);
}
foreach ($check->getResults() as $result) {
$ul->add(Html::tag('li', [
$this->colorizeState($result->getState()->getName()),
$this->colorizeStates($result->getOutput())
])->setSeparator(' '));
}
$this->state->raise($check->getState());
}
}
public function getState()
{
return $this->state;
}
protected function colorizeStates($string)
{
$string = Html::escape($string);
$string = preg_replace_callback(
"/'([^']+)'/",
[$this, 'highlightNames'],
$string
);
$string = preg_replace_callback(
'/(OK|WARNING|CRITICAL|UNKNOWN)/',
[$this, 'getColorized'],
$string
);
return new HtmlString($string);
}
protected function colorizeState($state)
{
return Html::tag('span', ['class' => 'badge state-' . strtolower($state)], $state);
}
protected function highlightNames($match)
{
return '"' . Html::tag('strong', $match[1]) . '"';
}
protected function getColorized($match)
{
return $this->colorizeState($match[1]);
}
}

View File

@ -599,6 +599,26 @@ a {
color: @color-pending;
}
}
ul.tabs a.state-critical {
background-color: @colorCritical;
font-weight: bold;
color: white;
}
ul.tabs a.state-warning {
background-color: @colorWarning;
font-weight: bold;
color: white;
}
ul.tabs a.state-ok {
background-color: @colorOk;
font-weight: bold;
color: white;
}
ul.tabs a.state-unknown {
background-color: @colorUnknown;
font-weight: bold;
color: white;
}
a:hover::before {
text-decoration: none;
@ -1033,6 +1053,25 @@ form div.hint {
/* END of Forms */
ul.health-check-result {
list-style-type: none;
padding-left: 2em;
margin-bottom: 2em;
li {
line-height: 2em;
}
.badge {
font-weight: bold;
}
}
.title-badges {
.badge {
font-size: 0.75em;
margin-left: 0.5em;
}
}
span.error {
color: @colorCritical;
@ -1040,6 +1079,7 @@ span.error {
color: inherit;
}
}
p.error {
color: white;
padding: 1em 2em;