]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[5351] Checkpoint: fix HR, doc, host DB
authorFrancis Dupont <fdupont@isc.org>
Sun, 3 Dec 2017 12:43:59 +0000 (13:43 +0100)
committerFrancis Dupont <fdupont@isc.org>
Sun, 3 Dec 2017 12:43:59 +0000 (13:43 +0100)
17 files changed:
src/bin/dhcp4/dhcp4_lexer.ll
src/bin/dhcp4/dhcp4_parser.yy
src/bin/dhcp4/parser_context.h
src/bin/dhcp4/tests/config_parser_unittest.cc
src/bin/dhcp4/tests/get_config_unittest.cc
src/bin/dhcp4/tests/get_config_unittest.cc.skel
src/bin/dhcp6/dhcp6_lexer.ll
src/bin/dhcp6/dhcp6_parser.yy
src/bin/dhcp6/parser_context.h
src/bin/dhcp6/tests/config_parser_unittest.cc
src/bin/dhcp6/tests/get_config_unittest.cc
src/bin/dhcp6/tests/get_config_unittest.cc.skel
src/lib/dhcpsrv/cfg_db_access.cc
src/lib/dhcpsrv/cfg_db_access.h
src/lib/dhcpsrv/parsers/dbaccess_parser.cc
src/lib/dhcpsrv/tests/cfg_db_access_unittest.cc
src/lib/testutils/user_context_utils.cc

index 65184f61d444372372cb344cd733175ea08c0a57..c688dc76ed026a5e53dde2635484d0b867f0bc1f 100644 (file)
@@ -135,6 +135,8 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
             return isc::dhcp::Dhcp4Parser::make_SUB_HOOKS_LIBRARY(driver.loc_);
         case Parser4Context::PARSER_DHCP_DDNS:
             return isc::dhcp::Dhcp4Parser::make_SUB_DHCP_DDNS(driver.loc_);
+        case Parser4Context::PARSER_LOGGING:
+            return isc::dhcp::Dhcp4Parser::make_SUB_LOGGING(driver.loc_);
         }
     }
 %}
@@ -580,8 +582,6 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     switch(driver.ctx_) {
     case isc::dhcp::Parser4Context::DHCP4:
     case isc::dhcp::Parser4Context::INTERFACES_CONFIG:
-    case isc::dhcp::Parser4Context::LEASE_DATABASE:
-    case isc::dhcp::Parser4Context::HOSTS_DATABASE:
     case isc::dhcp::Parser4Context::SUBNET4:
     case isc::dhcp::Parser4Context::POOLS:
     case isc::dhcp::Parser4Context::SHARED_NETWORK:
@@ -602,8 +602,6 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     switch(driver.ctx_) {
     case isc::dhcp::Parser4Context::DHCP4:
     case isc::dhcp::Parser4Context::INTERFACES_CONFIG:
-    case isc::dhcp::Parser4Context::LEASE_DATABASE:
-    case isc::dhcp::Parser4Context::HOSTS_DATABASE:
     case isc::dhcp::Parser4Context::SUBNET4:
     case isc::dhcp::Parser4Context::POOLS:
     case isc::dhcp::Parser4Context::SHARED_NETWORK:
index 3e5252313738e8ddaf7505f052d41c3bd2177520..a701979f081213f752970e6778988e648ab204f8 100644 (file)
@@ -206,6 +206,7 @@ using namespace std;
   SUB_OPTION_DATA
   SUB_HOOKS_LIBRARY
   SUB_DHCP_DDNS
+  SUB_LOGGING
 ;
 
 %token <std::string> STRING "constant string"
@@ -243,6 +244,7 @@ start: TOPLEVEL_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } sub_json
      | SUB_OPTION_DATA { ctx.ctx_ = ctx.OPTION_DATA; } sub_option_data
      | SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library
      | SUB_DHCP_DDNS { ctx.ctx_ = ctx.DHCP_DDNS; } sub_dhcp_ddns
+     | SUB_LOGGING { ctx.ctx_ = ctx.LOGGING; } sub_logging
      ;
 
 // ---- generic JSON parser ---------------------------------
@@ -582,8 +584,6 @@ database_map_param: database_type
                   | connect_timeout
                   | contact_points
                   | keyspace
-                  | user_context
-                  | comment
                   | unknown_map_entry
                   ;
 
@@ -1861,6 +1861,14 @@ logging_object: LOGGING {
     ctx.leave();
 };
 
+sub_logging: LCURLY_BRACKET {
+    // Parse the Logging map
+    ElementPtr m(new MapElement(ctx.loc2pos(@1)));
+    ctx.stack_.push_back(m);
+} logging_params RCURLY_BRACKET {
+    // parsing completed
+};
+
 // This defines the list of allowed parameters that may appear
 // in the top-level Logging object. It can either be a single
 // parameter or several parameters separated by commas.
index ee998e05f8fbca7a23e45b82f33af6a29ed08f55..189d7512aec84ed7fcdd5b58f8d4d92a18400e54 100644 (file)
@@ -86,7 +86,10 @@ public:
         PARSER_HOOKS_LIBRARY,
 
         /// This will parse the input as dhcp-ddns.
-        PARSER_DHCP_DDNS
+        PARSER_DHCP_DDNS,
+
+        /// This will parse the content of Logging.
+        PARSER_LOGGING
     } ParserType;
 
     /// @brief Default constructor.
index 22f37795c470590544fdbe620ab10ca0a5aeb67d..09e84ce723c284668fb9bca7719332452ae63ad7 100644 (file)
@@ -12,6 +12,7 @@
 #include <cc/command_interpreter.h>
 #include <config/module_spec.h>
 #include <dhcp4/dhcp4_srv.h>
+#include <dhcp4/ctrl_dhcp4_srv.h>
 #include <dhcp4/json_config_parser.h>
 #include <dhcp/option4_addrlst.h>
 #include <dhcp/option_custom.h>
@@ -165,7 +166,7 @@ public:
         // Open port 0 means to not do anything at all. We don't want to
         // deal with sockets here, just check if configuration handling
         // is sane.
-        srv_.reset(new Dhcpv4Srv(0));
+        srv_.reset(new ControlledDhcpv4Srv(0));
         // Create fresh context.
         resetConfiguration();
     }
@@ -5612,58 +5613,84 @@ TEST_F(Dhcp4ParserTest, comments) {
 
     string config = "{\n"
         "\"comment\": \"A DHCPv4 server\",\n"
+        "\"interfaces-config\": {\n"
+        "    \"comment\": \"Use wildcard\",\n"
+        "    \"interfaces\": [ \"*\" ] },\n"
         "\"option-def\": [ {\n"
+        "    \"comment\": \"An option definition\",\n"
         "    \"name\": \"foo\",\n"
         "    \"code\": 100,\n"
-        "    \"comment\": \"An option definition\",\n"
         "    \"type\": \"ipv4-address\",\n"
         "    \"space\": \"isc\"\n"
         " } ],\n"
         "\"option-data\": [ {\n"
-        "    \"name\": \"dhcp-message\",\n"
         "    \"comment\": \"Set option value\",\n"
+        "    \"name\": \"dhcp-message\",\n"
         "    \"data\": \"ABCDEF0105\",\n"
         "    \"csv-format\": false\n"
         " } ],\n"
         "\"client-classes\": [\n"
         "    {\n"
-        "       \"name\": \"all\",\n"
         "       \"comment\": \"match all\",\n"
+        "       \"name\": \"all\",\n"
         "       \"test\": \"'' == ''\"\n"
         "    },\n"
         "    {\n"
         "       \"name\": \"none\"\n"
         "    },\n"
         "    {\n"
-        "       \"name\": \"two\",\n"
         "       \"comment\": \"first comment\",\n"
-        "       \"comment\": \"second comment\"\n"
+        "       \"comment\": \"second comment\",\n"
+        "       \"name\": \"two\"\n"
         "    },\n"
         "    {\n"
-        "       \"name\": \"both\",\n"
         "       \"comment\": \"a comment\",\n"
+        "       \"name\": \"both\",\n"
         "       \"user-context\": {\n"
         "           \"version\": 1\n"
         "       }\n"
         "    }\n"
         "    ],\n"
+        "\"control-socket\": {\n"
+        "    \"comment\": \"REST API\",\n"
+        "    \"socket-type\": \"unix\",\n"
+        "    \"socket-name\": \"/tmp/kea4-ctrl-socket\",\n"
+        "    \"user-context\": { \"comment\": \"Indirect comment\" }\n"
+        "},\n"
         "\"shared-networks\": [ {\n"
-        "    \"name\": \"foo\"\n,"
         "    \"comment\": \"A shared network\"\n,"
+        "    \"name\": \"foo\"\n,"
         "    \"subnet4\": [\n"
         "    { \n"
-        "        \"subnet\": \"192.0.1.0/24\",\n"
         "        \"comment\": \"A subnet\"\n,"
+        "        \"subnet\": \"192.0.1.0/24\",\n"
+        "        \"id\": 100,\n"
         "        \"pools\": [\n"
         "        {\n"
-        "             \"pool\": \"192.0.1.1-192.0.1.10\",\n"
-        "             \"comment\": \"A pool\"\n"
+        "             \"comment\": \"A pool\",\n"
+        "             \"pool\": \"192.0.1.1-192.0.1.10\"\n"
+        "        }\n"
+        "        ],\n"
+        "        \"reservations\": [\n"
+        "        {\n"
+        "             \"comment\": \"A host reservation\",\n"
+        "             \"hw-address\": \"AA:BB:CC:DD:EE:FF\",\n"
+        "             \"hostname\": \"foo.example.com\",\n"
+        "             \"option-data\": [ {\n"
+        "                 \"comment\": \"An option in a reservation\",\n"
+        "                 \"name\": \"domain-name\",\n"
+        "                 \"data\": \"example.com\"\n"
+        "             } ]\n"
         "        }\n"
         "        ]\n"
         "    }\n"
         "    ]\n"
-        " } ]\n"
-        "} \n";
+        " } ],\n"
+        "\"dhcp-ddns\": {\n"
+        "    \"comment\": \"No dynamic DNS\",\n"
+        "    \"enable-updates\": false\n"
+        "}\n"
+        "}\n";
 
     extractConfig(config);
     configure(config, CONTROL_RESULT_SUCCESS, "");
@@ -5675,8 +5702,20 @@ TEST_F(Dhcp4ParserTest, comments) {
     ASSERT_TRUE(ctx->get("comment"));
     EXPECT_EQ("\"A DHCPv4 server\"", ctx->get("comment")->str());
 
+    // There is a network interface configuration.
+    ConstCfgIfacePtr iface = CfgMgr::instance().getStagingCfg()->getCfgIface();
+    ASSERT_TRUE(iface);
+
+    // Check network interface configuration user context.
+    ConstElementPtr ctx_iface = iface->getContext();
+    ASSERT_TRUE(ctx_iface);
+    ASSERT_EQ(1, ctx_iface->size());
+    ASSERT_TRUE(ctx_iface->get("comment"));
+    EXPECT_EQ("\"Use wildcard\"", ctx_iface->get("comment")->str());
+
     // There is a global option definition.
-    OptionDefinitionPtr opt_def = LibDHCP::getRuntimeOptionDef("isc", 100);
+    const OptionDefinitionPtr& opt_def =
+        LibDHCP::getRuntimeOptionDef("isc", 100);
     ASSERT_TRUE(opt_def);
     EXPECT_EQ("foo", opt_def->getName());
     EXPECT_EQ(100, opt_def->getCode());
@@ -5692,7 +5731,7 @@ TEST_F(Dhcp4ParserTest, comments) {
     EXPECT_EQ("\"An option definition\"", ctx_opt_def->get("comment")->str());
 
     // There is an option descriptor aka option data.
-    OptionDescriptor opt_desc =
+    const OptionDescriptor& opt_desc =
         CfgMgr::instance().getStagingCfg()->getCfgOption()->
             get(DHCP4_OPTION_SPACE, DHO_DHCP_MESSAGE);
     ASSERT_TRUE(opt_desc.option_);
@@ -5706,7 +5745,7 @@ TEST_F(Dhcp4ParserTest, comments) {
     EXPECT_EQ("\"Set option value\"", ctx_opt_desc->get("comment")->str());
 
     // And there are some client classes.
-    ClientClassDictionaryPtr dict =
+    const ClientClassDictionaryPtr& dict =
         CfgMgr::instance().getStagingCfg()->getClientClassDictionary();
     ASSERT_TRUE(dict);
     EXPECT_EQ(4, dict->getClasses()->size());
@@ -5752,15 +5791,34 @@ TEST_F(Dhcp4ParserTest, comments) {
     ASSERT_TRUE(ctx_class->get("version"));
     EXPECT_EQ("1", ctx_class->get("version")->str());
 
+    // There is a control socket.
+    ConstElementPtr socket =
+        CfgMgr::instance().getStagingCfg()->getControlSocketInfo();
+    ASSERT_TRUE(socket);
+    ASSERT_TRUE(socket->get("socket-type"));
+    EXPECT_EQ("\"unix\"", socket->get("socket-type")->str());
+    ASSERT_TRUE(socket->get("socket-name"));
+    EXPECT_EQ("\"/tmp/kea4-ctrl-socket\"", socket->get("socket-name")->str());
+
+    // Check control socket comment and user context.
+    ConstElementPtr ctx_socket = socket->get("comment");
+    ASSERT_TRUE(ctx_socket);
+    EXPECT_EQ("\"REST API\"", ctx_socket->str());
+    ctx_socket = socket->get("user-context");
+    ASSERT_EQ(1, ctx_socket->size());
+    ASSERT_TRUE(ctx_socket->get("comment"));
+    EXPECT_EQ("\"Indirect comment\"", ctx_socket->get("comment")->str());
+
     // Now verify that the shared network was indeed configured.
-    CfgSharedNetworks4Ptr cfg_net = CfgMgr::instance().getStagingCfg()
-        ->getCfgSharedNetworks4();
+    const CfgSharedNetworks4Ptr& cfg_net =
+        CfgMgr::instance().getStagingCfg()->getCfgSharedNetworks4();
     ASSERT_TRUE(cfg_net);
     const SharedNetwork4Collection* nets = cfg_net->getAll();
     ASSERT_TRUE(nets);
     ASSERT_EQ(1, nets->size());
     SharedNetwork4Ptr net = nets->at(0);
     ASSERT_TRUE(net);
+    EXPECT_EQ("foo", net->getName());
 
     // Check shared network user context.
     ConstElementPtr ctx_net = net->getContext();
@@ -5770,11 +5828,13 @@ TEST_F(Dhcp4ParserTest, comments) {
     EXPECT_EQ("\"A shared network\"", ctx_net->get("comment")->str());
 
     // The shared network has a subnet.
-    const Subnet4Collection * subs = net->getAllSubnets();
+    const Subnet4Collection* subs = net->getAllSubnets();
     ASSERT_TRUE(subs);
     ASSERT_EQ(1, subs->size());
     Subnet4Ptr sub = subs->at(0);
     ASSERT_TRUE(sub);
+    EXPECT_EQ(100, sub->getID());
+    EXPECT_EQ("192.0.1.0/24", sub->toText());
 
     // Check subnet user context.
     ConstElementPtr ctx_sub = sub->getContext();
@@ -5795,6 +5855,66 @@ TEST_F(Dhcp4ParserTest, comments) {
     ASSERT_EQ(1, ctx_pool->size());
     ASSERT_TRUE(ctx_pool->get("comment"));
     EXPECT_EQ("\"A pool\"", ctx_pool->get("comment")->str());
+
+    // The subnet has a host reservation.
+    uint8_t hw[] = { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
+    HWAddrPtr hwaddr(new HWAddr(hw, sizeof(hw), HTYPE_ETHER));
+    ConstHostPtr host =
+        CfgMgr::instance().getStagingCfg()->getCfgHosts()->get4(100, hwaddr);
+    ASSERT_TRUE(host);
+    EXPECT_EQ(Host::IDENT_HWADDR, host->getIdentifierType());
+    EXPECT_EQ("aa:bb:cc:dd:ee:ff", host->getHWAddress()->toText(false));
+    EXPECT_FALSE(host->getDuid());
+    EXPECT_EQ(100, host->getIPv4SubnetID());
+    EXPECT_EQ(0, host->getIPv6SubnetID());
+    EXPECT_EQ("foo.example.com", host->getHostname());
+
+    // Check host user context.
+    ConstElementPtr ctx_host = host->getContext();
+    ASSERT_TRUE(ctx_host);
+    ASSERT_EQ(1, ctx_host->size());
+    ASSERT_TRUE(ctx_host->get("comment"));
+    EXPECT_EQ("\"A host reservation\"", ctx_host->get("comment")->str());
+
+    // The host reservation has an option data.
+    ConstCfgOptionPtr opts = host->getCfgOption4();
+    ASSERT_TRUE(opts);
+    EXPECT_FALSE(opts->empty());
+    const OptionDescriptor& host_desc =
+        opts->get(DHCP4_OPTION_SPACE, DHO_DOMAIN_NAME);
+    ASSERT_TRUE(host_desc.option_);
+    EXPECT_EQ(DHO_DOMAIN_NAME, host_desc.option_->getType());
+
+    // Check embedded option data user context.
+    ConstElementPtr ctx_host_desc = host_desc.getContext();
+    ASSERT_TRUE(ctx_host_desc);
+    ASSERT_EQ(1, ctx_host_desc->size());
+    ASSERT_TRUE(ctx_host_desc->get("comment"));
+    EXPECT_EQ("\"An option in a reservation\"",
+              ctx_host_desc->get("comment")->str());
+
+    // Finally dynamic DNS update configuration.
+    const D2ClientConfigPtr& d2 =
+        CfgMgr::instance().getStagingCfg()->getD2ClientConfig();
+    ASSERT_TRUE(d2);
+    EXPECT_FALSE(d2->getEnableUpdates());
+
+    // Check dynamic DNS update configuration user context.
+    ConstElementPtr ctx_d2 = d2->getContext();
+    ASSERT_TRUE(ctx_d2);
+    ASSERT_EQ(1, ctx_d2->size());
+    ASSERT_TRUE(ctx_d2->get("comment"));
+    EXPECT_EQ("\"No dynamic DNS\"", ctx_d2->get("comment")->str());
+
+#if 0
+    // Loggers section supports comments too.
+
+    string logging = "{\n"
+        "\"loggers\": [ {\n"
+        "    \"comment\": \"A logger\",\n"
+        "    \"name\": \"kea-dhcp4\"\n"
+        "} ]\n";
+#endif
 }
 
 }
index 790fbc261eef40306bacd85602b955bc503e3010..40e7264caf710d0836218afb3f69337af252cc52 100644 (file)
@@ -16,6 +16,7 @@
 #include <dhcp4/tests/dhcp4_test_utils.h>
 #include <dhcp4/tests/get_config_unittest.h>
 #include <dhcp4/dhcp4_srv.h>
+#include <dhcp4/ctrl_dhcp4_srv.h>
 #include <dhcp4/json_config_parser.h>
 #include <dhcpsrv/parsers/simple_parser4.h>
 
@@ -1661,6 +1662,23 @@ const char* EXTRACTED_CONFIGS[] = {
 "                }\n"
 "            }\n"
 "        ],\n"
+"        \"control-socket\": {\n"
+"            \"comment\": \"REST API\",\n"
+"            \"socket-name\": \"/tmp/kea4-ctrl-socket\",\n"
+"            \"socket-type\": \"unix\",\n"
+"            \"user-context\": {\n"
+"                \"comment\": \"Indirect comment\"\n"
+"            }\n"
+"        },\n"
+"        \"dhcp-ddns\": {\n"
+"            \"comment\": \"No dynamic DNS\",\n"
+"            \"enable-updates\": false\n"
+"        },\n"
+"        \"interfaces-config\": {\n"
+"            \"comment\": \"Use wildcard\",\n"
+"            \"interfaces\": [ \"*\" ],\n"
+"            \"re-detect\": false\n"
+"        },\n"
 "        \"option-data\": [\n"
 "            {\n"
 "                \"comment\": \"Set option value\",\n"
@@ -1685,12 +1703,27 @@ const char* EXTRACTED_CONFIGS[] = {
 "                \"subnet4\": [\n"
 "                    {\n"
 "                        \"comment\": \"A subnet\",\n"
+"                        \"id\": 100,\n"
 "                        \"pools\": [\n"
 "                            {\n"
 "                                \"comment\": \"A pool\",\n"
 "                                \"pool\": \"192.0.1.1-192.0.1.10\"\n"
 "                            }\n"
 "                        ],\n"
+"                        \"reservations\": [\n"
+"                            {\n"
+"                                \"comment\": \"A host reservation\",\n"
+"                                \"hostname\": \"foo.example.com\",\n"
+"                                \"hw-address\": \"AA:BB:CC:DD:EE:FF\",\n"
+"                                \"option-data\": [\n"
+"                                    {\n"
+"                                        \"comment\": \"An option in a reservation\",\n"
+"                                        \"data\": \"example.com\",\n"
+"                                        \"name\": \"domain-name\"\n"
+"                                    }\n"
+"                                ]\n"
+"                            }\n"
+"                        ],\n"
 "                        \"subnet\": \"192.0.1.0/24\"\n"
 "                    }\n"
 "                ]\n"
@@ -6384,8 +6417,17 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"server-hostname\": \"\"\n"
 "            }\n"
 "        ],\n"
+"        \"control-socket\": {\n"
+"            \"comment\": \"REST API\",\n"
+"            \"socket-name\": \"/tmp/kea4-ctrl-socket\",\n"
+"            \"socket-type\": \"unix\",\n"
+"            \"user-context\": {\n"
+"                \"comment\": \"Indirect comment\"\n"
+"            }\n"
+"        },\n"
 "        \"decline-probation-period\": 86400,\n"
 "        \"dhcp-ddns\": {\n"
+"            \"comment\": \"No dynamic DNS\",\n"
 "            \"always-include-fqdn\": false,\n"
 "            \"enable-updates\": false,\n"
 "            \"generated-prefix\": \"myhost\",\n"
@@ -6414,7 +6456,8 @@ const char* UNPARSED_CONFIGS[] = {
 "        \"hooks-libraries\": [ ],\n"
 "        \"host-reservation-identifiers\": [ \"hw-address\", \"duid\", \"circuit-id\", \"client-id\" ],\n"
 "        \"interfaces-config\": {\n"
-"            \"interfaces\": [ ],\n"
+"            \"comment\": \"Use wildcard\",\n"
+"            \"interfaces\": [ \"*\" ],\n"
 "            \"re-detect\": false\n"
 "        },\n"
 "        \"lease-database\": {\n"
@@ -6462,7 +6505,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                        \"4o6-interface-id\": \"\",\n"
 "                        \"4o6-subnet\": \"\",\n"
 "                        \"boot-file-name\": \"\",\n"
-"                        \"id\": 1,\n"
+"                        \"id\": 100,\n"
 "                        \"match-client-id\": true,\n"
 "                        \"next-server\": \"0.0.0.0\",\n"
 "                        \"option-data\": [ ],\n"
@@ -6584,7 +6627,7 @@ public:
         // Open port 0 means to not do anything at all. We don't want to
         // deal with sockets here, just check if configuration handling
         // is sane.
-        srv_.reset(new Dhcpv4Srv(0));
+        srv_.reset(new ControlledDhcpv4Srv(0));
         // Create fresh context.
         resetConfiguration();
     }
@@ -6686,7 +6729,7 @@ public:
         CfgMgr::instance().setFamily(AF_INET);
     }
 
-    boost::scoped_ptr<Dhcpv4Srv> srv_;  ///< DHCP4 server under test
+    boost::scoped_ptr<ControlledDhcpv4Srv> srv_; ///< DHCP4 server under test
     int rcode_;                         ///< Return code from element parsing
     ConstElementPtr comment_;           ///< Reason for parse fail
 };
index f5bec0e103d64a503e37da7a465c6107376b17f2..4a0242c7d645c1a8828b48e08621d33677f5341e 100644 (file)
@@ -16,6 +16,7 @@
 #include <dhcp4/tests/dhcp4_test_utils.h>
 #include <dhcp4/tests/get_config_unittest.h>
 #include <dhcp4/dhcp4_srv.h>
+#include <dhcp4/ctrl_dhcp4_srv.h>
 #include <dhcp4/json_config_parser.h>
 #include <dhcpsrv/parsers/simple_parser4.h>
 
@@ -168,7 +169,7 @@ public:
         // Open port 0 means to not do anything at all. We don't want to
         // deal with sockets here, just check if configuration handling
         // is sane.
-        srv_.reset(new Dhcpv4Srv(0));
+        srv_.reset(new ControlledDhcpv4Srv(0));
         // Create fresh context.
         resetConfiguration();
     }
@@ -270,7 +271,7 @@ public:
         CfgMgr::instance().setFamily(AF_INET);
     }
 
-    boost::scoped_ptr<Dhcpv4Srv> srv_;  ///< DHCP4 server under test
+    boost::scoped_ptr<ControlledDhcpv4Srv> srv_; ///< DHCP4 server under test
     int rcode_;                         ///< Return code from element parsing
     ConstElementPtr comment_;           ///< Reason for parse fail
 };
index 38de3af809d66c8a2da3ac7ab67001932c594a38..ddfb8e39c2fa06166380499ae2e8c0696254fee3 100644 (file)
@@ -137,6 +137,8 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
             return isc::dhcp::Dhcp6Parser::make_SUB_HOOKS_LIBRARY(driver.loc_);
         case Parser6Context::PARSER_DHCP_DDNS:
             return isc::dhcp::Dhcp6Parser::make_SUB_DHCP_DDNS(driver.loc_);
+        case Parser6Context::PARSER_LOGGING:
+            return isc::dhcp::Dhcp6Parser::make_SUB_LOGGING(driver.loc_);
         }
     }
 %}
@@ -810,8 +812,6 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     switch(driver.ctx_) {
     case isc::dhcp::Parser6Context::DHCP6:
     case isc::dhcp::Parser6Context::INTERFACES_CONFIG:
-    case isc::dhcp::Parser6Context::LEASE_DATABASE:
-    case isc::dhcp::Parser6Context::HOSTS_DATABASE:
     case isc::dhcp::Parser6Context::SUBNET6:
     case isc::dhcp::Parser6Context::SHARED_NETWORK:
     case isc::dhcp::Parser6Context::OPTION_DEF:
@@ -834,8 +834,6 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     switch(driver.ctx_) {
     case isc::dhcp::Parser6Context::DHCP6:
     case isc::dhcp::Parser6Context::INTERFACES_CONFIG:
-    case isc::dhcp::Parser6Context::LEASE_DATABASE:
-    case isc::dhcp::Parser6Context::HOSTS_DATABASE:
     case isc::dhcp::Parser6Context::SUBNET6:
     case isc::dhcp::Parser6Context::SHARED_NETWORK:
     case isc::dhcp::Parser6Context::OPTION_DEF:
index 687aa99ea47dc2d9aedb0d1867348d61695fe978..f7bb0592941207ccbd6d73e6342208f526e7a818 100644 (file)
@@ -210,6 +210,7 @@ using namespace std;
   SUB_OPTION_DATA
   SUB_HOOKS_LIBRARY
   SUB_DHCP_DDNS
+  SUB_LOGGING
 ;
 
 %token <std::string> STRING "constant string"
@@ -247,6 +248,7 @@ start: TOPLEVEL_JSON { ctx.ctx_ = ctx.NO_KEYWORD; } sub_json
      | SUB_OPTION_DATA { ctx.ctx_ = ctx.OPTION_DATA; } sub_option_data
      | SUB_HOOKS_LIBRARY { ctx.ctx_ = ctx.HOOKS_LIBRARIES; } sub_hooks_library
      | SUB_DHCP_DDNS { ctx.ctx_ = ctx.DHCP_DDNS; } sub_dhcp_ddns
+     | SUB_LOGGING { ctx.ctx_ = ctx.LOGGING; } sub_logging
      ;
 
 // ---- generic JSON parser ---------------------------------
@@ -552,8 +554,6 @@ database_map_param: database_type
                   | connect_timeout
                   | contact_points
                   | keyspace
-                  | user_context
-                  | comment
                   | unknown_map_entry
                   ;
 
@@ -1945,6 +1945,14 @@ logging_object: LOGGING {
     ctx.leave();
 };
 
+sub_logging: LCURLY_BRACKET {
+    // Parse the Logging map
+    ElementPtr m(new MapElement(ctx.loc2pos(@1)));
+    ctx.stack_.push_back(m);
+} logging_params RCURLY_BRACKET {
+    // parsing completed
+};
+
 // This defines the list of allowed parameters that may appear
 // in the top-level Logging object. It can either be a single
 // parameter or several parameters separated by commas.
index 63f4b882c4b29bcfbf8e54e7bfba469d26c376b5..9cca5e630fa41b085b4100874211766839310e17 100644 (file)
@@ -89,7 +89,11 @@ public:
         PARSER_HOOKS_LIBRARY,
 
         /// This will parse the input as dhcp-ddns. (D2 client config)
-        PARSER_DHCP_DDNS
+        PARSER_DHCP_DDNS,
+
+        /// This will parse the content of Logging.
+        PARSER_LOGGING
+
     } ParserType;
 
     /// @brief Default constructor.
index ad0aab9de6f345b67b3fd80960152c440afef8eb..0d062321e995beaaa444e5ddfe00c15a801bf0bb 100644 (file)
@@ -17,6 +17,7 @@
 #include <dhcp/tests/iface_mgr_test_config.h>
 #include <dhcp6/json_config_parser.h>
 #include <dhcp6/dhcp6_srv.h>
+#include <dhcp6/ctrl_dhcp6_srv.h>
 #include <dhcpsrv/addr_utilities.h>
 #include <dhcpsrv/cfgmgr.h>
 #include <dhcpsrv/cfg_expiration.h>
@@ -812,8 +813,8 @@ public:
         EXPECT_TRUE(pool);
     }
 
-    int rcode_;          ///< Return code (see @ref isc::config::parseAnswer)
-    Dhcpv6Srv srv_;      ///< Instance of the Dhcp6Srv used during tests
+    int rcode_; ///< Return code (see @ref isc::config::parseAnswer)
+    ControlledDhcpv6Srv srv_; ///< Instance of the ControlledDhcp6Srv used during tests
     ConstElementPtr comment_; ///< Comment (see @ref isc::config::parseAnswer)
     string valid_iface_; ///< Valid network interface name (present in system)
     string bogus_iface_; ///< invalid network interface name (not in system)
@@ -6054,66 +6055,96 @@ TEST_F(Dhcp6ParserTest, comments) {
 
     string config = "{\n"
         "\"comment\": \"A DHCPv6 server\",\n"
+        "\"server-id\": {\n"
+        "    \"comment\": \"DHCPv6 specific\",\n"
+        "    \"type\": \"LL\"\n"
+        "},\n"
+        "\"interfaces-config\": {\n"
+        "    \"comment\": \"Use wildcard\",\n"
+        "    \"interfaces\": [ \"*\" ] },\n"
         "\"option-def\": [ {\n"
+        "    \"comment\": \"An option definition\",\n"
         "    \"name\": \"foo\",\n"
         "    \"code\": 100,\n"
-        "    \"comment\": \"An option definition\",\n"
         "    \"type\": \"ipv6-address\",\n"
         "    \"space\": \"isc\"\n"
         " } ],\n"
         "\"option-data\": [ {\n"
-        "    \"name\": \"subscriber-id\",\n"
         "    \"comment\": \"Set option value\",\n"
+        "    \"name\": \"subscriber-id\",\n"
         "    \"data\": \"ABCDEF0105\",\n"
         "        \"csv-format\": false\n"
         " } ],\n"
         "\"client-classes\": [\n"
         "    {\n"
-        "       \"name\": \"all\",\n"
         "       \"comment\": \"match all\",\n"
+        "       \"name\": \"all\",\n"
         "       \"test\": \"'' == ''\"\n"
         "    },\n"
         "    {\n"
         "       \"name\": \"none\"\n"
         "    },\n"
         "    {\n"
-        "       \"name\": \"two\",\n"
         "       \"comment\": \"first comment\",\n"
-        "       \"comment\": \"second comment\"\n"
+        "       \"comment\": \"second comment\",\n"
+        "       \"name\": \"two\"\n"
         "    },\n"
         "    {\n"
-        "       \"name\": \"both\",\n"
         "       \"comment\": \"a comment\",\n"
+        "       \"name\": \"both\",\n"
         "       \"user-context\": {\n"
         "           \"version\": 1\n"
         "       }\n"
         "    }\n"
         "    ],\n"
+        "\"control-socket\": {\n"
+        "    \"comment\": \"REST API\",\n"
+        "    \"socket-type\": \"unix\",\n"
+        "    \"socket-name\": \"/tmp/kea6-ctrl-socket\",\n"
+        "    \"user-context\": { \"comment\": \"Indirect comment\" }\n"
+        "},\n"
         "\"shared-networks\": [ {\n"
-        "    \"name\": \"foo\"\n,"
         "    \"comment\": \"A shared network\"\n,"
+        "    \"name\": \"foo\"\n,"
         "    \"subnet6\": [\n"
         "    { \n"
-        "        \"subnet\": \"2001:db1::/48\",\n"
         "        \"comment\": \"A subnet\"\n,"
+        "        \"subnet\": \"2001:db1::/48\",\n"
+        "        \"id\": 100,\n"
         "        \"pools\": [\n"
         "        {\n"
-        "             \"pool\": \"2001:db1::/64\",\n"
-        "             \"comment\": \"A pool\"\n"
+        "             \"comment\": \"A pool\",\n"
+        "             \"pool\": \"2001:db1::/64\"\n"
         "        }\n"
         "        ],\n"
         "        \"pd-pools\": [\n"
         "        {\n"
+        "             \"comment\": \"A prefix pool\",\n"
         "             \"prefix\": \"2001:db2::\",\n"
         "             \"prefix-len\": 48,\n"
-        "             \"delegated-len\": 64,\n"
-        "             \"comment\": \"A prefix pool\"\n"
+        "             \"delegated-len\": 64\n"
+        "        }\n"
+        "        ],\n"
+        "        \"reservations\": [\n"
+        "        {\n"
+        "             \"comment\": \"A host reservation\",\n"
+        "             \"hw-address\": \"AA:BB:CC:DD:EE:FF\",\n"
+        "             \"hostname\": \"foo.example.com\",\n"
+        "             \"option-data\": [ {\n"
+        "                 \"comment\": \"An option in a reservation\",\n"
+        "                 \"name\": \"domain-search\",\n"
+        "                 \"data\": \"example.com\"\n"
+        "             } ]\n"
         "        }\n"
         "        ]\n"
         "    }\n"
         "    ]\n"
-        " } ]\n"
-        "} \n";
+        " } ],\n"
+        "\"dhcp-ddns\": {\n"
+        "    \"comment\": \"No dynamic DNS\",\n"
+        "    \"enable-updates\": false\n"
+        "}\n"
+        "}\n";
 
     extractConfig(config);
     configure(config, CONTROL_RESULT_SUCCESS, "");
@@ -6125,8 +6156,32 @@ TEST_F(Dhcp6ParserTest, comments) {
     ASSERT_TRUE(ctx->get("comment"));
     EXPECT_EQ("\"A DHCPv6 server\"", ctx->get("comment")->str());
 
+    // There is a server id.
+    ConstCfgDUIDPtr duid = CfgMgr::instance().getStagingCfg()->getCfgDUID();
+    ASSERT_TRUE(duid);
+    EXPECT_EQ(DUID::DUID_LL, duid->getType());
+
+    // Check server id user context.
+    ConstElementPtr ctx_duid = duid->getContext();
+    ASSERT_TRUE(ctx_duid);
+    ASSERT_EQ(1, ctx_duid->size());
+    ASSERT_TRUE(ctx_duid->get("comment"));
+    EXPECT_EQ("\"DHCPv6 specific\"", ctx_duid->get("comment")->str());
+
+    // There is a network interface configuration.
+    ConstCfgIfacePtr iface = CfgMgr::instance().getStagingCfg()->getCfgIface();
+    ASSERT_TRUE(iface);
+
+    // Check network interface configuration user context.
+    ConstElementPtr ctx_iface = iface->getContext();
+    ASSERT_TRUE(ctx_iface);
+    ASSERT_EQ(1, ctx_iface->size());
+    ASSERT_TRUE(ctx_iface->get("comment"));
+    EXPECT_EQ("\"Use wildcard\"", ctx_iface->get("comment")->str());
+
     // There is a global option definition.
-    OptionDefinitionPtr opt_def = LibDHCP::getRuntimeOptionDef("isc", 100);
+    const OptionDefinitionPtr& opt_def =
+        LibDHCP::getRuntimeOptionDef("isc", 100);
     ASSERT_TRUE(opt_def);
     EXPECT_EQ("foo", opt_def->getName());
     EXPECT_EQ(100, opt_def->getCode());
@@ -6142,7 +6197,7 @@ TEST_F(Dhcp6ParserTest, comments) {
     EXPECT_EQ("\"An option definition\"", ctx_opt_def->get("comment")->str());
 
     // There is an option descriptor aka option data.
-    OptionDescriptor opt_desc =
+    const OptionDescriptor& opt_desc =
         CfgMgr::instance().getStagingCfg()->getCfgOption()->
             get(DHCP6_OPTION_SPACE, D6O_SUBSCRIBER_ID);
     ASSERT_TRUE(opt_desc.option_);
@@ -6156,7 +6211,7 @@ TEST_F(Dhcp6ParserTest, comments) {
     EXPECT_EQ("\"Set option value\"", ctx_opt_desc->get("comment")->str());
 
     // And there there are some client classes.
-    ClientClassDictionaryPtr dict =
+    const ClientClassDictionaryPtr& dict =
         CfgMgr::instance().getStagingCfg()->getClientClassDictionary();
     ASSERT_TRUE(dict);
     EXPECT_EQ(4, dict->getClasses()->size());
@@ -6202,15 +6257,34 @@ TEST_F(Dhcp6ParserTest, comments) {
     ASSERT_TRUE(ctx_class->get("version"));
     EXPECT_EQ("1", ctx_class->get("version")->str());
 
+    // There is a control socket.
+    ConstElementPtr socket =
+        CfgMgr::instance().getStagingCfg()->getControlSocketInfo();
+    ASSERT_TRUE(socket);
+    ASSERT_TRUE(socket->get("socket-type"));
+    EXPECT_EQ("\"unix\"", socket->get("socket-type")->str());
+    ASSERT_TRUE(socket->get("socket-name"));
+    EXPECT_EQ("\"/tmp/kea6-ctrl-socket\"", socket->get("socket-name")->str());
+
+    // Check control socket comment and user context.
+    ConstElementPtr ctx_socket = socket->get("comment");
+    ASSERT_TRUE(ctx_socket);
+    EXPECT_EQ("\"REST API\"", ctx_socket->str());
+    ctx_socket = socket->get("user-context");
+    ASSERT_EQ(1, ctx_socket->size());
+    ASSERT_TRUE(ctx_socket->get("comment"));
+    EXPECT_EQ("\"Indirect comment\"", ctx_socket->get("comment")->str());
+
     // Now verify that the shared network was indeed configured.
-    CfgSharedNetworks6Ptr cfg_net = CfgMgr::instance().getStagingCfg()
-        ->getCfgSharedNetworks6();
+    const CfgSharedNetworks6Ptr& cfg_net =
+        CfgMgr::instance().getStagingCfg()->getCfgSharedNetworks6();
     ASSERT_TRUE(cfg_net);
     const SharedNetwork6Collection* nets = cfg_net->getAll();
     ASSERT_TRUE(nets);
     ASSERT_EQ(1, nets->size());
     SharedNetwork6Ptr net = nets->at(0);
     ASSERT_TRUE(net);
+    EXPECT_EQ("foo", net->getName());
 
     // Check shared network user context.
     ConstElementPtr ctx_net = net->getContext();
@@ -6220,7 +6294,7 @@ TEST_F(Dhcp6ParserTest, comments) {
     EXPECT_EQ("\"A shared network\"", ctx_net->get("comment")->str());
 
     // The shared network has a subnet.
-    const Subnet6Collection * subs = net->getAllSubnets();
+    const Subnet6Collection* subs = net->getAllSubnets();
     ASSERT_TRUE(subs);
     ASSERT_EQ(1, subs->size());
     Subnet6Ptr sub = subs->at(0);
@@ -6232,6 +6306,8 @@ TEST_F(Dhcp6ParserTest, comments) {
     ASSERT_EQ(1, ctx_sub->size());
     ASSERT_TRUE(ctx_sub->get("comment"));
     EXPECT_EQ("\"A subnet\"", ctx_sub->get("comment")->str());
+    EXPECT_EQ(100, sub->getID());
+    EXPECT_EQ("2001:db1::/48", sub->toText());
 
     // The subnet has a pool.
     const PoolCollection& pools = sub->getPools(Lease::TYPE_NA);
@@ -6258,6 +6334,66 @@ TEST_F(Dhcp6ParserTest, comments) {
     ASSERT_EQ(1, ctx_pdpool->size());
     ASSERT_TRUE(ctx_pdpool->get("comment"));
     EXPECT_EQ("\"A prefix pool\"", ctx_pdpool->get("comment")->str());
+
+    // The subnet has a host reservation.
+    uint8_t hw[] = { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF };
+    HWAddrPtr hwaddr(new HWAddr(hw, sizeof(hw), HTYPE_ETHER));
+    ConstHostPtr host =
+        CfgMgr::instance().getStagingCfg()->getCfgHosts()->get6(100, DuidPtr(), hwaddr);
+    ASSERT_TRUE(host);
+    EXPECT_EQ(Host::IDENT_HWADDR, host->getIdentifierType());
+    EXPECT_EQ("aa:bb:cc:dd:ee:ff", host->getHWAddress()->toText(false));
+    EXPECT_FALSE(host->getDuid());
+    EXPECT_EQ(0, host->getIPv4SubnetID());
+    EXPECT_EQ(100, host->getIPv6SubnetID());
+    EXPECT_EQ("foo.example.com", host->getHostname());
+
+    // Check host user context.
+    ConstElementPtr ctx_host = host->getContext();
+    ASSERT_TRUE(ctx_host);
+    ASSERT_EQ(1, ctx_host->size());
+    ASSERT_TRUE(ctx_host->get("comment"));
+    EXPECT_EQ("\"A host reservation\"", ctx_host->get("comment")->str());
+
+    // The host reservation has an option data.
+    ConstCfgOptionPtr opts = host->getCfgOption6();
+    ASSERT_TRUE(opts);
+    EXPECT_FALSE(opts->empty());
+    const OptionDescriptor& host_desc =
+        opts->get(DHCP6_OPTION_SPACE, D6O_DOMAIN_SEARCH);
+    ASSERT_TRUE(host_desc.option_);
+    EXPECT_EQ(D6O_DOMAIN_SEARCH, host_desc.option_->getType());
+
+    // Check embedded option data user context.
+    ConstElementPtr ctx_host_desc = host_desc.getContext();
+    ASSERT_TRUE(ctx_host_desc);
+    ASSERT_EQ(1, ctx_host_desc->size());
+    ASSERT_TRUE(ctx_host_desc->get("comment"));
+    EXPECT_EQ("\"An option in a reservation\"",
+              ctx_host_desc->get("comment")->str());
+
+    // Finally dynamic DNS update configuration.
+    const D2ClientConfigPtr& d2 =
+        CfgMgr::instance().getStagingCfg()->getD2ClientConfig();
+    ASSERT_TRUE(d2);
+    EXPECT_FALSE(d2->getEnableUpdates());
+
+    // Check dynamic DNS update configuration user context.
+    ConstElementPtr ctx_d2 = d2->getContext();
+    ASSERT_TRUE(ctx_d2);
+    ASSERT_EQ(1, ctx_d2->size());
+    ASSERT_TRUE(ctx_d2->get("comment"));
+    EXPECT_EQ("\"No dynamic DNS\"", ctx_d2->get("comment")->str());
+
+#if 0
+    // Loggers section supports comments too.
+
+    string logging = "{\n"
+        "\"loggers\": [ {\n"
+        "    \"comment\": \"A logger\",\n"
+        "    \"name\": \"kea-dhcp6\"\n"
+        "} ]\n";
+#endif
 }
 
 };
index 5087aaa73e713d469b364392ff6e0d6025fd6d67..298e71647d0593dc03615e324d879f1da9d08d82 100644 (file)
@@ -17,6 +17,7 @@
 #include <dhcp6/tests/dhcp6_test_utils.h>
 #include <dhcp6/tests/get_config_unittest.h>
 #include <dhcp6/dhcp6_srv.h>
+#include <dhcp6/ctrl_dhcp6_srv.h>
 #include <dhcp6/json_config_parser.h>
 #include <dhcpsrv/parsers/simple_parser6.h>
 
@@ -1531,6 +1532,23 @@ const char* EXTRACTED_CONFIGS[] = {
 "                }\n"
 "            }\n"
 "        ],\n"
+"        \"control-socket\": {\n"
+"            \"comment\": \"REST API\",\n"
+"            \"socket-name\": \"/tmp/kea6-ctrl-socket\",\n"
+"            \"socket-type\": \"unix\",\n"
+"            \"user-context\": {\n"
+"                \"comment\": \"Indirect comment\"\n"
+"            }\n"
+"        },\n"
+"        \"dhcp-ddns\": {\n"
+"            \"comment\": \"No dynamic DNS\",\n"
+"            \"enable-updates\": false\n"
+"        },\n"
+"        \"interfaces-config\": {\n"
+"            \"comment\": \"Use wildcard\",\n"
+"            \"interfaces\": [ \"*\" ],\n"
+"            \"re-detect\": false\n"
+"        },\n"
 "        \"option-data\": [\n"
 "            {\n"
 "                \"comment\": \"Set option value\",\n"
@@ -1548,6 +1566,10 @@ const char* EXTRACTED_CONFIGS[] = {
 "                \"type\": \"ipv6-address\"\n"
 "            }\n"
 "        ],\n"
+"        \"server-id\": {\n"
+"            \"comment\": \"DHCPv6 specific\",\n"
+"            \"type\": \"LL\"\n"
+"        },\n"
 "        \"shared-networks\": [\n"
 "            {\n"
 "                \"comment\": \"A shared network\",\n"
@@ -1555,6 +1577,7 @@ const char* EXTRACTED_CONFIGS[] = {
 "                \"subnet6\": [\n"
 "                    {\n"
 "                        \"comment\": \"A subnet\",\n"
+"                        \"id\": 100,\n"
 "                        \"pd-pools\": [\n"
 "                            {\n"
 "                                \"comment\": \"A prefix pool\",\n"
@@ -1569,6 +1592,20 @@ const char* EXTRACTED_CONFIGS[] = {
 "                                \"pool\": \"2001:db1::/64\"\n"
 "                            }\n"
 "                        ],\n"
+"                        \"reservations\": [\n"
+"                            {\n"
+"                                \"comment\": \"A host reservation\",\n"
+"                                \"hostname\": \"foo.example.com\",\n"
+"                                \"hw-address\": \"AA:BB:CC:DD:EE:FF\",\n"
+"                                \"option-data\": [\n"
+"                                    {\n"
+"                                        \"comment\": \"An option in a reservation\",\n"
+"                                        \"data\": \"example.com\",\n"
+"                                        \"name\": \"domain-search\"\n"
+"                                    }\n"
+"                                ]\n"
+"                            }\n"
+"                        ],\n"
 "                        \"subnet\": \"2001:db1::/48\"\n"
 "                    }\n"
 "                ]\n"
@@ -5974,8 +6011,17 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"option-data\": [ ]\n"
 "            }\n"
 "        ],\n"
+"        \"control-socket\": {\n"
+"            \"comment\": \"REST API\",\n"
+"            \"socket-name\": \"/tmp/kea6-ctrl-socket\",\n"
+"            \"socket-type\": \"unix\",\n"
+"            \"user-context\": {\n"
+"                \"comment\": \"Indirect comment\"\n"
+"            }\n"
+"        },\n"
 "        \"decline-probation-period\": 86400,\n"
 "        \"dhcp-ddns\": {\n"
+"            \"comment\": \"No dynamic DNS\",\n"
 "            \"always-include-fqdn\": false,\n"
 "            \"enable-updates\": false,\n"
 "            \"generated-prefix\": \"myhost\",\n"
@@ -6003,7 +6049,8 @@ const char* UNPARSED_CONFIGS[] = {
 "        \"hooks-libraries\": [ ],\n"
 "        \"host-reservation-identifiers\": [ \"hw-address\", \"duid\" ],\n"
 "        \"interfaces-config\": {\n"
-"            \"interfaces\": [ ],\n"
+"            \"comment\": \"Use wildcard\",\n"
+"            \"interfaces\": [ \"*\" ],\n"
 "            \"re-detect\": false\n"
 "        },\n"
 "        \"lease-database\": {\n"
@@ -6035,12 +6082,13 @@ const char* UNPARSED_CONFIGS[] = {
 "        ],\n"
 "        \"relay-supplied-options\": [ \"65\" ],\n"
 "        \"server-id\": {\n"
+"            \"comment\": \"DHCPv6 specific\",\n"
 "            \"enterprise-id\": 0,\n"
 "            \"htype\": 0,\n"
 "            \"identifier\": \"\",\n"
 "            \"persist\": true,\n"
 "            \"time\": 0,\n"
-"            \"type\": \"LLT\"\n"
+"            \"type\": \"LL\"\n"
 "        },\n"
 "        \"shared-networks\": [\n"
 "            {\n"
@@ -6058,7 +6106,7 @@ const char* UNPARSED_CONFIGS[] = {
 "                \"subnet6\": [\n"
 "                    {\n"
 "                        \"comment\": \"A subnet\",\n"
-"                        \"id\": 1,\n"
+"                        \"id\": 100,\n"
 "                        \"option-data\": [ ],\n"
 "                        \"pd-pools\": [\n"
 "                            {\n"
@@ -6293,8 +6341,8 @@ public:
         CfgMgr::instance().setFamily(AF_INET6);
     }
 
-    int rcode_;          ///< Return code (see @ref isc::config::parseAnswer)
-    Dhcpv6Srv srv_;      ///< Instance of the Dhcp6Srv used during tests
+    int rcode_; ///< Return code (see @ref isc::config::parseAnswer)
+    ControlledDhcpv6Srv srv_; ///< Instance of the ControlledDhcp6Srv used during tests
     ConstElementPtr comment_; ///< Comment (see @ref isc::config::parseAnswer)
 };
 
index efb2accc4eef3f28da70fa0e074e4ad1f253cc3c..50c71cd53dc86e5f9f4069c02d7b4cbb8454db7d 100644 (file)
@@ -17,6 +17,7 @@
 #include <dhcp6/tests/dhcp6_test_utils.h>
 #include <dhcp6/tests/get_config_unittest.h>
 #include <dhcp6/dhcp6_srv.h>
+#include <dhcp6/ctrl_dhcp6_srv.h>
 #include <dhcp6/json_config_parser.h>
 #include <dhcpsrv/parsers/simple_parser6.h>
 
@@ -274,8 +275,8 @@ public:
         CfgMgr::instance().setFamily(AF_INET6);
     }
 
-    int rcode_;          ///< Return code (see @ref isc::config::parseAnswer)
-    Dhcpv6Srv srv_;      ///< Instance of the Dhcp6Srv used during tests
+    int rcode_; ///< Return code (see @ref isc::config::parseAnswer)
+    ControlledDhcpv6Srv srv_; ///< Instance of the ControlledDhcp6Srv used during tests
     ConstElementPtr comment_; ///< Comment (see @ref isc::config::parseAnswer)
 };
 
index 53ae5001c4ea0b9e971d921f05ede90b091ce9de..e93631dc7b6cd1c9803903703f3e53c6d3409eb5 100644 (file)
@@ -65,12 +65,12 @@ CfgDbAccess::getAccessString(const std::string& access_string) const {
     return (s.str());
 }
 
-void
-CfgDbAccess::toElementDbAccessString(const std::string& dbaccess,
-                                     ElementPtr map) {
+ElementPtr
+CfgDbAccess::toElementDbAccessString(const std::string& dbaccess) {
+    ElementPtr result = Element::createMap();
     // Code from DatabaseConnection::parse
     if (dbaccess.empty()) {
-        return;
+        return (result);
     }
     std::vector<std::string> tokens;
     boost::split(tokens, dbaccess, boost::is_any_of(std::string("\t ")));
@@ -86,7 +86,7 @@ CfgDbAccess::toElementDbAccessString(const std::string& dbaccess,
                 int64_t int_value;
                 try {
                     int_value = boost::lexical_cast<int64_t>(value);
-                    map->set(keyword, Element::create(int_value));
+                    result->set(keyword, Element::create(int_value));
                 } catch (...) {
                     isc_throw(ToElementError, "invalid DB access "
                               << "integer parameter: "
@@ -95,9 +95,9 @@ CfgDbAccess::toElementDbAccessString(const std::string& dbaccess,
             } else if ((keyword == "persist") ||
                        (keyword == "readonly")) {
                 if (value == "true") {
-                    map->set(keyword, Element::create(true));
+                    result->set(keyword, Element::create(true));
                 } else if (value == "false") {
-                    map->set(keyword, Element::create(false));
+                    result->set(keyword, Element::create(false));
                 } else {
                     isc_throw(ToElementError, "invalid DB access "
                               << "boolean parameter: "
@@ -110,7 +110,7 @@ CfgDbAccess::toElementDbAccessString(const std::string& dbaccess,
                        (keyword == "name") ||
                        (keyword == "contact_points") ||
                        (keyword == "keyspace")) {
-                map->set(keyword, Element::create(value));
+                result->set(keyword, Element::create(value));
             } else {
                 isc_throw(ToElementError, "unknown DB access parameter: "
                           << keyword << "=" << value);
@@ -120,23 +120,6 @@ CfgDbAccess::toElementDbAccessString(const std::string& dbaccess,
                       << ", expected format is name=value");
         }
     }
-}
-
-ElementPtr
-CfgLeaseDbAccess::toElement() const {
-    ElementPtr result = Element::createMap();
-    // Add user context
-    contextToElement(result);
-    CfgDbAccess::toElementDbAccessString(lease_db_access_, result);
-    return (result);
-}
-
-ElementPtr
-CfgHostDbAccess::toElement() const {
-    ElementPtr result = Element::createMap();
-    // Add user context
-    contextToElement(result);
-    CfgDbAccess::toElementDbAccessString(host_db_access_, result);
     return (result);
 }
 
index b74e94cc7f4b9f7e1468bf532aa8b258531722f7..2c87e4dafce22a384f14b4a553988360ee1a5b83 100644 (file)
@@ -8,7 +8,6 @@
 #define CFG_DBACCESS_H
 
 #include <cc/cfg_to_element.h>
-#include <cc/user_context.h>
 #include <boost/shared_ptr.hpp>
 #include <string>
 
@@ -20,7 +19,7 @@ namespace dhcp {
 ///
 /// The database access strings use the same format as the strings
 /// passed to the @ref isc::dhcp::LeaseMgrFactory::create function.
-class CfgDbAccess : public UserContext {
+class CfgDbAccess {
 public:
 
     /// @brief Constructor.
@@ -68,10 +67,9 @@ public:
     /// @brief Unparse an access string
     ///
     /// @param dbaccess the database access string
-    /// @param map the element map where the access string is unparse
-    static void
-    toElementDbAccessString(const std::string& dbaccess,
-                            isc::data::ElementPtr map);
+    /// @return a pointer to configuration
+    static
+    isc::data::ElementPtr toElementDbAccessString(const std::string& dbaccess);
 
 protected:
 
@@ -108,7 +106,9 @@ struct CfgLeaseDbAccess : public CfgDbAccess, public isc::data::CfgToElement {
     /// @ref isc::data::CfgToElement::toElement
     ///
     /// @result a pointer to a configuration
-    virtual isc::data::ElementPtr toElement() const;
+    virtual isc::data::ElementPtr toElement() const {
+        return (CfgDbAccess::toElementDbAccessString(lease_db_access_));
+    }
 };
 
 struct CfgHostDbAccess : public CfgDbAccess, public isc::data::CfgToElement {
@@ -120,9 +120,12 @@ struct CfgHostDbAccess : public CfgDbAccess, public isc::data::CfgToElement {
     /// @ref isc::data::CfgToElement::toElement
     ///
     /// @result a pointer to a configuration
-    virtual isc::data::ElementPtr toElement() const;
+    virtual isc::data::ElementPtr toElement() const {
+        return (CfgDbAccess::toElementDbAccessString(host_db_access_));
+    }
 };
 
 }
 }
+
 #endif // CFG_DBACCESS_H
index db54bbd137df00d6278a8a83d5f350b18349bc32..e4231dc1e28b54e2c370b77342b13760391cf2a4 100644 (file)
@@ -56,7 +56,6 @@ DbAccessParser::parse(CfgDbAccessPtr& cfg_db,
     int64_t lfc_interval = 0;
     int64_t timeout = 0;
     int64_t port = 0;
-    ConstElementPtr user_context;
     // 2. Update the copy with the passed keywords.
     BOOST_FOREACH(ConfigPair param, database_config->mapValue()) {
         try {
@@ -79,9 +78,6 @@ DbAccessParser::parse(CfgDbAccessPtr& cfg_db,
                 values_copy[param.first] =
                     boost::lexical_cast<std::string>(port);
 
-            } else if (param.first == "user-context") {
-                user_context = param.second;
-
             } else {
                 values_copy[param.first] = param.second->stringValue();
             }
@@ -162,9 +158,6 @@ DbAccessParser::parse(CfgDbAccessPtr& cfg_db,
         cfg_db->setHostDbAccessString(getDbAccessString());
     }
 
-    if (user_context) {
-        cfg_db->setContext(user_context);
-    }
 }
 
 // Create the database access string
index 4b86a32fd4547f1234f37b0c95ecd3b481bfa4b8..cc8361ae500635d0e63ac7d0c4999714e0c4d993 100644 (file)
@@ -19,7 +19,6 @@ using namespace isc;
 using namespace isc::dhcp;
 using namespace isc::dhcp::test;
 using namespace isc::test;
-using namespace isc::data;
 
 namespace {
 
@@ -52,12 +51,6 @@ TEST(CfgDbAccessTest, setLeaseDbAccessString) {
     // Additional parameters are not in lease_db_access_
     runToElementTest<CfgLeaseDbAccess>(expected, CfgLeaseDbAccess(cfg));
 
-    // Add and check user context
-    std::string user_context = "{ \"foo\": \"bar\" }";
-    cfg.setContext(Element::fromJSON(user_context));
-    expected = "{ \"user-context\": { \"foo\": \"bar\" }, \"type\": \"mysql\" }";
-    runToElementTest<CfgLeaseDbAccess>(expected, CfgLeaseDbAccess(cfg));
-
     // If access string is empty, no parameters will be appended.
     ASSERT_NO_THROW(cfg.setLeaseDbAccessString(""));
     EXPECT_TRUE(cfg.getLeaseDbAccessString().empty());
@@ -82,12 +75,6 @@ TEST(CfgDbAccessTest, setHostDbAccessString) {
     // Additional parameters are not in host_db_access_
     runToElementTest<CfgHostDbAccess>(expected, CfgHostDbAccess(cfg));
 
-    // Add and check user context
-    std::string user_context = "{ \"foo\": \"bar\" }";
-    cfg.setContext(Element::fromJSON(user_context));
-    expected = "{ \"user-context\": { \"foo\": \"bar\" }, \"type\": \"mysql\" }";
-    runToElementTest<CfgHostDbAccess>(expected, CfgHostDbAccess(cfg));
-
     // If access string is empty, no parameters will be appended.
     ASSERT_NO_THROW(cfg.setHostDbAccessString(""));
     EXPECT_TRUE(cfg.getHostDbAccessString().empty());
index e6eb52b334b685f7574285792ded7334f83d50eb..fc2e363276e9dfc49a2080fb2b7c6c8e9aef6b7a 100644 (file)
@@ -78,6 +78,9 @@ EP moveComments1(EP element) {
         } else if (it->first == "user-context") {
             // Do not traverse user-context entries
             result->set("user-context", it->second);
+        } else if (it->first == "control-socket") {
+            // Do not traverse control-socke entries
+            result->set("control-socket", it->second);
         } else {
             // Not comment or user-context
             try {
@@ -171,6 +174,9 @@ EP extractComments1(EP element) {
         if (it->first == "comment") {
             // Do not traverse comment entries
             result->set("comment", it->second);
+        } else if (it->first == "control-socket") {
+            // Do not traverse control-socke entries
+            result->set("control-socket", it->second);
         } else if (it->first == "user-context") {
             if (it->second->contains("comment")) {
                 // Note there is a  entry to move