Kea  2.3.3-git
cfgmgr.cc
Go to the documentation of this file.
1 // Copyright (C) 2012-2021 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 #include <asiolink/io_address.h>
9 #include <dhcp/iface_mgr.h>
10 #include <dhcp/libdhcp++.h>
11 #include <dhcpsrv/cfgmgr.h>
12 #include <dhcpsrv/dhcpsrv_log.h>
13 #include <sstream>
14 #include <string>
15 
16 using namespace isc::asiolink;
17 using namespace isc::util;
18 
19 namespace isc {
20 namespace dhcp {
21 
22 const size_t CfgMgr::CONFIG_LIST_SIZE = 10;
23 
24 CfgMgr&
25 CfgMgr::instance() {
26  static CfgMgr cfg_mgr;
27  return (cfg_mgr);
28 }
29 
31 CfgMgr::getDataDir() const {
32  return (datadir_);
33 }
34 
35 void
36 CfgMgr::setDataDir(const std::string& datadir, bool unspecified) {
37  datadir_ = Optional<std::string>(datadir, unspecified);
38 }
39 
40 void
41 CfgMgr::setD2ClientConfig(D2ClientConfigPtr& new_config) {
42  ensureCurrentAllocated();
43  // Note that D2ClientMgr::setD2Config() actually attempts to apply the
44  // configuration by stopping its sender and opening a new one and so
45  // forth per the new configuration.
46  d2_client_mgr_.setD2ClientConfig(new_config);
47 
48  // Manager will throw if the set fails, if it succeeds
49  // we'll update our SrvConfig, configuration_, with the D2ClientConfig
50  // used. This is largely bookkeeping in case we ever want to compare
51  // configuration_ to another SrvConfig.
52  configuration_->setD2ClientConfig(new_config);
53 }
54 
55 bool
56 CfgMgr::ddnsEnabled() {
57  return (d2_client_mgr_.ddnsEnabled());
58 }
59 
60 const D2ClientConfigPtr&
61 CfgMgr::getD2ClientConfig() const {
62  return (d2_client_mgr_.getD2ClientConfig());
63 }
64 
66 CfgMgr::getD2ClientMgr() {
67  return (d2_client_mgr_);
68 }
69 
70 void
71 CfgMgr::ensureCurrentAllocated() {
72  if (!configuration_ || configs_.empty()) {
73  configuration_.reset(new SrvConfig());
74  configs_.push_back(configuration_);
75  }
76 }
77 
78 void
79 CfgMgr::clear() {
80  if (configuration_) {
81  configuration_->removeStatistics();
82  }
83  configs_.clear();
84  external_configs_.clear();
85  D2ClientConfigPtr d2_default_conf(new D2ClientConfig());
86  setD2ClientConfig(d2_default_conf);
87 }
88 
89 void
90 CfgMgr::commit() {
91  ensureCurrentAllocated();
92 
93  // First we need to remove statistics. The new configuration can have fewer
94  // subnets. Also, it may change subnet-ids. So we need to remove them all
95  // and add it back.
96  configuration_->removeStatistics();
97 
98  if (!configs_.back()->sequenceEquals(*configuration_)) {
99  configuration_ = configs_.back();
100  // Keep track of the maximum size of the configs history. Before adding
101  // new element, we have to remove the oldest one.
102  if (configs_.size() > CONFIG_LIST_SIZE) {
103  SrvConfigList::iterator it = configs_.begin();
104  std::advance(it, configs_.size() - CONFIG_LIST_SIZE);
105  configs_.erase(configs_.begin(), it);
106  }
107  }
108 
109  // Set the last commit timestamp.
110  auto now = boost::posix_time::second_clock::universal_time();
111  configuration_->setLastCommitTime(now);
112 
113  // Now we need to set the statistics back.
114  configuration_->updateStatistics();
115 
116  configuration_->configureLowerLevelLibraries();
117 }
118 
119 void
120 CfgMgr::rollback() {
121  ensureCurrentAllocated();
122  if (!configuration_->sequenceEquals(*configs_.back())) {
123  configs_.pop_back();
124  }
125 }
126 
127 void
128 CfgMgr::revert(const size_t index) {
129  ensureCurrentAllocated();
130  if (index == 0) {
131  isc_throw(isc::OutOfRange, "invalid commit index 0 when reverting"
132  " to an old configuration");
133  } else if (index > configs_.size() - 1) {
134  isc_throw(isc::OutOfRange, "unable to revert to commit index '"
135  << index << "', only '" << configs_.size() - 1
136  << "' previous commits available");
137  }
138 
139  // Let's rollback an existing configuration to make sure that the last
140  // configuration on the list is the current one. Note that all remaining
141  // operations in this function should be exception free so there shouldn't
142  // be a problem that the revert operation fails and the staging
143  // configuration is destroyed by this rollback.
144  rollback();
145 
146  // Get the iterator to the current configuration and then advance to the
147  // desired one.
148  SrvConfigList::const_reverse_iterator it = configs_.rbegin();
149  std::advance(it, index);
150 
151  // Copy the desired configuration to the new staging configuration. The
152  // staging configuration is re-created here because we rolled back earlier
153  // in this function.
154  (*it)->copy(*getStagingCfg());
155 
156  // Make the staging configuration a current one.
157  commit();
158 }
159 
161 CfgMgr::getCurrentCfg() {
162  ensureCurrentAllocated();
163  return (configuration_);
164 }
165 
167 CfgMgr::getStagingCfg() {
168  ensureCurrentAllocated();
169  if (configuration_->sequenceEquals(*configs_.back())) {
170  uint32_t sequence = configuration_->getSequence();
171  configs_.push_back(SrvConfigPtr(new SrvConfig(++sequence)));
172  }
173  return (configs_.back());
174 }
175 
177 CfgMgr::createExternalCfg() {
178  uint32_t seq = 0;
179 
180  if (!external_configs_.empty()) {
181  seq = external_configs_.rbegin()->second->getSequence() + 1;
182  }
183 
184  SrvConfigPtr srv_config(new SrvConfig(seq));
185  external_configs_[seq] = srv_config;
186  return (srv_config);
187 }
188 
189 void
190 CfgMgr::mergeIntoStagingCfg(const uint32_t seq) {
191  mergeIntoCfg(getStagingCfg(), seq);
192 }
193 
194 void
195 CfgMgr::mergeIntoCurrentCfg(const uint32_t seq) {
196  try {
197  // First we need to remove statistics.
198  getCurrentCfg()->removeStatistics();
199  mergeIntoCfg(getCurrentCfg(), seq);
200 
201  } catch (...) {
202  // Make sure the statistics is updated even if the merge failed.
203  getCurrentCfg()->updateStatistics();
204  throw;
205  }
206  getCurrentCfg()->updateStatistics();
207 }
208 
209 void
210 CfgMgr::mergeIntoCfg(const SrvConfigPtr& target_config, const uint32_t seq) {
211  auto source_config = external_configs_.find(seq);
212  if (source_config != external_configs_.end()) {
213  target_config->merge(*source_config->second);
214  external_configs_.erase(source_config);
215 
216  } else {
217  isc_throw(BadValue, "the external configuration with the sequence number "
218  "of " << seq << " was not found");
219  }
220 }
221 
222 CfgMgr::CfgMgr()
223  : datadir_(DHCP_DATA_DIR, true), d2_client_mgr_(), family_(AF_INET) {
224  // DHCP_DATA_DIR must be set set with -DDHCP_DATA_DIR="..." in Makefile.am
225  // Note: the definition of DHCP_DATA_DIR needs to include quotation marks
226  // See AM_CPPFLAGS definition in Makefile.am
227 }
228 
230 }
231 
232 } // end of isc::dhcp namespace
233 } // end of isc namespace
boost::shared_ptr< SrvConfig > SrvConfigPtr
Non-const pointer to the SrvConfig.
Definition: srv_config.h:1191
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition: edns.h:19
Acts as a storage vault for D2 client configuration.
Definition: d2_client_cfg.h:57
virtual ~CfgMgr()
virtual destructor
Definition: cfgmgr.cc:229
Specifies current DHCP configuration.
Definition: srv_config.h:177
Defines the logger used by the top-level component of kea-lfc.
D2ClientMgr isolates Kea from the details of being a D2 client.
Definition: d2_client_mgr.h:79
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
boost::shared_ptr< D2ClientConfig > D2ClientConfigPtr
Defines a pointer for D2ClientConfig instances.
Configuration Manager.
Definition: cfgmgr.h:70