utils: refactor utils::getSubtree libyang wrapper
In the change for the commit to follow Vasek suggested that
the utils::getSubtree helper could be renamed to getUniqueSubtree and
the behaviour could be changed to return std::optional<>. When no
matching node is found the function returns std::nullopt. When multiple
matching nodes are found the function throws.
This code in the next commit could benefit a little from this change.
Change-Id: I8ded7695dc383e6654f8efa44b6a5442ef904485
diff --git a/src/system/Authentication.cpp b/src/system/Authentication.cpp
index f4d10ed..35c6c7d 100644
--- a/src/system/Authentication.cpp
+++ b/src/system/Authentication.cpp
@@ -301,9 +301,9 @@
auto,
auto output) {
- auto userNode = utils::getSubtree(input, (authentication_container + "/users" ).c_str());
- auto name = utils::getValueAsString(utils::getSubtree(userNode, "name"));
- auto password = utils::getValueAsString(utils::getSubtree(userNode, "change-password/password-cleartext"));
+ auto userNode = utils::getUniqueSubtree(input, (authentication_container + "/users" ).c_str()).value();
+ auto name = utils::getValueAsString(utils::getUniqueSubtree(userNode, "name").value());
+ auto password = utils::getValueAsString(utils::getUniqueSubtree(userNode, "change-password/password-cleartext").value());
m_log->debug("Changing password for {}", name);
try {
changePassword(name, password, m_etc_shadow);
@@ -326,9 +326,9 @@
auto,
auto output) {
- auto userNode = utils::getSubtree(input, (authentication_container + "/users").c_str());
- auto name = utils::getValueAsString(utils::getSubtree(userNode, "name"));
- auto key = utils::getValueAsString(utils::getSubtree(userNode, "add-authorized-key/key"));
+ auto userNode = utils::getUniqueSubtree(input, (authentication_container + "/users").c_str()).value();
+ auto name = utils::getValueAsString(utils::getUniqueSubtree(userNode, "name").value());
+ auto key = utils::getValueAsString(utils::getUniqueSubtree(userNode, "add-authorized-key/key").value());
m_log->debug("Adding key for {}", name);
try {
addKey(name, key);
@@ -351,9 +351,9 @@
auto,
auto output) {
- auto userNode = utils::getSubtree(input, (authentication_container + "/users").c_str());
- auto name = utils::getValueAsString(utils::getSubtree(userNode, "name"));
- auto key = std::stol(utils::getValueAsString(utils::getSubtree(userNode, "authorized-keys/index")));
+ auto userNode = utils::getUniqueSubtree(input, (authentication_container + "/users").c_str()).value();
+ auto name = utils::getValueAsString(utils::getUniqueSubtree(userNode, "name").value());
+ auto key = std::stol(utils::getValueAsString(utils::getUniqueSubtree(userNode, "authorized-keys/index").value()));
m_log->debug("Removing key for {}", name);
try {
removeKey(name, key);
diff --git a/src/system/IETFInterfacesConfig.cpp b/src/system/IETFInterfacesConfig.cpp
index f28f124..9ac681a 100644
--- a/src/system/IETFInterfacesConfig.cpp
+++ b/src/system/IETFInterfacesConfig.cpp
@@ -51,12 +51,11 @@
{
const auto xpath = "ietf-ip:" + proto + "/enabled";
- try {
- auto enabled = velia::utils::getValueAsString(velia::utils::getSubtree(linkEntry, xpath.c_str()));
- return enabled == "true"s;
- } catch (const std::runtime_error&) { // leaf and the presence container missing
- return false;
+ if (auto node = velia::utils::getUniqueSubtree(linkEntry, xpath.c_str())) {
+ return velia::utils::getValueAsString(node.value()) == "true"s;
}
+
+ return false;
}
}
@@ -90,7 +89,7 @@
for (const auto& linkEntry : linkEntries->data()) {
std::map<std::string, std::vector<std::string>> configValues;
- auto linkName = utils::getValueAsString(utils::getSubtree(linkEntry, "name"));
+ auto linkName = utils::getValueAsString(utils::getUniqueSubtree(linkEntry, "name").value());
if (auto set = linkEntry->find_path("description"); set->number() != 0) {
configValues["Network"].push_back("Description="s + utils::getValueAsString(set->data().front()));
@@ -107,8 +106,8 @@
const auto addresses = linkEntry->find_path(IPAddressListXPath.c_str());
for (const auto& ipEntry : addresses->data()) {
- auto ipAddress = utils::getValueAsString(utils::getSubtree(ipEntry, "ip"));
- auto prefixLen = utils::getValueAsString(utils::getSubtree(ipEntry, "prefix-length"));
+ auto ipAddress = utils::getValueAsString(utils::getUniqueSubtree(ipEntry, "ip").value());
+ auto prefixLen = utils::getValueAsString(utils::getUniqueSubtree(ipEntry, "prefix-length").value());
spdlog::get("system")->trace("Link {}: address {}/{} configured", linkName, ipAddress, prefixLen);
configValues["Network"].push_back("Address="s + ipAddress + "/" + prefixLen);
diff --git a/src/system/LED.cpp b/src/system/LED.cpp
index 1d0b68a..f658644 100644
--- a/src/system/LED.cpp
+++ b/src/system/LED.cpp
@@ -54,7 +54,7 @@
m_srSubscribe->rpc_subscribe_tree(
(CZECHLIGHT_SYSTEM_LEDS_MODULE_PREFIX + "uid").c_str(),
[this, uidMaxBrightness, triggerFile, brightnessFile](auto session, auto, auto input, auto, auto, auto) {
- std::string val = utils::getValueAsString(utils::getSubtree(input, (CZECHLIGHT_SYSTEM_LEDS_MODULE_PREFIX + "uid/state").c_str()));
+ std::string val = utils::getValueAsString(utils::getUniqueSubtree(input, (CZECHLIGHT_SYSTEM_LEDS_MODULE_PREFIX + "uid/state").c_str()).value());
try {
if (val == "on") {
diff --git a/src/utils/libyang.cpp b/src/utils/libyang.cpp
index d018a09..a4b7479 100644
--- a/src/utils/libyang.cpp
+++ b/src/utils/libyang.cpp
@@ -13,13 +13,17 @@
return libyang::Data_Node_Leaf_List(node).value_str();
}
-libyang::S_Data_Node getSubtree(const libyang::S_Data_Node& start, const char* path)
+std::optional<libyang::S_Data_Node> getUniqueSubtree(const libyang::S_Data_Node& start, const char* path)
{
auto set = start->find_path(path);
- if (set->number() != 1) {
- throw std::runtime_error(fmt::format("getSubtree({}, {}): didn't get exactly one match (got {})", start->path(), path, set->number()));
- }
- return set->data().front();
+ switch(set->number()) {
+ case 0:
+ return std::nullopt;
+ case 1:
+ return set->data().front();
+ default:
+ throw std::runtime_error(fmt::format("getUniqueSubtree({}, {}): more than one match (got {})", start->path(), path, set->number()));
+ }
}
}
diff --git a/src/utils/libyang.h b/src/utils/libyang.h
index 4ccc59d..389c1ac 100644
--- a/src/utils/libyang.h
+++ b/src/utils/libyang.h
@@ -7,6 +7,7 @@
#pragma once
#include <memory>
+#include <optional>
namespace libyang {
class Data_Node;
@@ -24,7 +25,7 @@
/** @brief Gets exactly one node based on `path` starting from `start`.
*
- * Throws if there is more than one matching node. Also throws if there aren't any matching nodes.
+ * Throws if there is more than one matching node. Returns std::nullopt if no node matches.
*/
-std::shared_ptr<libyang::Data_Node> getSubtree(const std::shared_ptr<libyang::Data_Node>& start, const char* path);
+std::optional<std::shared_ptr<libyang::Data_Node>> getUniqueSubtree(const std::shared_ptr<libyang::Data_Node>& start, const char* path);
}