From: Thomas Markwalder Date: Tue, 17 Nov 2015 18:28:40 +0000 (-0500) Subject: [4096] kea-dhcp4 now parses client class definitions list X-Git-Tag: trac4097a_base~1^2~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a419556f01409053a6435af080ab5b362bd4f051;p=thirdparty%2Fkea.git [4096] kea-dhcp4 now parses client class definitions list src/bin/dhcp4/json_config_parser.cc - createGlobalDhcp4ConfigParser() - creates ClientClassDefListParser for "client-classes" element - configureDhcp4Server() - runs the ClientClassDefListParser against the "client-classes" element src/bin/dhcp4/tests/config_parser_unittest.cc Added new tests for parsing client class definitions: TEST_F(Dhcp4ParserTest, clientClassDictionary) TEST_F(Dhcp4ParserTest, invalidClientClassDictionary) src/bin/dhcp4/dhcp4.spec Added global "client-classes" element --- diff --git a/src/bin/dhcp4/dhcp4.spec b/src/bin/dhcp4/dhcp4.spec index 84c28d75fe..d35dad7c8f 100644 --- a/src/bin/dhcp4/dhcp4.spec +++ b/src/bin/dhcp4/dhcp4.spec @@ -270,7 +270,71 @@ } ] }, - + { "item_name": "client-classes", + "item_type": "list", + "item_optional": true, + "item_default": [], + "list_item_spec": + { + "item_name": "client-class", + "item_type": "map", + "item_optional": false, + "item_default": {}, + "map_item_spec": [ + { "item_name": "name", + "item_type": "string", + "item_optional": false, + "item_default": "" + }, + { "item_name": "test", + "item_type": "string", + "item_optional": true, + "item_default": "" + }, + { "item_name": "option-data", + "item_type": "list", + "item_optional": true, + "item_default": [], + "list_item_spec": + { + "item_name": "single-option-data", + "item_type": "map", + "item_optional": false, + "item_default": {}, + "map_item_spec": [ + { + "item_name": "name", + "item_type": "string", + "item_optional": false, + "item_default": "" + }, + { + "item_name": "code", + "item_type": "integer", + "item_optional": false, + "item_default": 0 + }, + { + "item_name": "data", + "item_type": "string", + "item_optional": false, + "item_default": "" + }, + { "item_name": "csv-format", + "item_type": "boolean", + "item_optional": false, + "item_default": false + }, + { "item_name": "space", + "item_type": "string", + "item_optional": false, + "item_default": "dhcp4" + } ] + } + } + ] + } + }, { "item_name": "subnet4", "item_type": "list", "item_optional": false, diff --git a/src/bin/dhcp4/json_config_parser.cc b/src/bin/dhcp4/json_config_parser.cc index 46182be90b..d9c381e33c 100644 --- a/src/bin/dhcp4/json_config_parser.cc +++ b/src/bin/dhcp4/json_config_parser.cc @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -451,6 +452,8 @@ DhcpConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id, parser = new ControlSocketParser(config_id); } else if (config_id.compare("expired-leases-processing") == 0) { parser = new ExpirationConfigParser(); + } else if (config_id.compare("client-classes") == 0) { + parser = new ClientClassDefListParser(config_id, globalContext()); } else { isc_throw(DhcpConfigError, "unsupported global configuration parameter: " @@ -524,6 +527,7 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) { ParserPtr option_parser; ParserPtr iface_parser; ParserPtr leases_parser; + ParserPtr client_classes_parser; // Some of the parsers alter the state of the system in a way that can't // easily be undone. (Or alter it in a way such that undoing the change has @@ -574,6 +578,8 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) { // but defer the commit until everything else has committed. hooks_parser = parser; parser->build(config_pair.second); + } else if (config_pair.first == "client-classes") { + client_classes_parser = parser; } else { // Those parsers should be started before other // parsers so we can call build straight away. @@ -595,6 +601,15 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) { option_parser->commit(); } + // The class definitions parser is the next one to be run. + std::map::const_iterator cc_config = + values_map.find("client-classes"); + if (cc_config != values_map.end()) { + config_pair.first = "client-classes"; + client_classes_parser->build(cc_config->second); + client_classes_parser->commit(); + } + // The subnet parser is the next one to be run. std::map::const_iterator subnet_config = values_map.find("subnet4"); diff --git a/src/bin/dhcp4/tests/config_parser_unittest.cc b/src/bin/dhcp4/tests/config_parser_unittest.cc index c46d643a50..c2688627d1 100644 --- a/src/bin/dhcp4/tests/config_parser_unittest.cc +++ b/src/bin/dhcp4/tests/config_parser_unittest.cc @@ -3898,4 +3898,78 @@ TEST_F(Dhcp4ParserTest, 4o6subnetInterfaceId) { EXPECT_EQ(0, memcmp(&data[0], exp, data.size())); } +// Verifies that simple list of valid classes parses and +// is staged for commit. +TEST_F(Dhcp4ParserTest, validClientClassDictionary) { + string config = "{ " + genIfaceConfig() + "," + + "\"valid-lifetime\": 4000, \n" + "\"rebind-timer\": 2000, \n" + "\"renew-timer\": 1000, \n" + "\"client-classes\" : [ \n" + " { \n" + " \"name\": \"one\" \n" + " }, \n" + " { \n" + " \"name\": \"two\" \n" + " }, \n" + " { \n" + " \"name\": \"three\" \n" + " } \n" + "], \n" + "\"subnet4\": [ { \n" + " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ], \n" + " \"subnet\": \"192.0.2.0/24\" \n" + " } ] \n" + "} \n"; + + ConstElementPtr status; + ElementPtr json = Element::fromJSON(config); + + EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json)); + ASSERT_TRUE(status); + checkResult(status, 0); + + // We check staging config because CfgMgr::commit hasn't been executed. + ClientClassDictionaryPtr dictionary; + dictionary = CfgMgr::instance().getStagingCfg()->getClientClassDictionary(); + ASSERT_TRUE(dictionary); + EXPECT_EQ(3, dictionary->getClasses()->size()); + + // Execute the commit + ASSERT_NO_THROW(CfgMgr::instance().commit()); + + // Verify that after commit, the current config has the correct dictionary + dictionary = CfgMgr::instance().getCurrentCfg()->getClientClassDictionary(); + ASSERT_TRUE(dictionary); + EXPECT_EQ(3, dictionary->getClasses()->size()); +} + +// Verifies that an class list containing an invalid +// class definition causes a configuraiton error. +TEST_F(Dhcp4ParserTest, invalidClientClassDictionary) { + string config = "{ " + genIfaceConfig() + "," + + "\"valid-lifetime\": 4000, \n" + "\"rebind-timer\": 2000, \n" + "\"renew-timer\": 1000, \n" + "\"client-classes\" : [ \n" + " { \n" + " \"name\": \"one\", \n" + " \"bogus\": \"bad\" \n" + " } \n" + "], \n" + "\"subnet4\": [ { \n" + " \"pools\": [ { \"pool\": \"192.0.2.1 - 192.0.2.100\" } ], \n" + " \"subnet\": \"192.0.2.0/24\" \n" + " } ] \n" + "} \n"; + + ConstElementPtr status; + ElementPtr json = Element::fromJSON(config); + + EXPECT_NO_THROW(status = configureDhcp4Server(*srv_, json)); + ASSERT_TRUE(status); + checkResult(status, 1); +} + + } diff --git a/src/lib/dhcpsrv/parsers/client_class_def_parser.h b/src/lib/dhcpsrv/parsers/client_class_def_parser.h index 21558ce352..55aa69e753 100644 --- a/src/lib/dhcpsrv/parsers/client_class_def_parser.h +++ b/src/lib/dhcpsrv/parsers/client_class_def_parser.h @@ -150,7 +150,7 @@ typedef boost::shared_ptr ClientClassDefParserPtr; /// This parser iterates over all configuration entries that define /// client classes and creates ClientClassDef instances for each. /// If the parsing done in build() is successful, the collection of -/// created definitions is given to the @todo CfgMgr. +/// created definitions is given to the CfgMgr. class ClientClassDefListParser : public DhcpConfigParser { public: /// @brief Constructor.