Management framework: enable stdout/stderr reporting

This uses the new frameworks/management/supervisor functionality to maintain
stdout/stderr files, and hooks output context into set_configuration error
results.
This commit is contained in:
Christian Kreibich 2022-05-30 18:51:15 -07:00
parent 24a495da42
commit f10b94de39
5 changed files with 34 additions and 17 deletions

View file

@ -12,5 +12,6 @@
@endif @endif
@if ( Supervisor::is_supervisor() ) @if ( Supervisor::is_supervisor() )
@load policy/frameworks/management/supervisor
@load ./boot @load ./boot
@endif @endif

View file

@ -39,10 +39,9 @@ event zeek_init()
if ( ! mkdir(sn$directory) ) if ( ! mkdir(sn$directory) )
print(fmt("warning: could not create agent state dir '%s'", sn$directory)); print(fmt("warning: could not create agent state dir '%s'", sn$directory));
if ( Management::Agent::stdout_file != "" ) # We don't set sn$stdout_file/stderr_file here because the Management
sn$stdout_file = Management::Agent::stdout_file; # framework's Supervisor shim manages those output files itself. See
if ( Management::Agent::stderr_file != "" ) # frameworks/management/supervisor/main.zeek for details.
sn$stderr_file = Management::Agent::stderr_file;
# This helps identify Management framework nodes reliably. # This helps identify Management framework nodes reliably.
sn$env["ZEEK_MANAGEMENT_NODE"] = "AGENT"; sn$env["ZEEK_MANAGEMENT_NODE"] = "AGENT";

View file

@ -9,6 +9,8 @@
@load policy/frameworks/management @load policy/frameworks/management
@load policy/frameworks/management/node/api @load policy/frameworks/management/node/api
@load policy/frameworks/management/node/config @load policy/frameworks/management/node/config
@load policy/frameworks/management/supervisor/api
@load policy/frameworks/management/supervisor/config
@load ./api @load ./api
@load ./config @load ./config
@ -91,6 +93,10 @@ global g_config_reqid_pending: string = "";
# configurations. # configurations.
global g_cluster: table[string] of Supervisor::ClusterEndpoint; global g_cluster: table[string] of Supervisor::ClusterEndpoint;
# The most recent output contexts we've received from the Supervisor, for
# any of our nodes.
global g_outputs: table[string] of Management::NodeOutputs;
function agent_topic(): string function agent_topic(): string
{ {
@ -113,11 +119,12 @@ function send_set_configuration_response(req: Management::Request::Request)
if ( node in req$set_configuration_state_agent$nodes_pending ) if ( node in req$set_configuration_state_agent$nodes_pending )
{ {
# This node failed. Pull in any stdout/stderr context # This node failed.
# we might have.
res$success = F; res$success = F;
# XXX fill in stdout/stderr here if possible # Pull in any stdout/stderr context we might have.
if ( node in g_outputs )
res$data = g_outputs[node];
} }
# Add this result to the overall response # Add this result to the overall response
@ -135,6 +142,12 @@ function send_set_configuration_response(req: Management::Request::Request)
g_config_reqid_pending = ""; g_config_reqid_pending = "";
} }
event Management::Supervisor::API::notify_node_exit(node: string, outputs: Management::NodeOutputs)
{
if ( node in g_nodes )
g_outputs[node] = outputs;
}
event SupervisorControl::create_response(reqid: string, result: string) event SupervisorControl::create_response(reqid: string, result: string)
{ {
local req = Management::Request::lookup(reqid); local req = Management::Request::lookup(reqid);
@ -315,10 +328,10 @@ event Management::Agent::API::set_configuration_request(reqid: string, config: M
# node. # node.
nc$scripts[|nc$scripts|] = "policy/frameworks/management/node"; nc$scripts[|nc$scripts|] = "policy/frameworks/management/node";
if ( Management::Node::stdout_file != "" ) # We don't set nc$stdout_file/stderr_file here because the
nc$stdout_file = Management::Node::stdout_file; # Management framework's Supervisor shim manages those output
if ( Management::Node::stderr_file != "" ) # files itself. See frameworks/management/supervisor/main.zeek
nc$stderr_file = Management::Node::stderr_file; # for details.
# XXX could use options to enable per-node overrides for # XXX could use options to enable per-node overrides for
# directory, stdout, stderr, others? # directory, stdout, stderr, others?
@ -708,6 +721,7 @@ event zeek_init()
Broker::subscribe(agent_topic()); Broker::subscribe(agent_topic());
Broker::subscribe(SupervisorControl::topic_prefix); Broker::subscribe(SupervisorControl::topic_prefix);
Broker::subscribe(Management::Node::node_topic); Broker::subscribe(Management::Node::node_topic);
Broker::subscribe(Management::Supervisor::topic_prefix);
# Establish connectivity with the controller. # Establish connectivity with the controller.
if ( Management::Agent::controller$address != "0.0.0.0" ) if ( Management::Agent::controller$address != "0.0.0.0" )

View file

@ -34,10 +34,9 @@ event zeek_init()
if ( ! mkdir(sn$directory) ) if ( ! mkdir(sn$directory) )
print(fmt("warning: could not create controller state dir '%s'", sn$directory)); print(fmt("warning: could not create controller state dir '%s'", sn$directory));
if ( Management::Controller::stdout_file != "" ) # We don't set sn$stdout_file/stderr_file here because the Management
sn$stdout_file = Management::Controller::stdout_file; # framework's Supervisor shim manages those output files itself. See
if ( Management::Controller::stderr_file != "" ) # frameworks/management/supervisor/main.zeek for details.
sn$stderr_file = Management::Controller::stderr_file;
# This helps identify Management framework nodes reliably. # This helps identify Management framework nodes reliably.
sn$env["ZEEK_MANAGEMENT_NODE"] = "CONTROLLER"; sn$env["ZEEK_MANAGEMENT_NODE"] = "CONTROLLER";

View file

@ -363,11 +363,15 @@ event Management::Agent::API::set_configuration_response(reqid: string, results:
if ( Management::Request::is_null(req) ) if ( Management::Request::is_null(req) )
return; return;
# XXX the usual "any" handling needs to happen here if data is filled in
# Add this agent's results to the overall response # Add this agent's results to the overall response
for ( i in results ) for ( i in results )
{
# The usual "any" treatment to keep access predictable
if ( results[i]?$data )
results[i]$data = results[i]$data as Management::NodeOutputs;
req$results[|req$results|] = results[i]; req$results[|req$results|] = results[i];
}
# Mark this request as done by removing it from the table of pending # Mark this request as done by removing it from the table of pending
# ones. The following if-check should always be true. # ones. The following if-check should always be true.