Commit f4b4bb9f authored by Thomas Markwalder's avatar Thomas Markwalder

[#101,!58] Implemented ConfigBackendDhcp4Mgr, mysql backend registers/unregisters

src/hooks/dhcp/mysql_cb/mysql_cb_callouts.cc
    load() - added call to register MySQL backend
    unload() - added call to unregister MySQL backend

src/hooks/dhcp/mysql_cb/mysql_cb_dhcp4.*
    MySqlConfigBackendDHCPv4::registerBackendType()
    MySqlConfigBackendDHCPv4::unregisterBackendType()
    - new static methods for registering/unregistering

src/hooks/dhcp/mysql_cb/tests/Makefile.am
    mysql_cb_dhcp4_mgr_unittest.cc  - new file

src/lib/config_backend/base_config_backend_mgr.h
    bool unregisterBackendFactory(const std::string& db_type)
    - new method to unregister factory and delete backends

src/lib/config_backend/base_config_backend_pool.h
    void delAllBackends(const std::string& db_type)
    - new method to delete all backends of a given type

/src/lib/config_backend/tests/config_backend_mgr_unittest.cc
    TEST_F(ConfigBackendMgrTest, unregister) - new test

src/lib/dhcpsrv/Makefile.am
src/lib/dhcpsrv/config_backend_dhcp4.h
src/lib/dhcpsrv/config_backend_dhcp4.cc
    New files that implement ConfigBackendDhcp4Mgr

src/lib/dhcpsrv/config_backend_pool_dhcp4.h
    Added missing public scope, removed pure virtual function

src/lib/eval/tests/Makefile.am
    Added new dependency libkea-cc
parent 8ddd1a7b
......@@ -574,6 +574,8 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
// This operation should be exception safe but let's make sure.
if (!rollback) {
try {
// if we have config-control DBs attempt to create them here,
// if that fails, rollback?
// Setup the command channel.
configureCommandChannel();
......@@ -592,6 +594,9 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
const HooksConfig& libraries =
CfgMgr::instance().getStagingCfg()->getHooksConfig();
libraries.loadLibraries();
// now that we have config-db and hooks, merge in config from DB
// databaseConfigFetch(srv_config, mutable_cfg);
}
catch (const isc::Exception& ex) {
LOG_ERROR(dhcp4_logger, DHCP4_PARSER_COMMIT_FAIL).arg(ex.what());
......@@ -606,6 +611,7 @@ configureDhcp4Server(Dhcpv4Srv& server, isc::data::ConstElementPtr config_set,
}
}
// Rollback changes as the configuration parsing failed.
if (rollback) {
// Revert to original configuration of runtime option definitions
......
......@@ -10,6 +10,7 @@
#include <config.h>
#include <hooks/hooks.h>
#include <mysql_cb_dhcp4.h>
using namespace isc::hooks;
......@@ -19,7 +20,12 @@ extern "C" {
///
/// @param handle library handle
/// @return 0 when initialization is successful, 1 otherwise
int load(LibraryHandle& /* handle */) {
// Register MySQL CB factory with CB Manager
isc::dhcp::MySqlConfigBackendDHCPv4::registerBackendType();
return (0);
}
......@@ -27,6 +33,9 @@ int load(LibraryHandle& /* handle */) {
///
/// @return 0 if deregistration was successful, 1 otherwise
int unload() {
// Unregister the factory and remove MySQL backends
isc::dhcp::MySqlConfigBackendDHCPv4::unregisterBackendType();
return (0);
}
......
......@@ -14,6 +14,7 @@
#include <dhcp/libdhcp++.h>
#include <dhcp/option_data_types.h>
#include <dhcp/option_space.h>
#include <dhcpsrv/config_backend_dhcp4_mgr.h>
#include <dhcpsrv/network.h>
#include <dhcpsrv/pool.h>
#include <dhcpsrv/lease.h>
......@@ -153,7 +154,7 @@ public:
///
/// @return Pointer to the retrieved value or null if such parameter
/// doesn't exist.
StampedValuePtr getGlobalParameter4(const ServerSelector& server_selector,
StampedValuePtr getGlobalParameter4(const ServerSelector& /* server_selector */,
const std::string& name) {
MySqlBindingCollection in_bindings = {
MySqlBinding::createString(name)
......@@ -170,7 +171,7 @@ public:
/// @param server_selector Server selector.
/// @param name Name of the global parameter.
/// @param value Value of the global parameter.
void createUpdateGlobalParameter4(const db::ServerSelector& server_selector,
void createUpdateGlobalParameter4(const db::ServerSelector& /* server_selector */,
const StampedValuePtr& value) {
MySqlBindingCollection in_bindings = {
MySqlBinding::createString(value->getName()),
......@@ -1194,7 +1195,7 @@ public:
/// @return Pointer to the returned option or NULL if such option
/// doesn't exist.
OptionDescriptorPtr
getOption4(const ServerSelector& server_selector, const uint16_t code,
getOption4(const ServerSelector& /* server_selector */, const uint16_t code,
const std::string& space) {
OptionContainer options;
MySqlBindingCollection in_bindings = {
......@@ -1211,7 +1212,7 @@ public:
/// @param selector Server selector.
/// @return Container holding returned options.
OptionContainer
getAllOptions4(const ServerSelector& server_selector) {
getAllOptions4(const ServerSelector& /* server_selector */) {
OptionContainer options;
MySqlBindingCollection in_bindings;
getOptions(MySqlConfigBackendDHCPv4Impl::GET_ALL_OPTIONS4,
......@@ -1225,7 +1226,7 @@ public:
/// @param selector Server selector.
/// @return Container holding returned options.
OptionContainer
getModifiedOptions4(const ServerSelector& server_selector,
getModifiedOptions4(const ServerSelector& /* server_selector */,
const boost::posix_time::ptime& modification_time) {
OptionContainer options;
MySqlBindingCollection in_bindings = {
......@@ -2512,7 +2513,7 @@ MySqlConfigBackendDHCPv4::getGlobalParameter4(const ServerSelector& server_selec
}
StampedValueCollection
MySqlConfigBackendDHCPv4::getAllGlobalParameters4(const ServerSelector& server_selector) const {
MySqlConfigBackendDHCPv4::getAllGlobalParameters4(const ServerSelector& /* server_selector */) const {
MySqlBindingCollection in_bindings;
StampedValueCollection parameters;
impl_->getGlobalParameters4(MySqlConfigBackendDHCPv4Impl::GET_ALL_GLOBAL_PARAMETERS4,
......@@ -2522,7 +2523,7 @@ MySqlConfigBackendDHCPv4::getAllGlobalParameters4(const ServerSelector& server_s
StampedValueCollection
MySqlConfigBackendDHCPv4::
getModifiedGlobalParameters4(const db::ServerSelector& server_selector,
getModifiedGlobalParameters4(const db::ServerSelector& /* server_selector */,
const boost::posix_time::ptime& modification_time) const {
MySqlBindingCollection in_bindings = {
MySqlBinding::createTimestamp(modification_time)
......@@ -2663,14 +2664,14 @@ MySqlConfigBackendDHCPv4::deleteOption4(const ServerSelector& server_selector,
}
uint64_t
MySqlConfigBackendDHCPv4::deleteGlobalParameter4(const ServerSelector& server_selector,
MySqlConfigBackendDHCPv4::deleteGlobalParameter4(const ServerSelector& /*server_selector*/,
const std::string& name) {
return (impl_->deleteFromTable(MySqlConfigBackendDHCPv4Impl::DELETE_GLOBAL_PARAMETER4,
name));
}
uint64_t
MySqlConfigBackendDHCPv4::deleteAllGlobalParameters4(const ServerSelector& selector) {
MySqlConfigBackendDHCPv4::deleteAllGlobalParameters4(const ServerSelector& /* server_selector */) {
return (impl_->deleteFromTable(MySqlConfigBackendDHCPv4Impl::DELETE_ALL_GLOBAL_PARAMETERS4));
}
......@@ -2689,5 +2690,18 @@ MySqlConfigBackendDHCPv4::getPort() const {
return (0);
}
void
MySqlConfigBackendDHCPv4::registerBackendType() {
dhcp::ConfigBackendDHCPv4Mgr::instance().registerBackendFactory("mysql",
[](const db::DatabaseConnection::ParameterMap& params) -> dhcp::ConfigBackendDHCPv4Ptr {
return (dhcp::MySqlConfigBackendDHCPv4Ptr(new dhcp::MySqlConfigBackendDHCPv4(params)));
});
}
void
MySqlConfigBackendDHCPv4::unregisterBackendType() {
dhcp::ConfigBackendDHCPv4Mgr::instance().unregisterBackendFactory("mysql");
}
} // end of namespace isc::dhcp
} // end of namespace isc
......@@ -388,6 +388,16 @@ public:
/// @return Port number on which database service is available.
virtual uint16_t getPort() const;
/// @brief Registers the MySQL backend factory with backend config manager
///
/// This should be called by the hook lib load() function.
static void registerBackendType();
/// @brief Unregisters the MySQL backend factory and discards MySQL backends
///
/// This should be called by the hook lib unload() function.
static void unregisterBackendType();
private:
/// @brief Pointer to the implementation of the @c MySqlConfigBackendDHCPv4
......
......@@ -24,6 +24,7 @@ if HAVE_GTEST
TESTS += mysql_cb_unittests
mysql_cb_unittests_SOURCES = mysql_cb_dhcp4_unittest.cc
mysql_cb_unittests_SOURCES += mysql_cb_dhcp4_mgr_unittest.cc
mysql_cb_unittests_SOURCES += run_unittests.cc
mysql_cb_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES) $(LOG4CPLUS_INCLUDES)
......
// 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 <cc/stamped_value.h>
#include <dhcpsrv/config_backend_dhcp4_mgr.h>
#include <mysql_cb_dhcp4.h>
#include <mysql/testutils/mysql_schema.h>
#include <boost/shared_ptr.hpp>
#include <gtest/gtest.h>
using namespace isc::data;
using namespace isc::dhcp;
using namespace isc::db;
using namespace isc::db::test;
namespace {
/// @brief Test fixture class for @c MySqlConfigBackendDHCPv4Mgr.
class MySqlConfigBackendDHCPv4MgrTest : public ::testing::Test {
public:
/// @brief Constructor.
MySqlConfigBackendDHCPv4MgrTest() {
// Recreate a fresh mgr.
ConfigBackendDHCPv4Mgr::create();
// Recreate database schema.
destroyMySQLSchema();
createMySQLSchema();
}
/// @brief Destructor.
virtual ~MySqlConfigBackendDHCPv4MgrTest() {
destroyMySQLSchema();
}
};
// This test verifies that MySQL backend can be registered with and
// unregistered from the Config Backend Manager.
TEST_F(MySqlConfigBackendDHCPv4MgrTest, factoryRegistration) {
// Get the mgr singleton.
ConfigBackendDHCPv4Mgr& mgr = ConfigBackendDHCPv4Mgr::instance();
// With no factory registered, attempting to add a MySQL db should fail.
ASSERT_THROW(mgr.addBackend(validMySQLConnectionString()), InvalidType);
// Now we'll register the MySQL factory.
ASSERT_NO_THROW(MySqlConfigBackendDHCPv4::registerBackendType());
// With the factory registered, attempting to add a MySQL db should succeed.
ASSERT_NO_THROW(mgr.addBackend(validMySQLConnectionString()));
// Create a MySQL backend selector for convenience.
BackendSelector mysql(BackendSelector::Type::MYSQL);
// Should be able to create a global parameter.
StampedValuePtr server_tag = StampedValue::create("server-tag", "whale");
ASSERT_NO_THROW(mgr.getPool()->createUpdateGlobalParameter4(mysql, ServerSelector::UNASSIGNED(),
server_tag));
// Verify parameter can be fetched.
server_tag.reset();
ASSERT_NO_THROW(server_tag = mgr.getPool()->getGlobalParameter4(mysql, ServerSelector::UNASSIGNED(),
"server-tag"));
ASSERT_TRUE(server_tag);
EXPECT_EQ("server-tag", server_tag->getName());
EXPECT_EQ("whale", server_tag->getValue());
// Now we'll unregister MySQL.
ASSERT_NO_THROW(MySqlConfigBackendDHCPv4::unregisterBackendType());
// With no factory registered, attempting to add a MySQL db should fail.
ASSERT_THROW(mgr.addBackend(validMySQLConnectionString()), InvalidType);
// Attempting to read the global parameter should fail.
ASSERT_THROW(mgr.getPool()->getGlobalParameter4(mysql, ServerSelector::UNASSIGNED(), "server-tag"),
NoSuchDatabase);
}
}
......@@ -9,6 +9,7 @@
#include <config_backend/base_config_backend.h>
#include <database/database_connection.h>
#include <database/backend_selector.h>
#include <exceptions/exceptions.h>
#include <boost/shared_ptr.hpp>
#include <functional>
......@@ -104,6 +105,32 @@ public:
return (true);
}
/// @brief Unregisters the backend factory function for a given backend type.
///
/// The typical usage of this function is remove the factory function
/// when its type of backend is no longer supported (i.e hook lib is unloaded).
/// It should mirror the use @c registerBackendFactory and be called from the
/// hooks library @c unload function.
///
/// @param db_type Backend type, e.g. "mysql".
///
/// @return false if no factory for the given type was not registered, true
/// true if the factory was removed.
bool unregisterBackendFactory(const std::string& db_type) {
// Look for it.
auto index = factories_.find(db_type);
// If it's there remove it
if (index != factories_.end()) {
factories_.erase(index);
pool_->delAllBackends(db_type);
return (true);
}
return (false);
}
/// @brief Create an instance of a configuration backend.
///
/// This method uses provided @c dbaccess string representing database
......@@ -137,7 +164,7 @@ public:
if (index == factories_.end()) {
isc_throw(db::InvalidType, "The type of the configuration backend: '" <<
db_type << "' is not supported");
}
}
// Call the factory and push the pointer on sources.
auto backend = index->second(parameters);
......
......@@ -61,6 +61,21 @@ public:
backends_.clear();
}
/// @brief Deletes all backends of the given type from the pool.
///
/// @param db_type backend to remove
void delAllBackends(const std::string& db_type) {
typename std::list<ConfigBackendTypePtr>::iterator backend = backends_.begin();
while (backend != backends_.end()) {
if ((*backend)->getType() == db_type) {
backend = backends_.erase(backend);
} else {
++backend;
}
}
}
protected:
/// @brief Retrieve a single configuration property from the pool.
......
......@@ -525,5 +525,32 @@ TEST_F(ConfigBackendMgrTest, getAllProperties) {
NoSuchDatabase);
}
// Verify that unregistering a factory works.
TEST_F(ConfigBackendMgrTest, unregister) {
// Verify we can't remove what is not there.
ASSERT_FALSE(config_mgr_.unregisterBackendFactory("mysql"));
// Add both MySQL and Postgresql backends
addTestBackends();
// Backend should be present.
EXPECT_NO_THROW(config_mgr_.getPool()->getProperties("cats",
BackendSelector(BackendSelector::Type::MYSQL)));
// Verify that unregistering MySQL factory returns true.
ASSERT_TRUE(config_mgr_.unregisterBackendFactory("mysql"));
// Verify that the factory is actually gone.
ASSERT_THROW(config_mgr_.addBackend("type=mysql"), db::InvalidType);
// Verify we can't remove what is not there.
ASSERT_FALSE(config_mgr_.unregisterBackendFactory("mysql"));
// Try to use the backend that is not present.
EXPECT_THROW(config_mgr_.getPool()->getProperties("cats",
BackendSelector(BackendSelector::Type::MYSQL)),
NoSuchDatabase);
}
}
......@@ -110,6 +110,7 @@ libkea_dhcpsrv_la_SOURCES += cfgmgr.cc cfgmgr.h
libkea_dhcpsrv_la_SOURCES += client_class_def.cc client_class_def.h
libkea_dhcpsrv_la_SOURCES += config_backend_dhcp4.h
libkea_dhcpsrv_la_SOURCES += config_backend_pool_dhcp4.cc config_backend_pool_dhcp4.h
libkea_dhcpsrv_la_SOURCES += config_backend_dhcp4_mgr.cc config_backend_dhcp4_mgr.h
libkea_dhcpsrv_la_SOURCES += csv_lease_file4.cc csv_lease_file4.h
libkea_dhcpsrv_la_SOURCES += csv_lease_file6.cc csv_lease_file6.h
libkea_dhcpsrv_la_SOURCES += d2_client_cfg.cc d2_client_cfg.h
......
......@@ -15,6 +15,7 @@
#include <dhcpsrv/cfg_option.h>
#include <dhcpsrv/shared_network.h>
#include <dhcpsrv/subnet.h>
#include <boost/shared_ptr.hpp>
#include <boost/date_time/posix_time/ptime.hpp>
#include <string>
......@@ -367,6 +368,9 @@ public:
deleteAllGlobalParameters4(const db::ServerSelector& server_selector) = 0;
};
/// @brief Shared pointer to the @c ConfigBackendDHCPv4 instance.
typedef boost::shared_ptr<ConfigBackendDHCPv4> ConfigBackendDHCPv4Ptr;
} // end of namespace isc::dhcp
} // end of namespace 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
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
#include <dhcpsrv/config_backend_dhcp4_mgr.h>
#include <boost/scoped_ptr.hpp>
namespace isc {
namespace dhcp {
boost::scoped_ptr<ConfigBackendDHCPv4Mgr>&
ConfigBackendDHCPv4Mgr::getConfigBackendDHCPv4MgrPtr() {
static boost::scoped_ptr<ConfigBackendDHCPv4Mgr> cb_dhcp4_mgr;
return (cb_dhcp4_mgr);
}
void
ConfigBackendDHCPv4Mgr::create() {
getConfigBackendDHCPv4MgrPtr().reset(new ConfigBackendDHCPv4Mgr());
}
ConfigBackendDHCPv4Mgr&
ConfigBackendDHCPv4Mgr::instance() {
boost::scoped_ptr<ConfigBackendDHCPv4Mgr>& cb_dhcp4_mgr = getConfigBackendDHCPv4MgrPtr();
if (!cb_dhcp4_mgr) {
create();
}
return (*cb_dhcp4_mgr);
}
} // end of isc::dhcp namespace
} // end of isc namespace
// 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_BACKEND_DHCP4_MGR_H
#define CONFIG_BACKEND_DHCP4_MGR_H
#include <config_backend/base_config_backend_mgr.h>
#include <dhcpsrv/config_backend_pool_dhcp4.h>
#include <boost/scoped_ptr.hpp>
namespace isc {
namespace dhcp {
/// @brief Configuration Backend Manager for DHPCv4 servers.
///
/// Implements the "manager" class which holds information about the
/// supported and configured backends and provides access to those
/// backends. This is similar to @c HostMgr and @c LeaseMgr singletons
/// being used by the DHCP servers.
///
/// It is implemented as a singleton that can be accessed from any place
/// within the server code. This includes server configuration, data
/// fetching during normal server operation and data management, including
/// processing of control commands implemented within hooks libraries.
///
/// Unlike @c HostMgr, the it does not directly expose the API to fetch and
/// manipulate the data in the database. This is done via, the Configuration
/// Backend Pool, see @c ConfigBackendPoolDHCPv4 for details.
class ConfigBackendDHCPv4Mgr : public cb::BaseConfigBackendMgr<ConfigBackendPoolDHCPv4>,
public boost::noncopyable {
public:
/// @brief Creates new instance of the @c ConfigBackendDHCPv4Mgr.
///
/// If an instance of the @c ConfigBackendDHCPv4Mgr already exists,
/// it will be replaced by the new instance. Thus, any instances of
/// config databases will be dropped.
static void create();
/// @brief Returns a sole instance of the @c ConfigBackendDHCPv4Mgr.
///
/// This method should be used to retrieve an instance of the @c ConfigBackendDHCPv4Mgr
/// to be used to gather/manage config backends. It returns an instance
/// of the @c ConfigBackendDHCPv4Mgr created by the @c create method. If
/// the instance doesn't exist yet, it is created using the @c create method
/// with the an empty set of configuration databases.
static ConfigBackendDHCPv4Mgr& instance();
private:
/// @brief Private default constructor.
ConfigBackendDHCPv4Mgr() {}
/// @brief Returns a pointer to the currently used instance of the
/// @c ConfigBackendDHCPv4Mgr.
static boost::scoped_ptr<ConfigBackendDHCPv4Mgr>& getConfigBackendDHCPv4MgrPtr();
};
} // end of namespace isc::dhcp
} // end of namespace isc
#endif // CONFIG_BACKEND_DHCP4_MGR_H
......@@ -24,7 +24,7 @@ namespace isc {
namespace dhcp {
/// @brief Implementation of the Configuration Backend Pool for DHCPv4.
class ConfigBackendPoolDHCPv4 : cb::BaseConfigBackendPool<ConfigBackendDHCPv4> {
class ConfigBackendPoolDHCPv4 : public cb::BaseConfigBackendPool<ConfigBackendDHCPv4> {
public:
/// @brief Retrieves a single subnet by subnet_prefix.
......@@ -393,7 +393,7 @@ public:
const db::ServerSelector& server_selector,
const std::string& shared_network_name,
const uint16_t code,
const std::string& space) = 0;
const std::string& space);
/// @brief Deletes subnet level option.
///
......
......@@ -29,6 +29,7 @@ libeval_unittests_CXXFLAGS = $(AM_CXXFLAGS)
libeval_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
libeval_unittests_LDFLAGS = $(AM_LDFLAGS) $(CRYPTO_LDFLAGS) $(GTEST_LDFLAGS)
libeval_unittests_LDADD = $(top_builddir)/src/lib/eval/libkea-eval.la
libeval_unittests_LDADD += $(top_builddir)/src/lib/cc/libkea-cc.la
libeval_unittests_LDADD += $(top_builddir)/src/lib/dhcp/libkea-dhcp++.la
libeval_unittests_LDADD += $(top_builddir)/src/lib/asiolink/libkea-asiolink.la
libeval_unittests_LDADD += $(top_builddir)/src/lib/dns/libkea-dns++.la
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment