From 53738001db77f9cc52f684db38f88b34ae77a114 Mon Sep 17 00:00:00 2001 From: Koen Date: Tue, 24 Sep 2024 15:53:05 +0200 Subject: [PATCH 1/6] Add support for external checks --- luabridge.cc | 3 +++ netmon.cc | 36 ++++++++++++++++++++++++++++++++++++ simplomon.hh | 17 +++++++++++++++++ 3 files changed, 56 insertions(+) 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/netmon.cc b/netmon.cc index 76a6280..f8fdf28 100644 --- a/netmon.cc +++ b/netmon.cc @@ -531,3 +531,39 @@ 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::string exec(const char* cmd) { + char buffer[128]; + std::string result = ""; + FILE* pipe = popen(cmd, "r"); + if (!pipe) throw std::runtime_error("popen() failed!"); + try { + while (fgets(buffer, sizeof buffer, pipe) != NULL) { + result += buffer; + } + } catch (...) { + pclose(pipe); + throw; + } + pclose(pipe); + return result; +} + +ExternalChecker::ExternalChecker(sol::table data) : Checker(data) +{ + checkLuaTable(data, {"cmd", "regex"}); + + d_cmd = data.get("cmd"); + d_exp = data.get("regex"); +} + +CheckResult ExternalChecker::perform() +{ + string output = exec(d_cmd.c_str()); + if (!std::regex_search(output, std::regex(d_exp))) { + return fmt::format("External check \"{}\" against \"{}\" failed, actual output: \"{}\"", d_cmd, d_exp, output); + } + return ""; +} diff --git a/simplomon.hh b/simplomon.hh index d6dc6eb..d76417b 100644 --- a/simplomon.hh +++ b/simplomon.hh @@ -215,6 +215,23 @@ 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 {} using expression {}", d_cmd, d_exp); + } + +private: + std::string d_cmd; + std::string d_exp; +}; + + class HTTPSChecker : public Checker { public: From ab2ae30fc3cec501744f825c8e6cef2dfe22d089 Mon Sep 17 00:00:00 2001 From: Koen Date: Tue, 24 Sep 2024 17:46:53 +0200 Subject: [PATCH 2/6] Add support for RC checking --- netmon.cc | 27 +++++++++++++++++++-------- simplomon.hh | 3 ++- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/netmon.cc b/netmon.cc index f8fdf28..30aaa15 100644 --- a/netmon.cc +++ b/netmon.cc @@ -534,9 +534,10 @@ CheckResult PINGChecker::perform() // 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::string exec(const char* cmd) { +std::pair exec(const char* cmd) { char buffer[128]; std::string result = ""; + int rc; FILE* pipe = popen(cmd, "r"); if (!pipe) throw std::runtime_error("popen() failed!"); try { @@ -547,23 +548,33 @@ std::string exec(const char* cmd) { pclose(pipe); throw; } - pclose(pipe); - return result; + rc = pclose(pipe) / 256; + std::pair ret(rc, result); + return ret; } ExternalChecker::ExternalChecker(sol::table data) : Checker(data) { - checkLuaTable(data, {"cmd", "regex"}); + checkLuaTable(data, {"cmd"}, {"regex", "rc"}); d_cmd = data.get("cmd"); - d_exp = data.get("regex"); + d_exp = data.get_or("regex", ""); + d_rc = data.get_or("rc", -1); } CheckResult ExternalChecker::perform() { - string output = exec(d_cmd.c_str()); - if (!std::regex_search(output, std::regex(d_exp))) { - return fmt::format("External check \"{}\" against \"{}\" failed, actual output: \"{}\"", d_cmd, d_exp, output); + std::pair output = exec(d_cmd.c_str()); + + 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 d76417b..91adf26 100644 --- a/simplomon.hh +++ b/simplomon.hh @@ -223,12 +223,13 @@ public: std::string getCheckerName() override { return "external"; } std::string getDescription() override { - return fmt::format("External check {} using expression {}", d_cmd, d_exp); + return fmt::format("External check {}", d_cmd); } private: std::string d_cmd; std::string d_exp; + int d_rc; }; From 0eea5e722625678450e4f138158427c4f24a5cb8 Mon Sep 17 00:00:00 2001 From: Koen Date: Tue, 24 Sep 2024 17:50:12 +0200 Subject: [PATCH 3/6] Don't runtime error if pipe fails --- netmon.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netmon.cc b/netmon.cc index 30aaa15..f7c6bc3 100644 --- a/netmon.cc +++ b/netmon.cc @@ -539,7 +539,7 @@ std::pair exec(const char* cmd) { std::string result = ""; int rc; FILE* pipe = popen(cmd, "r"); - if (!pipe) throw std::runtime_error("popen() failed!"); + if (!pipe) return std::pair (255, ""); try { while (fgets(buffer, sizeof buffer, pipe) != NULL) { result += buffer; From f3f48eb868b7c2230f8d75e2b686214aea87a9ab Mon Sep 17 00:00:00 2001 From: Koen Date: Thu, 26 Sep 2024 12:31:46 +0200 Subject: [PATCH 4/6] Add example in the manual --- manual.md | 9 +++++++++ 1 file changed, 9 insertions(+) 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: From 2370414f81571c52169d81bea2649d7e21deaeb3 Mon Sep 17 00:00:00 2001 From: Koen Date: Mon, 30 Sep 2024 11:00:11 +0200 Subject: [PATCH 5/6] Add result showing for external commands --- netmon.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/netmon.cc b/netmon.cc index f7c6bc3..4204ef6 100644 --- a/netmon.cc +++ b/netmon.cc @@ -566,6 +566,10 @@ 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); From 8abaebc4d3dd6906232ecf03d4a3cd3fae2e71dc Mon Sep 17 00:00:00 2001 From: Koen Date: Mon, 30 Sep 2024 11:28:56 +0200 Subject: [PATCH 6/6] Ensure white space is shown in table --- html/style.css | 1 + 1 file changed, 1 insertion(+) 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 {