Mads
Multi-Agent Distributed System
Loading...
Searching...
No Matches
doctor_checks.hpp
Go to the documentation of this file.
1/*
2 ____ _ ____ _ _
3 | _ \ ___ ___| |_ ___ _ __ / ___| |__ ___ ___| | _____
4 | | | |/ _ \ / __| __/ _ \| '__| | | '_ \ / _ \/ __| |/ / __|
5 | |_| | (_) | (__| || (_) | | | |___| | | | __/ (__| <\__ \
6 |____/ \___/ \___|\__\___/|_| \____|_| |_|\___|\___|_|\_\___/
7
8Pure, unit-testable check logic backing `mads doctor` (src/main/doctor.cpp).
9
10Every function here either performs a small, self-contained, dependency-light
11check (settings-file parsing via toml++, CURVE key well-formedness via
12libzmq's Z85 codec, reading the pinned plugin protocol out of a JSON manifest
13text) or is a pure *evaluator* that turns already-collected facts (a broker
14probe's boolean result, a dry-run plugin load's outcome) into a CheckResult.
15
16Deliberately NOT here: the actual pugg::Kernel-based plugin dry-run load. That
17needs the mads_plugin headers (source.hpp/filter.hpp/sink.hpp) and pugg's
18Kernel.h, which -- exactly like mads-source/-filter/-sink -- are only on the
19include path for src/main (see the top-level CMakeLists.txt's
20`include_directories()` call, scoped to src/main and src/plugin). So the
21actual dlopen/registration/create() sequence
22lives in src/main/doctor.cpp (mirroring src/main/plugin_loader.cpp), which
23then hands the resulting facts to evaluate_plugin_load()/evaluate_plugin_protocol()
24here for the pass/warn/fail decision -- keeping that decision logic testable
25without linking pugg or building a real .plugin fixture.
26
27Author(s): Paolo Bosetti
28*/
29#ifndef MADS_DOCTOR_CHECKS_HPP
30#define MADS_DOCTOR_CHECKS_HPP
31
32#include "broker_probe.hpp"
33
34#include <chrono>
35#include <cstdint>
36#include <filesystem>
37#include <optional>
38#include <string>
39
40namespace Mads {
41namespace Doctor {
42
46enum class Status { Pass, Warn, Fail };
47
53 std::string name;
55 std::string message;
56 std::string fix_hint;
57 bool fixable = false;
58};
59
67
68/* ---- 1. Settings file found and parses ---------------------------------- */
69
76CheckResult check_settings_file(const std::filesystem::path &path);
77
78/* ---- 2. Broker reachable -------------------------------------------------
79 The actual probe is Mads::probe_broker() (src/broker_probe.hpp, from P5);
80 evaluate_broker_reachable() is split out so the pass/warn/fail wording is
81 testable without a real socket.
82
83 `curve` must be set whenever the broker runs with --crypto: the probe is an
84 ordinary REQ round-trip, so an unencrypted one gets dropped in the ZMTP
85 handshake and times out indistinguishably from a broker that is not there.
86 `crypto` on the evaluator only selects the wording for that case. */
87
88CheckResult evaluate_broker_reachable(const std::string &uri, bool reachable,
89 bool crypto = false);
90
92check_broker_reachable(const std::string &uri, std::chrono::milliseconds timeout,
93 const std::optional<CurveKeyCheck> &curve = std::nullopt);
94
95/* ---- 3. Declared plugin(s) resolve and load (dry-run) -------------------- */
96
100 std::string plugin_file; // path probed
101 bool file_exists = false;
102 bool loaded = false; // load + driver lookup + create() all succeeded
103 std::string driver_kind; // "source" | "filter" | "sink" | "" (unknown)
104 std::string driver_name; // the created instance's own kind()
105 int protocol_version = -1; // pugg::Driver::version(); -1 if unknown
106 std::string error; // populated when loaded == false
107};
108
110
111/* ---- 4. Plugin protocol matches the pinned mads_plugin version ---------- */
112
120
129std::optional<int> parse_pinned_plugin_protocol(const std::string &manifest_json_text);
130
132 std::optional<int> pinned_version,
133 int min_supported = kMinSupportedPluginProtocol);
134
135/* ---- 5. CURVE key files exist and are well-formed ------------------------
136 Uses CurveKeyCheck, declared at the top of this header because check 2
137 needs it too. */
138
142bool is_well_formed_curve_key(const std::string &key_line);
143
152
153/* ---- 6. Local port-availability sanity check ------------------------------
154 The actual probe is Mads::probe_tcp_port() (src/broker_probe.hpp): its
155 "true" means "something answered", i.e. the *opposite* of what doctor
156 wants to hear before launching a broker on that port -- so the evaluator
157 below inverts the pass/fail mapping relative to `ready = "port:<n>"`'s own
158 use of the same probe. */
159
160CheckResult evaluate_port_available(const std::string &host, int port, bool in_use);
161
162CheckResult check_port_available(const std::string &host, int port,
163 std::chrono::milliseconds timeout);
164
165/* ---- 7. CURVE handshake actually succeeds ---------------------------------
166 The actual probe is Mads::probe_curve_handshake() (src/broker_probe.hpp,
167 from ZMQ_DEVELOPMENT.md ยง2.1); evaluate_curve_handshake() is split out so
168 the pass/fail wording is testable without a real socket, mirroring
169 check 2. Reuses CurveKeyCheck (check 5) for the key-file location. */
170
172 CurveProbeResult result);
173
174CheckResult check_curve_handshake(const std::string &uri, const CurveKeyCheck &cfg,
175 std::chrono::milliseconds timeout);
176
177/* ---- 8. Open-file limit leaves room for the fleet -------------------------
178 The broker holds two descriptors per connected agent -- the agent's
179 publisher on the XSUB frontend, its subscriber on the XPUB backend -- so
180 RLIMIT_NOFILE, not anything in libzmq, is what bounds fleet size. The
181 default soft limit of 1024 stops at roughly 495 agents, and libzmq refuses
182 everything past it near-silently.
183
184 Reported from *this* process's limit: doctor cannot see what a broker
185 started under systemd would inherit, so the wording says "a broker started
186 the same way as this check". The evaluator takes the limits as plain
187 integers rather than the Mads::detail type that produces them, so this
188 installed header stays free of src/detail/. */
189
190CheckResult evaluate_fd_limit(bool supported, uint64_t soft, uint64_t hard,
191 std::optional<int64_t> configured);
192
193CheckResult check_fd_limit(std::optional<int64_t> configured);
194
195} // namespace Doctor
196} // namespace Mads
197
198#endif // MADS_DOCTOR_CHECKS_HPP
CheckResult evaluate_fd_limit(bool supported, uint64_t soft, uint64_t hard, std::optional< int64_t > configured)
CheckResult check_settings_file(const std::filesystem::path &path)
Checks that path is a local settings file that exists and parses as valid TOML. A tcp://....
CheckResult evaluate_curve_handshake(const std::string &uri, CurveProbeResult result)
CheckResult check_port_available(const std::string &host, int port, std::chrono::milliseconds timeout)
CheckResult check_curve_keys(const CurveKeyCheck &cfg)
Checks that a client's CURVE key files exist and are well-formed: <client>.key (secret),...
bool is_well_formed_curve_key(const std::string &key_line)
CheckResult evaluate_port_available(const std::string &host, int port, bool in_use)
CheckResult check_fd_limit(std::optional< int64_t > configured)
constexpr int kMinSupportedPluginProtocol
CheckResult check_broker_reachable(const std::string &uri, std::chrono::milliseconds timeout, const std::optional< CurveKeyCheck > &curve=std::nullopt)
CheckResult evaluate_broker_reachable(const std::string &uri, bool reachable, bool crypto=false)
std::optional< int > parse_pinned_plugin_protocol(const std::string &manifest_json_text)
Reads the plugin_protocol field out of share/plugin_deps.json's text content (already read by the cal...
CheckResult check_curve_handshake(const std::string &uri, const CurveKeyCheck &cfg, std::chrono::milliseconds timeout)
CheckResult evaluate_plugin_protocol(int loaded_version, std::optional< int > pinned_version, int min_supported=kMinSupportedPluginProtocol)
CheckResult evaluate_plugin_load(const PluginLoadFacts &facts)
Definition agent.hpp:67
Client-side CURVE credentials for a probe socket: the same key_dir/client/server naming convention ev...