summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorThomas Markwalder <tmark@isc.org>2018-09-26 16:17:04 +0200
committerThomas Markwalder <tmark@isc.org>2018-10-05 15:05:44 +0200
commitd06703a96313ca355e6495b2e40e23555eec54b7 (patch)
tree51d04ebb1f18eb0c1cb4abcea17db7d0a160869a /src
parent[128-netconf-use-libprocess] Final update before merge (diff)
downloadkea-d06703a96313ca355e6495b2e40e23555eec54b7.tar.xz
kea-d06703a96313ca355e6495b2e40e23555eec54b7.zip
[#32,!23] Added ControlConfigInfo to lib/config
src/lib/config/config_ctl_info.* New files, implementing ConfigDbInfo and ConfigControlInfo classes use for housing configuration backend and control information src/lib/config/Makefile.am Added config_ctl_info.h/cc Added libkea-database.la src/lib/config/tests/config_ctl_info_unitests.cc New file which unit tests new classes src/lib/database/database_connection.* DatabaseConnection::toElement(const ParameterMap& params) - new static function which turns a parameter map into Elements DatabaseConnection::toElementDbAccessString(const std::string& dbaccess) - new static function which turns an access string into Elements src/lib/database/dbaccess_parser.* Replaced StringPairMap with DatabaseConnection::ParameterMap src/lib/database/tests/database_connection_unittest.cc TEST(DatabaseConnection, toElementDbAccessStringValid) TEST(DatabaseConnection, toElementDbAccessStringInvalid) TEST(DatabaseConnection, toElementDbAccessStringEmpty) - new tests src/lib/dhcpsrv/cfg_db_access.* CfgDbAccess::toElementDbAccessString() - moved to lib/database/database_connection.cc so it can be shared
Diffstat (limited to 'src')
-rw-r--r--src/lib/config/Makefile.am2
-rw-r--r--src/lib/config/config_ctl_info.cc98
-rw-r--r--src/lib/config/config_ctl_info.h181
-rw-r--r--src/lib/config/tests/Makefile.am1
-rw-r--r--src/lib/config/tests/config_ctl_info_unittests.cc143
-rw-r--r--src/lib/database/database_connection.cc53
-rw-r--r--src/lib/database/database_connection.h15
-rw-r--r--src/lib/database/dbaccess_parser.cc7
-rw-r--r--src/lib/database/dbaccess_parser.h15
-rw-r--r--src/lib/database/tests/database_connection_unittest.cc70
-rw-r--r--src/lib/database/tests/dbaccess_parser_unittest.cc8
-rw-r--r--src/lib/dhcpsrv/cfg_db_access.cc60
-rw-r--r--src/lib/dhcpsrv/cfg_db_access.h11
13 files changed, 575 insertions, 89 deletions
diff --git a/src/lib/config/Makefile.am b/src/lib/config/Makefile.am
index 8b2102dfd2..1f2203033e 100644
--- a/src/lib/config/Makefile.am
+++ b/src/lib/config/Makefile.am
@@ -19,11 +19,13 @@ libkea_cfgclient_la_SOURCES = cmds_impl.h
libkea_cfgclient_la_SOURCES += base_command_mgr.cc base_command_mgr.h
libkea_cfgclient_la_SOURCES += client_connection.cc client_connection.h
libkea_cfgclient_la_SOURCES += command_mgr.cc command_mgr.h
+libkea_cfgclient_la_SOURCES += config_ctl_info.h config_ctl_info.cc
libkea_cfgclient_la_SOURCES += config_log.h config_log.cc
libkea_cfgclient_la_SOURCES += hooked_command_mgr.cc hooked_command_mgr.h
libkea_cfgclient_la_SOURCES += timeouts.h
libkea_cfgclient_la_LIBADD = $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
+libkea_cfgclient_la_LIBADD += $(top_builddir)/src/lib/database/libkea-database.la
libkea_cfgclient_la_LIBADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
libkea_cfgclient_la_LIBADD += $(top_builddir)/src/lib/cc/libkea-cc.la
libkea_cfgclient_la_LIBADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
diff --git a/src/lib/config/config_ctl_info.cc b/src/lib/config/config_ctl_info.cc
new file mode 100644
index 0000000000..190773182a
--- /dev/null
+++ b/src/lib/config/config_ctl_info.cc
@@ -0,0 +1,98 @@
+// 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 <config/config_ctl_info.h>
+
+using namespace isc::data;
+
+namespace isc {
+namespace config {
+
+void
+ConfigDbInfo::setAccessString(const std::string access_str) {
+ access_str_ = access_str;
+ access_params_.clear();
+ access_params_ = db::DatabaseConnection::parse(access_str_);
+}
+
+bool
+ConfigDbInfo::equals(const ConfigDbInfo& other) const {
+ return (access_params_ == other.access_params_);
+}
+
+isc::data::ElementPtr
+ConfigDbInfo::toElement() const {
+ return (isc::db::DatabaseConnection::toElementDbAccessString(access_str_));
+}
+
+bool
+ConfigDbInfo::getParameterValue(const std::string& name, std::string& value) const {
+ auto param = access_params_.find(name);
+ if (param == access_params_.end()) {
+ return(false);
+ }
+
+ value = param->second;
+ return(true);
+}
+
+void
+ConfigControlInfo::addConfigDatabase(const std::string& access_str) {
+ ConfigDbInfo new_db;
+ new_db.setAccessString(access_str);
+
+ for (auto db : db_infos_) {
+ if (new_db == db) {
+ // we have a duplicate!
+ isc_throw(BadValue, "database with access parameters: "
+ << access_str << " already exists");
+ }
+ }
+
+ db_infos_.push_back(new_db);
+}
+
+const ConfigDbInfo&
+ConfigControlInfo::findConfigDb(const std::string param_name,
+ const std::string param_value) {
+ for (ConfigDbInfoList::iterator db = db_infos_.begin();
+ db != db_infos_.end(); ++db) {
+ std::string db_value;
+ if (db->getParameterValue(param_name, db_value) &&
+ (param_value == db_value)) {
+ return (*db);
+ }
+ }
+
+ return (EMPTY_DB());
+}
+
+const ConfigDbInfo&
+ConfigControlInfo::EMPTY_DB() {
+ static ConfigDbInfo empty;
+ return (empty);
+}
+
+void
+ConfigControlInfo::clear() {
+ db_infos_.clear();
+}
+
+ElementPtr
+ConfigControlInfo::toElement() const {
+ ElementPtr result = Element::createMap();
+ ElementPtr db_list = Element::createList();
+ for (auto db_info : db_infos_) {
+ db_list->add(db_info.toElement());
+ }
+
+ result->set("config-databases", db_list);
+ return(result);
+}
+
+} // end of namespace isc::config
+} // end of namespace isc
diff --git a/src/lib/config/config_ctl_info.h b/src/lib/config/config_ctl_info.h
new file mode 100644
index 0000000000..7c940bcd49
--- /dev/null
+++ b/src/lib/config/config_ctl_info.h
@@ -0,0 +1,181 @@
+// 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/.
+
+#ifndef CONFIG_CONFIG_CTL_H
+#define CONFIG_CONFIG_CTL_H
+
+#include <cc/cfg_to_element.h>
+#include <database/database_connection.h>
+
+#include <boost/shared_ptr.hpp>
+#include <stdint.h>
+#include <vector>
+
+namespace isc {
+namespace config {
+
+/// @brief Provides configuration information used during a server's
+/// configuration process
+///
+class ConfigDbInfo : public isc::data::CfgToElement {
+public:
+ /// @brief Constructor
+ ConfigDbInfo() {};
+
+ /// @brief Set the access string
+ ///
+ /// Sest the db's access string to the given value and then parses it
+ /// into name-value pairs and storing them internally as a
+ /// DatabaseConnection::ParameterMap. It discards the existing content
+ /// of the map first. It does not validate the parameter names of values,
+ /// ensuring the validity of the string content is placed upon the caller.
+ ///
+ /// @param access_str string of name=value pairs seperated by spaces
+ void setAccessString(const std::string access_str);
+
+ /// @brief Retrieves the database access string.
+ ///
+ /// @return database access string
+ std::string getAccessString() const {
+ return (access_str_);
+ }
+
+ /// @brief Retrieve the map of parameter values.
+ ///
+ /// @return Constant reference to the database's parameter map.
+ const db::DatabaseConnection::ParameterMap& getParameters() const {
+ return (access_params_);
+ }
+
+ /// @brief Fetch the value of a given parmeter
+ ///
+ /// @param name name of the parameter value to fetch
+ /// @param[out] value string which will contain the value of the
+ /// parameter (if found).
+ ///
+ /// @return Boolean true if the parameter named is found in the map,
+ /// false otherwise.
+ bool getParameterValue(const std::string& name,
+ std::string& value) const;
+
+ /// @brief Unparse a configuration object
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
+
+ /// @brief Compares two objects for equality.
+ ///
+ /// @param other An object to be compared with this object.
+ ///
+ /// @return true if objects are equal, false otherwise.
+ bool equals(const ConfigDbInfo& other) const;
+
+ /// @brief Compares two objects for equality.
+ ///
+ /// @param other An object to be compared with this object.
+ ///
+ /// @return true if objects are equal, false otherwise.
+ bool operator==(const ConfigDbInfo& other) const {
+ return (equals(other));
+ }
+
+ /// @brief Compares two objects for inequality.
+ ///
+ /// @param other An object to be compared with this object.
+ ///
+ /// @return true if objects are not equal, false otherwise.
+ bool operator!=(const ConfigDbInfo& other) const {
+ return (!equals(other));
+ }
+
+private:
+ /// @brief Access string of parameters used to acces this database
+ std::string access_str_;
+
+ /// @brief Map of the access parameters and their values
+ db::DatabaseConnection::ParameterMap access_params_;
+};
+
+typedef std::vector<ConfigDbInfo> ConfigDbInfoList;
+
+/// @brief Embodies configuration information used during a server's
+/// configuration process
+///
+/// This is class conveys the configuration control information
+/// described by the following JSON text:
+///
+/// "ConfigCtl" :
+/// {
+/// "config-databases":
+/// [
+/// {
+/// # first config db
+/// # common database access parameters
+/// "type": <"mysql"|"postgresql"|"cql">,
+/// "name": <"db name">,
+/// "host": <"db host name">,
+/// :
+/// },
+/// {
+/// # next config db
+/// }
+/// ]
+/// }
+
+class ConfigControlInfo : public isc::data::CfgToElement {
+public:
+
+ /// @brief Constructor.
+ ConfigControlInfo() {};
+
+ /// @brief Sets host database access string.
+ ///
+ /// @param host_db_access New host database access string.
+ /// @param front Add at front if true, at back if false (default).
+ /// @throw BadValue if an entry exists that matches the parameters
+ /// in the given access string, or if the access string is invalid.
+ void addConfigDatabase(const std::string& access_str);
+
+ /// @brief Retrieves the list of databases
+ ///
+ /// @return a reference to a const list of databases
+ const ConfigDbInfoList& getConfigDatabases() const {
+ return (db_infos_);
+ }
+
+ /// @brief Retrieves the datbase with the given access parameter value
+ ///
+ /// @return A reference to the matching database or the not-found value
+ /// available via @c EMPTY_DB()
+ const ConfigDbInfo& findConfigDb(const std::string param_name,
+ const std::string param_value);
+
+ /// @brief Empties the contents of the class, including the database list
+ void clear();
+
+ /// @brief Unparse a configuration object
+ ///
+ /// @return a pointer to unparsed configuration
+ virtual isc::data::ElementPtr toElement() const;
+
+ /// @brief Fetches the not-found value returned by database list searches
+ ///
+ /// @return a reference to the empty ConfigDBInfo
+ static const ConfigDbInfo& EMPTY_DB();
+
+private:
+
+ /// @brief List of configuration databases
+ ConfigDbInfoList db_infos_;
+};
+
+/// @brief Defines a pointer to a ConfigControlInfo
+typedef boost::shared_ptr<ConfigControlInfo> ConfigControlInfoPtr;
+
+} // namespace config
+} // end namespace isc
+
+#endif // CONFIG_CONFIG_CTL_H
diff --git a/src/lib/config/tests/Makefile.am b/src/lib/config/tests/Makefile.am
index 69e2854578..77330bf0dd 100644
--- a/src/lib/config/tests/Makefile.am
+++ b/src/lib/config/tests/Makefile.am
@@ -22,6 +22,7 @@ TESTS += run_unittests
run_unittests_SOURCES = client_connection_unittests.cc
run_unittests_SOURCES += run_unittests.cc
run_unittests_SOURCES += command_mgr_unittests.cc
+run_unittests_SOURCES += config_ctl_info_unittests.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS)
diff --git a/src/lib/config/tests/config_ctl_info_unittests.cc b/src/lib/config/tests/config_ctl_info_unittests.cc
new file mode 100644
index 0000000000..f2726f6b3f
--- /dev/null
+++ b/src/lib/config/tests/config_ctl_info_unittests.cc
@@ -0,0 +1,143 @@
+// 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 <config/config_ctl_info.h>
+#include <exceptions/exceptions.h>
+
+#include <gtest/gtest.h>
+
+#include <sstream>
+#include <iostream>
+
+using namespace isc::config;
+using namespace isc::data;
+
+// Verifies initializing via an access string and unparsing into elements
+// We just test basic unparsing, as more rigorous testing is done in
+// libkea-db testing which ConfibDBInfo uses.
+TEST(ConfigDbInfo, basicOperation) {
+ ConfigDbInfo db;
+ std::string access = "type=mysql user=tom password=terrific";
+ std::string access_json = "{\n"
+ " \"type\":\"mysql\", \n"
+ " \"user\":\"tom\", \n"
+ " \"password\":\"terrific\" \n"
+ "} \n";
+
+ // Convert the above configuration into Elements for comparison.
+ ElementPtr exp_elems;
+ ASSERT_NO_THROW(exp_elems = Element::fromJSON(access_json))
+ << "test is broken";
+
+ // Initialize the db from an the access string
+ db.setAccessString(access);
+ EXPECT_EQ(access, db.getAccessString());
+
+ // Convert the db into Elements and make sure they are as expected.
+ ElementPtr db_elems;
+ ASSERT_NO_THROW(db_elems = db.toElement());
+ EXPECT_TRUE(db_elems->equals(*exp_elems));
+}
+
+// Verify that db parameter values may be retrieved.
+TEST(ConfigDbInfo, getParameterValue) {
+ ConfigDbInfo db1;
+ std::string access1 = "type=mysql name=keatest port=33 readonly=false";
+ db1.setAccessString(access1);
+
+ std::string value;
+ bool found = false;
+
+ // Should find "type"
+ ASSERT_NO_THROW(found = db1.getParameterValue("type", value));
+ EXPECT_TRUE(found);
+ EXPECT_EQ("mysql", value);
+
+ // Should find "name"
+ ASSERT_NO_THROW(found = db1.getParameterValue("name", value));
+ EXPECT_TRUE(found);
+ EXPECT_EQ("keatest", value);
+
+ // Should find "port"
+ ASSERT_NO_THROW(found = db1.getParameterValue("port", value));
+ EXPECT_TRUE(found);
+ EXPECT_EQ("33", value);
+
+ // Should find "readonly"
+ ASSERT_NO_THROW(found = db1.getParameterValue("readonly", value));
+ EXPECT_TRUE(found);
+ EXPECT_EQ("false", value);
+
+ // Should not find "bogus"
+ ASSERT_NO_THROW(found = db1.getParameterValue("bogus", value));
+ EXPECT_FALSE(found);
+}
+
+// Verify that db equality operators work correctly.
+TEST(ConfigDbInfo, equalityOperators) {
+ ConfigDbInfo db1;
+ std::string access1 = "type=mysql user=tom password=terrific";
+ ASSERT_NO_THROW(db1.setAccessString(access1));
+
+ ConfigDbInfo db2;
+ std::string access2 = "type=postgresql user=tom password=terrific";
+ ASSERT_NO_THROW(db2.setAccessString(access2));
+
+ // Verify that the two unequal dbs are in fact not equal.
+ EXPECT_FALSE(db1.equals(db2));
+ EXPECT_FALSE(db1 == db2);
+ EXPECT_TRUE(db1 != db2);
+
+ // Verify that the two equal dbs are in fact equal.
+ db2.setAccessString(access1);
+ EXPECT_TRUE(db1.equals(db2));
+ EXPECT_TRUE(db1 == db2);
+ EXPECT_FALSE(db1 != db2);
+}
+
+// Verifies the basic operations of ConfigControlInfo
+TEST(ConfigControlInfo, basicOperation) {
+
+ ConfigControlInfo ctl;
+ // We should have no dbs in the list.
+ EXPECT_EQ(0, ctl.getConfigDatabases().size());
+
+ // We should be able to add two distinct, valid dbs
+ std::string access_str1 = "type=mysql host=machine1.org";
+ ASSERT_NO_THROW(ctl.addConfigDatabase(access_str1));
+
+ std::string access_str2 = "type=postgresql host=machine2.org";
+ ASSERT_NO_THROW(ctl.addConfigDatabase(access_str2));
+
+ // We should fail on a duplicate db.
+ ASSERT_THROW(ctl.addConfigDatabase(access_str1), isc::BadValue);
+
+ // We should have two dbs in the list.
+ const ConfigDbInfoList& db_list = ctl.getConfigDatabases();
+ EXPECT_EQ(2, db_list.size());
+
+ // Verify the dbs in the list are as we expect them to be.
+ EXPECT_EQ (access_str1, db_list[0].getAccessString());
+ EXPECT_EQ (access_str2, db_list[1].getAccessString());
+
+ // Verify we can find dbs based on a property values.
+ const ConfigDbInfo& db_info = ctl.findConfigDb("type", "mysql");
+ EXPECT_FALSE(db_info == ConfigControlInfo::EMPTY_DB());
+ EXPECT_EQ (access_str1, db_info.getAccessString());
+
+ const ConfigDbInfo& db_info2 = ctl.findConfigDb("host", "machine2.org");
+ EXPECT_FALSE(db_info2 == ConfigControlInfo::EMPTY_DB());
+ EXPECT_EQ (access_str2, db_info2.getAccessString());
+
+ // Verify not finding a db reutrns EMPTY_DB().
+ const ConfigDbInfo& db_info3 = ctl.findConfigDb("type", "bogus");
+ EXPECT_TRUE(db_info3 == ConfigControlInfo::EMPTY_DB());
+
+ // Verify we can clear the list of dbs.
+ ctl.clear();
+ EXPECT_EQ(0, ctl.getConfigDatabases().size());
+}
diff --git a/src/lib/database/database_connection.cc b/src/lib/database/database_connection.cc
index 2f736e2e42..e58ebb4752 100644
--- a/src/lib/database/database_connection.cc
+++ b/src/lib/database/database_connection.cc
@@ -6,6 +6,7 @@
#include <config.h>
+#include <cc/cfg_to_element.h>
#include <database/database_connection.h>
#include <database/db_exceptions.h>
#include <database/db_log.h>
@@ -151,6 +152,58 @@ DatabaseConnection::invokeDbLostCallback() const {
return (false);
}
+isc::data::ElementPtr
+DatabaseConnection::toElement(const ParameterMap& params) {
+ isc::data::ElementPtr result = isc::data::Element::createMap();
+
+ for (auto param: params) {
+ std::string keyword = param.first;
+ std::string value = param.second;
+
+ if ((keyword == "lfc-interval") ||
+ (keyword == "connect-timeout") ||
+ (keyword == "port")) {
+ // integer parameters
+ int64_t int_value;
+ try {
+ int_value = boost::lexical_cast<int64_t>(value);
+ result->set(keyword, isc::data::Element::create(int_value));
+ } catch (...) {
+ isc_throw(ToElementError, "invalid DB access "
+ << "integer parameter: " << keyword << "=" << value);
+ }
+ } else if ((keyword == "persist") ||
+ (keyword == "readonly")) {
+ if (value == "true") {
+ result->set(keyword, isc::data::Element::create(true));
+ } else if (value == "false") {
+ result->set(keyword, isc::data::Element::create(false));
+ } else {
+ isc_throw(ToElementError, "invalid DB access "
+ << "boolean parameter: " << keyword << "=" << value);
+ }
+ } else if ((keyword == "type") ||
+ (keyword == "user") ||
+ (keyword == "password") ||
+ (keyword == "host") ||
+ (keyword == "name") ||
+ (keyword == "contact-points") ||
+ (keyword == "keyspace")) {
+ result->set(keyword, isc::data::Element::create(value));
+ } else {
+ isc_throw(ToElementError, "unknown DB access parameter: "
+ << keyword << "=" << value);
+ }
+ }
+
+ return (result);
+}
+
+isc::data::ElementPtr
+DatabaseConnection::toElementDbAccessString(const std::string& dbaccess) {
+ ParameterMap params = parse(dbaccess);
+ return (toElement(params));
+}
DatabaseConnection::DbLostCallback
DatabaseConnection::db_lost_callback = 0;
diff --git a/src/lib/database/database_connection.h b/src/lib/database/database_connection.h
index 515e20c5b5..5770a14366 100644
--- a/src/lib/database/database_connection.h
+++ b/src/lib/database/database_connection.h
@@ -7,6 +7,7 @@
#ifndef DATABASE_CONNECTION_H
#define DATABASE_CONNECTION_H
+#include <cc/data.h>
#include <boost/noncopyable.hpp>
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
@@ -96,7 +97,7 @@ public:
return (retries_left_ ? --retries_left_ : false);
}
- /// @brief Returns the maximum number for retries allowed
+ /// @brief Returns the maximum number for retries allowed
unsigned int maxRetries() {
return (max_retries_);
}
@@ -215,6 +216,18 @@ public:
/// callback.
bool invokeDbLostCallback() const;
+ /// @brief Unparse a parameter map
+ ///
+ /// @param params the parameter map to unparse
+ /// @return a pointer to configuration
+ static isc::data::ElementPtr toElement(const ParameterMap& params);
+
+ /// @brief Unparse an access string
+ ///
+ /// @param dbaccess the database access string
+ /// @return a pointer to configuration
+ static isc::data::ElementPtr toElementDbAccessString(const std::string& dbaccess);
+
/// @brief Optional call back function to invoke if a successfully
/// open connection subsequently fails
static DbLostCallback db_lost_callback;
diff --git a/src/lib/database/dbaccess_parser.cc b/src/lib/database/dbaccess_parser.cc
index 79f5bb5196..9afb625cd9 100644
--- a/src/lib/database/dbaccess_parser.cc
+++ b/src/lib/database/dbaccess_parser.cc
@@ -6,6 +6,7 @@
#include <config.h>
+#include <database/database_connection.h>
#include <database/db_exceptions.h>
#include <database/dbaccess_parser.h>
#include <dhcpsrv/parsers/dhcp_parsers.h>
@@ -45,7 +46,7 @@ DbAccessParser::parse(std::string& access_string,
// a flex/bison parser.
// 1. Take a copy of the stored keyword/value pairs.
- std::map<string, string> values_copy = values_;
+ DatabaseConnection::ParameterMap values_copy = values_;
int64_t lfc_interval = 0;
int64_t timeout = 0;
@@ -112,7 +113,7 @@ DbAccessParser::parse(std::string& access_string,
// 3. Perform validation checks on the updated set of keyword/values.
//
// a. Check if the "type" keyword exists and thrown an exception if not.
- StringPairMap::const_iterator type_ptr = values_copy.find("type");
+ auto type_ptr = values_copy.find("type");
if (type_ptr == values_copy.end()) {
isc_throw(DbConfigError,
"database access parameters must "
@@ -214,7 +215,7 @@ DbAccessParser::getDbAccessString() const {
// Construct the database access string from all keywords and values in the
// parameter map where the value is not null.
string dbaccess;
- for (StringPair keyval : values_) {
+ for (auto keyval : values_) {
if (!keyval.second.empty()) {
// Separate keyword/value pair from predecessor (if there is one).
diff --git a/src/lib/database/dbaccess_parser.h b/src/lib/database/dbaccess_parser.h
index dc8a2ab948..c2be71ef9e 100644
--- a/src/lib/database/dbaccess_parser.h
+++ b/src/lib/database/dbaccess_parser.h
@@ -24,13 +24,6 @@ namespace db {
///
class DbAccessParser: public isc::data::SimpleParser {
public:
-
- /// @brief Keyword and associated value
- typedef std::pair<std::string, std::string> StringPair;
-
- /// @brief Keyword/value collection of database access parameters
- typedef std::map<std::string, std::string> StringPairMap;
-
/// @brief Constructor
DbAccessParser();
@@ -60,8 +53,6 @@ public:
void parse(std::string& access_string,
isc::data::ConstElementPtr database_config);
-
-protected:
/// @brief Get database access parameters
///
/// Used in testing to check that the configuration information has been
@@ -70,10 +61,10 @@ protected:
/// @return Reference to the internal map of keyword/value pairs
/// representing database access information. This is valid only
/// for so long as the the parser remains in existence.
- const StringPairMap& getDbAccessParameters() const {
+ const DatabaseConnection::ParameterMap& getDbAccessParameters() const {
return (values_);
}
-
+protected:
/// @brief Construct database access string
///
@@ -84,7 +75,7 @@ protected:
private:
- std::map<std::string, std::string> values_; ///< Stored parameter values
+ DatabaseConnection::ParameterMap values_; ///< Stored parameter values
};
}; // namespace db
diff --git a/src/lib/database/tests/database_connection_unittest.cc b/src/lib/database/tests/database_connection_unittest.cc
index a56469750f..4939365e43 100644
--- a/src/lib/database/tests/database_connection_unittest.cc
+++ b/src/lib/database/tests/database_connection_unittest.cc
@@ -5,12 +5,16 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
-#include <exceptions/exceptions.h>
+#include <cc/cfg_to_element.h>
+#include <cc/data.h>
#include <database/database_connection.h>
+#include <database/dbaccess_parser.h>
+#include <exceptions/exceptions.h>
#include <gtest/gtest.h>
#include <boost/bind.hpp>
+using namespace isc::data;
using namespace isc::db;
/// @brief Test fixture for exercising DbLostCallback invocation
@@ -247,3 +251,67 @@ TEST(DatabaseConnectionTest, redactAccessStringNoPassword) {
EXPECT_EQ("kea", parameters["name"]);
EXPECT_EQ("mysql", parameters["type"]);
}
+
+// Check that the toElementDbAccessString() handles all valid parameters
+// Note that because toElementDbAccessString() utilizes
+// toElement() this tests both.
+TEST(DatabaseConnection, toElementDbAccessStringValid) {
+ const char* configs[] = {
+ "{\n"
+ "\"type\": \"memfile\", \n"
+ "\"user\": \"user_str\", \n"
+ "\"name\": \"name_str\", \n"
+ "\"host\": \"host_str\", \n"
+ "\"password\": \"password_str\", \n"
+ "\"contact-points\": \"contact_str\", \n"
+ "\"keyspace\": \"keyspace_str\", \n"
+ "\"lfc-interval\" : 100, \n"
+ "\"connect-timeout\" : 200, \n"
+ "\"port\" : 300, \n"
+ "\"persist\" : true, \n"
+ "\"readonly\" : false \n"
+ "}\n"
+ };
+
+ DbAccessParser parser;
+ std::string access_str;
+ ConstElementPtr json_elements;
+
+ ASSERT_NO_THROW(json_elements = Element::fromJSON(configs[0]));
+ ASSERT_NO_THROW(parser.parse(access_str, json_elements));
+
+ ElementPtr round_trip = DatabaseConnection::toElementDbAccessString(access_str);
+
+ ASSERT_TRUE(json_elements->equals(*round_trip));
+}
+
+// Check that toElementDbAccessString() catches invalid parameters.
+// Note that because toElementDbAccessString() utilizes
+// toElement() this tests both.
+TEST(DatabaseConnection, toElementDbAccessStringInvalid) {
+ std::vector<std::string> access_strs = {
+ "bogus-param=memfile",
+ "lfc-interval=not-an-integer",
+ "connect-timeout=not-an-integer",
+ "port=not-an-integer",
+ "persist=not-boolean",
+ "readonly=not-boolean"
+ };
+
+ for (auto access_str : access_strs) {
+ ASSERT_THROW(DatabaseConnection::toElementDbAccessString(access_str),
+ isc::ToElementError)
+ << "access string should have failed, string=["
+ << access_str << "]";
+ }
+}
+
+// Check that toElementDbAccessString() handles empty access string
+// Note that because toElementDbAccessString() utilizes
+// toElement() this tests both.
+TEST(DatabaseConnection, toElementDbAccessStringEmpty) {
+ ConstElementPtr elements;
+ ASSERT_NO_THROW(elements = DatabaseConnection::toElementDbAccessString(""));
+ ASSERT_TRUE(elements);
+ ASSERT_EQ(0, elements->size());
+}
diff --git a/src/lib/database/tests/dbaccess_parser_unittest.cc b/src/lib/database/tests/dbaccess_parser_unittest.cc
index dc735dfbe4..260032b4f9 100644
--- a/src/lib/database/tests/dbaccess_parser_unittest.cc
+++ b/src/lib/database/tests/dbaccess_parser_unittest.cc
@@ -114,7 +114,7 @@ public:
/// @param keyval Array of "const char*" strings in the order keyword,
/// value, keyword, value ... A NULL entry terminates the list.
void checkAccessString(const char* trace_string,
- const DbAccessParser::StringPairMap& parameters,
+ const DatabaseConnection::ParameterMap& parameters,
const char* keyval[]) {
SCOPED_TRACE(trace_string);
@@ -183,7 +183,7 @@ class TestDbAccessParser : public DbAccessParser {
public:
/// @brief Constructor
- TestDbAccessParser()
+ TestDbAccessParser()
: DbAccessParser()
{}
@@ -206,7 +206,7 @@ public:
///
/// @return Map of keyword/value pairs representing database access
/// information.
- const StringPairMap& getDbAccessParameters() const {
+ const DatabaseConnection::ParameterMap& getDbAccessParameters() const {
return (DbAccessParser::getDbAccessParameters());
}
@@ -664,7 +664,7 @@ TEST_F(DbAccessParserTest, multipleHost) {
string json_config2 = toJson(config2);
ConstElementPtr json_elements1 = Element::fromJSON(json_config1);
ConstElementPtr json_elements2 = Element::fromJSON(json_config2);
-
+
TestDbAccessParser parser1;
TestDbAccessParser parser2;
EXPECT_NO_THROW(parser1.parse(json_elements1));
diff --git a/src/lib/dhcpsrv/cfg_db_access.cc b/src/lib/dhcpsrv/cfg_db_access.cc
index 77bc826b12..333bd557eb 100644
--- a/src/lib/dhcpsrv/cfg_db_access.cc
+++ b/src/lib/dhcpsrv/cfg_db_access.cc
@@ -69,7 +69,7 @@ CfgDbAccess::createManagers() const {
HostMgr::checkCacheBackend(true);
}
-std::string
+std::string
CfgDbAccess::getAccessString(const std::string& access_string) const {
std::ostringstream s;
s << access_string;
@@ -84,63 +84,5 @@ CfgDbAccess::getAccessString(const std::string& access_string) const {
return (s.str());
}
-ElementPtr
-CfgDbAccess::toElementDbAccessString(const std::string& dbaccess) {
- ElementPtr result = Element::createMap();
- // Code from DatabaseConnection::parse
- if (dbaccess.empty()) {
- return (result);
- }
- std::vector<std::string> tokens;
- boost::split(tokens, dbaccess, boost::is_any_of(std::string("\t ")));
- BOOST_FOREACH(std::string token, tokens) {
- size_t pos = token.find("=");
- if (pos != std::string::npos) {
- std::string keyword = token.substr(0, pos);
- std::string value = token.substr(pos + 1);
- if ((keyword == "lfc-interval") ||
- (keyword == "connect-timeout") ||
- (keyword == "port")) {
- // integer parameters
- int64_t int_value;
- try {
- int_value = boost::lexical_cast<int64_t>(value);
- result->set(keyword, Element::create(int_value));
- } catch (...) {
- isc_throw(ToElementError, "invalid DB access "
- << "integer parameter: "
- << keyword << "=" << value);
- }
- } else if ((keyword == "persist") ||
- (keyword == "readonly")) {
- if (value == "true") {
- result->set(keyword, Element::create(true));
- } else if (value == "false") {
- result->set(keyword, Element::create(false));
- } else {
- isc_throw(ToElementError, "invalid DB access "
- << "boolean parameter: "
- << keyword << "=" << value);
- }
- } else if ((keyword == "type") ||
- (keyword == "user") ||
- (keyword == "password") ||
- (keyword == "host") ||
- (keyword == "name") ||
- (keyword == "contact-points") ||
- (keyword == "keyspace")) {
- result->set(keyword, Element::create(value));
- } else {
- isc_throw(ToElementError, "unknown DB access parameter: "
- << keyword << "=" << value);
- }
- } else {
- isc_throw(ToElementError, "Cannot unparse " << token
- << ", expected format is name=value");
- }
- }
- return (result);
-}
-
} // end of isc::dhcp namespace
} // end of isc namespace
diff --git a/src/lib/dhcpsrv/cfg_db_access.h b/src/lib/dhcpsrv/cfg_db_access.h
index db4ae335b8..b4ac00c245 100644
--- a/src/lib/dhcpsrv/cfg_db_access.h
+++ b/src/lib/dhcpsrv/cfg_db_access.h
@@ -78,13 +78,6 @@ public:
/// according to the configuration specified.
void createManagers() const;
- /// @brief Unparse an access string
- ///
- /// @param dbaccess the database access string
- /// @return a pointer to configuration
- static
- isc::data::ElementPtr toElementDbAccessString(const std::string& dbaccess);
-
protected:
/// @brief Returns lease or host database access string.
@@ -121,7 +114,7 @@ struct CfgLeaseDbAccess : public CfgDbAccess, public isc::data::CfgToElement {
///
/// @result a pointer to a configuration
virtual isc::data::ElementPtr toElement() const {
- return (CfgDbAccess::toElementDbAccessString(lease_db_access_));
+ return (db::DatabaseConnection::toElementDbAccessString(lease_db_access_));
}
};
@@ -138,7 +131,7 @@ struct CfgHostDbAccess : public CfgDbAccess, public isc::data::CfgToElement {
isc::data::ElementPtr result = isc::data::Element::createList();
for (const std::string& dbaccess : host_db_access_) {
isc::data::ElementPtr entry =
- CfgDbAccess::toElementDbAccessString(dbaccess);
+ db::DatabaseConnection::toElementDbAccessString(dbaccess);
if (entry->size() > 0) {
result->add(entry);
}