services: import monit service

Some things to work on:
* post-install should be a migration
* move to system?
* remove old notifications
This commit is contained in:
Franco Fichtner 2018-03-10 11:51:56 +01:00
parent 7cc7a26e60
commit 79500101c6
23 changed files with 2102 additions and 0 deletions

22
plist
View File

@ -35,6 +35,7 @@
/usr/local/etc/inc/plugins.inc.d/ipfw.inc
/usr/local/etc/inc/plugins.inc.d/ipsec.inc
/usr/local/etc/inc/plugins.inc.d/ipsec/auth-user.php
/usr/local/etc/inc/plugins.inc.d/monit.inc
/usr/local/etc/inc/plugins.inc.d/netflow.inc
/usr/local/etc/inc/plugins.inc.d/ntpd.inc
/usr/local/etc/inc/plugins.inc.d/ntpd/ntpdate_sync_once.sh
@ -374,6 +375,15 @@
/usr/local/opnsense/mvc/app/controllers/OPNsense/IDS/forms/dialogRuleset.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/IDS/forms/dialogUserDefined.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/IDS/forms/generalSettings.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Monit/Api/ServiceController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Monit/Api/SettingsController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Monit/Api/StatusController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Monit/IndexController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Monit/StatusController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Monit/forms/alerts.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Monit/forms/general.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Monit/forms/services.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Monit/forms/tests.xml
/usr/local/opnsense/mvc/app/controllers/OPNsense/Proxy/Api/ServiceController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Proxy/Api/SettingsController.php
/usr/local/opnsense/mvc/app/controllers/OPNsense/Proxy/IndexController.php
@ -481,6 +491,10 @@
/usr/local/opnsense/mvc/app/models/OPNsense/IDS/IDS.xml
/usr/local/opnsense/mvc/app/models/OPNsense/IDS/Menu/Menu.xml
/usr/local/opnsense/mvc/app/models/OPNsense/IDS/Migrations/M1_0_0.php
/usr/local/opnsense/mvc/app/models/OPNsense/Monit/ACL/ACL.xml
/usr/local/opnsense/mvc/app/models/OPNsense/Monit/Menu/Menu.xml
/usr/local/opnsense/mvc/app/models/OPNsense/Monit/Monit.php
/usr/local/opnsense/mvc/app/models/OPNsense/Monit/Monit.xml
/usr/local/opnsense/mvc/app/models/OPNsense/Ntpd/ACL/ACL.xml
/usr/local/opnsense/mvc/app/models/OPNsense/Ntpd/Menu/Menu.xml
/usr/local/opnsense/mvc/app/models/OPNsense/Proxy/ACL/ACL.xml
@ -512,6 +526,8 @@
/usr/local/opnsense/mvc/app/views/OPNsense/Diagnostics/systemactivity.volt
/usr/local/opnsense/mvc/app/views/OPNsense/Diagnostics/systemhealth.volt
/usr/local/opnsense/mvc/app/views/OPNsense/IDS/index.volt
/usr/local/opnsense/mvc/app/views/OPNsense/Monit/index.volt
/usr/local/opnsense/mvc/app/views/OPNsense/Monit/status.volt
/usr/local/opnsense/mvc/app/views/OPNsense/Proxy/index.volt
/usr/local/opnsense/mvc/app/views/OPNsense/Routes/index.volt
/usr/local/opnsense/mvc/app/views/OPNsense/TrafficShaper/index.volt
@ -572,6 +588,8 @@
/usr/local/opnsense/scripts/OPNsense/CaptivePortal/set_session_restrictions.py
/usr/local/opnsense/scripts/OPNsense/CaptivePortal/sql/init.sql
/usr/local/opnsense/scripts/OPNsense/CaptivePortal/strip_template.py
/usr/local/opnsense/scripts/OPNsense/Monit/post-install.php
/usr/local/opnsense/scripts/OPNsense/Monit/setup.sh
/usr/local/opnsense/scripts/dhcp/get_leases.py
/usr/local/opnsense/scripts/dhcp/prefixes.php
/usr/local/opnsense/scripts/dns/unbound_dhcpd.py
@ -681,6 +699,7 @@
/usr/local/opnsense/service/conf/actions.d/actions_interface.conf
/usr/local/opnsense/service/conf/actions.d/actions_ipfw.conf
/usr/local/opnsense/service/conf/actions.d/actions_ipsec.conf
/usr/local/opnsense/service/conf/actions.d/actions_monit.conf
/usr/local/opnsense/service/conf/actions.d/actions_netflow.conf
/usr/local/opnsense/service/conf/actions.d/actions_openssh.conf
/usr/local/opnsense/service/conf/actions.d/actions_openvpn.conf
@ -733,6 +752,9 @@
/usr/local/opnsense/service/templates/OPNsense/IPFW/ipfw.fw.conf
/usr/local/opnsense/service/templates/OPNsense/IPFW/rc.conf.d
/usr/local/opnsense/service/templates/OPNsense/Macros/interface.macro
/usr/local/opnsense/service/templates/OPNsense/Monit/+TARGETS
/usr/local/opnsense/service/templates/OPNsense/Monit/monitrc
/usr/local/opnsense/service/templates/OPNsense/Monit/rc.conf.d
/usr/local/opnsense/service/templates/OPNsense/Netflow/+TARGETS
/usr/local/opnsense/service/templates/OPNsense/Netflow/flowd.conf
/usr/local/opnsense/service/templates/OPNsense/Netflow/flowd.rc.conf.d

View File

@ -0,0 +1,66 @@
<?php
/*
Copyright (C) 2017 EURO-LOG AG
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.
*/
/**
* register service
* @return array
*/
function monit_services()
{
global $config;
$services = array();
if (isset($config['OPNsense']['monit']['general']['enabled']) && $config['OPNsense']['monit']['general']['enabled'] == 1) {
$services[] = array(
'description' => gettext('Monit System Monitoring'),
'configd' => array(
'restart' => array('monit restart'),
'start' => array('monit start'),
'stop' => array('monit stop'),
),
'name' => 'monit',
);
}
return $services;
}
/**
* sync configuration via xmlrpc
* @return array
*/
function monit_xmlrpc_sync()
{
$result = array();
$result[] = array(
'description' => gettext('Monit System Monitoring'),
'section' => 'OPNsense.monit',
'id' => 'monit',
);
return $result;
}

View File

@ -0,0 +1,79 @@
<?php
/**
* Copyright (C) 2017-2018 EURO-LOG AG
*
* 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\Monit\Api;
use \OPNsense\Base\ApiMutableServiceControllerBase;
use \OPNsense\Core\Backend;
use \OPNsense\Monit\Monit;
/**
* Class ServiceController
* @package OPNsense\Monit
*/
class ServiceController extends ApiMutableServiceControllerBase
{
static protected $internalServiceClass = '\OPNsense\Monit\Monit';
static protected $internalServiceEnabled = 'general.enabled';
static protected $internalServiceTemplate = 'OPNsense/Monit';
static protected $internalServiceName = 'monit';
/**
* test monit configuration
* @return array
*/
public function configtestAction()
{
if ($this->request->isPost()) {
$this->sessionClose();
$backend = new Backend();
$result['function'] = "configtest";
$result['template'] = trim($backend->configdRun('template reload OPNsense/Monit'));
if ($result['template'] != 'OK') {
$result['result'] = "Template error: " . $result['template'];
return $result;
}
$result['result'] = trim($backend->configdRun('monit configtest'));
return $result;
} else {
return array('status' => 'failed');
}
}
/**
* avoid restarting Relayd on reconfigure
*/
protected function reconfigureForceRestart()
{
return 0;
}
}

View File

@ -0,0 +1,341 @@
<?php
/**
* Copyright (C) 2017-2018 EURO-LOG AG
*
* 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\Monit\Api;
use \OPNsense\Base\ApiControllerBase;
use \OPNsense\Core\Config;
use \OPNsense\Monit\Monit;
use \OPNsense\Base\UIModelGrid;
/**
* Class SettingsController
* @package OPNsense\Monit
*/
class SettingsController extends ApiControllerBase
{
/**
* list with valid model node types
*/
private $nodeTypes = array('general', 'alert', 'service', 'test');
/**
* query monit settings
* @param $nodeType
* @param $uuid
* @return result array
*/
public function getAction($nodeType = null, $uuid = null)
{
$result = array("result" => "failed");
if ($this->request->isGet() && $nodeType != null) {
$this->validateNodeType($nodeType);
$mdlMonit = new Monit();
if ($nodeType == 'general') {
$node = $mdlMonit->getNodeByReference($nodeType);
} else {
if ($uuid != null) {
$node = $mdlMonit->getNodeByReference($nodeType . '.' . $uuid);
} else {
$node = $mdlMonit->$nodeType->Add();
}
}
if ($node != null) {
$result[$nodeType] = $node->getNodes();
$result["result"] = "ok";
}
}
return $result;
}
/**
* set monit properties
* @param $nodeType
* @param $uuid
* @return status array
*/
public function setAction($nodeType = null, $uuid = null)
{
$result = array("result" => "failed", "validations" => array());
if ($this->request->isPost() && $this->request->hasPost("monit") && $nodeType != null) {
$this->validateNodeType($nodeType);
$mdlMonit = new Monit();
if ($nodeType == 'general') {
$node = $mdlMonit->getNodeByReference($nodeType);
} else {
if ($uuid != null) {
$node = $mdlMonit->getNodeByReference($nodeType . '.' . $uuid);
} else {
$node = $mdlMonit->$nodeType->Add();
}
}
if ($node != null) {
$monitInfo = $this->request->getPost("monit");
// perform plugin specific validations
if ($nodeType == 'service') {
switch ($monitInfo[$nodeType]['type']) {
case 'process':
if (empty($monitInfo[$nodeType]['pidfile']) && empty($monitInfo[$nodeType]['match'])) {
$result["validations"]['monit.service.pidfile'] = "Please set at least one of Pidfile or Match.";
$result["validations"]['monit.service.match'] = $result["validations"]['monit.service.pidfile'];
}
break;
case 'host':
if (empty($monitInfo[$nodeType]['address'])) {
$result["validations"]['monit.service.address'] = "Address is mandatory for 'Remote Host' checks.";
}
break;
case 'network':
if (empty($monitInfo[$nodeType]['address']) && empty($monitInfo[$nodeType]['interface'])) {
$result["validations"]['monit.service.address'] = "Please set at least one of Address or Interface.";
$result["validations"]['monit.service.interface'] = $result["validations"]['monit.service.address'];
}
break;
case 'system':
break;
default:
if (empty($monitInfo[$nodeType]['path'])) {
$result["validations"]['monit.service.path'] = "Path is mandatory.";
}
}
}
$node->setNodes($monitInfo[$nodeType]);
$valMsgs = $mdlMonit->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, "monit." . $nodeType, $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
}
if (empty($result["validations"])) {
unset($result["validations"]);
$result['result'] = 'ok';
$mdlMonit->serializeToConfig();
Config::getInstance()->save();
if ($nodeType == 'general' && $monitInfo['general']['enabled'] == '0') {
$svcMonit = new ServiceController();
$result = $svcMonit->stopAction();
}
}
}
}
return $result;
}
/**
* delete monit settings
* @param $nodeType
* @param $uuid
* @return status array
*/
public function delAction($nodeType = null, $uuid = null)
{
$result = array("result" => "failed");
if ($nodeType != null) {
$this->validateNodeType($nodeType);
if ($uuid != null) {
$mdlMonit = new Monit();
$node = $mdlMonit->getNodeByReference($nodeType . '.' . $uuid);
if ($node != null) {
if ($mdlMonit->$nodeType->del($uuid) == true) {
// delete relations
if ($nodeType == 'test') {
$nodeName = $mdlMonit->getNodeByReference($nodeType . '.' . $uuid . '.name');
if ($nodeName != null) {
$nodeName = $nodeName->__toString();
$this->deleteRelations('service', 'tests', $uuid, 'test', $nodeName, $mdlMonit);
}
}
$mdlMonit->serializeToConfig();
Config::getInstance()->save();
$result["result"] = "ok";
}
}
}
}
return $result;
}
/**
* toggle monit items (enable/disable)
* @param $nodeType
* @param $uuid
* @return result array
*/
public function toggleAction($nodeType = null, $uuid = null)
{
$result = array("result" => "failed");
if ($this->request->isPost() && $nodeType != null) {
$mdlMonit = new Monit();
if ($uuid != null) {
$node = $mdlMonit->getNodeByReference($nodeType . '.' . $uuid);
if ($node != null) {
if ($node->enabled->__toString() == "1") {
$node->enabled = "0";
} else {
$node->enabled = "1";
}
$mdlMonit->serializeToConfig();
Config::getInstance()->save();
$svcMonit = new ServiceController();
$result= $svcMonit->reloadAction();
} else {
$result['result'] = "not found";
}
} else {
$result['result'] = "uuid not given";
}
}
return $result;
}
/**
* search monit settings
* @param $nodeType
* @return result array
*/
public function searchAction($nodeType = null)
{
$this->sessionClose();
if ($this->request->isPost() && $nodeType != null) {
$this->validateNodeType($nodeType);
$mdlMonit = new Monit();
$grid = new UIModelGrid($mdlMonit->$nodeType);
$fields = array();
switch ($nodeType) {
case 'alert':
$fields = array("enabled", "recipient", "noton", "events", "description");
break;
case 'service':
$fields = array("enabled", "name", "type", "description");
break;
case 'test':
$fields = array("name", "condition", "action");
break;
}
return $grid->fetchBindRequest($this->request, $fields);
}
}
/**
* import system notification settings
* @return result array
*/
public function notificationAction()
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
$this->sessionClose();
$cfg = Config::getInstance();
$cfgObj = $cfg->object();
$mdlMonit = new Monit();
$node = $mdlMonit->getNodeByReference('general');
$generalSettings = array();
// inherit SMTP settings from System->Settings->Notifications
if (!empty($cfgObj->notifications->smtp->ipaddress)) {
$generalSettings['mailserver'] = $cfgObj->notifications->smtp->ipaddress;
}
if (!empty($cfgObj->notifications->smtp->port)) {
$generalSettings['port'] = $cfgObj->notifications->smtp->port;
}
$generalSettings['username'] = $cfgObj->notifications->smtp->username;
$generalSettings['password'] = $cfgObj->notifications->smtp->password;
if ((!empty($cfgObj->notifications->smtp->tls) && $cfgObj->notifications->smtp->tls == 1) ||
(!empty($cfgObj->notifications->smtp->ssl) && $cfgObj->notifications->smtp->ssl == 1)) {
$generalSettings['ssl'] = 1;
} else {
$generalSettings['ssl'] = 0;
}
// apply them
$node->setNodes($generalSettings);
$valMsgs = $mdlMonit->performValidation();
foreach ($valMsgs as $field => $msg) {
$fieldnm = str_replace($node->__reference, "monit.general.", $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
}
if (empty($result["validations"])) {
unset($result["validations"]);
$result['result'] = 'ok';
$mdlMonit->serializeToConfig();
Config::getInstance()->save();
}
}
return $result;
}
/**
* validate nodeType
* @param $nodeType
* @throws \Exception
*/
private function validateNodeType($nodeType = null)
{
if (array_search($nodeType, $this->nodeTypes) === false) {
throw new \Exception('unknown nodeType: ' . $nodeType);
}
}
/**
* delete relations
* @param $nodeType
* @param $uuid
* @param $relNodeType
* @param &$mdlMonit
* @throws \Exception
*/
private function deleteRelations($nodeType = null, $nodeField = null, $relUuid = null, $relNodeType = null, $relNodeName = null, &$mdlMonit = null)
{
$nodes = $mdlMonit->$nodeType->getNodes();
// get nodes with relations
foreach ($nodes as $nodeUuid => $node) {
// get relation uuids
foreach ($node[$nodeField] as $fieldUuid => $field) {
// remove uuid from field
if ($fieldUuid == $relUuid) {
$refField = $nodeType . '.' . $nodeUuid . '.' . $nodeField;
$relNode = $mdlMonit->getNodeByReference($refField);
$nodeRels = str_replace($relUuid, '', $relNode->__toString());
$nodeRels = str_replace(',,', ',', $nodeRels);
$nodeRels = rtrim($nodeRels, ',');
$nodeRels = ltrim($nodeRels, ',');
$mdlMonit->setNodeByReference($refField, $nodeRels);
if ($relNode->isEmptyAndRequired()) {
$nodeName = $mdlMonit->getNodeByReference($nodeType . '.' . $nodeUuid . '.name')->__toString();
throw new \Exception("Cannot delete $relNodeType '$relNodeName' from $nodeType '$nodeName'");
}
}
}
}
}
}

View File

@ -0,0 +1,144 @@
<?php
/**
* Copyright (C) 2017-2018 EURO-LOG AG
*
* 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\Monit\Api;
use \OPNsense\Base\ApiControllerBase;
use \OPNsense\Monit\Monit;
/**
* Class StatusController
* @package OPNsense\Monit
*/
class StatusController extends ApiControllerBase
{
/**
* get monit status page
* see monit(1)
* @return array
*/
public function getAction($format = 'xml')
{
$result = array("result" => "failed");
$socketPath = "/var/run/monit.sock";
// map the requested html format from the status page to the Monit text format
$format = $format == 'html' ? 'text' : $format;
// check monit httpd socket defined in monitrc by 'set httpd ...'
if (file_exists($socketPath) && filetype($socketPath) == "socket") {
// set curl options
$ch = curl_init("http://127.0.0.1/_status?format=" . $format);
curl_setopt($ch, CURLOPT_UNIX_SOCKET_PATH, $socketPath);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// get credentials if configured
$mdlMonit = new Monit();
if ($mdlMonit->general->httpdUsername->__toString() != null && trim($mdlMonit->general->httpdUsername->__toString()) !== "" &&
$mdlMonit->general->httpdPassword->__toString() != null && trim($mdlMonit->general->httpdPassword->__toString()) !== "") {
curl_setopt($ch, CURLOPT_USERPWD, $mdlMonit->general->httpdUsername->__toString() . ":" . $mdlMonit->general->httpdPassword->__toString());
}
// send request
if (!$response = curl_exec($ch)) {
$result['status'] = curl_error($ch);
return $result;
}
$HTTPCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if ($HTTPCode != 200) {
$result['status'] = 'Monit returns with code ' . $HTTPCode;
} else {
$result['result'] = "ok";
// format the response
if ($format == 'xml') {
$result['status'] = simplexml_load_string($response);
} elseif ($format === 'text') {
$result['status'] = '<pre style="color:WhiteSmoke;background-color:DimGrey">' . $this->bashColorToCSS($response) . '</pre>';
}
}
} else {
$msg = "
Either the file " . $socketPath . " does not exists or it is not a unix socket.
Please check if the Monit service is running.
If you have started Monit recently, wait for StartDelay seconds and refresh this page.";
if ($format == 'xml') {
$result['status'] = $msg;
} elseif ($format === 'text') {
$result['status'] = '<pre style="color:WhiteSmoke;background-color:DimGrey">' . $msg . '</pre>';
}
}
return $result;
}
/**
* convert bash color escape codes to CSS
* @param $string
* @return string
*/
private function bashColorToCSS($string)
{
$colors = [
'/\x1b\[0;30m(.*?)\x1b\[0m/s' => '<span style="font-weight:bold">$1</span>',
'/\x1b\[0;30m(.*?)\x1b\[0m/s' => '<span style="color:Black;">$1</span>',
'/\x1b\[0;31m(.*?)\x1b\[0m/s' => '<span style="color:Red;">$1</span>',
'/\x1b\[0;32m(.*?)\x1b\[0m/s' => '<span style="color:Green;">$1</span>',
'/\x1b\[0;33m(.*?)\x1b\[0m/s' => '<span style="color:Yellow;">$1</span>',
'/\x1b\[0;34m(.*?)\x1b\[0m/s' => '<span style="color:Blue;">$1</span>',
'/\x1b\[0;35m(.*?)\x1b\[0m/s' => '<span style="color:Magents;">$1</span>',
'/\x1b\[0;36m(.*?)\x1b\[0m/s' => '<span style="color:Cyan;">$1</span>',
'/\x1b\[0;37m(.*?)\x1b\[0m/s' => '<span style="color:WhiteSmoke;">$1</span>',
'/\x1b\[0;39m(.*?)\x1b\[0m/s' => '<span>$1</span>',
'/\x1b\[1;30m(.*?)\x1b\[0m/s' => '<span style="font-weight:bold; color:Black;">$1</span>',
'/\x1b\[1;31m(.*?)\x1b\[0m/s' => '<span style="font-weight:bold; color:Red;">$1</span>',
'/\x1b\[1;32m(.*?)\x1b\[0m/s' => '<span style="font-weight:bold; color:Green;">$1</span>',
'/\x1b\[1;33m(.*?)\x1b\[0m/s' => '<span style="font-weight:bold; color:Yellow;">$1</span>',
'/\x1b\[1;34m(.*?)\x1b\[0m/s' => '<span style="font-weight:bold; color:Blue;">$1</span>',
'/\x1b\[1;35m(.*?)\x1b\[0m/s' => '<span style="font-weight:bold; color:Magenta;">$1</span>',
'/\x1b\[1;36m(.*?)\x1b\[0m/s' => '<span style="font-weight:bold; color:Cyan;">$1</span>',
'/\x1b\[1;37m(.*?)\x1b\[0m/s' => '<span style="font-weight:bold; color:White:">$1</span>',
'/\x1b\[0;90m(.*?)\x1b\[0m/s' => '<span style="color:DargGrey">$1</span>',
'/\x1b\[0;91m(.*?)\x1b\[0m/s' => '<span style="color:LightCoral">$1</span>',
'/\x1b\[0;92m(.*?)\x1b\[0m/s' => '<span style="color:LightGreen;">$1</span>',
'/\x1b\[0;93m(.*?)\x1b\[0m/s' => '<span style="color:LightYellow;">$1</span>',
'/\x1b\[0;94m(.*?)\x1b\[0m/s' => '<span style="color:LightSkyBlue;">$1</span>',
'/\x1b\[0;95m(.*?)\x1b\[0m/s' => '<span style="color:LightPink;">$1</span>',
'/\x1b\[0;96m(.*?)\x1b\[0m/s' => '<span style="color:LightCyan;">$1</span>',
'/\x1b\[0;97m(.*?)\x1b\[0m/s' => '<span style="color:White;">$1</span>'
];
return preg_replace(array_keys($colors), $colors, $string);
}
}

View File

@ -0,0 +1,51 @@
<?php
/**
* Copyright (C) 2017 EURO-LOG AG
*
* 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\Monit;
/**
* Class IndexController
* @package OPNsense\FtpProxy
*/
class IndexController extends \OPNsense\Base\IndexController
{
/**
* monit index page
* @throws \Exception
*/
public function indexAction()
{
$this->view->formGeneralSettings = $this->getForm("general");
$this->view->formDialogEditAlert = $this->getForm("alerts");
$this->view->formDialogEditService = $this->getForm("services");
$this->view->formDialogEditTest = $this->getForm("tests");
$this->view->pick('OPNsense/Monit/index');
}
}

View File

@ -0,0 +1,46 @@
<?php
/**
* Copyright (C) 2017 EURO-LOG AG
*
* 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\Monit;
/**
* Class StatusController
* @package OPNsense\Monit
*/
class StatusController extends \OPNsense\Base\IndexController
{
/**
* monit status page
* @throws \Exception
*/
public function indexAction()
{
$this->view->pick('OPNsense/Monit/status');
}
}

View File

@ -0,0 +1,47 @@
<form>
<field>
<id>monit.alert.enabled</id>
<label>Enable alert</label>
<type>checkbox</type>
<help><![CDATA[Enable or disable alert.]]></help>
</field>
<field>
<id>monit.alert.recipient</id>
<label>Recipient</label>
<type>text</type>
<style>tokenize</style>
<help><![CDATA[The email address to send alerts to.]]></help>
</field>
<field>
<id>monit.alert.noton</id>
<label>Not on</label>
<type>checkbox</type>
<help><![CDATA[Do not send alerts for the following events but on all others.]]></help>
</field>
<field>
<id>monit.alert.events</id>
<label>Events</label>
<type>select_multiple</type>
<nbDropdownElements>28</nbDropdownElements>
<style>tokenize</style>
<help><![CDATA[List with events. Leave it empty for all events.]]></help>
</field>
<field>
<id>monit.alert.format</id>
<label>Mail format</label>
<type>text</type>
<style>tokenize</style>
<help><![CDATA[The email format for alerts.<br><i>Subject: $SERVICE on $HOST failed</i>]]></help>
</field>
<field>
<id>monit.alert.reminder</id>
<label>Reminder</label>
<type>text</type>
<help><![CDATA[Send a reminder after some cycles]]></help>
</field>
<field>
<id>monit.alert.description</id>
<label>Description</label>
<type>text</type>
</field>
</form>

View File

@ -0,0 +1,124 @@
<form>
<field>
<id>monit.general.enabled</id>
<label>Enable monit</label>
<type>checkbox</type>
<help><![CDATA[Enable or disable monit.]]></help>
</field>
<field>
<id>monit.general.interval</id>
<label>Polling Interval</label>
<type>text</type>
<help><![CDATA[Polling interval in seconds]]></help>
</field>
<field>
<id>monit.general.startdelay</id>
<label>Start Delay</label>
<type>text</type>
<help><![CDATA[On system boot wait before Monit starts checking services.]]></help>
</field>
<field>
<id>monit.general.mailserver</id>
<label>Mail Server</label>
<type>select_multiple</type>
<allownew>true</allownew>
<style>tokenize</style>
<help><![CDATA[Comma separated list of SMTP servers for alert delivery.]]></help>
</field>
<field>
<id>monit.general.port</id>
<label>Mail Server Port</label>
<type>text</type>
<help><![CDATA[The port of the mail server. Typically 465 for SSL or 25 for TLS and non secure connections.]]></help>
</field>
<field>
<id>monit.general.username</id>
<label>Username</label>
<type>text</type>
<help><![CDATA[The username for authentication.]]></help>
</field>
<field>
<id>monit.general.password</id>
<label>Password</label>
<type>password</type>
<help><![CDATA[The password for authentication.]]></help>
</field>
<field>
<id>monit.general.ssl</id>
<label>Secure Connection</label>
<type>checkbox</type>
<help><![CDATA[Enable encryption.]]></help>
</field>
<field>
<id>monit.general.logfile</id>
<label>Log File</label>
<type>text</type>
<help><![CDATA[The log file of the Monit process. This can be the keyword <i>syslog</i> or the path to a file.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>monit.general.statefile</id>
<label>State File</label>
<type>text</type>
<help><![CDATA[The state file of the Monit process.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>monit.general.eventqueuePath</id>
<label>Eventqueue Path</label>
<type>text</type>
<help><![CDATA[The path to the eventqueue directory.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>monit.general.eventqueueSlots</id>
<label>Eventqueue Slots</label>
<type>text</type>
<help><![CDATA[The number of eventqueue slots.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>monit.general.httpdEnabled</id>
<label>Enable HTTPD</label>
<type>checkbox</type>
<help><![CDATA[Start the Monit httpd service.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>monit.general.httpdPort</id>
<label>Monit HTTPD Port</label>
<type>text</type>
<help><![CDATA[The listen port of the Monit httpd service.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>monit.general.httpdAllow</id>
<label>Monit HTTPD Access List</label>
<type>select_multiple</type>
<style>tokenize</style>
<allownew>true</allownew>
<help><![CDATA[The username:password or host/network etc. for accessing the Monit httpd service.<br>See <a rel="help" target="_blank" href="https://mmonit.com/monit/documentation/monit.html#Authentication">Monit Authentication</a>]]></help>
<advanced>true</advanced>
<hint>user:password, @group... Finish with TAB.</hint>
</field>
<field>
<id>monit.general.mmonitUrl</id>
<label>M/Monit URL</label>
<type>text</type>
<help><![CDATA[The M/Monit URL.<br><i>https://user:pass@192.168.1.10:8443/collector</i><br>If you want to control Monit services from your M/Monit instance you have to configure the Monit Port too and add corresponding firewall rules as well.]]></help>
<advanced>true</advanced>
</field>
<field>
<id>monit.general.mmonitTimeout</id>
<label>M/Monit Timeout</label>
<type>text</type>
<advanced>true</advanced>
</field>
<field>
<id>monit.general.mmonitRegisterCredentials</id>
<label>M/Monit Register Credentials</label>
<type>checkbox</type>
<help><![CDATA[Automatically register in M/Monit by sending Monit credentials (see Monit Access List above).]]></help>
<advanced>true</advanced>
</field>
</form>

View File

@ -0,0 +1,74 @@
<form>
<field>
<id>monit.service.enabled</id>
<label>Enable service checks</label>
<type>checkbox</type>
<help><![CDATA[Enable or disable service checks.]]></help>
</field>
<field>
<id>monit.service.name</id>
<label>Name</label>
<type>text</type>
<help><![CDATA[The name of the service.]]></help>
</field>
<field>
<id>monit.service.type</id>
<label>Type</label>
<type>dropdown</type>
<help><![CDATA[The service check type.]]></help>
</field>
<field>
<id>monit.service.pidfile</id>
<label>PID File</label>
<type>text</type>
<help><![CDATA[The PID file of the process.]]></help>
</field>
<field>
<id>monit.service.match</id>
<label>Match</label>
<type>text</type>
<help><![CDATA[Find the process by regular expression. Test your pattern with <br><b>monit procmatch &lt;PATTERN&gt;</b>]]></help>
</field>
<field>
<id>monit.service.path</id>
<label>Path</label>
<type>text</type>
<help><![CDATA[According to the service type path can be a file or a directory.]]></help>
</field>
<field>
<id>monit.service.address</id>
<label>Address</label>
<type>text</type>
<help><![CDATA[The target IP address for 'Remote Host' and 'Network' checks.]]></help>
</field>
<field>
<id>monit.service.interface</id>
<label>Interface</label>
<type>dropdown</type>
<help><![CDATA[The Interface for 'Network' checks.]]></help>
</field>
<field>
<id>monit.service.start</id>
<label>Start</label>
<type>text</type>
<help><![CDATA[The start skript of the service.]]></help>
</field>
<field>
<id>monit.service.stop</id>
<label>Stop</label>
<type>text</type>
<help><![CDATA[The stop skript of the service.]]></help>
</field>
<field>
<id>monit.service.tests</id>
<label>Tests</label>
<type>select_multiple</type>
<style>tokenize</style>
<help><![CDATA[This is a list with service tests.]]></help>
</field>
<field>
<id>monit.service.description</id>
<label>Description</label>
<type>text</type>
</field>
</form>

View File

@ -0,0 +1,26 @@
<form>
<field>
<id>monit.test.name</id>
<label>Name</label>
<type>text</type>
<help><![CDATA[The name of the test.]]></help>
</field>
<field>
<id>monit.test.condition</id>
<label>Condition</label>
<type>text</type>
<help><![CDATA[The test condition. E.g.<br><i>cpu is greater than 50%</i><br><i>failed host 127.0.0.1 port 22 protocol ssh</i><br>]]></help>
</field>
<field>
<id>monit.test.action</id>
<label>Action</label>
<type>dropdown</type>
<help><![CDATA[Simply <i>alert</i> or <i>restart</i> the service or <i>execute</i> a program.]]></help>
</field>
<field>
<id>monit.test.path</id>
<label>Path</label>
<type>text</type>
<help><![CDATA[Make sure the script is executable by the Monit service.]]></help>
</field>
</form>

View File

@ -0,0 +1,10 @@
<acl>
<page-services-monit>
<name>WebCfg - Services: Monit System Monitoring page</name>
<description>Allow access to the 'Services: Monit System Monitoring' page.</description>
<patterns>
<pattern>ui/monit/*</pattern>
<pattern>api/monit/*</pattern>
</patterns>
</page-services-monit>
</acl>

View File

@ -0,0 +1,8 @@
<menu>
<Services>
<Monit VisibleName="Monit" cssClass="fa fa-heartbeat fa-fw">
<Settings url="/ui/monit/"/>
<Status url="/ui/monit/status/"/>
</Monit>
</Services>
</menu>

View File

@ -0,0 +1,41 @@
<?php
/**
* Copyright (C) 2016 EURO-LOG AG
*
* 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\Monit;
use OPNsense\Base\BaseModel;
/**
* Class Monit
* @package OPNsense\Monit
*/
class Monit extends BaseModel
{
}

View File

@ -0,0 +1,269 @@
<model>
<mount>//OPNsense/monit</mount>
<version>1.0.3</version>
<description>Monit settings</description>
<items>
<general>
<enabled type="BooleanField">
<default>0</default>
<Required>Y</Required>
</enabled>
<interval type="IntegerField">
<default>120</default>
<Required>Y</Required>
<MinimumValue>0</MinimumValue>
<MaximumValue>86400</MaximumValue>
<ValidationMessage>Polling Interval needs to be an integer value between 0 and 86400</ValidationMessage>
</interval>
<startdelay type="IntegerField">
<default>120</default>
<Required>Y</Required>
<MinimumValue>0</MinimumValue>
<MaximumValue>86400</MaximumValue>
<ValidationMessage>Start Delay needs to be an integer value between 0 and 86400</ValidationMessage>
</startdelay>
<mailserver type="CSVListField">
<default>127.0.0.1</default>
<Required>Y</Required>
<multiple>Y</multiple>
<mask>/^([0-9a-zA-Z\.,_\-:]){0,1024}$/u</mask>
<ChangeCase>lower</ChangeCase>
<ValidationMessage>Please specify a valid servername or IP address.</ValidationMessage>
</mailserver>
<port type="IntegerField">
<Required>Y</Required>
<default>25</default>
<MinimumValue>0</MinimumValue>
<MaximumValue>65535</MaximumValue>
<ValidationMessage>Port needs to be an integer value between 0 and 65535</ValidationMessage>
</port>
<username type="TextField">
<Required>N</Required>
</username>
<password type="TextField">
<Required>N</Required>
</password>
<ssl type="BooleanField">
<default>0</default>
<Required>Y</Required>
</ssl>
<logfile type="TextField">
<Required>N</Required>
<default>syslog facility log_daemon</default>
<mask>/^(\/[^\/ ]*)+\/?|syslog.*$/</mask>
<ValidationMessage>Should be a valid absolute path to the log file or the keyword "syslog".</ValidationMessage>
</logfile>
<statefile type="TextField">
<Required>N</Required>
<mask>/^(\/[^\/ ]*)+\/?$/</mask>
<ValidationMessage>Should be a valid absolute path to the state file.</ValidationMessage>
</statefile>
<eventqueuePath type="TextField">
<Required>N</Required>
<mask>/^(\/[^\/ ]*)+\/?$/</mask>
<ValidationMessage>Should be a valid absolute path to the eventqueue directory.</ValidationMessage>
</eventqueuePath>
<eventqueueSlots type="IntegerField">
<Required>N</Required>
<ValidationMessage>Eventqueue Slots must be a numeric value.</ValidationMessage>
</eventqueueSlots>
<httpdEnabled type="BooleanField">
<default>0</default>
<Required>Y</Required>
</httpdEnabled>
<httpdUsername type="TextField"/>
<httpdPassword type="TextField"/>
<httpdPort type="IntegerField">
<default>2812</default>
<Required>Y</Required>
<MinimumValue>1</MinimumValue>
<MaximumValue>65535</MaximumValue>
<ValidationMessage>Local Monit Port needs to be an integer value between 0 and 65535</ValidationMessage>
</httpdPort>
<httpdAllow type="CSVListField">
<Required>N</Required>
<multiple>Y</multiple>
</httpdAllow>
<mmonitUrl type="TextField">
<Required>N</Required>
</mmonitUrl>
<mmonitTimeout type="IntegerField">
<default>5</default>
<Required>Y</Required>
<MinimumValue>0</MinimumValue>
<MaximumValue>86400</MaximumValue>
<ValidationMessage>M/Monit Timeout needs to be an integer value between 0 and 86400</ValidationMessage>
</mmonitTimeout>
<mmonitRegisterCredentials type="BooleanField">
<default>1</default>
<Required>Y</Required>
</mmonitRegisterCredentials>
</general>
<alert type="ArrayField">
<enabled type="BooleanField">
<default>0</default>
<Required>Y</Required>
</enabled>
<recipient type="EmailField">
<default>root@localhost.local</default>
<Required>Y</Required>
<ValidationMessage>Please enter a valid email address.</ValidationMessage>
</recipient>
<noton type="BooleanField">
<Required>Y</Required>
<default>0</default>
</noton>
<events type="CSVListField">
<Required>N</Required>
<SelectOptions>
<action>Action done</action>
<checksum>Checksum failed</checksum>
<bytein>Download bytes exceeded</bytein>
<byteout>Upload bytes exceeded</byteout>
<connection>Connection failed</connection>
<content>Content failed</content>
<data>Data access error</data>
<exec>Execution failed</exec>
<fsflags>Filesystem flags failed</fsflags>
<gid>GID failed</gid>
<icmp>Ping failed</icmp>
<instance>Monit instance changed</instance>
<invalid>Invalid type</invalid>
<nonexist>Does not exist</nonexist>
<packetin>Download packets exceeded</packetin>
<packetout>Upload packets exceeded</packetout>
<permission>Permission failed</permission>
<pid>PID failed</pid>
<ppid>PPID failed</ppid>
<resource>Resource limit matched</resource>
<saturation>Saturation exceeded</saturation>
<size>Size failed</size>
<speed>Speed failed</speed>
<status>Status failed</status>
<timeout>Timeout</timeout>
<timestamp>Timestamp failed</timestamp>
<uid>UID failed</uid>
<uptime>Uptime failed</uptime>
</SelectOptions>
</events>
<format type="TextField">
<Required>N</Required>
<mask>/^.{1,255}$/u</mask>
<ValidationMessage>Message format should be a string between 1 and 255 characters.</ValidationMessage>
</format>
<reminder type="IntegerField">
<default>10</default>
<Required>N</Required>
<MinimumValue>0</MinimumValue>
<MaximumValue>86400</MaximumValue>
<ValidationMessage>Reminder needs to be an integer value between 0 and 86400</ValidationMessage>
</reminder>
<description type="TextField">
<Required>N</Required>
<mask>/^.{1,255}$/u</mask>
<ValidationMessage>Enter a description.</ValidationMessage>
</description>
</alert>
<service type="ArrayField">
<enabled type="BooleanField">
<default>0</default>
<Required>Y</Required>
</enabled>
<name type="TextField">
<Required>Y</Required>
<mask>/^([0-9a-zA-Z\._\-\$]){1,255}$/u</mask>
<ValidationMessage>Should be a string between 1 and 255 characters. Allowed characters are letters and numbers as well as underscore, minus, dot and the dollar sign.</ValidationMessage>
</name>
<type type="OptionField">
<Required>Y</Required>
<OptionValues>
<process>Process</process>
<file>File</file>
<fifo>Fifo</fifo>
<filesystem>Filesystem</filesystem>
<directory>Directory</directory>
<host>Remote Host</host>
<system>System</system>
<custom>Custom</custom>
<network>Network</network>
</OptionValues>
</type>
<pidfile type="TextField">
<Required>N</Required>
<mask>/^(\/[^\/ ]*)+\/?$/</mask>
<ValidationMessage>Should be a valid absolute path to the PID file of the process.</ValidationMessage>
</pidfile>
<match type="TextField">
<Required>N</Required>
</match>
<path type="TextField">
<Required>N</Required>
<mask>/^(\/[^\/ ]*)+\/?.*$/</mask>
<ValidationMessage>Should be a valid absolute file or folder path.</ValidationMessage>
</path>
<address type="TextField">
<Required>N</Required>
<mask>/^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-4]|2[0-5][0-9]|[01]?[0-9][0-9]?)$/</mask>
<ValidationMessage>Address must be a valid IPv4 address</ValidationMessage>
</address>
<interface type="InterfaceField">
<Required>N</Required>
<multiple>N</multiple>
<filters>
<enable>/^(?!0).*$/</enable>
<ipaddr>/^((?!dhcp).)*$/</ipaddr>
</filters>
</interface>
<start type="TextField">
<Required>N</Required>
<mask>/^(\/[^\/ ]*)+\/? .*$/</mask>
<ValidationMessage>Should be a valid absolute path to the executable with its arguments.</ValidationMessage>
</start>
<stop type="TextField">
<Required>N</Required>
<mask>/^(\/[^\/ ]*)+\/? .*$/</mask>
<ValidationMessage>Should be a valid absolute path to the executable with its arguments.</ValidationMessage>
</stop>
<tests type="ModelRelationField">
<Model>
<template>
<source>OPNsense.monit.monit</source>
<items>test</items>
<display>name</display>
</template>
</Model>
<ValidationMessage>Related item not found</ValidationMessage>
<multiple>Y</multiple>
<Required>N</Required>
</tests>
</service>
<test type="ArrayField">
<name type="TextField">
<Required>Y</Required>
<mask>/^([0-9a-zA-Z\._\- ]){1,255}$/u</mask>
<ValidationMessage>Should be a string between 1 and 255 characters. Allowed characters are letters and numbers as well as underscore, minus, dot and space.</ValidationMessage>
</name>
<condition type="TextField">
<Required>Y</Required>
<mask>/^.{1,255}$/u</mask>
<ValidationMessage>Should be a string between 1 and 255 characters.</ValidationMessage>
</condition>
<action type="OptionField">
<Required>Y</Required>
<OptionValues>
<alert>Alert</alert>
<restart>Restart</restart>
<start>Start</start>
<stop>Stop</stop>
<exec>Execute</exec>
<unmonitor>Unmonitor</unmonitor>
</OptionValues>
</action>
<path type="TextField">
<Required>N</Required>
<mask>/^(\/[^\/ ]*)+\/?.*$/</mask>
<ValidationMessage>Should be a valid absolute file path.</ValidationMessage>
</path>
</test>
</items>
</model>

View File

@ -0,0 +1,372 @@
{#
Copyright © 2017-2018 by EURO-LOG AG
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.
#}
<script>
$( document ).ready(function() {
/**
* add button 'Import System Notification'
* can't do it via base_dialog
*/
$('<button class="btn btn-primary" id="btn_ImportSystemNotification" type="button" style="margin-left: 3px;">' +
'<b> {{ lang._('Import System Notification')}} </b>' +
'<i id="frm_ImportSystemNotification_progress"></i>' +
'</button>').insertAfter('#btn_ApplyGeneralSettings');
/**
* UI functions
*/
$('#btn_configtest').unbind('click').click(function(){
$('#btn_configtest_progress').addClass("fa fa-spinner fa-pulse");
ajaxCall(url="/api/monit/service/configtest", sendData={}, callback=function(data,status) {
$('#btn_configtest_progress').removeClass("fa fa-spinner fa-pulse");
$('#btn_configtest').blur();
$("#responseMsg").removeClass("hidden");
$("#responseMsg").html(data['result']);
});
});
$('#btn_reload').unbind('click').click(function(){
$('#btn_reload_progress').addClass("fa fa-spinner fa-pulse");
ajaxCall(url="/api/monit/service/reconfigure", sendData={}, callback=function(data,status) {
$('#btn_reload_progress').removeClass("fa fa-spinner fa-pulse");
$('#btn_reload').blur();
ajaxCall(url="/api/monit/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status']);
});
});
});
$('#btn_ImportSystemNotification').unbind('click').click(function(){
$('#frm_ImportSystemNotification_progress').addClass("fa fa-spinner fa-pulse");
ajaxCall(url="/api/monit/settings/notification", sendData={}, callback=function(data,status) {
$('#frm_ImportSystemNotification_progress').removeClass("fa fa-spinner fa-pulse");
$('#btn_ImportSystemNotification').blur();
ajaxCall(url="/api/monit/service/status", sendData={}, callback=function(data,status) {
mapDataToFormUI({'frm_GeneralSettings':"/api/monit/settings/get/general/"}).done(function(){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
ajaxCall(url="/api/monit/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status']);
});
});
});
});
});
/**
* general settings
*/
// load data
mapDataToFormUI({'frm_GeneralSettings':"/api/monit/settings/get/general/"}).done(function(){
formatTokenizersUI();
$('.selectpicker').selectpicker('refresh');
ajaxCall(url="/api/monit/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status']);
});
});
// show/hide httpd/mmonit options
function ShowHideGeneralFields(){
if ($('#monit\\.general\\.httpdEnabled')[0].checked) {
$('tr[for="monit.general.httpdPort"]').removeClass('hidden');
$('tr[for="monit.general.httpdAllow"]').removeClass('hidden');
$('tr[for="monit.general.mmonitUrl"]').removeClass('hidden');
$('tr[for="monit.general.mmonitTimeout"]').removeClass('hidden');
$('tr[for="monit.general.mmonitRegisterCredentials"]').removeClass('hidden');
} else {
$('tr[for="monit.general.httpdPort"]').addClass('hidden');
$('tr[for="monit.general.httpdAllow"]').addClass('hidden');
$('tr[for="monit.general.mmonitUrl"]').addClass('hidden');
$('tr[for="monit.general.mmonitTimeout"]').addClass('hidden');
$('tr[for="monit.general.mmonitRegisterCredentials"]').addClass('hidden');
}
};
$('#monit\\.general\\.httpdEnabled').unbind('click').click(function(){
ShowHideGeneralFields();
});
$('#show_advanced_frm_GeneralSettings').click(function(){
ShowHideGeneralFields();
});
$('#btn_ApplyGeneralSettings').unbind('click').click(function(){
$("#frm_GeneralSettings_progress").addClass("fa fa-spinner fa-pulse");
var frm_id = 'frm_GeneralSettings';
saveFormToEndpoint(url = "/api/monit/settings/set/general/",formid=frm_id,callback_ok=function(){
ajaxCall(url="/api/monit/service/status", sendData={}, callback=function(data,status) {
updateServiceStatusUI(data['status']);
});
});
$("#"+frm_id+"_progress").removeClass("fa fa-spinner fa-pulse");
$("#btn_ApplyGeneralSettings").blur();
});
/**
* alert settings
*/
function openAlertDialog(uuid) {
var editDlg = "DialogEditAlert";
var setUrl = "/api/monit/settings/set/alert/";
var getUrl = "/api/monit/settings/get/alert/";
var urlMap = {};
urlMap['frm_' + editDlg] = getUrl + uuid;
mapDataToFormUI(urlMap).done(function () {
$('.selectpicker').selectpicker('refresh');
clearFormValidation('frm_' + editDlg);
$('#'+editDlg).modal({backdrop: 'static', keyboard: false});
$('#'+editDlg).on('hidden.bs.modal', function () {
parent.history.back();
});
});
};
$("#grid-alerts").UIBootgrid({
'search':'/api/monit/settings/search/alert/',
'get':'/api/monit/settings/get/alert/',
'set':'/api/monit/settings/set/alert/',
'add':'/api/monit/settings/set/alert/',
'del':'/api/monit/settings/del/alert/',
'toggle':'/api/monit/settings/toggle/alert/'
});
/**
* service settings
*/
// show hide fields according to selected service type
function ShowHideFields(){
var servicetype = $('#monit\\.service\\.type').val();
$('tr[for="monit.service.pidfile"]').addClass('hidden');
$('tr[for="monit.service.match"]').addClass('hidden');
$('tr[for="monit.service.path"]').addClass('hidden');
$('tr[for="monit.service.address"]').addClass('hidden');
$('tr[for="monit.service.interface"]').addClass('hidden');
$('tr[for="monit.service.start"]').removeClass('hidden');
$('tr[for="monit.service.stop"]').removeClass('hidden');
switch (servicetype) {
case 'process':
var pidfile = $('#monit\\.service\\.pidfile').val();
var match = $('#monit\\.service\\.match').val();
if (pidfile !== '') {
$('tr[for="monit.service.pidfile"]').removeClass('hidden');
$('tr[for="monit.service.match"]').addClass('hidden');
} else if (match !== '') {
$('tr[for="monit.service.pidfile"]').addClass('hidden');
$('tr[for="monit.service.match"]').removeClass('hidden');
} else {
$('tr[for="monit.service.pidfile"]').removeClass('hidden');
$('tr[for="monit.service.match"]').removeClass('hidden');
}
break;
case 'host':
$('tr[for="monit.service.address"]').removeClass('hidden');
break;
case 'network':
var address = $('#monit\\.service\\.address').val();
var interface = $('#monit\\.service\\.interface').val();
console.log('-' + address + '-' + interface + '-');
if (address !== '') {
$('tr[for="monit.service.address"]').removeClass('hidden');
$('tr[for="monit.service.interface"]').addClass('hidden');
} else if (interface !== '') {
$('tr[for="monit.service.address"]').addClass('hidden');
$('tr[for="monit.service.interface"]').removeClass('hidden');
} else {
$('tr[for="monit.service.address"]').removeClass('hidden');
$('tr[for="monit.service.interface"]').removeClass('hidden');
}
break;
case 'system':
$('tr[for="monit.service.start"]').addClass('hidden');
$('tr[for="monit.service.stop"]').addClass('hidden');
break;
default:
$('tr[for="monit.service.path"]').removeClass('hidden');
}
};
$('#DialogEditService').on('shown.bs.modal', function() {ShowHideFields();});
$('#monit\\.service\\.type').on('changed.bs.select', function(e) {ShowHideFields();});
$('#monit\\.service\\.pidfile').on('input', function() {ShowHideFields();});
$('#monit\\.service\\.match').on('input', function() {ShowHideFields();});
$('#monit\\.service\\.path').on('input', function() {ShowHideFields();});
$('#monit\\.service\\.address').on('input', function() {ShowHideFields();});
$('#monit\\.service\\.interface').on('changed.bs.select', function(e) {ShowHideFields();});
$("#grid-services").UIBootgrid({
'search':'/api/monit/settings/search/service/',
'get':'/api/monit/settings/get/service/',
'set':'/api/monit/settings/set/service/',
'add':'/api/monit/settings/set/service/',
'del':'/api/monit/settings/del/service/',
'toggle':'/api/monit/settings/toggle/service/'
});
/**
* service test settings
*/
// show hide execute field
function ShowHideExecField(){
var actiontype = $('#monit\\.test\\.action').val();
$('tr[for="monit.test.path"]').addClass('hidden');
if (actiontype === 'exec') {
$('tr[for="monit.test.path"]').removeClass('hidden');
}
};
$('#DialogEditTest').on('shown.bs.modal', function() {ShowHideExecField();});
$('#monit\\.test\\.action').on('changed.bs.select', function(e) {ShowHideExecField();});
function openTestDialog(uuid) {
var editDlg = "TestEditAlert";
var setUrl = "/api/monit/settings/set/test/";
var getUrl = "/api/monit/settings/get/test/";
var urlMap = {};
urlMap['frm_' + editDlg] = getUrl + uuid;
mapDataToFormUI(urlMap).done(function () {
$('.selectpicker').selectpicker('refresh');
clearFormValidation('frm_' + editDlg);
$('#'+editDlg).modal({backdrop: 'static', keyboard: false});
$('#'+editDlg).on('hidden.bs.modal', function () {
parent.history.back();
});
});
};
$("#grid-tests").UIBootgrid({
'search':'/api/monit/settings/search/test/',
'get':'/api/monit/settings/get/test/',
'set':'/api/monit/settings/set/test/',
'add':'/api/monit/settings/set/test/',
'del':'/api/monit/settings/del/test/'
});
});
</script>
<div class="alert alert-info hidden" role="alert" id="responseMsg">
</div>
<ul class="nav nav-tabs" role="tablist" id="maintabs">
<li class="active"><a data-toggle="tab" href="#general">{{ lang._('General Settings') }}</a></li>
<li><a data-toggle="tab" href="#alerts">{{ lang._('Alert Settings') }}</a></li>
<li><a data-toggle="tab" href="#services">{{ lang._('Service Settings') }}</a></li>
<li><a data-toggle="tab" href="#tests">{{ lang._('Service Tests Settings') }}</a></li>
</ul>
<div class="tab-content content-box tab-content">
<div id="general" class="tab-pane fade in active">
<!-- monit general settings -->
{{ partial("layout_partials/base_form",['fields':formGeneralSettings,'id':'frm_GeneralSettings','apply_btn_id':'btn_ApplyGeneralSettings'])}}
</div>
<div id="alerts" class="tab-pane fade in">
<table id="grid-alerts" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="DialogEditAlert">
<thead>
<tr>
<th data-column-id="enabled" data-width="6em" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="recipient" data-width="12em" data-type="string">{{ lang._('Recipient') }}</th>
<th data-column-id="noton" data-width="2em" data-type="string" data-align="right" data-formatter="boolean"></th>
<th data-column-id="events" data-type="string">{{ lang._('Events') }}</th>
<th data-column-id="description" data-type="string">{{ lang._('Description') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Edit') }} | {{ lang._('Delete') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
</table>
</div>
<div id="services" class="tab-pane fade in">
<table id="grid-services" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="DialogEditService">
<thead>
<tr>
<th data-column-id="enabled" data-width="6em" data-type="string" data-formatter="rowtoggle">{{ lang._('Enabled') }}</th>
<th data-column-id="name" data-type="string">{{ lang._('Name') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Edit') }} | {{ lang._('Delete') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
</table>
</div>
<div id="tests" class="tab-pane fade in">
<table id="grid-tests" class="table table-condensed table-hover table-striped table-responsive" data-editDialog="DialogEditTest">
<thead>
<tr>
<th data-column-id="name" data-type="string">{{ lang._('Name') }}</th>
<th data-column-id="condition" data-type="string">{{ lang._('Condition') }}</th>
<th data-column-id="action" data-type="string">{{ lang._('Action') }}</th>
<th data-column-id="uuid" data-type="string" data-identifier="true" data-visible="false">{{ lang._('ID') }}</th>
<th data-column-id="commands" data-width="7em" data-formatter="commands" data-sortable="false">{{ lang._('Edit') }} | {{ lang._('Delete') }}</th>
</tr>
</thead>
<tbody>
</tbody>
<tfoot>
<tr>
<td></td>
<td>
<button data-action="add" type="button" class="btn btn-xs btn-default"><span class="fa fa-plus"></span></button>
<button data-action="deleteSelected" type="button" class="btn btn-xs btn-default"><span class="fa fa-trash-o"></span></button>
</td>
</tr>
</tfoot>
</table>
</div>
<div class="col-md-12">
<hr/>
<button class="btn btn-primary" id="btn_configtest" type="button"><b>{{ lang._('Test Configuration') }}</b><i id="btn_configtest_progress" class=""></i></button>
<button class="btn btn-primary" id="btn_reload" type="button"><b>{{ lang._('Reload Configuration') }}</b><i id="btn_reload_progress" class=""></i></button>
<br/>
<br/>
</div>
</div>
{# include dialogs #}
{{ partial("layout_partials/base_dialog",['fields':formDialogEditAlert,'id':'DialogEditAlert','label':'Edit Alert&nbsp;&nbsp;<small>NOTE: For a detailed description see monit(1) section "ALERT MESSAGES".</small>'])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogEditService,'id':'DialogEditService','label':'Edit Service'])}}
{{ partial("layout_partials/base_dialog",['fields':formDialogEditTest,'id':'DialogEditTest','label':'Edit Test&nbsp;&nbsp;<small>NOTE: For a detailed description see monit(1) section "SERVICE TESTS".</small>'])}}

View File

@ -0,0 +1,45 @@
{#
Copyright © 2017-2018 by EURO-LOG AG
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.
#}
<script>
$( document ).ready(function() {
function decodeEntities(encodedString) {
var textArea = document.createElement('textarea');
textArea.innerHTML = encodedString;
return textArea.value;
}
ajaxCall(url="/api/monit/status/get/html", sendData={}, callback=function(data,status) {
$("#status").html(decodeEntities(data['status']));
});
});
</script>
<div id="status" class="content-box tab-content">
Loading...
</div>

View File

@ -0,0 +1,161 @@
#!/usr/local/bin/php
<?php
/**
* Copyright (C) 2017 EURO-LOG AG
*
* 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");
use OPNsense\Core\Config;
use OPNsense\Core\Shell;
use OPNsense\Monit\Monit;
$mdlMonit = new Monit();
$cfg = Config::getInstance();
$cfgObj = $cfg->object();
$shellObj = new OPNsense\Core\Shell;
$generalNode = $mdlMonit->getNodeByReference('general');
if (empty($cfgObj->OPNsense->monit->general->httpdUsername) && empty($cfgObj->OPNsense->monit->general->httpdPassword)) {
print "Generate Monit httpd username and password\n";
srand();
$generalNode->setNodes(array(
"httpdUsername" => "root",
"httpdPassword" => substr(str_shuffle(str_repeat('0123456789AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz', 32)), rand(0, 16), rand(17, 32))
));
$mdlMonit->serializeToConfig(false, true);
$cfg->save();
}
$nodes = $mdlMonit->getNodes();
// test if Monit is already configured
if (count($nodes['service']) != 0 || count($nodes['test']) != 0) {
exit;
}
// get number of cpus and calculate load average limits
$nCPU = array();
$shellObj->exec('/sbin/sysctl -n kern.smp.cpus', false, $nCPU);
$LoadAvg1 = $nCPU[0] * 2;
$LoadAvg5 = $nCPU[0] + ($nCPU[0] / 2);
$LoadAvg15 = $nCPU[0];
// inherit SMTP settings from System->Settings->Notifications
$generalSettings = array();
if (!empty($cfgObj->notifications->smtp->ipaddress)) {
$generalSettings['mailserver'] = $cfgObj->notifications->smtp->ipaddress;
}
if (!empty($cfgObj->notifications->smtp->port)) {
$generalSettings['port'] = $cfgObj->notifications->smtp->port;
}
if (!empty($cfgObj->notifications->smtp->username)) {
$generalSettings['username'] = $cfgObj->notifications->smtp->username;
}
if (!empty($cfgObj->notifications->smtp->password)) {
$generalSettings['password'] = $cfgObj->notifications->smtp->password;
}
if ((!empty($cfgObj->notifications->smtp->tls) && $cfgObj->notifications->smtp->tls == 1) ||
(!empty($cfgObj->notifications->smtp->ssl) && $cfgObj->notifications->smtp->ssl == 1)) {
$generalSettings['ssl'] = 1;
}
$alertSettings = array();
if (!empty($cfgObj->notifications->smtp->notifyemailaddress)) {
$alertSettings['recipient'] = $cfgObj->notifications->smtp->notifyemailaddress;
}
if (!empty($cfgObj->notifications->smtp->fromaddress)) {
$alertSettings['format'] = 'from: ' . $cfgObj->notifications->smtp->fromaddress;
}
// define some tests
$defaultTests = array(
array("name" => "Ping", "condition" => "failed ping", "action" => "alert"),
array("name" => "NetworkLink", "condition" => "failed link", "action" => "alert"),
array("name" => "NetworkSaturation", "condition" => "saturation is greater than 75%", "action" => "alert"),
array("name" => "MemoryUsage", "condition" => "memory usage is greater than 75%", "action" => "alert"),
array("name" => "CPUUsage", "condition" => "cpu usage is greater than 75%", "action" => "alert"),
array("name" => "LoadAvg1", "condition" => "loadavg (1min) is greater than $LoadAvg1", "action" => "alert"),
array("name" => "LoadAvg5", "condition" => "loadavg (5min) is greater than $LoadAvg5", "action" => "alert"),
array("name" => "LoadAvg15", "condition" => "loadavg (15min) is greater than $LoadAvg15", "action" => "alert"),
array("name" => "SpaceUsage", "condition" => "space usage is greater than 75%", "action" => "alert")
);
// define system service
$systemService = array(
"enabled" => 1,
"name" => '$HOST',
"type" => "system",
"tests" => ""
);
// define root filesystem service
$rootFsService = array(
"enabled" => 1,
"name" => "RootFs",
"type" => "filesystem",
"path" => "/",
"tests" => ""
);
foreach ($defaultTests as $defaultTest) {
$testNode = $mdlMonit->test->Add();
$testNode->setNodes($defaultTest);
if ($defaultTest['name'] == "MemoryUsage" ||
$defaultTest['name'] == "CPUUsage" ||
$defaultTest['name'] == "LoadAvg1" ||
$defaultTest['name'] == "LoadAvg5" ) {
$systemService['tests'] .= $testNode->getAttributes()['uuid'] . ",";
}
if ($defaultTest['name'] == "SpaceUsage") {
$rootFsService['tests'] .= $testNode->getAttributes()['uuid'] . ",";
}
}
// remove last comma from tests csv
$systemService['tests'] = substr($systemService['tests'], 0, -1);
$rootFsService['tests'] = substr($rootFsService['tests'], 0, -1);
// set general properties
$generalNode->setNodes($generalSettings);
// add an alert with (almost) default settings
$alertNode = $mdlMonit->alert->Add();
$alertNode->setNodes($alertSettings);
// add system service
$serviceNode = $mdlMonit->service->Add();
$serviceNode->setNodes($systemService);
// add root filesystem service
$rootFsNode = $mdlMonit->service->Add();
$rootFsNode->setNodes($rootFsService);
// ignore validations because ModelRelationField does not work
$mdlMonit->serializeToConfig(false, true);
$cfg->save();

View File

@ -0,0 +1,5 @@
#!/bin/sh
# change permissions of the monit configuration file
chmod 600 /usr/local/etc/monitrc || exit 1
exit 0

View File

@ -0,0 +1,29 @@
[start]
command:/usr/local/opnsense/scripts/OPNsense/Monit/setup.sh; /usr/local/etc/rc.d/monit start
type:script
message:starting monit
[stop]
command:/usr/local/etc/rc.d/monit stop
type:script
message:stopping monit
[status]
command:/usr/local/etc/rc.d/monit status; exit 0
type:script_output
message:get monit status
[restart]
command:/usr/local/opnsense/scripts/OPNsense/Monit/setup.sh; /usr/local/etc/rc.d/monit restart
type:script
message:restarting monit
[reload]
command:/usr/local/opnsense/scripts/OPNsense/Monit/setup.sh; /usr/local/etc/rc.d/monit reload
type:script
message:reload monit configuration
[configtest]
command:/usr/local/opnsense/scripts/OPNsense/Monit/setup.sh; /usr/local/bin/monit -t 2>&1 || exit 0
type:script_output
message:testing monit configuration

View File

@ -0,0 +1,2 @@
monitrc:/usr/local/etc/monitrc
rc.conf.d:/etc/rc.conf.d/monit

View File

@ -0,0 +1,133 @@
# DO NOT EDIT THIS FILE -- OPNsense auto-generated file
{% from 'OPNsense/Macros/interface.macro' import physical_interface %}
{% if helpers.exists('OPNsense.monit.general') %}
{% if helpers.exists('OPNsense.monit.general.httpdEnabled') and OPNsense.monit.general.httpdEnabled|default('0') == '1' %}
{% set httpdCredentials = OPNsense.monit.general.httpdUsername ~ ':"' ~ OPNsense.monit.general.httpdPassword ~ '"' %}
{% set httpdport = "port " ~ OPNsense.monit.general.httpdPort %}
set httpd unixsocket /var/run/monit.sock {{ httpdport }}
allow localhost
allow {{ httpdCredentials }}
{% if helpers.exists('OPNsense.monit.general.httpdAllow') %}
{% for allow in OPNsense.monit.general.httpdAllow.split(",") %}
{% set cred = allow.split(":") %}
{% if cred[1] %}
{% set pass = cred[1].split() %}
{% set allow = cred[0] ~ ':"' ~ pass[0] ~ '" ' ~ pass[1] %}
{% endif %}
allow {{ allow }}
{% endfor %}
{% endif %}
{% if helpers.exists('OPNsense.monit.general.mmonitUrl') and OPNsense.monit.general.mmonitUrl|default('') != '' %}
{% set mregister = 'register without credentials' if OPNsense.monit.general.mmonitRegisterCredentials|default('1') == '0' %}
set mmonit {{ OPNsense.monit.general.mmonitUrl }} timeout {{ OPNsense.monit.general.mmonitTimeout }} seconds {{ mregister }}
{% endif %}
{% else %}
set httpd unixsocket /var/run/monit.sock
allow localhost
{% endif %}
set daemon {{ OPNsense.monit.general.interval }} with start delay {{ OPNsense.monit.general.startdelay }}
{% if helpers.exists('OPNsense.monit.general.logfile') and OPNsense.monit.general.logfile|default('') != '' %}
set logfile {{ OPNsense.monit.general.logfile }}
{% else %}
set logfile syslog facility log_daemon
{% endif %}
{% if helpers.exists('OPNsense.monit.general.statefile') and OPNsense.monit.general.statefile|default('') != '' %}
set statefile {{ OPNsense.monit.general.statefile }}
{% endif %}
{% if helpers.exists('OPNsense.monit.general.eventqueuePath') and OPNsense.monit.general.eventqueuePath|default('') != '' %}
{% set slots = '' %}
{% if helpers.exists('OPNsense.monit.general.eventqueueSlots') %}
{% set slots = "slots " ~ OPNsense.monit.general.eventqueueSlots %}
{% endif %}
set eventqueue basedir {{ OPNsense.monit.general.eventqueuePath }} {{ slots }}
{% endif %}
{% if helpers.exists('OPNsense.monit.general.mailserver') %}
{% set port = "port " ~ OPNsense.monit.general.port if OPNsense.monit.general.port|default('') != '' %}
{% set username = '' %}
{% set password = '' %}
{% if helpers.exists('OPNsense.monit.general.username') and helpers.exists('OPNsense.monit.general.password') %}
{% set username = "username " ~ OPNsense.monit.general.username %}
{% set password = "password " ~ '"' ~ OPNsense.monit.general.password ~ '"' %}
{% endif %}
{% set ssl = 'using ssl' if OPNsense.monit.general.ssl|default('0') == '1' %}
set mailserver {{ OPNsense.monit.general.mailserver }} {{ port }} {{ username }} {{ password }} {{ ssl }}
{% endif %}
{% if helpers.exists('OPNsense.monit.alert') %}
{% for alert in helpers.toList('OPNsense.monit.alert') %}
{% if alert.enabled|default('0') == '1' %}
{% set noton = 'not on' if alert.noton|default('0') == '1' %}
{% set mailformat = "mail-format { " ~ alert.format ~ " }" if alert.format|default('') != '' %}
{% set reminder = "reminder on " ~ alert.reminder ~ " cycles" if alert.reminder|default('0') != '0' %}
{% set events = "{ " ~ alert.events ~ " }" if alert.events|default('') != '' %}
set alert {{ alert.recipient }} {{ noton }} {{ events }} {{ mailformat }} {{ reminder }}
{% endif %}
{% endfor %}
{% endif %}
{% if helpers.exists('OPNsense.monit.service') %}
{% for service in helpers.toList('OPNsense.monit.service') %}
{% if service.enabled|default('0') == '1' %}
{% set pidfile = '' %}
{% set match = '' %}
{% set path = '' %}
{% set address = '' %}
{% set interface = '' %}
{% if service.type == 'process' %}
{% if service.pidfile|default('') != '' %}
{% set pidfile = "pidfile " ~ service.pidfile %}
{% elif service.match|default('') != '' %}
{% set match = "matching " ~ service.match if service.match|default('') != '' %}
{% endif %}
check {{ service.type }} {{ service.name }} {{ pidfile }} {{ match }}
{% elif service.type == 'host' %}
{% set address = "address " ~ service.address %}
check {{ service.type }} {{ service.name }} {{ address }}
{% elif service.type == 'network' %}
{% if service.address|default('') != '' %}
{% set address = "address " ~ service.address %}
{% elif service.interface|default('') != '' %}
{% set interface = "interface " ~ physical_interface(service.interface) %}
{% endif %}
check {{ service.type }} {{ service.name }} {{ address }} {{ interface }}
{% elif service.type == 'system' %}
check {{ service.type }} {{ service.name }}
{% else %}
{% set path = "with path " ~ service.path %}
{% if service.type == 'custom' %}
check program {{ service.name }} {{ path }}
{% else %}
check {{ service.type }} {{ service.name }} {{ path }}
{% endif %}
{% endif %}
{% if service.start|default('') != '' %}
start program = "{{ service.start }}"
{% endif %}
{% if service.start|default('') != '' %}
stop program = "{{ service.stop }}"
{% endif %}
{% if service.tests is defined %}
{% for test in service.tests.split(",") %}
{% set test = helpers.getUUID(test) %}
{% if test.condition is defined and test.action is defined %}
{% set epath = '' %}
{% if test.action == 'exec' and test.path|default('') != '' %}
{% set epath = test.path %}
{% endif %}
if {{ test.condition }} then {{ test.action }} {{ epath }}
{% endif %}
{% endfor %}
{% endif %}
{% endif %}
{% endfor %}
{% endif %}
{% endif %}

View File

@ -0,0 +1,7 @@
# DO NOT EDIT THIS FILE -- OPNsense auto-generated file
{% if helpers.exists('OPNsense.monit.general.enabled') and OPNsense.monit.general.enabled|default("0") == "1" %}
monit_var_script="/usr/local/opnsense/scripts/OPNsense/Monit/setup.sh"
monit_enable="YES"
{% else %}
monit_enable="NO"
{% endif %}