From: Thomas Markwalder Date: Tue, 17 Nov 2015 18:46:02 +0000 (-0500) Subject: [4096] kea-dhcp6 now parses client class definitions list X-Git-Tag: trac4097a_base~1^2~9 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=db990992e475c1b844cbf129b19853d3a866ab5a;p=thirdparty%2Fkea.git [4096] kea-dhcp6 now parses client class definitions list src/bin/dhcp6/json_config_parser.cc - createGlobalDhcp6ConfigParser() - creates ClientClassDefListParser for "client-classes" element - configureDhcp6Server() - runs the ClientClassDefListParser against the "client-classes" element src/bin/dhcp6/tests/config_parser_unittest.cc Added new tests for parsing client class definitions: TEST_F(Dhcp6ParserTest, clientClassDictionary) TEST_F(Dhcp6ParserTest, invalidClientClassDictionary) src/bin/dhcp6/dhcp6.spec Added global "client-classes" element --- diff --git a/src/bin/dhcp6/dhcp6.spec b/src/bin/dhcp6/dhcp6.spec index f24d15f20a..969111f6b9 100644 --- a/src/bin/dhcp6/dhcp6.spec +++ b/src/bin/dhcp6/dhcp6.spec @@ -252,7 +252,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": "subnet6", "item_type": "list", "item_optional": false, diff --git a/src/bin/dhcp6/json_config_parser.cc b/src/bin/dhcp6/json_config_parser.cc index c7bf0de63f..fe0af18311 100644 --- a/src/bin/dhcp6/json_config_parser.cc +++ b/src/bin/dhcp6/json_config_parser.cc @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -701,6 +702,8 @@ DhcpConfigParser* createGlobal6DhcpConfigParser(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: " @@ -763,6 +766,7 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) { ParserPtr option_parser; ParserPtr iface_parser; ParserPtr leases_parser; + ParserPtr client_classes_parser; // Some of the parsers alter state of the system that can't easily // be undone. (Or alter it in a way such that undoing the change @@ -815,6 +819,8 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) { // can be run here before other parsers. parser->build(config_pair.second); iface_parser = parser; + } 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. @@ -836,6 +842,15 @@ configureDhcp6Server(Dhcpv6Srv&, 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("subnet6"); diff --git a/src/bin/dhcp6/tests/config_parser_unittest.cc b/src/bin/dhcp6/tests/config_parser_unittest.cc index 983fcc0b5b..5b047af157 100644 --- a/src/bin/dhcp6/tests/config_parser_unittest.cc +++ b/src/bin/dhcp6/tests/config_parser_unittest.cc @@ -3992,5 +3992,77 @@ TEST_F(Dhcp6ParserTest, expiredLeasesProcessingError) { EXPECT_TRUE(errorContainsPosition(status, "")); } +// Verifies that simple list of valid classes parses and +// is staged for commit. +TEST_F(Dhcp6ParserTest, validClientClassDictionary) { + + string config = "{ " + genIfaceConfig() + "," + "\"preferred-lifetime\": 3000, \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" + "\"subnet6\": [ { \n" + " \"pools\": [ { \"pool\": \"2001:db8:1::1 - 2001:db8:1::ffff\" } ], \n" + " \"subnet\": \"2001:db8:1::/64\" } ], \n" + "\"valid-lifetime\": 4000 } \n"; + + ConstElementPtr status; + ElementPtr json = Element::fromJSON(config); + + EXPECT_NO_THROW(status = configureDhcp6Server(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(Dhcp6ParserTest, 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 = configureDhcp6Server(srv_, json)); + ASSERT_TRUE(status); + checkResult(status, 1); +} };