From 009b2b01fb4a1ca854402debd66d899a264db8f2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan=20Kundr=C3=A1t?= <jan.kundrat@cesnet.cz>
Date: Fri, 14 Mar 2025 13:57:26 +0100
Subject: [PATCH 33/44] Adapt to libyang-cpp API break in opaque nodes
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Organization: Wires

I was wondering for a while whether libyang will do the right thing when
printing the RPC's output nodes in XML, but apparently it does (and we
have a test for that).

Depends-on: https://gerrit.cesnet.cz/c/CzechLight/dependencies/+/8438
Change-Id: I82425743fd2613fcbe2b696848e2feb1c47fc658
Signed-off-by: Mattias Walström <lazzer@gmail.com>
---
 CMakeLists.txt              | 2 +-
 src/restconf/Server.cpp     | 5 +++--
 src/restconf/utils/yang.cpp | 9 +++++----
 3 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 272caad..bcabe84 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -76,7 +76,7 @@ find_package(Boost 1.66 REQUIRED CONFIG COMPONENTS system thread)
 
 pkg_check_modules(SYSREPO REQUIRED sysrepo>=3.6.5 IMPORTED_TARGET)
 pkg_check_modules(SYSREPO-CPP REQUIRED IMPORTED_TARGET sysrepo-cpp>=5)
-pkg_check_modules(LIBYANG-CPP REQUIRED IMPORTED_TARGET libyang-cpp>=3)
+pkg_check_modules(LIBYANG-CPP REQUIRED IMPORTED_TARGET libyang-cpp>=4)
 pkg_check_modules(SYSTEMD IMPORTED_TARGET libsystemd)
 pkg_check_modules(PAM REQUIRED IMPORTED_TARGET pam)
 pkg_check_modules(DOCOPT REQUIRED IMPORTED_TARGET docopt)
diff --git a/src/restconf/Server.cpp b/src/restconf/Server.cpp
index bae3992..28e2e4c 100644
--- a/src/restconf/Server.cpp
+++ b/src/restconf/Server.cpp
@@ -471,7 +471,8 @@ void processActionOrRPC(std::shared_ptr<RequestContext> requestCtx, const std::c
     auto responseNode = rpcReply->child();
     responseNode->unlinkWithSiblings();
 
-    auto envelope = ctx.newOpaqueJSON(rpcNode->schema().module().name(), "output", std::nullopt);
+    // libyang auto-resolves the XML namespace when the result is printed into XML
+    auto envelope = ctx.newOpaqueJSON({rpcNode->schema().module().name(), rpcNode->schema().module().name(), "output"}, std::nullopt);
     envelope->insertChild(*responseNode);
 
     requestCtx->res.write_head(200, {
@@ -735,7 +736,7 @@ libyang::DataNode apiResource(const libyang::Context& ctx, const RestconfRequest
             }
 
             for (const auto& rpc : mod.actionRpcs()) {
-                operations.insertChild(*ctx.newOpaqueJSON(rpc.module().name(), rpc.name(), libyang::JSON{"[null]"}));
+                operations.insertChild(*ctx.newOpaqueJSON({rpc.module().name(), rpc.module().name(), rpc.name()}, libyang::JSON{"[null]"}));
             }
         }
     } else {
diff --git a/src/restconf/utils/yang.cpp b/src/restconf/utils/yang.cpp
index 8acb160..9358840 100644
--- a/src/restconf/utils/yang.cpp
+++ b/src/restconf/utils/yang.cpp
@@ -89,6 +89,7 @@ std::string as_restconf_notification(const libyang::Context& ctx, libyang::DataF
 {
     static const auto jsonNamespace = "ietf-restconf";
     static const auto xmlNamespace = "urn:ietf:params:xml:ns:netconf:notification:1.0";
+    static const auto xmlPrefix = "ietf-netconf-notifications";
 
     std::optional<libyang::DataNode> envelope;
     std::optional<libyang::DataNode> eventTime;
@@ -96,11 +97,11 @@ std::string as_restconf_notification(const libyang::Context& ctx, libyang::DataF
 
     /* The namespaces for XML and JSON envelopes are different. See https://datatracker.ietf.org/doc/html/rfc8040#section-6.4 */
     if (dataFormat == libyang::DataFormat::JSON) {
-        envelope = ctx.newOpaqueJSON(jsonNamespace, "notification", std::nullopt);
-        eventTime = ctx.newOpaqueJSON(jsonNamespace, "eventTime", libyang::JSON{timeStr});
+        envelope = ctx.newOpaqueJSON({jsonNamespace, jsonNamespace, "notification"}, std::nullopt);
+        eventTime = ctx.newOpaqueJSON({jsonNamespace, jsonNamespace, "eventTime"}, libyang::JSON{timeStr});
     } else {
-        envelope = ctx.newOpaqueXML(xmlNamespace, "notification", std::nullopt);
-        eventTime = ctx.newOpaqueXML(xmlNamespace, "eventTime", libyang::XML{timeStr});
+        envelope = ctx.newOpaqueXML({xmlNamespace, xmlPrefix, "notification"}, std::nullopt);
+        eventTime = ctx.newOpaqueXML({xmlNamespace, xmlPrefix, "eventTime"}, libyang::XML{timeStr});
     }
 
     // the notification data node holds only the notification data tree but for nested notification we should print the whole YANG data tree
-- 
2.43.0

