Merge branch 'monit_migration' of https://github.com/fbrendel/core into fbrendel-monit_migration

This commit is contained in:
Ad Schellevis 2019-03-06 15:15:40 +01:00
commit 3d7e84eae4
3 changed files with 203 additions and 8 deletions

View File

@ -0,0 +1,45 @@
<?php
/*
* Copyright (C) 2019 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\Migrations;
use OPNsense\Base\BaseModelMigration;
use OPNsense\Core\Config;
class M1_0_8 extends BaseModelMigration
{
public function post($model)
{
foreach ($model->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();
}
}

View File

@ -1,7 +1,7 @@
<?php
/*
* Copyright (C) 2016 EURO-LOG AG
* Copyright (C) 2016-2019 EURO-LOG AG
* Copyright (c) 2019 Deciso B.V.
* All rights reserved.
*
@ -39,9 +39,9 @@ use OPNsense\Base\BaseModel;
class Monit extends BaseModel
{
/**
*
* array with service types and their possible test types
*/
private $testSyntax = [
private $serviceTestMapping = [
'process' => ['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;
}
}

View File

@ -186,6 +186,12 @@
<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>
<Constraints>
<check001>
<ValidationMessage>Service name must be unique.</ValidationMessage>
<type>UniqueConstraint</type>
</check001>
</Constraints>
</name>
<type type="OptionField">
<Required>Y</Required>
@ -298,6 +304,7 @@
<ProgramStatus>Program Status</ProgramStatus>
<NetworkInterface>Network Interface</NetworkInterface>
<NetworkPing>Network Ping</NetworkPing>
<Connection>Connection</Connection>
<Custom>Custom</Custom>
</OptionValues>
</type>