From 92e7202c7289ba0b9f928148c276e74eefb6a1a4 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Mon, 17 Mar 2025 17:35:25 +0100 Subject: [PATCH 01/14] Basic implementation using the new collector internal service --- collector/collector.cpp | 1 + collector/lib/CollectorService.cpp | 8 +- collector/lib/CollectorService.h | 1 + collector/lib/CollectorStatsExporter.cpp | 3 +- collector/lib/CollectorStatsExporter.h | 2 - collector/lib/ProcessSignalFormatter.cpp | 51 ++++++------ collector/lib/ProcessSignalFormatter.h | 20 ++--- collector/lib/ProcessSignalHandler.cpp | 18 ++-- collector/lib/ProcessSignalHandler.h | 5 +- collector/lib/SensorClient.cpp | 83 +++++++++++++++++++ collector/lib/SensorClient.h | 77 +++++++++++++++++ .../lib/system-inspector/EventExtractor.h | 2 - collector/lib/system-inspector/Service.cpp | 37 +++++++-- collector/lib/system-inspector/Service.h | 8 +- .../lib/system-inspector/SystemInspector.h | 1 + collector/proto/CMakeLists.txt | 1 + collector/proto/third_party/stackrox | 2 +- collector/test/NetworkStatusNotifierTest.cpp | 2 +- 18 files changed, 253 insertions(+), 69 deletions(-) create mode 100644 collector/lib/SensorClient.cpp create mode 100644 collector/lib/SensorClient.h diff --git a/collector/collector.cpp b/collector/collector.cpp index e9ff40bd9b..2f1aaba315 100644 --- a/collector/collector.cpp +++ b/collector/collector.cpp @@ -12,6 +12,7 @@ #include #include "ConfigLoader.h" +#include "SensorClient.h" extern "C" { #include diff --git a/collector/lib/CollectorService.cpp b/collector/lib/CollectorService.cpp index 71b6508cee..a8352adb65 100644 --- a/collector/lib/CollectorService.cpp +++ b/collector/lib/CollectorService.cpp @@ -27,7 +27,6 @@ static const std::string PROMETHEUS_PORT = "9090"; CollectorService::CollectorService(CollectorConfig& config, std::atomic* control, const std::atomic* signum) : config_(config), - system_inspector_(config_), control_(control), signum_(*signum), server_(OPTIONS), @@ -36,6 +35,13 @@ CollectorService::CollectorService(CollectorConfig& config, std::atomic(config_.grpc_channel); + } else { + client_ = std::make_unique(); + } + system_inspector_ = {config_, client_.get()}; + // Network tracking if (!config_.grpc_channel || !config_.DisableNetworkFlows()) { // In case if no GRPC is used, continue to setup networking infrasturcture diff --git a/collector/lib/CollectorService.h b/collector/lib/CollectorService.h index 01f6ee2a80..30be275982 100644 --- a/collector/lib/CollectorService.h +++ b/collector/lib/CollectorService.h @@ -32,6 +32,7 @@ class CollectorService { bool WaitForGRPCServer(); CollectorConfig& config_; + std::unique_ptr client_; system_inspector::Service system_inspector_; std::atomic* control_; diff --git a/collector/lib/CollectorStatsExporter.cpp b/collector/lib/CollectorStatsExporter.cpp index ee628c8eb6..a03a902343 100644 --- a/collector/lib/CollectorStatsExporter.cpp +++ b/collector/lib/CollectorStatsExporter.cpp @@ -1,13 +1,12 @@ #include "CollectorStatsExporter.h" #include -#include #include +#include "CollectorStats.h" #include "Containers.h" #include "EventNames.h" #include "Logging.h" -#include "Utility.h" #include "prometheus/gauge.h" #include "system-inspector/Service.h" diff --git a/collector/lib/CollectorStatsExporter.h b/collector/lib/CollectorStatsExporter.h index d9b6f5285c..b60e13beaf 100644 --- a/collector/lib/CollectorStatsExporter.h +++ b/collector/lib/CollectorStatsExporter.h @@ -3,8 +3,6 @@ #include #include "CollectorConfig.h" -#include "CollectorConnectionStats.h" -#include "CollectorStats.h" #include "StoppableThread.h" #include "prometheus/registry.h" #include "system-inspector/Service.h" diff --git a/collector/lib/ProcessSignalFormatter.cpp b/collector/lib/ProcessSignalFormatter.cpp index a588d75bd6..75851b714a 100644 --- a/collector/lib/ProcessSignalFormatter.cpp +++ b/collector/lib/ProcessSignalFormatter.cpp @@ -4,6 +4,7 @@ #include +#include "internalapi/sensor/collector_iservice.pb.h" #include "internalapi/sensor/signal_iservice.pb.h" #include "CollectorStats.h" @@ -65,9 +66,9 @@ ProcessSignalFormatter::ProcessSignalFormatter( event_extractor_->Init(inspector); } -ProcessSignalFormatter::~ProcessSignalFormatter() {} +ProcessSignalFormatter::~ProcessSignalFormatter() = default; -const SignalStreamMessage* ProcessSignalFormatter::ToProtoMessage(sinsp_evt* event) { +const sensor::MsgFromCollector* ProcessSignalFormatter::ToProtoMessage(sinsp_evt* event) { if (process_signals[event->get_type()] == ProcessSignalType::UNKNOWN_PROCESS_TYPE) { return nullptr; } @@ -80,38 +81,34 @@ const SignalStreamMessage* ProcessSignalFormatter::ToProtoMessage(sinsp_evt* eve } ProcessSignal* process_signal = CreateProcessSignal(event); - if (!process_signal) { + if (process_signal == nullptr) { return nullptr; } - Signal* signal = Allocate(); - signal->set_allocated_process_signal(process_signal); - - SignalStreamMessage* signal_stream_message = AllocateRoot(); - signal_stream_message->clear_collector_register_request(); - signal_stream_message->set_allocated_signal(signal); - return signal_stream_message; + auto* msg = AllocateRoot(); + msg->clear_info(); + msg->clear_register_(); + msg->set_allocated_process_signal(process_signal); + return msg; } -const SignalStreamMessage* ProcessSignalFormatter::ToProtoMessage(sinsp_threadinfo* tinfo) { +const sensor::MsgFromCollector* ProcessSignalFormatter::ToProtoMessage(sinsp_threadinfo* tinfo) { Reset(); if (!ValidateProcessDetails(tinfo)) { CLOG(INFO) << "Dropping process event: " << tinfo; return nullptr; } - ProcessSignal* process_signal = CreateProcessSignal(tinfo); - if (!process_signal) { + ProcessSignal* signal = CreateProcessSignal(tinfo); + if (signal == nullptr) { return nullptr; } - Signal* signal = Allocate(); - signal->set_allocated_process_signal(process_signal); - - SignalStreamMessage* signal_stream_message = AllocateRoot(); - signal_stream_message->clear_collector_register_request(); - signal_stream_message->set_allocated_signal(signal); - return signal_stream_message; + auto* msg = AllocateRoot(); + msg->clear_register_(); + msg->clear_info(); + msg->set_allocated_process_signal(signal); + return msg; } ProcessSignal* ProcessSignalFormatter::CreateProcessSignal(sinsp_evt* event) { @@ -173,7 +170,7 @@ ProcessSignal* ProcessSignalFormatter::CreateProcessSignal(sinsp_evt* event) { // set time auto timestamp = Allocate(); *timestamp = TimeUtil::NanosecondsToTimestamp(event->get_ts()); - signal->set_allocated_time(timestamp); + signal->set_allocated_creation_time(timestamp); // set container_id if (const std::string* container_id = event_extractor_->get_container_id(event)) { @@ -238,7 +235,7 @@ ProcessSignal* ProcessSignalFormatter::CreateProcessSignal(sinsp_threadinfo* tin // set time auto timestamp = Allocate(); *timestamp = TimeUtil::NanosecondsToTimestamp(tinfo->m_clone_ts); - signal->set_allocated_time(timestamp); + signal->set_allocated_creation_time(timestamp); // set container_id signal->set_container_id(tinfo->m_container_id); @@ -315,20 +312,20 @@ void ProcessSignalFormatter::CountLineage(const std::vector& lineag void ProcessSignalFormatter::GetProcessLineage(sinsp_threadinfo* tinfo, std::vector& lineage) { - if (tinfo == NULL) { + if (tinfo == nullptr) { return; } - sinsp_threadinfo* mt = NULL; + sinsp_threadinfo* mt = nullptr; if (tinfo->is_main_thread()) { mt = tinfo; } else { mt = tinfo->get_main_thread(); - if (mt == NULL) { + if (mt == nullptr) { return; } } - sinsp_threadinfo::visitor_func_t visitor = [this, &lineage](sinsp_threadinfo* pt) { - if (pt == NULL) { + sinsp_threadinfo::visitor_func_t visitor = [&lineage](sinsp_threadinfo* pt) { + if (pt == nullptr) { return false; } if (pt->m_pid == 0) { diff --git a/collector/lib/ProcessSignalFormatter.h b/collector/lib/ProcessSignalFormatter.h index 8c57011c5b..5da5d744ab 100644 --- a/collector/lib/ProcessSignalFormatter.h +++ b/collector/lib/ProcessSignalFormatter.h @@ -5,11 +5,9 @@ #include #include "api/v1/signal.pb.h" -#include "internalapi/sensor/signal_iservice.pb.h" -#include "storage/process_indicator.pb.h" +#include "internalapi/sensor/collector_iservice.pb.h" #include "CollectorConfig.h" -#include "CollectorStats.h" #include "ContainerMetadata.h" #include "EventNames.h" #include "ProtoSignalFormatter.h" @@ -17,25 +15,25 @@ // forward definitions class sinsp; class sinsp_threadinfo; -namespace collector { -namespace system_inspector { + +namespace collector::system_inspector { class EventExtractor; } -} // namespace collector namespace collector { -class ProcessSignalFormatter : public ProtoSignalFormatter { +class ProcessSignalFormatter : public ProtoSignalFormatter { public: ProcessSignalFormatter(sinsp* inspector, const CollectorConfig& config); ~ProcessSignalFormatter(); using Signal = v1::Signal; - using ProcessSignal = storage::ProcessSignal; - using LineageInfo = storage::ProcessSignal_LineageInfo; + using ProcessSignal = sensor::ProcessSignal; + using LineageInfo = sensor::ProcessSignal_LineageInfo; + using MsgFromCollector = sensor::MsgFromCollector; - const sensor::SignalStreamMessage* ToProtoMessage(sinsp_evt* event) override; - const sensor::SignalStreamMessage* ToProtoMessage(sinsp_threadinfo* tinfo); + const MsgFromCollector* ToProtoMessage(sinsp_evt* event) override; + const MsgFromCollector* ToProtoMessage(sinsp_threadinfo* tinfo); void GetProcessLineage(sinsp_threadinfo* tinfo, std::vector& lineage); diff --git a/collector/lib/ProcessSignalHandler.cpp b/collector/lib/ProcessSignalHandler.cpp index ed36ecbb37..ae21dff492 100644 --- a/collector/lib/ProcessSignalHandler.cpp +++ b/collector/lib/ProcessSignalHandler.cpp @@ -13,7 +13,7 @@ namespace collector { -std::string compute_process_key(const ::storage::ProcessSignal& s) { +std::string compute_process_key(const ::sensor::ProcessSignal& s) { std::stringstream ss; ss << s.container_id() << " " << s.name() << " "; if (s.args().length() <= 256) { @@ -39,21 +39,21 @@ bool ProcessSignalHandler::Stop() { SignalHandler::Result ProcessSignalHandler::HandleSignal(sinsp_evt* evt) { const auto* signal_msg = formatter_.ToProtoMessage(evt); - if (!signal_msg) { + if (signal_msg == nullptr) { ++(stats_->nProcessResolutionFailuresByEvt); return IGNORED; } - const char* name = signal_msg->signal().process_signal().name().c_str(); - const int pid = signal_msg->signal().process_signal().pid(); + const char* name = signal_msg->process_signal().name().c_str(); + const uint32_t pid = signal_msg->process_signal().pid(); DTRACE_PROBE2(collector, process_signal_handler, name, pid); - if (!rate_limiter_.Allow(compute_process_key(signal_msg->signal().process_signal()))) { + if (!rate_limiter_.Allow(compute_process_key(signal_msg->process_signal()))) { ++(stats_->nProcessRateLimitCount); return IGNORED; } - auto result = client_->PushSignals(*signal_msg); + auto result = client_->SendMsg(*signal_msg); if (result == SignalHandler::PROCESSED) { ++(stats_->nProcessSent); } else if (result == SignalHandler::ERROR) { @@ -65,17 +65,17 @@ SignalHandler::Result ProcessSignalHandler::HandleSignal(sinsp_evt* evt) { SignalHandler::Result ProcessSignalHandler::HandleExistingProcess(sinsp_threadinfo* tinfo) { const auto* signal_msg = formatter_.ToProtoMessage(tinfo); - if (!signal_msg) { + if (signal_msg == nullptr) { ++(stats_->nProcessResolutionFailuresByTinfo); return IGNORED; } - if (!rate_limiter_.Allow(compute_process_key(signal_msg->signal().process_signal()))) { + if (!rate_limiter_.Allow(compute_process_key(signal_msg->process_signal()))) { ++(stats_->nProcessRateLimitCount); return IGNORED; } - auto result = client_->PushSignals(*signal_msg); + auto result = client_->SendMsg(*signal_msg); if (result == SignalHandler::PROCESSED) { ++(stats_->nProcessSent); } else if (result == SignalHandler::ERROR) { diff --git a/collector/lib/ProcessSignalHandler.h b/collector/lib/ProcessSignalHandler.h index b6c2797a17..7f8d2bbaf2 100644 --- a/collector/lib/ProcessSignalHandler.h +++ b/collector/lib/ProcessSignalHandler.h @@ -7,6 +7,7 @@ #include "CollectorConfig.h" #include "ProcessSignalFormatter.h" #include "RateLimit.h" +#include "SensorClient.h" #include "SignalHandler.h" #include "system-inspector/Service.h" @@ -21,7 +22,7 @@ class ProcessSignalHandler : public SignalHandler { public: ProcessSignalHandler( sinsp* inspector, - ISignalServiceClient* client, + ISensorClient* client, system_inspector::Stats* stats, const CollectorConfig& config) : client_(client), @@ -43,7 +44,7 @@ class ProcessSignalHandler : public SignalHandler { std::vector GetRelevantEvents() override; private: - ISignalServiceClient* client_; + ISensorClient* client_; ProcessSignalFormatter formatter_; system_inspector::Stats* stats_; RateLimitCache rate_limiter_; diff --git a/collector/lib/SensorClient.cpp b/collector/lib/SensorClient.cpp new file mode 100644 index 0000000000..24606ecfb8 --- /dev/null +++ b/collector/lib/SensorClient.cpp @@ -0,0 +1,83 @@ +#include "SensorClient.h" + +#include "GRPCUtil.h" +#include "Logging.h" + +namespace collector { +bool SensorClient::EstablishGRPCStreamSingle() { + std::mutex mtx; + std::unique_lock lock(mtx); + stream_interrupted_.wait(lock, [this]() { return !stream_active_.load(std::memory_order_acquire) || thread_.should_stop(); }); + if (thread_.should_stop()) { + return false; + } + + CLOG(INFO) << "Trying to establish GRPC stream for signals ..."; + + if (!WaitForChannelReady(channel_, [this]() { return thread_.should_stop(); })) { + return false; + } + if (thread_.should_stop()) { + return false; + } + + // stream writer + context_ = std::make_unique(); + writer_ = DuplexClient::CreateWithReadsIgnored(&sensor::CollectorService::Stub::AsyncCommunicate, channel_, context_.get()); + if (!writer_->WaitUntilStarted(std::chrono::seconds(30))) { + CLOG(ERROR) << "Signal stream not ready after 30 seconds. Retrying ..."; + CLOG(ERROR) << "Error message: " << writer_->FinishNow().error_message(); + writer_.reset(); + return true; + } + CLOG(INFO) << "Successfully established GRPC stream for signals."; + + first_write_ = true; + stream_active_.store(true, std::memory_order_release); + return true; +} + +void SensorClient::EstablishGRPCStream() { + while (EstablishGRPCStreamSingle()); + CLOG(INFO) << "Signal service client terminating."; +} + +void SensorClient::Start() { + thread_.Start([this] { EstablishGRPCStream(); }); +} + +void SensorClient::Stop() { + stream_interrupted_.notify_one(); + thread_.Stop(); + context_->TryCancel(); + context_.reset(); +} + +SignalHandler::Result SensorClient::SendMsg(const sensor::MsgFromCollector& msg) { + if (!stream_active_.load(std::memory_order_acquire)) { + CLOG_THROTTLED(ERROR, std::chrono::seconds(10)) + << "GRPC stream is not established"; + return SignalHandler::ERROR; + } + + if (first_write_) { + first_write_ = false; + return SignalHandler::NEEDS_REFRESH; + } + + if (!writer_->Write(msg)) { + auto status = writer_->FinishNow(); + if (!status.ok()) { + CLOG(ERROR) << "GRPC writes failed: (" << status.error_code() << ") " << status.error_message(); + } + writer_.reset(); + + stream_active_.store(false, std::memory_order_release); + CLOG(ERROR) << "GRPC stream interrupted"; + stream_interrupted_.notify_one(); + return SignalHandler::ERROR; + } + + return SignalHandler::PROCESSED; +} +} // namespace collector diff --git a/collector/lib/SensorClient.h b/collector/lib/SensorClient.h new file mode 100644 index 0000000000..664e363e62 --- /dev/null +++ b/collector/lib/SensorClient.h @@ -0,0 +1,77 @@ +#ifndef _SENSOR_CLIENT_H_ +#define _SENSOR_CLIENT_H_ + +#include +#include + +#include + +#include "internalapi/sensor/collector_iservice.grpc.pb.h" +#include "internalapi/sensor/collector_iservice.pb.h" + +#include "DuplexGRPC.h" +#include "SignalHandler.h" +#include "StoppableThread.h" + +namespace collector { + +class ISensorClient { + public: + using Service = sensor::CollectorService; + + ISensorClient() = default; + ISensorClient(const ISensorClient&) = default; + ISensorClient(ISensorClient&&) = delete; + ISensorClient& operator=(const ISensorClient&) = default; + ISensorClient& operator=(ISensorClient&&) = delete; + virtual ~ISensorClient() = default; + + virtual void Start() = 0; + virtual void Stop() = 0; + + virtual SignalHandler::Result SendMsg(const sensor::MsgFromCollector& msg) = 0; +}; + +class SensorClient : public ISensorClient { + public: + using Service = sensor::CollectorService; + + explicit SensorClient(std::shared_ptr channel) + : channel_(std::move(channel)) { + } + + void Start() override; + void Stop() override; + + SignalHandler::Result SendMsg(const sensor::MsgFromCollector& msg) override; + + private: + void EstablishGRPCStream(); + bool EstablishGRPCStreamSingle(); + + std::shared_ptr channel_; + + StoppableThread thread_; + std::atomic stream_active_ = false; + std::condition_variable stream_interrupted_; + + // This needs to have the same lifetime as the class. + std::unique_ptr context_; + std::unique_ptr> writer_; + + bool first_write_ = false; +}; + +class SensorClientStdout : public ISensorClient { + void Start() override {} + void Stop() override {} + + SignalHandler::Result SendMsg(const sensor::MsgFromCollector& msg) override { + LogProtobufMessage(msg); + return SignalHandler::PROCESSED; + } +}; + +} // namespace collector + +#endif //_SENSOR_CLIENT_H_ diff --git a/collector/lib/system-inspector/EventExtractor.h b/collector/lib/system-inspector/EventExtractor.h index 94d129befc..66e1def320 100644 --- a/collector/lib/system-inspector/EventExtractor.h +++ b/collector/lib/system-inspector/EventExtractor.h @@ -1,9 +1,7 @@ #pragma once -#include #include -#include "libsinsp/filterchecks.h" #include "libsinsp/sinsp.h" #include "Logging.h" diff --git a/collector/lib/system-inspector/Service.cpp b/collector/lib/system-inspector/Service.cpp index 95c0394416..686017be81 100644 --- a/collector/lib/system-inspector/Service.cpp +++ b/collector/lib/system-inspector/Service.cpp @@ -32,15 +32,41 @@ namespace collector::system_inspector { +Service::Service() : signal_client_(nullptr) {} Service::~Service() = default; +Service& Service::operator=(Service&& other) noexcept { + { + auto other_sinsp_lock = std::lock_guard(other.libsinsp_mutex_); + auto this_sinsp_lock = std::lock_guard(libsinsp_mutex_); + + inspector_.swap(other.inspector_); + container_metadata_inspector_.swap(other.container_metadata_inspector_); + default_formatter_.swap(other.default_formatter_); + } + + std::swap(signal_client_, other.signal_client_); + signal_handlers_.swap(other.signal_handlers_); + + userspace_stats_ = other.userspace_stats_; + global_event_filter_ = other.global_event_filter_; + + { + auto other_running_lock = std::lock_guard(other.running_mutex_); + auto this_running_lock = std::lock_guard(running_mutex_); + std::swap(running_, other.running_); + } -Service::Service(const CollectorConfig& config) + return *this; +} + +Service::Service(const CollectorConfig& config, ISensorClient* client) : inspector_(std::make_unique(true)), container_metadata_inspector_(std::make_unique(inspector_.get())), default_formatter_(std::make_unique( inspector_.get(), DEFAULT_OUTPUT_STR, - EventExtractor::FilterList())) { + EventExtractor::FilterList())), + signal_client_(client) { // Setup the inspector. // peeking into arguments has a big overhead, so we prevent it from happening inspector_->set_snaplen(0); @@ -95,13 +121,8 @@ Service::Service(const CollectorConfig& config) AddSignalHandler(std::make_unique(inspector_.get())); AddSignalHandler(std::make_unique(inspector_.get())); - if (config.grpc_channel) { - signal_client_ = std::make_unique(config.grpc_channel); - } else { - signal_client_ = std::make_unique(); - } AddSignalHandler(std::make_unique(inspector_.get(), - signal_client_.get(), + signal_client_, &userspace_stats_, config)); diff --git a/collector/lib/system-inspector/Service.h b/collector/lib/system-inspector/Service.h index 651e7ff7cb..35dcbe3468 100644 --- a/collector/lib/system-inspector/Service.h +++ b/collector/lib/system-inspector/Service.h @@ -10,6 +10,7 @@ #include "ConnTracker.h" #include "ContainerMetadata.h" #include "Control.h" +#include "SensorClient.h" #include "SignalHandler.h" #include "SignalServiceClient.h" #include "SystemInspector.h" @@ -24,13 +25,14 @@ namespace collector::system_inspector { class Service : public SystemInspector { public: + Service(); Service(const Service&) = delete; Service(Service&&) = delete; Service& operator=(const Service&) = delete; - Service& operator=(Service&&) = delete; + Service& operator=(Service&&) noexcept; ~Service() override; - Service(const CollectorConfig& config); + Service(const CollectorConfig& config, ISensorClient* client); void Start() override; void Run(const std::atomic& control) override; void CleanUp() override; @@ -73,7 +75,7 @@ class Service : public SystemInspector { std::unique_ptr inspector_; std::shared_ptr container_metadata_inspector_; std::unique_ptr default_formatter_; - std::unique_ptr signal_client_; + ISensorClient* signal_client_; std::vector signal_handlers_; Stats userspace_stats_; std::bitset global_event_filter_; diff --git a/collector/lib/system-inspector/SystemInspector.h b/collector/lib/system-inspector/SystemInspector.h index 247da3f223..4e937b81a3 100644 --- a/collector/lib/system-inspector/SystemInspector.h +++ b/collector/lib/system-inspector/SystemInspector.h @@ -5,6 +5,7 @@ #include "CollectorConfig.h" #include "Control.h" +#include "SensorClient.h" #include "ppm_events_public.h" namespace collector::system_inspector { diff --git a/collector/proto/CMakeLists.txt b/collector/proto/CMakeLists.txt index 279d64c0dd..4290bb1a66 100644 --- a/collector/proto/CMakeLists.txt +++ b/collector/proto/CMakeLists.txt @@ -14,6 +14,7 @@ set(ROX_PROTO_FILES internalapi/sensor/network_connection_iservice.proto internalapi/sensor/network_enums.proto internalapi/sensor/signal_iservice.proto + internalapi/sensor/collector_iservice.proto storage/network_flow.proto storage/process_indicator.proto ) diff --git a/collector/proto/third_party/stackrox b/collector/proto/third_party/stackrox index 1d04bca326..91a0cccf27 160000 --- a/collector/proto/third_party/stackrox +++ b/collector/proto/third_party/stackrox @@ -1 +1 @@ -Subproject commit 1d04bca3268f5edd3837a0850284be0fbd4100c3 +Subproject commit 91a0cccf27fa9fd45ec00cc15b3d547d3da47fe9 diff --git a/collector/test/NetworkStatusNotifierTest.cpp b/collector/test/NetworkStatusNotifierTest.cpp index 4af986ea94..d26a4426cd 100644 --- a/collector/test/NetworkStatusNotifierTest.cpp +++ b/collector/test/NetworkStatusNotifierTest.cpp @@ -190,7 +190,7 @@ class NetworkConnectionInfoMessageParser { class NetworkStatusNotifierTest : public testing::Test { public: NetworkStatusNotifierTest() - : inspector(config), + : inspector(config, nullptr), conn_tracker(std::make_shared()), conn_scraper(std::make_unique()), comm(std::make_unique()), From bfe29a8357894f5f0b779771f433fe4adfbaba6a Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Mon, 24 Mar 2025 18:26:54 +0100 Subject: [PATCH 02/14] Add CollectorOutput component --- collector/lib/CollectorConfig.cpp | 3 + collector/lib/CollectorConfig.h | 3 + collector/lib/CollectorOutput.cpp | 42 ++++++++++ collector/lib/CollectorOutput.h | 76 +++++++++++++++++++ collector/lib/CollectorService.cpp | 9 +-- collector/lib/CollectorService.h | 3 +- collector/lib/ProcessSignalHandler.cpp | 11 --- collector/lib/ProcessSignalHandler.h | 9 +-- collector/lib/system-inspector/Service.cpp | 11 +-- collector/lib/system-inspector/Service.h | 8 +- .../lib/system-inspector/SystemInspector.h | 1 - 11 files changed, 139 insertions(+), 37 deletions(-) create mode 100644 collector/lib/CollectorOutput.cpp create mode 100644 collector/lib/CollectorOutput.h diff --git a/collector/lib/CollectorConfig.cpp b/collector/lib/CollectorConfig.cpp index 294e25bb4d..f3cb0cfbc7 100644 --- a/collector/lib/CollectorConfig.cpp +++ b/collector/lib/CollectorConfig.cpp @@ -82,6 +82,8 @@ PathEnvVar tls_client_cert_path("ROX_COLLECTOR_TLS_CLIENT_CERT"); PathEnvVar tls_client_key_path("ROX_COLLECTOR_TLS_CLIENT_KEY"); BoolEnvVar disable_process_arguments("ROX_COLLECTOR_NO_PROCESS_ARGUMENTS", false); + +BoolEnvVar use_stdout_output("ROX_COLLECTOR_USE_STDOUT", false); } // namespace constexpr bool CollectorConfig::kTurnOffScrape; @@ -112,6 +114,7 @@ void CollectorConfig::InitCollectorConfig(CollectorArgs* args) { enable_introspection_ = enable_introspection.value(); track_send_recv_ = track_send_recv.value(); disable_process_arguments_ = disable_process_arguments.value(); + use_stdout_ = use_stdout_output.value(); for (const auto& syscall : kSyscalls) { syscalls_.emplace_back(syscall); diff --git a/collector/lib/CollectorConfig.h b/collector/lib/CollectorConfig.h index 2a5244c29e..c09d849696 100644 --- a/collector/lib/CollectorConfig.h +++ b/collector/lib/CollectorConfig.h @@ -161,6 +161,7 @@ class CollectorConfig { unsigned int GetSinspTotalBufferSize() const { return sinsp_total_buffer_size_; } unsigned int GetSinspThreadCacheSize() const { return sinsp_thread_cache_size_; } bool DisableProcessArguments() const { return disable_process_arguments_; } + bool UseStdout() const { return use_stdout_; } static std::pair CheckConfiguration(const char* config, Json::Value* root); @@ -226,6 +227,8 @@ class CollectorConfig { bool disable_process_arguments_ = false; + bool use_stdout_ = false; + // One ring buffer will be initialized for this many CPUs unsigned int sinsp_cpu_per_buffer_ = 0; // Size of one ring buffer, in bytes. diff --git a/collector/lib/CollectorOutput.cpp b/collector/lib/CollectorOutput.cpp new file mode 100644 index 0000000000..6c5f45b2d2 --- /dev/null +++ b/collector/lib/CollectorOutput.cpp @@ -0,0 +1,42 @@ +#include "CollectorOutput.h" + +namespace collector { + +namespace { +SignalHandler::Result SensorOutput(std::vector>& clients, const sensor::MsgFromCollector& msg) { + for (auto& client : clients) { + auto res = client->SendMsg(msg); + if (res != SignalHandler::PROCESSED) { + return res; + } + } + return SignalHandler::PROCESSED; +} + +SignalHandler::Result SignalOutput(std::vector>& clients, const sensor::SignalStreamMessage& msg) { + for (auto& client : clients) { + auto res = client->PushSignals(msg); + if (res != SignalHandler::PROCESSED) { + return res; + } + } + return SignalHandler::PROCESSED; +} +} // namespace + +SignalHandler::Result CollectorOutput::SendMsg(const MessageType& msg) { + auto visitor = [this](auto&& m) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + return SensorOutput(sensor_clients_, m); + } else if constexpr (std::is_same_v) { + return SignalOutput(signal_clients_, m); + } + + // Unknown type + return SignalHandler::ERROR; + }; + + return std::visit(visitor, msg); +} +} // namespace collector diff --git a/collector/lib/CollectorOutput.h b/collector/lib/CollectorOutput.h new file mode 100644 index 0000000000..4f9f5896f3 --- /dev/null +++ b/collector/lib/CollectorOutput.h @@ -0,0 +1,76 @@ +#ifndef COLLECTOR_OUTPUT_H +#define COLLECTOR_OUTPUT_H + +#include + +#include "internalapi/sensor/collector_iservice.pb.h" +#include "internalapi/sensor/signal_iservice.pb.h" + +#include "CollectorConfig.h" +#include "SensorClient.h" +#include "SignalHandler.h" +#include "SignalServiceClient.h" + +namespace collector { + +using MessageType = std::variant; + +class CollectorOutput { + public: + CollectorOutput(const CollectorOutput&) = default; + CollectorOutput(CollectorOutput&&) = delete; + CollectorOutput& operator=(const CollectorOutput&) = delete; + CollectorOutput& operator=(CollectorOutput&&) = delete; + + CollectorOutput(const CollectorConfig& config) { + if (config.grpc_channel != nullptr) { + auto sensor_client = std::make_unique(config.grpc_channel); + auto signal_client = std::make_unique(config.grpc_channel); + sensor_clients_.emplace_back(std::move(sensor_client)); + signal_clients_.emplace_back(std::move(signal_client)); + } + + if (config.UseStdout()) { + auto sensor_client = std::make_unique(); + auto signal_client = std::make_unique(); + sensor_clients_.emplace_back(std::move(sensor_client)); + signal_clients_.emplace_back(std::move(signal_client)); + } + + if (sensor_clients_.empty() || signal_clients_.empty()) { + CLOG(FATAL) << "No available output configured"; + } + + StartClients(sensor_clients_); + StartClients(signal_clients_); + } + + ~CollectorOutput() { + StopClients(sensor_clients_); + StopClients(signal_clients_); + } + + SignalHandler::Result SendMsg(const MessageType& msg); + + private: + template + void StartClients(std::vector& clients) { + for (auto& client : clients) { + client->Start(); + } + } + + template + void StopClients(std::vector& clients) { + for (auto& client : clients) { + client->Stop(); + } + } + + std::vector> sensor_clients_; + std::vector> signal_clients_; +}; + +} // namespace collector + +#endif // COLLECTOR_OUTPUT_H diff --git a/collector/lib/CollectorService.cpp b/collector/lib/CollectorService.cpp index a8352adb65..e24231782b 100644 --- a/collector/lib/CollectorService.cpp +++ b/collector/lib/CollectorService.cpp @@ -27,6 +27,8 @@ static const std::string PROMETHEUS_PORT = "9090"; CollectorService::CollectorService(CollectorConfig& config, std::atomic* control, const std::atomic* signum) : config_(config), + output_(config), + system_inspector_(config, &output_), control_(control), signum_(*signum), server_(OPTIONS), @@ -35,13 +37,6 @@ CollectorService::CollectorService(CollectorConfig& config, std::atomic(config_.grpc_channel); - } else { - client_ = std::make_unique(); - } - system_inspector_ = {config_, client_.get()}; - // Network tracking if (!config_.grpc_channel || !config_.DisableNetworkFlows()) { // In case if no GRPC is used, continue to setup networking infrasturcture diff --git a/collector/lib/CollectorService.h b/collector/lib/CollectorService.h index 30be275982..551d211fd8 100644 --- a/collector/lib/CollectorService.h +++ b/collector/lib/CollectorService.h @@ -5,6 +5,7 @@ #include "CivetWrapper.h" #include "CollectorConfig.h" +#include "CollectorOutput.h" #include "CollectorStatsExporter.h" #include "ConfigLoader.h" #include "Control.h" @@ -32,7 +33,7 @@ class CollectorService { bool WaitForGRPCServer(); CollectorConfig& config_; - std::unique_ptr client_; + CollectorOutput output_; system_inspector::Service system_inspector_; std::atomic* control_; diff --git a/collector/lib/ProcessSignalHandler.cpp b/collector/lib/ProcessSignalHandler.cpp index ae21dff492..aad9ef9b2e 100644 --- a/collector/lib/ProcessSignalHandler.cpp +++ b/collector/lib/ProcessSignalHandler.cpp @@ -25,17 +25,6 @@ std::string compute_process_key(const ::sensor::ProcessSignal& s) { return ss.str(); } -bool ProcessSignalHandler::Start() { - client_->Start(); - return true; -} - -bool ProcessSignalHandler::Stop() { - client_->Stop(); - rate_limiter_.ResetRateLimitCache(); - return true; -} - SignalHandler::Result ProcessSignalHandler::HandleSignal(sinsp_evt* evt) { const auto* signal_msg = formatter_.ToProtoMessage(evt); diff --git a/collector/lib/ProcessSignalHandler.h b/collector/lib/ProcessSignalHandler.h index 7f8d2bbaf2..637a103ed2 100644 --- a/collector/lib/ProcessSignalHandler.h +++ b/collector/lib/ProcessSignalHandler.h @@ -1,13 +1,10 @@ #pragma once -#include - #include #include "CollectorConfig.h" #include "ProcessSignalFormatter.h" #include "RateLimit.h" -#include "SensorClient.h" #include "SignalHandler.h" #include "system-inspector/Service.h" @@ -22,7 +19,7 @@ class ProcessSignalHandler : public SignalHandler { public: ProcessSignalHandler( sinsp* inspector, - ISensorClient* client, + CollectorOutput* client, system_inspector::Stats* stats, const CollectorConfig& config) : client_(client), @@ -36,15 +33,13 @@ class ProcessSignalHandler : public SignalHandler { ProcessSignalHandler& operator=(ProcessSignalHandler&&) = delete; ~ProcessSignalHandler() override = default; - bool Start() override; - bool Stop() override; Result HandleSignal(sinsp_evt* evt) override; Result HandleExistingProcess(sinsp_threadinfo* tinfo) override; std::string GetName() override { return "ProcessSignalHandler"; } std::vector GetRelevantEvents() override; private: - ISensorClient* client_; + CollectorOutput* client_; ProcessSignalFormatter formatter_; system_inspector::Stats* stats_; RateLimitCache rate_limiter_; diff --git a/collector/lib/system-inspector/Service.cpp b/collector/lib/system-inspector/Service.cpp index 686017be81..5cb9676b18 100644 --- a/collector/lib/system-inspector/Service.cpp +++ b/collector/lib/system-inspector/Service.cpp @@ -14,6 +14,7 @@ #include "CollectionMethod.h" #include "CollectorException.h" +#include "CollectorOutput.h" #include "CollectorStats.h" #include "ContainerEngine.h" #include "ContainerMetadata.h" @@ -32,7 +33,7 @@ namespace collector::system_inspector { -Service::Service() : signal_client_(nullptr) {} +Service::Service() = default; Service::~Service() = default; Service& Service::operator=(Service&& other) noexcept { { @@ -44,7 +45,7 @@ Service& Service::operator=(Service&& other) noexcept { default_formatter_.swap(other.default_formatter_); } - std::swap(signal_client_, other.signal_client_); + std::swap(output_, other.output_); signal_handlers_.swap(other.signal_handlers_); userspace_stats_ = other.userspace_stats_; @@ -59,14 +60,14 @@ Service& Service::operator=(Service&& other) noexcept { return *this; } -Service::Service(const CollectorConfig& config, ISensorClient* client) +Service::Service(const CollectorConfig& config, CollectorOutput* client) : inspector_(std::make_unique(true)), container_metadata_inspector_(std::make_unique(inspector_.get())), default_formatter_(std::make_unique( inspector_.get(), DEFAULT_OUTPUT_STR, EventExtractor::FilterList())), - signal_client_(client) { + output_(client) { // Setup the inspector. // peeking into arguments has a big overhead, so we prevent it from happening inspector_->set_snaplen(0); @@ -122,7 +123,7 @@ Service::Service(const CollectorConfig& config, ISensorClient* client) AddSignalHandler(std::make_unique(inspector_.get())); AddSignalHandler(std::make_unique(inspector_.get(), - signal_client_, + output_, &userspace_stats_, config)); diff --git a/collector/lib/system-inspector/Service.h b/collector/lib/system-inspector/Service.h index 35dcbe3468..251d05f81d 100644 --- a/collector/lib/system-inspector/Service.h +++ b/collector/lib/system-inspector/Service.h @@ -7,12 +7,10 @@ #include -#include "ConnTracker.h" +#include "CollectorOutput.h" #include "ContainerMetadata.h" #include "Control.h" -#include "SensorClient.h" #include "SignalHandler.h" -#include "SignalServiceClient.h" #include "SystemInspector.h" // forward declarations @@ -32,7 +30,7 @@ class Service : public SystemInspector { Service& operator=(Service&&) noexcept; ~Service() override; - Service(const CollectorConfig& config, ISensorClient* client); + Service(const CollectorConfig& config, CollectorOutput* client); void Start() override; void Run(const std::atomic& control) override; void CleanUp() override; @@ -75,7 +73,7 @@ class Service : public SystemInspector { std::unique_ptr inspector_; std::shared_ptr container_metadata_inspector_; std::unique_ptr default_formatter_; - ISensorClient* signal_client_; + CollectorOutput* output_{}; std::vector signal_handlers_; Stats userspace_stats_; std::bitset global_event_filter_; diff --git a/collector/lib/system-inspector/SystemInspector.h b/collector/lib/system-inspector/SystemInspector.h index 4e937b81a3..247da3f223 100644 --- a/collector/lib/system-inspector/SystemInspector.h +++ b/collector/lib/system-inspector/SystemInspector.h @@ -5,7 +5,6 @@ #include "CollectorConfig.h" #include "Control.h" -#include "SensorClient.h" #include "ppm_events_public.h" namespace collector::system_inspector { From 46ff0878467aaa9d790dbb4c0b567c12eba991b7 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Tue, 25 Mar 2025 10:21:02 +0100 Subject: [PATCH 03/14] Cleanup --- collector/collector.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/collector/collector.cpp b/collector/collector.cpp index 2f1aaba315..e9ff40bd9b 100644 --- a/collector/collector.cpp +++ b/collector/collector.cpp @@ -12,7 +12,6 @@ #include #include "ConfigLoader.h" -#include "SensorClient.h" extern "C" { #include From 8f22e7af2b3827d1040f7074dcd990d7dc97ff14 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Tue, 25 Mar 2025 13:09:17 +0100 Subject: [PATCH 04/14] Update mock sensor to use the newer collector-sensor service --- integration-tests/go.mod | 96 ++++---- integration-tests/go.sum | 251 ++++++++++---------- integration-tests/pkg/mock_sensor/server.go | 125 +++++----- 3 files changed, 242 insertions(+), 230 deletions(-) diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 82b76dad97..5f3e7ad325 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -1,31 +1,32 @@ module github.com/stackrox/collector/integration-tests -go 1.23.0 +go 1.23.4 -toolchain go1.23.6 +toolchain go1.23.7 require ( github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc - github.com/docker/cli v26.1.3+incompatible - github.com/docker/docker v26.1.3+incompatible + github.com/docker/cli v27.5.1+incompatible + github.com/docker/docker v27.5.1+incompatible github.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 github.com/hashicorp/go-multierror v1.1.1 github.com/pkg/errors v0.9.1 + github.com/prometheus/common v0.63.0 github.com/stackrox/rox v0.0.0-20210914215712-9ac265932e28 - github.com/stretchr/testify v1.9.0 + github.com/stretchr/testify v1.10.0 github.com/thoas/go-funk v0.9.3 - go.opentelemetry.io/otel/trace v1.28.0 - golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 - golang.org/x/sys v0.26.0 - google.golang.org/grpc v1.65.0 + go.opentelemetry.io/otel/trace v1.34.0 + golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 + golang.org/x/sys v0.31.0 + google.golang.org/grpc v1.71.0 gopkg.in/yaml.v3 v3.0.1 - k8s.io/api v0.32.2 - k8s.io/apimachinery v0.32.2 - k8s.io/client-go v0.32.2 + k8s.io/api v0.32.3 + k8s.io/apimachinery v0.32.3 + k8s.io/client-go v0.32.3 k8s.io/cri-api v0.32.2 k8s.io/cri-client v0.32.2 - k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 + k8s.io/utils v0.0.0-20241210054802-24370beab758 ) require ( @@ -35,10 +36,10 @@ require ( github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/distribution/reference v0.6.0 // indirect - github.com/docker/docker-credential-helpers v0.8.1 // indirect + github.com/docker/docker-credential-helpers v0.8.2 // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect - github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/emicklei/go-restful/v3 v3.11.2 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect @@ -46,7 +47,6 @@ require ( github.com/go-openapi/jsonpointer v0.21.0 // indirect github.com/go-openapi/jsonreference v0.21.0 // indirect github.com/go-openapi/swag v0.23.0 // indirect - github.com/gofrs/uuid v4.4.0+incompatible // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/protobuf v1.5.4 // indirect github.com/gonum/blas v0.0.0-20181208220705-f22b278b28ac // indirect @@ -55,19 +55,20 @@ require ( github.com/gonum/internal v0.0.0-20181124074243-f884aa714029 // indirect github.com/gonum/lapack v0.0.0-20181123203213-e4cdc5a0bff9 // indirect github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9 // indirect - github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect - github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gnostic-models v0.6.9 // indirect + github.com/google/go-cmp v0.7.0 // indirect github.com/google/gofuzz v1.2.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/gorilla/websocket v1.5.0 // indirect + github.com/gorilla/websocket v1.5.1 // indirect github.com/graph-gophers/graphql-go v1.5.0 // indirect - github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 // indirect + github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/klauspost/compress v1.18.0 // indirect + github.com/mailru/easyjson v0.9.0 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/spdystream v0.5.0 // indirect @@ -77,42 +78,44 @@ require ( github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.1.0 // indirect - github.com/planetscale/vtprotobuf v0.6.0 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect + github.com/planetscale/vtprotobuf v0.6.1-0.20240409071808-615f978279ca // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect - github.com/prometheus/client_golang v1.19.1 // indirect + github.com/prometheus/client_golang v1.21.1 // indirect github.com/prometheus/client_model v0.6.1 // indirect - github.com/prometheus/common v0.55.0 // indirect github.com/prometheus/procfs v0.15.1 // indirect github.com/sirupsen/logrus v1.9.3 // indirect - github.com/spf13/cobra v1.8.1 // indirect - github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace // indirect - github.com/stackrox/scanner v0.0.0-20240723082853-9da484b1a94e // indirect + github.com/spf13/cobra v1.9.1 // indirect + github.com/spf13/pflag v1.0.6 // indirect + github.com/stackrox/scanner v0.0.0-20240830165150-d133ba942d59 // indirect + github.com/tkuchiki/go-timezone v0.2.3 // indirect github.com/x448/float16 v0.8.4 // indirect - go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 // indirect - go.opentelemetry.io/otel v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 // indirect + go.opentelemetry.io/otel v1.34.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 // indirect - go.opentelemetry.io/otel/metric v1.28.0 // indirect - go.opentelemetry.io/otel/sdk v1.28.0 // indirect + go.opentelemetry.io/otel/metric v1.34.0 // indirect + go.opentelemetry.io/otel/sdk v1.34.0 // indirect go.opentelemetry.io/proto/otlp v1.3.1 // indirect go.uber.org/atomic v1.11.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/net v0.30.0 // indirect - golang.org/x/oauth2 v0.23.0 // indirect - golang.org/x/term v0.25.0 // indirect - golang.org/x/text v0.19.0 // indirect - golang.org/x/time v0.7.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 // indirect - google.golang.org/protobuf v1.35.1 // indirect + golang.org/x/net v0.37.0 // indirect + golang.org/x/oauth2 v0.28.0 // indirect + golang.org/x/term v0.30.0 // indirect + golang.org/x/text v0.23.0 // indirect + golang.org/x/time v0.11.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 // indirect + google.golang.org/protobuf v1.36.5 // indirect gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect + gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect gotest.tools/v3 v3.5.1 // indirect - k8s.io/component-base v0.32.2 // indirect + k8s.io/component-base v0.32.3 // indirect k8s.io/klog/v2 v2.130.1 // indirect k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect @@ -126,6 +129,7 @@ replace ( github.com/fullsailor/pkcs7 => github.com/stackrox/pkcs7 v0.0.0-20220914154527-cfdb0aa47179 github.com/heroku/docker-registry-client => github.com/stackrox/docker-registry-client v0.0.0-20230714151239-78b1f5f70b8a github.com/operator-framework/helm-operator-plugins => github.com/stackrox/helm-operator v0.0.10-0.20220919093109-89f9785764c6 - github.com/stackrox/rox => github.com/stackrox/stackrox v0.0.0-20240723150257-4fb801159218 - go.uber.org/zap => github.com/stackrox/zap v1.15.1-0.20200720133746-810fd602fd0f + github.com/stackrox/rox => github.com/stackrox/stackrox v0.0.0-20250325114232-8e68c6a26ed1 + go.uber.org/zap => github.com/stackrox/zap v1.18.2-0.20240314134248-5f932edd0404 + ) diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 92de6e885f..046f56564e 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1,12 +1,12 @@ -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= -github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= -github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg= +github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= +github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A= +github.com/benbjohnson/clock v1.3.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM= @@ -17,25 +17,25 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/cli v26.1.3+incompatible h1:bUpXT/N0kDE3VUHI2r5VMsYQgi38kYuoC0oL9yt3lqc= -github.com/docker/cli v26.1.3+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v26.1.3+incompatible h1:lLCzRbrVZrljpVNobJu1J2FHk8V0s4BawoZippkc+xo= -github.com/docker/docker v26.1.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= -github.com/docker/docker-credential-helpers v0.8.1 h1:j/eKUktUltBtMzKqmfLB0PAgqYyMHOp5vfsD1807oKo= -github.com/docker/docker-credential-helpers v0.8.1/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= +github.com/docker/cli v27.5.1+incompatible h1:JB9cieUT9YNiMITtIsguaN55PLOHhBSz3LKVc6cqWaY= +github.com/docker/cli v27.5.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/docker v27.5.1+incompatible h1:4PYU5dnBYqRQi0294d1FBECqT9ECWeQAIfE8q4YnPY8= +github.com/docker/docker v27.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.8.2 h1:bX3YxiGzFP5sOXWc3bTPEXdEaZSeVMrFgOr3T+zrFAo= +github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRKft1KckHiO9a2rNtyFbZ/ry9M= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= -github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= -github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/emicklei/go-restful/v3 v3.11.2 h1:1onLa9DcsMYO9P+CXaL0dStDqQ2EHHXLiz+BtnqkLAU= +github.com/emicklei/go-restful/v3 v3.11.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= @@ -54,8 +54,6 @@ github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+Gr github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= -github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= @@ -74,28 +72,27 @@ github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9 h1:V2IgdyerlBa/MxaEFR github.com/gonum/matrix v0.0.0-20181209220409-c518dec07be9/go.mod h1:0EXg4mc1CNP0HCqCz+K4ts155PXIlUywf0wqN+GfPZw= github.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b h1:fbskpz/cPqWH8VqkQ7LJghFkl2KPAiIFUHrTJ2O3RGk= github.com/gonum/stat v0.0.0-20181125101827-41a0da705a5b/go.mod h1:Z4GIJBJO3Wa4gD4vbwQxXXZ+WHmW6E9ixmNrwvs0iZs= -github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 h1:0VpGH+cDhbDtdcweoyCVsF3fhN8kejK6rFe/2FFX2nU= -github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49/go.mod h1:BkkQ4L1KS1xMt2aWSPStnn55ChGC0DPOn2FQYj+f25M= +github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw= +github.com/google/gnostic-models v0.6.9/go.mod h1:CiWsm0s6BSQd1hRn8/QmxqB6BesYcbSZxsz9b0KuDBw= github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= -github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= -github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg= +github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= github.com/graph-gophers/graphql-go v1.5.0 h1:fDqblo50TEpD0LY7RXk/LFVYEVqo3+tXMNMPSVXA1yc= github.com/graph-gophers/graphql-go v1.5.0/go.mod h1:YtmJZDLbF1YYNrlNAuiO5zAStUWc3XZT07iGsVqe1Os= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1YCS1PXdKYWi8FsN0= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo= +github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= @@ -111,6 +108,8 @@ github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnr github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= @@ -118,16 +117,18 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= -github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU= github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI= -github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= -github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= +github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ= +github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= @@ -139,48 +140,46 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus= github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw= -github.com/onsi/ginkgo/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM= -github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= -github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= -github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0= +github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM= +github.com/onsi/gomega v1.36.3 h1:hID7cr8t3Wp26+cYnfcjR6HpJ00fdogN6dqZ1t6IylU= +github.com/onsi/gomega v1.36.3/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= -github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/planetscale/vtprotobuf v0.6.0 h1:nBeETjudeJ5ZgBHUz1fVHvbqUKnYOXNhsIEabROxmNA= -github.com/planetscale/vtprotobuf v0.6.0/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= +github.com/planetscale/vtprotobuf v0.6.1-0.20240409071808-615f978279ca h1:ujRGEVWJEoaxQ+8+HMl8YEpGaDAgohgZxJ5S+d2TTFQ= +github.com/planetscale/vtprotobuf v0.6.1-0.20240409071808-615f978279ca/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE= -github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho= +github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk= +github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg= github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= -github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= -github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k= +github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18= github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= -github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= -github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= -github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a h1:w3tdWGKbLGBPtR/8/oO74W6hmz0qE5q0z9aqSAewaaM= +github.com/rogpeppe/go-internal v1.13.2-0.20241226121412-a5dc8ff20d0a/go.mod h1:S8kfXMp+yh77OxPD4fdM6YUknrZpQxLhvxzS4gDHENY= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace h1:9PNP1jnUjRhfmGMlkXHjYPishpcw4jpSt/V/xYY3FMA= -github.com/spf13/pflag v1.0.6-0.20210604193023-d5e0c0615ace/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stackrox/scanner v0.0.0-20240723082853-9da484b1a94e h1:xpThhd/IXW0+QM1cF/KaxVWXAcN2owMouh9R/ht4F4I= -github.com/stackrox/scanner v0.0.0-20240723082853-9da484b1a94e/go.mod h1:r8K3aiQY1eVhTCua3yPuUSz8/WvvqrXLu6WXwc13B0o= -github.com/stackrox/stackrox v0.0.0-20240723150257-4fb801159218 h1:cK1RdGHKwDPzYDl5G/I3DRXOVGIXQVk6fMdMbEXcGgU= -github.com/stackrox/stackrox v0.0.0-20240723150257-4fb801159218/go.mod h1:SqNa3b3Y1QXyEw5H16YpZrv8rzK8GzO5nvmv6i9ohPU= -github.com/stackrox/zap v1.15.1-0.20200720133746-810fd602fd0f h1:Ofa3PAa609eSHcHP2kCJDUWUnuEWfiqXhsuppk/QtOE= -github.com/stackrox/zap v1.15.1-0.20200720133746-810fd602fd0f/go.mod h1:MA8QOfq0BHJwdXa996Y4dYkAqRKB8/1K1QMMZVaNZjQ= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= +github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= +github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stackrox/scanner v0.0.0-20240830165150-d133ba942d59 h1:XrOPpgBpAnwTXGbyAYSOongfFeVJJBWPTdWEgYw+Uck= +github.com/stackrox/scanner v0.0.0-20240830165150-d133ba942d59/go.mod h1:xVs4A0Vur2djLSTZYtIj/5hgUORT1t405Fg0RX4/1kA= +github.com/stackrox/stackrox v0.0.0-20250325114232-8e68c6a26ed1 h1:jZAR27J5MMRkn3eEOVjtBdVSYKLmx0DP3QdtNUMDZFY= +github.com/stackrox/stackrox v0.0.0-20250325114232-8e68c6a26ed1/go.mod h1:AJRmMSul3qXVhjXf4FuRjw5OvzorgBRJ5/ght/sZq8w= +github.com/stackrox/zap v1.18.2-0.20240314134248-5f932edd0404 h1:j2qhsZjUBpN4yaqEGkNrATdw3fE3vgMrVOhd44cUJDY= +github.com/stackrox/zap v1.18.2-0.20240314134248-5f932edd0404/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= @@ -188,137 +187,135 @@ github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UV github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= -github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/thoas/go-funk v0.9.3 h1:7+nAEx3kn5ZJcnDm2Bh23N2yOtweO14bi//dvRtgLpw= github.com/thoas/go-funk v0.9.3/go.mod h1:+IWnUfUmFO1+WVYQWQtIJHeRRdaIyyYglZN7xzUPe4Q= +github.com/tkuchiki/go-timezone v0.2.3 h1:D3TVdIPrFsu9lxGxqNX2wsZwn1MZtTqTW0mdevMozHc= +github.com/tkuchiki/go-timezone v0.2.3/go.mod h1:oFweWxYl35C/s7HMVZXiA19Jr9Y0qJHMaG/J2TES4LY= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0 h1:9G6E0TXzGFVfTnawRzrPl83iHOAV7L8NJiR8RSGYV1g= -go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.53.0/go.mod h1:azvtTADFQJA8mX80jIH/akaE7h+dbm/sVuaHqN13w74= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0 h1:4K4tsIXefpVJtvA/8srF4V4y0akAoPHkIslgAkjixJA= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.53.0/go.mod h1:jjdQuTGVsXV4vSs+CJ2qYDeDPf9yIJV23qlIzBm73Vg= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE= +go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I= go.opentelemetry.io/otel v1.6.3/go.mod h1:7BgNga5fNlF/iZjG06hM3yofffp0ofKCDwSXx1GC4dI= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0 h1:3Q/xZUyC1BBkualc9ROb4G8qkH90LXEIICcs5zv1OYY= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.28.0/go.mod h1:s75jGIWA9OfCMzF0xr+ZgfrB5FEbbV7UuYo32ahUiFI= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0 h1:qFffATk0X+HD+f1Z8lswGiOQYKHRlzfmdJm0wEaVrFA= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.27.0/go.mod h1:MOiCmryaYtc+V0Ei+Tx9o5S1ZjA7kzLucuVuyzBZloQ= +go.opentelemetry.io/otel v1.34.0 h1:zRLXxLCgL1WyKsPVrgbSdMN4c0FMkDAskSTQP+0hdUY= +go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0 h1:IJFEoHiytixx8cMiVAO+GmHR6Frwu+u5Ur8njpFO6Ac= +go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.32.0/go.mod h1:3rHrKNtLIoS0oZwkY2vxi+oJcwFRWdtUyRII+so45p8= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0 h1:9kV11HXBHZAvuPUZxmMWrH8hZn/6UnHX4K0mu36vNsU= +go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.32.0/go.mod h1:JyA0FHXe22E1NeNiHmVp7kFHglnexDQ7uRWDiiJ1hKQ= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0 h1:j9+03ymgYhPKmeXGk5Zu+cIZOlVzd9Zv7QIiyItjFBU= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0/go.mod h1:Y5+XiUG4Emn1hTfciPzGPJaSI+RpDts6BnCIir0SLqk= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= -go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= -go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= +go.opentelemetry.io/otel/metric v1.34.0 h1:+eTR3U0MyfWjRDhmFMxe2SsW64QrZ84AOhvqS7Y+PoQ= +go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE= +go.opentelemetry.io/otel/sdk v1.34.0 h1:95zS4k/2GOy069d321O8jWgYsW3MzVV+KuSPKp7Wr1A= +go.opentelemetry.io/otel/sdk v1.34.0/go.mod h1:0e/pNiaMAqaykJGKbi+tSjWfNNHMTxoC9qANsCzbyxU= +go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk= +go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w= go.opentelemetry.io/otel/trace v1.6.3/go.mod h1:GNJQusJlUgZl9/TQBPKU/Y/ty+0iVB5fjhKeJGZPGFs= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/otel/trace v1.34.0 h1:+ouXS2V8Rd4hp4580a8q23bg0azF2nI8cqLYnC8mh/k= +go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE= go.opentelemetry.io/proto/otlp v1.3.1 h1:TrMUixzpM0yuc/znrFTP9MMRh8trP93mkCiDVeXrui0= go.opentelemetry.io/proto/otlp v1.3.1/go.mod h1:0X1WI4de4ZsLrrJNLAQbFeLCm3T7yBkR0XqQ7niQU+8= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= +go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0= +go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto= go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= -go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU= -go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= +go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU= +go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM= +go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM= -golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de h1:5hukYrvBGR8/eNkX5mdUezrA6JiaEZDtJb9Ei+1LlBs= +golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo= +golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0= -golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= -golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= -golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs= -golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c= +golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= +golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= +golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= -golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= -golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= -golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ= -golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= +golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0= +golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= -golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= +golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7 h1:YcyjlL1PRr2Q17/I0dPk2JmYS5CDXfcdb2Z3YRioEbw= -google.golang.org/genproto/googleapis/api v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7 h1:2035KHhUv+EpyB+hWgJnaWKJOdX1E95w2S8Rr4uWKTs= -google.golang.org/genproto/googleapis/rpc v0.0.0-20240826202546-f6391c0de4c7/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc= -google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ= -google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= -google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= +google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950= +google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4 h1:iK2jbkWL86DXjEx0qiHcRE9dE4/Ahua5k6V8OWFb//c= +google.golang.org/genproto/googleapis/rpc v0.0.0-20250313205543-e70fdf4c4cb4/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I= +google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg= +google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec= +google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM= +google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= -honnef.co/go/tools v0.0.1-2019.2.3 h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM= -honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -k8s.io/api v0.32.2 h1:bZrMLEkgizC24G9eViHGOPbW+aRo9duEISRIJKfdJuw= -k8s.io/api v0.32.2/go.mod h1:hKlhk4x1sJyYnHENsrdCWw31FEmCijNGPJO5WzHiJ6Y= -k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ= -k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= -k8s.io/client-go v0.32.2 h1:4dYCD4Nz+9RApM2b/3BtVvBHw54QjMFUl1OLcJG5yOA= -k8s.io/client-go v0.32.2/go.mod h1:fpZ4oJXclZ3r2nDOv+Ux3XcJutfrwjKTCHz2H3sww94= -k8s.io/component-base v0.32.2 h1:1aUL5Vdmu7qNo4ZsE+569PV5zFatM9hl+lb3dEea2zU= -k8s.io/component-base v0.32.2/go.mod h1:PXJ61Vx9Lg+P5mS8TLd7bCIr+eMJRQTyXe8KvkrvJq0= +k8s.io/api v0.32.3 h1:Hw7KqxRusq+6QSplE3NYG4MBxZw1BZnq4aP4cJVINls= +k8s.io/api v0.32.3/go.mod h1:2wEDTXADtm/HA7CCMD8D8bK4yuBUptzaRhYcYEEYA3k= +k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U= +k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU= +k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY= +k8s.io/component-base v0.32.3 h1:98WJvvMs3QZ2LYHBzvltFSeJjEx7t5+8s71P7M74u8k= +k8s.io/component-base v0.32.3/go.mod h1:LWi9cR+yPAv7cu2X9rZanTiFKB2kHA+JjmhkKjCZRpI= k8s.io/cri-api v0.32.2 h1:7DuaOHpOcXweZeBUbRdK0iCroxctGp73VwgrA0u7kho= k8s.io/cri-api v0.32.2/go.mod h1:DCzMuTh2padoinefWME0G678Mc3QFbLMF2vEweGzBAI= k8s.io/cri-client v0.32.2 h1:vjowJUyu14IbmifqCKJHE9rK/BPSfkXvltqN42W1Zuo= @@ -327,8 +324,8 @@ k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f h1:GA7//TjRY9yWGy1poLzYYJJ4JRdzg3+O6e8I+e+8T5Y= k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f/go.mod h1:R/HEjbvWI0qdfb8viZUeVZm0X6IZnxAydC7YU42CMw4= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= -k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0= +k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= diff --git a/integration-tests/pkg/mock_sensor/server.go b/integration-tests/pkg/mock_sensor/server.go index 93b50187cb..c14e660a44 100644 --- a/integration-tests/pkg/mock_sensor/server.go +++ b/integration-tests/pkg/mock_sensor/server.go @@ -12,7 +12,6 @@ import ( sensorAPI "github.com/stackrox/rox/generated/internalapi/sensor" - "github.com/stackrox/rox/generated/storage" "google.golang.org/grpc" "google.golang.org/grpc/keepalive" @@ -53,8 +52,8 @@ type MockSensor struct { // every event will be forwarded to these channels, to allow // tests to look directly at the incoming data without // losing anything underneath - processChannel RingChan[*storage.ProcessSignal] - lineageChannel RingChan[*storage.ProcessSignal_LineageInfo] + processChannel RingChan[*sensorAPI.ProcessSignal] + lineageChannel RingChan[*sensorAPI.ProcessSignal_LineageInfo] connectionChannel RingChan[*sensorAPI.NetworkConnection] endpointChannel RingChan[*sensorAPI.NetworkEndpoint] } @@ -71,7 +70,7 @@ func NewMockSensor(test string) *MockSensor { // LiveProcesses returns a channel that can be used to read live // process events -func (m *MockSensor) LiveProcesses() <-chan *storage.ProcessSignal { +func (m *MockSensor) LiveProcesses() <-chan *sensorAPI.ProcessSignal { return m.processChannel.Stream() } @@ -107,7 +106,7 @@ func (m *MockSensor) HasProcess(containerID string, process types.ProcessInfo) b // LiveLineages returns a channel that can be used to read live // process lineage events -func (m *MockSensor) LiveLineages() <-chan *storage.ProcessSignal_LineageInfo { +func (m *MockSensor) LiveLineages() <-chan *sensorAPI.ProcessSignal_LineageInfo { return m.lineageChannel.Stream() } @@ -267,11 +266,11 @@ func (m *MockSensor) Start() { }), ) - sensorAPI.RegisterSignalServiceServer(m.grpcServer, m) + sensorAPI.RegisterCollectorServiceServer(m.grpcServer, m) sensorAPI.RegisterNetworkConnectionInfoServiceServer(m.grpcServer, m) - m.processChannel = NewRingChan[*storage.ProcessSignal](gDefaultRingSize) - m.lineageChannel = NewRingChan[*storage.ProcessSignal_LineageInfo](gDefaultRingSize) + m.processChannel = NewRingChan[*sensorAPI.ProcessSignal](gDefaultRingSize) + m.lineageChannel = NewRingChan[*sensorAPI.ProcessSignal_LineageInfo](gDefaultRingSize) m.connectionChannel = NewRingChan[*sensorAPI.NetworkConnection](gDefaultRingSize) m.endpointChannel = NewRingChan[*sensorAPI.NetworkEndpoint](gDefaultRingSize) @@ -301,53 +300,6 @@ func (m *MockSensor) Stop() { m.endpointChannel.Stop() } -// PushSignals conforms to the Sensor API. It is here that process signals and -// process lineage information is handled and stored/sent to the relevant channel -func (m *MockSensor) PushSignals(stream sensorAPI.SignalService_PushSignalsServer) error { - for { - signal, err := stream.Recv() - if err != nil { - return err - } - - if signal != nil && signal.GetSignal() != nil && signal.GetSignal().GetProcessSignal() != nil { - processSignal := signal.GetSignal().GetProcessSignal() - - if strings.HasPrefix(processSignal.GetExecFilePath(), "/proc/self") { - // - // There exists a potential race condition for the driver - // to capture very early container process events. - // - // This is known in falco, and somewhat documented here: - // https://github.com/falcosecurity/falco/blob/555bf9971cdb79318917949a5e5f9bab5293b5e2/rules/falco_rules.yaml#L1961 - // - // It is also filtered in sensor here: - // https://github.com/stackrox/stackrox/blob/4d3fb539547d1935a35040e4a4e8c258a53a92e4/sensor/common/signal/signal_service.go#L90 - // - // Further details can be found here https://issues.redhat.com/browse/ROX-11544 - // - m.logger.Printf("runtime-process: %s %s:%s:%d:%d:%d:%s\n", - processSignal.GetContainerId(), - processSignal.GetName(), - processSignal.GetExecFilePath(), - processSignal.GetUid(), - processSignal.GetGid(), - processSignal.GetPid(), - processSignal.GetArgs()) - continue - } - - m.pushProcess(processSignal.GetContainerId(), processSignal) - m.processChannel.Write(processSignal) - - for _, lineage := range processSignal.GetLineageInfo() { - m.pushLineage(processSignal.GetContainerId(), processSignal, lineage) - m.lineageChannel.Write(lineage) - } - } - } -} - func (m *MockSensor) convertConnection(connection *sensorAPI.NetworkConnection) types.NetworkInfo { conn := types.NetworkInfo{ LocalAddress: types.TranslateAddress(connection.LocalAddress), @@ -378,6 +330,65 @@ func (m *MockSensor) convertToContainerConnsMap(connections []*sensorAPI.Network return containerConnsMap } +// Communicate conforms to the Sensor API. It is here that process signals and +// process lineage information is handled and stored/sent to the relevant channel +func (m *MockSensor) Communicate(stream sensorAPI.CollectorService_CommunicateServer) error { + for { + signal, err := stream.Recv() + if err != nil { + return err + } + + switch signal.GetMsg().(type) { + case *sensorAPI.MsgFromCollector_ProcessSignal: + m.pushSignal(signal.GetProcessSignal()) + case *sensorAPI.MsgFromCollector_Register: + return nil + case *sensorAPI.MsgFromCollector_Info: + return nil + } + } +} + +func (m *MockSensor) pushSignal(signal *sensorAPI.ProcessSignal) error { + if signal == nil { + return nil + } + + if strings.HasPrefix(signal.GetExecFilePath(), "/proc/self") { + // + // There exists a potential race condition for the driver + // to capture very early container process events. + // + // This is known in falco, and somewhat documented here: + // https://github.com/falcosecurity/falco/blob/555bf9971cdb79318917949a5e5f9bab5293b5e2/rules/falco_rules.yaml#L1961 + // + // It is also filtered in sensor here: + // https://github.com/stackrox/stackrox/blob/4d3fb539547d1935a35040e4a4e8c258a53a92e4/sensor/common/signal/signal_service.go#L90 + // + // Further details can be found here https://issues.redhat.com/browse/ROX-11544 + // + m.logger.Printf("runtime-process: %s %s:%s:%d:%d:%d:%s\n", + signal.GetContainerId(), + signal.GetName(), + signal.GetExecFilePath(), + signal.GetUid(), + signal.GetGid(), + signal.GetPid(), + signal.GetArgs()) + return nil + } + + m.pushProcess(signal.GetContainerId(), signal) + m.processChannel.Write(signal) + + for _, lineage := range signal.GetLineageInfo() { + m.pushLineage(signal.GetContainerId(), signal, lineage) + m.lineageChannel.Write(lineage) + } + return nil +} + // PushNetworkConnectionInfo conforms to the Sensor API. It is here that networking // events (connections and endpoints) are handled and stored/sent to the relevant channel func (m *MockSensor) PushNetworkConnectionInfo(stream sensorAPI.NetworkConnectionInfoService_PushNetworkConnectionInfoServer) error { @@ -406,7 +417,7 @@ func (m *MockSensor) PushNetworkConnectionInfo(stream sensorAPI.NetworkConnectio // pushProcess converts a process signal into the test's own structure // and stores it -func (m *MockSensor) pushProcess(containerID string, processSignal *storage.ProcessSignal) { +func (m *MockSensor) pushProcess(containerID string, processSignal *sensorAPI.ProcessSignal) { m.processMutex.Lock() defer m.processMutex.Unlock() @@ -437,7 +448,7 @@ func (m *MockSensor) pushProcess(containerID string, processSignal *storage.Proc // pushLineage converts a process lineage into the test's own structure // and stores it -func (m *MockSensor) pushLineage(containerID string, process *storage.ProcessSignal, lineage *storage.ProcessSignal_LineageInfo) { +func (m *MockSensor) pushLineage(containerID string, process *sensorAPI.ProcessSignal, lineage *sensorAPI.ProcessSignal_LineageInfo) { m.processMutex.Lock() defer m.processMutex.Unlock() From b91ffa35f2cabf8a619063cbaa87ad1295c8d2b5 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Wed, 26 Mar 2025 15:21:06 +0100 Subject: [PATCH 05/14] Restore ProcessSignalFormatter, add SensorClientFormatter This change makes it possible to have backwards compatibility with older sensor versions that might no implement the new service. --- collector/lib/CollectorOutput.cpp | 43 +++ collector/lib/CollectorOutput.h | 28 +- collector/lib/CollectorService.cpp | 2 + collector/lib/ProcessSignalFormatter.cpp | 37 +- collector/lib/ProcessSignalFormatter.h | 13 +- collector/lib/ProcessSignalHandler.cpp | 90 ++++- collector/lib/ProcessSignalHandler.h | 20 +- collector/lib/ProtoSignalFormatter.h | 3 + collector/lib/SensorClient.cpp | 2 +- collector/lib/SensorClientFormatter.cpp | 377 +++++++++++++++++++++ collector/lib/SensorClientFormatter.h | 70 ++++ collector/lib/system-inspector/Service.cpp | 6 +- collector/lib/system-inspector/Service.h | 1 - 13 files changed, 624 insertions(+), 68 deletions(-) create mode 100644 collector/lib/SensorClientFormatter.cpp create mode 100644 collector/lib/SensorClientFormatter.h diff --git a/collector/lib/CollectorOutput.cpp b/collector/lib/CollectorOutput.cpp index 6c5f45b2d2..70ab1de1ad 100644 --- a/collector/lib/CollectorOutput.cpp +++ b/collector/lib/CollectorOutput.cpp @@ -1,7 +1,35 @@ #include "CollectorOutput.h" +#include "internalapi/sensor/collector.pb.h" +#include "internalapi/sensor/collector_iservice.pb.h" + +#include "HostInfo.h" + namespace collector { +CollectorOutput::CollectorOutput(const CollectorConfig& config) { + if (config.grpc_channel != nullptr) { + auto sensor_client = std::make_unique(config.grpc_channel); + auto signal_client = std::make_unique(config.grpc_channel); + sensor_clients_.emplace_back(std::move(sensor_client)); + signal_clients_.emplace_back(std::move(signal_client)); + } + + if (config.UseStdout()) { + auto sensor_client = std::make_unique(); + auto signal_client = std::make_unique(); + sensor_clients_.emplace_back(std::move(sensor_client)); + signal_clients_.emplace_back(std::move(signal_client)); + } + + if (sensor_clients_.empty() || signal_clients_.empty()) { + CLOG(FATAL) << "No available output configured"; + } + + StartClients(sensor_clients_); + StartClients(signal_clients_); +} + namespace { SignalHandler::Result SensorOutput(std::vector>& clients, const sensor::MsgFromCollector& msg) { for (auto& client : clients) { @@ -39,4 +67,19 @@ SignalHandler::Result CollectorOutput::SendMsg(const MessageType& msg) { return std::visit(visitor, msg); } + +void CollectorOutput::Register() { + sensor::MsgFromCollector msg; + msg.clear_info(); + msg.clear_process_signal(); + msg.mutable_register_()->set_hostname(GetHostname()); + + for (const auto& client : sensor_clients_) { + auto res = client->SendMsg(msg); + if (res != SignalHandler::PROCESSED) { + use_sensor_client_ = false; + break; + } + } +} } // namespace collector diff --git a/collector/lib/CollectorOutput.h b/collector/lib/CollectorOutput.h index 4f9f5896f3..f0afd402f2 100644 --- a/collector/lib/CollectorOutput.h +++ b/collector/lib/CollectorOutput.h @@ -22,28 +22,7 @@ class CollectorOutput { CollectorOutput& operator=(const CollectorOutput&) = delete; CollectorOutput& operator=(CollectorOutput&&) = delete; - CollectorOutput(const CollectorConfig& config) { - if (config.grpc_channel != nullptr) { - auto sensor_client = std::make_unique(config.grpc_channel); - auto signal_client = std::make_unique(config.grpc_channel); - sensor_clients_.emplace_back(std::move(sensor_client)); - signal_clients_.emplace_back(std::move(signal_client)); - } - - if (config.UseStdout()) { - auto sensor_client = std::make_unique(); - auto signal_client = std::make_unique(); - sensor_clients_.emplace_back(std::move(sensor_client)); - signal_clients_.emplace_back(std::move(signal_client)); - } - - if (sensor_clients_.empty() || signal_clients_.empty()) { - CLOG(FATAL) << "No available output configured"; - } - - StartClients(sensor_clients_); - StartClients(signal_clients_); - } + CollectorOutput(const CollectorConfig& config); ~CollectorOutput() { StopClients(sensor_clients_); @@ -51,6 +30,9 @@ class CollectorOutput { } SignalHandler::Result SendMsg(const MessageType& msg); + void Register(); + + bool UseSensorClient() { return use_sensor_client_; } private: template @@ -69,6 +51,8 @@ class CollectorOutput { std::vector> sensor_clients_; std::vector> signal_clients_; + + bool use_sensor_client_{true}; }; } // namespace collector diff --git a/collector/lib/CollectorService.cpp b/collector/lib/CollectorService.cpp index e24231782b..7915ad68c8 100644 --- a/collector/lib/CollectorService.cpp +++ b/collector/lib/CollectorService.cpp @@ -106,6 +106,8 @@ void CollectorService::RunForever() { CLOG(FATAL) << "Unable to start collector stats exporter"; } + output_.Register(); + system_inspector_.Start(); ControlValue cv; diff --git a/collector/lib/ProcessSignalFormatter.cpp b/collector/lib/ProcessSignalFormatter.cpp index 75851b714a..55afff4389 100644 --- a/collector/lib/ProcessSignalFormatter.cpp +++ b/collector/lib/ProcessSignalFormatter.cpp @@ -4,7 +4,6 @@ #include -#include "internalapi/sensor/collector_iservice.pb.h" #include "internalapi/sensor/signal_iservice.pb.h" #include "CollectorStats.h" @@ -68,7 +67,7 @@ ProcessSignalFormatter::ProcessSignalFormatter( ProcessSignalFormatter::~ProcessSignalFormatter() = default; -const sensor::MsgFromCollector* ProcessSignalFormatter::ToProtoMessage(sinsp_evt* event) { +const SignalStreamMessage* ProcessSignalFormatter::ToProtoMessage(sinsp_evt* event) { if (process_signals[event->get_type()] == ProcessSignalType::UNKNOWN_PROCESS_TYPE) { return nullptr; } @@ -85,30 +84,34 @@ const sensor::MsgFromCollector* ProcessSignalFormatter::ToProtoMessage(sinsp_evt return nullptr; } - auto* msg = AllocateRoot(); - msg->clear_info(); - msg->clear_register_(); - msg->set_allocated_process_signal(process_signal); - return msg; + auto* signal = Allocate(); + signal->set_allocated_process_signal(process_signal); + + SignalStreamMessage* signal_stream_message = AllocateRoot(); + signal_stream_message->clear_collector_register_request(); + signal_stream_message->set_allocated_signal(signal); + return signal_stream_message; } -const sensor::MsgFromCollector* ProcessSignalFormatter::ToProtoMessage(sinsp_threadinfo* tinfo) { +const SignalStreamMessage* ProcessSignalFormatter::ToProtoMessage(sinsp_threadinfo* tinfo) { Reset(); if (!ValidateProcessDetails(tinfo)) { CLOG(INFO) << "Dropping process event: " << tinfo; return nullptr; } - ProcessSignal* signal = CreateProcessSignal(tinfo); - if (signal == nullptr) { + ProcessSignal* process_signal = CreateProcessSignal(tinfo); + if (process_signal == nullptr) { return nullptr; } - auto* msg = AllocateRoot(); - msg->clear_register_(); - msg->clear_info(); - msg->set_allocated_process_signal(signal); - return msg; + auto* signal = Allocate(); + signal->set_allocated_process_signal(process_signal); + + SignalStreamMessage* signal_stream_message = AllocateRoot(); + signal_stream_message->clear_collector_register_request(); + signal_stream_message->set_allocated_signal(signal); + return signal_stream_message; } ProcessSignal* ProcessSignalFormatter::CreateProcessSignal(sinsp_evt* event) { @@ -170,7 +173,7 @@ ProcessSignal* ProcessSignalFormatter::CreateProcessSignal(sinsp_evt* event) { // set time auto timestamp = Allocate(); *timestamp = TimeUtil::NanosecondsToTimestamp(event->get_ts()); - signal->set_allocated_creation_time(timestamp); + signal->set_allocated_time(timestamp); // set container_id if (const std::string* container_id = event_extractor_->get_container_id(event)) { @@ -235,7 +238,7 @@ ProcessSignal* ProcessSignalFormatter::CreateProcessSignal(sinsp_threadinfo* tin // set time auto timestamp = Allocate(); *timestamp = TimeUtil::NanosecondsToTimestamp(tinfo->m_clone_ts); - signal->set_allocated_creation_time(timestamp); + signal->set_allocated_time(timestamp); // set container_id signal->set_container_id(tinfo->m_container_id); diff --git a/collector/lib/ProcessSignalFormatter.h b/collector/lib/ProcessSignalFormatter.h index 5da5d744ab..287a53ea86 100644 --- a/collector/lib/ProcessSignalFormatter.h +++ b/collector/lib/ProcessSignalFormatter.h @@ -6,6 +6,8 @@ #include "api/v1/signal.pb.h" #include "internalapi/sensor/collector_iservice.pb.h" +#include "internalapi/sensor/signal_iservice.pb.h" +#include "storage/process_indicator.pb.h" #include "CollectorConfig.h" #include "ContainerMetadata.h" @@ -22,18 +24,17 @@ class EventExtractor; namespace collector { -class ProcessSignalFormatter : public ProtoSignalFormatter { +class ProcessSignalFormatter : public ProtoSignalFormatter { public: ProcessSignalFormatter(sinsp* inspector, const CollectorConfig& config); ~ProcessSignalFormatter(); using Signal = v1::Signal; - using ProcessSignal = sensor::ProcessSignal; - using LineageInfo = sensor::ProcessSignal_LineageInfo; - using MsgFromCollector = sensor::MsgFromCollector; + using ProcessSignal = storage::ProcessSignal; + using LineageInfo = storage::ProcessSignal_LineageInfo; - const MsgFromCollector* ToProtoMessage(sinsp_evt* event) override; - const MsgFromCollector* ToProtoMessage(sinsp_threadinfo* tinfo); + const sensor::SignalStreamMessage* ToProtoMessage(sinsp_evt* event) override; + const sensor::SignalStreamMessage* ToProtoMessage(sinsp_threadinfo* tinfo) override; void GetProcessLineage(sinsp_threadinfo* tinfo, std::vector& lineage); diff --git a/collector/lib/ProcessSignalHandler.cpp b/collector/lib/ProcessSignalHandler.cpp index aad9ef9b2e..f48fd0871b 100644 --- a/collector/lib/ProcessSignalHandler.cpp +++ b/collector/lib/ProcessSignalHandler.cpp @@ -6,14 +6,16 @@ #include -#include "storage/process_indicator.pb.h" - #include "RateLimit.h" -#include "system-inspector/EventExtractor.h" namespace collector { -std::string compute_process_key(const ::sensor::ProcessSignal& s) { +namespace { +// The template functions in this namespace are meant to be used with +// sensor::ProcessSignal and storage::ProcessSignal, which are almost +// the same... Except they are not... +template +std::string compute_process_key(const S& s) { std::stringstream ss; ss << s.container_id() << " " << s.name() << " "; if (s.args().length() <= 256) { @@ -25,19 +27,39 @@ std::string compute_process_key(const ::sensor::ProcessSignal& s) { return ss.str(); } +template +void dtrace_probe(const S& s) { + const char* name = s.name().c_str(); + const uint32_t pid = s.pid(); + DTRACE_PROBE2(collector, process_signal_handler, name, pid); +} +} // namespace + SignalHandler::Result ProcessSignalHandler::HandleSignal(sinsp_evt* evt) { - const auto* signal_msg = formatter_.ToProtoMessage(evt); + if (client_->UseSensorClient()) { + return HandleSensorSignal(evt); + } + return HandleProcessSignal(evt); +} + +SignalHandler::Result ProcessSignalHandler::HandleExistingProcess(sinsp_threadinfo* tinfo) { + if (client_->UseSensorClient()) { + return HandleExistingProcessSensor(tinfo); + } + return HandleExistingProcessSignal(tinfo); +} + +SignalHandler::Result ProcessSignalHandler::HandleProcessSignal(sinsp_evt* evt) { + const auto* signal_msg = signal_formatter_.ToProtoMessage(evt); if (signal_msg == nullptr) { ++(stats_->nProcessResolutionFailuresByEvt); return IGNORED; } - const char* name = signal_msg->process_signal().name().c_str(); - const uint32_t pid = signal_msg->process_signal().pid(); - DTRACE_PROBE2(collector, process_signal_handler, name, pid); + dtrace_probe(signal_msg->signal().process_signal()); - if (!rate_limiter_.Allow(compute_process_key(signal_msg->process_signal()))) { + if (!rate_limiter_.Allow(compute_process_key(signal_msg->signal().process_signal()))) { ++(stats_->nProcessRateLimitCount); return IGNORED; } @@ -52,13 +74,38 @@ SignalHandler::Result ProcessSignalHandler::HandleSignal(sinsp_evt* evt) { return result; } -SignalHandler::Result ProcessSignalHandler::HandleExistingProcess(sinsp_threadinfo* tinfo) { - const auto* signal_msg = formatter_.ToProtoMessage(tinfo); +SignalHandler::Result ProcessSignalHandler::HandleExistingProcessSignal(sinsp_threadinfo* tinfo) { + const auto* signal_msg = signal_formatter_.ToProtoMessage(tinfo); if (signal_msg == nullptr) { ++(stats_->nProcessResolutionFailuresByTinfo); return IGNORED; } + if (!rate_limiter_.Allow(compute_process_key(signal_msg->signal().process_signal()))) { + ++(stats_->nProcessRateLimitCount); + return IGNORED; + } + + auto result = client_->SendMsg(*signal_msg); + if (result == SignalHandler::PROCESSED) { + ++(stats_->nProcessSent); + } else if (result == SignalHandler::ERROR) { + ++(stats_->nProcessSendFailures); + } + + return result; +} + +SignalHandler::Result ProcessSignalHandler::HandleSensorSignal(sinsp_evt* evt) { + const auto* signal_msg = sensor_formatter_.ToProtoMessage(evt); + + if (signal_msg == nullptr) { + ++(stats_->nProcessResolutionFailuresByEvt); + return IGNORED; + } + + dtrace_probe(signal_msg->process_signal()); + if (!rate_limiter_.Allow(compute_process_key(signal_msg->process_signal()))) { ++(stats_->nProcessRateLimitCount); return IGNORED; @@ -74,6 +121,27 @@ SignalHandler::Result ProcessSignalHandler::HandleExistingProcess(sinsp_threadin return result; } +SignalHandler::Result ProcessSignalHandler::HandleExistingProcessSensor(sinsp_threadinfo* tinfo) { + const auto* signal_msg = sensor_formatter_.ToProtoMessage(tinfo); + if (signal_msg == nullptr) { + ++(stats_->nProcessResolutionFailuresByTinfo); + return IGNORED; + } + + if (!rate_limiter_.Allow(compute_process_key(signal_msg->process_signal()))) { + ++(stats_->nProcessRateLimitCount); + return IGNORED; + } + + auto result = client_->SendMsg(*signal_msg); + if (result == SignalHandler::PROCESSED) { + ++(stats_->nProcessSent); + } else if (result == SignalHandler::ERROR) { + ++(stats_->nProcessSendFailures); + } + + return result; +} std::vector ProcessSignalHandler::GetRelevantEvents() { return {"execve<"}; } diff --git a/collector/lib/ProcessSignalHandler.h b/collector/lib/ProcessSignalHandler.h index 637a103ed2..de6833d494 100644 --- a/collector/lib/ProcessSignalHandler.h +++ b/collector/lib/ProcessSignalHandler.h @@ -5,6 +5,7 @@ #include "CollectorConfig.h" #include "ProcessSignalFormatter.h" #include "RateLimit.h" +#include "SensorClientFormatter.h" #include "SignalHandler.h" #include "system-inspector/Service.h" @@ -23,9 +24,9 @@ class ProcessSignalHandler : public SignalHandler { system_inspector::Stats* stats, const CollectorConfig& config) : client_(client), - formatter_(inspector, config), - stats_(stats), - config_(config) {} + signal_formatter_(inspector, config), + sensor_formatter_(inspector, config), + stats_(stats) {} ProcessSignalHandler(const ProcessSignalHandler&) = delete; ProcessSignalHandler(ProcessSignalHandler&&) = delete; @@ -39,12 +40,19 @@ class ProcessSignalHandler : public SignalHandler { std::vector GetRelevantEvents() override; private: + // Handlers for the old service + Result HandleProcessSignal(sinsp_evt* evt); + Result HandleExistingProcessSignal(sinsp_threadinfo* tinfo); + + // Handlers for the new service + Result HandleSensorSignal(sinsp_evt* evt); + Result HandleExistingProcessSensor(sinsp_threadinfo* tinfo); + CollectorOutput* client_; - ProcessSignalFormatter formatter_; + ProcessSignalFormatter signal_formatter_; + SensorClientFormatter sensor_formatter_; system_inspector::Stats* stats_; RateLimitCache rate_limiter_; - - const CollectorConfig& config_; }; } // namespace collector diff --git a/collector/lib/ProtoSignalFormatter.h b/collector/lib/ProtoSignalFormatter.h index 0e58034b4a..8cb28af1a5 100644 --- a/collector/lib/ProtoSignalFormatter.h +++ b/collector/lib/ProtoSignalFormatter.h @@ -8,6 +8,7 @@ // forward declarations class sinsp_evt; +class sinsp_threadinfo; namespace collector { @@ -20,6 +21,7 @@ class BaseProtoSignalFormatter { // Note: The caller does not assume ownership of the returned message. To avoid an additional heap allocation, the // implementing class should maintain an instance-level message whose address is returned by this method. virtual const google::protobuf::Message* ToProtoMessage(sinsp_evt* event) = 0; + virtual const google::protobuf::Message* ToProtoMessage(sinsp_threadinfo* tinfo) = 0; }; template @@ -28,6 +30,7 @@ class ProtoSignalFormatter : public BaseProtoSignalFormatter, protected ProtoAll ProtoSignalFormatter() = default; const Message* ToProtoMessage(sinsp_evt* event) override = 0; + const Message* ToProtoMessage(sinsp_threadinfo* tinfo) override = 0; }; } // namespace collector diff --git a/collector/lib/SensorClient.cpp b/collector/lib/SensorClient.cpp index 24606ecfb8..2453c65d77 100644 --- a/collector/lib/SensorClient.cpp +++ b/collector/lib/SensorClient.cpp @@ -60,7 +60,7 @@ SignalHandler::Result SensorClient::SendMsg(const sensor::MsgFromCollector& msg) return SignalHandler::ERROR; } - if (first_write_) { + if (first_write_ && msg.has_process_signal()) { first_write_ = false; return SignalHandler::NEEDS_REFRESH; } diff --git a/collector/lib/SensorClientFormatter.cpp b/collector/lib/SensorClientFormatter.cpp new file mode 100644 index 0000000000..867cc6d2c8 --- /dev/null +++ b/collector/lib/SensorClientFormatter.cpp @@ -0,0 +1,377 @@ +#include "SensorClientFormatter.h" + +#include + +#include + +#include "internalapi/sensor/collector_iservice.pb.h" +#include "internalapi/sensor/signal_iservice.pb.h" + +#include "CollectorStats.h" +#include "EventMap.h" +#include "Logging.h" +#include "Utility.h" +#include "system-inspector/EventExtractor.h" + +namespace collector { + +using SignalStreamMessage = sensor::SignalStreamMessage; +using Signal = SensorClientFormatter::Signal; +using ProcessSignal = SensorClientFormatter::ProcessSignal; +using LineageInfo = SensorClientFormatter::LineageInfo; + +using Timestamp = google::protobuf::Timestamp; +using TimeUtil = google::protobuf::util::TimeUtil; + +namespace { + +enum ProcessSignalType { + EXECVE, + UNKNOWN_PROCESS_TYPE +}; + +static EventMap process_signals = { + { + {"execve<", ProcessSignalType::EXECVE}, + }, + ProcessSignalType::UNKNOWN_PROCESS_TYPE, +}; + +std::string extract_proc_args(sinsp_threadinfo* tinfo) { + if (tinfo->m_args.empty()) { + return ""; + } + std::ostringstream args; + for (auto it = tinfo->m_args.begin(); it != tinfo->m_args.end();) { + auto arg = *it++; + auto arg_sanitized = SanitizedUTF8(arg); + + args << ((arg_sanitized ? *arg_sanitized : arg)); + + if (it != tinfo->m_args.end()) { + args << " "; + } + } + return args.str(); +} + +} // namespace + +SensorClientFormatter::SensorClientFormatter( + sinsp* inspector, + const CollectorConfig& config) : event_names_(EventNames::GetInstance()), + event_extractor_(std::make_unique()), + container_metadata_(inspector), + config_(config) { + event_extractor_->Init(inspector); +} + +SensorClientFormatter::~SensorClientFormatter() = default; + +const sensor::MsgFromCollector* SensorClientFormatter::ToProtoMessage(sinsp_evt* event) { + if (process_signals[event->get_type()] == ProcessSignalType::UNKNOWN_PROCESS_TYPE) { + return nullptr; + } + + Reset(); + + if (!ValidateProcessDetails(event)) { + CLOG(INFO) << "Dropping process event: " << ProcessDetails(event); + return nullptr; + } + + ProcessSignal* process_signal = CreateProcessSignal(event); + if (process_signal == nullptr) { + return nullptr; + } + + auto* msg = AllocateRoot(); + msg->clear_info(); + msg->clear_register_(); + msg->set_allocated_process_signal(process_signal); + return msg; +} + +const sensor::MsgFromCollector* SensorClientFormatter::ToProtoMessage(sinsp_threadinfo* tinfo) { + Reset(); + if (!ValidateProcessDetails(tinfo)) { + CLOG(INFO) << "Dropping process event: " << tinfo; + return nullptr; + } + + ProcessSignal* signal = CreateProcessSignal(tinfo); + if (signal == nullptr) { + return nullptr; + } + + auto* msg = AllocateRoot(); + msg->clear_register_(); + msg->clear_info(); + msg->set_allocated_process_signal(signal); + return msg; +} + +ProcessSignal* SensorClientFormatter::CreateProcessSignal(sinsp_evt* event) { + auto signal = Allocate(); + + // set id + signal->set_id(UUIDStr()); + + const std::string* name = event_extractor_->get_comm(event); + const std::string* exepath = event_extractor_->get_exepath(event); + + std::optional name_sanitized; + std::optional exepath_sanitized; + + if (name) { + name_sanitized = SanitizedUTF8(*name); + } + + if (exepath) { + exepath_sanitized = SanitizedUTF8(*exepath); + } + + // set name (if name is missing or empty, try to use exec_file_path) + if (name && !name->empty() && *name != "") { + signal->set_name(name_sanitized ? *name_sanitized : *name); + } else if (exepath && !exepath->empty() && *exepath != "") { + signal->set_name(exepath_sanitized ? *exepath_sanitized : *exepath); + } + + // set exec_file_path (if exec_file_path is missing or empty, try to use name) + if (exepath && !exepath->empty() && *exepath != "") { + signal->set_exec_file_path(exepath_sanitized ? *exepath_sanitized : *exepath); + } else if (name && !name->empty() && *name != "") { + signal->set_exec_file_path(name_sanitized ? *name_sanitized : *name); + } + + // set process arguments, if not explicitely disabled + if (!config_.DisableProcessArguments()) { + if (const char* args = event_extractor_->get_proc_args(event)) { + std::string args_str = args; + auto args_sanitized = SanitizedUTF8(args_str); + signal->set_args(args_sanitized ? *args_sanitized : args_str); + } + } + + // set pid + if (const int64_t* pid = event_extractor_->get_pid(event)) { + signal->set_pid(*pid); + } + + // set user and group id credentials + if (const uint32_t* uid = event_extractor_->get_uid(event)) { + signal->set_uid(*uid); + } + if (const uint32_t* gid = event_extractor_->get_gid(event)) { + signal->set_gid(*gid); + } + + // set time + auto timestamp = Allocate(); + *timestamp = TimeUtil::NanosecondsToTimestamp(event->get_ts()); + signal->set_allocated_creation_time(timestamp); + + // set container_id + if (const std::string* container_id = event_extractor_->get_container_id(event)) { + signal->set_container_id(*container_id); + } + + // set process lineage + std::vector lineage; + this->GetProcessLineage(event->get_thread_info(), lineage); + for (const auto& p : lineage) { + auto signal_lineage = signal->add_lineage_info(); + signal_lineage->set_parent_exec_file_path(p.parent_exec_file_path()); + signal_lineage->set_parent_uid(p.parent_uid()); + } + + CLOG(DEBUG) << "Process (" << signal->container_id() << ": " << signal->pid() << "): " + << signal->name() << "[" << container_metadata_.GetNamespace(event) << "] " + << " (" << signal->exec_file_path() << ")" + << " " << signal->args(); + + return signal; +} + +ProcessSignal* SensorClientFormatter::CreateProcessSignal(sinsp_threadinfo* tinfo) { + auto signal = Allocate(); + + // set id + signal->set_id(UUIDStr()); + + const auto& name = tinfo->m_comm; + auto name_sanitized = SanitizedUTF8(name); + const auto& exepath = tinfo->m_exepath; + auto exepath_sanitized = SanitizedUTF8(exepath); + + // set name (if name is missing or empty, try to use exec_file_path) + if (!name.empty() && name != "") { + signal->set_name(name_sanitized ? *name_sanitized : name); + } else if (!exepath.empty() && exepath != "") { + signal->set_name(exepath_sanitized ? *exepath_sanitized : exepath); + } + + // set exec_file_path (if exec_file_path is missing or empty, try to use name) + if (!exepath.empty() && exepath != "") { + signal->set_exec_file_path(exepath_sanitized ? *exepath_sanitized : exepath); + } else if (!name.empty() && name != "") { + signal->set_exec_file_path(name_sanitized ? *name_sanitized : name); + } + + // set the process as coming from a scrape as opposed to an exec + signal->set_scraped(true); + + // set process arguments + signal->set_args(extract_proc_args(tinfo)); + + // set pid + signal->set_pid(tinfo->m_pid); + + // set user and group id credentials + signal->set_uid(tinfo->m_user.uid()); + signal->set_gid(tinfo->m_group.gid()); + + // set time + auto timestamp = Allocate(); + *timestamp = TimeUtil::NanosecondsToTimestamp(tinfo->m_clone_ts); + signal->set_allocated_creation_time(timestamp); + + // set container_id + signal->set_container_id(tinfo->m_container_id); + + // set process lineage + std::vector lineage; + GetProcessLineage(tinfo, lineage); + + for (const auto& p : lineage) { + auto signal_lineage = signal->add_lineage_info(); + signal_lineage->set_parent_exec_file_path(p.parent_exec_file_path()); + signal_lineage->set_parent_uid(p.parent_uid()); + } + + CLOG(DEBUG) << "Process (" << signal->container_id() << ": " << signal->pid() << "): " + << signal->name() + << " (" << signal->exec_file_path() << ")" + << " " << signal->args(); + + return signal; +} + +std::string SensorClientFormatter::ProcessDetails(sinsp_evt* event) { + std::stringstream ss; + const std::string* path = event_extractor_->get_exepath(event); + const std::string* name = event_extractor_->get_comm(event); + const std::string* container_id = event_extractor_->get_container_id(event); + const char* args = event_extractor_->get_proc_args(event); + const int64_t* pid = event_extractor_->get_pid(event); + + ss << "Container: " << (container_id ? *container_id : "null") + << ", Name: " << (name ? *name : "null") + << ", PID: " << (pid ? *pid : -1) + << ", Path: " << (path ? *path : "null") + << ", Args: " << (args ? args : "null"); + + return ss.str(); +} + +bool SensorClientFormatter::ValidateProcessDetails(const sinsp_threadinfo* tinfo) { + if (tinfo == nullptr) { + return false; + } + + if (tinfo->m_exepath == "" && tinfo->m_comm == "") { + return false; + } + + return true; +} + +bool SensorClientFormatter::ValidateProcessDetails(sinsp_evt* event) { + const sinsp_threadinfo* tinfo = event->get_thread_info(); + + return ValidateProcessDetails(tinfo); +} + +int SensorClientFormatter::GetTotalStringLength(const std::vector& lineage) { + int totalStringLength = 0; + for (LineageInfo l : lineage) { + totalStringLength += l.parent_exec_file_path().size(); + } + + return totalStringLength; +} + +void SensorClientFormatter::CountLineage(const std::vector& lineage) { + int totalStringLength = GetTotalStringLength(lineage); + COUNTER_INC(CollectorStats::process_lineage_counts); + COUNTER_ADD(CollectorStats::process_lineage_total, lineage.size()); + COUNTER_ADD(CollectorStats::process_lineage_sqr_total, lineage.size() * lineage.size()); + COUNTER_ADD(CollectorStats::process_lineage_string_total, totalStringLength); +} + +void SensorClientFormatter::GetProcessLineage(sinsp_threadinfo* tinfo, + std::vector& lineage) { + if (tinfo == nullptr) { + return; + } + sinsp_threadinfo* mt = nullptr; + if (tinfo->is_main_thread()) { + mt = tinfo; + } else { + mt = tinfo->get_main_thread(); + if (mt == nullptr) { + return; + } + } + sinsp_threadinfo::visitor_func_t visitor = [&lineage](sinsp_threadinfo* pt) { + if (pt == nullptr) { + return false; + } + if (pt->m_pid == 0) { + return false; + } + + // + // Collection of process lineage information should stop at the container + // boundary to avoid collecting host process information. + // + // In back-ported eBPF probes, `m_vpid` will not be set for containers + // running when collector comes online because /proc/{pid}/status does + // not contain namespace information, so `m_container_id` is checked + // instead. `m_container_id` is not enough on its own to identify + // containerized processes, because it is not guaranteed to be set on + // all platforms. + // + if (pt->m_vpid == 0) { + if (pt->m_container_id.empty()) { + return false; + } + } else if (pt->m_pid == pt->m_vpid) { + return false; + } + + if (pt->m_vpid == -1) { + return false; + } + + // Collapse parent child processes that have the same path + if (lineage.empty() || (lineage.back().parent_exec_file_path() != pt->m_exepath)) { + LineageInfo info; + info.set_parent_uid(pt->m_user.uid()); + info.set_parent_exec_file_path(pt->m_exepath); + lineage.push_back(info); + } + + // Limit max number of ancestors + if (lineage.size() >= 10) { + return false; + } + + return true; + }; + mt->traverse_parent_state(visitor); + CountLineage(lineage); +} + +} // namespace collector diff --git a/collector/lib/SensorClientFormatter.h b/collector/lib/SensorClientFormatter.h new file mode 100644 index 0000000000..aa06710f3c --- /dev/null +++ b/collector/lib/SensorClientFormatter.h @@ -0,0 +1,70 @@ +#ifndef SENSOR_CLIENT_FORMATTER_H +#define SENSOR_CLIENT_FORMATTER_H + +#include + +#include + +#include "api/v1/signal.pb.h" +#include "internalapi/sensor/collector_iservice.pb.h" + +#include "CollectorConfig.h" +#include "ContainerMetadata.h" +#include "EventNames.h" +#include "ProtoSignalFormatter.h" + +// forward definitions +class sinsp; +class sinsp_threadinfo; + +namespace collector::system_inspector { +class EventExtractor; +} + +namespace collector { + +class SensorClientFormatter : public ProtoSignalFormatter { + public: + SensorClientFormatter(const SensorClientFormatter&) = delete; + SensorClientFormatter(SensorClientFormatter&&) = delete; + SensorClientFormatter& operator=(const SensorClientFormatter&) = delete; + SensorClientFormatter& operator=(SensorClientFormatter&&) = delete; + virtual ~SensorClientFormatter(); + + SensorClientFormatter(sinsp* inspector, const CollectorConfig& config); + + using Signal = v1::Signal; + using ProcessSignal = sensor::ProcessSignal; + using LineageInfo = sensor::ProcessSignal_LineageInfo; + using MsgFromCollector = sensor::MsgFromCollector; + + const MsgFromCollector* ToProtoMessage(sinsp_evt* event) override; + const MsgFromCollector* ToProtoMessage(sinsp_threadinfo* tinfo) override; + + void GetProcessLineage(sinsp_threadinfo* tinfo, std::vector& lineage); + + private: + FRIEND_TEST(ProcessSignalFormatterTest, NoProcessArguments); + FRIEND_TEST(ProcessSignalFormatterTest, ProcessArguments); + + ProcessSignal* CreateProcessSignal(sinsp_evt* event); + Signal* CreateSignal(sinsp_evt* event); + bool ValidateProcessDetails(const sinsp_threadinfo* tinfo); + bool ValidateProcessDetails(sinsp_evt* event); + std::string ProcessDetails(sinsp_evt* event); + + Signal* CreateSignal(sinsp_threadinfo* tinfo); + ProcessSignal* CreateProcessSignal(sinsp_threadinfo* tinfo); + int GetTotalStringLength(const std::vector& lineage); + void CountLineage(const std::vector& lineage); + + const EventNames& event_names_; + std::unique_ptr event_extractor_; + ContainerMetadata container_metadata_; + + const CollectorConfig& config_; +}; + +} // namespace collector + +#endif // SENSOR_CLIENT_FORMATTER_H diff --git a/collector/lib/system-inspector/Service.cpp b/collector/lib/system-inspector/Service.cpp index 5cb9676b18..1ae4db0928 100644 --- a/collector/lib/system-inspector/Service.cpp +++ b/collector/lib/system-inspector/Service.cpp @@ -45,7 +45,6 @@ Service& Service::operator=(Service&& other) noexcept { default_formatter_.swap(other.default_formatter_); } - std::swap(output_, other.output_); signal_handlers_.swap(other.signal_handlers_); userspace_stats_ = other.userspace_stats_; @@ -66,8 +65,7 @@ Service::Service(const CollectorConfig& config, CollectorOutput* client) default_formatter_(std::make_unique( inspector_.get(), DEFAULT_OUTPUT_STR, - EventExtractor::FilterList())), - output_(client) { + EventExtractor::FilterList())) { // Setup the inspector. // peeking into arguments has a big overhead, so we prevent it from happening inspector_->set_snaplen(0); @@ -123,7 +121,7 @@ Service::Service(const CollectorConfig& config, CollectorOutput* client) AddSignalHandler(std::make_unique(inspector_.get())); AddSignalHandler(std::make_unique(inspector_.get(), - output_, + client, &userspace_stats_, config)); diff --git a/collector/lib/system-inspector/Service.h b/collector/lib/system-inspector/Service.h index 251d05f81d..c12752f3b9 100644 --- a/collector/lib/system-inspector/Service.h +++ b/collector/lib/system-inspector/Service.h @@ -73,7 +73,6 @@ class Service : public SystemInspector { std::unique_ptr inspector_; std::shared_ptr container_metadata_inspector_; std::unique_ptr default_formatter_; - CollectorOutput* output_{}; std::vector signal_handlers_; Stats userspace_stats_; std::bitset global_event_filter_; From 8e0e05c137af2f9786df35bf4eb22858bebd9865 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Fri, 28 Mar 2025 12:18:03 +0100 Subject: [PATCH 06/14] Unify client reconnection thread in CollectorOutput --- collector/lib/CollectorOutput.cpp | 98 +++++++++++++++++---- collector/lib/CollectorOutput.h | 30 +++---- collector/lib/CollectorService.cpp | 4 +- collector/lib/SensorClient.cpp | 44 +-------- collector/lib/SensorClient.h | 22 ++--- collector/lib/SignalServiceClient.cpp | 45 +--------- collector/lib/SignalServiceClient.h | 29 +++--- integration-tests/pkg/mock_sensor/server.go | 4 +- 8 files changed, 132 insertions(+), 144 deletions(-) diff --git a/collector/lib/CollectorOutput.cpp b/collector/lib/CollectorOutput.cpp index 70ab1de1ad..bf1d1dab9e 100644 --- a/collector/lib/CollectorOutput.cpp +++ b/collector/lib/CollectorOutput.cpp @@ -3,14 +3,16 @@ #include "internalapi/sensor/collector.pb.h" #include "internalapi/sensor/collector_iservice.pb.h" -#include "HostInfo.h" +#include "GRPCUtil.h" namespace collector { CollectorOutput::CollectorOutput(const CollectorConfig& config) { if (config.grpc_channel != nullptr) { - auto sensor_client = std::make_unique(config.grpc_channel); - auto signal_client = std::make_unique(config.grpc_channel); + channel_ = config.grpc_channel; + + auto sensor_client = std::make_unique(channel_); + auto signal_client = std::make_unique(channel_); sensor_clients_.emplace_back(std::move(sensor_client)); signal_clients_.emplace_back(std::move(signal_client)); } @@ -26,39 +28,62 @@ CollectorOutput::CollectorOutput(const CollectorConfig& config) { CLOG(FATAL) << "No available output configured"; } - StartClients(sensor_clients_); - StartClients(signal_clients_); + thread_.Start([this] { EstablishGrpcStream(); }); +} + +void CollectorOutput::HandleOutputError() { + CLOG(ERROR) << "GRPC stream interrupted"; + stream_active_.store(false, std::memory_order_release); + stream_interrupted_.notify_one(); } -namespace { -SignalHandler::Result SensorOutput(std::vector>& clients, const sensor::MsgFromCollector& msg) { - for (auto& client : clients) { +SignalHandler::Result CollectorOutput::SensorOutput(const sensor::MsgFromCollector& msg) { + for (auto& client : sensor_clients_) { auto res = client->SendMsg(msg); - if (res != SignalHandler::PROCESSED) { - return res; + switch (res) { + case SignalHandler::PROCESSED: + break; + + case SignalHandler::ERROR: + HandleOutputError(); + return res; + + case SignalHandler::IGNORED: + case SignalHandler::NEEDS_REFRESH: + case SignalHandler::FINISHED: + return res; } } return SignalHandler::PROCESSED; } -SignalHandler::Result SignalOutput(std::vector>& clients, const sensor::SignalStreamMessage& msg) { - for (auto& client : clients) { +SignalHandler::Result CollectorOutput::SignalOutput(const sensor::SignalStreamMessage& msg) { + for (auto& client : signal_clients_) { auto res = client->PushSignals(msg); - if (res != SignalHandler::PROCESSED) { - return res; + switch (res) { + case SignalHandler::PROCESSED: + break; + + case SignalHandler::ERROR: + HandleOutputError(); + return res; + + case SignalHandler::IGNORED: + case SignalHandler::NEEDS_REFRESH: + case SignalHandler::FINISHED: + return res; } } return SignalHandler::PROCESSED; } -} // namespace SignalHandler::Result CollectorOutput::SendMsg(const MessageType& msg) { auto visitor = [this](auto&& m) { using T = std::decay_t; if constexpr (std::is_same_v) { - return SensorOutput(sensor_clients_, m); + return SensorOutput(m); } else if constexpr (std::is_same_v) { - return SignalOutput(signal_clients_, m); + return SignalOutput(m); } // Unknown type @@ -82,4 +107,43 @@ void CollectorOutput::Register() { } } } + +void CollectorOutput::EstablishGrpcStream() { + while (EstablishGrpcStreamSingle()) { + } + CLOG(INFO) << "Signal service client terminating."; +} + +bool CollectorOutput::EstablishGrpcStreamSingle() { + std::mutex mtx; + std::unique_lock lock(mtx); + stream_interrupted_.wait(lock, [this]() { return !stream_active_.load(std::memory_order_acquire) || thread_.should_stop(); }); + if (thread_.should_stop()) { + return false; + } + + CLOG(INFO) << "Trying to establish GRPC stream..."; + + if (!WaitForChannelReady(channel_, [this]() { return thread_.should_stop(); })) { + return false; + } + if (thread_.should_stop()) { + return false; + } + + // Refresh all clients + auto success = true; + for (const auto& client : signal_clients_) { + success &= client->Refresh(); + } + + for (const auto& client : sensor_clients_) { + success &= client->Refresh(); + } + + if (success) { + stream_active_.store(true, std::memory_order_release); + } + return true; +} } // namespace collector diff --git a/collector/lib/CollectorOutput.h b/collector/lib/CollectorOutput.h index f0afd402f2..ac54c149cb 100644 --- a/collector/lib/CollectorOutput.h +++ b/collector/lib/CollectorOutput.h @@ -17,7 +17,7 @@ using MessageType = std::variant - void StartClients(std::vector& clients) { - for (auto& client : clients) { - client->Start(); - } - } + void EstablishGrpcStream(); + bool EstablishGrpcStreamSingle(); - template - void StopClients(std::vector& clients) { - for (auto& client : clients) { - client->Stop(); - } - } + void HandleOutputError(); + SignalHandler::Result SensorOutput(const sensor::MsgFromCollector& msg); + SignalHandler::Result SignalOutput(const sensor::SignalStreamMessage& msg); std::vector> sensor_clients_; std::vector> signal_clients_; bool use_sensor_client_{true}; + + StoppableThread thread_; + std::atomic stream_active_{false}; + std::condition_variable stream_interrupted_; + std::shared_ptr channel_; }; } // namespace collector diff --git a/collector/lib/CollectorService.cpp b/collector/lib/CollectorService.cpp index 7915ad68c8..6a70747326 100644 --- a/collector/lib/CollectorService.cpp +++ b/collector/lib/CollectorService.cpp @@ -96,6 +96,8 @@ void CollectorService::RunForever() { // Start monitoring services. config_loader_.Start(); + output_.Register(); + CLOG(INFO) << "Network scrape interval set to " << config_.ScrapeInterval() << " seconds"; if (net_status_notifier_) { @@ -106,8 +108,6 @@ void CollectorService::RunForever() { CLOG(FATAL) << "Unable to start collector stats exporter"; } - output_.Register(); - system_inspector_.Start(); ControlValue cv; diff --git a/collector/lib/SensorClient.cpp b/collector/lib/SensorClient.cpp index 2453c65d77..a564c56ddb 100644 --- a/collector/lib/SensorClient.cpp +++ b/collector/lib/SensorClient.cpp @@ -1,58 +1,23 @@ #include "SensorClient.h" -#include "GRPCUtil.h" #include "Logging.h" namespace collector { -bool SensorClient::EstablishGRPCStreamSingle() { - std::mutex mtx; - std::unique_lock lock(mtx); - stream_interrupted_.wait(lock, [this]() { return !stream_active_.load(std::memory_order_acquire) || thread_.should_stop(); }); - if (thread_.should_stop()) { - return false; - } - - CLOG(INFO) << "Trying to establish GRPC stream for signals ..."; - - if (!WaitForChannelReady(channel_, [this]() { return thread_.should_stop(); })) { - return false; - } - if (thread_.should_stop()) { - return false; - } - - // stream writer +bool SensorClient::Refresh() { context_ = std::make_unique(); writer_ = DuplexClient::CreateWithReadsIgnored(&sensor::CollectorService::Stub::AsyncCommunicate, channel_, context_.get()); if (!writer_->WaitUntilStarted(std::chrono::seconds(30))) { CLOG(ERROR) << "Signal stream not ready after 30 seconds. Retrying ..."; CLOG(ERROR) << "Error message: " << writer_->FinishNow().error_message(); writer_.reset(); - return true; + return false; } - CLOG(INFO) << "Successfully established GRPC stream for signals."; first_write_ = true; stream_active_.store(true, std::memory_order_release); return true; } -void SensorClient::EstablishGRPCStream() { - while (EstablishGRPCStreamSingle()); - CLOG(INFO) << "Signal service client terminating."; -} - -void SensorClient::Start() { - thread_.Start([this] { EstablishGRPCStream(); }); -} - -void SensorClient::Stop() { - stream_interrupted_.notify_one(); - thread_.Stop(); - context_->TryCancel(); - context_.reset(); -} - SignalHandler::Result SensorClient::SendMsg(const sensor::MsgFromCollector& msg) { if (!stream_active_.load(std::memory_order_acquire)) { CLOG_THROTTLED(ERROR, std::chrono::seconds(10)) @@ -65,7 +30,8 @@ SignalHandler::Result SensorClient::SendMsg(const sensor::MsgFromCollector& msg) return SignalHandler::NEEDS_REFRESH; } - if (!writer_->Write(msg)) { + auto res = writer_->Write(msg); + if (!res) { auto status = writer_->FinishNow(); if (!status.ok()) { CLOG(ERROR) << "GRPC writes failed: (" << status.error_code() << ") " << status.error_message(); @@ -73,8 +39,6 @@ SignalHandler::Result SensorClient::SendMsg(const sensor::MsgFromCollector& msg) writer_.reset(); stream_active_.store(false, std::memory_order_release); - CLOG(ERROR) << "GRPC stream interrupted"; - stream_interrupted_.notify_one(); return SignalHandler::ERROR; } diff --git a/collector/lib/SensorClient.h b/collector/lib/SensorClient.h index 664e363e62..16c8a8524e 100644 --- a/collector/lib/SensorClient.h +++ b/collector/lib/SensorClient.h @@ -26,8 +26,7 @@ class ISensorClient { ISensorClient& operator=(ISensorClient&&) = delete; virtual ~ISensorClient() = default; - virtual void Start() = 0; - virtual void Stop() = 0; + virtual bool Refresh() = 0; virtual SignalHandler::Result SendMsg(const sensor::MsgFromCollector& msg) = 0; }; @@ -36,24 +35,26 @@ class SensorClient : public ISensorClient { public: using Service = sensor::CollectorService; + SensorClient(const SensorClient&) = delete; + SensorClient(SensorClient&&) = delete; + SensorClient& operator=(const SensorClient&) = delete; + SensorClient& operator=(SensorClient&&) = delete; + ~SensorClient() override { + context_->TryCancel(); + } + explicit SensorClient(std::shared_ptr channel) : channel_(std::move(channel)) { } - void Start() override; - void Stop() override; + bool Refresh() override; SignalHandler::Result SendMsg(const sensor::MsgFromCollector& msg) override; private: - void EstablishGRPCStream(); - bool EstablishGRPCStreamSingle(); - std::shared_ptr channel_; - StoppableThread thread_; std::atomic stream_active_ = false; - std::condition_variable stream_interrupted_; // This needs to have the same lifetime as the class. std::unique_ptr context_; @@ -63,8 +64,7 @@ class SensorClient : public ISensorClient { }; class SensorClientStdout : public ISensorClient { - void Start() override {} - void Stop() override {} + bool Refresh() override { return true; } SignalHandler::Result SendMsg(const sensor::MsgFromCollector& msg) override { LogProtobufMessage(msg); diff --git a/collector/lib/SignalServiceClient.cpp b/collector/lib/SignalServiceClient.cpp index 18a03b016a..819b0e6d5d 100644 --- a/collector/lib/SignalServiceClient.cpp +++ b/collector/lib/SignalServiceClient.cpp @@ -1,63 +1,25 @@ #include "SignalServiceClient.h" -#include - -#include "GRPCUtil.h" #include "Logging.h" -#include "ProtoUtil.h" #include "Utility.h" namespace collector { -bool SignalServiceClient::EstablishGRPCStreamSingle() { - std::mutex mtx; - std::unique_lock lock(mtx); - stream_interrupted_.wait(lock, [this]() { return !stream_active_.load(std::memory_order_acquire) || thread_.should_stop(); }); - if (thread_.should_stop()) { - return false; - } - - CLOG(INFO) << "Trying to establish GRPC stream for signals ..."; - - if (!WaitForChannelReady(channel_, [this]() { return thread_.should_stop(); })) { - return false; - } - if (thread_.should_stop()) { - return false; - } - - // stream writer +bool SignalServiceClient::Refresh() { context_ = std::make_unique(); writer_ = DuplexClient::CreateWithReadsIgnored(&SignalService::Stub::AsyncPushSignals, channel_, context_.get()); if (!writer_->WaitUntilStarted(std::chrono::seconds(30))) { CLOG(ERROR) << "Signal stream not ready after 30 seconds. Retrying ..."; CLOG(ERROR) << "Error message: " << writer_->FinishNow().error_message(); writer_.reset(); - return true; + return false; } - CLOG(INFO) << "Successfully established GRPC stream for signals."; first_write_ = true; stream_active_.store(true, std::memory_order_release); return true; } -void SignalServiceClient::EstablishGRPCStream() { - while (EstablishGRPCStreamSingle()); - CLOG(INFO) << "Signal service client terminating."; -} - -void SignalServiceClient::Start() { - thread_.Start([this] { EstablishGRPCStream(); }); -} - -void SignalServiceClient::Stop() { - stream_interrupted_.notify_one(); - thread_.Stop(); - context_->TryCancel(); - context_.reset(); -} - SignalHandler::Result SignalServiceClient::PushSignals(const SignalStreamMessage& msg) { if (!stream_active_.load(std::memory_order_acquire)) { CLOG_THROTTLED(ERROR, std::chrono::seconds(10)) @@ -76,10 +38,7 @@ SignalHandler::Result SignalServiceClient::PushSignals(const SignalStreamMessage CLOG(ERROR) << "GRPC writes failed: " << status.error_message(); } writer_.reset(); - stream_active_.store(false, std::memory_order_release); - CLOG(ERROR) << "GRPC stream interrupted"; - stream_interrupted_.notify_one(); return SignalHandler::ERROR; } diff --git a/collector/lib/SignalServiceClient.h b/collector/lib/SignalServiceClient.h index 8dd8b68d2b..2a1b65f66f 100644 --- a/collector/lib/SignalServiceClient.h +++ b/collector/lib/SignalServiceClient.h @@ -22,11 +22,10 @@ class ISignalServiceClient { public: using SignalStreamMessage = sensor::SignalStreamMessage; - virtual void Start() = 0; - virtual void Stop() = 0; + virtual bool Refresh() = 0; virtual SignalHandler::Result PushSignals(const SignalStreamMessage& msg) = 0; - virtual ~ISignalServiceClient() {} + virtual ~ISignalServiceClient() = default; }; class SignalServiceClient : public ISignalServiceClient { @@ -34,13 +33,20 @@ class SignalServiceClient : public ISignalServiceClient { using SignalService = sensor::SignalService; using SignalStreamMessage = sensor::SignalStreamMessage; + SignalServiceClient(const SignalServiceClient&) = delete; + SignalServiceClient(SignalServiceClient&&) = delete; + SignalServiceClient& operator=(const SignalServiceClient&) = delete; + SignalServiceClient& operator=(SignalServiceClient&&) = delete; + ~SignalServiceClient() override { + context_->TryCancel(); + } + explicit SignalServiceClient(std::shared_ptr channel) : channel_(std::move(channel)), stream_active_(false) {} - void Start(); - void Stop(); + bool Refresh() override; - SignalHandler::Result PushSignals(const SignalStreamMessage& msg); + SignalHandler::Result PushSignals(const SignalStreamMessage& msg) override; private: void EstablishGRPCStream(); @@ -48,27 +54,24 @@ class SignalServiceClient : public ISignalServiceClient { std::shared_ptr channel_; - StoppableThread thread_; std::atomic stream_active_; - std::condition_variable stream_interrupted_; // This needs to have the same lifetime as the class. std::unique_ptr context_; std::unique_ptr> writer_; - bool first_write_; + bool first_write_{}; }; class StdoutSignalServiceClient : public ISignalServiceClient { public: using SignalStreamMessage = sensor::SignalStreamMessage; - explicit StdoutSignalServiceClient() {} + explicit StdoutSignalServiceClient() = default; - void Start() {}; - void Stop() {}; + bool Refresh() override { return true; } - SignalHandler::Result PushSignals(const SignalStreamMessage& msg); + SignalHandler::Result PushSignals(const SignalStreamMessage& msg) override; }; } // namespace collector diff --git a/integration-tests/pkg/mock_sensor/server.go b/integration-tests/pkg/mock_sensor/server.go index c14e660a44..363753e035 100644 --- a/integration-tests/pkg/mock_sensor/server.go +++ b/integration-tests/pkg/mock_sensor/server.go @@ -343,9 +343,9 @@ func (m *MockSensor) Communicate(stream sensorAPI.CollectorService_CommunicateSe case *sensorAPI.MsgFromCollector_ProcessSignal: m.pushSignal(signal.GetProcessSignal()) case *sensorAPI.MsgFromCollector_Register: - return nil + // Ignored event case *sensorAPI.MsgFromCollector_Info: - return nil + // Unimplemented event } } } From 6750efdd21eb521f673ed95b623ba3f45f9e7857 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Fri, 28 Mar 2025 13:03:58 +0100 Subject: [PATCH 07/14] Remove unneeded operator= overloads --- collector/lib/CollectorOutput.cpp | 3 ++- collector/lib/system-inspector/Service.cpp | 24 ---------------------- collector/lib/system-inspector/Service.h | 3 +-- 3 files changed, 3 insertions(+), 27 deletions(-) diff --git a/collector/lib/CollectorOutput.cpp b/collector/lib/CollectorOutput.cpp index bf1d1dab9e..93c2d17e63 100644 --- a/collector/lib/CollectorOutput.cpp +++ b/collector/lib/CollectorOutput.cpp @@ -4,6 +4,7 @@ #include "internalapi/sensor/collector_iservice.pb.h" #include "GRPCUtil.h" +#include "HostInfo.h" namespace collector { @@ -97,7 +98,7 @@ void CollectorOutput::Register() { sensor::MsgFromCollector msg; msg.clear_info(); msg.clear_process_signal(); - msg.mutable_register_()->set_hostname(GetHostname()); + msg.mutable_register_()->set_hostname(HostInfo::GetHostname()); for (const auto& client : sensor_clients_) { auto res = client->SendMsg(msg); diff --git a/collector/lib/system-inspector/Service.cpp b/collector/lib/system-inspector/Service.cpp index 1ae4db0928..61082115b6 100644 --- a/collector/lib/system-inspector/Service.cpp +++ b/collector/lib/system-inspector/Service.cpp @@ -33,31 +33,7 @@ namespace collector::system_inspector { -Service::Service() = default; Service::~Service() = default; -Service& Service::operator=(Service&& other) noexcept { - { - auto other_sinsp_lock = std::lock_guard(other.libsinsp_mutex_); - auto this_sinsp_lock = std::lock_guard(libsinsp_mutex_); - - inspector_.swap(other.inspector_); - container_metadata_inspector_.swap(other.container_metadata_inspector_); - default_formatter_.swap(other.default_formatter_); - } - - signal_handlers_.swap(other.signal_handlers_); - - userspace_stats_ = other.userspace_stats_; - global_event_filter_ = other.global_event_filter_; - - { - auto other_running_lock = std::lock_guard(other.running_mutex_); - auto this_running_lock = std::lock_guard(running_mutex_); - std::swap(running_, other.running_); - } - - return *this; -} Service::Service(const CollectorConfig& config, CollectorOutput* client) : inspector_(std::make_unique(true)), diff --git a/collector/lib/system-inspector/Service.h b/collector/lib/system-inspector/Service.h index c12752f3b9..36731525b4 100644 --- a/collector/lib/system-inspector/Service.h +++ b/collector/lib/system-inspector/Service.h @@ -23,11 +23,10 @@ namespace collector::system_inspector { class Service : public SystemInspector { public: - Service(); Service(const Service&) = delete; Service(Service&&) = delete; Service& operator=(const Service&) = delete; - Service& operator=(Service&&) noexcept; + Service& operator=(Service&&) = delete; ~Service() override; Service(const CollectorConfig& config, CollectorOutput* client); From e0649e74324941a4a157040b2fe9d7c71a981008 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Fri, 28 Mar 2025 18:03:41 +0100 Subject: [PATCH 08/14] Add some unit tests --- collector/lib/CollectorConfig.h | 3 + collector/lib/CollectorOutput.h | 11 +- collector/lib/SensorClientFormatter.h | 4 +- collector/test/CollectorOutputTest.cpp | 63 +++ collector/test/SensorClientFormatterTest.cpp | 404 +++++++++++++++++++ 5 files changed, 482 insertions(+), 3 deletions(-) create mode 100644 collector/test/CollectorOutputTest.cpp create mode 100644 collector/test/SensorClientFormatterTest.cpp diff --git a/collector/lib/CollectorConfig.h b/collector/lib/CollectorConfig.h index c09d849696..962a32682a 100644 --- a/collector/lib/CollectorConfig.h +++ b/collector/lib/CollectorConfig.h @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -191,6 +192,8 @@ class CollectorConfig { } protected: + FRIEND_TEST(SensorClientFormatterTest, NoProcessArguments); + int scrape_interval_; CollectionMethod collection_method_; bool turn_off_scrape_; diff --git a/collector/lib/CollectorOutput.h b/collector/lib/CollectorOutput.h index ac54c149cb..5dc00f33ec 100644 --- a/collector/lib/CollectorOutput.h +++ b/collector/lib/CollectorOutput.h @@ -26,7 +26,16 @@ class CollectorOutput { ~CollectorOutput() { stream_interrupted_.notify_one(); - thread_.Stop(); + if (thread_.running()) { + thread_.Stop(); + } + } + + // Constructor for tests + CollectorOutput(std::unique_ptr&& sensor_client, + std::unique_ptr&& signal_client) { + sensor_clients_.emplace_back(std::move(sensor_client)); + signal_clients_.emplace_back(std::move(signal_client)); } SignalHandler::Result SendMsg(const MessageType& msg); diff --git a/collector/lib/SensorClientFormatter.h b/collector/lib/SensorClientFormatter.h index aa06710f3c..aba932b74b 100644 --- a/collector/lib/SensorClientFormatter.h +++ b/collector/lib/SensorClientFormatter.h @@ -44,8 +44,8 @@ class SensorClientFormatter : public ProtoSignalFormatter& lineage); private: - FRIEND_TEST(ProcessSignalFormatterTest, NoProcessArguments); - FRIEND_TEST(ProcessSignalFormatterTest, ProcessArguments); + FRIEND_TEST(SensorClientFormatterTest, NoProcessArguments); + FRIEND_TEST(SensorClientFormatterTest, ProcessArguments); ProcessSignal* CreateProcessSignal(sinsp_evt* event); Signal* CreateSignal(sinsp_evt* event); diff --git a/collector/test/CollectorOutputTest.cpp b/collector/test/CollectorOutputTest.cpp new file mode 100644 index 0000000000..1de9801164 --- /dev/null +++ b/collector/test/CollectorOutputTest.cpp @@ -0,0 +1,63 @@ +#include +#include + +#include "internalapi/sensor/collector_iservice.pb.h" + +#include "CollectorOutput.h" +#include "SensorClient.h" +#include "SignalServiceClient.h" + +namespace collector { +class MockSensorClient : public ISensorClient { + public: + MOCK_METHOD(bool, Refresh, ()); + MOCK_METHOD(SignalHandler::Result, SendMsg, (const sensor::MsgFromCollector&)); +}; + +class MockSignalClient : public ISignalServiceClient { + public: + MOCK_METHOD(bool, Refresh, ()); + MOCK_METHOD(SignalHandler::Result, PushSignals, (const sensor::SignalStreamMessage&)); +}; + +class CollectorOutputTest : public testing::Test { + public: + CollectorOutputTest() + : sensor_client(std::make_unique()), + signal_client(std::make_unique()) {} + + protected: + std::unique_ptr sensor_client; + std::unique_ptr signal_client; +}; + +TEST_F(CollectorOutputTest, Register) { + EXPECT_CALL(*sensor_client, SendMsg).Times(1).WillOnce(testing::Return(SignalHandler::PROCESSED)); + + CollectorOutput output{std::move(sensor_client), std::move(signal_client)}; + output.Register(); +} + +TEST_F(CollectorOutputTest, SensorClient) { + sensor::MsgFromCollector msg; + + EXPECT_CALL(*sensor_client, SendMsg).Times(1).WillOnce(testing::Return(SignalHandler::PROCESSED)); + + CollectorOutput output{std::move(sensor_client), std::move(signal_client)}; + auto result = output.SendMsg(msg); + + EXPECT_EQ(result, SignalHandler::PROCESSED); +} + +TEST_F(CollectorOutputTest, SignalClient) { + sensor::SignalStreamMessage msg; + + EXPECT_CALL(*signal_client, PushSignals).Times(1).WillOnce(testing::Return(SignalHandler::PROCESSED)); + + CollectorOutput output{std::move(sensor_client), std::move(signal_client)}; + + auto result = output.SendMsg(msg); + + EXPECT_EQ(result, SignalHandler::PROCESSED); +} +} // namespace collector diff --git a/collector/test/SensorClientFormatterTest.cpp b/collector/test/SensorClientFormatterTest.cpp new file mode 100644 index 0000000000..57c19c63e6 --- /dev/null +++ b/collector/test/SensorClientFormatterTest.cpp @@ -0,0 +1,404 @@ +#include + +#include +#include + +#include "libsinsp/sinsp.h" + +#include "CollectorStats.h" +#include "SensorClientFormatter.h" +#include "Utility.h" + +namespace collector { + +using LineageInfo = SensorClientFormatter::LineageInfo; + +struct ThreadInfoParams { + int64_t pid; + int64_t tid; + int64_t ptid; + int64_t vpid; + int64_t uid; + std::string container_id; + std::string exepath; +}; + +static void ExpectStatsCounter(size_t index, long expected) { + auto value = CollectorStats::GetOrCreate().GetCounter(index); + EXPECT_EQ(value, expected); +} + +class SensorClientFormatterTest : public testing::Test { + public: + SensorClientFormatterTest() : inspector(new sinsp()), formatter(inspector.get(), config) { + } + + protected: + std::unique_ptr build_threadinfo(const ThreadInfoParams& params) { + auto tinfo = inspector->build_threadinfo(); + tinfo->m_pid = params.pid; + tinfo->m_tid = params.tid; + tinfo->m_ptid = params.ptid; + tinfo->m_vpid = params.vpid; + tinfo->m_user.set_uid(params.uid); + tinfo->m_container_id = params.container_id; + tinfo->m_exepath = params.exepath; + return tinfo; + } + + std::unique_ptr inspector; + CollectorConfig config; + SensorClientFormatter formatter; +}; + +TEST_F(SensorClientFormatterTest, NoProcessTest) { + sinsp_threadinfo* tinfo = nullptr; + std::vector lineage; + + formatter.GetProcessLineage(tinfo, lineage); + + ExpectStatsCounter(CollectorStats::process_lineage_counts, 0); + ExpectStatsCounter(CollectorStats::process_lineage_total, 0); + ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 0); + ExpectStatsCounter(CollectorStats::process_lineage_string_total, 0); + + EXPECT_TRUE(lineage.empty()); +} + +TEST_F(SensorClientFormatterTest, ProcessWithoutParentTest) { + // {pid, tid, ptid, vpid, uid, container_id, exepath}, + inspector->add_thread(build_threadinfo({0, 0, -1, 2, 7, "", "qwerty"})); + std::vector lineage; + + formatter.GetProcessLineage(inspector->get_thread_ref(0).get(), lineage); + + ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); + ExpectStatsCounter(CollectorStats::process_lineage_total, 0); + ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 0); + ExpectStatsCounter(CollectorStats::process_lineage_string_total, 0); + + EXPECT_TRUE(lineage.empty()); + + CollectorStats::Reset(); +} + +TEST_F(SensorClientFormatterTest, ProcessWithParentTest) { + // {pid, tid, ptid, vpid, uid, container_id, exepath}, + std::vector tinfo_params = { + {3, 3, -1, 1, 42, "", "asdf"}, + {1, 1, 3, 2, 7, "", "qwerty"}, + }; + + for (const auto& params : tinfo_params) { + inspector->add_thread(build_threadinfo(params)); + } + + std::vector lineage; + formatter.GetProcessLineage(inspector->get_thread_ref(1).get(), lineage); + + ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); + ExpectStatsCounter(CollectorStats::process_lineage_total, 1); + ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 1); + ExpectStatsCounter(CollectorStats::process_lineage_string_total, 4); + + EXPECT_EQ(lineage.size(), 1); + + EXPECT_EQ(lineage[0].parent_uid(), 42); + EXPECT_EQ(lineage[0].parent_exec_file_path(), "asdf"); + + CollectorStats::Reset(); +} + +TEST_F(SensorClientFormatterTest, ProcessWithParentWithPid0Test) { + // {pid, tid, ptid, vpid, uid, container_id, exepath}, + std::vector tinfo_params = { + {0, 0, -1, 1, 0, "", "asdf"}, + {1, 1, 0, 2, 0, "", "qwerty"}, + }; + + for (const auto& params : tinfo_params) { + inspector->add_thread(build_threadinfo(params)); + } + + std::vector lineage; + formatter.GetProcessLineage(inspector->get_thread_ref(1).get(), lineage); + + ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); + ExpectStatsCounter(CollectorStats::process_lineage_total, 0); + ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 0); + ExpectStatsCounter(CollectorStats::process_lineage_string_total, 0); + + EXPECT_TRUE(lineage.empty()); + + CollectorStats::Reset(); +} + +TEST_F(SensorClientFormatterTest, ProcessWithParentWithSameNameTest) { + // {pid, tid, ptid, vpid, uid, container_id, exepath}, + std::vector tinfo_params = { + {3, 3, -1, 1, 43, "", "asdf"}, + {1, 1, 3, 2, 42, "", "asdf"}, + }; + + for (const auto& params : tinfo_params) { + inspector->add_thread(build_threadinfo(params)); + } + + std::vector lineage; + formatter.GetProcessLineage(inspector->get_thread_ref(1).get(), lineage); + + ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); + ExpectStatsCounter(CollectorStats::process_lineage_total, 1); + ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 1); + ExpectStatsCounter(CollectorStats::process_lineage_string_total, 4); + + EXPECT_EQ(lineage.size(), 1); + + EXPECT_EQ(lineage[0].parent_uid(), 43); + EXPECT_EQ(lineage[0].parent_exec_file_path(), "asdf"); + + CollectorStats::Reset(); +} + +TEST_F(SensorClientFormatterTest, ProcessWithTwoParentsTest) { + // {pid, tid, ptid, vpid, uid, container_id, exepath}, + std::vector tinfo_params = { + {3, 3, -1, 1, 42, "", "asdf"}, + {1, 1, 3, 2, 7, "", "qwerty"}, + {4, 4, 1, 9, 8, "", "uiop"}, + }; + + for (const auto& params : tinfo_params) { + inspector->add_thread(build_threadinfo(params)); + } + + std::vector lineage; + formatter.GetProcessLineage(inspector->get_thread_ref(4).get(), lineage); + + ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); + ExpectStatsCounter(CollectorStats::process_lineage_total, 2); + ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 4); + ExpectStatsCounter(CollectorStats::process_lineage_string_total, 10); + + EXPECT_EQ(lineage.size(), 2); + + EXPECT_EQ(lineage[0].parent_uid(), 7); + EXPECT_EQ(lineage[0].parent_exec_file_path(), "qwerty"); + + EXPECT_EQ(lineage[1].parent_uid(), 42); + EXPECT_EQ(lineage[1].parent_exec_file_path(), "asdf"); + + CollectorStats::Reset(); +} + +TEST_F(SensorClientFormatterTest, ProcessWithTwoParentsWithTheSameNameTest) { + // {pid, tid, ptid, vpid, uid, container_id, exepath}, + std::vector tinfo_params = { + {3, 3, -1, 1, 42, "", "asdf"}, + {1, 1, 3, 2, 7, "", "asdf"}, + {4, 4, 1, 9, 8, "", "asdf"}, + }; + + for (const auto& params : tinfo_params) { + inspector->add_thread(build_threadinfo(params)); + } + + std::vector lineage; + formatter.GetProcessLineage(inspector->get_thread_ref(4).get(), lineage); + + ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); + ExpectStatsCounter(CollectorStats::process_lineage_total, 1); + ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 1); + ExpectStatsCounter(CollectorStats::process_lineage_string_total, 4); + + EXPECT_EQ(lineage.size(), 1); + + EXPECT_EQ(lineage[0].parent_uid(), 7); + EXPECT_EQ(lineage[0].parent_exec_file_path(), "asdf"); + + CollectorStats::Reset(); +} + +TEST_F(SensorClientFormatterTest, ProcessCollapseParentChildWithSameNameTest) { + // {pid, tid, ptid, vpid, uid, container_id, exepath}, + std::vector tinfo_params = { + {3, 3, -1, 1, 42, "", "asdf"}, + {1, 1, 3, 2, 7, "", "asdf"}, + {4, 4, 1, 9, 8, "", "asdf"}, + {5, 5, 4, 10, 9, "", "qwerty"}, + }; + + for (const auto& params : tinfo_params) { + inspector->add_thread(build_threadinfo(params)); + } + + std::vector lineage; + formatter.GetProcessLineage(inspector->get_thread_ref(5).get(), lineage); + + ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); + ExpectStatsCounter(CollectorStats::process_lineage_total, 1); + ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 1); + ExpectStatsCounter(CollectorStats::process_lineage_string_total, 4); + + EXPECT_EQ(lineage.size(), 1); + + EXPECT_EQ(lineage[0].parent_uid(), 8); + EXPECT_EQ(lineage[0].parent_exec_file_path(), "asdf"); + + CollectorStats::Reset(); +} + +TEST_F(SensorClientFormatterTest, ProcessCollapseParentChildWithSameName2Test) { + // {pid, tid, ptid, vpid, uid, container_id, exepath}, + std::vector tinfo_params = { + {3, 3, -1, 1, 42, "", "qwerty"}, + {1, 1, 3, 2, 7, "", "asdf"}, + {4, 4, 1, 9, 8, "", "asdf"}, + {5, 5, 4, 10, 9, "", "asdf"}, + }; + + for (const auto& params : tinfo_params) { + inspector->add_thread(build_threadinfo(params)); + } + std::vector lineage; + formatter.GetProcessLineage(inspector->get_thread_ref(5).get(), lineage); + + ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); + ExpectStatsCounter(CollectorStats::process_lineage_total, 2); + ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 4); + ExpectStatsCounter(CollectorStats::process_lineage_string_total, 10); + + EXPECT_EQ(lineage.size(), 2); + + EXPECT_EQ(lineage[0].parent_uid(), 8); + EXPECT_EQ(lineage[0].parent_exec_file_path(), "asdf"); + + EXPECT_EQ(lineage[1].parent_uid(), 42); + EXPECT_EQ(lineage[1].parent_exec_file_path(), "qwerty"); + + CollectorStats::Reset(); +} + +TEST_F(SensorClientFormatterTest, ProcessWithUnrelatedProcessTest) { + // {pid, tid, ptid, vpid, uid, container_id, exepath}, + std::vector tinfo_params = { + {3, 3, -1, 1, 42, "", "qwerty"}, + {1, 1, 3, 2, 7, "", "asdf"}, + {4, 4, 1, 9, 8, "", "uiop"}, + {5, 5, 555, 10, 9, "", "jkl;"}, + }; + + for (const auto& params : tinfo_params) { + inspector->add_thread(build_threadinfo(params)); + } + + std::vector lineage; + formatter.GetProcessLineage(inspector->get_thread_ref(4).get(), lineage); + + ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); + ExpectStatsCounter(CollectorStats::process_lineage_total, 2); + ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 4); + ExpectStatsCounter(CollectorStats::process_lineage_string_total, 10); + + EXPECT_EQ(lineage.size(), 2); + + EXPECT_EQ(lineage[0].parent_uid(), 7); + EXPECT_EQ(lineage[0].parent_exec_file_path(), "asdf"); + + EXPECT_EQ(lineage[1].parent_uid(), 42); + EXPECT_EQ(lineage[1].parent_exec_file_path(), "qwerty"); + + CollectorStats::Reset(); +} + +TEST_F(SensorClientFormatterTest, CountTwoCounterCallsTest) { + std::vector lineage; + std::vector lineage2; + + // {pid, tid, ptid, vpid, uid, container_id, exepath}, + inspector->add_thread(build_threadinfo({1, 1, 555, 10, 9, "", "jkl;"})); + + formatter.GetProcessLineage(inspector->get_thread_ref(1).get(), lineage); + + // {pid, tid, ptid, vpid, uid, container_id, exepath}, + inspector->add_thread(build_threadinfo({2, 2, 555, 10, 9, "", "jkl;"})); + + formatter.GetProcessLineage(inspector->get_thread_ref(2).get(), lineage2); + + ExpectStatsCounter(CollectorStats::process_lineage_counts, 2); + ExpectStatsCounter(CollectorStats::process_lineage_total, 0); + ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 0); + ExpectStatsCounter(CollectorStats::process_lineage_string_total, 0); + + EXPECT_TRUE(lineage2.empty()); + + CollectorStats::Reset(); +} + +TEST_F(SensorClientFormatterTest, Rox3377ProcessLineageWithNoVPidTest) { + // {pid, tid, ptid, vpid, uid, container_id, exepath}, + std::vector tinfo_params = { + {3, 3, -1, 0, 42, "", "qwerty"}, + {1, 1, 3, 0, 7, "id", "asdf"}, + {4, 4, 1, 0, 8, "id", "uiop"}, + }; + + for (const auto& params : tinfo_params) { + inspector->add_thread(build_threadinfo(params)); + } + + std::vector lineage; + formatter.GetProcessLineage(inspector->get_thread_ref(4).get(), lineage); + + ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); + ExpectStatsCounter(CollectorStats::process_lineage_total, 1); + ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 1); + ExpectStatsCounter(CollectorStats::process_lineage_string_total, 4); + + EXPECT_EQ(lineage.size(), 1); + + EXPECT_EQ(lineage[0].parent_uid(), 7); + EXPECT_EQ(lineage[0].parent_exec_file_path(), "asdf"); + + CollectorStats::Reset(); +} + +TEST_F(SensorClientFormatterTest, ProcessArguments) { + // {pid, tid, ptid, vpid, uid, container_id, exepath}, + auto tinfo = build_threadinfo({3, 3, -1, 0, 42, "", "qwerty"}); + + std::vector args = {std::string("args")}; + tinfo->set_args(args); + + std::unique_ptr evt(new sinsp_evt()); + std::unique_ptr s_evt(new scap_evt()); + + s_evt->type = PPME_SYSCALL_EXECVE_19_X; + evt->set_tinfo(tinfo.get()); + evt->set_scap_evt(s_evt.get()); + + auto* signal = formatter.CreateProcessSignal(evt.get()); + EXPECT_FALSE(signal->args().empty()); +} + +TEST_F(SensorClientFormatterTest, NoProcessArguments) { + config.disable_process_arguments_ = true; + + // {pid, tid, ptid, vpid, uid, container_id, exepath}, + auto tinfo = build_threadinfo({3, 3, -1, 0, 42, "", "qwerty"}); + + std::vector args = {std::string("args")}; + tinfo->set_args(args); + + std::unique_ptr evt(new sinsp_evt()); + std::unique_ptr s_evt(new scap_evt()); + + s_evt->type = PPME_SYSCALL_EXECVE_19_X; + evt->set_tinfo(tinfo.get()); + evt->set_scap_evt(s_evt.get()); + + auto* signal = formatter.CreateProcessSignal(evt.get()); + EXPECT_TRUE(signal->args().empty()); +} + +} // namespace collector From fc606f5a41283d25b971b36d68004b92e8a773df Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Mon, 31 Mar 2025 16:53:52 +0200 Subject: [PATCH 09/14] Use an env variable for legacy services configuration --- collector/lib/CollectorConfig.cpp | 3 ++ collector/lib/CollectorConfig.h | 3 ++ collector/lib/CollectorOutput.cpp | 41 +++++++++++--------------- collector/lib/CollectorOutput.h | 1 - collector/lib/CollectorService.cpp | 2 -- collector/test/CollectorOutputTest.cpp | 7 ----- 6 files changed, 23 insertions(+), 34 deletions(-) diff --git a/collector/lib/CollectorConfig.cpp b/collector/lib/CollectorConfig.cpp index f3cb0cfbc7..55daf41cc1 100644 --- a/collector/lib/CollectorConfig.cpp +++ b/collector/lib/CollectorConfig.cpp @@ -84,6 +84,8 @@ PathEnvVar tls_client_key_path("ROX_COLLECTOR_TLS_CLIENT_KEY"); BoolEnvVar disable_process_arguments("ROX_COLLECTOR_NO_PROCESS_ARGUMENTS", false); BoolEnvVar use_stdout_output("ROX_COLLECTOR_USE_STDOUT", false); + +BoolEnvVar use_legacy_services("ROX_COLLECTOR_USE_LEGACY_SERVICES", false); } // namespace constexpr bool CollectorConfig::kTurnOffScrape; @@ -115,6 +117,7 @@ void CollectorConfig::InitCollectorConfig(CollectorArgs* args) { track_send_recv_ = track_send_recv.value(); disable_process_arguments_ = disable_process_arguments.value(); use_stdout_ = use_stdout_output.value(); + use_legacy_services_ = use_legacy_services.value(); for (const auto& syscall : kSyscalls) { syscalls_.emplace_back(syscall); diff --git a/collector/lib/CollectorConfig.h b/collector/lib/CollectorConfig.h index 962a32682a..a7d357ca95 100644 --- a/collector/lib/CollectorConfig.h +++ b/collector/lib/CollectorConfig.h @@ -163,6 +163,7 @@ class CollectorConfig { unsigned int GetSinspThreadCacheSize() const { return sinsp_thread_cache_size_; } bool DisableProcessArguments() const { return disable_process_arguments_; } bool UseStdout() const { return use_stdout_; } + bool UseLegacyServices() const { return use_legacy_services_; } static std::pair CheckConfiguration(const char* config, Json::Value* root); @@ -232,6 +233,8 @@ class CollectorConfig { bool use_stdout_ = false; + bool use_legacy_services_ = false; + // One ring buffer will be initialized for this many CPUs unsigned int sinsp_cpu_per_buffer_ = 0; // Size of one ring buffer, in bytes. diff --git a/collector/lib/CollectorOutput.cpp b/collector/lib/CollectorOutput.cpp index 93c2d17e63..b058b0ea86 100644 --- a/collector/lib/CollectorOutput.cpp +++ b/collector/lib/CollectorOutput.cpp @@ -9,23 +9,31 @@ namespace collector { CollectorOutput::CollectorOutput(const CollectorConfig& config) { + use_sensor_client_ = !config.UseLegacyServices(); + if (config.grpc_channel != nullptr) { channel_ = config.grpc_channel; - auto sensor_client = std::make_unique(channel_); - auto signal_client = std::make_unique(channel_); - sensor_clients_.emplace_back(std::move(sensor_client)); - signal_clients_.emplace_back(std::move(signal_client)); + if (use_sensor_client_) { + auto sensor_client = std::make_unique(channel_); + sensor_clients_.emplace_back(std::move(sensor_client)); + } else { + auto signal_client = std::make_unique(channel_); + signal_clients_.emplace_back(std::move(signal_client)); + } } if (config.UseStdout()) { - auto sensor_client = std::make_unique(); - auto signal_client = std::make_unique(); - sensor_clients_.emplace_back(std::move(sensor_client)); - signal_clients_.emplace_back(std::move(signal_client)); + if (use_sensor_client_) { + auto sensor_client = std::make_unique(); + sensor_clients_.emplace_back(std::move(sensor_client)); + } else { + auto signal_client = std::make_unique(); + signal_clients_.emplace_back(std::move(signal_client)); + } } - if (sensor_clients_.empty() || signal_clients_.empty()) { + if (sensor_clients_.empty() && signal_clients_.empty()) { CLOG(FATAL) << "No available output configured"; } @@ -94,21 +102,6 @@ SignalHandler::Result CollectorOutput::SendMsg(const MessageType& msg) { return std::visit(visitor, msg); } -void CollectorOutput::Register() { - sensor::MsgFromCollector msg; - msg.clear_info(); - msg.clear_process_signal(); - msg.mutable_register_()->set_hostname(HostInfo::GetHostname()); - - for (const auto& client : sensor_clients_) { - auto res = client->SendMsg(msg); - if (res != SignalHandler::PROCESSED) { - use_sensor_client_ = false; - break; - } - } -} - void CollectorOutput::EstablishGrpcStream() { while (EstablishGrpcStreamSingle()) { } diff --git a/collector/lib/CollectorOutput.h b/collector/lib/CollectorOutput.h index 5dc00f33ec..9e6f5bac68 100644 --- a/collector/lib/CollectorOutput.h +++ b/collector/lib/CollectorOutput.h @@ -39,7 +39,6 @@ class CollectorOutput { } SignalHandler::Result SendMsg(const MessageType& msg); - void Register(); bool UseSensorClient() const { return use_sensor_client_; } diff --git a/collector/lib/CollectorService.cpp b/collector/lib/CollectorService.cpp index 6a70747326..e24231782b 100644 --- a/collector/lib/CollectorService.cpp +++ b/collector/lib/CollectorService.cpp @@ -96,8 +96,6 @@ void CollectorService::RunForever() { // Start monitoring services. config_loader_.Start(); - output_.Register(); - CLOG(INFO) << "Network scrape interval set to " << config_.ScrapeInterval() << " seconds"; if (net_status_notifier_) { diff --git a/collector/test/CollectorOutputTest.cpp b/collector/test/CollectorOutputTest.cpp index 1de9801164..601fdc49e6 100644 --- a/collector/test/CollectorOutputTest.cpp +++ b/collector/test/CollectorOutputTest.cpp @@ -31,13 +31,6 @@ class CollectorOutputTest : public testing::Test { std::unique_ptr signal_client; }; -TEST_F(CollectorOutputTest, Register) { - EXPECT_CALL(*sensor_client, SendMsg).Times(1).WillOnce(testing::Return(SignalHandler::PROCESSED)); - - CollectorOutput output{std::move(sensor_client), std::move(signal_client)}; - output.Register(); -} - TEST_F(CollectorOutputTest, SensorClient) { sensor::MsgFromCollector msg; From 27ce867cf3abf4ee9b3868c3c770a8a622c5816b Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Mon, 31 Mar 2025 17:03:36 +0200 Subject: [PATCH 10/14] Restore some log messages needed for testing in the main repo --- collector/lib/CollectorOutput.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/collector/lib/CollectorOutput.cpp b/collector/lib/CollectorOutput.cpp index b058b0ea86..3f3a4717a3 100644 --- a/collector/lib/CollectorOutput.cpp +++ b/collector/lib/CollectorOutput.cpp @@ -1,6 +1,5 @@ #include "CollectorOutput.h" -#include "internalapi/sensor/collector.pb.h" #include "internalapi/sensor/collector_iservice.pb.h" #include "GRPCUtil.h" @@ -105,7 +104,7 @@ SignalHandler::Result CollectorOutput::SendMsg(const MessageType& msg) { void CollectorOutput::EstablishGrpcStream() { while (EstablishGrpcStreamSingle()) { } - CLOG(INFO) << "Signal service client terminating."; + CLOG(INFO) << "Service client terminating."; } bool CollectorOutput::EstablishGrpcStreamSingle() { @@ -136,7 +135,10 @@ bool CollectorOutput::EstablishGrpcStreamSingle() { } if (success) { + CLOG(INFO) << "Successfully established GRPC stream."; stream_active_.store(true, std::memory_order_release); + } else { + CLOG(WARNING) << "Failed to establish GRPC stream, retrying..."; } return true; } From ccf52576b7bb9aa727e0f0d8db0c8e43b40e379c Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Fri, 4 Apr 2025 11:58:28 +0200 Subject: [PATCH 11/14] Address PR comments - Rollback no grpc channel behaviour. - Add documentation to new classes. - Remove unneeded workaround for old kernels. - Minor refactorings in SensorClientFormatter. --- collector/lib/CollectorOutput.cpp | 13 +- collector/lib/CollectorOutput.h | 19 ++- collector/lib/ProtoSignalFormatter.h | 19 +++ collector/lib/SensorClient.h | 14 ++ collector/lib/SensorClientFormatter.cpp | 68 +++----- collector/lib/SensorClientFormatter.h | 58 ++++++- collector/lib/SignalServiceClient.h | 2 +- collector/test/SensorClientFormatterTest.cpp | 163 +++++++------------ 8 files changed, 188 insertions(+), 168 deletions(-) diff --git a/collector/lib/CollectorOutput.cpp b/collector/lib/CollectorOutput.cpp index 3f3a4717a3..5faaf044b4 100644 --- a/collector/lib/CollectorOutput.cpp +++ b/collector/lib/CollectorOutput.cpp @@ -7,9 +7,8 @@ namespace collector { -CollectorOutput::CollectorOutput(const CollectorConfig& config) { - use_sensor_client_ = !config.UseLegacyServices(); - +CollectorOutput::CollectorOutput(const CollectorConfig& config) + : use_sensor_client_(!config.UseLegacyServices()) { if (config.grpc_channel != nullptr) { channel_ = config.grpc_channel; @@ -22,7 +21,7 @@ CollectorOutput::CollectorOutput(const CollectorConfig& config) { } } - if (config.UseStdout()) { + if (config.grpc_channel == nullptr || config.UseStdout()) { if (use_sensor_client_) { auto sensor_client = std::make_unique(); sensor_clients_.emplace_back(std::move(sensor_client)); @@ -32,10 +31,6 @@ CollectorOutput::CollectorOutput(const CollectorConfig& config) { } } - if (sensor_clients_.empty() && signal_clients_.empty()) { - CLOG(FATAL) << "No available output configured"; - } - thread_.Start([this] { EstablishGrpcStream(); }); } @@ -125,7 +120,7 @@ bool CollectorOutput::EstablishGrpcStreamSingle() { } // Refresh all clients - auto success = true; + bool success = true; for (const auto& client : signal_clients_) { success &= client->Refresh(); } diff --git a/collector/lib/CollectorOutput.h b/collector/lib/CollectorOutput.h index 9e6f5bac68..2472689ee5 100644 --- a/collector/lib/CollectorOutput.h +++ b/collector/lib/CollectorOutput.h @@ -38,8 +38,23 @@ class CollectorOutput { signal_clients_.emplace_back(std::move(signal_client)); } + /** + * Send a message to sensor. + * + * @param msg One of sensor::MsgFromCollector or + * sensor::SignalStreamMessage, the proper service to be + * used will be determined from the type held in msg. + * @returns A SignalHandler::Result with the outcome of the send + * operation + */ SignalHandler::Result SendMsg(const MessageType& msg); + /** + * Whether we should use the new iservice or not. + * + * @returns true if configuration indicates we should use the new + * iservice, false otherwise. + */ bool UseSensorClient() const { return use_sensor_client_; } private: @@ -53,10 +68,10 @@ class CollectorOutput { std::vector> sensor_clients_; std::vector> signal_clients_; - bool use_sensor_client_{true}; + bool use_sensor_client_ = true; StoppableThread thread_; - std::atomic stream_active_{false}; + std::atomic stream_active_ = false; std::condition_variable stream_interrupted_; std::shared_ptr channel_; }; diff --git a/collector/lib/ProtoSignalFormatter.h b/collector/lib/ProtoSignalFormatter.h index 8cb28af1a5..0273cb5ba8 100644 --- a/collector/lib/ProtoSignalFormatter.h +++ b/collector/lib/ProtoSignalFormatter.h @@ -29,7 +29,26 @@ class ProtoSignalFormatter : public BaseProtoSignalFormatter, protected ProtoAll public: ProtoSignalFormatter() = default; + /** + * Turn a sinsp_evt into a protobuf message to be sent to sensor. + * + * @param event The event to be translated. + * @returns A pointer to the message to be sent or nullptr if no + * message should be sent. Ownership of the message is kept + * in the implementing class, caller must not attempt to free + * it. + */ const Message* ToProtoMessage(sinsp_evt* event) override = 0; + + /** + * Turn a sinsp_threadinfo into a protobuf message to be sent to sensor. + * + * @param event The event to be translated. + * @returns A pointer to the message to be sent or nullptr if no + * message should be sent. Ownership of the message is kept + * in the implementing class, caller must not attempt to free + * it. + */ const Message* ToProtoMessage(sinsp_threadinfo* tinfo) override = 0; }; diff --git a/collector/lib/SensorClient.h b/collector/lib/SensorClient.h index 16c8a8524e..46aca7d6a3 100644 --- a/collector/lib/SensorClient.h +++ b/collector/lib/SensorClient.h @@ -26,8 +26,22 @@ class ISensorClient { ISensorClient& operator=(ISensorClient&&) = delete; virtual ~ISensorClient() = default; + /** + * Recreate the internal state of the object to allow communication. + * + * Mostly useful for handling gRPC reconnections. + * + * @returns true if the refresh was succesful, false otherwise. + */ virtual bool Refresh() = 0; + /** + * Send a message to sensor through the iservice. + * + * @param msg The message to be sent to sensor. + * @returns A SignalHandler::Result with the outcome of the send + * operation. + */ virtual SignalHandler::Result SendMsg(const sensor::MsgFromCollector& msg) = 0; }; diff --git a/collector/lib/SensorClientFormatter.cpp b/collector/lib/SensorClientFormatter.cpp index 867cc6d2c8..9db4a28d07 100644 --- a/collector/lib/SensorClientFormatter.cpp +++ b/collector/lib/SensorClientFormatter.cpp @@ -76,7 +76,7 @@ const sensor::MsgFromCollector* SensorClientFormatter::ToProtoMessage(sinsp_evt* Reset(); if (!ValidateProcessDetails(event)) { - CLOG(INFO) << "Dropping process event: " << ProcessDetails(event); + CLOG(INFO) << "Dropping process event: " << ToString(event); return nullptr; } @@ -178,10 +178,9 @@ ProcessSignal* SensorClientFormatter::CreateProcessSignal(sinsp_evt* event) { } // set process lineage - std::vector lineage; - this->GetProcessLineage(event->get_thread_info(), lineage); + auto lineage = GetProcessLineage(event->get_thread_info()); for (const auto& p : lineage) { - auto signal_lineage = signal->add_lineage_info(); + auto* signal_lineage = signal->add_lineage_info(); signal_lineage->set_parent_exec_file_path(p.parent_exec_file_path()); signal_lineage->set_parent_uid(p.parent_uid()); } @@ -241,11 +240,10 @@ ProcessSignal* SensorClientFormatter::CreateProcessSignal(sinsp_threadinfo* tinf signal->set_container_id(tinfo->m_container_id); // set process lineage - std::vector lineage; - GetProcessLineage(tinfo, lineage); + auto lineage = GetProcessLineage(tinfo); for (const auto& p : lineage) { - auto signal_lineage = signal->add_lineage_info(); + auto* signal_lineage = signal->add_lineage_info(); signal_lineage->set_parent_exec_file_path(p.parent_exec_file_path()); signal_lineage->set_parent_uid(p.parent_uid()); } @@ -258,7 +256,7 @@ ProcessSignal* SensorClientFormatter::CreateProcessSignal(sinsp_threadinfo* tinf return signal; } -std::string SensorClientFormatter::ProcessDetails(sinsp_evt* event) { +std::string SensorClientFormatter::ToString(sinsp_evt* event) { std::stringstream ss; const std::string* path = event_extractor_->get_exepath(event); const std::string* name = event_extractor_->get_comm(event); @@ -293,37 +291,28 @@ bool SensorClientFormatter::ValidateProcessDetails(sinsp_evt* event) { return ValidateProcessDetails(tinfo); } -int SensorClientFormatter::GetTotalStringLength(const std::vector& lineage) { - int totalStringLength = 0; - for (LineageInfo l : lineage) { - totalStringLength += l.parent_exec_file_path().size(); - } - - return totalStringLength; -} +void SensorClientFormatter::UpdateLineageStats(const std::vector& lineage) { + int string_total = std::accumulate(lineage.cbegin(), lineage.cend(), 0, [](int acc, const auto& l) { + return acc + l.parent_exec_file_path().size(); + }); -void SensorClientFormatter::CountLineage(const std::vector& lineage) { - int totalStringLength = GetTotalStringLength(lineage); COUNTER_INC(CollectorStats::process_lineage_counts); COUNTER_ADD(CollectorStats::process_lineage_total, lineage.size()); COUNTER_ADD(CollectorStats::process_lineage_sqr_total, lineage.size() * lineage.size()); - COUNTER_ADD(CollectorStats::process_lineage_string_total, totalStringLength); + COUNTER_ADD(CollectorStats::process_lineage_string_total, string_total); } -void SensorClientFormatter::GetProcessLineage(sinsp_threadinfo* tinfo, - std::vector& lineage) { +std::vector SensorClientFormatter::GetProcessLineage(sinsp_threadinfo* tinfo) { + std::vector lineage; if (tinfo == nullptr) { - return; + return lineage; } - sinsp_threadinfo* mt = nullptr; - if (tinfo->is_main_thread()) { - mt = tinfo; - } else { - mt = tinfo->get_main_thread(); - if (mt == nullptr) { - return; - } + + sinsp_threadinfo* mt = tinfo->get_main_thread(); + if (mt == nullptr) { + return lineage; } + sinsp_threadinfo::visitor_func_t visitor = [&lineage](sinsp_threadinfo* pt) { if (pt == nullptr) { return false; @@ -332,22 +321,9 @@ void SensorClientFormatter::GetProcessLineage(sinsp_threadinfo* tinfo, return false; } - // // Collection of process lineage information should stop at the container // boundary to avoid collecting host process information. - // - // In back-ported eBPF probes, `m_vpid` will not be set for containers - // running when collector comes online because /proc/{pid}/status does - // not contain namespace information, so `m_container_id` is checked - // instead. `m_container_id` is not enough on its own to identify - // containerized processes, because it is not guaranteed to be set on - // all platforms. - // - if (pt->m_vpid == 0) { - if (pt->m_container_id.empty()) { - return false; - } - } else if (pt->m_pid == pt->m_vpid) { + if (pt->m_pid == pt->m_vpid) { return false; } @@ -371,7 +347,9 @@ void SensorClientFormatter::GetProcessLineage(sinsp_threadinfo* tinfo, return true; }; mt->traverse_parent_state(visitor); - CountLineage(lineage); + UpdateLineageStats(lineage); + + return lineage; } } // namespace collector diff --git a/collector/lib/SensorClientFormatter.h b/collector/lib/SensorClientFormatter.h index aba932b74b..ab4ad66fe5 100644 --- a/collector/lib/SensorClientFormatter.h +++ b/collector/lib/SensorClientFormatter.h @@ -41,22 +41,68 @@ class SensorClientFormatter : public ProtoSignalFormatter& lineage); + /** + * Get the list of processes that spawned the current one. + * + * The list will be limited to processes inside the same container as + * the one being processed. + * + * @param tinfo The sinsp_threadinfo for which we should generate + * lineage. + * @returns A vector with the lineage information. + */ + static std::vector GetProcessLineage(sinsp_threadinfo* tinfo); private: FRIEND_TEST(SensorClientFormatterTest, NoProcessArguments); FRIEND_TEST(SensorClientFormatterTest, ProcessArguments); + /** + * Allocate and fill in a ProcessSignal message. + * + * @param event A Falco event to be translated into a ProcessSignal. + * @returns A non-owning pointer to the ProcessSignal. + */ ProcessSignal* CreateProcessSignal(sinsp_evt* event); - Signal* CreateSignal(sinsp_evt* event); + + /** + * Check if the provided threadinfo has the required fields. + * + * @param tinfo the Falco threadinfo to validate. + * @returns true if the threadinfo is valid, false otherwise. + */ bool ValidateProcessDetails(const sinsp_threadinfo* tinfo); + + /** + * Check if the provided event has the required fields. + * + * @param event the Falco event to validate. + * @returns true if the threadinfo is valid, false otherwise. + */ bool ValidateProcessDetails(sinsp_evt* event); - std::string ProcessDetails(sinsp_evt* event); - Signal* CreateSignal(sinsp_threadinfo* tinfo); + /** + * Translate a Falco event to a printable string. + * + * @param event The Falco event to be translated. + * @returns A printable string. + */ + std::string ToString(sinsp_evt* event); + + /** + * Allocate and fill in a ProcessSignal message. + * + * @param tinfo A Falco threadinfo to be translated into a ProcessSignal. + * @returns A non-owning pointer to the ProcessSignal. + */ ProcessSignal* CreateProcessSignal(sinsp_threadinfo* tinfo); - int GetTotalStringLength(const std::vector& lineage); - void CountLineage(const std::vector& lineage); + + /** + * Update lineage related prometheus stats. + * + * @param lineage The lineage used for updating the stats. + */ + static void UpdateLineageStats(const std::vector& lineage); const EventNames& event_names_; std::unique_ptr event_extractor_; diff --git a/collector/lib/SignalServiceClient.h b/collector/lib/SignalServiceClient.h index 2a1b65f66f..7013650d9e 100644 --- a/collector/lib/SignalServiceClient.h +++ b/collector/lib/SignalServiceClient.h @@ -60,7 +60,7 @@ class SignalServiceClient : public ISignalServiceClient { std::unique_ptr context_; std::unique_ptr> writer_; - bool first_write_{}; + bool first_write_ = false; }; class StdoutSignalServiceClient : public ISignalServiceClient { diff --git a/collector/test/SensorClientFormatterTest.cpp b/collector/test/SensorClientFormatterTest.cpp index 57c19c63e6..4b62573081 100644 --- a/collector/test/SensorClientFormatterTest.cpp +++ b/collector/test/SensorClientFormatterTest.cpp @@ -23,10 +23,8 @@ struct ThreadInfoParams { std::string exepath; }; -static void ExpectStatsCounter(size_t index, long expected) { - auto value = CollectorStats::GetOrCreate().GetCounter(index); - EXPECT_EQ(value, expected); -} +#define EXPECT_STATS_COUNTER(index, expected) \ + EXPECT_EQ(CollectorStats::GetOrCreate().GetCounter(index), expected) class SensorClientFormatterTest : public testing::Test { public: @@ -53,14 +51,12 @@ class SensorClientFormatterTest : public testing::Test { TEST_F(SensorClientFormatterTest, NoProcessTest) { sinsp_threadinfo* tinfo = nullptr; - std::vector lineage; - - formatter.GetProcessLineage(tinfo, lineage); + auto lineage = SensorClientFormatter::GetProcessLineage(tinfo); - ExpectStatsCounter(CollectorStats::process_lineage_counts, 0); - ExpectStatsCounter(CollectorStats::process_lineage_total, 0); - ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 0); - ExpectStatsCounter(CollectorStats::process_lineage_string_total, 0); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_counts, 0); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_total, 0); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_sqr_total, 0); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_string_total, 0); EXPECT_TRUE(lineage.empty()); } @@ -68,14 +64,12 @@ TEST_F(SensorClientFormatterTest, NoProcessTest) { TEST_F(SensorClientFormatterTest, ProcessWithoutParentTest) { // {pid, tid, ptid, vpid, uid, container_id, exepath}, inspector->add_thread(build_threadinfo({0, 0, -1, 2, 7, "", "qwerty"})); - std::vector lineage; - - formatter.GetProcessLineage(inspector->get_thread_ref(0).get(), lineage); + auto lineage = SensorClientFormatter::GetProcessLineage(inspector->get_thread_ref(0).get()); - ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); - ExpectStatsCounter(CollectorStats::process_lineage_total, 0); - ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 0); - ExpectStatsCounter(CollectorStats::process_lineage_string_total, 0); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_counts, 1); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_total, 0); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_sqr_total, 0); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_string_total, 0); EXPECT_TRUE(lineage.empty()); @@ -93,13 +87,12 @@ TEST_F(SensorClientFormatterTest, ProcessWithParentTest) { inspector->add_thread(build_threadinfo(params)); } - std::vector lineage; - formatter.GetProcessLineage(inspector->get_thread_ref(1).get(), lineage); + auto lineage = SensorClientFormatter::GetProcessLineage(inspector->get_thread_ref(1).get()); - ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); - ExpectStatsCounter(CollectorStats::process_lineage_total, 1); - ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 1); - ExpectStatsCounter(CollectorStats::process_lineage_string_total, 4); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_counts, 1); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_total, 1); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_sqr_total, 1); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_string_total, 4); EXPECT_EQ(lineage.size(), 1); @@ -120,13 +113,12 @@ TEST_F(SensorClientFormatterTest, ProcessWithParentWithPid0Test) { inspector->add_thread(build_threadinfo(params)); } - std::vector lineage; - formatter.GetProcessLineage(inspector->get_thread_ref(1).get(), lineage); + auto lineage = SensorClientFormatter::GetProcessLineage(inspector->get_thread_ref(1).get()); - ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); - ExpectStatsCounter(CollectorStats::process_lineage_total, 0); - ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 0); - ExpectStatsCounter(CollectorStats::process_lineage_string_total, 0); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_counts, 1); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_total, 0); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_sqr_total, 0); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_string_total, 0); EXPECT_TRUE(lineage.empty()); @@ -144,13 +136,12 @@ TEST_F(SensorClientFormatterTest, ProcessWithParentWithSameNameTest) { inspector->add_thread(build_threadinfo(params)); } - std::vector lineage; - formatter.GetProcessLineage(inspector->get_thread_ref(1).get(), lineage); + auto lineage = SensorClientFormatter::GetProcessLineage(inspector->get_thread_ref(1).get()); - ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); - ExpectStatsCounter(CollectorStats::process_lineage_total, 1); - ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 1); - ExpectStatsCounter(CollectorStats::process_lineage_string_total, 4); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_counts, 1); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_total, 1); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_sqr_total, 1); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_string_total, 4); EXPECT_EQ(lineage.size(), 1); @@ -172,13 +163,12 @@ TEST_F(SensorClientFormatterTest, ProcessWithTwoParentsTest) { inspector->add_thread(build_threadinfo(params)); } - std::vector lineage; - formatter.GetProcessLineage(inspector->get_thread_ref(4).get(), lineage); + auto lineage = SensorClientFormatter::GetProcessLineage(inspector->get_thread_ref(4).get()); - ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); - ExpectStatsCounter(CollectorStats::process_lineage_total, 2); - ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 4); - ExpectStatsCounter(CollectorStats::process_lineage_string_total, 10); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_counts, 1); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_total, 2); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_sqr_total, 4); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_string_total, 10); EXPECT_EQ(lineage.size(), 2); @@ -203,13 +193,12 @@ TEST_F(SensorClientFormatterTest, ProcessWithTwoParentsWithTheSameNameTest) { inspector->add_thread(build_threadinfo(params)); } - std::vector lineage; - formatter.GetProcessLineage(inspector->get_thread_ref(4).get(), lineage); + auto lineage = SensorClientFormatter::GetProcessLineage(inspector->get_thread_ref(4).get()); - ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); - ExpectStatsCounter(CollectorStats::process_lineage_total, 1); - ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 1); - ExpectStatsCounter(CollectorStats::process_lineage_string_total, 4); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_counts, 1); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_total, 1); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_sqr_total, 1); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_string_total, 4); EXPECT_EQ(lineage.size(), 1); @@ -232,13 +221,12 @@ TEST_F(SensorClientFormatterTest, ProcessCollapseParentChildWithSameNameTest) { inspector->add_thread(build_threadinfo(params)); } - std::vector lineage; - formatter.GetProcessLineage(inspector->get_thread_ref(5).get(), lineage); + auto lineage = SensorClientFormatter::GetProcessLineage(inspector->get_thread_ref(5).get()); - ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); - ExpectStatsCounter(CollectorStats::process_lineage_total, 1); - ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 1); - ExpectStatsCounter(CollectorStats::process_lineage_string_total, 4); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_counts, 1); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_total, 1); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_sqr_total, 1); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_string_total, 4); EXPECT_EQ(lineage.size(), 1); @@ -260,13 +248,12 @@ TEST_F(SensorClientFormatterTest, ProcessCollapseParentChildWithSameName2Test) { for (const auto& params : tinfo_params) { inspector->add_thread(build_threadinfo(params)); } - std::vector lineage; - formatter.GetProcessLineage(inspector->get_thread_ref(5).get(), lineage); + auto lineage = SensorClientFormatter::GetProcessLineage(inspector->get_thread_ref(5).get()); - ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); - ExpectStatsCounter(CollectorStats::process_lineage_total, 2); - ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 4); - ExpectStatsCounter(CollectorStats::process_lineage_string_total, 10); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_counts, 1); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_total, 2); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_sqr_total, 4); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_string_total, 10); EXPECT_EQ(lineage.size(), 2); @@ -292,13 +279,12 @@ TEST_F(SensorClientFormatterTest, ProcessWithUnrelatedProcessTest) { inspector->add_thread(build_threadinfo(params)); } - std::vector lineage; - formatter.GetProcessLineage(inspector->get_thread_ref(4).get(), lineage); + auto lineage = SensorClientFormatter::GetProcessLineage(inspector->get_thread_ref(4).get()); - ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); - ExpectStatsCounter(CollectorStats::process_lineage_total, 2); - ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 4); - ExpectStatsCounter(CollectorStats::process_lineage_string_total, 10); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_counts, 1); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_total, 2); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_sqr_total, 4); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_string_total, 10); EXPECT_EQ(lineage.size(), 2); @@ -312,57 +298,24 @@ TEST_F(SensorClientFormatterTest, ProcessWithUnrelatedProcessTest) { } TEST_F(SensorClientFormatterTest, CountTwoCounterCallsTest) { - std::vector lineage; - std::vector lineage2; - // {pid, tid, ptid, vpid, uid, container_id, exepath}, inspector->add_thread(build_threadinfo({1, 1, 555, 10, 9, "", "jkl;"})); - - formatter.GetProcessLineage(inspector->get_thread_ref(1).get(), lineage); + auto lineage = SensorClientFormatter::GetProcessLineage(inspector->get_thread_ref(1).get()); // {pid, tid, ptid, vpid, uid, container_id, exepath}, inspector->add_thread(build_threadinfo({2, 2, 555, 10, 9, "", "jkl;"})); + auto lineage2 = SensorClientFormatter::GetProcessLineage(inspector->get_thread_ref(2).get()); - formatter.GetProcessLineage(inspector->get_thread_ref(2).get(), lineage2); - - ExpectStatsCounter(CollectorStats::process_lineage_counts, 2); - ExpectStatsCounter(CollectorStats::process_lineage_total, 0); - ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 0); - ExpectStatsCounter(CollectorStats::process_lineage_string_total, 0); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_counts, 2); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_total, 0); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_sqr_total, 0); + EXPECT_STATS_COUNTER(CollectorStats::process_lineage_string_total, 0); EXPECT_TRUE(lineage2.empty()); CollectorStats::Reset(); } -TEST_F(SensorClientFormatterTest, Rox3377ProcessLineageWithNoVPidTest) { - // {pid, tid, ptid, vpid, uid, container_id, exepath}, - std::vector tinfo_params = { - {3, 3, -1, 0, 42, "", "qwerty"}, - {1, 1, 3, 0, 7, "id", "asdf"}, - {4, 4, 1, 0, 8, "id", "uiop"}, - }; - - for (const auto& params : tinfo_params) { - inspector->add_thread(build_threadinfo(params)); - } - - std::vector lineage; - formatter.GetProcessLineage(inspector->get_thread_ref(4).get(), lineage); - - ExpectStatsCounter(CollectorStats::process_lineage_counts, 1); - ExpectStatsCounter(CollectorStats::process_lineage_total, 1); - ExpectStatsCounter(CollectorStats::process_lineage_sqr_total, 1); - ExpectStatsCounter(CollectorStats::process_lineage_string_total, 4); - - EXPECT_EQ(lineage.size(), 1); - - EXPECT_EQ(lineage[0].parent_uid(), 7); - EXPECT_EQ(lineage[0].parent_exec_file_path(), "asdf"); - - CollectorStats::Reset(); -} - TEST_F(SensorClientFormatterTest, ProcessArguments) { // {pid, tid, ptid, vpid, uid, container_id, exepath}, auto tinfo = build_threadinfo({3, 3, -1, 0, 42, "", "qwerty"}); From 055f3a57a25da82ead8b1de059aa958c7f17a97f Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Fri, 4 Apr 2025 13:01:18 +0200 Subject: [PATCH 12/14] Minor cleanup --- collector/lib/SensorClientFormatter.cpp | 15 ++++++------- collector/test/SensorClientFormatterTest.cpp | 22 ++------------------ 2 files changed, 8 insertions(+), 29 deletions(-) diff --git a/collector/lib/SensorClientFormatter.cpp b/collector/lib/SensorClientFormatter.cpp index 9db4a28d07..a0756f77f5 100644 --- a/collector/lib/SensorClientFormatter.cpp +++ b/collector/lib/SensorClientFormatter.cpp @@ -57,12 +57,11 @@ std::string extract_proc_args(sinsp_threadinfo* tinfo) { } // namespace -SensorClientFormatter::SensorClientFormatter( - sinsp* inspector, - const CollectorConfig& config) : event_names_(EventNames::GetInstance()), - event_extractor_(std::make_unique()), - container_metadata_(inspector), - config_(config) { +SensorClientFormatter::SensorClientFormatter(sinsp* inspector, const CollectorConfig& config) + : event_names_(EventNames::GetInstance()), + event_extractor_(std::make_unique()), + container_metadata_(inspector), + config_(config) { event_extractor_->Init(inspector); } @@ -286,9 +285,7 @@ bool SensorClientFormatter::ValidateProcessDetails(const sinsp_threadinfo* tinfo } bool SensorClientFormatter::ValidateProcessDetails(sinsp_evt* event) { - const sinsp_threadinfo* tinfo = event->get_thread_info(); - - return ValidateProcessDetails(tinfo); + return ValidateProcessDetails(event->get_thread_info()); } void SensorClientFormatter::UpdateLineageStats(const std::vector& lineage) { diff --git a/collector/test/SensorClientFormatterTest.cpp b/collector/test/SensorClientFormatterTest.cpp index 4b62573081..b49ab965d8 100644 --- a/collector/test/SensorClientFormatterTest.cpp +++ b/collector/test/SensorClientFormatterTest.cpp @@ -31,6 +31,8 @@ class SensorClientFormatterTest : public testing::Test { SensorClientFormatterTest() : inspector(new sinsp()), formatter(inspector.get(), config) { } + ~SensorClientFormatterTest() override { CollectorStats::Reset(); } + protected: std::unique_ptr build_threadinfo(const ThreadInfoParams& params) { auto tinfo = inspector->build_threadinfo(); @@ -72,8 +74,6 @@ TEST_F(SensorClientFormatterTest, ProcessWithoutParentTest) { EXPECT_STATS_COUNTER(CollectorStats::process_lineage_string_total, 0); EXPECT_TRUE(lineage.empty()); - - CollectorStats::Reset(); } TEST_F(SensorClientFormatterTest, ProcessWithParentTest) { @@ -98,8 +98,6 @@ TEST_F(SensorClientFormatterTest, ProcessWithParentTest) { EXPECT_EQ(lineage[0].parent_uid(), 42); EXPECT_EQ(lineage[0].parent_exec_file_path(), "asdf"); - - CollectorStats::Reset(); } TEST_F(SensorClientFormatterTest, ProcessWithParentWithPid0Test) { @@ -121,8 +119,6 @@ TEST_F(SensorClientFormatterTest, ProcessWithParentWithPid0Test) { EXPECT_STATS_COUNTER(CollectorStats::process_lineage_string_total, 0); EXPECT_TRUE(lineage.empty()); - - CollectorStats::Reset(); } TEST_F(SensorClientFormatterTest, ProcessWithParentWithSameNameTest) { @@ -147,8 +143,6 @@ TEST_F(SensorClientFormatterTest, ProcessWithParentWithSameNameTest) { EXPECT_EQ(lineage[0].parent_uid(), 43); EXPECT_EQ(lineage[0].parent_exec_file_path(), "asdf"); - - CollectorStats::Reset(); } TEST_F(SensorClientFormatterTest, ProcessWithTwoParentsTest) { @@ -177,8 +171,6 @@ TEST_F(SensorClientFormatterTest, ProcessWithTwoParentsTest) { EXPECT_EQ(lineage[1].parent_uid(), 42); EXPECT_EQ(lineage[1].parent_exec_file_path(), "asdf"); - - CollectorStats::Reset(); } TEST_F(SensorClientFormatterTest, ProcessWithTwoParentsWithTheSameNameTest) { @@ -204,8 +196,6 @@ TEST_F(SensorClientFormatterTest, ProcessWithTwoParentsWithTheSameNameTest) { EXPECT_EQ(lineage[0].parent_uid(), 7); EXPECT_EQ(lineage[0].parent_exec_file_path(), "asdf"); - - CollectorStats::Reset(); } TEST_F(SensorClientFormatterTest, ProcessCollapseParentChildWithSameNameTest) { @@ -232,8 +222,6 @@ TEST_F(SensorClientFormatterTest, ProcessCollapseParentChildWithSameNameTest) { EXPECT_EQ(lineage[0].parent_uid(), 8); EXPECT_EQ(lineage[0].parent_exec_file_path(), "asdf"); - - CollectorStats::Reset(); } TEST_F(SensorClientFormatterTest, ProcessCollapseParentChildWithSameName2Test) { @@ -262,8 +250,6 @@ TEST_F(SensorClientFormatterTest, ProcessCollapseParentChildWithSameName2Test) { EXPECT_EQ(lineage[1].parent_uid(), 42); EXPECT_EQ(lineage[1].parent_exec_file_path(), "qwerty"); - - CollectorStats::Reset(); } TEST_F(SensorClientFormatterTest, ProcessWithUnrelatedProcessTest) { @@ -293,8 +279,6 @@ TEST_F(SensorClientFormatterTest, ProcessWithUnrelatedProcessTest) { EXPECT_EQ(lineage[1].parent_uid(), 42); EXPECT_EQ(lineage[1].parent_exec_file_path(), "qwerty"); - - CollectorStats::Reset(); } TEST_F(SensorClientFormatterTest, CountTwoCounterCallsTest) { @@ -312,8 +296,6 @@ TEST_F(SensorClientFormatterTest, CountTwoCounterCallsTest) { EXPECT_STATS_COUNTER(CollectorStats::process_lineage_string_total, 0); EXPECT_TRUE(lineage2.empty()); - - CollectorStats::Reset(); } TEST_F(SensorClientFormatterTest, ProcessArguments) { From c411fe1203e3775a101e0c1041fde5873c2b28a0 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Mon, 7 Apr 2025 16:09:11 +0200 Subject: [PATCH 13/14] Rename Refresh to Recreate --- collector/lib/CollectorOutput.cpp | 4 ++-- collector/lib/CollectorOutput.h | 1 + collector/lib/SensorClient.cpp | 2 +- collector/lib/SensorClient.h | 8 +++----- collector/lib/SignalServiceClient.cpp | 2 +- collector/lib/SignalServiceClient.h | 10 +++------- collector/test/CollectorOutputTest.cpp | 4 ++-- 7 files changed, 13 insertions(+), 18 deletions(-) diff --git a/collector/lib/CollectorOutput.cpp b/collector/lib/CollectorOutput.cpp index 5faaf044b4..6ac9392caa 100644 --- a/collector/lib/CollectorOutput.cpp +++ b/collector/lib/CollectorOutput.cpp @@ -122,11 +122,11 @@ bool CollectorOutput::EstablishGrpcStreamSingle() { // Refresh all clients bool success = true; for (const auto& client : signal_clients_) { - success &= client->Refresh(); + success &= client->Recreate(); } for (const auto& client : sensor_clients_) { - success &= client->Refresh(); + success &= client->Recreate(); } if (success) { diff --git a/collector/lib/CollectorOutput.h b/collector/lib/CollectorOutput.h index 2472689ee5..baa9a518b6 100644 --- a/collector/lib/CollectorOutput.h +++ b/collector/lib/CollectorOutput.h @@ -10,6 +10,7 @@ #include "SensorClient.h" #include "SignalHandler.h" #include "SignalServiceClient.h" +#include "StoppableThread.h" namespace collector { diff --git a/collector/lib/SensorClient.cpp b/collector/lib/SensorClient.cpp index a564c56ddb..3420162ec2 100644 --- a/collector/lib/SensorClient.cpp +++ b/collector/lib/SensorClient.cpp @@ -3,7 +3,7 @@ #include "Logging.h" namespace collector { -bool SensorClient::Refresh() { +bool SensorClient::Recreate() { context_ = std::make_unique(); writer_ = DuplexClient::CreateWithReadsIgnored(&sensor::CollectorService::Stub::AsyncCommunicate, channel_, context_.get()); if (!writer_->WaitUntilStarted(std::chrono::seconds(30))) { diff --git a/collector/lib/SensorClient.h b/collector/lib/SensorClient.h index 46aca7d6a3..9865ec60be 100644 --- a/collector/lib/SensorClient.h +++ b/collector/lib/SensorClient.h @@ -1,7 +1,6 @@ #ifndef _SENSOR_CLIENT_H_ #define _SENSOR_CLIENT_H_ -#include #include #include @@ -11,7 +10,6 @@ #include "DuplexGRPC.h" #include "SignalHandler.h" -#include "StoppableThread.h" namespace collector { @@ -33,7 +31,7 @@ class ISensorClient { * * @returns true if the refresh was succesful, false otherwise. */ - virtual bool Refresh() = 0; + virtual bool Recreate() = 0; /** * Send a message to sensor through the iservice. @@ -61,7 +59,7 @@ class SensorClient : public ISensorClient { : channel_(std::move(channel)) { } - bool Refresh() override; + bool Recreate() override; SignalHandler::Result SendMsg(const sensor::MsgFromCollector& msg) override; @@ -78,7 +76,7 @@ class SensorClient : public ISensorClient { }; class SensorClientStdout : public ISensorClient { - bool Refresh() override { return true; } + bool Recreate() override { return true; } SignalHandler::Result SendMsg(const sensor::MsgFromCollector& msg) override { LogProtobufMessage(msg); diff --git a/collector/lib/SignalServiceClient.cpp b/collector/lib/SignalServiceClient.cpp index 819b0e6d5d..6ae2abd8c2 100644 --- a/collector/lib/SignalServiceClient.cpp +++ b/collector/lib/SignalServiceClient.cpp @@ -5,7 +5,7 @@ namespace collector { -bool SignalServiceClient::Refresh() { +bool SignalServiceClient::Recreate() { context_ = std::make_unique(); writer_ = DuplexClient::CreateWithReadsIgnored(&SignalService::Stub::AsyncPushSignals, channel_, context_.get()); if (!writer_->WaitUntilStarted(std::chrono::seconds(30))) { diff --git a/collector/lib/SignalServiceClient.h b/collector/lib/SignalServiceClient.h index 7013650d9e..07b41e2726 100644 --- a/collector/lib/SignalServiceClient.h +++ b/collector/lib/SignalServiceClient.h @@ -3,18 +3,14 @@ // SIGNAL_SERVICE_CLIENT.h // This class defines our GRPC client abstraction -#include - #include #include #include -#include "api/v1/signal.pb.h" #include "internalapi/sensor/signal_iservice.grpc.pb.h" #include "DuplexGRPC.h" #include "SignalHandler.h" -#include "StoppableThread.h" namespace collector { @@ -22,7 +18,7 @@ class ISignalServiceClient { public: using SignalStreamMessage = sensor::SignalStreamMessage; - virtual bool Refresh() = 0; + virtual bool Recreate() = 0; virtual SignalHandler::Result PushSignals(const SignalStreamMessage& msg) = 0; virtual ~ISignalServiceClient() = default; @@ -44,7 +40,7 @@ class SignalServiceClient : public ISignalServiceClient { explicit SignalServiceClient(std::shared_ptr channel) : channel_(std::move(channel)), stream_active_(false) {} - bool Refresh() override; + bool Recreate() override; SignalHandler::Result PushSignals(const SignalStreamMessage& msg) override; @@ -69,7 +65,7 @@ class StdoutSignalServiceClient : public ISignalServiceClient { explicit StdoutSignalServiceClient() = default; - bool Refresh() override { return true; } + bool Recreate() override { return true; } SignalHandler::Result PushSignals(const SignalStreamMessage& msg) override; }; diff --git a/collector/test/CollectorOutputTest.cpp b/collector/test/CollectorOutputTest.cpp index 601fdc49e6..92954f2471 100644 --- a/collector/test/CollectorOutputTest.cpp +++ b/collector/test/CollectorOutputTest.cpp @@ -10,13 +10,13 @@ namespace collector { class MockSensorClient : public ISensorClient { public: - MOCK_METHOD(bool, Refresh, ()); + MOCK_METHOD(bool, Recreate, ()); MOCK_METHOD(SignalHandler::Result, SendMsg, (const sensor::MsgFromCollector&)); }; class MockSignalClient : public ISignalServiceClient { public: - MOCK_METHOD(bool, Refresh, ()); + MOCK_METHOD(bool, Recreate, ()); MOCK_METHOD(SignalHandler::Result, PushSignals, (const sensor::SignalStreamMessage&)); }; From a1d1772c596060d87b72c8189e09e8df045d9191 Mon Sep 17 00:00:00 2001 From: Mauro Ezequiel Moltrasio Date: Wed, 23 Apr 2025 18:24:02 +0200 Subject: [PATCH 14/14] Use pragma once on new header files --- collector/lib/CollectorOutput.h | 5 +---- collector/lib/SensorClient.h | 5 +---- collector/lib/SensorClientFormatter.h | 5 +---- 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/collector/lib/CollectorOutput.h b/collector/lib/CollectorOutput.h index baa9a518b6..1546c29ee2 100644 --- a/collector/lib/CollectorOutput.h +++ b/collector/lib/CollectorOutput.h @@ -1,5 +1,4 @@ -#ifndef COLLECTOR_OUTPUT_H -#define COLLECTOR_OUTPUT_H +#pragma once #include @@ -78,5 +77,3 @@ class CollectorOutput { }; } // namespace collector - -#endif // COLLECTOR_OUTPUT_H diff --git a/collector/lib/SensorClient.h b/collector/lib/SensorClient.h index 9865ec60be..2c04ed3fd2 100644 --- a/collector/lib/SensorClient.h +++ b/collector/lib/SensorClient.h @@ -1,5 +1,4 @@ -#ifndef _SENSOR_CLIENT_H_ -#define _SENSOR_CLIENT_H_ +#pragma once #include @@ -85,5 +84,3 @@ class SensorClientStdout : public ISensorClient { }; } // namespace collector - -#endif //_SENSOR_CLIENT_H_ diff --git a/collector/lib/SensorClientFormatter.h b/collector/lib/SensorClientFormatter.h index ab4ad66fe5..56b3085545 100644 --- a/collector/lib/SensorClientFormatter.h +++ b/collector/lib/SensorClientFormatter.h @@ -1,5 +1,4 @@ -#ifndef SENSOR_CLIENT_FORMATTER_H -#define SENSOR_CLIENT_FORMATTER_H +#pragma once #include @@ -112,5 +111,3 @@ class SensorClientFormatter : public ProtoSignalFormatter