Kea 2.7.8
legal_log_mgr_factory.cc
Go to the documentation of this file.
1// Copyright (C) 2025 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
10#include <dhcpsrv/dhcpsrv_log.h>
11
12using namespace isc::db;
13using namespace std;
14
15namespace isc {
16namespace dhcp {
17
19map<string, pair<LegalLogMgrFactory::Factory, LegalLogMgrFactory::DBVersion>> LegalLogMgrFactory::map_;
21
22bool
24 const Factory& factory,
25 bool no_log,
26 DBVersion db_version) {
27 if (map_.count(db_type)) {
28 return (false);
29 }
30
31 static auto default_db_version = []() -> string {
32 return (string());
33 };
34
35 if (!db_version) {
36 db_version = default_db_version;
37 }
38
39 map_.insert(pair<string, pair<Factory, DBVersion>>(db_type, pair<Factory, DBVersion>(factory, db_version)));
40
41 // We are dealing here with static logger initialization fiasco.
42 // registerFactory may be called from constructors of static global
43 // objects for built in backends. The logging is not initialized yet,
44 // so the LOG_DEBUG would throw.
45 if (!no_log) {
47 .arg(db_type);
48 }
49 return (true);
50}
51
52bool
53LegalLogMgrFactory::unregisterBackendFactory(const string& db_type, bool no_log) {
54 // Look for it.
55 auto index = map_.find(db_type);
56
57 // If it's there remove it
58 if (index != map_.end()) {
59 map_.erase(index);
60 delAllBackends(db_type);
61 if (!no_log) {
64 .arg(db_type);
65 }
66 return (true);
67 }
68 return (false);
69}
70
71void
73 // Get the database type to locate a factory function.
74 auto it = parameters.find("type");
75 if (it == parameters.end()) {
76 isc_throw(InvalidParameter, "Forensic log backend specification lacks the "
77 "'type' keyword");
78 }
79
80 string db_type = it->second;
81 auto index = map_.find(db_type);
82
83 // No match?
84 if (index == map_.end()) {
85 if ((db_type == "mysql") || (db_type == "postgresql")) {
86 string with = (db_type == "postgresql" ? "pgsql" : db_type);
87 isc_throw(InvalidType, "The Kea server has not been compiled with "
88 "support for configuration database type: " << db_type
89 << ". Did you forget to use --with-"
90 << with << " during compilation or to load libdhcp_"
91 << with << " hook library?");
92 }
93 isc_throw(InvalidType, "The type of the forensic log backend: '" <<
94 db_type << "' is not supported");
95 }
96
97 // Call the factory and push the pointer on sources.
98 auto backend = index->second.first(parameters);
99 if (!backend) {
100 isc_throw(Unexpected, "Forensic log backend " << db_type <<
101 " factory returned NULL");
102 }
103
104 // Add the parameters and an empty instance in case retry on startup is configured.
105 pool_[id] = pair<DatabaseConnection::ParameterMap, LegalLogMgrPtr>(parameters, LegalLogMgrPtr());
106
107 backend->open();
108
109 // Apply extra parameters.
110 if (parameters.find("request-parser-format") != parameters.end()) {
111 backend->setRequestFormatExpression(parameters["request-parser-format"]);
112 }
113 if (parameters.find("response-parser-format") != parameters.end()) {
114 backend->setResponseFormatExpression(parameters["response-parser-format"]);
115 }
116 if (parameters.find("timestamp-format") != parameters.end()) {
117 backend->setTimestampFormat(parameters["timestamp-format"]);
118 }
119
120 // Backend instance created successfully.
121 pool_[id] = pair<DatabaseConnection::ParameterMap, LegalLogMgrPtr>(parameters, backend);
122}
123
124void
128
129void
130LegalLogMgrFactory::delAllBackends(const std::string& db_type) {
131 auto it = pool_.begin();
132
133 while (it != pool_.end()) {
134 if (it->second.second && it->second.second->getType() == db_type) {
135 it = pool_.erase(it);
136 } else {
137 ++it;
138 }
139 }
140}
141
144 auto it = pool_.find(id);
145 if (it != pool_.end()) {
146 return (it->second.second);
147 }
148 // Usually the unit tests do not create the instances using LegalLogMgrFactory::addBackend or by
149 // calling parseConfig or parseDatabase or parseFile, so an empty instance must be returned when
150 // calling LegalLogMgrFactory::instance() - this function returns a reference, so it can not be
151 // created on the stack, it must be stored as a static variable.
152 static LegalLogMgrPtr backend;
153 if (!id) {
155 pool_[id] = pair<DatabaseConnection::ParameterMap, LegalLogMgrPtr>(parameters, backend);
156 return (pool_[id].second);
157 }
158 return (backend);
159}
160
161void
163 // Call LegalLogMgrFactory::instance first so that unit tests can have access to the empty
164 // entry in the pool.
166 auto it = pool_.find(id);
167 if (it != pool_.end()) {
168 it->second.first = parameters;
169 return;
170 }
171}
172
175 auto it = pool_.find(id);
176 if (it != pool_.end()) {
177 return (it->second.first);
178 }
180}
181
182bool
183LegalLogMgrFactory::delBackend(const string& db_type,
185 bool if_unusable) {
186 bool deleted = false;
187 if (if_unusable) {
188 deleted = true;
189 }
190
191 for (auto it = pool_.begin(); it != pool_.end(); ++it) {
192 if (!it->second.second || it->second.second->getType() != db_type || it->second.first != parameters) {
193 continue;
194 }
195 if (if_unusable && (!(it->second.second->isUnusable()))) {
196 deleted = false;
197 continue;
198 }
199 it->second.second = LegalLogMgrPtr();
200 return (true);
201 }
202 return (deleted);
203}
204
205bool
207 bool if_unusable) {
208 bool deleted = false;
209 if (if_unusable) {
210 deleted = true;
211 }
212
213 auto it = pool_.find(id);
214 if (it != pool_.end()) {
215 if (if_unusable && it->second.second && !it->second.second->isUnusable()) {
216 return (false);
217 }
218 it->second.second = LegalLogMgrPtr();
219 return (true);
220 }
221 return (deleted);
222}
223
224bool
226 auto index = map_.find(db_type);
227 return (index != map_.end());
228}
229
230void
232 stringstream txt;
233
234 for (auto const& x : map_) {
235 if (!txt.str().empty()) {
236 txt << " ";
237 }
238 txt << x.first;
239 }
240
242 .arg(txt.str());
243}
244
245list<string>
247 list<string> result;
248 for (auto const& x : map_) {
249 auto version = x.second.second();
250 if (!version.empty()) {
251 result.push_back(version);
252 }
253 }
254
255 return (result);
256}
257
258bool
260 for (auto const& backend : pool_) {
261 if (backend.second.second && backend.second.second->getType() == type) {
262 return (true);
263 }
264 }
265 return (false);
266}
267
268} // end of namespace isc::dhcp
269} // end of namespace isc
270
int version()
returns Kea hooks version.
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.
std::map< std::string, std::string > ParameterMap
Database configuration parameter map.
Invalid type exception.
static std::map< std::string, std::pair< LegalLogMgrFactory::Factory, LegalLogMgrFactory::DBVersion > > map_
A map holding registered backend factory functions.
static bool unregisterBackendFactory(const std::string &db_type, bool no_log=false)
Unregisters the backend factory function for a given backend type.
static void addBackend(db::DatabaseConnection::ParameterMap &parameters, ManagerID id=0)
Create an instance of a forensic log backend.
static void delAllBackends()
Removes all backends from the pool.
static bool registerBackendFactory(const std::string &db_type, const Factory &factory, bool no_log=false, DBVersion db_version=DBVersion())
Registers new backend factory function for a given backend type.
static LegalLogMgrPool pool_
Pointer to the forensic log backends pool.
static isc::db::DatabaseConnection::ParameterMap getParameters(ManagerID id=0)
Gets the forensic backend manager parameters.
static void logRegistered()
Logs out all registered backends.
static bool delBackend(const std::string &db_type, db::DatabaseConnection::ParameterMap &parameters, bool if_unusable=false)
Delete a forensic backend manager.
static bool registeredFactory(const std::string &db_type)
Check if a backend store factory was registered.
static LegalLogMgrPtr & instance(ManagerID id=0)
Returns the forensic backend manager with specified ID.
static std::list< std::string > getDBVersions()
Return extended version info for registered backends.
static bool haveInstance(std::string type)
Returns true is respective backend store is present, false otherwise.
static void setParameters(isc::db::DatabaseConnection::ParameterMap parameters, ManagerID id=0)
Sets the forensic backend manager parameters.
static isc::asiolink::IOServicePtr io_service_
The hook I/O service.
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
#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
isc::log::Logger dhcpsrv_logger("dhcpsrv")
DHCP server library Logger.
Definition dhcpsrv_log.h:56
const isc::log::MessageID DHCPSRV_FORENSIC_BACKEND_REGISTER
const isc::log::MessageID DHCPSRV_FORENSIC_BACKENDS_REGISTERED
boost::shared_ptr< LegalLogMgr > LegalLogMgrPtr
Defines a smart pointer to a LegalLogMgr.
const isc::log::MessageID DHCPSRV_FORENSIC_BACKEND_DEREGISTER
std::map< ManagerID, std::pair< isc::db::DatabaseConnection::ParameterMap, LegalLogMgrPtr > > LegalLogMgrPool
LegalLogMgr pool.
uint64_t ManagerID
Manger ID used by hook libraries to retrieve respective LegalLogMgr instance.
const int DHCPSRV_DBG_TRACE
DHCP server library logging levels.
Definition dhcpsrv_log.h:26
Defines the logger used by the top-level component of kea-lfc.