Lobby: Dashboard - gateway status widget, add gateway status endpoint (api/routes/gateway/status) and refactor widget to use it. closes https://github.com/opnsense/core/issues/4261

This commit is contained in:
Ad Schellevis 2020-08-21 12:36:10 +02:00
parent 7cfa870850
commit 89cfc06d8e
6 changed files with 205 additions and 128 deletions

View File

@ -0,0 +1,53 @@
<?php
/*
* Copyright (C) 2015-2018 Deciso B.V.
* Copyright (C) 2017 Fabian Franz
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Routes\Api;
use OPNsense\Base\ApiControllerBase;
use OPNsense\Core\Backend;
/**
* @package OPNsense\Routes
*/
class GatewayController extends ApiControllerBase
{
public function statusAction()
{
$result = ["items" => [], "status" => "failed"];
$backend = new Backend();
$gw_status = json_decode($backend->configdRun('interface gateways status'), true);
if (!empty($gw_status)) {
$result['items'] = $gw_status;
$result['status'] = "ok";
}
return $result;
}
}

View File

@ -47,12 +47,20 @@
<pattern>widgets/widgets/*.widget.php*</pattern>
<pattern>widgets/api/get.php*</pattern>
<pattern>api/diagnostics/dns/reverse_lookup*</pattern>
<pattern>api/routes/gateway/status*</pattern>
<pattern>api/diagnostics/interface/getInterfaceNames</pattern>
<pattern>api/diagnostics/firewall/log</pattern>
<pattern>api/monit/status/get/xml</pattern>
</patterns>
</page-dashboard-all>
<page-dashboard-widgets>
<name>Dashboard (widgets only)</name>
<patterns>
<pattern>widgets/widgets/*.widget.php*</pattern>
<pattern>api/routes/gateway/status*</pattern>
<pattern>api/diagnostics/interface/getInterfaceNames</pattern>
<pattern>api/diagnostics/firewall/log</pattern>
<pattern>api/monit/status/get/xml</pattern>
</patterns>
</page-dashboard-widgets>
<page-diagnostics-authentication>

View File

@ -0,0 +1,74 @@
#!/usr/local/bin/php
<?php
/*
* Copyright (C) 2016-2020 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
require_once 'config.inc';
require_once 'util.inc';
require_once 'interfaces.inc';
$result = array();
$gateways_status = return_gateways_status();
foreach ((new \OPNsense\Routing\Gateways(legacy_interfaces_details()))->gatewaysIndexedByName() as $gname => $gw) {
$gatewayItem = array('name' => $gname);
$gatewayItem['address'] = !empty($gw['gateway']) ? $gw['gateway'] : "~";
if (!empty($gateways_status[$gname])) {
$gatewayItem['status'] = strtolower($gateways_status[$gname]['status']);
$gatewayItem['loss'] = $gateways_status[$gname]['loss'];
$gatewayItem['delay'] = $gateways_status[$gname]['delay'];
$gatewayItem['stddev'] = $gateways_status[$gname]['stddev'];
switch ($gatewayItem['status']) {
case 'none':
$gatewayItem['status_translated'] = gettext('Online');
break;
case 'force_down':
$gatewayItem['status_translated'] = gettext('Offline (forced)');
break;
case 'down':
$gatewayItem['status_translated'] = gettext('Offline');
break;
case 'delay':
$gatewayItem['status_translated'] = gettext('Latency');
break;
case 'loss':
$gatewayItem['status_translated'] = gettext('Packetloss');
break;
default:
$gatewayItem['status_translated'] = gettext('Pending');
break;
}
} else {
$gatewayItem['status'] = 'none';
$gatewayItem['status_translated'] = gettext('Online');
$gatewayItem['loss'] = '~';
$gatewayItem['stddev'] = '~';
$gatewayItem['delay'] = '~';
}
$result[] = $gatewayItem;
}
echo json_encode($result) . PHP_EOL;

View File

@ -93,6 +93,11 @@ command:/usr/local/opnsense/scripts/routes/gateways.php
type:script_output
message:list gateways
[gateways.status]
command:/usr/local/opnsense/scripts/routes/gateway_status.php
type:script_output
message:list gateway status
[vxlan.configure]
command: /usr/local/sbin/pluginctl -c vxlan_prepare
message: Reconfiguring vxlan

View File

@ -1,74 +0,0 @@
<?php
/*
* Copyright (C) 2016 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* widget gateway data
*/
function gateway_api()
{
$result = array();
$gateways_status = return_gateways_status();
foreach ((new \OPNsense\Routing\Gateways(legacy_interfaces_details()))->gatewaysIndexedByName() as $gname => $gw) {
$gatewayItem = array('name' => $gname);
$gatewayItem['address'] = !empty($gw['gateway']) ? $gw['gateway'] : "~";
if (!empty($gateways_status[$gname])) {
$gatewayItem['status'] = strtolower($gateways_status[$gname]['status']);
$gatewayItem['loss'] = $gateways_status[$gname]['loss'];
$gatewayItem['delay'] = $gateways_status[$gname]['delay'];
$gatewayItem['stddev'] = $gateways_status[$gname]['stddev'];
switch ($gatewayItem['status']) {
case 'none':
$gatewayItem['status_translated'] = gettext('Online');
break;
case 'force_down':
$gatewayItem['status_translated'] = gettext('Offline (forced)');
break;
case 'down':
$gatewayItem['status_translated'] = gettext('Offline');
break;
case 'delay':
$gatewayItem['status_translated'] = gettext('Latency');
break;
case 'loss':
$gatewayItem['status_translated'] = gettext('Packetloss');
break;
default:
$gatewayItem['status_translated'] = gettext('Pending');
break;
}
} else {
$gatewayItem['status'] = 'none';
$gatewayItem['status_translated'] = gettext('Online');
$gatewayItem['loss'] = '~';
$gatewayItem['stddev'] = '~';
$gatewayItem['delay'] = '~';
}
$result[] = $gatewayItem;
}
return $result;
}

View File

@ -27,7 +27,6 @@
*/
require_once("guiconfig.inc");
require_once("widgets/include/gateways.inc");
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
$pconfig = array();
@ -52,47 +51,73 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
}
$gateways = (new \OPNsense\Routing\Gateways(legacy_interfaces_details()))->gatewaysIndexedByName();
?>
<script>
function gateways_widget_update(sender, data)
{
data.map(function(gateway) {
var tr_id = "gateways_widget_gw_" + gateway['name'];
if ($("#"+tr_id).length) {
$("#"+tr_id+" > td:eq(0)").html('<small><strong>'+gateway['name']+'</strong><br/>'+gateway['address']+'</small>');
$("#"+tr_id+" > td:eq(1)").html(gateway['delay']);
$("#"+tr_id+" > td:eq(2)").html(gateway['stddev']);
$("#"+tr_id+" > td:eq(3)").html(gateway['loss']);
$("#"+tr_id+" > td:eq(4)").html('<span>'+gateway['status_translated']+'</span>');
// set color on status text
let status_color;
switch (gateway['status']) {
case 'force_down':
case 'down':
status_color = 'danger';
break;
case 'loss':
case 'delay':
status_color = 'warning';
break;
case 'none':
status_color = 'success';
break;
default:
status_color = 'default';
break;
}
$("#"+tr_id+" > td:eq(4) > span").removeClass("label-danger label-warning label-success label");
if (status_color != '') {
$("#"+tr_id+" > td:eq(4) > span").addClass("label label-" + status_color);
}
}
});
}
$(window).on("load", function() {
function fetch_gateway_statusses(){
ajaxGet('/api/routes/gateway/status', {}, function(data, status) {
if (data.items !== undefined) {
$.each(data.items, function(key, gateway) {
let $gw_item = $("#gateways_widget_gw_"+gateway.name);
if ($gw_item.length == 0) {
$gw_item = $("<tr>").attr('id', "gateways_widget_gw_"+gateway.name);
$gw_item.append($("<td/>").append(
"<small><strong>~</strong><br/><div>~</div></small>")
);
$gw_item.append($("<td class='text-nowrap'/>").text("~"));
$gw_item.append($("<td class='text-nowrap'/>").text("~"));
$gw_item.append($("<td class='text-nowrap'/>").text("~"));
$gw_item.append(
$("<td/>").append(
$("<span class='label label-default'/>").text("<?= gettext('Unknown') ?>")
)
);
$("#gateway_widget_table").append($gw_item);
$gw_item.hide();
}
$gw_item.find('td:eq(0) > small > strong').text(gateway.name);
$gw_item.find('td:eq(0) > small > div').text(gateway.address);
$gw_item.find('td:eq(1)').text(gateway.delay);
$gw_item.find('td:eq(2)').text(gateway.stddev);
$gw_item.find('td:eq(3)').text(gateway.loss);
let status_color;
switch (gateway.status) {
case 'force_down':
case 'down':
status_color = 'danger';
break;
case 'loss':
case 'delay':
status_color = 'warning';
break;
case 'none':
status_color = 'success';
break;
default:
status_color = 'default';
break;
}
$gw_item.find('td:eq(4) > span').removeClass("label-danger label-warning label-success label");
if (status_color != '') {
$gw_item.find('td:eq(4) > span')
.addClass("label label-" + status_color)
.text(gateway.status_translated);
}
let show_item = $("#gatewaysinvert").val() == 'yes' ? false : true;
if ($("#gatewaysfilter").val() && $("#gatewaysfilter").val().includes(gateway.name)) {
show_item = !show_item;
}
if (show_item) {
$gw_item.show();
}
});
}
});
setTimeout(fetch_gateway_statusses, 5000);
}
fetch_gateway_statusses();
});
</script>
<div id="gateways-settings" class="widgetconfigdiv" style="display:none;">
@ -117,7 +142,7 @@ $gateways = (new \OPNsense\Routing\Gateways(legacy_interfaces_details()))->gatew
</div>
<!-- gateway table -->
<table class="table table-striped table-condensed" data-plugin="gateway" data-callback="gateways_widget_update">
<table id="gateway_widget_table" class="table table-striped table-condensed">
<tr>
<th><?=gettext('Name')?></th>
<th><?=gettext('RTT')?></th>
@ -125,20 +150,6 @@ $gateways = (new \OPNsense\Routing\Gateways(legacy_interfaces_details()))->gatew
<th><?=gettext('Loss')?></th>
<th><?=gettext('Status')?></th>
</tr>
<?php foreach (array_keys($gateways) as $gwname):
$listed = in_array($gwname, $pconfig['gatewaysfilter']);
$listed = !empty($pconfig['gatewaysinvert']) ? $listed : !$listed;
if (!$listed) {
continue;
} ?>
<tr id="gateways_widget_gw_<?= html_safe($gwname) ?>">
<td><small><strong><?= $gwname ?></strong><br/>~</small></td>
<td class="text-nowrap">~</td>
<td class="text-nowrap">~</td>
<td class="text-nowrap">~</td>
<td><span class="label label-default"><?= gettext('Unknown') ?></span></td>
</tr>
<?php endforeach ?>
</table>
<!-- needed to display the widget settings menu -->