BIND 10 trac2955, updated. cddad16de73088a9e11330746e33a1faed947f64 [2395] Created the initial, bare-bones implementation DHCP-DDNS service process class, D2Process, and the abstract class from which it derives, DProcess. This class provides DHCP-DDNS specific event loop and business logic.
BIND 10 source code commits
bind10-changes at lists.isc.org
Wed May 22 17:26:37 UTC 2013
The branch, trac2955 has been updated
via cddad16de73088a9e11330746e33a1faed947f64 (commit)
from 6f344e77217625e36e924f41c24d88ac0ba685be (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit cddad16de73088a9e11330746e33a1faed947f64
Author: Thomas Markwalder <tmark at isc.org>
Date: Wed May 22 13:24:25 2013 -0400
[2395] Created the initial, bare-bones implementation DHCP-DDNS service
process class, D2Process, and the abstract class from which it derives,
DProcess. This class provides DHCP-DDNS specific event loop and business
logic.
The following new files have been added:
src/bin/d2/d_process.h - defines the DProcess base class
src/bin/d2/d2_process.h - defines the D2Process class
src/bin/d2/d2_process.cc - implements the D2Process class
src/bin/d2/tests/d2_process_unittests.cc - initial unit tests
-----------------------------------------------------------------------
Summary of changes:
src/bin/d2/d2_process.cc | 88 ++++++++++++++++
src/bin/d2/d2_process.h | 98 ++++++++++++++++++
src/bin/d2/d_process.h | 135 +++++++++++++++++++++++++
src/bin/d2/tests/d2_process_unittests.cc | 161 ++++++++++++++++++++++++++++++
4 files changed, 482 insertions(+)
create mode 100644 src/bin/d2/d2_process.cc
create mode 100644 src/bin/d2/d2_process.h
create mode 100644 src/bin/d2/d_process.h
create mode 100644 src/bin/d2/tests/d2_process_unittests.cc
-----------------------------------------------------------------------
diff --git a/src/bin/d2/d2_process.cc b/src/bin/d2/d2_process.cc
new file mode 100644
index 0000000..8fdb6a6
--- /dev/null
+++ b/src/bin/d2/d2_process.cc
@@ -0,0 +1,88 @@
+// Copyright (C) 2013 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 <d2/d2_log.h>
+#include <d2/d2_process.h>
+
+using namespace asio;
+
+namespace isc {
+namespace d2 {
+
+D2Process::D2Process(const char* name, IOServicePtr io_service)
+ : DProcess(name, io_service) {
+};
+
+void
+D2Process::init() {
+};
+
+int
+D2Process::run() {
+ // Until shut down or an fatal error occurs, wait for and
+ // execute a single callback. This is a preliminary implementation
+ // that is likely to evolve as development progresses.
+ // To use run(), the "managing" layer must issue an io_service::stop
+ // or the call to run will continue to block, and shutdown will not
+ // occur.
+ LOG_DEBUG(d2_logger, DBGLVL_START_SHUT, D2PRC_RUN_ENTER);
+ while (!shut_down_) {
+ try {
+ io_service_->run_one();
+ } catch (const std::exception& ex) {
+ LOG_FATAL(d2_logger, D2PRC_FAILED).arg(ex.what());
+ return (EXIT_FAILURE);
+ }
+ }
+
+ LOG_DEBUG(d2_logger, DBGLVL_START_SHUT, D2PRC_RUN_EXIT);
+ return (EXIT_SUCCESS);
+};
+
+int
+D2Process::shutdown() {
+ LOG_DEBUG(d2_logger, DBGLVL_START_SHUT, D2PRC_SHUTDOWN);
+ shut_down_ = true;
+ return (0);
+}
+
+isc::data::ConstElementPtr
+D2Process::configure(isc::data::ConstElementPtr config_set) {
+ // @TODO This is the initial implementation which simply accepts
+ // any content in config_set as valid. This is sufficient to
+ // allow participation as a BIND10 module, while D2 configuration support
+ // is being developed.
+ LOG_DEBUG(d2_logger, DBGLVL_TRACE_BASIC,
+ D2PRC_CONFIGURE).arg(config_set->str());
+
+ return (isc::config::createAnswer(0, "Configuration accepted."));
+}
+
+isc::data::ConstElementPtr
+D2Process::command(const std::string& command, isc::data::ConstElementPtr args){
+ // @TODO This is the initial implementation. If and when D2 is extended
+ // to support its own commands, this implementation must change. Otherwise
+ // it should reject all commands as it does now.
+ LOG_DEBUG(d2_logger, DBGLVL_TRACE_BASIC,
+ D2PRC_COMMAND).arg(command).arg(args->str());
+
+ return (isc::config::createAnswer(1, "Unrecognized command:" + command));
+}
+
+D2Process::~D2Process() {
+};
+
+}; // namespace isc::d2
+}; // namespace isc
diff --git a/src/bin/d2/d2_process.h b/src/bin/d2/d2_process.h
new file mode 100644
index 0000000..2f36de1
--- /dev/null
+++ b/src/bin/d2/d2_process.h
@@ -0,0 +1,98 @@
+// Copyright (C) 2013 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 D2_PROCESS_H
+#define D2_PROCESS_H
+
+#include <d2/d_process.h>
+
+namespace isc {
+namespace d2 {
+
+/// @brief @TODO DHCP-DDNS Application Process
+///
+/// D2Process provides the top level application logic for DHCP-driven DDNS
+/// update processing. It provides the asynchronous event processing required
+/// to receive DNS mapping change requests and carry them out.
+/// It implements the DProcess interface, which structures it such that it
+/// is a managed "application", controlled by a management layer.
+
+class D2Process : public DProcess {
+public:
+ /// @brief Constructor
+ ///
+ /// @param name name is a text label for the process. Generally used
+ /// in log statements, but otherwise arbitrary.
+ /// @param io_service is the io_service used by the caller for
+ /// asynchronous event handling.
+ ///
+ /// @throw DProcessError is io_service is NULL.
+ D2Process(const char* name, IOServicePtr io_service);
+
+ /// @brief Will be used after instantiation to perform initialization
+ /// unique to D2. This will likely include interactions with QueueMgr and
+ /// UpdateMgr, to prepare for request receipt and processing.
+ virtual void init();
+
+ /// @brief Implements the process's event loop.
+ /// The initial implementation is quite basic, surrounding calls to
+ /// io_service->runOne() with a test of the shutdown flag.
+ /// Once invoked, the method will continue until the process itself is
+ /// exiting due to a request to shutdown or some anomaly forces an exit.
+ /// @return returns 0 upon a successful, "normal" termination, non
+ /// zero to indicate an abnormal termination.
+ virtual int run();
+
+ // @TODO need brief
+ virtual int shutdown();
+
+ // @TODO need brief
+ /// @brief Processes the given configuration.
+ ///
+ /// This method may be called multiple times during the process lifetime.
+ /// Certainly once during process startup, and possibly later if the user
+ /// alters configuration. This method must not throw, it should catch any
+ /// processing errors and return a success or failure answer as described
+ /// below.
+ ///
+ /// @param config_set a new configuration (JSON) for the process
+ /// @return an Element that contains the results of configuration composed
+ /// of an integer status value (0 means successful, non-zero means failure),
+ /// and a string explanation of the outcome.
+ virtual isc::data::ConstElementPtr configure(isc::data::ConstElementPtr
+ config_set);
+
+ // @TODO need brief
+ /// @brief Processes the given command.
+ ///
+ /// This method is called to execute any custom commands supported by the
+ /// process. This method must not throw, it should catch any processing
+ /// errors and return a success or failure answer as described below.
+ ///
+ /// @param command is a string label representing the command to execute.
+ /// @param args is a set of arguments (if any) required for the given
+ /// command.
+ /// @return an Element that contains the results of command composed
+ /// of an integer status value (0 means successful, non-zero means failure),
+ /// and a string explanation of the outcome.
+ virtual isc::data::ConstElementPtr command(const std::string& command,
+ isc::data::ConstElementPtr args);
+ // @TODO need brief
+ virtual ~D2Process();
+};
+
+}; // namespace isc::d2
+}; // namespace isc
+
+#endif
diff --git a/src/bin/d2/d_process.h b/src/bin/d2/d_process.h
new file mode 100644
index 0000000..7398fa2
--- /dev/null
+++ b/src/bin/d2/d_process.h
@@ -0,0 +1,135 @@
+// Copyright (C) 2013 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 D_PROCESS_H
+#define D_PROCESS_H
+
+#include <asiolink/asiolink.h>
+#include <cc/data.h>
+#include <boost/shared_ptr.hpp>
+
+#include <exceptions/exceptions.h>
+
+typedef boost::shared_ptr<isc::asiolink::IOService> IOServicePtr;
+
+namespace isc {
+namespace d2 {
+
+/// @brief Exception thrown if the process encountered an operational error.
+class DProcessError : public isc::Exception {
+public:
+ DProcessError(const char* file, size_t line, const char* what) :
+ isc::Exception(file, line, what) { };
+};
+
+/// @brief Application Process Interface
+///
+/// DProcess is an abstract class represents the primary "application" level
+/// object in a "managed" asyncrhonous application. It provides a uniform
+/// interface such that a managing layer can construct, intialize, and start
+/// the application's event loop. The event processing is centered around the
+/// use of isc::asiolink::io_service. The io_service is shared between the
+/// the managing layer and the DProcess. This allows management layer IO
+/// such as directives to be sensed and handled, as well as processing IO
+/// activity specific to the application. In terms fo management layer IO,
+/// there are methods shutdown, configuration updates, and commands unique
+/// to the application.
+class DProcess {
+public:
+ /// @brief Constructor
+ ///
+ /// @param name name is a text label for the process. Generally used
+ /// in log statements, but otherwise arbitrary.
+ /// @param io_service is the io_service used by the caller for
+ /// asynchronous event handling.
+ ///
+ /// @throw DProcessError is io_service is NULL.
+ DProcess(const char* name, IOServicePtr io_service) : name_(name),
+ io_service_(io_service), shut_down_(false) {
+
+ if (!io_service_) {
+ isc_throw (DProcessError, "IO Service cannot be null");
+ }
+ };
+
+ /// @brief May be used after instantiation to perform initialization unique
+ /// to application. It must be invoked prior to invoking run. This would
+ /// likely include the creation of additional IO sources and their
+ /// integration into the io_service.
+ virtual void init() = 0;
+
+ /// @brief Implements the process's event loop. In its simplest form it
+ /// would an invocation io_service_->run(). This method should not exit
+ /// until the process itself is exiting due to a request to shutdown or
+ /// some anomaly is forcing an exit.
+ /// @return returns EXIT_SUCCESS upon a successful, normal termination,
+ /// and EXIT_FAILURE to indicate an abnormal termination.
+ virtual int run() = 0;
+
+ /// @brief Implements the process's shutdown processing. When invoked, it
+ /// should ensure that the process gracefully exits the run method.
+ virtual int shutdown() = 0;
+
+ /// @brief Processes the given configuration.
+ ///
+ /// This method may be called multiple times during the process lifetime.
+ /// Certainly once during process startup, and possibly later if the user
+ /// alters configuration. This method must not throw, it should catch any
+ /// processing errors and return a success or failure answer as described
+ /// below.
+ ///
+ /// @param config_set a new configuration (JSON) for the process
+ /// @return an Element that contains the results of configuration composed
+ /// of an integer status value (0 means successful, non-zero means failure),
+ /// and a string explanation of the outcome.
+ virtual isc::data::ConstElementPtr configure(isc::data::ConstElementPtr
+ config_set) = 0;
+
+ /// @brief Processes the given command.
+ ///
+ /// This method is called to execute any custom commands supported by the
+ /// process. This method must not throw, it should catch any processing
+ /// errors and return a success or failure answer as described below.
+ ///
+ /// @param command is a string label representing the command to execute.
+ /// @param args is a set of arguments (if any) required for the given
+ /// command.
+ /// @return an Element that contains the results of command composed
+ /// of an integer status value (0 means successful, non-zero means failure),
+ /// and a string explanation of the outcome.
+ virtual isc::data::ConstElementPtr command(
+ const std::string& command, isc::data::ConstElementPtr args) = 0;
+
+ /// @brief Destructor
+ virtual ~DProcess(){};
+
+protected:
+ /// @brief Text label for the process. Generally used in log statements,
+ /// but otherwise can be arbitrary.
+ std::string name_;
+
+ /// @brief The IOService to be used for asynchronous event handling.
+ IOServicePtr io_service_;
+
+ /// @brief Boolean flag set when shutdown has been requested.
+ bool shut_down_;
+};
+
+/// @brief Defines a shared pointer to DProcess.
+typedef boost::shared_ptr<DProcess> DProcessPtr;
+
+}; // namespace isc::d2
+}; // namespace isc
+
+#endif
diff --git a/src/bin/d2/tests/d2_process_unittests.cc b/src/bin/d2/tests/d2_process_unittests.cc
new file mode 100644
index 0000000..8391b1c
--- /dev/null
+++ b/src/bin/d2/tests/d2_process_unittests.cc
@@ -0,0 +1,161 @@
+// Copyright (C) 2013 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 <d2/d2_process.h>
+
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <gtest/gtest.h>
+
+#include <config.h>
+#include <sstream>
+
+using namespace std;
+using namespace isc;
+using namespace isc::config;
+using namespace isc::d2;
+using namespace boost::posix_time;
+
+namespace {
+
+/// @brief D2Process test fixture class
+class D2ProcessTest : public ::testing::Test {
+public:
+
+ /// @brief Static instance accessible via test callbacks.
+ static DProcessPtr process_;
+
+ /// @brief Constructor
+ D2ProcessTest() {
+ io_service_.reset(new isc::asiolink::IOService());
+ process_.reset(new D2Process("TestProcess", io_service_));
+ }
+
+ /// @brief Destructor
+ ~D2ProcessTest() {
+ io_service_.reset();
+ process_.reset();
+ }
+
+ /// @brief Callback that will invoke shutdown method.
+ static void genShutdownCallback() {
+ D2ProcessTest::process_->shutdown();
+ }
+
+ /// @brief Callback that throws an exception.
+ static void genFatalErrorCallback() {
+ isc_throw (DProcessError, "simulated fatal error");
+ }
+
+ /// @brief IOService for event processing. Fills in for IOservice
+ /// supplied by management layer.
+ IOServicePtr io_service_;
+};
+
+
+/// @brief Verifies D2Process constructor behavior.
+/// 1. Verifies that constructor fails with an invalid IOService
+/// 2. Verifies that constructor succeeds with a valid IOService
+TEST(D2Process, construction) {
+ // Verify that the constructor will fail if given an empty
+ // io service.
+ IOServicePtr lcl_io_service;
+ EXPECT_THROW (D2Process("TestProcess", lcl_io_service), DProcessError);
+
+ // Verify that the constructor succeeds with a valid io_service
+ lcl_io_service.reset(new isc::asiolink::IOService());
+ ASSERT_NO_THROW (D2Process("TestProcess", lcl_io_service));
+}
+
+/// @brief Verifies basic configure method behavior.
+// @TODO This test is simplistic and will need to be augmented
+// as configuration ability is implemented.
+TEST_F(D2ProcessTest, configure) {
+ // Verify that given a configuration "set", configure returns
+ // a successful response.
+ int rcode = -1;
+ string config = "{ \"test-value\": 1000 } ";
+ isc::data::ElementPtr json = isc::data::Element::fromJSON(config);
+ isc::data::ConstElementPtr answer = process_->configure(json);
+ isc::config::parseAnswer(rcode, answer);
+ EXPECT_EQ(0, rcode);
+}
+
+/// @brief Verifies basic command method behavior.
+// @TODO IF the D2Process is extended to support extra commands
+// this testing will need to augmented accordingly.
+TEST_F(D2ProcessTest, command) {
+ // Verfiy that the process will process unsupported command and
+ // return a failure response.
+ int rcode = -1;
+ string args = "{ \"arg1\": 77 } ";
+ isc::data::ElementPtr json = isc::data::Element::fromJSON(args);
+ isc::data::ConstElementPtr answer =
+ process_->command("bogus_command", json);
+ parseAnswer(rcode, answer);
+ EXPECT_EQ(1, rcode);
+}
+
+/// @brief Verifies that an "external" call to shutdown causes
+/// the run method to exit gracefully with a return value of EXIT_SUCCESS.
+TEST_F(D2ProcessTest, normalShutdown) {
+ // Use an asiolink IntervalTimer and callback to generate the
+ // shutdown invocation.
+ isc::asiolink::IntervalTimer timer(*io_service_);
+ timer.setup(genShutdownCallback, 2*1000);
+
+ // Record start time, and invoke run().
+ ptime start = second_clock::universal_time();
+ int rcode = process_->run();
+
+ // Record stop time.
+ ptime stop = second_clock::universal_time();
+
+ // Verify normal shutdown status.
+ EXPECT_EQ(EXIT_SUCCESS, rcode);
+
+ // Verify that duration of the run invocation is the same as the
+ // timer duration. This demonstrates that the shutdown was driven
+ // by an io_service event and callback.
+ time_duration elapsed = stop - start;
+ EXPECT_EQ(2L, elapsed.seconds());
+}
+
+/// @brief Verifies that an "uncaught" exception thrown during event loop
+/// processing is treated as a fatal error.
+TEST_F(D2ProcessTest, fatalErrorShutdown) {
+ // Use an asiolink IntervalTimer and callback to generate the
+ // the exception.
+ isc::asiolink::IntervalTimer timer(*io_service_);
+ timer.setup(genFatalErrorCallback, 2*1000);
+
+ // Record start time, and invoke run().
+ ptime start = second_clock::universal_time();
+ int rcode = process_->run();
+
+ // Record stop time.
+ ptime stop = second_clock::universal_time();
+
+ // Verify failure status.
+ EXPECT_EQ(EXIT_FAILURE, rcode);
+
+ // Verify that duration of the run invocation is the same as the
+ // timer duration. This demonstrates that the anomaly occurred
+ // during io callback processing.
+ time_duration elapsed = stop - start;
+ EXPECT_EQ(2L, elapsed.seconds());
+}
+
+} // end of anonymous namespace
More information about the bind10-changes
mailing list