Kea 3.3.2
cb_ctl_base.h
Go to the documentation of this file.
1// Copyright (C) 2019-2026 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
80template<typename ConfigBackendMgrType>
82public:
83
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_UPDATE && !databaseConfigConnect(srv_cfg)) {
186 // There are no CB databases so we're done
187 return;
188 }
189
190 if (fetch_mode == FetchMode::FETCH_NONE) {
191 return;
192 }
193
195
196 // For now we find data based on first backend that has it.
198
199 // Use the server_tag if set, otherwise use ALL.
200 std::string server_tag = srv_cfg->getServerTag();
201 db::ServerSelector server_selector =
202 (server_tag.empty()? db::ServerSelector::ALL() : db::ServerSelector::ONE(server_tag));
203
204 // This collection will hold the audit entries since the last update if
205 // we're running this method to fetch the configuration updates.
206 db::AuditEntryCollection audit_entries;
207
208 // If we're fetching updates we need to retrieve audit entries to see
209 // which objects have to be updated. If we're performing full reconfiguration
210 // we also need audit entries to set the last_audit_revision_time_ to the
211 // time of the most recent audit entry.
212
215
216 // Save the timestamp indicating last audit revision time.
217 auto lb_modification_time = last_audit_revision_time_;
218 // Save the identifier indicating last audit revision id.
219 auto lb_modification_id = last_audit_revision_id_;
220
221 audit_entries = getMgr().getPool()->getRecentAuditEntries(backend_selector,
222 server_selector,
223 lb_modification_time,
224 lb_modification_id);
225 // Store the last audit revision time. It should be set to the most recent
226 // audit entry fetched. If returned audit is empty we don't update.
227 updateLastAuditRevisionTimeId(audit_entries);
228
229 // If this is full reconfiguration we don't need the audit entries anymore.
230 // Let's remove them and proceed as if they don't exist.
231 if (fetch_mode == FetchMode::FETCH_ALL) {
232 audit_entries.clear();
233 }
234
235 // If we fetch the entire config or we're updating the config and there are
236 // audit entries indicating that there are some pending updates, let's
237 // execute the server specific function that fetches and merges the data
238 // into the given configuration.
239 if ((fetch_mode == FetchMode::FETCH_ALL) || !audit_entries.empty()) {
240 try {
241 databaseConfigApply(backend_selector, server_selector,
242 lb_modification_time, audit_entries);
243 } catch (...) {
244 // Revert last audit revision time and id so as we can retry
245 // from the last successful attempt.
248 last_audit_revision_time_ = lb_modification_time;
249 last_audit_revision_id_ = lb_modification_id;
250 throw;
251 }
252 }
253 }
254
255protected:
256
275 const std::string& object_type) const {
277 auto const& index = audit_entries.get<db::AuditEntryObjectTypeTag>();
278 auto range = index.equal_range(object_type);
279 BOOST_FOREACH(auto const& it, range) {
280 if (it->getModificationType() != db::AuditEntry::ModificationType::DELETE) {
281 result.insert(it);
282 }
283 }
284
285 return (result);
286 }
287
315 virtual void databaseConfigApply(const db::BackendSelector& backend_selector,
316 const db::ServerSelector& server_selector,
317 const boost::posix_time::ptime& lb_modification_time,
318 const db::AuditEntryCollection& audit_entries) = 0;
319
324 ConfigBackendMgrType& getMgr() const {
325 return (ConfigBackendMgrType::instance());
326 }
327
332 static boost::posix_time::ptime getInitialAuditRevisionTime() {
333 static boost::posix_time::ptime
334 initial_time(boost::gregorian::date(2000, boost::gregorian::Jan, 1));
335 return (initial_time);
336 }
337
346 // Do nothing if there are no audit entries. It is the case if
347 // there were no updates to the configuration.
348 if (audit_entries.empty()) {
349 return;
350 }
351
352 // Get the audit entries sorted by modification time and id,
353 // and pick the latest entry.
354 auto const& index = audit_entries.get<db::AuditEntryModificationTimeIdTag>();
355 last_audit_revision_time_ = (*index.rbegin())->getModificationTime();
356 last_audit_revision_id_ = (*index.rbegin())->getRevisionId();
357 }
358
360 boost::posix_time::ptime last_audit_revision_time_;
361
369};
370
375inline bool
377 const uint64_t& object_id) {
378 auto const& object_id_idx = audit_entries.get<db::AuditEntryObjectIdTag>();
379 return (object_id_idx.count(object_id) > 0);
380}
381
382} // end of namespace isc::process
383} // end of namespace isc
384
385#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.
FetchMode
Fetch mode used in invocations to databaseConfigFetch.
Definition cb_ctl_base.h:89
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.