mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 14:48:21 +00:00
Merge remote-tracking branch 'origin/topic/awelzel/pluggable-cluster-backends-part1'
* origin/topic/awelzel/pluggable-cluster-backends-part1: btest: Test Broker::make_event() together with Cluster::publish_hrw() btest: Add cluster dir, minimal test for enum value broker: Add shim plugin adding a backend component zeek-setup: Instantiate backend::manager cluster: Add to src/CMakeLists.txt cluster: Add Components and ComponentManager for new components cluster/Backend: Interface for cluster backends cluster/Serializer: Interface for event and log serializers logging: Introduce logging/Types.h SerialTypes/Field: Allow default construction and add move constructor DebugLogger: Add cluster debugging stream plugin: Add component enums for pluggable cluster backends broker: Pass frame to MakeEvent()
This commit is contained in:
commit
97f05b2f8c
34 changed files with 1542 additions and 28 deletions
44
CHANGES
44
CHANGES
|
@ -1,3 +1,47 @@
|
||||||
|
7.1.0-dev.607 | 2024-11-22 12:32:21 +0100
|
||||||
|
|
||||||
|
* btest: Test Broker::make_event() together with Cluster::publish_hrw() (Arne Welzel, Corelight)
|
||||||
|
|
||||||
|
* btest: Add cluster dir, minimal test for enum value (Arne Welzel, Corelight)
|
||||||
|
|
||||||
|
* broker: Add shim plugin adding a backend component (Arne Welzel, Corelight)
|
||||||
|
|
||||||
|
For broker, this isn't really functioning, but at least makes the
|
||||||
|
CLUSTER_BACKEND_BROKER enum available.
|
||||||
|
|
||||||
|
* zeek-setup: Instantiate backend::manager (Arne Welzel, Corelight)
|
||||||
|
|
||||||
|
Required to allow registration of cluster components.
|
||||||
|
|
||||||
|
* cluster: Add to src/CMakeLists.txt (Arne Welzel, Corelight)
|
||||||
|
|
||||||
|
* cluster: Add Components and ComponentManager for new components (Arne Welzel, Corelight)
|
||||||
|
|
||||||
|
* cluster/Backend: Interface for cluster backends (Arne Welzel, Corelight)
|
||||||
|
|
||||||
|
* cluster/Serializer: Interface for event and log serializers (Arne Welzel, Corelight)
|
||||||
|
|
||||||
|
* logging: Introduce logging/Types.h (Arne Welzel, Corelight)
|
||||||
|
|
||||||
|
Header and implementation for types shared between the cluster and
|
||||||
|
logging framework. The logging framework will be adapted later to
|
||||||
|
use these. For now, the new cluster components will simply reference
|
||||||
|
them.
|
||||||
|
|
||||||
|
* SerialTypes/Field: Allow default construction and add move constructor (Arne Welzel, Corelight)
|
||||||
|
|
||||||
|
This is in preparation of using SerialTypes to serialize and
|
||||||
|
unserialize complete log batches which include Field instances
|
||||||
|
and not just Value's.
|
||||||
|
|
||||||
|
* DebugLogger: Add cluster debugging stream (Arne Welzel, Corelight)
|
||||||
|
|
||||||
|
* plugin: Add component enums for pluggable cluster backends (Arne Welzel, Corelight)
|
||||||
|
|
||||||
|
* broker: Pass frame to MakeEvent() (Arne Welzel, Corelight)
|
||||||
|
|
||||||
|
This was lost in a prior change.
|
||||||
|
|
||||||
7.1.0-dev.592 | 2024-11-21 16:38:55 +0100
|
7.1.0-dev.592 | 2024-11-21 16:38:55 +0100
|
||||||
|
|
||||||
* sumstat/non-cluster: Move last epoch processing to zeek_done() (Arne Welzel, Corelight)
|
* sumstat/non-cluster: Move last epoch processing to zeek_done() (Arne Welzel, Corelight)
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
||||||
7.1.0-dev.592
|
7.1.0-dev.607
|
||||||
|
|
|
@ -280,6 +280,14 @@ export {
|
||||||
## Returns: a topic string that may used to send a message exclusively to
|
## Returns: a topic string that may used to send a message exclusively to
|
||||||
## a given cluster node.
|
## a given cluster node.
|
||||||
global nodeid_topic: function(id: string): string;
|
global nodeid_topic: function(id: string): string;
|
||||||
|
|
||||||
|
## An event instance for cluster pub/sub.
|
||||||
|
type Event: record {
|
||||||
|
## The event handler to be invoked on the remote node.
|
||||||
|
ev: any;
|
||||||
|
## The arguments for the event.
|
||||||
|
args: vector of any;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
# Track active nodes per type.
|
# Track active nodes per type.
|
||||||
|
|
|
@ -194,6 +194,7 @@ gen_zam_target(${GEN_ZAM_SRC_DIR})
|
||||||
option(USE_SQLITE "Should Zeek use SQLite?" ON)
|
option(USE_SQLITE "Should Zeek use SQLite?" ON)
|
||||||
|
|
||||||
add_subdirectory(analyzer)
|
add_subdirectory(analyzer)
|
||||||
|
add_subdirectory(cluster)
|
||||||
add_subdirectory(packet_analysis)
|
add_subdirectory(packet_analysis)
|
||||||
add_subdirectory(broker)
|
add_subdirectory(broker)
|
||||||
add_subdirectory(telemetry)
|
add_subdirectory(telemetry)
|
||||||
|
|
|
@ -19,7 +19,8 @@ DebugLogger::Stream DebugLogger::streams[NUM_DBGS] =
|
||||||
{"main-loop", 0, false}, {"dpd", 0, false}, {"packet-analysis", 0, false}, {"file-analysis", 0, false},
|
{"main-loop", 0, false}, {"dpd", 0, false}, {"packet-analysis", 0, false}, {"file-analysis", 0, false},
|
||||||
{"tm", 0, false}, {"logging", 0, false}, {"input", 0, false}, {"threading", 0, false},
|
{"tm", 0, false}, {"logging", 0, false}, {"input", 0, false}, {"threading", 0, false},
|
||||||
{"plugins", 0, false}, {"zeekygen", 0, false}, {"pktio", 0, false}, {"broker", 0, false},
|
{"plugins", 0, false}, {"zeekygen", 0, false}, {"pktio", 0, false}, {"broker", 0, false},
|
||||||
{"scripts", 0, false}, {"supervisor", 0, false}, {"hashkey", 0, false}, {"spicy", 0, false}};
|
{"scripts", 0, false}, {"supervisor", 0, false}, {"hashkey", 0, false}, {"spicy", 0, false},
|
||||||
|
{"cluster", 0, false}};
|
||||||
|
|
||||||
DebugLogger::~DebugLogger() {
|
DebugLogger::~DebugLogger() {
|
||||||
if ( file && file != stderr )
|
if ( file && file != stderr )
|
||||||
|
|
|
@ -54,6 +54,7 @@ enum DebugStream {
|
||||||
DBG_SUPERVISOR, // Process supervisor
|
DBG_SUPERVISOR, // Process supervisor
|
||||||
DBG_HASHKEY, // HashKey buffers
|
DBG_HASHKEY, // HashKey buffers
|
||||||
DBG_SPICY, // Spicy functionality
|
DBG_SPICY, // Spicy functionality
|
||||||
|
DBG_CLUSTER, // Cluster functionality
|
||||||
|
|
||||||
NUM_DBGS // Has to be last
|
NUM_DBGS // Has to be last
|
||||||
};
|
};
|
||||||
|
|
|
@ -12,3 +12,6 @@ zeek_add_subdir_library(
|
||||||
data.bif
|
data.bif
|
||||||
messaging.bif
|
messaging.bif
|
||||||
store.bif)
|
store.bif)
|
||||||
|
|
||||||
|
# Small plugin shim to make the CLUSTER_BACKEND_BROKER enum value available.
|
||||||
|
zeek_add_plugin(Zeek Cluster_Backend_Broker SOURCES Plugin.cc)
|
||||||
|
|
28
src/broker/Plugin.cc
Normal file
28
src/broker/Plugin.cc
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
#include "zeek/broker/Plugin.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "zeek/cluster/Backend.h"
|
||||||
|
#include "zeek/cluster/Component.h"
|
||||||
|
#include "zeek/cluster/Serializer.h"
|
||||||
|
|
||||||
|
using namespace zeek::plugin::Zeek_Cluster_Backend_Broker;
|
||||||
|
|
||||||
|
zeek::plugin::Configuration Plugin::Configure() {
|
||||||
|
// For now, there's always the broker_mgr instance that's explicitly
|
||||||
|
// instantiated in zeek-setup.cc. Don't even allow to instantiate
|
||||||
|
// a second one via the plugin mechanism. In the future, this could
|
||||||
|
// be changed so that broker is instantiated on demand only.
|
||||||
|
auto fail_instantiate = [](std::unique_ptr<cluster::EventSerializer>,
|
||||||
|
std::unique_ptr<cluster::LogSerializer>) -> std::unique_ptr<cluster::Backend> {
|
||||||
|
zeek::reporter->FatalError("do not instantiate broker explicitly");
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
AddComponent(new cluster::BackendComponent("BROKER", fail_instantiate));
|
||||||
|
|
||||||
|
zeek::plugin::Configuration config;
|
||||||
|
config.name = "Zeek::Cluster_Backend_Broker";
|
||||||
|
config.description = "Cluster backend using Broker";
|
||||||
|
return config;
|
||||||
|
}
|
14
src/broker/Plugin.h
Normal file
14
src/broker/Plugin.h
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "zeek/plugin/Plugin.h"
|
||||||
|
|
||||||
|
namespace zeek::plugin::Zeek_Cluster_Backend_Broker {
|
||||||
|
|
||||||
|
class Plugin : public zeek::plugin::Plugin {
|
||||||
|
public:
|
||||||
|
zeek::plugin::Configuration Configure() override;
|
||||||
|
} plugin;
|
||||||
|
|
||||||
|
} // namespace zeek::plugin::Zeek_Cluster_Backend_Broker
|
|
@ -99,7 +99,7 @@ function Broker::make_event%(...%): Broker::Event
|
||||||
%{
|
%{
|
||||||
zeek::Broker::Manager::ScriptScopeGuard ssg;
|
zeek::Broker::Manager::ScriptScopeGuard ssg;
|
||||||
|
|
||||||
auto ev = zeek::broker_mgr->MakeEvent(ArgsSpan{*@ARGS@});
|
auto ev = zeek::broker_mgr->MakeEvent(ArgsSpan{*@ARGS@}, frame);
|
||||||
return zeek::cast_intrusive<RecordVal>(ev);
|
return zeek::cast_intrusive<RecordVal>(ev);
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
|
214
src/cluster/Backend.cc
Normal file
214
src/cluster/Backend.cc
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#include "zeek/cluster/Backend.h"
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include "zeek/Desc.h"
|
||||||
|
#include "zeek/Event.h"
|
||||||
|
#include "zeek/EventRegistry.h"
|
||||||
|
#include "zeek/Func.h"
|
||||||
|
#include "zeek/Reporter.h"
|
||||||
|
#include "zeek/Type.h"
|
||||||
|
#include "zeek/cluster/Serializer.h"
|
||||||
|
#include "zeek/iosource/Manager.h"
|
||||||
|
|
||||||
|
using namespace zeek::cluster;
|
||||||
|
|
||||||
|
std::optional<zeek::Args> detail::check_args(const zeek::FuncValPtr& handler, zeek::ArgsSpan args) {
|
||||||
|
const auto& func_type = handler->GetType<zeek::FuncType>();
|
||||||
|
|
||||||
|
if ( func_type->Flavor() != zeek::FUNC_FLAVOR_EVENT ) {
|
||||||
|
zeek::reporter->Error("unexpected function type for %s: %s", handler->AsFunc()->GetName().c_str(),
|
||||||
|
func_type->FlavorString().c_str());
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& types = func_type->ParamList()->GetTypes();
|
||||||
|
if ( args.size() != types.size() ) {
|
||||||
|
zeek::reporter->Error("bad number of arguments for %s: got %zu, expect %zu",
|
||||||
|
handler->AsFunc()->GetName().c_str(), args.size(), types.size());
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
zeek::Args result(args.size());
|
||||||
|
|
||||||
|
for ( size_t i = 0; i < args.size(); i++ ) {
|
||||||
|
const auto& a = args[i];
|
||||||
|
const auto& got_type = a->GetType();
|
||||||
|
const auto& expected_type = types[i];
|
||||||
|
|
||||||
|
if ( ! same_type(got_type, expected_type) ) {
|
||||||
|
zeek::reporter->Error("event parameter #%zu type mismatch, got %s, expecting %s", i + 1,
|
||||||
|
zeek::obj_desc_short(got_type.get()).c_str(),
|
||||||
|
zeek::obj_desc_short(expected_type.get()).c_str());
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
result[i] = args[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<detail::Event> Backend::MakeClusterEvent(FuncValPtr handler, ArgsSpan args, double timestamp) const {
|
||||||
|
auto checked_args = detail::check_args(handler, args);
|
||||||
|
if ( ! checked_args )
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
if ( timestamp == 0.0 )
|
||||||
|
timestamp = zeek::event_mgr.CurrentEventTime();
|
||||||
|
|
||||||
|
const auto& eh = zeek::event_registry->Lookup(handler->AsFuncPtr()->GetName());
|
||||||
|
if ( ! eh ) {
|
||||||
|
zeek::reporter->Error("event registry lookup of '%s' failed", obj_desc(handler.get()).c_str());
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
return zeek::cluster::detail::Event{eh, std::move(*checked_args), timestamp};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default implementation doing the serialization.
|
||||||
|
bool Backend::DoPublishEvent(const std::string& topic, const cluster::detail::Event& event) {
|
||||||
|
cluster::detail::byte_buffer buf;
|
||||||
|
|
||||||
|
if ( ! event_serializer->SerializeEvent(buf, event) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return DoPublishEvent(topic, event_serializer->Name(), buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default implementation doing log record serialization.
|
||||||
|
bool Backend::DoPublishLogWrites(const zeek::logging::detail::LogWriteHeader& header,
|
||||||
|
zeek::Span<zeek::logging::detail::LogRecord> records) {
|
||||||
|
cluster::detail::byte_buffer buf;
|
||||||
|
|
||||||
|
if ( ! log_serializer->SerializeLogWrite(buf, header, records) )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return DoPublishLogWrites(header, log_serializer->Name(), buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Backend::ProcessEventMessage(const std::string_view& topic, const std::string_view& format,
|
||||||
|
const detail::byte_buffer_span payload) {
|
||||||
|
if ( format != event_serializer->Name() ) {
|
||||||
|
zeek::reporter->Error("ProcessEventMessage: Wrong format: %s vs %s", std::string{format}.c_str(),
|
||||||
|
event_serializer->Name().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto r = event_serializer->UnserializeEvent(payload);
|
||||||
|
|
||||||
|
if ( ! r ) {
|
||||||
|
auto escaped =
|
||||||
|
util::get_escaped_string(std::string(reinterpret_cast<const char*>(payload.data()), payload.size()), false);
|
||||||
|
zeek::reporter->Error("Failed to unserialize message: %s: %s", std::string{topic}.c_str(), escaped.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& event = *r;
|
||||||
|
zeek::event_mgr.Enqueue(event.Handler(), std::move(event.args), util::detail::SOURCE_BROKER, 0, nullptr,
|
||||||
|
event.timestamp);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Backend::ProcessLogMessage(const std::string_view& format, detail::byte_buffer_span payload) {
|
||||||
|
// We could also dynamically lookup the right de-serializer, but
|
||||||
|
// for now assume we just receive what is configured.
|
||||||
|
if ( format != log_serializer->Name() ) {
|
||||||
|
zeek::reporter->Error("Got log message in format '%s', but have deserializer '%s'", std::string{format}.c_str(),
|
||||||
|
log_serializer->Name().c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto result = log_serializer->UnserializeLogWrite(payload);
|
||||||
|
|
||||||
|
if ( ! result ) {
|
||||||
|
zeek::reporter->Error("Failed to unserialize log message using '%s'", std::string{format}.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Send the whole batch to the logging manager.
|
||||||
|
// return zeek::log_mgr->WritesFromRemote(result->header, std::move(result->records));
|
||||||
|
zeek::reporter->FatalError("not implemented");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ThreadedBackend::ProcessBackendMessage(int tag, detail::byte_buffer_span payload) {
|
||||||
|
return DoProcessBackendMessage(tag, payload);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool register_io_source(zeek::iosource::IOSource* src, int fd, bool dont_count) {
|
||||||
|
constexpr bool manage_lifetime = true;
|
||||||
|
|
||||||
|
zeek::iosource_mgr->Register(src, dont_count, manage_lifetime);
|
||||||
|
|
||||||
|
if ( ! zeek::iosource_mgr->RegisterFd(fd, src) ) {
|
||||||
|
zeek::reporter->Error("Failed to register messages_flare with IO manager");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool ThreadedBackend::DoInit() {
|
||||||
|
// Register as counting during DoInit() to avoid Zeek from shutting down.
|
||||||
|
return register_io_source(this, messages_flare.FD(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadedBackend::DoInitPostScript() {
|
||||||
|
// Register non-counting after parsing scripts.
|
||||||
|
register_io_source(this, messages_flare.FD(), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadedBackend::QueueForProcessing(QueueMessages&& qmessages) {
|
||||||
|
bool fire = false;
|
||||||
|
|
||||||
|
// Enqueue under lock.
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(messages_mtx);
|
||||||
|
fire = messages.empty();
|
||||||
|
|
||||||
|
if ( messages.empty() ) {
|
||||||
|
messages = std::move(qmessages);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
messages.reserve(messages.size() + qmessages.size());
|
||||||
|
for ( auto& qmsg : qmessages )
|
||||||
|
messages.emplace_back(std::move(qmsg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( fire )
|
||||||
|
messages_flare.Fire();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ThreadedBackend::Process() {
|
||||||
|
QueueMessages to_process;
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(messages_mtx);
|
||||||
|
to_process = std::move(messages);
|
||||||
|
messages_flare.Extinguish();
|
||||||
|
messages.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
for ( const auto& msg : to_process ) {
|
||||||
|
// sonarlint wants to use std::visit. not sure...
|
||||||
|
if ( auto* emsg = std::get_if<EventMessage>(&msg) ) {
|
||||||
|
ProcessEventMessage(emsg->topic, emsg->format, emsg->payload_span());
|
||||||
|
}
|
||||||
|
else if ( auto* lmsg = std::get_if<LogMessage>(&msg) ) {
|
||||||
|
ProcessLogMessage(lmsg->format, lmsg->payload_span());
|
||||||
|
}
|
||||||
|
else if ( auto* bmsg = std::get_if<BackendMessage>(&msg) ) {
|
||||||
|
ProcessBackendMessage(bmsg->tag, bmsg->payload_span());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
zeek::reporter->FatalError("Unimplemented QueueMessage %zu", msg.index());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
399
src/cluster/Backend.h
Normal file
399
src/cluster/Backend.h
Normal file
|
@ -0,0 +1,399 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
// The interface for cluster backends and remote events.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <optional>
|
||||||
|
#include <string_view>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
#include "zeek/EventHandler.h"
|
||||||
|
#include "zeek/Flare.h"
|
||||||
|
#include "zeek/IntrusivePtr.h"
|
||||||
|
#include "zeek/Span.h"
|
||||||
|
#include "zeek/cluster/Serializer.h"
|
||||||
|
#include "zeek/iosource/IOSource.h"
|
||||||
|
#include "zeek/logging/Types.h"
|
||||||
|
|
||||||
|
namespace zeek {
|
||||||
|
|
||||||
|
class FuncVal;
|
||||||
|
|
||||||
|
using FuncValPtr = IntrusivePtr<FuncVal>;
|
||||||
|
|
||||||
|
class Val;
|
||||||
|
using ValPtr = IntrusivePtr<Val>;
|
||||||
|
using ArgsSpan = Span<const ValPtr>;
|
||||||
|
|
||||||
|
namespace cluster {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cluster event class.
|
||||||
|
*/
|
||||||
|
class Event {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
|
Event(const EventHandlerPtr& handler, zeek::Args args, double timestamp = 0.0)
|
||||||
|
: handler(handler), args(std::move(args)), timestamp(timestamp) {}
|
||||||
|
|
||||||
|
EventHandlerPtr handler;
|
||||||
|
zeek::Args args;
|
||||||
|
double timestamp; // TODO: This should be more generic, possibly holding a
|
||||||
|
// vector of key/value metadata, rather than just
|
||||||
|
// the timestamp.
|
||||||
|
|
||||||
|
std::string_view HandlerName() const { return handler->Name(); }
|
||||||
|
const EventHandlerPtr& Handler() const { return handler; }
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate that the provided args are suitable for handler.
|
||||||
|
*
|
||||||
|
* @param handler An event handler.
|
||||||
|
* @param args The provide arguments for the handler as a span.
|
||||||
|
*
|
||||||
|
* @return A zeek::Args instance if successful, else std::nullopt.
|
||||||
|
*/
|
||||||
|
std::optional<zeek::Args> check_args(const zeek::FuncValPtr& handler, zeek::ArgsSpan args);
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for a cluster backend implementing publish/subscribe communication.
|
||||||
|
* Serialization of events should be done using the serializers injected into
|
||||||
|
* the constructor.
|
||||||
|
*/
|
||||||
|
class Backend {
|
||||||
|
public:
|
||||||
|
virtual ~Backend() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook invoked after all scripts have been parsed.
|
||||||
|
*/
|
||||||
|
void InitPostScript() { DoInitPostScript(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method invoked from the Cluster::Backend::__init() bif.
|
||||||
|
*/
|
||||||
|
bool Init() { return DoInit(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook invoked when Zeek is about to terminate.
|
||||||
|
*/
|
||||||
|
void Terminate() { DoTerminate(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a cluster::detail::Event instance given an event handler and the
|
||||||
|
* script function arguments to it.
|
||||||
|
*
|
||||||
|
* @param handler A function val representing an event handler.
|
||||||
|
* @param args The arguments for the event handler.
|
||||||
|
* @param timestamp The network time to add to the event as metadata.
|
||||||
|
*/
|
||||||
|
std::optional<detail::Event> MakeClusterEvent(FuncValPtr handler, ArgsSpan args, double timestamp = 0.0) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publish a cluster::detail::Event instance to a given topic.
|
||||||
|
*
|
||||||
|
* @param topic The topic string to publish the event to.
|
||||||
|
* @param event The event to publish.
|
||||||
|
*
|
||||||
|
* @return true if the event was successfully published.
|
||||||
|
*/
|
||||||
|
bool PublishEvent(const std::string& topic, const cluster::detail::Event& event) {
|
||||||
|
return DoPublishEvent(topic, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register interest in messages that use a certain topic prefix.
|
||||||
|
*
|
||||||
|
* @param topic_prefix a prefix to match against remote message topics.
|
||||||
|
* @return true if it's a new event subscription and it is now registered.
|
||||||
|
*/
|
||||||
|
bool Subscribe(const std::string& topic_prefix) { return DoSubscribe(topic_prefix); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister interest in messages on a certain topic.
|
||||||
|
*
|
||||||
|
* @param topic_prefix a prefix previously supplied to Subscribe()
|
||||||
|
* @return true if interest in topic prefix is no longer advertised.
|
||||||
|
*/
|
||||||
|
bool Unsubscribe(const std::string& topic_prefix) { return DoUnsubscribe(topic_prefix); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publish multiple log records.
|
||||||
|
*
|
||||||
|
* All log records belong to the (stream, filter, path) tuple that is
|
||||||
|
* described by \a header.
|
||||||
|
*
|
||||||
|
* @param header Fixed information about the stream, writer, filter and schema of the records.
|
||||||
|
* @param records A span of logging::detail::LogRecords to be published.
|
||||||
|
*/
|
||||||
|
bool PublishLogWrites(const zeek::logging::detail::LogWriteHeader& header,
|
||||||
|
zeek::Span<zeek::logging::detail::LogRecord> records) {
|
||||||
|
return DoPublishLogWrites(header, records);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
|
Backend(std::unique_ptr<EventSerializer> es, std::unique_ptr<LogSerializer> ls)
|
||||||
|
: event_serializer(std::move(es)), log_serializer(std::move(ls)) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process an incoming event message.
|
||||||
|
*/
|
||||||
|
bool ProcessEventMessage(const std::string_view& topic, const std::string_view& format,
|
||||||
|
detail::byte_buffer_span payload);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process an incoming log message.
|
||||||
|
*/
|
||||||
|
bool ProcessLogMessage(const std::string_view& format, detail::byte_buffer_span payload);
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Called after all Zeek scripts have been loaded.
|
||||||
|
*
|
||||||
|
* A cluster backend should initialize itself based on script variables,
|
||||||
|
* register any IO sources, etc. It should not yet start any connections, that
|
||||||
|
* should happen in DoInit() instead.
|
||||||
|
*/
|
||||||
|
virtual void DoInitPostScript() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called from Cluster::Backend::__init().
|
||||||
|
*
|
||||||
|
* Backend implementations should start connections with
|
||||||
|
* remote systems or other nodes, open listening ports or
|
||||||
|
* do whatever is needed to be functional.
|
||||||
|
*/
|
||||||
|
virtual bool DoInit() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called at termination time.
|
||||||
|
*
|
||||||
|
* This should be used to shut down connectivity. Any last messages
|
||||||
|
* to be published should be sent from script land, rather than in
|
||||||
|
* DoTerminate(). A backend may wait for a bounded and configurable
|
||||||
|
* amount of time to flush any last messages out.
|
||||||
|
*/
|
||||||
|
virtual void DoTerminate() = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publish a cluster::detail::Event to the given topic.
|
||||||
|
*
|
||||||
|
* The default implementation serializes to a detail::byte_buffer and
|
||||||
|
* calls DoPublishEvent() with the resulting buffer.
|
||||||
|
*
|
||||||
|
* This hook method only exists for the existing Broker implementation that
|
||||||
|
* short-circuits serialization. Other backends should not override this.
|
||||||
|
*/
|
||||||
|
virtual bool DoPublishEvent(const std::string& topic, const cluster::detail::Event& event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a serialized cluster::detail::Event to the given topic.
|
||||||
|
*
|
||||||
|
* Semantics of this call are "fire-and-forget". An implementation should
|
||||||
|
* ensure the message is enqueued for delivery, but may not have been sent out
|
||||||
|
* let alone received by any subscribers of the topic when this call returns.
|
||||||
|
*
|
||||||
|
* If the backend has not established a connection, the published message is
|
||||||
|
* allowed to be discarded.
|
||||||
|
*
|
||||||
|
* @param topic a topic string associated with the message.
|
||||||
|
* @param format the format/serializer used for serialization of the message payload.
|
||||||
|
* @param buf the serialized Event.
|
||||||
|
* @return true if the message has been published successfully.
|
||||||
|
*/
|
||||||
|
virtual bool DoPublishEvent(const std::string& topic, const std::string& format,
|
||||||
|
const detail::byte_buffer& buf) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register interest in messages that use a certain topic prefix.
|
||||||
|
*
|
||||||
|
* If the backend hasn't yet established a connection, any subscriptions
|
||||||
|
* should be queued until they can be processed.
|
||||||
|
*
|
||||||
|
* @param topic_prefix a prefix to match against remote message topics.
|
||||||
|
*
|
||||||
|
* @return true if it's a new event subscription and now registered.
|
||||||
|
*/
|
||||||
|
virtual bool DoSubscribe(const std::string& topic_prefix) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister interest in messages on a certain topic.
|
||||||
|
*
|
||||||
|
* @param topic_prefix a prefix previously supplied to Subscribe()
|
||||||
|
* @return true if interest in topic prefix is no longer advertised.
|
||||||
|
*/
|
||||||
|
virtual bool DoUnsubscribe(const std::string& topic_prefix) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize a log batch, then forward it to DoPublishLogWrites() below.
|
||||||
|
|
||||||
|
* The default implementation serializes to a detail::byte_buffer and
|
||||||
|
* calls DoPublishLogWrites() with the resulting buffer.
|
||||||
|
*
|
||||||
|
* This hook method only exists for the existing Broker implementation that
|
||||||
|
* short-circuits serialization. Other backends should not override this.
|
||||||
|
*
|
||||||
|
* @param header The header describing the writer frontend where the records originate from.
|
||||||
|
* @param records Records to be serialized.
|
||||||
|
*
|
||||||
|
* @return true if the message has been published successfully.
|
||||||
|
*/
|
||||||
|
virtual bool DoPublishLogWrites(const zeek::logging::detail::LogWriteHeader& header,
|
||||||
|
zeek::Span<zeek::logging::detail::LogRecord> records);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send out a serialized log batch.
|
||||||
|
*
|
||||||
|
* A backend implementation may use the values from \a header to
|
||||||
|
* construct a topic to write the logs to.
|
||||||
|
*
|
||||||
|
* Semantics of this call are "fire-and-forget". An implementation should
|
||||||
|
* ensure the message is enqueued for delivery, but may not have been sent out
|
||||||
|
* let alone received by the destination when this call returns.
|
||||||
|
*
|
||||||
|
* Sharding log writes to multiple receivers (logger nodes) is backend specific.
|
||||||
|
* Broker, for example, involves Zeek script layer cluster pool concepts.
|
||||||
|
* Other backends may use appropriate native mechanisms that may be more
|
||||||
|
* efficient.
|
||||||
|
*
|
||||||
|
* @param header the header describing the writer frontend where the records originate from.
|
||||||
|
* @param format the format/serializer used for serialization of the message payload.
|
||||||
|
* @param buf the serialized log batch. This is the message payload.
|
||||||
|
* @return true if the message has been published successfully.
|
||||||
|
*/
|
||||||
|
virtual bool DoPublishLogWrites(const zeek::logging::detail::LogWriteHeader& header, const std::string& format,
|
||||||
|
detail::byte_buffer& buf) = 0;
|
||||||
|
|
||||||
|
std::unique_ptr<EventSerializer> event_serializer;
|
||||||
|
std::unique_ptr<LogSerializer> log_serializer;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A cluster backend may receive event and log messages asynchronously
|
||||||
|
* through threads. The following structs can be used with QueueForProcessing()
|
||||||
|
* to enqueue these messages onto the main IO loop for processing.
|
||||||
|
*
|
||||||
|
* EventMessage and LogMessage are processed in a generic fashion in
|
||||||
|
* the Process() method. The BackendMessage can be intercepted with
|
||||||
|
* DoProcessBackendMessage(). DoProcessBackendMessage() is guaranteed
|
||||||
|
* to run on Zeek's main thread.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message on a topic for events was received.
|
||||||
|
*/
|
||||||
|
struct EventMessage {
|
||||||
|
std::string topic;
|
||||||
|
std::string format;
|
||||||
|
detail::byte_buffer payload;
|
||||||
|
|
||||||
|
auto payload_span() const { return Span(payload.data(), payload.size()); };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A message that represents log records.
|
||||||
|
*/
|
||||||
|
struct LogMessage {
|
||||||
|
std::string format;
|
||||||
|
detail::byte_buffer payload;
|
||||||
|
|
||||||
|
auto payload_span() const { return Span(payload.data(), payload.size()); };
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A backend specific message.
|
||||||
|
*
|
||||||
|
* This provides a mechanism to transfer auxiliary information
|
||||||
|
* from a background thread to Zeek's main thread.
|
||||||
|
*/
|
||||||
|
struct BackendMessage {
|
||||||
|
int tag;
|
||||||
|
detail::byte_buffer payload;
|
||||||
|
|
||||||
|
auto payload_span() const { return Span(payload.data(), payload.size()); };
|
||||||
|
};
|
||||||
|
|
||||||
|
using QueueMessage = std::variant<EventMessage, LogMessage, BackendMessage>;
|
||||||
|
using QueueMessages = std::vector<QueueMessage>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Support for backends that use background threads or invoke
|
||||||
|
* callbacks on non-main threads.
|
||||||
|
*/
|
||||||
|
class ThreadedBackend : public Backend, public zeek::iosource::IOSource {
|
||||||
|
public:
|
||||||
|
using Backend::Backend;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* To be used by implementations to enqueue messages for processing on the IO loop.
|
||||||
|
*
|
||||||
|
* It's safe to call this method from any thread.
|
||||||
|
*
|
||||||
|
* @param messages Messages to be enqueued.
|
||||||
|
*/
|
||||||
|
void QueueForProcessing(QueueMessages&& messages);
|
||||||
|
|
||||||
|
void Process() override;
|
||||||
|
|
||||||
|
double GetNextTimeout() override { return -1; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The DoInitPostScript() implementation of ThreadedBackend
|
||||||
|
* registers itself as a non-counting IO source.
|
||||||
|
*
|
||||||
|
* Classes deriving from ThreadedBackend and providing their
|
||||||
|
* own DoInitPostScript() method should invoke the ThreadedBackend's
|
||||||
|
* implementation to register themselves as a non-counting
|
||||||
|
* IO source with the IO loop.
|
||||||
|
*/
|
||||||
|
void DoInitPostScript() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default DoInit() implementation of ThreadedBackend
|
||||||
|
* registers itself as a counting IO source to keep the IO
|
||||||
|
* loop alive after initialization.
|
||||||
|
*
|
||||||
|
* Classes deriving from ThreadedBackend and providing their
|
||||||
|
* own DoInit() method should invoke the ThreadedBackend's
|
||||||
|
* implementation to register themselves as a counting
|
||||||
|
* IO source with the IO loop.
|
||||||
|
*/
|
||||||
|
bool DoInit() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/**
|
||||||
|
* Process a backend specific message queued as BackendMessage.
|
||||||
|
*/
|
||||||
|
bool ProcessBackendMessage(int tag, detail::byte_buffer_span payload);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a cluster backend produces messages of type BackendMessage,
|
||||||
|
* this method will be invoked by the main thread to process it.
|
||||||
|
*/
|
||||||
|
virtual bool DoProcessBackendMessage(int tag, detail::byte_buffer_span payload) { return false; };
|
||||||
|
|
||||||
|
// Members used for communication with the main thread.
|
||||||
|
std::mutex messages_mtx;
|
||||||
|
std::vector<QueueMessage> messages;
|
||||||
|
zeek::detail::Flare messages_flare;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Cluster backend instance used for publish() and subscribe() calls.
|
||||||
|
extern Backend* backend;
|
||||||
|
|
||||||
|
} // namespace cluster
|
||||||
|
} // namespace zeek
|
9
src/cluster/CMakeLists.txt
Normal file
9
src/cluster/CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
zeek_add_subdir_library(
|
||||||
|
cluster
|
||||||
|
INCLUDE_DIRS
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
|
SOURCES
|
||||||
|
Component.cc
|
||||||
|
Backend.cc
|
||||||
|
Manager.cc)
|
56
src/cluster/Component.cc
Normal file
56
src/cluster/Component.cc
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#include "zeek/cluster/Component.h"
|
||||||
|
|
||||||
|
#include "zeek/Desc.h"
|
||||||
|
#include "zeek/Tag.h"
|
||||||
|
#include "zeek/cluster/Manager.h"
|
||||||
|
#include "zeek/util.h"
|
||||||
|
|
||||||
|
using namespace zeek::cluster;
|
||||||
|
|
||||||
|
BackendComponent::BackendComponent(const std::string& name, factory_callback arg_factory)
|
||||||
|
: plugin::Component(plugin::component::CLUSTER_BACKEND, name, 0, cluster::manager->Backends().GetTagType()) {
|
||||||
|
factory = arg_factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackendComponent::Initialize() {
|
||||||
|
InitializeTag();
|
||||||
|
cluster::manager->Backends().RegisterComponent(this, "CLUSTER_BACKEND_");
|
||||||
|
}
|
||||||
|
|
||||||
|
void BackendComponent::DoDescribe(ODesc* d) const {
|
||||||
|
d->Add("Cluster::CLUSTER_BACKEND_");
|
||||||
|
d->Add(CanonicalName());
|
||||||
|
}
|
||||||
|
|
||||||
|
EventSerializerComponent::EventSerializerComponent(const std::string& name, factory_callback arg_factory)
|
||||||
|
: plugin::Component(plugin::component::EVENT_SERIALIZER, name, 0,
|
||||||
|
cluster::manager->EventSerializers().GetTagType()) {
|
||||||
|
factory = arg_factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventSerializerComponent::Initialize() {
|
||||||
|
InitializeTag();
|
||||||
|
cluster::manager->EventSerializers().RegisterComponent(this, "EVENT_SERIALIZER_");
|
||||||
|
}
|
||||||
|
|
||||||
|
void EventSerializerComponent::DoDescribe(ODesc* d) const {
|
||||||
|
d->Add("Cluster::EVENT_SERIALIZER_");
|
||||||
|
d->Add(CanonicalName());
|
||||||
|
}
|
||||||
|
|
||||||
|
LogSerializerComponent::LogSerializerComponent(const std::string& name, factory_callback arg_factory)
|
||||||
|
: plugin::Component(plugin::component::LOG_SERIALIZER, name, 0, cluster::manager->LogSerializers().GetTagType()) {
|
||||||
|
factory = arg_factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogSerializerComponent::Initialize() {
|
||||||
|
InitializeTag();
|
||||||
|
cluster::manager->LogSerializers().RegisterComponent(this, "LOG_SERIALIZER_");
|
||||||
|
}
|
||||||
|
|
||||||
|
void LogSerializerComponent::DoDescribe(ODesc* d) const {
|
||||||
|
d->Add("Cluster::LOG_SERIALIZER_");
|
||||||
|
d->Add(CanonicalName());
|
||||||
|
}
|
131
src/cluster/Component.h
Normal file
131
src/cluster/Component.h
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "zeek/cluster/Backend.h"
|
||||||
|
#include "zeek/cluster/Serializer.h"
|
||||||
|
#include "zeek/plugin/Component.h"
|
||||||
|
|
||||||
|
namespace zeek::cluster {
|
||||||
|
|
||||||
|
class BackendComponent : public plugin::Component {
|
||||||
|
public:
|
||||||
|
using factory_callback = std::unique_ptr<Backend> (*)(std::unique_ptr<EventSerializer>,
|
||||||
|
std::unique_ptr<LogSerializer>);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param name The name of the cluster backend. A Zeek script-level enum
|
||||||
|
* with the name Cluster::CLUSTER_BACKEND_<NAME> will be created.
|
||||||
|
*
|
||||||
|
* @param factory A factory function to instantiate instances of the
|
||||||
|
* cluster backend.
|
||||||
|
*/
|
||||||
|
BackendComponent(const std::string& name, factory_callback factory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor.
|
||||||
|
*/
|
||||||
|
~BackendComponent() override = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialization function. This function has to be called before any
|
||||||
|
* plugin component functionality is used; it is used to add the
|
||||||
|
* plugin component to the list of components and to initialize tags
|
||||||
|
*/
|
||||||
|
void Initialize() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the analyzer's factory function.
|
||||||
|
*/
|
||||||
|
factory_callback Factory() const { return factory; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void DoDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
factory_callback factory;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class EventSerializerComponent : public plugin::Component {
|
||||||
|
public:
|
||||||
|
using factory_callback = std::unique_ptr<EventSerializer> (*)();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param name The name of the event serializer. A Zeek script-level enum
|
||||||
|
* with the name Cluster::EVENT_SERIALIZER_<NAME> will be created.
|
||||||
|
*
|
||||||
|
* @param factory A factory function to instantiate instances of the
|
||||||
|
* event serializer.
|
||||||
|
*/
|
||||||
|
EventSerializerComponent(const std::string& name, factory_callback factory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor.
|
||||||
|
*/
|
||||||
|
~EventSerializerComponent() override = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialization function. This function has to be called before any
|
||||||
|
* plugin component functionality is used; it is used to add the
|
||||||
|
* plugin component to the list of components and to initialize tags
|
||||||
|
*/
|
||||||
|
void Initialize() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the analyzer's factory function.
|
||||||
|
*/
|
||||||
|
factory_callback Factory() const { return factory; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void DoDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
factory_callback factory;
|
||||||
|
};
|
||||||
|
|
||||||
|
class LogSerializerComponent : public plugin::Component {
|
||||||
|
public:
|
||||||
|
using factory_callback = std::unique_ptr<LogSerializer> (*)();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* @param name The name of the log serializer. A Zeek script-level enum
|
||||||
|
* with the name Cluster::LOG_SERIALIZER_<NAME> will be created.
|
||||||
|
*
|
||||||
|
* @param factory A factory function to instantiate instances of the
|
||||||
|
* log serializer.
|
||||||
|
*/
|
||||||
|
LogSerializerComponent(const std::string& name, factory_callback factory);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor.
|
||||||
|
*/
|
||||||
|
~LogSerializerComponent() override = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialization function. This function has to be called before any
|
||||||
|
* plugin component functionality is used; it is used to add the
|
||||||
|
* plugin component to the list of components and to initialize tags
|
||||||
|
*/
|
||||||
|
void Initialize() override;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the analyzer's factory function.
|
||||||
|
*/
|
||||||
|
factory_callback Factory() const { return factory; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void DoDescribe(ODesc* d) const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
factory_callback factory;
|
||||||
|
};
|
||||||
|
} // namespace zeek::cluster
|
27
src/cluster/Manager.cc
Normal file
27
src/cluster/Manager.cc
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include "zeek/cluster/Manager.h"
|
||||||
|
|
||||||
|
#include "zeek/cluster/Serializer.h"
|
||||||
|
|
||||||
|
using namespace zeek::cluster;
|
||||||
|
|
||||||
|
Manager::Manager()
|
||||||
|
: backends(plugin::ComponentManager<BackendComponent>("Cluster", "BackendTag")),
|
||||||
|
event_serializers(plugin::ComponentManager<EventSerializerComponent>("Cluster", "EventSerializerTag")),
|
||||||
|
log_serializers(plugin::ComponentManager<LogSerializerComponent>("Cluster", "LogSerializerTag")) {}
|
||||||
|
|
||||||
|
std::unique_ptr<Backend> Manager::InstantiateBackend(const zeek::EnumValPtr& tag,
|
||||||
|
std::unique_ptr<EventSerializer> event_serializer,
|
||||||
|
std::unique_ptr<LogSerializer> log_serializer) {
|
||||||
|
const BackendComponent* c = Backends().Lookup(tag);
|
||||||
|
return c ? c->Factory()(std::move(event_serializer), std::move(log_serializer)) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<EventSerializer> Manager::InstantiateEventSerializer(const zeek::EnumValPtr& tag) {
|
||||||
|
const EventSerializerComponent* c = EventSerializers().Lookup(tag);
|
||||||
|
return c ? c->Factory()() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<LogSerializer> Manager::InstantiateLogSerializer(const zeek::EnumValPtr& tag) {
|
||||||
|
const LogSerializerComponent* c = LogSerializers().Lookup(tag);
|
||||||
|
return c ? c->Factory()() : nullptr;
|
||||||
|
}
|
80
src/cluster/Manager.h
Normal file
80
src/cluster/Manager.h
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "zeek/cluster/Component.h"
|
||||||
|
#include "zeek/cluster/Serializer.h"
|
||||||
|
#include "zeek/plugin/ComponentManager.h"
|
||||||
|
|
||||||
|
namespace zeek::cluster {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manager to allow registration of cluster components.
|
||||||
|
*
|
||||||
|
* This manager holds three component manager for event and log serializers
|
||||||
|
* components, as well as backend components themselves.
|
||||||
|
*/
|
||||||
|
class Manager {
|
||||||
|
public:
|
||||||
|
Manager();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate a cluster backend with the given enum value and
|
||||||
|
* pre-instantiated event and log serializers.
|
||||||
|
*
|
||||||
|
* @param tag The enum value identifying the backend.
|
||||||
|
* @param event_serializer The event serializer to inject.
|
||||||
|
* @param log_serializer The log serializer to inject.
|
||||||
|
*
|
||||||
|
* @return New ClusterBackend instance, or null if there's no such component.
|
||||||
|
*/
|
||||||
|
std::unique_ptr<Backend> InstantiateBackend(const EnumValPtr& tag,
|
||||||
|
std::unique_ptr<EventSerializer> event_serializer,
|
||||||
|
std::unique_ptr<LogSerializer> log_serializer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate a event serializer with the given enum value.
|
||||||
|
*
|
||||||
|
* @param tag The enum value identifying a serializer.
|
||||||
|
*
|
||||||
|
* @return New Serializer instance, or null if there's no such component.
|
||||||
|
*/
|
||||||
|
std::unique_ptr<EventSerializer> InstantiateEventSerializer(const EnumValPtr& tag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instantiate a log serializer with the given enum value.
|
||||||
|
*
|
||||||
|
* @param tag The enum value identifying a serializer.
|
||||||
|
*
|
||||||
|
* @return New Serializer instance, or null if there's no such component.
|
||||||
|
*/
|
||||||
|
std::unique_ptr<LogSerializer> InstantiateLogSerializer(const EnumValPtr& tag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The ComponentManager for backends.
|
||||||
|
*/
|
||||||
|
plugin::ComponentManager<BackendComponent>& Backends() { return backends; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The ComponentManager for event serializers.
|
||||||
|
*/
|
||||||
|
plugin::ComponentManager<EventSerializerComponent>& EventSerializers() { return event_serializers; };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The ComponentManager for serializers.
|
||||||
|
*/
|
||||||
|
plugin::ComponentManager<LogSerializerComponent>& LogSerializers() { return log_serializers; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
plugin::ComponentManager<BackendComponent> backends;
|
||||||
|
plugin::ComponentManager<EventSerializerComponent> event_serializers;
|
||||||
|
plugin::ComponentManager<LogSerializerComponent> log_serializers;
|
||||||
|
};
|
||||||
|
|
||||||
|
// This manager instance only exists for plugins to register components,
|
||||||
|
// not for actual cluster functionality.
|
||||||
|
extern Manager* manager;
|
||||||
|
|
||||||
|
} // namespace zeek::cluster
|
107
src/cluster/Serializer.h
Normal file
107
src/cluster/Serializer.h
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
// Interfaces to be implemented by event and log serializer components.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "zeek/Span.h"
|
||||||
|
#include "zeek/logging/Types.h"
|
||||||
|
|
||||||
|
namespace zeek::cluster {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
class Event;
|
||||||
|
|
||||||
|
using byte_buffer = std::vector<std::byte>;
|
||||||
|
using byte_buffer_span = Span<const std::byte>;
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class handles encoding of events into byte buffers and back.
|
||||||
|
*
|
||||||
|
* An event and its parameters can be serialized as a message which
|
||||||
|
* another node can unserialize and then enqueue as an event.
|
||||||
|
*/
|
||||||
|
class EventSerializer {
|
||||||
|
public:
|
||||||
|
virtual ~EventSerializer() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize an event into the given byte buffer.
|
||||||
|
*
|
||||||
|
* @param buf The buffer to use for serialization.
|
||||||
|
* @param event The event to serialize.
|
||||||
|
*
|
||||||
|
* @returns True on success, false in exceptional cases (e.g. unsupported serialization).
|
||||||
|
*/
|
||||||
|
virtual bool SerializeEvent(detail::byte_buffer& buf, const detail::Event& event) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unserialize an event from a given byte buffer.
|
||||||
|
*
|
||||||
|
* @param buf A span representing a received remote event.
|
||||||
|
*
|
||||||
|
* @returns The event, or std::nullopt on error.
|
||||||
|
*/
|
||||||
|
virtual std::optional<cluster::detail::Event> UnserializeEvent(detail::byte_buffer_span buf) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns The name of this event serializer instance.
|
||||||
|
*/
|
||||||
|
const std::string& Name() { return name; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
|
EventSerializer(std::string name) : name(std::move(name)) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Interface for a serializer for logging::LogRecord instances.
|
||||||
|
*/
|
||||||
|
class LogSerializer {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*/
|
||||||
|
explicit LogSerializer(std::string name) : name(std::move(name)) {};
|
||||||
|
|
||||||
|
virtual ~LogSerializer() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize log records into a byte buffer.
|
||||||
|
*
|
||||||
|
* @param buf The buffer to serialize into.
|
||||||
|
* @param header The log batch header.
|
||||||
|
* @param records The actual log writes.
|
||||||
|
*/
|
||||||
|
virtual bool SerializeLogWrite(detail::byte_buffer& buf, const logging::detail::LogWriteHeader& header,
|
||||||
|
zeek::Span<logging::detail::LogRecord> records) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unserialize log writes from a given byte buffer.
|
||||||
|
*
|
||||||
|
* @param buf The span representing received log writes.
|
||||||
|
*/
|
||||||
|
virtual std::optional<logging::detail::LogWriteBatch> UnserializeLogWrite(detail::byte_buffer_span buf) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns The name of this log serializer instance.
|
||||||
|
*/
|
||||||
|
const std::string& Name() { return name; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace zeek::cluster
|
|
@ -5,6 +5,7 @@ zeek_add_subdir_library(
|
||||||
Manager.cc
|
Manager.cc
|
||||||
WriterBackend.cc
|
WriterBackend.cc
|
||||||
WriterFrontend.cc
|
WriterFrontend.cc
|
||||||
|
Types.cc
|
||||||
BIFS
|
BIFS
|
||||||
logging.bif)
|
logging.bif)
|
||||||
|
|
||||||
|
|
48
src/logging/Types.cc
Normal file
48
src/logging/Types.cc
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
#include "zeek/logging/Types.h"
|
||||||
|
|
||||||
|
#include "zeek/Desc.h"
|
||||||
|
#include "zeek/Type.h"
|
||||||
|
#include "zeek/Val.h"
|
||||||
|
|
||||||
|
namespace zeek::logging::detail {
|
||||||
|
|
||||||
|
LogWriteHeader::LogWriteHeader() = default;
|
||||||
|
|
||||||
|
LogWriteHeader::LogWriteHeader(EnumValPtr arg_stream_id, EnumValPtr arg_writer_id, std::string arg_filter_name,
|
||||||
|
std::string arg_path)
|
||||||
|
: stream_id(std::move(arg_stream_id)),
|
||||||
|
writer_id(std::move(arg_writer_id)),
|
||||||
|
filter_name(std::move(arg_filter_name)),
|
||||||
|
path(std::move(arg_path)) {
|
||||||
|
stream_name = obj_desc_short(stream_id.get());
|
||||||
|
writer_name = obj_desc_short(writer_id.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
LogWriteHeader& LogWriteHeader::operator=(const LogWriteHeader& other) = default;
|
||||||
|
|
||||||
|
LogWriteHeader::~LogWriteHeader() = default;
|
||||||
|
|
||||||
|
bool LogWriteHeader::PopulateEnumVals() {
|
||||||
|
static const auto& stream_id_type = zeek::id::find_type<zeek::EnumType>("Log::ID");
|
||||||
|
static const auto& writer_id_type = zeek::id::find_type<zeek::EnumType>("Log::Writer");
|
||||||
|
|
||||||
|
if ( stream_name.empty() || writer_name.empty() )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto sid = stream_id_type->Lookup(stream_name);
|
||||||
|
if ( sid < 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto wid = writer_id_type->Lookup(writer_name);
|
||||||
|
if ( wid < 0 )
|
||||||
|
return false;
|
||||||
|
|
||||||
|
stream_id = stream_id_type->GetEnumVal(sid);
|
||||||
|
writer_id = writer_id_type->GetEnumVal(wid);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace zeek::logging::detail
|
99
src/logging/Types.h
Normal file
99
src/logging/Types.h
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
// See the file "COPYING" in the main distribution directory for copyright.
|
||||||
|
|
||||||
|
// Header for types shared between cluster and logging components.
|
||||||
|
//
|
||||||
|
// Currently these are in detail, but over time may move into the
|
||||||
|
// public namespace once established.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "zeek/IntrusivePtr.h"
|
||||||
|
#include "zeek/threading/SerialTypes.h"
|
||||||
|
|
||||||
|
namespace zeek {
|
||||||
|
class EnumVal;
|
||||||
|
using EnumValPtr = IntrusivePtr<EnumVal>;
|
||||||
|
|
||||||
|
namespace logging::detail {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A single log record.
|
||||||
|
*
|
||||||
|
* This is what a Zeek record value passed into Log::write()
|
||||||
|
* is converted into before passed to a local log writer or
|
||||||
|
* send via the cluster to a remote node.
|
||||||
|
*/
|
||||||
|
using LogRecord = std::vector<threading::Value>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A struct holding all necessary information that relates to
|
||||||
|
* log writes for a given path. These values are constant over
|
||||||
|
* the lifetime of a \a WriterFrontend.
|
||||||
|
*
|
||||||
|
* Note that the constructor, destructor and assignment operator are
|
||||||
|
* defaulted in Types.cc. This is to avoid a Val.h include here.
|
||||||
|
*/
|
||||||
|
struct LogWriteHeader {
|
||||||
|
/**
|
||||||
|
* Default constructor.
|
||||||
|
*/
|
||||||
|
LogWriteHeader();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor that populates stream_name and writer_name.
|
||||||
|
*
|
||||||
|
* @param stream_id Enum value representing the stream.
|
||||||
|
* @param writer_id Enum value representing the writer.
|
||||||
|
* @param filter_name The filter name of the writer frontend.
|
||||||
|
* @param path The path of the writer frontend.
|
||||||
|
*/
|
||||||
|
LogWriteHeader(EnumValPtr stream_id, EnumValPtr writer_id, std::string filter_name, std::string path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assignment operator.
|
||||||
|
*/
|
||||||
|
LogWriteHeader& operator=(const LogWriteHeader& other);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destructor.
|
||||||
|
*/
|
||||||
|
~LogWriteHeader();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper to populate stream_id and writer_id after the
|
||||||
|
* stream_name and writer_name members were set.
|
||||||
|
*
|
||||||
|
* @return true if matching enum values were, else false.
|
||||||
|
*/
|
||||||
|
bool PopulateEnumVals();
|
||||||
|
|
||||||
|
EnumValPtr stream_id; // The enum identifying the stream.
|
||||||
|
std::string stream_name; // The name of the stream, e.g. Conn::LOG
|
||||||
|
EnumValPtr writer_id; // The enum identifying the writer. Mostly for backwards compat with broker.
|
||||||
|
std::string writer_name; // The name of the writer, e.g. WRITER_ASCII.
|
||||||
|
std::string filter_name; // The name of the filter.
|
||||||
|
std::string path; // The path as configured or produced by the filter's path_func.
|
||||||
|
std::vector<threading::Field> fields; // The schema describing a log record.
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A batch of log records including their header.
|
||||||
|
*
|
||||||
|
* This is the object created when unserialzing a log-write
|
||||||
|
* from another cluster node.
|
||||||
|
*
|
||||||
|
* This layout currently implies that during de-serialization
|
||||||
|
* data is copied into LogRecord / threading::Value structures.
|
||||||
|
* If the need for zero-copy approaches arises, might need a
|
||||||
|
* different approach to free the underlying buffer (capnproto).
|
||||||
|
*/
|
||||||
|
struct LogWriteBatch {
|
||||||
|
LogWriteHeader header;
|
||||||
|
std::vector<LogRecord> records;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace logging::detail
|
||||||
|
} // namespace zeek
|
|
@ -39,6 +39,12 @@ void Component::Describe(ODesc* d) const {
|
||||||
|
|
||||||
case component::SESSION_ADAPTER: d->Add("Session Adapter"); break;
|
case component::SESSION_ADAPTER: d->Add("Session Adapter"); break;
|
||||||
|
|
||||||
|
case component::CLUSTER_BACKEND: d->Add("Cluster Backend"); break;
|
||||||
|
|
||||||
|
case component::EVENT_SERIALIZER: d->Add("Event Serializer"); break;
|
||||||
|
|
||||||
|
case component::LOG_SERIALIZER: d->Add("Log Serializer"); break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
reporter->InternalWarning("unknown component type in plugin::Component::Describe");
|
reporter->InternalWarning("unknown component type in plugin::Component::Describe");
|
||||||
d->Add("<unknown component type>");
|
d->Add("<unknown component type>");
|
||||||
|
|
|
@ -30,6 +30,9 @@ enum Type {
|
||||||
PKTSRC, /// A packet source.
|
PKTSRC, /// A packet source.
|
||||||
PKTDUMPER, /// A packet dumper.
|
PKTDUMPER, /// A packet dumper.
|
||||||
SESSION_ADAPTER, /// A session adapter analyzer.
|
SESSION_ADAPTER, /// A session adapter analyzer.
|
||||||
|
CLUSTER_BACKEND, /// A cluster backend.
|
||||||
|
EVENT_SERIALIZER, /// A serializer for events, used by cluster backends.
|
||||||
|
LOG_SERIALIZER, /// A serializer for log batches, used by cluster backends.
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace component
|
} // namespace component
|
||||||
|
|
|
@ -19,13 +19,21 @@ namespace zeek::threading {
|
||||||
* Definition of a log file, i.e., one column of a log stream.
|
* Definition of a log file, i.e., one column of a log stream.
|
||||||
*/
|
*/
|
||||||
struct Field {
|
struct Field {
|
||||||
const char* name; //! Name of the field.
|
const char* name = nullptr; //! Name of the field.
|
||||||
//! Needed by input framework. Port fields have two names (one for the
|
//! Needed by input framework. Port fields have two names (one for the
|
||||||
//! port, one for the type), and this specifies the secondary name.
|
//! port, one for the type), and this specifies the secondary name.
|
||||||
const char* secondary_name;
|
const char* secondary_name = nullptr;
|
||||||
TypeTag type; //! Type of the field.
|
TypeTag type = TYPE_ERROR; //! Type of the field.
|
||||||
TypeTag subtype; //! Inner type for sets and vectors.
|
TypeTag subtype = TYPE_ERROR; //! Inner type for sets and vectors.
|
||||||
bool optional; //! True if field is optional.
|
bool optional = false; //! True if field is optional.
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor.
|
||||||
|
*
|
||||||
|
* For Read() usage. Initializes with TYPE_ERROR.
|
||||||
|
*/
|
||||||
|
Field() = default;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor.
|
* Constructor.
|
||||||
|
@ -47,6 +55,23 @@ struct Field {
|
||||||
subtype(other.subtype),
|
subtype(other.subtype),
|
||||||
optional(other.optional) {}
|
optional(other.optional) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move constructor.
|
||||||
|
*/
|
||||||
|
Field(Field&& other) noexcept {
|
||||||
|
name = other.name;
|
||||||
|
secondary_name = other.secondary_name;
|
||||||
|
type = other.type;
|
||||||
|
subtype = other.subtype;
|
||||||
|
optional = other.optional;
|
||||||
|
|
||||||
|
other.name = nullptr;
|
||||||
|
other.secondary_name = nullptr;
|
||||||
|
other.type = TYPE_ERROR;
|
||||||
|
other.subtype = TYPE_ERROR;
|
||||||
|
other.optional = false;
|
||||||
|
}
|
||||||
|
|
||||||
~Field() {
|
~Field() {
|
||||||
delete[] name;
|
delete[] name;
|
||||||
delete[] secondary_name;
|
delete[] secondary_name;
|
||||||
|
@ -91,10 +116,6 @@ struct Field {
|
||||||
* thread-safe.
|
* thread-safe.
|
||||||
*/
|
*/
|
||||||
std::string TypeName() const;
|
std::string TypeName() const;
|
||||||
|
|
||||||
private:
|
|
||||||
// Force usage of constructor above.
|
|
||||||
Field() {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -50,6 +50,7 @@
|
||||||
#include "zeek/analyzer/Manager.h"
|
#include "zeek/analyzer/Manager.h"
|
||||||
#include "zeek/binpac_zeek.h"
|
#include "zeek/binpac_zeek.h"
|
||||||
#include "zeek/broker/Manager.h"
|
#include "zeek/broker/Manager.h"
|
||||||
|
#include "zeek/cluster/Manager.h"
|
||||||
#include "zeek/file_analysis/Manager.h"
|
#include "zeek/file_analysis/Manager.h"
|
||||||
#include "zeek/input.h"
|
#include "zeek/input.h"
|
||||||
#include "zeek/input/Manager.h"
|
#include "zeek/input/Manager.h"
|
||||||
|
@ -177,6 +178,8 @@ zeek::detail::trigger::Manager* zeek::detail::trigger_mgr = nullptr;
|
||||||
zeek::spicy::Manager* zeek::spicy_mgr = nullptr;
|
zeek::spicy::Manager* zeek::spicy_mgr = nullptr;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
zeek::cluster::Manager* zeek::cluster::manager = nullptr;
|
||||||
|
|
||||||
std::vector<std::string> zeek::detail::zeek_script_prefixes;
|
std::vector<std::string> zeek::detail::zeek_script_prefixes;
|
||||||
zeek::detail::Stmt* zeek::detail::stmts = nullptr;
|
zeek::detail::Stmt* zeek::detail::stmts = nullptr;
|
||||||
zeek::EventRegistry* zeek::event_registry = nullptr;
|
zeek::EventRegistry* zeek::event_registry = nullptr;
|
||||||
|
@ -389,6 +392,7 @@ static void terminate_zeek() {
|
||||||
delete packet_mgr;
|
delete packet_mgr;
|
||||||
delete analyzer_mgr;
|
delete analyzer_mgr;
|
||||||
delete file_mgr;
|
delete file_mgr;
|
||||||
|
delete cluster::manager;
|
||||||
// broker_mgr, timer_mgr, supervisor, and dns_mgr are deleted via iosource_mgr
|
// broker_mgr, timer_mgr, supervisor, and dns_mgr are deleted via iosource_mgr
|
||||||
delete iosource_mgr;
|
delete iosource_mgr;
|
||||||
delete event_registry;
|
delete event_registry;
|
||||||
|
@ -666,6 +670,7 @@ SetupResult setup(int argc, char** argv, Options* zopts) {
|
||||||
log_mgr = new logging::Manager();
|
log_mgr = new logging::Manager();
|
||||||
input_mgr = new input::Manager();
|
input_mgr = new input::Manager();
|
||||||
file_mgr = new file_analysis::Manager();
|
file_mgr = new file_analysis::Manager();
|
||||||
|
cluster::manager = new cluster::Manager();
|
||||||
auto broker_real_time = ! options.pcap_file && ! options.deterministic_mode;
|
auto broker_real_time = ! options.pcap_file && ! options.deterministic_mode;
|
||||||
broker_mgr = new Broker::Manager(broker_real_time);
|
broker_mgr = new Broker::Manager(broker_real_time);
|
||||||
trigger_mgr = new trigger::Manager();
|
trigger_mgr = new trigger::Manager();
|
||||||
|
|
|
@ -313,6 +313,14 @@ void ScriptInfo::DoInitPostScript() {
|
||||||
const auto& id = zeek::detail::global_scope()->Find("Log::Writer");
|
const auto& id = zeek::detail::global_scope()->Find("Log::Writer");
|
||||||
types.push_back(new IdentifierInfo(id, this));
|
types.push_back(new IdentifierInfo(id, this));
|
||||||
}
|
}
|
||||||
|
else if ( name == "base/frameworks/cluster/main.zeek" ) {
|
||||||
|
const auto& backend_id = zeek::detail::global_scope()->Find("Cluster::BackendTag");
|
||||||
|
types.push_back(new IdentifierInfo(backend_id, this));
|
||||||
|
const auto& event_serializer_id = zeek::detail::global_scope()->Find("Cluster::EventSerializerTag");
|
||||||
|
types.push_back(new IdentifierInfo(event_serializer_id, this));
|
||||||
|
const auto& log_serializer_id = zeek::detail::global_scope()->Find("Cluster::LogSerializerTag");
|
||||||
|
types.push_back(new IdentifierInfo(log_serializer_id, this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vector<string> ScriptInfo::GetComments() const { return comments; }
|
vector<string> ScriptInfo::GetComments() const { return comments; }
|
||||||
|
|
5
testing/btest/Baseline/cluster.backend-enum/out
Normal file
5
testing/btest/Baseline/cluster.backend-enum/out
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
Zeek::Cluster_Backend_Broker - Cluster backend using Broker (built-in)
|
||||||
|
[Cluster Backend] BROKER (Cluster::CLUSTER_BACKEND_BROKER)
|
||||||
|
|
||||||
|
Cluster::CLUSTER_BACKEND_BROKER, Cluster::BackendTag
|
|
@ -7,10 +7,10 @@
|
||||||
#open XXXX-XX-XX-XX-XX-XX
|
#open XXXX-XX-XX-XX-XX-XX
|
||||||
#fields ts fuid uid id.orig_h id.orig_p id.resp_h id.resp_p source depth analyzers mime_type filename duration local_orig is_orig seen_bytes total_bytes missing_bytes overflow_bytes timedout parent_fuid md5 sha1 sha256
|
#fields ts fuid uid id.orig_h id.orig_p id.resp_h id.resp_p source depth analyzers mime_type filename duration local_orig is_orig seen_bytes total_bytes missing_bytes overflow_bytes timedout parent_fuid md5 sha1 sha256
|
||||||
#types time string string addr port addr port string count set[string] string string interval bool bool count count count count bool string string string string
|
#types time string string addr port addr port string count set[string] string string interval bool bool count count count count bool string string string string
|
||||||
XXXXXXXXXX.XXXXXX FgN3AE3of2TRIqaeQe CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-user-cert - 0.000000 F F 1859 - 0 0 F - 7af07aca6d5c6e8e87fe4bb34786edc0 548b9e03bc183d1cd39f93a37985cb3950f8f06f 6bacfa4536150ed996f2b0c05ab6e345a257225f449aeb9d2018ccd88f4ede43
|
XXXXXXXXXX.XXXXXX FgN3AE3of2TRIqaeQe CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-user-cert - 0.000000 F F 1859 - 0 0 F - 7af07aca6d5c6e8e87fe4bb34786edc0 548b9e03bc183d1cd39f93a37985cb3950f8f06f 6bacfa4536150ed996f2b0c05ab6e345a257225f449aeb9d2018ccd88f4ede43
|
||||||
XXXXXXXXXX.XXXXXX Fv2Agc4z5boBOacQi6 CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 1032 - 0 0 F - 9e4ac96474245129d9766700412a1f89 d83c1a7f4d0446bb2081b81a1670f8183451ca24 a047a37fa2d2e118a4f5095fe074d6cfe0e352425a7632bf8659c03919a6c81d
|
XXXXXXXXXX.XXXXXX Fv2Agc4z5boBOacQi6 CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 1032 - 0 0 F - 9e4ac96474245129d9766700412a1f89 d83c1a7f4d0446bb2081b81a1670f8183451ca24 a047a37fa2d2e118a4f5095fe074d6cfe0e352425a7632bf8659c03919a6c81d
|
||||||
XXXXXXXXXX.XXXXXX Ftmyeg2qgI2V38Dt3g CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 897 - 0 0 F - 2e7db2a31d0e3da4b25f49b9542a2e1a 7359755c6df9a0abc3060bce369564c8ec4542a3 3c35cc963eb004451323d3275d05b353235053490d9cd83729a2faf5e7ca1cc0
|
XXXXXXXXXX.XXXXXX Ftmyeg2qgI2V38Dt3g CHhAvVGS1DHFjwGM9 192.168.4.149 60623 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 897 - 0 0 F - 2e7db2a31d0e3da4b25f49b9542a2e1a 7359755c6df9a0abc3060bce369564c8ec4542a3 3c35cc963eb004451323d3275d05b353235053490d9cd83729a2faf5e7ca1cc0
|
||||||
XXXXXXXXXX.XXXXXX FUFNf84cduA0IJCp07 ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-user-cert - 0.000000 F F 1859 - 0 0 F - 7af07aca6d5c6e8e87fe4bb34786edc0 548b9e03bc183d1cd39f93a37985cb3950f8f06f 6bacfa4536150ed996f2b0c05ab6e345a257225f449aeb9d2018ccd88f4ede43
|
XXXXXXXXXX.XXXXXX FUFNf84cduA0IJCp07 ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-user-cert - 0.000000 F F 1859 - 0 0 F - 7af07aca6d5c6e8e87fe4bb34786edc0 548b9e03bc183d1cd39f93a37985cb3950f8f06f 6bacfa4536150ed996f2b0c05ab6e345a257225f449aeb9d2018ccd88f4ede43
|
||||||
XXXXXXXXXX.XXXXXX F1H4bd2OKGbLPEdHm4 ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 1032 - 0 0 F - 9e4ac96474245129d9766700412a1f89 d83c1a7f4d0446bb2081b81a1670f8183451ca24 a047a37fa2d2e118a4f5095fe074d6cfe0e352425a7632bf8659c03919a6c81d
|
XXXXXXXXXX.XXXXXX F1H4bd2OKGbLPEdHm4 ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 1032 - 0 0 F - 9e4ac96474245129d9766700412a1f89 d83c1a7f4d0446bb2081b81a1670f8183451ca24 a047a37fa2d2e118a4f5095fe074d6cfe0e352425a7632bf8659c03919a6c81d
|
||||||
XXXXXXXXXX.XXXXXX Fgsbci2jxFXYMOHOhi ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 SHA256,X509,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 897 - 0 0 F - 2e7db2a31d0e3da4b25f49b9542a2e1a 7359755c6df9a0abc3060bce369564c8ec4542a3 3c35cc963eb004451323d3275d05b353235053490d9cd83729a2faf5e7ca1cc0
|
XXXXXXXXXX.XXXXXX Fgsbci2jxFXYMOHOhi ClEkJM2Vm5giqnMf4h 192.168.4.149 60624 74.125.239.129 443 SSL 0 X509,SHA256,SHA1,MD5 application/x-x509-ca-cert - 0.000000 F F 897 - 0 0 F - 2e7db2a31d0e3da4b25f49b9542a2e1a 7359755c6df9a0abc3060bce369564c8ec4542a3 3c35cc963eb004451323d3275d05b353235053490d9cd83729a2faf5e7ca1cc0
|
||||||
#close XXXX-XX-XX-XX-XX-XX
|
#close XXXX-XX-XX-XX-XX-XX
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
1st stuff
|
||||||
|
hrw, 0, T
|
||||||
|
hrw, 1, T
|
||||||
|
hrw, 2, T
|
||||||
|
hrw, 3, T
|
||||||
|
hrw, 13, T
|
||||||
|
hrw, 37, T
|
||||||
|
hrw, 42, T
|
||||||
|
hrw, 101, T
|
||||||
|
rr, T
|
||||||
|
rr, T
|
||||||
|
rr, T
|
||||||
|
rr, T
|
||||||
|
rr, T
|
||||||
|
rr, T
|
||||||
|
rr, T
|
||||||
|
rr, T
|
||||||
|
2nd stuff
|
||||||
|
hrw, 0, T
|
||||||
|
hrw, 1, T
|
||||||
|
hrw, 2, T
|
||||||
|
hrw, 3, T
|
||||||
|
hrw, 13, T
|
||||||
|
hrw, 37, T
|
||||||
|
hrw, 42, T
|
||||||
|
hrw, 101, T
|
||||||
|
rr, T
|
||||||
|
rr, T
|
||||||
|
rr, T
|
||||||
|
rr, T
|
||||||
|
rr, T
|
||||||
|
rr, T
|
||||||
|
rr, T
|
||||||
|
rr, T
|
||||||
|
no stuff
|
||||||
|
hrw, 0, F
|
||||||
|
hrw, 1, F
|
||||||
|
hrw, 2, F
|
||||||
|
hrw, 3, F
|
||||||
|
hrw, 13, F
|
||||||
|
hrw, 37, F
|
||||||
|
hrw, 42, F
|
||||||
|
hrw, 101, F
|
||||||
|
rr, F
|
||||||
|
rr, F
|
||||||
|
rr, F
|
||||||
|
rr, F
|
||||||
|
rr, F
|
||||||
|
rr, F
|
||||||
|
rr, F
|
||||||
|
rr, F
|
|
@ -0,0 +1,10 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
got distributed event hrw, 1
|
||||||
|
got distributed event hrw, 13
|
||||||
|
got distributed event hrw, 37
|
||||||
|
got distributed event hrw, 42
|
||||||
|
got distributed event hrw, 101
|
||||||
|
got distributed event rr, 0
|
||||||
|
got distributed event rr, 2
|
||||||
|
got distributed event rr, 13
|
||||||
|
got distributed event rr, 42
|
|
@ -0,0 +1,24 @@
|
||||||
|
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
|
||||||
|
got distributed event hrw, 0
|
||||||
|
got distributed event hrw, 2
|
||||||
|
got distributed event hrw, 3
|
||||||
|
got distributed event rr, 1
|
||||||
|
got distributed event rr, 3
|
||||||
|
got distributed event rr, 37
|
||||||
|
got distributed event rr, 101
|
||||||
|
got distributed event hrw, 0
|
||||||
|
got distributed event hrw, 1
|
||||||
|
got distributed event hrw, 2
|
||||||
|
got distributed event hrw, 3
|
||||||
|
got distributed event hrw, 13
|
||||||
|
got distributed event hrw, 37
|
||||||
|
got distributed event hrw, 42
|
||||||
|
got distributed event hrw, 101
|
||||||
|
got distributed event rr, 0
|
||||||
|
got distributed event rr, 1
|
||||||
|
got distributed event rr, 2
|
||||||
|
got distributed event rr, 3
|
||||||
|
got distributed event rr, 13
|
||||||
|
got distributed event rr, 37
|
||||||
|
got distributed event rr, 42
|
||||||
|
got distributed event rr, 101
|
|
@ -4,7 +4,7 @@
|
||||||
build_dir = build
|
build_dir = build
|
||||||
|
|
||||||
[btest]
|
[btest]
|
||||||
TestDirs = af_packet doc bifs language core scripts coverage signatures plugins broker spicy supervisor telemetry javascript misc opt dns_mgr
|
TestDirs = af_packet doc bifs language core scripts coverage signatures plugins broker spicy supervisor telemetry javascript misc opt dns_mgr cluster
|
||||||
TmpDir = %(testbase)s/.tmp
|
TmpDir = %(testbase)s/.tmp
|
||||||
BaselineDir = %(testbase)s/Baseline
|
BaselineDir = %(testbase)s/Baseline
|
||||||
IgnoreDirs = .svn CVS .tmp
|
IgnoreDirs = .svn CVS .tmp
|
||||||
|
|
10
testing/btest/cluster/backend-enum.zeek
Normal file
10
testing/btest/cluster/backend-enum.zeek
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# @TEST-DOC: Test cluster backend enum
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: zeek -NN Zeek::Cluster_Backend_Broker >>out
|
||||||
|
# @TEST-EXEC: zeek -b %INPUT >>out
|
||||||
|
# @TEST-EXEC: btest-diff out
|
||||||
|
|
||||||
|
event zeek_init()
|
||||||
|
{
|
||||||
|
print Cluster::CLUSTER_BACKEND_BROKER, type_name(Cluster::CLUSTER_BACKEND_BROKER);
|
||||||
|
}
|
|
@ -0,0 +1,99 @@
|
||||||
|
# @TEST-DOC: Broker::make_event() together with Cluster::publish_hrw() and Cluster::publish_rr()
|
||||||
|
# @TEST-PORT: BROKER_PORT1
|
||||||
|
# @TEST-PORT: BROKER_PORT2
|
||||||
|
# @TEST-PORT: BROKER_PORT3
|
||||||
|
# @TEST-PORT: BROKER_PORT4
|
||||||
|
# @TEST-PORT: BROKER_PORT5
|
||||||
|
#
|
||||||
|
# @TEST-EXEC: zeek -b --parse-only %INPUT
|
||||||
|
# @TEST-EXEC: btest-bg-run manager-1 ZEEKPATH=$ZEEKPATH:.. CLUSTER_NODE=manager-1 zeek -b %INPUT
|
||||||
|
# @TEST-EXEC: btest-bg-run proxy-1 ZEEKPATH=$ZEEKPATH:.. CLUSTER_NODE=proxy-1 zeek -b %INPUT
|
||||||
|
# @TEST-EXEC: btest-bg-run proxy-2 ZEEKPATH=$ZEEKPATH:.. CLUSTER_NODE=proxy-2 zeek -b %INPUT
|
||||||
|
# @TEST-EXEC: btest-bg-wait 30
|
||||||
|
# @TEST-EXEC: btest-diff manager-1/.stdout
|
||||||
|
# @TEST-EXEC: btest-diff proxy-1/.stdout
|
||||||
|
# @TEST-EXEC: btest-diff proxy-2/.stdout
|
||||||
|
|
||||||
|
@load policy/frameworks/cluster/experimental
|
||||||
|
|
||||||
|
@TEST-START-FILE cluster-layout.zeek
|
||||||
|
redef Cluster::nodes = {
|
||||||
|
["manager-1"] = [$node_type=Cluster::MANAGER, $ip=127.0.0.1, $p=to_port(getenv("BROKER_PORT1"))],
|
||||||
|
["proxy-1"] = [$node_type=Cluster::PROXY, $ip=127.0.0.1, $p=to_port(getenv("BROKER_PORT2")), $manager="manager-1"],
|
||||||
|
["proxy-2"] = [$node_type=Cluster::PROXY, $ip=127.0.0.1, $p=to_port(getenv("BROKER_PORT3")), $manager="manager-1"],
|
||||||
|
};
|
||||||
|
@TEST-END-FILE
|
||||||
|
|
||||||
|
global q = 0;
|
||||||
|
|
||||||
|
event go_away()
|
||||||
|
{
|
||||||
|
terminate();
|
||||||
|
}
|
||||||
|
|
||||||
|
event distributed_event_hrw(c: count)
|
||||||
|
{
|
||||||
|
print "got distributed event hrw", c;
|
||||||
|
}
|
||||||
|
|
||||||
|
event distributed_event_rr(c: count)
|
||||||
|
{
|
||||||
|
print "got distributed event rr", c;
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_stuff(heading: string)
|
||||||
|
{
|
||||||
|
print heading;
|
||||||
|
|
||||||
|
local v: vector of count = vector(0, 1, 2, 3, 13, 37, 42, 101);
|
||||||
|
local e: Broker::Event;
|
||||||
|
|
||||||
|
for ( i in v )
|
||||||
|
{
|
||||||
|
e = Broker::make_event(distributed_event_hrw, v[i]);
|
||||||
|
print "hrw", v[i], Cluster::publish_hrw(Cluster::proxy_pool, v[i], e);
|
||||||
|
}
|
||||||
|
|
||||||
|
local rr_key = "test";
|
||||||
|
|
||||||
|
for ( i in v )
|
||||||
|
{
|
||||||
|
e = Broker::make_event(distributed_event_rr, v[i]);
|
||||||
|
print "rr", Cluster::publish_rr(Cluster::proxy_pool, rr_key, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event Cluster::Experimental::cluster_started()
|
||||||
|
{
|
||||||
|
if ( Cluster::node != "manager-1" )
|
||||||
|
return;
|
||||||
|
|
||||||
|
send_stuff("1st stuff");
|
||||||
|
local e = Broker::make_event(go_away);
|
||||||
|
Broker::publish(Cluster::node_topic("proxy-1"), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
event Cluster::node_down(name: string, id: string)
|
||||||
|
{
|
||||||
|
if ( Cluster::node != "manager-1" )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( name == "proxy-1" )
|
||||||
|
{
|
||||||
|
send_stuff("2nd stuff");
|
||||||
|
local e = Broker::make_event(go_away);
|
||||||
|
Broker::publish(Cluster::node_topic("proxy-2"), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( name == "proxy-2" )
|
||||||
|
{
|
||||||
|
send_stuff("no stuff");
|
||||||
|
terminate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
event Cluster::node_down(name: string, id: string)
|
||||||
|
{
|
||||||
|
if ( name == "manager-1" )
|
||||||
|
terminate();
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue