You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
319 lines
9.1 KiB
319 lines
9.1 KiB
<?php declare(strict_types = 0);
|
|
/*
|
|
** Zabbix
|
|
** Copyright (C) 2001-2023 Zabbix SIA
|
|
**
|
|
** This program is free software; you can redistribute it and/or modify
|
|
** it under the terms of the GNU General Public License as published by
|
|
** the Free Software Foundation; either version 2 of the License, or
|
|
** (at your option) any later version.
|
|
**
|
|
** This program is distributed in the hope that it will be useful,
|
|
** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
** GNU General Public License for more details.
|
|
**
|
|
** You should have received a copy of the GNU General Public License
|
|
** along with this program; if not, write to the Free Software
|
|
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
**/
|
|
|
|
|
|
namespace Widgets\Geomap\Actions;
|
|
|
|
use API,
|
|
CControllerDashboardWidgetView,
|
|
CControllerResponseData,
|
|
CGeomapCoordinatesParser,
|
|
CParser,
|
|
CProfile,
|
|
CSettingsHelper,
|
|
CSeverityHelper;
|
|
|
|
class WidgetView extends CControllerDashboardWidgetView {
|
|
|
|
private const NO_PROBLEMS_MARKER_COLOR = '#009900';
|
|
|
|
protected string $widgetid;
|
|
|
|
/**
|
|
* Global geomap configuration.
|
|
*
|
|
* @param array
|
|
*/
|
|
protected array $geomap_config;
|
|
|
|
protected function init(): void {
|
|
parent::init();
|
|
|
|
$this->addValidationRules([
|
|
'initial_load' => 'in 0,1',
|
|
'widgetid' => 'db widget.widgetid',
|
|
'unique_id' => 'required|string',
|
|
'dynamic_hostid' => 'db hosts.hostid'
|
|
]);
|
|
}
|
|
|
|
protected function doAction(): void {
|
|
$this->widgetid = $this->getInput('widgetid', 0);
|
|
|
|
$data = [
|
|
'name' => $this->getInput('name', $this->widget->getDefaultName()),
|
|
'hosts' => self::convertToRFC7946($this->getHosts()),
|
|
'user' => [
|
|
'debug_mode' => $this->getDebugMode()
|
|
],
|
|
'unique_id' => $this->getInput('unique_id')
|
|
];
|
|
|
|
if ($this->getInput('initial_load', 0)) {
|
|
$this->geomap_config = self::getMapConfig();
|
|
|
|
$data['config'] = $this->geomap_config + $this->getMapCenter() + [
|
|
'filter' => $this->getUserProfileFilter(),
|
|
'colors' => self::getSeveritySettings()
|
|
];
|
|
}
|
|
|
|
$this->setResponse(new CControllerResponseData($data));
|
|
}
|
|
|
|
/**
|
|
* Get hosts and their properties to show on the map as markers.
|
|
*/
|
|
private function getHosts(): array {
|
|
if ($this->isTemplateDashboard()) {
|
|
if ($this->hasInput('dynamic_hostid')) {
|
|
$hosts = API::Host()->get([
|
|
'output' => ['hostid', 'name'],
|
|
'selectInventory' => ['location_lat', 'location_lon'],
|
|
'hostids' => [$this->getInput('dynamic_hostid')],
|
|
'filter' => [
|
|
'inventory_mode' => [HOST_INVENTORY_MANUAL, HOST_INVENTORY_AUTOMATIC]
|
|
],
|
|
'monitored_hosts' => true,
|
|
'preservekeys' => true
|
|
]);
|
|
}
|
|
else {
|
|
return [];
|
|
}
|
|
}
|
|
else {
|
|
$filter_groupids = $this->fields_values['groupids'] ? getSubGroups($this->fields_values['groupids']) : null;
|
|
|
|
$hosts = API::Host()->get([
|
|
'output' => ['hostid', 'name'],
|
|
'selectInventory' => ['location_lat', 'location_lon'],
|
|
'groupids' => $filter_groupids,
|
|
'hostids' => $this->fields_values['hostids'] ?: null,
|
|
'evaltype' => $this->fields_values['evaltype'],
|
|
'tags' => $this->fields_values['tags'],
|
|
'filter' => [
|
|
'inventory_mode' => [HOST_INVENTORY_MANUAL, HOST_INVENTORY_AUTOMATIC]
|
|
],
|
|
'monitored_hosts' => true,
|
|
'preservekeys' => true
|
|
]);
|
|
}
|
|
|
|
$hosts = array_filter($hosts, static function ($host) {
|
|
$lat = $host['inventory']['location_lat'];
|
|
$lng = $host['inventory']['location_lon'];
|
|
|
|
return (is_numeric($lat) && $lat >= GEOMAP_LAT_MIN && $lat <= GEOMAP_LAT_MAX
|
|
&& is_numeric($lng) && $lng >= GEOMAP_LNG_MIN && $lng <= GEOMAP_LNG_MAX);
|
|
});
|
|
|
|
// Get triggers.
|
|
$triggers = API::Trigger()->get([
|
|
'output' => [],
|
|
'selectHosts' => ['hostid'],
|
|
'hostids' => array_keys($hosts),
|
|
'filter' => [
|
|
'value' => TRIGGER_VALUE_TRUE
|
|
],
|
|
'monitored' => true,
|
|
'preservekeys' => true
|
|
]);
|
|
|
|
// Get problems.
|
|
$problems = API::Problem()->get([
|
|
'output' => ['objectid', 'severity'],
|
|
'objectids' => array_keys($triggers),
|
|
'symptom' => false
|
|
]);
|
|
|
|
// Group problems by hosts.
|
|
$problems_by_host = [];
|
|
foreach ($problems as $problem) {
|
|
foreach ($triggers[$problem['objectid']]['hosts'] as $trigger_host) {
|
|
if (!array_key_exists($trigger_host['hostid'], $problems_by_host)) {
|
|
$problems_by_host[$trigger_host['hostid']] = [
|
|
TRIGGER_SEVERITY_DISASTER => 0,
|
|
TRIGGER_SEVERITY_HIGH => 0,
|
|
TRIGGER_SEVERITY_AVERAGE => 0,
|
|
TRIGGER_SEVERITY_WARNING => 0,
|
|
TRIGGER_SEVERITY_INFORMATION => 0,
|
|
TRIGGER_SEVERITY_NOT_CLASSIFIED => 0
|
|
];
|
|
}
|
|
|
|
$problems_by_host[$trigger_host['hostid']][$problem['severity']]++;
|
|
}
|
|
}
|
|
|
|
// Filter hosts by severity filter.
|
|
$severity_filter = CProfile::get('web.dashboard.widget.geomap.severity_filter', '', $this->widgetid);
|
|
$severity_filter = ($severity_filter !== '') ? array_flip(explode(',', $severity_filter)) : [];
|
|
|
|
if ($severity_filter && count($severity_filter) != 7) {
|
|
$hosts = array_filter($hosts, static function ($host) use ($severity_filter, $problems_by_host) {
|
|
return array_key_exists($host['hostid'], $problems_by_host)
|
|
? (bool) array_intersect_key(array_filter($problems_by_host[$host['hostid']]), $severity_filter)
|
|
: array_key_exists(-1, $severity_filter);
|
|
});
|
|
}
|
|
|
|
$result_hosts = [];
|
|
foreach ($hosts as $host) {
|
|
$problems = array_key_exists($host['hostid'], $problems_by_host)
|
|
? $problems_by_host[$host['hostid']]
|
|
: [
|
|
TRIGGER_SEVERITY_DISASTER => 0,
|
|
TRIGGER_SEVERITY_HIGH => 0,
|
|
TRIGGER_SEVERITY_AVERAGE => 0,
|
|
TRIGGER_SEVERITY_WARNING => 0,
|
|
TRIGGER_SEVERITY_INFORMATION => 0,
|
|
TRIGGER_SEVERITY_NOT_CLASSIFIED => 0
|
|
];
|
|
|
|
$result_hosts[] = $host + ['problems' => $problems];
|
|
}
|
|
|
|
return $result_hosts;
|
|
}
|
|
|
|
/**
|
|
* Get initial map center point, zoom level and coordinates to center when clicking on navigate home button.
|
|
*/
|
|
private function getMapCenter(): array {
|
|
$geoloc_parser = new CGeomapCoordinatesParser();
|
|
$home_coords = [];
|
|
$center = [];
|
|
|
|
$user_default_view = CProfile::get('web.dashboard.widget.geomap.default_view', '', $this->widgetid);
|
|
if ($user_default_view !== '' && $geoloc_parser->parse($user_default_view) == CParser::PARSE_SUCCESS) {
|
|
$home_coords['default'] = true;
|
|
$center = $geoloc_parser->result;
|
|
$center['zoom'] = min($this->geomap_config['max_zoom'], $center['zoom']);
|
|
}
|
|
|
|
if (array_key_exists('default_view', $this->fields_values)
|
|
&& $this->fields_values['default_view'] !== ''
|
|
&& $geoloc_parser->parse($this->fields_values['default_view']) == CParser::PARSE_SUCCESS) {
|
|
$initial_view = $geoloc_parser->result;
|
|
|
|
if (array_key_exists('zoom', $initial_view)) {
|
|
$initial_view['zoom'] = min($this->geomap_config['max_zoom'], $initial_view['zoom']);
|
|
}
|
|
else {
|
|
$initial_view['zoom'] = ceil($this->geomap_config['max_zoom'] / 2);
|
|
}
|
|
|
|
$home_coords['initial'] = $initial_view;
|
|
if (!$center) {
|
|
$center = $home_coords['initial'];
|
|
}
|
|
}
|
|
|
|
$defaults = [
|
|
'latitude' => 0,
|
|
'longitude' => 0,
|
|
'zoom' => 1
|
|
];
|
|
|
|
return [
|
|
'center' => $center ?: $defaults,
|
|
'home_coords' => $home_coords
|
|
];
|
|
}
|
|
|
|
private function getUserProfileFilter(): array {
|
|
return [
|
|
'severity' => CProfile::get('web.dashboard.widget.geomap.severity_filter', [], $this->widgetid)
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Get global map configuration.
|
|
*/
|
|
private static function getMapConfig(): array {
|
|
if (CSettingsHelper::get(CSettingsHelper::GEOMAPS_TILE_PROVIDER) === '') {
|
|
return [
|
|
'tile_url' => CSettingsHelper::get(CSettingsHelper::GEOMAPS_TILE_URL),
|
|
'max_zoom' => CSettingsHelper::get(CSettingsHelper::GEOMAPS_MAX_ZOOM),
|
|
'attribution' => htmlspecialchars(CSettingsHelper::get(CSettingsHelper::GEOMAPS_ATTRIBUTION),
|
|
ENT_NOQUOTES, 'UTF-8'
|
|
)
|
|
];
|
|
}
|
|
|
|
$tile_provider = getTileProviders()[CSettingsHelper::get(CSettingsHelper::GEOMAPS_TILE_PROVIDER)];
|
|
|
|
return [
|
|
'tile_url' => $tile_provider['geomaps_tile_url'],
|
|
'max_zoom' => $tile_provider['geomaps_max_zoom'],
|
|
'attribution' => $tile_provider['geomaps_attribution']
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Create an array of problem severity colors.
|
|
*/
|
|
private static function getSeveritySettings(): array {
|
|
$severity_config = [
|
|
-1 => self::NO_PROBLEMS_MARKER_COLOR
|
|
];
|
|
|
|
for ($severity = TRIGGER_SEVERITY_NOT_CLASSIFIED; $severity < TRIGGER_SEVERITY_COUNT; $severity++) {
|
|
$severity_config[$severity] = '#'.CSeverityHelper::getColor($severity);
|
|
}
|
|
|
|
return $severity_config;
|
|
}
|
|
|
|
/**
|
|
* Convert array of hosts to valid GeoJSON (RFC7946) object.
|
|
*/
|
|
private static function convertToRFC7946(array $hosts) : array {
|
|
$geo_json = [];
|
|
|
|
foreach ($hosts as $host) {
|
|
$problems = array_filter($host['problems']);
|
|
$severities = array_keys($problems);
|
|
$top_severity = reset($severities);
|
|
|
|
$geo_json[] = [
|
|
'type' => 'Feature',
|
|
'geometry' => [
|
|
'type' => 'Point',
|
|
'coordinates' => [
|
|
$host['inventory']['location_lon'],
|
|
$host['inventory']['location_lat'],
|
|
0
|
|
]
|
|
],
|
|
'properties' => [
|
|
'hostid' => $host['hostid'],
|
|
'name' => $host['name'],
|
|
'severity' => ($top_severity === false) ? -1 : $top_severity,
|
|
'problems' => $problems
|
|
]
|
|
];
|
|
}
|
|
|
|
return $geo_json;
|
|
}
|
|
}
|