Kea  1.9.9-git
host_data_source_factory.cc
Go to the documentation of this file.
1 // Copyright (C) 2015-2021 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>
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 #ifdef HAVE_CQL
24 #endif
25 
26 #include <boost/algorithm/string.hpp>
27 #include <boost/foreach.hpp>
28 #include <boost/scoped_ptr.hpp>
29 
30 #include <algorithm>
31 #include <iostream>
32 #include <iterator>
33 #include <map>
34 #include <sstream>
35 #include <utility>
36 
37 using namespace isc::db;
38 using namespace std;
39 
40 namespace isc {
41 namespace dhcp {
42 
43 map<string, HostDataSourceFactory::Factory> HostDataSourceFactory::map_;
44 
45 void
46 HostDataSourceFactory::add(HostDataSourceList& sources,
47  const string& dbaccess) {
48  // Parse the access string and create a redacted string for logging.
50  DatabaseConnection::parse(dbaccess);
51 
52  // Get the database type and open the corresponding database
53  DatabaseConnection::ParameterMap::iterator it = parameters.find("type");
54  if (it == parameters.end()) {
55  isc_throw(InvalidParameter, "Host database configuration does not "
56  "contain the 'type' keyword");
57  }
58 
59  string db_type = it->second;
60  auto index = map_.find(db_type);
61 
62  // No match?
63  if (index == map_.end()) {
64  if ((db_type == "mysql") ||
65  (db_type == "postgresql") ||
66  (db_type == "cql")) {
67  string with = (db_type == "postgresql" ? "pgsql" : db_type);
68  isc_throw(InvalidType, "The type of host backend: '" << db_type
69  << "' is not compiled in. Did you forget to use --with-"
70  << with << " during compilation?");
71  }
72  isc_throw(InvalidType, "The type of host backend: '" <<
73  db_type << "' is not supported");
74  }
75 
76  // Call the factory and push the pointer on sources.
77  sources.push_back(index->second(parameters));
78 
79  // Check the factory did not return NULL.
80  if (!sources.back()) {
81  sources.pop_back();
82  isc_throw(Unexpected, "Hosts database " << db_type <<
83  " factory returned NULL");
84  }
85 }
86 
87 bool
88 HostDataSourceFactory::del(HostDataSourceList& sources,
89  const string& db_type) {
90  for (auto it = sources.begin(); it != sources.end(); ++it) {
91  if ((*it)->getType() != db_type) {
92  continue;
93  }
95  .arg(db_type);
96  sources.erase(it);
97  return (true);
98  }
99  return (false);
100 }
101 
102 bool
103 HostDataSourceFactory::del(HostDataSourceList& sources,
104  const string& db_type,
105  const string& dbaccess,
106  bool if_unusable) {
108  DatabaseConnection::parse(dbaccess);
109  bool deleted = false;
110  if (if_unusable) {
111  deleted = true;
112  }
113 
114  for (auto it = sources.begin(); it != sources.end(); ++it) {
115  if ((*it)->getType() != db_type || (*it)->getParameters() != parameters) {
116  continue;
117  }
118  if (if_unusable && (!(*it)->isUnusable())) {
119  deleted = false;
120  continue;
121  }
123  .arg((*it)->getType());
124  sources.erase(it);
125  return (true);
126  }
127  return (deleted);
128 }
129 
130 bool
131 HostDataSourceFactory::registerFactory(const string& db_type,
132  const Factory& factory,
133  bool no_log) {
134  if (map_.count(db_type)) {
135  return (false);
136  }
137  map_.insert(pair<string, Factory>(db_type, factory));
138 
139  // We are dealing here with static logger initialization fiasco.
140  // registerFactory may be called from constructors of static global
141  // objects for built in backends. The logging is not initialized yet,
142  // so the LOG_DEBUG would throw.
143  if (!no_log) {
145  .arg(db_type);
146  }
147  return (true);
148 }
149 
150 bool
151 HostDataSourceFactory::deregisterFactory(const string& db_type, bool no_log) {
152  auto index = map_.find(db_type);
153  if (index != map_.end()) {
154  map_.erase(index);
155  if (!no_log) {
158  .arg(db_type);
159  }
160  return (true);
161  } else {
162  return (false);
163  }
164 }
165 
166 bool
167 HostDataSourceFactory::registeredFactory(const std::string& db_type) {
168  auto index = map_.find(db_type);
169  return (index != map_.end());
170 }
171 
172 void
173 HostDataSourceFactory::printRegistered() {
174  std::stringstream txt;
175 
176  for (auto x : map_) {
177  txt << x.first << " ";
178  }
179 
181 }
182 
183 } // namespace dhcp
184 } // namespace isc
185 
186 //
187 // Register database backends
188 //
189 
190 using namespace isc::dhcp;
191 
192 namespace {
193 
194 #ifdef HAVE_MYSQL
195 struct MySqlHostDataSourceInit {
196  // Constructor registers
197  MySqlHostDataSourceInit() {
198  HostDataSourceFactory::registerFactory("mysql", factory, true);
199  }
200 
201  // Destructor deregisters
202  ~MySqlHostDataSourceInit() {
203  HostDataSourceFactory::deregisterFactory("mysql", true);
204  }
205 
206  // Factory class method
207  static HostDataSourcePtr
208  factory(const DatabaseConnection::ParameterMap& parameters) {
211  return (HostDataSourcePtr(new MySqlHostDataSource(parameters)));
212  }
213 };
214 
215 // Database backend will be registered at object initialization
216 MySqlHostDataSourceInit mysql_init_;
217 #endif
218 
219 #ifdef HAVE_PGSQL
220 struct PgSqlHostDataSourceInit {
221  // Constructor registers
222  PgSqlHostDataSourceInit() {
223  HostDataSourceFactory::registerFactory("postgresql", factory, true);
224  }
225 
226  // Destructor deregisters
227  ~PgSqlHostDataSourceInit() {
228  HostDataSourceFactory::deregisterFactory("postgresql", true);
229  }
230 
231  // Factory class method
232  static HostDataSourcePtr
233  factory(const DatabaseConnection::ParameterMap& parameters) {
236  return (HostDataSourcePtr(new PgSqlHostDataSource(parameters)));
237  }
238 };
239 
240 // Database backend will be registered at object initialization
241 PgSqlHostDataSourceInit pgsql_init_;
242 #endif
243 
244 #ifdef HAVE_CQL
245 struct CqlHostDataSourceInit {
246  // Constructor registers
247  CqlHostDataSourceInit() {
248  HostDataSourceFactory::registerFactory("cql", factory, true);
249  }
250 
251  // Destructor deregisters
252  ~CqlHostDataSourceInit() {
253  HostDataSourceFactory::deregisterFactory("cql", true);
254  }
255 
256  // Factory class method
257  static HostDataSourcePtr
258  factory(const DatabaseConnection::ParameterMap& parameters) {
261  return (HostDataSourcePtr(new CqlHostDataSource(parameters)));
262  }
263 };
264 
265 // Database backend will be registered at object initialization
266 CqlHostDataSourceInit cql_init_;
267 #endif
268 
269 } // end of anonymous namespace
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition: macros.h:20
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
STL namespace.
static ParameterMap parse(const std::string &dbaccess)
Parse database access string.
boost::shared_ptr< BaseHostDataSource > HostDataSourcePtr
HostDataSource pointer.
const isc::log::MessageID HOSTS_BACKENDS_REGISTERED
Invalid type exception.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
std::function< HostDataSourcePtr(const db::DatabaseConnection::ParameterMap &)> Factory
Type of host data source factory.
isc::log::Logger hosts_logger("hosts")
Logger for the HostMgr and the code it calls.
Definition: hosts_log.h:51
A generic exception that is thrown when an unexpected error condition occurs.
Defines the logger used by the top-level component of kea-dhcp-ddns.
const isc::log::MessageID DHCPSRV_PGSQL_HOST_DB
Logging initialization functions.
const isc::log::MessageID HOSTS_BACKEND_REGISTER
const isc::log::MessageID DHCPSRV_CQL_HOST_DB
std::vector< HostDataSourcePtr > HostDataSourceList
HostDataSource list.
const isc::log::MessageID HOSTS_BACKEND_DEREGISTER
PostgreSQL Host Data Source.
#define LOG_DEBUG(LOGGER, LEVEL, MESSAGE)
Macro to conveniently test debug output and log it.
Definition: macros.h:14
const int DHCPSRV_DBG_TRACE
DHCP server library logging levels.
Definition: dhcpsrv_log.h:26
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
static std::string redactedAccessString(const ParameterMap &parameters)
Redact database access string.
Cassandra host data source.
const isc::log::MessageID DHCPSRV_MYSQL_HOST_DB
const isc::log::MessageID HOSTS_CFG_CLOSE_HOST_DATA_SOURCE