Commit f9db8f64 authored by Francis Dupont's avatar Francis Dupont

[30-implement-control-socket-for-ddns-2] Added channel management - todo finish new unit tests

parent 96414103
...@@ -55,22 +55,22 @@ D2Controller::registerCommands() { ...@@ -55,22 +55,22 @@ D2Controller::registerCommands() {
// These are the commands always supported by the D2 server. // These are the commands always supported by the D2 server.
// Please keep the list in alphabetic order. // Please keep the list in alphabetic order.
CommandMgr::instance().registerCommand("build-report", CommandMgr::instance().registerCommand(BUILD_REPORT_COMMAND,
boost::bind(&D2Controller::buildReportHandler, this, _1, _2)); boost::bind(&D2Controller::buildReportHandler, this, _1, _2));
CommandMgr::instance().registerCommand("config-get", CommandMgr::instance().registerCommand(CONFIG_GET_COMMAND,
boost::bind(&D2Controller::configGetHandler, this, _1, _2)); boost::bind(&D2Controller::configGetHandler, this, _1, _2));
CommandMgr::instance().registerCommand("config-test", CommandMgr::instance().registerCommand(CONFIG_TEST_COMMAND,
boost::bind(&D2Controller::configTestHandler, this, _1, _2)); boost::bind(&D2Controller::configTestHandler, this, _1, _2));
CommandMgr::instance().registerCommand("config-write", CommandMgr::instance().registerCommand(CONFIG_WRITE_COMMAND,
boost::bind(&D2Controller::configWriteHandler, this, _1, _2)); boost::bind(&D2Controller::configWriteHandler, this, _1, _2));
CommandMgr::instance().registerCommand("shutdown", CommandMgr::instance().registerCommand(SHUT_DOWN_COMMAND,
boost::bind(&D2Controller::shutdownHandler, this, _1, _2)); boost::bind(&D2Controller::shutdownHandler, this, _1, _2));
CommandMgr::instance().registerCommand("version-get", CommandMgr::instance().registerCommand(VERSION_GET_COMMAND,
boost::bind(&D2Controller::versionGetHandler, this, _1, _2)); boost::bind(&D2Controller::versionGetHandler, this, _1, _2));
} }
...@@ -81,12 +81,12 @@ D2Controller::deregisterCommands() { ...@@ -81,12 +81,12 @@ D2Controller::deregisterCommands() {
CommandMgr::instance().closeCommandSocket(); CommandMgr::instance().closeCommandSocket();
// Deregister any registered commands (please keep in alphabetic order) // Deregister any registered commands (please keep in alphabetic order)
CommandMgr::instance().deregisterCommand("build-report"); CommandMgr::instance().deregisterCommand(BUILD_REPORT_COMMAND);
CommandMgr::instance().deregisterCommand("config-get"); CommandMgr::instance().deregisterCommand(CONFIG_GET_COMMAND);
CommandMgr::instance().deregisterCommand("config-test"); CommandMgr::instance().deregisterCommand(CONFIG_TEST_COMMAND);
CommandMgr::instance().deregisterCommand("config-write"); CommandMgr::instance().deregisterCommand(CONFIG_WRITE_COMMAND);
CommandMgr::instance().deregisterCommand("shutdown"); CommandMgr::instance().deregisterCommand(SHUT_DOWN_COMMAND);
CommandMgr::instance().deregisterCommand("version-get"); CommandMgr::instance().deregisterCommand(VERSION_GET_COMMAND);
} catch (...) { } catch (...) {
// What to do? Simply ignore... // What to do? Simply ignore...
...@@ -110,7 +110,6 @@ D2Controller::parseFile(const std::string& file_name) { ...@@ -110,7 +110,6 @@ D2Controller::parseFile(const std::string& file_name) {
} }
D2Controller::~D2Controller() { D2Controller::~D2Controller() {
deregisterCommands();
} }
std::string std::string
......
...@@ -12,6 +12,10 @@ ...@@ -12,6 +12,10 @@
namespace isc { namespace isc {
namespace d2 { namespace d2 {
class D2Controller;
/// @brief Pointer to a process controller.
typedef boost::shared_ptr<D2Controller> D2ControllerPtr;
/// @brief Process Controller for D2 Process /// @brief Process Controller for D2 Process
/// This class is the DHCP-DDNS specific derivation of DControllerBase. It /// This class is the DHCP-DDNS specific derivation of DControllerBase. It
/// creates and manages an instance of the DHCP-DDNS application process, /// creates and manages an instance of the DHCP-DDNS application process,
...@@ -46,6 +50,7 @@ public: ...@@ -46,6 +50,7 @@ public:
void registerCommands(); void registerCommands();
/// @brief Deregister commands. /// @brief Deregister commands.
/// @note Does not throw.
void deregisterCommands(); void deregisterCommands();
protected: protected:
...@@ -77,6 +82,9 @@ private: ...@@ -77,6 +82,9 @@ private:
/// @brief Constructor is declared private to maintain the integrity of /// @brief Constructor is declared private to maintain the integrity of
/// the singleton instance. /// the singleton instance.
D2Controller(); D2Controller();
/// To facilitate unit testing.
friend class NakedD2Controller;
}; };
}; // namespace isc::d2 }; // namespace isc::d2
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <config.h> #include <config.h>
#include <asiolink/asio_wrapper.h> #include <asiolink/asio_wrapper.h>
#include <cc/command_interpreter.h> #include <cc/command_interpreter.h>
#include <config/command_mgr.h>
#include <d2/d2_log.h> #include <d2/d2_log.h>
#include <d2/d2_cfg_mgr.h> #include <d2/d2_cfg_mgr.h>
#include <d2/d2_controller.h> #include <d2/d2_controller.h>
...@@ -23,7 +24,8 @@ const unsigned int D2Process::QUEUE_RESTART_PERCENT = 80; ...@@ -23,7 +24,8 @@ const unsigned int D2Process::QUEUE_RESTART_PERCENT = 80;
D2Process::D2Process(const char* name, const asiolink::IOServicePtr& io_service) D2Process::D2Process(const char* name, const asiolink::IOServicePtr& io_service)
: DProcessBase(name, io_service, DCfgMgrBasePtr(new D2CfgMgr())), : DProcessBase(name, io_service, DCfgMgrBasePtr(new D2CfgMgr())),
reconf_queue_flag_(false), shutdown_type_(SD_NORMAL) { reconf_queue_flag_(false), reconf_control_socket_flag_(false),
shutdown_type_(SD_NORMAL) {
// Instantiate queue manager. Note that queue manager does not start // Instantiate queue manager. Note that queue manager does not start
// listening at this point. That can only occur after configuration has // listening at this point. That can only occur after configuration has
...@@ -46,12 +48,19 @@ D2Process::init() { ...@@ -46,12 +48,19 @@ D2Process::init() {
void void
D2Process::run() { D2Process::run() {
LOG_INFO(d2_logger, DHCP_DDNS_STARTED).arg(VERSION); LOG_INFO(d2_logger, DHCP_DDNS_STARTED).arg(VERSION);
D2ControllerPtr controller =
boost::dynamic_pointer_cast<D2Controller>(D2Controller::instance());
try { try {
// Now logging was initialized so commands can be registered. // Now logging was initialized so commands can be registered.
boost::dynamic_pointer_cast<D2Controller>(D2Controller::instance())->registerCommands(); controller->registerCommands();
// Loop forever until we are allowed to shutdown. // Loop forever until we are allowed to shutdown.
while (!canShutdown()) { while (!canShutdown()) {
// Check if the command channel should be (re-)configured.
if (getReconfControlSocketFlag()) {
reconfigureCommandChannel();
}
// Check on the state of the request queue. Take any // Check on the state of the request queue. Take any
// actions necessary regarding it. // actions necessary regarding it.
checkQueueStatus(); checkQueueStatus();
...@@ -65,7 +74,8 @@ D2Process::run() { ...@@ -65,7 +74,8 @@ D2Process::run() {
// a. NCR message has been received // a. NCR message has been received
// b. Transaction IO has completed // b. Transaction IO has completed
// c. Interval timer expired // c. Interval timer expired
// d. Something stopped IO service (runIO returns 0) // d. Control channel event
// e. Something stopped IO service (runIO returns 0)
if (runIO() == 0) { if (runIO() == 0) {
// Pretty sure this amounts to an unexpected stop and we // Pretty sure this amounts to an unexpected stop and we
// should bail out now. Normal shutdowns do not utilize // should bail out now. Normal shutdowns do not utilize
...@@ -76,7 +86,7 @@ D2Process::run() { ...@@ -76,7 +86,7 @@ D2Process::run() {
} }
} catch (const std::exception& ex) { } catch (const std::exception& ex) {
LOG_FATAL(d2_logger, DHCP_DDNS_FAILED).arg(ex.what()); LOG_FATAL(d2_logger, DHCP_DDNS_FAILED).arg(ex.what());
boost::dynamic_pointer_cast<D2Controller>(D2Controller::instance())->deregisterCommands(); controller->deregisterCommands();
isc_throw (DProcessBaseError, isc_throw (DProcessBaseError,
"Process run method failed: " << ex.what()); "Process run method failed: " << ex.what());
} }
...@@ -85,7 +95,7 @@ D2Process::run() { ...@@ -85,7 +95,7 @@ D2Process::run() {
// this might be the place to do it, once there is a persistence mgr. // this might be the place to do it, once there is a persistence mgr.
// This may also be better in checkQueueStatus. // This may also be better in checkQueueStatus.
boost::dynamic_pointer_cast<D2Controller>(D2Controller::instance())->deregisterCommands(); controller->deregisterCommands();
LOG_DEBUG(d2_logger, isc::log::DBGLVL_START_SHUT, DHCP_DDNS_RUN_EXIT); LOG_DEBUG(d2_logger, isc::log::DBGLVL_START_SHUT, DHCP_DDNS_RUN_EXIT);
...@@ -219,6 +229,7 @@ D2Process::configure(isc::data::ConstElementPtr config_set, bool check_only) { ...@@ -219,6 +229,7 @@ D2Process::configure(isc::data::ConstElementPtr config_set, bool check_only) {
// action. In integrated mode, this will send a failed response back // action. In integrated mode, this will send a failed response back
// to the configuration backend. // to the configuration backend.
reconf_queue_flag_ = false; reconf_queue_flag_ = false;
reconf_control_socket_flag_ = false;
return (answer); return (answer);
} }
...@@ -234,6 +245,7 @@ D2Process::configure(isc::data::ConstElementPtr config_set, bool check_only) { ...@@ -234,6 +245,7 @@ D2Process::configure(isc::data::ConstElementPtr config_set, bool check_only) {
// things that need reconfiguration. It might also be useful if we // things that need reconfiguration. It might also be useful if we
// did some analysis to decide what if anything we need to do.) // did some analysis to decide what if anything we need to do.)
reconf_queue_flag_ = true; reconf_queue_flag_ = true;
reconf_control_socket_flag_ = true;
// If we are here, configuration was valid, at least it parsed correctly // If we are here, configuration was valid, at least it parsed correctly
// and therefore contained no invalid values. // and therefore contained no invalid values.
...@@ -399,5 +411,39 @@ const char* D2Process::getShutdownTypeStr(const ShutdownType& type) { ...@@ -399,5 +411,39 @@ const char* D2Process::getShutdownTypeStr(const ShutdownType& type) {
return (str); return (str);
} }
void
D2Process::reconfigureCommandChannel() {
reconf_control_socket_flag_ = false;
// Current socket configuration.
static isc::data::ConstElementPtr current_sock_cfg;
// Get new socket configuration.
isc::data::ConstElementPtr sock_cfg = getD2CfgMgr()->getControlSocketInfo();
// Determine if the socket configuration has changed. It has if
// both old and new configuration is specified but respective
// data elements aren'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 existing socket and open a new socket as appropriate.
// Note that closing an existing socket means the client 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) {
isc::config::CommandMgr::instance().openCommandSocket(sock_cfg);
}
}
// Commit the new socket configuration.
current_sock_cfg = sock_cfg;
}
}; // namespace isc::d2 }; // namespace isc::d2
}; // namespace isc }; // namespace isc
// Copyright (C) 2013-2017 Internet Systems Consortium, Inc. ("ISC") // Copyright (C) 2013-2018 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
...@@ -254,6 +254,15 @@ protected: ...@@ -254,6 +254,15 @@ protected:
shutdown_type_ = value; shutdown_type_ = value;
} }
/// @brief (Re-)Configure the command channel.
///
/// 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 reconfigureCommandChannel();
public: public:
/// @brief Returns a pointer to the configuration manager. /// @brief Returns a pointer to the configuration manager.
/// Note, this method cannot return a reference as it uses dynamic /// Note, this method cannot return a reference as it uses dynamic
...@@ -275,6 +284,11 @@ public: ...@@ -275,6 +284,11 @@ public:
return (reconf_queue_flag_); return (reconf_queue_flag_);
} }
/// @brief Returns true if the control socket should be reconfigured.
bool getReconfControlSocketFlag() const {
return (reconf_control_socket_flag_);
}
/// @brief Returns the type of shutdown requested. /// @brief Returns the type of shutdown requested.
/// ///
/// Note, this value is meaningless unless shouldShutdown() returns true. /// Note, this value is meaningless unless shouldShutdown() returns true.
...@@ -300,6 +314,9 @@ private: ...@@ -300,6 +314,9 @@ private:
/// @brief Indicates if the queue manager should be reconfigured. /// @brief Indicates if the queue manager should be reconfigured.
bool reconf_queue_flag_; bool reconf_queue_flag_;
/// @brief Indicates if the control socket should be reconfigured.
bool reconf_control_socket_flag_;
/// @brief Indicates the type of shutdown requested. /// @brief Indicates the type of shutdown requested.
ShutdownType shutdown_type_; ShutdownType shutdown_type_;
}; };
......
...@@ -58,6 +58,7 @@ d2_unittests_SOURCES += d2_controller_unittests.cc ...@@ -58,6 +58,7 @@ d2_unittests_SOURCES += d2_controller_unittests.cc
d2_unittests_SOURCES += d2_simple_parser_unittest.cc d2_unittests_SOURCES += d2_simple_parser_unittest.cc
d2_unittests_SOURCES += parser_unittest.cc parser_unittest.h d2_unittests_SOURCES += parser_unittest.cc parser_unittest.h
d2_unittests_SOURCES += get_config_unittest.cc d2_unittests_SOURCES += get_config_unittest.cc
d2_unittests_SOURCES += d2_command_unittest.cc
d2_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) d2_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
d2_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) d2_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS)
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment