// 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();
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());
}
}
+
// Rollback changes as the configuration parsing failed.
if (rollback) {
// Revert to original configuration of runtime option definitions
#include <config.h>
#include <hooks/hooks.h>
+#include <mysql_cb_dhcp4.h>
using namespace isc::hooks;
///
/// @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);
}
///
/// @return 0 if deregistration was successful, 1 otherwise
int unload() {
+
+ // Unregister the factory and remove MySQL backends
+ isc::dhcp::MySqlConfigBackendDHCPv4::unregisterBackendType();
return (0);
}
#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>
///
/// @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)
/// @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()),
/// @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 = {
/// @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,
/// @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 = {
}
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,
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)
}
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));
}
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
/// @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
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)
--- /dev/null
+// 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);
+}
+
+}
#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>
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
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);
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.
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);
}
+}
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
#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>
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
--- /dev/null
+// 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
--- /dev/null
+// 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
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.
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.
///
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