Browse Source

[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
Thomas Markwalder 9 years ago
parent
commit
db990992e4

+ 65 - 1
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_name": "subnet6",
         "item_type": "list",
         "item_type": "list",
         "item_optional": false,
         "item_optional": false,

+ 15 - 0
src/bin/dhcp6/json_config_parser.cc

@@ -28,6 +28,7 @@
 #include <dhcpsrv/subnet.h>
 #include <dhcpsrv/subnet.h>
 #include <dhcpsrv/timer_mgr.h>
 #include <dhcpsrv/timer_mgr.h>
 #include <dhcpsrv/triplet.h>
 #include <dhcpsrv/triplet.h>
+#include <dhcpsrv/parsers/client_class_def_parser.h>
 #include <dhcpsrv/parsers/dbaccess_parser.h>
 #include <dhcpsrv/parsers/dbaccess_parser.h>
 #include <dhcpsrv/parsers/dhcp_config_parser.h>
 #include <dhcpsrv/parsers/dhcp_config_parser.h>
 #include <dhcpsrv/parsers/dhcp_parsers.h>
 #include <dhcpsrv/parsers/dhcp_parsers.h>
@@ -701,6 +702,8 @@ DhcpConfigParser* createGlobal6DhcpConfigParser(const std::string& config_id,
         parser = new ControlSocketParser(config_id);
         parser = new ControlSocketParser(config_id);
     } else if (config_id.compare("expired-leases-processing") == 0) {
     } else if (config_id.compare("expired-leases-processing") == 0) {
         parser = new ExpirationConfigParser();
         parser = new ExpirationConfigParser();
+    } else if (config_id.compare("client-classes") == 0) {
+        parser = new ClientClassDefListParser(config_id, globalContext());
     } else {
     } else {
         isc_throw(DhcpConfigError,
         isc_throw(DhcpConfigError,
                 "unsupported global configuration parameter: "
                 "unsupported global configuration parameter: "
@@ -763,6 +766,7 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
     ParserPtr option_parser;
     ParserPtr option_parser;
     ParserPtr iface_parser;
     ParserPtr iface_parser;
     ParserPtr leases_parser;
     ParserPtr leases_parser;
+    ParserPtr client_classes_parser;
 
 
     // Some of the parsers alter state of the system that can't easily
     // 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
     // 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.
                 // can be run here before other parsers.
                 parser->build(config_pair.second);
                 parser->build(config_pair.second);
                 iface_parser = parser;
                 iface_parser = parser;
+            } else if (config_pair.first == "client-classes") {
+                client_classes_parser = parser;
             } else {
             } else {
                 // Those parsers should be started before other
                 // Those parsers should be started before other
                 // parsers so we can call build straight away.
                 // parsers so we can call build straight away.
@@ -836,6 +842,15 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
             option_parser->commit();
             option_parser->commit();
         }
         }
 
 
+        // The class definitions parser is the next one to be run.
+        std::map<std::string, ConstElementPtr>::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.
         // The subnet parser is the next one to be run.
         std::map<std::string, ConstElementPtr>::const_iterator subnet_config =
         std::map<std::string, ConstElementPtr>::const_iterator subnet_config =
             values_map.find("subnet6");
             values_map.find("subnet6");

+ 72 - 0
src/bin/dhcp6/tests/config_parser_unittest.cc

@@ -3992,5 +3992,77 @@ TEST_F(Dhcp6ParserTest, expiredLeasesProcessingError) {
     EXPECT_TRUE(errorContainsPosition(status, "<string>"));
     EXPECT_TRUE(errorContainsPosition(status, "<string>"));
 }
 }
 
 
+// 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);
+}
 
 
 };
 };