diff options
Diffstat (limited to 'src/lib/dhcpsrv/host_data_source_factory.cc')
-rw-r--r-- | src/lib/dhcpsrv/host_data_source_factory.cc | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/src/lib/dhcpsrv/host_data_source_factory.cc b/src/lib/dhcpsrv/host_data_source_factory.cc new file mode 100644 index 0000000..6f6141d --- /dev/null +++ b/src/lib/dhcpsrv/host_data_source_factory.cc @@ -0,0 +1,239 @@ +// Copyright (C) 2015-2022 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/dhcpsrv_log.h> +#include <dhcpsrv/host_data_source_factory.h> +#include <dhcpsrv/hosts_log.h> +#include <log/logger_support.h> + +#ifdef HAVE_MYSQL +#include <dhcpsrv/mysql_host_data_source.h> +#endif + +#ifdef HAVE_PGSQL +#include <dhcpsrv/pgsql_host_data_source.h> +#endif + +#include <boost/algorithm/string.hpp> +#include <boost/foreach.hpp> +#include <boost/scoped_ptr.hpp> + +#include <algorithm> +#include <iostream> +#include <iterator> +#include <map> +#include <sstream> +#include <utility> + +using namespace isc::db; +using namespace std; + +namespace isc { +namespace dhcp { + +map<string, HostDataSourceFactory::Factory> HostDataSourceFactory::map_; + +void +HostDataSourceFactory::add(HostDataSourceList& sources, + const string& dbaccess) { + // Parse the access string and create a redacted string for logging. + DatabaseConnection::ParameterMap parameters = + DatabaseConnection::parse(dbaccess); + + // Get the database type and open the corresponding database + DatabaseConnection::ParameterMap::iterator it = parameters.find("type"); + if (it == parameters.end()) { + isc_throw(InvalidParameter, "Host database configuration does not " + "contain the 'type' keyword"); + } + + string db_type = it->second; + auto index = map_.find(db_type); + + // No match? + if (index == map_.end()) { + if ((db_type == "mysql") || + (db_type == "postgresql")) { + string with = (db_type == "postgresql" ? "pgsql" : db_type); + isc_throw(InvalidType, "The type of host backend: '" << db_type + << "' is not compiled in. Did you forget to use --with-" + << with << " during compilation?"); + } + isc_throw(InvalidType, "The type of host backend: '" << + db_type << "' is not supported"); + } + + // Call the factory and push the pointer on sources. + sources.push_back(index->second(parameters)); + + // Check the factory did not return NULL. + if (!sources.back()) { + sources.pop_back(); + isc_throw(Unexpected, "Hosts database " << db_type << + " factory returned NULL"); + } +} + +bool +HostDataSourceFactory::del(HostDataSourceList& sources, + const string& db_type) { + for (auto it = sources.begin(); it != sources.end(); ++it) { + if ((*it)->getType() != db_type) { + continue; + } + LOG_DEBUG(hosts_logger, DHCPSRV_DBG_TRACE, HOSTS_CFG_CLOSE_HOST_DATA_SOURCE) + .arg(db_type); + sources.erase(it); + return (true); + } + return (false); +} + +bool +HostDataSourceFactory::del(HostDataSourceList& sources, + const string& db_type, + const string& dbaccess, + bool if_unusable) { + DatabaseConnection::ParameterMap parameters = + DatabaseConnection::parse(dbaccess); + bool deleted = false; + if (if_unusable) { + deleted = true; + } + + for (auto it = sources.begin(); it != sources.end(); ++it) { + if ((*it)->getType() != db_type || (*it)->getParameters() != parameters) { + continue; + } + if (if_unusable && (!(*it)->isUnusable())) { + deleted = false; + continue; + } + LOG_DEBUG(hosts_logger, DHCPSRV_DBG_TRACE, HOSTS_CFG_CLOSE_HOST_DATA_SOURCE) + .arg((*it)->getType()); + sources.erase(it); + return (true); + } + return (deleted); +} + +bool +HostDataSourceFactory::registerFactory(const string& db_type, + const Factory& factory, + bool no_log) { + if (map_.count(db_type)) { + return (false); + } + map_.insert(pair<string, Factory>(db_type, factory)); + + // We are dealing here with static logger initialization fiasco. + // registerFactory may be called from constructors of static global + // objects for built in backends. The logging is not initialized yet, + // so the LOG_DEBUG would throw. + if (!no_log) { + LOG_DEBUG(hosts_logger, DHCPSRV_DBG_TRACE, HOSTS_BACKEND_REGISTER) + .arg(db_type); + } + return (true); +} + +bool +HostDataSourceFactory::deregisterFactory(const string& db_type, bool no_log) { + auto index = map_.find(db_type); + if (index != map_.end()) { + map_.erase(index); + if (!no_log) { + LOG_DEBUG(hosts_logger, DHCPSRV_DBG_TRACE, + HOSTS_BACKEND_DEREGISTER) + .arg(db_type); + } + return (true); + } else { + return (false); + } +} + +bool +HostDataSourceFactory::registeredFactory(const std::string& db_type) { + auto index = map_.find(db_type); + return (index != map_.end()); +} + +void +HostDataSourceFactory::printRegistered() { + std::stringstream txt; + + for (auto x : map_) { + txt << x.first << " "; + } + + LOG_INFO(hosts_logger, HOSTS_BACKENDS_REGISTERED).arg(txt.str()); +} + +} // namespace dhcp +} // namespace isc + +// +// Register database backends +// + +using namespace isc::dhcp; + +namespace { + +#ifdef HAVE_MYSQL +struct MySqlHostDataSourceInit { + // Constructor registers + MySqlHostDataSourceInit() { + HostDataSourceFactory::registerFactory("mysql", factory, true); + } + + // Destructor deregisters + ~MySqlHostDataSourceInit() { + HostDataSourceFactory::deregisterFactory("mysql", true); + } + + // Factory class method + static HostDataSourcePtr + factory(const DatabaseConnection::ParameterMap& parameters) { + LOG_INFO(hosts_logger, DHCPSRV_MYSQL_HOST_DB) + .arg(DatabaseConnection::redactedAccessString(parameters)); + return (HostDataSourcePtr(new MySqlHostDataSource(parameters))); + } +}; + +// Database backend will be registered at object initialization +MySqlHostDataSourceInit mysql_init_; +#endif + +#ifdef HAVE_PGSQL +struct PgSqlHostDataSourceInit { + // Constructor registers + PgSqlHostDataSourceInit() { + HostDataSourceFactory::registerFactory("postgresql", factory, true); + } + + // Destructor deregisters + ~PgSqlHostDataSourceInit() { + HostDataSourceFactory::deregisterFactory("postgresql", true); + } + + // Factory class method + static HostDataSourcePtr + factory(const DatabaseConnection::ParameterMap& parameters) { + LOG_INFO(hosts_logger, DHCPSRV_PGSQL_HOST_DB) + .arg(DatabaseConnection::redactedAccessString(parameters)); + return (HostDataSourcePtr(new PgSqlHostDataSource(parameters))); + } +}; + +// Database backend will be registered at object initialization +PgSqlHostDataSourceInit pgsql_init_; +#endif + +} // end of anonymous namespace |