Browse Source

3401 - D2 now supports with-kea-config switch

The configuration switch --with-kea-config, now selects between
two versions of D2Controller:

1. One which must run as a BUNDY module and is implemented in
bundy_d2_controller.(h/cc)

All of the BIND10 support was extracted from DControllerBase and moved
into this version of D2Controller.

This controller is tested in tests/bundy_d2_controller_unittests.cc

2. One that runs as a stand alone executable which must be supplied
with a configuration file via the command line and is implemented in
d2_controller.(h/cc).

This version of D2Controller is nearly identical the the original.
DControllerBase supports configuration from file.

This controller is tested in tests/d2_controller_unittests.cc

DControllerBase now inherits from Daemon which keeps it in step with
K4 and K6.

The stand-alone mode flag has been removed from all controllers.
Thomas Markwalder 11 years ago
parent
commit
1c4d345d90

+ 11 - 3
src/bin/d2/Makefile.am

@@ -50,12 +50,12 @@ BUILT_SOURCES = spec_config.h d2_messages.h d2_messages.cc
 pkglibexec_PROGRAMS = b10-dhcp-ddns
 pkglibexec_PROGRAMS = b10-dhcp-ddns
 
 
 b10_dhcp_ddns_SOURCES  = main.cc
 b10_dhcp_ddns_SOURCES  = main.cc
+b10_dhcp_ddns_SOURCES += d_process.h
+b10_dhcp_ddns_SOURCES += d_controller.cc d_controller.h
+b10_dhcp_ddns_SOURCES += d_cfg_mgr.cc d_cfg_mgr.h
 b10_dhcp_ddns_SOURCES += d2_asio.h
 b10_dhcp_ddns_SOURCES += d2_asio.h
 b10_dhcp_ddns_SOURCES += d2_log.cc d2_log.h
 b10_dhcp_ddns_SOURCES += d2_log.cc d2_log.h
 b10_dhcp_ddns_SOURCES += d2_process.cc d2_process.h
 b10_dhcp_ddns_SOURCES += d2_process.cc d2_process.h
-b10_dhcp_ddns_SOURCES += d_controller.cc d_controller.h
-b10_dhcp_ddns_SOURCES += d2_controller.cc d2_controller.h
-b10_dhcp_ddns_SOURCES += d_cfg_mgr.cc d_cfg_mgr.h
 b10_dhcp_ddns_SOURCES += d2_config.cc d2_config.h
 b10_dhcp_ddns_SOURCES += d2_config.cc d2_config.h
 b10_dhcp_ddns_SOURCES += d2_cfg_mgr.cc d2_cfg_mgr.h
 b10_dhcp_ddns_SOURCES += d2_cfg_mgr.cc d2_cfg_mgr.h
 b10_dhcp_ddns_SOURCES += d2_queue_mgr.cc d2_queue_mgr.h
 b10_dhcp_ddns_SOURCES += d2_queue_mgr.cc d2_queue_mgr.h
@@ -69,6 +69,14 @@ b10_dhcp_ddns_SOURCES += nc_remove.cc nc_remove.h
 b10_dhcp_ddns_SOURCES += nc_trans.cc nc_trans.h
 b10_dhcp_ddns_SOURCES += nc_trans.cc nc_trans.h
 b10_dhcp_ddns_SOURCES += state_model.cc state_model.h
 b10_dhcp_ddns_SOURCES += state_model.cc state_model.h
 
 
+if CONFIG_BACKEND_BUNDY
+b10_dhcp_ddns_SOURCES += bundy_d2_controller.cc bundy_d2_controller.h
+else
+if CONFIG_BACKEND_JSON
+b10_dhcp_ddns_SOURCES += d2_controller.cc d2_controller.h
+endif
+endif
+
 nodist_b10_dhcp_ddns_SOURCES = d2_messages.h d2_messages.cc
 nodist_b10_dhcp_ddns_SOURCES = d2_messages.h d2_messages.cc
 EXTRA_DIST += d2_messages.mes
 EXTRA_DIST += d2_messages.mes
 
 

+ 294 - 0
src/bin/d2/bundy_d2_controller.cc

@@ -0,0 +1,294 @@
+// Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <d2/bundy_d2_controller.h>
+#include <d2/d2_process.h>
+#include <d2/spec_config.h>
+
+#include <sstream>
+
+namespace isc {
+namespace d2 {
+
+/// @brief Defines the application name, this is passed into base class
+/// it may be used to locate configuration data and appears in log statement.
+const char* D2Controller::d2_app_name_ = "DHCP-DDNS";
+
+/// @brief Defines the executable name. This is passed into the base class
+const char* D2Controller::d2_bin_name_ = "b10-dhcp-ddns";
+
+DControllerBasePtr&
+D2Controller::instance() {
+    // If the instance hasn't been created yet, create it.  Note this method
+    // must use the base class singleton instance methods.  The base class
+    // must have access to the singleton in order to use it within BUNDY
+    // static function callbacks.
+    if (!getController()) {
+        DControllerBasePtr controller_ptr(new D2Controller());
+        setController(controller_ptr);
+    }
+
+    return (getController());
+}
+
+DProcessBase* D2Controller::createProcess() {
+    // Instantiate and return an instance of the D2 application process. Note
+    // that the process is passed the controller's io_service.
+    return (new D2Process(getAppName().c_str(), getIOService()));
+}
+
+D2Controller::D2Controller()
+    : DControllerBase(d2_app_name_, d2_bin_name_) {
+    // set the spec file either from the environment or
+    // use the production value.
+    if (getenv("B10_FROM_BUILD")) {
+        setSpecFileName(std::string(getenv("B10_FROM_BUILD")) +
+            "/src/bin/d2/dhcp-ddns.spec");
+    } else {
+        setSpecFileName(D2_SPECFILE_LOCATION);
+    }
+}
+
+D2Controller::~D2Controller() {
+}
+
+void
+D2Controller::launch(int argc, char* argv[], const bool test_mode) {
+    // Step 1 is to parse the command line arguments.
+    try {
+        parseArgs(argc, argv);
+    } catch (const InvalidUsage& ex) {
+        usage(ex.what());
+        throw; // rethrow it
+    }
+
+    // Do not initialize logger here if we are running unit tests. It would
+    // replace an instance of unit test specific logger.
+    if (!test_mode) {
+        // Now that we know what the mode flags are, we can init logging.
+        // If standalone is enabled, do not buffer initial log messages
+        isc::log::initLogger(getBinName(),
+                             (isVerbose() ? isc::log::DEBUG : isc::log::INFO),
+                             isc::log::MAX_DEBUG_LEVEL, NULL, true);
+    }
+
+    LOG_DEBUG(dctl_logger, DBGLVL_START_SHUT, DCTL_STARTING)
+              .arg(getAppName()).arg(getpid());
+    try {
+        // Step 2 is to create and initialize the application process object.
+        initProcess();
+    } catch (const std::exception& ex) {
+        LOG_FATAL(dctl_logger, DCTL_INIT_PROCESS_FAIL)
+                  .arg(getAppName()).arg(ex.what());
+        isc_throw (ProcessInitError,
+                   "Application Process initialization failed: " << ex.what());
+    }
+
+    // Next we connect to Bundy.
+    try {
+        establishSession();
+    } catch (const std::exception& ex) {
+        LOG_FATAL(dctl_logger, DCTL_SESSION_FAIL).arg(ex.what());
+        isc_throw (SessionStartError,
+                   "Session start up failed: " << ex.what());
+    }
+
+    // Everything is clear for launch, so start the application's
+    // event loop.
+    try {
+        runProcess();
+    } catch (const std::exception& ex) {
+        LOG_FATAL(dctl_logger, DCTL_PROCESS_FAILED)
+                  .arg(getAppName()).arg(ex.what());
+        isc_throw (ProcessRunError,
+                   "Application process event loop failed: " << ex.what());
+    }
+
+    // Disconnect from Bundy.
+    try {
+        disconnectSession();
+    } catch (const std::exception& ex) {
+        LOG_ERROR(dctl_logger, DCTL_DISCONNECT_FAIL)
+                  .arg(getAppName()).arg(ex.what());
+        isc_throw (SessionEndError, "Session end failed: " << ex.what());
+    }
+
+    // All done, so bail out.
+    LOG_INFO(dctl_logger, DCTL_STOPPING).arg(getAppName());
+}
+
+void
+D2Controller::parseArgs(int argc, char* argv[])
+{
+    // Iterate over the given command line options. If its a stock option
+    // ("s" or "v") handle it here.  If its a valid custom option, then
+    // invoke customOption.
+    int ch;
+    opterr = 0;
+    optind = 1;
+    std::string opts(":v" + getCustomOpts());
+    while ((ch = getopt(argc, argv, opts.c_str())) != -1) {
+        switch (ch) {
+        case 'v':
+            // Enables verbose logging.
+            setVerbose(true);
+            break;
+
+        case '?': {
+            // We hit an invalid option.
+            isc_throw(InvalidUsage, "unsupported option: ["
+                      << static_cast<char>(optopt) << "] "
+                      << (!optarg ? "" : optarg));
+
+            break;
+            }
+
+        default:
+            // We hit a valid custom option
+            if (!customOption(ch, optarg)) {
+                // This would be a programmatic error.
+                isc_throw(InvalidUsage, " Option listed but implemented?: ["
+                          << static_cast<char>(ch) << "] "
+                          << (!optarg ? "" : optarg));
+            }
+            break;
+        }
+    }
+
+    // There was too much information on the command line.
+    if (argc > optind) {
+        isc_throw(InvalidUsage, "extraneous command line information");
+    }
+}
+
+void
+D2Controller::establishSession() {
+    LOG_DEBUG(dctl_logger, DBGLVL_START_SHUT, DCTL_CCSESSION_STARTING)
+              .arg(getAppName()).arg(getSpecFileName());
+
+    // Create the BIND10 command control session with the our IOService.
+    cc_session_ = SessionPtr(new isc::cc::Session(
+                             getIOService()->get_io_service()));
+
+    // Create the BIND10 config session with the stub configuration handler.
+    // This handler is internally invoked by the constructor and on success
+    // the constructor updates the current session with the configuration that
+    // had been committed in the previous session. If we do not install
+    // the dummy handler, the previous configuration would be lost.
+    config_session_ = ModuleCCSessionPtr(new isc::config::ModuleCCSession(
+                                         getSpecFileName(), *cc_session_,
+                                         dummyConfigHandler, 
+                                         DControllerBase::commandHandler,
+                                         false));
+    // Enable configuration even processing.
+    config_session_->start();
+
+    // We initially create ModuleCCSession() with a dummy configHandler, as
+    // the session module is too eager to send partial configuration.
+    // Replace the dummy config handler with the real handler.
+    config_session_->setConfigHandler(DControllerBase::configHandler);
+
+    // Call the real configHandler with the full configuration retrieved
+    // from the config session.
+    isc::data::ConstElementPtr answer = configHandler(
+                                            config_session_->getFullConfig());
+
+    // Parse the answer returned from the configHandler.  Log the error but
+    // keep running. This provides an opportunity for the user to correct
+    // the configuration dynamically.
+    int ret = 0;
+    isc::data::ConstElementPtr comment = isc::config::parseAnswer(ret, answer);
+    if (ret) {
+        LOG_ERROR(dctl_logger, DCTL_CONFIG_LOAD_FAIL)
+                  .arg(getAppName()).arg(comment->str());
+    }
+}
+
+void D2Controller::disconnectSession() {
+    LOG_DEBUG(dctl_logger, DBGLVL_START_SHUT, DCTL_CCSESSION_ENDING)
+              .arg(getAppName());
+
+    // Destroy the BIND10 config session.
+    if (config_session_) {
+        config_session_.reset();
+    }
+
+    // Destroy the BIND10 command and control session.
+    if (cc_session_) {
+        cc_session_->disconnect();
+        cc_session_.reset();
+    }
+}
+
+isc::data::ConstElementPtr
+D2Controller::dummyConfigHandler(isc::data::ConstElementPtr) {
+    LOG_DEBUG(dctl_logger, DBGLVL_START_SHUT, DCTL_CONFIG_STUB)
+             .arg(getController()->getAppName());
+    return (isc::config::createAnswer(0, "Configuration accepted."));
+}
+
+isc::data::ConstElementPtr
+D2Controller::updateConfig(isc::data::ConstElementPtr new_config) {
+    if (!config_session_) {
+        // That should never happen as we install config_handler
+        // after we instantiate the server.
+        isc::data::ConstElementPtr answer =
+            isc::config::createAnswer(1, "Configuration rejected,"
+                                              " Session has not started.");
+        return (answer);
+    }
+
+    // Let's get the existing configuration.
+    isc::data::ConstElementPtr full_config = config_session_->getFullConfig();
+
+    // The configuration passed to this handler function is partial.
+    // In other words, it just includes the values being modified.
+    // In the same time, there may be dependencies between various
+    // configuration parsers. For example: the option value can
+    // be set if the definition of this option is set. If someone removes
+    // an existing option definition then the partial configuration that
+    // removes that definition is triggered while a relevant option value
+    // may remain configured. This eventually results in the
+    // configuration being in the inconsistent state.
+    // In order to work around this problem we need to merge the new
+    // configuration with the existing (full) configuration.
+
+    // Let's create a new object that will hold the merged configuration.
+    boost::shared_ptr<isc::data::MapElement>
+                            merged_config(new isc::data::MapElement());
+
+    // Merge an existing and new configuration.
+    merged_config->setValue(full_config->mapValue());
+    isc::data::merge(merged_config, new_config);
+
+    // Send the merged configuration to the application.
+    return (getProcess()->configure(merged_config));
+}
+
+
+void
+D2Controller::usage(const std::string & text)
+{
+    if (text != "") {
+        std::cerr << "Usage error: " << text << std::endl;
+    }
+
+    std::cerr << "Usage: " << getBinName() <<  std::endl;
+    std::cerr << "  -v: verbose output" << std::endl;
+    std::cerr << getUsageText() << std::endl;
+}
+
+
+}; // namespace isc::d2
+}; // namespace isc

+ 230 - 0
src/bin/d2/bundy_d2_controller.h

@@ -0,0 +1,230 @@
+// Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef BUNDY_D2_CONTROLLER_H
+#define BUNDY_D2_CONTROLLER_H
+
+#include <cc/data.h>
+#include <cc/session.h>
+#include <config/ccsession.h>
+#include <d2/d2_asio.h>
+#include <d2/d2_log.h>
+#include <d2/d_controller.h>
+#include <d2/d_process.h>
+#include <exceptions/exceptions.h>
+#include <log/logger_support.h>
+
+#include <boost/shared_ptr.hpp>
+#include <boost/noncopyable.hpp>
+
+
+namespace isc {
+namespace d2 {
+
+/// @brief Exception thrown when the session start up fails.
+class SessionStartError: public isc::Exception {
+public:
+    SessionStartError (const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { };
+};
+
+/// @brief Exception thrown when the session end fails.
+class SessionEndError: public isc::Exception {
+public:
+    SessionEndError (const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) { };
+};
+
+/// @brief Defines a shared pointer to a Session.
+typedef boost::shared_ptr<isc::cc::Session> SessionPtr;
+
+/// @brief Defines a shared pointer to a ModuleCCSession.
+typedef boost::shared_ptr<isc::config::ModuleCCSession> ModuleCCSessionPtr;
+
+/// @brief Bundy-integrated Process Controller for D2 Process 
+/// This class is the DHCP-DDNS specific derivation of DControllerBase which
+/// is managed by BUNDY. It creates and manages an instance of the DHCP-DDNS 
+/// application process, D2Process.
+///
+/// D2 will be constructed with this class if the project is configured with
+/// --with-kea-config=BUNDY
+class D2Controller : public DControllerBase {
+public:
+    /// @brief Static singleton instance method. This method returns the
+    /// base class singleton instance member.  It instantiates the singleton
+    /// and sets the base class instance member upon first invocation.
+    ///
+    /// @return returns the pointer reference to the singleton instance.
+    static DControllerBasePtr& instance();
+
+    /// @brief Destructor.
+    virtual ~D2Controller();
+
+    /// @brief Defines the application name, this is passed into base class
+    /// and appears in log statements.
+    static const char* d2_app_name_;
+
+    /// @brief Defines the executable name. This is passed into the base class
+    /// by convention this should match the BUNDY module name.
+    static const char* d2_bin_name_;
+
+    /// @brief Acts as the primary entry point into the controller execution
+    /// and provides the outermost application control logic:
+    ///
+    /// 1. parse command line arguments
+    /// 2. instantiate and initialize the application process
+    /// 3. establish BUNDY session(s) if in integrated mode
+    /// 4. start and wait on the application process event loop
+    /// 5. upon event loop completion, disconnect from BUNDY (if needed)
+    /// 6. exit to the caller
+    ///
+    /// It is intended to be called from main() and be given the command line
+    /// arguments. Note this method is deliberately not virtual to ensure the
+    /// proper sequence of events occur.
+    ///
+    /// This function can be run in the test mode. It prevents initialization
+    /// of D2 module logger. This is used in unit tests which initialize logger
+    /// in their main function. Such logger uses environmental variables to
+    /// control severity, verbosity etc. Reinitialization of logger by this
+    /// function would replace unit tests specific logger configuration with
+    /// this suitable for D2 running as a bind10 module.
+    ///
+    /// @param argc  is the number of command line arguments supplied
+    /// @param argv  is the array of string (char *) command line arguments
+    /// @param test_mode is a bool value which indicates if
+    /// @c DControllerBase::launch should be run in the test mode (if true).
+    /// This parameter doesn't have default value to force test implementers to
+    /// enable test mode explicitly.
+    ///
+    /// @throw throws one of the following exceptions:
+    /// InvalidUsage - Indicates invalid command line.
+    /// ProcessInitError  - Failed to create and initialize application
+    /// process object.
+    /// SessionStartError  - Could not connect to BUNDY (integrated mode only).
+    /// ProcessRunError - A fatal error occurred while in the application
+    /// process event loop.
+    /// SessionEndError - Could not disconnect from BUNDY (integrated mode
+    /// only).
+    virtual void launch(int argc, char* argv[], const bool test_mode);
+
+    /// @brief A dummy configuration handler that always returns success.
+    ///
+    /// This configuration handler does not perform configuration
+    /// parsing and always returns success. A dummy handler should
+    /// be installed using \ref isc::config::ModuleCCSession ctor
+    /// to get the initial configuration. This initial configuration
+    /// comprises values for only those elements that were modified
+    /// the previous session. The D2 configuration parsing can't be
+    /// used to parse the initial configuration because it may need the
+    /// full configuration to satisfy dependencies between the
+    /// various configuration values. Installing the dummy handler
+    /// that guarantees to return success causes initial configuration
+    /// to be stored for the session being created and that it can
+    /// be later accessed with \ref isc::config::ConfigData::getFullConfig.
+    ///
+    /// @param new_config new configuration.
+    ///
+    /// @return success configuration status.
+    static isc::data::ConstElementPtr
+    dummyConfigHandler(isc::data::ConstElementPtr new_config);
+
+    /// @brief Instance method invoked by the configuration event handler and
+    /// which processes the actual configuration update.  Provides behavioral
+    /// path for both integrated and stand-alone modes. The current
+    /// implementation will merge the configuration update into the existing
+    /// configuration and then invoke the application process' configure method.
+    ///
+    /// @todo This implementation is will evolve as the D2 configuration
+    /// management task is implemented (trac #2957).
+    ///
+    /// @param  new_config is the new configuration
+    ///
+    /// @return returns an Element that contains the results of configuration
+    /// update composed of an integer status value (0 means successful,
+    /// non-zero means failure), and a string explanation of the outcome.
+    virtual isc::data::ConstElementPtr
+    updateConfig(isc::data::ConstElementPtr new_config);
+
+protected:
+    /// @brief Processes the command line arguments. It is the first step
+    /// taken after the controller has been launched.  It combines the stock
+    /// list of options with those returned by getCustomOpts(), and uses
+    /// cstdlib's getopt to loop through the command line.  The stock options
+    /// It handles stock options directly, and passes any custom options into
+    /// the customOption method.  Currently there are only two stock options
+    /// -s for stand alone mode, and -v for verbose logging.
+    ///
+    /// @param argc  is the number of command line arguments supplied
+    /// @param argv  is the array of string (char *) command line arguments
+    ///
+    /// @throw throws InvalidUsage when there are usage errors.
+    void parseArgs(int argc, char* argv[]);
+
+    /// @brief Establishes connectivity with BUNDY.  This method is used
+    /// invoked during launch, if running in integrated mode, following
+    /// successful process initialization.  It is responsible for establishing
+    /// the BUNDY control and config sessions. During the session creation,
+    /// it passes in the controller's IOService and the callbacks for command
+    /// directives and config events.  Lastly, it will invoke the onConnect
+    /// method providing the derivation an opportunity to execute any custom
+    /// logic associated with session establishment.
+    ///
+    /// @throw the BUNDY framework may throw std::exceptions.
+    void establishSession();
+
+    /// @brief Terminates connectivity with BUNDY. This method is invoked
+    /// in integrated mode after the application event loop has exited. It
+    /// first calls the onDisconnect method providing the derivation an
+    /// opportunity to execute custom logic if needed, and then terminates the
+    /// BUNDY config and control sessions.
+    ///
+    /// @throw the BUNDY framework may throw std:exceptions.
+    void disconnectSession();
+
+    /// @brief Prints the program usage text to std error.
+    ///
+    /// @param text is a string message which will preceded the usage text.
+    /// This is intended to be used for specific usage violation messages.
+    void usage(const std::string& text);
+
+private:
+    /// @brief Creates an instance of the DHCP-DDNS specific application
+    /// process.  This method is invoked during the process initialization
+    /// step of the controller launch.
+    ///
+    /// @return returns a DProcessBase* to the application process created.
+    /// Note the caller is responsible for destructing the process. This
+    /// is handled by the base class, which wraps this pointer with a smart
+    /// pointer.
+    virtual DProcessBase* createProcess();
+
+    /// @brief Helper session object that represents raw connection to msgq.
+    SessionPtr cc_session_;
+
+    /// @brief Session that receives configuration and commands.
+    ModuleCCSessionPtr config_session_;
+
+    /// @brief Constructor is declared private to maintain the integrity of
+    /// the singleton instance.
+    D2Controller();
+
+    // DControllerTest is named a friend class to facilitate unit testing while
+    // leaving the intended member scopes intact.
+    friend class DControllerTest;
+};
+
+}; // namespace isc::d2
+}; // namespace isc
+
+#endif

+ 4 - 5
src/bin/d2/d2_controller.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -22,11 +22,10 @@ namespace isc {
 namespace d2 {
 namespace d2 {
 
 
 /// @brief Defines the application name, this is passed into base class
 /// @brief Defines the application name, this is passed into base class
-/// and appears in log statements.
-const char* D2Controller::d2_app_name_ = "DHCP-DDNS";
+/// it may be used to locate configuration data and appears in log statement.
+const char* D2Controller::d2_app_name_ = "DhcpDdns";
 
 
 /// @brief Defines the executable name. This is passed into the base class
 /// @brief Defines the executable name. This is passed into the base class
-/// by convention this should match the BIND10 module name.
 const char* D2Controller::d2_bin_name_ = "b10-dhcp-ddns";
 const char* D2Controller::d2_bin_name_ = "b10-dhcp-ddns";
 
 
 DControllerBasePtr&
 DControllerBasePtr&
@@ -51,7 +50,7 @@ DProcessBase* D2Controller::createProcess() {
 
 
 D2Controller::D2Controller()
 D2Controller::D2Controller()
     : DControllerBase(d2_app_name_, d2_bin_name_) {
     : DControllerBase(d2_app_name_, d2_bin_name_) {
-    // set the BIND10 spec file either from the environment or
+    // set the spec file either from the environment or
     // use the production value.
     // use the production value.
     if (getenv("B10_FROM_BUILD")) {
     if (getenv("B10_FROM_BUILD")) {
         setSpecFileName(std::string(getenv("B10_FROM_BUILD")) +
         setSpecFileName(std::string(getenv("B10_FROM_BUILD")) +

+ 2 - 2
src/bin/d2/d2_controller.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -47,7 +47,7 @@ public:
     static const char* d2_app_name_;
     static const char* d2_app_name_;
 
 
     /// @brief Defines the executable name. This is passed into the base class
     /// @brief Defines the executable name. This is passed into the base class
-    /// by convention this should match the BIND10 module name.
+    /// by convention this should match the executable name.
     static const char* d2_bin_name_;
     static const char* d2_bin_name_;
 
 
 private:
 private:

+ 4 - 0
src/bin/d2/d2_messages.mes

@@ -37,6 +37,10 @@ This critical error message indicates that the initial application
 configuration has failed. The service will start, but will not
 configuration has failed. The service will start, but will not
 process requests until the configuration has been corrected.
 process requests until the configuration has been corrected.
 
 
+% DCTL_CONFIG_FILE_LOAD_FAIL %1 configuration could not be loaded from file: %2
+This fatal error message indicates that the application attempted to load its
+initial configuration from file and has failed. The service will exit.
+
 % DCTL_CONFIG_START parsing new configuration: %1
 % DCTL_CONFIG_START parsing new configuration: %1
 A debug message indicating that the application process has received an
 A debug message indicating that the application process has received an
 updated configuration and has passed it to its configuration manager
 updated configuration and has passed it to its configuration manager

+ 102 - 179
src/bin/d2/d_controller.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -14,6 +14,7 @@
 
 
 
 
 #include <d2/d2_log.h>
 #include <d2/d2_log.h>
+#include <config/ccsession.h>
 #include <d2/d_controller.h>
 #include <d2/d_controller.h>
 #include <exceptions/exceptions.h>
 #include <exceptions/exceptions.h>
 #include <log/logger_support.h>
 #include <log/logger_support.h>
@@ -27,12 +28,11 @@ DControllerBasePtr DControllerBase::controller_;
 
 
 // Note that the constructor instantiates the controller's primary IOService.
 // Note that the constructor instantiates the controller's primary IOService.
 DControllerBase::DControllerBase(const char* app_name, const char* bin_name)
 DControllerBase::DControllerBase(const char* app_name, const char* bin_name)
-    : app_name_(app_name), bin_name_(bin_name), stand_alone_(false),
+    : app_name_(app_name), bin_name_(bin_name),
       verbose_(false), spec_file_name_(""),
       verbose_(false), spec_file_name_(""),
       io_service_(new isc::asiolink::IOService()){
       io_service_(new isc::asiolink::IOService()){
 }
 }
 
 
-
 void
 void
 DControllerBase::setController(const DControllerBasePtr& controller) {
 DControllerBase::setController(const DControllerBasePtr& controller) {
     if (controller_) {
     if (controller_) {
@@ -47,6 +47,7 @@ DControllerBase::setController(const DControllerBasePtr& controller) {
 
 
 void
 void
 DControllerBase::launch(int argc, char* argv[], const bool test_mode) {
 DControllerBase::launch(int argc, char* argv[], const bool test_mode) {
+
     // Step 1 is to parse the command line arguments.
     // Step 1 is to parse the command line arguments.
     try {
     try {
         parseArgs(argc, argv);
         parseArgs(argc, argv);
@@ -59,11 +60,7 @@ DControllerBase::launch(int argc, char* argv[], const bool test_mode) {
     // replace an instance of unit test specific logger.
     // replace an instance of unit test specific logger.
     if (!test_mode) {
     if (!test_mode) {
         // Now that we know what the mode flags are, we can init logging.
         // Now that we know what the mode flags are, we can init logging.
-        // If standalone is enabled, do not buffer initial log messages
-        isc::log::initLogger(bin_name_,
-                             ((verbose_ && stand_alone_)
-                              ? isc::log::DEBUG : isc::log::INFO),
-                             isc::log::MAX_DEBUG_LEVEL, NULL, !stand_alone_);
+        Daemon::loggerInit(bin_name_.c_str(), verbose_);
     }
     }
 
 
     LOG_DEBUG(dctl_logger, DBGLVL_START_SHUT, DCTL_STARTING)
     LOG_DEBUG(dctl_logger, DBGLVL_START_SHUT, DCTL_STARTING)
@@ -78,18 +75,17 @@ DControllerBase::launch(int argc, char* argv[], const bool test_mode) {
                    "Application Process initialization failed: " << ex.what());
                    "Application Process initialization failed: " << ex.what());
     }
     }
 
 
-    // Next we connect if we are running integrated.
-    if (stand_alone_) {
-        LOG_DEBUG(dctl_logger, DBGLVL_START_SHUT, DCTL_STANDALONE)
-                  .arg(app_name_);
-    } else {
-        try {
-            establishSession();
-        } catch (const std::exception& ex) {
-            LOG_FATAL(dctl_logger, DCTL_SESSION_FAIL).arg(ex.what());
-            isc_throw (SessionStartError,
-                       "Session start up failed: " << ex.what());
-        }
+    LOG_DEBUG(dctl_logger, DBGLVL_START_SHUT, DCTL_STANDALONE).arg(app_name_);
+
+    // Step 3 is to load configuration from file.
+    int rcode;
+    isc::data::ConstElementPtr comment
+        = isc::config::parseAnswer(rcode, configFromFile());
+    if (rcode != 0) {
+        LOG_FATAL(dctl_logger, DCTL_CONFIG_FILE_LOAD_FAIL)
+                  .arg(app_name_).arg(comment->stringValue());
+        isc_throw (ProcessInitError, "Could Not load configration file: "
+                   << comment->stringValue());
     }
     }
 
 
     // Everything is clear for launch, so start the application's
     // Everything is clear for launch, so start the application's
@@ -103,22 +99,10 @@ DControllerBase::launch(int argc, char* argv[], const bool test_mode) {
                    "Application process event loop failed: " << ex.what());
                    "Application process event loop failed: " << ex.what());
     }
     }
 
 
-    // If running integrated, disconnect.
-    if (!stand_alone_) {
-        try {
-            disconnectSession();
-        } catch (const std::exception& ex) {
-            LOG_ERROR(dctl_logger, DCTL_DISCONNECT_FAIL)
-                      .arg(app_name_).arg(ex.what());
-            isc_throw (SessionEndError, "Session end failed: " << ex.what());
-        }
-    }
-
     // All done, so bail out.
     // All done, so bail out.
     LOG_INFO(dctl_logger, DCTL_STOPPING).arg(app_name_);
     LOG_INFO(dctl_logger, DCTL_STOPPING).arg(app_name_);
 }
 }
 
 
-
 void
 void
 DControllerBase::parseArgs(int argc, char* argv[])
 DControllerBase::parseArgs(int argc, char* argv[])
 {
 {
@@ -128,7 +112,7 @@ DControllerBase::parseArgs(int argc, char* argv[])
     int ch;
     int ch;
     opterr = 0;
     opterr = 0;
     optind = 1;
     optind = 1;
-    std::string opts(":vs" + getCustomOpts());
+    std::string opts("vc:" + getCustomOpts());
     while ((ch = getopt(argc, argv, opts.c_str())) != -1) {
     while ((ch = getopt(argc, argv, opts.c_str())) != -1) {
         switch (ch) {
         switch (ch) {
         case 'v':
         case 'v':
@@ -136,9 +120,13 @@ DControllerBase::parseArgs(int argc, char* argv[])
             verbose_ = true;
             verbose_ = true;
             break;
             break;
 
 
-        case 's':
-            // Enables stand alone or "BINDLESS" operation.
-            stand_alone_ = true;
+        case 'c':
+            // config file name
+            if (optarg == NULL) {
+                isc_throw(InvalidUsage, "configuration file name missing");
+            }
+
+            Daemon::init(optarg);
             break;
             break;
 
 
         case '?': {
         case '?': {
@@ -168,6 +156,28 @@ DControllerBase::parseArgs(int argc, char* argv[])
     }
     }
 }
 }
 
 
+isc::data::ConstElementPtr
+DControllerBase::configHandler(isc::data::ConstElementPtr new_config) {
+    LOG_DEBUG(dctl_logger, DBGLVL_COMMAND, DCTL_CONFIG_UPDATE)
+              .arg(controller_->getAppName()).arg(new_config->str());
+
+    // Invoke the instance method on the controller singleton.
+    return (controller_->updateConfig(new_config));
+}
+
+// Static callback which invokes non-static handler on singleton
+isc::data::ConstElementPtr
+DControllerBase::commandHandler(const std::string& command,
+                                isc::data::ConstElementPtr args) {
+
+    LOG_DEBUG(dctl_logger, DBGLVL_COMMAND, DCTL_COMMAND_RECEIVED)
+        .arg(controller_->getAppName()).arg(command)
+        .arg(args ? args->str() : "(no args)");
+
+    // Invoke the instance method on the controller singleton.
+    return (controller_->executeCommand(command, args));
+}
+
 bool
 bool
 DControllerBase::customOption(int /* option */, char* /*optarg*/)
 DControllerBase::customOption(int /* option */, char* /*optarg*/)
 {
 {
@@ -197,52 +207,41 @@ DControllerBase::initProcess() {
     process_->init();
     process_->init();
 }
 }
 
 
-void
-DControllerBase::establishSession() {
-    LOG_DEBUG(dctl_logger, DBGLVL_START_SHUT, DCTL_CCSESSION_STARTING)
-              .arg(app_name_).arg(spec_file_name_);
-
-    // Create the BIND10 command control session with the our IOService.
-    cc_session_ = SessionPtr(new isc::cc::Session(
-                             io_service_->get_io_service()));
-
-    // Create the BIND10 config session with the stub configuration handler.
-    // This handler is internally invoked by the constructor and on success
-    // the constructor updates the current session with the configuration that
-    // had been committed in the previous session. If we do not install
-    // the dummy handler, the previous configuration would be lost.
-    config_session_ = ModuleCCSessionPtr(new isc::config::ModuleCCSession(
-                                         spec_file_name_, *cc_session_,
-                                         dummyConfigHandler, commandHandler,
-                                         false));
-    // Enable configuration even processing.
-    config_session_->start();
-
-    // We initially create ModuleCCSession() with a dummy configHandler, as
-    // the session module is too eager to send partial configuration.
-    // Replace the dummy config handler with the real handler.
-    config_session_->setConfigHandler(configHandler);
-
-    // Call the real configHandler with the full configuration retrieved
-    // from the config session.
-    isc::data::ConstElementPtr answer = configHandler(
-                                            config_session_->getFullConfig());
-
-    // Parse the answer returned from the configHandler.  Log the error but
-    // keep running. This provides an opportunity for the user to correct
-    // the configuration dynamically.
-    int ret = 0;
-    isc::data::ConstElementPtr comment = isc::config::parseAnswer(ret, answer);
-    if (ret) {
-        LOG_ERROR(dctl_logger, DCTL_CONFIG_LOAD_FAIL)
-                  .arg(app_name_).arg(comment->str());
+isc::data::ConstElementPtr
+DControllerBase::configFromFile() {
+    isc::data::ConstElementPtr module_config;
+
+    try {
+        std::string config_file = getConfigFileName();
+        if (config_file.empty()) {
+            // Basic sanity check: file name must not be empty.
+            isc_throw(BadValue, "JSON configuration file not specified. Please "
+                                "use -c command line option.");
+        }
+
+        // Read contents of the file and parse it as JSON
+        isc::data::ConstElementPtr whole_config =
+            isc::data::Element::fromJSONFile(config_file, true);
+
+        // Extract derivation-specific portion of the configuration.
+        module_config = whole_config->get(getAppName());
+        if (!module_config) {
+            isc_throw(BadValue, "Config file " << config_file <<
+                                " does not include '" <<
+                                 getAppName() << "' entry.");
+        }
+    } catch (const std::exception& ex) {
+        // build an error result
+        isc::data::ConstElementPtr error =
+            isc::config::createAnswer(1,
+                std::string("Configuration parsing failed: ") + ex.what());
+        return (error);
     }
     }
 
 
-    // Lastly, call onConnect. This allows deriving class to execute custom
-    // logic predicated by session connect.
-    onSessionConnect();
+    return (updateConfig(module_config));
 }
 }
 
 
+
 void
 void
 DControllerBase::runProcess() {
 DControllerBase::runProcess() {
     LOG_DEBUG(dctl_logger, DBGLVL_START_SHUT, DCTL_RUN_PROCESS).arg(app_name_);
     LOG_DEBUG(dctl_logger, DBGLVL_START_SHUT, DCTL_RUN_PROCESS).arg(app_name_);
@@ -256,105 +255,14 @@ DControllerBase::runProcess() {
     process_->run();
     process_->run();
 }
 }
 
 
-void DControllerBase::disconnectSession() {
-    LOG_DEBUG(dctl_logger, DBGLVL_START_SHUT, DCTL_CCSESSION_ENDING)
-              .arg(app_name_);
-
-    // Call virtual onDisconnect. Allows deriving class to execute custom
-    // logic prior to session loss.
-    onSessionDisconnect();
-
-    // Destroy the BIND10 config session.
-    if (config_session_) {
-        config_session_.reset();
-    }
-
-    // Destroy the BIND10 command and control session.
-    if (cc_session_) {
-        cc_session_->disconnect();
-        cc_session_.reset();
-    }
-}
-
-isc::data::ConstElementPtr
-DControllerBase::dummyConfigHandler(isc::data::ConstElementPtr) {
-    LOG_DEBUG(dctl_logger, DBGLVL_START_SHUT, DCTL_CONFIG_STUB)
-             .arg(controller_->getAppName());
-    return (isc::config::createAnswer(0, "Configuration accepted."));
-}
-
-isc::data::ConstElementPtr
-DControllerBase::configHandler(isc::data::ConstElementPtr new_config) {
-
-    LOG_DEBUG(dctl_logger, DBGLVL_COMMAND, DCTL_CONFIG_UPDATE)
-              .arg(controller_->getAppName()).arg(new_config->str());
-
-    // Invoke the instance method on the controller singleton.
-    return (controller_->updateConfig(new_config));
-}
-
-// Static callback which invokes non-static handler on singleton
-isc::data::ConstElementPtr
-DControllerBase::commandHandler(const std::string& command,
-                                isc::data::ConstElementPtr args) {
-
-    LOG_DEBUG(dctl_logger, DBGLVL_COMMAND, DCTL_COMMAND_RECEIVED)
-        .arg(controller_->getAppName()).arg(command)
-        .arg(args ? args->str() : "(no args)");
-
-    // Invoke the instance method on the controller singleton.
-    return (controller_->executeCommand(command, args));
-}
-
+// Instance method for handling new config
 isc::data::ConstElementPtr
 isc::data::ConstElementPtr
 DControllerBase::updateConfig(isc::data::ConstElementPtr new_config) {
 DControllerBase::updateConfig(isc::data::ConstElementPtr new_config) {
-    isc::data::ConstElementPtr full_config;
-    if (stand_alone_) {
-        // @todo Until there is a configuration manager to provide retrieval
-        // we'll just assume the incoming config is the full configuration set.
-        // It may also make more sense to isolate the controller from the
-        // configuration manager entirely. We could do something like
-        // process_->getFullConfig() here for stand-alone mode?
-        full_config = new_config;
-    } else {
-        if (!config_session_) {
-            // That should never happen as we install config_handler
-            // after we instantiate the server.
-            isc::data::ConstElementPtr answer =
-                    isc::config::createAnswer(1, "Configuration rejected,"
-                                              " Session has not started.");
-            return (answer);
-        }
-
-        // Let's get the existing configuration.
-        full_config = config_session_->getFullConfig();
-    }
-
-    // The configuration passed to this handler function is partial.
-    // In other words, it just includes the values being modified.
-    // In the same time, there may be dependencies between various
-    // configuration parsers. For example: the option value can
-    // be set if the definition of this option is set. If someone removes
-    // an existing option definition then the partial configuration that
-    // removes that definition is triggered while a relevant option value
-    // may remain configured. This eventually results in the
-    // configuration being in the inconsistent state.
-    // In order to work around this problem we need to merge the new
-    // configuration with the existing (full) configuration.
-
-    // Let's create a new object that will hold the merged configuration.
-    boost::shared_ptr<isc::data::MapElement>
-                            merged_config(new isc::data::MapElement());
-
-    // Merge an existing and new configuration.
-    merged_config->setValue(full_config->mapValue());
-    isc::data::merge(merged_config, new_config);
-
-    // Send the merged configuration to the application.
-    return (process_->configure(merged_config));
+    return (process_->configure(new_config));
 }
 }
 
 
 
 
+// Instance method for executing commands
 isc::data::ConstElementPtr
 isc::data::ConstElementPtr
 DControllerBase::executeCommand(const std::string& command,
 DControllerBase::executeCommand(const std::string& command,
                             isc::data::ConstElementPtr args) {
                             isc::data::ConstElementPtr args) {
@@ -364,7 +272,7 @@ DControllerBase::executeCommand(const std::string& command,
     // as it may be supported there.
     // as it may be supported there.
     isc::data::ConstElementPtr answer;
     isc::data::ConstElementPtr answer;
     if (command.compare(SHUT_DOWN_COMMAND) == 0) {
     if (command.compare(SHUT_DOWN_COMMAND) == 0) {
-        answer = shutdown(args);
+        answer = shutdownProcess(args);
     } else {
     } else {
         // It wasn't shutdown, so may be a custom controller command.
         // It wasn't shutdown, so may be a custom controller command.
         int rcode = 0;
         int rcode = 0;
@@ -390,10 +298,10 @@ DControllerBase::customControllerCommand(const std::string& command,
 }
 }
 
 
 isc::data::ConstElementPtr
 isc::data::ConstElementPtr
-DControllerBase::shutdown(isc::data::ConstElementPtr args) {
+DControllerBase::shutdownProcess(isc::data::ConstElementPtr args) {
     if (process_) {
     if (process_) {
         return (process_->shutdown(args));
         return (process_->shutdown(args));
-    } 
+    }
 
 
     // Not really a failure, but this condition is worth noting. In reality
     // Not really a failure, but this condition is worth noting. In reality
     // it should be pretty hard to cause this.
     // it should be pretty hard to cause this.
@@ -408,16 +316,31 @@ DControllerBase::usage(const std::string & text)
         std::cerr << "Usage error: " << text << std::endl;
         std::cerr << "Usage error: " << text << std::endl;
     }
     }
 
 
-    std::cerr << "Usage: " << bin_name_ <<  std::endl;
-    std::cerr << "  -v: verbose output" << std::endl;
-    std::cerr << "  -s: stand-alone mode (don't connect to BIND10)"
-              << std::endl;
+    std::cerr << "Usage: " << bin_name_ <<  std::endl
+              << "  -c <config file name> : mandatory,"
+              <<   " specifies name of configuration file " << std::endl
+              << "  -v: optional, verbose output " << std::endl;
 
 
+    // add any derivation specific usage
     std::cerr << getUsageText() << std::endl;
     std::cerr << getUsageText() << std::endl;
 }
 }
 
 
 DControllerBase::~DControllerBase() {
 DControllerBase::~DControllerBase() {
 }
 }
 
 
+std::string
+DControllerBase::getConfigFileName() {
+    return (Daemon::getConfigFile());
+}
+
 }; // namespace isc::d2
 }; // namespace isc::d2
+
+// Provide an implementation until we figure out a better way to do this.
+void
+dhcp::Daemon::loggerInit(const char* log_name, bool verbose) {
+    isc::log::initLogger(log_name,
+                         (verbose ? isc::log::DEBUG : isc::log::INFO),
+                         isc::log::MAX_DEBUG_LEVEL, NULL, true);
+}
+
 }; // namespace isc
 }; // namespace isc

+ 120 - 205
src/bin/d2/d_controller.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -16,11 +16,10 @@
 #define D_CONTROLLER_H
 #define D_CONTROLLER_H
 
 
 #include <cc/data.h>
 #include <cc/data.h>
-#include <cc/session.h>
-#include <config/ccsession.h>
 #include <d2/d2_asio.h>
 #include <d2/d2_asio.h>
 #include <d2/d2_log.h>
 #include <d2/d2_log.h>
 #include <d2/d_process.h>
 #include <d2/d_process.h>
+#include <dhcpsrv/daemon.h>
 #include <exceptions/exceptions.h>
 #include <exceptions/exceptions.h>
 #include <log/logger_support.h>
 #include <log/logger_support.h>
 
 
@@ -49,13 +48,6 @@ public:
         isc::Exception(file, line, what) { };
         isc::Exception(file, line, what) { };
 };
 };
 
 
-/// @brief Exception thrown when the session start up fails.
-class SessionStartError: public isc::Exception {
-public:
-    SessionStartError (const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) { };
-};
-
 /// @brief Exception thrown when the application process encounters an
 /// @brief Exception thrown when the application process encounters an
 /// operation in its event loop (i.e. run method).
 /// operation in its event loop (i.e. run method).
 class ProcessRunError: public isc::Exception {
 class ProcessRunError: public isc::Exception {
@@ -64,14 +56,6 @@ public:
         isc::Exception(file, line, what) { };
         isc::Exception(file, line, what) { };
 };
 };
 
 
-/// @brief Exception thrown when the session end fails.
-class SessionEndError: public isc::Exception {
-public:
-    SessionEndError (const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) { };
-};
-
-
 /// @brief Exception thrown when the controller encounters an operational error.
 /// @brief Exception thrown when the controller encounters an operational error.
 class DControllerBaseError : public isc::Exception {
 class DControllerBaseError : public isc::Exception {
 public:
 public:
@@ -84,47 +68,33 @@ public:
 class DControllerBase;
 class DControllerBase;
 typedef boost::shared_ptr<DControllerBase> DControllerBasePtr;
 typedef boost::shared_ptr<DControllerBase> DControllerBasePtr;
 
 
-/// @brief Defines a shared pointer to a Session.
-typedef boost::shared_ptr<isc::cc::Session> SessionPtr;
-
-/// @brief Defines a shared pointer to a ModuleCCSession.
-typedef boost::shared_ptr<isc::config::ModuleCCSession> ModuleCCSessionPtr;
-
-
 /// @brief Application Controller
 /// @brief Application Controller
 ///
 ///
 /// DControllerBase is an abstract singleton which provides the framework and
 /// DControllerBase is an abstract singleton which provides the framework and
 /// services for managing an application process that implements the
 /// services for managing an application process that implements the
-/// DProcessBase interface.  It allows the process to run either in
-/// integrated mode as a BIND10 module or stand-alone. It coordinates command
-/// line argument parsing, process instantiation and initialization, and runtime
-/// control through external command and configuration event handling.
+/// DProcessBase interface.  It runs the process like a stand-alone, command
+/// line driven executable, which must be supplied a configuration file at
+/// startup. It coordinates command line argument parsing, process
+/// instantiation and initialization, and runtime control through external
+/// command and configuration event handling.
 /// It creates the IOService instance which is used for runtime control
 /// It creates the IOService instance which is used for runtime control
 /// events and passes the IOService into the application process at process
 /// events and passes the IOService into the application process at process
-/// creation.  In integrated mode it is responsible for establishing BIND10
-/// session(s) and passes this IOService into the session creation method(s).
-/// It also provides the callback handlers for command and configuration events
-/// received from the external framework (aka BIND10).  For example, when
-/// running in integrated mode and a user alters the configuration with the
-/// bindctl tool, BIND10 will emit a configuration message which is sensed by
-/// the controller's IOService. The IOService in turn invokes the configuration
-/// callback, DControllerBase::configHandler().  If the user issues a command
-/// such as shutdown via bindctl,  BIND10 will emit a command message, which is
-/// sensed by controller's IOService which invokes the command callback,
-/// DControllerBase::commandHandler().
+/// creation.
+/// It provides the callback handlers for command and configuration events
+/// which could be triggered by an external source.  Such sources are intended
+/// to be registed with and monitored by the controller's IOService such that
+/// the appropriate handler can be invoked.
 ///
 ///
 /// NOTE: Derivations must supply their own static singleton instance method(s)
 /// NOTE: Derivations must supply their own static singleton instance method(s)
 /// for creating and fetching the instance. The base class declares the instance
 /// for creating and fetching the instance. The base class declares the instance
-/// member in order for it to be available for BIND10 callback functions. This
-/// would not be required if BIND10 supported instance method callbacks.
-class DControllerBase : public boost::noncopyable {
+/// member in order for it to be available for static callback functions.
+class DControllerBase : public dhcp::Daemon {
 public:
 public:
     /// @brief Constructor
     /// @brief Constructor
     ///
     ///
     /// @param app_name is display name of the application under control. This
     /// @param app_name is display name of the application under control. This
     /// name appears in log statements.
     /// name appears in log statements.
-    /// @param bin_name is the name of the application executable. Typically
-    /// this matches the BIND10 module name.
+    /// @param bin_name is the name of the application executable.
     DControllerBase(const char* app_name, const char* bin_name);
     DControllerBase(const char* app_name, const char* bin_name);
 
 
     /// @brief Destructor
     /// @brief Destructor
@@ -135,21 +105,17 @@ public:
     ///
     ///
     /// 1. parse command line arguments
     /// 1. parse command line arguments
     /// 2. instantiate and initialize the application process
     /// 2. instantiate and initialize the application process
-    /// 3. establish BIND10 session(s) if in integrated mode
+    /// 3. load the configuration file
     /// 4. start and wait on the application process event loop
     /// 4. start and wait on the application process event loop
-    /// 5. upon event loop completion, disconnect from BIND10 (if needed)
-    /// 6. exit to the caller
+    /// 5. exit to the caller
     ///
     ///
     /// It is intended to be called from main() and be given the command line
     /// It is intended to be called from main() and be given the command line
-    /// arguments. Note this method is deliberately not virtual to ensure the
-    /// proper sequence of events occur.
+    /// arguments.
     ///
     ///
-    /// This function can be run in the test mode. It prevents initialization
+    /// This function can be run in "test mode". It prevents initialization
     /// of D2 module logger. This is used in unit tests which initialize logger
     /// of D2 module logger. This is used in unit tests which initialize logger
-    /// in their main function. Such logger uses environmental variables to
-    /// control severity, verbosity etc. Reinitialization of logger by this
-    /// function would replace unit tests specific logger configuration with
-    /// this suitable for D2 running as a bind10 module.
+    /// in their main function. Such a logger uses environmental variables to
+    /// control severity, verbosity etc.
     ///
     ///
     /// @param argc  is the number of command line arguments supplied
     /// @param argc  is the number of command line arguments supplied
     /// @param argv  is the array of string (char *) command line arguments
     /// @param argv  is the array of string (char *) command line arguments
@@ -162,59 +128,9 @@ public:
     /// InvalidUsage - Indicates invalid command line.
     /// InvalidUsage - Indicates invalid command line.
     /// ProcessInitError  - Failed to create and initialize application
     /// ProcessInitError  - Failed to create and initialize application
     /// process object.
     /// process object.
-    /// SessionStartError  - Could not connect to BIND10 (integrated mode only).
     /// ProcessRunError - A fatal error occurred while in the application
     /// ProcessRunError - A fatal error occurred while in the application
     /// process event loop.
     /// process event loop.
-    /// SessionEndError - Could not disconnect from BIND10 (integrated mode
-    /// only).
-    void launch(int argc, char* argv[], const bool test_mode);
-
-    /// @brief A dummy configuration handler that always returns success.
-    ///
-    /// This configuration handler does not perform configuration
-    /// parsing and always returns success. A dummy handler should
-    /// be installed using \ref isc::config::ModuleCCSession ctor
-    /// to get the initial configuration. This initial configuration
-    /// comprises values for only those elements that were modified
-    /// the previous session. The D2 configuration parsing can't be
-    /// used to parse the initial configuration because it may need the
-    /// full configuration to satisfy dependencies between the
-    /// various configuration values. Installing the dummy handler
-    /// that guarantees to return success causes initial configuration
-    /// to be stored for the session being created and that it can
-    /// be later accessed with \ref isc::config::ConfigData::getFullConfig.
-    ///
-    /// @param new_config new configuration.
-    ///
-    /// @return success configuration status.
-    static isc::data::ConstElementPtr
-    dummyConfigHandler(isc::data::ConstElementPtr new_config);
-
-    /// @brief A callback for handling all incoming configuration updates.
-    ///
-    /// As a pointer to this method is used as a callback in ASIO for
-    /// ModuleCCSession, it has to be static.  It acts as a wrapper around
-    /// the virtual instance method, updateConfig.
-    ///
-    /// @param new_config textual representation of the new configuration
-    ///
-    /// @return status of the config update
-    static isc::data::ConstElementPtr
-    configHandler(isc::data::ConstElementPtr new_config);
-
-    /// @brief A callback for handling all incoming commands.
-    ///
-    /// As a pointer to this method is used as a callback in ASIO for
-    /// ModuleCCSession, it has to be static.  It acts as a wrapper around
-    /// the virtual instance method, executeCommand.
-    ///
-    /// @param command textual representation of the command
-    /// @param args parameters of the command. It can be NULL pointer if no
-    /// arguments exist for a particular command.
-    ///
-    /// @return status of the processed command
-    static isc::data::ConstElementPtr
-    commandHandler(const std::string& command, isc::data::ConstElementPtr args);
+    virtual void launch(int argc, char* argv[], const bool test_mode);
 
 
     /// @brief Instance method invoked by the configuration event handler and
     /// @brief Instance method invoked by the configuration event handler and
     /// which processes the actual configuration update.  Provides behavioral
     /// which processes the actual configuration update.  Provides behavioral
@@ -222,17 +138,40 @@ public:
     /// implementation will merge the configuration update into the existing
     /// implementation will merge the configuration update into the existing
     /// configuration and then invoke the application process' configure method.
     /// configuration and then invoke the application process' configure method.
     ///
     ///
-    /// @todo This implementation is will evolve as the D2 configuration
-    /// management task is implemented (trac #2957).
-    ///
     /// @param  new_config is the new configuration
     /// @param  new_config is the new configuration
     ///
     ///
     /// @return returns an Element that contains the results of configuration
     /// @return returns an Element that contains the results of configuration
     /// update composed of an integer status value (0 means successful,
     /// update composed of an integer status value (0 means successful,
     /// non-zero means failure), and a string explanation of the outcome.
     /// non-zero means failure), and a string explanation of the outcome.
-    virtual isc::data::ConstElementPtr
-    updateConfig(isc::data::ConstElementPtr new_config);
+    virtual isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr
+                                                    new_config);
 
 
+    /// @brief Reconfigures the process from a configuration file
+    ///
+    /// By default the file is assumed to be a JSON text file whose contents
+    /// include at least:
+    ///
+    /// @code
+    ///  { "<module-name>": {<module-config>} }
+    ///
+    ///  where:
+    ///     module-name : is a label which uniquely identifies the
+    ///                   configuration data for this controller's application
+    ///
+    ///     module-config: a set of zero or more JSON elements which comprise
+    ///                    the application'ss configuration values
+    /// @endcode
+    ///
+    /// The method extracts the set of configuration elements for the
+    /// module-name which matches the controller's app_name_ and passes that
+    /// set into @c udpateConfig().
+    ///
+    /// The file may contain an arbitrary number of other modules.
+    ///
+    /// @return returns an Element that contains the results of configuration
+    /// update composed of an integer status value (0 means successful,
+    /// non-zero means failure), and a string explanation of the outcome.
+    virtual isc::data::ConstElementPtr configFromFile();
 
 
     /// @brief Instance method invoked by the command event handler and  which
     /// @brief Instance method invoked by the command event handler and  which
     /// processes the actual command directive.
     /// processes the actual command directive.
@@ -262,8 +201,51 @@ public:
     ///   failure.
     ///   failure.
     ///   D2::COMMAND_INVALID - Command is not recognized as valid be either
     ///   D2::COMMAND_INVALID - Command is not recognized as valid be either
     ///   the controller or the application process.
     ///   the controller or the application process.
-    virtual isc::data::ConstElementPtr
-    executeCommand(const std::string& command, isc::data::ConstElementPtr args);
+    virtual isc::data::ConstElementPtr executeCommand(const std::string&
+                                                      command,
+                                                      isc::data::
+                                                      ConstElementPtr args);
+
+    /// @brief A callback for handling all incoming configuration updates.
+    ///
+    /// Provides a static callback that can be used to handle asynchronsouly
+    /// received configurations. It acts as a wrapper around the singleton's
+    /// virtual instance method, updateConfig.
+    ///
+    /// @param new_config textual representation of the new configuration
+    ///
+    /// @return status of the config update
+    static isc::data::ConstElementPtr configHandler(isc::data::ConstElementPtr
+                                                    new_config);
+
+    /// @brief A callback for handling all incoming commands.
+    ///
+    /// Provides a static callback that can be used to handle asynchronsouly
+    /// received commands. It acts as a wrapper around the singleton's virtual
+    /// instance method, executeCommand.
+    ///
+    /// @param command textual representation of the command
+    /// @param args parameters of the command. It can be NULL pointer if no
+    /// arguments exist for a particular command.
+    ///
+    /// @return status of the processed command
+    static isc::data::ConstElementPtr commandHandler(const std::string& command,
+                                                     isc::data::ConstElementPtr
+                                                     args);
+
+    /// @brief Fetches the name of the application under control.
+    ///
+    /// @return returns the controller service name string
+    const std::string getAppName() const {
+        return (app_name_);
+    }
+
+    /// @brief Fetches the name of the application executable.
+    ///
+    /// @return returns the controller logger name string
+    const std::string getBinName() const {
+        return (bin_name_);
+    }
 
 
 protected:
 protected:
     /// @brief Virtual method that provides derivations the opportunity to
     /// @brief Virtual method that provides derivations the opportunity to
@@ -309,26 +291,6 @@ protected:
     virtual isc::data::ConstElementPtr customControllerCommand(
     virtual isc::data::ConstElementPtr customControllerCommand(
             const std::string& command, isc::data::ConstElementPtr args);
             const std::string& command, isc::data::ConstElementPtr args);
 
 
-    /// @brief Virtual method which is invoked after the controller successfully
-    /// establishes BIND10 connectivity.  It provides an opportunity for the
-    /// derivation to execute any custom behavior associated with session
-    /// establishment.
-    ///
-    /// Note, it is not called  when running stand-alone.
-    ///
-    /// @throw should throw a DControllerBaseError if it fails.
-    virtual void onSessionConnect(){};
-
-    /// @brief Virtual method which is invoked as the first action taken when
-    /// the controller is terminating the session(s) with BIND10.  It provides
-    /// an opportunity for the derivation to execute any custom behavior
-    /// associated with session termination.
-    ///
-    /// Note, it is not called  when running stand-alone.
-    ///
-    /// @throw should throw a DControllerBaseError if it fails.
-    virtual void onSessionDisconnect(){};
-
     /// @brief Virtual method which can be used to contribute derivation
     /// @brief Virtual method which can be used to contribute derivation
     /// specific usage text.  It is invoked by the usage() method under
     /// specific usage text.  It is invoked by the usage() method under
     /// invalid usage conditions.
     /// invalid usage conditions.
@@ -340,7 +302,7 @@ protected:
 
 
     /// @brief Virtual method which returns a string containing the option
     /// @brief Virtual method which returns a string containing the option
     /// letters for any custom command line options supported by the derivation.
     /// letters for any custom command line options supported by the derivation.
-    /// These are added to the stock options of "s" and "v" during command
+    /// These are added to the stock options of "c" and "v" during command
     /// line interpretation.
     /// line interpretation.
     ///
     ///
     /// @return returns a string containing the custom option letters.
     /// @return returns a string containing the custom option letters.
@@ -348,34 +310,6 @@ protected:
         return ("");
         return ("");
     }
     }
 
 
-    /// @brief Fetches the name of the application under control.
-    ///
-    /// @return returns the controller service name string
-    const std::string getAppName() const {
-        return (app_name_);
-    }
-
-    /// @brief Fetches the name of the application executable.
-    ///
-    /// @return returns the controller logger name string
-    const std::string getBinName() const {
-        return (bin_name_);
-    }
-
-    /// @brief Supplies whether or not the controller is in stand alone mode.
-    ///
-    /// @return returns true if in stand alone mode, false otherwise
-    bool isStandAlone() const {
-        return (stand_alone_);
-    }
-
-    /// @brief Method for enabling or disabling stand alone mode.
-    ///
-    /// @param value is the new value to assign the flag.
-    void setStandAlone(bool value) {
-        stand_alone_ = value;
-    }
-
     /// @brief Supplies whether or not verbose logging is enabled.
     /// @brief Supplies whether or not verbose logging is enabled.
     ///
     ///
     /// @return returns true if verbose logging is enabled.
     /// @return returns true if verbose logging is enabled.
@@ -397,7 +331,7 @@ protected:
         return (io_service_);
         return (io_service_);
     }
     }
 
 
-    /// @brief Getter for fetching the name of the controller's BIND10 spec
+    /// @brief Getter for fetching the name of the controller's config spec
     /// file.
     /// file.
     ///
     ///
     /// @return returns the file name string.
     /// @return returns the file name string.
@@ -405,7 +339,7 @@ protected:
         return (spec_file_name_);
         return (spec_file_name_);
     }
     }
 
 
-    /// @brief Setter for setting the name of the controller's BIND10 spec file.
+    /// @brief Setter for setting the name of the controller's config spec file.
     ///
     ///
     /// @param spec_file_name the file name string.
     /// @param spec_file_name the file name string.
     void setSpecFileName(const std::string& spec_file_name) {
     void setSpecFileName(const std::string& spec_file_name) {
@@ -428,14 +362,13 @@ protected:
     /// instance a second time.
     /// instance a second time.
     static void setController(const DControllerBasePtr& controller);
     static void setController(const DControllerBasePtr& controller);
 
 
-private:
     /// @brief Processes the command line arguments. It is the first step
     /// @brief Processes the command line arguments. It is the first step
     /// taken after the controller has been launched.  It combines the stock
     /// taken after the controller has been launched.  It combines the stock
     /// list of options with those returned by getCustomOpts(), and uses
     /// list of options with those returned by getCustomOpts(), and uses
     /// cstdlib's getopt to loop through the command line.  The stock options
     /// cstdlib's getopt to loop through the command line.  The stock options
     /// It handles stock options directly, and passes any custom options into
     /// It handles stock options directly, and passes any custom options into
     /// the customOption method.  Currently there are only two stock options
     /// the customOption method.  Currently there are only two stock options
-    /// -s for stand alone mode, and -v for verbose logging.
+    /// -c for specifying the configuration file, and -v for verbose logging.
     ///
     ///
     /// @param argc  is the number of command line arguments supplied
     /// @param argc  is the number of command line arguments supplied
     /// @param argv  is the array of string (char *) command line arguments
     /// @param argv  is the array of string (char *) command line arguments
@@ -453,18 +386,6 @@ private:
     /// if there is a failure creating or initializing the application process.
     /// if there is a failure creating or initializing the application process.
     void initProcess();
     void initProcess();
 
 
-    /// @brief Establishes connectivity with BIND10.  This method is used
-    /// invoked during launch, if running in integrated mode, following
-    /// successful process initialization.  It is responsible for establishing
-    /// the BIND10 control and config sessions. During the session creation,
-    /// it passes in the controller's IOService and the callbacks for command
-    /// directives and config events.  Lastly, it will invoke the onConnect
-    /// method providing the derivation an opportunity to execute any custom
-    /// logic associated with session establishment.
-    ///
-    /// @throw the BIND10 framework may throw std::exceptions.
-    void establishSession();
-
     /// @brief Invokes the application process's event loop,(DBaseProcess::run).
     /// @brief Invokes the application process's event loop,(DBaseProcess::run).
     /// It is called during launch only after successfully completing the
     /// It is called during launch only after successfully completing the
     /// requested setup: command line parsing, application initialization,
     /// requested setup: command line parsing, application initialization,
@@ -476,15 +397,6 @@ private:
     // @throw throws DControllerBaseError or indirectly DProcessBaseError
     // @throw throws DControllerBaseError or indirectly DProcessBaseError
     void runProcess();
     void runProcess();
 
 
-    /// @brief Terminates connectivity with BIND10. This method is invoked
-    /// in integrated mode after the application event loop has exited. It
-    /// first calls the onDisconnect method providing the derivation an
-    /// opportunity to execute custom logic if needed, and then terminates the
-    /// BIND10 config and control sessions.
-    ///
-    /// @throw the BIND10 framework may throw std:exceptions.
-    void disconnectSession();
-
     /// @brief Initiates shutdown procedure.  This method is invoked
     /// @brief Initiates shutdown procedure.  This method is invoked
     /// by executeCommand in response to the shutdown command. It will invoke
     /// by executeCommand in response to the shutdown command. It will invoke
     /// the application process's shutdown method which causes the process to
     /// the application process's shutdown method which causes the process to
@@ -495,12 +407,24 @@ private:
     /// until the process has halted.  Rather it is used to convey the
     /// until the process has halted.  Rather it is used to convey the
     /// need to shutdown.  A successful return indicates that the shutdown
     /// need to shutdown.  A successful return indicates that the shutdown
     /// has successfully commenced, but does not indicate that the process
     /// has successfully commenced, but does not indicate that the process
-    /// has actually exited. 
+    /// has actually exited.
     ///
     ///
     /// @return returns an Element that contains the results of shutdown
     /// @return returns an Element that contains the results of shutdown
     /// command composed of an integer status value (0 means successful,
     /// command composed of an integer status value (0 means successful,
     /// non-zero means failure), and a string explanation of the outcome.
     /// non-zero means failure), and a string explanation of the outcome.
-    isc::data::ConstElementPtr shutdown(isc::data::ConstElementPtr args);
+    isc::data::ConstElementPtr shutdownProcess(isc::data::ConstElementPtr args);
+
+    /// @brief Fetches the name of the configuration file
+    ///
+    /// @return the configuration file name as a string
+    virtual std::string getConfigFileName();
+
+    /// @brief Fetches the current process
+    ///
+    /// @return the a pointer to the current process instance.
+    DProcessBasePtr getProcess() {
+        return (process_);
+    }
 
 
     /// @brief Prints the program usage text to std error.
     /// @brief Prints the program usage text to std error.
     ///
     ///
@@ -509,23 +433,20 @@ private:
     void usage(const std::string& text);
     void usage(const std::string& text);
 
 
 private:
 private:
-    /// @brief Display name of the service under control. This name
-    /// appears in log statements.
+    /// @brief Name of the service under control.
+    /// This name is used as the configuration module name and appears in log
+    /// statements.
     std::string app_name_;
     std::string app_name_;
 
 
-    /// @brief Name of the service executable. By convention this matches
-    /// the BIND10 module name. It is also used to establish the logger
-    /// name.
+    /// @brief Name of the service executable.
+    /// By convention this matches the executable nam. It is also used to
+    /// establish the logger name.
     std::string bin_name_;
     std::string bin_name_;
 
 
-    /// @brief Indicates if the controller stand alone mode is enabled. When
-    /// enabled, the controller will not establish connectivity with BIND10.
-    bool stand_alone_;
-
     /// @brief Indicates if the verbose logging mode is enabled.
     /// @brief Indicates if the verbose logging mode is enabled.
     bool verbose_;
     bool verbose_;
 
 
-    /// @brief The absolute file name of the BIND10 spec file.
+    /// @brief The absolute file name of the JSON spec file.
     std::string spec_file_name_;
     std::string spec_file_name_;
 
 
     /// @brief Pointer to the instance of the process.
     /// @brief Pointer to the instance of the process.
@@ -537,12 +458,6 @@ private:
     /// @brief Shared pointer to an IOService object, used for ASIO operations.
     /// @brief Shared pointer to an IOService object, used for ASIO operations.
     IOServicePtr io_service_;
     IOServicePtr io_service_;
 
 
-    /// @brief Helper session object that represents raw connection to msgq.
-    SessionPtr cc_session_;
-
-    /// @brief Session that receives configuration and commands.
-    ModuleCCSessionPtr config_session_;
-
     /// @brief Singleton instance value.
     /// @brief Singleton instance value.
     static DControllerBasePtr controller_;
     static DControllerBasePtr controller_;
 
 

+ 13 - 5
src/bin/d2/tests/Makefile.am

@@ -54,10 +54,9 @@ TESTS += d2_unittests
 d2_unittests_SOURCES = ../d2_asio.h
 d2_unittests_SOURCES = ../d2_asio.h
 d2_unittests_SOURCES += ../d2_log.h ../d2_log.cc
 d2_unittests_SOURCES += ../d2_log.h ../d2_log.cc
 d2_unittests_SOURCES += ../d_process.h
 d2_unittests_SOURCES += ../d_process.h
-d2_unittests_SOURCES += ../d_controller.cc ../d2_controller.h
-d2_unittests_SOURCES += ../d2_process.cc ../d2_process.h
-d2_unittests_SOURCES += ../d2_controller.cc ../d2_controller.h
+d2_unittests_SOURCES += ../d_controller.cc ../d_controller.h
 d2_unittests_SOURCES += ../d_cfg_mgr.cc ../d_cfg_mgr.h
 d2_unittests_SOURCES += ../d_cfg_mgr.cc ../d_cfg_mgr.h
+d2_unittests_SOURCES += ../d2_process.cc ../d2_process.h
 d2_unittests_SOURCES += ../d2_config.cc ../d2_config.h
 d2_unittests_SOURCES += ../d2_config.cc ../d2_config.h
 d2_unittests_SOURCES += ../d2_cfg_mgr.cc ../d2_cfg_mgr.h
 d2_unittests_SOURCES += ../d2_cfg_mgr.cc ../d2_cfg_mgr.h
 d2_unittests_SOURCES += ../d2_queue_mgr.cc ../d2_queue_mgr.h
 d2_unittests_SOURCES += ../d2_queue_mgr.cc ../d2_queue_mgr.h
@@ -73,8 +72,6 @@ d2_unittests_SOURCES += ../state_model.cc ../state_model.h
 d2_unittests_SOURCES += d_test_stubs.cc d_test_stubs.h
 d2_unittests_SOURCES += d_test_stubs.cc d_test_stubs.h
 d2_unittests_SOURCES += d2_unittests.cc
 d2_unittests_SOURCES += d2_unittests.cc
 d2_unittests_SOURCES += d2_process_unittests.cc
 d2_unittests_SOURCES += d2_process_unittests.cc
-d2_unittests_SOURCES += d_controller_unittests.cc
-d2_unittests_SOURCES += d2_controller_unittests.cc
 d2_unittests_SOURCES += d_cfg_mgr_unittests.cc
 d2_unittests_SOURCES += d_cfg_mgr_unittests.cc
 d2_unittests_SOURCES += d2_cfg_mgr_unittests.cc
 d2_unittests_SOURCES += d2_cfg_mgr_unittests.cc
 d2_unittests_SOURCES += d2_queue_mgr_unittests.cc
 d2_unittests_SOURCES += d2_queue_mgr_unittests.cc
@@ -90,6 +87,17 @@ d2_unittests_SOURCES += nc_trans_unittests.cc
 d2_unittests_SOURCES += state_model_unittests.cc
 d2_unittests_SOURCES += state_model_unittests.cc
 nodist_d2_unittests_SOURCES = ../d2_messages.h ../d2_messages.cc
 nodist_d2_unittests_SOURCES = ../d2_messages.h ../d2_messages.cc
 
 
+if CONFIG_BACKEND_BUNDY
+d2_unittests_SOURCES += ../bundy_d2_controller.cc ../bundy_d2_controller.h
+d2_unittests_SOURCES += bundy_d2_controller_unittests.cc
+else
+if CONFIG_BACKEND_JSON
+d2_unittests_SOURCES += ../d2_controller.cc ../d2_controller.h
+d2_unittests_SOURCES += d2_controller_unittests.cc
+d2_unittests_SOURCES += d_controller_unittests.cc
+endif
+endif
+
 d2_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 d2_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 d2_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 d2_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
 d2_unittests_LDADD = $(GTEST_LDADD)
 d2_unittests_LDADD = $(GTEST_LDADD)

+ 191 - 0
src/bin/d2/tests/bundy_d2_controller_unittests.cc

@@ -0,0 +1,191 @@
+// Copyright (C) 2014  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config/ccsession.h>
+#include <d_test_stubs.h>
+#include <d2/bundy_d2_controller.h>
+#include <d2/spec_config.h>
+
+#include <boost/pointer_cast.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <gtest/gtest.h>
+
+#include <config.h>
+#include <sstream>
+
+using namespace boost::posix_time;
+
+namespace isc {
+namespace d2 {
+
+/// @brief Test fixture class for testing D2Controller class. This class
+/// derives from DControllerTest and wraps a D2Controller.  Much of the
+/// underlying functionality is in the DControllerBase class which has an
+/// extensive set of unit tests that are independent of DHCP-DDNS.
+/// @TODO Currently These tests are relatively light and duplicate some of
+/// the testing done on the base class.  These tests are sufficient to ensure
+/// that D2Controller properly derives from its base class and to test the
+/// logic that is unique to D2Controller. These tests will be augmented and
+/// or new tests added as additional functionality evolves.
+/// Unlike the stub testing, there is no use of SimFailure to induce error
+/// conditions as this is production code.
+class BundyD2ControllerTest : public DControllerTest {
+public:
+    /// @brief Constructor
+    /// Note the constructor passes in the static D2Controller instance
+    /// method.
+    BundyD2ControllerTest() : DControllerTest(D2Controller::instance) {
+    }
+
+    /// @brief Destructor
+    ~BundyD2ControllerTest() {
+    }
+};
+
+/// @brief Basic Controller instantiation testing.
+/// Verifies that the controller singleton gets created and that the
+/// basic derivation from the base class is intact.
+TEST_F(BundyD2ControllerTest, basicInstanceTesting) {
+    // Verify the we can the singleton instance can be fetched and that
+    // it is the correct type.
+    DControllerBasePtr& controller = DControllerTest::getController();
+    ASSERT_TRUE(controller);
+    ASSERT_NO_THROW(boost::dynamic_pointer_cast<D2Controller>(controller));
+
+    // Verify that controller's app name is correct.
+    EXPECT_TRUE(checkAppName(D2Controller::d2_app_name_));
+
+    // Verify that controller's bin name is correct.
+    EXPECT_TRUE(checkBinName(D2Controller::d2_bin_name_));
+
+    // Verify that controller's spec file name is correct.
+    EXPECT_TRUE(checkSpecFileName(D2_SPECFILE_LOCATION));
+
+    // Verify that controller's IOService exists.
+    EXPECT_TRUE(checkIOService());
+
+    // Verify that the Process does NOT exist.
+    EXPECT_FALSE(checkProcess());
+}
+
+/// @brief Tests basic command line processing.
+/// Verifies that:
+/// 1. Standard command line options are supported.
+/// 2. Invalid options are detected.
+TEST_F(BundyD2ControllerTest, commandLineArgs) {
+    char* argv[] = { const_cast<char*>("progName"),
+                     const_cast<char*>("-v") };
+    int argc = 2;
+
+    // Verify that verbose flag is false initially.
+    EXPECT_TRUE(checkVerbose(false));
+
+    // Verify that standard options can be parsed without error.
+    EXPECT_NO_THROW(parseArgs(argc, argv));
+
+    // Verify that verbose flag is now true.
+    EXPECT_TRUE(checkVerbose(true));
+
+    // Verify that an unknown option is detected.
+    char* argv2[] = { const_cast<char*>("progName"),
+                      const_cast<char*>("-x") };
+    argc = 2;
+    EXPECT_THROW(parseArgs(argc, argv2), InvalidUsage);
+}
+
+/// @brief Tests application process creation and initialization.
+/// Verifies that the process can be successfully created and initialized.
+TEST_F(BundyD2ControllerTest, initProcessTesting) {
+    ASSERT_NO_THROW(initProcess());
+    EXPECT_TRUE(checkProcess());
+}
+
+/// @brief Configuration update event testing.
+/// This really tests just the ability of the handlers to invoke the necessary
+/// chain of methods and handle error conditions. Configuration parsing and
+/// retrieval should be tested as part of the d2 configuration management
+/// implementation.  Note that this testing calls the configuration update event
+/// callback, configHandler, directly.
+/// This test verifies that:
+/// 1. Configuration will be rejected in integrated mode when there is no
+/// session established. (This is a very contrived situation).
+/// 2. In stand-alone mode a configuration update results in successful
+/// status return.
+/// 3. That an application process error in configuration updating is handled
+/// properly.
+TEST_F(BundyD2ControllerTest, configUpdateTests) {
+    int rcode = -1;
+    isc::data::ConstElementPtr answer;
+
+    // Initialize the application process.
+    ASSERT_NO_THROW(initProcess());
+    EXPECT_TRUE(checkProcess());
+
+    // Create a configuration set using a small, valid D2 configuration.
+    isc::data::ElementPtr config_set =
+                                isc::data::Element::fromJSON(valid_d2_config);
+
+    // Configuration should be rejected as there is no session.  This is a 
+    // pretty contrived situation that shouldn't be possible other than the 
+    // handler being called directly (like this does).
+    answer = DControllerBase::configHandler(config_set);
+    isc::config::parseAnswer(rcode, answer);
+    EXPECT_EQ(1, rcode);
+}
+
+/// @brief Command execution tests.
+/// This really tests just the ability of the handler to invoke the necessary
+/// chain of methods and to handle error conditions. Note that this testing
+/// calls the command callback, commandHandler, directly.
+/// This test verifies that:
+/// 1. That an unrecognized command is detected and returns a status of
+/// d2::COMMAND_INVALID.
+/// 2. Shutdown command is recognized and returns a d2::COMMAND_SUCCESS status.
+TEST_F(BundyD2ControllerTest, executeCommandTests) {
+    int rcode = -1;
+    isc::data::ConstElementPtr answer;
+    isc::data::ElementPtr arg_set;
+
+    // Initialize the application process.
+    ASSERT_NO_THROW(initProcess());
+    EXPECT_TRUE(checkProcess());
+
+    // Verify that an unknown command returns an COMMAND_INVALID response.
+    std::string bogus_command("bogus");
+    answer = DControllerBase::commandHandler(bogus_command, arg_set);
+    isc::config::parseAnswer(rcode, answer);
+    EXPECT_EQ(COMMAND_INVALID, rcode);
+
+    // Verify that shutdown command returns COMMAND_SUCCESS response.
+    //answer = executeCommand(SHUT_DOWN_COMMAND, isc::data::ElementPtr());
+    answer = DControllerBase::commandHandler(SHUT_DOWN_COMMAND, arg_set);
+    isc::config::parseAnswer(rcode, answer);
+    EXPECT_EQ(COMMAND_SUCCESS, rcode);
+}
+
+/// @brief Tests launch with a session establishment failure.
+/// This test launches with a valid command line for integrated mode and no.
+/// Attempting to connect to BIND10 should fail, even if BIND10 is running
+/// UNLESS the test is run as root.  Launch should throw SessionStartError.
+TEST_F(BundyD2ControllerTest, launchSessionFailure) {
+    // Command line to run integrated
+    char* argv[] = { (char*)"progName" };
+    int argc = 1;
+
+    // Launch the controller in integrated mode.
+    EXPECT_THROW(launch(argc, argv), SessionStartError);
+}
+
+}; // end of isc::d2 namespace
+}; // end of isc namespace

+ 19 - 24
src/bin/d2/tests/d2_controller_unittests.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -85,21 +85,23 @@ TEST_F(D2ControllerTest, basicInstanceTesting) {
 /// 2. Invalid options are detected.
 /// 2. Invalid options are detected.
 TEST_F(D2ControllerTest, commandLineArgs) {
 TEST_F(D2ControllerTest, commandLineArgs) {
     char* argv[] = { const_cast<char*>("progName"),
     char* argv[] = { const_cast<char*>("progName"),
-                     const_cast<char*>("-s"),
+                     const_cast<char*>("-c"),
+                     const_cast<char*>(DControllerTest::CFG_TEST_FILE),
                      const_cast<char*>("-v") };
                      const_cast<char*>("-v") };
-    int argc = 3;
+    int argc = 4;
 
 
-    // Verify that both flags are false initially.
-    EXPECT_TRUE(checkStandAlone(false));
+    // Verify that verbose flag is false initially.
     EXPECT_TRUE(checkVerbose(false));
     EXPECT_TRUE(checkVerbose(false));
 
 
     // Verify that standard options can be parsed without error.
     // Verify that standard options can be parsed without error.
     EXPECT_NO_THROW(parseArgs(argc, argv));
     EXPECT_NO_THROW(parseArgs(argc, argv));
 
 
-    // Verify that flags are now true.
-    EXPECT_TRUE(checkStandAlone(true));
+    // Verify that verbose flag is true.
     EXPECT_TRUE(checkVerbose(true));
     EXPECT_TRUE(checkVerbose(true));
 
 
+    // Verify configuration file name is correct.
+    EXPECT_TRUE(checkConfigFileName(DControllerTest::CFG_TEST_FILE));
+
     // Verify that an unknown option is detected.
     // Verify that an unknown option is detected.
     char* argv2[] = { const_cast<char*>("progName"),
     char* argv2[] = { const_cast<char*>("progName"),
                       const_cast<char*>("-x") };
                       const_cast<char*>("-x") };
@@ -120,9 +122,13 @@ TEST_F(D2ControllerTest, initProcessTesting) {
 TEST_F(D2ControllerTest, launchNormalShutdown) {
 TEST_F(D2ControllerTest, launchNormalShutdown) {
     // command line to run standalone
     // command line to run standalone
     char* argv[] = { const_cast<char*>("progName"),
     char* argv[] = { const_cast<char*>("progName"),
-                     const_cast<char*>("-s"),
+                     const_cast<char*>("-c"),
+                     const_cast<char*>(DControllerTest::CFG_TEST_FILE),
                      const_cast<char*>("-v") };
                      const_cast<char*>("-v") };
-    int argc = 3;
+    int argc = 4;
+
+    // Create a valid D2 configuration file.
+    writeFile(valid_d2_config);
 
 
     // Use an asiolink IntervalTimer and callback to generate the
     // Use an asiolink IntervalTimer and callback to generate the
     // shutdown invocation. (Note IntervalTimer setup is in milliseconds).
     // shutdown invocation. (Note IntervalTimer setup is in milliseconds).
@@ -151,11 +157,8 @@ TEST_F(D2ControllerTest, launchNormalShutdown) {
 /// implementation.  Note that this testing calls the configuration update event
 /// implementation.  Note that this testing calls the configuration update event
 /// callback, configHandler, directly.
 /// callback, configHandler, directly.
 /// This test verifies that:
 /// This test verifies that:
-/// 1. Configuration will be rejected in integrated mode when there is no
-/// session established. (This is a very contrived situation).
-/// 2. In stand-alone mode a configuration update results in successful
-/// status return.
-/// 3. That an application process error in configuration updating is handled
+/// 1. A valid configuration yields a successful parse result.
+/// 2. That an application process error in configuration updating is handled
 /// properly.
 /// properly.
 TEST_F(D2ControllerTest, configUpdateTests) {
 TEST_F(D2ControllerTest, configUpdateTests) {
     int rcode = -1;
     int rcode = -1;
@@ -169,15 +172,7 @@ TEST_F(D2ControllerTest, configUpdateTests) {
     isc::data::ElementPtr config_set =
     isc::data::ElementPtr config_set =
                                 isc::data::Element::fromJSON(valid_d2_config);
                                 isc::data::Element::fromJSON(valid_d2_config);
 
 
-    // We are not stand-alone, so configuration should be rejected as there is
-    // no session.  This is a pretty contrived situation that shouldn't be
-    // possible other than the handler being called directly (like this does).
-    answer = DControllerBase::configHandler(config_set);
-    isc::config::parseAnswer(rcode, answer);
-    EXPECT_EQ(1, rcode);
-
-    // Verify that in stand alone we get a successful update result.
-    setStandAlone(true);
+    // Verify that given a valid config we get a successful update result.
     answer = DControllerBase::configHandler(config_set);
     answer = DControllerBase::configHandler(config_set);
     isc::config::parseAnswer(rcode, answer);
     isc::config::parseAnswer(rcode, answer);
     EXPECT_EQ(0, rcode);
     EXPECT_EQ(0, rcode);
@@ -193,7 +188,7 @@ TEST_F(D2ControllerTest, configUpdateTests) {
 /// @brief Command execution tests.
 /// @brief Command execution tests.
 /// This really tests just the ability of the handler to invoke the necessary
 /// This really tests just the ability of the handler to invoke the necessary
 /// chain of methods and to handle error conditions. Note that this testing
 /// chain of methods and to handle error conditions. Note that this testing
-/// calls the command callback, commandHandler, directly.
+/// calls the executeCommand method directly.
 /// This test verifies that:
 /// This test verifies that:
 /// 1. That an unrecognized command is detected and returns a status of
 /// 1. That an unrecognized command is detected and returns a status of
 /// d2::COMMAND_INVALID.
 /// d2::COMMAND_INVALID.

+ 2 - 3
src/bin/d2/tests/d2_test.py

@@ -1,4 +1,4 @@
-# Copyright (C) 2013 Internet Systems Consortium.
+# Copyright (C) 2013-2014 Internet Systems Consortium.
 #
 #
 # Permission to use, copy, modify, and distribute this software for any
 # Permission to use, copy, modify, and distribute this software for any
 # purpose with or without fee is hereby granted, provided that the above
 # purpose with or without fee is hereby granted, provided that the above
@@ -159,8 +159,7 @@ class TestD2Daemon(unittest.TestCase):
         print("Note: Simple test to verify that D2 server can be started.")
         print("Note: Simple test to verify that D2 server can be started.")
         # note that "-s" for stand alone is necessary in order to flush the log output
         # note that "-s" for stand alone is necessary in order to flush the log output
         # soon enough to catch it.
         # soon enough to catch it.
-        (returncode, output, error) = self.runCommand(["../b10-dhcp-ddns", 
-                                                       "-s", "-v"])
+        (returncode, output, error) = self.runCommand(["../b10-dhcp-ddns", "-v"])
         output_text = str(output) + str(error)
         output_text = str(output) + str(error)
         self.assertEqual(output_text.count("DCTL_STARTING"), 1)
         self.assertEqual(output_text.count("DCTL_STARTING"), 1)
 
 

+ 67 - 41
src/bin/d2/tests/d_controller_unittests.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -76,21 +76,23 @@ TEST_F(DStubControllerTest, basicInstanceTesting) {
 /// 4. Extraneous command line information is detected.
 /// 4. Extraneous command line information is detected.
 TEST_F(DStubControllerTest, commandLineArgs) {
 TEST_F(DStubControllerTest, commandLineArgs) {
 
 
-    // Verify that both flags are false initially.
-    EXPECT_TRUE(checkStandAlone(false));
+    // Verify that verbose flag is false initially.
     EXPECT_TRUE(checkVerbose(false));
     EXPECT_TRUE(checkVerbose(false));
 
 
     // Verify that standard options can be parsed without error.
     // Verify that standard options can be parsed without error.
     char* argv[] = { const_cast<char*>("progName"),
     char* argv[] = { const_cast<char*>("progName"),
-                     const_cast<char*>("-s"),
+                     const_cast<char*>("-c"),
+                     const_cast<char*>("cfgName"),
                      const_cast<char*>("-v") };
                      const_cast<char*>("-v") };
-    int argc = 3;
+    int argc = 4;
     EXPECT_NO_THROW(parseArgs(argc, argv));
     EXPECT_NO_THROW(parseArgs(argc, argv));
 
 
-    // Verify that flags are now true.
-    EXPECT_TRUE(checkStandAlone(true));
+    // Verify that verbose is true.
     EXPECT_TRUE(checkVerbose(true));
     EXPECT_TRUE(checkVerbose(true));
 
 
+    // Verify configuration file name is correct
+    EXPECT_TRUE(checkConfigFileName("cfgName"));
+
     // Verify that the custom command line option is parsed without error.
     // Verify that the custom command line option is parsed without error.
     char xopt[3] = "- ";
     char xopt[3] = "- ";
     xopt[1] =  *DStubController::stub_option_x_;
     xopt[1] =  *DStubController::stub_option_x_;
@@ -166,9 +168,10 @@ TEST_F(DStubControllerTest, launchInvalidUsage) {
 TEST_F(DStubControllerTest, launchProcessInitError) {
 TEST_F(DStubControllerTest, launchProcessInitError) {
     // Command line to run integrated
     // Command line to run integrated
     char* argv[] = { const_cast<char*>("progName"),
     char* argv[] = { const_cast<char*>("progName"),
-                     const_cast<char*>("-s"),
+                     const_cast<char*>("-c"),
+                     const_cast<char*>(DControllerTest::CFG_TEST_FILE),
                      const_cast<char*>("-v") };
                      const_cast<char*>("-v") };
-    int argc = 3;
+    int argc = 4;
 
 
     // Launch the controller in stand alone mode.
     // Launch the controller in stand alone mode.
     SimFailure::set(SimFailure::ftCreateProcessException);
     SimFailure::set(SimFailure::ftCreateProcessException);
@@ -177,13 +180,19 @@ TEST_F(DStubControllerTest, launchProcessInitError) {
 
 
 /// @brief Tests launch and normal shutdown (stand alone mode).
 /// @brief Tests launch and normal shutdown (stand alone mode).
 /// This creates an interval timer to generate a normal shutdown and then
 /// This creates an interval timer to generate a normal shutdown and then
-/// launches with a valid, stand-alone command line and no simulated errors.
+/// launches with a valid, command line, with a valid configuration file
+///  and no simulated errors.
 TEST_F(DStubControllerTest, launchNormalShutdown) {
 TEST_F(DStubControllerTest, launchNormalShutdown) {
     // command line to run standalone
     // command line to run standalone
     char* argv[] = { const_cast<char*>("progName"),
     char* argv[] = { const_cast<char*>("progName"),
-                     const_cast<char*>("-s"),
+                     const_cast<char*>("-c"),
+                     const_cast<char*>(DControllerTest::CFG_TEST_FILE),
                      const_cast<char*>("-v") };
                      const_cast<char*>("-v") };
-    int argc = 3;
+    int argc = 4;
+
+    // Create a non-empty, config file.  writeFile will wrap the contents
+    // with the module name for us.
+    writeFile("{}");
 
 
     // Use an asiolink IntervalTimer and callback to generate the
     // Use an asiolink IntervalTimer and callback to generate the
     // shutdown invocation. (Note IntervalTimer setup is in milliseconds).
     // shutdown invocation. (Note IntervalTimer setup is in milliseconds).
@@ -205,6 +214,42 @@ TEST_F(DStubControllerTest, launchNormalShutdown) {
                 elapsed.total_milliseconds() <= 2200);
                 elapsed.total_milliseconds() <= 2200);
 }
 }
 
 
+/// @brief Tests launch with an nonexistant configuration file.
+TEST_F(DStubControllerTest, nonexistantConfigFile) {
+    // command line to run standalone
+    char* argv[] = { const_cast<char*>("progName"),
+                     const_cast<char*>("-c"),
+                     const_cast<char*>("bogus-file"),
+                     const_cast<char*>("-v") };
+    int argc = 4;
+
+    // Record start time, and invoke launch().
+    EXPECT_THROW(launch(argc, argv), ProcessInitError);
+}
+
+/// @brief Tests launch with configuration file argument but no file name
+TEST_F(DStubControllerTest, missingConfigFileName) {
+    // command line to run standalone
+    char* argv[] = { const_cast<char*>("progName"),
+                     const_cast<char*>("-c"),
+                     const_cast<char*>("-v") };
+    int argc = 3;
+
+    // Record start time, and invoke launch().
+    EXPECT_THROW(launch(argc, argv), ProcessInitError);
+}
+
+/// @brief Tests launch with no configuration file argument
+TEST_F(DStubControllerTest, missingConfigFileArgument) {
+    // command line to run standalone
+    char* argv[] = { const_cast<char*>("progName"),
+                     const_cast<char*>("-v") };
+    int argc = 2;
+
+    // Record start time, and invoke launch().
+    EXPECT_THROW(launch(argc, argv), ProcessInitError);
+}
+
 /// @brief Tests launch with an operational error during application execution.
 /// @brief Tests launch with an operational error during application execution.
 /// This test creates an interval timer to generate a runtime exception during
 /// This test creates an interval timer to generate a runtime exception during
 /// the process event loop. It launches wih a valid, stand-alone command line
 /// the process event loop. It launches wih a valid, stand-alone command line
@@ -212,9 +257,14 @@ TEST_F(DStubControllerTest, launchNormalShutdown) {
 TEST_F(DStubControllerTest, launchRuntimeError) {
 TEST_F(DStubControllerTest, launchRuntimeError) {
     // command line to run standalone
     // command line to run standalone
     char* argv[] = { const_cast<char*>("progName"),
     char* argv[] = { const_cast<char*>("progName"),
-                     const_cast<char*>("-s"),
+                     const_cast<char*>("-c"),
+                     const_cast<char*>(DControllerTest::CFG_TEST_FILE),
                      const_cast<char*>("-v") };
                      const_cast<char*>("-v") };
-    int argc = 3;
+    int argc = 4;
+
+    // Create a non-empty, config file.  writeFile will wrap the contents
+    // with the module name for us.
+    writeFile("{}");
 
 
     // Use an asiolink IntervalTimer and callback to generate the
     // Use an asiolink IntervalTimer and callback to generate the
     // shutdown invocation. (Note IntervalTimer setup is in milliseconds).
     // shutdown invocation. (Note IntervalTimer setup is in milliseconds).
@@ -236,19 +286,6 @@ TEST_F(DStubControllerTest, launchRuntimeError) {
                 elapsed.total_milliseconds() <= 2200);
                 elapsed.total_milliseconds() <= 2200);
 }
 }
 
 
-/// @brief Tests launch with a session establishment failure.
-/// This test launches with a valid command line for integrated mode and no.
-/// Attempting to connect to BIND10 should fail, even if BIND10 is running
-/// UNLESS the test is run as root.  Launch should throw SessionStartError.
-TEST_F(DStubControllerTest, launchSessionFailure) {
-    // Command line to run integrated
-    char* argv[] = { (char*)"progName" };
-    int argc = 1;
-
-    // Launch the controller in integrated mode.
-    EXPECT_THROW(launch(argc, argv), SessionStartError);
-}
-
 /// @brief Configuration update event testing.
 /// @brief Configuration update event testing.
 /// This really tests just the ability of the handlers to invoke the necessary
 /// This really tests just the ability of the handlers to invoke the necessary
 /// chain of methods and handle error conditions. Configuration parsing and
 /// chain of methods and handle error conditions. Configuration parsing and
@@ -256,11 +293,8 @@ TEST_F(DStubControllerTest, launchSessionFailure) {
 /// implementation.  Note that this testing calls the configuration update event
 /// implementation.  Note that this testing calls the configuration update event
 /// callback, configHandler, directly.
 /// callback, configHandler, directly.
 /// This test verifies that:
 /// This test verifies that:
-/// 1. Configuration will be rejected in integrated mode when there is no
-/// session established. (This is a very contrived situation).
-/// 2. In stand-alone mode a configuration update results in successful
-/// status return.
-/// 3. That an application process error in configuration updating is handled
+/// 1. That a valid configuration update results in successful status return.
+/// 2. That an application process error in configuration updating is handled
 /// properly.
 /// properly.
 TEST_F(DStubControllerTest, configUpdateTests) {
 TEST_F(DStubControllerTest, configUpdateTests) {
     int rcode = -1;
     int rcode = -1;
@@ -275,15 +309,7 @@ TEST_F(DStubControllerTest, configUpdateTests) {
     std::string config = "{ \"test-value\": 1000 } ";
     std::string config = "{ \"test-value\": 1000 } ";
     isc::data::ElementPtr config_set = isc::data::Element::fromJSON(config);
     isc::data::ElementPtr config_set = isc::data::Element::fromJSON(config);
 
 
-    // We are not stand-alone, so configuration should be rejected as there is
-    // no session.  This is a pretty contrived situation that shouldn't be
-    // possible other than the handler being called directly (like this does).
-    answer = DControllerBase::configHandler(config_set);
-    isc::config::parseAnswer(rcode, answer);
-    EXPECT_EQ(1, rcode);
-
-    // Verify that in stand alone we get a successful update result.
-    setStandAlone(true);
+    // Verify that a valid config gets a successful update result.
     answer = DControllerBase::configHandler(config_set);
     answer = DControllerBase::configHandler(config_set);
     isc::config::parseAnswer(rcode, answer);
     isc::config::parseAnswer(rcode, answer);
     EXPECT_EQ(0, rcode);
     EXPECT_EQ(0, rcode);

+ 6 - 1
src/bin/d2/tests/d_test_stubs.cc

@@ -1,4 +1,4 @@
-// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -55,6 +55,7 @@ DStubProcess::DStubProcess(const char* name, IOServicePtr io_service)
     : DProcessBase(name, io_service, DCfgMgrBasePtr(new DStubCfgMgr())) {
     : DProcessBase(name, io_service, DCfgMgrBasePtr(new DStubCfgMgr())) {
 };
 };
 
 
+
 void
 void
 DStubProcess::init() {
 DStubProcess::init() {
     if (SimFailure::shouldFailOn(SimFailure::ftProcessInit)) {
     if (SimFailure::shouldFailOn(SimFailure::ftProcessInit)) {
@@ -140,6 +141,7 @@ const char* DStubController::stub_app_name_ = "TestService";
 /// @brief Defines the bin name used to construct the controller
 /// @brief Defines the bin name used to construct the controller
 const char* DStubController::stub_bin_name_ = "TestBin";
 const char* DStubController::stub_bin_name_ = "TestBin";
 
 
+
 DControllerBasePtr&
 DControllerBasePtr&
 DStubController::instance() {
 DStubController::instance() {
     // If the singleton hasn't been created, do it now.
     // If the singleton hasn't been created, do it now.
@@ -217,6 +219,9 @@ DStubController::~DStubController() {
 // Initialize controller wrapper's static instance getter member.
 // Initialize controller wrapper's static instance getter member.
 DControllerTest::InstanceGetter DControllerTest::instanceGetter_ = NULL;
 DControllerTest::InstanceGetter DControllerTest::instanceGetter_ = NULL;
 
 
+/// @brief Defines the name of the configuration file to use
+const char* DControllerTest::CFG_TEST_FILE = "d2-test-config.json";
+
 //************************** ObjectParser *************************
 //************************** ObjectParser *************************
 
 
 ObjectParser::ObjectParser(const std::string& param_name,
 ObjectParser::ObjectParser(const std::string& param_name,

+ 48 - 30
src/bin/d2/tests/d_test_stubs.h

@@ -1,4 +1,4 @@
-// Copyright (C) 2013  Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2013-2014 Internet Systems Consortium, Inc. ("ISC")
 //
 //
 // Permission to use, copy, modify, and/or distribute this software for any
 // Permission to use, copy, modify, and/or distribute this software for any
 // purpose with or without fee is hereby granted, provided that the above
 // purpose with or without fee is hereby granted, provided that the above
@@ -25,6 +25,10 @@
 
 
 #include <gtest/gtest.h>
 #include <gtest/gtest.h>
 
 
+#include <fstream>
+#include <iostream>
+#include <sstream>
+
 namespace isc {
 namespace isc {
 namespace d2 {
 namespace d2 {
 
 
@@ -293,6 +297,7 @@ public:
     /// a clean start between tests.
     /// a clean start between tests.
     virtual ~DControllerTest() {
     virtual ~DControllerTest() {
         getController().reset();
         getController().reset();
+        static_cast<void>(unlink(CFG_TEST_FILE));
     }
     }
 
 
     /// @brief Convenience method that destructs and then recreates the
     /// @brief Convenience method that destructs and then recreates the
@@ -361,31 +366,22 @@ public:
         return (getController()->io_service_);
         return (getController()->io_service_);
     }
     }
 
 
-    /// @brief Compares stand alone flag with the given value.
+    /// @brief Compares verbose flag with the given value.
     ///
     ///
     /// @param value
     /// @param value
     ///
     ///
-    /// @return returns true if the stand alone flag is equal to the given
-    /// value.
-    bool checkStandAlone(bool value) {
-        return (getController()->isStandAlone() == value);
-    }
-
-    /// @brief Sets the controller's stand alone flag to the given value.
-    ///
-    /// @param value is the new value to assign.
-    ///
-    void setStandAlone(bool value) {
-        getController()->setStandAlone(value);
+    /// @return returns true if the verbose flag is equal to the given value.
+    bool checkVerbose(bool value) {
+        return (getController()->isVerbose() == value);
     }
     }
 
 
-    /// @brief Compares verbose flag with the given value.
+    /// @brief Compares configuration file name with the given value.
     ///
     ///
-    /// @param value
+    /// @param value file name to compare against
     ///
     ///
     /// @return returns true if the verbose flag is equal to the given value.
     /// @return returns true if the verbose flag is equal to the given value.
-    bool checkVerbose(bool value) {
-        return (getController()->isVerbose() == value);
+    bool checkConfigFileName(const std::string& value) {
+        return (getController()->getConfigFileName() == value);
     }
     }
 
 
     /// @Wrapper to invoke the Controller's parseArgs method.  Please refer to
     /// @Wrapper to invoke the Controller's parseArgs method.  Please refer to
@@ -400,12 +396,6 @@ public:
         getController()->initProcess();
         getController()->initProcess();
     }
     }
 
 
-    /// @Wrapper to invoke the Controller's establishSession method.  Please
-    /// refer to DControllerBase::establishSession for details.
-    void establishSession() {
-        getController()->establishSession();
-    }
-
     /// @Wrapper to invoke the Controller's launch method.  Please refer to
     /// @Wrapper to invoke the Controller's launch method.  Please refer to
     /// DControllerBase::launch for details.
     /// DControllerBase::launch for details.
     void launch(int argc, char* argv[]) {
     void launch(int argc, char* argv[]) {
@@ -413,12 +403,6 @@ public:
         getController()->launch(argc, argv, true);
         getController()->launch(argc, argv, true);
     }
     }
 
 
-    /// @Wrapper to invoke the Controller's disconnectSession method.  Please
-    /// refer to DControllerBase::disconnectSession for details.
-    void disconnectSession() {
-        getController()->disconnectSession();
-    }
-
     /// @Wrapper to invoke the Controller's updateConfig method.  Please
     /// @Wrapper to invoke the Controller's updateConfig method.  Please
     /// refer to DControllerBase::updateConfig for details.
     /// refer to DControllerBase::updateConfig for details.
     isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr
     isc::data::ConstElementPtr updateConfig(isc::data::ConstElementPtr
@@ -444,6 +428,40 @@ public:
     static void genFatalErrorCallback() {
     static void genFatalErrorCallback() {
         isc_throw (DProcessBaseError, "simulated fatal error");
         isc_throw (DProcessBaseError, "simulated fatal error");
     }
     }
+
+    /// @brief writes specified content to a well known file
+    ///
+    /// Writes given JSON content to CFG_TEST_FILE. It will wrap the
+    /// content within a JSON element whose name is equal to the controller's
+    /// app name or the given module name if not blank:
+    ///
+    /// @code
+    ///    { "<app_name>" : <content> }
+    /// @endcod
+    ///
+    /// suffix the content within a JSON element with the given module
+    /// name or  wrapped by a JSON
+    /// element  . Tests will
+    /// attempt to read that file.
+    ///
+    /// @param content JSON text to be written to file
+    /// @param module_name  content content to be written to file
+    void writeFile(const std::string& content,
+                   const std::string module_name = "") {
+        std::ofstream out(CFG_TEST_FILE, std::ios::trunc);
+        ASSERT_TRUE(out.is_open());
+
+        out << "{ \"" << (!module_name.empty() ? module_name :
+                          getController()->getAppName())
+             << "\": " << std::endl;
+
+        out << content;
+        out << " } " << std::endl;
+        out.close();
+    }
+
+    /// Name of a config file used during tests
+    static const char* CFG_TEST_FILE;
 };
 };
 
 
 /// @brief a collection of elements that store uint32 values
 /// @brief a collection of elements that store uint32 values