Mirror the changes made in kea-dhcp6.
return (processConfig(args));
}
+ConstElementPtr
+ControlledDhcpv4Srv::commandSetConfigHandler(const string&,
+ ConstElementPtr args) {
+ const int status_code = 1; // 1 indicates an error
+ ConstElementPtr dhcp4;
+ string message;
+
+ // We are starting the configuration process so we should remove any
+ // staging configuration that has been created during previous
+ // configuration attempts.
+ CfgMgr::instance().rollback();
+
+ // Command arguments are expected to be:
+ // { "Dhcp4": { ... }, "Logging": { ... } }
+ // The Logging component is technically optional, but very recommended.
+ if (!args) {
+ message = "Missing mandatory 'arguments' parameter.";
+ } else {
+ dhcp4 = args->get("Dhcp4");
+ if (!dhcp4) {
+ message = "Missing mandatory 'Dhcp4' parameter.";
+ } else if (dhcp4->getType() != Element::map) {
+ message = "'Dhcp4' parameter expected to be a map.";
+ }
+ }
+
+ if (!message.empty()) {
+ // Something is amiss with arguments, return a failure response.
+ ConstElementPtr result = isc::config::createAnswer(status_code,
+ message);
+ return (result);
+ }
+
+ // Logging is a sibling element and must be be parsed explicitly.
+ // The call to configureLogger parses the given Logging element if
+ // not null, into the staging config. Note this DOES alter the
+ // current loggers, they remain in effect until we apply the
+ // logging config.
+ Daemon::configureLogger(args->get("Logging"),
+ CfgMgr::instance().getStagingCfg());
+
+ // Now we configure the server proper.
+ return (processConfig(dhcp4));
+}
+
ConstElementPtr
ControlledDhcpv4Srv::commandLeasesReclaimHandler(const string&,
ConstElementPtr args) {
} else if (command == "config-reload") {
return (srv->commandConfigReloadHandler(command, args));
+ } else if (command == "set-config") {
+ return (srv->commandSetConfigHandler(command, args));
+
} else if (command == "leases-reclaim") {
return (srv->commandLeasesReclaimHandler(command, args));
}
}
}
+ // Configuration was parsed successfully, apply the new logger
+ // configuration to log4cplus. It is done before commit in case
+ // something goes wrong.
+ CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
+ // Use new configuration.
+ CfgMgr::instance().commit();
return (answer);
}
boost::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, _1, _2));
/// @todo: register config-reload (see CtrlDhcpv4Srv::commandConfigReloadHandler)
+
+ CommandMgr::instance().registerCommand("set-config",
+ boost::bind(&ControlledDhcpv4Srv::commandSetConfigHandler, this, _1, _2));
+
/// @todo: register libreload (see CtrlDhcpv4Srv::commandLibReloadHandler)
CommandMgr::instance().registerCommand("leases-reclaim",
// Deregister any registered commands
CommandMgr::instance().deregisterCommand("shutdown");
+ CommandMgr::instance().deregisterCommand("set-config");
CommandMgr::instance().deregisterCommand("leases-reclaim");
CommandMgr::instance().deregisterCommand("statistic-get");
CommandMgr::instance().deregisterCommand("statistic-reset");
commandConfigReloadHandler(const std::string& command,
isc::data::ConstElementPtr args);
+ /// @brief handler for processing 'set-config' command
+ ///
+ /// This handler processes set-config command, which processes
+ /// configuration specified in args parameter.
+ /// @param command (parameter ignored)
+ /// @param args configuration to be processed. Expected format:
+ /// map containing Dhcp4 map that contains DHCPv4 server configuration.
+ /// May also contain Logging map that specifies logging configuration.
+ ///
+ /// @return status of the command
+ isc::data::ConstElementPtr
+ commandSetConfigHandler(const std::string& command,
+ isc::data::ConstElementPtr args);
/// @brief Handler for processing 'leases-reclaim' command
///
}
}
+/// @brief Initialize the command channel based on the staging configuration
+///
+/// Only close the current channel, if the new channel configuration is
+/// different. This avoids disconnecting a client and hence not sending them
+/// a command result, unless they specifically alter the channel configuration.
+/// In that case the user simply has to accept they'll be disconnected.
+///
+void configureCommandChannel() {
+ // Get new socket configuration.
+ ConstElementPtr sock_cfg =
+ CfgMgr::instance().getStagingCfg()->getControlSocketInfo();
+
+ // Get current socket configuration.
+ ConstElementPtr current_sock_cfg =
+ CfgMgr::instance().getCurrentCfg()->getControlSocketInfo();
+
+ // Determine if the socket configuration has changed. It has if
+ // both old and new configuration is specified but respective
+ // data elements are't equal.
+ bool sock_changed = (sock_cfg && current_sock_cfg &&
+ !sock_cfg->equals(*current_sock_cfg));
+
+ // If the previous or new socket configuration doesn't exist or
+ // the new configuration differs from the old configuration we
+ // close the exisitng socket and open a new socket as appropriate.
+ // Note that closing an existing socket means the clien will not
+ // receive the configuration result.
+ if (!sock_cfg || !current_sock_cfg || sock_changed) {
+ // Close the existing socket (if any).
+ isc::config::CommandMgr::instance().closeCommandSocket();
+
+ if (sock_cfg) {
+ // This will create a control socket and install the external
+ // socket in IfaceMgr. That socket will be monitored when
+ // Dhcp4Srv::receivePacket() calls IfaceMgr::receive4() and
+ // callback in CommandMgr will be called, if necessary.
+ isc::config::CommandMgr::instance().openCommandSocket(sock_cfg);
+ }
+ }
+}
+
isc::data::ConstElementPtr
configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
if (!config_set) {
subnet_parser->build(subnet_config->second);
}
- // Get command socket configuration from the config file.
- // This code expects the following structure:
- // {
- // "socket-type": "unix",
- // "socket-name": "/tmp/kea4.sock"
- // }
- ConstElementPtr sock_cfg =
- CfgMgr::instance().getStagingCfg()->getControlSocketInfo();
-
- // Close existing socket (if any).
- isc::config::CommandMgr::instance().closeCommandSocket();
- if (sock_cfg) {
- // This will create a control socket and will install external socket
- // in IfaceMgr. That socket will be monitored when Dhcp4Srv::receivePacket()
- // calls IfaceMgr::receive4() and callback in CommandMgr will be called,
- // if necessary. If there were previously open command socket, it will
- // be closed.
- isc::config::CommandMgr::instance().openCommandSocket(sock_cfg);
- }
+ // Setup the command channel.
+ configureCommandChannel();
// the leases database parser is the last to be run.
std::map<std::string, ConstElementPtr>::const_iterator leases_config =
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2016 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
// This is a configuration backend implementation that reads the
// configuration from a JSON file.
- // We are starting the configuration process so we should remove any
- // staging configuration that has been created during previous
- // configuration attempts.
- CfgMgr::instance().rollback();
-
isc::data::ConstElementPtr json;
isc::data::ConstElementPtr dhcp4;
isc::data::ConstElementPtr logger;
" Did you forget to add { } around your configuration?");
}
- // If there's no logging element, we'll just pass NULL pointer,
- // which will be handled by configureLogger().
- Daemon::configureLogger(json->get("Logging"),
- CfgMgr::instance().getStagingCfg());
-
- // Get Dhcp4 component from the config
- dhcp4 = json->get("Dhcp4");
- if (!dhcp4) {
- isc_throw(isc::BadValue, "no mandatory 'Dhcp4' entry in"
- " the configuration");
- }
-
// Use parsed JSON structures to configure the server
- result = ControlledDhcpv4Srv::processCommand("config-reload", dhcp4);
+ result = ControlledDhcpv4Srv::processCommand("set-config", json);
if (!result) {
// Undetermined status of the configuration. This should never
// happen, but as the configureDhcp4Server returns a pointer, it is
// theoretically possible that it will return NULL.
isc_throw(isc::BadValue, "undefined result of "
- "processCommand(\"config-reload\", dhcp4)");
+ "processCommand(\"set-config\", json)");
}
// Now check is the returned result is successful (rcode=0) or not
"no details available";
isc_throw(isc::BadValue, reason);
}
-
- // If configuration was parsed successfully, apply the new logger
- // configuration to log4cplus. It is done before commit in case
- // something goes wrong.
- CfgMgr::instance().getStagingCfg()->applyLoggingCfg();
-
- // Use new configuration.
- /// @todo: This commit should be moved to
- /// CtrlDhcp4Srv::commandConfigReloadHandler.
- CfgMgr::instance().commit();
-
} catch (const std::exception& ex) {
// If configuration failed at any stage, we drop the staging
// configuration and continue to use the previous one.
#include <dhcpsrv/lease.h>
#include <dhcpsrv/lease_mgr_factory.h>
#include <hooks/hooks_manager.h>
+#include <log/logger_support.h>
#include <stats/stats_mgr.h>
#include <testutils/unix_control_client.h>
ConstElementPtr answer = server_->processConfig(config);
ASSERT_TRUE(answer);
+#if 0
+ // If the configuration doesn't contain logging config, processConfig()
+ // will revert the logging to default (stdout). We call initLogger()
+ // to restore unit test logging.
+ isc::log::initLogger();
+#endif
+
int status = 0;
ConstElementPtr txt = isc::config::parseAnswer(status, answer);
// This should succeed. If not, print the error message.
#include <dhcpsrv/lease.h>
#include <dhcpsrv/lease_mgr.h>
#include <dhcpsrv/lease_mgr_factory.h>
+#include <log/logger_support.h>
#include <stats/stats_mgr.h>
using namespace std;
// Revert to original data directory.
CfgMgr::instance().setDataDir(original_datadir_);
+
+ // Revert to unit test logging, in case the test reconfigured it.
+ isc::log::initLogger();
}
Dhcpv4SrvTest::Dhcpv4SrvTest()
#include <dhcpsrv/lease.h>
#include <dhcpsrv/lease_mgr_factory.h>
#include <dhcp4/dhcp4_srv.h>
+#include <log/logger_support.h>
#include <asiolink/io_address.h>
#include <cc/command_interpreter.h>
#include <list>
// Create fixed server id.
server_id_.reset(new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER,
asiolink::IOAddress("192.0.3.1")));
+ // Revert to unit test logging
+ isc::log::initLogger();
}
/// @brief Returns fixed server identifier assigned to the naked server
}
virtual ~NakedDhcpv4Srv() {
+ // Revert to unit test logging
+ isc::log::initLogger();
}
/// @brief Dummy server identifier option used by various tests.