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
11#include <dhcpsrv/hosts_log.h>
12#include <log/logger_support.h>
13
14#ifdef HAVE_MYSQL
16#endif
17
18#ifdef HAVE_PGSQL
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
43 const string& dbaccess) {
44 // Parse the access string and create a redacted string for logging.
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
84 const string& db_type) {
85 for (auto it = sources.begin(); it != sources.end(); ++it) {
86 if ((*it)->getType() != db_type) {
87 continue;
88 }
90 .arg(db_type);
91 sources.erase(it);
92 return (true);
93 }
94 return (false);
95}
96
97bool
99 const string& db_type,
100 const string& dbaccess,
101 bool if_unusable) {
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 }
118 .arg((*it)->getType());
119 sources.erase(it);
120 return (true);
121 }
122 return (deleted);
123}
124
125bool
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) {
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) {
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
169 std::stringstream txt;
170
171 for (auto x : map_) {
172 txt << x.first << " ";
173 }
174
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) {
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) {
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
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
A generic exception that is thrown when an unexpected error condition occurs.
static ParameterMap parse(const std::string &dbaccess)
Parse database access string.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
Invalid type exception.
static bool deregisterFactory(const std::string &db_type, bool no_log=false)
Deregister a host data source factory.
static void add(HostDataSourceList &sources, const std::string &dbaccess)
Create and add an instance of a host data source.
static void printRegistered()
Prints out all registered backends.
std::function< HostDataSourcePtr(const db::DatabaseConnection::ParameterMap &)> Factory
Type of host data source factory.
static bool registerFactory(const std::string &db_type, const Factory &factory, bool no_log=false)
Register a host data source factory.
static bool del(HostDataSourceList &sources, const std::string &db_type)
Delete a host data source.
static bool registeredFactory(const std::string &db_type)
Check if a host data source factory was registered.
PostgreSQL Host Data Source.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Logging initialization functions.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
boost::shared_ptr< BaseHostDataSource > HostDataSourcePtr
HostDataSource pointer.
isc::log::Logger hosts_logger("hosts")
Logger for the HostMgr and the code it calls.
Definition: hosts_log.h:51
const isc::log::MessageID HOSTS_BACKEND_DEREGISTER
std::vector< HostDataSourcePtr > HostDataSourceList
HostDataSource list.
const isc::log::MessageID HOSTS_CFG_CLOSE_HOST_DATA_SOURCE
const isc::log::MessageID DHCPSRV_PGSQL_HOST_DB
const isc::log::MessageID HOSTS_BACKEND_REGISTER
const isc::log::MessageID DHCPSRV_MYSQL_HOST_DB
const int DHCPSRV_DBG_TRACE
DHCP server library logging levels.
Definition: dhcpsrv_log.h:26
const isc::log::MessageID HOSTS_BACKENDS_REGISTERED
Defines the logger used by the top-level component of kea-lfc.