]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[3543] Checkpoint: specific unit tests to write
authorFrancis Dupont <fdupont@isc.org>
Tue, 26 Jun 2018 14:35:13 +0000 (16:35 +0200)
committerFrancis Dupont <fdupont@isc.org>
Thu, 27 Dec 2018 20:00:13 +0000 (21:00 +0100)
14 files changed:
doc/examples/ddns/comments.json
doc/examples/ddns/sample1.json
doc/examples/ddns/template.json
doc/guide/ctrl-channel.xml
doc/guide/ddns.xml
src/bin/d2/d2_controller.h
src/bin/d2/d2_lexer.cc
src/bin/d2/d2_lexer.ll
src/bin/d2/d2_process.cc
src/bin/d2/d2_simple_parser.cc
src/bin/d2/tests/d2_cfg_mgr_unittests.cc
src/bin/d2/tests/d2_simple_parser_unittest.cc
src/bin/d2/tests/parser_unittest.cc
src/bin/d2/tests/testdata/get_config.json

index 44a28b83642769a26deea8907cd3a2bdd95dd3fb..f97005b0986a4943d6ced4141e7e39cd2cb0a661 100644 (file)
     "port": 53001,
     "dns-server-timeout" : 1000,
 
+    "control-socket":
+    {
+        "comment": "Control channel",
+        "socket-type": "unix",
+        "socket-name": "/tmp/d2-ctrl-socket"
+    },
+
     "forward-ddns":
     {
         "ddns-domains":
index a413dc6e1b0295d042b3224b4501856c5bf5fe52..890fc08adf1783ba4dee273e59cf5e91106da6a1 100644 (file)
 
     "user-context": { "version": 1 },
 
+//
+// ----------------- Control Socket -----------------
+//
+
+    "control-socket":
+    {
+        "socket-type": "unix",
+        "socket-name": "/tmp/d2-ctrl-socket"
+    },
 
 //
 // ----------------- Forward DDNS  ------------------
index c11f5b38e4f66ba126f6975d8425cd4cd079acb5..a3024bf364d527acc3c6965c1d46d0d2a26da175 100644 (file)
 //    "ncr-protocol" : "UDP"
 //    "ncr-format" : "JSON"
 
+//
+// ----------------- Control Socket -----------------
+//
+
+//    "control-socket":
+//    {
+//        "socket-type": "unix",
+//        "socket-name": "/tmp/d2-ctrl-socket"
+//    },
+
 //
 // ----------------- Forward DDNS  ------------------
 //
index 0fdf8e83408b178ccd9aa56359f047b6fddbcaec..213d80db97503ee7e3d7cfd9752d30b5ce941847 100644 (file)
     the server may refuse to start, which will further extend the
     downtime period until the issue is resolved.</para>
 
-    <para>To avoid such problems, both the DHCPv4 and DHCPv6 servers
+    <para>To avoid such problems, the DHCPv4, DHCPv6 and D2 servers
     include support for a mechanism that allows
     on-line reconfiguration without requiring server shutdown.
     Both servers can be instructed to open control sockets, which
     is a communication channel. The server is able to receive
     commands on that channel, act on them and report back status.</para>
 
-    <para>The DHCPv4 and DHCPv6 servers receive commands over the
+    <para>The DHCPv4, DHCPv6 and D2 servers receive commands over the
     unix domain sockets. The details how to configure these sockets,
     see <xref linkend="dhcp4-ctrl-channel"/> and <xref linkend="dhcp6-ctrl-channel"/>. While it is possible control
     the servers directly using unix domain sockets it requires that
@@ -613,6 +613,36 @@ $ curl -X POST -H "Content-Type: application/json" -d '{ "command": "config-get"
 
     </section> <!-- end of commands supported by both servers -->
 
+    <section>
+      <title>Commands Supported by D2 Server</title>
+      <para>The D2 server supports only a subset of DHCPv4 / DHCPv6 server
+      commands:
+      <itemizedlist>
+        <listitem>
+          <simpara>build-report</simpara>
+        </listitem>
+        <listitem>
+          <simpara>config-get</simpara>
+        </listitem>
+        <listitem>
+          <simpara>config-test</simpara>
+        </listitem>
+        <listitem>
+          <simpara>config-write</simpara>
+        </listitem>
+        <listitem>
+          <simpara>list-commands</simpara>
+        </listitem>
+        <listitem>
+          <simpara>shutdown</simpara>
+        </listitem>
+        <listitem>
+          <simpara>version-get</simpara>
+        </listitem>
+      </itemizedlist>
+      </para>
+    </section>
+
     <section xml:id="agent-commands">
       <title>Commands Supported by Control Agent</title>
       <para>The following commands listed in <xref linkend="commands-common"/>
index 2bde0a43b506b6a4a34dd57a88cdfd2e5246caee..fd2e5bc7219f877f60a0bd80122891749b050016 100644 (file)
@@ -238,6 +238,11 @@ strings <userinput>path</userinput>/kea-dhcp-ddns | sed -n 's/;;;; //p'
         <emphasis>Global Server Parameters</emphasis> - values which control connectivity and global server behavior
             </simpara>
           </listitem>
+          <listitem>
+            <simpara>
+              <emphasis>Control Socket</emphasis> - defines the Control Socket type and name.
+            </simpara>
+          </listitem>
           <listitem>
             <simpara>
               <emphasis>TSIG Key Info</emphasis> - defines the TSIG keys used for secure traffic with DNS servers
@@ -320,6 +325,57 @@ corresponding values in the DHCP servers' "dhcp-ddns" configuration section.
 </note>
       </section> <!-- "d2-server-parameter-config" -->
 
+      <section xml:id="d2-ctrl-channel">
+        <title>Management API for the D2 Server</title>
+        <para>
+          The management API allows the issuing of specific management
+          commands, such as configuration retrieval or shutdown.
+          For more details, see <xref linkend="ctrl-channel"/>.
+          Currently the only supported communication channel type is UNIX
+          stream socket. By default there are no sockets open. To instruct
+          Kea to open a socket, the following entry in the configuration
+          file can be used:
+<screen>
+"DhcpDdns": {
+    "control-socket": {
+        "socket-type": "unix",
+        "socket-name": <userinput>"/path/to/the/unix/socket"</userinput>
+    },
+    ...
+}
+</screen>
+        </para>
+
+        <para>
+          The length of the path specified by
+          the <command>socket-name</command> parameter is restricted by
+          the maximum length for the unix socket name on your operating
+          system, i.e. the size of the <command>sun_path</command> field
+          in the <command>sockaddr_un</command> structure, decreased by 1.
+          This value varies on different operating systems between
+          91 and 107 characters. Typical values are 107 on Linux and 103
+          on FreeBSD.
+        </para>
+
+        <para>
+          Communication over control channel is conducted using JSON
+          structures.  See the Control Channel section in the Kea
+          Developer's Guide for more details.
+        </para>
+
+        <para>The D2 server supports the following operational commands:
+          <itemizedlist>
+              <listitem>build-report</listitem>
+              <listitem>config-get</listitem>
+              <listitem>config-test</listitem>
+              <listitem>config-write</listitem>
+              <listitem>list-commands</listitem>
+              <listitem>shutdown</listitem>
+              <listitem>version-get</listitem>
+          </itemizedlist>
+        </para>
+      </section> <!-- "d2-ctrl-channel" -->
+
       <section xml:id="d2-tsig-key-list-config">
         <title>TSIG Key List</title>
         <para>
index e34bfd5d2afc083109685322f10af3a0813f8693..1673533929552edc7667fb090f6a0e84b51e82e4 100644 (file)
 namespace isc {
 namespace d2 {
 
+class D2Controller;
+/// @brief Pointer to a process controller.
+typedef boost::shared_ptr<D2Controller> D2ControllerPtr;
+
 /// @brief Process Controller for D2 Process
 /// This class is the DHCP-DDNS specific derivation of DControllerBase. It
 /// creates and manages an instance of the DHCP-DDNS application process,
index 2878cf69c70bb85e594130faad0c846e2a4beff6..10da0eb1a9b55b8c56971c2f69b49e5d2a2167d5 100644 (file)
@@ -1782,6 +1782,7 @@ YY_RULE_SETUP
     case isc::d2::D2ParserContext::DNS_SERVERS:
     case isc::d2::D2ParserContext::TSIG_KEY:
     case isc::d2::D2ParserContext::TSIG_KEYS:
+    case isc::d2::D2ParserContext::CONTROL_SOCKET:
     case isc::d2::D2ParserContext::LOGGERS:
         return isc::d2::D2Parser::make_USER_CONTEXT(driver.loc_);
     default:
@@ -1801,6 +1802,7 @@ YY_RULE_SETUP
     case isc::d2::D2ParserContext::DNS_SERVERS:
     case isc::d2::D2ParserContext::TSIG_KEY:
     case isc::d2::D2ParserContext::TSIG_KEYS:
+    case isc::d2::D2ParserContext::CONTROL_SOCKET:
     case isc::d2::D2ParserContext::LOGGERS:
         return isc::d2::D2Parser::make_COMMENT(driver.loc_);
     default:
index ce5262d3dbd4f325f6fee51ac114996ce50e3116..df44c7e7fe22064e1c70b038467901fe80a757b1 100644 (file)
@@ -269,6 +269,7 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     case isc::d2::D2ParserContext::DNS_SERVERS:
     case isc::d2::D2ParserContext::TSIG_KEY:
     case isc::d2::D2ParserContext::TSIG_KEYS:
+    case isc::d2::D2ParserContext::CONTROL_SOCKET:
     case isc::d2::D2ParserContext::LOGGERS:
         return isc::d2::D2Parser::make_USER_CONTEXT(driver.loc_);
     default:
@@ -285,6 +286,7 @@ ControlCharacterFill            [^"\\]|\\{JSONEscapeSequence}
     case isc::d2::D2ParserContext::DNS_SERVERS:
     case isc::d2::D2ParserContext::TSIG_KEY:
     case isc::d2::D2ParserContext::TSIG_KEYS:
+    case isc::d2::D2ParserContext::CONTROL_SOCKET:
     case isc::d2::D2ParserContext::LOGGERS:
         return isc::d2::D2Parser::make_COMMENT(driver.loc_);
     default:
index 215c146ba8a9d0549caec4c1336a33649c5e34f4..5848f7f85b45180671d836940beddcf45b0aa9bb 100644 (file)
@@ -10,6 +10,7 @@
 #include <config/command_mgr.h>
 #include <d2/d2_log.h>
 #include <d2/d2_cfg_mgr.h>
+#include <d2/d2_controller.h>
 #include <d2/d2_process.h>
 
 using namespace isc::process;
@@ -248,10 +249,17 @@ D2Process::configureCommandChannel() {
     if (!ctx) {
         return;
     }
+    D2ControllerPtr ctrl =
+        boost::dynamic_pointer_cast<D2Controller>(D2Controller::instance());
+    if (!ctrl) {
+        return;
+    }
     isc::data::ConstElementPtr sock_cfg = ctx->getControlSocketInfo();
-    if (sock_cfg) {
+    if (sock_cfg && (sock_cfg->size() > 0)) {
         // Assume that CommandMgr works with D2 I/O.
+        isc::config::CommandMgr::instance().setIOService(getIoService());
         isc::config::CommandMgr::instance().openCommandSocket(sock_cfg);
+        ctrl->registerCommands();
     }
 }
 
index ad5c68314e69fa64787cfa25a95c5c0a4b1c5a09..6880fd524d1b4219ffd2e8593770bba4a67a9d30 100644 (file)
@@ -120,6 +120,13 @@ D2SimpleParser::setAllDefaults(isc::data::ElementPtr global) {
     // Set global defaults first.
     cnt = setDefaults(global, D2_GLOBAL_DEFAULTS);
 
+    // If the control socket is no present, set it to empty map.
+    if (!global->find("control-socket")) {
+        ConstElementPtr map(new MapElement());
+        global->set("control-socket", map);
+        cnt++;
+    }
+
     // If the key list is present, set its members' defaults
     if (global->find("tsig-keys")) {
         ConstElementPtr keys = global->get("tsig-keys");
index 2579b2ef46a50b83face60aa9217732703a4134f..5ce55843bf61026bf181292ebc180ffce4fd11ca 100644 (file)
@@ -271,6 +271,10 @@ TEST_F(D2CfgMgrTest, defaultValues) {
     ASSERT_NO_THROW(deflt = defaults->get("ip-address"));
     ASSERT_TRUE(deflt);
     EXPECT_EQ(deflt->stringValue(), d2_params_->getIpAddress().toText());
+    ConstElementPtr ctrl_sock;
+    ASSERT_NO_THROW(ctrl_sock = defaults->get("control-socket"));
+    ASSERT_TRUE(ctrl_sock);
+    EXPECT_EQ(0, ctrl_sock->size());
 
     // Check that omitting port gets you its default
     config =
@@ -426,6 +430,8 @@ TEST_F(D2CfgMgrTest, invalidEntry) {
                          " unexpected constant string, expecting JSON");
 }
 
+// Control socket tests in d2_process_unittests.cc
+
 // DdnsDomainList and TSIGKey tests moved to d2_simple_parser_unittest.cc
 
 /// @brief Tests construction of D2CfgMgr
@@ -462,9 +468,13 @@ TEST_F(D2CfgMgrTest, fullConfig) {
     std::string config = "{ "
                         "\"ip-address\" : \"192.168.1.33\" , "
                         "\"port\" : 88 , "
-                        " \"dns-server-timeout\": 333 , "
-                        " \"ncr-protocol\": \"UDP\" , "
-                        " \"ncr-format\": \"JSON\", "
+                        "\"dns-server-timeout\": 333 , "
+                        "\"ncr-protocol\": \"UDP\" , "
+                        "\"ncr-format\": \"JSON\", "
+                        "\"control-socket\" : {"
+                        " \"socket-type\" : \"unix\" ,"
+                        " \"socket-name\" : \"/tmp/d2-ctrl-channel\" "
+                        "},"
                         "\"tsig-keys\": ["
                         "{"
                         "  \"name\": \"d2_key.example.com\" , "
@@ -533,6 +543,16 @@ TEST_F(D2CfgMgrTest, fullConfig) {
     EXPECT_EQ(dhcp_ddns::NCR_UDP, d2_params->getNcrProtocol());
     EXPECT_EQ(dhcp_ddns::FMT_JSON, d2_params->getNcrFormat());
 
+    // Verify that the control socket can be retrieved.
+    ConstElementPtr ctrl_sock = context->getControlSocketInfo();
+    ASSERT_TRUE(ctrl_sock);
+    ASSERT_EQ(Element::map, ctrl_sock->getType());
+    EXPECT_EQ(2, ctrl_sock->size());
+    ASSERT_TRUE(ctrl_sock->get("socket-type"));
+    EXPECT_EQ("\"unix\"", ctrl_sock->get("socket-type")->str());
+    ASSERT_TRUE(ctrl_sock->get("socket-name"));
+    EXPECT_EQ("\"/tmp/d2-ctrl-channel\"", ctrl_sock->get("socket-name")->str());
+
     // Verify that the forward manager can be retrieved.
     DdnsDomainListMgrPtr mgr = context->getForwardMgr();
     ASSERT_TRUE(mgr);
@@ -941,6 +961,11 @@ TEST_F(D2CfgMgrTest, comments) {
                         "\"comment\": \"D2 config\" , "
                         "\"ip-address\" : \"192.168.1.33\" , "
                         "\"port\" : 88 , "
+                        "\"control-socket\": {"
+                        " \"comment\": \"Control channel\" , "
+                        " \"socket-type\": \"unix\" ,"
+                        " \"socket-name\": \"/tmp/d2-ctrl-channel\" "
+                        "},"
                         "\"tsig-keys\": ["
                         "{"
                         "  \"user-context\": { "
@@ -976,6 +1001,13 @@ TEST_F(D2CfgMgrTest, comments) {
     ASSERT_TRUE(ctx->get("comment"));
     EXPECT_EQ("\"D2 config\"", ctx->get("comment")->str());
 
+    // Check control socket.
+    ConstElementPtr ctrl_sock = d2_context->getControlSocketInfo();
+    ASSERT_TRUE(ctrl_sock);
+    ASSERT_TRUE(ctrl_sock->get("user-context"));
+    EXPECT_EQ("{ \"comment\": \"Control channel\" }",
+              ctrl_sock->get("user-context")->str());
+
     // Check TSIG keys.
     TSIGKeyInfoMapPtr keys = d2_context->getKeys();
     ASSERT_TRUE(keys);
index 686d7fae8c5397ca37fcec3dcd4314a98d9ec09e..6bb3ab968e8657a450e4e83a9ddca66db2855646 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2017-2018 Internet Systems Consortium, Inc. ("ISC")
 //
 // This Source Code Form is subject to the terms of the Mozilla Public
 // License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -70,8 +70,22 @@ void checkStringValue(const ConstElementPtr& element,
     ASSERT_EQ(Element::string, element->getType());
 
     // Verify it has the expected value
-        EXPECT_EQ(deflt.value_, element->stringValue());
-    }
+    EXPECT_EQ(deflt.value_, element->stringValue());
+}
+
+/// @brief Checks if specified element is a map
+///
+/// @param element defaulted element to check
+/// @param deflt expected size
+void checkMap(const ConstElementPtr& element, size_t deflt) {
+    ASSERT_TRUE(element);
+
+    // Verify it's a map
+    ASSERT_EQ(Element::map, element->getType());
+
+    // verify the map size
+    EXPECT_EQ(deflt, element->size());
+}
 
 /// TSIGKeyInfo against the given set of values, and that the TSIGKey
 /// member points to a key.
@@ -273,8 +287,8 @@ TEST_F(D2SimpleParserTest, globalD2Defaults) {
 
     EXPECT_NO_THROW(num = D2SimpleParser::setAllDefaults(empty));
 
-    // We expect 5 parameters to be inserted.
-    EXPECT_EQ(num, 8);
+    // We expect 9 parameters to be inserted.
+    EXPECT_EQ(num, 9);
 
     // Let's go over all parameters we have defaults for.
     BOOST_FOREACH(SimpleDefault deflt, D2SimpleParser::D2_GLOBAL_DEFAULTS) {
@@ -296,6 +310,9 @@ TEST_F(D2SimpleParserTest, globalD2Defaults) {
             }
         }
     }
+
+    // Check control-socket
+    checkMap(empty->get("control-socket"), 0);
 }
 
 /// @brief Test fixture class for testing TSIGKeyInfo parsing.
index 2bb62543f638f0d64dfc6c5a289d6c01f878b14d..37c454bf4ef5b8ed9277f9fa9b4c617ef28c46b5 100644 (file)
@@ -128,9 +128,9 @@ TEST(ParserTest, keywordDhcpDdns) {
             " \"ip-address\": \"192.168.77.1\", \n"
             " \"port\": 777 , \n "
             " \"ncr-protocol\": \"UDP\", \n"
-            "\"tsig-keys\": [], \n"
-            "\"forward-ddns\" : {}, \n"
-            "\"reverse-ddns\" : {} \n"
+            " \"tsig-keys\": [], \n"
+            " \"forward-ddns\" : {}, \n"
+            " \"reverse-ddns\" : {} \n"
             "} \n"
          "} \n";
      testParser(txt, D2ParserContext::PARSER_DHCPDDNS);
index b040c058edf54ce31f631f0da07102eb4cbb3414..d0905d1e27d7cc07c6c1d60c74dbf757be63c399 100644 (file)
@@ -1,5 +1,9 @@
 {
     "DhcpDdns": {
+        "control-socket": {
+            "socket-name": "/tmp/d2-ctrl-socket",
+            "socket-type": "unix"
+        },
         "dns-server-timeout": 1000,
         "forward-ddns": {
             "ddns-domains": [