Skip to content
Snippets Groups Projects

7911 update appmonitor client

Merged Hahn Axel (hahn) requested to merge 7911-update-appmonitor-client into master
24 files
+ 1443
177
Compare changes
  • Side-by-side
  • Inline
Files
24
<?php
require_once 'validateparam.class.php';
if (!defined('RESULT_OK')) {
define("RESULT_OK", 0);
@@ -36,24 +37,28 @@ if (!defined('RESULT_OK')) {
* --------------------------------------------------------------------------------<br>
* <br>
* --- HISTORY:<br>
* 2014-10-24 0.5 axel.hahn@iml.unibe.ch<br>
* 2015-04-08 0.9 axel.hahn@iml.unibe.ch added sochket test: checkPortTcp<br>
* 2018-06-29 0.24 axel.hahn@iml.unibe.ch add file and directory checks<br>
* 2018-07-17 0.42 axel.hahn@iml.unibe.ch add port on mysqli check<br>
* 2018-07-26 0.46 axel.hahn@iml.unibe.ch fix mysql connection check with empty port param<br>
* 2018-08-14 0.47 axel.hahn@iml.unibe.ch appmonitor client: use timeout of 5 sec for tcp socket connections<br>
* 2018-08-15 0.49 axel.hahn@iml.unibe.ch cert check: added flag to skip verification<br>
* 2018-08-23 0.50 axel.hahn@iml.unibe.ch replace mysqli connect with mysqli real connect (to use a timeout)<br>
* 2018-08-27 0.52 axel.hahn@iml.unibe.ch add pdo connect (starting with mysql)<br>
* 2018-11-05 0.58 axel.hahn@iml.unibe.ch additional flag in http check to show content<br>
* 2019-05-31 0.87 axel.hahn@iml.unibe.ch add timeout as param in connective checks (http, tcp, databases)<br>
* 2019-06-05 0.88 axel.hahn@iml.unibe.ch add plugins<br>
* 2021-10-28 0.93 axel.hahn@iml.unibe.ch add plugins<br>
* 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
* 2014-10-24 0.5 axel.hahn@iml.unibe.ch<br>
* 2015-04-08 0.9 axel.hahn@iml.unibe.ch added sochket test: checkPortTcp<br>
* 2018-06-29 0.24 axel.hahn@iml.unibe.ch add file and directory checks<br>
* 2018-07-17 0.42 axel.hahn@iml.unibe.ch add port on mysqli check<br>
* 2018-07-26 0.46 axel.hahn@iml.unibe.ch fix mysql connection check with empty port param<br>
* 2018-08-14 0.47 axel.hahn@iml.unibe.ch appmonitor client: use timeout of 5 sec for tcp socket connections<br>
* 2018-08-15 0.49 axel.hahn@iml.unibe.ch cert check: added flag to skip verification<br>
* 2018-08-23 0.50 axel.hahn@iml.unibe.ch replace mysqli connect with mysqli real connect (to use a timeout)<br>
* 2018-08-27 0.52 axel.hahn@iml.unibe.ch add pdo connect (starting with mysql)<br>
* 2018-11-05 0.58 axel.hahn@iml.unibe.ch additional flag in http check to show content<br>
* 2019-05-31 0.87 axel.hahn@iml.unibe.ch add timeout as param in connective checks (http, tcp, databases)<br>
* 2019-06-05 0.88 axel.hahn@iml.unibe.ch add plugins<br>
* 2021-10-28 0.93 axel.hahn@iml.unibe.ch add plugins<br>
* 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"
. "<pre>INPUT " . print_r($aConfig, true) . '</pre>'
. "<pre>RESPONSE " . print_r($aResponse, true) . '</pre>'
$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>',
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
);
}
Loading