Skip to content

Commit d108359

Browse files
ROX-26516: Collector reads runtime config from configmap (#1878)
1 parent 0cbc2f0 commit d108359

File tree

9 files changed

+187
-0
lines changed

9 files changed

+187
-0
lines changed

.gitmodules

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,7 @@
6060
[submodule "third_party/uthash"]
6161
path = builder/third_party/uthash
6262
url = https://github.com/troydhanson/uthash.git
63+
[submodule "builder/third_party/yaml-cpp"]
64+
path = builder/third_party/yaml-cpp
65+
url = https://github.com/jbeder/yaml-cpp.git
66+
branch = master

builder/install/10-yaml-cpp.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
#!/usr/bin/env bash
2+
3+
set -e
4+
5+
cd third_party/yaml-cpp
6+
cp LICENSE "${LICENSE_DIR}/yaml-cpp-${YAMLCPP_VERSION}"
7+
8+
cmake -B build/ \
9+
-DYAML_CPP_BUILD_CONTRIB=OFF \
10+
-DYAML_CPP_BUILD_TOOLS=OFF \
11+
-DYAML_BUILD_SHARED_LIBS=OFF \
12+
-DYAML_CPP_INSTALL=ON
13+
cmake --build build --target install ${NPROCS:+-j ${NPROCS}}

builder/install/versions.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ export VALIJSON_VERSION=0.6
1818
export RE2_VERSION=2022-06-01
1919
export GPERFTOOLS_VERSION=2.13
2020
export UTHASH_VERSION=v1.9.8
21+
export YAMLCPP_VERSION=0.8.0

builder/third_party/yaml-cpp

Submodule yaml-cpp added at f732014

collector/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ project(collector-bin)
22

33
find_package(Threads)
44
find_package(CURL REQUIRED)
5+
find_package(yaml-cpp REQUIRED)
56

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

7475
add_executable(collector collector.cpp)
76+
target_link_libraries(collector_lib yaml-cpp)
7577
target_link_libraries(collector collector_lib)
7678

7779
target_link_libraries(collector libprometheus-cpp-pull.a)

collector/lib/CollectorConfig.cpp

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ PathEnvVar tls_ca_path("ROX_COLLECTOR_TLS_CA");
7777
PathEnvVar tls_client_cert_path("ROX_COLLECTOR_TLS_CLIENT_CERT");
7878
PathEnvVar tls_client_key_path("ROX_COLLECTOR_TLS_CLIENT_KEY");
7979

80+
PathEnvVar config_file("ROX_COLLECTOR_CONFIG_PATH", "/etc/stackrox/runtime_config.yaml");
81+
8082
} // namespace
8183

8284
constexpr bool CollectorConfig::kTurnOffScrape;
@@ -283,6 +285,7 @@ void CollectorConfig::InitCollectorConfig(CollectorArgs* args) {
283285
HandleAfterglowEnvVars();
284286
HandleConnectionStatsEnvVars();
285287
HandleSinspEnvVars();
288+
HandleConfig(config_file.value());
286289

287290
host_config_ = ProcessHostHeuristics(*this);
288291
}
@@ -400,6 +403,56 @@ void CollectorConfig::HandleSinspEnvVars() {
400403
}
401404
}
402405

406+
bool CollectorConfig::YamlConfigToConfig(YAML::Node& yamlConfig) {
407+
if (yamlConfig.IsNull() || !yamlConfig.IsDefined()) {
408+
CLOG(FATAL) << "Unable to read config from config file";
409+
return false;
410+
}
411+
YAML::Node networkConnectionConfig = yamlConfig["networkConnectionConfig"];
412+
if (!networkConnectionConfig) {
413+
CLOG(WARNING) << "No networkConnectionConfig in config file";
414+
return false;
415+
}
416+
417+
bool enableExternalIps = false;
418+
if (networkConnectionConfig["enableExternalIps"]) {
419+
enableExternalIps = networkConnectionConfig["enableExternalIps"].as<bool>(false);
420+
}
421+
422+
sensor::CollectorConfig runtime_config;
423+
auto* networkConfig = runtime_config.mutable_network_connection_config();
424+
networkConfig->set_enable_external_ips(enableExternalIps);
425+
426+
SetRuntimeConfig(runtime_config);
427+
CLOG(INFO) << "Runtime configuration:";
428+
CLOG(INFO) << GetRuntimeConfigStr();
429+
430+
return true;
431+
}
432+
433+
void CollectorConfig::HandleConfig(const std::filesystem::path& filePath) {
434+
if (!std::filesystem::exists(filePath)) {
435+
CLOG(DEBUG) << "No configuration file found. " << filePath;
436+
return;
437+
}
438+
439+
try {
440+
YAML::Node yamlConfig = YAML::LoadFile(filePath);
441+
YamlConfigToConfig(yamlConfig);
442+
} catch (const YAML::BadFile& e) {
443+
CLOG(FATAL) << "Failed to open the configuration file: " << filePath
444+
<< ". Error: " << e.what();
445+
} catch (const YAML::ParserException& e) {
446+
CLOG(FATAL) << "Failed to parse the configuration file: " << filePath
447+
<< ". Error: " << e.what();
448+
} catch (const YAML::Exception& e) {
449+
CLOG(FATAL) << "An error occurred while loading the configuration file: " << filePath
450+
<< ". Error: " << e.what();
451+
} catch (const std::exception& e) {
452+
CLOG(FATAL) << "An unexpected error occurred while trying to read: " << filePath << e.what();
453+
}
454+
}
455+
403456
bool CollectorConfig::TurnOffScrape() const {
404457
return turn_off_scrape_;
405458
}

collector/lib/CollectorConfig.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <vector>
77

88
#include <json/json.h>
9+
#include <yaml-cpp/yaml.h>
910

1011
#include <grpcpp/channel.h>
1112

@@ -99,6 +100,14 @@ class CollectorConfig {
99100
return enable_external_ips_;
100101
}
101102

103+
std::string GetRuntimeConfigStr() {
104+
if (runtime_config_.has_value()) {
105+
const auto& cfg = runtime_config_.value();
106+
return cfg.DebugString();
107+
}
108+
return "{}";
109+
}
110+
102111
bool EnableConnectionStats() const { return enable_connection_stats_; }
103112
bool EnableDetailedMetrics() const { return enable_detailed_metrics_; }
104113
bool EnableRuntimeConfig() const { return enable_runtime_config_; }
@@ -188,6 +197,8 @@ class CollectorConfig {
188197
void HandleAfterglowEnvVars();
189198
void HandleConnectionStatsEnvVars();
190199
void HandleSinspEnvVars();
200+
bool YamlConfigToConfig(YAML::Node& yamlConfig);
201+
void HandleConfig(const std::filesystem::path& filePath);
191202

192203
// Protected, used for testing purposes
193204
void SetSinspBufferSize(unsigned int buffer_size);

collector/test/CollectorConfigTest.cpp

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include <optional>
22

3+
#include <internalapi/sensor/collector.pb.h>
4+
35
#include "CollectorArgs.h"
46
#include "CollectorConfig.h"
57
#include "gmock/gmock.h"
@@ -32,6 +34,10 @@ class MockCollectorConfig : public CollectorConfig {
3234
void MockSetEnableExternalIPs(bool value) {
3335
SetEnableExternalIPs(value);
3436
}
37+
38+
bool MockYamlConfigToConfig(YAML::Node& yamlConfig) {
39+
return YamlConfigToConfig(yamlConfig);
40+
}
3541
};
3642

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

154+
TEST(CollectorConfigTest, TestYamlConfigToConfigMultiple) {
155+
std::vector<std::pair<std::string, bool>> tests = {
156+
{R"(
157+
networkConnectionConfig:
158+
enableExternalIps: true
159+
)",
160+
true},
161+
{R"(
162+
networkConnectionConfig:
163+
enableExternalIps: false
164+
)",
165+
false},
166+
{R"(
167+
networkConnectionConfig:
168+
)",
169+
false},
170+
{R"(
171+
networkConnectionConfig:
172+
unknownField: asdf
173+
)",
174+
false}};
175+
176+
for (const auto& [yamlStr, expected] : tests) {
177+
YAML::Node yamlNode = YAML::Load(yamlStr);
178+
179+
MockCollectorConfig config;
180+
181+
bool result = config.MockYamlConfigToConfig(yamlNode);
182+
auto runtime_config = config.GetRuntimeConfig();
183+
184+
EXPECT_TRUE(result);
185+
EXPECT_TRUE(runtime_config.has_value());
186+
187+
const auto& cfg = runtime_config.value();
188+
const auto& network_cfg = cfg.network_connection_config();
189+
EXPECT_EQ(network_cfg.enable_external_ips(), expected);
190+
EXPECT_EQ(config.EnableExternalIPs(), expected);
191+
}
192+
}
193+
194+
TEST(CollectorConfigTest, TestYamlConfigToConfigInvalid) {
195+
std::string yamlStr = R"(
196+
unknownField: asdf
197+
)";
198+
199+
YAML::Node yamlNode = YAML::Load(yamlStr);
200+
201+
MockCollectorConfig config;
202+
203+
bool result = config.MockYamlConfigToConfig(yamlNode);
204+
auto runtime_config = config.GetRuntimeConfig();
205+
206+
EXPECT_FALSE(result);
207+
EXPECT_FALSE(runtime_config.has_value());
208+
}
209+
210+
TEST(CollectorConfigTest, TestYamlConfigToConfigEmpty) {
211+
std::string yamlStr = R"()";
212+
YAML::Node yamlNode = YAML::Load(yamlStr);
213+
214+
MockCollectorConfig config;
215+
216+
EXPECT_DEATH({ config.MockYamlConfigToConfig(yamlNode); }, ".*");
217+
}
218+
148219
} // namespace collector

docs/references.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ internal state of Collector. Refer to the
8989
[troubleshooting](troubleshooting.md#introspection-endpoints) section for more details.
9090
The default is false.
9191

92+
* `ROX_ENABLE_EXTERNAL_IPS`: Enables or disables the external IPs feature.
93+
9294
NOTE: Using environment variables is a preferred way of configuring Collector,
9395
so if you're adding a new configuration knob, keep this in mind.
9496

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

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

109+
### File mount or ConfigMap
110+
111+
The external IPs feature can be enabled or disabled using a file or ConfigMap. This is an optional
112+
method and does not have to be used. This file overwites the ENABLE_EXTERNAL_IPS feature flag.
113+
When using collector by itself a file can be mounted to it at /etc/stackrox/runtime_config.yaml. The
114+
following is an example of the contents
115+
116+
```
117+
networkConnectionConfig:
118+
enableExternalIps: true
119+
```
120+
121+
Alternatively, if collector is used as a part of Stackrox, the configuration can be set
122+
using a ConfigMap. The following is an example of such a ConfigMap.
123+
124+
```
125+
apiVersion: v1
126+
kind: ConfigMap
127+
metadata:
128+
name: collector-config
129+
namespace: stackrox
130+
data:
131+
runtime_config.yaml: |
132+
networkConnectionConfig:
133+
enableExternalIps: true
134+
```
135+
136+
The file path can be set using the `ROX_COLLECTOR_CONFIG_PATH` environment variable.
137+
107138
### Other arguments
108139

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

0 commit comments

Comments
 (0)