diff options
Diffstat (limited to 'application')
-rw-r--r-- | application/controllers/ConfigController.php | 25 | ||||
-rw-r--r-- | application/controllers/DataController.php | 213 | ||||
-rw-r--r-- | application/controllers/IndexController.php | 93 | ||||
-rw-r--r-- | application/forms/Config/GeneralConfigForm.php | 139 | ||||
-rw-r--r-- | application/locale/de_DE/LC_MESSAGES/map.mo | bin | 0 -> 2534 bytes | |||
-rw-r--r-- | application/locale/de_DE/LC_MESSAGES/map.po | 161 | ||||
-rw-r--r-- | application/views/scripts/config/index.phtml | 6 | ||||
-rw-r--r-- | application/views/scripts/index/index.phtml | 57 |
8 files changed, 694 insertions, 0 deletions
diff --git a/application/controllers/ConfigController.php b/application/controllers/ConfigController.php new file mode 100644 index 0000000..8ddf94f --- /dev/null +++ b/application/controllers/ConfigController.php @@ -0,0 +1,25 @@ +<?php + +namespace Icinga\Module\Map\Controllers; + +use Icinga\Module\Map\Forms\Config\GeneralConfigForm; +use Icinga\Web\Controller; + +class ConfigController extends Controller +{ + public function init() + { + $this->assertPermission('config/modules'); + } + + public function indexAction() + { + $form = new GeneralConfigForm(); + $form->setIniConfig($this->Config()); + $form->handleRequest(); + + $this->view->form = $form; + $this->view->tabs = $this->Module()->getConfigTabs()->activate('config'); + } +} + diff --git a/application/controllers/DataController.php b/application/controllers/DataController.php new file mode 100644 index 0000000..c6051eb --- /dev/null +++ b/application/controllers/DataController.php @@ -0,0 +1,213 @@ +<?php + +namespace Icinga\Module\Map\Controllers; + +use Icinga\Data\Filter\Filter; +use Icinga\Module\Monitoring\Controller; +use Icinga\Module\Monitoring\DataView\DataView; + +class DataController extends Controller +{ + /** + * Apply filters on a DataView + * + * @param DataView $dataView The DataView to apply filters on + * + * @return DataView $dataView + */ + protected function filterQuery(DataView $dataView) + { + $this->setupFilterControl($dataView, null, null, ['stateType', 'objectType', 'problems']); + return $dataView; + } + + private $stateColumn; + private $stateChangeColumn; + + /** + * Get JSON state objects + */ + public function pointsAction() + { + $points = array(); + + try { + // Borrowed from monitoring module + // Handle soft and hard states + $config = $this->config(); + $stateType = strtolower($this->params->shift('stateType', + $config->get('map', 'stateType', 'soft') + )); + + $userPreferences = $this->Auth()->getUser()->getPreferences(); + if ($userPreferences->has("map")) { + $stateType = $userPreferences->getValue("map", "stateType", $stateType); + } + + $filter = (bool)$this->params->shift('problems', false) ? Filter::where('service_problem', 1) : null; + + $objectType = strtolower($this->params->shift('objectType', 'all')); + + if ($stateType === 'hard') { + $this->stateColumn = 'hard_state'; + $this->stateChangeColumn = 'last_hard_state_change'; + } else { + $this->stateColumn = 'state'; + $this->stateChangeColumn = 'last_state_change'; + } + + if (in_array($objectType, ['all', 'host'])) { + // get host data + $hostQuery = $this->backend + ->select() + ->from('hoststatus', array( + 'host_display_name', + 'host_name', + 'host_acknowledged', + 'host_state' => 'host_' . $this->stateColumn, + 'host_last_state_change' => 'host_' . $this->stateChangeColumn, + 'host_in_downtime', + 'host_problem', + 'coordinates' => '_host_geolocation', + 'icon' => '_host_map_icon', + )) + ->applyFilter(Filter::fromQueryString('_host_geolocation >')); + + $this->applyRestriction('monitoring/filter/objects', $hostQuery); + $this->filterQuery($hostQuery); + + // get service data + $serviceQuery = $this->backend + ->select() + ->from('servicestatus', array( + 'host_name', + 'service_display_name', + 'service_name' => 'service', + 'service_acknowledged', + 'service_state' => 'service_' . $this->stateColumn, + 'service_last_state_change' => 'service_' . $this->stateChangeColumn, + 'service_in_downtime' + )) + ->applyFilter(Filter::fromQueryString('_host_geolocation >')); + + if ($filter) { + $serviceQuery->applyFilter($filter); + } + + $this->applyRestriction('monitoring/filter/objects', $serviceQuery); + $this->filterQuery($serviceQuery); + + if ($hostQuery->count() > 0) { + foreach ($hostQuery as $row) { + $hostname = $row->host_name; + + $host = (array)$row; + $host['services'] = array(); + + // check for broken coordinates + $coordinate_pattern = '/^(\-?\d+(\.\d+)?),\s*(\-?\d+(\.\d+)?)$/'; + + if (!preg_match($coordinate_pattern, $host['coordinates'])) { + continue; + } + + $host['coordinates'] = explode(",", $host['coordinates']); + + $points['hosts'][$hostname] = $host; + } + } + + // add services to host + if ($serviceQuery->count() > 0) { + foreach ($serviceQuery as $row) { + $hostname = $row->host_name; + + $service = (array)$row; + unset($service['host_name']); + + if (isset($points['hosts'][$hostname])) { + $points['hosts'][$hostname]['services'][$service['service_display_name']] = $service; + } + } + } + + // remove hosts without problems and services + if ($filter) { + foreach ($points['hosts'] as $name => $host) { + if (empty($host['services']) && $host['host_problem'] != '1') { + unset($points['hosts'][$name]); + } + } + } + } + + if (in_array($objectType, ['all', 'service'])) { + + // get services with geolocation + $geoServiceQuery = $this->backend + ->select() + ->from('servicestatus', array( + 'host_display_name', + 'host_name', + 'host_acknowledged', + 'host_state' => 'host_' . $this->stateColumn, + 'host_last_state_change' => 'host_' . $this->stateChangeColumn, + 'host_in_downtime', + 'service_display_name', + 'service_name' => 'service', + 'service_acknowledged', + 'service_state' => 'service_' . $this->stateColumn, + 'service_last_state_change' => 'service_' . $this->stateChangeColumn, + 'service_in_downtime', + 'coordinates' => '_service_geolocation', + 'icon' => '_service_map_icon', + + ))->applyFilter(Filter::fromQueryString('_service_geolocation >')); + + if ($filter) { + $geoServiceQuery->applyFilter($filter); + } + + + $this->applyRestriction('monitoring/filter/objects', $geoServiceQuery); + $this->filterQuery($geoServiceQuery); + // --- + + if ($geoServiceQuery->count() > 0) { + foreach ($geoServiceQuery as $row) { + $identifier = $row->host_name . "!" . $row->service_name; + + $ar = (array)$row; + + $host = array_filter($ar, function ($k) { + return (preg_match("/^host_|^coordinates/", $k)); + }, ARRAY_FILTER_USE_KEY); + + $service = array_filter($ar, function ($k) { + return (preg_match("/^service_/", $k)); + }, ARRAY_FILTER_USE_KEY); + + $host['services'][$service['service_display_name']] = $service; + + // check for broken coordinates + $coordinate_pattern = '/^(\-?\d+(\.\d+)?),\s*(\-?\d+(\.\d+)?)$/'; + + if (!preg_match($coordinate_pattern, $host['coordinates'])) { + continue; + } + + $host['coordinates'] = explode(",", $host['coordinates']); + $host['icon'] = $ar['icon']; + $points['services'][$identifier] = $host; + } + } + } + } catch (\Exception $e) { + $points['message'] = $e->getMessage(); + $points['trace'] = $e->getTraceAsString(); + } + + echo json_encode($points); + exit(); + } +} diff --git a/application/controllers/IndexController.php b/application/controllers/IndexController.php new file mode 100644 index 0000000..6160c67 --- /dev/null +++ b/application/controllers/IndexController.php @@ -0,0 +1,93 @@ +<?php + +namespace Icinga\Module\Map\Controllers; + +use Icinga\Data\Filter\FilterException; +use Icinga\Web\Controller\ModuleActionController; + +class IndexController extends ModuleActionController +{ + public function indexAction() + { + $config = $this->Config(); + $map = null; + $mapConfig = null; + + // try to load stored map + if ($this->params->has("load")) { + $map = $this->params->get("load"); + + if (!preg_match("/^[\w]+$/", $map)) { + throw new FilterException("Invalid character in map name. Allow characters: a-zA-Z0-9_"); + } + + $mapConfig = $this->Config("maps"); + if (!$mapConfig->hasSection($map)) { + throw new FilterException("Could not find stored map with name = " . $map); + } + } + + $this->view->id = uniqid(); + $this->view->host = $this->params->get("showHost"); + $this->view->expand = $this->params->get("expand"); + $this->view->fullscreen = ($this->params->get("showFullscreen") == 1); + + $parameterDefaults = array( + "default_zoom" => "4", + "default_long" => '13.377485', + "default_lat" => '52.515855', + "min_zoom" => "2", + "max_zoom" => "19", + "max_native_zoom" => "19", + "disable_cluster_at_zoom" => null, // should be by default: max_zoom - 1 + "cluster_problem_count" => 0, + "tile_url" => "//{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", + ); + + /* + * 1. url + * 2. stored map + * 3. user config + * 4. config + */ + $userPreferences = $this->Auth()->getUser()->getPreferences(); + if ($userPreferences->has("map")) { + $config->getSection("map")->merge($userPreferences->get("map")); + } + + foreach ($parameterDefaults as $parameter => $default) { + if ($this->params->has($parameter)) { + $this->view->$parameter = $this->params->get($parameter); + } elseif (isset($map) && $mapConfig->getSection($map)->offsetExists($parameter)) { + $this->view->$parameter = $mapConfig->get($map, $parameter); + } else { + $this->view->$parameter = $config->get("map", $parameter, $default); + } + } + + if (!$this->view->disable_cluster_at_zoom) { + $this->view->disable_cluster_at_zoom = $this->view->max_zoom - 1; + } + + $pattern = "/^([_]{0,1}(host|service))|\(|(object|state)Type/"; + $urlParameters = $this->filterArray($this->getAllParams(), $pattern); + + if (isset($map)) { + $mapParameters = $this->filterArray($mapConfig->getSection($map)->toArray(), $pattern); + $urlParameters = array_merge($mapParameters, $urlParameters); + } + + array_walk($urlParameters, function (&$a, $b) { + $a = $b . "=" . $a; + }); + $this->view->url_parameters = join('&', $urlParameters); + + $this->view->dashletHeight = $config->get('map', 'dashlet_height', '300'); + } + + function filterArray($array, $pattern) + { + $matches = preg_grep($pattern, array_keys($array)); + return array_intersect_key($array, array_flip($matches)); + } +} diff --git a/application/forms/Config/GeneralConfigForm.php b/application/forms/Config/GeneralConfigForm.php new file mode 100644 index 0000000..1351655 --- /dev/null +++ b/application/forms/Config/GeneralConfigForm.php @@ -0,0 +1,139 @@ +<?php + +namespace Icinga\Module\Map\Forms\Config; + +use Icinga\Application\Config; +use Icinga\Forms\ConfigForm; + +class GeneralConfigForm extends ConfigForm +{ + /** + * Initialize this form + */ + public function init() + { + $this->setName('form_config_map_general'); + $this->setSubmitLabel($this->translate('Save Changes')); + } + + /** + * {@inheritdoc} + */ + public function createElements(array $formData) + { + $this->addElement( + 'text', + 'map_default_lat', + array( + 'placeholder' => '52.520645', + 'label' => $this->translate('Default latitude (WGS84)'), + 'description' => $this->translate('Default map position (latitude)'), + 'required' => false + ) + ); + $this->addElement( + 'text', + 'map_default_long', + array( + 'placeholder' => '13.409779', + 'label' => $this->translate('Default longitude (WGS84)'), + 'description' => $this->translate('Default map position (longitude)'), + 'required' => false + ) + ); + $this->addElement( + 'text', + 'map_default_zoom', + array( + 'placeholder' => '6', + 'label' => $this->translate('Default zoom level'), + 'description' => $this->translate('Default zoom level of the map'), + 'required' => false + ) + ); + $this->addElement( + 'text', + 'map_max_zoom', + array( + 'placeholder' => '19', + 'label' => $this->translate('Maximum zoom level'), + 'description' => $this->translate('Maximum zoom level of the map'), + 'required' => false + ) + ); + $this->addElement( + 'text', + 'map_max_native_zoom', + array( + 'placeholder' => '19', + 'label' => $this->translate('Maximum native zoom level '), + 'description' => $this->translate('Maximum zoom level natively supported by the map'), + 'required' => false + ) + ); + $this->addElement( + 'text', + 'map_min_zoom', + array( + 'placeholder' => '2', + 'label' => $this->translate('Minimal zoom level'), + 'description' => $this->translate('Minimal zoom level of the map'), + 'required' => false + ) + ); + $this->addElement( + 'text', + 'map_tile_url', + array( + 'placeholder' => '//\{s\}.tile.openstreetmap.org/\{z\}/\{x\}/\{y\}.png', + 'label' => $this->translate('URL for tile server'), + 'description' => $this->translate('Escaped server url, for leaflet tilelayer'), + 'required' => false, + ) + ); + $this->addElement( + 'text', + 'map_dashlet_height', + array( + 'placeholder' => '300', + 'label' => $this->translate('Dashlet height'), + 'description' => $this->translate('Dashlet height'), + 'required' => false + ) + ); + $this->addElement( + 'select', + 'map_stateType', + array( + 'label' => $this->translate('State type'), + 'description' => $this->translate('State type for status indication'), + 'multiOptions' => array( + 'soft' => 'soft', + 'hard' => 'hard' + ), + ) + ); + $this->addElement( + 'text', + 'map_disable_cluster_at_zoom', + array( + 'label' => $this->translate('Disable clustering at zoomlevel'), + 'description' => $this->translate('Don\'t cluster marker at a certain zoomlevel. Use 1 for disabling clustering'), + 'required' => false, + ) + ); + + $this->addElement( + 'checkbox', + 'map_cluster_problem_count', + array( + 'label' => $this->translate('Show number of problems in cluster'), + 'description' => $this->translate('Show number of problems in cluster instead of the number of markers'), + 'required' => false, + 'default' => false, + ) + ); + + } +} + diff --git a/application/locale/de_DE/LC_MESSAGES/map.mo b/application/locale/de_DE/LC_MESSAGES/map.mo Binary files differnew file mode 100644 index 0000000..0041879 --- /dev/null +++ b/application/locale/de_DE/LC_MESSAGES/map.mo diff --git a/application/locale/de_DE/LC_MESSAGES/map.po b/application/locale/de_DE/LC_MESSAGES/map.po new file mode 100644 index 0000000..a81a43a --- /dev/null +++ b/application/locale/de_DE/LC_MESSAGES/map.po @@ -0,0 +1,161 @@ +# Icinga Web 2 - Head for multiple monitoring backends. +# Copyright (C) 2018 Icinga Development Team +# This file is distributed under the same license as Map Module. +# Nicolai Buchwitz <nb@odly.de>, 2017. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: Map Module (1.0.4)\n" +"Report-Msgid-Bugs-To: dev@icinga.com\n" +"POT-Creation-Date: 2018-06-18 12:46+0200\n" +"PO-Revision-Date: 2017-10-20 16:42+0200\n" +"Last-Translator: Nicolai Buchwitz <nb@odly.de>\n" +"Language: de_DE\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Poedit-Basepath: .\n" +"X-Poedit-SearchPath-0: .\n" + +#: ../../../../modules/map/application/views/scripts/index/index.phtml:16 +msgctxt "icinga.state" +msgid "CRITICAL" +msgstr "KRITISCH" + +#: ../../../../modules/map/configuration.php:33 +msgid "Configuration" +msgstr "Konfiguration" + +#: ../../../../modules/map/configuration.php:32 +msgid "Configure the map module" +msgstr "Konfiguration des Karten Moduls" + +#: ../../../../modules/map/application/forms/Config/GeneralConfigForm.php:79 +#: ../../../../modules/map/application/forms/Config/GeneralConfigForm.php:80 +msgid "Dashlet height" +msgstr "Höhe des Dashlets" + +#: ../../../../modules/map/application/forms/Config/GeneralConfigForm.php:29 +msgid "Default latitude (WGS84)" +msgstr "Standard Breitengrad (WGS84)" + +#: ../../../../modules/map/application/forms/Config/GeneralConfigForm.php:39 +msgid "Default longitude (WGS84)" +msgstr "Standard Längengrad (WGS84)" + +#: ../../../../modules/map/application/forms/Config/GeneralConfigForm.php:30 +msgid "Default map position (latitude)" +msgstr "Mittelpunkt der Karte (Breitengrad)" + +#: ../../../../modules/map/application/forms/Config/GeneralConfigForm.php:40 +msgid "Default map position (longitude)" +msgstr "Mittelpunkt der Karte (Längengrad)" + +#: ../../../../modules/map/application/forms/Config/GeneralConfigForm.php:49 +msgid "Default zoom level" +msgstr "Standard-Zoomstufe" + +#: ../../../../modules/map/application/forms/Config/GeneralConfigForm.php:50 +msgid "Default zoom level of the map" +msgstr "Standard-Zoomstufe des Karte" + +#: ../../../../modules/map/configuration.php:4 +#, fuzzy +msgid "Host map" +msgstr "Host-Karte" + +#: ../../../../modules/map/configuration.php:2 +msgid "Maps" +msgstr "Karten" + +#: ../../../../modules/map/application/forms/Config/GeneralConfigForm.php:59 +msgid "Maximum zoom level" +msgstr "Maximale Zoomstufe" + +#: ../../../../modules/map/application/forms/Config/GeneralConfigForm.php:60 +msgid "Maximum zoom level of the map" +msgstr "Maximale Zoomstufe der Karte" + +#: ../../../../modules/map/application/forms/Config/GeneralConfigForm.php:69 +msgid "Minimal zoom level" +msgstr "Minimale Zoomstufe" + +#: ../../../../modules/map/application/forms/Config/GeneralConfigForm.php:70 +msgid "Minimal zoom level of the map" +msgstr "Minimale Zoomstufe der Karte" + +#: ../../../../modules/map/application/views/scripts/index/index.phtml:14 +msgctxt "icinga.state" +msgid "OK" +msgstr "" + +#: ../../../../modules/map/application/views/scripts/index/index.phtml:18 +msgctxt "icinga.state" +msgid "PENDING" +msgstr "AUSSTEHEND" + +#: ../../../../modules/map/application/forms/Config/GeneralConfigForm.php:16 +msgid "Save Changes" +msgstr "Änderungen speichern" + +#: ../../../../modules/map/library/Map/ProvidedHook/CubeLinks.php:31 +#: ../../../../modules/map/library/Map/ProvidedHook/Monitoring/HostActions.php:21 +#: ../../../../modules/map/library/Map/ProvidedHook/Monitoring/ServiceActions.php:19 +msgid "Show on map" +msgstr "Auf der Karte zeigen" + +#: ../../../../modules/map/application/forms/Config/GeneralConfigForm.php:88 +msgid "State type" +msgstr "Zustandsart" + +#: ../../../../modules/map/application/forms/Config/GeneralConfigForm.php:89 +msgid "State type for status indication" +msgstr "Art der angezeigten Statusinformationen" + +#: ../../../../modules/map/library/Map/ProvidedHook/CubeLinks.php:32 +msgid "This shows all matching hosts and their current state on the map module" +msgstr "" + +#: ../../../../modules/map/application/views/scripts/index/index.phtml:17 +msgctxt "icinga.state" +msgid "UNKNOWN" +msgstr "UNBEKANNT" + +#: ../../../../modules/map/configuration.php:6 +msgid "Visualize your hosts and services on a map" +msgstr "Visualisierung von Hosts und Services auf der Karte" + +#: ../../../../modules/map/application/views/scripts/index/index.phtml:15 +msgctxt "icinga.state" +msgid "WARNING" +msgstr "WARNUNG" + +msgid "Marker size" +msgstr "Icon Größe" + +msgid "Size of the host markers" +msgstr "Größe der Host-Icons" + +msgid "Zoom in" +msgstr "Vergrößern" + +msgid "Zoom out" +msgstr "Verkleinern" + +msgid "Add to dashboard" +msgstr "Zum Dashboard hinzufügen" + +msgid "Fullscreen" +msgstr "Vollbild" + +msgid "Show current location" +msgstr "Zeige aktuelle Position" + +msgid "Show default view" +msgstr "Zeige Standardansicht" + +msgid "Host is down" +msgstr "Host ist nicht erreichbar" diff --git a/application/views/scripts/config/index.phtml b/application/views/scripts/config/index.phtml new file mode 100644 index 0000000..f6e5731 --- /dev/null +++ b/application/views/scripts/config/index.phtml @@ -0,0 +1,6 @@ +<div class="controls"> + <?= $tabs; ?> +</div> +<div class="content"> + <?= $form; ?> +</div> diff --git a/application/views/scripts/index/index.phtml b/application/views/scripts/index/index.phtml new file mode 100644 index 0000000..220dec7 --- /dev/null +++ b/application/views/scripts/index/index.phtml @@ -0,0 +1,57 @@ +<?php +?> +<script type="text/javascript"> + <?php + echo 'var map_default_zoom = ' . (!empty($this->default_zoom) ? $this->default_zoom : "null") . ";\n"; + echo 'var map_default_long = ' . (!empty($this->default_long) ? $this->default_long : "null") . ";\n"; + echo 'var map_default_lat = ' . (!empty($this->default_lat) ? $this->default_lat : "null") . ";\n"; + echo 'var map_max_zoom = ' . $this->max_zoom . ";\n"; + echo 'var map_max_native_zoom = ' . $this->max_native_zoom . ";\n"; + echo 'var map_min_zoom = ' . $this->min_zoom . ";\n"; + echo 'var disable_cluster_at_zoom = ' . $this->disable_cluster_at_zoom . ";\n"; + echo "var tile_url = '" . $this->tile_url . "';\n"; + echo "var cluster_problem_count = " . $this->cluster_problem_count . ";\n"; + echo 'var map_show_host = "' . $this->host . "\";\n"; + ?> + var service_status = {}; + service_status[0] = ['<?= $this->translate('OK', 'icinga.state') ?>', 'OK']; + service_status[1] = ['<?= $this->translate('WARNING', 'icinga.state') ?>', 'WARNING']; + service_status[2] = ['<?= $this->translate('CRITICAL', 'icinga.state') ?>', 'CRITICAL']; + service_status[3] = ['<?= $this->translate('UNKNOWN', 'icinga.state') ?>', 'UNKNOWN']; + service_status[99] = ['<?= $this->translate('PENDING', 'icinga.state') ?>', 'PENDING']; + + // @TODO: Is there a better way of translation in JS-Code? + <?php + $toTranslate = array( + "btn-zoom-in" => "Zoom in", + "btn-zoom-out" => "Zoom out", + "btn-dashboard" => "Add to dashboard", + "btn-fullscreen" => "Fullscreen", + "btn-default" => "Show default view", + "btn-locate" => "Show current location", + "host-down" => "Host is down" + ); + + print("var translation = {"); + foreach ($toTranslate as $key => $value) { + printf("'%s': '%s',", $key, $this->translate($value)); + } + print("};\n"); + ?> + + var url_parameters = "<?=$this->url_parameters; ?>"; + var id = '<?= $this->id ?>'; + var dashlet = <?= $this->compact ? 'true' : 'false' ?>; + var expand = <?= $this->expand ? 'true' : 'false' ?>; +</script> +<div class="controls"> + <?php if (!$this->compact && !$this->fullscreen): ?> + <?= $this->tabs ?> + <?php endif ?> +</div> +<div class="content"> + <div <?= ($this->compact ? 'style="height:' . $this->dashletHeight . 'px;" ' : ""); ?>id="map-<?= $this->id ?>" + class="map<?php if ($this->compact): ?> + compact +<?php endif ?>"></div> +</div> |