mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-22 01:13:00 +02:00
Bump rousette to latest GIT hash
Since we are using an old GCC we need to add a new requirement for rousette 'date' this is included in GCC 14+.
This commit is contained in:
committed by
Joachim Wiberg
parent
c456fa1c75
commit
f5884098fb
@@ -32,4 +32,5 @@ source "$BR2_EXTERNAL_INFIX_PATH/package/libyang-cpp/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/sysrepo-cpp/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/rousette/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/nghttp2-asio/Config.in"
|
||||
source "$BR2_EXTERNAL_INFIX_PATH/package/date-cpp/Config.in
|
||||
endmenu
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
From c8ec120afa3a66674ef30b10490eeeb36d806eed Mon Sep 17 00:00:00 2001
|
||||
From: Tomas Pecka <peckato1@fit.cvut.cz>
|
||||
Date: Fri, 17 Feb 2023 13:50:17 +0100
|
||||
Subject: [PATCH] Fix getting current timezone on ARM-based devices
|
||||
Our software using date on buildroot ARM-based device terminates with an
|
||||
uncaught exception.
|
||||
terminate called after throwing an instance of 'std::runtime_error'
|
||||
what(): posix/Etc/UTC not found in timezone database
|
||||
I have applied workaround from [1].
|
||||
[1] https://github.com/HowardHinnant/date/issues/252
|
||||
Bug: https://github.com/HowardHinnant/date/issues/252
|
||||
---
|
||||
src/tz.cpp | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
diff --git a/src/tz.cpp b/src/tz.cpp
|
||||
index bd9fad4..eea48ce 100644
|
||||
--- a/src/tz.cpp
|
||||
+++ b/src/tz.cpp
|
||||
@@ -3925,7 +3925,7 @@ sniff_realpath(const char* timezone)
|
||||
if (realpath(timezone, rp) == nullptr)
|
||||
throw system_error(errno, system_category(), "realpath() failed");
|
||||
auto result = extract_tz_name(rp);
|
||||
- return result != "posixrules";
|
||||
+ return result.find("posix") == decltype(result)::npos;
|
||||
}
|
||||
|
||||
const time_zone*
|
||||
--
|
||||
2.39.2
|
||||
@@ -0,0 +1,6 @@
|
||||
config BR2_PACKAGE_DATE_CPP
|
||||
bool "date-cpp"
|
||||
help
|
||||
A date and time library based on the C++11/14/17 <chrono> header
|
||||
|
||||
https://github.com/HowardHinnant/date
|
||||
@@ -0,0 +1,3 @@
|
||||
# Locally calculated
|
||||
sha256 c90f6c00fb961170560299cbda28ca2d45804913aa8b2a9f36dbb8e0028d6930 LICENSE.txt
|
||||
sha256 7a390f200f0ccd207e8cff6757e04817c1a0aec3e327b006b7eb451c57ee3538 date-3.0.1.tar.gz
|
||||
@@ -0,0 +1,10 @@
|
||||
DATE_CPP_VERSION = 3.0.1
|
||||
DATE_CPP_SITE = $(call github,HowardHinnant,date,v$(DATE_CPP_VERSION))
|
||||
DATE_CPP_INSTALL_STAGING = YES
|
||||
DATE_CPP_LICENSE = MIT
|
||||
DATE_CPP_LICENSE_FILES = LICENSE.txt
|
||||
DATE_CPP_CONF_OPTS = \
|
||||
-DBUILD_TZ_LIB=ON \
|
||||
-DUSE_SYSTEM_TZ_DB:BOOL=ON \
|
||||
-DENABLE_DATE_TESTING=OFF
|
||||
$(eval $(cmake-package))
|
||||
@@ -1,3 +1,3 @@
|
||||
# Locally calculated
|
||||
sha256 82e3758011ec44c78e98d0777799d6e12aec5b8a64b32ebb20d0fe50e32488bb LICENSE
|
||||
sha256 fc5ae5218d441afef697d4fc7912ddbe322060103c053d50fc2db829bd359458 libyang-cpp-b852ea3b9a2729da364f2c4122db05d882df37f2-br1.tar.gz
|
||||
sha256 b1ae9848c9810462fdca89b83297d5992e9c0c00399c21f65a0eef183d4789b4 libyang-cpp-38e3399c99a82d3c0f693fb19ab1e1b3cd72aed9-br1.tar.gz
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
# CPP bindings for libyang
|
||||
#
|
||||
################################################################################
|
||||
LIBYANG_CPP_VERSION = b852ea3b9a2729da364f2c4122db05d882df37f2
|
||||
LIBYANG_CPP_VERSION = 38e3399c99a82d3c0f693fb19ab1e1b3cd72aed9
|
||||
LIBYANG_CPP_SITE = https://github.com/kernelkit/libyang-cpp.git
|
||||
LIBYANG_CPP_SITE_METHOD = git
|
||||
LIBYANG_CPP_LICENSE = BSD-3-Clause
|
||||
|
||||
@@ -2,7 +2,6 @@ config BR2_PACKAGE_ROUSETTE
|
||||
bool "rousette"
|
||||
depends on BR2_USE_MMU
|
||||
select BR2_PACKAGE_BOOST
|
||||
select BR2_PACKAGE_BOOST_ATOMIC
|
||||
select BR2_PACKAGE_BOOST_THREAD
|
||||
select BR2_PACKAGE_BOOST_SYSTEM
|
||||
select BR2_PACKAGE_DOCOPT_CPP
|
||||
@@ -11,5 +10,6 @@ config BR2_PACKAGE_ROUSETTE
|
||||
select BR2_PACKAGE_NGHTTP2_ASIO
|
||||
select BR2_PACKAGE_SPDLOG
|
||||
select BR2_PACKAGE_SYSREPO_CPP
|
||||
select BR2_PACKAGE_DATE
|
||||
help
|
||||
RESTconf server
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Locally calculated
|
||||
sha256 cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30 LICENSE
|
||||
sha256 74b0d3115e73335399c5f8847fb7baa4d23497be75d12fccf56a754015af4c76 rousette-226a2410376e5befd0bf6dc180618a108b11b256-br1.tar.gz
|
||||
sha256 3ba8a5dedff9a55af0b41ef07c8ffa2400f5a08bb70dfb18f850fa0416829f5e rousette-cf7a1d6eafc29ea708f18833ceb2f297dc2b7f74-br1.tar.gz
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
#
|
||||
################################################################################
|
||||
|
||||
ROUSETTE_VERSION = 226a2410376e5befd0bf6dc180618a108b11b256
|
||||
ROUSETTE_VERSION = cf7a1d6eafc29ea708f18833ceb2f297dc2b7f74
|
||||
ROUSETTE_SITE = https://github.com/kernelkit/rousette.git
|
||||
ROUSETTE_SITE_METHOD = git
|
||||
ROUSETTE_LICENSE = Apache-2.0
|
||||
ROUSETTE_LICENSE_FILES = LICENSE
|
||||
ROUSETTE_DEPENDENCIES = boost docopt-cpp nghttp2-asio spdlog sysrepo-cpp linux-pam
|
||||
ROUSETTE_DEPENDENCIES = boost docopt-cpp nghttp2-asio spdlog sysrepo-cpp linux-pam date-cpp
|
||||
|
||||
ROUSETTE_CONF_OPTS = \
|
||||
-DTESTAR=on \
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
# Locally calculated
|
||||
sha256 82e3758011ec44c78e98d0777799d6e12aec5b8a64b32ebb20d0fe50e32488bb LICENSE
|
||||
sha256 74d7d89307c9fc188c7f23ae5128fe320a569f455a325286122eaa927a0d95ed sysrepo-cpp-99747f74e57a09c664251ea1f4e059e3f4f8e66a-br1.tar.gz
|
||||
sha256 f675acde97f95058252b2b9338e9d05e755dd4bf394ab8d68ea6edbb8cd9d75c sysrepo-cpp-e59193c772fa0e5963eff216b4fbb574383a64f2-br1.tar.gz
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#
|
||||
################################################################################
|
||||
|
||||
SYSREPO_CPP_VERSION = 99747f74e57a09c664251ea1f4e059e3f4f8e66a
|
||||
SYSREPO_CPP_VERSION = e59193c772fa0e5963eff216b4fbb574383a64f2
|
||||
SYSREPO_CPP_SITE = https://github.com/kernelkit/sysrepo-cpp.git
|
||||
SYSREPO_CPP_SITE_METHOD = git
|
||||
SYSREPO_CPP_LICENSE = BSD-3-Clause
|
||||
|
||||
@@ -1,300 +0,0 @@
|
||||
From 0a09b00dab204bb5890978a17bb23c4c25280580 Mon Sep 17 00:00:00 2001
|
||||
From: Jan Kundrát <jan.kundrat@cesnet.cz>
|
||||
Date: Sun, 24 Mar 2024 20:41:25 +0100
|
||||
Subject: [PATCH] Port to libyang v3
|
||||
|
||||
Four parts, really:
|
||||
|
||||
- some enum reshuffling when creating new nodes
|
||||
|
||||
- a more capable XPath finding, but we have not been exporting any
|
||||
"non-JSON XPaths", whatever that might be
|
||||
|
||||
- system-ordered lists are now ordered alphabetically
|
||||
|
||||
- a more capable error handling API
|
||||
|
||||
Change-Id: Ic6de06f004c16e56cef93fae0136c07d903394c0
|
||||
---
|
||||
|
||||
diff --git a/.zuul.yaml b/.zuul.yaml
|
||||
index d9d95e1..b41c490 100644
|
||||
--- a/.zuul.yaml
|
||||
+++ b/.zuul.yaml
|
||||
@@ -4,13 +4,13 @@
|
||||
- f38-gcc-cover:
|
||||
required-projects:
|
||||
- name: github/CESNET/libyang
|
||||
- override-checkout: cesnet/2024-03--v2-latest
|
||||
+ override-checkout: devel
|
||||
- name: github/onqtam/doctest
|
||||
override-checkout: v2.3.6
|
||||
- f38-clang-asan-ubsan:
|
||||
required-projects: &projects
|
||||
- name: github/CESNET/libyang
|
||||
- override-checkout: cesnet/2024-03--v2-latest
|
||||
+ override-checkout: devel
|
||||
- name: github/onqtam/doctest
|
||||
override-checkout: v2.4.11
|
||||
- f38-clang-tsan:
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 288b62a..6e54707 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -28,7 +28,7 @@
|
||||
option(BUILD_SHARED_LIBS "By default, shared libs are enabled. Turn off for a static build." ON)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
-pkg_check_modules(LIBYANG REQUIRED libyang>=2.1.140 IMPORTED_TARGET)
|
||||
+pkg_check_modules(LIBYANG REQUIRED libyang>=2.2.3 IMPORTED_TARGET)
|
||||
set(LIBYANG_CPP_PKG_VERSION "1.1.0")
|
||||
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
diff --git a/README.md b/README.md
|
||||
index 5e79a23..9009a54 100644
|
||||
--- a/README.md
|
||||
+++ b/README.md
|
||||
@@ -8,8 +8,7 @@
|
||||
Object lifetimes are managed automatically via RAII.
|
||||
|
||||
## Dependencies
|
||||
-- [libyang](https://github.com/CESNET/libyang) - ~~the `devel` branch (even for the `master` branch of *libyang-cpp*)~~
|
||||
- - temporarily (March 2024) this requires the [pre-v3 API of libyang (commit `b3d079fc3`)](https://github.com/CESNET/libyang/tree/b3d079fc37ac119f5a2a4a120b86d1c7102c3a08)
|
||||
+- [libyang v3](https://github.com/CESNET/libyang) - the `devel` branch (even for the `master` branch of *libyang-cpp*)
|
||||
- C++20 compiler (e.g., GCC 10.x+, clang 10+)
|
||||
- CMake 3.19+
|
||||
|
||||
diff --git a/include/libyang-cpp/Context.hpp b/include/libyang-cpp/Context.hpp
|
||||
index 1dab9f3..6f6e233 100644
|
||||
--- a/include/libyang-cpp/Context.hpp
|
||||
+++ b/include/libyang-cpp/Context.hpp
|
||||
@@ -69,7 +69,9 @@
|
||||
LogLevel level;
|
||||
std::string message;
|
||||
ErrorCode code;
|
||||
- std::optional<std::string> path;
|
||||
+ std::optional<std::string> dataPath;
|
||||
+ std::optional<std::string> schemaPath;
|
||||
+ uint64_t line;
|
||||
ValidationErrorCode validationCode;
|
||||
};
|
||||
|
||||
diff --git a/include/libyang-cpp/Enum.hpp b/include/libyang-cpp/Enum.hpp
|
||||
index 3ded4d2..85dcc83 100644
|
||||
--- a/include/libyang-cpp/Enum.hpp
|
||||
+++ b/include/libyang-cpp/Enum.hpp
|
||||
@@ -115,11 +115,15 @@
|
||||
};
|
||||
|
||||
enum class CreationOptions : uint32_t {
|
||||
- Update = 0x01,
|
||||
- Output = 0x02,
|
||||
- Opaque = 0x04,
|
||||
- // BinaryLyb = 0x08, TODO
|
||||
- CanonicalValue = 0x10
|
||||
+ Output = 0x01,
|
||||
+ StoreOnly = 0x02,
|
||||
+ // BinaryLyb = 0x04, TODO
|
||||
+ CanonicalValue = 0x08,
|
||||
+ ClearDefaultFromParents = 0x10,
|
||||
+ Update = 0x20,
|
||||
+ Opaque = 0x40,
|
||||
+ PathWithOpaque = 0x80,
|
||||
+ // LYD_NEW_ANY_USE_VALUE is not relevant
|
||||
};
|
||||
|
||||
/**
|
||||
diff --git a/src/Context.cpp b/src/Context.cpp
|
||||
index 337070f..713c50f 100644
|
||||
--- a/src/Context.cpp
|
||||
+++ b/src/Context.cpp
|
||||
@@ -579,8 +579,10 @@
|
||||
.appTag = errIt->apptag ? std::optional{errIt->apptag} : std::nullopt,
|
||||
.level = utils::toLogLevel(errIt->level),
|
||||
.message = errIt->msg,
|
||||
- .code = static_cast<ErrorCode>(errIt->no),
|
||||
- .path = errIt->path ? std::optional{errIt->path} : std::nullopt,
|
||||
+ .code = static_cast<ErrorCode>(errIt->err),
|
||||
+ .dataPath = errIt->data_path ? std::optional{errIt->data_path} : std::nullopt,
|
||||
+ .schemaPath = errIt->schema_path ? std::optional{errIt->schema_path} : std::nullopt,
|
||||
+ .line = errIt->line,
|
||||
.validationCode = utils::toValidationErrorCode(errIt->vecode)
|
||||
});
|
||||
|
||||
diff --git a/src/DataNode.cpp b/src/DataNode.cpp
|
||||
index ab8cb4a..0e609c4 100644
|
||||
--- a/src/DataNode.cpp
|
||||
+++ b/src/DataNode.cpp
|
||||
@@ -1187,7 +1187,8 @@
|
||||
const std::string& xpath)
|
||||
{
|
||||
ly_set* set;
|
||||
- auto ret = lyd_find_xpath3(contextNode ? contextNode->m_node : nullptr, forest.m_node, xpath.c_str(), nullptr, &set);
|
||||
+ auto ret = lyd_find_xpath3(contextNode ? contextNode->m_node : nullptr, forest.m_node, xpath.c_str(),
|
||||
+ LY_VALUE_JSON, nullptr, nullptr, &set);
|
||||
|
||||
throwIfError(ret, "libyang::findXPathAt:");
|
||||
|
||||
diff --git a/src/utils/enum.hpp b/src/utils/enum.hpp
|
||||
index 7674fc6..5e02d24 100644
|
||||
--- a/src/utils/enum.hpp
|
||||
+++ b/src/utils/enum.hpp
|
||||
@@ -72,11 +72,14 @@
|
||||
{
|
||||
return static_cast<uint32_t>(flags);
|
||||
}
|
||||
-static_assert(LYD_NEW_PATH_UPDATE == toCreationOptions(CreationOptions::Update));
|
||||
-static_assert(LYD_NEW_PATH_OUTPUT == toCreationOptions(CreationOptions::Output));
|
||||
-static_assert(LYD_NEW_PATH_OPAQ == toCreationOptions(CreationOptions::Opaque));
|
||||
+static_assert(LYD_NEW_VAL_OUTPUT == toCreationOptions(CreationOptions::Output));
|
||||
+static_assert(LYD_NEW_VAL_STORE_ONLY == toCreationOptions(CreationOptions::StoreOnly));
|
||||
// static_assert(LYD_NEW_PATH_BIN_VALUE == toCreationOptions(CreationOptions::BinaryLyb));
|
||||
-static_assert(LYD_NEW_PATH_CANON_VALUE == toCreationOptions(CreationOptions::CanonicalValue));
|
||||
+static_assert(LYD_NEW_VAL_CANON == toCreationOptions(CreationOptions::CanonicalValue));
|
||||
+static_assert(LYD_NEW_META_CLEAR_DFLT == toCreationOptions(CreationOptions::ClearDefaultFromParents));
|
||||
+static_assert(LYD_NEW_PATH_UPDATE == toCreationOptions(CreationOptions::Update));
|
||||
+static_assert(LYD_NEW_PATH_OPAQ == toCreationOptions(CreationOptions::Opaque));
|
||||
+static_assert(LYD_NEW_PATH_WITH_OPAQ == toCreationOptions(CreationOptions::PathWithOpaque));
|
||||
|
||||
constexpr uint32_t toDuplicationOptions(const DuplicationOptions options)
|
||||
{
|
||||
diff --git a/tests/context.cpp b/tests/context.cpp
|
||||
index d19f78b..cb629ef 100644
|
||||
--- a/tests/context.cpp
|
||||
+++ b/tests/context.cpp
|
||||
@@ -457,7 +457,9 @@
|
||||
.level = libyang::LogLevel::Error,
|
||||
.message = "Invalid character sequence \"invalid\", expected a keyword.",
|
||||
.code = libyang::ErrorCode::ValidationFailure,
|
||||
- .path = "Line number 1.",
|
||||
+ .dataPath = std::nullopt,
|
||||
+ .schemaPath = std::nullopt,
|
||||
+ .line = 1,
|
||||
.validationCode = libyang::ValidationErrorCode::Syntax,
|
||||
}
|
||||
};
|
||||
@@ -476,7 +478,9 @@
|
||||
.level = libyang::LogLevel::Error,
|
||||
.message = "Value \"9001\" is out of type int8 min/max bounds.",
|
||||
.code = libyang::ErrorCode::ValidationFailure,
|
||||
- .path = "Schema location \"/example-schema:leafInt8\".",
|
||||
+ .dataPath = std::nullopt,
|
||||
+ .schemaPath = "/example-schema:leafInt8",
|
||||
+ .line = 0,
|
||||
.validationCode = libyang::ValidationErrorCode::Data,
|
||||
}
|
||||
};
|
||||
@@ -491,7 +495,9 @@
|
||||
.level = libyang::LogLevel::Error,
|
||||
.message = "Invalid type int8 empty value.",
|
||||
.code = libyang::ErrorCode::ValidationFailure,
|
||||
- .path = "Schema location \"/example-schema:leafInt8\".",
|
||||
+ .dataPath = std::nullopt,
|
||||
+ .schemaPath = "/example-schema:leafInt8",
|
||||
+ .line = 0,
|
||||
.validationCode = libyang::ValidationErrorCode::Data,
|
||||
},
|
||||
libyang::ErrorInfo {
|
||||
@@ -499,7 +505,9 @@
|
||||
.level = libyang::LogLevel::Error,
|
||||
.message = "Value \"9001\" is out of type int8 min/max bounds.",
|
||||
.code = libyang::ErrorCode::ValidationFailure,
|
||||
- .path = "Schema location \"/example-schema:leafInt8\".",
|
||||
+ .dataPath = std::nullopt,
|
||||
+ .schemaPath = "/example-schema:leafInt8",
|
||||
+ .line = 0,
|
||||
.validationCode = libyang::ValidationErrorCode::Data,
|
||||
}
|
||||
};
|
||||
diff --git a/tests/data_node.cpp b/tests/data_node.cpp
|
||||
index 15fb727..2d27979 100644
|
||||
--- a/tests/data_node.cpp
|
||||
+++ b/tests/data_node.cpp
|
||||
@@ -1026,12 +1026,12 @@
|
||||
"/example-schema:bigTree/one",
|
||||
"/example-schema:bigTree/one/myLeaf",
|
||||
"/example-schema:bigTree/two",
|
||||
- "/example-schema:bigTree/two/myList[thekey='43221']",
|
||||
- "/example-schema:bigTree/two/myList[thekey='43221']/thekey",
|
||||
+ "/example-schema:bigTree/two/myList[thekey='213']",
|
||||
+ "/example-schema:bigTree/two/myList[thekey='213']/thekey",
|
||||
"/example-schema:bigTree/two/myList[thekey='432']",
|
||||
"/example-schema:bigTree/two/myList[thekey='432']/thekey",
|
||||
- "/example-schema:bigTree/two/myList[thekey='213']",
|
||||
- "/example-schema:bigTree/two/myList[thekey='213']/thekey"
|
||||
+ "/example-schema:bigTree/two/myList[thekey='43221']",
|
||||
+ "/example-schema:bigTree/two/myList[thekey='43221']/thekey",
|
||||
};
|
||||
|
||||
REQUIRE(res == expected);
|
||||
@@ -1255,6 +1255,7 @@
|
||||
|
||||
DOCTEST_SUBCASE("DataNode::findXPath")
|
||||
{
|
||||
+ // libyang v3 sorts these alphabetically
|
||||
const auto data3 = R"({
|
||||
"example-schema:person": [
|
||||
{
|
||||
@@ -1308,13 +1309,13 @@
|
||||
auto set = node->findXPath("/example-schema:person");
|
||||
REQUIRE(set.size() == 3);
|
||||
|
||||
- REQUIRE(set.front().path() == "/example-schema:person[name='John']");
|
||||
- REQUIRE(set.back().path() == "/example-schema:person[name='David']");
|
||||
+ REQUIRE(set.front().path() == "/example-schema:person[name='Dan']");
|
||||
+ REQUIRE(set.back().path() == "/example-schema:person[name='John']");
|
||||
|
||||
auto iter = set.begin();
|
||||
- REQUIRE((iter++)->path() == "/example-schema:person[name='John']");
|
||||
REQUIRE((iter++)->path() == "/example-schema:person[name='Dan']");
|
||||
REQUIRE((iter++)->path() == "/example-schema:person[name='David']");
|
||||
+ REQUIRE((iter++)->path() == "/example-schema:person[name='John']");
|
||||
REQUIRE(iter == set.end());
|
||||
REQUIRE_THROWS_WITH_AS(*iter, "Dereferenced an .end() iterator", std::out_of_range);
|
||||
}
|
||||
@@ -1324,23 +1325,23 @@
|
||||
auto set = node->findXPath("/example-schema:person");
|
||||
|
||||
REQUIRE((set.begin() + 0) == set.begin());
|
||||
- REQUIRE((set.begin() + 0)->path() == "/example-schema:person[name='John']");
|
||||
- REQUIRE((set.begin() + 1)->path() == "/example-schema:person[name='Dan']");
|
||||
- REQUIRE((set.begin() + 2)->path() == "/example-schema:person[name='David']");
|
||||
+ REQUIRE((set.begin() + 0)->path() == "/example-schema:person[name='Dan']");
|
||||
+ REQUIRE((set.begin() + 1)->path() == "/example-schema:person[name='David']");
|
||||
+ REQUIRE((set.begin() + 2)->path() == "/example-schema:person[name='John']");
|
||||
REQUIRE((set.begin() + 3) == set.end());
|
||||
REQUIRE_THROWS(set.begin() + 4);
|
||||
|
||||
REQUIRE((set.end() - 0) == set.end());
|
||||
- REQUIRE((set.end() - 1)->path() == "/example-schema:person[name='David']");
|
||||
- REQUIRE((set.end() - 2)->path() == "/example-schema:person[name='Dan']");
|
||||
- REQUIRE((set.end() - 3)->path() == "/example-schema:person[name='John']");
|
||||
+ REQUIRE((set.end() - 1)->path() == "/example-schema:person[name='John']");
|
||||
+ REQUIRE((set.end() - 2)->path() == "/example-schema:person[name='David']");
|
||||
+ REQUIRE((set.end() - 3)->path() == "/example-schema:person[name='Dan']");
|
||||
REQUIRE((set.end() - 3) == set.begin());
|
||||
REQUIRE_THROWS(set.end() - 4);
|
||||
|
||||
auto iter = set.end();
|
||||
+ REQUIRE((--iter)->path() == "/example-schema:person[name='John']");
|
||||
REQUIRE((--iter)->path() == "/example-schema:person[name='David']");
|
||||
REQUIRE((--iter)->path() == "/example-schema:person[name='Dan']");
|
||||
- REQUIRE((--iter)->path() == "/example-schema:person[name='John']");
|
||||
REQUIRE_THROWS(--iter);
|
||||
}
|
||||
|
||||
diff --git a/tests/pretty_printers.hpp b/tests/pretty_printers.hpp
|
||||
index 6ae8934..6bbc16f 100644
|
||||
--- a/tests/pretty_printers.hpp
|
||||
+++ b/tests/pretty_printers.hpp
|
||||
@@ -59,7 +59,9 @@
|
||||
oss << "appTag: " << (err.appTag ? *err.appTag : "std::nullopt") << "\n ";
|
||||
oss << "code: " << err.code << "\n ";
|
||||
oss << "message: " << err.message << "\n ";
|
||||
- oss << "path: " << (err.path ? *err.path : "std::nullopt") << "\n ";
|
||||
+ oss << "dataPath: " << (err.dataPath ? *err.dataPath : "std::nullopt") << "\n ";
|
||||
+ oss << "schemaPath: " << (err.schemaPath ? *err.schemaPath : "std::nullopt") << "\n ";
|
||||
+ oss << "line: " << err.line << "\n ";
|
||||
oss << "level: " << err.level << "\n ";
|
||||
oss << "validationCode: " << err.validationCode << "\n }";
|
||||
return oss.str();
|
||||
@@ -1,165 +0,0 @@
|
||||
From 02ff08f881c726b5b14eb489f4a906ec4b421a6f Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Mattias=20Walstr=C3=B6m?= <lazzer@gmail.com>
|
||||
Date: Tue, 25 Jun 2024 11:17:03 +0200
|
||||
Subject: [PATCH 1/2] Change systemd from a required dependency to an optional
|
||||
dependency.
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
Organization: Addiva Elektronik
|
||||
|
||||
In addition to journal logging, enable logging to syslog and stdout.
|
||||
|
||||
Signed-off-by: Mattias Walström <lazzer@gmail.com>
|
||||
Change-Id: I90cb9169e8fdf9103c31bc983a1ec8a5de3dd26c
|
||||
---
|
||||
CMakeLists.txt | 13 +++++++++++--
|
||||
README.md | 3 ++-
|
||||
ci/pre.yaml | 6 ++++++
|
||||
src/configure.cmake.h.in | 3 +++
|
||||
src/restconf/main.cpp | 36 ++++++++++++++++++++++++++++++++----
|
||||
5 files changed, 54 insertions(+), 7 deletions(-)
|
||||
create mode 100644 src/configure.cmake.h.in
|
||||
|
||||
diff --git a/CMakeLists.txt b/CMakeLists.txt
|
||||
index 7f82660..1cd27b2 100644
|
||||
--- a/CMakeLists.txt
|
||||
+++ b/CMakeLists.txt
|
||||
@@ -75,8 +75,14 @@ find_package(Boost REQUIRED COMPONENTS system thread)
|
||||
|
||||
pkg_check_modules(SYSREPO-CPP REQUIRED IMPORTED_TARGET sysrepo-cpp>=1.1.0)
|
||||
pkg_check_modules(LIBYANG-CPP REQUIRED IMPORTED_TARGET libyang-cpp>=1.1.0)
|
||||
-pkg_check_modules(SYSTEMD REQUIRED IMPORTED_TARGET libsystemd)
|
||||
+pkg_check_modules(SYSTEMD IMPORTED_TARGET libsystemd)
|
||||
pkg_check_modules(PAM REQUIRED IMPORTED_TARGET pam)
|
||||
+pkg_check_modules(DOCOPT REQUIRED IMPORTED_TARGET docopt)
|
||||
+if(SYSTEMD_FOUND)
|
||||
+ set(HAVE_SYSTEMD TRUE)
|
||||
+endif()
|
||||
+
|
||||
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/src/configure.cmake.h.in ${CMAKE_CURRENT_BINARY_DIR}/configure.cmake.h)
|
||||
|
||||
add_library(rousette-http STATIC
|
||||
src/http/EventStream.cpp
|
||||
@@ -116,7 +122,10 @@ add_executable(watch-operational-ds
|
||||
target_link_libraries(watch-operational-ds PUBLIC rousette-sysrepo)
|
||||
|
||||
add_executable(rousette src/restconf/main.cpp)
|
||||
-target_link_libraries(rousette PUBLIC rousette-restconf PkgConfig::SYSTEMD)
|
||||
+target_link_libraries(rousette PUBLIC rousette-restconf PkgConfig::DOCOPT)
|
||||
+if(SYSTEMD_FOUND)
|
||||
+ target_link_libraries(rousette PUBLIC PkgConfig::SYSTEMD)
|
||||
+endif()
|
||||
|
||||
install(TARGETS
|
||||
# clock-demo
|
||||
diff --git a/README.md b/README.md
|
||||
index 68b4b99..55b8241 100644
|
||||
--- a/README.md
|
||||
+++ b/README.md
|
||||
@@ -37,12 +37,13 @@ The anonymous user access is disabled whenever these rules are not met.
|
||||
- [nghttp2-asio](https://github.com/nghttp2/nghttp2-asio) - asynchronous C++ library for HTTP/2
|
||||
- [sysrepo-cpp](https://github.com/sysrepo/sysrepo-cpp) - object-oriented bindings of the [*sysrepo*](https://github.com/sysrepo/sysrepo) library
|
||||
- [libyang-cpp](https://github.com/CESNET/libyang-cpp) - C++ bindings for *libyang*
|
||||
-- systemd - the shared library for logging to `sd-journal`
|
||||
- [PAM](http://www.linux-pam.org/) - for authentication
|
||||
- [spdlog](https://github.com/gabime/spdlog) - Very fast, header-only/compiled, C++ logging library
|
||||
+- [docopt-cpp](https://github.com/docopt/docopt.cpp) - command-line argument parser
|
||||
- Boost's system and thread
|
||||
- C++20 compiler (e.g., GCC 10.x+, clang 10+)
|
||||
- CMake 3.19+
|
||||
+- optionally systemd - the shared library for logging to `sd-journal`
|
||||
- optionally for built-in tests, [Doctest](https://github.com/onqtam/doctest/) as a C++ unit test framework
|
||||
- optionally for built-in tests, [trompeloeil](https://github.com/rollbear/trompeloeil) for mock objects in C++
|
||||
- optionally for built-in tests, [`pam_matrix` and `pam_wrapper`](https://cwrap.org/pam_wrapper.html) for PAM mocking
|
||||
diff --git a/ci/pre.yaml b/ci/pre.yaml
|
||||
index 51f1c66..325dbf4 100644
|
||||
--- a/ci/pre.yaml
|
||||
+++ b/ci/pre.yaml
|
||||
@@ -11,3 +11,9 @@
|
||||
name: pam_wrapper
|
||||
state: present
|
||||
become: true
|
||||
+
|
||||
+ - name: install docopt-cpp
|
||||
+ package:
|
||||
+ name: docopt-cpp-devel
|
||||
+ state: present
|
||||
+ become: true
|
||||
diff --git a/src/configure.cmake.h.in b/src/configure.cmake.h.in
|
||||
new file mode 100644
|
||||
index 0000000..bc26981
|
||||
--- /dev/null
|
||||
+++ b/src/configure.cmake.h.in
|
||||
@@ -0,0 +1,3 @@
|
||||
+#pragma once
|
||||
+
|
||||
+#cmakedefine HAVE_SYSTEMD
|
||||
diff --git a/src/restconf/main.cpp b/src/restconf/main.cpp
|
||||
index bba3cbf..2bc9a86 100644
|
||||
--- a/src/restconf/main.cpp
|
||||
+++ b/src/restconf/main.cpp
|
||||
@@ -9,14 +9,30 @@
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
#include <inttypes.h>
|
||||
-#include <spdlog/sinks/systemd_sink.h>
|
||||
+
|
||||
+#include "configure.cmake.h" /* Expose HAVE_SYSTEMD */
|
||||
+
|
||||
+#ifdef HAVE_SYSTEMD
|
||||
+ #include <spdlog/sinks/systemd_sink.h>
|
||||
+#endif
|
||||
+#include <spdlog/sinks/syslog_sink.h>
|
||||
#include <spdlog/sinks/ansicolor_sink.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
+#include <docopt.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
#include <sysrepo-cpp/Session.hpp>
|
||||
#include "restconf/Server.h"
|
||||
+static const char usage[] =
|
||||
+ R"(Rousette - RESTCONF server
|
||||
+Usage:
|
||||
+ rousette [--syslog] [--help]
|
||||
+Options:
|
||||
+ -h --help Show this screen.
|
||||
+ --syslog Log to syslog.
|
||||
+)";
|
||||
+#ifdef HAVE_SYSTEMD
|
||||
|
||||
namespace {
|
||||
/** @short Is stderr connected to journald? Not thread safe. */
|
||||
@@ -54,13 +70,25 @@ public:
|
||||
}
|
||||
};
|
||||
}
|
||||
-
|
||||
-int main(int argc [[maybe_unused]], char* argv [[maybe_unused]] [])
|
||||
+#endif
|
||||
+int main(int argc, char* argv [])
|
||||
{
|
||||
- if (is_journald_active()) {
|
||||
+ auto args = docopt::docopt(usage, {argv + 1, argv + argc}, true,""/* version */, true);
|
||||
+
|
||||
+ if (args["--syslog"].asBool()) {
|
||||
+ auto syslog_sink = std::make_shared<spdlog::sinks::syslog_sink_mt>("rousette", LOG_PID, LOG_USER, true);
|
||||
+ auto logger = std::make_shared<spdlog::logger>("rousette", syslog_sink);
|
||||
+ spdlog::set_default_logger(logger);
|
||||
+#ifdef HAVE_SYSTEMD
|
||||
+ } else if (is_journald_active()) {
|
||||
auto sink = std::make_shared<journald_sink<std::mutex>>();
|
||||
auto logger = std::make_shared<spdlog::logger>("rousette", sink);
|
||||
spdlog::set_default_logger(logger);
|
||||
+#endif
|
||||
+ } else {
|
||||
+ auto stdout_sink = std::make_shared<spdlog::sinks::ansicolor_stdout_sink_mt>();
|
||||
+ auto logger = std::make_shared<spdlog::logger>("rousette", stdout_sink);
|
||||
+ spdlog::set_default_logger(logger);
|
||||
}
|
||||
spdlog::set_level(spdlog::level::trace);
|
||||
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -1,248 +0,0 @@
|
||||
commit c83585452819b6e06008aba49237f46977a73a9a
|
||||
Author: Mattias Walström <lazzer@gmail.com>
|
||||
Date: Wed Jun 26 11:04:36 2024 +0200
|
||||
|
||||
Add optional timeout option
|
||||
|
||||
Since rousette will fail applying a new configuration
|
||||
on really slow systems and a lot of sysrepo callbacks.
|
||||
|
||||
Change-Id: I61d92a1f64e4c3617587e544cfd9d6a4269e0d35
|
||||
|
||||
diff --git a/src/restconf/Server.cpp b/src/restconf/Server.cpp
|
||||
index 5327b52..685bf78 100644
|
||||
--- a/src/restconf/Server.cpp
|
||||
+++ b/src/restconf/Server.cpp
|
||||
@@ -202,14 +202,13 @@ DataFormat chooseDataEncoding(const nghttp2::asio_http2::header_map& headers)
|
||||
return {resContentType, resAccept ? *resAccept : libyang::DataFormat::JSON};
|
||||
}
|
||||
|
||||
-bool dataExists(sysrepo::Session session, const std::string& path)
|
||||
+bool dataExists(sysrepo::Session session, const std::string& path, std::chrono::milliseconds timeout)
|
||||
{
|
||||
- if (auto data = session.getData(path)) {
|
||||
- if (data->findPath(path)) {
|
||||
+ if (auto data = session.getData(path, 0, sysrepo::GetOptions::Default,timeout)) {
|
||||
+ if (data->findPath(path))
|
||||
return true;
|
||||
}
|
||||
- }
|
||||
- return false;
|
||||
+ return false;
|
||||
}
|
||||
|
||||
/** @brief Checks if node is a key node in a maybeList node list */
|
||||
@@ -261,7 +260,7 @@ struct RequestContext {
|
||||
std::string payload;
|
||||
};
|
||||
|
||||
-void processActionOrRPC(std::shared_ptr<RequestContext> requestCtx)
|
||||
+void processActionOrRPC(std::shared_ptr<RequestContext> requestCtx, std::chrono::milliseconds timeout)
|
||||
{
|
||||
requestCtx->sess.switchDatastore(sysrepo::Datastore::Operational);
|
||||
auto ctx = requestCtx->sess.getContext();
|
||||
@@ -276,7 +275,7 @@ void processActionOrRPC(std::shared_ptr<RequestContext> requestCtx)
|
||||
if (rpcSchemaNode.nodeType() == libyang::NodeType::Action) {
|
||||
// FIXME: This is race-prone: we check for existing action data node but before we send the RPC the node may be gone
|
||||
auto [pathToParent, pathSegment] = asLibyangPathSplit(ctx, requestCtx->req.uri().path);
|
||||
- if (!dataExists(requestCtx->sess, pathToParent)) {
|
||||
+ if (!dataExists(requestCtx->sess, pathToParent,timeout)) {
|
||||
throw ErrorResponse(400, "application", "operation-failed", "Action data node '" + requestCtx->lyPathOriginal + "' does not exist.");
|
||||
}
|
||||
}
|
||||
@@ -287,7 +286,7 @@ void processActionOrRPC(std::shared_ptr<RequestContext> requestCtx)
|
||||
rpcNode->parseOp(requestCtx->payload, *requestCtx->dataFormat.request, libyang::OperationType::RpcRestconf);
|
||||
}
|
||||
|
||||
- auto rpcReply = requestCtx->sess.sendRPC(*rpcNode);
|
||||
+ auto rpcReply = requestCtx->sess.sendRPC(*rpcNode, timeout);
|
||||
|
||||
if (rpcReply.immediateChildren().empty()) {
|
||||
requestCtx->res.write_head(204, {{"access-control-allow-origin", {"*", false}}});
|
||||
@@ -330,7 +329,7 @@ void processActionOrRPC(std::shared_ptr<RequestContext> requestCtx)
|
||||
}
|
||||
}
|
||||
|
||||
-void processPost(std::shared_ptr<RequestContext> requestCtx)
|
||||
+void processPost(std::shared_ptr<RequestContext> requestCtx, std::chrono::milliseconds timeout)
|
||||
{
|
||||
try {
|
||||
auto ctx = requestCtx->sess.getContext();
|
||||
@@ -374,7 +373,7 @@ void processPost(std::shared_ptr<RequestContext> requestCtx)
|
||||
createdNodes.begin()->newMeta(*mod, "operation", "create"); // FIXME: check no other nc:operations in the tree
|
||||
|
||||
requestCtx->sess.editBatch(*edit, sysrepo::DefaultOperation::Merge);
|
||||
- requestCtx->sess.applyChanges();
|
||||
+ requestCtx->sess.applyChanges(timeout);
|
||||
|
||||
requestCtx->res.write_head(201,
|
||||
{
|
||||
@@ -402,7 +401,7 @@ void processPost(std::shared_ptr<RequestContext> requestCtx)
|
||||
}
|
||||
}
|
||||
|
||||
-void processPut(std::shared_ptr<RequestContext> requestCtx)
|
||||
+void processPut(std::shared_ptr<RequestContext> requestCtx, std::chrono::milliseconds timeout)
|
||||
{
|
||||
try {
|
||||
auto ctx = requestCtx->sess.getContext();
|
||||
@@ -410,7 +409,7 @@ void processPut(std::shared_ptr<RequestContext> requestCtx)
|
||||
// PUT / means replace everything
|
||||
if (requestCtx->lyPathOriginal == "/") {
|
||||
auto edit = ctx.parseData(requestCtx->payload, *requestCtx->dataFormat.request, libyang::ParseOptions::Strict | libyang::ParseOptions::NoState | libyang::ParseOptions::ParseOnly);
|
||||
- requestCtx->sess.replaceConfig(edit);
|
||||
+ requestCtx->sess.replaceConfig(edit, std::nullopt, timeout);
|
||||
|
||||
requestCtx->res.write_head(edit ? 201 : 204,
|
||||
{
|
||||
@@ -422,7 +421,7 @@ void processPut(std::shared_ptr<RequestContext> requestCtx)
|
||||
}
|
||||
|
||||
auto mod = ctx.getModuleImplemented("ietf-netconf");
|
||||
- bool nodeExisted = dataExists(requestCtx->sess, requestCtx->lyPathOriginal);
|
||||
+ bool nodeExisted = dataExists(requestCtx->sess, requestCtx->lyPathOriginal, timeout);
|
||||
std::optional<libyang::DataNode> edit;
|
||||
std::optional<libyang::DataNode> replacementNode;
|
||||
|
||||
@@ -471,7 +470,7 @@ void processPut(std::shared_ptr<RequestContext> requestCtx)
|
||||
replacementNode->newMeta(*mod, "operation", "replace"); // FIXME: check no other nc:operations in the tree
|
||||
|
||||
requestCtx->sess.editBatch(*edit, sysrepo::DefaultOperation::Merge);
|
||||
- requestCtx->sess.applyChanges();
|
||||
+ requestCtx->sess.applyChanges(timeout);
|
||||
|
||||
requestCtx->res.write_head(nodeExisted ? 204 : 201,
|
||||
{
|
||||
@@ -551,7 +550,7 @@ Server::~Server()
|
||||
server->join();
|
||||
}
|
||||
|
||||
-Server::Server(sysrepo::Connection conn, const std::string& address, const std::string& port)
|
||||
+Server::Server(sysrepo::Connection conn, const std::string& address, const std::string& port, long timeout_seconds)
|
||||
: nacm(conn)
|
||||
, server{std::make_unique<nghttp2::asio_http2::server::http2>()}
|
||||
, dwdmEvents{std::make_unique<sr::OpticalEvents>(conn.sessionStart())}
|
||||
@@ -562,6 +561,8 @@ Server::Server(sysrepo::Connection conn, const std::string& address, const std::
|
||||
}
|
||||
}
|
||||
|
||||
+ std::chrono::milliseconds timeout(timeout_seconds * 1000);
|
||||
+
|
||||
// RFC 8527, we must implement at least ietf-yang-library@2019-01-04 and support operational DS
|
||||
if (auto mod = conn.sessionStart().getContext().getModuleImplemented("ietf-yang-library"); !mod || mod->revision() < "2019-01-04") {
|
||||
throw std::runtime_error("Module ietf-yang-library of revision at least 2019-01-04 is not implemented");
|
||||
@@ -627,7 +628,7 @@ Server::Server(sysrepo::Connection conn, const std::string& address, const std::
|
||||
});
|
||||
|
||||
server->handle(restconfRoot,
|
||||
- [conn /* intentionally by value, otherwise conn gets destroyed when the ctor returns */, this](const auto& req, const auto& res) mutable {
|
||||
+ [conn /* intentionally by value, otherwise conn gets destroyed when the ctor returns */, this, timeout](const auto& req, const auto& res) mutable {
|
||||
const auto& peer = http::peer_from_request(req);
|
||||
spdlog::info("{}: {} {}", peer, req.method(), req.uri().raw_path);
|
||||
|
||||
@@ -665,7 +666,7 @@ Server::Server(sysrepo::Connection conn, const std::string& address, const std::
|
||||
|
||||
case RestconfRequest::Type::GetData:
|
||||
sess.switchDatastore(restconfRequest.datastore.value_or(sysrepo::Datastore::Operational));
|
||||
- if (auto data = sess.getData(restconfRequest.path); data) {
|
||||
+ if (auto data = sess.getData(restconfRequest.path, 0, sysrepo::GetOptions::Default,timeout); data) {
|
||||
res.write_head(
|
||||
200,
|
||||
{
|
||||
@@ -692,16 +693,16 @@ Server::Server(sysrepo::Connection conn, const std::string& address, const std::
|
||||
|
||||
auto requestCtx = std::make_shared<RequestContext>(req, res, dataFormat, sess, restconfRequest.path);
|
||||
|
||||
- req.on_data([requestCtx, restconfRequest /* intentional copy */](const uint8_t* data, std::size_t length) {
|
||||
+ req.on_data([requestCtx, restconfRequest /* intentional copy */, timeout](const uint8_t* data, std::size_t length) {
|
||||
if (length > 0) { // there are still some data to be read
|
||||
requestCtx->payload.append(reinterpret_cast<const char*>(data), length);
|
||||
return;
|
||||
}
|
||||
|
||||
if (restconfRequest.type == RestconfRequest::Type::CreateOrReplaceThisNode) {
|
||||
- processPut(requestCtx);
|
||||
+ processPut(requestCtx, timeout);
|
||||
} else {
|
||||
- processPost(requestCtx);
|
||||
+ processPost(requestCtx, timeout);
|
||||
}
|
||||
});
|
||||
break;
|
||||
@@ -725,7 +726,7 @@ Server::Server(sysrepo::Connection conn, const std::string& address, const std::
|
||||
}
|
||||
|
||||
sess.editBatch(*edit, sysrepo::DefaultOperation::Merge);
|
||||
- sess.applyChanges();
|
||||
+ sess.applyChanges(timeout);
|
||||
} catch (const sysrepo::ErrorWithCode& e) {
|
||||
if (e.code() == sysrepo::ErrorCode::Unauthorized) {
|
||||
throw ErrorResponse(403, "application", "access-denied", "Access denied.", restconfRequest.path);
|
||||
@@ -747,11 +748,11 @@ Server::Server(sysrepo::Connection conn, const std::string& address, const std::
|
||||
case RestconfRequest::Type::Execute: {
|
||||
auto requestCtx = std::make_shared<RequestContext>(req, res, dataFormat, sess, restconfRequest.path);
|
||||
|
||||
- req.on_data([requestCtx](const uint8_t* data, std::size_t length) {
|
||||
+ req.on_data([requestCtx,timeout](const uint8_t* data, std::size_t length) {
|
||||
if (length > 0) {
|
||||
requestCtx->payload.append(reinterpret_cast<const char*>(data), length);
|
||||
} else {
|
||||
- processActionOrRPC(requestCtx);
|
||||
+ processActionOrRPC(requestCtx,timeout);
|
||||
}
|
||||
});
|
||||
break;
|
||||
diff --git a/src/restconf/Server.h b/src/restconf/Server.h
|
||||
index bf6fecc..b2c42f4 100644
|
||||
--- a/src/restconf/Server.h
|
||||
+++ b/src/restconf/Server.h
|
||||
@@ -24,11 +24,10 @@ class OpticalEvents;
|
||||
namespace restconf {
|
||||
|
||||
std::optional<std::string> as_subtree_path(const std::string& path);
|
||||
-
|
||||
/** @short A RESTCONF-ish server */
|
||||
class Server {
|
||||
public:
|
||||
- explicit Server(sysrepo::Connection conn, const std::string& address, const std::string& port);
|
||||
+ explicit Server(sysrepo::Connection conn, const std::string& address, const std::string& port, long timeout);
|
||||
~Server();
|
||||
|
||||
private:
|
||||
diff --git a/src/restconf/main.cpp b/src/restconf/main.cpp
|
||||
index 2bc9a86..e295f63 100644
|
||||
--- a/src/restconf/main.cpp
|
||||
+++ b/src/restconf/main.cpp
|
||||
@@ -27,9 +27,10 @@
|
||||
static const char usage[] =
|
||||
R"(Rousette - RESTCONF server
|
||||
Usage:
|
||||
- rousette [--syslog] [--help]
|
||||
+ rousette [--syslog] [--timeout <SECONDS>] [--help]
|
||||
Options:
|
||||
-h --help Show this screen.
|
||||
+ -t --timeout <SECONDS> Change default timeout in sysrepo (if not set, use sysrepo internal).
|
||||
--syslog Log to syslog.
|
||||
)";
|
||||
#ifdef HAVE_SYSTEMD
|
||||
@@ -74,6 +75,10 @@ public:
|
||||
int main(int argc, char* argv [])
|
||||
{
|
||||
auto args = docopt::docopt(usage, {argv + 1, argv + argc}, true,""/* version */, true);
|
||||
+ long timeout = 0;
|
||||
+
|
||||
+ if (args["--timeout"])
|
||||
+ timeout = args["--timeout"].asLong();
|
||||
|
||||
if (args["--syslog"].asBool()) {
|
||||
auto syslog_sink = std::make_shared<spdlog::sinks::syslog_sink_mt>("rousette", LOG_PID, LOG_USER, true);
|
||||
@@ -100,8 +105,7 @@ int main(int argc, char* argv [])
|
||||
}
|
||||
|
||||
auto conn = sysrepo::Connection{};
|
||||
- auto server = rousette::restconf::Server{conn, "::1", "10080"};
|
||||
-
|
||||
+ auto server = rousette::restconf::Server{conn, "::1", "10080", timeout};
|
||||
signal(SIGTERM, [](int) {});
|
||||
signal(SIGINT, [](int) {});
|
||||
pause();
|
||||
@@ -1,67 +0,0 @@
|
||||
From 36f2ad3c009f4234d906485439ead42a6fbb7adf Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Mattias=20Walstr=C3=B6m?= <lazzer@gmail.com>
|
||||
Date: Tue, 25 Jun 2024 16:18:07 +0200
|
||||
Subject: [PATCH] Add optional timeouts for calls to sr_get_data and
|
||||
sr_get_node
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
Organization: Addiva Elektronik
|
||||
|
||||
Signed-off-by: Mattias Walström <lazzer@gmail.com>
|
||||
|
||||
Change-Id: Ia91eb6823e64322e37e661b60b369dfedc5677fb
|
||||
---
|
||||
include/sysrepo-cpp/Session.hpp | 4 ++--
|
||||
src/Session.cpp | 8 ++++----
|
||||
2 files changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/include/sysrepo-cpp/Session.hpp b/include/sysrepo-cpp/Session.hpp
|
||||
index 7c5c71c..350df7a 100644
|
||||
--- a/include/sysrepo-cpp/Session.hpp
|
||||
+++ b/include/sysrepo-cpp/Session.hpp
|
||||
@@ -88,9 +88,9 @@ public:
|
||||
void discardItems(const std::optional<std::string>& xpath);
|
||||
void moveItem(const std::string& path, const MovePosition move, const std::optional<std::string>& keys_or_value, const std::optional<std::string>& origin = std::nullopt, const EditOptions opts = sysrepo::EditOptions::Default);
|
||||
// TODO: allow timeout argument
|
||||
- std::optional<libyang::DataNode> getData(const std::string& path, int maxDepth = 0, const GetOptions opts = sysrepo::GetOptions::Default) const;
|
||||
+ std::optional<libyang::DataNode> getData(const std::string& path, int maxDepth = 0, const GetOptions opts = sysrepo::GetOptions::Default, std::chrono::milliseconds timeout = std::chrono::milliseconds{0}) const;
|
||||
// TODO: allow all arguments
|
||||
- libyang::DataNode getOneNode(const std::string& path) const;
|
||||
+ libyang::DataNode getOneNode(const std::string& path, std::chrono::milliseconds timeout = std::chrono::milliseconds{0}) const;
|
||||
std::optional<const libyang::DataNode> getPendingChanges() const;
|
||||
void applyChanges(std::chrono::milliseconds timeout = std::chrono::milliseconds{0});
|
||||
void discardChanges();
|
||||
diff --git a/src/Session.cpp b/src/Session.cpp
|
||||
index e9d2976..04b0333 100644
|
||||
--- a/src/Session.cpp
|
||||
+++ b/src/Session.cpp
|
||||
@@ -191,10 +191,10 @@ libyang::DataNode wrapSrData(std::shared_ptr<sr_session_ctx_s> sess, sr_data_t*
|
||||
* @param opts GetOptions overriding default behaviour
|
||||
* @returns std::nullopt if no matching data found, otherwise the requested data.
|
||||
*/
|
||||
-std::optional<libyang::DataNode> Session::getData(const std::string& path, int maxDepth, const GetOptions opts) const
|
||||
+std::optional<libyang::DataNode> Session::getData(const std::string& path, int maxDepth, const GetOptions opts, std::chrono::milliseconds timeout) const
|
||||
{
|
||||
sr_data_t* data;
|
||||
- auto res = sr_get_data(m_sess.get(), path.c_str(), maxDepth, 0, toGetOptions(opts), &data);
|
||||
+ auto res = sr_get_data(m_sess.get(), path.c_str(), maxDepth, timeout.count(), toGetOptions(opts), &data);
|
||||
|
||||
throwIfError(res, "Session::getData: Couldn't get '"s + path + "'", m_sess.get());
|
||||
|
||||
@@ -219,10 +219,10 @@ std::optional<libyang::DataNode> Session::getData(const std::string& path, int m
|
||||
* @param path XPath which corresponds to the data that should be retrieved.
|
||||
* @returns the requested data node (as a disconnected node)
|
||||
*/
|
||||
-libyang::DataNode Session::getOneNode(const std::string& path) const
|
||||
+libyang::DataNode Session::getOneNode(const std::string& path, std::chrono::milliseconds timeout) const
|
||||
{
|
||||
sr_data_t* data;
|
||||
- auto res = sr_get_node(m_sess.get(), path.c_str(), 0, &data);
|
||||
+ auto res = sr_get_node(m_sess.get(), path.c_str(), timeout.count(), &data);
|
||||
|
||||
throwIfError(res, "Session::getOneNode: Couldn't get '"s + path + "'", m_sess.get());
|
||||
|
||||
--
|
||||
2.34.1
|
||||
|
||||
@@ -37,17 +37,23 @@ MODULES=(
|
||||
"ieee802-ethernet-interface@2019-06-21.yang"
|
||||
"infix-ethernet-interface@2024-02-27.yang"
|
||||
"infix-factory-default@2023-06-28.yang"
|
||||
"infix-interfaces@2024-01-15.yang -e vlan-filtering"
|
||||
|
||||
# from rousette
|
||||
"ietf-restconf@2017-01-26.yang"
|
||||
"ietf-yang-patch@2017-02-22.yang"
|
||||
"ietf-restconf-monitoring@2017-01-26.yang"
|
||||
|
||||
# from sysrepo
|
||||
"sysrepo-plugind@2022-08-26.yang"
|
||||
# from netopeer
|
||||
"nc-notifications@2008-07-14.yang"
|
||||
"ietf-crypto-types@2023-12-28.yang -e encrypted-private-keys"
|
||||
"ietf-netconf-server@2023-12-28.yang -e ssh-listen -e tls-listen -e ssh-call-home -e tls-call-home"
|
||||
"ietf-netconf-server@2023-12-28.yang -e ssh-listen -e tls-listen -e ssh-call-home -e tls-call-home"
|
||||
"ietf-netconf-acm@2018-02-14.yang"
|
||||
"ietf-netconf@2013-09-29.yang -e writable-running -e candidate -e rollback-on-error -e validate -e startup -e url -e xpath -e confirmed-commit"
|
||||
"ietf-truststore@2023-12-28.yang -e central-truststore-supported -e certificates"
|
||||
"ietf-keystore@2023-12-28.yang -e central-keystore-supported -e inline-definitions-supported -e asymmetric-keys -e symmetric-keys"
|
||||
"ietf-tls-server@2023-12-28.yang -e server-ident-raw-public-key -e server-ident-x509-cert"
|
||||
"ietf-restconf@2017-01-26.yang"
|
||||
"infix-interfaces@2024-01-15.yang -e vlan-filtering"
|
||||
|
||||
)
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
module ietf-restconf-monitoring {
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-restconf-monitoring";
|
||||
prefix "rcmon";
|
||||
|
||||
import ietf-yang-types { prefix yang; }
|
||||
import ietf-inet-types { prefix inet; }
|
||||
|
||||
organization
|
||||
"IETF NETCONF (Network Configuration) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: <https://datatracker.ietf.org/wg/netconf/>
|
||||
WG List: <mailto:netconf@ietf.org>
|
||||
|
||||
Author: Andy Bierman
|
||||
<mailto:andy@yumaworks.com>
|
||||
|
||||
Author: Martin Bjorklund
|
||||
<mailto:mbj@tail-f.com>
|
||||
|
||||
Author: Kent Watsen
|
||||
<mailto:kwatsen@juniper.net>";
|
||||
|
||||
description
|
||||
"This module contains monitoring information for the
|
||||
RESTCONF protocol.
|
||||
|
||||
Copyright (c) 2017 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD License
|
||||
set forth in Section 4.c of the IETF Trust's Legal Provisions
|
||||
Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 8040; see
|
||||
the RFC itself for full legal notices.";
|
||||
|
||||
revision 2017-01-26 {
|
||||
description
|
||||
"Initial revision.";
|
||||
reference
|
||||
"RFC 8040: RESTCONF Protocol.";
|
||||
}
|
||||
|
||||
container restconf-state {
|
||||
config false;
|
||||
description
|
||||
"Contains RESTCONF protocol monitoring information.";
|
||||
|
||||
container capabilities {
|
||||
description
|
||||
"Contains a list of protocol capability URIs.";
|
||||
|
||||
leaf-list capability {
|
||||
type inet:uri;
|
||||
description
|
||||
"A RESTCONF protocol capability URI.";
|
||||
}
|
||||
}
|
||||
|
||||
container streams {
|
||||
description
|
||||
"Container representing the notification event streams
|
||||
supported by the server.";
|
||||
reference
|
||||
"RFC 5277, Section 3.4, <streams> element.";
|
||||
|
||||
list stream {
|
||||
key name;
|
||||
description
|
||||
"Each entry describes an event stream supported by
|
||||
the server.";
|
||||
|
||||
leaf name {
|
||||
type string;
|
||||
description
|
||||
"The stream name.";
|
||||
reference
|
||||
"RFC 5277, Section 3.4, <name> element.";
|
||||
}
|
||||
|
||||
leaf description {
|
||||
type string;
|
||||
description
|
||||
"Description of stream content.";
|
||||
reference
|
||||
"RFC 5277, Section 3.4, <description> element.";
|
||||
}
|
||||
|
||||
leaf replay-support {
|
||||
type boolean;
|
||||
default false;
|
||||
description
|
||||
"Indicates if replay buffer is supported for this stream.
|
||||
If 'true', then the server MUST support the 'start-time'
|
||||
and 'stop-time' query parameters for this stream.";
|
||||
reference
|
||||
"RFC 5277, Section 3.4, <replaySupport> element.";
|
||||
}
|
||||
|
||||
leaf replay-log-creation-time {
|
||||
when "../replay-support" {
|
||||
description
|
||||
"Only present if notification replay is supported.";
|
||||
}
|
||||
type yang:date-and-time;
|
||||
description
|
||||
"Indicates the time the replay log for this stream
|
||||
was created.";
|
||||
reference
|
||||
"RFC 5277, Section 3.4, <replayLogCreationTime>
|
||||
element.";
|
||||
}
|
||||
|
||||
list access {
|
||||
key encoding;
|
||||
min-elements 1;
|
||||
description
|
||||
"The server will create an entry in this list for each
|
||||
encoding format that is supported for this stream.
|
||||
The media type 'text/event-stream' is expected
|
||||
for all event streams. This list identifies the
|
||||
subtypes supported for this stream.";
|
||||
|
||||
leaf encoding {
|
||||
type string;
|
||||
description
|
||||
"This is the secondary encoding format within the
|
||||
'text/event-stream' encoding used by all streams.
|
||||
The type 'xml' is supported for XML encoding.
|
||||
The type 'json' is supported for JSON encoding.";
|
||||
}
|
||||
|
||||
leaf location {
|
||||
type inet:uri;
|
||||
mandatory true;
|
||||
description
|
||||
"Contains a URL that represents the entry point
|
||||
for establishing notification delivery via
|
||||
server-sent events.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,390 @@
|
||||
module ietf-yang-patch {
|
||||
yang-version 1.1;
|
||||
namespace "urn:ietf:params:xml:ns:yang:ietf-yang-patch";
|
||||
prefix "ypatch";
|
||||
|
||||
import ietf-restconf { prefix rc; }
|
||||
|
||||
organization
|
||||
"IETF NETCONF (Network Configuration) Working Group";
|
||||
|
||||
contact
|
||||
"WG Web: <https://datatracker.ietf.org/wg/netconf/>
|
||||
WG List: <mailto:netconf@ietf.org>
|
||||
|
||||
Author: Andy Bierman
|
||||
<mailto:andy@yumaworks.com>
|
||||
|
||||
Author: Martin Bjorklund
|
||||
<mailto:mbj@tail-f.com>
|
||||
|
||||
Author: Kent Watsen
|
||||
<mailto:kwatsen@juniper.net>";
|
||||
|
||||
description
|
||||
"This module contains conceptual YANG specifications
|
||||
for the YANG Patch and YANG Patch Status data structures.
|
||||
|
||||
Note that the YANG definitions within this module do not
|
||||
represent configuration data of any kind.
|
||||
The YANG grouping statements provide a normative syntax
|
||||
for XML and JSON message-encoding purposes.
|
||||
|
||||
Copyright (c) 2017 IETF Trust and the persons identified as
|
||||
authors of the code. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or
|
||||
without modification, is permitted pursuant to, and subject
|
||||
to the license terms contained in, the Simplified BSD License
|
||||
set forth in Section 4.c of the IETF Trust's Legal Provisions
|
||||
Relating to IETF Documents
|
||||
(http://trustee.ietf.org/license-info).
|
||||
|
||||
This version of this YANG module is part of RFC 8072; see
|
||||
the RFC itself for full legal notices.";
|
||||
|
||||
revision 2017-02-22 {
|
||||
description
|
||||
"Initial revision.";
|
||||
reference
|
||||
"RFC 8072: YANG Patch Media Type.";
|
||||
}
|
||||
|
||||
typedef target-resource-offset {
|
||||
type string;
|
||||
description
|
||||
"Contains a data resource identifier string representing
|
||||
a sub-resource within the target resource.
|
||||
The document root for this expression is the
|
||||
target resource that is specified in the
|
||||
protocol operation (e.g., the URI for the PATCH request).
|
||||
|
||||
This string is encoded according to the same rules as those
|
||||
for a data resource identifier in a RESTCONF request URI.";
|
||||
reference
|
||||
"RFC 8040, Section 3.5.3.";
|
||||
}
|
||||
|
||||
rc:yang-data "yang-patch" {
|
||||
uses yang-patch;
|
||||
}
|
||||
|
||||
rc:yang-data "yang-patch-status" {
|
||||
uses yang-patch-status;
|
||||
}
|
||||
|
||||
grouping yang-patch {
|
||||
|
||||
description
|
||||
"A grouping that contains a YANG container representing the
|
||||
syntax and semantics of a YANG Patch edit request message.";
|
||||
|
||||
container yang-patch {
|
||||
description
|
||||
"Represents a conceptual sequence of datastore edits,
|
||||
called a patch. Each patch is given a client-assigned
|
||||
patch identifier. Each edit MUST be applied
|
||||
in ascending order, and all edits MUST be applied.
|
||||
If any errors occur, then the target datastore MUST NOT
|
||||
be changed by the YANG Patch operation.
|
||||
|
||||
It is possible for a datastore constraint violation to occur
|
||||
due to any node in the datastore, including nodes not
|
||||
included in the 'edit' list. Any validation errors MUST
|
||||
be reported in the reply message.";
|
||||
|
||||
reference
|
||||
"RFC 7950, Section 8.3.";
|
||||
|
||||
leaf patch-id {
|
||||
type string;
|
||||
mandatory true;
|
||||
description
|
||||
"An arbitrary string provided by the client to identify
|
||||
the entire patch. Error messages returned by the server
|
||||
that pertain to this patch will be identified by this
|
||||
'patch-id' value. A client SHOULD attempt to generate
|
||||
unique 'patch-id' values to distinguish between
|
||||
transactions from multiple clients in any audit logs
|
||||
maintained by the server.";
|
||||
}
|
||||
|
||||
leaf comment {
|
||||
type string;
|
||||
description
|
||||
"An arbitrary string provided by the client to describe
|
||||
the entire patch. This value SHOULD be present in any
|
||||
audit logging records generated by the server for the
|
||||
patch.";
|
||||
}
|
||||
|
||||
list edit {
|
||||
key edit-id;
|
||||
ordered-by user;
|
||||
|
||||
description
|
||||
"Represents one edit within the YANG Patch request message.
|
||||
The 'edit' list is applied in the following manner:
|
||||
|
||||
- The first edit is conceptually applied to a copy
|
||||
of the existing target datastore, e.g., the
|
||||
running configuration datastore.
|
||||
- Each ascending edit is conceptually applied to
|
||||
the result of the previous edit(s).
|
||||
- After all edits have been successfully processed,
|
||||
the result is validated according to YANG constraints.
|
||||
- If successful, the server will attempt to apply
|
||||
the result to the target datastore.";
|
||||
|
||||
leaf edit-id {
|
||||
type string;
|
||||
description
|
||||
"Arbitrary string index for the edit.
|
||||
Error messages returned by the server that pertain
|
||||
to a specific edit will be identified by this value.";
|
||||
}
|
||||
|
||||
leaf operation {
|
||||
type enumeration {
|
||||
enum create {
|
||||
description
|
||||
"The target data node is created using the supplied
|
||||
value, only if it does not already exist. The
|
||||
'target' leaf identifies the data node to be
|
||||
created, not the parent data node.";
|
||||
}
|
||||
enum delete {
|
||||
description
|
||||
"Delete the target node, only if the data resource
|
||||
currently exists; otherwise, return an error.";
|
||||
}
|
||||
|
||||
enum insert {
|
||||
description
|
||||
"Insert the supplied value into a user-ordered
|
||||
list or leaf-list entry. The target node must
|
||||
represent a new data resource. If the 'where'
|
||||
parameter is set to 'before' or 'after', then
|
||||
the 'point' parameter identifies the insertion
|
||||
point for the target node.";
|
||||
}
|
||||
enum merge {
|
||||
description
|
||||
"The supplied value is merged with the target data
|
||||
node.";
|
||||
}
|
||||
enum move {
|
||||
description
|
||||
"Move the target node. Reorder a user-ordered
|
||||
list or leaf-list. The target node must represent
|
||||
an existing data resource. If the 'where' parameter
|
||||
is set to 'before' or 'after', then the 'point'
|
||||
parameter identifies the insertion point to move
|
||||
the target node.";
|
||||
}
|
||||
enum replace {
|
||||
description
|
||||
"The supplied value is used to replace the target
|
||||
data node.";
|
||||
}
|
||||
enum remove {
|
||||
description
|
||||
"Delete the target node if it currently exists.";
|
||||
}
|
||||
}
|
||||
mandatory true;
|
||||
description
|
||||
"The datastore operation requested for the associated
|
||||
'edit' entry.";
|
||||
}
|
||||
|
||||
leaf target {
|
||||
type target-resource-offset;
|
||||
mandatory true;
|
||||
description
|
||||
"Identifies the target data node for the edit
|
||||
operation. If the target has the value '/', then
|
||||
the target data node is the target resource.
|
||||
The target node MUST identify a data resource,
|
||||
not the datastore resource.";
|
||||
}
|
||||
|
||||
leaf point {
|
||||
when "(../operation = 'insert' or ../operation = 'move')"
|
||||
+ "and (../where = 'before' or ../where = 'after')" {
|
||||
description
|
||||
"This leaf only applies for 'insert' or 'move'
|
||||
operations, before or after an existing entry.";
|
||||
}
|
||||
type target-resource-offset;
|
||||
description
|
||||
"The absolute URL path for the data node that is being
|
||||
used as the insertion point or move point for the
|
||||
target of this 'edit' entry.";
|
||||
}
|
||||
|
||||
leaf where {
|
||||
when "../operation = 'insert' or ../operation = 'move'" {
|
||||
description
|
||||
"This leaf only applies for 'insert' or 'move'
|
||||
operations.";
|
||||
}
|
||||
type enumeration {
|
||||
enum before {
|
||||
description
|
||||
"Insert or move a data node before the data resource
|
||||
identified by the 'point' parameter.";
|
||||
}
|
||||
enum after {
|
||||
description
|
||||
"Insert or move a data node after the data resource
|
||||
identified by the 'point' parameter.";
|
||||
}
|
||||
|
||||
enum first {
|
||||
description
|
||||
"Insert or move a data node so it becomes ordered
|
||||
as the first entry.";
|
||||
}
|
||||
enum last {
|
||||
description
|
||||
"Insert or move a data node so it becomes ordered
|
||||
as the last entry.";
|
||||
}
|
||||
}
|
||||
default last;
|
||||
description
|
||||
"Identifies where a data resource will be inserted
|
||||
or moved. YANG only allows these operations for
|
||||
list and leaf-list data nodes that are
|
||||
'ordered-by user'.";
|
||||
}
|
||||
|
||||
anydata value {
|
||||
when "../operation = 'create' "
|
||||
+ "or ../operation = 'merge' "
|
||||
+ "or ../operation = 'replace' "
|
||||
+ "or ../operation = 'insert'" {
|
||||
description
|
||||
"The anydata 'value' is only used for 'create',
|
||||
'merge', 'replace', and 'insert' operations.";
|
||||
}
|
||||
description
|
||||
"Value used for this edit operation. The anydata 'value'
|
||||
contains the target resource associated with the
|
||||
'target' leaf.
|
||||
|
||||
For example, suppose the target node is a YANG container
|
||||
named foo:
|
||||
|
||||
container foo {
|
||||
leaf a { type string; }
|
||||
leaf b { type int32; }
|
||||
}
|
||||
|
||||
The 'value' node contains one instance of foo:
|
||||
|
||||
<value>
|
||||
<foo xmlns='example-foo-namespace'>
|
||||
<a>some value</a>
|
||||
<b>42</b>
|
||||
</foo>
|
||||
</value>
|
||||
";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // grouping yang-patch
|
||||
|
||||
grouping yang-patch-status {
|
||||
|
||||
description
|
||||
"A grouping that contains a YANG container representing the
|
||||
syntax and semantics of a YANG Patch Status response
|
||||
message.";
|
||||
|
||||
container yang-patch-status {
|
||||
description
|
||||
"A container representing the response message sent by the
|
||||
server after a YANG Patch edit request message has been
|
||||
processed.";
|
||||
|
||||
leaf patch-id {
|
||||
type string;
|
||||
mandatory true;
|
||||
description
|
||||
"The 'patch-id' value used in the request.";
|
||||
}
|
||||
|
||||
choice global-status {
|
||||
description
|
||||
"Report global errors or complete success.
|
||||
If there is no case selected, then errors
|
||||
are reported in the 'edit-status' container.";
|
||||
|
||||
case global-errors {
|
||||
uses rc:errors;
|
||||
description
|
||||
"This container will be present if global errors that
|
||||
are unrelated to a specific edit occurred.";
|
||||
}
|
||||
leaf ok {
|
||||
type empty;
|
||||
description
|
||||
"This leaf will be present if the request succeeded
|
||||
and there are no errors reported in the 'edit-status'
|
||||
container.";
|
||||
}
|
||||
}
|
||||
|
||||
container edit-status {
|
||||
description
|
||||
"This container will be present if there are
|
||||
edit-specific status responses to report.
|
||||
If all edits succeeded and the 'global-status'
|
||||
returned is 'ok', then a server MAY omit this
|
||||
container.";
|
||||
|
||||
list edit {
|
||||
key edit-id;
|
||||
|
||||
description
|
||||
"Represents a list of status responses,
|
||||
corresponding to edits in the YANG Patch
|
||||
request message. If an 'edit' entry was
|
||||
skipped or not reached by the server,
|
||||
then this list will not contain a corresponding
|
||||
entry for that edit.";
|
||||
|
||||
leaf edit-id {
|
||||
type string;
|
||||
description
|
||||
"Response status is for the 'edit' list entry
|
||||
with this 'edit-id' value.";
|
||||
}
|
||||
|
||||
choice edit-status-choice {
|
||||
description
|
||||
"A choice between different types of status
|
||||
responses for each 'edit' entry.";
|
||||
leaf ok {
|
||||
type empty;
|
||||
description
|
||||
"This 'edit' entry was invoked without any
|
||||
errors detected by the server associated
|
||||
with this edit.";
|
||||
}
|
||||
case errors {
|
||||
uses rc:errors;
|
||||
description
|
||||
"The server detected errors associated with the
|
||||
edit identified by the same 'edit-id' value.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} // grouping yang-patch-status
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user