Kea  2.1.7-git
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>
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 
33 using namespace isc::db;
34 using namespace std;
35 
36 namespace isc {
37 namespace dhcp {
38 
39 map<string, HostDataSourceFactory::Factory> HostDataSourceFactory::map_;
40 
41 void
42 HostDataSourceFactory::add(HostDataSourceList& sources,
43  const string& dbaccess) {
44  // Parse the access string and create a redacted string for logging.
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 
82 bool
83 HostDataSourceFactory::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  }
90  .arg(db_type);
91  sources.erase(it);
92  return (true);
93  }
94  return (false);
95 }
96 
97 bool
98 HostDataSourceFactory::del(HostDataSourceList& sources,
99  const string& db_type,
100  const string& dbaccess,
101  bool if_unusable) {
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  }
118  .arg((*it)->getType());
119  sources.erase(it);
120  return (true);
121  }
122  return (deleted);
123 }
124 
125 bool
126 HostDataSourceFactory::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) {
140  .arg(db_type);
141  }
142  return (true);
143 }
144 
145 bool
146 HostDataSourceFactory::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 
161 bool
162 HostDataSourceFactory::registeredFactory(const std::string& db_type) {
163  auto index = map_.find(db_type);
164  return (index != map_.end());
165 }
166 
167 void
168 HostDataSourceFactory::printRegistered() {
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 
185 using namespace isc::dhcp;
186 
187 namespace {
188 
189 #ifdef HAVE_MYSQL
190 struct 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) {
206  return (HostDataSourcePtr(new MySqlHostDataSource(parameters)));
207  }
208 };
209 
210 // Database backend will be registered at object initialization
211 MySqlHostDataSourceInit mysql_init_;
212 #endif
213 
214 #ifdef HAVE_PGSQL
215 struct 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) {
231  return (HostDataSourcePtr(new PgSqlHostDataSource(parameters)));
232  }
233 };
234 
235 // Database backend will be registered at object initialization
236 PgSqlHostDataSourceInit pgsql_init_;
237 #endif
238 
239 } // 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-lfc.
const isc::log::MessageID DHCPSRV_PGSQL_HOST_DB
Logging initialization functions.
const isc::log::MessageID HOSTS_BACKEND_REGISTER
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.
const isc::log::MessageID DHCPSRV_MYSQL_HOST_DB
const isc::log::MessageID HOSTS_CFG_CLOSE_HOST_DATA_SOURCE