|
@@ -1,4 +1,4 @@
|
|
|
-// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC")
|
|
|
+// Copyright (C) 2012-2017 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
|
|
@@ -15,8 +15,10 @@
|
|
|
#include <dhcp6/ctrl_dhcp6_srv.h>
|
|
|
#include <dhcp6/tests/dhcp6_test_utils.h>
|
|
|
#include <hooks/hooks_manager.h>
|
|
|
+#include <log/logger_support.h>
|
|
|
#include <stats/stats_mgr.h>
|
|
|
#include <testutils/unix_control_client.h>
|
|
|
+#include <testutils/io_utils.h>
|
|
|
|
|
|
#include "marker_file.h"
|
|
|
#include "test_libraries.h"
|
|
@@ -25,6 +27,7 @@
|
|
|
#include <gtest/gtest.h>
|
|
|
|
|
|
#include <sys/select.h>
|
|
|
+#include <sys/stat.h>
|
|
|
#include <sys/ioctl.h>
|
|
|
#include <cstdlib>
|
|
|
|
|
@@ -148,6 +151,12 @@ public:
|
|
|
ConstElementPtr config;
|
|
|
ASSERT_NO_THROW(config = parseDHCP6(config_txt));
|
|
|
ConstElementPtr answer = server_->processConfig(config);
|
|
|
+
|
|
|
+ // Commit the configuration so any subsequent reconfigurations
|
|
|
+ // will only close the command channel if its configuration has
|
|
|
+ // changed.
|
|
|
+ CfgMgr::instance().commit();
|
|
|
+
|
|
|
ASSERT_TRUE(answer);
|
|
|
|
|
|
int status = 0;
|
|
@@ -291,7 +300,7 @@ TEST_F(CtrlDhcpv6SrvTest, configReload) {
|
|
|
|
|
|
// Use empty parameters list
|
|
|
// Prepare configuration file.
|
|
|
- string config_txt = "{ \"interfaces-config\": {"
|
|
|
+ string config_txt = "{ \"Dhcp6\": { \"interfaces-config\": {"
|
|
|
" \"interfaces\": [ \"*\" ]"
|
|
|
"},"
|
|
|
"\"preferred-lifetime\": 3000,"
|
|
@@ -310,10 +319,10 @@ TEST_F(CtrlDhcpv6SrvTest, configReload) {
|
|
|
" \"pools\": [ { \"pool\": \"2001:db8:3::/80\" } ],"
|
|
|
" \"subnet\": \"2001:db8:3::/64\" "
|
|
|
" } ],"
|
|
|
- "\"valid-lifetime\": 4000 }";
|
|
|
+ "\"valid-lifetime\": 4000 }}";
|
|
|
|
|
|
ConstElementPtr config;
|
|
|
- ASSERT_NO_THROW(config = parseDHCP6(config_txt));
|
|
|
+ ASSERT_NO_THROW(config = parseJSON(config_txt));
|
|
|
|
|
|
// Make sure there are no subnets configured.
|
|
|
CfgMgr::instance().clear();
|
|
@@ -327,13 +336,158 @@ TEST_F(CtrlDhcpv6SrvTest, configReload) {
|
|
|
|
|
|
// Check that the config was indeed applied.
|
|
|
const Subnet6Collection* subnets =
|
|
|
- CfgMgr::instance().getStagingCfg()->getCfgSubnets6()->getAll();
|
|
|
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
|
|
|
EXPECT_EQ(3, subnets->size());
|
|
|
|
|
|
// Clean up after the test.
|
|
|
CfgMgr::instance().clear();
|
|
|
}
|
|
|
|
|
|
+// Check that the "set-config" command will replace current configuration
|
|
|
+TEST_F(CtrlChannelDhcpv6SrvTest, set_config) {
|
|
|
+ createUnixChannelServer();
|
|
|
+
|
|
|
+ // Define strings to permutate the config arguments
|
|
|
+ // (Note the line feeds makes errors easy to find)
|
|
|
+ string set_config_txt = "{ \"command\": \"set-config\" \n";
|
|
|
+ string args_txt = " \"arguments\": { \n";
|
|
|
+ string dhcp6_cfg_txt =
|
|
|
+ " \"Dhcp6\": { \n"
|
|
|
+ " \"interfaces-config\": { \n"
|
|
|
+ " \"interfaces\": [\"*\"] \n"
|
|
|
+ " }, \n"
|
|
|
+ " \"preferred-lifetime\": 3000, \n"
|
|
|
+ " \"valid-lifetime\": 4000, \n"
|
|
|
+ " \"renew-timer\": 1000, \n"
|
|
|
+ " \"rebind-timer\": 2000, \n"
|
|
|
+ " \"lease-database\": { \n"
|
|
|
+ " \"type\": \"memfile\", \n"
|
|
|
+ " \"persist\":false, \n"
|
|
|
+ " \"lfc-interval\": 0 \n"
|
|
|
+ " }, \n"
|
|
|
+ " \"expired-leases-processing\": { \n"
|
|
|
+ " \"reclaim-timer-wait-time\": 0, \n"
|
|
|
+ " \"hold-reclaimed-time\": 0, \n"
|
|
|
+ " \"flush-reclaimed-timer-wait-time\": 0 \n"
|
|
|
+ " },"
|
|
|
+ " \"subnet6\": [ \n";
|
|
|
+ string subnet1 =
|
|
|
+ " {\"subnet\": \"3002::/64\", \n"
|
|
|
+ " \"pools\": [{ \"pool\": \"3002::100-3002::200\" }]}\n";
|
|
|
+ string subnet2 =
|
|
|
+ " {\"subnet\": \"3003::/64\", \n"
|
|
|
+ " \"pools\": [{ \"pool\": \"3003::100-3003::200\" }]}\n";
|
|
|
+ string bad_subnet =
|
|
|
+ " {\"BOGUS\": \"3005::/64\", \n"
|
|
|
+ " \"pools\": [{ \"pool\": \"3005::100-3005::200\" }]}\n";
|
|
|
+ string subnet_footer =
|
|
|
+ " ] \n";
|
|
|
+ string control_socket_header =
|
|
|
+ " ,\"control-socket\": { \n"
|
|
|
+ " \"socket-type\": \"unix\", \n"
|
|
|
+ " \"socket-name\": \"";
|
|
|
+ string control_socket_footer =
|
|
|
+ "\" \n} \n";
|
|
|
+ string logger_txt =
|
|
|
+ " \"Logging\": { \n"
|
|
|
+ " \"loggers\": [ { \n"
|
|
|
+ " \"name\": \"kea\", \n"
|
|
|
+ " \"severity\": \"FATAL\", \n"
|
|
|
+ " \"output_options\": [{ \n"
|
|
|
+ " \"output\": \"/dev/null\" \n"
|
|
|
+ " }] \n"
|
|
|
+ " }] \n"
|
|
|
+ " } \n";
|
|
|
+
|
|
|
+ std::ostringstream os;
|
|
|
+
|
|
|
+ // Create a valid config with all the parts should parse
|
|
|
+ os << set_config_txt << ","
|
|
|
+ << args_txt
|
|
|
+ << dhcp6_cfg_txt
|
|
|
+ << subnet1
|
|
|
+ << subnet_footer
|
|
|
+ << control_socket_header
|
|
|
+ << socket_path_
|
|
|
+ << control_socket_footer
|
|
|
+ << "}\n" // close dhcp6
|
|
|
+ << ","
|
|
|
+ << logger_txt
|
|
|
+ << "}}";
|
|
|
+
|
|
|
+ // Send the set-config command
|
|
|
+ std::string response;
|
|
|
+ sendUnixCommand(os.str(), response);
|
|
|
+
|
|
|
+ // Verify the configuration was successful.
|
|
|
+ EXPECT_EQ("{ \"result\": 0, \"text\": \"Configuration successful.\" }",
|
|
|
+ response);
|
|
|
+
|
|
|
+ // Check that the config was indeed applied.
|
|
|
+ const Subnet6Collection* subnets =
|
|
|
+ CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
|
|
|
+ EXPECT_EQ(1, subnets->size());
|
|
|
+
|
|
|
+ // Create a config with malformed subnet that should fail to parse.
|
|
|
+ os.str("");
|
|
|
+ os << set_config_txt << ","
|
|
|
+ << args_txt
|
|
|
+ << dhcp6_cfg_txt
|
|
|
+ << bad_subnet
|
|
|
+ << subnet_footer
|
|
|
+ << control_socket_header
|
|
|
+ << socket_path_
|
|
|
+ << control_socket_footer
|
|
|
+ << "}\n" // close dhcp6
|
|
|
+ "}}";
|
|
|
+
|
|
|
+ // Send the set-config command
|
|
|
+ sendUnixCommand(os.str(), response);
|
|
|
+
|
|
|
+ // Should fail with a syntax error
|
|
|
+ EXPECT_EQ("{ \"result\": 1, "
|
|
|
+ "\"text\": \"unsupported parameter: BOGUS (<string>:21:26)\" }",
|
|
|
+ response);
|
|
|
+
|
|
|
+ // Check that the config was not lost
|
|
|
+ subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
|
|
|
+ EXPECT_EQ(1, subnets->size());
|
|
|
+
|
|
|
+ // Create a valid config with two subnets and no command channel.
|
|
|
+ // It should succeed but client will not receive a the response
|
|
|
+ os.str("");
|
|
|
+ os << set_config_txt << ","
|
|
|
+ << args_txt
|
|
|
+ << dhcp6_cfg_txt
|
|
|
+ << subnet1
|
|
|
+ << ",\n"
|
|
|
+ << subnet2
|
|
|
+ << subnet_footer
|
|
|
+ << "}\n" // close dhcp6
|
|
|
+ << "}}";
|
|
|
+
|
|
|
+ /* Verify the control channel socket exists */
|
|
|
+ ASSERT_TRUE(fileExists(socket_path_));
|
|
|
+
|
|
|
+ // Send the set-config command
|
|
|
+ sendUnixCommand(os.str(), response);
|
|
|
+
|
|
|
+ /* Verify the control channel socket no longer exists */
|
|
|
+ EXPECT_FALSE(fileExists(socket_path_));
|
|
|
+
|
|
|
+ // With no command channel, should still receive the response.
|
|
|
+ EXPECT_EQ("{ \"result\": 0, \"text\": \"Configuration successful.\" }",
|
|
|
+ response);
|
|
|
+
|
|
|
+ // Check that the config was not lost
|
|
|
+ subnets = CfgMgr::instance().getCurrentCfg()->getCfgSubnets6()->getAll();
|
|
|
+ EXPECT_EQ(2, subnets->size());
|
|
|
+
|
|
|
+ // Clean up after the test.
|
|
|
+ CfgMgr::instance().clear();
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
typedef std::map<std::string, isc::data::ConstElementPtr> ElementMap;
|
|
|
|
|
|
// This test checks which commands are registered by the DHCPv4 server.
|