Browse Source

[3569] Implemented configuration for host data source.

Tomek Mrugalski 9 years ago
parent
commit
a3a40b9c2b

+ 5 - 1
src/bin/dhcp4/json_config_parser.cc

@@ -438,7 +438,11 @@ DhcpConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id,
         parser  = new StringParser(config_id,
                                     globalContext()->string_values_);
     } else if (config_id.compare("lease-database") == 0) {
-        parser = new DbAccessParser(config_id, *globalContext());
+        parser = new DbAccessParser(config_id, DbAccessParser::LEASE_DB,
+                                    *globalContext());
+    } else if (config_id.compare("hosts-database") == 0) {
+        parser = new DbAccessParser(config_id, DbAccessParser::HOSTS_DB,
+                                    *globalContext());
     } else if (config_id.compare("hooks-libraries") == 0) {
         parser = new HooksLibrariesParser(config_id);
     } else if (config_id.compare("echo-client-id") == 0) {

+ 5 - 1
src/bin/dhcp6/json_config_parser.cc

@@ -689,7 +689,11 @@ DhcpConfigParser* createGlobal6DhcpConfigParser(const std::string& config_id,
         parser  = new StringParser(config_id,
                                    globalContext()->string_values_);
     } else if (config_id.compare("lease-database") == 0) {
-        parser = new DbAccessParser(config_id, *globalContext());
+        parser = new DbAccessParser(config_id, DbAccessParser::LEASE_DB,
+                                    *globalContext());
+    } else if (config_id.compare("hosts-database") == 0) {
+        parser = new DbAccessParser(config_id, DbAccessParser::HOSTS_DB,
+                                    *globalContext());
     } else if (config_id.compare("hooks-libraries") == 0) {
         parser = new HooksLibrariesParser(config_id);
     } else if (config_id.compare("dhcp-ddns") == 0) {

+ 4 - 0
src/lib/dhcpsrv/base_host_data_source.h

@@ -20,6 +20,7 @@
 #include <dhcp/hwaddr.h>
 #include <dhcpsrv/host.h>
 #include <exceptions/exceptions.h>
+#include <boost/shared_ptr.hpp>
 
 namespace isc {
 namespace dhcp {
@@ -214,6 +215,9 @@ public:
     virtual void rollback() {};
 };
 
+/// @brief HostDataSource pointer
+typedef boost::shared_ptr<BaseHostDataSource> HostDataSourcePtr;
+
 }
 }
 

+ 9 - 1
src/lib/dhcpsrv/host_mgr.h

@@ -207,6 +207,14 @@ public:
         return (std::string("host_mgr"));
     }
 
+    /// @brief Returns pointer to the host data source
+    ///
+    /// May return NULL
+    /// @return pointer to the host data source (or NULL)
+    HostDataSourcePtr getHostDataSource() const {
+        return (alternate_source);
+    }
+
 private:
 
     /// @brief Private default constructor.
@@ -215,7 +223,7 @@ private:
     /// @brief Pointer to an alternate host data source.
     ///
     /// If this pointer is NULL, the source is not in use.
-    static boost::shared_ptr<BaseHostDataSource> alternate_source;
+    HostDataSourcePtr alternate_source;
 
     /// @brief Returns a pointer to the currently used instance of the
     /// @c HostMgr.

+ 26 - 6
src/lib/dhcpsrv/parsers/dbaccess_parser.cc

@@ -17,6 +17,7 @@
 #include <dhcp/option.h>
 #include <dhcpsrv/dhcpsrv_log.h>
 #include <dhcpsrv/lease_mgr_factory.h>
+#include <dhcpsrv/host_mgr.h>
 #include <dhcpsrv/parsers/dbaccess_parser.h>
 
 #include <boost/foreach.hpp>
@@ -34,8 +35,9 @@ namespace dhcp {
 
 
 // Factory function to build the parser
-DbAccessParser::DbAccessParser(const std::string&, const ParserContext& ctx)
-    : values_(), ctx_(ctx)
+DbAccessParser::DbAccessParser(const std::string&, DBType db_type,
+                               const ParserContext& ctx)
+    : values_(), type_(db_type), ctx_(ctx)
 {
 }
 
@@ -139,11 +141,29 @@ DbAccessParser::getDbAccessString() const {
 // Commit the changes - reopen the database with the new parameters
 void
 DbAccessParser::commit() {
-    // Close current lease manager database.
-    LeaseMgrFactory::destroy();
 
-    // ... and open the new database using the access string.
-    LeaseMgrFactory::create(getDbAccessString());
+    switch (type_) {
+    case LEASE_DB:
+    {
+        // Close current lease manager database.
+        LeaseMgrFactory::destroy();
+
+        // ... and open the new database using the access string.
+        LeaseMgrFactory::create(getDbAccessString());
+        break;
+    }
+    case HOSTS_DB:
+    {
+        // Let's instantiate HostMgr with new parameters. Note that HostMgr's
+        // constructor will call HostDataSourceFactory::create() with appropriate
+        // parameters.
+        HostMgr::create(getDbAccessString());
+        break;
+    }
+    default:
+        isc_throw(BadValue, "Incorrect type specified in DbAccessParser: "
+                  << type_);
+    };
 }
 
 };  // namespace dhcp

+ 20 - 2
src/lib/dhcpsrv/parsers/dbaccess_parser.h

@@ -45,6 +45,13 @@ public:
 /// depend on the database chosen.
 class DbAccessParser: public DhcpConfigParser {
 public:
+
+    /// @brief Specifies the database type
+    typedef enum {
+        LEASE_DB = 1,
+        HOSTS_DB = 2
+    } DBType;
+
     /// @brief Keyword and associated value
     typedef std::pair<std::string, std::string> StringPair;
 
@@ -55,8 +62,10 @@ public:
     ///
     /// @param param_name Name of the parameter under which the database
     ///        access details are held.
+    /// @param db_type Specifies database type (lease or hosts)
     /// @param ctx Parser context.
-    DbAccessParser(const std::string& param_name, const ParserContext& ctx);
+    DbAccessParser(const std::string& param_name, DBType db_type,
+                   const ParserContext& ctx);
 
     /// The destructor.
     virtual ~DbAccessParser()
@@ -103,7 +112,14 @@ public:
     ///         destroying the parser after use.
     static DhcpConfigParser* factory(const std::string& param_name,
                                      const ParserContext& ctx) {
-        return (new DbAccessParser(param_name, ctx));
+        if (param_name == "lease-database") {
+            return (new DbAccessParser(param_name, DbAccessParser::LEASE_DB, ctx));
+        } else if (param_name == "hosts-database") {
+            return (new DbAccessParser(param_name, DbAccessParser::HOSTS_DB, ctx));
+        } else {
+            isc_throw(BadValue, "Unexpected parameter name (" << param_name
+                      << ") passed to DbAccessParser::factory");
+        }
     }
 
 protected:
@@ -130,6 +146,8 @@ private:
 
     std::map<std::string, std::string> values_; ///< Stored parameter values
 
+    DBType type_; ///< Database type (leases or hosts)
+
     ParserContext ctx_; ///< Parser context
 };
 

+ 74 - 18
src/lib/dhcpsrv/tests/dbaccess_parser_unittest.cc

@@ -17,6 +17,7 @@
 #include <cc/command_interpreter.h>
 #include <dhcpsrv/lease_mgr_factory.h>
 #include <dhcpsrv/parsers/dbaccess_parser.h>
+#include <dhcpsrv/host_mgr.h>
 #include <log/logger_support.h>
 
 #include <gtest/gtest.h>
@@ -201,8 +202,9 @@ public:
     /// @brief Constructor
     ///
     /// @brief Keyword/value collection of ddatabase access parameters
-    TestDbAccessParser(const std::string& param_name, const ParserContext& ctx)
-        : DbAccessParser(param_name, ctx)
+    TestDbAccessParser(const std::string& param_name, DbAccessParser::DBType type,
+                       const ParserContext& ctx)
+        : DbAccessParser(param_name, type, ctx)
     {}
 
     /// @brief Destructor
@@ -243,7 +245,8 @@ TEST_F(DbAccessParserTest, validTypeMemfile) {
     ConstElementPtr json_elements = Element::fromJSON(json_config);
     EXPECT_TRUE(json_elements);
 
-    TestDbAccessParser parser("lease-database", ParserContext(Option::V4));
+    TestDbAccessParser parser("lease-database", DbAccessParser::LEASE_DB,
+                              ParserContext(Option::V4));
     EXPECT_NO_THROW(parser.build(json_elements));
     checkAccessString("Valid memfile", parser.getDbAccessParameters(), config);
 }
@@ -259,7 +262,8 @@ TEST_F(DbAccessParserTest, emptyKeyword) {
     ConstElementPtr json_elements = Element::fromJSON(json_config);
     EXPECT_TRUE(json_elements);
 
-    TestDbAccessParser parser("lease-database", ParserContext(Option::V4));
+    TestDbAccessParser parser("lease-database", DbAccessParser::LEASE_DB,
+                              ParserContext(Option::V4));
     EXPECT_NO_THROW(parser.build(json_elements));
     checkAccessString("Valid memfile", parser.getDbAccessParameters(), config);
 }
@@ -276,7 +280,8 @@ TEST_F(DbAccessParserTest, persistV4Memfile) {
     ConstElementPtr json_elements = Element::fromJSON(json_config);
     EXPECT_TRUE(json_elements);
 
-    TestDbAccessParser parser("lease-database", ParserContext(Option::V4));
+    TestDbAccessParser parser("lease-database", DbAccessParser::LEASE_DB,
+                              ParserContext(Option::V4));
     EXPECT_NO_THROW(parser.build(json_elements));
 
     checkAccessString("Valid memfile", parser.getDbAccessParameters(),
@@ -295,7 +300,8 @@ TEST_F(DbAccessParserTest, persistV6Memfile) {
     ConstElementPtr json_elements = Element::fromJSON(json_config);
     EXPECT_TRUE(json_elements);
 
-    TestDbAccessParser parser("lease-database", ParserContext(Option::V6));
+    TestDbAccessParser parser("lease-database", DbAccessParser::LEASE_DB,
+                              ParserContext(Option::V6));
     EXPECT_NO_THROW(parser.build(json_elements));
 
     checkAccessString("Valid memfile", parser.getDbAccessParameters(),
@@ -314,7 +320,8 @@ TEST_F(DbAccessParserTest, validLFCInterval) {
     ConstElementPtr json_elements = Element::fromJSON(json_config);
     EXPECT_TRUE(json_elements);
 
-    TestDbAccessParser parser("lease-database", ParserContext(Option::V6));
+    TestDbAccessParser parser("lease-database", DbAccessParser::LEASE_DB,
+                              ParserContext(Option::V6));
     ASSERT_NO_THROW(parser.build(json_elements));
     checkAccessString("Valid LFC Interval", parser.getDbAccessParameters(),
                       config, Option::V6);
@@ -332,7 +339,8 @@ TEST_F(DbAccessParserTest, negativeLFCInterval) {
     ConstElementPtr json_elements = Element::fromJSON(json_config);
     EXPECT_TRUE(json_elements);
 
-    TestDbAccessParser parser("lease-database", ParserContext(Option::V6));
+    TestDbAccessParser parser("lease-database", DbAccessParser::LEASE_DB,
+                              ParserContext(Option::V6));
     EXPECT_THROW(parser.build(json_elements), BadValue);
 }
 
@@ -348,7 +356,8 @@ TEST_F(DbAccessParserTest, largeLFCInterval) {
     ConstElementPtr json_elements = Element::fromJSON(json_config);
     EXPECT_TRUE(json_elements);
 
-    TestDbAccessParser parser("lease-database", ParserContext(Option::V6));
+    TestDbAccessParser parser("lease-database", DbAccessParser::LEASE_DB,
+                              ParserContext(Option::V6));
     EXPECT_THROW(parser.build(json_elements), BadValue);
 }
 
@@ -365,7 +374,8 @@ TEST_F(DbAccessParserTest, validTypeMysql) {
     ConstElementPtr json_elements = Element::fromJSON(json_config);
     EXPECT_TRUE(json_elements);
 
-    TestDbAccessParser parser("lease-database", ParserContext(Option::V4));
+    TestDbAccessParser parser("lease-database", DbAccessParser::LEASE_DB,
+                              ParserContext(Option::V4));
     EXPECT_NO_THROW(parser.build(json_elements));
     checkAccessString("Valid mysql", parser.getDbAccessParameters(), config);
 }
@@ -382,7 +392,8 @@ TEST_F(DbAccessParserTest, missingTypeKeyword) {
     ConstElementPtr json_elements = Element::fromJSON(json_config);
     EXPECT_TRUE(json_elements);
 
-    TestDbAccessParser parser("lease-database", ParserContext(Option::V4));
+    TestDbAccessParser parser("lease-database", DbAccessParser::LEASE_DB,
+                              ParserContext(Option::V4));
     EXPECT_THROW(parser.build(json_elements), TypeKeywordMissing);
 }
 
@@ -442,7 +453,8 @@ TEST_F(DbAccessParserTest, incrementalChanges) {
                              "name",     "keatest",
                              NULL};
 
-    TestDbAccessParser parser("lease-database", ParserContext(Option::V4));
+    TestDbAccessParser parser("lease-database", DbAccessParser::LEASE_DB,
+                              ParserContext(Option::V4));
 
     // First configuration string should cause a representation of that string
     // to be held.
@@ -506,7 +518,8 @@ TEST_F(DbAccessParserTest, getDbAccessString) {
     ConstElementPtr json_elements = Element::fromJSON(json_config);
     EXPECT_TRUE(json_elements);
 
-    TestDbAccessParser parser("lease-database", ParserContext(Option::V4));
+    TestDbAccessParser parser("lease-database", DbAccessParser::LEASE_DB,
+                              ParserContext(Option::V4));
     EXPECT_NO_THROW(parser.build(json_elements));
 
     // Get the database access string
@@ -518,10 +531,10 @@ TEST_F(DbAccessParserTest, getDbAccessString) {
     EXPECT_EQ(dbaccess, "name=keatest type=mysql universe=4");
 }
 
-// Check that the "commit" function actually opens the database.  We will
-// only do this for the "memfile" database, as that does not assume that the
-// test has been built with MySQL support.
-TEST_F(DbAccessParserTest, commit) {
+// Check that the "commit" function actually opens the database, when type
+// is set to LEASE_DB.  We will only do this for the "memfile" database, as
+// that does not assume that the test has been built with MySQL support.
+TEST_F(DbAccessParserTest, commitLeaseDb) {
 
     // Verify that no lease database is open
     EXPECT_THROW({
@@ -536,7 +549,8 @@ TEST_F(DbAccessParserTest, commit) {
     ConstElementPtr json_elements = Element::fromJSON(json_config);
     EXPECT_TRUE(json_elements);
 
-    TestDbAccessParser parser("lease-database", ParserContext(Option::V4));
+    TestDbAccessParser parser("lease-database", DbAccessParser::LEASE_DB,
+                              ParserContext(Option::V4));
     EXPECT_NO_THROW(parser.build(json_elements));
 
     // Ensure that the access string is as expected.
@@ -552,4 +566,46 @@ TEST_F(DbAccessParserTest, commit) {
     EXPECT_EQ(std::string("memfile"), dbtype);
 }
 
+// Check that the "commit" function actually opens the database, when type
+// is set to HOSTS_DB.
+TEST_F(DbAccessParserTest, commitHostsDb) {
+
+    // Verify that no lease database is open
+    EXPECT_THROW({
+            LeaseMgr& manager = LeaseMgrFactory::instance();
+            manager.getType();  // Never executed but satisfies compiler
+            }, isc::dhcp::NoLeaseManager);
+
+    // Set up the parser to open the memfile database.
+    const char* config[] = {"type", "memfile", "persist", "false", NULL};
+    string json_config = toJson(config);
+
+    ConstElementPtr json_elements = Element::fromJSON(json_config);
+    EXPECT_TRUE(json_elements);
+
+    TestDbAccessParser parser("hosts-database", DbAccessParser::HOSTS_DB,
+                              ParserContext(Option::V4));
+    EXPECT_NO_THROW(parser.build(json_elements));
+
+    // Ensure that the access string is as expected.
+    EXPECT_EQ("persist=false type=memfile universe=4",
+              parser.getDbAccessString());
+
+    // Destroy lease mgr (if there's any)
+    LeaseMgrFactory::destroy();
+
+    // Committal of the parser changes should not create LeaseMgr.
+    // It should create HostDataSource instead.
+    EXPECT_NO_THROW(parser.commit());
+
+    // Check that LeaseMgr was NOT created (it shouldn't, this is for HOSTS_DB.
+    EXPECT_THROW(LeaseMgrFactory::instance(), NoLeaseManager);
+
+    HostDataSourcePtr hds = HostMgr::instance().getHostDataSource();
+
+    /// @todo: Uncomment this once 3682 is merged. The whole unit-test
+    /// should create MySQL database and be ifdefed appropriately.
+    // ASSERT_TRUE(hds);
+}
+
 };  // Anonymous namespace