blob: b44ef5faed528e0ebdc574484adecc695165a9c5 [file] [log] [blame]
Václav Kubernát0d4db442018-07-18 17:18:43 +02001/*
2 * Copyright (C) 2018 CESNET, https://photonics.cesnet.cz/
3 * Copyright (C) 2018 FIT CVUT, https://fit.cvut.cz/
4 *
5 * Written by Václav Kubernát <kubervac@fit.cvut.cz>
6 *
7*/
8
9#include <libyang/Libyang.hpp>
Václav Kubernátc31bd602019-03-07 11:44:48 +010010#include <libyang/Tree_Data.hpp>
Václav Kubernát0d4db442018-07-18 17:18:43 +020011#include <libyang/Tree_Schema.hpp>
12#include <string_view>
Václav Kubernát26b56082020-02-03 18:28:56 +010013#include "UniqueResource.hpp"
Václav Kubernát0d4db442018-07-18 17:18:43 +020014#include "utils.hpp"
15#include "yang_schema.hpp"
16
17class YangLoadError : public std::runtime_error {
18public:
19 using std::runtime_error::runtime_error;
20 ~YangLoadError() override = default;
21};
22
23class UnsupportedYangTypeException : public std::runtime_error {
24public:
25 using std::runtime_error::runtime_error;
26 ~UnsupportedYangTypeException() override = default;
27};
28
29class InvalidSchemaQueryException : public std::runtime_error {
30public:
31 using std::runtime_error::runtime_error;
32 ~InvalidSchemaQueryException() override = default;
33};
34
Václav Kubernát2eaceb82018-10-08 19:56:30 +020035template <typename T>
36std::string pathToYangAbsSchemPath(const T& path)
Václav Kubernát0d4db442018-07-18 17:18:43 +020037{
38 std::string res = "/";
39 std::string currentModule;
40
41 for (const auto& it : path.m_nodes) {
42 const auto name = nodeToSchemaString(it);
43
44 if (it.m_suffix.type() == typeid(module_)) {
45 currentModule = name;
46 continue;
47 } else {
48 res += currentModule + ":";
49 res += name + "/";
50 }
51 }
52
53 return res;
54}
55
56YangSchema::YangSchema()
Václav Kubernáta6c5fff2018-09-07 15:16:25 +020057 : m_context(std::make_shared<libyang::Context>(nullptr, LY_CTX_DISABLE_SEARCHDIRS | LY_CTX_DISABLE_SEARCHDIR_CWD))
Václav Kubernát0d4db442018-07-18 17:18:43 +020058{
Václav Kubernát0d4db442018-07-18 17:18:43 +020059}
60
Václav Kubernát1d50a5b2020-02-03 16:44:22 +010061YangSchema::YangSchema(std::shared_ptr<libyang::Context> lyCtx)
62 : m_context(lyCtx)
63{
64
65}
66
Václav Kubernát0d4db442018-07-18 17:18:43 +020067YangSchema::~YangSchema() = default;
68
69void YangSchema::addSchemaString(const char* schema)
70{
71 if (!m_context->parse_module_mem(schema, LYS_IN_YANG)) {
72 throw YangLoadError("Couldn't load schema");
73 }
74}
75
76void YangSchema::addSchemaDirectory(const char* directoryName)
77{
78 if (m_context->set_searchdir(directoryName)) {
79 throw YangLoadError("Couldn't add schema search directory");
80 }
81}
82
83void YangSchema::addSchemaFile(const char* filename)
84{
85 if (!m_context->parse_module_path(filename, LYS_IN_YANG)) {
86 throw YangLoadError("Couldn't load schema");
87 }
88}
89
Václav Kubernát75877de2019-11-20 17:43:02 +010090bool YangSchema::isModule(const std::string& name) const
Václav Kubernát0d4db442018-07-18 17:18:43 +020091{
92 const auto set = modules();
93 return set.find(name) != set.end();
94}
95
Václav Kubernát2eaceb82018-10-08 19:56:30 +020096bool YangSchema::listHasKey(const schemaPath_& location, const ModuleNodePair& node, const std::string& key) const
Václav Kubernát0d4db442018-07-18 17:18:43 +020097{
98 if (!isList(location, node))
99 return false;
100 const auto keys = listKeys(location, node);
101 return keys.find(key) != keys.end();
102}
103
Václav Kubernát2db124c2020-05-28 21:58:36 +0200104bool YangSchema::listHasKey(const schemaPath_& listPath, const std::string& key) const
105{
106 const auto keys = listKeys(listPath);
107 return keys.find(key) != keys.end();
108}
109
Václav Kubernátc3866792020-02-20 14:12:56 +0100110bool YangSchema::leafIsKey(const std::string& leafPath) const
111{
112 auto node = getSchemaNode(leafPath);
113 if (!node || node->nodetype() != LYS_LEAF)
114 return false;
115
116 return libyang::Schema_Node_Leaf{node}.is_key().get();
117}
118
Václav Kubernát47a3f672019-11-08 15:42:43 +0100119libyang::S_Schema_Node YangSchema::impl_getSchemaNode(const std::string& node) const
Václav Kubernát0d4db442018-07-18 17:18:43 +0200120{
Václav Kubernátf2b91e02019-04-11 15:36:48 +0200121 // If no node is found find_path prints an error message, so we have to
122 // disable logging
123 // https://github.com/CESNET/libyang/issues/753
124 {
125 int oldOptions;
126 auto logBlocker = make_unique_resource(
127 [&oldOptions]() {
128 oldOptions = libyang::set_log_options(0);
129 },
130 [&oldOptions]() {
131 libyang::set_log_options(oldOptions);
132 });
Václav Kubernát47a3f672019-11-08 15:42:43 +0100133 return m_context->get_node(nullptr, node.c_str());
Václav Kubernátf2b91e02019-04-11 15:36:48 +0200134 }
Václav Kubernát0d4db442018-07-18 17:18:43 +0200135}
136
Václav Kubernát47a3f672019-11-08 15:42:43 +0100137
138libyang::S_Schema_Node YangSchema::getSchemaNode(const std::string& node) const
139{
140 return impl_getSchemaNode(node);
141}
142
143libyang::S_Schema_Node YangSchema::getSchemaNode(const schemaPath_& location, const ModuleNodePair& node) const
144{
Václav Kubernátefcac932020-01-10 15:26:32 +0100145 std::string absPath = joinPaths(pathToSchemaString(location, Prefixes::Always), fullNodeName(location, node));
Václav Kubernát47a3f672019-11-08 15:42:43 +0100146
147 return impl_getSchemaNode(absPath);
148}
149
Václav Kubernát2db124c2020-05-28 21:58:36 +0200150libyang::S_Schema_Node YangSchema::getSchemaNode(const schemaPath_& listPath) const
151{
152 std::string absPath = pathToSchemaString(listPath, Prefixes::Always);
153 return impl_getSchemaNode(absPath);
154}
155
156namespace {
157const std::set<std::string> impl_listKeys(const libyang::S_Schema_Node_List& list)
Václav Kubernát0d4db442018-07-18 17:18:43 +0200158{
159 std::set<std::string> keys;
Václav Kubernát2db124c2020-05-28 21:58:36 +0200160 const auto& keysVec = list->keys();
Václav Kubernát0d4db442018-07-18 17:18:43 +0200161
Václav Kubernát90de9502019-11-20 17:19:44 +0100162 std::transform(keysVec.begin(), keysVec.end(), std::inserter(keys, keys.begin()), [](const auto& it) { return it->name(); });
Václav Kubernát0d4db442018-07-18 17:18:43 +0200163 return keys;
164}
Václav Kubernát2db124c2020-05-28 21:58:36 +0200165}
166
167const std::set<std::string> YangSchema::listKeys(const schemaPath_& location, const ModuleNodePair& node) const
168{
169 if (!isList(location, node))
170 return {};
171 auto list = std::make_shared<libyang::Schema_Node_List>(getSchemaNode(location, node));
172 return impl_listKeys(list);
173}
174
175const std::set<std::string> YangSchema::listKeys(const schemaPath_& listPath) const
176{
177 auto list = std::make_shared<libyang::Schema_Node_List>(getSchemaNode(listPath));
178 return impl_listKeys(list);
179}
Václav Kubernát0d4db442018-07-18 17:18:43 +0200180
Václav Kubernát3a99f002020-03-31 02:27:41 +0200181namespace {
Václav Kubernát2984f442020-02-20 17:43:35 +0100182std::set<enum_> enumValues(const libyang::S_Type& typeArg)
Václav Kubernát0d4db442018-07-18 17:18:43 +0200183{
Václav Kubernát2984f442020-02-20 17:43:35 +0100184 auto type = typeArg;
Václav Kubernát3a99f002020-03-31 02:27:41 +0200185 auto enm = type->info()->enums()->enm();
186 // The enum can be a derived type and enm() only returns values,
187 // if that specific typedef changed the possible values. So we go
188 // up the hierarchy until we find a typedef that defined these values.
189 while (enm.empty()) {
190 type = type->der()->type();
191 enm = type->info()->enums()->enm();
Václav Kubernát6a8d1d92019-04-24 20:30:36 +0200192 }
Václav Kubernát3a99f002020-03-31 02:27:41 +0200193
194 std::vector<libyang::S_Type_Enum> enabled;
195 std::copy_if(enm.begin(), enm.end(), std::back_inserter(enabled), [](const libyang::S_Type_Enum& it) {
196 auto iffeatures = it->iffeature();
197 return std::all_of(iffeatures.begin(), iffeatures.end(), [](auto it) { return it->value(); });
198 });
199
200 std::set<enum_> enumSet;
201 std::transform(enabled.begin(), enabled.end(), std::inserter(enumSet, enumSet.end()), [](auto it) { return enum_{it->name()}; });
202 return enumSet;
Václav Kubernát6a8d1d92019-04-24 20:30:36 +0200203}
204
Václav Kubernát2984f442020-02-20 17:43:35 +0100205std::set<identityRef_> validIdentities(const libyang::S_Type& type)
Václav Kubernát3a99f002020-03-31 02:27:41 +0200206{
207 std::set<identityRef_> identSet;
208
209 // auto topLevelModule = leaf->module();
210
Václav Kubernát2984f442020-02-20 17:43:35 +0100211 auto info = type->info();
Václav Kubernát3a99f002020-03-31 02:27:41 +0200212 for (auto base : info->ident()->ref()) { // Iterate over all bases
213 identSet.emplace(base->module()->name(), base->name());
214 // Iterate over derived identities (this is recursive!)
215 for (auto derived : base->der()->schema()) {
216 identSet.emplace(derived->module()->name(), derived->name());
217 }
218 }
219
220 return identSet;
221}
222
Václav Kubernát2984f442020-02-20 17:43:35 +0100223std::string leafrefPath(const libyang::S_Type& type)
Václav Kubernát3a99f002020-03-31 02:27:41 +0200224{
Václav Kubernát2984f442020-02-20 17:43:35 +0100225 return type->info()->lref()->target()->path(LYS_PATH_FIRST_PREFIX);
Václav Kubernát3a99f002020-03-31 02:27:41 +0200226}
227}
228
Václav Kubernát5b8a8f32020-05-20 00:57:22 +0200229template <typename NodeType>
Václav Kubernát13b23d72020-04-16 21:49:51 +0200230yang::TypeInfo YangSchema::impl_leafType(const libyang::S_Schema_Node& node) const
Václav Kubernát6a8d1d92019-04-24 20:30:36 +0200231{
232 using namespace std::string_literals;
Václav Kubernát5b8a8f32020-05-20 00:57:22 +0200233 auto leaf = std::make_shared<NodeType>(node);
Václav Kubernát13b23d72020-04-16 21:49:51 +0200234 auto leafUnits = leaf->units();
235 std::function<yang::TypeInfo(std::shared_ptr<libyang::Type>)> resolveType;
236 resolveType = [this, &resolveType, leaf, leafUnits] (std::shared_ptr<libyang::Type> type) -> yang::TypeInfo {
237 yang::LeafDataType resType;
Václav Kubernát2984f442020-02-20 17:43:35 +0100238 switch (type->base()) {
239 case LY_TYPE_STRING:
Václav Kubernát13b23d72020-04-16 21:49:51 +0200240 resType.emplace<yang::String>();
241 break;
Václav Kubernát2984f442020-02-20 17:43:35 +0100242 case LY_TYPE_DEC64:
Václav Kubernát13b23d72020-04-16 21:49:51 +0200243 resType.emplace<yang::Decimal>();
244 break;
Václav Kubernát2984f442020-02-20 17:43:35 +0100245 case LY_TYPE_BOOL:
Václav Kubernát13b23d72020-04-16 21:49:51 +0200246 resType.emplace<yang::Bool>();
247 break;
Václav Kubernát2984f442020-02-20 17:43:35 +0100248 case LY_TYPE_INT8:
Václav Kubernát13b23d72020-04-16 21:49:51 +0200249 resType.emplace<yang::Int8>();
250 break;
Václav Kubernát2984f442020-02-20 17:43:35 +0100251 case LY_TYPE_INT16:
Václav Kubernát13b23d72020-04-16 21:49:51 +0200252 resType.emplace<yang::Int16>();
253 break;
Václav Kubernát2984f442020-02-20 17:43:35 +0100254 case LY_TYPE_INT32:
Václav Kubernát13b23d72020-04-16 21:49:51 +0200255 resType.emplace<yang::Int32>();
256 break;
Václav Kubernát2984f442020-02-20 17:43:35 +0100257 case LY_TYPE_INT64:
Václav Kubernát13b23d72020-04-16 21:49:51 +0200258 resType.emplace<yang::Int64>();
259 break;
Václav Kubernát2984f442020-02-20 17:43:35 +0100260 case LY_TYPE_UINT8:
Václav Kubernát13b23d72020-04-16 21:49:51 +0200261 resType.emplace<yang::Uint8>();
262 break;
Václav Kubernát2984f442020-02-20 17:43:35 +0100263 case LY_TYPE_UINT16:
Václav Kubernát13b23d72020-04-16 21:49:51 +0200264 resType.emplace<yang::Uint16>();
265 break;
Václav Kubernát2984f442020-02-20 17:43:35 +0100266 case LY_TYPE_UINT32:
Václav Kubernát13b23d72020-04-16 21:49:51 +0200267 resType.emplace<yang::Uint32>();
268 break;
Václav Kubernát2984f442020-02-20 17:43:35 +0100269 case LY_TYPE_UINT64:
Václav Kubernát13b23d72020-04-16 21:49:51 +0200270 resType.emplace<yang::Uint64>();
271 break;
Václav Kubernát2984f442020-02-20 17:43:35 +0100272 case LY_TYPE_BINARY:
Václav Kubernát13b23d72020-04-16 21:49:51 +0200273 resType.emplace<yang::Binary>();
274 break;
Jan Kundrát379bb572020-05-07 03:23:13 +0200275 case LY_TYPE_EMPTY:
276 resType.emplace<yang::Empty>();
277 break;
Václav Kubernát2984f442020-02-20 17:43:35 +0100278 case LY_TYPE_ENUM:
Václav Kubernát13b23d72020-04-16 21:49:51 +0200279 resType.emplace<yang::Enum>(enumValues(type));
280 break;
Václav Kubernát2984f442020-02-20 17:43:35 +0100281 case LY_TYPE_IDENT:
Václav Kubernát13b23d72020-04-16 21:49:51 +0200282 resType.emplace<yang::IdentityRef>(validIdentities(type));
283 break;
Václav Kubernát2984f442020-02-20 17:43:35 +0100284 case LY_TYPE_LEAFREF:
Václav Kubernát13b23d72020-04-16 21:49:51 +0200285 resType.emplace<yang::LeafRef>(::leafrefPath(type), std::make_unique<yang::TypeInfo>(leafType(::leafrefPath(type))));
286 break;
Václav Kubernát2984f442020-02-20 17:43:35 +0100287 case LY_TYPE_UNION:
288 {
Václav Kubernát13b23d72020-04-16 21:49:51 +0200289 auto resUnion = yang::Union{};
Václav Kubernát2984f442020-02-20 17:43:35 +0100290 for (auto unionType : type->info()->uni()->types()) {
Václav Kubernát13b23d72020-04-16 21:49:51 +0200291 resUnion.m_unionTypes.push_back(resolveType(unionType));
Václav Kubernát2984f442020-02-20 17:43:35 +0100292 }
Václav Kubernát13b23d72020-04-16 21:49:51 +0200293 resType.emplace<yang::Union>(std::move(resUnion));
294 break;
Václav Kubernát2984f442020-02-20 17:43:35 +0100295 }
296 default:
297 using namespace std::string_literals;
298 throw UnsupportedYangTypeException("the type of "s + leaf->name() + " is not supported: " + std::to_string(leaf->type()->base()));
299 }
Václav Kubernát13b23d72020-04-16 21:49:51 +0200300
301 std::optional<std::string> resUnits;
302
303 if (leafUnits) {
304 resUnits = leafUnits;
305 } else {
306 for (auto parentTypedef = type->der(); parentTypedef; parentTypedef = parentTypedef->type()->der()) {
307 auto units = parentTypedef->units();
308 if (units) {
309 resUnits = units;
310 break;
311 }
312 }
313 }
314
315 return yang::TypeInfo(resType, resUnits);
316 };
Václav Kubernát2984f442020-02-20 17:43:35 +0100317 return resolveType(leaf->type());
Václav Kubernát6a8d1d92019-04-24 20:30:36 +0200318}
319
Václav Kubernát13b23d72020-04-16 21:49:51 +0200320yang::TypeInfo YangSchema::leafType(const schemaPath_& location, const ModuleNodePair& node) const
Václav Kubernát9bf36852020-02-18 17:47:56 +0100321{
Václav Kubernát5b8a8f32020-05-20 00:57:22 +0200322 auto lyNode = getSchemaNode(location, node);
323 switch (lyNode->nodetype()) {
324 case LYS_LEAF:
325 return impl_leafType<libyang::Schema_Node_Leaf>(lyNode);
326 case LYS_LEAFLIST:
327 return impl_leafType<libyang::Schema_Node_Leaflist>(lyNode);
328 default:
329 throw std::logic_error("YangSchema::leafType: type must be leaf or leaflist");
330 }
Václav Kubernát9bf36852020-02-18 17:47:56 +0100331}
332
Václav Kubernát13b23d72020-04-16 21:49:51 +0200333yang::TypeInfo YangSchema::leafType(const std::string& path) const
Václav Kubernát9bf36852020-02-18 17:47:56 +0100334{
Václav Kubernát5b8a8f32020-05-20 00:57:22 +0200335 auto lyNode = getSchemaNode(path);
336 switch (lyNode->nodetype()) {
337 case LYS_LEAF:
338 return impl_leafType<libyang::Schema_Node_Leaf>(lyNode);
339 case LYS_LEAFLIST:
340 return impl_leafType<libyang::Schema_Node_Leaflist>(lyNode);
341 default:
342 throw std::logic_error("YangSchema::leafType: type must be leaf or leaflist");
343 }
Václav Kubernát9bf36852020-02-18 17:47:56 +0100344}
Václav Kubernát6a8d1d92019-04-24 20:30:36 +0200345
Václav Kubernát6fcd0282020-02-21 16:33:08 +0100346std::optional<std::string> YangSchema::leafTypeName(const std::string& path) const
347{
348 libyang::Schema_Node_Leaf leaf(getSchemaNode(path));
Václav Kubernát76ba4ec2020-05-18 13:26:56 +0200349 return leaf.type()->der().get() && leaf.type()->der()->type()->der().get() ? std::optional{leaf.type()->der()->name()} : std::nullopt;
Václav Kubernát6fcd0282020-02-21 16:33:08 +0100350}
351
Václav Kubernátbd5e3c22020-02-19 15:22:00 +0100352std::string YangSchema::leafrefPath(const std::string& leafrefPath) const
353{
354 using namespace std::string_literals;
355 libyang::Schema_Node_Leaf leaf(getSchemaNode(leafrefPath));
356 return leaf.type()->info()->lref()->target()->path(LYS_PATH_FIRST_PREFIX);
357}
Václav Kubernát0d4db442018-07-18 17:18:43 +0200358
359std::set<std::string> YangSchema::modules() const
360{
Jan Kundrát4030b772018-08-23 15:54:56 +0200361 const auto& modules = m_context->get_module_iter();
Václav Kubernát0d4db442018-07-18 17:18:43 +0200362
363 std::set<std::string> res;
Václav Kubernát90de9502019-11-20 17:19:44 +0100364 std::transform(modules.begin(), modules.end(), std::inserter(res, res.end()), [](const auto module) { return module->name(); });
Václav Kubernát0d4db442018-07-18 17:18:43 +0200365 return res;
366}
367
Václav Kubernát95b08872020-04-28 01:04:17 +0200368std::set<ModuleNodePair> YangSchema::availableNodes(const boost::variant<dataPath_, schemaPath_, module_>& path, const Recursion recursion) const
Václav Kubernát0d4db442018-07-18 17:18:43 +0200369{
370 using namespace std::string_view_literals;
Václav Kubernát95b08872020-04-28 01:04:17 +0200371 std::set<ModuleNodePair> res;
Václav Kubernáte7d4aea2018-09-11 18:15:48 +0200372 std::vector<libyang::S_Schema_Node> nodes;
Václav Kubernát3a823f42020-04-29 23:40:21 +0200373 std::string topLevelModule;
Václav Kubernáte7d4aea2018-09-11 18:15:48 +0200374
Václav Kubernát3a823f42020-04-29 23:40:21 +0200375 if (path.type() == typeid(module_)) {
376 nodes = m_context->get_module(boost::get<module_>(path).m_name.c_str())->data_instantiables(0);
Václav Kubernát0d4db442018-07-18 17:18:43 +0200377 } else {
Václav Kubernát3a823f42020-04-29 23:40:21 +0200378 auto schemaPath = anyPathToSchemaPath(path);
379 if (schemaPath.m_nodes.empty()) {
380 nodes = m_context->data_instantiables(0);
381 } else {
382 const auto pathString = pathToSchemaString(schemaPath, Prefixes::Always);
383 const auto node = getSchemaNode(pathString);
384 nodes = node->child_instantiables(0);
385 topLevelModule = schemaPath.m_nodes.begin()->m_prefix->m_name;
386 }
Václav Kubernát0d4db442018-07-18 17:18:43 +0200387 }
Václav Kubernáte7d4aea2018-09-11 18:15:48 +0200388
Václav Kubernátef085742020-04-21 09:28:44 +0200389 for (const auto& node : nodes) {
Václav Kubernáte7d4aea2018-09-11 18:15:48 +0200390 if (node->module()->name() == "ietf-yang-library"sv)
Václav Kubernát89728d82018-09-13 16:28:28 +0200391 continue;
Václav Kubernátaaafeae2020-05-05 15:41:45 +0200392
Václav Kubernáte7d4aea2018-09-11 18:15:48 +0200393 if (recursion == Recursion::Recursive) {
394 for (auto it : node->tree_dfs()) {
Václav Kubernát95b08872020-04-28 01:04:17 +0200395 res.insert(ModuleNodePair(boost::none, it->path(LYS_PATH_FIRST_PREFIX)));
Václav Kubernáte7d4aea2018-09-11 18:15:48 +0200396 }
397 } else {
Václav Kubernát95b08872020-04-28 01:04:17 +0200398 ModuleNodePair toInsert;
Václav Kubernát3a823f42020-04-29 23:40:21 +0200399 if (topLevelModule.empty() || topLevelModule != node->module()->name()) {
Václav Kubernát82d74632020-05-11 15:59:53 +0200400 toInsert.first = node->module()->type() == 0 ? node->module()->name() : libyang::Submodule(node->module()).belongsto()->name();
Václav Kubernát4f77a252019-02-19 16:51:30 +0100401 }
Václav Kubernát95b08872020-04-28 01:04:17 +0200402 toInsert.second = node->name();
Václav Kubernát4f77a252019-02-19 16:51:30 +0100403 res.insert(toInsert);
Václav Kubernáte7d4aea2018-09-11 18:15:48 +0200404 }
405 }
406
Václav Kubernát0d4db442018-07-18 17:18:43 +0200407 return res;
408}
Václav Kubernáta6c5fff2018-09-07 15:16:25 +0200409
410void YangSchema::loadModule(const std::string& moduleName)
411{
412 m_context->load_module(moduleName.c_str());
413}
414
Václav Kubernátbf9c6112019-11-04 16:03:35 +0100415void YangSchema::enableFeature(const std::string& moduleName, const std::string& featureName)
416{
417 m_context->get_module(moduleName.c_str())->feature_enable(featureName.c_str());
418}
419
Václav Kubernátb52dc252019-12-04 13:03:39 +0100420void YangSchema::registerModuleCallback(const std::function<std::string(const char*, const char*, const char*, const char*)>& clb)
Václav Kubernáta6c5fff2018-09-07 15:16:25 +0200421{
422 auto lambda = [clb](const char* mod_name, const char* mod_revision, const char* submod_name, const char* submod_revision) {
423 (void)submod_revision;
Václav Kubernátb52dc252019-12-04 13:03:39 +0100424 auto moduleSource = clb(mod_name, mod_revision, submod_name, submod_revision);
Václav Kubernáta6c5fff2018-09-07 15:16:25 +0200425 if (moduleSource.empty()) {
426 return libyang::Context::mod_missing_cb_return{LYS_IN_YANG, nullptr};
427 }
428 return libyang::Context::mod_missing_cb_return{LYS_IN_YANG, strdup(moduleSource.c_str())};
429 };
430
431 auto deleter = [](void* data) {
432 free(data);
433 };
434 m_context->add_missing_module_callback(lambda, deleter);
435}
Václav Kubernátc31bd602019-03-07 11:44:48 +0100436
437std::shared_ptr<libyang::Data_Node> YangSchema::dataNodeFromPath(const std::string& path, const std::optional<const std::string> value) const
438{
439 return std::make_shared<libyang::Data_Node>(m_context,
440 path.c_str(),
441 value ? value.value().c_str() : nullptr,
442 LYD_ANYDATA_CONSTSTRING,
Václav Kubernátab612e92019-11-26 19:51:31 +0100443 LYD_PATH_OPT_EDIT);
Václav Kubernátc31bd602019-03-07 11:44:48 +0100444}
445
446std::shared_ptr<libyang::Module> YangSchema::getYangModule(const std::string& name)
447{
448 return m_context->get_module(name.c_str(), nullptr, 0);
449}
Václav Kubernát34ee85a2020-02-18 17:12:12 +0100450
451namespace {
452yang::NodeTypes impl_nodeType(const libyang::S_Schema_Node& node)
453{
454 if (!node) {
455 throw InvalidNodeException();
456 }
457 switch (node->nodetype()) {
458 case LYS_CONTAINER:
459 return libyang::Schema_Node_Container{node}.presence() ? yang::NodeTypes::PresenceContainer : yang::NodeTypes::Container;
460 case LYS_LEAF:
461 return yang::NodeTypes::Leaf;
462 case LYS_LIST:
463 return yang::NodeTypes::List;
Václav Kubernátaaafeae2020-05-05 15:41:45 +0200464 case LYS_RPC:
465 return yang::NodeTypes::Rpc;
466 case LYS_ACTION:
467 return yang::NodeTypes::Action;
468 case LYS_NOTIF:
469 return yang::NodeTypes::Notification;
470 case LYS_ANYXML:
471 return yang::NodeTypes::AnyXml;
472 case LYS_LEAFLIST:
473 return yang::NodeTypes::LeafList;
Václav Kubernát34ee85a2020-02-18 17:12:12 +0100474 default:
Václav Kubernát2a141392020-02-18 17:12:32 +0100475 throw InvalidNodeException(); // FIXME: Implement all types.
Václav Kubernát34ee85a2020-02-18 17:12:12 +0100476 }
477}
478}
479
480yang::NodeTypes YangSchema::nodeType(const schemaPath_& location, const ModuleNodePair& node) const
481{
482 return impl_nodeType(getSchemaNode(location, node));
483}
484
485yang::NodeTypes YangSchema::nodeType(const std::string& path) const
486{
487 return impl_nodeType(getSchemaNode(path));
488}
Václav Kubernát1e09bd62020-02-17 15:13:38 +0100489
490std::optional<std::string> YangSchema::description(const std::string& path) const
491{
492 auto node = getSchemaNode(path.c_str());
493 return node->dsc() ? std::optional{node->dsc()} : std::nullopt;
494}
Václav Kubernát0599e9f2020-04-21 09:51:33 +0200495
Václav Kubernáta1c4c9e2020-04-22 00:37:52 +0200496yang::Status YangSchema::status(const std::string& location) const
497{
498 auto node = getSchemaNode(location.c_str());
499 if (node->flags() & LYS_STATUS_DEPRC) {
500 return yang::Status::Deprecated;
501 } else if (node->flags() & LYS_STATUS_OBSLT) {
502 return yang::Status::Obsolete;
503 } else {
504 return yang::Status::Current;
505 }
506}
507
Václav Kubernát0599e9f2020-04-21 09:51:33 +0200508bool YangSchema::isConfig(const std::string& path) const
509{
510 return getSchemaNode(path.c_str())->flags() & LYS_CONFIG_W;
511}
Václav Kubernátb1a75c62020-04-21 15:20:16 +0200512
513std::optional<std::string> YangSchema::defaultValue(const std::string& leafPath) const
514{
515 libyang::Schema_Node_Leaf leaf(getSchemaNode(leafPath));
516
517 if (auto leafDefault = leaf.dflt()) {
518 return leafDefault;
519 }
520
521 for (auto type = leaf.type()->der(); type != nullptr; type = type->type()->der()) {
522 if (auto defaultValue = type->dflt()) {
523 return defaultValue;
524 }
525 }
526
527 return std::nullopt;
528}