"port": 53001,
"dns-server-timeout" : 1000,
+ "control-socket":
+ {
+ "comment": "Control channel",
+ "socket-type": "unix",
+ "socket-name": "/tmp/d2-ctrl-socket"
+ },
+
"forward-ddns":
{
"ddns-domains":
"user-context": { "version": 1 },
+//
+// ----------------- Control Socket -----------------
+//
+
+ "control-socket":
+ {
+ "socket-type": "unix",
+ "socket-name": "/tmp/d2-ctrl-socket"
+ },
//
// ----------------- Forward DDNS ------------------
// "ncr-protocol" : "UDP"
// "ncr-format" : "JSON"
+//
+// ----------------- Control Socket -----------------
+//
+
+// "control-socket":
+// {
+// "socket-type": "unix",
+// "socket-name": "/tmp/d2-ctrl-socket"
+// },
+
//
// ----------------- Forward DDNS ------------------
//
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
</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"/>
<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
</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>
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,
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:
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:
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:
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:
#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;
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();
}
}
// 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");
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 =
" 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
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\" , "
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);
"\"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\": { "
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);
-// 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
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.
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) {
}
}
}
+
+ // Check control-socket
+ checkMap(empty->get("control-socket"), 0);
}
/// @brief Test fixture class for testing TSIGKeyInfo parsing.
" \"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);
{
"DhcpDdns": {
+ "control-socket": {
+ "socket-name": "/tmp/d2-ctrl-socket",
+ "socket-type": "unix"
+ },
"dns-server-timeout": 1000,
"forward-ddns": {
"ddns-domains": [