Kea 2.7.6
cb_ctl_base.h
Go to the documentation of this file.
1// Copyright (C) 2019-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#ifndef CB_CTL_BASE_H
8#define CB_CTL_BASE_H
9
14#include <process/config_base.h>
16#include <boost/foreach.hpp>
17#include <boost/date_time/posix_time/posix_time.hpp>
18#include <boost/date_time/gregorian/gregorian.hpp>
19#include <process/d_log.h>
20
21namespace isc {
22namespace process {
23
24
81template<typename ConfigBackendMgrType>
83public:
84
90 enum class FetchMode {
93 };
94
103
107 virtual ~CBControlBase() {
109 }
110
120
133 bool databaseConfigConnect(const ConfigPtr& srv_cfg) {
134 // We need to get rid of any existing backends. These would be any
135 // opened by previous configuration cycle.
137
138 // Fetch the config-control info.
139 ConstConfigControlInfoPtr config_ctl = srv_cfg->getConfigControlInfo();
140 if (!config_ctl || config_ctl->getConfigDatabases().empty()) {
141 // No config dbs, nothing to do.
142 return (false);
143 }
144
145 // Iterate over the configured DBs and instantiate them.
146 for (auto const& db : config_ctl->getConfigDatabases()) {
147 const std::string& redacted = db.redactedAccessString();
149 .arg(redacted);
150 try {
151 getMgr().addBackend(db.getAccessString());
152 } catch (const isc::db::DbOpenErrorWithRetry& err) {
154 .arg(redacted).arg(err.what());
155 }
156 }
157
158 // Let the caller know we have opened DBs.
159 return (true);
160 }
161
164 getMgr().delAllBackends();
165 }
166
181 virtual void databaseConfigFetch(const ConfigPtr& srv_cfg,
182 const FetchMode& fetch_mode = FetchMode::FETCH_ALL) {
183 // If the server starts up we need to connect to the database(s).
184 // If there are no databases available simply do nothing.
185 if ((fetch_mode == FetchMode::FETCH_ALL) && !databaseConfigConnect(srv_cfg)) {
186 // There are no CB databases so we're done
187 return;
188 }
189
191
192 // For now we find data based on first backend that has it.
194
195 // Use the server_tag if set, otherwise use ALL.
196 std::string server_tag = srv_cfg->getServerTag();
197 db::ServerSelector server_selector =
198 (server_tag.empty()? db::ServerSelector::ALL() : db::ServerSelector::ONE(server_tag));
199
200 // This collection will hold the audit entries since the last update if
201 // we're running this method to fetch the configuration updates.
202 db::AuditEntryCollection audit_entries;
203
204 // If we're fetching updates we need to retrieve audit entries to see
205 // which objects have to be updated. If we're performing full reconfiguration
206 // we also need audit entries to set the last_audit_revision_time_ to the
207 // time of the most recent audit entry.
208
211
212 // Save the timestamp indicating last audit revision time.
213 auto lb_modification_time = last_audit_revision_time_;
214 // Save the identifier indicating last audit revision id.
215 auto lb_modification_id = last_audit_revision_id_;
216
217 audit_entries = getMgr().getPool()->getRecentAuditEntries(backend_selector,
218 server_selector,
219 lb_modification_time,
220 lb_modification_id);
221 // Store the last audit revision time. It should be set to the most recent
222 // audit entry fetched. If returned audit is empty we don't update.
223 updateLastAuditRevisionTimeId(audit_entries);
224
225 // If this is full reconfiguration we don't need the audit entries anymore.
226 // Let's remove them and proceed as if they don't exist.
227 if (fetch_mode == FetchMode::FETCH_ALL) {
228 audit_entries.clear();
229 }
230
231 // If we fetch the entire config or we're updating the config and there are
232 // audit entries indicating that there are some pending updates, let's
233 // execute the server specific function that fetches and merges the data
234 // into the given configuration.
235 if ((fetch_mode == FetchMode::FETCH_ALL) || !audit_entries.empty()) {
236 try {
237 databaseConfigApply(backend_selector, server_selector,
238 lb_modification_time, audit_entries);
239 } catch (...) {
240 // Revert last audit revision time and id so as we can retry
241 // from the last successful attempt.
244 last_audit_revision_time_ = lb_modification_time;
245 last_audit_revision_id_ = lb_modification_id;
246 throw;
247 }
248 }
249 }
250
251protected:
252
271 const std::string& object_type) const {
273 auto const& index = audit_entries.get<db::AuditEntryObjectTypeTag>();
274 auto range = index.equal_range(object_type);
275 BOOST_FOREACH(auto const& it, range) {
276 if (it->getModificationType() != db::AuditEntry::ModificationType::DELETE) {
277 result.insert(it);
278 }
279 }
280
281 return (result);
282 }
283
311 virtual void databaseConfigApply(const db::BackendSelector& backend_selector,
312 const db::ServerSelector& server_selector,
313 const boost::posix_time::ptime& lb_modification_time,
314 const db::AuditEntryCollection& audit_entries) = 0;
315
320 ConfigBackendMgrType& getMgr() const {
321 return (ConfigBackendMgrType::instance());
322 }
323
328 static boost::posix_time::ptime getInitialAuditRevisionTime() {
329 static boost::posix_time::ptime
330 initial_time(boost::gregorian::date(2000, boost::gregorian::Jan, 1));
331 return (initial_time);
332 }
333
342 // Do nothing if there are no audit entries. It is the case if
343 // there were no updates to the configuration.
344 if (audit_entries.empty()) {
345 return;
346 }
347
348 // Get the audit entries sorted by modification time and id,
349 // and pick the latest entry.
350 auto const& index = audit_entries.get<db::AuditEntryModificationTimeIdTag>();
351 last_audit_revision_time_ = (*index.rbegin())->getModificationTime();
352 last_audit_revision_id_ = (*index.rbegin())->getRevisionId();
353 }
354
356 boost::posix_time::ptime last_audit_revision_time_;
357
365};
366
371inline bool
373 const uint64_t& object_id) {
374 auto const& object_id_idx = audit_entries.get<db::AuditEntryObjectIdTag>();
375 return (object_id_idx.count(object_id) > 0);
376}
377
378} // end of namespace isc::process
379} // end of namespace isc
380
381#endif /* CB_CTL_BASE_H */
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Config Backend selector.
Exception thrown on failure to open database but permit retries.
Server selector for associating objects in a database with specific servers.
static ServerSelector ALL()
Factory returning "all servers" selector.
static ServerSelector ONE(const std::string &server_tag)
Factory returning selector of one server.
Base class for implementing server specific mechanisms to control the use of the Configuration Backen...
Definition cb_ctl_base.h:82
FetchMode
Fetch mode used in invocations to databaseConfigFetch.
Definition cb_ctl_base.h:90
db::AuditEntryCollection fetchConfigElement(const db::AuditEntryCollection &audit_entries, const std::string &object_type) const
Returns audit entries for new or updated configuration elements of specific type to be fetched from t...
bool databaseConfigConnect(const ConfigPtr &srv_cfg)
(Re)connects to the specified configuration backends.
uint64_t last_audit_revision_id_
Stores the most recent audit revision identifier.
virtual void databaseConfigApply(const db::BackendSelector &backend_selector, const db::ServerSelector &server_selector, const boost::posix_time::ptime &lb_modification_time, const db::AuditEntryCollection &audit_entries)=0
Server specific method to fetch and apply back end configuration into the local configuration.
virtual void databaseConfigFetch(const ConfigPtr &srv_cfg, const FetchMode &fetch_mode=FetchMode::FETCH_ALL)
Fetches the entire or partial configuration from the database.
virtual ~CBControlBase()
Virtual destructor.
boost::posix_time::ptime last_audit_revision_time_
Stores the most recent audit revision timestamp.
void reset()
Resets the state of this object.
void databaseConfigDisconnect()
Disconnects from the configuration backends.
void updateLastAuditRevisionTimeId(const db::AuditEntryCollection &audit_entries)
Updates timestamp of the most recent audit entry fetched from the database.
static boost::posix_time::ptime getInitialAuditRevisionTime()
Convenience method returning initial timestamp to set the last_audit_revision_time_ to.
ConfigBackendMgrType & getMgr() const
Returns the instance of the Config Backend Manager used by this object.
#define LOG_INFO(LOGGER, MESSAGE)
Macro to conveniently test info output and log it.
Definition macros.h:20
boost::multi_index_container< AuditEntryPtr, boost::multi_index::indexed_by< boost::multi_index::ordered_non_unique< boost::multi_index::tag< AuditEntryObjectTypeTag >, boost::multi_index::composite_key< AuditEntry, boost::multi_index::const_mem_fun< AuditEntry, std::string, &AuditEntry::getObjectType >, boost::multi_index::const_mem_fun< AuditEntry, AuditEntry::ModificationType, &AuditEntry::getModificationType > > >, boost::multi_index::ordered_non_unique< boost::multi_index::tag< AuditEntryModificationTimeIdTag >, boost::multi_index::composite_key< AuditEntry, boost::multi_index::const_mem_fun< AuditEntry, boost::posix_time::ptime, &AuditEntry::getModificationTime >, boost::multi_index::const_mem_fun< AuditEntry, uint64_t, &AuditEntry::getRevisionId > > >, boost::multi_index::hashed_non_unique< boost::multi_index::tag< AuditEntryObjectIdTag >, boost::multi_index::const_mem_fun< AuditEntry, uint64_t, &AuditEntry::getObjectId > > > > AuditEntryCollection
Multi index container holding AuditEntry instances.
isc::log::Logger dctl_logger("dctl")
Defines the logger used within libkea-process library.
Definition d_log.h:18
bool hasObjectId(const db::AuditEntryCollection &audit_entries, const uint64_t &object_id)
Checks if an object is in a collection od audit entries.
boost::shared_ptr< ConfigBase > ConfigPtr
Non-const pointer to the ConfigBase.
const isc::log::MessageID DCTL_OPEN_CONFIG_DB
const isc::log::MessageID DCTL_CONFIG_FETCH
boost::shared_ptr< const ConfigControlInfo > ConstConfigControlInfoPtr
Defines a pointer to a const ConfigControlInfo.
const isc::log::MessageID DCTL_DB_OPEN_CONNECTION_WITH_RETRY_FAILED
Defines the logger used by the top-level component of kea-lfc.
Tag used to access index by modification time.
Tag used to access index by object id.
Tag used to access index by object type.