Skip to content
Snippets Groups Projects
amcli.php 6.55 KiB
#!/usr/bin/env php
<?php
/**
 * ======================================================================
 * 
 * IML APPMONITOR CLIENT 
 * AS CLI APP
 * 
 * ---------------------------------------------------------------------
 * 2025-03-04  v0.1    Initial version
 * ======================================================================
 */


$FLAG_DEBUG = 0;
$VERSION = "0.1";

// ---MARK---INCLUDE-CHECKS---START---
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 __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);
}
// ---MARK---INCLUDE-CHECKS---END


// --------------------------------------------------------------------
//
// FUNCTIONS
//
// --------------------------------------------------------------------


/**
 * Call $oMonitor-><METHODNAME> with 1 or 2 params.
 * This function was introduced to shorten the code.
 * 
 * @param string $sMethod  method name of appmonitor class
 * @param mixed  $value
 * @param mixed  $value2
 * @return void
 */
function _set(string $sMethod, mixed $value = null, mixed $value2 = null)
{
    global $oMonitor;
    if (!isset($value)) {
        _wd("SKIP \$oMonitor->$sMethod(<no_value>)");

    } else {
        if (!isset($value2)) {
            _wd("calling \$oMonitor->$sMethod('$value')");
            $oMonitor->$sMethod($value);
        } else {
            _wd("calling \$oMonitor->$sMethod('$value', '$value2')");
            $oMonitor->$sMethod($value, $value2);
        }
    }
}

/**
 * Write debug output if FLAG_DEBUG is true (use -v or --verbose on command line)
 * @param string $s  message to show; a prefix "DEBUG:" will be added in front
 * @return void
 */
function _wd($s): void
{
    global $FLAG_DEBUG;
    if ($FLAG_DEBUG) {
        fwrite(STDERR, "DEBUG: $s\n");
    }
}

/**
 * Show help text
 * @return void
 */
function _showHelp(): void
{
    global $VERSION;
    $_self = basename(__FILE__);
    echo "IML Appmonitor as CLI client $VERSION

This client performs appmonitor checks and puts the results as JSON to stdout.
You can use the compiled binary on non PHP systems.
(c) 2025 Institute for Medical education * University of Bern

SYNTAX: $_self [OPTIONS] --ini=<INI-FILE>

OPTIONS:
    -h, --help      Print this help and exit
    -i, --ini       Set an INI File to parse
    -l, --list      list available checks and exit
    -m, --modules   list available Php modules in this binary and exit
    -v, --verbose   Enable verbose output
    -V, --version   Show version and exit

EXAMPLES:

    $_self -i=my.ini
    $_self --ini=my.ini
        Execute checks from INI file 'my.ini'.

    $_self --list
        List available checks.
    
";
}

// --------------------------------------------------------------------
//
// MAIN
//
// --------------------------------------------------------------------

// put params to $ARGS
if ($argc > 1) {
    parse_str(implode('&', array_slice($argv, 1)), $ARGS);
}

// check params

if (isset($ARGS['-v']) || isset($ARGS['--verbose'])) {
    $FLAG_DEBUG = 1;
    _wd("Verbose mode enabled. Showing debug infos on STDOUT.");
}
_wd("CLI ARGS: " . print_r($ARGS ?? [], 1));

// show version
if (isset($ARGS['-V']) || isset($ARGS['--version'])) {
    _wd("Showing version");
    echo "$VERSION\n";
    exit(0);
}
// show help
if (isset($ARGS['-h']) || isset($ARGS['--help'])) {
    _wd("Showing help");
    _showHelp();
    exit(0);
}

// ----------------------------------------------------------------------

_wd("Initializing appmonitor class");

$oMonitor = new appmonitor();
$sPreSpace=" - ";

// show builtin checks
if (isset($ARGS['-l']) || isset($ARGS['--list'])) {
    _wd("Showing checks");
    echo $sPreSpace . implode("\n$sPreSpace", $oMonitor->listChecks());
    exit(0);
}

// show builtin modules
if (isset($ARGS['-m']) || isset($ARGS['--modules'])) {
    _wd("Showing php modules");
    $aMods = get_loaded_extensions();
    sort($aMods);
    echo $sPreSpace . implode("\n$sPreSpace", $aMods);
    exit(0);
}

$inifile = $ARGS["--ini"] ?? ($ARGS["-i"] ?? "");
if (!$inifile) {
    echo "ERROR: Set an INI File using -i=<FILE> (or --ini=<FILE>).\n";
    exit(3);
}

_wd("Using ini file '$inifile'.");

if (!file_exists($inifile)) {
    echo "ERROR: INI File '$inifile' does not exist.\n";
    exit(4);
}

$aIni = parse_ini_file($inifile, true);
if (!is_array($aIni)) {
    echo "ERROR: INI File '$inifile' could not be parsed.\n";
    exit(5);
}

_wd("Parsed INI data: " . print_r($aIni, 1));

// ----------------------------------------------------------------------

// set metadata
_set("setHost", $aIni['meta']['host'] ?? null);
_set("setWebsite", $aIni['meta']['website'] ?? null);
_set("setTtl", $aIni['meta']['ttl'] ?? null);

foreach ($aIni['notifications']['email'] ?? [] as $sValue) {
    _set("addEmail", $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);
}
// ----------------------------------------------------------------------

// loop over checks
$aChecks = $aIni;
unset($aChecks["meta"]);
unset($aChecks["notifications"]);

$aArray = [];
foreach ($aChecks as $sKey => $aCheck) {
    $aChecks[$sKey]['name'] = $aCheck['name'] ?? $sKey;
    if ($aCheck['params']) {
        $aArray = json_decode($aCheck['params'], 1);
        if (!is_array($aArray)) {
            echo "ERROR: key 'params' for check [$sKey] must be JSON.\n";
            echo "Value in $inifile: $aCheck[params]\n";
            exit(6);
        }
    }

    $aAddCheck = [
        "name" => $aCheck['name'] ?? $sKey,
        "description" => $aCheck['description'] ?? "",
        "check" => [
            "function" => $aCheck['function'],
            "params" => $aArray ?? [],
        ],
    ];
    foreach (["group", "parent", "worstresult"] as $sCustomKey) {
        if (isset($aCheck[$sCustomKey])) {
            $aAddCheck[$sCustomKey] = $aCheck[$sCustomKey];
        }
    }
    _wd("Execute Check '$sKey': " . print_r($aAddCheck, 1));
    $oMonitor->addCheck($aAddCheck);

}


// ----------------------------------------------------------------------
// send the response

_wd("Setting result");
$oMonitor->setResult();

_wd("Send response");
$oMonitor->render();
$sOut = ob_get_contents();
ob_end_clean();

echo $sOut;

// ----------------------------------------------------------------------