Commit 05c79aa7 authored by Marcin Siodelski's avatar Marcin Siodelski

[3696] It is allowed to not specify lease database configuration.

In such case, the server will use a default configuration - memfile
lease database backend.
parent 25697857
// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2016 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
......@@ -11,6 +11,7 @@
#include <hooks/hooks_manager.h>
#include <dhcp4/json_config_parser.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/cfg_db_access.h>
#include <config/command_mgr.h>
#include <stats/stats_mgr.h>
......@@ -168,6 +169,17 @@ ControlledDhcpv4Srv::processConfig(isc::data::ConstElementPtr config) {
return (isc::config::createAnswer(1, err.str()));
}
// Re-open lease and host database with new parameters.
try {
CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
cfg_db->setAppendedParameters("universe=4");
cfg_db->createManagers();
} catch (const std::exception& ex) {
err << "Unable to open database: " << ex.what();
return (isc::config::createAnswer(1, err.str()));
}
// Server will start DDNS communications if its enabled.
try {
srv->startD2();
......
......@@ -431,11 +431,9 @@ DhcpConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id,
parser = new StringParser(config_id,
globalContext()->string_values_);
} else if (config_id.compare("lease-database") == 0) {
parser = new DbAccessParser(config_id, DbAccessParser::LEASE_DB,
*globalContext());
parser = new DbAccessParser(config_id, DbAccessParser::LEASE_DB);
} else if (config_id.compare("hosts-database") == 0) {
parser = new DbAccessParser(config_id, DbAccessParser::HOSTS_DB,
*globalContext());
parser = new DbAccessParser(config_id, DbAccessParser::HOSTS_DB);
} else if (config_id.compare("hooks-libraries") == 0) {
parser = new HooksLibrariesParser(config_id);
} else if (config_id.compare("echo-client-id") == 0) {
......
......@@ -32,6 +32,16 @@ namespace isc {
namespace dhcp {
namespace test {
BaseServerTest::BaseServerTest()
: original_datadir_(CfgMgr::instance().getDataDir()) {
CfgMgr::instance().setDataDir(TEST_DATA_BUILDDIR);
}
BaseServerTest::~BaseServerTest() {
// Revert to original data directory.
CfgMgr::instance().setDataDir(original_datadir_);
}
Dhcpv4SrvTest::Dhcpv4SrvTest()
:rcode_(-1), srv_(0) {
......
......@@ -209,7 +209,28 @@ public:
// dependencies, we use forward declaration here.
class Dhcp4Client;
class Dhcpv4SrvTest : public ::testing::Test {
/// @brief Base class for DHCPv4 server testing.
///
/// Currently it configures the test data path directory in
/// the @c CfgMgr. When the object is destroyed, the original
/// path is reverted.
class BaseServerTest : public ::testing::Test {
public:
/// @brief Constructor.
BaseServerTest();
/// @brief Destructor.
virtual ~BaseServerTest();
private:
/// @brief Holds the original data directory.
std::string original_datadir_;
};
class Dhcpv4SrvTest : public BaseServerTest {
public:
enum ExpectedResult {
......
// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2016 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
......@@ -12,6 +12,7 @@
#include <dhcp/hwaddr.h>
#include <dhcp/iface_mgr.h>
#include <dhcp4/ctrl_dhcp4_srv.h>
#include <dhcp4/tests/dhcp4_test_utils.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/lease.h>
#include <dhcpsrv/lease_mgr_factory.h>
......@@ -50,7 +51,7 @@ public:
/// It is very simple and currently focuses on reading
/// config file from disk. It is expected to be expanded in the
/// near future.
class JSONFileBackendTest : public ::testing::Test {
class JSONFileBackendTest : public isc::dhcp::test::BaseServerTest {
public:
JSONFileBackendTest() {
}
......@@ -59,6 +60,11 @@ public:
LeaseMgrFactory::destroy();
isc::log::setDefaultLoggingOutput();
static_cast<void>(remove(TEST_FILE));
// Remove default lease file.
std::ostringstream s;
s << CfgMgr::instance().getDataDir() << "/kea-leases4.csv";
static_cast<void>(remove(s.str().c_str()));
};
/// @brief writes specified content to a well known file
......@@ -395,4 +401,31 @@ TEST_F(JSONFileBackendTest, timers) {
EXPECT_FALSE(lease_reclaimed);
}
// This test verifies that the server uses default (Memfile) lease database
// backend when no backend is explicitly specified in the configuration.
TEST_F(JSONFileBackendTest, defaultLeaseDbBackend) {
// This is basic server configuration which excludes lease database
// backend specification. The default Memfile backend should be
// initialized in this case.
string config =
"{ \"Dhcp4\": {"
"\"interfaces-config\": {"
" \"interfaces\": [ ]"
"},"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, \n"
"\"subnet4\": [ ],"
"\"valid-lifetime\": 4000 }"
"}";
writeFile(config);
// Create an instance of the server and intialize it.
boost::scoped_ptr<ControlledDhcpv4Srv> srv;
ASSERT_NO_THROW(srv.reset(new ControlledDhcpv4Srv(0)));
ASSERT_NO_THROW(srv->init(TEST_FILE));
// The backend should have been created.
EXPECT_NO_THROW(static_cast<void>(LeaseMgrFactory::instance()));
}
} // End of anonymous namespace
// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2014-2016 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
......@@ -9,6 +9,7 @@
#include <config/command_mgr.h>
#include <dhcp/libdhcp++.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/cfg_db_access.h>
#include <dhcp6/ctrl_dhcp6_srv.h>
#include <dhcp6/dhcp6_log.h>
#include <dhcp6/json_config_parser.h>
......@@ -173,6 +174,17 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) {
+ string(ex.what())));
}
// Re-open lease and host database with new parameters.
try {
CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
cfg_db->setAppendedParameters("universe=6");
cfg_db->createManagers();
} catch (const std::exception& ex) {
return (isc::config::createAnswer(1, "Unable to open database: "
+ std::string(ex.what())));
}
// Regenerate server identifier if needed.
try {
const std::string duid_file = CfgMgr::instance().getDataDir() + "/" +
......
......@@ -682,11 +682,9 @@ DhcpConfigParser* createGlobal6DhcpConfigParser(const std::string& config_id,
parser = new StringParser(config_id,
globalContext()->string_values_);
} else if (config_id.compare("lease-database") == 0) {
parser = new DbAccessParser(config_id, DbAccessParser::LEASE_DB,
*globalContext());
parser = new DbAccessParser(config_id, DbAccessParser::LEASE_DB);
} else if (config_id.compare("hosts-database") == 0) {
parser = new DbAccessParser(config_id, DbAccessParser::HOSTS_DB,
*globalContext());
parser = new DbAccessParser(config_id, DbAccessParser::HOSTS_DB);
} else if (config_id.compare("hooks-libraries") == 0) {
parser = new HooksLibrariesParser(config_id);
} else if (config_id.compare("dhcp-ddns") == 0) {
......
// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2016 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
......@@ -56,6 +56,11 @@ public:
LeaseMgrFactory::destroy();
isc::log::setDefaultLoggingOutput();
static_cast<void>(remove(TEST_FILE));
// Remove default lease file.
std::ostringstream s;
s << CfgMgr::instance().getDataDir() << "/kea-leases6.csv";
static_cast<void>(remove(s.str().c_str()));
};
void writeFile(const std::string& file_name, const std::string& content) {
......@@ -378,4 +383,32 @@ TEST_F(JSONFileBackendTest, serverId) {
EXPECT_EQ(1234, duid_cfg->getEnterpriseId());
}
// This test verifies that the server uses default (Memfile) lease database
// backend when no backend is explicitly specified in the configuration.
TEST_F(JSONFileBackendTest, defaultLeaseDbBackend) {
// This is basic server configuration which excludes lease database
// backend specification. The default Memfile backend should be
// initialized in this case.
string config =
"{ \"Dhcp6\": {"
"\"interfaces-config\": {"
" \"interfaces\": [ ]"
"},"
"\"rebind-timer\": 2000, "
"\"renew-timer\": 1000, \n"
"\"subnet6\": [ ],"
"\"preferred-lifetime\": 3000, "
"\"valid-lifetime\": 4000 }"
"}";
writeFile(TEST_FILE, config);
// Create an instance of the server and intialize it.
boost::scoped_ptr<ControlledDhcpv6Srv> srv;
ASSERT_NO_THROW(srv.reset(new ControlledDhcpv6Srv(0)));
ASSERT_NO_THROW(srv->init(TEST_FILE));
// The backend should have been created.
EXPECT_NO_THROW(static_cast<void>(LeaseMgrFactory::instance()));
}
} // End of anonymous namespace
......@@ -85,6 +85,7 @@ libkea_dhcpsrv_la_SOURCES += alloc_engine.cc alloc_engine.h
libkea_dhcpsrv_la_SOURCES += alloc_engine_log.cc alloc_engine_log.h
libkea_dhcpsrv_la_SOURCES += base_host_data_source.h
libkea_dhcpsrv_la_SOURCES += callout_handle_store.h
libkea_dhcpsrv_la_SOURCES += cfg_db_access.cc cfg_db_access.h
libkea_dhcpsrv_la_SOURCES += cfg_duid.cc cfg_duid.h
libkea_dhcpsrv_la_SOURCES += cfg_hosts.cc cfg_hosts.h
libkea_dhcpsrv_la_SOURCES += cfg_iface.cc cfg_iface.h
......
// Copyright (C) 2016 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 <dhcpsrv/cfg_db_access.h>
#include <dhcpsrv/host_data_source_factory.h>
#include <dhcpsrv/lease_mgr_factory.h>
#include <sstream>
namespace isc {
namespace dhcp {
CfgDbAccess::CfgDbAccess()
: appended_parameters_(), lease_db_access_("type=memfile"),
host_db_access_() {
}
std::string
CfgDbAccess::getLeaseDbAccessString() const {
return (getAccessString(lease_db_access_));
}
std::string
CfgDbAccess::getHostDbAccessString() const {
return (getAccessString(host_db_access_));
}
void
CfgDbAccess::createManagers() const {
// Recreate lease manager.
LeaseMgrFactory::destroy();
LeaseMgrFactory::create(getLeaseDbAccessString());
// Recreate host data source.
HostDataSourceFactory::destroy();
if (!host_db_access_.empty()) {
HostDataSourceFactory::create(getHostDbAccessString());
}
}
std::string
CfgDbAccess::getAccessString(const std::string& access_string) const {
std::ostringstream s;
s << access_string;
// Only append additional parameters if any parameters are specified
// in a configuration. For host database, no parameters mean that
// database access is disabled and thus we don't want to append any
// parameters.
if ((s.tellp() != std::streampos(0)) && (!appended_parameters_.empty())) {
s << " " << appended_parameters_;
}
return (s.str());
}
} // end of isc::dhcp namespace
} // end of isc namespace
// Copyright (C) 2016 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 CFG_DBACCESS_H
#define CFG_DBACCESS_H
#include <boost/shared_ptr.hpp>
#include <string>
namespace isc {
namespace dhcp {
/// @brief Holds access parameters and the configuration of the
/// lease and hosts database connection.
///
/// The database access strings use the same format as the strings
/// passed to the @ref isc::dhcp::LeaseMgrFactory::create function.
class CfgDbAccess {
public:
/// @brief Constructor.
CfgDbAccess();
/// @brief Sets parameters which will be appended to the database
/// access strings.
void setAppendedParameters(const std::string& appended_parameters) {
appended_parameters_ = appended_parameters;
}
/// @brief Retrieves lease database access string.
///
/// @return Lease database access string with additional parameters
/// specified with @ref CfgDbAccess::setAppendedParameters.
std::string getLeaseDbAccessString() const;
/// @brief Sets lease database access string.
///
/// @param lease_db_access New lease database access string.
void setLeaseDbAccessString(const std::string& lease_db_access) {
lease_db_access_ = lease_db_access;
}
/// @brief Retrieves host database access string.
///
/// @return Host database access string with additional parameters
/// specified with @ref CfgDbAccess::setAppendedParameters.
std::string getHostDbAccessString() const;
/// @brief Sets 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;
}
/// @brief Creates instance of @ref LeaseMgr @ref HostDataSource
/// according to the configuration specified.
void createManagers() const;
private:
/// @brief Returns lease or host database access string.
///
/// @param Access string without additional (appended) parameters.
std::string getAccessString(const std::string& access_string) const;
/// @brief Parameters to be appended to the database access
/// 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 A pointer to the @c CfgDbAccess.
typedef boost::shared_ptr<CfgDbAccess> CfgDbAccessPtr;
/// @brief A pointer to the const @c CfgDbAccess.
typedef boost::shared_ptr<const CfgDbAccess> ConstCfgDbAccessPtr;
}
}
#endif // CFG_DBACCESS_H
// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2016 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
......@@ -36,6 +36,14 @@ public:
isc::Exception(file, line, what) {}
};
/// @brief Invalid type exception
///
/// Thrown when the factory doesn't recognize the type of the backend.
class InvalidType : public Exception {
public:
InvalidType(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
/// @brief Common database connection class.
///
......
// Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2015-2016 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
......@@ -17,15 +17,6 @@
namespace isc {
namespace dhcp {
/// @brief Invalid type exception
///
/// Thrown when the factory doesn't recognise the type of the backend.
class InvalidType : public Exception {
public:
InvalidType(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
/// @brief No host data source instance exception
///
/// Thrown if an attempt is made to get a reference to the current
......
// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2016 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
......@@ -18,14 +18,6 @@
namespace isc {
namespace dhcp {
/// @brief Invalid type exception
///
/// Thrown when the factory doesn't recognize the type of the backend.
class InvalidType : public Exception {
public:
InvalidType(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) {}
};
/// @brief No lease manager exception
///
......
// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2016 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
......@@ -777,9 +777,7 @@ Memfile_LeaseMgr::deleteExpiredReclaimedLeases(const uint32_t secs,
std::string
Memfile_LeaseMgr::getDescription() const {
return (std::string("This is a dummy memfile backend implementation.\n"
"It does not offer any useful lease management and its only\n"
"purpose is to test abstract lease manager API."));
return (std::string("In Memory Database"));
}
void
......
// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2016 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
......@@ -7,6 +7,8 @@
#include <config.h>
#include <dhcp/option.h>
#include <dhcpsrv/cfg_db_access.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/dhcpsrv_log.h>
#include <dhcpsrv/lease_mgr_factory.h>
#include <dhcpsrv/host_mgr.h>
......@@ -27,10 +29,8 @@ namespace dhcp {
// Factory function to build the parser
DbAccessParser::DbAccessParser(const std::string&, DBType db_type,
const ParserContext& ctx)
: values_(), type_(db_type), ctx_(ctx)
{
DbAccessParser::DbAccessParser(const std::string&, DBType db_type)
: values_(), type_(db_type) {
}
// Parse the configuration and check that the various keywords are consistent.
......@@ -39,21 +39,17 @@ DbAccessParser::build(isc::data::ConstElementPtr config_value) {
// To cope with incremental updates, the strategy is:
// 1. Take a copy of the stored keyword/value pairs.
// 2. Inject the universe parameter.
// 3. Update the copy with the passed keywords.
// 4. Perform validation checks on the updated keyword/value pairs.
// 5. If all is OK, update the stored keyword/value pairs.
// 2. Update the copy with the passed keywords.
// 3. Perform validation checks on the updated keyword/value pairs.
// 4. If all is OK, update the stored keyword/value pairs.
// 5. Save resulting database access string in the Configuration
// Manager.
// 1. Take a copy of the stored keyword/value pairs.
std::map<string, string> values_copy = values_;
// 2. Inject the parameter which defines whether we are configuring
// DHCPv4 or DHCPv6. Some database backends (e.g. Memfile make
// use of it).
values_copy["universe"] = ctx_.universe_ == Option::V4 ? "4" : "6";
int64_t lfc_interval = 0;
// 3. Update the copy with the passed keywords.
// 2. Update the copy with the passed keywords.
BOOST_FOREACH(ConfigPair param, config_value->mapValue()) {
try {
if (param.first == "persist") {
......@@ -75,7 +71,7 @@ DbAccessParser::build(isc::data::ConstElementPtr config_value) {
}
}
// 4. Perform validation checks on the updated set of keyword/values.
// 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");
......@@ -100,11 +96,21 @@ DbAccessParser::build(isc::data::ConstElementPtr config_value) {
<< std::numeric_limits<uint32_t>::max());
}
// 5. If all is OK, update the stored keyword/value pairs. We do this by
// 4. If all is OK, update the stored keyword/value pairs. We do this by
// swapping contents - values_copy is destroyed immediately after the
// operation (when the method exits), so we are not interested in its new
// value.
values_.swap(values_copy);
// 5. Save the database access string in the Configuration Manager.
CfgDbAccessPtr cfg_db = CfgMgr::instance().getStagingCfg()->getCfgDbAccess();
if (type_ == LEASE_DB) {
cfg_db->setLeaseDbAccessString(getDbAccessString());
} else {
cfg_db->setHostDbAccessString(getDbAccessString());
}
}
// Create the database access string
......@@ -133,30 +139,6 @@ DbAccessParser::getDbAccessString() const {
// Commit the changes - reopen the database with the new parameters
void
DbAccessParser::commit() {
switch (type_) {
case LEASE_DB:
{
// Close current lease manager database.
LeaseMgrFactory::destroy();
// ... and open the new database using the access string.
LeaseMgrFactory::create(getDbAccessString());
break;
}
case HOSTS_DB:
{
// Let's instantiate HostMgr with new parameters. Note that HostMgr's
// create method will call HostDataSourceFactory::create() with
// appropriate parameters. It will also destroy a pre-existing
// instance, if it existed.
HostMgr::create(getDbAccessString());
break;
}
default:
isc_throw(BadValue, "Incorrect type specified in DbAccessParser: "
<< type_);
};
}
}; // namespace dhcp
......
// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012-2016 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
......@@ -55,9 +55,7 @@ public:
/// @param param_name Name of the parameter under which the database
/// access details are held.
/// @param db_type Specifies database type (lease or hosts)
/// @param ctx Parser context.
DbAccessParser(const std::string& param_name, DBType db_type,
const ParserContext& ctx);
DbAccessParser(const std::string& param_name, DBType db_type);
/// The destructor.
virtual ~DbAccessParser()
......@@ -83,13 +81,7 @@ public:
/// the list of database access keywords.
virtual void build(isc::data::ConstElementPtr config_value);
/// @brief Apply the prepared configuration value to the server.
///
/// With the string validated, this closes the currently open database (if
/// any), then opens a database corresponding to the stored string.
///
/// This method is expected to be called after \c build(), and only once.
/// The result is undefined otherwise.
/// @brief This method is no-op.