Skip to content
Snippets Groups Projects
Commit 88dfc9ef authored by Hahn Axel (hahn)'s avatar Hahn Axel (hahn)
Browse files

Merge branch 'update-appmonitor' into 'master'

7911 - update appmonitor client

See merge request !4
parents 14df0c21 f7bd113a
Branches
No related tags found
1 merge request!47911 - update appmonitor client
Showing
with 1306 additions and 170 deletions
<?php
require_once 'validateparam.class.php';
if (!defined('RESULT_OK')) {
define("RESULT_OK", 0);
......@@ -52,8 +53,12 @@ if (!defined('RESULT_OK')) {
* 2021-12-14 0.93 axel.hahn@iml.unibe.ch split plugins into single files; added key group in a check<br>
* 2023-06-02 0.125 axel.hahn@unibe.ch replace array_key_exists for better readability
* 2024-07-22 0.137 axel.hahn@unibe.ch php 8 only: use typed variables
* 2025-02-28 0.152 axel.hahn@unibe.ch listChecks: add loop over currently loaded classes
* 2025-03-03 0.153 axel.hahn@unibe.ch getSize() preg_replace did not work in compiled binary
* 2025-03-04 0.154 axel.hahn@unibe.ch finish with existcode instead of die()
* 2025-03-18 0.156 axel.hahn@unibe.ch add validation class
* --------------------------------------------------------------------------------<br>
* @version 0.137
* @version 0.156-dev
* @author Axel Hahn
* @link TODO
* @license GPL
......@@ -66,6 +71,47 @@ class appmonitorcheck
// CONFIG
// ----------------------------------------------------------------------
protected array $_aCheckDocs = [
'name' => [
'type' => 'string',
'required' => true,
'description' => 'Name of a check',
'regex'=>'/./',
'example' => 'configfile',
],
'description' => [
'type' => 'string',
'required' => true,
'description' => 'A short description to describe what is tested',
'regex'=>'/./',
'example' => 'Check if config file inc_config.php exists, is readable and writable',
],
'check' => [
'type' => 'array',
'required' => true,
'description' => 'Array of the check',
],
'parent' => [
'type' => 'string',
'required' => false,
'description' => 'Reference a \'name\' of another check to generate a dependency tree',
'regex'=>'/./',
],
'group' => [
'type' => 'string',
'required' => false,
'description' => 'Name of a group to be nedsted in',
'regex'=>'/./',
],
'worstresult' => [
'type' => 'int',
'required' => false,
'description' => 'A failed check is max counted as given result. Use it on not required but optional checks',
'min'=>RESULT_OK,
'max'=>RESULT_ERROR,
],
];
/**
* starting time using microtime
* @var float
......@@ -118,6 +164,25 @@ class appmonitorcheck
// PRIVATE FUNCTIONS
// ----------------------------------------------------------------------
/**
* Exit execution with error message and given exicode.
* @param int $iHttpcode http statuscode
* @param string $sMessage detailed message
* @param int $iExitcode exitcode
* @return never
*/
protected function _exit($iHttpcode, $sMessage, $iExitcode): never
{
$aStatus=[
503 => 'Service Unavailable',
];
header("HTTP/1.1 $iHttpcode $aStatus[$iHttpcode]");
echo "<h1>$iHttpcode $aStatus[$iHttpcode]</h1>
<h2>Details</h2>
$sMessage\n";
exit($iExitcode);
}
/**
* Internal: create basic array values for metadata
* @return boolean
......@@ -195,36 +260,52 @@ class appmonitorcheck
/**
* Check a given array if it contains wanted keys
* @param array $aConfig array to verify
* @param string $sKeyList key or keys as comma seprated list
* @param string $sMustKeys key or keys as comma seprated list
* @return boolean
*/
protected function _checkArrayKeys($aConfig, $sKeyList)
protected function _checkArrayKeys($aConfig, $sMustKeys, $sOptionalKeys = '')
{
foreach (explode(",", $sKeyList) as $sKey) {
$aTmp=$aConfig;
foreach (explode(",", $sMustKeys) as $sKey) {
if (!isset($aConfig[$sKey])) {
header('HTTP/1.0 503 Service Unavailable');
die('<h1>503 Service Unavailable</h1>'
. '<h2>Details</h2>'
. __METHOD__ . " - array of check parameters requires the keys [$sKeyList] - but key <code>$sKey</code> was not found in config array."
. "<pre>" . print_r($aConfig, true) . '</pre>'
$this->_exit(
503,
__METHOD__ . " - array of check parameters requires the keys [$sMustKeys] - but key <code>$sKey</code> was not found in config array."
. "<pre>" . print_r($aConfig, true) . '</pre>',
20
);
}
if (is_null($aConfig[$sKey])) {
header('HTTP/1.0 503 Service Unavailable');
die('<h1>503 Service Unavailable</h1>'
. '<h2>Details</h2>'
. __METHOD__ . " - key <code>$sKey</code> is empty in config array"
. "<pre>" . print_r($aConfig, true) . '</pre>'
$this->_exit(
503,
__METHOD__ . " - key <code>$sKey</code> is empty in config array"
. "<pre>" . print_r($aConfig, true) . '</pre>',
21
);
}
unset($aTmp[$sKey]);
}
return true;
}
// ----------------------------------------------------------------------
// PUBLIC FUNCTIONS
// ----------------------------------------------------------------------
/**
* Self documentation of a check. The array is defined in
* plugins/checks/*.php files
*
* @return array
*/
public function explain(): array
{
return $this->_aDoc??[];
}
/**
* Perform a check
* @param array $aConfig configuration array for a check, eg.
......@@ -237,6 +318,9 @@ class appmonitorcheck
* [params] => [array] // optional; arguments for Check function
* // its keys depend on the function
* ]
* [group] => Group A
* [parent] => field "name" of another check
* [worstresult] => RESULT_WARNING
* ]
* </code>
* @return array
......@@ -244,8 +328,24 @@ class appmonitorcheck
public function makeCheck(array $aConfig): array
{
$this->_iStart = microtime(true);
$this->_checkArrayKeys($aConfig, "name,description,check");
$this->_checkArrayKeys($aConfig["check"], "function");
$oVal=new validateparam();
$aErrors=$oVal->validateArray($this->_aCheckDocs, $aConfig);
if(count($aErrors)){
$this->_exit(
503,
__METHOD__ . " - validation of params failed\n"
. "<pre>Errors: "
. print_r($aErrors, true)
. "Input array was: "
. print_r($aConfig, true)
. '</pre>',
22
);
}
$this->_checkArrayKeys($aConfig, "name,description,check", "group,parent,worstresult", true);
$this->_checkArrayKeys($aConfig["check"], "function", "params", true);
$this->_aConfig = $aConfig;
$this->_createDefaultMetadata();
......@@ -264,33 +364,49 @@ class appmonitorcheck
}
if (!class_exists($sCheckClass)) {
header('HTTP/1.0 503 Service Unavailable');
die('<h1>503 Service Unavailable</h1>'
. '<h2>Details</h2>'
. __METHOD__ . " - check class not found: <code>$sCheckClass</code>"
. "<pre>" . print_r($aConfig, true) . '</pre>'
. "<h2>Known checks</h2>\n" . print_r($this->listChecks(), 1)
$this->_exit(
503,
__METHOD__ . " - [$aConfig[name]] - check class not found: <code>$sCheckClass</code>"
. "<pre>" . print_r($aConfig, true) . '</pre>',
22
);
}
$oPlugin = new $sCheckClass;
$aCheckDoc=$oPlugin->explain();
$aErrors=$oVal->validateArray($oPlugin->explain()['parameters']??[], $aParams);
if(count($aErrors)){
$this->_exit(
503,
__METHOD__ . " - [$aConfig[name]] - validation of check -> params failed\n"
. "<pre>Errors: "
. print_r($aErrors, true)
. "Input array: "
. print_r($aConfig, true)
. '</pre>',
22
);
}
// die(__FILE__.":".__LINE__);
$aResponse = $oPlugin->run($aParams);
if (!is_array($aResponse)) {
header('HTTP/1.0 503 Service Unavailable');
die('<h1>503 Service Unavailable</h1>'
. '<h2>Details</h2>'
. __METHOD__ . " - plugin : $sCheck does not responses an array"
$this->_exit(
503,
__METHOD__ . " - plugin : $sCheck does not responses an array"
. "<pre>INPUT " . print_r($aConfig, true) . '</pre>'
. "<pre>RESPONSE " . print_r($aResponse, true) . '</pre>'
. "<pre>RESPONSE " . print_r($aResponse, true) . '</pre>',
23
);
}
if (count($aResponse) < 2) {
header('HTTP/1.0 503 Service Unavailable');
die('<h1>503 Service Unavailable</h1>'
. '<h2>Details</h2>'
. __METHOD__ . " - plugin : $sCheck does not responses the minimum of 2 array values"
$this->_exit(
503,
__METHOD__ . " - plugin : $sCheck does not responses the minimum of 2 array values"
. "<pre>INPUT " . print_r($aConfig, true) . '</pre>'
. "<pre>RESPONSE " . print_r($aResponse, true) . '</pre>'
. "<pre>RESPONSE " . print_r($aResponse, true) . '</pre>',
24
);
}
if (!isset($aResponse[2]) || !$aResponse[2]) {
......@@ -315,6 +431,8 @@ class appmonitorcheck
public function listChecks(): array
{
$aReturn = [];
// **DEPRECATED**
// return internal protected fuctions named "check[whatever]"
$class = new ReflectionClass($this);
foreach ($class->getMethods(ReflectionMethod::IS_PROTECTED) as $oReflectionMethod) {
......@@ -326,6 +444,15 @@ class appmonitorcheck
foreach (glob($this->_sPluginDir . '/checks/*.php') as $sPluginFile) {
$aReturn[str_replace('.php', '', basename($sPluginFile))] = 1;
}
// from currently loaded classes
foreach(get_declared_classes() as $sClass){
if (strpos($sClass, "check") === 0) {
$aReturn[str_replace('check','',$sClass)] = 1;
}
}
array_unique($aReturn);
ksort($aReturn);
return array_keys($aReturn);
}
......@@ -406,17 +533,18 @@ class appmonitorcheck
$power = 0;
foreach ($this->_units as $sUnit) {
if (preg_match('/^[0-9\.\ ]*' . $sUnit . '/', $sValue)) {
$i = preg_replace('/([0-9\.]*).*/', '$1', $sValue);
// $i = preg_replace('/([0-9\.]*).*/', '$1', $sValue);
$i = str_replace($sUnit, '', $sValue);
$iReal = $i * pow(1024, $power);
// die("FOUND: $sValue with unit ${sUnit} - 1024^$power * $i = $iReal");
return $iReal;
}
$power++;
}
header('HTTP/1.0 503 Service Unavailable');
die('<h1>503 Service Unavailable</h1>'
. '<h2>Details</h2>'
. __METHOD__ . " ERROR in space value parameter - there is no size unit in [$sValue] - allowed size units are " . implode('|', $this->_units)
$this->_exit(
503,
__METHOD__ . " ERROR in space value parameter - there is no size unit in [$sValue] - allowed size units are " . implode('|', $this->_units),
25
);
}
......
......@@ -44,8 +44,12 @@ if (!class_exists('appmonitorcheck')) {
* 2024-07-19 0.137 axel.hahn@unibe.ch php 8 only: use typed variables
* 2024-11-22 0.141 axel.hahn@unibe.ch Set client version to server version after updating http, mysqli and app checks
* 2025-01-02 0.149 axel.hahn@unibe.ch add getChecks method
* 2025-03-03 0.153 axel.hahn@unibe.ch fix client checks during development of a compiled binary
* 2025-03-04 0.154 axel.hahn@unibe.ch finish with exitcode instead of die()
* 2025-03-17 0.155 axel.hahn@unibe.ch added: getVersion() and setVersion()
* 2025-03-19 0.156 axel.hahn@unibe.ch added: validation rules for parameters in all checks
* --------------------------------------------------------------------------------<br>
* @version 0.149
* @version 0.155
* @author Axel Hahn
* @link TODO
* @license GPL
......@@ -59,7 +63,7 @@ class appmonitor
* Name and Version number
* @var string
*/
protected string $_sVersion = 'php-client-v0.149';
protected string $_sVersion = '0.156';
/**
* config: default ttl for server before requesting the client check again
......@@ -119,13 +123,14 @@ class appmonitor
"ttl" => false,
"result" => false,
"time" => false,
"version" => $this->_sVersion,
"version" => false,
];
// fill with default values
$this->setHost();
$this->setWebsite();
$this->setTTL();
$this->setVersion();
return true;
}
......@@ -151,28 +156,19 @@ class appmonitor
$this->_aMeta["host"] = $s;
return true;
}
/**
* Set a name for this website or application and its environment
* (dev, test, prod);
*
* If you have several application in subdirectories, i.e. /blog, /shop...
* then you should the path or any description to identify them too
*
* if no argument is given the name of HTTP_HOST will be used
* Set final result in meta data; if no value was given then it
* sets the biggest value of any check.
*
* @param string $sWebsite Name of the website or web application
* @param integer $iResult set resultcode; one of RESULT_OK|RESULT_WARNING|RESULT_ERROR|RESULT_UNKNOWN
* @return boolean
*/
public function setWebsite($sWebsite = ''): bool
public function setResult(int $iResult = -1): bool
{
if (!$sWebsite && isset($_SERVER["HTTP_HOST"])) {
$sWebsite = $_SERVER["HTTP_HOST"];
}
if (!$sWebsite) {
return false;
if ($iResult === -1) {
$iResult = $this->_iMaxResult; // see addCheck()
}
$this->_aMeta["website"] = $sWebsite;
$this->_aMeta["result"] = $iResult;
return true;
}
......@@ -192,18 +188,38 @@ class appmonitor
}
/**
* Set final result in meta data; if no value was given then it
* sets the biggest value of any check.
* Set a prefix for meta -> version ... before "-php-client-v<VERSION>"
* @param string $sVersionPrefix new prefix
* @return bool
*/
public function setVersion($sVersionPrefix = ""): bool
{
$this->_aMeta["version"] = ($sVersionPrefix ? "$sVersionPrefix-" : "")
. "php-client-v$this->_sVersion"
;
return true;
}
/**
* Set a name for this website or application and its environment
* (dev, test, prod);
*
* @param integer $iResult set resultcode; one of RESULT_OK|RESULT_WARNING|RESULT_ERROR|RESULT_UNKNOWN
* If you have several application in subdirectories, i.e. /blog, /shop...
* then you should the path or any description to identify them too
*
* if no argument is given the name of HTTP_HOST will be used
*
* @param string $sWebsite Name of the website or web application
* @return boolean
*/
public function setResult(int $iResult = -1): bool
public function setWebsite($sWebsite = ''): bool
{
if ($iResult === -1) {
$iResult = $this->_iMaxResult; // see addCheck()
if (!$sWebsite && isset($_SERVER["HTTP_HOST"])) {
$sWebsite = $_SERVER["HTTP_HOST"];
}
$this->_aMeta["result"] = $iResult;
if (!$sWebsite) {
return false;
}
$this->_aMeta["website"] = $sWebsite;
return true;
}
......@@ -318,8 +334,11 @@ class appmonitor
return true;
}
}
header('HTTP/1.0 403 Forbidden');
die('ERROR: Your ip address [' . $sIP . '] has no access.');
$this->_exit(
403,
'ERROR: Your ip address [' . $sIP . '] has no access.',
11
);
}
/**
......@@ -339,14 +358,26 @@ class appmonitor
if (isset($_GET[$sVarname]) && $_GET[$sVarname] === $sToken) {
return true;
}
header('HTTP/1.0 403 Forbidden');
die('ERROR: A token is required.');
$this->_exit(
403,
'ERROR: A token is required.',
12
);
}
// ----------------------------------------------------------------------
// getter
// ----------------------------------------------------------------------
/**
* Get version of the appmoinitor php client
* @return string
*/
public function getVersion(): string
{
return $this->_sVersion;
}
/**
* list all available check functions. This is a helper class you cann call
* to get an overview over built in functions. You get a flat array with
......@@ -381,9 +412,11 @@ class appmonitor
}
if (count($aErrors)) {
$this->abort(
'<h2>Error: client check is not complete</h2><p>Found errors:</p><ol><li>' . implode('<li>', $aErrors) . '</ol><br><br>'
// .'Dump of your data so far:<pre>' . json_encode($this->getResults(), JSON_PRETTY_PRINT) . '</pre><hr>'
$this->_exit(
503,
'Client check is not complete<br>Found errors:<br>'
. '<ol><li>' . implode('<li>', $aErrors) . '</ol><br><br>',
10
);
}
return true;
......@@ -394,14 +427,24 @@ class appmonitor
// ----------------------------------------------------------------------
/**
* Stop processing the client checks and abort with an error
* @param string $sMessage text to show after a 503 headline
* @return void
* Exit execution with error message and given exicode.
* @param int $iHttpcode http statuscode
* @param string $sMessage detailed message
* @param int $iExitcode exitcode
* @return never
*/
public function abort(string $sMessage): void
protected function _exit($iHttpcode, $sMessage, $iExitcode): never
{
header('HTTP/1.0 503 Service Unavailable');
die('<h1>503 Service Unavailable</h1>' . $sMessage);
$aStatus = [
403 => 'Forbidden',
503 => 'Service Unavailable',
];
header("HTTP/1.1 $iHttpcode $aStatus[$iHttpcode]");
echo "<h1>$iHttpcode $aStatus[$iHttpcode]</h1>
<h2>Details</h2>
$sMessage\n";
exit($iExitcode);
}
/**
......
<?php
class validateparam
{
/**
* Summary of _aValidationDefs
* @var array
*/
protected array $_aValidationDefs = [];
protected bool $_flag_debug = false;
/**
* Write debug line if _flag_debug is set to true
* @param string $s message to show
* @return void
*/
protected function _wd(string $s)
{
if ($this->_flag_debug) {
echo "DEBUG: $s<br>\n";
}
}
/**
* Include the default validation rules defined in validateparam.settings.php
*/
public function __construct(){
// IMPORTANT:
// This style is not so nice like <variable> = include <file>;
// keep the include line unchanged - it is detected by installer
// CLI client project (amcli)
include 'validateparam.settings.php';
}
/**
* shared validaten checks for floor and integer
*
* @param array $aOpt Validation rules
* @param mixed $value value to verify
* @return string with found error
*/
protected function _checkCount(array $aOpt, mixed $value)
{
$sError = "";
if ($aOpt['min'] ?? false) {
if ($value < $aOpt['min']) {
$sError .= "Value is too small; minimum is $aOpt[min]. ";
}
}
if ($aOpt['max'] ?? false) {
if ($value > $aOpt['max']) {
$sError .= "Value is too big; maximum is $aOpt[max]. ";
}
}
if (isset($aOpt['oneof']) && is_array($aOpt['oneof'])) {
if (array_search($value, $aOpt['oneof']) == false) {
$sError .= "Value is invalid. Value doesn't match one of these values " . print_r($aOpt['oneof']);
}
}
return $sError;
}
/**
* Validate a single value. It returns a string with an errormessage.
* No error means ok.
*
* @param array $aOpt Validation rules
* @param mixed $value value to verify
* @return string with found error
*/
public function validateValue(array $aOpt, mixed $value): string
{
$sError = '';
if (isset($aOpt['validate'])){
if ($this->_aValidationDefs[$aOpt['validate']] ?? false) {
$this->_wd("adding options ".print_r($this->_aValidationDefs[$aOpt['validate']],true));
$aOpt = array_merge($aOpt, $this->_aValidationDefs[$aOpt['validate']]);
} else {
$sError .= "Unknown value in 'validate'='$aOpt[validate]'";
}
}
// check type
if (isset($aOpt['type'])) {
$this->_wd("check type $aOpt[type]");
switch ($aOpt['type']) {
case 'array':
if (!is_array($value)) {
$sError .= "Value isn't an array";
}
break;
case 'bool':
if (!is_bool($value)) {
$sError .= "Value '$value' isn't a bool";
}
break;
case 'float':
if (!is_float($value) && !is_int($value)) {
$sError .= "Value isn't a float";
} else {
$sError .= $this->_checkCount($aOpt, $value);
}
break;
case 'int':
case 'integer':
if (!is_int($value)) {
$sError .= "Value '$value' isn't an integer";
} else {
$sError .= $this->_checkCount($aOpt, $value);
}
break;
case 'string':
if (!is_string($value)) {
$sError .= "Value '$value' isn't a string";
} else {
if ($aOpt['regex'] ?? false) {
if (!preg_match($aOpt['regex'], $value)) {
$sError .= "Value is invalid. Regex doesn't match: $aOpt[regex]";
}
}
if (isset($aOpt['oneof']) && is_array($aOpt['oneof'])) {
if (array_search($value, $aOpt['oneof']) == false) {
$sError .= "Value is invalid. Value doesn't match one of these values " . print_r($aOpt['oneof']);
}
}
}
break;
default:
$sError .= "ERROR Cannot validate unknown type: '$aOpt[type]'<br>\n";
}
}
// if string: verify regex
return $sError;
}
/**
* Validate an array of parameter definitions. It returns an array of all error messages
* No error / an empty array means ok.
*
* @param mixed $aDefs array with definitions
* @param mixed $aParams array of given values
* @param mixed $bStrict flag: strict checking to detect wrong keys.
* @return array with errors
*/
public function validateArray(array $aDefs, array $aParams, bool $bStrict = true)
{
$aErrors = [];
// echo "<pre>";
// echo "aDefs = "; print_r($aDefs);
// echo "aParams = "; print_r($aParams);
// echo "<hr>";
if (!count($aDefs)) {
return ['Defs' => 'No validation rules given.'];
}
$aTmp = $aParams;
foreach ($aDefs as $sKey => $aOpt) {
unset($aTmp[$sKey]);
if ($aOpt['required'] ?? false) {
$this->_wd("Check MUST $sKey");
// verify MUST field
if (!isset($aParams[$sKey])) {
$aErrors[$sKey] = "Missing required key '$sKey'";
} else {
$this->_wd("MUST field exists: $sKey");
$sError = $this->validateValue($aOpt, $aParams[$sKey]);
if ($sError) {
$aErrors[$sKey] = $sError;
} else {
$this->_wd("$sKey was successfully validated.<hr>");
}
}
}
if (isset($aOpt['required']) && !$aOpt['required'] && isset($aParams[$sKey])) {
$this->_wd("Check OPTIONAL $sKey");
$sError = $this->validateValue($aOpt, $aParams[$sKey]);
if ($sError) {
$aErrors[$sKey] = $sError;
}
}
}
if ($bStrict && isset($aTmp) && count($aTmp)) {
foreach (array_keys($aTmp) as $sKey) {
$aErrors[$sKey] = "Invalid key was found: '$sKey'; allowed keys are '" . implode("', '", array_keys($aDefs ?? [])) . "'";
}
}
$this->_wd("found errors: " . print_r($aErrors, 1));
return $aErrors;
}
}
\ No newline at end of file
# validateparam.class.php
## Description
This class can validate values and arrays.
You define type and validateion rules. A validation method checks the given value against your rules. It returns the error message(s). No error means, the value is ok.
## Usage
```php
$oVal=new validateparam();
// check an array
$aErrors=$oVal->validateArray($aRules, $aGivenValues, $bStrict);
if(count($aErrors)){
echo "Something is wrong: <pre>".print_r($aErrors, 1)."</pre>";
exit(1);
}
```
## Validate Arrays
First something visual - an example:
```txt
Array
(
[name] => Array
(
[type] => string
[required] => true
[regex] => /./
)
[description] => Array
(
[type] => string
[required] => true
[regex] => /./
)
:
[worstresult] => Array
(
'type' => 'int',
'required' => false,
'description' => 'A failed check is max counted as given result. Use it on not required but optional checks',
'min'=>RESULT_OK,
'max'=>RESULT_ERROR,
)
)
```
### Type check
Each key can be marked to be a value of a given type.
It can be a mandantory value or optional.
| Name | Type | Description
|-- |-- |--
| 'type' | {string} | variable type that must match; one of "array", "bool", "count", "float", "int", "integer", "string"
| 'required' | {bool} | define value as required
Next to these keys per type you can define validation rules in dependency of the type.
### Validate numbers
This section describes values of the `type`
* int|integer - integer values
* float - float values (or integer)
Values you can verify if it is in a wanted range.
| Name | Type | Description
|-- |-- |--
| 'min' | {float\|int} | allowed minimum value
| 'max' | {float\|int} | allowed maximum value
| 'oneof' | {array} | value must match one of the given values
### Validate string
Values of type "string" can be verified
* against a given regex
* with a set of allowed values
| Name | Type | Description
|-- |-- |--
| 'regex' | {string} | value must match given regex
| 'oneof' | {array} | value must match one of the given values
### Validate with presets
In the file *validateparam.settings.php* you can put presets and their validation rules for elements that repeat.
```php
<?php
/*
validation rules
if a param has the key 'validate' that matches a key then its values will
be added for validation.
SYNTAX
KEY - value for'validate' key
VALUE - array with these possible keys
- type - set a type
- regex - define a regex for type sting
- min, max - range for types float and int
- oneof
*/
return [
'hostname' => [ 'type' => 'string', 'regex' => '/^[a-z0-9\_\-\.]/i'],
'portnumber' => [ 'type' => 'int', 'min' => 0, 'max' => 65535],
'website' => [ 'type' => 'string', 'regex' => '/https?:\/\//'],
];
```
```txt
[port] => Array
(
[type] => int
[required] => true
[validate] => portnumber
)
```
<?php
/*
validation rules
if a param has the key 'validate' that matches a key then its values will
be added for validation.
This file is included in the constructor of the validateparam class
SYNTAX:
KEY - value for'validate' key
VALUE - array with these possible keys
- type - set a type
- regex - define a regex for type sting
- min, max - range for types float and int
- oneof
*/
$this->_aValidationDefs = [
'hostname' => [ 'type' => 'string', 'regex' => '/^[a-z0-9\_\-\.]/i'],
'portnumber' => [ 'type' => 'int', 'min' => 0, 'max' => 65535],
'website' => [ 'type' => 'string', 'regex' => '/https?:\/\//'],
];
<?php
/*
validation rules
if a param has the key 'validate' that matches a key then its values will
be added for validation.
SYNTAX
KEY - value for'validate' key
VALUE - array with these possible keys
- type - set a type
- regex - define a regex for type sting
- min, max - range for types float and int
- oneof
*/
$this->_aValidationDefs = [
'hostname' => [ 'type' => 'string', 'regex' => '/^[a-z0-9\_\-\.]/i'],
'portnumber' => [ 'type' => 'int', 'min' => 0, 'max' => 65535],
'website' => [ 'type' => 'string', 'regex' => '/https?:\/\//'],
];
......@@ -14,6 +14,7 @@
* 2022-03-28 move checks into plugins/apps/
* 2024-07-23 php 8: short array syntax
* 2024-12-28 added check for custom config and url file (if they exist)
* 2025-02-24 add checks for sqlite and data dir
*/
// ----------------------------------------------------------------------
......@@ -28,7 +29,7 @@ $oMonitor->addCheck(
"check" => [
"function" => "Phpmodules",
"params" => [
"required" => ["curl"],
"required" => ["curl", "json", "pdo_sqlite"],
"optional" => [],
],
],
......@@ -123,6 +124,22 @@ if (is_file("$sApproot/server/config/appmonitor-server-urls.json")) {
);
}
$oMonitor->addCheck(
[
"name" => "write to ./data/",
"description" => "Check sqlite data directory",
// "group" => "folder",
"check" => [
"function" => "File",
"params" => [
"filename" => "$sApproot/server/data",
"dir" => true,
"writable" => true,
],
],
]
);
// ----------------------------------------------------------------------
// protect dirs against web access
// specialty: if the test results in an error, the total result switches
......@@ -132,7 +149,7 @@ $sBaseUrl = 'http' . (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] ? 's' : '')
. '://' . $_SERVER['SERVER_NAME'] . ':' . $_SERVER['SERVER_PORT']
. dirname(dirname($_SERVER['REQUEST_URI']));
foreach (['server/config', 'server/tmp'] as $sMyDir) {
foreach (['server/config', 'server/data', 'server/tmp'] as $sMyDir) {
$oMonitor->addCheck(
[
"name" => "http to $sMyDir",
......@@ -154,14 +171,58 @@ foreach (['server/config', 'server/tmp'] as $sMyDir) {
// count of current projects
// ----------------------------------------------------------------------
require_once($sApproot . '/server/classes/appmonitor-server.class.php');
$oServer = new appmonitorserver();
$oServer = new appmonitorserver(false);
$aCfg=$oServer->getConfigVars();
$oMonitor->addCheck(
[
"name" => "db-config",
"description" => "Check if the service is running",
// "group" => "service",
"parent" => "check custom config file",
"check" => [
"function" => "Simple",
"params" => [
"result" => ($aCfg['db']['dsn'] ? RESULT_OK : RESULT_ERROR),
"value" => ($aCfg['db']['dsn']
? "OK: dsn was set"
:"Error: database dsn was not found in config."
)
],
]
]
);
if($aCfg['db']['dsn']){
$aDB=[
'connect'=>$aCfg['db']['dsn'] ?? '',
'user'=>$aCfg['db']['user'] ?? '',
'password'=> $aCfg['db']['password'] ?? ''
];
// print_r($aDB);
$oMonitor->addCheck(
[
"name" => "connect db",
"description" => "Connnect PDO database",
"group" => "database",
"parent" => "db-config",
"check" => [
"function" => "PdoConnect",
"params" => $aDB
],
]
);
}
$iCount = count($oServer->getAppIds());
$oMonitor->addCheck(
[
"name" => "appcounter",
"description" => "Monitored apps",
"group" => "monitor",
"parent" => false,
"parent" => null,
"check" => [
"function" => "Simple",
"params" => [
......@@ -173,6 +234,7 @@ $oMonitor->addCheck(
],
]
);
// ----------------------------------------------------------------------
// check running service
// ----------------------------------------------------------------------
......@@ -211,7 +273,7 @@ $oMonitor->addCheck(
"name" => "plugin Load",
"description" => "current load",
"group" => 'monitor',
"parent" => false,
"parent" => null,
"check" => [
"function" => "Loadmeter",
"params" => [
......
......@@ -64,8 +64,10 @@ $aDb = [
// checks
// ----------------------------------------------------------------------
// required php modules
// see https://ertano.com/required-php-modules-for-wordpress/
// required php modules * WIP
// see https://wordpress.org/about/requirements/ << doesn't say anything about php modules
// see https://ertano.com/rired-php-modules-for-wordpress/ << too many modules
// see https://zeropointdevelopment.com/required-php-extensions-for-wordpress-wpquickies/
$oMonitor->addCheck(
[
"name" => "PHP modules",
......@@ -76,22 +78,24 @@ $oMonitor->addCheck(
"params" => [
"required" => [
// "cmath",
"cli",
// "cli",
"curl",
"date",
"dom",
"fileinfo",
"filter",
"gd",
// "filter",
// "gd",
"gettext",
"hash",
"iconv",
// "iconv",
"imagick",
"json",
// "libsodium",
"mysql",
"mbstring",
"mysqli",
"openssl",
"pcre",
"sodium",
// "opcache",
// "readline",
"xml",
......
......@@ -45,7 +45,8 @@
* 2019-06-07 <axel.hahn@iml.unibe.ch>
* 2022-07-06 <axel.hahn@iml.unibe.ch> set group "monitor"
* 2024-07-23 <axel.hahn@unibe.ch> php 8 only: use typed variables
*
* 2025-03-04 <axel.hahn@unibe.ch> fix sComment error on failed apache status
* 2025-03-19 <axel.hahn@unibe.ch> add validation rules and parameter description
*/
class checkApacheProcesses extends appmonitorcheck
{
......@@ -69,39 +70,37 @@ class checkApacheProcesses extends appmonitorcheck
protected float $_iError = 75;
/**
* Self documentation (as idea)
* @return array
* Self documentation and validation rules
* @var array
*/
public function explain(): array
{
return [
protected array $_aDoc = [
'name' => 'Plugin ApacheProcesses',
'descriptionm' => 'Check count running Apache processes',
'description' => 'Check count running Apache processes',
'parameters' => [
'url' => [
'type' => 'string',
'required' => false,
'decsription' => 'Override https server-status page; default is http://localhost/server-status; Use it if the protocol to localhost is not http, but https or if it requires an authentication',
'default' => $this->_sServerStatusUrl,
'description' => 'Override https server-status page; default is http://localhost/server-status; Use it if the protocol to localhost is not http, but https or if it requires an authentication',
'default' => "http://localhost/server-status",
'regex'=>'/^https?:\/\/[^\s]+/',
'example' => '',
],
'warning' => [
'type' => 'float',
'required' => false,
'decsription' => 'Limit to switch to warning (in percent)',
'default' => $this->_iWarn,
'description' => 'Limit to switch to warning (in percent)',
'default' => "50",
'example' => 30,
],
'error' => [
'type' => 'float',
'required' => false,
'decsription' => 'Limit to switch to critical (in percent)',
'default' => $this->_iError,
'description' => 'Limit to switch to critical (in percent)',
'default' => "75",
'example' => 50,
],
],
];
}
/**
* Fetch http server status and return slots, active and waiting processes
......@@ -112,7 +111,7 @@ class checkApacheProcesses extends appmonitorcheck
*/
protected function _getApacheProcesses(): bool|array
{
$sBody = file_get_contents($this->_sServerStatusUrl);
$sBody = @file_get_contents($this->_sServerStatusUrl);
if (!$sBody) {
return false;
}
......@@ -163,12 +162,12 @@ class checkApacheProcesses extends appmonitorcheck
// --- (2) do something magic
$aProcesses = $this->_getApacheProcesses();
$iActive = $aProcesses ? $aProcesses['active'] : false;
$sComment = '';
// set result code
if ($iActive === false) {
$iResult = RESULT_UNKNOWN;
} else {
$sComment = '';
$iTotal = $aProcesses['total'];
$iResult = RESULT_OK;
if (($iActive / $iTotal * 100) > $this->_iWarn) {
......
......@@ -40,10 +40,52 @@
* 2022-05-02 <axel.hahn@iml.unibe.ch> set warning to 21 days (old value was 30); add "critical" param
* 2022-05-03 <axel.hahn@iml.unibe.ch> critical limit is a warning only (because app is still functional)
* 2024-07-23 <axel.hahn@unibe.ch> php 8 only: use typed variables
*
* 2025-03-03 <axel.hahn@unibe.ch> comment block for host check in DND names
* 2025-03-19 <axel.hahn@unibe.ch> add validation rules and parameter description
*/
class checkCert extends appmonitorcheck
{
/**
* Self documentation and validation rules
* @var array
*/
protected array $_aDoc = [
'name' => 'Plugin Cert',
'description' => 'Check if a SSL certificate is still valid … and does not expire soon.',
'parameters' => [
'url' => [
'type' => 'string',
'required' => true,
'description' => 'Url to check https://[server}[:{port}] or ssl://[server}[:{port}]',
'default' => null,
'regex'=>'/^(https|ssl):\/\/[^\s]+/',
'example' => '',
],
'verify' => [
'type' => 'bool',
'required' => false,
'description' => 'optional: flag verify certificate; default = true',
'default' => true,
'example' => "false",
],
'warning' => [
'type' => 'int',
'required' => false,
'description' => 'optional: count of days to warn; default=21',
'default' => 21,
'example' => 30,
],
'critical' => [
'type' => 'int',
'required' => false,
'description' => 'optional: count of days to raise critical; default=5',
'default' => 5,
'example' => "7",
],
],
];
/**
* Get default group of this check
* @return string
......@@ -80,6 +122,11 @@ class checkCert extends appmonitorcheck
];
}
/*
unneeded:
when verify is true (=default) then it cannot connect with wrong certificate
$sDNS = $certinfo['extensions']['subjectAltName'] ?? false;
$sHost = parse_url($sUrl, PHP_URL_HOST);
if (strstr($sDNS, "DNS:$sHost") === false) {
......@@ -88,6 +135,7 @@ class checkCert extends appmonitorcheck
"Wrong certificate: $sHost is not listed as DNS alias in [$sDNS]. $sMessage"
];
}
*/
$iDaysleft = round(($certinfo['validTo_time_t'] - date('U')) / 60 / 60 / 24);
$sMessage .= 'Issuer: ' . $certinfo['issuer']['O']
......
......@@ -20,9 +20,44 @@
* 2021-10-26 <axel.hahn@iml.unibe.ch>
* 2024-07-23 <axel.hahn@unibe.ch> php 8 only: use typed variables
* 2025-01-02 <www.axel-hahn.de> update output
* 2025-03-19 <axel.hahn@unibe.ch> add validation rules and parameter description
*/
class checkDiskfree extends appmonitorcheck
{
/**
* Self documentation and validation rules
* @var array
*/
protected array $_aDoc = [
'name' => 'Plugin Diskfree',
'description' => 'Check if a given filesystem / directory that it has enough space.',
'parameters' => [
'directory' => [
'type' => 'string',
'required' => true,
'description' => 'directory to check',
'default' => null,
'regex'=>'/./',
'example' => '',
],
'warning' => [
'type' => 'string',
'required' => false,
'description' => 'size for warning level',
'default' => 21,
'example' => "1.25GB",
],
'critical' => [
'type' => 'string',
'required' => true,
'description' => 'size for critical level',
'default' => 5,
'example' => "500.7MB",
],
],
];
/**
* Get default group of this check
* @return string
......
......@@ -21,10 +21,58 @@
*
* 2022-09-19 <axel.hahn@iml.unibe.ch>
* 2024-07-23 <axel.hahn@unibe.ch> php 8 only: use typed variables
*
* 2025-03-19 <axel.hahn@unibe.ch> add validation rules and parameter description
*/
class checkExec extends appmonitorcheck
{
/**
* Self documentation and validation rules
* @var array
*/
protected array $_aDoc = [
'name' => 'Plugin Exec',
'description' => 'Execute a shell command.',
'parameters' => [
'command' => [
'type' => 'string',
'required' => true,
'description' => 'Command line',
'default' => null,
'regex'=>'/./',
'example' => '[command] [parameters] 2>&1',
],
'output' => [
'type' => 'bool',
'required' => false,
'description' => 'size for warning level',
'default' => 21,
'example' => "1.25GB",
],
'exitOk' => [
'type' => 'array',
'required' => false,
'description' => 'array of integers for ok exitcodes',
'default' => null,
'example' => "",
],
'exitWarn' => [
'type' => 'array',
'required' => false,
'description' => 'array of integers for warning exitcodes',
'default' => null,
'example' => "",
],
'exitCritical' => [
'type' => 'array',
'required' => false,
'description' => 'array of integers for critical exitcodes',
'default' => null,
'example' => "",
],
],
];
/**
* Get default group of this check
* @return string
......
......@@ -22,9 +22,79 @@
*
* 2021-10-26 <axel.hahn@iml.unibe.ch>
* 2024-07-23 <axel.hahn@unibe.ch> php 8 only: use typed variables
* 2025-03-01 <axel.hahn@unibe.ch> fix check for files that must be absent
* 2025-03-19 <axel.hahn@unibe.ch> add validation rules and parameter description
*/
class checkFile extends appmonitorcheck
{
/**
* Self documentation and validation rules
* @var array
*/
protected array $_aDoc = [
'name' => 'Plugin File',
'description' => 'Check existing or absent file objects: files, directories, softlinks',
'parameters' => [
'filename' => [
'type' => 'string',
'required' => true,
'description' => 'filename or directory to check',
'default' => "",
'regex' => '/./',
'example' => '/var/www/myfile.txt',
],
'exists' => [
'type' => 'bool',
'required' => false,
'description' => 'true = file object must exist (default); false = file object must not exist',
'default' => true,
'example' => "true",
],
'dir' => [
'type' => 'bool',
'required' => false,
'description' => 'If true then check if fileobject is a directory',
'default' => null,
'example' => "false",
],
'file' => [
'type' => 'bool',
'required' => false,
'description' => 'If true then check if fileobject is a file',
'default' => null,
'example' => "true",
],
'link' => [
'type' => 'bool',
'required' => false,
'description' => 'If true then check if fileobject is a file',
'default' => null,
'example' => "true",
],
'executable' => [
'type' => 'bool',
'required' => false,
'description' => 'If true then check if fileobject has executable permissions; if false it must be not executable',
'default' => null,
'example' => "false",
],
'readable' => [
'type' => 'bool',
'required' => false,
'description' => 'If true then check if fileobject is readable; if false it must be not readable',
'default' => null,
'example' => "true",
],
'writable' => [
'type' => 'bool',
'required' => false,
'description' => 'If true then check if fileobject is writable; ; if false it must be not writable',
'default' => null,
'example' => "true",
],
],
];
/**
* Get default group of this check
* @param array $aParams - see run() method
......@@ -68,7 +138,10 @@ class checkFile extends appmonitorcheck
if (isset($aParams['exists'])) {
$sMyflag = 'exists=' . ($aParams['exists'] ? 'yes' : 'no');
if (file_exists($sFile) && $aParams['exists']) {
if (
file_exists($sFile) && $aParams['exists']
|| !file_exists($sFile) && !$aParams['exists']
) {
$aOK[] = $sMyflag;
} else {
$aErrors[] = $sMyflag;
......
......@@ -41,10 +41,28 @@
*
* 2019-06-05 <axel.hahn@iml.unibe.ch>
* 2024-07-23 <axel.hahn@unibe.ch> php 8 only: use typed variables
*
* 2025-03-19 <axel.hahn@unibe.ch> add validation rules and parameter description
*/
class checkHello extends appmonitorcheck
{
/**
* Self documentation and validation rules
* @var array
*/
protected array $_aDoc = [
'name' => 'Plugin Hello',
'description' => 'Show a simple message',
'parameters' => [
'message' => [
'type' => 'string',
'required' => true,
'description' => 'Message to show',
'default' => "",
'regex' => '/./',
'example' => 'Here I am',
],
],
];
/**
* Run the check
......
......@@ -22,9 +22,115 @@
* 2023-07-06 <axel.hahn@unibe.ch> add flag userpwd
* 2024-07-23 <axel.hahn@unibe.ch> php 8 only: use typed variables
* 2024-11-22 <axel.hahn@unibe.ch> Return unknown if curl module is not active
* 2025-03-17 <axel.hahn@unibe.ch> Fix check for http status code
* 2025-03-19 <axel.hahn@unibe.ch> add validation rules and parameter description
*/
class checkHttpContent extends appmonitorcheck
{
/**
* Self documentation and validation rules
* @var array
*/
protected array $_aDoc = [
'name' => 'Plugin HttpContent',
'description' => 'This check verifies if a given url can be requested. Optionally you can test if it follows wanted rules.',
'parameters' => [
'url' => [
'type' => 'string',
'required' => true,
'description' => 'Url to fetch',
'default' => "",
'regex' => '/https?:\/\//',
'example' => 'https://www.example.com/',
],
'userpwd' => [
'type' => 'string',
'required' => false,
'description' => 'User and password; syntax: “[username]:[password]”',
'regex' => '/.*:.*/',
'default' => "",
'example' => "myuser:aVerySecretPassword",
],
'timeout' => [
'type' => 'int',
'required' => false,
'description' => 'Timeout in sec',
'default' => 5,
'example' => "10",
],
'headeronly' => [
'type' => 'bool',
'required' => false,
'description' => 'flag to fetch http response herader only (HEAD request); default: false = returns header and body;',
'default' => false,
'example' => "true",
],
'follow' => [
'type' => 'bool',
'required' => false,
'description' => 'flag to follow a location; default: false = do not follow; If you set it to true it ries to follow (but this is not a safe method)',
'default' => false,
'example' => "true",
],
'sslverify' => [
'type' => 'bool',
'required' => false,
'description' => 'Enable/ disable verification of ssl certificate; default: true (verification is on)',
'default' => true,
'example' => "false",
],
'status' => [
'type' => 'int',
'required' => false,
'description' => 'Test for an expected http status code; if none is given then test fails on status 400 and greater.',
'default' => null,
'example' => "401",
],
'headercontains' => [
'type' => 'string',
'required' => false,
'description' => 'Test for a string in the http response header; it returns OK if the text was found',
'default' => null,
'example' => "Content-Type: text/css",
],
'headernotcontains' => [
'type' => 'string',
'required' => false,
'description' => 'Test for a string in the http response header; it returns OK if the text was not found',
'default' => null,
'example' => "Server:",
],
'headerregex' => [
'type' => 'string',
'required' => false,
'description' => 'Test for a regex in the http response header; it returns OK if the regex matches',
'default' => null,
'example' => "",
],
'bodycontains' => [
'type' => 'string',
'required' => false,
'description' => 'Test for a string in the http response body; it returns OK if the text was found',
'default' => null,
'example' => "Content-Type: text/css",
],
'bodynotcontains' => [
'type' => 'string',
'required' => false,
'description' => 'Test for a string in the http response body; it returns OK if the text was not found',
'default' => null,
'example' => "Server:",
],
'bodyregex' => [
'type' => 'string',
'required' => false,
'description' => 'Test for a regex in the http response body; it returns OK if the regex matches',
'default' => null,
'example' => "",
],
],
];
/**
* Get default group of this check
* It is a "service" icon or "deny" for expected failures
......@@ -67,7 +173,7 @@ class checkHttpContent extends appmonitorcheck
{
$this->_checkArrayKeys($aParams, "url");
if (!function_exists("curl_init")) {
return [RESULT_UNKNOWN, "UNKNOWN: Unable to perform mysqli test. The php-curl module is not active."];
return [RESULT_UNKNOWN, "UNKNOWN: Unable to perform http test. The php-curl module is not active."];
}
$bShowContent = (isset($aParams["content"]) && $aParams["content"]) ? true : false;
$ch = curl_init($aParams["url"]);
......@@ -141,12 +247,12 @@ class checkHttpContent extends appmonitorcheck
// ---------- check functions
// --- http status code
$sOut .= "Http status: " . $aInfos['http_code'] . " - ";
$sOut .= "Http status: $aInfos[http_code] - ";
if (isset($aParams["status"])) {
if ($aInfos['http_code'] === $aParams["status"]) {
$sOut .= "compare OK<br>";
if ($aInfos['http_code'] == $aParams["status"]) {
$sOut .= "as expected - OK<br>";
} else {
$sOut .= "compare failed<br>";
$sOut .= "compare failed - not eaqual $aParams[status]<br>";
$bError = true;
}
} else {
......@@ -159,7 +265,7 @@ class checkHttpContent extends appmonitorcheck
}
// --- http header
if (isset($aParams["headercontains"]) && $aParams["headercontains"]) {
$sOut .= "Http header contains &quot;" . $aParams["headercontains"] . "&quot; - ";
$sOut .= "Http header contains '$aParams[headercontains]' - ";
if (!strstr($sHttpHeader, $aParams["headercontains"]) === false) {
$sOut .= "compare OK<br>";
} else {
......@@ -168,7 +274,7 @@ class checkHttpContent extends appmonitorcheck
}
}
if (isset($aParams["headernotcontains"]) && $aParams["headernotcontains"]) {
$sOut .= "Http header does not contain &quot;" . $aParams["headernotcontains"] . "&quot; - ";
$sOut .= "Http header does not contain '$aParams[headernotcontains]' - ";
if (strstr($sHttpHeader, $aParams["headernotcontains"]) === false) {
$sOut .= "compare OK<br>";
} else {
......@@ -177,7 +283,7 @@ class checkHttpContent extends appmonitorcheck
}
}
if (isset($aParams["headerregex"]) && $aParams["headerregex"]) {
$sOut .= "Http header regex test &quot;" . $aParams["headerregex"] . "&quot; - ";
$sOut .= "Http header regex test '$aParams[headerregex]' - ";
try {
$bRegex = preg_match($aParams["headerregex"], $sHttpHeader);
if ($bRegex) {
......@@ -193,7 +299,7 @@ class checkHttpContent extends appmonitorcheck
}
// --- http body
if (isset($aParams["bodycontains"]) && $aParams["bodycontains"]) {
$sOut .= "Http body contains &quot;" . $aParams["bodycontains"] . "&quot; - ";
$sOut .= "Http body contains '$aParams[bodycontains]' - ";
if (!strstr($sHttpBody, $aParams["bodycontains"]) === false) {
$sOut .= "compare OK<br>";
} else {
......@@ -202,7 +308,7 @@ class checkHttpContent extends appmonitorcheck
}
}
if (isset($aParams["bodynotcontains"]) && $aParams["bodynotcontains"]) {
$sOut .= "Http body does not contain &quot;" . $aParams["bodynotcontains"] . "&quot; - ";
$sOut .= "Http body does not contain '$aParams[bodynotcontains]' - ";
if (strstr($sHttpBody, $aParams["bodynotcontains"]) === false) {
$sOut .= "compare OK<br>";
} else {
......@@ -211,7 +317,7 @@ class checkHttpContent extends appmonitorcheck
}
}
if (isset($aParams["bodyregex"]) && $aParams["bodyregex"]) {
$sOut .= "Http body regex test &quot;" . $aParams["bodyregex"] . "&quot; - ";
$sOut .= "Http body regex test '$aParams[bodyregex]' - ";
try {
$bRegex = preg_match($aParams["bodyregex"], $sHttpBody);
if ($bRegex) {
......@@ -229,12 +335,12 @@ class checkHttpContent extends appmonitorcheck
if (!$bError) {
return [
RESULT_OK,
'OK: http check "' . $aParams["url"] . '".<br>' . $sOut
"OK: http check '$aParams[url]'<br>$sOut"
];
} else {
return [
RESULT_ERROR,
'ERROR: http check "' . $aParams["url"] . '".<br>' . $sOut
"ERROR: http check '$aParams[url]'<br>$sOut"
];
}
......
......@@ -45,10 +45,37 @@
* 2019-06-06 <axel.hahn@iml.unibe.ch>
* 2024-07-23 <axel.hahn@unibe.ch> php 8 only: use typed variables
* 2024-07-25 <axel.hahn@unibe.ch> float return with 2 digits behind comma
*
* 2025-03-19 <axel.hahn@unibe.ch> add validation rules and parameter description
*/
class checkLoadmeter extends appmonitorcheck
{
/**
* Self documentation and validation rules
* @var array
*/
protected array $_aDoc = [
'name' => 'Plugin Loadmeter',
'description' => 'Get system load and render it as a tile.',
'parameters' => [
'warning' => [
'type' => 'float',
'required' => false,
'description' => 'Warning level',
// doc
'default' => null,
'example' => '1.5',
],
'error' => [
'type' => 'float',
'required' => false,
'description' => 'Critical level when to raise an error',
'default' => null,
'example' => '2.5',
],
],
];
/**
* Get default group of this check
* @return string
......
......@@ -20,9 +20,70 @@
* 2021-10-27 <axel.hahn@iml.unibe.ch>
* 2024-07-23 <axel.hahn@unibe.ch> php 8 only: use typed variables
* 2024-11-22 <axel.hahn@unibe.ch> detect installed mysqli function
* 2025-03-01 <axel.hahn@unibe.ch> add try catch
* 2025-03-19 <axel.hahn@unibe.ch> add validation rules and parameter description
*/
class checkMysqlConnect extends appmonitorcheck
{
/**
* Self documentation and validation rules
* @var array
*/
protected array $_aDoc = [
'name' => 'Plugin Mysqlconnect',
'description' => 'Verify a database connection with mysqli real connect function.',
'parameters' => [
'server' => [
'type' => 'string',
'required' => true,
'description' => 'Hostname/ ip of mysql server',
'validate' => 'hostname',
// doc
'default' => null,
'example' => 'localhost',
],
'port' => [
'type' => 'int',
'required' => false,
'description' => 'port of mysql server',
'validate' => 'portnumber',
'default' => 5,
'example' => '3',
],
'user' => [
'type' => 'string',
'required' => false,
'description' => 'Database user to connect with',
'default' => null,
'example' => 'dbuser',
],
'password' => [
'type' => 'string',
'required' => false,
'description' => 'Password of the database user to authenticate',
'default' => null,
'example' => 'mySecretDatabasePassword',
],
'db' => [
'type' => 'string',
'required' => false,
'description' => 'Database name to connect',
'default' => null,
'example' => 'wordpress',
],
'timeout' => [
'type' => 'float',
'required' => false,
'description' => 'Timeout in sec',
'default' => 5,
'example' => '3',
],
],
];
/**
* Get default group of this check
* @return string
......@@ -59,6 +120,8 @@ class checkMysqlConnect extends appmonitorcheck
return [RESULT_ERROR, 'ERROR: setting mysqli_options failed.'];
}
try{
$db = (isset($aParams["port"]) && $aParams["port"])
? $mysqli->real_connect($aParams["server"], $aParams["user"], $aParams["password"], $aParams["db"], $aParams["port"])
: $mysqli->real_connect($aParams["server"], $aParams["user"], $aParams["password"], $aParams["db"])
......@@ -72,5 +135,11 @@ class checkMysqlConnect extends appmonitorcheck
"ERROR: Mysql database " . $aParams["db"] . " was not connected. Error " . mysqli_connect_errno() . ": " . mysqli_connect_error()
];
}
} catch (Exception $e) {
return [
RESULT_ERROR,
"ERROR: Mysql database " . $aParams["db"] . " was not connected. Error " . mysqli_connect_errno() . ": " . mysqli_connect_error()
];
}
}
}
......@@ -19,10 +19,52 @@
*
* 2021-10-27 <axel.hahn@iml.unibe.ch>
* 2024-07-23 <axel.hahn@unibe.ch> php 8 only: use typed variables
*
* 2025-03-19 <axel.hahn@unibe.ch> add validation rules and parameter description
*/
class checkPdoConnect extends appmonitorcheck
{
/**
* Self documentation and validation rules
* @var array
*/
protected array $_aDoc = [
'name' => 'Plugin PdoConnect',
'description' => 'Verify a database connection with PDO connect',
'parameters' => [
'connect' => [
'type' => 'string',
'required' => true,
'description' => 'PDO conect string. See http://php.net/manual/en/pdo.drivers.php',
// doc
'default' => null,
'example' => 'mysql:host=$aDb[server];port=3306;dbname=$aDb[database]',
],
'user' => [
'type' => 'string',
'required' => false,
'description' => 'Database user to connect with',
'default' => null,
'example' => 'dbuser',
],
'password' => [
'type' => 'string',
'required' => false,
'description' => 'Password of the database user to authenticate',
'default' => null,
'example' => 'mySecretDatabasePassword',
],
'timeout' => [
'type' => 'float',
'required' => false,
'description' => 'Timeout in sec',
'default' => 5,
'example' => '3',
],
],
];
/**
* Get default group of this check
* @return string
......@@ -31,6 +73,7 @@ class checkPdoConnect extends appmonitorcheck
{
return 'database';
}
/**
* Check connection to a database using pdo
* see http://php.net/manual/en/pdo.drivers.php
......
......@@ -19,10 +19,37 @@
*
* 2022-05-06 <axel.hahn@iml.unibe.ch> first lines
* 2024-07-23 <axel.hahn@unibe.ch> php 8 only: use typed variables
*
* 2025-03-19 <axel.hahn@unibe.ch> add validation rules and parameter description
*/
class checkPhpmodules extends appmonitorcheck
{
/**
* Self documentation and validation rules
* @var array
*/
protected array $_aDoc = [
'name' => 'Plugin Phpmodules',
'description' => 'Check loaded php modules',
'parameters' => [
'required' => [
'type' => 'array',
'required' => true,
'description' => 'List of php modules that are required',
// doc
'default' => [],
'example' => '["curl", "PDO"]',
],
'optional' => [
'type' => 'array',
'required' => false,
'description' => 'List of php modules that are optional. If one is missing, the status is set to warning.',
'default' => [],
'example' => '["gd"]',
],
],
];
/**
* Get default group of this check
* @return string
......
......@@ -21,9 +21,32 @@
* 2022-09-16 <axel.hahn@iml.unibe.ch> read error before closing socket.
* 2022-11-22 <axel.hahn@iml.unibe.ch> Use exec with detecting MS Win for the ping parameter for count of pings
* 2024-07-23 <axel.hahn@unibe.ch> php 8 only: use typed variables
* 2025-03-19 <axel.hahn@unibe.ch> add validation rules and parameter description
*/
class checkPing extends appmonitorcheck
{
/**
* Self documentation and validation rules
* @var array
*/
protected array $_aDoc = [
'name' => 'Plugin Ping',
'description' => 'Check if a given host can be pinged.',
'parameters' => [
'host' => [
'type' => 'string',
'required' => false,
'description' => 'Hostname to ping; default: 127.0.0.1',
'regex' => '/^[a-z0-9\_\-\.]/i',
// doc
'default' => "127.0.0.1",
'example' => 'www.example.com',
],
],
];
/**
* Get default group of this check
* @return string
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment