added new view for device congestion
This commit is contained in:
@@ -130,6 +130,7 @@
|
|||||||
<?php if($me->isAdmin() || $me->can("Cpeshipping")): ?><li><a href="<?=self::getUrl("Cpeshipping")?>"><i class="fad fa-fw fa-shipping-fast text-info"></i> CPE Versand</a></li><?php endif; ?>
|
<?php if($me->isAdmin() || $me->can("Cpeshipping")): ?><li><a href="<?=self::getUrl("Cpeshipping")?>"><i class="fad fa-fw fa-shipping-fast text-info"></i> CPE Versand</a></li><?php endif; ?>
|
||||||
<?php if($me->isAdmin()) : ?><li><a href="<?=self::getUrl("Domain")?>"><i class="fad fa-fw fa-globe text-info"></i> Domains</a></li><?php endif; ?>
|
<?php if($me->isAdmin()) : ?><li><a href="<?=self::getUrl("Domain")?>"><i class="fad fa-fw fa-globe text-info"></i> Domains</a></li><?php endif; ?>
|
||||||
<?php if($me->isAdmin()) : ?><li><a href="<?=self::getUrl("IpNetwork")?>"><i class="fa-solid fa-network-wired text-info"></i> IPAM</a></li><?php endif; ?>
|
<?php if($me->isAdmin()) : ?><li><a href="<?=self::getUrl("IpNetwork")?>"><i class="fa-solid fa-network-wired text-info"></i> IPAM</a></li><?php endif; ?>
|
||||||
|
<?php if($me->isAdmin()) : ?><li><a href="<?=self::getUrl("DeviceMonitoring/congestion")?>"><i class="fa-solid fa-block-brick-fire text-info"></i> Device Congestion</a></li><?php endif; ?>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property mixed|null $name
|
||||||
|
*/
|
||||||
|
class DeviceMonitoring extends mfBaseModel
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class DeviceMonitoringController extends mfBaseController {
|
||||||
|
private User $me;
|
||||||
|
private string $ZABBIX_API_URL = ZABBIX_API_URL;
|
||||||
|
private string $ZABBIX_API_KEY = ZABBIX_API_KEY;
|
||||||
|
|
||||||
|
private Zabbix $zabbix;
|
||||||
|
|
||||||
|
|
||||||
|
protected function init(): void {
|
||||||
|
$me = new User();
|
||||||
|
$me->loadMe();
|
||||||
|
$this->layout()->set("me", $me);
|
||||||
|
$this->me = $me;
|
||||||
|
|
||||||
|
if (!$this->me->isAdmin()) {
|
||||||
|
$this->redirect("dashboard");
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->zabbix = new Zabbix($this->ZABBIX_API_URL, $this->ZABBIX_API_KEY);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function congestionAction() {
|
||||||
|
$congestionData = $this->getCongestionData();
|
||||||
|
|
||||||
|
Helper::renderVue($this, "DeviceMonitoringCongestion", $this->mod,
|
||||||
|
["CONGESTION_DATA" => $congestionData]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getCongestionData(): array {
|
||||||
|
$filename = TEMP_DIR . "/DeviceMonitoring/interfacesWithCongestion.json";
|
||||||
|
|
||||||
|
// if file is older than 50 minutes, fetch new data
|
||||||
|
if (file_exists($filename) && (time() - filemtime($filename)) < 3000) {
|
||||||
|
$interfacesWithCongestion = json_decode(file_get_contents($filename), true);
|
||||||
|
$fileCreateTime = date("Y-m-d H:i:s", filemtime($filename));
|
||||||
|
|
||||||
|
return ["interfacesWithCongestion" => $interfacesWithCongestion, "fileCreateTime" => $fileCreateTime];
|
||||||
|
}
|
||||||
|
|
||||||
|
$congestionInterfaces = $this->zabbix->getAllCongestionInterfaces();
|
||||||
|
|
||||||
|
$interfacesWithCongestion = [];
|
||||||
|
|
||||||
|
$fetchedHosts = [];
|
||||||
|
|
||||||
|
foreach ($congestionInterfaces as $interface) {
|
||||||
|
$itemId = $interface['itemid'];
|
||||||
|
$name = $interface['name'];
|
||||||
|
$name = str_replace(": Congestion Packets", "", $name);
|
||||||
|
$hostId = $interface['hostid'];
|
||||||
|
|
||||||
|
$values = $this->zabbix->getItemValues($itemId);
|
||||||
|
|
||||||
|
$highestValue = 0;
|
||||||
|
$highestValueTime = 0;
|
||||||
|
foreach ($values as $value) {
|
||||||
|
if ($value['value'] > $highestValue) {
|
||||||
|
$highestValue = $value['value'];
|
||||||
|
$highestValueTime = $value['clock'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if highest value is 0, then there is no congestion
|
||||||
|
if ($highestValue == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in_array($hostId, $fetchedHosts)) {
|
||||||
|
$host = $fetchedHosts[$hostId];
|
||||||
|
} else {
|
||||||
|
$host = $this->zabbix->getHostById($hostId);
|
||||||
|
$fetchedHosts[$hostId] = $host;
|
||||||
|
}
|
||||||
|
|
||||||
|
$hostname = $host[0]['name'];
|
||||||
|
$ip = $host[0]['host'];
|
||||||
|
|
||||||
|
|
||||||
|
$interfacesWithCongestion[] = [
|
||||||
|
"hostname" => $hostname,
|
||||||
|
"ip" => $ip,
|
||||||
|
"name" => $name,
|
||||||
|
"zabbixUrl" => ZABBIX_URL . "/zabbix.php?action=latest.view&hostids%5B%5D=" . $hostId,
|
||||||
|
"grafanaUrl" => GRAFANA_URL . "/d/Ta3PtRWZk/mikrotik-dashboard?orgId=1&var-host=" . $hostname,
|
||||||
|
"highestValue" => $highestValue,
|
||||||
|
"highestValueTime" => $highestValueTime
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!file_exists(TEMP_DIR . "/DeviceMonitoring")) {
|
||||||
|
mkdir(TEMP_DIR . "/DeviceMonitoring");
|
||||||
|
}
|
||||||
|
|
||||||
|
file_put_contents($filename, json_encode($interfacesWithCongestion));
|
||||||
|
return ["interfacesWithCongestion" => $interfacesWithCongestion, "fileCreateTime" => date("Y-m-d H:i:s")];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected function indexAction(): void {
|
||||||
|
$JSGlobals = ["BASE_URL" => self::getUrl("VoiceCallActive"),
|
||||||
|
"DASHBOARD_URL" => self::getUrl("Dashboard"),
|
||||||
|
"MFAPPNAME" => MFAPPNAME_SLUG,
|
||||||
|
"PAGE_TITLE" => "Active Voice Calls",
|
||||||
|
"PATH" => [
|
||||||
|
["text" => MFAPPNAME_SLUG, "href" => self::getUrl("Dashboard")],
|
||||||
|
["text" => "Active Voice Calls", "href" => self::getUrl("VoiceCallActive")]
|
||||||
|
],
|
||||||
|
"VOICE_CALL_ACTIVE_API_URL" => self::getUrl("VoiceCallActive/api"),
|
||||||
|
];
|
||||||
|
|
||||||
|
$this->layout()->set("additionalCSS", ["css/views/VoiceCallActive.css"]);
|
||||||
|
$this->layout()->set("vueViewName", "VoiceCallActive");
|
||||||
|
$this->layout()->set("JSGlobals", $JSGlobals);
|
||||||
|
$this->layout()->setTemplate("VueViews/Vue");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function apiAction() {
|
||||||
|
$do = $this->request->do;
|
||||||
|
|
||||||
|
if (!$this->me->isAdmin()) {
|
||||||
|
$this->redirect("dashboard");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($do) {
|
||||||
|
case "getActiveCalls":
|
||||||
|
$return = $this->getActiveCalls();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
$return = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$return) {
|
||||||
|
$return = [
|
||||||
|
"status" => "error",
|
||||||
|
"message" => "Invalid request."
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
die(json_encode($return));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getActiveCalls(): array {
|
||||||
|
$activeCalls = $this->kolmisoftMore->getActiveCalls();
|
||||||
|
|
||||||
|
return is_null($activeCalls) ? [] : (is_object($activeCalls) ? [$activeCalls] : $activeCalls);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class Zabbix {
|
||||||
|
private $url;
|
||||||
|
private $apiKey;
|
||||||
|
|
||||||
|
public function __construct($url, $apiKey) {
|
||||||
|
$this->url = $url;
|
||||||
|
$this->apiKey = $apiKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function zabbixRequest($method, $params) {
|
||||||
|
$data = array(
|
||||||
|
'jsonrpc' => '2.0',
|
||||||
|
'method' => $method,
|
||||||
|
'params' => $params,
|
||||||
|
'id' => 1
|
||||||
|
);
|
||||||
|
|
||||||
|
$options = array(
|
||||||
|
'http' => array(
|
||||||
|
'header' => "Content-Type: application/json\r\n" .
|
||||||
|
"Authorization: Bearer " . $this->apiKey . "\r\n",
|
||||||
|
'method' => 'POST',
|
||||||
|
'content' => json_encode($data)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$context = stream_context_create($options);
|
||||||
|
$result = file_get_contents($this->url, false, $context);
|
||||||
|
|
||||||
|
return json_decode($result, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllCongestionInterfaces() {
|
||||||
|
$response = $this->zabbixRequest('item.get', array(
|
||||||
|
'search' => array('name' => array("Congestion")),
|
||||||
|
));
|
||||||
|
return $response['result'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHostById($hostId) {
|
||||||
|
$response = $this->zabbixRequest('host.get', array(
|
||||||
|
'hostids' => $hostId
|
||||||
|
));
|
||||||
|
return $response['result'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getItemValues($itemIds) {
|
||||||
|
$response = $this->zabbixRequest('history.get', array(
|
||||||
|
'itemids' => $itemIds,
|
||||||
|
'output' => 'extend',
|
||||||
|
'sortfield' => 'clock',
|
||||||
|
'sortorder' => 'DESC',
|
||||||
|
'limit' => 15
|
||||||
|
));
|
||||||
|
return $response['result'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHosts($hostname) {
|
||||||
|
$response = $this->zabbixRequest('host.get', array(
|
||||||
|
'search' => array('name' => array($hostname))
|
||||||
|
));
|
||||||
|
return $response['result'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInterfaceItems($hostId, $interfaceName) {
|
||||||
|
$response = $this->zabbixRequest('item.get', array(
|
||||||
|
'hostids' => $hostId,
|
||||||
|
'search' => array('name' => array($interfaceName, "Bits"))
|
||||||
|
));
|
||||||
|
return $response['result'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUptimeItems($hostId) {
|
||||||
|
$response = $this->zabbixRequest('item.get', array(
|
||||||
|
'hostids' => $hostId,
|
||||||
|
'search' => array('name' => array("Uptime"))
|
||||||
|
));
|
||||||
|
return $response['result'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHostInterfaces($hostIds) {
|
||||||
|
$response = $this->zabbixRequest('hostinterface.get', array('hostids' => $hostIds));
|
||||||
|
return $response['result'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function createTask($itemid) {
|
||||||
|
$response = $this->zabbixRequest('task.create', array(
|
||||||
|
'type' => 6,
|
||||||
|
'request' => array(
|
||||||
|
'itemid' => $itemid
|
||||||
|
)
|
||||||
|
));
|
||||||
|
return $response['result'];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
Vue.component('device-monitoring-congestion', {
|
||||||
|
//language=Vue
|
||||||
|
template: `
|
||||||
|
|
||||||
|
<tt-card>
|
||||||
|
<!--@formatter:off-->
|
||||||
|
<div>Letzte Abfragezeit: {{ window.moment.utc(window['TT_CONFIG']['CONGESTION_DATA']['fileCreateTime']).add(1, 'hours').format('DD.MM.YYYY HH:mm:ss') }}</div>
|
||||||
|
<!--@formatter:on-->
|
||||||
|
<tt-table :data="window['TT_CONFIG']['CONGESTION_DATA']['interfacesWithCongestion']" :config="DeviceTableConfig" excel-export>
|
||||||
|
|
||||||
|
<template v-slot:actions="{ row }">
|
||||||
|
<a :href="row.zabbixUrl" target="_blank"><i class="fas fa-chart-line" title="Zabbix"></i></a>
|
||||||
|
<a :href="row.grafanaUrl" target="_blank"><i class="fas fa-chart-bar" title="Grafana"></i></a>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template v-slot:highestvaluetime="{ row }">
|
||||||
|
{{ window.moment.unix(row.highestValueTime).format('DD.MM.YYYY HH:mm:ss') }}
|
||||||
|
</template>
|
||||||
|
|
||||||
|
</tt-table>
|
||||||
|
</tt-card>
|
||||||
|
`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
window: window,
|
||||||
|
DeviceTableConfig: {
|
||||||
|
key: 'DeviceMonitoringCongestion',
|
||||||
|
tableHeader: 'Device Monitoring - Congestion',
|
||||||
|
defaultPageSize: 25,
|
||||||
|
headers: [
|
||||||
|
{text: 'Hostname', key: 'hostname', sortable: true, class: 'text-nowrap'},
|
||||||
|
{text: 'IP-Adresse', key: 'ip', filter: 'search', class: 'text-center'},
|
||||||
|
{text: 'Name', key: 'name', filter: 'search', class: 'text-center'},
|
||||||
|
{text: 'Höchster Wert', key: 'highestValue', filter: 'search', class: 'text-center'},
|
||||||
|
{text: 'Zeit', key: 'highestValueTime', filter: 'search', class: 'text-center'},
|
||||||
|
{text: 'Aktionen', key: 'actions', class: 'text-center', sortable: false, filter: false, priority: 9},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#!/usr/bin/php
|
||||||
|
<?php
|
||||||
|
|
||||||
|
//require 'vendor/autoload.php';
|
||||||
|
require("../../config/config.php");
|
||||||
|
|
||||||
|
define('FRONKDB_SQLDEBUG',false);
|
||||||
|
error_reporting(E_ALL & ~(E_NOTICE | E_STRICT | E_DEPRECATED));
|
||||||
|
|
||||||
|
require_once(LIBDIR."/mvcfronk/mfRouter/mfRouter.php");
|
||||||
|
require_once(LIBDIR."/mvcfronk/mfBase/mfBaseModel.php");
|
||||||
|
require_once(LIBDIR."/mvcfronk/mfBase/mfBaseController.php");
|
||||||
|
|
||||||
|
$me = new User(1);
|
||||||
|
|
||||||
|
define("INTERNAL_USER_ID", $me->id);
|
||||||
|
define("INTERNAL_USER_USERNAME", $me->username);
|
||||||
|
|
||||||
|
$DeviceMonitoringController = new DeviceMonitoringController(false);
|
||||||
|
|
||||||
|
$DeviceMonitoringController->getCongestionData();
|
||||||
Reference in New Issue
Block a user