]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5351] checkpoint: added comment
authorFrancis Dupont <fdupont@isc.org>
Tue, 28 Nov 2017 11:45:51 +0000 (12:45 +0100)
committerFrancis Dupont <fdupont@isc.org>
Tue, 28 Nov 2017 11:45:51 +0000 (12:45 +0100)
doc/examples/kea4/advanced.json
doc/examples/kea6/advanced.json
doc/guide/dhcp4-srv.xml
doc/guide/dhcp6-srv.xml
doc/guide/hooks.xml
src/lib/dhcpsrv/pool.cc
src/lib/dhcpsrv/subnet.cc
src/lib/dhcpsrv/tests/cfg_subnets4_unittest.cc
src/lib/dhcpsrv/tests/cfg_subnets6_unittest.cc

index 327047bcd24b2cbf5a8768fe82144a7a8c5996e7..03ff4dc98c74446028176202e579ab78d2efa391 100644 (file)
     // It is intended to keep anything you may want to put there - comments,
     // extra designations, floor or department names etc. These structures
     // will be made available to Kea hooks.
+    // You can define multiple user-contexts in the same scope without
+    // the last one replacing previous values. A comment entry is
+    // translated into a user-context with a "comment" property so
+    // you can include comments inside the configuration itself.
     "subnet4": [
         {
             "pools": [ {
             "user-context": {
                 "comment": "Our first subnet!"
             }
+            // Equivalent using smart parser
+            // "comment": "Our first subnet!"
         },
         {
             // This particular subnet has match-client-id value changed.
index a8e67ee973fff17fbcfdc964b5a9e93488c2082c..8e0fb0faaeb41d475c28f82de6cc9eea0155a3c8 100644 (file)
     // structures. You can put anything you want in the user-context
     // as long as it is a valid JSON and it starts with a map (i.e.
     // is enclosed by curly brackets).
+    // You can define multiple user-contexts in the same scope without
+    // the last one replacing previous values. A comment entry is
+    // translated into a user-context with a "comment" property so
+    // you can include comments inside the configuration itself.
     "subnet6": [
     {
         "pools": [
 
         // Here's the user-context for the whole subnet.
         "user-context": { "comment": "Floor one, west wing" },
+        // Equivalent using smart parser
+        // "comment": "Floor one, west wing",
 
         // This defines PD (prefix delegation) pools. In this case
         // we have only one pool. That consists of /64 prefixes
index b0070184be427c4bee809de44fe6622b1bd68bbf..bc6ee58d2fa036a427d50d34581a4e00de3f3d4b 100644 (file)
@@ -4683,6 +4683,9 @@ autogenerated IDs are not stable across configuration changes.</para>
           It should be noted that Kea will not use that information, but will
           simply store and make it available to hook libraries. It is up to the
           hook library to extract that information and make use of it.
+          The parser translates "comment" entries into a user-context
+          with the entry, this allows to attach comments inside the
+          configuration itself.
         </para>
         <para>
           For more background information, see <xref linkend="user-context"/>.
index 06d5717aede1433e238fc011cb732005fb064f9d..befbca5b3e688912f87b61fb704a178733d9c1ac 100644 (file)
@@ -4650,6 +4650,9 @@ autogenerated IDs are not stable across configuration changes.
           it just stores it, making it available to the hook
           libraries. It is up to each hook library to extract the information
           and make use of it.
+          The parser translates "comment" entries into a user-context
+          with the entry, this allows to attach comments inside the
+          configuration itself.
         </para>
         <para>
           For more background information, see <xref linkend="user-context"/>.
index 3be72d337b114dc0638be41ac21624978668de22..e1b8630fd042f6c87ce8cee0e1f4cf969c17d156 100644 (file)
@@ -2543,6 +2543,14 @@ both the command and the response.
       arbitrary complexity. Kea does not use that data on its own, simply stores
       and makes it available for the hook libraries.
       </para>
+      <para>
+        Usually when an entry is defined multiple times in the same scope
+        the last value is used overwriting previous values (silently:
+        this behavior should be fixed soon). With user contexts values
+        are combined at the first level, for instance multiple user context
+        with a "comment" entry gives an entry with the list of accumulated
+        values.
+      </para>
       <para>
         Another use case for user contexts may be storing comments and other
         information that will be retained by Kea. Regular comments are discarded
@@ -2550,6 +2558,13 @@ both the command and the response.
         useful if you want your comments to survive config-set, config-get
         operations for example.
       </para>
+      <para>
+        The parser translates "comment" entries at locations user context
+        are valid into a user context with a "comment" entry. The pretty
+        print of a configuration does the opposite operation and puts
+        "comment" entries at the beginning of maps as it seems to be the
+        common usage.
+      </para>
       <para>
         As of Kea 1.3, the structures that allow user contexts are pools of all
         types (addresses and prefixes) and subnets. These are supported in both
index 77cdc461214aed9a6042a7dac302c6a4ed81191c..b57b0fb06a6b3faf7888b521a256577660bcd1b8 100644 (file)
@@ -80,10 +80,20 @@ Pool::toElement() const {
     // Prepare the map
     ElementPtr map = Element::createMap();
 
-    // Set user-context
+    // Set user-context extracting comment
     ConstElementPtr context = getContext();
     if (!isNull(context)) {
-        map->set("user-context", context);
+        if ((context->getType() == Element::map) &&
+            context->contains("comment")) {
+            ElementPtr copied = isc::data::copy(context);
+            map->set("comment", copied->get("comment"));
+            copied->remove("comment");
+            if (copied->size() > 0) {
+                map->set("user-context", copied);
+            }
+        } else {
+            map->set("user-context", context);
+        }
     }
 
     // Set pool options
index 837faed17171e0b03457af52ac56b3dd72ad5f21..d8482dd3b3735b0a5f5acd9c75c3f01ba3e4e1cc 100644 (file)
@@ -566,9 +566,20 @@ Subnet::toElement() const {
     map->set("subnet", Element::create(toText()));
 
     // Add user-context, but only if defined. Omit if it was not.
+    // Extract comment so it will be printed first.
     ConstElementPtr ctx = getContext();
     if (ctx) {
-        map->set("user-context", ctx);
+        if ((ctx->getType() == Element::map) &&
+            ctx->contains("comment")) {
+            ElementPtr copied = isc::data::copy(ctx);
+            map->set("comment",copied->get("comment"));
+            copied->remove("comment");
+            if (copied->size() > 0) {
+                map->set("user-context", copied);
+            }
+        } else {
+            map->set("user-context", ctx);
+        }
     }
 
     return (map);
@@ -638,7 +649,17 @@ Subnet6::toElement() const {
         // Set user-context
         ConstElementPtr context = (*pool)->getContext();
         if (!isNull(context)) {
-            pool_map->set("user-context", context);
+            if ((context->getType() == Element::map) &&
+                context->contains("comment")) {
+                ElementPtr copied = isc::data::copy(context);
+                pool_map->set("comment", copied->get("comment"));
+                copied->remove("comment");
+                if (copied->size() > 0) {
+                    pool_map->set("user-context", copied);
+                }
+            } else {
+                pool_map->set("user-context", context);
+            }
         }
         // Set pool options
         ConstCfgOptionPtr opts = (*pool)->getCfgOption();
@@ -692,7 +713,17 @@ Subnet6::toElement() const {
         // Set user-context
         ConstElementPtr context = pdpool->getContext();
         if (!isNull(context)) {
-            pool_map->set("user-context", context);
+            if ((context->getType() == Element::map) &&
+                context->contains("comment")) {
+                ElementPtr copied = isc::data::copy(context);
+                pool_map->set("comment", copied->get("comment"));
+                copied->remove("comment");
+                if (copied->size() > 0) {
+                    pool_map->set("user-context", copied);
+                }
+            } else {
+                pool_map->set("user-context", context);
+            }
         }
         // Set pool options
         ConstCfgOptionPtr opts = pdpool->getCfgOption();
index c8083d0c84c704f3ff0bf32f242474a8580b8844..cfe0363bdab1befb2a94b9bb30626f932770a05a 100644 (file)
@@ -740,6 +740,11 @@ TEST(CfgSubnets4Test, unparseSubnet) {
     subnet2->setRelayInfo(IOAddress("10.0.0.1"));
     subnet3->setIface("eth1");
 
+    data::ElementPtr ctx1 = data::Element::fromJSON("{ \"comment\": \"foo\" }");
+    subnet1->setContext(ctx1);
+    data::ElementPtr ctx2 = data::Element::createMap();
+    subnet2->setContext(ctx2);
+
     cfg.add(subnet1);
     cfg.add(subnet2);
     cfg.add(subnet3);
@@ -747,6 +752,7 @@ TEST(CfgSubnets4Test, unparseSubnet) {
     // Unparse
     std::string expected = "[\n"
         "{\n"
+        "    \"comment\": \"foo\",\n"
         "    \"id\": 123,\n"
         "    \"subnet\": \"192.0.2.0/26\",\n"
         "    \"relay\": { \"ip-address\": \"0.0.0.0\" },\n"
@@ -780,6 +786,7 @@ TEST(CfgSubnets4Test, unparseSubnet) {
         "    \"4o6-interface-id\": \"\",\n"
         "    \"4o6-subnet\": \"\",\n"
         "    \"reservation-mode\": \"all\",\n"
+        "    \"user-context\": {},\n"
         "    \"option-data\": [ ],\n"
         "    \"pools\": [ ]\n"
         "},{\n"
@@ -813,6 +820,12 @@ TEST(CfgSubnets4Test, unparsePool) {
     Pool4Ptr pool1(new Pool4(IOAddress("192.0.2.1"), IOAddress("192.0.2.10")));
     Pool4Ptr pool2(new Pool4(IOAddress("192.0.2.64"), 26));
 
+    std::string json1 = "{ \"comment\": \"foo\", \"version\": 1 }";
+    data::ElementPtr ctx1 = data::Element::fromJSON(json1);
+    pool1->setContext(ctx1);
+    data::ElementPtr ctx2 = data::Element::fromJSON("{ \"foo\": \"bar\" }");
+    pool2->setContext(ctx2);
+
     subnet->addPool(pool1);
     subnet->addPool(pool2);
     cfg.add(subnet);
@@ -837,11 +850,14 @@ TEST(CfgSubnets4Test, unparsePool) {
         "    \"option-data\": [],\n"
         "    \"pools\": [\n"
         "        {\n"
+        "            \"comment\": \"foo\",\n"
         "            \"option-data\": [ ],\n"
-        "            \"pool\": \"192.0.2.1-192.0.2.10\"\n"
+        "            \"pool\": \"192.0.2.1-192.0.2.10\",\n"
+        "            \"user-context\": { \"version\": 1 }\n"
         "        },{\n"
         "            \"option-data\": [ ],\n"
-        "            \"pool\": \"192.0.2.64/26\"\n"
+        "            \"pool\": \"192.0.2.64/26\"\n,"
+        "            \"user-context\": { \"foo\": \"bar\" }\n"
         "        }\n"
         "    ]\n"
         "} ]\n";
index 575a0b8e90b42e124b4c1b07c6ddfd5409e1684e..f8200fad0652a2a8a0dcf72cae02964791e39aa6 100644 (file)
@@ -439,6 +439,11 @@ TEST(CfgSubnets6Test, unparseSubnet) {
     subnet2->setRelayInfo(IOAddress("2001:db8:ff::2"));
     subnet3->setIface("eth1");
 
+    data::ElementPtr ctx1 = data::Element::fromJSON("{ \"comment\": \"foo\" }");
+    subnet1->setContext(ctx1);
+    data::ElementPtr ctx2 = data::Element::createMap();
+    subnet2->setContext(ctx2);
+
     cfg.add(subnet1);
     cfg.add(subnet2);
     cfg.add(subnet3);
@@ -446,6 +451,7 @@ TEST(CfgSubnets6Test, unparseSubnet) {
     // Unparse
     std::string expected = "[\n"
         "{\n"
+        "    \"comment\": \"foo\",\n"
         "    \"id\": 123,\n"
         "    \"subnet\": \"2001:db8:1::/48\",\n"
         "    \"relay\": { \"ip-address\": \"::\" },\n"
@@ -471,6 +477,7 @@ TEST(CfgSubnets6Test, unparseSubnet) {
         "    \"valid-lifetime\": 4,\n"
         "    \"rapid-commit\": false,\n"
         "    \"reservation-mode\": \"all\",\n"
+        "    \"user-context\": { },\n"
         "    \"pools\": [ ],\n"
         "    \"pd-pools\": [ ],\n"
         "    \"option-data\": [ ]\n"
@@ -504,6 +511,12 @@ TEST(CfgSubnets6Test, unparsePool) {
                              IOAddress("2001:db8:1::199")));
     Pool6Ptr pool2(new Pool6(Lease::TYPE_NA, IOAddress("2001:db8:1:1::"), 64));
 
+    std::string json1 = "{ \"comment\": \"foo\", \"version\": 1 }";
+    data::ElementPtr ctx1 = data::Element::fromJSON(json1);
+    pool1->setContext(ctx1);
+    data::ElementPtr ctx2 = data::Element::fromJSON("{ \"foo\": \"bar\" }");
+    pool2->setContext(ctx2);
+
     subnet->addPool(pool1);
     subnet->addPool(pool2);
     cfg.add(subnet);
@@ -522,10 +535,13 @@ TEST(CfgSubnets6Test, unparsePool) {
         "    \"reservation-mode\": \"all\",\n"
         "    \"pools\": [\n"
         "        {\n"
+        "            \"comment\": \"foo\",\n"
         "            \"pool\": \"2001:db8:1::100-2001:db8:1::199\",\n"
+        "            \"user-context\": { \"version\": 1 },\n"
         "            \"option-data\": [ ]\n"
         "        },{\n"
         "            \"pool\": \"2001:db8:1:1::/64\",\n"
+        "            \"user-context\": { \"foo\": \"bar\" },\n"
         "            \"option-data\": [ ]\n"
         "        }\n"
         "    ],\n"
@@ -548,6 +564,9 @@ TEST(CfgSubnets6Test, unparsePdPool) {
     Pool6Ptr pdpool2(new Pool6(IOAddress("2001:db8:3::"), 48, 56,
                                IOAddress("2001:db8:3::"), 64));
 
+    data::ElementPtr ctx1 = data::Element::fromJSON("{ \"foo\": [ \"bar\" ] }");
+    pdpool1->setContext(ctx1);
+
     subnet->addPool(pdpool1);
     subnet->addPool(pdpool2);
     cfg.add(subnet);
@@ -570,6 +589,7 @@ TEST(CfgSubnets6Test, unparsePdPool) {
         "            \"prefix\": \"2001:db8:2::\",\n"
         "            \"prefix-len\": 48,\n"
         "            \"delegated-len\": 64,\n"
+        "            \"user-context\": { \"foo\": [ \"bar\" ] },\n"
         "            \"option-data\": [ ]\n"
         "        },{\n"
         "            \"prefix\": \"2001:db8:3::\",\n"