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