From e840a4ada0d156c95c1f28a32f8db24d3631e53d Mon Sep 17 00:00:00 2001 From: Federico Di Pierro Date: Wed, 10 Apr 2024 09:30:13 +0200 Subject: [PATCH] new(unit_tests,userspace/falco): support loading and merging configs files when used from cmdline option. Also, moved core logic from yaml_helper to falco_configuration class. Finally, updated tests. Signed-off-by: Federico Di Pierro --- unit_tests/falco/test_configuration.cpp | 249 +++++++++++++++--------- userspace/falco/configuration.cpp | 61 +++++- userspace/falco/configuration.h | 7 +- userspace/falco/yaml_helper.h | 83 ++------ 4 files changed, 237 insertions(+), 163 deletions(-) diff --git a/unit_tests/falco/test_configuration.cpp b/unit_tests/falco/test_configuration.cpp index 89dd0a7c..9c4f2b75 100644 --- a/unit_tests/falco/test_configuration.cpp +++ b/unit_tests/falco/test_configuration.cpp @@ -37,8 +37,6 @@ static std::string sample_yaml = " - elem2\n" " - elem3\n"; -static std::vector loaded_conf_files; - TEST(Configuration, configuration_exceptions) { yaml_helper conf; @@ -137,8 +135,10 @@ TEST(Configuration, configuration_config_files_secondary_fail) outfile << conf_yaml_2; outfile.close(); - yaml_helper conf; - ASSERT_ANY_THROW(conf.load_from_file("main.yaml", loaded_conf_files)); + std::vector cmdline_config_options; + std::vector loaded_conf_files; + falco_configuration falco_config; + ASSERT_ANY_THROW(falco_config.init("main.yaml", loaded_conf_files, cmdline_config_options)); std::filesystem::remove("main.yaml"); std::filesystem::remove("conf_2.yaml"); @@ -184,29 +184,31 @@ TEST(Configuration, configuration_config_files_ok) outfile << conf_yaml_4; outfile.close(); - yaml_helper conf; - ASSERT_NO_THROW(conf.load_from_file("main.yaml", loaded_conf_files)); + std::vector cmdline_config_options; + std::vector loaded_conf_files; + falco_configuration falco_config; + ASSERT_NO_THROW(falco_config.init("main.yaml", loaded_conf_files, cmdline_config_options)); // main + conf_2 + conf_3 ASSERT_EQ(loaded_conf_files.size(), 3); - ASSERT_TRUE(conf.is_defined("foo")); - ASSERT_EQ(conf.get_scalar("foo", ""), "bar"); - ASSERT_TRUE(conf.is_defined("base_value.id")); - ASSERT_EQ(conf.get_scalar("base_value.id", 0), 1); - ASSERT_TRUE(conf.is_defined("base_value.name")); - ASSERT_EQ(conf.get_scalar("base_value.name", ""), "foo"); - ASSERT_TRUE(conf.is_defined("foo2")); - ASSERT_EQ(conf.get_scalar("foo2", ""), "bar2"); - ASSERT_TRUE(conf.is_defined("base_value_2.id")); - ASSERT_EQ(conf.get_scalar("base_value_2.id", 0), 2); - ASSERT_TRUE(conf.is_defined("foo3")); - ASSERT_EQ(conf.get_scalar("foo3", ""), "bar3"); - ASSERT_TRUE(conf.is_defined("base_value_3.id")); - ASSERT_EQ(conf.get_scalar("base_value_3.id", 0), 3); - ASSERT_TRUE(conf.is_defined("base_value_3.name")); - ASSERT_EQ(conf.get_scalar("base_value_3.name", ""), "foo3"); - ASSERT_FALSE(conf.is_defined("base_value_4.id")); // conf_4 is not included + ASSERT_TRUE(falco_config.config.is_defined("foo")); + ASSERT_EQ(falco_config.config.get_scalar("foo", ""), "bar"); + ASSERT_TRUE(falco_config.config.is_defined("base_value.id")); + ASSERT_EQ(falco_config.config.get_scalar("base_value.id", 0), 1); + ASSERT_TRUE(falco_config.config.is_defined("base_value.name")); + ASSERT_EQ(falco_config.config.get_scalar("base_value.name", ""), "foo"); + ASSERT_TRUE(falco_config.config.is_defined("foo2")); + ASSERT_EQ(falco_config.config.get_scalar("foo2", ""), "bar2"); + ASSERT_TRUE(falco_config.config.is_defined("base_value_2.id")); + ASSERT_EQ(falco_config.config.get_scalar("base_value_2.id", 0), 2); + ASSERT_TRUE(falco_config.config.is_defined("foo3")); + ASSERT_EQ(falco_config.config.get_scalar("foo3", ""), "bar3"); + ASSERT_TRUE(falco_config.config.is_defined("base_value_3.id")); + ASSERT_EQ(falco_config.config.get_scalar("base_value_3.id", 0), 3); + ASSERT_TRUE(falco_config.config.is_defined("base_value_3.name")); + ASSERT_EQ(falco_config.config.get_scalar("base_value_3.name", ""), "foo3"); + ASSERT_FALSE(falco_config.config.is_defined("base_value_4.id")); // conf_4 is not included std::filesystem::remove("main.yaml"); std::filesystem::remove("conf_2.yaml"); @@ -255,24 +257,26 @@ TEST(Configuration, configuration_config_files_relative_main) outfile << conf_yaml_3; outfile.close(); - yaml_helper conf; - ASSERT_NO_THROW(conf.load_from_file(temp_main.string(), loaded_conf_files)); + std::vector cmdline_config_options; + std::vector loaded_conf_files; + falco_configuration falco_config; + ASSERT_NO_THROW(falco_config.init(temp_main.string(), loaded_conf_files, cmdline_config_options)); // main + conf_2 + conf_3 ASSERT_EQ(loaded_conf_files.size(), 3); - ASSERT_TRUE(conf.is_defined("foo")); - ASSERT_EQ(conf.get_scalar("foo", ""), "bar"); - ASSERT_TRUE(conf.is_defined("base_value.id")); - ASSERT_EQ(conf.get_scalar("base_value.id", 0), 1); - ASSERT_TRUE(conf.is_defined("base_value.name")); - ASSERT_EQ(conf.get_scalar("base_value.name", ""), "foo"); - ASSERT_TRUE(conf.is_defined("foo2")); - ASSERT_EQ(conf.get_scalar("foo2", ""), "bar2"); - ASSERT_TRUE(conf.is_defined("base_value_2")); - ASSERT_EQ(conf.get_scalar("base_value_2.id", 0), 2); - ASSERT_TRUE(conf.is_defined("base_value_3.id")); - ASSERT_EQ(conf.get_scalar("base_value_3.id", 0), 3); + ASSERT_TRUE(falco_config.config.is_defined("foo")); + ASSERT_EQ(falco_config.config.get_scalar("foo", ""), "bar"); + ASSERT_TRUE(falco_config.config.is_defined("base_value.id")); + ASSERT_EQ(falco_config.config.get_scalar("base_value.id", 0), 1); + ASSERT_TRUE(falco_config.config.is_defined("base_value.name")); + ASSERT_EQ(falco_config.config.get_scalar("base_value.name", ""), "foo"); + ASSERT_TRUE(falco_config.config.is_defined("foo2")); + ASSERT_EQ(falco_config.config.get_scalar("foo2", ""), "bar2"); + ASSERT_TRUE(falco_config.config.is_defined("base_value_2")); + ASSERT_EQ(falco_config.config.get_scalar("base_value_2.id", 0), 2); + ASSERT_TRUE(falco_config.config.is_defined("base_value_3.id")); + ASSERT_EQ(falco_config.config.get_scalar("base_value_3.id", 0), 3); std::filesystem::remove(temp_main.string()); std::filesystem::remove("conf_2.yaml"); @@ -310,22 +314,24 @@ TEST(Configuration, configuration_config_files_override) outfile << conf_yaml_3; outfile.close(); - yaml_helper conf; - ASSERT_NO_THROW(conf.load_from_file("main.yaml", loaded_conf_files)); + std::vector cmdline_config_options; + std::vector loaded_conf_files; + falco_configuration falco_config; + ASSERT_NO_THROW(falco_config.init("main.yaml", loaded_conf_files, cmdline_config_options)); // main + conf_2 + conf_3 ASSERT_EQ(loaded_conf_files.size(), 3); - ASSERT_TRUE(conf.is_defined("foo")); - ASSERT_EQ(conf.get_scalar("foo", ""), "bar"); - ASSERT_TRUE(conf.is_defined("base_value.id")); - ASSERT_EQ(conf.get_scalar("base_value.id", 0), 3); // overridden! - ASSERT_FALSE(conf.is_defined("base_value.name")); // no more present since entire `base_value` block was overridden - ASSERT_TRUE(conf.is_defined("foo2")); - ASSERT_EQ(conf.get_scalar("foo2", ""), "bar2"); - ASSERT_TRUE(conf.is_defined("base_value_2.id")); - ASSERT_EQ(conf.get_scalar("base_value_2.id", 0), 2); - ASSERT_FALSE(conf.is_defined("base_value_3.id")); // not defined + ASSERT_TRUE(falco_config.config.is_defined("foo")); + ASSERT_EQ(falco_config.config.get_scalar("foo", ""), "bar"); + ASSERT_TRUE(falco_config.config.is_defined("base_value.id")); + ASSERT_EQ(falco_config.config.get_scalar("base_value.id", 0), 3); // overridden! + ASSERT_FALSE(falco_config.config.is_defined("base_value.name")); // no more present since entire `base_value` block was overridden + ASSERT_TRUE(falco_config.config.is_defined("foo2")); + ASSERT_EQ(falco_config.config.get_scalar("foo2", ""), "bar2"); + ASSERT_TRUE(falco_config.config.is_defined("base_value_2.id")); + ASSERT_EQ(falco_config.config.get_scalar("base_value_2.id", 0), 2); + ASSERT_FALSE(falco_config.config.is_defined("base_value_3.id")); // not defined std::filesystem::remove("main.yaml"); std::filesystem::remove("conf_2.yaml"); @@ -334,7 +340,7 @@ TEST(Configuration, configuration_config_files_override) TEST(Configuration, configuration_config_files_unexistent) { - /* Test that including an unexistent file throws an exception */ + /* Test that including an unexistent file just skips it */ const std::string main_conf_yaml = yaml_helper::configs_key + ":\n" " - conf_5.yaml\n" @@ -346,8 +352,18 @@ TEST(Configuration, configuration_config_files_unexistent) outfile << main_conf_yaml; outfile.close(); - yaml_helper conf; - ASSERT_ANY_THROW(conf.load_from_file("main.yaml", loaded_conf_files)); + std::vector cmdline_config_options; + std::vector loaded_conf_files; + falco_configuration falco_config; + ASSERT_NO_THROW(falco_config.init("main.yaml", loaded_conf_files, cmdline_config_options)); + + // main + ASSERT_EQ(loaded_conf_files.size(), 1); + + ASSERT_TRUE(falco_config.config.is_defined("base_value.id")); + ASSERT_EQ(falco_config.config.get_scalar("base_value.id", 0), 1); + ASSERT_TRUE(falco_config.config.is_defined("base_value.name")); + ASSERT_EQ(falco_config.config.get_scalar("base_value.name", ""), "foo"); std::filesystem::remove("main.yaml"); } @@ -374,22 +390,24 @@ TEST(Configuration, configuration_config_files_scalar_configs_files) outfile << conf_yaml_2; outfile.close(); - yaml_helper conf; - ASSERT_NO_THROW(conf.load_from_file("main.yaml", loaded_conf_files)); + std::vector cmdline_config_options; + std::vector loaded_conf_files; + falco_configuration falco_config; + ASSERT_NO_THROW(falco_config.init("main.yaml", loaded_conf_files, cmdline_config_options)); // main + conf_2 ASSERT_EQ(loaded_conf_files.size(), 2); - ASSERT_TRUE(conf.is_defined("foo")); - ASSERT_EQ(conf.get_scalar("foo", ""), "bar"); - ASSERT_TRUE(conf.is_defined("base_value.id")); - ASSERT_EQ(conf.get_scalar("base_value.id", 0), 1); - ASSERT_TRUE(conf.is_defined("base_value.name")); - ASSERT_EQ(conf.get_scalar("base_value.name", ""), "foo"); - ASSERT_TRUE(conf.is_defined("foo2")); - ASSERT_EQ(conf.get_scalar("foo2", ""), "bar2"); - ASSERT_TRUE(conf.is_defined("base_value_2.id")); - ASSERT_EQ(conf.get_scalar("base_value_2.id", 0), 2); + ASSERT_TRUE(falco_config.config.is_defined("foo")); + ASSERT_EQ(falco_config.config.get_scalar("foo", ""), "bar"); + ASSERT_TRUE(falco_config.config.is_defined("base_value.id")); + ASSERT_EQ(falco_config.config.get_scalar("base_value.id", 0), 1); + ASSERT_TRUE(falco_config.config.is_defined("base_value.name")); + ASSERT_EQ(falco_config.config.get_scalar("base_value.name", ""), "foo"); + ASSERT_TRUE(falco_config.config.is_defined("foo2")); + ASSERT_EQ(falco_config.config.get_scalar("foo2", ""), "bar2"); + ASSERT_TRUE(falco_config.config.is_defined("base_value_2.id")); + ASSERT_EQ(falco_config.config.get_scalar("base_value_2.id", 0), 2); std::filesystem::remove("main.yaml"); std::filesystem::remove("conf_2.yaml"); @@ -409,18 +427,20 @@ TEST(Configuration, configuration_config_files_empty_configs_files) outfile << main_conf_yaml; outfile.close(); - yaml_helper conf; - ASSERT_NO_THROW(conf.load_from_file("main.yaml", loaded_conf_files)); + std::vector cmdline_config_options; + std::vector loaded_conf_files; + falco_configuration falco_config; + ASSERT_NO_THROW(falco_config.init("main.yaml", loaded_conf_files, cmdline_config_options)); // main ASSERT_EQ(loaded_conf_files.size(), 1); - ASSERT_TRUE(conf.is_defined("foo")); - ASSERT_EQ(conf.get_scalar("foo", ""), "bar"); - ASSERT_TRUE(conf.is_defined("base_value.id")); - ASSERT_EQ(conf.get_scalar("base_value.id", 0), 1); - ASSERT_TRUE(conf.is_defined("base_value.name")); - ASSERT_EQ(conf.get_scalar("base_value.name", ""), "foo"); + ASSERT_TRUE(falco_config.config.is_defined("foo")); + ASSERT_EQ(falco_config.config.get_scalar("foo", ""), "bar"); + ASSERT_TRUE(falco_config.config.is_defined("base_value.id")); + ASSERT_EQ(falco_config.config.get_scalar("base_value.id", 0), 1); + ASSERT_TRUE(falco_config.config.is_defined("base_value.name")); + ASSERT_EQ(falco_config.config.get_scalar("base_value.name", ""), "foo"); std::filesystem::remove("main.yaml"); } @@ -439,8 +459,10 @@ TEST(Configuration, configuration_config_files_self) outfile << main_conf_yaml; outfile.close(); - yaml_helper conf; - ASSERT_ANY_THROW(conf.load_from_file("main.yaml", loaded_conf_files)); + std::vector cmdline_config_options; + std::vector loaded_conf_files; + falco_configuration falco_config; + ASSERT_ANY_THROW(falco_config.init("main.yaml", loaded_conf_files, cmdline_config_options)); std::filesystem::remove("main.yaml"); } @@ -491,31 +513,80 @@ TEST(Configuration, configuration_config_files_directory) outfile << conf_yaml_4; outfile.close(); - yaml_helper conf; - ASSERT_NO_THROW(conf.load_from_file("main.yaml", loaded_conf_files)); + std::vector cmdline_config_options; + std::vector loaded_conf_files; + falco_configuration falco_config; + ASSERT_NO_THROW(falco_config.init("main.yaml", loaded_conf_files, cmdline_config_options)); // main + conf_2 + conf_3. // test/foo is not parsed. ASSERT_EQ(loaded_conf_files.size(), 3); - ASSERT_TRUE(conf.is_defined("foo")); - ASSERT_EQ(conf.get_scalar("foo", ""), "bar"); - ASSERT_TRUE(conf.is_defined("base_value.id")); - ASSERT_EQ(conf.get_scalar("base_value.id", 0), 1); - ASSERT_TRUE(conf.is_defined("base_value.name")); - ASSERT_EQ(conf.get_scalar("base_value.name", ""), "foo"); - ASSERT_TRUE(conf.is_defined("base_value_2")); - ASSERT_EQ(conf.get_scalar("base_value_2.id", 0), 2); - ASSERT_TRUE(conf.is_defined("base_value_3.id")); - ASSERT_EQ(conf.get_scalar("base_value_3.id", 0), 3); - ASSERT_TRUE(conf.is_defined("foo2")); - ASSERT_EQ(conf.get_scalar("foo2", ""), "bar3"); - ASSERT_FALSE(conf.is_defined("foo4")); + ASSERT_TRUE(falco_config.config.is_defined("foo")); + ASSERT_EQ(falco_config.config.get_scalar("foo", ""), "bar"); + ASSERT_TRUE(falco_config.config.is_defined("base_value.id")); + ASSERT_EQ(falco_config.config.get_scalar("base_value.id", 0), 1); + ASSERT_TRUE(falco_config.config.is_defined("base_value.name")); + ASSERT_EQ(falco_config.config.get_scalar("base_value.name", ""), "foo"); + ASSERT_TRUE(falco_config.config.is_defined("base_value_2")); + ASSERT_EQ(falco_config.config.get_scalar("base_value_2.id", 0), 2); + ASSERT_TRUE(falco_config.config.is_defined("base_value_3.id")); + ASSERT_EQ(falco_config.config.get_scalar("base_value_3.id", 0), 3); + ASSERT_TRUE(falco_config.config.is_defined("foo2")); + ASSERT_EQ(falco_config.config.get_scalar("foo2", ""), "bar3"); + ASSERT_FALSE(falco_config.config.is_defined("foo4")); std::filesystem::remove("main"); std::filesystem::remove_all(std::filesystem::temp_directory_path()/"test"); } +TEST(Configuration, configuration_config_files_cmdline) +{ + /* Test that we support including configs files from cmdline option */ + const std::string main_conf_yaml = + "foo: bar\n" + "base_value:\n" + " id: 1\n" + " name: foo\n"; + const std::string conf_yaml_2 = + "foo2: bar2\n" + "base_value_2:\n" + " id: 2\n"; + + std::ofstream outfile("main.yaml"); + outfile << main_conf_yaml; + outfile.close(); + + outfile.open("conf_2.yaml"); + outfile << conf_yaml_2; + outfile.close(); + + // Pass "configs_files=..." cmdline option + std::vector cmdline_config_options; + cmdline_config_options.push_back((yaml_helper::configs_key+"=conf_2.yaml")); + + std::vector loaded_conf_files; + falco_configuration falco_config; + ASSERT_NO_THROW(falco_config.init("main.yaml", loaded_conf_files, cmdline_config_options)); + + // main + conf_2 + ASSERT_EQ(loaded_conf_files.size(), 2); + + ASSERT_TRUE(falco_config.config.is_defined("foo")); + ASSERT_EQ(falco_config.config.get_scalar("foo", ""), "bar"); + ASSERT_TRUE(falco_config.config.is_defined("base_value.id")); + ASSERT_EQ(falco_config.config.get_scalar("base_value.id", 0), 1); + ASSERT_TRUE(falco_config.config.is_defined("base_value.name")); + ASSERT_EQ(falco_config.config.get_scalar("base_value.name", ""), "foo"); + ASSERT_TRUE(falco_config.config.is_defined("foo2")); + ASSERT_EQ(falco_config.config.get_scalar("foo2", ""), "bar2"); + ASSERT_TRUE(falco_config.config.is_defined("base_value_2.id")); + ASSERT_EQ(falco_config.config.get_scalar("base_value_2.id", 0), 2); + + std::filesystem::remove("main.yaml"); + std::filesystem::remove("conf_2.yaml"); +} + TEST(Configuration, configuration_environment_variables) { // Set an environment variable for testing purposes diff --git a/userspace/falco/configuration.cpp b/userspace/falco/configuration.cpp index 61e632cc..79468f85 100644 --- a/userspace/falco/configuration.cpp +++ b/userspace/falco/configuration.cpp @@ -93,9 +93,10 @@ void falco_configuration::init(const std::vector& cmdline_options) void falco_configuration::init(const std::string& conf_filename, std::vector& loaded_conf_files, const std::vector &cmdline_options) { + loaded_conf_files.clear(); try { - config.load_from_file(conf_filename, loaded_conf_files); + config.load_from_file(conf_filename); } catch(const std::exception& e) { @@ -103,6 +104,7 @@ void falco_configuration::init(const std::string& conf_filename, std::vector& loaded_config_files) +{ + // Load configs files to be included and merge them into current config + loaded_config_files.push_back(config_name); + const auto ppath = std::filesystem::path(config_name); + // Parse files to be included + std::vector include_files; + config.get_sequence>(include_files, yaml_helper::configs_key); + for(const std::string& include_file : include_files) + { + auto include_file_path = std::filesystem::path(include_file); + if (include_file_path == ppath) + { + throw std::logic_error( + "Config error: '" + yaml_helper::configs_key + "' directive tried to recursively include main config file: " + config_name + "."); + } + if (!std::filesystem::exists(include_file_path)) + { + // Same we do for rules_file: just skip the entry. + continue; + } + if (std::filesystem::is_regular_file(include_file_path)) + { + config.include_config_file(include_file_path.string()); + loaded_config_files.push_back(include_file); + } + else if (std::filesystem::is_directory(include_file_path)) + { + std::vector v; + const auto it_options = std::filesystem::directory_options::follow_directory_symlink + | std::filesystem::directory_options::skip_permission_denied; + for (auto const& dir_entry : std::filesystem::directory_iterator(include_file_path, it_options)) + { + if (std::filesystem::is_regular_file(dir_entry.path())) + { + v.push_back(dir_entry.path().string()); + } + } + std::sort(v.begin(), v.end()); + for (const auto &f : v) + { + config.include_config_file(f); + loaded_config_files.push_back(f); + } + } + } +} + void falco_configuration::load_engine_config(const std::string& config_name) { // Set driver mode if not already set. @@ -608,12 +658,5 @@ void falco_configuration::set_cmdline_option(const std::string &opt) throw std::logic_error("Error parsing config option \"" + opt + "\". Must be of the form key=val or key.subkey=val"); } - if (keyval.first.rfind(yaml_helper::configs_key, 0) == 0) - { - falco_logger::log(falco_logger::level::WARNING, "Ignoring '-o " + yaml_helper::configs_key + "' directive: cannot be overridden by cmdline.\n"); - } - else - { - config.set_scalar(keyval.first, keyval.second); - } + config.set_scalar(keyval.first, keyval.second); } diff --git a/userspace/falco/configuration.h b/userspace/falco/configuration.h index 2eaab095..d760dc00 100644 --- a/userspace/falco/configuration.h +++ b/userspace/falco/configuration.h @@ -163,7 +163,12 @@ public: replay_config m_replay = {}; gvisor_config m_gvisor = {}; + // Needed by tests + yaml_helper config; + private: + void merge_configs_files(const std::string& config_name, std::vector& loaded_config_files); + void load_yaml(const std::string& config_name); void load_engine_config(const std::string& config_name); @@ -177,8 +182,6 @@ private: * are supported and only scalar values are supported. */ void set_cmdline_option(const std::string& spec); - - yaml_helper config; }; namespace YAML { diff --git a/userspace/falco/yaml_helper.h b/userspace/falco/yaml_helper.h index 8836302a..3d69ad56 100644 --- a/userspace/falco/yaml_helper.h +++ b/userspace/falco/yaml_helper.h @@ -92,50 +92,31 @@ public: /** * Load the YAML document from the given file path. */ - void load_from_file(const std::string& path, std::vector& loaded_config_files) + void load_from_file(const std::string& path) { - loaded_config_files.clear(); + m_root = load_from_file_int(path); + } - m_root = load_from_file_int(path, loaded_config_files); - - const auto ppath = std::filesystem::path(path); - // Parse files to be included - std::vector include_files; - get_sequence>(include_files, configs_key); - for(const std::string& include_file : include_files) + void include_config_file(const std::string& include_file_path) + { + auto loaded_nodes = load_from_file_int(include_file_path); + for(auto n : loaded_nodes) { - auto include_file_path = std::filesystem::path(include_file); - if (include_file_path == ppath) + /* + * To avoid recursion hell, + * we don't support `configs_files` directives from included config files + * (that use load_from_file_int recursively). + */ + const auto &key = n.first.Scalar(); + if (key == configs_key) { throw std::runtime_error( - "Config error: '" + configs_key + "' directive tried to recursively include main config file: " + path + "."); - } - if (!std::filesystem::exists(include_file_path)) - { - throw std::runtime_error("Included config entry not existent: " + include_file_path.string()); - } - if (std::filesystem::is_regular_file(include_file_path)) - { - include_config_file(include_file_path.string(), loaded_config_files); - } - else if (std::filesystem::is_directory(include_file_path)) - { - std::vector v; - const auto it_options = std::filesystem::directory_options::follow_directory_symlink - | std::filesystem::directory_options::skip_permission_denied; - for (auto const& dir_entry : std::filesystem::directory_iterator(include_file_path, it_options)) - { - if (std::filesystem::is_regular_file(dir_entry.path())) - { - v.push_back(dir_entry.path().string()); - } - } - std::sort(v.begin(), v.end()); - for (const auto &f : v) - { - include_config_file(f, loaded_config_files); - } + "Config error: '" + configs_key + "' directive in included config file " + include_file_path + "."); } + // We allow to override keys. + // We don't need to use `get_node()` here, + // since key is a top-level one. + m_root[key] = n.second; } } @@ -204,37 +185,13 @@ public: private: YAML::Node m_root; - YAML::Node load_from_file_int(const std::string& path, std::vector& loaded_config_files) + YAML::Node load_from_file_int(const std::string& path) { auto root = YAML::LoadFile(path); pre_process_env_vars(root); - loaded_config_files.push_back(path); return root; } - void include_config_file(const std::string& include_file_path, std::vector& loaded_config_files) - { - auto loaded_nodes = load_from_file_int(include_file_path, loaded_config_files); - for(auto n : loaded_nodes) - { - /* - * To avoid recursion hell, - * we don't support `configs_files` directives from included config files - * (that use load_from_file_int recursively). - */ - const auto &key = n.first.Scalar(); - if (key == configs_key) - { - throw std::runtime_error( - "Config error: '" + configs_key + "' directive in included config file " + include_file_path + "."); - } - // We allow to override keys. - // We don't need to use `get_node()` here, - // since key is a top-level one. - m_root[key] = n.second; - } - } - /* * When loading a yaml file, * we immediately pre process all scalar values through a visitor private API,