diff --git a/src/opnsense/mvc/app/models/OPNsense/Monit/Migrations/M1_0_8.php b/src/opnsense/mvc/app/models/OPNsense/Monit/Migrations/M1_0_8.php
new file mode 100644
index 000000000..4e779dff7
--- /dev/null
+++ b/src/opnsense/mvc/app/models/OPNsense/Monit/Migrations/M1_0_8.php
@@ -0,0 +1,45 @@
+getNodeByReference('test')->__items as $test) {
+ $test->type = $model->getTestType($test->condition->getNodeData());
+ }
+ // validation will fail because we want to change the type of tests linked to services
+ $model->serializeToConfig(false, true);
+ Config::getInstance()->save();
+ }
+}
diff --git a/src/opnsense/mvc/app/models/OPNsense/Monit/Monit.php b/src/opnsense/mvc/app/models/OPNsense/Monit/Monit.php
index 69610ace8..f430cf000 100644
--- a/src/opnsense/mvc/app/models/OPNsense/Monit/Monit.php
+++ b/src/opnsense/mvc/app/models/OPNsense/Monit/Monit.php
@@ -1,7 +1,7 @@
['Existence', 'ProcessResource', 'ProcessDiskIO',
'UID', 'GID', 'PID', 'PPID', 'Uptime', 'Connection', 'Custom'],
'file' => ['Existence', 'FileChecksum', 'Timestamp', 'FileSize',
@@ -56,6 +56,96 @@ class Monit extends BaseModel
'network' => ['NetworkInterface', 'Custom']
];
+ /**
+ * array with condition patterns for test types
+ */
+ private $conditionPatterns = [
+ 'Existence' => [
+ 'exist', 'not exist'
+ ],
+ 'SystemResource' => [
+ 'loadavg (1min)', 'loadavg (5min)', 'loadavg (15min)', 'cpu usage',
+ 'cpu user usage', 'cpu system usage', 'cpu wait usage', 'memory usage',
+ 'swap usage'
+ ],
+ 'ProcessResource' => [
+ 'cpu', 'total cpu', 'threads', 'children', 'memory usage',
+ 'total memory usage'
+ ],
+ 'ProcessDiskIO' => [
+ 'disk read rate', 'disk write rate'
+ ],
+ 'FileChecksum' => [
+ 'failed md5 checksum', 'changed md5 checksum', 'failed checksum expect'
+ ],
+ 'Timestamp' => [
+ 'access time', 'modification time', 'change time', 'timestamp',
+ 'changed access time', 'changed modification time', 'changed change time',
+ 'changed timestamp'
+ ],
+ 'FileSize' => [
+ 'size', 'changed size'
+ ],
+ 'FileContent' => [
+ 'content =', 'content !='
+ ],
+ 'FilesystemMountFlags' => [
+ 'changed fsflags'
+ ],
+ 'SpaceUsage' => [
+ 'space', 'space free'
+ ],
+ 'InodeUsage' => [
+ 'inodes',
+ 'inodes free'
+ ],
+ 'DiskIO' => [
+ 'read rate',
+ 'write rate',
+ 'service time'
+ ],
+ 'Permisssion' => [
+ 'failed permission',
+ 'changed permission'
+ ],
+ 'UID' => [
+ 'failed uid'
+ ],
+ 'GID' => [
+ 'failed uid'
+ ],
+ 'PID' => [
+ 'changed pid'
+ ],
+ 'PPID' => [
+ 'changed ppid'
+ ],
+ 'Uptime' => [
+ 'uptime'
+ ],
+ 'ProgramStatus' => [
+ 'status',
+ 'changed status'
+ ],
+ 'NetworkInterface' => [
+ 'failed link',
+ 'changed link capacity',
+ 'saturation',
+ 'upload',
+ 'download'
+ ],
+ 'NetworkPing' => [
+ 'failed ping',
+ 'failed ping4',
+ 'failed ping6'
+ ],
+ 'Connection' => [
+ 'failed host',
+ 'failed port',
+ 'failed unixsocket'
+ ],
+ 'Custom' => []
+ ];
/**
* validate full model using all fields and data in a single (1 deep) array
@@ -77,26 +167,44 @@ class Monit extends BaseModel
// test node validations
switch ($node->getInternalXMLTagName()) {
case 'type':
+ // only 'Custom' is allowed if test is linked to a service
$testUuid = $parentNode->getAttribute('uuid');
- if ($node->isFieldChanged() && $this->isTestServiceRelated($testUuid)) {
+ if (strcmp((string)$node, 'Custom') != 0 &&
+ $node->isFieldChanged() &&
+ $this->isTestServiceRelated($testUuid)) {
$messages->appendMessage(new \Phalcon\Validation\Message(
gettext("Cannot change the type. Test is linked to a service."),
$key
));
}
break;
+ case 'condition':
+ // only 'Custom' or the same test type (from condition) allowed if test is linked to a service
+ $type = $this->getTestType((string)$node);
+ if (strcmp($type, 'Custom') != 0 &&
+ strcmp((string)$parentNode->type, $type) != 0 &&
+ $this->isTestServiceRelated($parentNode->getAttribute('uuid'))) {
+ $messages->appendMessage(new \Phalcon\Validation\Message(
+ gettext("Condition would change the type of the test but it is linked to a service."),
+ $key
+ ));
+ } else {
+ // set the test tytpe according to the condition
+ $parentNode->type = $type;
+ }
+ break;
}
break;
case 'service':
// service node validations
switch ($node->getInternalXMLTagName()) {
case 'tests':
- // test dependencies defined in $this->testSyntax
+ // test dependencies defined in $this->serviceTestMapping
foreach (explode(',', (string)$parentNode->tests) as $testUUID) {
$test = $this->getNodeByReference('test.' . $testUUID);
if ($test != null) {
- if (!empty($this->testSyntax[(string)$parentNode->type])) {
- $options = $this->testSyntax[(string)$parentNode->type];
+ if (!empty($this->serviceTestMapping[(string)$parentNode->type])) {
+ $options = $this->serviceTestMapping[(string)$parentNode->type];
if (!in_array((string)$test->type, $options)) {
$validationMsg = sprintf(
gettext("Test %s with type %s not allowed for this service type"),
@@ -182,7 +290,6 @@ class Monit extends BaseModel
return parent::serializeToConfig($validateFullModel, $disable_validation);
}
-
/**
* get configuration state
* @return bool
@@ -216,4 +323,40 @@ class Monit extends BaseModel
}
return false;
}
+
+ /**
+ * get test type from condition string
+ * @param condition string
+ * @return string
+ */
+ public function getTestType($condition)
+ {
+ $condition = preg_replace('/\s\s+/', ' ', $condition);
+ $keyLength = 0;
+ $foundOperand = '';
+ $foundTestType = 'Custom';
+
+ foreach ($this->conditionPatterns as $testType => $operandList) {
+ // find the operand for this condition using the longest match
+ foreach ($operandList as $operand) {
+ $operandLength = strlen($operand);
+ if (!strncmp($condition, $operand, $operandLength) &&
+ $operandLength > $keyLength) {
+ $keyLength = $operandLength;
+ $foundOperand = $operand;
+ $foundTestType = $testType;
+ }
+ }
+ }
+
+ // 'memory usage' can be ambiguous but 'percent' unit makes it clear
+ if (strcmp('memory usage', $foundOperand) == 0) {
+ if (preg_match('/^.*\spercent|%\s*$/', $condition)) {
+ $foundTestType = 'SystemResource';
+ } else {
+ $foundTestType = 'ProcessResource';
+ }
+ }
+ return $foundTestType;
+ }
}
diff --git a/src/opnsense/mvc/app/models/OPNsense/Monit/Monit.xml b/src/opnsense/mvc/app/models/OPNsense/Monit/Monit.xml
index ea290ca70..c4e900fc2 100644
--- a/src/opnsense/mvc/app/models/OPNsense/Monit/Monit.xml
+++ b/src/opnsense/mvc/app/models/OPNsense/Monit/Monit.xml
@@ -186,6 +186,12 @@
Y
/^([0-9a-zA-Z\._\-\$]){1,255}$/u
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.
+
+
+ Service name must be unique.
+ UniqueConstraint
+
+
Y
@@ -298,6 +304,7 @@
Program Status
Network Interface
Network Ping
+ Connection
Custom