// reservations list, within the subnet (configuration file). If there are
// no reservations there, the server will try to retrieve reservations
// from this database.
- "hosts-database": {
- "type": "postgresql",
- "name": "kea",
- "user": "kea",
- "password": "kea",
- "host": "localhost"
- },
+// The database specification can go into one hosts-database entry for
+// backward compatibility or be listed in hosts-databases list.
+ "hosts-databases": [
+ {
+ "type": "postgresql",
+ "name": "kea",
+ "user": "kea",
+ "password": "kea",
+ "host": "localhost"
+ }
+ ],
// Define a subnet with a single pool of dynamic addresses. Addresses from
// this pool will be assigned to clients which don't have reservations in the
// reservations list, within the subnet (configuration file). If there are
// no reservations there, the server will try to retrieve reservations
// from this database.
- "hosts-database": {
- "type": "postgresql",
- "name": "kea",
- "user": "kea",
- "password": "kea",
- "host": "localhost"
- },
+// The database specification can go into one hosts-database entry for
+// backward compatibility or be listed in hosts-databases list.
+ "hosts-databases": [
+ {
+ "type": "postgresql",
+ "name": "kea",
+ "user": "kea",
+ "password": "kea",
+ "host": "localhost"
+ }
+ ],
// Define a subnet with a pool of dynamic addresses and a pool of dynamic
// prefixes. Addresses and prefixes from those pools will be assigned to
from the configuration file are checked first and external storage is checked
later, if necessary.</para>
-<section xml:id="hosts-database-configuration4">
+ <para>Version 1.4 extends the host storage to multiple storages. Operations
+ are performed on host storages in the configuration order with a special
+ case for addition: read-only storages must be configured after a
+ required read-write storage, or host reservation addition will
+ always fail.</para>
+
+<section xml:id="hosts-databases-configuration4">
<title>DHCPv4 Hosts Database Configuration</title>
<para>Hosts database configuration is controlled through the Dhcp4/hosts-database
</screen>
If there is no password to the account, set the password to the empty string
"". (This is also the default.)</para>
+
+ <para>The multiple storage extension uses a similar syntax: a configuration
+ is placed into a "hosts-databases" list instead of into a "hosts-database"
+ entry as in:
+<screen>
+"Dhcp4": { "hosts-databases": [ { <userinput>"type": "mysql"</userinput>, ... }, ... ], ... }
+</screen>
+
+ </para>
+
</section>
<section xml:id="read-only-database-configuration4">
from the configuration file are checked first and external storage is checked
later, if necessary.</para>
-<section xml:id="hosts-database-configuration6">
+ <para>Version 1.4 extends the host storage to multiple storages. Operations
+ are performed on host storages in the configuration order with a special
+ case for addition: read-only storages must be configured after a
+ required read-write storage, or host reservation addition will
+ always fail.</para>
+
+<section xml:id="hosts-databases-configuration6">
<title>DHCPv6 Hosts Database Configuration</title>
<para>Hosts database configuration is controlled through the Dhcp6/hosts-database
</screen>
If there is no password to the account, set the password to the empty string
"". (This is also the default.)</para>
+
+ <para>The multiple storage extension uses a similar syntax: a configuration
+ is placed into a "hosts-databases" list instead of into a "hosts-database"
+ entry as in:
+<screen>
+"Dhcp6": { "hosts-databases": [ { <userinput>"type": "mysql"</userinput>, ... }, ... ], ... }
+</screen>
+
+ </para>
+
</section>
<section xml:id="read-only-database-configuration6">
criteria). To use commands that change the reservation information
(currently these are reservation-add and reservation-del, but this
rule applies to other commands that may be implemented in the future),
- hosts database must be specified (see hosts-database description in
- <xref linkend="hosts-database-configuration4"/> and <xref linkend="hosts-database-configuration6"/>) and it must not operate in
- read-only mode. If the hosts-database is not specified or is running
+ hosts database must be specified (see hosts-databases description in
+ <xref linkend="hosts-databases-configuration4"/> and <xref linkend="hosts-databases-configuration6"/>) and it must not operate in
+ read-only mode. If the hosts-databases are not specified or are running
in read-only mode, the host_cmds library will load, but any attempts
to use reservation-add or reservation-del will fail.
</para>
<para>
As <command>reservation-add</command> is expected to store the host,
- hosts-database parameter must be specified in your configuration and
- the database must not run in read-only mode. In the future versions
+ hosts-databases parameter must be specified in your configuration and
+ databases must not run in read-only mode. In the future versions
it will be possible to modify the reservations read from a
configuration file. Please contact ISC if you are interested in this
functionality.
// Please move at the end when migration will be finished.
if (config_pair.first == "lease-database") {
- DbAccessParser parser(DbAccessParser::LEASE_DB);
+ DbAccessParser parser(CfgDbAccess::LEASE_DB);
CfgDbAccessPtr cfg_db_access = srv_cfg->getCfgDbAccess();
parser.parse(cfg_db_access, config_pair.second);
continue;
}
if (config_pair.first == "hosts-database") {
- DbAccessParser parser(DbAccessParser::HOSTS_DB);
+ DbAccessParser parser(CfgDbAccess::HOSTS_DB);
CfgDbAccessPtr cfg_db_access = srv_cfg->getCfgDbAccess();
parser.parse(cfg_db_access, config_pair.second);
continue;
}
- // For now only support empty or singleton, ignoring extra entries.
if (config_pair.first == "hosts-databases") {
- if (config_pair.second->size() == 0) {
- continue;
- }
- DbAccessParser parser(DbAccessParser::HOSTS_DB);
CfgDbAccessPtr cfg_db_access = srv_cfg->getCfgDbAccess();
- parser.parse(cfg_db_access, config_pair.second->get(0));
+ for (size_t i = 0; i < config_pair.second->size(); ++i) {
+ DbAccessParser parser(CfgDbAccess::HOSTS_DB + i);
+ parser.parse(cfg_db_access, config_pair.second->get(i));
+ }
continue;
}
-// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-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
" } ]"
"}",
+ // Configuration 4: two host databases
+ "{"
+ " \"interfaces-config\": {"
+ " \"interfaces\": [\"*\" ]"
+ " },"
+ " \"valid-lifetime\": 4000,"
+ " \"rebind-timer\": 2000,"
+ " \"renew-timer\": 1000,"
+ " \"hosts-databases\": [ {"
+ " \"type\": \"mysql\","
+ " \"name\": \"keatest1\","
+ " \"user\": \"keatest\","
+ " \"password\": \"keatest\""
+ " },{"
+ " \"type\": \"mysql\","
+ " \"name\": \"keatest2\","
+ " \"user\": \"keatest\","
+ " \"password\": \"keatest\""
+ " }"
+ " ]"
+ "}",
+
// Last Configuration for comments
"{"
" \"comment\": \"A DHCPv4 server\","
EXPECT_TRUE(classes.empty());
}
+// This test checks multiple host data sources.
+TEST_F(Dhcp4ParserTest, hostsDatabases) {
+
+ string config = PARSER_CONFIGS[4];
+ extractConfig(config);
+ configure(config, CONTROL_RESULT_SUCCESS, "");
+
+ // Check database config
+ ConstCfgDbAccessPtr cfgdb =
+ CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
+ ASSERT_TRUE(cfgdb);
+ const std::vector<std::string>& hal = cfgdb->getHostDbAccessStringList();
+ ASSERT_EQ(2, hal.size());
+ // Keywords are in alphabetical order
+ EXPECT_EQ("name=keatest1 password=keatest type=mysql user=keatest", hal[0]);
+ EXPECT_EQ("name=keatest2 password=keatest type=mysql user=keatest", hal[1]);
+}
+
// This test checks comments. Please keep it last.
TEST_F(Dhcp4ParserTest, comments) {
- string config = PARSER_CONFIGS[4];
+ string config = PARSER_CONFIGS[5];
extractConfig(config);
configure(config, CONTROL_RESULT_SUCCESS, "");
-// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+// 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
" }\n",
// CONFIGURATION 60
"{\n"
+" \"hosts-databases\": [\n"
+" {\n"
+" \"name\": \"keatest1\",\n"
+" \"password\": \"keatest\",\n"
+" \"type\": \"mysql\",\n"
+" \"user\": \"keatest\"\n"
+" },\n"
+" {\n"
+" \"name\": \"keatest2\",\n"
+" \"password\": \"keatest\",\n"
+" \"type\": \"mysql\",\n"
+" \"user\": \"keatest\"\n"
+" }\n"
+" ],\n"
+" \"interfaces-config\": {\n"
+" \"interfaces\": [ \"*\" ],\n"
+" \"re-detect\": false\n"
+" },\n"
+" \"rebind-timer\": 2000,\n"
+" \"renew-timer\": 1000,\n"
+" \"valid-lifetime\": 4000\n"
+" }\n",
+ // CONFIGURATION 61
+"{\n"
" \"comment\": \"A DHCPv4 server\",\n"
" \"client-classes\": [\n"
" {\n"
" }\n",
// CONFIGURATION 60
"{\n"
+" \"decline-probation-period\": 86400,\n"
+" \"dhcp-ddns\": {\n"
+" \"always-include-fqdn\": false,\n"
+" \"enable-updates\": false,\n"
+" \"generated-prefix\": \"myhost\",\n"
+" \"max-queue-size\": 1024,\n"
+" \"ncr-format\": \"JSON\",\n"
+" \"ncr-protocol\": \"UDP\",\n"
+" \"override-client-update\": false,\n"
+" \"override-no-update\": false,\n"
+" \"qualifying-suffix\": \"\",\n"
+" \"replace-client-name\": \"never\",\n"
+" \"sender-ip\": \"0.0.0.0\",\n"
+" \"sender-port\": 0,\n"
+" \"server-ip\": \"127.0.0.1\",\n"
+" \"server-port\": 53001\n"
+" },\n"
+" \"dhcp4o6-port\": 0,\n"
+" \"echo-client-id\": true,\n"
+" \"expired-leases-processing\": {\n"
+" \"flush-reclaimed-timer-wait-time\": 25,\n"
+" \"hold-reclaimed-time\": 3600,\n"
+" \"max-reclaim-leases\": 100,\n"
+" \"max-reclaim-time\": 250,\n"
+" \"reclaim-timer-wait-time\": 10,\n"
+" \"unwarned-reclaim-cycles\": 5\n"
+" },\n"
+" \"hooks-libraries\": [ ],\n"
+" \"host-reservation-identifiers\": [ \"hw-address\", \"duid\", \"circuit-id\", \"client-id\" ],\n"
+" \"hosts-databases\": [\n"
+" {\n"
+" \"name\": \"keatest1\",\n"
+" \"password\": \"keatest\",\n"
+" \"type\": \"mysql\",\n"
+" \"user\": \"keatest\"\n"
+" },\n"
+" {\n"
+" \"name\": \"keatest2\",\n"
+" \"password\": \"keatest\",\n"
+" \"type\": \"mysql\",\n"
+" \"user\": \"keatest\"\n"
+" }\n"
+" ],\n"
+" \"interfaces-config\": {\n"
+" \"interfaces\": [ \"*\" ],\n"
+" \"re-detect\": false\n"
+" },\n"
+" \"lease-database\": {\n"
+" \"type\": \"memfile\"\n"
+" },\n"
+" \"option-data\": [ ],\n"
+" \"option-def\": [ ],\n"
+" \"shared-networks\": [ ],\n"
+" \"subnet4\": [ ]\n"
+" }\n",
+ // CONFIGURATION 61
+"{\n"
" \"comment\": \"A DHCPv4 server\",\n"
" \"client-classes\": [\n"
" {\n"
-// Copyright (C) 2017 Internet Systems Consortium, Inc. ("ISC")
+// 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
}
}
-};
+} // namespace
namespace isc {
namespace dhcp {
++extract_count;
}
-};
-};
-};
+} // namespace test
+} // namespace dhcp
+} // namespace isc
namespace {
// Please move at the end when migration will be finished.
if (config_pair.first == "lease-database") {
- DbAccessParser parser(DbAccessParser::LEASE_DB);
+ DbAccessParser parser(CfgDbAccess::LEASE_DB);
CfgDbAccessPtr cfg_db_access = srv_config->getCfgDbAccess();
parser.parse(cfg_db_access, config_pair.second);
continue;
}
if (config_pair.first == "hosts-database") {
- DbAccessParser parser(DbAccessParser::HOSTS_DB);
+ DbAccessParser parser(CfgDbAccess::HOSTS_DB);
CfgDbAccessPtr cfg_db_access = srv_config->getCfgDbAccess();
parser.parse(cfg_db_access, config_pair.second);
continue;
// For now only support empty or singleton, ignoring extra entries.
if (config_pair.first == "hosts-databases") {
- if (config_pair.second->size() == 0) {
- continue;
- }
- DbAccessParser parser(DbAccessParser::HOSTS_DB);
CfgDbAccessPtr cfg_db_access = srv_config->getCfgDbAccess();
- parser.parse(cfg_db_access, config_pair.second->get(0));
+ for (size_t i = 0; i < config_pair.second->size(); ++i) {
+ DbAccessParser parser(CfgDbAccess::HOSTS_DB + i);
+ parser.parse(cfg_db_access, config_pair.second->get(i));
+ }
continue;
}
" } ]"
"}",
+ // Configuration 7: two host databases
+ "{"
+ " \"interfaces-config\": {"
+ " \"interfaces\": [\"*\" ]"
+ " },"
+ " \"valid-lifetime\": 4000,"
+ " \"preferred-lifetime\": 3000,"
+ " \"rebind-timer\": 2000,"
+ " \"renew-timer\": 1000,"
+ " \"hosts-databases\": [ {"
+ " \"type\": \"mysql\","
+ " \"name\": \"keatest1\","
+ " \"user\": \"keatest\","
+ " \"password\": \"keatest\""
+ " },{"
+ " \"type\": \"mysql\","
+ " \"name\": \"keatest2\","
+ " \"user\": \"keatest\","
+ " \"password\": \"keatest\""
+ " }"
+ " ]"
+ "}",
+
// Last configuration for comments
"{"
" \"comment\": \"A DHCPv6 server\","
"shared-network or the shared-network itself used rapid-commit true");
}
+// This test checks multiple host data sources.
+TEST_F(Dhcp6ParserTest, hostsDatabases) {
+
+ string config = PARSER_CONFIGS[7];
+ extractConfig(config);
+ configure(config, CONTROL_RESULT_SUCCESS, "");
+
+ // Check database config
+ ConstCfgDbAccessPtr cfgdb =
+ CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
+ ASSERT_TRUE(cfgdb);
+ const std::vector<std::string>& hal = cfgdb->getHostDbAccessStringList();
+ ASSERT_EQ(2, hal.size());
+ // Keywords are in alphabetical order
+ EXPECT_EQ("name=keatest1 password=keatest type=mysql user=keatest", hal[0]);
+ EXPECT_EQ("name=keatest2 password=keatest type=mysql user=keatest", hal[1]);
+}
+
// This test checks comments. Please keep it last.
TEST_F(Dhcp6ParserTest, comments) {
- string config = PARSER_CONFIGS[7];
+ string config = PARSER_CONFIGS[8];
extractConfig(config);
configure(config, CONTROL_RESULT_SUCCESS, "");
" }\n",
// CONFIGURATION 53
"{\n"
+" \"hosts-databases\": [\n"
+" {\n"
+" \"name\": \"keatest1\",\n"
+" \"password\": \"keatest\",\n"
+" \"type\": \"mysql\",\n"
+" \"user\": \"keatest\"\n"
+" },\n"
+" {\n"
+" \"name\": \"keatest2\",\n"
+" \"password\": \"keatest\",\n"
+" \"type\": \"mysql\",\n"
+" \"user\": \"keatest\"\n"
+" }\n"
+" ],\n"
+" \"interfaces-config\": {\n"
+" \"interfaces\": [ \"*\" ],\n"
+" \"re-detect\": false\n"
+" },\n"
+" \"preferred-lifetime\": 3000,\n"
+" \"rebind-timer\": 2000,\n"
+" \"renew-timer\": 1000,\n"
+" \"valid-lifetime\": 4000\n"
+" }\n",
+ // CONFIGURATION 54
+"{\n"
" \"comment\": \"A DHCPv6 server\",\n"
" \"client-classes\": [\n"
" {\n"
" }\n",
// CONFIGURATION 53
"{\n"
+" \"decline-probation-period\": 86400,\n"
+" \"dhcp-ddns\": {\n"
+" \"always-include-fqdn\": false,\n"
+" \"enable-updates\": false,\n"
+" \"generated-prefix\": \"myhost\",\n"
+" \"max-queue-size\": 1024,\n"
+" \"ncr-format\": \"JSON\",\n"
+" \"ncr-protocol\": \"UDP\",\n"
+" \"override-client-update\": false,\n"
+" \"override-no-update\": false,\n"
+" \"qualifying-suffix\": \"\",\n"
+" \"replace-client-name\": \"never\",\n"
+" \"sender-ip\": \"0.0.0.0\",\n"
+" \"sender-port\": 0,\n"
+" \"server-ip\": \"127.0.0.1\",\n"
+" \"server-port\": 53001\n"
+" },\n"
+" \"dhcp4o6-port\": 0,\n"
+" \"expired-leases-processing\": {\n"
+" \"flush-reclaimed-timer-wait-time\": 25,\n"
+" \"hold-reclaimed-time\": 3600,\n"
+" \"max-reclaim-leases\": 100,\n"
+" \"max-reclaim-time\": 250,\n"
+" \"reclaim-timer-wait-time\": 10,\n"
+" \"unwarned-reclaim-cycles\": 5\n"
+" },\n"
+" \"hooks-libraries\": [ ],\n"
+" \"host-reservation-identifiers\": [ \"hw-address\", \"duid\" ],\n"
+" \"hosts-databases\": [\n"
+" {\n"
+" \"name\": \"keatest1\",\n"
+" \"password\": \"keatest\",\n"
+" \"type\": \"mysql\",\n"
+" \"user\": \"keatest\"\n"
+" },\n"
+" {\n"
+" \"name\": \"keatest2\",\n"
+" \"password\": \"keatest\",\n"
+" \"type\": \"mysql\",\n"
+" \"user\": \"keatest\"\n"
+" }\n"
+" ],\n"
+" \"interfaces-config\": {\n"
+" \"interfaces\": [ \"*\" ],\n"
+" \"re-detect\": false\n"
+" },\n"
+" \"lease-database\": {\n"
+" \"type\": \"memfile\"\n"
+" },\n"
+" \"mac-sources\": [ \"any\" ],\n"
+" \"option-data\": [ ],\n"
+" \"option-def\": [ ],\n"
+" \"relay-supplied-options\": [ \"65\" ],\n"
+" \"server-id\": {\n"
+" \"enterprise-id\": 0,\n"
+" \"htype\": 0,\n"
+" \"identifier\": \"\",\n"
+" \"persist\": true,\n"
+" \"time\": 0,\n"
+" \"type\": \"LLT\"\n"
+" },\n"
+" \"shared-networks\": [ ],\n"
+" \"subnet6\": [ ]\n"
+" }\n",
+ // CONFIGURATION 54
+"{\n"
" \"comment\": \"A DHCPv6 server\",\n"
" \"client-classes\": [\n"
" {\n"
}
}
-}
+} // namespace
namespace isc {
namespace dhcp {
}
}
-};
+} // namespace
namespace isc {
namespace dhcp {
++extract_count;
}
-};
-};
-};
+} // namespace test
+} // namespace dhcp
+} // namespace isc
namespace {
namespace dhcp {
CfgDbAccess::CfgDbAccess()
- : appended_parameters_(), lease_db_access_("type=memfile"),
- host_db_access_() {
+ : appended_parameters_(), db_access_(2) {
+ db_access_[LEASE_DB] = "type=memfile";
}
std::string
CfgDbAccess::getLeaseDbAccessString() const {
- return (getAccessString(lease_db_access_));
+ return (getAccessString(db_access_[LEASE_DB]));
}
std::string
CfgDbAccess::getHostDbAccessString() const {
- return (getAccessString(host_db_access_));
+ return (getAccessString(db_access_[HOSTS_DB]));
}
+std::vector<std::string>
+CfgDbAccess::getHostDbAccessStringList() const {
+ std::vector<std::string> ret;
+ for (size_t idx = HOSTS_DB; idx < db_access_.size(); ++idx) {
+ if (!db_access_[idx].empty()) {
+ ret.push_back(getAccessString(db_access_[idx]));
+ }
+ }
+ return (ret);
+}
void
CfgDbAccess::createManagers() const {
// Recreate host data source.
HostMgr::create();
- if (!host_db_access_.empty()) {
- HostMgr::addSource(getHostDbAccessString());
+ auto host_db_access_list = getHostDbAccessStringList();
+ for (auto it = host_db_access_list.begin();
+ it != host_db_access_list.end(); ++it) {
+ HostMgr::addSource(*it);
}
}
-// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-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
#include <cc/cfg_to_element.h>
#include <boost/shared_ptr.hpp>
#include <string>
+#include <vector>
namespace isc {
namespace dhcp {
/// passed to the @ref isc::dhcp::LeaseMgrFactory::create function.
class CfgDbAccess {
public:
+ /// @brief Specifies the database types
+ static const size_t LEASE_DB = 0;
+ static const size_t HOSTS_DB = 1;
/// @brief Constructor.
CfgDbAccess();
///
/// @param lease_db_access New lease database access string.
void setLeaseDbAccessString(const std::string& lease_db_access) {
- lease_db_access_ = lease_db_access;
+ db_access_[LEASE_DB] = lease_db_access;
}
/// @brief Retrieves host database access string.
///
/// @param host_db_access New host database access string.
void setHostDbAccessString(const std::string& host_db_access) {
- host_db_access_ = host_db_access;
+ db_access_[HOSTS_DB] = host_db_access;
}
- /// @brief Creates instance of lease manager and host data source
+ /// @brief Retrieves host database access string.
+ ///
+ /// @return Database access strings with additional parameters
+ /// specified with @ref CfgDbAccess::setAppendedParameters
+ std::vector<std::string> getHostDbAccessStringList() const;
+
+ /// @brief Pushes host database access string.
+ ///
+ /// @param db_access New host database access string.
+ void pushHostDbAccessString(const std::string& db_access) {
+ db_access_.push_back(db_access);
+ }
+
+ /// @brief Creates instance of lease manager and host data sources
/// according to the configuration specified.
void createManagers() const;
/// strings.
std::string appended_parameters_;
- /// @brief Holds lease database access string.
- std::string lease_db_access_;
-
- /// @brief Holds host database access string.
- std::string host_db_access_;
+ /// @brief Holds database access strings.
+ std::vector<std::string> db_access_;
};
///
/// @result a pointer to a configuration
virtual isc::data::ElementPtr toElement() const {
- return (CfgDbAccess::toElementDbAccessString(lease_db_access_));
+ return (CfgDbAccess::toElementDbAccessString(db_access_[LEASE_DB]));
}
};
///
/// @result a pointer to a configuration
virtual isc::data::ElementPtr toElement() const {
- return (CfgDbAccess::toElementDbAccessString(host_db_access_));
+ isc::data::ElementPtr result = isc::data::Element::createList();
+ for (size_t idx = HOSTS_DB; idx < db_access_.size(); ++idx) {
+ isc::data::ElementPtr entry =
+ CfgDbAccess::toElementDbAccessString(db_access_[idx]);
+ if (entry->size() > 0) {
+ result->add(entry);
+ }
+ }
+ return (result);
}
};
-// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-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
// Factory function to build the parser
-DbAccessParser::DbAccessParser(DBType db_type)
+DbAccessParser::DbAccessParser(size_t db_type)
: values_(), type_(db_type) {
}
// a. Check if the "type" keyword exists and thrown an exception if not.
StringPairMap::const_iterator type_ptr = values_copy.find("type");
if (type_ptr == values_copy.end()) {
- isc_throw(DhcpConfigError, (type_ == LEASE_DB ? "lease" : "host")
+ isc_throw(DhcpConfigError,
+ (type_ == CfgDbAccess::LEASE_DB ? "lease" : "host")
<< " database access parameters must "
"include the keyword 'type' to determine type of database "
"to be accessed (" << database_config->getPosition() << ")");
values_.swap(values_copy);
// 5. Save the database access string in the Configuration Manager.
- if (type_ == LEASE_DB) {
+ if (type_ == CfgDbAccess::LEASE_DB) {
cfg_db->setLeaseDbAccessString(getDbAccessString());
- } else if (type_ == HOSTS_DB) {
+ } else if (type_ == CfgDbAccess::HOSTS_DB) {
cfg_db->setHostDbAccessString(getDbAccessString());
+ } else if (type_ > CfgDbAccess::HOSTS_DB) {
+ cfg_db->pushHostDbAccessString(getDbAccessString());
}
}
-// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-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
class DbAccessParser: public isc::data::SimpleParser {
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;
/// @brief Constructor
///
/// @param db_type Specifies database type (lease or hosts)
- explicit DbAccessParser(DBType db_type);
+ explicit DbAccessParser(size_t db_type);
/// The destructor.
virtual ~DbAccessParser()
std::map<std::string, std::string> values_; ///< Stored parameter values
- DBType type_; ///< Database type (leases or hosts)
+ size_t type_; ///< Database type (leases or hosts)
};
}; // namespace dhcp
-// Copyright (C) 2014-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-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
// Set lease-database
CfgLeaseDbAccess lease_db(*cfg_db_access_);
dhcp->set("lease-database", lease_db.toElement());
- // Set hosts-database
+ // Set hosts-databases
CfgHostDbAccess host_db(*cfg_db_access_);
- // @todo accept empty map
- ConstElementPtr hosts_database = host_db.toElement();
- if (hosts_database->size() > 0) {
- dhcp->set("hosts-database", hosts_database);
+ ConstElementPtr hosts_databases = host_db.toElement();
+ if (hosts_databases->size() > 0) {
+ dhcp->set("hosts-databases", hosts_databases);
}
// Set host-reservation-identifiers
ConstElementPtr host_ids;
-// Copyright (C) 2016-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2016-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
runToElementTest<CfgLeaseDbAccess>(expected, CfgLeaseDbAccess(cfg));
EXPECT_TRUE(cfg.getHostDbAccessString().empty());
- runToElementTest<CfgHostDbAccess>("{ }", CfgHostDbAccess(cfg));
+ runToElementTest<CfgHostDbAccess>("[ ]", CfgHostDbAccess(cfg));
}
// This test verifies that it is possible to set the lease database
EXPECT_EQ("type=mysql", cfg.getHostDbAccessString());
// Check unparse
- std::string expected = "{ \"type\": \"mysql\" }";
+ std::string expected = "[ { \"type\": \"mysql\" } ]";
runToElementTest<CfgHostDbAccess>(expected, CfgHostDbAccess(cfg));
// Append additional parameter.
EXPECT_TRUE(cfg.getHostDbAccessString().empty());
}
+// This test verifies that it is possible to set multiple host
+// database string.
+TEST(CfgDbAccessTest, pushHostDbAccessString) {
+ CfgDbAccess cfg;
+ ASSERT_NO_THROW(cfg.setHostDbAccessString("type=mysql"));
+ EXPECT_EQ("type=mysql", cfg.getHostDbAccessString());
+
+ // Push two other strings
+ ASSERT_NO_THROW(cfg.pushHostDbAccessString("type=foo"));
+ ASSERT_NO_THROW(cfg.pushHostDbAccessString("type=bar"));
+
+ // Check unparse
+ std::string expected = "[ { \"type\": \"mysql\" }, ";
+ expected += "{ \"type\": \"foo\" }, { \"type\": \"bar\" } ]";
+ runToElementTest<CfgHostDbAccess>(expected, CfgHostDbAccess(cfg));
+
+ // Check access strings
+ std::vector<std::string> hal = cfg.getHostDbAccessStringList();
+ ASSERT_EQ(3, hal.size());
+ EXPECT_EQ("type=mysql", hal[0]);
+ EXPECT_EQ("type=foo", hal[1]);
+ EXPECT_EQ("type=bar", hal[2]);
+
+ // Reset the first string so it will be ignored.
+ ASSERT_NO_THROW(cfg.setHostDbAccessString(""));
+ expected = "[ { \"type\": \"foo\" }, { \"type\": \"bar\" } ]";
+ runToElementTest<CfgHostDbAccess>(expected, CfgHostDbAccess(cfg));
+ hal = cfg.getHostDbAccessStringList();
+ ASSERT_EQ(2, hal.size());
+ EXPECT_EQ("type=foo", hal[0]);
+ EXPECT_EQ("type=bar", hal[1]);
+}
+
// Tests that lease manager can be created from a specified configuration.
TEST(CfgDbAccessTest, createLeaseMgr) {
CfgDbAccess cfg;
-// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-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
/// @brief Constructor
///
/// @brief Keyword/value collection of database access parameters
- TestDbAccessParser(DbAccessParser::DBType type)
+ TestDbAccessParser(size_t type)
: DbAccessParser(type)
{}
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid memfile", parser.getDbAccessParameters(), config);
}
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::HOSTS_DB);
+ TestDbAccessParser parser(CfgDbAccess::HOSTS_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid memfile", parser.getDbAccessParameters(), config);
}
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid memfile", parser.getDbAccessParameters(), config);
}
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid memfile", parser.getDbAccessParameters(),
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid memfile", parser.getDbAccessParameters(),
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid LFC Interval", parser.getDbAccessParameters(),
config);
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_THROW(parser.parse(json_elements), DhcpConfigError);
}
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_THROW(parser.parse(json_elements), DhcpConfigError);
}
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid timeout", parser.getDbAccessParameters(),
config);
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_THROW(parser.parse(json_elements), DhcpConfigError);
}
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_THROW(parser.parse(json_elements), DhcpConfigError);
}
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid port", parser.getDbAccessParameters(),
config);
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_THROW(parser.parse(json_elements), DhcpConfigError);
}
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_THROW(parser.parse(json_elements), DhcpConfigError);
}
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid mysql", parser.getDbAccessParameters(), config);
}
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_THROW(parser.parse(json_elements), DhcpConfigError);
}
"name", "keatest",
NULL};
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
// First configuration string should cause a representation of that string
// to be held.
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
// Get the database access string
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_NO_THROW(parser.parse(json_elements));
checkAccessString("Valid readonly parameter",
ConstElementPtr json_elements = Element::fromJSON(json_config);
EXPECT_TRUE(json_elements);
- TestDbAccessParser parser(DbAccessParser::LEASE_DB);
+ TestDbAccessParser parser(CfgDbAccess::LEASE_DB);
EXPECT_THROW(parser.parse(json_elements), DhcpConfigError);
}
+// Check that multiple host storages are correctly parsed.
+TEST_F(DbAccessParserTest, multipleHost) {
+ const char* config1[] = {"type", "mysql",
+ "name", "keatest1",
+ NULL};
+ const char* config2[] = {"type", "mysql",
+ "name", "keatest2",
+ NULL};
+
+ string json_config1 = toJson(config1);
+ string json_config2 = toJson(config2);
+ ConstElementPtr json_elements1 = Element::fromJSON(json_config1);
+ ConstElementPtr json_elements2 = Element::fromJSON(json_config2);
+
+ TestDbAccessParser parser1(2);
+ TestDbAccessParser parser2(3);
+ EXPECT_NO_THROW(parser1.parse(json_elements1));
+ EXPECT_NO_THROW(parser2.parse(json_elements2));
+
+ checkAccessString("First config",
+ parser1.getDbAccessParameters(),
+ config1);
+ checkAccessString("Second config",
+ parser2.getDbAccessParameters(),
+ config2);
+}
}; // Anonymous namespace