From 990545f6169c6bb9b97c36cce48fb750873ed3b2 Mon Sep 17 00:00:00 2001 From: Amnon Heiman Date: Tue, 31 Jan 2023 17:21:38 +0200 Subject: [PATCH] Add relabel from file support. This patch adds a configuration with an optional file name for relabeling metrics. It also adds a function that accepts a file name and loads the relabel config from a file. An example for such a file: ``` $cat conf.yml relabel_configs: - source_labels: [shard] action: drop target_label: shard regex: (2) - source_labels: [shard] action: replace target_label: level replacement: $1 regex: (.*3) ``` update_relabel_config_from_file throws an exception on failure, it's up to the caller to decide what to do in such cases. --- db/config.cc | 66 ++++++++++++++++++++++++++++++++++++++++++++++++++++ db/config.hh | 8 +++++++ 2 files changed, 74 insertions(+) diff --git a/db/config.cc b/db/config.cc index 74be53db26..6f453f3768 100644 --- a/db/config.cc +++ b/db/config.cc @@ -28,6 +28,9 @@ #include "extensions.hh" #include "log.hh" #include "utils/config_file_impl.hh" +#include +#include +#include namespace utils { @@ -927,6 +930,7 @@ db::config::config(std::shared_ptr exts) , wasm_udf_yield_fuel(this, "wasm_udf_yield_fuel", value_status::Used, 100000, "Wasmtime fuel a WASM UDF can consume before yielding") , wasm_udf_total_fuel(this, "wasm_udf_total_fuel", value_status::Used, 100000000, "Wasmtime fuel a WASM UDF can consume before termination") , wasm_udf_memory_limit(this, "wasm_udf_memory_limit", value_status::Used, 2*1024*1024, "How much memory each WASM UDF can allocate at most") + , relabel_config_file(this, "relabel_config_file", value_status::Used, "", "Optionally, read relabel config from file") , minimum_keyspace_rf(this, "minimum_keyspace_rf", liveness::LiveUpdate, value_status::Used, 0, "The minimum allowed replication factor when creating or altering a keyspace.") , default_log_level(this, "default_log_level", value_status::Used) , logger_log_level(this, "logger_log_level", value_status::Used) @@ -1174,4 +1178,66 @@ future resolve(const config_file::named_value& addre co_return coroutine::exception(std::move(ex)); } +static future> get_relable_from_file(const std::string& name) { + file f = co_await seastar::open_file_dma(name, open_flags::ro); + size_t s = co_await f.size(); + seastar::input_stream in = seastar::make_file_input_stream(f); + temporary_buffer buf = co_await in.read_exactly(s); + auto yaml = YAML::Load(sstring(buf.begin(), buf.end())); + std::vector relabels; + const YAML::Node& relabel_configs = yaml["relabel_configs"]; + relabels.resize(relabel_configs.size()); + size_t i = 0; + for (auto it = relabel_configs.begin(); it != relabel_configs.end(); ++it, i++) { + const YAML::Node& element = *it; + for(YAML::const_iterator e_it = element.begin(); e_it != element.end(); ++e_it) { + std::string key = e_it->first.as(); + if (key == "source_labels") { + auto labels = e_it->second; + std::vector source_labels; + source_labels.resize(labels.size()); + size_t j = 0; + for (auto label_it = labels.begin(); label_it != labels.end(); ++label_it, j++) { + source_labels[j] = label_it->as(); + } + relabels[i].source_labels = source_labels; + } else if (key == "action") { + relabels[i].action = seastar::metrics::relabel_config_action(e_it->second.as()); + } else if (key == "replacement") { + relabels[i].replacement = e_it->second.as(); + } else if (key == "target_label") { + relabels[i].target_label = e_it->second.as(); + } else if (key == "separator") { + relabels[i].separator = e_it->second.as(); + } else if (key == "regex") { + relabels[i].expr = e_it->second.as(); + } else { + throw std::runtime_error("unkown entry '" + key + "' in file " + name); + } + } + } + co_return relabels; +} + +future<> update_relabel_config_from_file(const std::string& name) { + if (name.empty()) { + co_return; + } + + std::vector relabels = co_await get_relable_from_file(name); + bool failed = false; + co_await smp::invoke_on_all([&relabels, &failed] { + return metrics::set_relabel_configs(relabels).then([&failed](const metrics::metric_relabeling_result& result) { + if (result.metrics_relabeled_due_to_collision > 0) { + failed = true; + } + return; + }); + }); + if (failed) { + throw std::runtime_error("conflicts found during relabeling"); + } + co_return; +} + } diff --git a/db/config.hh b/db/config.hh index 4e2e86d251..e339164701 100644 --- a/db/config.hh +++ b/db/config.hh @@ -406,6 +406,7 @@ public: named_value wasm_udf_yield_fuel; named_value wasm_udf_total_fuel; named_value wasm_udf_memory_limit; + named_value relabel_config_file; // wasm_udf_reserved_memory is static because the options in db::config // are parsed using seastar::app_template, while this option is used for // configuring the Seastar memory subsystem. @@ -464,4 +465,11 @@ inline bool is_true(sstring val) { future<> configure_tls_creds_builder(seastar::tls::credentials_builder& creds, db::config::string_map options); future resolve(const config_file::named_value&, gms::inet_address::opt_family family = {}, gms::inet_address::opt_family preferred = {}); + +/*! + * \brief read the the relabel config from a file + * + * Will throw an exception if there is a conflict with the metrics names + */ +future<> update_relabel_config_from_file(const std::string& name); }