From 4c0543d0ed8be353bbf2682915fd1ed0ab5aee6d Mon Sep 17 00:00:00 2001 From: Christian Kreibich Date: Thu, 9 Jun 2022 22:15:25 -0700 Subject: [PATCH 1/3] Management framework: fix module naming typo This had no effect since this module name wasn't used anywhere else. --- scripts/policy/frameworks/management/agent/main.zeek | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/policy/frameworks/management/agent/main.zeek b/scripts/policy/frameworks/management/agent/main.zeek index 6105edb8dd..a958d45612 100644 --- a/scripts/policy/frameworks/management/agent/main.zeek +++ b/scripts/policy/frameworks/management/agent/main.zeek @@ -15,7 +15,7 @@ @load ./api @load ./config -module Mangement::Agent::Runtime; +module Management::Agent::Runtime; # This export is mainly to appease Zeekygen's need to understand redefs of the # Request record below. Without it, it fails to establish link targets for the From a3fcd1462d0f3c338d3d3bdd07a2ce8c3da48484 Mon Sep 17 00:00:00 2001 From: Christian Kreibich Date: Thu, 9 Jun 2022 22:16:20 -0700 Subject: [PATCH 2/3] Management framework: make agents support zeek-archiver invocations This makes agents handle log archival automatically. By default, they invoke zeek-archiver once every log rotation interval to archive rotated files from the log-queue spool directory into the installation's log directory. The user can disable the feature, customize the command to invoke, and adjust the rotation interval. --- .../frameworks/management/agent/config.zeek | 21 +++++++ .../frameworks/management/agent/main.zeek | 60 +++++++++++++++++++ 2 files changed, 81 insertions(+) diff --git a/scripts/policy/frameworks/management/agent/config.zeek b/scripts/policy/frameworks/management/agent/config.zeek index ae9266c57a..e6cd13bb9d 100644 --- a/scripts/policy/frameworks/management/agent/config.zeek +++ b/scripts/policy/frameworks/management/agent/config.zeek @@ -1,5 +1,6 @@ ##! Configuration settings for a cluster agent. +@load base/misc/installation @load policy/frameworks/management # We source the controller configuration to obtain its network coordinates, so @@ -44,6 +45,26 @@ export { ## The fallback listen port if :zeek:see:`Management::Agent::listen_port` remains empty. const default_port = 2151/tcp &redef; + ## Whether the agent should periodically invoke zeek-archiver to + ## finalize logs. + const archive_logs = T &redef; + + ## The archival interval to use. When 0, it defaults to the log rotation + ## interval. + const archive_interval = 0 sec &redef; + + ## The archival command. When empty, defaults to the zeek-archiver + ## installed with the Zeek distribution. Whatever the command, the + ## agent will invoke it like zeek-archiver, so take a look at its + ## command-line arguments if you're planning to put in place a + ## substitute. Archival happens from the + ## :zeek:see:`Log::default_rotation_dir` to + ## :zeek:see:`Management::Agent::archive_dir`. + const archive_cmd = "" &redef; + + ## The destination interval for archived logs. + const archive_dir = Installation::log_dir &redef; + ## The agent's Broker topic prefix. For its own communication, the agent ## suffixes this with "/", based on :zeek:see:`Management::Agent::get_name`. const topic_prefix = "zeek/management/agent" &redef; diff --git a/scripts/policy/frameworks/management/agent/main.zeek b/scripts/policy/frameworks/management/agent/main.zeek index a958d45612..4757f5a3ec 100644 --- a/scripts/policy/frameworks/management/agent/main.zeek +++ b/scripts/policy/frameworks/management/agent/main.zeek @@ -43,6 +43,17 @@ export { ## Request state for every node managed by this agent. requests: set[string] &default=set(); }; + + # When Management::Agent::archive_logs is T (the default) and the + # logging configuration doesn't permanently prevent archival + # (e.g. because log rotation isn't configured), the agent triggers this + # event each Management::Controller::archive_interval to initiate log + # archival. + # + # run_archival: whether to actually invoke the archiver or just + # ensure (re-)scheduling. + # + global trigger_log_archival: event(run_archival: bool &default=T); } # We need to go out of our way here to avoid colliding record field names with @@ -142,6 +153,52 @@ function send_set_configuration_response(req: Management::Request::Request) g_config_reqid_pending = ""; } +event Management::Agent::Runtime::trigger_log_archival(run_archival: bool) + { + # This is currently final, but could be considered dynamically in the + # future if we make this an option. + if ( Management::Agent::archive_logs == F ) + return; + + local ival = Management::Agent::archive_interval; + + # Fall back to the default rotation interval when not set explicitly: + if ( ival == 0 secs ) + ival = Log::default_rotation_interval; + + # Without a default rotation interval individual log streams might still + # have rotation enabled, and we could scan all filters to determine + # their rotation configuration. But it's not clear that this is + # intuitive or needed, since it's uncommon to want rotation for only + # some logs. So we simply don't proceed if it's not configured. + if ( ival == 0 secs ) + return; + + local cmd = Management::Agent::archive_cmd; + + if ( cmd == "" ) + { + cmd = join_string_vec(vector(Installation::root_dir, "bin"), "/"); + cmd = build_path_compressed(cmd, "zeek-archiver"); + } + + # The logging framework creates the rotation directory on demand, so + # only trigger archival when it exists. Don't warn when it does not: + # this will often be expected, since in larger clusters many instances + # may not run loggers. + if ( run_archival && file_size(Log::default_rotation_dir) > 0 ) + { + cmd = fmt("%s -1 %s %s", + cmd, Log::default_rotation_dir, + Management::Agent::archive_dir); + + Management::Log::info(fmt("triggering log archival via '%s'", cmd)); + system(cmd); + } + + schedule ival { Management::Agent::Runtime::trigger_log_archival() }; + } + event Management::Supervisor::API::notify_node_exit(node: string, outputs: Management::NodeOutputs) { if ( node in g_nodes ) @@ -737,5 +794,8 @@ event zeek_init() # If the controller connects to us, it also uses this port. Broker::listen(cat(epi$network$address), epi$network$bound_port); + if ( Management::Agent::archive_logs ) + schedule 0 secs { Management::Agent::Runtime::trigger_log_archival(F) }; + Management::Log::info(fmt("agent is live, Broker ID %s", Broker::node_id())); } From e92c78798720ff91a8078e6ab51b7ac88e1f44a3 Mon Sep 17 00:00:00 2001 From: Christian Kreibich Date: Fri, 10 Jun 2022 14:01:53 -0700 Subject: [PATCH 3/3] Management framework: bump external cluster testsuite --- testing/external/commit-hash.zeek-testing-cluster | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/external/commit-hash.zeek-testing-cluster b/testing/external/commit-hash.zeek-testing-cluster index d9b7621df3..a9ffaaa89b 100644 --- a/testing/external/commit-hash.zeek-testing-cluster +++ b/testing/external/commit-hash.zeek-testing-cluster @@ -1 +1 @@ -a1c8c09c8c661a1ea9299e0356f3652502b8dcd2 +67ecd94d8e1cf5e95637dae7d4430cbdf05dab1f