diff --git a/plist b/plist index 2905b8977..c29bae379 100644 --- a/plist +++ b/plist @@ -1973,6 +1973,7 @@ /usr/local/opnsense/www/js/widgets/Interfaces.js /usr/local/opnsense/www/js/widgets/Mbuf.js /usr/local/opnsense/www/js/widgets/Memory.js +/usr/local/opnsense/www/js/widgets/Monit.js /usr/local/opnsense/www/js/widgets/Swap.js /usr/local/opnsense/www/js/widgets/SystemInformation.js /usr/local/opnsense/www/js/widgets/ThermalSensors.js diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Core/Api/DashboardController.php b/src/opnsense/mvc/app/controllers/OPNsense/Core/Api/DashboardController.php index 8a44c9094..da51be21d 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/Core/Api/DashboardController.php +++ b/src/opnsense/mvc/app/controllers/OPNsense/Core/Api/DashboardController.php @@ -138,6 +138,24 @@ class DashboardController extends ApiControllerBase 'help' => gettext('CPU thermal sensors often measure the same temperature for each core. If this is the case, only the first core is shown.'), 'unconfigured' => gettext('Thermal sensors not available or not configured.') ], + 'monit' => [ + 'title' => gettext('Monit Status'), + 'filesystem' => gettext('Filesystem'), + 'directory' => gettext('Directory'), + 'file' => gettext('File'), + 'process' => gettext('Process'), + 'host' => gettext('Host'), + 'system' => gettext('System'), + 'fifo' => gettext('FIFO'), + 'custom' => gettext('Custom'), + 'network' => gettext('Network'), + 'ok' => gettext('OK'), + 'failed' => gettext('Failed'), + 'changed' => gettext('Changed'), + 'unchanged' => gettext('Not changed'), + 'type' => gettext('Type'), + 'unconfigured' => gettext('Monit is disabled or not configured.'), + ] ]; } diff --git a/src/opnsense/www/js/widgets/Monit.js b/src/opnsense/www/js/widgets/Monit.js new file mode 100644 index 000000000..53aad1c1e --- /dev/null +++ b/src/opnsense/www/js/widgets/Monit.js @@ -0,0 +1,117 @@ +// endpoint:/api/monit/status/get/xml + +/* + * Copyright (C) 2024 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. + */ + +import BaseTableWidget from "./BaseTableWidget.js"; + +export default class Monit extends BaseTableWidget { + constructor() { + super(); + + this.tickTimeout = 20000; + } + + getMarkup() { + let $table = this.createTable('monit-table', { + headerPosition: 'left' + }); + return $(`
`).append($table); + } + + async onMarkupRendered() { + this.serviceIcons = { + "0": "fa-hdd-o", + "1": "fa-folder", + "2": "fa-file", + "3": "fa-cogs", + "4": "fa-desktop", + "5": "fa-server", + "6": "fa-sort-amount-asc", + "7": "fa-cube", + "8": "fa-globe" + }; + + this.statusColors = { + "1": "text-danger", + "2": "text-warning", + "3": "text-warning" + }; + + this.serviceMap = [ + this.translations.filesystem, + this.translations.directory, + this.translations.file, + this.translations.process, + this.translations.host, + this.translations.system, + this.translations.fifo, + this.translations.custom, + this.translations.network + ]; + + this.statusMap = [ + this.translations.ok, + this.translations.failed, + this.translations.changed, + this.translations.unchanged + ]; + } + + async onWidgetTick() { + await ajaxGet('/api/monit/status/get/xml', {}, (data, status) => { + if (data['result'] !== 'ok') { + $('#monit-table').html(`${this.translations.unconfigured}`); + return; + } + + let rows = []; + $.each(data['status']['service'], (index, service) => { + let color = this.statusColors[service['status']] || "text-success"; + let icon = this.serviceIcons[service['@attributes']['type']] || "fa-circle"; + + let $header = $(` +
+ + +   + + +   + ${service['name']} +
+ `); + + rows.push([$header.prop('outerHTML'), '']); + + }); + + this.updateTable('monit-table', rows); + }); + } +}