diff --git a/html/style.css b/html/style.css index 76e5c0e..12049ce 100644 --- a/html/style.css +++ b/html/style.css @@ -212,6 +212,7 @@ td { border: 1px solid var(--clr-primary-fg); padding: var(--size-xs); vertical-align: top; + white-space: pre-wrap; } th { diff --git a/luabridge.cc b/luabridge.cc index 2514f77..33a428b 100644 --- a/luabridge.cc +++ b/luabridge.cc @@ -119,6 +119,9 @@ void initLua() g_checkers.emplace_back(make_unique(data)); }); + g_lua.set_function("external", [&](sol::table data) { + g_checkers.emplace_back(make_unique(data)); + }); g_lua.set_function("smtp", [&](sol::table data) { g_checkers.emplace_back(make_unique(data)); diff --git a/manual.md b/manual.md index d452361..dcc646b 100644 --- a/manual.md +++ b/manual.md @@ -92,6 +92,15 @@ dnssoa{domain="berthub.eu", servers= nameservers} dnssoa{domain="hubertnet.nl", servers= nameservers} ``` +## external + +Execute some external program, and check whether the output matches a regex and/or a return code: + +```lua +external{cmd="do-thing", regex="success"} +external{cmd="do-other-thing", rc=0} +``` + ## httpredir Does the http redirect work? TBC. Example: diff --git a/netmon.cc b/netmon.cc index 76a6280..4204ef6 100644 --- a/netmon.cc +++ b/netmon.cc @@ -531,3 +531,54 @@ CheckResult PINGChecker::perform() } return ret; } + + +// Based on: https://stackoverflow.com/questions/478898/how-do-i-execute-a-command-and-get-the-output-of-the-command-within-c-using-po +std::pair exec(const char* cmd) { + char buffer[128]; + std::string result = ""; + int rc; + FILE* pipe = popen(cmd, "r"); + if (!pipe) return std::pair (255, ""); + try { + while (fgets(buffer, sizeof buffer, pipe) != NULL) { + result += buffer; + } + } catch (...) { + pclose(pipe); + throw; + } + rc = pclose(pipe) / 256; + std::pair ret(rc, result); + return ret; +} + +ExternalChecker::ExternalChecker(sol::table data) : Checker(data) +{ + checkLuaTable(data, {"cmd"}, {"regex", "rc"}); + + d_cmd = data.get("cmd"); + d_exp = data.get_or("regex", ""); + d_rc = data.get_or("rc", -1); +} + +CheckResult ExternalChecker::perform() +{ + std::pair output = exec(d_cmd.c_str()); + + d_results.clear(); + d_results[d_cmd]["rc"] = output.first; + d_results[d_cmd]["output"] = output.second; + + if (d_exp != "") { + if (!std::regex_search(output.second, std::regex(d_exp))) { + return fmt::format("External check \"{}\" against \"{}\" failed, actual output: \"{}\"", d_cmd, d_exp, output.second); + } + } + if (d_rc != -1) { + if (output.first != d_rc) { + return fmt::format("External check \"{}\" expected rc \"{}\", received: \"{}\"", d_cmd, d_rc, output.first); + } + } + return ""; +} diff --git a/simplomon.hh b/simplomon.hh index d6dc6eb..91adf26 100644 --- a/simplomon.hh +++ b/simplomon.hh @@ -215,6 +215,24 @@ private: }; +class ExternalChecker : public Checker +{ +public: + ExternalChecker(sol::table data); + CheckResult perform() override; + std::string getCheckerName() override { return "external"; } + std::string getDescription() override + { + return fmt::format("External check {}", d_cmd); + } + +private: + std::string d_cmd; + std::string d_exp; + int d_rc; +}; + + class HTTPSChecker : public Checker { public: