diff --git a/NEWS b/NEWS index b8d0c39564..4b14c8d423 100644 --- a/NEWS +++ b/NEWS @@ -71,6 +71,12 @@ New Functionality directly or indirectly. The number is not meant to be precise, but rather comparable: larger footprint correlates with more memory consumption. +- The Supervisor features two new events, ``Supervisor::node_status`` and + ``SupervisorControl::node_status``, to notify recipients of the fact that + the stem process has (re-)started a node. The events indicate the node's + name and its new PID, reflecting the information the stem already shares + with the Supervisor core. + - The new ``configure --statedir`` option lets you adjust the installation's persistent state directory. It defaults to ``var/lib`` under your Zeek installation's root directory. diff --git a/scripts/base/frameworks/supervisor/api.zeek b/scripts/base/frameworks/supervisor/api.zeek index 01c41f6f14..da3ddde0e3 100644 --- a/scripts/base/frameworks/supervisor/api.zeek +++ b/scripts/base/frameworks/supervisor/api.zeek @@ -150,4 +150,15 @@ export { ## ## msg: line-buffered contents from the stderr of a child process. global stderr_hook: hook(node: string, msg: string); + + ## A notification event the Supervisor generates when it receives a + ## status message update from the stem, indicating node has + ## (re-)started. + ## + ## node: the name of a previously created node via + ## :zeek:see:`Supervisor::create` indicating to which + ## child process the stdout line is associated. + ## + ## pid: the process ID the stem reported for this node. + global node_status: event(node: string, pid: count); } diff --git a/scripts/base/frameworks/supervisor/control.zeek b/scripts/base/frameworks/supervisor/control.zeek index ed9c083cb9..acbb578f7a 100644 --- a/scripts/base/frameworks/supervisor/control.zeek +++ b/scripts/base/frameworks/supervisor/control.zeek @@ -91,4 +91,16 @@ export { ## process tree. There is no response to this message as the Supervisor ## simply terminates on receipt. global SupervisorControl::stop_request: event(); + + ## A notification event the Supervisor generates when it receives a + ## status message update from the stem, indicating node has + ## (re-)started. This is the remote equivalent of + ## :zeek:see:`Supervisor::node_status`. + ## + ## node: the name of a previously created node via + ## :zeek:see:`Supervisor::create` indicating to which + ## child process the stdout line is associated. + ## + ## pid: the process ID the stem reported for this node. + global SupervisorControl::node_status: event(node: string, pid: count); } diff --git a/scripts/base/frameworks/supervisor/main.zeek b/scripts/base/frameworks/supervisor/main.zeek index 171ccc6971..fbc7cf1009 100644 --- a/scripts/base/frameworks/supervisor/main.zeek +++ b/scripts/base/frameworks/supervisor/main.zeek @@ -99,3 +99,12 @@ event SupervisorControl::restart_request(reqid: string, node: string) local topic = SupervisorControl::topic_prefix + fmt("/restart_response/%s", reqid); Broker::publish(topic, SupervisorControl::restart_response, reqid, res); } + +event Supervisor::node_status(node: string, pid: count) + { + if ( ! Supervisor::is_supervisor() ) + return; + + local topic = SupervisorControl::topic_prefix + "/node_status"; + Broker::publish(topic, SupervisorControl::node_status, node, pid); + } diff --git a/src/supervisor/Supervisor.cc b/src/supervisor/Supervisor.cc index 53d9f4a77f..556be2a5fe 100644 --- a/src/supervisor/Supervisor.cc +++ b/src/supervisor/Supervisor.cc @@ -26,6 +26,8 @@ extern "C" #include "zeek/DebugLogger.h" #include "zeek/Dict.h" +#include "zeek/Event.h" +#include "zeek/EventHandler.h" #include "zeek/ID.h" #include "zeek/NetVar.h" #include "zeek/RE.h" @@ -484,6 +486,8 @@ void Supervisor::HandleChildSignal() void Supervisor::InitPostScript() { + node_status = event_registry->Register("Supervisor::node_status"); + stem_stdout.hook = id::find_func("Supervisor::stdout_hook"); stem_stderr.hook = id::find_func("Supervisor::stderr_hook"); @@ -597,6 +601,10 @@ size_t Supervisor::ProcessMessages() if ( it != nodes.end() ) it->second.pid = std::stoi(msg_tokens[2]); + + if ( node_status ) + event_mgr.Enqueue(node_status, make_intrusive(name), + val_mgr->Count(std::stoi(msg_tokens[2]))); } else if ( type == "debug" ) { diff --git a/src/supervisor/Supervisor.h b/src/supervisor/Supervisor.h index d2895b0156..ec3e08bb2b 100644 --- a/src/supervisor/Supervisor.h +++ b/src/supervisor/Supervisor.h @@ -332,6 +332,7 @@ private: detail::Flare signal_flare; NodeMap nodes; std::string msg_buffer; + EventHandlerPtr node_status; }; namespace detail diff --git a/testing/btest/Baseline/core.check-unused-event-handlers/.stderr b/testing/btest/Baseline/core.check-unused-event-handlers/.stderr index 808ae449a1..247ea60e17 100644 --- a/testing/btest/Baseline/core.check-unused-event-handlers/.stderr +++ b/testing/btest/Baseline/core.check-unused-event-handlers/.stderr @@ -2,6 +2,7 @@ ### NOTE: This file has been sorted with diff-sort. warning in , line 1: event handler never invoked: InputConfig::new_value warning in , line 1: event handler never invoked: InputRaw::process_finished +warning in , line 1: event handler never invoked: Supervisor::node_status warning in , line 1: event handler never invoked: SupervisorControl::create_request warning in , line 1: event handler never invoked: SupervisorControl::destroy_request warning in , line 1: event handler never invoked: SupervisorControl::restart_request diff --git a/testing/btest/Baseline/supervisor.node_status/zeek..stdout b/testing/btest/Baseline/supervisor.node_status/zeek..stdout new file mode 100644 index 0000000000..072133ecfc --- /dev/null +++ b/testing/btest/Baseline/supervisor.node_status/zeek..stdout @@ -0,0 +1,3 @@ +### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63. +got node_status event, grault +got node_status event, grault diff --git a/testing/btest/supervisor/node_status.zeek b/testing/btest/supervisor/node_status.zeek new file mode 100644 index 0000000000..e6652386c3 --- /dev/null +++ b/testing/btest/supervisor/node_status.zeek @@ -0,0 +1,47 @@ +# This test verifies that the Supervisor triggers Supervisor::node_status +# events when the stem (re)creates nodes. +# +# @TEST-EXEC: btest-bg-run zeek zeek -j -b %INPUT +# @TEST-EXEC: btest-bg-wait 30 +# @TEST-EXEC: btest-diff zeek/.stdout + +# So the supervised node doesn't terminate right away. +redef exit_only_after_terminate=T; + +global status_count = 0; +global check_interval = 0.1sec; + +event Supervisor::node_status(node: string, pid: count) + { + # We handle this once for the initial node creation, once for the + # restart, then quit. + if ( ++status_count == 2) + terminate(); + + print "got node_status event", node; + + # The status update has a PID for the new node, so checking node status + # now should report a matching PID. This will output only in case the + # PIDs do not match, failing the test. + local s = Supervisor::status(node); + local ns = s$nodes["grault"]; + + if ( ! ns$pid ) + print "pid unavailable via Supervisor::status()", pid; + else if ( ns$pid != pid ) + print "pid mismatch", ns$pid, pid; + + Supervisor::restart("grault"); + } + +event zeek_init() + { + if ( Supervisor::is_supervisor() ) + { + local sn = Supervisor::NodeConfig($name="grault"); + local res = Supervisor::create(sn); + + if ( res != "" ) + print "failed to create node", res; + } + }