Migrate to libyang2
libnetconf2: getSchema and getConfig were no longer used in netconf-cli,
so I deleted them. They can get readded once the bindings get split into
a separate project.
sysrepo_access: Some sr_val stuff was removed.
YangSchema: type descriptions are not available
availableNodes returns only input nodes for RPC nodes
impl_getSchemaNode: no longer disables error printing
libyang: No longer supports leafrefs without the leaf it points to.
Depends-on: https://cesnet-gerrit-czechlight/c/CzechLight/dependencies/+/5171
Depends-on: https://gerrit.cesnet.cz/c/CzechLight/dependencies/+/5171
Change-Id: Ie49381a003a61a7bb028be7b2fa1d9d926ac4e58
diff --git a/src/libyang_utils.cpp b/src/libyang_utils.cpp
index a6b22cd..f3881fe 100644
--- a/src/libyang_utils.cpp
+++ b/src/libyang_utils.cpp
@@ -1,130 +1,131 @@
#include <boost/algorithm/string/predicate.hpp>
#include <cmath>
+#include <libyang-cpp/Context.hpp>
#include "datastore_access.hpp"
#include "libyang_utils.hpp"
#include "utils.hpp"
-leaf_data_ leafValueFromNode(libyang::S_Data_Node_Leaf_List node)
+struct impl_leafValueFromNode {
+ leaf_data_ operator()(const libyang::Empty) const
+ {
+ return empty_{};
+ }
+
+ leaf_data_ operator()(const libyang::Binary& bin) const
+ {
+ return binary_{std::string{bin.base64}};
+ }
+
+ leaf_data_ operator()(const std::vector<libyang::Bit>& bits) const
+ {
+ bits_ res;
+ std::transform(bits.begin(), bits.end(), std::back_inserter(res.m_bits), [] (const libyang::Bit& bit) {
+ return bit.name;
+ });
+ return res;
+ }
+
+ leaf_data_ operator()(const libyang::Enum& enumVal) const
+ {
+ return enum_{enumVal.name};
+ }
+
+ leaf_data_ operator()(const libyang::IdentityRef& identRef) const
+ {
+ return identityRef_{identRef.module, identRef.name};
+ }
+
+ leaf_data_ operator()(const libyang::Decimal64& dec) const
+ {
+ return dec.number * std::pow(10, -dec.digits);
+ }
+
+ leaf_data_ operator()(const std::optional<libyang::DataNode>&) const
+ {
+ throw std::runtime_error("instance-identifier is not supported");
+ }
+
+ template <typename Type>
+ leaf_data_ operator()(const Type& val) const
+ {
+ return val;
+ }
+};
+
+leaf_data_ leafValueFromNode(libyang::DataNodeTerm node)
{
- std::function<leaf_data_(libyang::S_Data_Node_Leaf_List)> impl = [&impl](libyang::S_Data_Node_Leaf_List node) -> leaf_data_ {
- // value_type() is what's ACTUALLY stored inside `node`
- // Leafrefs sometimes don't hold a reference to another, but they have the actual pointed-to value.
- switch (node->value_type()) {
- case LY_TYPE_ENUM:
- return enum_{node->value()->enm()->name()};
- case LY_TYPE_UINT8:
- return node->value()->uint8();
- case LY_TYPE_UINT16:
- return node->value()->uint16();
- case LY_TYPE_UINT32:
- return node->value()->uint32();
- case LY_TYPE_UINT64:
- return node->value()->uint64();
- case LY_TYPE_INT8:
- return node->value()->int8();
- case LY_TYPE_INT16:
- return node->value()->int16();
- case LY_TYPE_INT32:
- return node->value()->int32();
- case LY_TYPE_INT64:
- return node->value()->int64();
- case LY_TYPE_DEC64: {
- auto v = node->value()->dec64();
- return v.value * std::pow(10, -v.digits);
- }
- case LY_TYPE_BOOL:
- return node->value()->bln();
- case LY_TYPE_STRING:
- return std::string{node->value()->string()};
- case LY_TYPE_BINARY:
- return binary_{node->value()->binary()};
- case LY_TYPE_IDENT:
- return identityRef_{node->value()->ident()->module()->name(), node->value()->ident()->name()};
- case LY_TYPE_EMPTY:
- return empty_{};
- case LY_TYPE_LEAFREF: {
- auto refsTo = node->value()->leafref();
- assert(refsTo);
- return impl(std::make_shared<libyang::Data_Node_Leaf_List>(node->value()->leafref()));
- }
- case LY_TYPE_BITS: {
- auto bits = node->value()->bit();
- std::vector<libyang::S_Type_Bit> filterNull;
- std::copy_if(bits.begin(), bits.end(), std::back_inserter(filterNull), [](auto bit) { return bit; });
- bits_ res;
- std::transform(filterNull.begin(), filterNull.end(), std::inserter(res.m_bits, res.m_bits.end()), [](const auto& bit) { return bit->name(); });
- return bits_{res};
- }
- default:
- return std::string{"(can't print)"};
- }
- };
- return impl(node);
+ return std::visit(impl_leafValueFromNode{},node.value());
}
namespace {
-void impl_lyNodesToTree(DatastoreAccess::Tree& res, const std::vector<std::shared_ptr<libyang::Data_Node>> items, std::optional<std::string> ignoredXPathPrefix)
+template <typename CollectionType>
+void impl_lyNodesToTree(DatastoreAccess::Tree& res, CollectionType items, std::optional<std::string> ignoredXPathPrefix)
{
auto stripXPathPrefix = [&ignoredXPathPrefix](auto path) {
return ignoredXPathPrefix && path.find(*ignoredXPathPrefix) != std::string::npos ? path.substr(ignoredXPathPrefix->size()) : path;
};
for (const auto& it : items) {
- if (it->schema()->nodetype() == LYS_CONTAINER) {
- if (libyang::Schema_Node_Container{it->schema()}.presence()) {
+ if (it.schema().nodeType() == libyang::NodeType::Container) {
+ if (it.schema().asContainer().isPresence()) {
// The fact that the container is included in the data tree
// means that it is present and I don't need to check any
// value.
- res.emplace_back(stripXPathPrefix(it->path()), special_{SpecialValue::PresenceContainer});
+ res.emplace_back(stripXPathPrefix(std::string{it.path()}), special_{SpecialValue::PresenceContainer});
}
}
- if (it->schema()->nodetype() == LYS_LIST) {
- res.emplace_back(stripXPathPrefix(it->path()), special_{SpecialValue::List});
+ if (it.schema().nodeType() == libyang::NodeType::List) {
+ res.emplace_back(stripXPathPrefix(std::string{it.path()}), special_{SpecialValue::List});
}
- if (it->schema()->nodetype() == LYS_LEAF || it->schema()->nodetype() == LYS_LEAFLIST) {
- auto leaf = std::make_shared<libyang::Data_Node_Leaf_List>(it);
- auto value = leafValueFromNode(leaf);
- res.emplace_back(stripXPathPrefix(it->path()), value);
+ if (it.schema().nodeType() == libyang::NodeType::Leaf || it.schema().nodeType() == libyang::NodeType::Leaflist) {
+ auto term = it.asTerm();
+ auto value = leafValueFromNode(term);
+ res.emplace_back(stripXPathPrefix(std::string{it.path()}), value);
}
}
}
}
-void lyNodesToTree(DatastoreAccess::Tree& res, const std::vector<std::shared_ptr<libyang::Data_Node>> items, std::optional<std::string> ignoredXPathPrefix)
+template <typename CollectionType>
+void lyNodesToTree(DatastoreAccess::Tree& res, CollectionType items, std::optional<std::string> ignoredXPathPrefix)
{
- for (auto it = items.begin(); it < items.end(); it++) {
- if ((*it)->schema()->nodetype() == LYS_LEAFLIST) {
- auto leafListPath = stripLeafListValueFromPath((*it)->path());
+ for (auto it = items.begin(); it != items.end(); /* nothing */) {
+ if ((*it).schema().nodeType() == libyang::NodeType::Leaflist) {
+ auto leafListPath = stripLeafListValueFromPath(std::string{(*it).path()});
res.emplace_back(leafListPath, special_{SpecialValue::LeafList});
- while (it != items.end() && boost::starts_with((*it)->path(), leafListPath)) {
- impl_lyNodesToTree(res, (*it)->tree_dfs(), ignoredXPathPrefix);
+ while (it != items.end() && boost::starts_with(std::string{(*it).path()}, leafListPath)) {
+ impl_lyNodesToTree(res, it->childrenDfs(), ignoredXPathPrefix);
it++;
}
} else {
- impl_lyNodesToTree(res, (*it)->tree_dfs(), ignoredXPathPrefix);
+ impl_lyNodesToTree(res, it->childrenDfs(), ignoredXPathPrefix);
+ it++;
}
}
}
-DatastoreAccess::Tree rpcOutputToTree(const std::string& rpcPath, libyang::S_Data_Node output)
+using SiblingColl = libyang::Collection<libyang::DataNode, libyang::IterationType::Sibling>;
+using DfsColl = libyang::Collection<libyang::DataNode, libyang::IterationType::Dfs>;
+
+template
+void lyNodesToTree<SiblingColl>(DatastoreAccess::Tree& res, SiblingColl items, std::optional<std::string> ignoredXPathPrefix);
+template
+void lyNodesToTree<DfsColl>(DatastoreAccess::Tree& res, DfsColl items, std::optional<std::string> ignoredXPathPrefix);
+template
+void lyNodesToTree<libyang::Set<libyang::DataNode>>(DatastoreAccess::Tree& res, libyang::Set<libyang::DataNode> items, std::optional<std::string> ignoredXPathPrefix);
+
+DatastoreAccess::Tree rpcOutputToTree(libyang::DataNode output)
{
DatastoreAccess::Tree res;
- if (output) {
- // The output is "some top-level node". If we actually want the output of our RPC/action we need to use
- // find_path. Also, our `path` is fully prefixed, but the output paths aren't. So we use outputNode->path() to
- // get the unprefixed path.
-
- auto outputNode = output->find_path(rpcPath.c_str())->data().front();
- lyNodesToTree(res, {outputNode}, joinPaths(outputNode->path(), "/"));
- }
+ lyNodesToTree(res, output.siblings(), joinPaths(std::string{output.path()}, "/"));
return res;
}
-libyang::S_Data_Node treeToRpcInput(libyang::S_Context ctx, const std::string& path, DatastoreAccess::Tree in)
+libyang::DataNode treeToRpcInput(libyang::Context ctx, const std::string& path, DatastoreAccess::Tree in)
{
- auto root = std::make_shared<libyang::Data_Node>(ctx, path.c_str(), nullptr, LYD_ANYDATA_CONSTSTRING, LYD_PATH_OPT_UPDATE);
+ auto root = ctx.newPath(path.c_str(), nullptr, libyang::CreationOptions::Update);
for (const auto& [k, v] : in) {
- root->new_path(ctx, k.c_str(), leafDataToString(v).c_str(), LYD_ANYDATA_CONSTSTRING, LYD_PATH_OPT_UPDATE);
+ root.newPath(k.c_str(), leafDataToString(v).c_str(), libyang::CreationOptions::Update);
}
return root;