Skip to content

Commit

Permalink
ROX-26516: Collector reads runtime config from configmap (#1878)
Browse files Browse the repository at this point in the history
  • Loading branch information
JoukoVirtanen authored Oct 9, 2024
1 parent 0cbc2f0 commit d108359
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,7 @@
[submodule "third_party/uthash"]
path = builder/third_party/uthash
url = https://github.com/troydhanson/uthash.git
[submodule "builder/third_party/yaml-cpp"]
path = builder/third_party/yaml-cpp
url = https://github.com/jbeder/yaml-cpp.git
branch = master
13 changes: 13 additions & 0 deletions builder/install/10-yaml-cpp.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env bash

set -e

cd third_party/yaml-cpp
cp LICENSE "${LICENSE_DIR}/yaml-cpp-${YAMLCPP_VERSION}"

cmake -B build/ \
-DYAML_CPP_BUILD_CONTRIB=OFF \
-DYAML_CPP_BUILD_TOOLS=OFF \
-DYAML_BUILD_SHARED_LIBS=OFF \
-DYAML_CPP_INSTALL=ON
cmake --build build --target install ${NPROCS:+-j ${NPROCS}}
1 change: 1 addition & 0 deletions builder/install/versions.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ export VALIJSON_VERSION=0.6
export RE2_VERSION=2022-06-01
export GPERFTOOLS_VERSION=2.13
export UTHASH_VERSION=v1.9.8
export YAMLCPP_VERSION=0.8.0
1 change: 1 addition & 0 deletions builder/third_party/yaml-cpp
Submodule yaml-cpp added at f73201
2 changes: 2 additions & 0 deletions collector/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ project(collector-bin)

find_package(Threads)
find_package(CURL REQUIRED)
find_package(yaml-cpp REQUIRED)

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall --std=c++17 -pthread -Wno-deprecated-declarations -fno-omit-frame-pointer -rdynamic")
Expand Down Expand Up @@ -72,6 +73,7 @@ add_definitions(-DASSERT_TO_LOG)
add_subdirectory(lib)

add_executable(collector collector.cpp)
target_link_libraries(collector_lib yaml-cpp)
target_link_libraries(collector collector_lib)

target_link_libraries(collector libprometheus-cpp-pull.a)
Expand Down
53 changes: 53 additions & 0 deletions collector/lib/CollectorConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ PathEnvVar tls_ca_path("ROX_COLLECTOR_TLS_CA");
PathEnvVar tls_client_cert_path("ROX_COLLECTOR_TLS_CLIENT_CERT");
PathEnvVar tls_client_key_path("ROX_COLLECTOR_TLS_CLIENT_KEY");

PathEnvVar config_file("ROX_COLLECTOR_CONFIG_PATH", "/etc/stackrox/runtime_config.yaml");

} // namespace

constexpr bool CollectorConfig::kTurnOffScrape;
Expand Down Expand Up @@ -283,6 +285,7 @@ void CollectorConfig::InitCollectorConfig(CollectorArgs* args) {
HandleAfterglowEnvVars();
HandleConnectionStatsEnvVars();
HandleSinspEnvVars();
HandleConfig(config_file.value());

host_config_ = ProcessHostHeuristics(*this);
}
Expand Down Expand Up @@ -400,6 +403,56 @@ void CollectorConfig::HandleSinspEnvVars() {
}
}

bool CollectorConfig::YamlConfigToConfig(YAML::Node& yamlConfig) {
if (yamlConfig.IsNull() || !yamlConfig.IsDefined()) {
CLOG(FATAL) << "Unable to read config from config file";
return false;
}
YAML::Node networkConnectionConfig = yamlConfig["networkConnectionConfig"];
if (!networkConnectionConfig) {
CLOG(WARNING) << "No networkConnectionConfig in config file";
return false;
}

bool enableExternalIps = false;
if (networkConnectionConfig["enableExternalIps"]) {
enableExternalIps = networkConnectionConfig["enableExternalIps"].as<bool>(false);
}

sensor::CollectorConfig runtime_config;
auto* networkConfig = runtime_config.mutable_network_connection_config();
networkConfig->set_enable_external_ips(enableExternalIps);

SetRuntimeConfig(runtime_config);
CLOG(INFO) << "Runtime configuration:";
CLOG(INFO) << GetRuntimeConfigStr();

return true;
}

void CollectorConfig::HandleConfig(const std::filesystem::path& filePath) {
if (!std::filesystem::exists(filePath)) {
CLOG(DEBUG) << "No configuration file found. " << filePath;
return;
}

try {
YAML::Node yamlConfig = YAML::LoadFile(filePath);
YamlConfigToConfig(yamlConfig);
} catch (const YAML::BadFile& e) {
CLOG(FATAL) << "Failed to open the configuration file: " << filePath
<< ". Error: " << e.what();
} catch (const YAML::ParserException& e) {
CLOG(FATAL) << "Failed to parse the configuration file: " << filePath
<< ". Error: " << e.what();
} catch (const YAML::Exception& e) {
CLOG(FATAL) << "An error occurred while loading the configuration file: " << filePath
<< ". Error: " << e.what();
} catch (const std::exception& e) {
CLOG(FATAL) << "An unexpected error occurred while trying to read: " << filePath << e.what();
}
}

bool CollectorConfig::TurnOffScrape() const {
return turn_off_scrape_;
}
Expand Down
11 changes: 11 additions & 0 deletions collector/lib/CollectorConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <vector>

#include <json/json.h>
#include <yaml-cpp/yaml.h>

#include <grpcpp/channel.h>

Expand Down Expand Up @@ -99,6 +100,14 @@ class CollectorConfig {
return enable_external_ips_;
}

std::string GetRuntimeConfigStr() {
if (runtime_config_.has_value()) {
const auto& cfg = runtime_config_.value();
return cfg.DebugString();
}
return "{}";
}

bool EnableConnectionStats() const { return enable_connection_stats_; }
bool EnableDetailedMetrics() const { return enable_detailed_metrics_; }
bool EnableRuntimeConfig() const { return enable_runtime_config_; }
Expand Down Expand Up @@ -188,6 +197,8 @@ class CollectorConfig {
void HandleAfterglowEnvVars();
void HandleConnectionStatsEnvVars();
void HandleSinspEnvVars();
bool YamlConfigToConfig(YAML::Node& yamlConfig);
void HandleConfig(const std::filesystem::path& filePath);

// Protected, used for testing purposes
void SetSinspBufferSize(unsigned int buffer_size);
Expand Down
71 changes: 71 additions & 0 deletions collector/test/CollectorConfigTest.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include <optional>

#include <internalapi/sensor/collector.pb.h>

#include "CollectorArgs.h"
#include "CollectorConfig.h"
#include "gmock/gmock.h"
Expand Down Expand Up @@ -32,6 +34,10 @@ class MockCollectorConfig : public CollectorConfig {
void MockSetEnableExternalIPs(bool value) {
SetEnableExternalIPs(value);
}

bool MockYamlConfigToConfig(YAML::Node& yamlConfig) {
return YamlConfigToConfig(yamlConfig);
}
};

// Test that unmodified value is returned, when some dependency values are
Expand Down Expand Up @@ -145,4 +151,69 @@ TEST(CollectorConfigTest, TestEnableExternalIpsRuntimeConfig) {
EXPECT_TRUE(config.EnableExternalIPs());
}

TEST(CollectorConfigTest, TestYamlConfigToConfigMultiple) {
std::vector<std::pair<std::string, bool>> tests = {
{R"(
networkConnectionConfig:
enableExternalIps: true
)",
true},
{R"(
networkConnectionConfig:
enableExternalIps: false
)",
false},
{R"(
networkConnectionConfig:
)",
false},
{R"(
networkConnectionConfig:
unknownField: asdf
)",
false}};

for (const auto& [yamlStr, expected] : tests) {
YAML::Node yamlNode = YAML::Load(yamlStr);

MockCollectorConfig config;

bool result = config.MockYamlConfigToConfig(yamlNode);
auto runtime_config = config.GetRuntimeConfig();

EXPECT_TRUE(result);
EXPECT_TRUE(runtime_config.has_value());

const auto& cfg = runtime_config.value();
const auto& network_cfg = cfg.network_connection_config();
EXPECT_EQ(network_cfg.enable_external_ips(), expected);
EXPECT_EQ(config.EnableExternalIPs(), expected);
}
}

TEST(CollectorConfigTest, TestYamlConfigToConfigInvalid) {
std::string yamlStr = R"(
unknownField: asdf
)";

YAML::Node yamlNode = YAML::Load(yamlStr);

MockCollectorConfig config;

bool result = config.MockYamlConfigToConfig(yamlNode);
auto runtime_config = config.GetRuntimeConfig();

EXPECT_FALSE(result);
EXPECT_FALSE(runtime_config.has_value());
}

TEST(CollectorConfigTest, TestYamlConfigToConfigEmpty) {
std::string yamlStr = R"()";
YAML::Node yamlNode = YAML::Load(yamlStr);

MockCollectorConfig config;

EXPECT_DEATH({ config.MockYamlConfigToConfig(yamlNode); }, ".*");
}

} // namespace collector
31 changes: 31 additions & 0 deletions docs/references.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ internal state of Collector. Refer to the
[troubleshooting](troubleshooting.md#introspection-endpoints) section for more details.
The default is false.

* `ROX_ENABLE_EXTERNAL_IPS`: Enables or disables the external IPs feature.

NOTE: Using environment variables is a preferred way of configuring Collector,
so if you're adding a new configuration knob, keep this in mind.

Expand All @@ -104,6 +106,35 @@ seconds. The default value is 30 seconds.

* `logLevel`: Sets logging level. The default is INFO.

### File mount or ConfigMap

The external IPs feature can be enabled or disabled using a file or ConfigMap. This is an optional
method and does not have to be used. This file overwites the ENABLE_EXTERNAL_IPS feature flag.
When using collector by itself a file can be mounted to it at /etc/stackrox/runtime_config.yaml. The
following is an example of the contents

```
networkConnectionConfig:
enableExternalIps: true
```

Alternatively, if collector is used as a part of Stackrox, the configuration can be set
using a ConfigMap. The following is an example of such a ConfigMap.

```
apiVersion: v1
kind: ConfigMap
metadata:
name: collector-config
namespace: stackrox
data:
runtime_config.yaml: |
networkConnectionConfig:
enableExternalIps: true
```

The file path can be set using the `ROX_COLLECTOR_CONFIG_PATH` environment variable.

### Other arguments

* `--collection-method`: Which technology to use for data gathering. Either
Expand Down

0 comments on commit d108359

Please sign in to comment.