From 0e0672e0c12c622f73562be768ecaa7bc968927e Mon Sep 17 00:00:00 2001
From: Alexander Klimov <Alexander.Klimov@netways.de>
Date: Wed, 5 Feb 2014 17:23:51 +0100
Subject: [PATCH] Add tactical overview (WIP)

refs #3782
---
 .../controllers/TacticalController.php        |  17 +++
 .../views/scripts/tactical/index.phtml        | 120 ++++++++++++++++++
 .../Backend/Ido/Query/StatusSummaryQuery.php  |  61 ++++++---
 .../Monitoring/DataView/StatusSummary.php     |  60 ++++++++-
 modules/monitoring/public/css/main.less       |  75 +++++++++++
 5 files changed, 315 insertions(+), 18 deletions(-)
 create mode 100644 modules/monitoring/application/controllers/TacticalController.php
 create mode 100644 modules/monitoring/application/views/scripts/tactical/index.phtml

diff --git a/modules/monitoring/application/controllers/TacticalController.php b/modules/monitoring/application/controllers/TacticalController.php
new file mode 100644
index 000000000..2b434bb2f
--- /dev/null
+++ b/modules/monitoring/application/controllers/TacticalController.php
@@ -0,0 +1,17 @@
+<?php
+// @codingStandardsIgnoreStart
+// {{{ICINGA_LICENSE_HEADER}}}
+// {{{ICINGA_LICENSE_HEADER}}}
+
+use Icinga\Module\Monitoring\Controller as MonitoringController;
+use Icinga\Module\Monitoring\DataView\StatusSummary;
+use Icinga\Chart\PieChart;
+
+class Monitoring_TacticalController extends MonitoringController
+{
+    public function indexAction()
+    {
+        $this->view->statusSummary = StatusSummary::fromRequest($this->_request)->getQuery()->fetchRow();
+    }
+}
+// @codingStandardsIgnoreStop
\ No newline at end of file
diff --git a/modules/monitoring/application/views/scripts/tactical/index.phtml b/modules/monitoring/application/views/scripts/tactical/index.phtml
new file mode 100644
index 000000000..4c0d61600
--- /dev/null
+++ b/modules/monitoring/application/views/scripts/tactical/index.phtml
@@ -0,0 +1,120 @@
+<?php
+$summary = $this->statusSummary;
+$state = array(
+    'host'    => array(
+        'up'          =>  0,
+        'down'        =>  1,
+        'unreachable' =>  2,
+        'pending'     => 99
+    ),
+    'service' => array(
+        'ok'       =>  0,
+        'warning'  =>  1,
+        'critical' =>  2,
+        'unknown'  =>  3,
+        'pending'  => 99
+    )
+);
+function init_upper($string) {
+    return mb_strtoupper(substr($string, 0, 1)) . substr($string, 1);
+}
+$tacticalTables = array();
+foreach (array(
+    'host'    => array('up', 'down', 'unreachable', 'pending'),
+    'service' => array('ok', 'critical', 'warning', 'unknown', 'pending')
+) as $key => $value) {
+    $tacticalTables[$key] = array();
+    foreach ($value as $valueState) {
+        $tacticalTables[$key][$valueState] = array();
+        $value_2_ref = $key . 's_' . $valueState;
+        $tacticalTables[$key][$valueState][$valueState] = (int)$summary->{$value_2_ref};
+        foreach (array('disabled', 'unhandled', 'on_problem_hosts') as $value_3) {
+            $value_3_ref = $value_2_ref . '_' . $value_3;
+            if (isset($summary->{$value_3_ref})) {
+                $tacticalTables[$key][$valueState][$value_3] = (int)$summary->{$value_3_ref};
+            }
+        }
+    }
+}
+foreach ($tacticalTables as $key => $value) {
+    printf(
+        '<table class="tacticalTable"><tr><td colspan="%d"><h1>%ss</h1></td></tr><tr>',
+        count($value),
+        init_upper($key)
+    );
+    foreach ($value as $keyState => $valueState) {
+        printf(
+            '<td class="topbar-status-%s"><a style="font-weight: bold; color: black" href="%s" title="%ss %s">%s: %d</a>',
+            $keyState,
+            $this->href(
+                'monitoring/list/' . $key . 's',
+                array($key . '_state' => $state[$key][$keyState])
+            ),
+            init_upper($key),
+            $keyState,
+            init_upper($keyState),
+            $valueState[$keyState]
+        );
+        foreach ($valueState as $keyStateDetail => $valueStateDetail) {
+            if ($keyStateDetail !== $keyState && $valueStateDetail !== 0) {
+                $strReplaced = str_replace('_', ' ', $keyStateDetail);
+                printf(
+                    '<br /><a href="%s" title="%ss %s %s"%s>%s: %d</a>',
+                    $this->href(
+                        'monitoring/list/' . $key . 's',
+                        array(
+                            $key . '_state' => $state[$key][$keyState],
+                            $key . '_' . $keyStateDetail => 1
+                        )
+                    ),
+                    init_upper($key),
+                    $keyState,
+                    $strReplaced,
+                    ($strReplaced === 'unhandled' ? '' : ' style="color: #f5a9a9"'),
+                    $strReplaced,
+                    $valueStateDetail
+                );
+            }
+        }
+        echo '</td>';
+    }
+    echo '</tr></table>';
+}
+?>
+<table class="tacticalTable">
+    <tr>
+        <td colspan="2"><h1>Host Checks</h1></td>
+        <td colspan="2"><h1>Service Checks</h1></td>
+    </tr>
+    <tr>
+        <td>Active</td><td>Passive</td>
+        <td>Active</td><td>Passive</td>
+    </tr>
+    <?php
+        foreach (array(true, false) as $check_enabled) {
+            echo '<tr>';
+            foreach (array('host', 'service') as $hst_srv) {
+                foreach (array('act', 'pass') as $act_pass) {
+                    $var_ref = $this->statusSummary->{sprintf(
+                            '%ss%s_%sive_checked',
+                            $hst_srv,
+                            ($check_enabled ? '' : '_not'),
+                            $act_pass
+                        )};
+                    if ($var_ref === '0') {
+                        echo '<td>';
+                    } else {
+                        printf(
+                            '<td class="topbar-status-%s">%sabled: %s',
+                            ($check_enabled ? 'up' : 'down'),
+                            ($check_enabled ? 'en' : 'dis'),
+                            $var_ref
+                        );
+                    }
+                    echo '</td>';
+                }
+            }
+            echo '</tr>';
+        }
+    ?>
+</table>
\ No newline at end of file
diff --git a/modules/monitoring/library/Monitoring/Backend/Ido/Query/StatusSummaryQuery.php b/modules/monitoring/library/Monitoring/Backend/Ido/Query/StatusSummaryQuery.php
index e3e8c8bca..13b3fdbf4 100644
--- a/modules/monitoring/library/Monitoring/Backend/Ido/Query/StatusSummaryQuery.php
+++ b/modules/monitoring/library/Monitoring/Backend/Ido/Query/StatusSummaryQuery.php
@@ -37,21 +37,46 @@ class StatusSummaryQuery extends IdoQuery
     protected $columnMap = array(
         'hoststatussummary'     => array(
             'hosts_up'                      => 'SUM(CASE WHEN object_type = \'host\' AND state = 0 THEN 1 ELSE 0 END)',
-            'hosts_unreachable_handled'     => 'SUM(CASE WHEN object_type = \'host\' AND state = 2 AND acknowledged + in_downtime != 0 THEN 1 ELSE 0 END)',
-            'hosts_unreachable_unhandled'   => 'SUM(CASE WHEN object_type = \'host\' AND state = 2 AND acknowledged + in_downtime = 0 THEN 1 ELSE 0 END)',
+            'hosts_up_disabled'             => 'SUM(CASE WHEN object_type = \'host\' AND state = 0 AND is_active_checked = 0 AND is_passive_checked = 0 THEN 1 ELSE 0 END)',
+            'hosts_down'                    => 'SUM(CASE WHEN object_type = \'host\' AND state = 1 THEN 1 ELSE 0 END)',
             'hosts_down_handled'            => 'SUM(CASE WHEN object_type = \'host\' AND state = 1 AND acknowledged + in_downtime != 0 THEN 1 ELSE 0 END)',
             'hosts_down_unhandled'          => 'SUM(CASE WHEN object_type = \'host\' AND state = 1 AND acknowledged + in_downtime = 0 THEN 1 ELSE 0 END)',
-            'hosts_pending'                 => 'SUM(CASE WHEN object_type = \'host\' AND state = 99 THEN 1 ELSE 0 END)'
+            'hosts_down_disabled'           => 'SUM(CASE WHEN object_type = \'host\' AND state = 1 AND is_active_checked = 0 AND is_passive_checked = 0 THEN 1 ELSE 0 END)',
+            'hosts_unreachable'             => 'SUM(CASE WHEN object_type = \'host\' AND state = 2 THEN 1 ELSE 0 END)',
+            'hosts_unreachable_handled'     => 'SUM(CASE WHEN object_type = \'host\' AND state = 2 AND acknowledged + in_downtime != 0 THEN 1 ELSE 0 END)',
+            'hosts_unreachable_unhandled'   => 'SUM(CASE WHEN object_type = \'host\' AND state = 2 AND acknowledged + in_downtime = 0 THEN 1 ELSE 0 END)',
+            'hosts_unreachable_disabled'    => 'SUM(CASE WHEN object_type = \'host\' AND state = 2 AND is_active_checked = 0 AND is_passive_checked = 0 THEN 1 ELSE 0 END)',
+            'hosts_pending'                 => 'SUM(CASE WHEN object_type = \'host\' AND state = 99 THEN 1 ELSE 0 END)',
+            'hosts_pending_disabled'        => 'SUM(CASE WHEN object_type = \'host\' AND state = 99 AND is_active_checked = 0 AND is_passive_checked = 0 THEN 1 ELSE 0 END)',
+            'hosts_active_checked'          => 'SUM(CASE WHEN object_type = \'host\' AND is_active_checked = 1 THEN 1 ELSE 0 END)',
+            'hosts_not_active_checked'      => 'SUM(CASE WHEN object_type = \'host\' AND is_active_checked = 0 THEN 1 ELSE 0 END)',
+            'hosts_passive_checked'         => 'SUM(CASE WHEN object_type = \'host\' AND is_passive_checked = 1 THEN 1 ELSE 0 END)',
+            'hosts_not_passive_checked'     => 'SUM(CASE WHEN object_type = \'host\' AND is_passive_checked = 0 THEN 1 ELSE 0 END)'
         ),
         'servicestatussummary'  => array(
-            'services_ok'                   => 'SUM(CASE WHEN object_type = \'service\' AND state = 0 THEN 1 ELSE 0 END)',
-            'services_pending'              => 'SUM(CASE WHEN object_type = \'service\' AND state = 99 THEN 1 ELSE 0 END)',
-            'services_warning_handled'      => 'SUM(CASE WHEN object_type = \'service\' AND state = 1 AND (acknowledged + in_downtime + COALESCE(host_state, 0)) > 0 THEN 1 ELSE 0 END)',
-            'services_critical_handled'     => 'SUM(CASE WHEN object_type = \'service\' AND state = 2 AND (acknowledged + in_downtime + COALESCE(host_state, 0)) > 0 THEN 1 ELSE 0 END)',
-            'services_unknown_handled'      => 'SUM(CASE WHEN object_type = \'service\' AND state = 3 AND (acknowledged + in_downtime + COALESCE(host_state, 0)) > 0 THEN 1 ELSE 0 END)',
-            'services_warning_unhandled'    => 'SUM(CASE WHEN object_type = \'service\' AND state = 1 AND (acknowledged + in_downtime + COALESCE(host_state, 0)) = 0 THEN 1 ELSE 0 END)',
-            'services_critical_unhandled'   => 'SUM(CASE WHEN object_type = \'service\' AND state = 2 AND (acknowledged + in_downtime + COALESCE(host_state, 0)) = 0 THEN 1 ELSE 0 END)',
-            'services_unknown_unhandled'    => 'SUM(CASE WHEN object_type = \'service\' AND state = 3 AND (acknowledged + in_downtime + COALESCE(host_state, 0)) = 0 THEN 1 ELSE 0 END)'
+            'services_ok'                           => 'SUM(CASE WHEN object_type = \'service\' AND state = 0 THEN 1 ELSE 0 END)',
+            'services_ok_disabled'                  => 'SUM(CASE WHEN object_type = \'service\' AND state = 0 AND is_active_checked = 0 AND is_passive_checked = 0 THEN 1 ELSE 0 END)',
+            'services_warning'                      => 'SUM(CASE WHEN object_type = \'service\' AND state = 1 THEN 1 ELSE 0 END)',
+            'services_warning_handled'              => 'SUM(CASE WHEN object_type = \'service\' AND state = 1 AND (acknowledged + in_downtime + COALESCE(host_state, 0)) > 0 THEN 1 ELSE 0 END)',
+            'services_warning_unhandled'            => 'SUM(CASE WHEN object_type = \'service\' AND state = 1 AND (acknowledged + in_downtime + COALESCE(host_state, 0)) = 0 THEN 1 ELSE 0 END)',
+            'services_warning_on_problem_hosts'     => 'SUM(CASE WHEN object_type = \'service\' AND state = 1 AND host_state != 99 AND host_state != 0 THEN 1 ELSE 0 END)',
+            'services_warning_disabled'             => 'SUM(CASE WHEN object_type = \'service\' AND state = 1 AND is_active_checked = 0 AND is_passive_checked = 0 THEN 1 ELSE 0 END)',
+            'services_critical'                     => 'SUM(CASE WHEN object_type = \'service\' AND state = 2 THEN 1 ELSE 0 END)',
+            'services_critical_handled'             => 'SUM(CASE WHEN object_type = \'service\' AND state = 2 AND (acknowledged + in_downtime + COALESCE(host_state, 0)) > 0 THEN 1 ELSE 0 END)',
+            'services_critical_unhandled'           => 'SUM(CASE WHEN object_type = \'service\' AND state = 2 AND (acknowledged + in_downtime + COALESCE(host_state, 0)) = 0 THEN 1 ELSE 0 END)',
+            'services_critical_on_problem_hosts'    => 'SUM(CASE WHEN object_type = \'service\' AND state = 2 AND host_state != 99 AND host_state != 0 THEN 1 ELSE 0 END)',
+            'services_critical_disabled'            => 'SUM(CASE WHEN object_type = \'service\' AND state = 2 AND is_active_checked = 0 AND is_passive_checked = 0 THEN 1 ELSE 0 END)',
+            'services_unknown'                      => 'SUM(CASE WHEN object_type = \'service\' AND state = 3 THEN 1 ELSE 0 END)',
+            'services_unknown_handled'              => 'SUM(CASE WHEN object_type = \'service\' AND state = 3 AND (acknowledged + in_downtime + COALESCE(host_state, 0)) > 0 THEN 1 ELSE 0 END)',
+            'services_unknown_unhandled'            => 'SUM(CASE WHEN object_type = \'service\' AND state = 3 AND (acknowledged + in_downtime + COALESCE(host_state, 0)) = 0 THEN 1 ELSE 0 END)',
+            'services_unknown_on_problem_hosts'     => 'SUM(CASE WHEN object_type = \'service\' AND state = 3 AND host_state != 99 AND host_state != 0 THEN 1 ELSE 0 END)',
+            'services_unknown_disabled'             => 'SUM(CASE WHEN object_type = \'service\' AND state = 3 AND is_active_checked = 0 AND is_passive_checked = 0 THEN 1 ELSE 0 END)',
+            'services_pending'                      => 'SUM(CASE WHEN object_type = \'service\' AND state = 99 THEN 1 ELSE 0 END)',
+            'services_pending_disabled'             => 'SUM(CASE WHEN object_type = \'service\' AND state = 99 AND is_active_checked = 0 AND is_passive_checked = 0 THEN 1 ELSE 0 END)',
+            'services_active_checked'               => 'SUM(CASE WHEN object_type = \'service\' AND is_active_checked = 1 THEN 1 ELSE 0 END)',
+            'services_not_active_checked'           => 'SUM(CASE WHEN object_type = \'service\' AND is_active_checked = 0 THEN 1 ELSE 0 END)',
+            'services_passive_checked'              => 'SUM(CASE WHEN object_type = \'service\' AND is_passive_checked = 1 THEN 1 ELSE 0 END)',
+            'services_not_passive_checked'          => 'SUM(CASE WHEN object_type = \'service\' AND is_passive_checked = 0 THEN 1 ELSE 0 END)'
         )
     );
 
@@ -86,17 +111,21 @@ class StatusSummaryQuery extends IdoQuery
             array()
         );
         $hosts->columns(array(
-            'state'         => 'CASE WHEN hs.has_been_checked = 0 OR hs.has_been_checked IS NULL THEN 99 ELSE hs.current_state END',
-            'acknowledged'  => 'hs.problem_has_been_acknowledged',
-            'in_downtime'   => 'CASE WHEN (hs.scheduled_downtime_depth = 0) THEN 0 ELSE 1 END',
-            'host_state'    => 'CASE WHEN hs.has_been_checked = 0 OR hs.has_been_checked IS NULL THEN 99 ELSE hs.current_state END',
-            'object_type'   => '(\'host\')'
+            'state'                 => 'CASE WHEN hs.has_been_checked = 0 OR hs.has_been_checked IS NULL THEN 99 ELSE hs.current_state END',
+            'acknowledged'          => 'hs.problem_has_been_acknowledged',
+            'in_downtime'           => 'CASE WHEN (hs.scheduled_downtime_depth = 0) THEN 0 ELSE 1 END',
+            'host_state'            => 'CASE WHEN hs.has_been_checked = 0 OR hs.has_been_checked IS NULL THEN 99 ELSE hs.current_state END',
+            'is_active_checked'     => 'CASE WHEN hs.active_checks_enabled  = 1 THEN 1 ELSE 0 END',
+            'is_passive_checked'    => 'CASE WHEN hs.passive_checks_enabled = 1 THEN 1 ELSE 0 END',
+            'object_type'           => '(\'host\')'
         ));
         $services->columns(array(
             'state'         => 'CASE WHEN ss.has_been_checked = 0 OR ss.has_been_checked IS NULL THEN 99 ELSE ss.current_state END',
             'acknowledged'  => 'ss.problem_has_been_acknowledged',
             'in_downtime'   => 'CASE WHEN (ss.scheduled_downtime_depth = 0) THEN 0 ELSE 1 END',
             'host_state'    => 'CASE WHEN hs.has_been_checked = 0 OR hs.has_been_checked IS NULL THEN 99 ELSE hs.current_state END',
+            'is_active_checked'     => 'CASE WHEN ss.active_checks_enabled  = 1 THEN 1 ELSE 0 END',
+            'is_passive_checked'    => 'CASE WHEN ss.passive_checks_enabled = 1 THEN 1 ELSE 0 END',
             'object_type'   => '(\'service\')'
         ));
         $union = $this->db->select()->union(array($hosts, $services), Zend_Db_Select::SQL_UNION_ALL);
diff --git a/modules/monitoring/library/Monitoring/DataView/StatusSummary.php b/modules/monitoring/library/Monitoring/DataView/StatusSummary.php
index 908a01da2..6b12110eb 100644
--- a/modules/monitoring/library/Monitoring/DataView/StatusSummary.php
+++ b/modules/monitoring/library/Monitoring/DataView/StatusSummary.php
@@ -39,20 +39,76 @@ class StatusSummary extends DataView
     public function getColumns()
     {
         return array(
-            'hosts_up',
+            /*'hosts_up',
+            'hosts_unreachable',
             'hosts_unreachable_handled',
             'hosts_unreachable_unhandled',
+            'hosts_down',
             'hosts_down_handled',
             'hosts_down_unhandled',
             'hosts_pending',
             'services_ok',
+            'services_critical',
             'services_critical_handled',
             'services_critical_unhandled',
+            'services_warning',
             'services_warning_handled',
             'services_warning_unhandled',
+            'services_unknown',
             'services_unknown_handled',
             'services_unknown_unhandled',
-            'services_pending'
+            'services_pending',
+            'services_active_checked',
+            'services_not_active_checked',
+            'services_passive_checked',
+            'services_not_passive_checked',
+            'hosts_active_checked',
+            'hosts_not_active_checked',
+            'hosts_passive_checked',
+            'hosts_not_passive_checked',
+            'services_critical_on_problem_hosts',
+            'services_warning_on_problem_hosts',
+            'services_unknown_on_problem_hosts'*/
+
+            'hosts_up',
+            'hosts_up_disabled',
+            'hosts_down',
+            'hosts_down_handled',
+            'hosts_down_unhandled',
+            'hosts_down_disabled',
+            'hosts_unreachable',
+            'hosts_unreachable_handled',
+            'hosts_unreachable_unhandled',
+            'hosts_unreachable_disabled',
+            'hosts_pending',
+            'hosts_pending_disabled',
+            'hosts_active_checked',
+            'hosts_not_active_checked',
+            'hosts_passive_checked',
+            'hosts_not_passive_checked',
+            'services_ok',
+            'services_ok_disabled',
+            'services_warning',
+            'services_warning_handled',
+            'services_warning_unhandled',
+            'services_warning_on_problem_hosts',
+            'services_warning_disabled',
+            'services_critical',
+            'services_critical_handled',
+            'services_critical_unhandled',
+            'services_critical_on_problem_hosts',
+            'services_critical_disabled',
+            'services_unknown',
+            'services_unknown_handled',
+            'services_unknown_unhandled',
+            'services_unknown_on_problem_hosts',
+            'services_unknown_disabled',
+            'services_pending',
+            'services_pending_disabled',
+            'services_active_checked',
+            'services_not_active_checked',
+            'services_passive_checked',
+            'services_not_passive_checked'
         );
     }
 }
diff --git a/modules/monitoring/public/css/main.less b/modules/monitoring/public/css/main.less
index 5bf5f2db5..c80da2b67 100644
--- a/modules/monitoring/public/css/main.less
+++ b/modules/monitoring/public/css/main.less
@@ -39,6 +39,69 @@
 @colorWarning : #FFA500;
 @colorUnreachable : #E066FF;
 
+table.tacticalTable {
+  //width: 100%;
+  border: 0px;
+  border-collapse: separate;
+  border-spacing: 5px;
+}
+
+a.tacticalLink:link,
+a.tacticalLink:visited,
+a.tacticalLink:hover,
+a.tacticalLink:active {
+  color: black;
+}
+
+a.tacticalLinkWhite:link,
+a.tacticalLinkWhite:visited,
+a.tacticalLinkWhite:hover,
+a.tacticalLinkWhite:active {
+  color: white;
+}
+
+a.tacticalLink:link,
+a.tacticalLink:visited,
+a.tacticalLink:active,
+a.tacticalLinkWhite:link,
+a.tacticalLinkWhite:visited,
+a.tacticalLinkWhite:active {
+  text-decoration: underline;
+}
+
+a.tacticalLink:hover,
+a.tacticalLinkWhite:hover {
+  text-decoration: none;
+}
+
+.whiteFont {
+  color: white;
+}
+
+.tacticalHeader {
+  //background-color: darkgray;
+  font-weight: bold;
+}
+
+.tacticalSubHeader {
+  background-color: lightgray;
+}
+
+.tacticalText {
+  font-weight: bold;
+  color: black;
+}
+
+.equalheight-container {
+  overflow: hidden;
+}
+
+.equalheight {
+  margin-bottom: -99999px;
+  padding-bottom: 99999px;
+  background-color:#efefef;
+}
+
 .host-name {
   display: block;
   margin-top: 5px;
@@ -90,6 +153,18 @@
    Status colors
    ========================================================================== */
 
+.status-ok {
+  background-color: @colorOk!important;
+}
+
+.status-down {
+  background-color: @colorDown!important;
+}
+
+.status-unreachable {
+  background-color: @colorUnreachable!important;
+}
+
 .status-up {
   background-color: @colorUp!important;
 }