diff --git a/src/supervisor/Supervisor.cc b/src/supervisor/Supervisor.cc index 74a04f8fe1..d2aa958eb5 100644 --- a/src/supervisor/Supervisor.cc +++ b/src/supervisor/Supervisor.cc @@ -44,8 +44,11 @@ extern "C" { #endif using namespace zeek; +using zeek::detail::SupervisedNode; +using zeek::detail::SupervisorNode; +using zeek::detail::SupervisorStemHandle; -std::optional Supervisor::supervised_node; +std::optional Supervisor::supervised_node; namespace { @@ -68,29 +71,29 @@ struct Stem { ~Stem(); - Supervisor::SupervisedNode Run(); + SupervisedNode Run(); - std::optional Poll(); + std::optional Poll(); - std::optional Revive(); + std::optional Revive(); void Reap(); - std::variant Spawn(Supervisor::Node* node); + std::variant Spawn(SupervisorNode* node); int AliveNodeCount() const; void KillNodes(int signal); - void KillNode(Supervisor::Node* node, int signal) const; + void KillNode(SupervisorNode* node, int signal) const; - void Destroy(Supervisor::Node* node) const; + void Destroy(SupervisorNode* node) const; - bool Wait(Supervisor::Node* node, int options) const; + bool Wait(SupervisorNode* node, int options) const; void Shutdown(int exit_code); - void ReportStatus(const Supervisor::Node& node) const; + void ReportStatus(const SupervisorNode& node) const; void Log(std::string_view type, const char* format, va_list args) const; @@ -102,7 +105,7 @@ struct Stem { int last_signal = -1; std::unique_ptr signal_flare; std::unique_ptr pipe; - std::map nodes; + std::map nodes; std::string msg_buffer; bool shutting_down = false; }; @@ -181,7 +184,7 @@ void zeek::detail::ParentProcessCheckTimer::Dispatch(double t, bool is_expire) interval)); } -Supervisor::Supervisor(Supervisor::Config cfg, StemHandle sh) +Supervisor::Supervisor(Supervisor::Config cfg, SupervisorStemHandle sh) : config(std::move(cfg)), stem_pid(sh.pid), stem_pipe(std::move(sh.pipe)) { stem_stdout.pipe = std::move(sh.stdout_pipe); @@ -618,7 +621,7 @@ void Stem::Reap() } } -bool Stem::Wait(Supervisor::Node* node, int options) const +bool Stem::Wait(SupervisorNode* node, int options) const { if ( node->pid <= 0 ) { @@ -671,7 +674,7 @@ bool Stem::Wait(Supervisor::Node* node, int options) const return true; } -void Stem::KillNode(Supervisor::Node* node, int signal) const +void Stem::KillNode(SupervisorNode* node, int signal) const { if ( node->pid <= 0 ) { @@ -699,7 +702,7 @@ static int get_kill_signal(int attempts, int max_attempts) return SIGKILL; } -void Stem::Destroy(Supervisor::Node* node) const +void Stem::Destroy(SupervisorNode* node) const { constexpr auto max_term_attempts = 13; constexpr auto kill_delay = 2; @@ -727,7 +730,7 @@ void Stem::Destroy(Supervisor::Node* node) const } } -std::optional Stem::Revive() +std::optional Stem::Revive() { constexpr auto attempts_before_delay_increase = 3; constexpr auto delay_increase_factor = 2; @@ -763,8 +766,8 @@ std::optional Stem::Revive() auto spawn_res = Spawn(&node); - if ( std::holds_alternative(spawn_res) ) - return std::get(spawn_res); + if ( std::holds_alternative(spawn_res) ) + return std::get(spawn_res); if ( std::get(spawn_res) ) LogError("Supervised node '%s' (PID %d) revived after premature exit", @@ -776,7 +779,7 @@ std::optional Stem::Revive() return {}; } -std::variant Stem::Spawn(Supervisor::Node* node) +std::variant Stem::Spawn(SupervisorNode* node) { auto ppid = getpid(); auto fork_res = fork_with_stdio_redirect(fmt("node %s", node->Name().data())); @@ -794,7 +797,7 @@ std::variant Stem::Spawn(Supervisor::Node* nod setsignal(SIGCHLD, SIG_DFL); setsignal(SIGTERM, SIG_DFL); zeek::set_thread_name(fmt("zeek.%s", node->Name().data())); - Supervisor::SupervisedNode rval; + SupervisedNode rval; rval.config = node->config; rval.parent_pid = ppid; return rval; @@ -877,7 +880,7 @@ void Stem::Shutdown(int exit_code) } } -void Stem::ReportStatus(const Supervisor::Node& node) const +void Stem::ReportStatus(const SupervisorNode& node) const { std::string msg = fmt("status %s %d", node.Name().data(), node.pid); safe_write(pipe->OutFD(), msg.data(), msg.size() + 1); @@ -916,7 +919,7 @@ void Stem::LogError(const char* format, ...) const va_end(args); } -Supervisor::SupervisedNode Stem::Run() +SupervisedNode Stem::Run() { for ( ; ; ) { @@ -931,7 +934,7 @@ Supervisor::SupervisedNode Stem::Run() return {}; } -std::optional Stem::Poll() +std::optional Stem::Poll() { std::map node_pollfd_indices; constexpr auto fixed_fd_count = 2; @@ -1062,8 +1065,8 @@ std::optional Stem::Poll() DBG_STEM("Stem creating node: %s (PID %d)", node.Name().data(), node.pid); auto spawn_res = Spawn(&node); - if ( std::holds_alternative(spawn_res) ) - return std::get(spawn_res); + if ( std::holds_alternative(spawn_res) ) + return std::get(spawn_res); ReportStatus(node); } @@ -1085,8 +1088,8 @@ std::optional Stem::Poll() auto spawn_res = Spawn(&node); - if ( std::holds_alternative(spawn_res) ) - return std::get(spawn_res); + if ( std::holds_alternative(spawn_res) ) + return std::get(spawn_res); ReportStatus(node); } @@ -1097,7 +1100,7 @@ std::optional Stem::Poll() return {}; } -std::optional Supervisor::CreateStem(bool supervisor_mode) +std::optional Supervisor::CreateStem(bool supervisor_mode) { // If the Stem needs to be re-created via fork()/exec(), then the necessary // state information is communicated via ZEEK_STEM env. var. @@ -1157,12 +1160,12 @@ std::optional Supervisor::CreateStem(bool supervisor_mod return {}; } - StemHandle sh; + SupervisorStemHandle sh; sh.pipe = std::move(ss.pipe); sh.pid = pid; sh.stdout_pipe = std::move(fork_res.stdout_pipe); sh.stderr_pipe = std::move(fork_res.stderr_pipe); - return std::optional(std::move(sh)); + return std::optional(std::move(sh)); } static BifEnum::Supervisor::ClusterRole role_str_to_enum(std::string_view r) @@ -1356,7 +1359,7 @@ RecordValPtr Supervisor::NodeConfig::ToRecord() const return rval; } -RecordValPtr Supervisor::Node::ToRecord() const +RecordValPtr SupervisorNode::ToRecord() const { const auto& rt = zeek::BifType::Record::Supervisor::NodeStatus; auto rval = zeek::make_intrusive(rt); @@ -1388,7 +1391,7 @@ static ValPtr supervisor_role_to_cluster_node_type(BifEnum::Supervisor::ClusterR } } -bool Supervisor::SupervisedNode::InitCluster() const +bool SupervisedNode::InitCluster() const { if ( config.cluster.empty() ) return false; @@ -1435,7 +1438,7 @@ bool Supervisor::SupervisedNode::InitCluster() const return true; } -void Supervisor::SupervisedNode::Init(zeek::Options* options) const +void SupervisedNode::Init(zeek::Options* options) const { const auto& node_name = config.name; diff --git a/src/supervisor/Supervisor.h b/src/supervisor/Supervisor.h index f81aea594a..3c3f777e24 100644 --- a/src/supervisor/Supervisor.h +++ b/src/supervisor/Supervisor.h @@ -24,6 +24,11 @@ namespace zeek { namespace detail { + +struct SupervisorStemHandle; +struct SupervisedNode; +struct SupervisorNode; + /** * A simple wrapper around a pipe to help do line-buffered output * of a Supervisor/Stem child process' redirected stdout/stderr. @@ -185,132 +190,6 @@ public: std::map cluster; }; - /** - * State which defines a Supervised node's understanding of itself. - */ - struct SupervisedNode { - /** - * Initialize the Supervised node within the Zeek Cluster Framework. - * This function populates the "Cluster::nodes" script-layer variable - * that otherwise is expected to be populated by a - * "cluster-layout.zeek" script in other context (e.g. ZeekCtl - * generates that cluster layout). - * @return true if the supervised node is using the Cluster Framework - * else false. - */ - bool InitCluster() const; - - /** - * Initialize the Supervised node. - * @param options the Zeek options to extend/modify as appropriate - * for the node's configuration. - */ - void Init(zeek::Options* options) const; - - /** - * The node's configuration options. - */ - NodeConfig config; - /** - * The process ID of the supervised node's parent process (i.e. the PID - * of the Stem process). - */ - pid_t parent_pid; - }; - - /** - * The state of a supervised node from the Supervisor's perspective. - */ - struct Node { - /** - * Convert the node into script-layer Supervisor::NodeStatus record - * representation. - */ - RecordValPtr ToRecord() const; - - /** - * @return the name of the node. - */ - const std::string& Name() const - { return config.name; } - - /** - * Create a new node state from a given configuration. - * @param arg_config the configuration to use for the node. - */ - Node(NodeConfig arg_config) : config(std::move(arg_config)) - { } - - /** - * The desired configuration for the node. - */ - NodeConfig config; - /** - * Process ID of the node (positive/non-zero are valid/live PIDs). - */ - pid_t pid = 0; - /** - * Whether the node is voluntarily marked for termination by the - * Supervisor. - */ - bool killed = false; - /** - * The last exit status of the node. - */ - int exit_status = 0; - /** - * The last signal which terminated the node. - */ - int signal_number = 0; - /** - * Number of process revival attempts made after the node first died - * prematurely. - */ - int revival_attempts = 0; - /** - * How many seconds to wait until the next revival attempt for the node. - */ - int revival_delay = 1; - /** - * The time at which the node's process was last spawned. - */ - std::chrono::time_point spawn_time; - /** - * A pipe that the Supervisor Stem can read from to obtain - * any output written to the Nodes's stdout. - */ - zeek::detail::LineBufferedPipe stdout_pipe; - /** - * A pipe that the Supervisor Stem can read from to obtain - * any output written to the Node's stdout. - */ - zeek::detail::LineBufferedPipe stderr_pipe; - }; - - /** - * State used to initalialize and communicate with the Stem process. - */ - struct StemHandle { - /** - * Bidirectional pipes that allow the Supervisor and Stem to talk. - */ - std::unique_ptr pipe; - /** - * A pipe that the Supervisor can read from to obtain - * any output written to the Stem's stdout. - */ - std::unique_ptr stdout_pipe; - /** - * A pipe that the Supervisor can read from to obtain - * any output written to the Stem's stdout. - */ - std::unique_ptr stderr_pipe; - /** - * The Stem's process ID. - */ - pid_t pid = 0; - }; - /** * Create and run the Stem process if necessary. * @param supervisor_mode whether Zeek was invoked with the supervisor @@ -320,24 +199,24 @@ public: * function but a node it spawns via fork() will return from it and * information about it is available in ThisNode(). */ - static std::optional CreateStem(bool supervisor_mode); + static std::optional CreateStem(bool supervisor_mode); /** * @return the state which describes what a supervised node should know * about itself if this is a supervised process. If called from a process * that is not supervised, this returns an "empty" object. */ - static const std::optional& ThisNode() + static const std::optional& ThisNode() { return supervised_node; } - using NodeMap = std::map>; + using NodeMap = std::map>; /** * Create a new Supervisor object. * @param stem_handle information about the Stem process that was already * created via CreateStem() */ - Supervisor(Config cfg, StemHandle stem_handle); + Supervisor(Config cfg, detail::SupervisorStemHandle stem_handle); /** * Destruction also cleanly shuts down the entire supervised process tree. @@ -424,7 +303,7 @@ private: const char* Tag() override { return "zeek::Supervisor"; } - static std::optional supervised_node; + static std::optional supervised_node; Config config; pid_t stem_pid; @@ -438,6 +317,132 @@ private: }; namespace detail { +/** + * State used to initalialize and talk to the Supervisor Stem process. + */ +struct SupervisorStemHandle { + /** + * Bidirectional pipes that allow the Supervisor and Stem to talk. + */ + std::unique_ptr pipe; + /** + * A pipe that the Supervisor can read from to obtain + * any output written to the Stem's stdout. + */ + std::unique_ptr stdout_pipe; + /** + * A pipe that the Supervisor can read from to obtain + * any output written to the Stem's stdout. + */ + std::unique_ptr stderr_pipe; + /** + * The Stem's process ID. + */ + pid_t pid = 0; +}; + +/** + * State which defines a Supervised Zeek node's understanding of itself. + */ +struct SupervisedNode { + /** + * Initialize the Supervised node within the Zeek Cluster Framework. + * This function populates the "Cluster::nodes" script-layer variable + * that otherwise is expected to be populated by a + * "cluster-layout.zeek" script in other context (e.g. ZeekCtl + * generates that cluster layout). + * @return true if the supervised node is using the Cluster Framework + * else false. + */ + bool InitCluster() const; + + /** + * Initialize the Supervised node. + * @param options the Zeek options to extend/modify as appropriate + * for the node's configuration. + */ + void Init(zeek::Options* options) const; + + /** + * The node's configuration options. + */ + Supervisor::NodeConfig config; + /** + * The process ID of the supervised node's parent process (i.e. the PID + * of the Stem process). + */ + pid_t parent_pid; +}; + +/** + * The state of a supervised node from the Supervisor's perspective. + */ +struct SupervisorNode { + /** + * Convert the node into script-layer Supervisor::NodeStatus record + * representation. + */ + RecordValPtr ToRecord() const; + + /** + * @return the name of the node. + */ + const std::string& Name() const + { return config.name; } + + /** + * Create a new node state from a given configuration. + * @param arg_config the configuration to use for the node. + */ + SupervisorNode(Supervisor::NodeConfig arg_config) : config(std::move(arg_config)) + { } + + /** + * The desired configuration for the node. + */ + Supervisor::NodeConfig config; + /** + * Process ID of the node (positive/non-zero are valid/live PIDs). + */ + pid_t pid = 0; + /** + * Whether the node is voluntarily marked for termination by the + * Supervisor. + */ + bool killed = false; + /** + * The last exit status of the node. + */ + int exit_status = 0; + /** + * The last signal which terminated the node. + */ + int signal_number = 0; + /** + * Number of process revival attempts made after the node first died + * prematurely. + */ + int revival_attempts = 0; + /** + * How many seconds to wait until the next revival attempt for the node. + */ + int revival_delay = 1; + /** + * The time at which the node's process was last spawned. + */ + std::chrono::time_point spawn_time; + /** + * A pipe that the Supervisor Stem can read from to obtain + * any output written to the Nodes's stdout. + */ + zeek::detail::LineBufferedPipe stdout_pipe; + /** + * A pipe that the Supervisor Stem can read from to obtain + * any output written to the Node's stdout. + */ + zeek::detail::LineBufferedPipe stderr_pipe; +}; + /** * A timer used by supervised processes to periodically check whether their * parent (supervisor) process has died. If it has died, the supervised