]> git.ipfire.org Git - thirdparty/kea.git/commitdiff
[#101,!73] kea-dhcp4 can init CB backends based on config
authorThomas Markwalder <tmark@isc.org>
Tue, 16 Oct 2018 17:21:20 +0000 (13:21 -0400)
committerThomas Markwalder <tmark@isc.org>
Tue, 16 Oct 2018 17:21:20 +0000 (13:21 -0400)
src/bin/dhcp4/json_config_parser.*
    databaseConfigConnect(const SrvConfigPtr& srv_cfg)
    databaseConfigFetch(const SrvConfigPtr& srv_cfg, ElementPtr /*global_scope*/)
    - new functions

    configureDhcp4Server() - modified to call databaseConfigFetch() after
    loading hook libs

src/bin/dhcp4/tests/config_parser_unittest.cc
    TEST_F(Dhcp4ParserTest, configControlInfoNoFactory) - new test
    TEST_F(Dhcp4ParserTest, configControlInfo) - modified to register
    dummy backend

src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.*
    New files that implement DHPC4 dummy backend for testing

src/bin/dhcp4/json_config_parser.cc
src/bin/dhcp4/json_config_parser.h
src/bin/dhcp4/tests/config_parser_unittest.cc
src/lib/dhcpsrv/testutils/Makefile.am
src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc [new file with mode: 0644]
src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.h [new file with mode: 0644]

index 8b9b35ab44750f6a05fbb7183becb249be7687f0..e44e8599580c66c1c2b2d3fb9e0b5089b3d862f9 100644 (file)
 #include <database/dbaccess_parser.h>
 #include <dhcp4/dhcp4_log.h>
 #include <dhcp4/dhcp4_srv.h>
+#include <dhcp4/json_config_parser.h>
 #include <dhcp/libdhcp++.h>
 #include <dhcp/option_definition.h>
 #include <dhcpsrv/cfg_option.h>
 #include <dhcpsrv/cfgmgr.h>
-#include <dhcp4/json_config_parser.h>
+#include <dhcpsrv/config_backend_dhcp4_mgr.h>
 #include <dhcpsrv/db_type.h>
 #include <dhcpsrv/parsers/client_class_def_parser.h>
 #include <dhcpsrv/parsers/dhcp_parsers.h>
@@ -50,6 +51,7 @@ using namespace isc::dhcp;
 using namespace isc::data;
 using namespace isc::asiolink;
 using namespace isc::hooks;
+using namespace isc::process;
 
 namespace {
 
@@ -318,9 +320,11 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
     // the parsers.  It is declared outside the loops so in case of an error,
     // the name of the failing parser can be retrieved in the "catch" clause.
     ConfigPair config_pair;
+    ElementPtr mutable_cfg;
+    SrvConfigPtr srv_cfg;
     try {
-
-        SrvConfigPtr srv_cfg = CfgMgr::instance().getStagingCfg();
+        // Get the staging configuration
+        srv_cfg = CfgMgr::instance().getStagingCfg();
 
         // Preserve all scalar global parameters
         srv_cfg->extractConfiguredGlobals(config_set);
@@ -328,7 +332,7 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
         // This is a way to convert ConstElementPtr to ElementPtr.
         // We need a config that can be edited, because we will insert
         // default values and will insert derived values as well.
-        ElementPtr mutable_cfg = boost::const_pointer_cast<Element>(config_set);
+        mutable_cfg = boost::const_pointer_cast<Element>(config_set);
 
         // Set all default values if not specified by the user.
         SimpleParser4::setAllDefaults(mutable_cfg);
@@ -464,7 +468,6 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
             }
 
             if (config_pair.first == "subnet4") {
-                SrvConfigPtr srv_cfg = CfgMgr::instance().getStagingCfg();
                 Subnets4ListConfigParser subnets_parser;
                 // parse() returns number of subnets parsed. We may log it one day.
                 subnets_parser.parse(srv_cfg, config_pair.second);
@@ -500,8 +503,8 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
             }
 
             if (config_pair.first == "config-control") {
-                process::ConfigControlParser parser;
-                process::ConfigControlInfoPtr config_ctl_info = parser.parse(config_pair.second);
+                ConfigControlParser parser;
+                ConfigControlInfoPtr config_ctl_info = parser.parse(config_pair.second);
                 CfgMgr::instance().getStagingCfg()->setConfigControlInfo(config_ctl_info);
                 continue;
             }
@@ -574,9 +577,6 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
     // This operation should be exception safe but let's make sure.
     if (!rollback) {
         try {
-            // if we have config-control DBs attempt to create them here,
-            // if that fails, rollback?
-
             // Setup the command channel.
             configureCommandChannel();
 
@@ -595,8 +595,8 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
                 CfgMgr::instance().getStagingCfg()->getHooksConfig();
             libraries.loadLibraries();
 
-            // now that we have config-db and hooks, merge in config from DB
-            // databaseConfigFetch(srv_config, mutable_cfg);
+            // If there are config backends, fetch and merge into staging config
+            databaseConfigFetch(srv_cfg, mutable_cfg);
         }
         catch (const isc::Exception& ex) {
             LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(ex.what());
@@ -629,5 +629,47 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
     return (answer);
 }
 
+bool databaseConfigConnect(const SrvConfigPtr& srv_cfg) {
+    // We need to get rid of any existing backends.  These would be any
+    // opened by previous configuration cycle.
+    ConfigBackendDHCPv4Mgr& mgr = ConfigBackendDHCPv4Mgr::instance();
+    mgr.delAllBackends();
+
+    // SrvConfigPtr staging_cfg = CfgMgr::instance().getStagingCfg();
+    ConstConfigControlInfoPtr config_ctl = srv_cfg->getConfigControlInfo();
+    if (!config_ctl || config_ctl->getConfigDatabases().empty()) {
+        // No config dbs, nothing to do.
+        return (false);
+    }
+
+    // First step is to create all of the backends.
+    for (auto db : config_ctl->getConfigDatabases()) {
+            // Good place for a log message?
+            mgr.addBackend(db.getAccessString());
+    }
+
+    return (true);
+}
+
+void databaseConfigFetch(const SrvConfigPtr& srv_cfg, ElementPtr /*global_scope*/) {
+
+    // Close any existing CB databasess, then open all in srv_cfg (if any)
+    if (!databaseConfigConnect(srv_cfg)) {
+        // There are no CB databases so we're done
+        return;
+    }
+
+    // @todo Fetching and merging the configuration falls under #99
+    // ConfigBackendDHCPv4Mgr& mgr = ConfigBackendDHCPv4Mgr::instance();
+    // Next we have to fetch the pieces we care about it and merge them
+    // probably in this order?
+    // globals
+    // shared networks
+    // subnets
+    // option defs
+    // options
+}
+
+
 }; // end of isc::dhcp namespace
 }; // end of isc namespace
index 7687e8983bd30a3be95a42a22ce74f9cf4b14598..0c4cae769420caed2014d3c4f44014963a9e1acb 100644 (file)
@@ -59,6 +59,34 @@ configureDhcp4Server(Dhcpv4Srv&,
                      isc::data::ConstElementPtr config_set,
                      bool check_only = false);
 
+/// @brief Attempts to the configured CB databases  (if any)
+///
+/// This function will close all the existing CB backends. It
+/// then attempt to connect to all of the CB databases in the
+/// given SrvConfig (if any).
+///
+/// It will return true if there are configured CB databases
+/// false, otherwise.  Any errors encountered along the way
+/// should generate throws.
+///
+/// @param srv_cfg Server configuration from which to get
+/// the config-control information to use.
+///
+/// @return True if are configured CB databases, false if not.
+bool
+databaseConfigConnect(const SrvConfigPtr& srv_cfg);
+
+/// @brief Fetch configuration from CB databases and merge it into the given configuration
+///
+/// It will call @c databaseConfigConnect passing in the given server configuration. If
+/// results in open CB databases it will proceed to fetch configuration components from
+/// those databases and merge them into the given server configuration.
+///
+/// @param srv_config Server configuration to merge into
+/// @param global_scope global configuration as elements
+void
+databaseConfigFetch(const SrvConfigPtr& srv_cfg, isc::data::ElementPtr /*global_scope*/);
+
 }; // end of isc::dhcp namespace
 }; // end of isc namespace
 
index 19a5bd143e41768773bccd61155f9a3b397c2653..b1a4cc18f3201e832ec10c4afc38f6b512e8ef54 100644 (file)
@@ -25,6 +25,7 @@
 #include <dhcpsrv/cfg_hosts.h>
 #include <dhcpsrv/cfg_subnets4.h>
 #include <dhcpsrv/testutils/config_result_check.h>
+#include <dhcpsrv/testutils/test_config_backend_dhcp4.h>
 #include <process/config_ctl_info.h>
 #include <hooks/hooks_manager.h>
 
@@ -6258,10 +6259,27 @@ TEST_F(Dhcp4ParserTest, globalReservations) {
     EXPECT_FALSE(hosts_cfg->get4(542, Host::IDENT_DUID, &duid[0], duid.size()));
 }
 
+// This test verifies that configuration control with unsupported type fails
+TEST_F(Dhcp4ParserTest, configControlInfoNoFactory) {
+    string config = PARSER_CONFIGS[6];
+    extractConfig(config);
+
+    // Should fail because "type=mysql" has no factories.
+    configure(config, CONTROL_RESULT_COMMAND_UNSUPPORTED,
+              "The type of the configuration backend: 'mysql' is not supported");
+}
+
 // This test verifies that configuration control info gets populated.
 TEST_F(Dhcp4ParserTest, configControlInfo) {
     string config = PARSER_CONFIGS[6];
     extractConfig(config);
+
+    // Should be able to register a backend factory for "mysql".
+    ASSERT_TRUE(TestConfigBackendDHCPv4Impl::
+                registerBackendType(ConfigBackendDHCPv4Mgr::instance(),
+                                    "mysql"));
+
+    // Should parse ok, now that the factory has been registered.
     configure(config, CONTROL_RESULT_SUCCESS, "");
 
     // Make sure the config control info is there.
@@ -6273,12 +6291,12 @@ TEST_F(Dhcp4ParserTest, configControlInfo) {
     const process::ConfigDbInfoList& dblist = info->getConfigDatabases();
     ASSERT_EQ(2, dblist.size());
 
-    // Make sure the entries are what we expect and in the right order. 
-    // (DbAccessParser creates access strings with the keywords in 
+    // Make sure the entries are what we expect and in the right order.
+    // (DbAccessParser creates access strings with the keywords in
     //  alphabetical order).
-    EXPECT_EQ("name=keatest1 password=keatest type=mysql user=keatest", 
+    EXPECT_EQ("name=keatest1 password=keatest type=mysql user=keatest",
               dblist.front().getAccessString());
-    EXPECT_EQ("name=keatest2 password=keatest type=mysql user=keatest", 
+    EXPECT_EQ("name=keatest2 password=keatest type=mysql user=keatest",
               dblist.back().getAccessString());
 }
 
index f5252365319dd56a94d101c4e3f449bbb23e5f23..829e65da180e8a63e714988ce3a0dfe716d7b460 100644 (file)
@@ -19,6 +19,7 @@ libdhcpsrvtest_la_SOURCES += memory_host_data_source.cc memory_host_data_source.
 libdhcpsrvtest_la_SOURCES += generic_backend_unittest.cc generic_backend_unittest.h
 libdhcpsrvtest_la_SOURCES += generic_host_data_source_unittest.cc generic_host_data_source_unittest.h
 libdhcpsrvtest_la_SOURCES += lease_file_io.cc lease_file_io.h
+libdhcpsrvtest_la_SOURCES += test_config_backend_dhcp4.cc test_config_backend_dhcp4.h
 
 libdhcpsrvtest_la_CXXFLAGS = $(AM_CXXFLAGS)
 libdhcpsrvtest_la_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
diff --git a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.cc
new file mode 100644 (file)
index 0000000..00aff16
--- /dev/null
@@ -0,0 +1,256 @@
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <database/database_connection.h>
+#include <test_config_backend_dhcp4.h>
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+bool
+TestConfigBackendDHCPv4Impl::registerBackendType(ConfigBackendDHCPv4Mgr& mgr,
+                                                 const std::string& db_type) {
+    return(mgr.registerBackendFactory(db_type,
+                [](const db::DatabaseConnection::ParameterMap& params)
+                -> dhcp::ConfigBackendDHCPv4Ptr {
+                return (TestConfigBackendDHCPv4ImplPtr(new TestConfigBackendDHCPv4Impl(params)));
+            })
+    );
+}
+
+void
+TestConfigBackendDHCPv4Impl::unregisterBackendType(ConfigBackendDHCPv4Mgr& mgr,
+                                                   const std::string& db_type) {
+    mgr.unregisterBackendFactory(db_type);
+}
+
+Subnet4Ptr
+TestConfigBackendDHCPv4Impl::getSubnet4(const db::ServerSelector& /* server_selector */,
+                                        const std::string& /* subnet_prefix */) const{
+    return (Subnet4Ptr());
+}
+
+Subnet4Ptr
+TestConfigBackendDHCPv4Impl::getSubnet4(const db::ServerSelector& /* server_selector */,
+                                        const SubnetID& /* subnet_id */) const {
+    return (Subnet4Ptr());
+}
+
+Subnet4Collection
+TestConfigBackendDHCPv4Impl::getAllSubnets4(const db::ServerSelector& /* server_selector */) const {
+    return(subnets_);
+}
+
+Subnet4Collection
+TestConfigBackendDHCPv4Impl::getModifiedSubnets4(const db::ServerSelector& /* server_selector */,
+                                                 const boost::posix_time::ptime& /* modification_time */) const {
+    return(subnets_);
+}
+
+SharedNetwork4Ptr
+TestConfigBackendDHCPv4Impl::getSharedNetwork4(const db::ServerSelector& /* server_selector */,
+                                               const std::string& /* name */) const {
+    return(SharedNetwork4Ptr());
+}
+
+SharedNetwork4Collection
+TestConfigBackendDHCPv4Impl::getAllSharedNetworks4(const db::ServerSelector& /* server_selector */) const{
+    return(shared_networks_);
+}
+
+SharedNetwork4Collection
+TestConfigBackendDHCPv4Impl::getModifiedSharedNetworks4(const db::ServerSelector& /* server_selector */,
+                                                        const boost::posix_time::ptime& /* modification_time */) const {
+    return(shared_networks_);
+}
+
+OptionDefinitionPtr
+TestConfigBackendDHCPv4Impl::getOptionDef4(const db::ServerSelector& /* server_selector */,
+                                           const uint16_t /* code */,
+                                           const std::string& /* space */) const {
+    return (OptionDefinitionPtr());
+}
+
+OptionDefContainer
+TestConfigBackendDHCPv4Impl::getAllOptionDefs4(const db::ServerSelector& /* server_selector */) const {
+    return (option_defs_);
+}
+
+OptionDefContainer
+TestConfigBackendDHCPv4Impl::getModifiedOptionDefs4(const db::ServerSelector& /* server_selector */,
+                                                    const boost::posix_time::ptime& /* modification_time */) const {
+    return (option_defs_);
+}
+
+OptionDescriptorPtr
+TestConfigBackendDHCPv4Impl::getOption4(const db::ServerSelector& /* server_selector */,
+                                        const uint16_t /* code */,
+                                        const std::string& /* space */) const {
+    return (OptionDescriptorPtr());
+}
+
+OptionContainer
+TestConfigBackendDHCPv4Impl::getAllOptions4(const db::ServerSelector& /* server_selector */) const {
+    return (options_);
+}
+
+OptionContainer
+TestConfigBackendDHCPv4Impl::getModifiedOptions4(const db::ServerSelector& /* selector */,
+                                                 const boost::posix_time::ptime& /* modification_time */) const {
+    return (options_);
+}
+
+data::StampedValuePtr
+TestConfigBackendDHCPv4Impl::getGlobalParameter4(const db::ServerSelector& /* selector */,
+                                                 const std::string& /* name */) const {
+    return(data::StampedValuePtr());
+}
+
+
+data::StampedValueCollection
+TestConfigBackendDHCPv4Impl::getAllGlobalParameters4(const db::ServerSelector& /* selector */) const {
+    return (globals_);
+}
+
+data::StampedValueCollection
+TestConfigBackendDHCPv4Impl::getModifiedGlobalParameters4(const db::ServerSelector& /* selector */,
+                                                          const boost::posix_time::ptime& /* modification_time */) const {
+    return (globals_);
+}
+
+void
+TestConfigBackendDHCPv4Impl::createUpdateSubnet4(const db::ServerSelector& /* server_selector */,
+                                                 const Subnet4Ptr& /* subnet */) {
+}
+
+void
+TestConfigBackendDHCPv4Impl::createUpdateSharedNetwork4(const db::ServerSelector& /* server_selector */,
+                                                        const SharedNetwork4Ptr& /* shared_network */) {
+}
+
+void
+TestConfigBackendDHCPv4Impl::createUpdateOptionDef4(const db::ServerSelector& /* server_selector */,
+                                                    const OptionDefinitionPtr& /* option_def */) {
+}
+
+void
+TestConfigBackendDHCPv4Impl::createUpdateOption4(const db::ServerSelector& /* server_selector */,
+                                                 const OptionDescriptorPtr& /* option */) {
+}
+
+void
+TestConfigBackendDHCPv4Impl::createUpdateOption4(const db::ServerSelector& /* selector */,
+                                                 const std::string& /* shared_network_name */,
+                                                 const OptionDescriptorPtr& /* option */) {
+}
+
+void
+TestConfigBackendDHCPv4Impl::createUpdateOption4(const db::ServerSelector& /* server_selector */,
+                                                 const SubnetID& /* subnet_id */,
+                                                 const OptionDescriptorPtr& /* option */) {
+}
+
+void
+TestConfigBackendDHCPv4Impl::createUpdateOption4(const db::ServerSelector& /* server_selector */,
+                                                 const asiolink::IOAddress& /* pool_start_address */,
+                                                 const asiolink::IOAddress& /* pool_end_address */,
+                                                 const OptionDescriptorPtr& /* option */) {
+}
+
+void
+TestConfigBackendDHCPv4Impl::createUpdateGlobalParameter4(const db::ServerSelector& /* server_selector */,
+                                                          const data::StampedValuePtr& /* value */) {
+}
+
+uint64_t
+TestConfigBackendDHCPv4Impl::deleteSubnet4(const db::ServerSelector& /* server_selector */,
+                                           const std::string& /* subnet_prefix */) {
+    return (0);
+}
+
+uint64_t
+TestConfigBackendDHCPv4Impl::deleteSubnet4(const db::ServerSelector& /* server_selector */,
+                                           const SubnetID& /* subnet_id */) {
+    return (0);
+}
+
+uint64_t
+TestConfigBackendDHCPv4Impl::deleteAllSubnets4(const db::ServerSelector& /* server_selector */) {
+    return (0);
+}
+
+uint64_t
+TestConfigBackendDHCPv4Impl::deleteSharedNetwork4(const db::ServerSelector& /* server_selector */,
+                                                  const std::string& /* name */) {
+    return (0);
+}
+
+uint64_t
+TestConfigBackendDHCPv4Impl::deleteAllSharedNetworks4(const db::ServerSelector& /* server_selector */) {
+    return (0);
+}
+
+uint64_t
+TestConfigBackendDHCPv4Impl::deleteOptionDef4(const db::ServerSelector& /* server_selector */,
+                                              const uint16_t /* code */,
+                                              const std::string& /* space */) {
+    return (0);
+}
+
+uint64_t
+TestConfigBackendDHCPv4Impl::deleteAllOptionDefs4(const db::ServerSelector& /* server_selector */) {
+    return (0);
+}
+
+uint64_t
+TestConfigBackendDHCPv4Impl::deleteOption4(const db::ServerSelector& /* server_selector */,
+                                           const uint16_t /* code */,
+                                           const std::string& /* space */) {
+    return (0);
+}
+
+uint64_t
+TestConfigBackendDHCPv4Impl::deleteOption4(const db::ServerSelector& /* server_selector */,
+                                           const std::string& /* shared_network_name */,
+                                           const uint16_t /* code */,
+                                           const std::string& /* space */) {
+    return (0);
+}
+
+uint64_t
+TestConfigBackendDHCPv4Impl::deleteOption4(const db::ServerSelector& /* server_selector */,
+                                           const SubnetID& /* subnet_id */,
+                                           const uint16_t /* code */,
+                                           const std::string& /* space */) {
+    return (0);
+}
+
+uint64_t
+TestConfigBackendDHCPv4Impl::deleteOption4(const db::ServerSelector& /* server_selector */,
+                                           const asiolink::IOAddress& /* pool_start_address */,
+                                           const asiolink::IOAddress& /* pool_end_address */,
+                                           const uint16_t /* code */,
+                                           const std::string& /* space */) {
+    return (0);
+}
+
+uint64_t
+TestConfigBackendDHCPv4Impl::deleteGlobalParameter4(const db::ServerSelector& /* server_selector */,
+                                                    const std::string& /* name */) {
+    return (0);
+}
+
+uint64_t
+TestConfigBackendDHCPv4Impl::deleteAllGlobalParameters4(const db::ServerSelector& /* server_selector */) {
+    return (0);
+}
+
+} // namespace test
+} // namespace dhcp
+} // namespace isc
diff --git a/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.h b/src/lib/dhcpsrv/testutils/test_config_backend_dhcp4.h
new file mode 100644 (file)
index 0000000..8ce6bc8
--- /dev/null
@@ -0,0 +1,472 @@
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <database/database_connection.h>
+#include <dhcpsrv/config_backend_dhcp4_mgr.h>
+#include <boost/shared_ptr.hpp>
+#include <boost/lexical_cast.hpp>
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+/// @brief Base class for implementing fake backends
+class TestConfigBackendDHCPv4 : public ConfigBackendDHCPv4 {
+public:
+    /// @brief Constructor
+    ///
+    /// @param params database connection parameters
+    /// @throw BadValue if parameters do not include "type"
+    TestConfigBackendDHCPv4(const db::DatabaseConnection::ParameterMap& params)
+     : connection_(params) {
+        try {
+            db_type_ = connection_.getParameter("type");
+        } catch (...) {
+            isc_throw(BadValue, "Backend parameters must include \"type\"");
+        }
+
+        try {
+            db_type_ = connection_.getParameter("host");
+        } catch (...) {
+            host_ = "default_host";
+        }
+
+        try {
+            port_ = boost::lexical_cast<uint16_t>(connection_.getParameter("host"));
+        } catch (...) {
+            port_ = 0;
+        }
+    }
+
+    /// @brief virtual Destructor.
+    virtual ~TestConfigBackendDHCPv4(){};
+
+    /// @brief Returns backend type.
+    ///
+    /// @return string db_type name
+    virtual std::string getType() const {
+        return (db_type_);
+    }
+
+    /// @brief Returns backend host.
+    ///
+    /// @return string host
+    virtual std::string getHost() const {
+        return (host_);
+    }
+
+    /// @brief Returns backend port.
+    ///
+    /// @return uint16_t port
+    virtual uint16_t getPort() const {
+        return (port_);
+    }
+
+    /// @brief Fake database connection
+    db::DatabaseConnection connection_;
+
+    /// @brief  Back end type
+    std::string db_type_;
+
+    /// @brief  Back end host
+    std::string host_;
+
+    /// @brief  Back end port
+    uint16_t port_;
+};
+
+/// @brief Test backend for that implements all of the DHCPv4 API calls
+///
+/// Currently all API get calls which return a single entry, will return an
+/// empty pointer of appropriate type. API calls which return a collection of
+/// entires will return an empty collection of the appropriate type.
+///
+/// In addition provides static register and unregister methods so it may be
+/// registered with a configuration backend manager.
+class TestConfigBackendDHCPv4Impl : public TestConfigBackendDHCPv4 {
+public:
+    /// @brief Constructor
+    ///
+    ///
+    TestConfigBackendDHCPv4Impl(const db::DatabaseConnection::ParameterMap& params)
+        : TestConfigBackendDHCPv4(params) {
+    }
+
+    /// @brief virtual Destructor.
+    virtual ~TestConfigBackendDHCPv4Impl(){};
+
+    /// @brief Registers the backend type with the given backend manager
+    ///
+    /// @param mgr configuration manager to register with
+    /// @brief db_type back end type - Note you will need to
+    /// use the same value here as you do when creating backend instances.
+    static bool registerBackendType(ConfigBackendDHCPv4Mgr& mgr,
+                                    const std::string& db_type);
+
+    /// @brief Unregisters the backend from the given backend manager
+    ///
+    /// @param mgr configuration manager to unregister from
+    /// @brief db_type back end type - Note you will need to
+    /// use the same value here as you do when registering the backend type
+    static void unregisterBackendType(ConfigBackendDHCPv4Mgr& mgr,
+                                      const std::string& db_type);
+
+    /// @brief Retrieves a single subnet by subnet_prefix.
+    ///
+    /// @param server_selector Server selector.
+    /// @param subnet_prefix Prefix of the subnet to be retrieved.
+    /// @return Pointer to the retrieved subnet or NULL if not found.
+    virtual Subnet4Ptr
+    getSubnet4(const db::ServerSelector& server_selector,
+               const std::string& subnet_prefix) const;
+
+    /// @brief Retrieves a single subnet by subnet identifier.
+    ///
+    /// @param server_selector Server selector.
+    /// @param subnet_id Identifier of a subnet to be retrieved.
+    /// @return Pointer to the retrieved subnet or NULL if not found.
+    virtual Subnet4Ptr
+    getSubnet4(const db::ServerSelector& server_selector, const SubnetID& subnet_id) const;
+
+    /// @brief Retrieves all subnets.
+    ///
+    /// @param server_selector Server selector.
+    /// @return Collection of subnets or empty collection if no subnet found.
+    virtual Subnet4Collection
+    getAllSubnets4(const db::ServerSelector& server_selector) const;
+
+    /// @brief Retrieves subnets modified after specified time.
+    ///
+    /// @param server_selector Server selector.
+    /// @param modification_time Lower bound subnet modification time.
+    /// @return Collection of subnets or empty collection if no subnet found.
+    virtual Subnet4Collection
+    getModifiedSubnets4(const db::ServerSelector& server_selector,
+                        const boost::posix_time::ptime& modification_time) const;
+
+    /// @brief Retrieves shared network by name.
+    ///
+    /// @param server_selector Server selector.
+    /// @param name Name of the shared network to be retrieved.
+    /// @return Pointer to the shared network or NULL if not found.
+    virtual SharedNetwork4Ptr
+    getSharedNetwork4(const db::ServerSelector& server_selector,
+                      const std::string& name) const;
+
+    /// @brief Retrieves all shared networks.
+    ///
+    /// @param server_selector Server selector.
+    /// @return Collection of shared network or empty collection if
+    /// no shared network found.
+    virtual SharedNetwork4Collection
+    getAllSharedNetworks4(const db::ServerSelector& server_selector) const;
+
+    /// @brief Retrieves shared networks modified after specified time.
+    ///
+    /// @param server_selector Server selector.
+    /// @param modification_time Lower bound shared network modification time.
+    /// @return Collection of shared network or empty collection if
+    /// no shared network found.
+    virtual SharedNetwork4Collection
+    getModifiedSharedNetworks4(const db::ServerSelector& server_selector,
+                               const boost::posix_time::ptime& modification_time) const;
+
+    /// @brief Retrieves single option definition by code and space.
+    ///
+    /// @param server_selector Server selector.
+    /// @param code Code of the option to be retrieved.
+    /// @param space Option space of the option to be retrieved.
+    /// @return Pointer to the option definition or NULL if not found.
+    virtual OptionDefinitionPtr
+    getOptionDef4(const db::ServerSelector& server_selector, const uint16_t code,
+                  const std::string& space) const;
+
+    /// @brief Retrieves all option definitions.
+    ///
+    /// @param server_selector Server selector.
+    /// @return Collection of option definitions or empty collection if
+    /// no option definition found.
+    virtual OptionDefContainer
+    getAllOptionDefs4(const db::ServerSelector& server_selector) const;
+
+    /// @brief Retrieves option definitions modified after specified time.
+    ///
+    /// @param server_selector Server selector.
+    /// @param modification_time Lower bound option definition modification
+    /// time.
+    /// @return Collection of option definitions or empty collection if
+    /// no option definition found.
+    virtual OptionDefContainer
+    getModifiedOptionDefs4(const db::ServerSelector& server_selector,
+                           const boost::posix_time::ptime& modification_time) const;
+
+    /// @brief Retrieves single option by code and space.
+    ///
+    /// @param server_selector Server selector.
+    /// @return Pointer to the retrieved option descriptor or null if
+    /// no option was found.
+    virtual OptionDescriptorPtr
+    getOption4(const db::ServerSelector& server_selector, const uint16_t code,
+               const std::string& space) const;
+
+    /// @brief Retrieves all global options.
+    ///
+    /// @param server_selector Server selector.
+    /// @return Collection of global options or empty collection if no
+    /// option found.
+    virtual OptionContainer
+    getAllOptions4(const db::ServerSelector& server_selector) const;
+
+    /// @brief Retrieves option modified after specified time.
+    ///
+    /// @param selector Server selector.
+    /// @param modification_time Lower bound option modification time.
+    /// @return Collection of global options or empty collection if no
+    /// option found.
+    virtual OptionContainer
+    getModifiedOptions4(const db::ServerSelector& selector,
+                        const boost::posix_time::ptime& modification_time) const;
+
+    /// @brief Retrieves global parameter value.
+    ///
+    /// @param server_selector Server selector.
+    /// @param name Name of the global parameter to be retrieved.
+    /// @return Value of the global parameter or null if parameter doesn't
+    /// exist.
+    virtual data::StampedValuePtr
+    getGlobalParameter4(const db::ServerSelector& selector,
+                        const std::string& name) const;
+
+    /// @return Collection of global parameters.
+    virtual data::StampedValueCollection
+    getAllGlobalParameters4(const db::ServerSelector& selector) const;
+
+    /// @brief Retrieves global parameters modified after specified time.
+    ///
+    /// @param selector Server selector.
+    /// @return Collection of modified global parameters.
+    virtual data::StampedValueCollection
+    getModifiedGlobalParameters4(const db::ServerSelector& selector,
+                                 const boost::posix_time::ptime& modification_time) const;
+
+    /// @brief Creates or updates a subnet.
+    ///
+    /// @param server_selector Server selector.
+    /// @param subnet Subnet to be added or updated.
+    virtual void
+    createUpdateSubnet4(const db::ServerSelector& server_selector,
+                        const Subnet4Ptr& subnet);
+
+    /// @brief Creates or updates a shared network.
+    ///
+    /// @param server_selector Server selector.
+    /// @param shared_network Shared network to be added or updated.
+    virtual void
+    createUpdateSharedNetwork4(const db::ServerSelector& server_selector,
+                               const SharedNetwork4Ptr& shared_network);
+
+    /// @brief Creates or updates an option definition.
+    ///
+    /// @param server_selector Server selector.
+    /// @param option_def Option definition to be added or updated.
+    virtual void
+    createUpdateOptionDef4(const db::ServerSelector& server_selector,
+                           const OptionDefinitionPtr& option_def);
+
+    /// @brief Creates or updates global option.
+    ///
+    /// @param server_selector Server selector.
+    /// @param option Option to be added or updated.
+    virtual void
+    createUpdateOption4(const db::ServerSelector& server_selector,
+                        const OptionDescriptorPtr& option);
+
+    /// @brief Creates or updates shared network level option.
+    ///
+    /// @param selector Server selector.
+    /// @param shared_network_name Name of a shared network to which option
+    /// belongs.
+    /// @param option Option to be added or updated.
+    virtual void
+    createUpdateOption4(const db::ServerSelector& selector,
+                        const std::string& shared_network_name,
+                        const OptionDescriptorPtr& option);
+
+    /// @brief Creates or updates subnet level option.
+    ///
+    /// @param server_selector Server selector.
+    /// @param subnet_id Identifier of a subnet to which option belongs.
+    /// @param option Option to be added or updated.
+    virtual void
+    createUpdateOption4(const db::ServerSelector& server_selector,
+                        const SubnetID& subnet_id,
+                        const OptionDescriptorPtr& option);
+
+    /// @brief Creates or updates pool level option.
+    ///
+    /// @param server_selector Server selector.
+    /// @param pool_start_address Lower bound address of the pool to which
+    /// the option belongs.
+    /// @param pool_end_address Upper bound address of the pool to which the
+    /// option belongs.
+    /// @param option Option to be added or updated.
+    virtual void
+    createUpdateOption4(const db::ServerSelector& server_selector,
+                        const asiolink::IOAddress& pool_start_address,
+                        const asiolink::IOAddress& pool_end_address,
+                        const OptionDescriptorPtr& option);
+
+    /// @brief Creates or updates global parameter.
+    ///
+    /// @param server_selector Server selector.
+    /// @param value Value of the global parameter.
+    virtual void
+    createUpdateGlobalParameter4(const db::ServerSelector& server_selector,
+                                 const data::StampedValuePtr& value);
+
+    /// @brief Deletes subnet by prefix.
+    ///
+    /// @param server_selector Server selector.
+    /// @param subnet_prefix Prefix of the subnet to be deleted.
+    /// @return Number of deleted subnets.
+    virtual uint64_t
+    deleteSubnet4(const db::ServerSelector& server_selector,
+                  const std::string& subnet_prefix);
+
+    /// @brief Deletes subnet by identifier.
+    ///
+    /// @param server_selector Server selector.
+    /// @param subnet_id Identifier of the subnet to be deleted.
+    /// @return Number of deleted subnets.
+    virtual uint64_t
+    deleteSubnet4(const db::ServerSelector& server_selector, const SubnetID& subnet_id);
+
+    /// @brief Deletes all subnets.
+    ///
+    /// @param server_selector Server selector.
+    /// @return Number of deleted subnets.
+    virtual uint64_t
+    deleteAllSubnets4(const db::ServerSelector& server_selector);
+
+    /// @brief Deletes shared network by name.
+    ///
+    /// @param server_selector Server selector.
+    /// @param name Name of the shared network to be deleted.
+    /// @return Number of deleted shared networks..
+    virtual uint64_t
+    deleteSharedNetwork4(const db::ServerSelector& server_selector,
+                         const std::string& name);
+
+    /// @brief Deletes all shared networks.
+    ///
+    /// @param server_selector Server selector.
+    /// @return Number of deleted shared networks.
+    virtual uint64_t
+    deleteAllSharedNetworks4(const db::ServerSelector& server_selector);
+
+    /// @brief Deletes option definition.
+    ///
+    /// @param server_selector Server selector.
+    /// @param code Code of the option to be deleted.
+    /// @param space Option space of the option to be deleted.
+    /// @return Number of deleted option definitions.
+    virtual uint64_t
+    deleteOptionDef4(const db::ServerSelector& server_selector, const uint16_t code,
+                     const std::string& space);
+
+    /// @brief Deletes all option definitions.
+    ///
+    /// @param server_selector Server selector.
+    /// @return Number of deleted option definitions.
+    virtual uint64_t
+    deleteAllOptionDefs4(const db::ServerSelector& server_selector);
+
+    /// @brief Deletes global option.
+    ///
+    /// @param server_selector Server selector.
+    /// @param code Code of the option to be deleted.
+    /// @param space Option space of the option to be deleted.
+    /// @return Number of deleted options.
+    virtual uint64_t
+    deleteOption4(const db::ServerSelector& server_selector, const uint16_t code,
+                  const std::string& space);
+
+    /// @brief Deletes shared network level option.
+    ///
+    /// @param selector Server selector.
+    /// @param shared_network_name Name of the shared network which option
+    /// belongs to.
+    /// @param code Code of the option to be deleted.
+    /// @param space Option space of the option to be deleted.
+    virtual uint64_t
+    deleteOption4(const db::ServerSelector& selector,
+                  const std::string& shared_network_name,
+                  const uint16_t code,
+                  const std::string& space);
+
+    /// @brief Deletes subnet level option.
+    ///
+    /// @param server_selector Server selector.
+    /// @param subnet_id Identifier of the subnet to which deleted option
+    /// belongs.
+    /// @param code Code of the deleted option.
+    /// @param space Option space of the deleted option.
+    /// @return Number of deleted options.
+    virtual uint64_t
+    deleteOption4(const db::ServerSelector& server_selector, const SubnetID& subnet_id,
+                  const uint16_t code, const std::string& space);
+
+    /// @brief Deletes pool level option.
+    ///
+    /// @param server_selector Server selector.
+    /// @param pool_start_address Lower bound address of the pool to which
+    /// deleted option belongs.
+    /// @param pool_end_address Upper bound address of the pool to which the
+    /// deleted option belongs.
+    /// @param code Code of the deleted option.
+    /// @param space Option space of the deleted option.
+    /// @return Number of deleted options.
+    virtual uint64_t
+    deleteOption4(const db::ServerSelector& server_selector,
+                  const asiolink::IOAddress& pool_start_address,
+                  const asiolink::IOAddress& pool_end_address,
+                  const uint16_t code,
+                  const std::string& space);
+
+    /// @brief Deletes global parameter.
+    ///
+    /// @param server_selector Server selector.
+    /// @param name Name of the global parameter to be deleted.
+    /// @return Number of deleted global parameters.
+    virtual uint64_t
+    deleteGlobalParameter4(const db::ServerSelector& server_selector,
+                           const std::string& name);
+
+    /// @brief Deletes all global parameters.
+    ///
+    /// @param server_selector Server selector.
+    /// @return Number of deleted global parameters.
+    virtual uint64_t
+    deleteAllGlobalParameters4(const db::ServerSelector& server_selector);
+
+/// @{
+/// @brief Containers used to house the "database" entries
+    Subnet4Collection subnets_;
+    SharedNetwork4Collection shared_networks_;
+    OptionDefContainer option_defs_;
+    OptionContainer options_;
+    data::StampedValueCollection globals_;
+/// @}
+};
+
+/// @brief Shared pointer to the @c TestConfigBackendImpl.
+typedef boost::shared_ptr<TestConfigBackendDHCPv4Impl> TestConfigBackendDHCPv4ImplPtr;
+
+} // namespace test
+} // namespace dhcp
+} // namespace isc