2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-09-01 14:35:29 +00:00

[#3931] Update NETCONF dependencies to v3

This commit is contained in:
Andrei Pavel
2025-06-04 12:35:43 +03:00
parent 5f50fffd9b
commit d6cda7da63
7 changed files with 78 additions and 81 deletions

View File

@@ -22,21 +22,10 @@ Installing NETCONF
To get its NETCONF capabilities, Kea requires the v2 versions of libyang and
Sysrepo. The specific versions that have been thoroughly tested with Kea are:
* libyang v2.1.4
* sysrepo v2.2.12
* libyang-cpp v1.1.0 (ae7d649ea75da081725c119dd553b2ef3121a6f8)
* sysrepo-cpp v1.1.0 (02634174ffc60568301c3d9b9b7cf710cff6a586)
.. note::
For users who are unable to upgrade to one of the versions of libyang
and Sysrepo listed above, these are the oldest versions known to work
reliably with current Kea releases:
* libyang v2.0.256 (56d4e07ef1cdeab3eb2e6700247f83ec9148edcc)
* sysrepo v2.1.84
* libyang-cpp v1.1.0 (7824d9a862f2dc1d8ad4f6a90ab6cee9200f7c81)
* sysrepo-cpp v1.1.0 (e66b2f0c53a428eeb743d355cf86fb30e8e491f1)
* libyang v3.12.2 (da7272e19d9e27d1bfdd68108fa9dce25fbdf5e8)
* sysrepo v3.6.11 (b2d60c137aa5179af2af0ce1243d4147c4e5f974)
* libyang-cpp v3 (f3cd4e05462a16e81d6bfd0c4a5b385cf88a8549)
* sysrepo-cpp v3 (fe4edfa3998fdf312099ee1fb08a06983b6907f6)
.. note::

View File

@@ -7,6 +7,7 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# pylint: disable=broad-exception-caught
# pylint: disable=logging-fstring-interpolation
"""Hammer - Kea development environment management tool."""
@@ -1211,23 +1212,25 @@ def _install_gtest_sources():
def _install_libyang_from_sources(ignore_errors=False):
"""Install libyang from sources."""
for prefix in ['/usr', '/usr/local']:
libyang_so_candidates = [f'{prefix}/lib/libyang.so', f'{prefix}/lib64/libyang.so']
libyang_header = f'{prefix}/include/libyang/version.h'
if (any(os.path.exists(i) for i in libyang_so_candidates) and os.path.exists(libyang_header) and
execute(f"grep -F '#define LY_VERSION_MAJOR 2' '{libyang_header}'", raise_error=False) == 0):
log.info('libyang is already installed at %s.', libyang_header)
return
version = '3.12.2'
version = 'v2.1.4'
libdirs = [f'{usr}/{lib}' for usr in ['/usr', '/usr/local'] for lib in ['lib', 'lib64']]
for libdir in libdirs:
pc_file = f'{libdir}/pkgconfig/libyang.pc'
if os.path.exists(pc_file):
with open(pc_file, encoding='utf-8') as file:
for line in file:
if line.rstrip('\n') == f'Version: {version}':
log.info(f'libyang is already installed: {pc_file}.')
return
execute('rm -rf ~/.hammer-tmp')
execute('mkdir -p ~/.hammer-tmp')
try:
execute('git clone https://github.com/CESNET/libyang.git ~/.hammer-tmp/libyang')
execute(f'git checkout {version}', cwd='~/.hammer-tmp/libyang')
execute(f'git checkout v{version}', cwd='~/.hammer-tmp/libyang')
execute('mkdir ~/.hammer-tmp/libyang/build')
execute('cmake -DBUILD_TESTING=OFF -DCMAKE_C_FLAGS="-Wno-incompatible-pointer-types" ..',
execute('cmake -DBUILD_TESTING=OFF ..',
cwd='~/.hammer-tmp/libyang/build')
execute('make -j $(nproc || gnproc || echo 1)', cwd='~/.hammer-tmp/libyang/build')
execute('sudo make install', cwd='~/.hammer-tmp/libyang/build')
@@ -1244,15 +1247,17 @@ def _install_libyang_from_sources(ignore_errors=False):
def _install_sysrepo_from_sources(ignore_errors=False):
"""Install sysrepo from sources."""
for prefix in ['/usr', '/usr/local']:
sysrepo_so_candidates = [f'{prefix}/lib/libsysrepo.so', f'{prefix}/lib64/libsysrepo.so']
sysrepo_header = f'{prefix}/include/sysrepo/version.h'
if (any(os.path.exists(i) for i in sysrepo_so_candidates) and os.path.exists(sysrepo_header) and
execute(f"grep -F '#define SR_VERSION_MAJOR 7' '{sysrepo_header}'", raise_error=False) == 0):
log.info('sysrepo is already installed at %s.', sysrepo_header)
return
version = '3.6.11'
version = 'v2.2.12'
libdirs = [f'{usr}/{lib}' for usr in ['/usr', '/usr/local'] for lib in ['lib', 'lib64']]
for libdir in libdirs:
pc_file = f'{libdir}/pkgconfig/sysrepo.pc'
if os.path.exists(pc_file):
with open(pc_file, encoding='utf-8') as file:
for line in file:
if line.rstrip('\n') == f'Version: {version}':
log.info(f'sysrepo is already installed: {pc_file}.')
return
# Create repository for YANG modules and change ownership to current user.
execute('sudo mkdir -p /etc/sysrepo')
@@ -1262,7 +1267,7 @@ def _install_sysrepo_from_sources(ignore_errors=False):
execute('mkdir -p ~/.hammer-tmp')
try:
execute('git clone https://github.com/sysrepo/sysrepo.git ~/.hammer-tmp/sysrepo')
execute(f'git checkout {version}', cwd='~/.hammer-tmp/sysrepo')
execute(f'git checkout v{version}', cwd='~/.hammer-tmp/sysrepo')
execute('mkdir ~/.hammer-tmp/sysrepo/build')
execute('cmake -DBUILD_TESTING=OFF -DREPO_PATH=/etc/sysrepo ..', cwd='~/.hammer-tmp/sysrepo/build')
execute('make -j $(nproc || gnproc || echo 1)', cwd='~/.hammer-tmp/sysrepo/build')
@@ -1280,33 +1285,23 @@ def _install_sysrepo_from_sources(ignore_errors=False):
def _install_libyang_cpp_from_sources(ignore_errors=False):
"""Install libyang-cpp from sources."""
for prefix_lib in ['/usr/lib', '/usr/lib64', '/usr/local/lib', '/usr/local/lib64']:
libyang_cpp_so = f'{prefix_lib}/libyang-cpp.so'
libyang_cpp_pc = f'{prefix_lib}/pkgconfig/libyang-cpp.pc'
if (os.path.exists(libyang_cpp_so) and os.path.exists(libyang_cpp_pc) and
execute(f"grep -F 'Version: 1.1.0' '{libyang_cpp_pc}'", raise_error=False) == 0):
log.info('libyang-cpp is already installed at %s.', libyang_cpp_so)
return
version = '3'
version = 'ae7d649ea75da081725c119dd553b2ef3121a6f8'
libdirs = [f'{usr}/{lib}' for usr in ['/usr', '/usr/local'] for lib in ['lib', 'lib64']]
for libdir in libdirs:
pc_file = f'{libdir}/pkgconfig/libyang-cpp.pc'
if os.path.exists(pc_file):
with open(pc_file, encoding='utf-8') as file:
for line in file:
if line.rstrip('\n') == f'Version: {version}':
log.info(f'libyang-cpp is already installed: {pc_file}.')
return
execute('rm -rf ~/.hammer-tmp')
execute('mkdir -p ~/.hammer-tmp')
try:
execute('git clone https://github.com/CESNET/libyang-cpp.git ~/.hammer-tmp/libyang-cpp')
execute(f'git checkout {version}', cwd='~/.hammer-tmp/libyang-cpp')
# New cpp compiler is more picky about missing headers. (ex. Fedora 40)
execute("""git apply <<EOF
diff --git a/src/Context.cpp b/src/Context.cpp
index b2fe887..add11cc 100644
--- a/src/Context.cpp
+++ b/src/Context.cpp
@@ -13,2 +13,3 @@
#include <libyang/libyang.h>
+#include <algorithm>
#include <span>
EOF
""", cwd='~/.hammer-tmp/libyang-cpp')
execute(f'git checkout v{version}', cwd='~/.hammer-tmp/libyang-cpp')
execute('mkdir ~/.hammer-tmp/libyang-cpp/build')
execute('cmake -DBUILD_TESTING=OFF .. ', cwd='~/.hammer-tmp/libyang-cpp/build')
execute('make -j $(nproc || gnproc || echo 1)', cwd='~/.hammer-tmp/libyang-cpp/build')
@@ -1324,21 +1319,23 @@ EOF
def _install_sysrepo_cpp_from_sources(ignore_errors=False):
"""Install sysrepo-cpp from sources."""
for prefix_lib in ['/usr/lib', '/usr/lib64', '/usr/local/lib', '/usr/local/lib64']:
sysrepo_cpp_so = f'{prefix_lib}/libsysrepo-cpp.so'
sysrepo_cpp_pc = f'{prefix_lib}/pkgconfig/sysrepo-cpp.pc'
if (os.path.exists(sysrepo_cpp_so) and os.path.exists(sysrepo_cpp_pc) and
execute(f"grep -F 'Version: 1.1.0' '{sysrepo_cpp_pc}'", raise_error=False) == 0):
log.info('sysrepo-cpp is already installed at %s.', sysrepo_cpp_so)
return
version = '3'
version = '02634174ffc60568301c3d9b9b7cf710cff6a586'
libdirs = [f'{usr}/{lib}' for usr in ['/usr', '/usr/local'] for lib in ['lib', 'lib64']]
for libdir in libdirs:
pc_file = f'{libdir}/pkgconfig/sysrepo-cpp.pc'
if os.path.exists(pc_file):
with open(pc_file, encoding='utf-8') as file:
for line in file:
if line.rstrip('\n') == f'Version: {version}':
log.info(f'sysrepo-cpp is already installed: {pc_file}.')
return
execute('rm -rf ~/.hammer-tmp')
execute('mkdir -p ~/.hammer-tmp')
try:
execute('git clone https://github.com/sysrepo/sysrepo-cpp.git ~/.hammer-tmp/sysrepo-cpp')
execute(f'git checkout {version}', cwd='~/.hammer-tmp/sysrepo-cpp')
execute(f'git checkout v{version}', cwd='~/.hammer-tmp/sysrepo-cpp')
execute('mkdir ~/.hammer-tmp/sysrepo-cpp/build')
execute('cmake -DBUILD_TESTING=OFF .. ', cwd='~/.hammer-tmp/sysrepo-cpp/build')
execute('make -j $(nproc || gnproc || echo 1)', cwd='~/.hammer-tmp/sysrepo-cpp/build')

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2018-2024 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2018-2025 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -1164,7 +1164,7 @@ TEST_F(NetconfAgentTest, noValidate) {
"BOGUS", LeafBaseType::String, true }
});
EXPECT_THROW_MSG(repr.set(tree1, *agent_->running_sess_), sysrepo::Error,
"Session::applyChanges: Couldn't apply changes: SR_ERR_CALLBACK_FAILED");
"Session::applyChanges: Couldn't apply changes: SR_ERR_VALIDATION_FAILED\n Validation failed (SR_ERR_VALIDATION_FAILED)");
}
} // namespace

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2018-2024 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2018-2025 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -183,15 +183,18 @@ TEST_F(TranslatorOptionDataListTestv4, set) {
EXPECT_THROW_MSG(sess_->setItem(xoption + "/code", s_code), sysrepo::Error,
"Session::setItem: Couldn't set "
"'/kea-dhcp4-server:config/option-data[code='100'][space='dns'][data='12121212']/code' to "
"'15': SR_ERR_INVAL_ARG");
"'15': SR_ERR_INVAL_ARG\n Editing list key \"code\" is not supported, edit list instances "
"instead. (SR_ERR_INVAL_ARG)");
EXPECT_THROW_MSG(sess_->setItem(xoption + "/space", s_space), sysrepo::Error,
"Session::setItem: Couldn't set "
"'/kea-dhcp4-server:config/option-data[code='100'][space='dns'][data='12121212']/space' to "
"'dhcp4': SR_ERR_INVAL_ARG");
"'dhcp4': SR_ERR_INVAL_ARG\n Editing list key \"space\" is not supported, edit list instances "
"instead. (SR_ERR_INVAL_ARG)");
EXPECT_THROW_MSG(sess_->setItem(xoption + "/data", s_data), sysrepo::Error,
"Session::setItem: Couldn't set "
"'/kea-dhcp4-server:config/option-data[code='100'][space='dns'][data='12121212']/data' to "
"'12121212': SR_ERR_INVAL_ARG");
"'12121212': SR_ERR_INVAL_ARG\n Editing list key \"data\" is not supported, edit list "
"instances instead. (SR_ERR_INVAL_ARG)");
// Setting the list element directly should work.
EXPECT_NO_THROW_LOG(sess_->setItem(xoption, std::nullopt));
@@ -228,15 +231,18 @@ TEST_F(TranslatorOptionDataListTestv6, set) {
EXPECT_THROW_MSG(sess_->setItem(xoption + "/code", s_code), sysrepo::Error,
"Session::setItem: Couldn't set "
"'/kea-dhcp6-server:config/option-data[code='100'][space='dns'][data='12121212']/code' to "
"'15': SR_ERR_INVAL_ARG");
"'15': SR_ERR_INVAL_ARG\n Editing list key \"code\" is not supported, edit list instances "
"instead. (SR_ERR_INVAL_ARG)");
EXPECT_THROW_MSG(sess_->setItem(xoption + "/space", s_space), sysrepo::Error,
"Session::setItem: Couldn't set "
"'/kea-dhcp6-server:config/option-data[code='100'][space='dns'][data='12121212']/space' to "
"'dhcp6': SR_ERR_INVAL_ARG");
"'dhcp6': SR_ERR_INVAL_ARG\n Editing list key \"space\" is not supported, edit list instances "
"instead. (SR_ERR_INVAL_ARG)");
EXPECT_THROW_MSG(sess_->setItem(xoption + "/data", s_data), sysrepo::Error,
"Session::setItem: Couldn't set "
"'/kea-dhcp6-server:config/option-data[code='100'][space='dns'][data='12121212']/data' to "
"'12121212': SR_ERR_INVAL_ARG");
"'12121212': SR_ERR_INVAL_ARG\n Editing list key \"data\" is not supported, edit list instances "
"instead. (SR_ERR_INVAL_ARG)");
// Setting the list element directly should work.
EXPECT_NO_THROW_LOG(sess_->setItem(xoption, std::nullopt));

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2018-2022 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2018-2025 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -155,8 +155,9 @@ TEST_F(TranslatorSharedNetworksTestKeaV6, getList) {
"\"subnet\": \"2001:db8:101::/48\" }, "
"{ \"id\": 102, \"subnet\": \"2001:db8:102::/48\" } ] }";
// Since v3, lists seem to be ordered by keys. Shouldn't be too big of a problem.
const string exp_both =
"[ " + exp_net1 + ", " + exp_net2 + " ]";
"[ " + exp_net2 + ", " + exp_net1 + " ]";
// Create the subnet1: 2001:db8:1::/48 #1 in shared network foo.
const string& xsubnet1 = xnetwork1 + "/subnet6[id='1']/subnet";

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2018-2024 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2018-2025 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -344,13 +344,17 @@ TEST_F(TranslatorTest, getItem) {
// Not existing.
xpath = "/keatest-module:main/no_such_node";
EXPECT_NO_THROW_LOG(element = translator->getItemFromAbsoluteXpath(xpath));
EXPECT_THROW_MSG(element = translator->getItemFromAbsoluteXpath(xpath), NetconfError,
"getting item at '/keatest-module:main/no_such_node': Session::getData: "
"Couldn't get '/keatest-module:main/no_such_node': SR_ERR_NOT_FOUND");
EXPECT_FALSE(element);
element.reset();
// Check error.
xpath = "null";
EXPECT_NO_THROW_LOG(element = translator->getItemFromAbsoluteXpath(xpath));
EXPECT_THROW_MSG(element = translator->getItemFromAbsoluteXpath(xpath), NetconfError,
"getting item at 'null': Session::getData: Couldn't get 'null': "
"SR_ERR_NOT_FOUND");
EXPECT_FALSE(element);
}

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2018-2022 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2018-2025 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
@@ -27,7 +27,7 @@ YangRepr::YangReprItem::getUnionType(Value const& value) {
static_assert(
std::is_same<
Value, std::variant<int8_t, int16_t, int32_t, int64_t, uint8_t, uint16_t, uint32_t,
uint64_t, bool, Empty, Binary, string, optional<DataNode>,
uint64_t, bool, Empty, Binary, string, InstanceIdentifier,
Decimal64, vector<Bit>, Enum, IdentityRef>>::value,
"Value type has changed. The if statement needs to be adjusted to include all alternatives "
"of the std::variant.");
@@ -56,7 +56,7 @@ YangRepr::YangReprItem::getUnionType(Value const& value) {
return LeafBaseType::Binary;
} else if (holds_alternative<string>(value)) {
return LeafBaseType::String;
} else if (holds_alternative<optional<DataNode>>(value)) {
} else if (holds_alternative<InstanceIdentifier>(value)) {
return LeafBaseType::InstanceIdentifier;
} else if (holds_alternative<Decimal64>(value)) {
return LeafBaseType::Dec64;