From 1cf7e206e583c76a5c9877690bf7fe84295611ae Mon Sep 17 00:00:00 2001 From: Mathieu Poussin <359877+kedare@users.noreply.github.com> Date: Fri, 13 Mar 2020 11:22:32 +0100 Subject: [PATCH] Geographical map: Show network links between locations (#11269) * Geographical map: Show links between locations * Fix manifest after merge conflict --- html/mix-manifest.json | 14 +-- includes/html/common/worldmap.inc.php | 117 ++++++++++++++++++++++++++ misc/config_definitions.json | 7 ++ resources/lang/en/settings.php | 5 ++ 4 files changed, 136 insertions(+), 7 deletions(-) diff --git a/html/mix-manifest.json b/html/mix-manifest.json index f17e38323c..eeaddc9a39 100644 --- a/html/mix-manifest.json +++ b/html/mix-manifest.json @@ -3,10 +3,10 @@ "/css/app.css": "/css/app.css?id=2a88c6515df894dc6f36", "/js/manifest.js": "/js/manifest.js?id=3c768977c2574a34506e", "/js/vendor.js": "/js/vendor.js?id=58c8fc0774b5843ec004", - "/js/lang/de.js": "/js/lang/de.js?id=e0623715e8df0895188b", - "/js/lang/en.js": "/js/lang/en.js?id=ad9c97639001057c62d7", - "/js/lang/fr.js": "/js/lang/fr.js?id=2d1159debd99a1909f12", - "/js/lang/ru.js": "/js/lang/ru.js?id=b007ddce75134acbe635", - "/js/lang/uk.js": "/js/lang/uk.js?id=146819d3cf1dfb16672d", - "/js/lang/zh-TW.js": "/js/lang/zh-TW.js?id=e578b34b9d5e21cf929d" -} + "/js/lang/de.js": "/js/lang/de.js?id=8c1c390a5f45ac01d54b", + "/js/lang/en.js": "/js/lang/en.js?id=201d470a19d7fa80027b", + "/js/lang/fr.js": "/js/lang/fr.js?id=807a43a37f4eeb4c1d17", + "/js/lang/ru.js": "/js/lang/ru.js?id=1a4435677a27aa615af1", + "/js/lang/uk.js": "/js/lang/uk.js?id=6ce358a9e9387947ee03", + "/js/lang/zh-TW.js": "/js/lang/zh-TW.js?id=3ad4a3e6a5a59165e806" +} \ No newline at end of file diff --git a/includes/html/common/worldmap.inc.php b/includes/html/common/worldmap.inc.php index 08eb09bf6f..f18505c79c 100644 --- a/includes/html/common/worldmap.inc.php +++ b/includes/html/common/worldmap.inc.php @@ -130,6 +130,123 @@ var marker = L.marker(new L.LatLng(".$map_devices['lat'].", ".$map_devices['lng' marker.bindPopup(title); markers.addLayer(marker);\n"; } + + if (Config::get('network_map_show_on_worldmap')) { + if (Auth::user()->hasGlobalRead()) { + $sql = " + SELECT + ll.id AS left_id, + ll.lat AS left_lat, + ll.lng AS left_lng, + rl.id AS right_id, + rl.lat AS right_lat, + rl.lng AS right_lng, + sum(lp.ifHighSpeed) AS link_capacity, + sum(lp.ifOutOctets_rate) * 8 / sum(lp.ifSpeed) * 100 as link_out_usage_pct, + sum(lp.ifInOctets_rate) * 8 / sum(lp.ifSpeed) * 100 as link_in_usage_pct + FROM + devices AS ld, + devices AS rd, + links AS l, + locations AS ll, + locations AS rl, + ports as lp + WHERE + l.local_device_id = ld.device_id + AND l.remote_device_id = rd.device_id + AND ld.location_id != rd.location_id + AND ld.location_id = ll.id + AND rd.location_id = rl.id + AND lp.device_id = ld.device_id + AND lp.port_id = l.local_port_id + AND lp.ifType = 'ethernetCsmacd' + AND ld.disabled = 0 + AND ld.ignore = 0 + AND rd.disabled = 0 + AND rd.ignore = 0 + AND ld.status IN " . dbGenPlaceholders(count($show_status)) . " + AND rd.status IN " . dbGenPlaceholders(count($show_status)) . " + GROUP BY + left_id, right_id, ll.lat, ll.lng, rl.lat, rl.lng + "; + $param = array_merge($show_status, $show_status); + } else { + $device_ids = Permissions::devicesForUser()->toArray() ?: [0]; + $sql = " + SELECT + ll.id AS left_id, + ll.lat AS left_lat, + ll.lng AS left_lng, + rl.id AS right_id, + rl.lat AS right_lat, + rl.lng AS right_lng, + sum(lp.ifHighSpeed) AS link_capacity, + sum(lp.ifOutOctets_rate) * 8 / sum(lp.ifSpeed) * 100 as link_out_usage_pct, + sum(lp.ifInOctets_rate) * 8 / sum(lp.ifSpeed) * 100 as link_in_usage_pct + FROM + devices AS ld, + devices AS rd, + links AS l, + locations AS ll, + locations AS rl, + ports as lp + WHERE + l.local_device_id = ld.device_id + AND l.remote_device_id = rd.device_id + AND ld.location_id != rd.location_id + AND ld.location_id = ll.id + AND rd.location_id = rl.id + AND lp.device_id = ld.device_id + AND lp.port_id = l.local_port_id + AND lp.ifType = 'ethernetCsmacd' + AND ld.disabled = 0 + AND ld.ignore = 0 + AND rd.disabled = 0 + AND rd.ignore = 0 + AND ld.status IN " . dbGenPlaceholders(count($show_status)) . " + AND rd.status IN " . dbGenPlaceholders(count($show_status)) . " + AND ld.device_id IN " . dbGenPlaceholders(count($device_ids)) . " + AND rd.device_id IN " . dbGenPlaceholders(count($device_ids)) . " + GROUP BY + left_id, right_id, ll.lat, ll.lng, rl.lat, rl.lng + "; + $param = array_merge($show_status, $show_status, $device_ids, $device_ids); + } + + foreach (dbFetchRows($sql, $param) as $link) { + $icon = 'greenMarker'; + $z_offset = 0; + + $speed = $link['link_capacity']/1000; + if ($speed > 500000) { + $width = 20; + } else { + $width = round(0.77 * pow($speed, 0.25)); + } + + $link_used = ($link["link_out_usage_pct"] + $link["link_in_usage_pct"]) / 2; + $link_used = round(2 * $link_used, -1) / 2; + if ($link_used > 100) { + $link_used = 100; + } + if (is_nan($link_used)) { + $link_used = 0; + } + $link_color = Config::get("network_map_legend.$link_used"); + + $temp_output .= "var marker = new L.Polyline([new L.LatLng(". $link["left_lat"] .", ". $link["left_lng"] ."), new L.LatLng(". $link["right_lat"] .", ". $link["right_lng"] .")], { + color: '". $link_color ."', + weight: ". $width .", + opacity: 0.8, + smoothFactor: 1 + }); + markers.addLayer(marker); + "; + } + } + + + $temp_output .= 'map.addLayer(markers); map.scrollWheelZoom.disable(); $(document).ready(function(){ diff --git a/misc/config_definitions.json b/misc/config_definitions.json index 86f0f9bc39..27d9f5b52b 100644 --- a/misc/config_definitions.json +++ b/misc/config_definitions.json @@ -3649,6 +3649,13 @@ }, "type": "array" }, + "network_map_show_on_worldmap": { + "default": false, + "type": "boolean", + "group": "webui", + "section": "worldmap", + "order": 1 + }, "network_map_vis_options": { "default": "{\n layout:{\n randomSeed:2\n },\n \"edges\": {\n arrows: {\n to: {enabled: true, scaleFactor:0.5},\n },\n \"smooth\": {\n enabled: false\n },\n font: {\n size: 14,\n color: \"red\",\n face: \"sans\",\n background: \"white\",\n strokeWidth:3,\n align: \"middle\",\n strokeWidth: 2\n }\n },\n \"physics\": {\n \"barnesHut\": {\n \"gravitationalConstant\": -2000,\n \"centralGravity\": 0.3,\n \"springLength\": 200,\n \"springConstant\": 0.04,\n \"damping\": 0.09,\n \"avoidOverlap\": 1\n },\n\n \"forceAtlas2Based\": {\n \"gravitationalConstant\": -50,\n \"centralGravity\": 0.01,\n \"springLength\": 200,\n \"springConstant\": 0.08,\n \"damping\": 0.4,\n \"avoidOverlap\": 1\n },\n\n \"repulsion\": {\n \"centralGravity\": 0.2,\n \"springLength\": 250,\n \"springConstant\": 0.2,\n \"nodeDistance\": 200,\n \"damping\": 0.07\n },\n\n \"hierarchicalRepulsion\": {\n \"nodeDistance\": 300,\n \"centralGravity\": 0.2,\n \"springLength\": 300,\n \"springConstant\": 0.2,\n \"damping\": 0.07\n },\n\n \"maxVelocity\": 50,\n \"minVelocity\": 0.4,\n \"solver\": \"hierarchicalRepulsion\",\n \"stabilization\": {\n \"enabled\": true,\n \"iterations\": 1000,\n \"updateInterval\": 100,\n \"onlyDynamicEdges\": false,\n \"fit\": true\n },\n\n \"timestep\": 0.4,\n }\n}", "type": "text" diff --git a/resources/lang/en/settings.php b/resources/lang/en/settings.php index ebdb7f9120..4198fd8413 100644 --- a/resources/lang/en/settings.php +++ b/resources/lang/en/settings.php @@ -67,6 +67,7 @@ return [ 'search' => 'Search Settings', 'style' => 'Style', 'device' => 'Device Settings', + 'worldmap' => 'World Map Settings' ] ], 'settings' => [ @@ -761,6 +762,10 @@ return [ 'description' => 'Primary Domain', 'help' => 'This domain is used for network auto-discovery and other processes. LibreNMS will attempt to append it to unqualified hostnames.' ], + 'network_map_show_on_worldmap' => [ + 'description' => 'Display network links on the map', + 'help' => 'Show the networks links between the different location on the worldmap (weathermap-like)' + ], 'nfsen_enable' => [ 'description' => 'Enable NfSen', 'help' => 'Enable Integration with NfSen',