Kea 2.7.5
translator.cc
Go to the documentation of this file.
1// Copyright (C) 2018-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#include <config.h>
8
10#include <yang/adaptor.h>
11#include <yang/translator.h>
12
13#include <sysrepo-cpp/utils/exception.hpp>
14
15#include <cstring>
16#include <vector>
17
18using namespace std;
19using namespace isc::data;
20using namespace isc::util::encode;
21using namespace libyang;
22using namespace sysrepo;
23
24namespace isc {
25namespace yang {
26
27Translator::Translator(Session session, const string& model)
28 : session_(session), model_(model) {
29}
30
31void
33 DataNode const& data_node,
34 string const& name) const {
35 ElementPtr const& x(getItem(data_node, name));
36 if (x) {
37 storage->set(name, x);
38 }
39}
40
41void
43 DataNode const& data_node,
44 string const& name,
45 string const& yang_name) const {
46 ElementPtr const& x(getItem(data_node, yang_name));
47 if (x) {
48 storage->set(name, x);
49 }
50}
51
52void
54 DataNode const& data_node,
55 string const& name) const {
56 ElementPtr const& x(getItem(data_node, name));
57 if (x) {
58 storage->set(name, Element::fromJSON(x->stringValue()));
59 }
60}
61
62void
64 string const& xpath,
65 string const& name,
66 LeafBaseType const type) {
67 ConstElementPtr const& x(from->get(name));
68 if (x) {
69 setItem(xpath + "/" + name, x, type);
70 }
71}
72
73void
75 string const& xpath,
76 string const& name,
77 string const& yang_name,
78 LeafBaseType const type) {
79 ConstElementPtr const& x(from->get(name));
80 if (x) {
81 setItem(xpath + "/" + yang_name, x, type);
82 }
83}
84
85void
87 string const& xpath,
88 string const& name,
89 LeafBaseType const type) {
90 ConstElementPtr const& leaf_list(from->get(name));
91 if (leaf_list && !leaf_list->empty()) {
92 for (ElementPtr const& leaf : leaf_list->listValue()) {
93 setItem(xpath + "/" + name, leaf, type);
94 }
95 }
96}
97
98void
100 string const& xpath) {
101 ConstElementPtr const& user_context(Adaptor::getContext(from));
102 if (user_context) {
103 setItem(xpath + "/user-context", Element::create(user_context->str()),
104 LeafBaseType::String);
105 }
106}
107
108void
110 string const& xpath,
111 string const& name) {
112 ConstElementPtr const& x(from->get(name));
113 if (x) {
114 ElementPtr const& json(Element::create(x->str()));
115 setItem(xpath + "/" + name, json, LeafBaseType::String);
116 }
117}
118
119void
120Translator::deleteItem(string const& xpath) {
121 try {
122 if (session_.getData(xpath)) {
123 session_.deleteItem(xpath);
124 }
125 } catch (sysrepo::Error const& ex) {
126 isc_throw(NetconfError, "deleting item at '" << xpath << "': " << ex.what());
127 }
128 session_.applyChanges();
129}
130
131DataNode
132Translator::findXPath(string const& xpath) const {
133 optional<DataNode> const& data_node(getData(xpath));
134 if (!data_node) {
135 isc_throw(NetconfError, "no data at xpath " << xpath);
136 }
137 Set<DataNode> at_path(data_node->findXPath(xpath));
138 if (at_path.empty()) {
139 isc_throw(NetconfError, "no data at xpath " << xpath);
140 }
141 return at_path.front();
142}
143
144optional<DataNode>
145Translator::getData(string const& xpath) const {
146 optional<DataNode> data_node;
147 try {
148 data_node = session_.getData(xpath);
149 } catch (sysrepo::Error const& ex) {
150 isc_throw(NetconfError, "getting item at '" << xpath << "': " << ex.what());
151 }
152
153 return data_node;
154}
155
157Translator::getItem(DataNode const& data_node,
158 string const& xpath) const {
159 try {
160 Set<DataNode> const& nodes(data_node.findXPath(xpath));
161 if (nodes.empty()) {
162 return ElementPtr();
163 }
164 DataNode const& front(nodes.front());
165 NodeType const node_type(front.schema().nodeType());
166
167 // Leaf
168 if (node_type == NodeType::Leaf) {
169 return translateFromYang(front);
170 } else if (node_type == NodeType::Leaflist) {
172 for (DataNode const& i : nodes) {
173 result->add(translateFromYang(i));
174 }
175 return result;
176 } else {
177 isc_throw(NotImplemented, "getting node of type "
178 << int(node_type) << " not supported, xpath is '" << xpath
179 << "'");
180 }
181
182 } catch (sysrepo::Error const& ex) {
183 isc_throw(NetconfError, "getting item at '" << xpath << "': " << ex.what());
184 }
185}
186
188Translator::getItemFromAbsoluteXpath(string const& xpath) const {
189 optional<DataNode> const& data_node(getData(xpath));
190 if (!data_node) {
191 return ElementPtr();
192 }
193 return getItem(*data_node, xpath);
194}
195
196void
198 DataNode const& data_node,
199 string const& name) const {
200 ElementPtr const& x(getItem(data_node, name));
201 if (!x) {
202 isc_throw(MissingNode, name);
203 }
204 storage->set(name, x);
205}
206
207void
209 DataNode const& data_node,
210 string const& name,
211 string const& yang_name) const {
212 ElementPtr const& x(getItem(data_node, yang_name));
213 if (!x) {
214 isc_throw(MissingNode, yang_name);
215 }
216 storage->set(name, x);
217}
218
219bool
220Translator::schemaNodeExists(string const& xpath) const {
221 Context const& context(session_.getContext());
222 try {
223 context.findPath(xpath);
224 } catch (libyang::Error const& ex) {
225 return false;
226 }
227 return true;
228}
229
230void
231Translator::setItem(const string& xpath,
232 ConstElementPtr const elem,
233 LeafBaseType const type) {
234 optional<string> const value(translateToYang(elem, type));
235 try {
236 session_.setItem(xpath, value);
237 } catch (sysrepo::Error const& ex) {
238 isc_throw(NetconfError, "setting item '" << (elem ? elem->str() : "nullopt")
239 << "' at '" << xpath << "': " << ex.what());
240 }
241 session_.applyChanges();
242}
243
244void
246 string const& xpath,
247 string const& name,
248 LeafBaseType const type) {
249 ConstElementPtr const& x(from->get(name));
250 if (!x) {
251 isc_throw(MissingNode, "xpath: " << xpath << ", name: " << name);
252 }
253 setItem(xpath + "/" + name, x, type);
254}
255
256void
258 string const& xpath,
259 string const& name,
260 string const& yang_name,
261 LeafBaseType const type) {
262 ConstElementPtr const& x(from->get(name));
263 if (!x) {
264 isc_throw(MissingNode, "xpath: " << xpath << ", name: " << name);
265 }
266 setItem(xpath + "/" + yang_name, x, type);
267}
268
270Translator::translateFromYang(optional<DataNode> data_node) {
271 NodeType const node_type(data_node->schema().nodeType());
272 if (node_type == NodeType::Leaf || node_type == NodeType::Leaflist) {
273 DataNodeTerm const& leaf(data_node->asTerm());
274 LeafBaseType type;
275 if (node_type == NodeType::Leaf) {
276 type = leaf.schema().asLeaf().valueType().base();
277 } else {
278 type = leaf.schema().asLeafList().valueType().base();
279 }
280
281 static Deserializer deserializer(initializeDeserializer());
282 return deserializer.at(type)(string(leaf.valueStr()));
283 }
284 return ElementPtr();
285}
286
287optional<string>
289 libyang::LeafBaseType const type) {
290 string string_representation;
291 if (!element) {
292 // A null ElementPtr is how we signal that this item requires no value.
293 // Useful when setting YANG lists which is the only way to set their
294 // keys in sysrepo since setting the key itself results in an error.
295 return nullopt;
296 } else if (element->getType() == Element::map) {
297 isc_throw(NotImplemented, "Translator::value(): map element");
298 } else if (element->getType() == Element::list) {
299 isc_throw(NotImplemented, "Translator::value(): list element");
300 } else if (element->getType() == Element::string) {
301 // If it's a string, get the variant without quotes.
302 string_representation = element->stringValue();
303 } else {
304 // If it's not a string, also get the variant without quotes, but it's a different method.
305 string_representation = element->str();
306 }
307
308 static Serializer serializer(initializeSerializer());
309 return serializer.at(type)(string_representation);
310}
311
312string
313Translator::decode64(string const& input) {
314 vector<uint8_t> binary;
315 decodeBase64(input, binary);
316 string result;
317 result.resize(binary.size());
318 memcpy(&result[0], &binary[0], result.size());
319 return (result);
320}
321
322string
323Translator::encode64(string const& input) {
324 vector<uint8_t> binary;
325 binary.resize(input.size());
326 memcpy(&binary[0], input.c_str(), binary.size());
327 return (encodeBase64(binary));
328}
329
332 Deserializer result;
333
334 result.emplace(LeafBaseType::Binary, [](string const& value) -> ElementPtr const {
335 return Element::create(decode64(value));
336 });
337
338 for (LeafBaseType const& i :
339 {LeafBaseType::Bool, LeafBaseType::Dec64, LeafBaseType::Int8, LeafBaseType::Int16,
340 LeafBaseType::Int32, LeafBaseType::Int64, LeafBaseType::Uint8, LeafBaseType::Uint16,
341 LeafBaseType::Uint32, LeafBaseType::Uint64}) {
342 result.emplace(i, [](string const& value) -> ElementPtr const {
343 return Element::fromJSON(value);
344 });
345 }
346
347 // The rest of YANG values can be expressed as strings.
348 for (LeafBaseType const& i :
349 {LeafBaseType::Bits, LeafBaseType::Empty, LeafBaseType::Enum, LeafBaseType::IdentityRef,
350 LeafBaseType::InstanceIdentifier, LeafBaseType::Leafref, LeafBaseType::String,
351 LeafBaseType::Union}) {
352 result.emplace(i, [](string const& value) -> ElementPtr const {
353 return Element::create(value);
354 });
355 }
356
357 return result;
358}
359
362 Serializer result;
363
364 result.emplace(LeafBaseType::Binary, [](string const& value) -> string const {
365 return encode64(value);
366 });
367
368 // The rest of YANG values can be expressed directly.
369 for (LeafBaseType const& i :
370 {LeafBaseType::Bits, LeafBaseType::Bool, LeafBaseType::Dec64, LeafBaseType::Empty,
371 LeafBaseType::Enum, LeafBaseType::IdentityRef, LeafBaseType::InstanceIdentifier,
372 LeafBaseType::Int8, LeafBaseType::Int16, LeafBaseType::Int32, LeafBaseType::Int64,
373 LeafBaseType::Leafref, LeafBaseType::String, LeafBaseType::Uint8, LeafBaseType::Uint16,
374 LeafBaseType::Uint32, LeafBaseType::Uint64, LeafBaseType::Union, LeafBaseType::Unknown}) {
375 result.emplace(i, [](string const& value) -> string const {
376 return value;
377 });
378 }
379
380 return result;
381}
382
383} // namespace yang
384} // namespace isc
virtual const char * what() const
Returns a C-style character string of the cause of the exception.
A generic exception that is thrown when a function is not implemented.
static ElementPtr create(const Position &pos=ZERO_POSITION())
Definition data.cc:249
static ElementPtr fromJSON(const std::string &in, bool preproc=false)
These functions will parse the given string (JSON) representation of a compound element.
Definition data.cc:798
static ElementPtr createList(const Position &pos=ZERO_POSITION())
Creates an empty ListElement type ElementPtr.
Definition data.cc:299
static isc::data::ConstElementPtr getContext(isc::data::ConstElementPtr parent)
Get user context.
Definition adaptor.cc:20
void getMandatoryDivergingLeaf(isc::data::ElementPtr &storage, libyang::DataNode const &data_node, std::string const &name, std::string const &yang_name) const
Retrieves a child YANG data node identified by one name from the given parent YANG container node and...
void setMandatoryLeaf(isc::data::ConstElementPtr const &from, std::string const &xpath, std::string const &name, libyang::LeafBaseType const type)
Get an element from given ElementPtr node and set it in sysrepo at given xpath.
isc::data::ElementPtr getItemFromAbsoluteXpath(std::string const &xpath) const
Translate a basic value from YANG to JSON for a given absolute xpath.
void checkAndSetLeaf(isc::data::ConstElementPtr const &from, std::string const &xpath, std::string const &name, libyang::LeafBaseType const type)
Get an element from given ElementPtr node and set it in sysrepo at given xpath.
Definition translator.cc:63
static std::string decode64(std::string const &input)
Decode a YANG element of binary type to a string that can be stored in an Element::string JSON.
isc::data::ElementPtr getItem(libyang::DataNode const &data_node, std::string const &xpath) const
Translate a basic value from YANG to JSON for a given xpath that is relative to the given source node...
static isc::data::ElementPtr translateFromYang(std::optional< libyang::DataNode > data_node)
Translate basic value from the given YANG data node to JSON element.
void setMandatoryDivergingLeaf(isc::data::ConstElementPtr const &from, std::string const &xpath, std::string const &name, std::string const &yang_name, libyang::LeafBaseType const type)
Get an element from given ElementPtr node and set it in sysrepo at given xpath.
libyang::DataNode findXPath(std::string const &xpath) const
Retrieves a YANG data node by xpath.
void getMandatoryLeaf(isc::data::ElementPtr &storage, libyang::DataNode const &data_node, std::string const &name) const
Retrieves a child YANG data node identified by name from the given parent YANG container node and sto...
void checkAndGetLeaf(isc::data::ElementPtr &storage, libyang::DataNode const &data_node, std::string const &name) const
Retrieves a child YANG data node identified by name from the given parent YANG container node and sto...
Definition translator.cc:32
void checkAndSetUserContext(isc::data::ConstElementPtr const &from, std::string const &xpath)
Get an element from given ElementPtr node and set it in sysrepo at given xpath.
Definition translator.cc:99
static Serializer initializeSerializer()
Initializes the serializer which is used to translate the string value of an Element to a string that...
void deleteItem(const std::string &xpath)
Delete basic value from YANG.
std::unordered_map< libyang::LeafBaseType, std::function< std::string const (std::string const &)> > Serializer
Maps YANG types to functions that transform the string representation of an Element into a string tha...
Definition translator.h:413
void checkAndGetDivergingLeaf(isc::data::ElementPtr &storage, libyang::DataNode const &data_node, std::string const &name, std::string const &yang_name) const
Retrieves a child YANG data node identified by name from the given parent YANG container node and sto...
Definition translator.cc:42
void setItem(const std::string &xpath, isc::data::ConstElementPtr const elem, libyang::LeafBaseType const type)
Translate and set basic value from JSON to YANG.
void checkAndSetDivergingLeaf(isc::data::ConstElementPtr const &from, std::string const &xpath, std::string const &name, std::string const &yang_name, libyang::LeafBaseType const type)
Get an element from given ElementPtr node and set it in sysrepo at given xpath.
Definition translator.cc:74
std::unordered_map< libyang::LeafBaseType, std::function< isc::data::ElementPtr const (std::string const &)> > Deserializer
Maps YANG types to functions that transform a YANG type into an ElementPtr.
Definition translator.h:402
bool schemaNodeExists(std::string const &xpath) const
Checks whether a YANG node exists in the schema.
void checkAndGetAndJsonifyLeaf(isc::data::ElementPtr &storage, libyang::DataNode const &data_node, const std::string &name) const
Retrieves a child YANG data node identified by name from the given parent YANG container node,...
Definition translator.cc:53
void checkAndSetLeafList(isc::data::ConstElementPtr const &from, std::string const &xpath, std::string const &name, libyang::LeafBaseType const type)
Get an element from given ElementPtr node and set it in sysrepo at given xpath as a leaf-list.
Definition translator.cc:86
sysrepo::Session session_
The sysrepo session.
Definition translator.h:424
std::optional< libyang::DataNode > getData(std::string const &xpath) const
Get a YANG data node found at the given absolute xpath.
void checkAndStringifyAndSetLeaf(isc::data::ConstElementPtr const &from, std::string const &xpath, std::string const &name)
Get an element from given ElementPtr node and set it in sysrepo at given xpath.
static std::optional< std::string > translateToYang(isc::data::ConstElementPtr const &elem, libyang::LeafBaseType const type)
Translate basic value from JSON to YANG.
static Deserializer initializeDeserializer()
Initializes the deserializer which is used to translate a YANG node to an ElementPtr.
static std::string encode64(std::string const &input)
Encode a string such that it can be stored in a YANG element of binary type.
Translator(sysrepo::Session session, const std::string &model)
Constructor.
Definition translator.cc:27
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< const Element > ConstElementPtr
Definition data.h:29
boost::shared_ptr< Element > ElementPtr
Definition data.h:28
string encodeBase64(const vector< uint8_t > &binary)
Encode binary data in the base64 format.
Definition encode.cc:337
void decodeBase64(const std::string &encoded_str, std::vector< uint8_t > &output)
Decode a base64 encoded string into binary data.
Definition encode.cc:343
Defines the logger used by the top-level component of kea-lfc.
Missing node error.
Generic NETCONF error.