diff options
author | Thomas Markwalder <tmark@isc.org> | 2018-09-26 16:17:04 +0200 |
---|---|---|
committer | Thomas Markwalder <tmark@isc.org> | 2018-10-05 15:05:44 +0200 |
commit | d06703a96313ca355e6495b2e40e23555eec54b7 (patch) | |
tree | 51d04ebb1f18eb0c1cb4abcea17db7d0a160869a /src | |
parent | [128-netconf-use-libprocess] Final update before merge (diff) | |
download | kea-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.am | 2 | ||||
-rw-r--r-- | src/lib/config/config_ctl_info.cc | 98 | ||||
-rw-r--r-- | src/lib/config/config_ctl_info.h | 181 | ||||
-rw-r--r-- | src/lib/config/tests/Makefile.am | 1 | ||||
-rw-r--r-- | src/lib/config/tests/config_ctl_info_unittests.cc | 143 | ||||
-rw-r--r-- | src/lib/database/database_connection.cc | 53 | ||||
-rw-r--r-- | src/lib/database/database_connection.h | 15 | ||||
-rw-r--r-- | src/lib/database/dbaccess_parser.cc | 7 | ||||
-rw-r--r-- | src/lib/database/dbaccess_parser.h | 15 | ||||
-rw-r--r-- | src/lib/database/tests/database_connection_unittest.cc | 70 | ||||
-rw-r--r-- | src/lib/database/tests/dbaccess_parser_unittest.cc | 8 | ||||
-rw-r--r-- | src/lib/dhcpsrv/cfg_db_access.cc | 60 | ||||
-rw-r--r-- | src/lib/dhcpsrv/cfg_db_access.h | 11 |
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); } |