diff --git a/src/cluster/Backend.cc b/src/cluster/Backend.cc index e1665addeb..80abb8d9bd 100644 --- a/src/cluster/Backend.cc +++ b/src/cluster/Backend.cc @@ -2,14 +2,17 @@ #include "zeek/cluster/Backend.h" +#include #include #include "zeek/Desc.h" #include "zeek/Event.h" +#include "zeek/EventHandler.h" #include "zeek/EventRegistry.h" #include "zeek/Func.h" #include "zeek/Reporter.h" #include "zeek/Type.h" +#include "zeek/Val.h" #include "zeek/cluster/Manager.h" #include "zeek/cluster/OnLoop.h" #include "zeek/cluster/Serializer.h" @@ -19,8 +22,40 @@ #include "zeek/plugin/Plugin.h" #include "zeek/util.h" +#include "zeek/3rdparty/doctest.h" + using namespace zeek::cluster; +double detail::Event::Timestamp() const { + if ( meta ) { + for ( const auto& m : *meta ) { + if ( m.Id() == static_cast(zeek::detail::MetadataType::NetworkTimestamp) ) + return m.Val()->AsTime(); + } + } + + return zeek::detail::NO_TIMESTAMP; +} + +bool detail::Event::AddMetadata(const EnumValPtr& id, zeek::ValPtr val) { + if ( ! id || ! val ) + return false; + + const auto* desc = zeek::event_registry->LookupMetadata(id->Get()); + if ( ! desc ) + return false; + + if ( ! same_type(val->GetType(), desc->Type()) ) + return false; + + if ( ! meta ) + meta = std::make_unique(); + + // Internally stored as zeek_uint_t for serializers. + meta->emplace_back(desc->Id(), std::move(val)); + + return true; +} bool detail::LocalEventHandlingStrategy::DoProcessEvent(std::string_view topic, detail::Event e) { zeek::detail::EventMetadataVectorPtr meta; @@ -243,3 +278,48 @@ void ThreadedBackend::Process(QueueMessage&& msg) { zeek::reporter->FatalError("Unimplemented QueueMessage %zu", msg.index()); } } + +TEST_SUITE_BEGIN("cluster event"); + +TEST_CASE("add metadata") { + auto* handler = zeek::event_registry->Lookup("Supervisor::node_status"); + zeek::Args args{zeek::make_intrusive("TEST"), zeek::val_mgr->Count(42)}; + zeek::cluster::detail::Event event{handler, args, nullptr}; + + auto nts = zeek::id::find_val("EventMetadata::NETWORK_TIMESTAMP"); + REQUIRE(nts); + auto unk = zeek::id::find_val("Log::UNKNOWN"); + REQUIRE(unk); + + bool registered = zeek::event_registry->RegisterMetadata(nts, zeek::base_type(zeek::TYPE_TIME)); + REQUIRE(registered); + + SUBCASE("valid") { + CHECK_EQ(event.Timestamp(), -1.0); + CHECK(event.AddMetadata(nts, zeek::make_intrusive(42.0))); + CHECK_EQ(event.Timestamp(), 42.0); + } + + SUBCASE("valid-two-times") { + CHECK_EQ(event.Timestamp(), -1.0); + CHECK(event.AddMetadata(nts, zeek::make_intrusive(42.0))); + CHECK(event.AddMetadata(nts, zeek::make_intrusive(43.0))); + CHECK_EQ(event.Timestamp(), 42.0); // finds the first one + CHECK_EQ(event.Metadata()->size(), 2); // both are stored + } + + SUBCASE("invalid-value-type") { + CHECK_EQ(event.Timestamp(), -1.0); + CHECK_FALSE(event.AddMetadata(nts, zeek::make_intrusive(42.0))); + CHECK_EQ(event.Timestamp(), -1.0); + CHECK_EQ(event.Metadata(), nullptr); + } + + SUBCASE("unregistered-metadata-identifier") { + CHECK_EQ(event.Timestamp(), -1.0); + CHECK_FALSE(event.AddMetadata(unk, zeek::make_intrusive(42.0))); + CHECK_EQ(event.Timestamp(), -1.0); + CHECK_EQ(event.Metadata(), nullptr); + } +} +TEST_SUITE_END(); diff --git a/src/cluster/Backend.h b/src/cluster/Backend.h index c3506cc3e2..2d29d67f1b 100644 --- a/src/cluster/Backend.h +++ b/src/cluster/Backend.h @@ -9,6 +9,7 @@ #include #include +#include "zeek/Event.h" #include "zeek/EventHandler.h" #include "zeek/Span.h" #include "zeek/Tag.h" @@ -37,8 +38,14 @@ public: /** * Constructor. */ - Event(const EventHandlerPtr& handler, zeek::Args args, double timestamp = 0.0) - : handler(handler), args(std::move(args)), timestamp(timestamp) {} + Event(const EventHandlerPtr& handler, zeek::Args args, zeek::detail::EventMetadataVectorPtr meta) + : handler(handler), args(std::move(args)), meta(std::move(meta)) {} + + /** + * Constructor. + */ + [[deprecated]] Event(const EventHandlerPtr& handler, zeek::Args args, double timestamp = 0.0) + : handler(handler), args(std::move(args)), meta(zeek::detail::MakeEventMetadataVector(timestamp)) {} /** * @return The name of the event. @@ -60,16 +67,35 @@ public: zeek::Args& Args() { return args; } /** - * @return The network timestamp metadata of this event or 0.0. + * @return The network timestamp metadata of this event or -1.0 if not set. */ - double Timestamp() const { return timestamp; } + double Timestamp() const; + + /** + * Add metadata to this cluster event. + * + * The used metadata \a id has to be registered via the Zeek script-layer + * function EventMetadata::register(), or via the C++ API + * EventMgr::RegisterMetadata() during an InitPostScript() hook. + * + * Non-registered metadata will not be added and false is returned. + * + * @param id The enum value identifying the event metadata. + * @param val The value to use. + + * @return true if \a val was was added, else false. + */ + bool AddMetadata(const EnumValPtr& id, ValPtr val); + + /** + * @return A pointer to the metadata vector, or nullptr if no Metadata has been added yet. + */ + const zeek::detail::EventMetadataVector* Metadata() const { return meta.get(); } private: 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. + zeek::detail::EventMetadataVectorPtr meta; }; /**