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/netconf_access.cpp b/src/netconf_access.cpp
index a6dbb7c..2b76e50 100644
--- a/src/netconf_access.cpp
+++ b/src/netconf_access.cpp
@@ -5,8 +5,6 @@
*
*/
-#include <libyang/Libyang.hpp>
-#include <libyang/Tree_Data.hpp>
#include "libyang_utils.hpp"
#include "netconf-client.hpp"
#include "netconf_access.hpp"
@@ -55,7 +53,7 @@
}();
if (config) {
- lyNodesToTree(res, config->tree_for());
+ lyNodesToTree(res, config->siblings());
}
return res;
}
@@ -107,22 +105,28 @@
void NetconfAccess::setLeaf(const std::string& path, leaf_data_ value)
{
auto lyValue = value.type() == typeid(empty_) ? std::nullopt : std::optional(leafDataToString(value));
- auto node = m_schema->dataNodeFromPath(path, lyValue);
- doEditFromDataNode(node);
+ auto nodes = m_schema->dataNodeFromPath(path, lyValue);
+ doEditFromDataNode(*nodes.createdParent);
}
void NetconfAccess::createItem(const std::string& path)
{
- auto node = m_schema->dataNodeFromPath(path);
- doEditFromDataNode(node);
+ auto nodes = m_schema->dataNodeFromPath(path);
+ doEditFromDataNode(*nodes.createdParent);
}
void NetconfAccess::deleteItem(const std::string& path)
{
- auto node = m_schema->dataNodeFromPath(path);
- auto container = *(node->find_path(path.c_str())->data().begin());
- container->insert_attr(m_schema->getYangModule("ietf-netconf"), "operation", "delete");
- doEditFromDataNode(node);
+ auto nodes = m_schema->dataNodeFromPath(path);
+
+ // When deleting leafs, `nodes.newNode` is opaque, because the leaf does not have a value. We need to use
+ // newAttrOpaqueJSON for opaque leafs.
+ if (nodes.createdNode->isOpaque()) {
+ nodes.createdNode->newAttrOpaqueJSON("ietf-netconf", "ietf-netconf:operation", "delete");
+ } else {
+ nodes.createdNode->newMeta(*m_schema->getYangModule("ietf-netconf"), "operation", "delete");
+ }
+ doEditFromDataNode(*nodes.createdParent);
}
struct impl_toYangInsert {
@@ -143,29 +147,29 @@
void NetconfAccess::moveItem(const std::string& source, std::variant<yang::move::Absolute, yang::move::Relative> move)
{
- auto node = m_schema->dataNodeFromPath(source);
- auto sourceNode = *(node->find_path(source.c_str())->data().begin());
- auto yangModule = m_schema->getYangModule("yang");
- sourceNode->insert_attr(yangModule, "insert", toYangInsert(move).c_str());
+ auto nodes = m_schema->dataNodeFromPath(source);
+ auto sourceNode = *(nodes.createdNode->findPath(source.c_str()));
+ auto yangModule = *m_schema->getYangModule("yang");
+ sourceNode.newMeta(yangModule, "insert", toYangInsert(move).c_str());
if (std::holds_alternative<yang::move::Relative>(move)) {
auto relative = std::get<yang::move::Relative>(move);
if (m_schema->nodeType(source) == yang::NodeTypes::LeafList) {
- sourceNode->insert_attr(yangModule, "value", leafDataToString(relative.m_path.at(".")).c_str());
+ sourceNode.newMeta(yangModule, "value", leafDataToString(relative.m_path.at(".")).c_str());
} else {
- sourceNode->insert_attr(yangModule, "key", instanceToString(relative.m_path, node->node_module()->name()).c_str());
+ sourceNode.newMeta(yangModule, "key", instanceToString(relative.m_path, std::string{nodes.createdNode->schema().module().name()}).c_str());
}
}
doEditFromDataNode(sourceNode);
}
-void NetconfAccess::doEditFromDataNode(std::shared_ptr<libyang::Data_Node> dataNode)
+void NetconfAccess::doEditFromDataNode(libyang::DataNode dataNode)
{
- auto data = dataNode->print_mem(LYD_XML, 0);
+ auto data = dataNode.printStr(libyang::DataFormat::XML, libyang::PrintFlags::WithSiblings);
if (m_serverHasNMDA) {
- m_session->editData(targetToDs_set(m_target), data);
+ m_session->editData(targetToDs_set(m_target), std::string{*data});
} else {
- m_session->editConfig(NC_DATASTORE_CANDIDATE, NC_RPC_EDIT_DFLTOP_MERGE, NC_RPC_EDIT_TESTOPT_TESTSET, NC_RPC_EDIT_ERROPT_STOP, data);
+ m_session->editConfig(NC_DATASTORE_CANDIDATE, NC_RPC_EDIT_DFLTOP_MERGE, NC_RPC_EDIT_TESTOPT_TESTSET, NC_RPC_EDIT_ERROPT_STOP, std::string{*data});
}
}
@@ -182,10 +186,13 @@
DatastoreAccess::Tree NetconfAccess::execute(const std::string& path, const Tree& input)
{
auto inputNode = treeToRpcInput(m_session->libyangContext(), path, input);
- auto data = inputNode->print_mem(LYD_XML, 0);
+ auto data = inputNode.printStr(libyang::DataFormat::XML, libyang::PrintFlags::WithSiblings);
- auto output = m_session->rpc_or_action(data);
- return rpcOutputToTree(path, output);
+ auto output = m_session->rpc_or_action(std::string{*data});
+ if (!output) {
+ return {};
+ }
+ return rpcOutputToTree(*output);
}
NC_DATASTORE toNcDatastore(Datastore datastore)
@@ -212,41 +219,41 @@
std::vector<ListInstance> NetconfAccess::listInstances(const std::string& path)
{
std::vector<ListInstance> res;
- auto list = m_schema->dataNodeFromPath(path);
+ auto keys = m_session->libyangContext().findXPath(path.c_str()).front().asList().keys();
+ auto nodes = m_session->libyangContext().newPath2(path.c_str(), nullptr, libyang::CreationOptions::Opaque);
- // This inserts selection nodes - I only want keys not other data
- // To get the keys, I have to call find_path here - otherwise I would get keys of a top-level node (which might not even be a list)
- auto keys = libyang::Schema_Node_List{(*(list->find_path(path.c_str())->data().begin()))->schema()}.keys();
+ // Here we create a tree with "selection leafs" for all they keys of our wanted list. These leafs tell NETCONF, that
+ // we only want the list's keys and not any other data.
for (const auto& keyLeaf : keys) {
- // Have to call find_path here - otherwise I'll have the list, not the leaf inside it
- auto selectionLeaf = *(m_schema->dataNodeFromPath(keyLeaf->path())->find_path(keyLeaf->path().c_str())->data().begin());
- auto actualList = *(list->find_path(path.c_str())->data().begin());
- actualList->insert(selectionLeaf);
+ // Selection leafs need to be inserted directly to the list using relative paths, that's why `newNode` is used
+ // here.
+ nodes.createdNode->newPath(keyLeaf.name().data(), nullptr, libyang::CreationOptions::Opaque);
}
- auto instances = m_session->get(list->print_mem(LYD_XML, 0));
+ // Have to use `newParent` in case our wanted list is a nested list. With `newNode` I would only send the inner
+ // nested list and not the whole tree.
+ auto instances = m_session->get(std::string{*nodes.createdParent->printStr(libyang::DataFormat::XML, libyang::PrintFlags::WithSiblings)});
if (!instances) {
return res;
}
- for (const auto& instance : instances->find_path(path.c_str())->data()) {
+ for (const auto& instance : instances->findXPath(path.c_str())) {
ListInstance instanceRes;
- // I take the first child here, because the first element (the parent of the child()) will be the list
- for (const auto& keyLeaf : instance->child()->tree_for()) {
+ for (const auto& keyLeaf : instance.child()->siblings()) {
// FIXME: even though we specified we only want the key leafs, Netopeer disregards that and sends more data,
// even lists and other stuff. We only want keys, so filter out non-leafs and non-keys
// https://github.com/CESNET/netopeer2/issues/825
- if (keyLeaf->schema()->nodetype() != LYS_LEAF) {
+ if (keyLeaf.schema().nodeType() != libyang::NodeType::Leaf) {
continue;
}
- if (!std::make_shared<libyang::Schema_Node_Leaf>(keyLeaf->schema())->is_key()) {
+ if (!keyLeaf.schema().asLeaf().isKey()) {
continue;
}
- auto leafData = std::make_shared<libyang::Data_Node_Leaf_List>(keyLeaf);
- instanceRes.insert({leafData->schema()->name(), leafValueFromNode(leafData)});
+ auto leafData = keyLeaf.asTerm();
+ instanceRes.insert({std::string{leafData.schema().name()}, leafValueFromNode(leafData)});
}
res.emplace_back(instanceRes);
}
@@ -260,5 +267,10 @@
if (!config) {
return "";
}
- return config->print_mem(format == DataFormat::Xml ? LYD_XML : LYD_JSON, LYP_WITHSIBLINGS | LYP_FORMAT);
+ auto str = config->printStr(format == DataFormat::Xml ? libyang::DataFormat::XML : libyang::DataFormat::JSON, libyang::PrintFlags::WithSiblings);
+ if (!str) {
+ return "";
+ }
+
+ return std::string{*str};
}