Kea: host_data_source_factory.cc Source File

| Kea 2.2.0

host_data_source_factory.cc
Go to the documentation of this file.
1// Copyright (C) 2015-2022 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <dhcpsrv/dhcpsrv_log.h>
10#include <dhcpsrv/host_data_source_factory.h>
11#include <dhcpsrv/hosts_log.h>
12#include <log/logger_support.h>
13
14#ifdef HAVE_MYSQL
15#include <dhcpsrv/mysql_host_data_source.h>
16#endif
17
18#ifdef HAVE_PGSQL
19#include <dhcpsrv/pgsql_host_data_source.h>
20#endif
21
22#include <boost/algorithm/string.hpp>
23#include <boost/foreach.hpp>
24#include <boost/scoped_ptr.hpp>
25
26#include <algorithm>
27#include <iostream>
28#include <iterator>
29#include <map>
30#include <sstream>
31#include <utility>
32
33using namespace isc::db;
34using namespace std;
35
36namespace isc {
37namespace dhcp {
38
39map<string, HostDataSourceFactory::Factory> HostDataSourceFactory::map_;
40
41void
42HostDataSourceFactory::add(HostDataSourceList& sources,
43 const string& dbaccess) {
44 // Parse the access string and create a redacted string for logging.
45 DatabaseConnection::ParameterMap parameters =
46 DatabaseConnection::parse(dbaccess);
47
48 // Get the database type and open the corresponding database
49 DatabaseConnection::ParameterMap::iterator it = parameters.find("type");
50 if (it == parameters.end()) {
51 isc_throw(InvalidParameter, "Host database configuration does not "
52 "contain the 'type' keyword");
53 }
54
55 string db_type = it->second;
56 auto index = map_.find(db_type);
57
58 // No match?
59 if (index == map_.end()) {
60 if ((db_type == "mysql") ||
61 (db_type == "postgresql")) {
62 string with = (db_type == "postgresql" ? "pgsql" : db_type);
63 isc_throw(InvalidType, "The type of host backend: '" << db_type
64 << "' is not compiled in. Did you forget to use --with-"
65 << with << " during compilation?");
66 }
67 isc_throw(InvalidType, "The type of host backend: '" <<
68 db_type << "' is not supported");
69 }
70
71 // Call the factory and push the pointer on sources.
72 sources.push_back(index->second(parameters));
73
74 // Check the factory did not return NULL.
75 if (!sources.back()) {
76 sources.pop_back();
77 isc_throw(Unexpected, "Hosts database " << db_type <<
78 " factory returned NULL");
79 }
80}
81
82bool
83HostDataSourceFactory::del(HostDataSourceList& sources,
84 const string& db_type) {
85 for (auto it = sources.begin(); it != sources.end(); ++it) {
86 if ((*it)->getType() != db_type) {
87 continue;
88 }
89 LOG_DEBUG(hosts_logger, DHCPSRV_DBG_TRACE, HOSTS_CFG_CLOSE_HOST_DATA_SOURCE)
90 .arg(db_type);
91 sources.erase(it);
92 return (true);
93 }
94 return (false);
95}
96
97bool
98 HostDataSourceFactory::del(HostDataSourceList& sources,
99 const string& db_type,
100 const string& dbaccess,
101 bool if_unusable) {
102 DatabaseConnection::ParameterMap parameters =
103 DatabaseConnection::parse(dbaccess);
104 bool deleted = false;
105 if (if_unusable) {
106 deleted = true;
107 }
108
109 for (auto it = sources.begin(); it != sources.end(); ++it) {
110 if ((*it)->getType() != db_type || (*it)->getParameters() != parameters) {
111 continue;
112 }
113 if (if_unusable && (!(*it)->isUnusable())) {
114 deleted = false;
115 continue;
116 }
117 LOG_DEBUG(hosts_logger, DHCPSRV_DBG_TRACE, HOSTS_CFG_CLOSE_HOST_DATA_SOURCE)
118 .arg((*it)->getType());
119 sources.erase(it);
120 return (true);
121 }
122 return (deleted);
123}
124
125bool
126HostDataSourceFactory::registerFactory(const string& db_type,
127 const Factory& factory,
128 bool no_log) {
129 if (map_.count(db_type)) {
130 return (false);
131 }
132 map_.insert(pair<string, Factory>(db_type, factory));
133
134 // We are dealing here with static logger initialization fiasco.
135 // registerFactory may be called from constructors of static global
136 // objects for built in backends. The logging is not initialized yet,
137 // so the LOG_DEBUG would throw.
138 if (!no_log) {
139 LOG_DEBUG(hosts_logger, DHCPSRV_DBG_TRACE, HOSTS_BACKEND_REGISTER)
140 .arg(db_type);
141 }
142 return (true);
143}
144
145bool
146HostDataSourceFactory::deregisterFactory(const string& db_type, bool no_log) {
147 auto index = map_.find(db_type);
148 if (index != map_.end()) {
149 map_.erase(index);
150 if (!no_log) {
151 LOG_DEBUG(hosts_logger, DHCPSRV_DBG_TRACE,
152 HOSTS_BACKEND_DEREGISTER)
153 .arg(db_type);
154 }
155 return (true);
156 } else {
157 return (false);
158 }
159}
160
161bool
162HostDataSourceFactory::registeredFactory(const std::string& db_type) {
163 auto index = map_.find(db_type);
164 return (index != map_.end());
165}
166
167void
168HostDataSourceFactory::printRegistered() {
169 std::stringstream txt;
170
171 for (auto x : map_) {
172 txt << x.first << " ";
173 }
174
175 LOG_INFO(hosts_logger, HOSTS_BACKENDS_REGISTERED).arg(txt.str());
176}
177
178} // namespace dhcp
179} // namespace isc
180
181//
182// Register database backends
183//
184
185using namespace isc::dhcp;
186
187namespace {
188
189#ifdef HAVE_MYSQL
190struct MySqlHostDataSourceInit {
191 // Constructor registers
192 MySqlHostDataSourceInit() {
193 HostDataSourceFactory::registerFactory("mysql", factory, true);
194 }
195
196 // Destructor deregisters
197 ~MySqlHostDataSourceInit() {
198 HostDataSourceFactory::deregisterFactory("mysql", true);
199 }
200
201 // Factory class method
202 static HostDataSourcePtr
203 factory(const DatabaseConnection::ParameterMap& parameters) {
204 LOG_INFO(hosts_logger, DHCPSRV_MYSQL_HOST_DB)
205 .arg(DatabaseConnection::redactedAccessString(parameters));
206 return (HostDataSourcePtr(new MySqlHostDataSource(parameters)));
207 }
208};
209
210// Database backend will be registered at object initialization
211MySqlHostDataSourceInit mysql_init_;
212#endif
213
214#ifdef HAVE_PGSQL
215struct PgSqlHostDataSourceInit {
216 // Constructor registers
217 PgSqlHostDataSourceInit() {
218 HostDataSourceFactory::registerFactory("postgresql", factory, true);
219 }
220
221 // Destructor deregisters
222 ~PgSqlHostDataSourceInit() {
223 HostDataSourceFactory::deregisterFactory("postgresql", true);
224 }
225
226 // Factory class method
227 static HostDataSourcePtr
228 factory(const DatabaseConnection::ParameterMap& parameters) {
229 LOG_INFO(hosts_logger, DHCPSRV_PGSQL_HOST_DB)
230 .arg(DatabaseConnection::redactedAccessString(parameters));
231 return (HostDataSourcePtr(new PgSqlHostDataSource(parameters)));
232 }
233};
234
235// Database backend will be registered at object initialization
236PgSqlHostDataSourceInit pgsql_init_;
237#endif
238
239} // end of anonymous namespace
isc::InvalidParameter
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
Definition: exceptions/exceptions.h:124
isc::Unexpected
A generic exception that is thrown when an unexpected error condition occurs.
Definition: exceptions/exceptions.h:153
isc::db::DatabaseConnection::parse
static ParameterMap parse(const std::string &dbaccess)
Parse database access string.
Definition: database_connection.cc:39
isc::db::DatabaseConnection::ParameterMap
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
Definition: database_connection.h:115
isc::db::InvalidType
Invalid type exception.
Definition: database_connection.h:56
isc::dhcp::HostDataSourceFactory::deregisterFactory
static bool deregisterFactory(const std::string &db_type, bool no_log=false)
Deregister a host data source factory.
Definition: host_data_source_factory.cc:146
isc::dhcp::HostDataSourceFactory::add
static void add(HostDataSourceList &sources, const std::string &dbaccess)
Create and add an instance of a host data source.
Definition: host_data_source_factory.cc:42
isc::dhcp::HostDataSourceFactory::printRegistered
static void printRegistered()
Prints out all registered backends.
Definition: host_data_source_factory.cc:168
isc::dhcp::HostDataSourceFactory::Factory
std::function< HostDataSourcePtr(const db::DatabaseConnection::ParameterMap &)> Factory
Type of host data source factory.
Definition: host_data_source_factory.h:101
isc::dhcp::HostDataSourceFactory::registerFactory
static bool registerFactory(const std::string &db_type, const Factory &factory, bool no_log=false)
Register a host data source factory.
Definition: host_data_source_factory.cc:126
isc::dhcp::HostDataSourceFactory::del
static bool del(HostDataSourceList &sources, const std::string &db_type)
Delete a host data source.
Definition: host_data_source_factory.cc:83
isc::dhcp::HostDataSourceFactory::registeredFactory
static bool registeredFactory(const std::string &db_type)
Check if a host data source factory was registered.
Definition: host_data_source_factory.cc:162
isc::dhcp::MySqlHostDataSource
MySQL Host Data Source.
Definition: mysql_host_data_source.h:40
isc::dhcp::PgSqlHostDataSource
PostgreSQL Host Data Source.
Definition: pgsql_host_data_source.h:45
dhcpsrv_log.h
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:210
host_data_source_factory.h
hosts_log.h
logger_support.h
Logging initialization functions.
LOG_INFO
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
LOG_DEBUG
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
mysql_host_data_source.h
isc::db
Definition: audit_entry.cc:14
isc::dhcp
Definition: dhcp4/client_handler.cc:20
isc::dhcp::HostDataSourcePtr
boost::shared_ptr< BaseHostDataSource > HostDataSourcePtr
HostDataSource pointer.
Definition: base_host_data_source.h:514
isc::dhcp::hosts_logger
isc::log::Logger hosts_logger("hosts")
Logger for the HostMgr and the code it calls.
Definition: hosts_log.h:51
isc::dhcp::HOSTS_BACKEND_DEREGISTER
const isc::log::MessageID HOSTS_BACKEND_DEREGISTER
Definition: hosts_messages.h:12
isc::dhcp::HostDataSourceList
std::vector< HostDataSourcePtr > HostDataSourceList
HostDataSource list.
Definition: base_host_data_source.h:517
isc::dhcp::HOSTS_CFG_CLOSE_HOST_DATA_SOURCE
const isc::log::MessageID HOSTS_CFG_CLOSE_HOST_DATA_SOURCE
Definition: hosts_messages.h:16
isc::dhcp::DHCPSRV_PGSQL_HOST_DB
const isc::log::MessageID DHCPSRV_PGSQL_HOST_DB
Definition: dhcpsrv_messages.h:202
isc::dhcp::HOSTS_BACKEND_REGISTER
const isc::log::MessageID HOSTS_BACKEND_REGISTER
Definition: hosts_messages.h:13
isc::dhcp::DHCPSRV_MYSQL_HOST_DB
const isc::log::MessageID DHCPSRV_MYSQL_HOST_DB
Definition: dhcpsrv_messages.h:153
isc::dhcp::DHCPSRV_DBG_TRACE
const int DHCPSRV_DBG_TRACE
DHCP server library logging levels.
Definition: dhcpsrv_log.h:26
isc::dhcp::HOSTS_BACKENDS_REGISTERED
const isc::log::MessageID HOSTS_BACKENDS_REGISTERED
Definition: hosts_messages.h:11
isc
Defines the logger used by the top-level component of kea-lfc.
Definition: agent_parser.cc:143
pgsql_host_data_source.h