From: Marcin Siodelski Date: Thu, 8 Jul 2021 17:12:13 +0000 (+0200) Subject: [#1928] Optionally skip checking deps X-Git-Tag: Kea-1.9.10~72 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fff7ab6ffc6460094a5e4a0defdeda00fe424a72;p=thirdparty%2Fkea.git [#1928] Optionally skip checking deps The client class parser can be configured to skip checking class dependencies during parsing. --- diff --git a/src/lib/dhcpsrv/parsers/client_class_def_parser.cc b/src/lib/dhcpsrv/parsers/client_class_def_parser.cc index fb1c2c7108..75a71ca1b7 100644 --- a/src/lib/dhcpsrv/parsers/client_class_def_parser.cc +++ b/src/lib/dhcpsrv/parsers/client_class_def_parser.cc @@ -70,7 +70,8 @@ void ClientClassDefParser::parse(ClientClassDictionaryPtr& class_dictionary, ConstElementPtr class_def_cfg, uint16_t family, - bool append_error_position) { + bool append_error_position, + bool check_dependencies) { // name is now mandatory, so let's deal with it first. std::string name = getString(class_def_cfg, "name"); if (name.empty()) { @@ -87,11 +88,11 @@ ClientClassDefParser::parse(ClientClassDictionaryPtr& class_dictionary, if (test_cfg) { ExpressionParser parser; auto check_defined = - [&class_dictionary, &depend_on_known] + [&class_dictionary, &depend_on_known, check_dependencies] (const ClientClass& cclass) { - return (isClientClassDefined(class_dictionary, - depend_on_known, - cclass)); + return (!check_dependencies || isClientClassDefined(class_dictionary, + depend_on_known, + cclass)); }; parser.parse(match_expr, test_cfg, family, check_defined); test = test_cfg->stringValue(); @@ -282,12 +283,12 @@ ClientClassDefParser::checkParametersSupported(const ConstElementPtr& class_def_ ClientClassDictionaryPtr ClientClassDefListParser::parse(ConstElementPtr client_class_def_list, - uint16_t family) { + uint16_t family, bool check_dependencies) { ClientClassDictionaryPtr dictionary(new ClientClassDictionary()); BOOST_FOREACH(ConstElementPtr client_class_def, client_class_def_list->listValue()) { ClientClassDefParser parser; - parser.parse(dictionary, client_class_def, family); + parser.parse(dictionary, client_class_def, family, true, check_dependencies); } return (dictionary); } diff --git a/src/lib/dhcpsrv/parsers/client_class_def_parser.h b/src/lib/dhcpsrv/parsers/client_class_def_parser.h index 221ba13850..a0720d0464 100644 --- a/src/lib/dhcpsrv/parsers/client_class_def_parser.h +++ b/src/lib/dhcpsrv/parsers/client_class_def_parser.h @@ -94,12 +94,15 @@ public: /// of the parsed string within parsed JSON should be appended. The /// default setting is to append it, but it is typically set to false /// when this parser is used by hooks libraries. + /// @param check_dependencies indicates if the parser should evaluate an + /// expression to see if the referenced client classes exist. /// /// @throw DhcpConfigError if parsing was unsuccessful. void parse(ClientClassDictionaryPtr& class_dictionary, isc::data::ConstElementPtr client_class_def, uint16_t family, - bool append_error_position = true); + bool append_error_position = true, + bool check_dependencies = true); /// @brief Iterates over class parameters and checks if they are supported. /// @@ -135,10 +138,13 @@ public: /// @param class_def_list pointer to an element that holds entries /// for client class definitions. /// @param family the address family of the client class definitions. + /// @param check_dependencies indicates if the parser should evaluate an + /// expression to see if the referenced client classes exist. /// @return a pointer to the filled dictionary /// @throw DhcpConfigError if configuration parsing fails. ClientClassDictionaryPtr - parse(isc::data::ConstElementPtr class_def_list, uint16_t family); + parse(isc::data::ConstElementPtr class_def_list, uint16_t family, + bool check_dependencies = true); }; } // end of namespace isc::dhcp diff --git a/src/lib/dhcpsrv/tests/client_class_def_parser_unittest.cc b/src/lib/dhcpsrv/tests/client_class_def_parser_unittest.cc index 495a560a8f..2c6f901059 100644 --- a/src/lib/dhcpsrv/tests/client_class_def_parser_unittest.cc +++ b/src/lib/dhcpsrv/tests/client_class_def_parser_unittest.cc @@ -157,18 +157,21 @@ protected: /// @param config - JSON string containing the list of definitions to parse. /// @param family - the address family in which the parsing should /// occur. + /// @param check_dependencies - indicates if the parser should check whether + /// referenced classes exist. /// @return Returns a pointer to class dictionary created /// @throw indirectly, exceptions converting the JSON text to elements, /// or by the parsing itself are not caught ClientClassDictionaryPtr parseClientClassDefList(const std::string& config, - uint16_t family) + uint16_t family, + bool check_dependencies = true) { // Turn config into elements. This may emit exceptions. ElementPtr config_element = Element::fromJSON(config); // Parse the configuration. This may emit exceptions. ClientClassDefListParser parser; - return (parser.parse(config_element, family)); + return (parser.parse(config_element, family, check_dependencies)); } }; @@ -1087,6 +1090,24 @@ TEST_F(ClientClassDefListParserTest, dependentNotDefined) { EXPECT_THROW(parseClientClassDefList(cfg_text, AF_INET6), DhcpConfigError); } +// Verifies that error is not reported when a class references another +// not defined class, but dependency checking is disabled. +TEST_F(ClientClassDefListParserTest, dependencyCheckingDisabled) { + std::string cfg_text = + "[ \n" + " { \n" + " \"name\": \"one\", \n" + " \"test\": \"member('foo')\" \n" + " } \n" + "] \n"; + try { + parseClientClassDefList(cfg_text, AF_INET6, false); + } catch ( const std::exception& ex) { + std::cout << ex.what() << std::endl; + } + EXPECT_NO_THROW(parseClientClassDefList(cfg_text, AF_INET6, false)); +} + // Verifies that forward dependencies will not parse. TEST_F(ClientClassDefListParserTest, dependentForwardError) { std::string cfg_text =