%PDF- %PDF-
| Direktori : /proc/thread-self/root/backups/router/usr/local/opnsense/mvc/app/models/OPNsense/Monit/ |
| Current File : //proc/thread-self/root/backups/router/usr/local/opnsense/mvc/app/models/OPNsense/Monit/Monit.php |
<?php
/*
* Copyright (C) 2016-2019 EURO-LOG AG
* Copyright (c) 2019 Deciso B.V.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
namespace OPNsense\Monit;
use OPNsense\Base\Messages\Message;
use OPNsense\Base\BaseModel;
/**
* Class Monit
* @package OPNsense\Monit
*/
class Monit extends BaseModel
{
/**
* array with service types and their possible test types
*/
private $serviceTestMapping = [
'process' => ['Existence', 'ProcessResource', 'ProcessDiskIO',
'UID', 'GID', 'PID', 'PPID', 'Uptime', 'Connection', 'Custom'],
'file' => ['Existence', 'FileChecksum', 'Timestamp', 'FileSize',
'FileContent', 'Permisssion', 'UID', 'GID', 'Custom'],
'fifo' => ['Existence', 'Timestamp', 'Permisssion', 'UID', 'GID', 'Custom'],
'filesystem' => ['Existence', 'FilesystemMountFlags',
'SpaceUsage', 'InodeUsage', 'DiskIO', 'Permisssion', 'Custom'],
'directory' => ['Existence', 'Timestamp', 'Permisssion', 'UID', 'GID', 'Custom'],
'host' => ['NetworkPing', 'Connection', 'Custom'],
'system' => ['SystemResource', 'Uptime', 'Custom'],
'custom' => ['ProgramStatus', 'Custom'],
'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' => []
];
/**
* {@inheritdoc}
*/
public function performValidation($validateFullModel = false)
{
// standard model validations
$messages = parent::performValidation($validateFullModel);
$all_nodes = $this->getFlatNodes();
foreach ($all_nodes as $key => $node) {
if ($validateFullModel || $node->isFieldChanged()) {
// the item container may have different validations attached.
$parentNode = $node->getParentNode();
// perform plugin specific validations
switch ($parentNode->getInternalXMLTagName()) {
case 'alert':
switch ($node->getInternalXMLTagName()) {
case 'noton':
case 'events':
if (!empty((string)$parentNode->noton) && empty((string)$parentNode->events)) {
$messages->appendMessage(new Message(
gettext("At least one event should be selected when using an inverted selection."),
$key
));
}
break;
}
break;
case 'test':
// test node validations
switch ($node->getInternalXMLTagName()) {
case 'type':
$testUuid = $parentNode->getAttribute('uuid');
if (
strcmp((string)$node, 'Custom') != 0 &&
$node->isFieldChanged() &&
$this->isTestServiceRelated($testUuid)
) {
$messages->appendMessage(new Message(
sprintf(
gettext("Cannot change the test type to '%s'. Test '%s' is linked to a service."),
(string)$node,
(string)$this->getNodeByReference('test.' . $parentNode->getAttribute('uuid'))->name
),
$key
));
}
break;
case 'condition':
// only 'Custom' or the same test type (see $conditionPatterns)
// are 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 Message(
sprintf(
gettext("Condition '%s' would change the type of the test '%s' but it is linked to a service."),
(string)$node,
(string)$this->getNodeByReference('test.' . $parentNode->getAttribute('uuid'))->name
),
$key
));
} else {
// set the test type according to the condition
$parentNode->type = $type;
}
break;
}
break;
case 'service':
// service node validations
switch ($node->getInternalXMLTagName()) {
case 'tests':
// test dependencies defined in $this->serviceTestMapping
foreach (explode(',', (string)$parentNode->tests) as $testUUID) {
$test = $this->getNodeByReference('test.' . $testUUID);
if ($test != null) {
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"),
(string)$test->name,
$test->type->getNodeData()[(string)$test->type]['value']
);
$messages->appendMessage(
new Message($validationMsg, $key)
);
}
}
}
}
break;
case 'pidfile':
if (
empty((string)$node) && (string)$parentNode->type == 'process'
&& empty((string)$parentNode->match)
) {
$messages->appendMessage(new Message(
gettext("Please set at least one of Pidfile or Match."),
$key
));
}
break;
case 'match':
if (
empty((string)$node) && (string)$parentNode->type == 'process'
&& empty((string)$parentNode->pidfile)
) {
$messages->appendMessage(new Message(
gettext("Please set at least one of Pidfile or Match."),
$key
));
}
break;
case 'address':
if (empty((string)$node) && (string)$parentNode->type == 'host') {
$messages->appendMessage(new Message(
gettext("Address is mandatory for 'Remote Host' checks."),
$key
));
} elseif (
empty((string)$node) && (string)$parentNode->type == 'network'
&& empty((string)$parentNode->interface)
) {
$messages->appendMessage(new Message(
gettext("Please set at least one of Address or Interface."),
$key
));
}
break;
case 'interface':
if (
empty((string)$node) && (string)$parentNode->type == 'network'
&& empty((string)$parentNode->address)
) {
$messages->appendMessage(new Message(
gettext("Please set at least one of Address or Interface."),
$key
));
}
break;
case 'path':
if (
empty((string)$node) && in_array(
(string)$parentNode->type,
['file', 'fifo', 'filesystem', 'directory']
)
) {
$messages->appendMessage(new Message(
gettext("Path is mandatory."),
$key
));
}
break;
}
break;
default:
break;
}
}
}
return $messages;
}
/**
* mark configuration as changed when data is pushed back to the config
*/
public function serializeToConfig($validateFullModel = false, $disable_validation = false)
{
@touch("/tmp/monit.dirty");
return parent::serializeToConfig($validateFullModel, $disable_validation);
}
/**
* get configuration state
* @return bool
*/
public function configChanged()
{
return file_exists("/tmp/monit.dirty");
}
/**
* mark configuration as consistent with the running config
* @return bool
*/
public function configClean()
{
return @unlink("/tmp/monit.dirty");
}
/**
* determine if services have links to this test node
* @param string $testUUID uuid of the test node
* @return bool
*/
public function isTestServiceRelated($testUUID = null)
{
$serviceNodes = $this->service->getNodes();
foreach ($this->service->iterateItems() as $serviceNode) {
if (in_array($testUUID, explode(',', (string)$serviceNode->tests))) {
return true;
}
}
return false;
}
/**
* get test type from condition string
* @param string $condition 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;
}
}