Kea  1.9.9-git
translator_pool.cc
Go to the documentation of this file.
1 // Copyright (C) 2018-2019 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 <asiolink/io_address.h>
11 #include <yang/adaptor.h>
12 #include <yang/translator_pool.h>
13 #include <yang/yang_models.h>
14 #include <boost/lexical_cast.hpp>
15 #include <sstream>
16 
17 using namespace std;
18 using namespace isc::data;
19 using namespace isc::asiolink;
20 #ifndef HAVE_PRE_0_7_6_SYSREPO
21 using namespace sysrepo;
22 #endif
23 
24 namespace isc {
25 namespace yang {
26 
27 TranslatorPool::TranslatorPool(S_Session session, const string& model)
28  : TranslatorBasic(session, model),
29  TranslatorOptionData(session, model),
30  TranslatorOptionDataList(session, model) {
31 }
32 
34 }
35 
37 TranslatorPool::getPool(const string& xpath) {
38  try {
39  if (model_ == IETF_DHCPV6_SERVER) {
40  return (getPoolIetf6(xpath));
41  } else if ((model_ == KEA_DHCP4_SERVER) ||
42  (model_ == KEA_DHCP6_SERVER)) {
43  return (getPoolKea(xpath));
44  }
45  } catch (const sysrepo_exception& ex) {
47  "sysrepo error getting pool at '" << xpath
48  << "': " << ex.what());
49  }
51  "getPool not implemented for the model: " << model_);
52 }
53 
55 TranslatorPool::getPoolIetf6(const string& xpath) {
56  ElementPtr result = Element::createMap();
57  // Skip pool-id which exists but is not used.
58  ConstElementPtr pool = getItem(xpath + "/pool-prefix");
59  if (!pool) {
60  isc_throw(BadValue, "getPoolIetf6 requires pool prefix at " << xpath);
61  }
62  result->set("pool", pool);
63  // Ignore start-address - end-address as prefix form is mandatory?
64  ConstElementPtr guard = getItem(xpath + "/client-class");
65  if (guard) {
66  result->set("client-class", guard);
67  }
68  ConstElementPtr valid_lifetime = getItem(xpath + "/valid-lifetime");
69  if (valid_lifetime) {
70  result->set("valid-lifetime", valid_lifetime);
71  }
72  ConstElementPtr preferred_lifetime =
73  getItem(xpath + "/preferred-lifetime");
74  if (preferred_lifetime) {
75  result->set("preferred-lifetime", preferred_lifetime);
76  }
77  ConstElementPtr renew_time = getItem(xpath + "/renew-time");
78  if (renew_time) {
79  result->set("renew-timer", renew_time);
80  }
81  ConstElementPtr rebind_time = getItem(xpath + "/rebind-time");
82  if (rebind_time) {
83  result->set("rebind-timer", rebind_time);
84  }
85  // Skip max-addr-count
86  // @todo: option-data
88  // Skip rapid-commit.
89  return (result);
90 }
91 
93 TranslatorPool::getPoolKea(const string& xpath) {
94  ElementPtr result = Element::createMap();
95  ConstElementPtr prefix = getItem(xpath + "/prefix");
96  if (prefix) {
97  result->set("pool", prefix);
98  } else {
99  ConstElementPtr start_addr = getItem(xpath + "/start-address");
100  ConstElementPtr end_addr = getItem(xpath + "/end-address");
101  if (!start_addr || !end_addr) {
102  isc_throw(BadValue, "getPoolKea requires either prefix or "
103  "both start and end addresses at " << xpath);
104  }
105  ostringstream range;
106  range << start_addr->stringValue() << " - "
107  << end_addr->stringValue();
108  result->set("pool", Element::create(range.str()));
109  }
110  ConstElementPtr options = getOptionDataList(xpath);
111  if (options && (options->size() > 0)) {
112  result->set("option-data", options);
113  }
114  ConstElementPtr guard = getItem(xpath + "/client-class");
115  if (guard) {
116  result->set("client-class", guard);
117  }
118  ConstElementPtr required = getItems(xpath + "/require-client-classes");
119  if (required && (required->size() > 0)) {
120  result->set("require-client-classes", required);
121  }
122  ConstElementPtr context = getItem(xpath + "/user-context");
123  if (context) {
124  result->set("user-context", Element::fromJSON(context->stringValue()));
125  }
126  return (result);
127 }
128 
129 void
130 TranslatorPool::setPool(const string& xpath, ConstElementPtr elem) {
131  try {
132  if (model_ == IETF_DHCPV6_SERVER) {
133  setPoolIetf6(xpath, elem);
134  } else if ((model_ == KEA_DHCP4_SERVER) ||
135  (model_ == KEA_DHCP6_SERVER)) {
136  setPoolKea(xpath, elem);
137  } else {
139  "setPool not implemented for the model: " << model_);
140  }
141  } catch (const sysrepo_exception& ex) {
143  "sysrepo error setting pool '" << elem->str()
144  << "' at '" << xpath << "': " << ex.what());
145  }
146 }
147 
148 void
149 TranslatorPool::setPoolIetf6(const string& xpath, ConstElementPtr elem) {
150  ConstElementPtr pool = elem->get("pool");
151  if (!pool) {
152  isc_throw(BadValue, "setPoolIetf6 requires pool: " << elem->str());
153  }
154  string prefix = pool->stringValue();
155  if (prefix.find("/") == string::npos) {
157  "setPoolIetf only supports pools in prefix (vs range) "
158  "format and was called with '" << prefix << "'");
159  }
160  setItem(xpath + "/pool-prefix", pool, SR_STRING_T);
161  string addr = prefix.substr(0, prefix.find_first_of(" /"));
162  uint8_t plen = boost::lexical_cast<unsigned>
163  (prefix.substr(prefix.find_last_of(" /") + 1, string::npos));
164  const IOAddress& base(addr);
165  setItem(xpath + "/start-address",
166  Element::create(firstAddrInPrefix(base, plen).toText()),
167  SR_STRING_T);
168  setItem(xpath + "/end-address",
169  Element::create(lastAddrInPrefix(base, plen).toText()),
170  SR_STRING_T);
171  ConstElementPtr valid_lifetime = elem->get("valid-lifetime");
172  if (valid_lifetime) {
173  setItem(xpath + "/valid-lifetime", valid_lifetime, SR_UINT32_T);
174  }
175  ConstElementPtr preferred_lifetime = elem->get("preferred-lifetime");
176  if (preferred_lifetime) {
177  setItem(xpath + "/preferred-lifetime",
178  preferred_lifetime, SR_UINT32_T);
179  }
180  ConstElementPtr renew_timer = elem->get("renew-timer");
181  if (renew_timer) {
182  setItem(xpath + "/renew-time", renew_timer, SR_UINT32_T);
183  }
184  ConstElementPtr rebind_timer = elem->get("rebind-timer");
185  if (rebind_timer) {
186  setItem(xpath + "/rebind-time", rebind_timer, SR_UINT32_T);
187  }
188  // skip rapid-commit
189  ConstElementPtr guard = elem->get("client-class");
190  if (guard) {
191  setItem(xpath + "/client-class", guard, SR_STRING_T);
192  }
193  // skip max-addr-count
194  // @todo option-data
195  // Set max address count to disabled.
196  setItem(xpath + "/max-address-count",
197  Element::create(string("disabled")),
198  SR_ENUM_T);
199 }
200 
201 void
202 TranslatorPool::setPoolKea(const string& xpath, ConstElementPtr elem) {
203  ConstElementPtr pool = elem->get("pool");
204  if (!pool) {
205  isc_throw(BadValue, "setPoolKea requires pool: " << elem->str());
206  }
207  bool created = false;
208  string prefix = pool->stringValue();
209  string start_addr;
210  string end_addr;
211  getAddresses(prefix, start_addr, end_addr);
212  if (prefix.find("/") != string::npos) {
213  setItem(xpath + "/prefix", pool, SR_STRING_T);
214  created = true;
215  }
216  // Skip start-address and end-address as are the keys.
217  ConstElementPtr options = elem->get("option-data");
218  if (options && (options->size() > 0)) {
219  setOptionDataList(xpath, options);
220  created = true;
221  }
222  ConstElementPtr guard = elem->get("client-class");
223  if (guard) {
224  setItem(xpath + "/client-class", guard, SR_STRING_T);
225  created = true;
226  }
227  ConstElementPtr required = elem->get("require-client-classes");
228  if (required && (required->size() > 0)) {
229  for (ConstElementPtr rclass : required->listValue()) {
230  setItem(xpath + "/require-client-classes", rclass, SR_STRING_T);
231  created = true;
232  }
233  }
234  ConstElementPtr context = Adaptor::getContext(elem);
235  if (context) {
236  setItem(xpath + "/user-context", Element::create(context->str()),
237  SR_STRING_T);
238  created = true;
239  }
240  // There is no mandatory fields outside the keys so force creation.
241  if (!created) {
242  ConstElementPtr list = Element::createList();
243  setItem(xpath, list, SR_LIST_T);
244  }
245 }
246 
247 void
248 TranslatorPool::getAddresses(const string& prefix,
249  string& start_address, string& end_address) {
250  size_t slash = prefix.find("/");
251  if (slash != string::npos) {
252  string addr = prefix.substr(0, prefix.find_first_of(" /"));
253  uint8_t plen = boost::lexical_cast<unsigned>
254  (prefix.substr(prefix.find_last_of(" /") + 1, string::npos));
255  start_address = firstAddrInPrefix(IOAddress(addr), plen).toText();
256  end_address = lastAddrInPrefix(IOAddress(addr), plen).toText();
257  return;
258  }
259  size_t dash = prefix.find("-");
260  if (dash == string::npos) {
262  "getAddresses called with invalid prefix: " << prefix);
263  }
264  start_address = prefix.substr(0, prefix.find_first_of(" -"));
265  end_address = prefix.substr(prefix.find_last_of(" -") + 1, string::npos);
266 }
267 
268 TranslatorPools::TranslatorPools(S_Session session, const string& model)
269  : TranslatorBasic(session, model),
270  TranslatorOptionData(session, model),
271  TranslatorOptionDataList(session, model),
272  TranslatorPool(session, model) {
273 }
274 
276 }
277 
279 TranslatorPools::getPools(const string& xpath) {
280  try {
281  if (model_ == IETF_DHCPV6_SERVER) {
282  return (getPoolsIetf(xpath));
283  } else if ((model_ == KEA_DHCP4_SERVER) ||
284  (model_ == KEA_DHCP6_SERVER)) {
285  return (getPoolsKea(xpath));
286  }
287  } catch (const sysrepo_exception& ex) {
289  "sysrepo error getting pools at '" << xpath
290  << "': " << ex.what());
291  }
293  "getPools not implemented for the model: " << model_);
294 }
295 
297 TranslatorPools::getPoolsIetf(const string& xpath) {
298  ElementPtr result = Element::createList();
299  S_Iter_Value iter = getIter(xpath + "/address-pool");
300  if (!iter) {
301  // Can't happen.
302  isc_throw(Unexpected, "getPoolsIetf can't get iterator: " << xpath);
303  }
304  for (;;) {
305  const string& pool = getNext(iter);
306  if (pool.empty()) {
307  break;
308  }
309  result->add(getPool(pool));
310  }
311  return (result);
312 }
313 
315 TranslatorPools::getPoolsKea(const string& xpath) {
316  ElementPtr result = Element::createList();
317  S_Iter_Value iter = getIter(xpath + "/pool");
318  if (!iter) {
319  // Can't happen.
320  isc_throw(Unexpected, "getPoolsKea can't get iterator: " << xpath);
321  }
322  for (;;) {
323  const string& pool = getNext(iter);
324  if (pool.empty()) {
325  break;
326  }
327  result->add(getPool(pool));
328  }
329  return (result);
330 }
331 
332 void
333 TranslatorPools::setPools(const string& xpath, ConstElementPtr elem) {
334  try {
335  if (model_ == IETF_DHCPV6_SERVER) {
336  setPoolsById(xpath, elem);
337  } else if ((model_ == KEA_DHCP4_SERVER) ||
338  (model_ == KEA_DHCP6_SERVER)) {
339  setPoolsByAddresses(xpath, elem);
340  } else {
342  "setPools not implemented for the model: " << model_);
343  }
344  } catch (const sysrepo_exception& ex) {
346  "sysrepo error setting pools '" << elem->str()
347  << "' at '" << xpath << "': " << ex.what());
348  }
349 }
350 
351 void
352 TranslatorPools::setPoolsById(const string& xpath, ConstElementPtr elem) {
353  for (size_t i = 0; i < elem->size(); ++i) {
354  ConstElementPtr pool = elem->get(i);
355  ostringstream prefix;
356  prefix << xpath << "/address-pool[pool-id='" << i << "']";
357  setPool(prefix.str(), pool);
358  }
359 }
360 
361 void
363  ConstElementPtr elem) {
364  for (size_t i = 0; i < elem->size(); ++i) {
365  ConstElementPtr pool = elem->get(i);
366  if (!pool->contains("pool")) {
367  isc_throw(BadValue, "setPoolsByAddresses: missing required pool: "
368  << pool->str());
369  }
370  string pref = pool->get("pool")->stringValue();
371  string start_addr;
372  string end_addr;
373  getAddresses(pref, start_addr, end_addr);
374  ostringstream prefix;
375  prefix << xpath << "/pool[start-address='" << start_addr
376  << "'][end-address='" << end_addr << "']";
377  setPool(prefix.str(), pool);
378  }
379 }
380 
381 }; // end of namespace isc::yang
382 }; // end of namespace isc
isc::data::ElementPtr getPool(const std::string &xpath)
Get and translate a pool from YANG to JSON.
isc::data::ElementPtr getItems(const std::string &xpath)
Get and translate a list of basic values from YANG to JSON.
Definition: translator.cc:126
A generic exception that is thrown when a function is not implemented.
isc::data::ElementPtr getPoolIetf6(const std::string &xpath)
getPool for ietf-dhcpv6-server.
virtual ~TranslatorPools()
Destructor.
isc::data::ElementPtr getPoolsKea(const std::string &xpath)
getPools for kea-dhcp[46]-server.
isc::data::ElementPtr getPoolsIetf(const std::string &xpath)
getPools for ietf-dhcpv6-server.
Between YANG and JSON translator class for basic values.
Definition: translator.h:27
boost::shared_ptr< Element > ElementPtr
Definition: data.h:20
STL namespace.
void setPool(const std::string &xpath, isc::data::ConstElementPtr elem)
Translate and set (address) pool from JSON to YANG.
sysrepo::S_Iter_Value getIter(const std::string &xpath)
List iterator methods keeping the session private.
Definition: translator.cc:316
static void getAddresses(const std::string &prefix, std::string &start_address, std::string &end_address)
Get start and end addresses from prefix.
void setPools(const std::string &xpath, isc::data::ConstElementPtr elem)
Translate and set (address) pools from JSON to YANG.
#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...
void setItem(const std::string &xpath, isc::data::ConstElementPtr elem, sr_type_t type)
Translate and set basic value from JSON to YANG.
Definition: translator.cc:288
void setPoolsById(const std::string &xpath, isc::data::ConstElementPtr elem)
setPools using pool-id.
TranslatorPools(sysrepo::S_Session session, const std::string &model)
Constructor.
void setPoolKea(const std::string &xpath, isc::data::ConstElementPtr elem)
setPool for kea-dhcp[46]-server.
A translator class for converting an option data list between YANG and JSON.
A generic exception that is thrown when an unexpected error condition occurs.
std::string model_
The model.
Definition: translator.h:132
boost::shared_ptr< const Element > ConstElementPtr
Definition: data.h:23
std::string getNext(sysrepo::S_Iter_Value iter)
Get xpath of the next YANG list item.
Definition: translator.cc:321
static isc::data::ConstElementPtr getContext(isc::data::ConstElementPtr parent)
Get user context.
Definition: adaptor.cc:27
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
Defines the logger used by the top-level component of kea-dhcp-ddns.
isc::data::ConstElementPtr getOptionDataList(const std::string &xpath)
Get and translate option data list from YANG to JSON.
isc::data::ElementPtr getItem(const std::string &xpath)
Get and translate basic value from YANG to JSON.
Definition: translator.cc:111
A translator class for converting a pool between YANG and JSON.
void setPoolIetf6(const std::string &xpath, isc::data::ConstElementPtr elem)
setPool for ietf-dhcpv6-server.
isc::data::ElementPtr getPools(const std::string &xpath)
Get and translate pools from YANG to JSON.
Option data translation between YANG and JSON.
void setOptionDataList(const std::string &xpath, isc::data::ConstElementPtr elem)
Translate and set option data list from JSON to YANG.
void setPoolsByAddresses(const std::string &xpath, isc::data::ConstElementPtr elem)
setPools using address pair.
virtual ~TranslatorPool()
Destructor.
isc::data::ElementPtr getPoolKea(const std::string &xpath)
getPool for kea-dhcp[46]-server.