diff --git a/application/Device/DeviceController.php b/application/Device/DeviceController.php index 161aced15..341b29cac 100644 --- a/application/Device/DeviceController.php +++ b/application/Device/DeviceController.php @@ -49,6 +49,8 @@ class DeviceController extends mfBaseController "DEVICE_MANUFACTURERS" => $deviceManufacturers, "DEVICE_TYPES" => $deviceTypes, "DEVICES" => $this->getDevices(), + "ZABBIX_URL" => ZABBIX_URL, + "GRAFANA_URL" => GRAFANA_URL, ]; $this->layout()->set("vueViewName", "Device"); @@ -398,7 +400,7 @@ class DeviceController extends mfBaseController $locationText = ""; $locationUrl = ""; - if (trim($device->pop->name)) { + if (isset($device->pop) && trim($device->pop->name)) { $locationText = $device->pop->name; $locationUrl = self::getUrl("Pop", "Detail", ["id" => $device->pop->id]); } else if (trim($device->addr_street)) { @@ -431,6 +433,8 @@ class DeviceController extends mfBaseController "ip" => $device->ip, "mac" => $device->mac, "serial" => $device->serial, + "zabbix_online" => $device->zabbix_online, + "zabbix_host_id" => $device->zabbix_host_id, "price" => $device->price != "0.00" ? $device->price : $device->devicetype->price, "power" => $device->power != "0.00" ? intval($device->power) : intval($device->devicetype->power), "backup" => $backup, diff --git a/application/DeviceMonitoring/DeviceMonitoringController.php b/application/DeviceMonitoring/DeviceMonitoringController.php index cc98cfcb4..440dc1570 100644 --- a/application/DeviceMonitoring/DeviceMonitoringController.php +++ b/application/DeviceMonitoring/DeviceMonitoringController.php @@ -29,10 +29,17 @@ class DeviceMonitoringController extends mfBaseController { ["CONGESTION_DATA" => $congestionData]); } + protected function syncAction() { + $this->syncToolZabbix(); + die("Sync done"); + } + public function getCongestionData(): array { $filename = TEMP_DIR . "/DeviceMonitoring/interfacesWithCongestion.json"; + $interfacesWithCongestion = []; + $fetchedHosts = []; - // if file is older than 50 minutes, fetch new data + // If file exists and is not older than 3000 seconds, then return the cached 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)); @@ -42,16 +49,10 @@ class DeviceMonitoringController extends mfBaseController { $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']; + // Check if congestion exists on this interface $values = $this->zabbix->getItemValues($itemId); $highestValue = 0; @@ -63,11 +64,11 @@ class DeviceMonitoringController extends mfBaseController { } } - // if highest value is 0, then there is no congestion if ($highestValue == 0) { continue; } + $hostId = $interface['hostid']; if (in_array($hostId, $fetchedHosts)) { $host = $fetchedHosts[$hostId]; } else { @@ -75,16 +76,12 @@ class DeviceMonitoringController extends mfBaseController { $fetchedHosts[$hostId] = $host; } - $hostname = $host[0]['name']; - $ip = $host[0]['host']; - - $interfacesWithCongestion[] = [ - "hostname" => $hostname, - "ip" => $ip, - "name" => $name, + "hostname" => $host[0]['name'], + "ip" => $host[0]['host'], + "name" => str_replace(": Congestion Packets", "", $interface['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, + "grafanaUrl" => GRAFANA_URL . "/d/Ta3PtRWZk/mikrotik-dashboard?orgId=1&var-host=" . $host[0]['name'], "highestValue" => $highestValue, "highestValueTime" => $highestValueTime ]; @@ -98,54 +95,38 @@ class DeviceMonitoringController extends mfBaseController { return ["interfacesWithCongestion" => $interfacesWithCongestion, "fileCreateTime" => date("Y-m-d H:i:s")]; } + public function syncToolZabbix() { + $devices = DeviceModel::getAll(); - 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"), - ]; + foreach ($devices as $device) { + $hostname = $device->name; - $this->layout()->set("additionalCSS", ["css/views/VoiceCallActive.css"]); - $this->layout()->set("vueViewName", "VoiceCallActive"); - $this->layout()->set("JSGlobals", $JSGlobals); - $this->layout()->setTemplate("VueViews/Vue"); - } + $hosts = $this->zabbix->getHosts($hostname); + if (empty($hosts)) { + // TODO: implement any type of logging + continue; + } - protected function apiAction() { - $do = $this->request->do; + $hostId = $hosts[0]['hostid']; - if (!$this->me->isAdmin()) { - $this->redirect("dashboard"); + $icmpItems = $this->zabbix->getICMPItems($hostId); + + $status = 0; // 0 = unknown, 1 = down, 2 = up + foreach ($icmpItems as $icmpItem) { + if (strpos($icmpItem['key_'], 'icmpping[') !== false) { + $status = $icmpItem['lastvalue'] + 1; + break; + } + } + + $device->update([ + "zabbix_online" => $status, + "zabbix_host_id" => $hostId + ]); + + $device->zabbix_online = $status; + $device->zabbix_host_id = $hostId; + $id = $device->save(); } - - 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); } } \ No newline at end of file diff --git a/db/migrations/20241105200000_device_add_zabbix_status.php b/db/migrations/20241105200000_device_add_zabbix_status.php new file mode 100644 index 000000000..6b98196af --- /dev/null +++ b/db/migrations/20241105200000_device_add_zabbix_status.php @@ -0,0 +1,25 @@ +getEnvironment() == "thetool") { + $Device = $this->table("Device"); + $Device->addColumn('zabbix_online', 'integer', ['null' => false, 'default' => 0]); + $Device->addColumn('zabbix_host_id', 'integer', ['null' => true]); + $Device->update(); + } + } + + public function down(): void { + if ($this->getEnvironment() == "thetool") { + $Device = $this->table("Device"); + $Device->removeColumn('zabbix_online'); + $Device->removeColumn('zabbix_host_id'); + $Device->update(); + } + } +} \ No newline at end of file diff --git a/lib/Zabbix/Zabbix.php b/lib/Zabbix/Zabbix.php index cbe21ddc1..536519551 100644 --- a/lib/Zabbix/Zabbix.php +++ b/lib/Zabbix/Zabbix.php @@ -72,6 +72,14 @@ class Zabbix { return $response['result']; } + public function getICMPItems($hostId) { + $response = $this->zabbixRequest('item.get', array( + 'hostids' => $hostId, + 'search' => array('name' => array("ICMP")) + )); + return $response['result']; + } + public function getUptimeItems($hostId) { $response = $this->zabbixRequest('item.get', array( 'hostids' => $hostId, diff --git a/public/js/pages/Device/Device.js b/public/js/pages/Device/Device.js index d55e5a7bb..d0c14bc40 100644 --- a/public/js/pages/Device/Device.js +++ b/public/js/pages/Device/Device.js @@ -74,6 +74,11 @@ Vue.component('DeviceTable', { @@ -88,7 +93,7 @@ Vue.component('DeviceTable', { headers: [ { text: 'Device Name', key: 'name', sortable: true, class: 'text-nowrap', priority: 10 }, { text: 'Hersteller', key: 'devicemanufactor', filter: 'select',class: 'text-nowrap text-center', filterOptions: deviceManufacturerFilterOptions }, - { text: 'Geräte Typ', key: 'devicetype', filter: 'autocomplete', class: 'text-nowrap text-center', filterOptions: deviceTypeFilterOptions , priority: 7}, + { text: 'Geräte Typ', key: 'devicetype', filter: 'select', class: 'text-nowrap text-center', filterOptions: deviceTypeFilterOptions , priority: 7}, { text: 'Pop/Adresse', key: 'locationText', filter: 'search' , class: 'text-nowrap text-center'}, { text: 'IP-Adresse', key: 'ip', filter: 'search',class: 'text-center', priority: 8}, { text: 'Mac-Adresse', key: 'mac', filter: 'search',class: 'text-center' }, @@ -107,6 +112,17 @@ Vue.component('DeviceTable', { ], priority: 6, sortable: false, + }, { + text: 'Status', + key: 'zabbix_online', + filter: 'iconSelect', + filterOptions: [ + { value: 0, text: 'Status unbekannt', icon: 'fa-regular fa-circle-xmark' }, + { value: 1, text: 'Offline', icon: 'fa-regular fa-circle-xmark text-danger' }, + { value: 2, text: 'Online', icon: 'fa-regular fa-circle-check text-success' }, + ], + priority: 5, + sortable: false, }, {text: 'Aktionen', key: 'actions', class: 'text-center', sortable: false, filter: false, priority: 9}, ], diff --git a/scripts/monitoring/run-zabbix-device-sync.php b/scripts/monitoring/run-zabbix-device-sync.php new file mode 100644 index 000000000..0615e1a0b --- /dev/null +++ b/scripts/monitoring/run-zabbix-device-sync.php @@ -0,0 +1,21 @@ +#!/usr/bin/php +id); +define("INTERNAL_USER_USERNAME", $me->username); + +$DeviceMonitoringController = new DeviceMonitoringController(false); + +$DeviceMonitoringController->syncToolZabbix(); \ No newline at end of file