diff --git a/public_html/appmonitor/appmonitor-checks.class.php b/public_html/appmonitor/appmonitor-checks.class.php new file mode 100644 index 0000000000000000000000000000000000000000..f5f8b84f40fbc279196c2afbc89b6620fd7edda8 --- /dev/null +++ b/public_html/appmonitor/appmonitor-checks.class.php @@ -0,0 +1,306 @@ +<?php + +define("RESULT_OK", 0); +define("RESULT_WARNING", 1); +define("RESULT_ERROR", 2); +define("RESULT_UNKNOWN", 255); +/** + * APPMONITOR CLIENT CHECKS<br> + * <br> + * THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE <br> + * LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR <br> + * OTHER PARTIES PROVIDE THE PROGRAM ?AS IS? WITHOUT WARRANTY OF ANY KIND, <br> + * EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED <br> + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE <br> + * ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. <br> + * SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY <br> + * SERVICING, REPAIR OR CORRECTION.<br> + * <br> + * --------------------------------------------------------------------------------<br> + * <br> + * --- HISTORY:<br> + * 2014-10-24 0.5 axel.hahn@iml.unibe.ch<br> + * --------------------------------------------------------------------------------<br> + * @version 0.5 + * @author Axel Hahn + * @link TODO + * @license GPL + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL 3.0 + * @package IML-Appmonitor + */ +class appmonitorcheck { + + // ---------------------------------------------------------------------- + // CONFIG + // ---------------------------------------------------------------------- + + /** + * config container + * @var array + */ + private $_aConfig = array(); + + /** + * data of all checks + * @var array + */ + private $_aData = array(); + + // ---------------------------------------------------------------------- + // CONSTRUCTOR + // ---------------------------------------------------------------------- + + /** + * constructor (nothing) + */ + public function __construct() { + + } + + // ---------------------------------------------------------------------- + // PRIVATE FUNCTIONS + // ---------------------------------------------------------------------- + + /** + * create basic array values for metadata + * @return boolean + */ + private function _createDefaultMetadata() { + + $this->_aData = array( + "name" => $this->_aConfig["name"], + "description" => $this->_aConfig["description"], + "result" => RESULT_UNKNOWN, + "value" => false, + ); + return true; + } + + /** + * set a result value of a check + * @param type $iResult + * @return type + */ + private function _setResult($iResult) { + return $this->_aData["result"] = (int) $iResult; + } + + /** + * set a result value of a check + * @param type $iResult + * @return type + */ + private function _setOutput($s) { + return $this->_aData["value"] = (string) $s; + } + + /** + * set result and output + * @param type $iResult + * @param type $s + * @return boolean + */ + private function _setReturn($iResult, $s) { + $this->_setResult($iResult); + $this->_setOutput($s); + return true; + } + + private function _checkArrayKeys($aConfig, $sKeyList) { + foreach (explode(",", $sKeyList) as $sKey) { + if (!array_key_exists($sKey, $aConfig)) { + die('ERROR in ' . __CLASS__ . "<br>array requires the keys [$sKeyList] - but key '$sKey' was not found in config array <pre>" . print_r($aConfig, true)); + } + if (is_null($aConfig[$sKey])) { + die('ERROR in ' . __CLASS__ . "<br> key '$sKey' is empty in config array <pre>" . print_r($aConfig, true)); + } + } + return true; + } + + // ---------------------------------------------------------------------- + // PUBLIC FUNCTIONS + // ---------------------------------------------------------------------- + + /** + * perform a check + * @param type $aConfig + * Array + * ( + * [name] => Dummy + * [description] => Dummy Test + * [check] => array( + * [function] => [check function] // i.e. Simple + * [params] => [array] // optional; arguments for Check function + * // its keys depend on the function + * ) + * ) + * + * @return array + */ + public function makeCheck($aConfig) { + $this->_checkArrayKeys($aConfig, "name,description,check"); + $this->_checkArrayKeys($aConfig["check"], "function"); + + $this->_aConfig = $aConfig; + $this->_createDefaultMetadata(); + + $sCheck = "check" . $this->_aConfig["check"]["function"]; + if (!method_exists($this, $sCheck)) { + die(__CLASS__ . " check not found: $sCheck <pre>" . print_r($aConfig, true)); + } + $aParams = array_key_exists("params", $this->_aConfig["check"]) ? $this->_aConfig["check"]["params"] : array(); + + // call the check ... + call_user_func(array($this, $sCheck), $aParams); + + // echo "<pre>"; print_r($this->listChecks()); die(); + // ... and send response + return $this->respond(); + } + + /** + * list all available check functions. This is a helper class you cann call + * to get an overview overbuilt in functions. You get a flat array with + * all function names. + * @return array + */ + public function listChecks() { + $aReturn = array(); + $class = new ReflectionClass($this); + foreach ($class->getMethods(ReflectionMethod::IS_PRIVATE) as $oReflectionMethod) { + if (strpos($oReflectionMethod->name, "check") === 0) { + $aReturn[] = (string) $oReflectionMethod->name; + } + } + return $aReturn; + } + + /** + * final call of class: send response (data array) + * @return type + */ + public function respond() { + return $this->_aData; + } + + // ---------------------------------------------------------------------- + // CHECK FUNCTIONS (private) + // ---------------------------------------------------------------------- + + /** + * most simple check: set values + * @return type + */ + private function checkSimple($aParams) { + $aHelp = array( + "result" => "(integer) result value", + "value" => "(string) explaination" + ); + $this->_checkArrayKeys($aParams, "result,value"); + return $this->_setReturn((int) $aParams["result"], $aParams["value"]); + } + + /** + * make http request and test response body + * @param array $aParams + * array( + * "url" url to fetch + * "contains" string that must exist in response body + * ) + */ + private function checkHttpContent($aParams, $iTimeout = 5) { + $this->_checkArrayKeys($aParams, "url,contains"); + if (!function_exists("curl_init")) { + die("ERROR: PHP CURL module is not installed."); + } + $ch = curl_init($aParams["url"]); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); + curl_setopt($ch, CURLOPT_TIMEOUT, $iTimeout); + $res = curl_exec($ch); + curl_close($ch); + + if (!$res) { + $this->_setReturn(RESULT_ERROR, 'ERROR: failed to fetch ' . $aParams["url"] . '.'); + } else { + if (!strpos($res, $aParams["contains"]) === false) { + $this->_setReturn(RESULT_OK, 'OK: The text "' . $aParams["contains"] . '" was found in response of ' . $aParams["url"] . '.'); + } else { + $this->_setReturn(RESULT_ERROR, 'ERROR: The text ' . $aParams["contains"] . ' was NOT found in response of ' . $aParams["url"] . '.'); + } + } + return $res; + } + + /** + * check mysql connection to a database + * @param array $aParams + * array( + * "server" + * "user" + * "password" + * "db" + * ) + */ + private function checkMysqlConnect($aParams) { + $this->_checkArrayKeys($aParams, "server,user,password,db"); + $db = mysqli_connect( + $aParams["server"], $aParams["user"], $aParams["password"], $aParams["db"] + ); + if ($db) { + $this->_setReturn(RESULT_OK, "OK: Mysql database " . $aParams["db"] . " was connected"); + return true; + } else { + $this->_setReturn(RESULT_ERROR, "ERROR: Mysql database " . $aParams["db"] . " was not connected. " . mysqli_connect_error()); + return false; + } + } + + /** + * check sqlite connection + * @param array $aParams + * array( + * "db" + * ) + * @return boolean + */ + private function checkSqliteConnect($aParams) { + $this->_checkArrayKeys($aParams, "db"); + if (!file_exists($aParams["db"])) { + $this->_setReturn(RESULT_ERROR, "ERROR: Sqlite database file " . $aParams["db"] . " does not exist."); + return false; + } + try { + // $db = new SQLite3($sqliteDB); + // $db = new PDO("sqlite:".$sqliteDB); + $o = new PDO("sqlite:" . $aParams["db"]); + $this->_setReturn(RESULT_OK, "OK: Sqlite database " . $aParams["db"] . " was connected"); + return true; + } catch (Exception $exc) { + $this->_setReturn(RESULT_ERROR, "ERROR: Sqlite database " . $aParams["db"] . " was not connected. " . mysqli_connect_error()); + return false; + } + } + + /** + * check if system is listening to a given port + * @param array $aParams + * array( + * "port" + * ) + * @return boolean + */ + private function checkListeningIp($aParams) { + $this->_checkArrayKeys($aParams, "port"); + $sResult = exec('netstat -tulen | grep ":' . $aParams["port"] . ' "'); + if ($sResult) { + $this->_setReturn(RESULT_OK, "OK: Port " . $aParams["port"] . " was found: " . $sResult); + return true; + } else { + $this->_setReturn(RESULT_ERROR, "ERROR: Port " . $aParams["port"] . " is not in use."); + return false; + } + } + +} diff --git a/public_html/appmonitor/appmonitor-client.class.php b/public_html/appmonitor/appmonitor-client.class.php new file mode 100644 index 0000000000000000000000000000000000000000..a468e240963accd75c6efde22e52419b5a6355b4 --- /dev/null +++ b/public_html/appmonitor/appmonitor-client.class.php @@ -0,0 +1,287 @@ +<?php +/** + * APPMONITOR CLIENT<br> + * <br> + * THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE <br> + * LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR <br> + * OTHER PARTIES PROVIDE THE PROGRAM ?AS IS? WITHOUT WARRANTY OF ANY KIND, <br> + * EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED <br> + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE <br> + * ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. <br> + * SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY <br> + * SERVICING, REPAIR OR CORRECTION.<br> + * <br> + * --------------------------------------------------------------------------------<br> + * <br> + * --- HISTORY:<br> + * 2014-10-24 0.5 axel.hahn@iml.unibe.ch<br> + * --------------------------------------------------------------------------------<br> + * @version 0.5 + * @author Axel Hahn + * @link TODO + * @license GPL + * @license http://www.gnu.org/licenses/gpl-3.0.html GPL 3.0 + * @package IML-Appmonitor + */ +class appmonitor { + + /** + * config: default ttl for server before requesting the client check again + * value is in seconds + * @var int + */ + private $_iDefaultTtl = 300; + + /** + * internal counter: greatest return value of all checks + * @var type + */ + private $_iMaxResult = false; + + /** + * responded metadata of a website + * @see _createDefaultMetadata() + * @var array + */ + private $_aMeta = array(); + + /** + * repended array of all checks + * @see addCheck() + * @var array + */ + private $_aChecks = array(); + + /** + * @var array + */ + private $_aMustKeysChecks = array("name", "description", "result", "value"); + + /** + * constructor: init data + */ + public function __construct() { + $this->_createDefaultMetadata(); + } + + // ---------------------------------------------------------------------- + // private function + // ---------------------------------------------------------------------- + + /** + * create basic array values for metadata + * @return boolean + */ + private function _createDefaultMetadata() { + $this->_aMeta = array( + "host" => false, + "website" => false, + "ttl" => false, + "ts" => (int) date("U"), + "result" => false + ); + + // fill with default values + $this->setHost(); + $this->setWebsite(); + $this->setTTL(); + + return true; + } + + // ---------------------------------------------------------------------- + // setter + // ---------------------------------------------------------------------- + + /** + * set a host for metadata + * @param string $s hostname + * @return bool + */ + public function setHost($s = false) { + if (!$s) { + $s = php_uname("n"); + } + return $this->_aMeta["host"] = $s; + } + + /** + * set a vhost for metadata + * @param string $sNewHost hostname + * @return bool + */ + public function setWebsite($s = false) { + if (!$s) { + $s = $_SERVER["HTTP_HOST"]; + } + return $this->_aMeta["website"] = $s; + } + + /** + * set a ttl value for + * @param int $iTTl TTL value in sec + * @return boolean + */ + public function setTTL($iTTl = false) { + if (!$iTTl) { + $iTTl = $this->_iDefaultTtl; + } + return $this->_aMeta["ttl"] = $iTTl; + } + + /** + * set final result in meta data; if no value was given then it + * sets the biggest value of any check. + * @param integer $iResult set resultcode + * @return boolean + */ + public function setResult($iResult = false) { + if ($iResult === false) { + $iResult = $this->_iMaxResult; // see addCheck() + } + return $this->_aMeta["result"] = $iResult; + } + + /** + * add a check array; + * @param type $aJob + * @return type + */ + public function addCheck($aJob = array()) { + + require_once 'appmonitor-checks.class.php'; + $oCheck = new appmonitorcheck(); + // print_r($aJob); die(); + $aCheck = $oCheck->makecheck($aJob); + + if (!$this->_iMaxResult || $aCheck["result"] > $this->_iMaxResult) { + $this->_iMaxResult = $aCheck["result"]; + } + return $this->_aChecks[] = $aCheck; + } + + // ---------------------------------------------------------------------- + // getter + // ---------------------------------------------------------------------- + + /** + * list all available check functions. This is a helper class you cann call + * to get an overview overbuilt in functions. You get a flat array with + * all function names. + * @return array + */ + public function listChecks() { + require_once 'appmonitor-checks.class.php'; + $oCheck = new appmonitorcheck(); + return $oCheck->listChecks(); + } + + // ---------------------------------------------------------------------- + // checks + // ---------------------------------------------------------------------- + + /** + * verify array values and abort with all found errors + */ + private function _checkData() { + $aErrors = array(); + + if (!count($this->_aChecks)) { + $aErrors[] = "No checks have been defined."; + } + + if ($this->_aMeta["result"] === false) { + $aErrors[] = "method setResult was not used to set a final result for all checks."; + } + + + if (count($aErrors)) { + echo "<h1>Errors detected</h1><ol><li>" . implode("<li>", $aErrors) . "</ol><hr>"; + echo "<pre>" . print_r($this->_generateOutputArray(), true) . "</pre><hr>"; + die("ABORT"); + } + } + + // ---------------------------------------------------------------------- + // output + // ---------------------------------------------------------------------- + + /** + * get full array for response with metadata and Checks + * @return type + */ + private function _generateOutputArray() { + return array( + "meta" => $this->_aMeta, + "checks" => $this->_aChecks, + ); + } + + /** + * output appmonitor values as JSON + * @param bool $bPretty turn on pretty print; default is false + * @param bool $bHighlight print syntax highlighted html code; $bPretty must be true to enable + */ + public function render($bPretty = false, $bHighlight = false) { + $this->_checkData(); + + // JSON_PRETTY_PRINT reqires PHP 5.4 + if (!defined('JSON_PRETTY_PRINT')) { + $bPretty=false; + } + if (!$bPretty) { + $bHighlight=false; + $sOut = json_encode($this->_generateOutputArray()); + } else { + $sOut = json_encode($this->_generateOutputArray(), JSON_PRETTY_PRINT); + if ($bHighlight) { + $aMsg=array( + 0=>"OK", + 1=>"WARNING", + 2=>"ERROR", + 255=>"UNKNOWN" + ); + foreach(array_keys($aMsg) as $iCode){ + $sOut = preg_replace('/(\"result\":\ '.$iCode.')/', '$1 <span class="result'.$iCode.'"> <--- '.$aMsg[$iCode].' </span>', $sOut); + } + + $sOut = preg_replace('/:\ \"(.*)\"/U', ': "<span style="color:#66e;">$1</span>"', $sOut); + $sOut = preg_replace('/:\ ([0-9]*)/', ': <span style="color:#3a3; font-weight: bold;">$1</span>', $sOut); + $sOut = preg_replace('/\"(.*)\":/U', '"<span style="color:#e90;">$1</span>":', $sOut); + + $sOut = preg_replace('/([{\[])/', '$1<blockquote>', $sOut); + $sOut = preg_replace('/([}\]])/', '</blockquote>$1', $sOut); + $sOut = str_replace(' ', '', $sOut); + // $sOut = preg_replace('/([{}])/', '<span style="color:#a00; ">$1</span>', $sOut); + // $sOut = preg_replace('/([\[\]])/', '<span style="color:#088; ">$1</span>', $sOut); + + $sOut = '<!DOCTYPE html><html><head>' + . '<style>' + . 'body{background:#282830; color:#9ac; font-family: verdana,arial;}' + . 'blockquote{background:rgba(215,180,255,0.03); border-left: 5px solid #222; margin-top: 0; padding: 0; ;}' + . 'blockquote blockquote:hover{border-color: #345; }' + . 'blockquote blockquote blockquote:hover{border-color: #808;}' + . 'pre{background:#222; padding: 1em; border-radius: 1em;}' + . '.result0{background:#080; border-right: 1em solid #0f0;}' + . '.result1{background:#860; border-right: 1em solid #fc0;}' + . '.result2{background:#800; border-right: 1em solid #f00;}' + . '.result255{background:#666; border-right: 1em solid #ccc;}' + . '</style>' + . '<title>'.__CLASS__.'</title>' + . '</head><body>' + . '<h1>'.__CLASS__.' :: debug</h1>' + . '<pre>' + . $sOut + . '</pre></body></html>'; + } + } + if (!$bHighlight) { + header('Content-type: application/json'); + header('Cache-Control: cache'); + header('max-age: ' . $this->_aMeta["ttl"]); + } + echo $sOut; + return $sOut; + } + +} diff --git a/public_html/appmonitor/index.php b/public_html/appmonitor/index.php new file mode 100644 index 0000000000000000000000000000000000000000..303c2c67b7dae7cd8aa51e05a7fab0394e989734 --- /dev/null +++ b/public_html/appmonitor/index.php @@ -0,0 +1,41 @@ +<?php + +require_once('appmonitor-client.class.php'); +$oMonitor = new appmonitor(); + +$oMonitor->addCheck( + array( + "name" => "simple", + "description" => "Very simple test", + "check" => array( + "function" => "Simple", + "params" => array( + "result" => 0, + "value" => "The appmonitor client is reachable.", + ), + ), + ) +); + + +require_once '../../config/inc_projects_config.php'; +$sSqlitefile=$aConfig['dataDir'].'/database/logs.db'; +$oMonitor->addCheck( + array( + "name" => "Sqlite DB for action logs", + "description" => "Connect sqlite db ". basename($sSqlitefile), + "check" => array( + "function" => "SqliteConnect", + "params" => array( + "db"=>$sSqlitefile + ), + ), + ) +); + + +// Gesamt-Ergebnis - ohne Param=aut. max. Wert nehmen +$oMonitor->setResult(); + +// Ausgabe +$oMonitor->render();