From e9890596a05ec8a2235ec8e77d80ebfaa786e775 Mon Sep 17 00:00:00 2001 From: "Hahn Axel (hahn)" <axel.hahn@unibe.ch> Date: Fri, 28 Feb 2025 16:57:25 +0100 Subject: [PATCH] update base files --- .gitignore | 1 + TODO.md | 42 +++++++++++ build.php | 32 ++++++--- inc_functions.php | 172 ++++++++++++++++++++++++++++++++++++++++++++-- installer.php | 54 +++++++++++---- src/amcli.php | 29 +++++--- src/simple.ini | 5 +- 7 files changed, 293 insertions(+), 42 deletions(-) create mode 100644 TODO.md diff --git a/.gitignore b/.gitignore index c81286c..ce6d634 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ built_packages/ external/ build src/include_checks.php +src/amcli.php.tmp diff --git a/TODO.md b/TODO.md new file mode 100644 index 0000000..ccd91b2 --- /dev/null +++ b/TODO.md @@ -0,0 +1,42 @@ +# TODOs + +was ich so sehe ... + +✅ Slack-Notifikation: statt Parsing-mechanismus eines Strings --> JSON in der INI schreiben +✅ `--ini=<FILE>` bei relativem Pfad ist relativ zum Binary --> nicht ins eigene Verzeichnis wechseln +⬜ Dokumentation +⬜ Code aufräumen + +## Tests schreiben + +✅ Test auf gesetzte Metadaten +⬜ für alle Checks einen Test schreiben + + ⬜ ApacheProcesses + ✅ Cert + ✅ Diskfree + ✅ Exec + ⬜ File --> "exists": false meldet bei Test einer nicht existierenden Datei fälschlicherweise einen Fehler + ✅ Hello + ⬜ HttpContent + ⬜ Loadmeter + ⬜ MysqlConnect + ⬜ PdoConnect + ⬜ Phpmodules + ⬜ Ping + ⬜ PortTcp + ⬜ Simple + ⬜ SqliteConnect + +## Done + +✅ PHP compiliert zum Binary +✅ Binary startet in einem fremden Verzichnis +✅ Binary startet auf einen Nicht-PHP-System + +--- +Legende: + +⬜ +✅ +❌ diff --git a/build.php b/build.php index 51d5aae..4b993e5 100755 --- a/build.php +++ b/build.php @@ -7,6 +7,8 @@ require("inc_functions.php"); $INFILE="$selfdir/src/amcli.php"; $INCFILE="$selfdir/src/include_checks.php"; $TMPFILE="$selfdir/src/amcli.php.tmp"; +$OUTFILE="$selfdir/$dirPackages/".str_replace('.php', '', basename($INFILE)); + echo " @@ -16,12 +18,10 @@ echo " "; - _chdir($selfdir); _mkdir($dirPackages); - -$OUTFILE="$selfdir/$dirPackages/".str_replace('.php', '', basename($INFILE)); +// ---------------------------------------------------------------------- _h1("Check target file"); if(file_exists($OUTFILE)){ @@ -35,17 +35,20 @@ if(file_exists($OUTFILE)){ } } +// ---------------------------------------------------------------------- + _h1("Prepare source"); $in=file_get_contents($INFILE); $inccode=file_get_contents($INCFILE); $inccode=str_replace("<?php", "", $inccode); -$tempcode=preg_replace("#\/\/ ---MARK---INCLUDE-CHECKS---START---(.*)END#s", "$inccode", $in); +$tempcode=preg_replace("#\/\/ ---MARK---INCLUDE-CHECKS---START---.*---MARK---INCLUDE-CHECKS---END#s", "$inccode", $in); if(file_put_contents($TMPFILE, $tempcode)){ - echo "✅ OK $TMPFILE was written\n"; + _ok("$TMPFILE was written"); } +// ---------------------------------------------------------------------- _h1("Compile"); _chdir("$selfdir/$dirBuild"); @@ -54,14 +57,25 @@ _exec("$SPC \ '$TMPFILE' \ -O '$OUTFILE'"); -if(unlink($TMPFILE)){ - echo "Cleanup: $TMPFILE was deleted\n"; -} +// if(unlink($TMPFILE)){ +// echo "Cleanup: $TMPFILE was deleted\n"; +// } + +// ---------------------------------------------------------------------- _h1("Test generated binary"); _exec("file '$OUTFILE'"); -_exec("'$OUTFILE' --verbose --ini=../src/simple.ini"); +_exec("'$OUTFILE' --ini=../src/simple.ini"); +_h1("Test binary in other location"); +$testfile="/tmp/".basename($OUTFILE); +_exec("cp '$OUTFILE' '$testfile'"); +_exec("'$testfile' --ini=$selfdir/src/simple.ini"); +_exec("rm '$testfile'"); + +// ---------------------------------------------------------------------- _h1("Done"); + +// ---------------------------------------------------------------------- diff --git a/inc_functions.php b/inc_functions.php index c5a1a4d..075db46 100644 --- a/inc_functions.php +++ b/inc_functions.php @@ -6,6 +6,13 @@ function _h1($s): void { echo "\n>>>>>>>>>> $s\n"; + + /* + echo "\n __".str_repeat("_", strlen($s))."\n"; + echo "__/ ".str_repeat(" ", strlen($s))." \___".str_repeat("_", 70-strlen($s))."\n"; + echo " $s\n"; + echo str_repeat(".", 79)."\n\n"; + */ } function _abort($sMessage, $iExitcode = 1): never { @@ -13,6 +20,15 @@ function _abort($sMessage, $iExitcode = 1): never exit($iExitcode); } +function _ok(string $sMessage=""): void +{ + echo "✅ OK $sMessage\n"; +} +function _skip(string $sMessage=""): void +{ + echo "🔹 SKIP: $sMessage\n"; +} + function _chdir($sDir): void { if (!is_dir($sDir)) { @@ -32,16 +48,16 @@ function _exec($cmd): void echo "cmd > $cmd\n"; exec("$cmd 2>&1", $aOut, $rc); - if(!count($aOut)) { - $aOut=["-- no output --"]; + if (!count($aOut)) { + $aOut = ["-- no output --"]; } - echo implode("\n", $aOut)."\n"; + echo implode("\n", $aOut) . "\n"; if ($rc != 0) { echo "rc=$rc "; _abort("Error: Command failed. Aborting.", $rc); } - echo "✅ OK\n"; + _ok(); } function _mkdir(string $sMyDir): void @@ -51,9 +67,153 @@ function _mkdir(string $sMyDir): void if (!mkdir($sMyDir, 0755, true)) { _abort("ERROR: mkdir failed."); } - echo "✅ OK\n\n"; + _ok(); + echo "\n"; } else { - echo "⏩ SKIP mkdir: already exists: '$sMyDir'\n"; + _skip("mkdir: already exists: '$sMyDir"); + } + +} + + +/** + * Compress PHP code + * from https://www.php.net/manual/de/function.php-strip-whitespace.php + * with removed lowercase function + * + * @param string $src source code or filename + * @return bool|string + */ +function compress_php_src(string $src): bool|string +{ + // Whitespaces left and right from this signs can be ignored + static $IW = array( + T_CONCAT_EQUAL, // .= + T_DOUBLE_ARROW, // => + T_BOOLEAN_AND, // && + T_BOOLEAN_OR, // || + T_IS_EQUAL, // == + T_IS_NOT_EQUAL, // != or <> + T_IS_SMALLER_OR_EQUAL, // <= + T_IS_GREATER_OR_EQUAL, // >= + T_INC, // ++ + T_DEC, // -- + T_PLUS_EQUAL, // += + T_MINUS_EQUAL, // -= + T_MUL_EQUAL, // *= + T_DIV_EQUAL, // /= + T_IS_IDENTICAL, // === + T_IS_NOT_IDENTICAL, // !== + T_DOUBLE_COLON, // :: + T_PAAMAYIM_NEKUDOTAYIM, // :: + T_OBJECT_OPERATOR, // -> + T_DOLLAR_OPEN_CURLY_BRACES, // ${ + T_AND_EQUAL, // &= + T_MOD_EQUAL, // %= + T_XOR_EQUAL, // ^= + T_OR_EQUAL, // |= + T_SL, // << + T_SR, // >> + T_SL_EQUAL, // <<= + T_SR_EQUAL, // >>= + ); + if (is_file($src)) { + if (!$src = file_get_contents($src)) { + return false; + } } + $tokens = token_get_all($src); + $new = ""; + $c = sizeof($tokens); + $iw = false; // ignore whitespace + $ih = false; // in HEREDOC + $ls = ""; // last sign + $ot = null; // open tag + for ($i = 0; $i < $c; $i++) { + $token = $tokens[$i]; + if (is_array($token)) { + list($tn, $ts) = $token; // tokens: number, string, line + $tname = token_name($tn); + if ($tn == T_INLINE_HTML) { + $new .= $ts; + $iw = false; + } else { + if ($tn == T_OPEN_TAG) { + if (strpos($ts, " ") || strpos($ts, "\n") || strpos($ts, "\t") || strpos($ts, "\r")) { + $ts = rtrim($ts); + } + $ts .= " "; + $new .= $ts; + $ot = T_OPEN_TAG; + $iw = true; + } elseif ($tn == T_OPEN_TAG_WITH_ECHO) { + $new .= $ts; + $ot = T_OPEN_TAG_WITH_ECHO; + $iw = true; + } elseif ($tn == T_CLOSE_TAG) { + if ($ot == T_OPEN_TAG_WITH_ECHO) { + $new = rtrim($new, "; "); + } else { + $ts = " " . $ts; + } + $new .= $ts; + $ot = null; + $iw = false; + } elseif (in_array($tn, $IW)) { + $new .= $ts; + $iw = true; + } elseif ($tn == T_CONSTANT_ENCAPSED_STRING || $tn == T_ENCAPSED_AND_WHITESPACE) { + if ($ts[0] == '"') { + $ts = addcslashes($ts, "\n\t\r"); + } + $new .= $ts; + $iw = true; + } elseif ($tn == T_WHITESPACE) { + $nt = @$tokens[$i + 1]; + if (!$iw && (!is_string($nt) || $nt == '$') && !in_array($nt[0], $IW)) { + $new .= " "; + } + $iw = false; + } elseif ($tn == T_START_HEREDOC) { + $new .= "<<<S\n"; + $iw = false; + $ih = true; // in HEREDOC + } elseif ($tn == T_END_HEREDOC) { + $new .= "S;"; + $iw = true; + $ih = false; // in HEREDOC + for ($j = $i + 1; $j < $c; $j++) { + if (is_string($tokens[$j]) && $tokens[$j] == ";") { + $i = $j; + break; + } else if ($tokens[$j][0] == T_CLOSE_TAG) { + break; + } + } + } elseif ($tn == T_COMMENT || $tn == T_DOC_COMMENT) { + $iw = true; + } else { + /* + * Axel: DISABLE lowercase - it has bad impact on constants + * + if (!$ih) { + $ts = strtolower($ts); + } + * + */ + $new .= $ts; + $iw = false; + } + } + $ls = ""; + } else { + if (($token != ";" && $token != ":") || $ls != $token) { + $new .= $token; + $ls = $token; + } + $iw = true; + } + } + return $new; } \ No newline at end of file diff --git a/installer.php b/installer.php index 42dd1d1..00c4e6b 100755 --- a/installer.php +++ b/installer.php @@ -66,36 +66,62 @@ if(!is_dir("appmonitor")){ // ---------------------------------------------------------------------- _h1("Generate include file with all available checks..."); +// _exec("ln -s $selfdir/$dirExternal/appmonitor/public_html/client $selfdir/src"); + $incfile="$selfdir/src/include_checks.php"; -_chdir("$selfdir/$dirExternal"); -$out="<?php +_chdir("$selfdir"); -// This file was generated by -// ".__FILE__." -// at ".(date("Y-m-d H:i:s"))." +$aFiles2Merge=array_merge( + [ + "$dirExternal/appmonitor/public_html/client/classes/appmonitor-checks.class.php", + "$dirExternal/appmonitor/public_html/client/classes/appmonitor-client.class.php", + ], + glob("$dirExternal/appmonitor/public_html/client/plugins/checks/*php") +); + +$out="<?php +/* + This file was generated by + ".__FILE__." + at ".(date("Y-m-d H:i:s"))." -// ----- appmonitor client classes -require_once('../$dirExternal/appmonitor/public_html/client/classes/appmonitor-checks.class.php'); -require_once('../$dirExternal/appmonitor/public_html/client/classes/appmonitor-client.class.php'); + merged files: + ".implode("\n ", $aFiles2Merge)." -// ----- appmonitor checks +*/ "; -foreach(glob("appmonitor/public_html/client/plugins/checks/*php") as $sFile){ - $out.="require_once('../$dirExternal/$sFile');\n"; + +foreach($aFiles2Merge as $sMyFile){ + $sSource=file_get_contents($sMyFile); + $sSource=preg_replace( + [ + "/(require[\ \_].*;)/", + "/(\<\?php)/" + ], + [ + "// REMOVED-BY-MERGER: $1", + "", + ], + $sSource + ); + $out.="$sSource\n"; } + if(file_put_contents($incfile, $out)){ - echo "✅ OK $incfile was written\n"; + _ok("$incfile was written"); } +_exec("php -l '$incfile'"); + // ---------------------------------------------------------------------- _h1("Get / update spc"); _chdir("$selfdir/$dirExternal/bin"); if(!file_exists($SPC)){ _exec("wget -O $SPC '$spcUrl'"); } else { - echo "⏩ SKIP download of spc.\n"; + _skip("download of spc."); } if (PHP_OS == "Linux") { @@ -114,7 +140,7 @@ if(!file_exists("$doneBuild")){ _exec("$SPC build --no-interaction --build-micro '$php_libs'"); touch("$doneBuild"); } else { - echo "⏩ SKIP: Micro already built - php $php_version - extensions '$php_libs'\n"; + _skip("Micro already built - php $php_version - extensions '$php_libs'"); } diff --git a/src/amcli.php b/src/amcli.php index feeef54..1d1d8d8 100755 --- a/src/amcli.php +++ b/src/amcli.php @@ -1,18 +1,18 @@ #!/usr/bin/env php <?php -chdir(__DIR__); +# chdir(__DIR__); $FLAG_DEBUG = 0; $VERSION = "0.0.1"; // ---MARK---INCLUDE-CHECKS---START--- -if (!file_exists("include_checks.php")) { +if (!file_exists(__DIR__."/include_checks.php")) { echo "ERROR: File 'include_checks.php' does not exist yet..\n"; echo "Run the ../installer.php first!\n"; exit(1); } -if (!include "include_checks.php") { +if (!include __DIR__."/include_checks.php") { echo "ERROR: Include of generated 'include_checks.php' failed.\n"; echo "Check its generation by installer or run the installer again.\n"; exit(2); @@ -84,7 +84,7 @@ You can use the compiled binary on non PHP systems. !!! This tool is in alpha stadium !!! -SYNTAX: $_self [OPTIONS] +SYNTAX: $_self [OPTIONS] -i <INIFILE> OPTIONS: -h, --help Print this help and exit @@ -136,12 +136,17 @@ $oMonitor = new appmonitor(); // show builtin checks if (isset($ARGS['-l']) || isset($ARGS['--list'])) { + _wd("Showing checks"); echo implode("\n", $oMonitor->listChecks()); exit(0); } +$inifile = $ARGS["--ini"] ?? ($ARGS["-i"] ?? ""); +if (!$inifile) { + echo "ERROR: Set an INI File using -i=<FILE> (or --ini=<FILE>).\n"; + exit(1); +} -$inifile = $ARGS["--ini"] ?? ($ARGS["-i"] ?? "simple.ini"); _wd("Using ini file '$inifile'."); if (!file_exists($inifile)) { @@ -165,12 +170,14 @@ _set("setHost", $aIni['meta']['host'] ?? null); _set("setWebsite", $aIni['meta']['website'] ?? null); _set("setTtl", $aIni['meta']['ttl'] ?? null); -foreach ($aIni['notification']['email'] ?? [] as $sValue) { +foreach ($aIni['notifications']['email'] ?? [] as $sValue) { _set("addEmail", $sValue); } -foreach ($aIni['notification']['slack'] ?? [] as $sValue) { - $sChannel = preg_filter('/,.*/', '', $sValue); - $sWebhook = preg_filter('/^.*,/', '', $sValue); +foreach ($aIni['notifications']['slack'] ?? [] as $sValue) { + + $aArray = json_decode($sValue, 1); + $sChannel = array_keys($aArray)[0]; + $sWebhook = array_values($aArray)[0]; _set("addSlackWebhook", $sChannel, $sWebhook); } @@ -178,7 +185,7 @@ foreach ($aIni['notification']['slack'] ?? [] as $sValue) { // loop over checks $aChecks = $aIni; unset($aChecks["meta"]); -unset($aChecks["notification"]); +unset($aChecks["notifications"]); foreach ($aChecks as $sKey => $aCheck) { $aChecks[$sKey]['name'] = $aCheck['name'] ?? $sKey; @@ -191,7 +198,7 @@ foreach ($aChecks as $sKey => $aCheck) { } } - _wd("Execute Check '$sKey'"); + _wd("Execute Check '$sKey' with params: " . print_r($aArray ?? [], 1)); $oMonitor->addCheck([ "name" => $aCheck['name'] ?? $sKey, "description" => $aCheck['description'], diff --git a/src/simple.ini b/src/simple.ini index 61897d1..56e1efa 100644 --- a/src/simple.ini +++ b/src/simple.ini @@ -22,13 +22,14 @@ ttl = 300 tags[]="monitoring" -[notification] +[notifications] email[]="support@example.com" email[]="webmaster@example.com" ; for slack use the following format ; <channelname> + comma + <webhook url> -slack[]="#support-channel,https://hooks.slack.com/services/XXXXXX/YYYYYY/ZZZZZ" +; slack[]="#support-channel,https://hooks.slack.com/services/XXXXXX/YYYYYY/ZZZZZ" +slack[]='{ "#support-channel": "https://hooks.slack.com/services/XXXXXX/YYYYYY/ZZZZZ" }' ; ----------------------------------------------------------------------- -- GitLab