Kea 2.5.8
host_data_source_factory.cc
Go to the documentation of this file.
1// Copyright (C) 2015-2024 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
24#include <algorithm>
25#include <iostream>
26#include <iterator>
27#include <map>
28#include <sstream>
29#include <utility>
30
31using namespace isc::db;
32using namespace std;
33
34namespace isc {
35namespace dhcp {
36
37map<string, HostDataSourceFactory::Factory> HostDataSourceFactory::map_;
38
39void
41 const string& dbaccess) {
42 // Parse the access string and create a redacted string for logging.
45
46 // Get the database type and open the corresponding database
47 DatabaseConnection::ParameterMap::iterator it = parameters.find("type");
48 if (it == parameters.end()) {
49 isc_throw(InvalidParameter, "Host database configuration does not "
50 "contain the 'type' keyword");
51 }
52
53 string db_type = it->second;
54 auto index = map_.find(db_type);
55
56 // No match?
57 if (index == map_.end()) {
58 if ((db_type == "mysql") ||
59 (db_type == "postgresql")) {
60 string with = (db_type == "postgresql" ? "pgsql" : db_type);
61 isc_throw(InvalidType, "The type of host backend: '" << db_type
62 << "' is not compiled in. Did you forget to use --with-"
63 << with << " during compilation?");
64 }
65 isc_throw(InvalidType, "The type of host backend: '" <<
66 db_type << "' is not supported");
67 }
68
69 // Call the factory and push the pointer on sources.
70 sources.push_back(index->second(parameters));
71
72 // Check the factory did not return NULL.
73 if (!sources.back()) {
74 sources.pop_back();
75 isc_throw(Unexpected, "Hosts database " << db_type <<
76 " factory returned NULL");
77 }
78}
79
80bool
82 const string& db_type) {
83 for (auto it = sources.begin(); it != sources.end(); ++it) {
84 if ((*it)->getType() != db_type) {
85 continue;
86 }
88 .arg(db_type);
89 sources.erase(it);
90 return (true);
91 }
92 return (false);
93}
94
95bool
97 const string& db_type,
98 const string& dbaccess,
99 bool if_unusable) {
102 bool deleted = false;
103 if (if_unusable) {
104 deleted = true;
105 }
106
107 for (auto it = sources.begin(); it != sources.end(); ++it) {
108 if ((*it)->getType() != db_type || (*it)->getParameters() != parameters) {
109 continue;
110 }
111 if (if_unusable && (!(*it)->isUnusable())) {
112 deleted = false;
113 continue;
114 }
116 .arg((*it)->getType());
117 sources.erase(it);
118 return (true);
119 }
120 return (deleted);
121}
122
123bool
125 const Factory& factory,
126 bool no_log) {
127 if (map_.count(db_type)) {
128 return (false);
129 }
130 map_.insert(pair<string, Factory>(db_type, factory));
131
132 // We are dealing here with static logger initialization fiasco.
133 // registerFactory may be called from constructors of static global
134 // objects for built in backends. The logging is not initialized yet,
135 // so the LOG_DEBUG would throw.
136 if (!no_log) {
138 .arg(db_type);
139 }
140 return (true);
141}
142
143bool
144HostDataSourceFactory::deregisterFactory(const string& db_type, bool no_log) {
145 auto index = map_.find(db_type);
146 if (index != map_.end()) {
147 map_.erase(index);
148 if (!no_log) {
151 .arg(db_type);
152 }
153 return (true);
154 } else {
155 return (false);
156 }
157}
158
159bool
160HostDataSourceFactory::registeredFactory(const std::string& db_type) {
161 auto index = map_.find(db_type);
162 return (index != map_.end());
163}
164
165void
167 std::stringstream txt;
168
169 for (auto const& x : map_) {
170 txt << x.first << " ";
171 }
172
174}
175
176} // namespace dhcp
177} // namespace isc
178
179//
180// Register database backends
181//
182
183using namespace isc::dhcp;
184
185namespace {
186
187#ifdef HAVE_MYSQL
188struct MySqlHostDataSourceInit {
189 // Constructor registers
190 MySqlHostDataSourceInit() {
191 HostDataSourceFactory::registerFactory("mysql", factory, true);
192 }
193
194 // Destructor deregisters
195 ~MySqlHostDataSourceInit() {
197 }
198
199 // Factory class method
200 static HostDataSourcePtr
201 factory(const DatabaseConnection::ParameterMap& parameters) {
204 return (HostDataSourcePtr(new MySqlHostDataSource(parameters)));
205 }
206};
207
208// Database backend will be registered at object initialization
209MySqlHostDataSourceInit mysql_init_;
210#endif
211
212#ifdef HAVE_PGSQL
213struct PgSqlHostDataSourceInit {
214 // Constructor registers
215 PgSqlHostDataSourceInit() {
216 HostDataSourceFactory::registerFactory("postgresql", factory, true);
217 }
218
219 // Destructor deregisters
220 ~PgSqlHostDataSourceInit() {
222 }
223
224 // Factory class method
225 static HostDataSourcePtr
226 factory(const DatabaseConnection::ParameterMap& parameters) {
229 return (HostDataSourcePtr(new PgSqlHostDataSource(parameters)));
230 }
231};
232
233// Database backend will be registered at object initialization
234PgSqlHostDataSourceInit pgsql_init_;
235#endif
236
237} // 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 std::string redactedAccessString(const ParameterMap &parameters)
Redact database access string.
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.