]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5351] Added client classes. Todo: update doc
authorFrancis Dupont <fdupont@isc.org>
Wed, 29 Nov 2017 09:27:30 +0000 (10:27 +0100)
committerFrancis Dupont <fdupont@isc.org>
Wed, 29 Nov 2017 09:27:30 +0000 (10:27 +0100)
src/bin/dhcp4/tests/config_parser_unittest.cc
src/bin/dhcp4/tests/get_config_unittest.cc
src/bin/dhcp6/tests/config_parser_unittest.cc
src/bin/dhcp6/tests/get_config_unittest.cc
src/lib/dhcpsrv/client_class_def.cc
src/lib/dhcpsrv/client_class_def.h
src/lib/dhcpsrv/parsers/client_class_def_parser.cc
src/lib/dhcpsrv/tests/client_class_def_unittest.cc

index 02820f538364f71b7d5a98860242c7638922dd93..0afa9b0b7a695ff8482fcbf3c74cd15abe4152c5 100644 (file)
@@ -5625,6 +5625,11 @@ TEST_F(Dhcp4ParserTest, comments) {
         "    \"data\": \"ABCDEF0105\",\n"
         "    \"csv-format\": false\n"
         " } ],\n"
+        "\"client-classes\": [ {\n"
+        "    \"name\": \"all\",\n"
+        "    \"comment\": \"match all\",\n"
+        "    \"test\": \"'' == ''\"\n"
+        " } ],\n"
         "\"shared-networks\": [ {\n"
         "    \"name\": \"foo\"\n,"
         "    \"comment\": \"A shared network\"\n,"
@@ -5683,6 +5688,23 @@ TEST_F(Dhcp4ParserTest, comments) {
     ASSERT_TRUE(ctx_opt_desc->get("comment"));
     EXPECT_EQ("\"Set option value\"", ctx_opt_desc->get("comment")->str());
 
+    // And there is a client class.
+    ClientClassDictionaryPtr dict =
+        CfgMgr::instance().getStagingCfg()->getClientClassDictionary();
+    ASSERT_TRUE(dict);
+    EXPECT_EQ(1, dict->getClasses()->size());
+    ClientClassDefPtr cclass = dict->findClass("all");
+    ASSERT_TRUE(cclass);
+    EXPECT_EQ("all", cclass->getName());
+    EXPECT_EQ("'' == ''", cclass->getTest());
+
+    // Check client class user context.
+    ConstElementPtr ctx_class = cclass->getContext();
+    ASSERT_TRUE(ctx_class);
+    ASSERT_EQ(1, ctx_class->size());
+    ASSERT_TRUE(ctx_class->get("comment"));
+    EXPECT_EQ("\"match all\"", ctx_class->get("comment")->str());
+
     // Now verify that the shared network was indeed configured.
     CfgSharedNetworks4Ptr cfg_net = CfgMgr::instance().getStagingCfg()
         ->getCfgSharedNetworks4();
index adeabb72b666579251775dcdcae2a24c99a4649c..c457e98b8d9359ffd8c2a049e4c3b0f91828e71b 100644 (file)
@@ -1588,6 +1588,21 @@ const char* EXTRACTED_CONFIGS[] = {
     // CONFIGURATION 58
 "{\n"
 "        \"comment\": \"A DHCPv4 server\",\n"
+"        \"client-classes\": [\n"
+"            {\n"
+"                \"comment\": \"match all\",\n"
+"                \"name\": \"all\",\n"
+"                \"test\": \"'' == ''\"\n"
+"            }\n"
+"        ],\n"
+"        \"option-data\": [\n"
+"            {\n"
+"                \"comment\": \"Set option value\",\n"
+"                \"csv-format\": false,\n"
+"                \"data\": \"ABCDEF0105\",\n"
+"                \"name\": \"dhcp-message\"\n"
+"            }\n"
+"        ],\n"
 "        \"option-def\": [\n"
 "            {\n"
 "                \"comment\": \"An option definition\",\n"
@@ -6262,6 +6277,18 @@ const char* UNPARSED_CONFIGS[] = {
     // CONFIGURATION 58
 "{\n"
 "        \"comment\": \"A DHCPv4 server\",\n"
+"        \"client-classes\": [\n"
+"            {\n"
+"                \"comment\": \"match all\",\n"
+"                \"boot-file-name\": \"\",\n"
+"                \"name\": \"all\",\n"
+"                \"next-server\": \"0.0.0.0\",\n"
+"                \"option-data\": [ ],\n"
+"                \"option-def\": [ ],\n"
+"                \"server-hostname\": \"\",\n"
+"                \"test\": \"'' == ''\"\n"
+"            }\n"
+"        ],\n"
 "        \"decline-probation-period\": 86400,\n"
 "        \"dhcp-ddns\": {\n"
 "            \"always-include-fqdn\": false,\n"
@@ -6298,7 +6325,17 @@ const char* UNPARSED_CONFIGS[] = {
 "        \"lease-database\": {\n"
 "            \"type\": \"memfile\"\n"
 "        },\n"
-"        \"option-data\": [ ],\n"
+"        \"option-data\": [\n"
+"            {\n"
+"                \"comment\": \"Set option value\",\n"
+"                \"always-send\": false,\n"
+"                \"code\": 56,\n"
+"                \"csv-format\": false,\n"
+"                \"data\": \"ABCDEF0105\",\n"
+"                \"name\": \"dhcp-message\",\n"
+"                \"space\": \"dhcp4\"\n"
+"            }\n"
+"        ],\n"
 "        \"option-def\": [\n"
 "            {\n"
 "                \"comment\": \"An option definition\",\n"
index 2d69334b6a453bb02b1eb66b8bb8ef4b50ddf321..5962f0873ef7f94530c9f833788bf7c7cf889fad 100644 (file)
@@ -6067,6 +6067,11 @@ TEST_F(Dhcp6ParserTest, comments) {
         "    \"data\": \"ABCDEF0105\",\n"
         "        \"csv-format\": false\n"
         " } ],\n"
+        "\"client-classes\": [ {\n"
+        "    \"name\": \"all\",\n"
+        "    \"comment\": \"match all\",\n"
+        "    \"test\": \"'' == ''\"\n"
+        " } ],\n"
         "\"shared-networks\": [ {\n"
         "    \"name\": \"foo\"\n,"
         "    \"comment\": \"A shared network\"\n,"
@@ -6133,6 +6138,23 @@ TEST_F(Dhcp6ParserTest, comments) {
     ASSERT_TRUE(ctx_opt_desc->get("comment"));
     EXPECT_EQ("\"Set option value\"", ctx_opt_desc->get("comment")->str());
 
+    // And there is a client class.
+    ClientClassDictionaryPtr dict =
+        CfgMgr::instance().getStagingCfg()->getClientClassDictionary();
+    ASSERT_TRUE(dict);
+    EXPECT_EQ(1, dict->getClasses()->size());
+    ClientClassDefPtr cclass = dict->findClass("all");
+    ASSERT_TRUE(cclass);
+    EXPECT_EQ("all", cclass->getName());
+    EXPECT_EQ("'' == ''", cclass->getTest());
+
+    // Check client class user context.
+    ConstElementPtr ctx_class = cclass->getContext();
+    ASSERT_TRUE(ctx_class);
+    ASSERT_EQ(1, ctx_class->size());
+    ASSERT_TRUE(ctx_class->get("comment"));
+    EXPECT_EQ("\"match all\"", ctx_class->get("comment")->str());
+
     // Now verify that the shared network was indeed configured.
     CfgSharedNetworks6Ptr cfg_net = CfgMgr::instance().getStagingCfg()
         ->getCfgSharedNetworks6();
index fb0d2bde29296db472ee41a24718ba166fdda333..4ac8ae512c1422eea8e45f4b088f7531a73a26cb 100644 (file)
@@ -1463,6 +1463,21 @@ const char* EXTRACTED_CONFIGS[] = {
     // CONFIGURATION 51
 "{\n"
 "        \"comment\": \"A DHCPv6 server\",\n"
+"        \"client-classes\": [\n"
+"            {\n"
+"                \"comment\": \"match all\",\n"
+"                \"name\": \"all\",\n"
+"                \"test\": \"'' == ''\"\n"
+"            }\n"
+"        ],\n"
+"        \"option-data\": [\n"
+"            {\n"
+"                \"comment\": \"Set option value\",\n"
+"                \"csv-format\": false,\n"
+"                \"data\": \"ABCDEF0105\",\n"
+"                \"name\": \"subscriber-id\"\n"
+"            }\n"
+"        ],\n"
 "        \"option-def\": [\n"
 "            {\n"
 "                \"comment\": \"An option definition\",\n"
@@ -5873,6 +5888,14 @@ const char* UNPARSED_CONFIGS[] = {
     // CONFIGURATION 51
 "{\n"
 "        \"comment\": \"A DHCPv6 server\",\n"
+"        \"client-classes\": [\n"
+"            {\n"
+"                \"comment\": \"match all\",\n"
+"                \"name\": \"all\",\n"
+"                \"option-data\": [ ],\n"
+"                \"test\": \"'' == ''\"\n"
+"            }\n"
+"        ],\n"
 "        \"decline-probation-period\": 86400,\n"
 "        \"dhcp-ddns\": {\n"
 "            \"always-include-fqdn\": false,\n"
@@ -5909,7 +5932,17 @@ const char* UNPARSED_CONFIGS[] = {
 "            \"type\": \"memfile\"\n"
 "        },\n"
 "        \"mac-sources\": [ \"any\" ],\n"
-"        \"option-data\": [ ],\n"
+"        \"option-data\": [\n"
+"            {\n"
+"                \"comment\": \"Set option value\",\n"
+"                \"always-send\": false,\n"
+"                \"code\": 38,\n"
+"                \"csv-format\": false,\n"
+"                \"data\": \"ABCDEF0105\",\n"
+"                \"name\": \"subscriber-id\",\n"
+"                \"space\": \"dhcp6\"\n"
+"            }\n"
+"        ],\n"
 "        \"option-def\": [\n"
 "            {\n"
 "                \"comment\": \"An option definition\",\n"
index d07de4b71732d033929e3a42a3f35eb3f265741a..5eb263777b43243fef2d15833c61976c640600ef 100644 (file)
@@ -132,6 +132,8 @@ ElementPtr
 ClientClassDef:: toElement() const {
     uint16_t family = CfgMgr::instance().getFamily();
     ElementPtr result = Element::createMap();
+    // Set user-context
+    contextToElement(result);
     // Set name
     result->set("name", Element::create(name_));
     // Set original match expression (empty string won't parse)
@@ -185,12 +187,14 @@ ClientClassDictionary::addClass(const std::string& name,
                                 const std::string& test,
                                 const CfgOptionPtr& cfg_option,
                                 CfgOptionDefPtr cfg_option_def,
+                                ConstElementPtr user_context,
                                 asiolink::IOAddress next_server,
                                 const std::string& sname,
                                 const std::string& filename) {
     ClientClassDefPtr cclass(new ClientClassDef(name, match_expr, cfg_option));
     cclass->setTest(test);
     cclass->setCfgOptionDef(cfg_option_def);
+    cclass->setContext(user_context),
     cclass->setNextServer(next_server);
     cclass->setSname(sname);
     cclass->setFilename(filename);
index 1167aa012aff6fa0c018f865ffaaea195bb00f48..81e4a179aafec21050c54530aa6c1af879a1a21b 100644 (file)
@@ -8,6 +8,7 @@
 #define CLIENT_CLASS_DEF_H
 
 #include <cc/cfg_to_element.h>
+#include <cc/user_context.h>
 #include <dhcpsrv/cfg_option.h>
 #include <dhcpsrv/cfg_option_def.h>
 #include <eval/token.h>
@@ -39,7 +40,7 @@ public:
 };
 
 /// @brief Embodies a single client class definition
-class ClientClassDef : public isc::data::CfgToElement {
+class ClientClassDef : public UserContext, public isc::data::CfgToElement {
 public:
     /// @brief Constructor
     ///
@@ -236,6 +237,7 @@ public:
     /// @param test Original version of match_expr
     /// @param options Collection of options members should be given
     /// @param defs Option definitions (optional)
+    /// @param user_context User context (optional)
     /// @param next_server next-server value for this class (optional)
     /// @param sname server-name value for this class (optional)
     /// @param filename boot-file-name value for this class (optional)
@@ -246,6 +248,7 @@ public:
     void addClass(const std::string& name, const ExpressionPtr& match_expr,
                   const std::string& test, const CfgOptionPtr& options,
                   CfgOptionDefPtr defs = CfgOptionDefPtr(),
+                  isc::data::ConstElementPtr user_context = isc::data::ConstElementPtr(),
                   asiolink::IOAddress next_server = asiolink::IOAddress("0.0.0.0"),
                   const std::string& sname = std::string(),
                   const std::string& filename = std::string());
index 582939334264410010f67287118f46918ea3ab66..bd1ac035103ef1cedab14528ab803dcc022d7bf5 100644 (file)
@@ -127,6 +127,9 @@ ClientClassDefParser::parse(ClientClassDictionaryPtr& class_dictionary,
         opts_parser.parse(options, option_data);
     }
 
+    // Parse user context
+    ConstElementPtr user_context = class_def_cfg->get("user-context");
+
     // Let's try to parse the next-server field
     IOAddress next_server("0.0.0.0");
     if (class_def_cfg->contains("next-server")) {
@@ -182,8 +185,8 @@ ClientClassDefParser::parse(ClientClassDictionaryPtr& class_dictionary,
 
     // Add the client class definition
     try {
-        class_dictionary->addClass(name, match_expr, test, options,
-                                   defs, next_server, sname, filename);
+        class_dictionary->addClass(name, match_expr, test, options, defs,
+                                   user_context, next_server, sname, filename);
     } catch (const std::exception& ex) {
         isc_throw(DhcpConfigError, "Can't add class: " << ex.what()
                   << " (" << class_def_cfg->getPosition() << ")");
index d7dd3ae58eb4eead54db171af126c18ff4613ff0..a4fb2ac007a0a9faa5da5d0d6f7d36cb7628d88d 100644 (file)
@@ -386,6 +386,9 @@ TEST(ClientClassDef, unparseDef) {
     ASSERT_NO_THROW(cclass.reset(new ClientClassDef(name, expr)));
     std::string test = "option[12].text == 'foo'";
     cclass->setTest(test);
+    std::string comment = "bar";
+    std::string user_context = "{ \"comment\": \"" + comment + "\" }";
+    cclass->setContext(isc::data::Element::fromJSON(user_context));
     std::string next_server = "1.2.3.4";
     cclass->setNextServer(IOAddress(next_server));
     std::string sname = "my-server.example.com";
@@ -395,6 +398,7 @@ TEST(ClientClassDef, unparseDef) {
 
     // Unparse it
     std::string expected = "{\n"
+        "\"comment\": \"" + comment + "\",\n"
         "\"name\": \"" + name + "\",\n"
         "\"test\": \"" + test + "\",\n"
         "\"next-server\": \"" + next_server + "\",\n"