mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-09-03 07:25:18 +00:00
[5046] Implement set-config command in kea-dhcp4
Mirror the changes made in kea-dhcp6.
This commit is contained in:
@@ -65,6 +65,51 @@ ControlledDhcpv4Srv::commandConfigReloadHandler(const string&,
|
|||||||
return (processConfig(args));
|
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
|
ConstElementPtr
|
||||||
ControlledDhcpv4Srv::commandLeasesReclaimHandler(const string&,
|
ControlledDhcpv4Srv::commandLeasesReclaimHandler(const string&,
|
||||||
ConstElementPtr args) {
|
ConstElementPtr args) {
|
||||||
@@ -116,6 +161,9 @@ ControlledDhcpv4Srv::processCommand(const string& command,
|
|||||||
} else if (command == "config-reload") {
|
} else if (command == "config-reload") {
|
||||||
return (srv->commandConfigReloadHandler(command, args));
|
return (srv->commandConfigReloadHandler(command, args));
|
||||||
|
|
||||||
|
} else if (command == "set-config") {
|
||||||
|
return (srv->commandSetConfigHandler(command, args));
|
||||||
|
|
||||||
} else if (command == "leases-reclaim") {
|
} else if (command == "leases-reclaim") {
|
||||||
return (srv->commandLeasesReclaimHandler(command, args));
|
return (srv->commandLeasesReclaimHandler(command, args));
|
||||||
}
|
}
|
||||||
@@ -235,7 +283,13 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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);
|
return (answer);
|
||||||
}
|
}
|
||||||
@@ -253,6 +307,10 @@ ControlledDhcpv4Srv::ControlledDhcpv4Srv(uint16_t port /*= DHCP4_SERVER_PORT*/)
|
|||||||
boost::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, _1, _2));
|
boost::bind(&ControlledDhcpv4Srv::commandShutdownHandler, this, _1, _2));
|
||||||
|
|
||||||
/// @todo: register config-reload (see CtrlDhcpv4Srv::commandConfigReloadHandler)
|
/// @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)
|
/// @todo: register libreload (see CtrlDhcpv4Srv::commandLibReloadHandler)
|
||||||
|
|
||||||
CommandMgr::instance().registerCommand("leases-reclaim",
|
CommandMgr::instance().registerCommand("leases-reclaim",
|
||||||
@@ -297,6 +355,7 @@ ControlledDhcpv4Srv::~ControlledDhcpv4Srv() {
|
|||||||
|
|
||||||
// Deregister any registered commands
|
// Deregister any registered commands
|
||||||
CommandMgr::instance().deregisterCommand("shutdown");
|
CommandMgr::instance().deregisterCommand("shutdown");
|
||||||
|
CommandMgr::instance().deregisterCommand("set-config");
|
||||||
CommandMgr::instance().deregisterCommand("leases-reclaim");
|
CommandMgr::instance().deregisterCommand("leases-reclaim");
|
||||||
CommandMgr::instance().deregisterCommand("statistic-get");
|
CommandMgr::instance().deregisterCommand("statistic-get");
|
||||||
CommandMgr::instance().deregisterCommand("statistic-reset");
|
CommandMgr::instance().deregisterCommand("statistic-reset");
|
||||||
|
@@ -143,6 +143,19 @@ private:
|
|||||||
commandConfigReloadHandler(const std::string& command,
|
commandConfigReloadHandler(const std::string& command,
|
||||||
isc::data::ConstElementPtr args);
|
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 Handler for processing 'leases-reclaim' command
|
||||||
///
|
///
|
||||||
|
@@ -501,6 +501,47 @@ void setGlobalParameters4() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @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
|
isc::data::ConstElementPtr
|
||||||
configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
|
configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
|
||||||
if (!config_set) {
|
if (!config_set) {
|
||||||
@@ -632,25 +673,8 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
|
|||||||
subnet_parser->build(subnet_config->second);
|
subnet_parser->build(subnet_config->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get command socket configuration from the config file.
|
// Setup the command channel.
|
||||||
// This code expects the following structure:
|
configureCommandChannel();
|
||||||
// {
|
|
||||||
// "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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// the leases database parser is the last to be run.
|
// the leases database parser is the last to be run.
|
||||||
std::map<std::string, ConstElementPtr>::const_iterator leases_config =
|
std::map<std::string, ConstElementPtr>::const_iterator leases_config =
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
// 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
|
// 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
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
@@ -33,11 +33,6 @@ void configure(const std::string& file_name) {
|
|||||||
// This is a configuration backend implementation that reads the
|
// This is a configuration backend implementation that reads the
|
||||||
// configuration from a JSON file.
|
// 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 json;
|
||||||
isc::data::ConstElementPtr dhcp4;
|
isc::data::ConstElementPtr dhcp4;
|
||||||
isc::data::ConstElementPtr logger;
|
isc::data::ConstElementPtr logger;
|
||||||
@@ -68,26 +63,14 @@ void configure(const std::string& file_name) {
|
|||||||
" Did you forget to add { } around your configuration?");
|
" 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
|
// Use parsed JSON structures to configure the server
|
||||||
result = ControlledDhcpv4Srv::processCommand("config-reload", dhcp4);
|
result = ControlledDhcpv4Srv::processCommand("set-config", json);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
// Undetermined status of the configuration. This should never
|
// Undetermined status of the configuration. This should never
|
||||||
// happen, but as the configureDhcp4Server returns a pointer, it is
|
// happen, but as the configureDhcp4Server returns a pointer, it is
|
||||||
// theoretically possible that it will return NULL.
|
// theoretically possible that it will return NULL.
|
||||||
isc_throw(isc::BadValue, "undefined result of "
|
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
|
// Now check is the returned result is successful (rcode=0) or not
|
||||||
@@ -100,17 +83,6 @@ void configure(const std::string& file_name) {
|
|||||||
"no details available";
|
"no details available";
|
||||||
isc_throw(isc::BadValue, reason);
|
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) {
|
} catch (const std::exception& ex) {
|
||||||
// If configuration failed at any stage, we drop the staging
|
// If configuration failed at any stage, we drop the staging
|
||||||
// configuration and continue to use the previous one.
|
// configuration and continue to use the previous one.
|
||||||
|
@@ -14,6 +14,7 @@
|
|||||||
#include <dhcpsrv/lease.h>
|
#include <dhcpsrv/lease.h>
|
||||||
#include <dhcpsrv/lease_mgr_factory.h>
|
#include <dhcpsrv/lease_mgr_factory.h>
|
||||||
#include <hooks/hooks_manager.h>
|
#include <hooks/hooks_manager.h>
|
||||||
|
#include <log/logger_support.h>
|
||||||
#include <stats/stats_mgr.h>
|
#include <stats/stats_mgr.h>
|
||||||
#include <testutils/unix_control_client.h>
|
#include <testutils/unix_control_client.h>
|
||||||
|
|
||||||
@@ -121,6 +122,13 @@ public:
|
|||||||
ConstElementPtr answer = server_->processConfig(config);
|
ConstElementPtr answer = server_->processConfig(config);
|
||||||
ASSERT_TRUE(answer);
|
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;
|
int status = 0;
|
||||||
ConstElementPtr txt = isc::config::parseAnswer(status, answer);
|
ConstElementPtr txt = isc::config::parseAnswer(status, answer);
|
||||||
// This should succeed. If not, print the error message.
|
// This should succeed. If not, print the error message.
|
||||||
|
@@ -24,6 +24,7 @@
|
|||||||
#include <dhcpsrv/lease.h>
|
#include <dhcpsrv/lease.h>
|
||||||
#include <dhcpsrv/lease_mgr.h>
|
#include <dhcpsrv/lease_mgr.h>
|
||||||
#include <dhcpsrv/lease_mgr_factory.h>
|
#include <dhcpsrv/lease_mgr_factory.h>
|
||||||
|
#include <log/logger_support.h>
|
||||||
#include <stats/stats_mgr.h>
|
#include <stats/stats_mgr.h>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@@ -47,6 +48,9 @@ BaseServerTest::~BaseServerTest() {
|
|||||||
|
|
||||||
// Revert to original data directory.
|
// Revert to original data directory.
|
||||||
CfgMgr::instance().setDataDir(original_datadir_);
|
CfgMgr::instance().setDataDir(original_datadir_);
|
||||||
|
|
||||||
|
// Revert to unit test logging, in case the test reconfigured it.
|
||||||
|
isc::log::initLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
Dhcpv4SrvTest::Dhcpv4SrvTest()
|
Dhcpv4SrvTest::Dhcpv4SrvTest()
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#include <dhcpsrv/lease.h>
|
#include <dhcpsrv/lease.h>
|
||||||
#include <dhcpsrv/lease_mgr_factory.h>
|
#include <dhcpsrv/lease_mgr_factory.h>
|
||||||
#include <dhcp4/dhcp4_srv.h>
|
#include <dhcp4/dhcp4_srv.h>
|
||||||
|
#include <log/logger_support.h>
|
||||||
#include <asiolink/io_address.h>
|
#include <asiolink/io_address.h>
|
||||||
#include <cc/command_interpreter.h>
|
#include <cc/command_interpreter.h>
|
||||||
#include <list>
|
#include <list>
|
||||||
@@ -122,6 +123,8 @@ public:
|
|||||||
// Create fixed server id.
|
// Create fixed server id.
|
||||||
server_id_.reset(new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER,
|
server_id_.reset(new Option4AddrLst(DHO_DHCP_SERVER_IDENTIFIER,
|
||||||
asiolink::IOAddress("192.0.3.1")));
|
asiolink::IOAddress("192.0.3.1")));
|
||||||
|
// Revert to unit test logging
|
||||||
|
isc::log::initLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Returns fixed server identifier assigned to the naked server
|
/// @brief Returns fixed server identifier assigned to the naked server
|
||||||
@@ -167,6 +170,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
virtual ~NakedDhcpv4Srv() {
|
virtual ~NakedDhcpv4Srv() {
|
||||||
|
// Revert to unit test logging
|
||||||
|
isc::log::initLogger();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Dummy server identifier option used by various tests.
|
/// @brief Dummy server identifier option used by various tests.
|
||||||
|
Reference in New Issue
Block a user