diff --git a/sysutils/monit/Makefile b/sysutils/monit/Makefile
new file mode 100644
index 000000000..11462e3dd
--- /dev/null
+++ b/sysutils/monit/Makefile
@@ -0,0 +1,7 @@
+PLUGIN_NAME= monit
+PLUGIN_VERSION= 0.1
+PLUGIN_COMMENT= Proactive system monitoring
+PLUGIN_MAINTAINER= frank.brendel@eurolog.com
+PLUGIN_DEPENDS= monit
+
+.include "../../Mk/plugins.mk"
diff --git a/sysutils/monit/src/etc/inc/plugins.inc.d/monit.inc b/sysutils/monit/src/etc/inc/plugins.inc.d/monit.inc
new file mode 100644
index 000000000..fd864f5bf
--- /dev/null
+++ b/sysutils/monit/src/etc/inc/plugins.inc.d/monit.inc
@@ -0,0 +1,48 @@
+ gettext('Monit System Monitoring'),
+ 'configd' => array(
+ 'restart' => array('monit restart'),
+ 'start' => array('monit start'),
+ 'stop' => array('monit stop'),
+ ),
+ 'name' => 'monit',
+ );
+ }
+ return $services;
+}
diff --git a/sysutils/monit/src/opnsense/mvc/app/controllers/OPNsense/Monit/Api/ServiceController.php b/sysutils/monit/src/opnsense/mvc/app/controllers/OPNsense/Monit/Api/ServiceController.php
new file mode 100644
index 000000000..6d441feb0
--- /dev/null
+++ b/sysutils/monit/src/opnsense/mvc/app/controllers/OPNsense/Monit/Api/ServiceController.php
@@ -0,0 +1,172 @@
+request->isPost()) {
+ $this->sessionClose();
+ }
+ $result['function'] = "configtest";
+
+ $result['template'] = $this->callBackend('template');
+ if ($result['template'] != 'OK')
+ {
+ $result['result'] = "Template error: " . $result['template'];
+ return $result;
+ }
+
+ $result['result'] = $this->callBackend('configtest');
+ return $result;
+ }
+
+ /**
+ * reload monit with new configuration
+ * @return array
+ */
+ public function reloadAction()
+ {
+ if ($this->request->isPost()) {
+ $this->sessionClose();
+ }
+ $result['function'] = "reload";
+
+ $result['template'] = $this->callBackend('template');
+ if ($result['template'] != 'OK')
+ {
+ $result['result'] = "Template error: " . $result['template'];
+ return $result;
+ }
+
+ $status = $this->callBackend('status');
+ if (substr($status, 0, 16) != 'monit is running') {
+ $result['result'] = "Monit is not running";
+ return $result;
+ }
+
+ $result['result'] = $this->callBackend('reload');
+ return $result;
+ }
+
+ /**
+ * get status of monit process
+ * @return array
+ */
+ public function statusAction()
+ {
+ if ($this->request->isPost()) {
+ $this->sessionClose();
+ }
+ $result['function'] = "status";
+ $result['result'] = "failed";
+ $result['status'] = 'stopped';
+ $status = $this->callBackend('status');
+ if (substr($status, 0, 16) == 'monit is running') {
+ $result['result'] = "ok";
+ $result['status'] = 'running';
+ } else {
+ $result['error'] = $status;
+ }
+ return $result;
+ }
+
+ /**
+ * start monit service
+ * @return array
+ */
+ public function startAction()
+ {
+ $result = array("result" => "failed", "function" => "start");
+ if ($this->request->isPost()) {
+ $this->sessionClose();
+ $result['result'] = $this->callBackend('start');
+ }
+ return $result;
+ }
+
+ /**
+ * stop monit service
+ * @return array
+ */
+ public function stopAction()
+ {
+ $result = array("result" => "failed", "function" => "stop");
+ if ($this->request->isPost()) {
+ $this->sessionClose();
+ $result['result'] = $this->callBackend('stop');
+ }
+ return $result;
+ }
+
+ /**
+ * restart monit service
+ * @return array
+ */
+ public function restartAction()
+ {
+ $result = array("result" => "failed", "function" => "restart");
+ if ($this->request->isPost()) {
+ $this->sessionClose();
+ $result['result'] = $this->callBackend('restart');
+ }
+ return $result;
+ }
+
+ /**
+ * call backend functions
+ * @param action
+ * @return string
+ */
+ protected function callBackend($action)
+ {
+ $backend = new Backend();
+ if ($action == 'template') {
+ return trim($backend->configdRun('template reload OPNsense/Monit'));
+ } else {
+ return trim($backend->configdRun('monit ' . $action));
+ }
+ }
+}
diff --git a/sysutils/monit/src/opnsense/mvc/app/controllers/OPNsense/Monit/Api/SettingsController.php b/sysutils/monit/src/opnsense/mvc/app/controllers/OPNsense/Monit/Api/SettingsController.php
new file mode 100644
index 000000000..78856ae3c
--- /dev/null
+++ b/sysutils/monit/src/opnsense/mvc/app/controllers/OPNsense/Monit/Api/SettingsController.php
@@ -0,0 +1,463 @@
+get('general');
+ }
+
+ /**
+ * update monit general settings with given properties
+ * @return array
+ */
+ public function setGeneralAction()
+ {
+ return $this->set('general');
+ }
+
+ //// ALERT SETTINGS ////
+
+ /**
+ * search alert
+ * @return array
+ */
+ public function searchAlertAction()
+ {
+ $fields = array("enabled", "recipient", "noton", "events", "description");
+ return $this->search('alert', $fields);
+ }
+
+ /**
+ * retrieve monit alert settings or return defaults
+ * @param $uuid item unique id
+ * @return array
+ */
+ public function getAlertAction($uuid = null)
+ {
+ return $this->get('alert', $uuid);
+ }
+
+ /**
+ * set monit alert parameter
+ * @param $uuid item unique id
+ * @return array
+ */
+ public function setAlertAction($uuid = null)
+ {
+ if ($uuid != null) {
+ return $this->set('alert', $uuid);
+ }
+ return array("result" => "failed");
+ }
+
+ /**
+ * add monit alert parameter
+ * @return array
+ */
+ public function addAlertAction()
+ {
+ return $this->set('alert', null, true);
+ }
+
+ /**
+ * delete monit alert parameter
+ * @param $uuid item unique id
+ * @return array
+ */
+ public function delAlertAction($uuid = null)
+ {
+ if ($uuid != null) {
+ return $this->del('alert', $uuid);
+ }
+ return array("result" => "failed");
+ }
+
+ /**
+ * toggle monit alert by uuid (enable/disable)
+ * @param $uuid item unique id
+ * @return array
+ */
+ public function toggleAlertAction($uuid)
+ {
+ if ($uuid != null) {
+ return $this->toggle('alert', $uuid);
+ }
+ return array("result" => "failed");
+ }
+
+ //// SERVICE SETTINGS ////
+
+ /**
+ * search service
+ * @return array
+ */
+ public function searchServiceAction()
+ {
+ $fields = array("enabled", "name", "type", "description");
+ return $this->search('service', $fields);
+ }
+
+ /**
+ * retrieve monit service settings or return defaults
+ * @param $uuid item unique id
+ * @return array
+ */
+ public function getServiceAction($uuid = null)
+ {
+ return $this->get('service', $uuid);
+ }
+
+ /**
+ * set monit service parameter
+ * @param $uuid item unique id
+ * @return array
+ */
+ public function setServiceAction($uuid = null)
+ {
+ if ($uuid != null) {
+ return $this->set('service', $uuid);
+ }
+ return array("result" => "failed");
+ }
+
+ /**
+ * add monit service parameter
+ * @return array
+ */
+ public function addServiceAction()
+ {
+ return $this->set('service', null, true);
+ }
+
+ /**
+ * delete monit service parameter
+ * @param $uuid item unique id
+ * @return array
+ */
+ public function delServiceAction($uuid = null)
+ {
+ if ($uuid != null) {
+ return $this->del('service', $uuid);
+ }
+ return array("result" => "failed");
+ }
+
+ /**
+ * toggle monit service by uuid (enable/disable)
+ * @param $uuid item unique id
+ * @return array
+ */
+ public function toggleServiceAction($uuid)
+ {
+ if ($uuid != null) {
+ return $this->toggle('service', $uuid);
+ }
+ return array("result" => "failed");
+ }
+
+ //// SERVICE TEST SETTINGS ////
+
+ /**
+ * search test
+ * @return array
+ */
+ public function searchTestAction()
+ {
+ $fields = array("name", "condition", "action");
+ return $this->search('test', $fields);
+ }
+
+ /**
+ * retrieve monit service test settings or return defaults
+ * @param $uuid item unique id
+ * @return array
+ */
+ public function getTestAction($uuid = null)
+ {
+ return $this->get('test', $uuid);
+ }
+
+ /**
+ * set monit service test parameter
+ * @param $uuid item unique id
+ * @return array
+ */
+ public function setTestAction($uuid = null)
+ {
+ if ($uuid != null) {
+ return $this->set('test', $uuid);
+ }
+ return array("result" => "failed");
+ }
+
+ /**
+ * add monit service test parameter
+ * @return array
+ */
+ public function addTestAction()
+ {
+ return $this->set('test', null, true);
+ }
+
+ /**
+ * delete monit service test parameter
+ * @param $uuid item unique id
+ * @return array
+ */
+ public function delTestAction($uuid = null)
+ {
+ if ($uuid != null) {
+ return $this->del('test', $uuid);
+ }
+ return array("result" => "failed");
+ }
+
+ //// ABSTRACT FUNCTIONS ////
+
+ /**
+ * retrieve monit settings
+ * @param $nodeType
+ * @param $uuid
+ * @return result array
+ */
+ private function get($nodeType = null, $uuid = null)
+ {
+ $result = array("result" => "failed");
+ if($this->request->isGet() && $nodeType != null) {
+ $mdlMonit = new Monit();
+ if ($uuid != null) {
+ $node = $mdlMonit->getNodeByReference($nodeType . '.' . $uuid);
+ } else {
+ if ($nodeType == 'general') {
+ $node = $mdlMonit->getNodeByReference($nodeType);
+ } else {
+ $node = $mdlMonit->$nodeType->Add();
+ }
+ }
+ if ($node != null) {
+ $result[$nodeType] = $node->getNodes();
+ $result["result"] = "ok";
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * set monit properties
+ * @param $nodeType
+ * @param $uuid
+ * @parm $action set or add node
+ * @return result array
+ */
+ private function set($nodeType = null, $uuid = null, $add = false)
+ {
+ $result = array("result" => "failed");
+ if ($this->request->isPost() && $this->request->hasPost("monit") && $nodeType != null) {
+ $mdlMonit = new Monit();
+ if($add == false) { // set node
+ if ($uuid != null) {
+ $node = $mdlMonit->getNodeByReference($nodeType . '.' . $uuid);
+ } else {
+ if ($nodeType == 'general') {
+ $node = $mdlMonit->getNodeByReference($nodeType);
+ } else {
+ $node = $mdlMonit->$nodeType->Add();
+ }
+ }
+ } 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 ($valMsgs->count() == 0) {
+ $mdlMonit->serializeToConfig();
+ Config::getInstance()->save();
+ $result["result"] = "saved";
+ }
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * delete monit properties
+ * @param $nodeType
+ * @param $uuid
+ * @return result array
+ */
+ private function del($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 ($mdlMonit->$nodeType->del($uuid) == true) {
+ // remove test from services
+ if ($nodeType == 'test') {
+ // get a list of all services
+ $services = $mdlMonit->service->getNodes();
+ foreach ($services as $serviceUuid => $service) {
+ foreach ($service['tests'] as $testUuid => $test) {
+ // service has a reference to a test
+ if ($testUuid == $uuid) {
+ // get service model and remove $uuid from tests
+ $ref = 'service.' . $serviceUuid . '.tests';
+ $tstNode = $mdlMonit->getNodeByReference($ref);
+ $svcTests = str_replace($uuid, '', $tstNode->__toString());
+ $svcTests = str_replace(',,', ',', $svcTests);
+ $svcTests = rtrim($svcTests, ',');
+ $svcTests = ltrim($svcTests, ',');
+ $mdlMonit->setNodeByReference($ref, $svcTests);
+ }
+ }
+ }
+ }
+ $mdlMonit->serializeToConfig();
+ Config::getInstance()->save();
+ $svcMonit = new ServiceController();
+ $result = $svcMonit->reloadAction();
+ }
+ } else {
+ $result['result'] = "not found";
+ }
+ } else {
+ $result['result'] = "uuid not given";
+ }
+ }
+ return $result;
+ }
+
+ /**
+ * toggle monit items (enable/disable)
+ * @param $nodeType
+ * @param $uuid
+ * @return result array
+ */
+ private function toggle($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
+ * @param requested field list
+ * @return array
+ */
+ private function search($nodeType = null, &$fields = null)
+ {
+ $this->sessionClose();
+ if($nodeType != null) {
+ $mdlMonit = new Monit();
+ $grid = new UIModelGrid($mdlMonit->$nodeType);
+ return $grid->fetchBindRequest($this->request, $fields);
+ }
+ }
+}
diff --git a/sysutils/monit/src/opnsense/mvc/app/controllers/OPNsense/Monit/Api/StatusController.php b/sysutils/monit/src/opnsense/mvc/app/controllers/OPNsense/Monit/Api/StatusController.php
new file mode 100644
index 000000000..525950a30
--- /dev/null
+++ b/sysutils/monit/src/opnsense/mvc/app/controllers/OPNsense/Monit/Api/StatusController.php
@@ -0,0 +1,134 @@
+ "failed", "function" => "getStatus");
+
+ // connect monit httpd socket defined in monitrc by 'set httpd ...'
+ if (file_exists("/var/run/monit.sock") && filetype("/var/run/monit.sock") == "socket" ) {
+ // throws an exception therefore no error handling
+ $socket = stream_socket_client("unix:///var/run/monit.sock", $errno, $errstr);
+
+ // get monit status page
+ $request = "GET /_status?format=text HTTP/1.0\r\n";
+ $request .= "\r\n";
+ $count = fwrite($socket, $request);
+ $result['count'] = $count;
+ $result['status'] = '';
+ $result['orig'] = '';
+ $result['httpstatus'] = preg_replace( "/\r|\n/", "", fgets($socket));
+ $ignorelines = 1;
+ if ($result['httpstatus'] == 'HTTP/1.0 200 OK') {
+ while (!feof($socket)) {
+ $line = fgets($socket);
+ $result['orig'] .= $line;
+
+ // ignore lines (mostly HTTP headers) until a line starts with 'Monit' e.g. 'Monit 5.20.0 uptime: 2d 23h 2m'
+ if (substr($line, 0, 5) == 'Monit') {
+ $ignorelines = 0;
+ }
+ if ($ignorelines) {
+ continue;
+ }
+ $result['status'] .= $line;
+ }
+ $result['result'] = "ok";
+
+ }
+ fclose($socket);
+
+ // response contains shell color escape codes; convert them to CSS
+ $result['status'] = '
' . $this->bashColorToCSS($result['status']) . '
';
+ } else {
+ $result['status'] = '
+Either the file /var/run/monit.sock 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.