From 0c299b43f90ce155635dcec4b1f3c01685ede733 Mon Sep 17 00:00:00 2001 From: Brad House Date: Tue, 11 Feb 2025 12:28:57 -0500 Subject: [PATCH 1/5] IGNORE THIS COMMIT: merge libyang3 step 1 (PR #21679) --- .github/CODEOWNERS | 6 +- .gitmodules | 2 +- rules/docker-fpm-frr.mk | 4 +- rules/frr.mk | 5 +- rules/libyang.mk | 4 +- rules/libyang1.dep | 10 - rules/libyang1.mk | 43 -- rules/libyang2.dep | 10 - rules/libyang2.mk | 31 - rules/libyang3-py3.dep | 11 + rules/libyang3-py3.mk | 18 + rules/libyang3.dep | 10 + rules/libyang3.mk | 28 + rules/sonic-yang-models-py3.mk | 4 +- slave.mk | 2 +- sonic-slave-bookworm/Dockerfile.j2 | 9 +- sonic-slave-bullseye/Dockerfile.j2 | 12 +- sonic-slave-buster/Dockerfile.j2 | 10 +- src/libyang1/Makefile | 44 -- src/libyang2/.gitignore | 3 - src/libyang2/Makefile | 49 -- src/libyang3-py3/Makefile | 24 + src/libyang3-py3/patch/0001-debian.patch | 60 ++ .../0002-pr134-json-string-datatypes.patch | 85 +++ .../patch/0003-parse_module-memleak.patch | 40 ++ .../patch/0004-pr132-backlinks.patch | 322 ++++++++++ src/libyang3-py3/patch/series | 4 + src/{libyang1 => libyang3}/.gitignore | 2 + src/libyang3/Makefile | 36 ++ .../patch/0001-pr2344-json-strings.patch | 220 +++++++ .../patch/0002-pr2352-backlinks.patch | 554 ++++++++++++++++++ .../patch/0003-minmax-errpath-3adb304.patch | 158 +++++ .../patch/0004-union-apptag-529a594.patch | 56 ++ .../0005-pr2360-validate-union-errors.patch | 366 ++++++++++++ .../patch/0006-pr2361-union-sort-assert.patch | 45 ++ src/libyang3/patch/series | 6 + .../patch/0081-backport-libyang3.patch | 230 ++++++++ src/sonic-frr/patch/series | 1 + .../tests/yang_model_tests/test_yang_model.py | 22 +- .../yang_model_tests/tests/asic-sensors.json | 2 +- .../tests/auto_techsupport.json | 8 +- .../tests/yang_model_tests/tests/bgp.json | 11 +- .../yang_model_tests/tests/buffer_pool.json | 2 +- .../tests/device_metadata.json | 6 +- .../tests/dhcp_server_ipv4.json | 2 +- .../tests/fine-grained-ecmp.json | 8 +- .../yang_model_tests/tests/flex_counter.json | 9 +- .../tests/yang_model_tests/tests/kdump.json | 4 +- .../tests/kubernetes_master.json | 2 +- .../tests/memory_statistics.json | 8 +- .../yang_model_tests/tests/mgmt_port.json | 6 +- .../tests/mirror_session.json | 2 +- .../tests/yang_model_tests/tests/nat.json | 9 +- .../tests/yang_model_tests/tests/neigh.json | 4 +- .../tests/yang_model_tests/tests/ntp.json | 4 +- .../tests/yang_model_tests/tests/nvgre.json | 6 +- .../tests/password_hardening.json | 10 +- .../tests/yang_model_tests/tests/pbh.json | 6 +- .../yang_model_tests/tests/peer-switch.json | 2 +- .../tests/yang_model_tests/tests/port.json | 17 +- .../yang_model_tests/tests/portchannel.json | 8 +- .../tests/yang_model_tests/tests/qos.json | 4 +- .../tests/yang_model_tests/tests/restapi.json | 4 +- .../yang_model_tests/tests/route_filter.json | 3 +- .../tests/serial_console.json | 2 +- .../tests/yang_model_tests/tests/sflow.json | 4 +- .../tests/yang_model_tests/tests/snmp.json | 16 +- .../tests/sonic-events-bgp.json | 6 +- .../tests/sonic-events-dhcp-relay.json | 6 +- .../tests/sonic-events-host.json | 28 +- .../tests/sonic-events-swss.json | 8 +- .../tests/sonic-events-syncd.json | 4 +- .../yang_model_tests/tests/ssh-server.json | 10 +- .../yang_model_tests/tests/stormond.json | 4 +- .../tests/suppress_asic_sdk_health_event.json | 2 +- .../tests/yang_model_tests/tests/syslog.json | 10 +- .../yang_model_tests/tests/system_port.json | 2 +- .../tests/yang_model_tests/tests/tunnel.json | 6 +- .../tests/yang_model_tests/tests/vnet.json | 12 +- .../yang_model_tests/tests_config/neigh.json | 2 +- .../yang_model_tests/tests_config/port.json | 4 +- 81 files changed, 2454 insertions(+), 365 deletions(-) delete mode 100644 rules/libyang1.dep delete mode 100644 rules/libyang1.mk delete mode 100644 rules/libyang2.dep delete mode 100644 rules/libyang2.mk create mode 100644 rules/libyang3-py3.dep create mode 100644 rules/libyang3-py3.mk create mode 100644 rules/libyang3.dep create mode 100644 rules/libyang3.mk delete mode 100644 src/libyang1/Makefile delete mode 100644 src/libyang2/.gitignore delete mode 100644 src/libyang2/Makefile create mode 100644 src/libyang3-py3/Makefile create mode 100644 src/libyang3-py3/patch/0001-debian.patch create mode 100644 src/libyang3-py3/patch/0002-pr134-json-string-datatypes.patch create mode 100644 src/libyang3-py3/patch/0003-parse_module-memleak.patch create mode 100644 src/libyang3-py3/patch/0004-pr132-backlinks.patch create mode 100644 src/libyang3-py3/patch/series rename src/{libyang1 => libyang3}/.gitignore (58%) create mode 100644 src/libyang3/Makefile create mode 100644 src/libyang3/patch/0001-pr2344-json-strings.patch create mode 100644 src/libyang3/patch/0002-pr2352-backlinks.patch create mode 100644 src/libyang3/patch/0003-minmax-errpath-3adb304.patch create mode 100644 src/libyang3/patch/0004-union-apptag-529a594.patch create mode 100644 src/libyang3/patch/0005-pr2360-validate-union-errors.patch create mode 100644 src/libyang3/patch/0006-pr2361-union-sort-assert.patch create mode 100644 src/libyang3/patch/series create mode 100644 src/sonic-frr/patch/0081-backport-libyang3.patch diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f553a042f9a6..269863f04e24 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -63,10 +63,10 @@ # yang /src/sonic-yang-models/ @praveen-li @dgsudharsan @rathnasabapathyv @venkatmahalingam @qiluo-msft -/src/sonic-yang-mgmt/ @sonet-net/sonic-management +/src/sonic-yang-mgmt/ @sonic-net/sonic-management /src/libyang/ @sonic-net/sonic-management -/src/libyang1/ @sonic-net/sonic-management -/src/libyang2/ @sonic-net/sonic-management +/src/libyang3/ @sonic-net/sonic-management +/src/libyang3-py3/ @sonic-net/sonic-management # bgpcfgd /src/sonic-bgpcfgd/ @StormLiangMS diff --git a/.gitmodules b/.gitmodules index f8d10f3af4ab..92a585eefd9f 100644 --- a/.gitmodules +++ b/.gitmodules @@ -132,4 +132,4 @@ url = https://github.com/Marvell-switching/sonic-platform-marvell.git [submodule "platform/vpp"] path = platform/vpp - url = https://github.com/sonic-net/sonic-platform-vpp.git \ No newline at end of file + url = https://github.com/sonic-net/sonic-platform-vpp.git diff --git a/rules/docker-fpm-frr.mk b/rules/docker-fpm-frr.mk index c914dbff1da6..441c8054a05d 100644 --- a/rules/docker-fpm-frr.mk +++ b/rules/docker-fpm-frr.mk @@ -7,10 +7,10 @@ DOCKER_FPM_FRR_DBG = $(DOCKER_FPM_FRR_STEM)-$(DBG_IMAGE_MARK).gz $(DOCKER_FPM_FRR)_PATH = $(DOCKERS_PATH)/$(DOCKER_FPM_FRR_STEM) $(DOCKER_FPM_FRR)_PYTHON_WHEELS += $(SONIC_BGPCFGD) $(SONIC_FRR_MGMT_FRAMEWORK) -$(DOCKER_FPM_FRR)_DEPENDS += $(FRR) $(FRR_SNMP) $(SWSS) $(LIBYANG2) +$(DOCKER_FPM_FRR)_DEPENDS += $(FRR) $(FRR_SNMP) $(SWSS) $(LIBYANG3) $(DOCKER_FPM_FRR)_DBG_DEPENDS = $($(DOCKER_SWSS_LAYER_BOOKWORM)_DBG_DEPENDS) $(DOCKER_FPM_FRR)_DBG_DEPENDS += $(SWSS_DBG) $(LIBSWSSCOMMON_DBG) \ - $(FRR_DBG) $(FRR_SNMP_DBG) $(LIBYANG2_DBG) + $(FRR_DBG) $(FRR_SNMP_DBG) $(LIBYANG3_DBG) $(DOCKER_FPM_FRR)_DBG_IMAGE_PACKAGES = $($(DOCKER_SWSS_LAYER_BOOKWORM)_DBG_IMAGE_PACKAGES) diff --git a/rules/frr.mk b/rules/frr.mk index ff3c3ea4ab17..a952a455fe63 100644 --- a/rules/frr.mk +++ b/rules/frr.mk @@ -8,9 +8,8 @@ export FRR_VERSION FRR_SUBVERSION FRR_BRANCH FRR_TAG FRR = frr_$(FRR_VERSION)-sonic-$(FRR_SUBVERSION)_$(CONFIGURED_ARCH).deb -$(FRR)_DEPENDS += $(LIBSNMP_DEV) $(LIBYANG2) $(LIBYANG2_DEV) -$(FRR)_RDEPENDS += $(LIBYANG2) -$(FRR)_UNINSTALLS = $(LIBYANG2_DEV) $(LIBYANG2) +$(FRR)_DEPENDS += $(LIBSNMP_DEV) $(LIBYANG3_DEV) +$(FRR)_RDEPENDS += $(LIBYANG3) $(FRR)_SRC_PATH = $(SRC_PATH)/sonic-frr SONIC_MAKE_DEBS += $(FRR) diff --git a/rules/libyang.mk b/rules/libyang.mk index a8e6734459ea..0819b0a54318 100644 --- a/rules/libyang.mk +++ b/rules/libyang.mk @@ -29,7 +29,7 @@ LIBYANG_PY3 = python3-yang_$(LIBYANG_VERSION)_$(CONFIGURED_ARCH).deb $(LIBYANG_PY3)_DEPENDS += $(LIBYANG) $(LIBYANG_CPP) $(eval $(call add_derived_package,$(LIBYANG),$(LIBYANG_PY3))) -$(eval $(call add_conflict_package,$(LIBYANG),$(LIBYANG1),$(LIBYANG2))) -$(eval $(call add_conflict_package,$(LIBYANG_DEV),$(LIBYANG1_DEV),$(LIBYANG2_DEV))) +#$(eval $(call add_conflict_package,$(LIBYANG),$(LIBYANG3))) +$(eval $(call add_conflict_package,$(LIBYANG_DEV),$(LIBYANG3_DEV))) export LIBYANG LIBYANG_DBGSYM LIBYANG_DEV LIBYANG_CPP LIBYANG_PY3 diff --git a/rules/libyang1.dep b/rules/libyang1.dep deleted file mode 100644 index 343b06cf9611..000000000000 --- a/rules/libyang1.dep +++ /dev/null @@ -1,10 +0,0 @@ - -SPATH := $($(LIBYANG1)_SRC_PATH) -DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/libyang1.mk rules/libyang1.dep -DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) -DEP_FILES += $(shell git ls-files $(SPATH)) - -$(LIBYANG1)_CACHE_MODE := GIT_CONTENT_SHA -$(LIBYANG1)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) -$(LIBYANG1)_DEP_FILES := $(DEP_FILES) - diff --git a/rules/libyang1.mk b/rules/libyang1.mk deleted file mode 100644 index 6d24e3fc5a4e..000000000000 --- a/rules/libyang1.mk +++ /dev/null @@ -1,43 +0,0 @@ -# libyang1 - -LIBYANG1_VERSION_BASE = 1.0 -LIBYANG1_VERSION = $(LIBYANG1_VERSION_BASE).184 -LIBYANG1_SUBVERSION = 2 -LIBYANG1_FULLVERSION = $(LIBYANG1_VERSION)-$(LIBYANG1_SUBVERSION) - -export LIBYANG1_VERSION_BASE -export LIBYANG1_VERSION -export LIBYANG1_SUBVERSION -export LIBYANG1_FULLVERSION - -LIBYANG1 = libyang1_$(LIBYANG1_FULLVERSION)_$(CONFIGURED_ARCH).deb -$(LIBYANG1)_SRC_PATH = $(SRC_PATH)/libyang1 -SONIC_MAKE_DEBS += $(LIBYANG1) - -LIBYANG1_DEV = libyang-dev_$(LIBYANG1_FULLVERSION)_$(CONFIGURED_ARCH).deb -$(eval $(call add_derived_package,$(LIBYANG1),$(LIBYANG1_DEV))) - -LIBYANG1_DBG = libyang1-dbgsym_$(LIBYANG1_FULLVERSION)_$(CONFIGURED_ARCH).deb -$(eval $(call add_derived_package,$(LIBYANG1),$(LIBYANG1_DBG))) - -LIBYANG1_CPP = libyang-cpp1_$(LIBYANG1_FULLVERSION)_$(CONFIGURED_ARCH).deb -$(LIBYANG1_CPP)_DEPENDS += $(LIBYANG1) -$(eval $(call add_derived_package,$(LIBYANG1),$(LIBYANG1_CPP))) - -LIBYANG1_CPP_DEV = libyang-cpp-dev_$(LIBYANG1_FULLVERSION)_$(CONFIGURED_ARCH).deb -$(eval $(call add_derived_package,$(LIBYANG1),$(LIBYANG1_CPP_DEV))) - -LIBYANG1_CPP_DBG = libyang-cpp1-dbgsym_$(LIBYANG1_FULLVERSION)_$(CONFIGURED_ARCH).deb -$(eval $(call add_derived_package,$(LIBYANG1),$(LIBYANG1_CPP_DBG))) - -YANG_TOOLS = yang-tools_$(LIBYANG1_FULLVERSION)_all.deb -$(YANG_TOOLS)_DEPENDS += $(LIBYANG1) -$(eval $(call add_derived_package,$(LIBYANG1),$(YANG_TOOLS))) - -LIBYANG1_TOOLS = libyang-tools_$(LIBYANG1_FULLVERSION)_$(CONFIGURED_ARCH).deb -$(eval $(call add_derived_package,$(LIBYANG1),$(LIBYANG1_TOOLS))) - -LIBYANG1_TOOLS_DBG = libyang-tools-dbgsym_$(LIBYANG1_FULLVERSION)_$(CONFIGURED_ARCH).deb -$(eval $(call add_derived_package,$(LIBYANG1),$(LIBYANG1_TOOLS_DBG))) - -export LIBYANG1 LIBYANG1_DBG LIBYANG1_DEV LIBYANG1_CPP LIBYANG1_CPP_DEV LIBYANG1_CPP_DBG YANG_TOOLS LIBYANG1_TOOLS LIBYANG1_TOOLS_DBG diff --git a/rules/libyang2.dep b/rules/libyang2.dep deleted file mode 100644 index a1b3977f2d86..000000000000 --- a/rules/libyang2.dep +++ /dev/null @@ -1,10 +0,0 @@ - -SPATH := $($(LIBYANG2)_SRC_PATH) -DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/libyang2.mk rules/libyang2.dep -DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) -DEP_FILES += $(shell git ls-files $(SPATH)) - -$(LIBYANG2)_CACHE_MODE := GIT_CONTENT_SHA -$(LIBYANG2)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) -$(LIBYANG2)_DEP_FILES := $(DEP_FILES) - diff --git a/rules/libyang2.mk b/rules/libyang2.mk deleted file mode 100644 index e683ff05eb1f..000000000000 --- a/rules/libyang2.mk +++ /dev/null @@ -1,31 +0,0 @@ -# libyang2 - -LIBYANG2_VERSION_BASE = 2.1 -LIBYANG2_VERSION = $(LIBYANG2_VERSION_BASE).148 -LIBYANG2_SUBVERSION = 0.2 -LIBYANG2_FULLVERSION = $(LIBYANG2_VERSION)-$(LIBYANG2_SUBVERSION) - -export LIBYANG2_VERSION_BASE -export LIBYANG2_VERSION -export LIBYANG2_SUBVERSION -export LIBYANG2_FULLVERSION - -LIBYANG2 = libyang2t64_$(LIBYANG2_FULLVERSION)_$(CONFIGURED_ARCH).deb -$(LIBYANG2)_SRC_PATH = $(SRC_PATH)/libyang2 -SONIC_MAKE_DEBS += $(LIBYANG2) - -LIBYANG2_DEV = libyang2-dev_$(LIBYANG2_FULLVERSION)_$(CONFIGURED_ARCH).deb -$(eval $(call add_derived_package,$(LIBYANG2),$(LIBYANG2_DEV))) - -LIBYANG2_DBG = libyang2t64-dbgsym_$(LIBYANG2_FULLVERSION)_$(CONFIGURED_ARCH).deb -$(eval $(call add_derived_package,$(LIBYANG2),$(LIBYANG2_DBG))) - - -LIBYANG2_TOOLS = libyang2-tools_$(LIBYANG2_FULLVERSION)_$(CONFIGURED_ARCH).deb -$(eval $(call add_derived_package,$(LIBYANG2),$(LIBYANG2_TOOLS))) - -LIBYANG2_TOOLS_DBG = libyang2-tools-dbgsym_$(LIBYANG2_FULLVERSION)_$(CONFIGURED_ARCH).deb -$(eval $(call add_derived_package,$(LIBYANG2),$(LIBYANG2_TOOLS_DBG))) - -export LIBYANG2 LIBYANG2_DBG LIBYANG2_DEV LIBYANG2_TOOLS LIBYANG2_TOOLS_DBG - diff --git a/rules/libyang3-py3.dep b/rules/libyang3-py3.dep new file mode 100644 index 000000000000..117f59c641dd --- /dev/null +++ b/rules/libyang3-py3.dep @@ -0,0 +1,11 @@ + +SPATH := $($(LIBYANG3_PY3)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/libyang3-py3.mk rules/libyang3-py3.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +SMDEP_FILES := $(addprefix $(SPATH)/,$(shell cd $(SPATH) && find . -type f -exec sh -c 'git ls-files --error-unmatch "$0" >/dev/null 2>&1' {} \; -printf '%P\n')) + +$(LIBYANG3_PY3)_CACHE_MODE := GIT_CONTENT_SHA +$(LIBYANG3_PY3)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(LIBYANG3_PY3)_DEP_FILES := $(DEP_FILES) +$(LIBYANG3_PY3)_SMDEP_FILES := $(SMDEP_FILES) +$(LIBYANG3_PY3)_SMDEP_PATHS := $(SPATH) diff --git a/rules/libyang3-py3.mk b/rules/libyang3-py3.mk new file mode 100644 index 000000000000..a2f1716878ac --- /dev/null +++ b/rules/libyang3-py3.mk @@ -0,0 +1,18 @@ +# libyang3 python3 deb package + +LIBYANG3_PY3_VERSION = 3.0.3 +LIBYANG3_PY3_SUBVERSION = 1 +LIBYANG3_PY3_FULLVERSION = $(LIBYANG3_PY3_VERSION)-$(LIBYANG3_PY3_SUBVERSION) + +export LIBYANG3_PY3_VERSION +export LIBYANG3_PY3_SUBVERSION +export LIBYANG3_PY3_FULLVERSION + +LIBYANG3_PY3 = python3-libyang_$(LIBYANG3_PY3_FULLVERSION)_$(CONFIGURED_ARCH).deb +$(LIBYANG3_PY3)_SRC_PATH = $(SRC_PATH)/libyang3-py3 +$(LIBYANG3_PY3)_DEPENDS += $(LIBYANG3) $(LIBYANG3_DEV) +$(LIBYANG3_PY3)_RDEPENDS += $(LIBYANG3) +SONIC_MAKE_DEBS += $(LIBYANG3_PY3) + +export LIBYANG3_PY3 + diff --git a/rules/libyang3.dep b/rules/libyang3.dep new file mode 100644 index 000000000000..a49a6900ac83 --- /dev/null +++ b/rules/libyang3.dep @@ -0,0 +1,10 @@ + +SPATH := $($(LIBYANG3)_SRC_PATH) +DEP_FILES := $(SONIC_COMMON_FILES_LIST) rules/libyang3.mk rules/libyang3.dep +DEP_FILES += $(SONIC_COMMON_BASE_FILES_LIST) +DEP_FILES += $(shell git ls-files $(SPATH)) + +$(LIBYANG3)_CACHE_MODE := GIT_CONTENT_SHA +$(LIBYANG3)_DEP_FLAGS := $(SONIC_COMMON_FLAGS_LIST) +$(LIBYANG3)_DEP_FILES := $(DEP_FILES) + diff --git a/rules/libyang3.mk b/rules/libyang3.mk new file mode 100644 index 000000000000..695eb3a6b306 --- /dev/null +++ b/rules/libyang3.mk @@ -0,0 +1,28 @@ +# libyang3 + +LIBYANG3_VERSION = 3.7.8 +LIBYANG3_SUBVERSION = 3 +LIBYANG3_FULLVERSION = $(LIBYANG3_VERSION)-$(LIBYANG3_SUBVERSION) + +export LIBYANG3_VERSION +export LIBYANG3_SUBVERSION +export LIBYANG3_FULLVERSION + +LIBYANG3 = libyang3_$(LIBYANG3_FULLVERSION)_$(CONFIGURED_ARCH).deb +$(LIBYANG3)_SRC_PATH = $(SRC_PATH)/libyang3 +SONIC_MAKE_DEBS += $(LIBYANG3) + +LIBYANG3_DEV = libyang-dev_$(LIBYANG3_FULLVERSION)_$(CONFIGURED_ARCH).deb +$(eval $(call add_derived_package,$(LIBYANG3),$(LIBYANG3_DEV))) + +LIBYANG3_TOOLS = libyang3-tools_$(LIBYANG3_FULLVERSION)_$(CONFIGURED_ARCH).deb +$(eval $(call add_derived_package,$(LIBYANG3),$(LIBYANG3_TOOLS))) + +LIBYANG3_DBG = libyang3-dbgsym_$(LIBYANG3_FULLVERSION)_$(CONFIGURED_ARCH).deb +$(eval $(call add_derived_package,$(LIBYANG3),$(LIBYANG3_DBG))) + +LIBYANG3_TOOLS_DBG = libyang3-tools-dbgsym_$(LIBYANG3_FULLVERSION)_$(CONFIGURED_ARCH).deb +$(eval $(call add_derived_package,$(LIBYANG3),$(LIBYANG3_TOOLS_DBG))) + +export LIBYANG3 LIBYANG3_DBG LIBYANG3_DEV LIBYANG3_TOOLS LIBYANG3_TOOLS_DBG + diff --git a/rules/sonic-yang-models-py3.mk b/rules/sonic-yang-models-py3.mk index f5a606c28c3a..d5e64ac07584 100644 --- a/rules/sonic-yang-models-py3.mk +++ b/rules/sonic-yang-models-py3.mk @@ -2,7 +2,9 @@ SONIC_YANG_MODELS_PY3 = sonic_yang_models-1.0-py3-none-any.whl $(SONIC_YANG_MODELS_PY3)_SRC_PATH = $(SRC_PATH)/sonic-yang-models $(SONIC_YANG_MODELS_PY3)_PYTHON_VERSION = 3 $(SONIC_YANG_MODELS_PY3)_DEBS_DEPENDS = $(LIBYANG) $(LIBYANG_CPP) \ - $(LIBYANG_PY3) + $(LIBYANG_PY3) \ + $(LIBYANG3) \ + $(LIBYANG3_PY3) SONIC_PYTHON_WHEELS += $(SONIC_YANG_MODELS_PY3) export SONIC_YANG_MODELS_PY3 diff --git a/slave.mk b/slave.mk index 8f3864c42c97..2f39f6ded8b6 100644 --- a/slave.mk +++ b/slave.mk @@ -1733,4 +1733,4 @@ jessie : $$(addprefix $(TARGET_PATH)/,$$(JESSIE_DOCKER_IMAGES)) \ ## To build some commonly used libs. Some submodules depend on these libs. ## It is used in component pipelines. For example: swss needs libnl, libyang -lib-packages: $(addprefix $(DEBS_PATH)/,$(LIBNL3) $(LIBYANG) $(PROTOBUF) $(LIB_SONIC_DASH_API)) +lib-packages: $(addprefix $(DEBS_PATH)/,$(LIBNL3) $(LIBYANG) $(LIBYANG3) $(PROTOBUF) $(LIB_SONIC_DASH_API)) diff --git a/sonic-slave-bookworm/Dockerfile.j2 b/sonic-slave-bookworm/Dockerfile.j2 index 9bbce1541923..24fd1f882460 100644 --- a/sonic-slave-bookworm/Dockerfile.j2 +++ b/sonic-slave-bookworm/Dockerfile.j2 @@ -281,7 +281,7 @@ RUN apt-get update && apt-get install -y eatmydata && eatmydata apt-get install debhelper \ autotools-dev \ libbsd-dev \ - pkg-config \ + pkgconf \ check \ # For bmp librdkafka-dev \ @@ -370,6 +370,10 @@ RUN apt-get update && apt-get install -y eatmydata && eatmydata apt-get install libevent-dev \ # For libyang swig \ + pkgconf \ + tcl-expect \ +# For libyang3-py3 + python3-cffi \ # For build dtb device-tree-compiler \ # For sonic-mgmt-framework @@ -424,7 +428,6 @@ RUN apt-get update && apt-get install -y eatmydata && eatmydata apt-get install libdbus-1-dev \ libgirepository1.0-dev \ libsystemd-dev \ - pkg-config \ # For sonic-utilities build python3-cryptography \ # For audisp-tacplus @@ -714,7 +717,7 @@ RUN eatmydata apt-get install -y \ libxtables12:$arch \ libatm1-dev:$arch \ libbpf-dev:$arch \ - libdb-dev:$arch pkg-config:$arch \ + libdb-dev:$arch pkgconf:$arch \ libnghttp2-14:$arch \ librtmp1:$arch \ libssh2-1:$arch \ diff --git a/sonic-slave-bullseye/Dockerfile.j2 b/sonic-slave-bullseye/Dockerfile.j2 index d9517ca7d5e3..558454055489 100644 --- a/sonic-slave-bullseye/Dockerfile.j2 +++ b/sonic-slave-bullseye/Dockerfile.j2 @@ -283,7 +283,7 @@ RUN apt-get update && apt-get install -y eatmydata && eatmydata apt-get install debhelper \ autotools-dev \ libbsd-dev \ - pkg-config \ + pkgconf \ check \ # For mpdecimal docutils-common \ @@ -363,6 +363,10 @@ RUN apt-get update && apt-get install -y eatmydata && eatmydata apt-get install libevent-dev \ # For libyang swig \ + pkgconf \ + tcl-expect \ +# For libyang3-py3 + python3-cffi \ # For build dtb device-tree-compiler \ # For sonic-mgmt-framework @@ -416,7 +420,7 @@ RUN apt-get update && apt-get install -y eatmydata && eatmydata apt-get install libdbus-1-dev \ libgirepository1.0-dev \ libsystemd-dev \ - pkg-config \ + pkgconf \ # For sonic-swss-common build libhiredis-dev \ # For audisp-tacplus @@ -457,7 +461,7 @@ RUN eatmydata apt install -y \ python3-ply \ python3-scapy \ python3-thrift \ - libabsl20200923 libc-ares2 python3-six libboost-thread1.74.0 libboost-dev libboost-system-dev libboost-thread-dev libboost-filesystem1.74.0 libboost-program-options1.74.0 libboost-thread1.74.0 libnanomsg5 libpcap0.8 libthrift-0.13.0 libboost-dev libboost-filesystem-dev libboost-program-options-dev libgmp-dev libnanomsg-dev libpcap-dev libtool pkg-config libthrift-dev python3-thrift thrift-compiler libboost-iostreams1.74.0 libgc1 cpp libboost-dev libboost-all-dev libboost-graph-dev libboost-iostreams-dev libfl-dev libgc-dev libgmp-dev libbpf-dev tcpdump libelf-dev llvm clang python3-pyroute2 python3-ply python3-scapy python3-setuptools python3-thrift libthrift-0.13.0 + libabsl20200923 libc-ares2 python3-six libboost-thread1.74.0 libboost-dev libboost-system-dev libboost-thread-dev libboost-filesystem1.74.0 libboost-program-options1.74.0 libboost-thread1.74.0 libnanomsg5 libpcap0.8 libthrift-0.13.0 libboost-dev libboost-filesystem-dev libboost-program-options-dev libgmp-dev libnanomsg-dev libpcap-dev libtool pkgconf libthrift-dev python3-thrift thrift-compiler libboost-iostreams1.74.0 libgc1 cpp libboost-dev libboost-all-dev libboost-graph-dev libboost-iostreams-dev libfl-dev libgc-dev libgmp-dev libbpf-dev tcpdump libelf-dev llvm clang python3-pyroute2 python3-ply python3-scapy python3-setuptools python3-thrift libthrift-0.13.0 {%- endif %} {%- if CONFIGURED_ARCH == "amd64" %} @@ -681,7 +685,7 @@ RUN eatmydata apt-get install -y nodejs {%- if CROSS_BUILD_ENVIRON == "y" %} RUN eatmydata apt-get install -y rsync dh-python -RUN eatmydata apt-get install -y libelf-dev:$arch libdw-dev:$arch libbz2-dev:$arch liblzo2-dev:$arch libedit-dev:$arch libevent-dev:$arch libopts25-dev:$arch libssl-dev:$arch pps-tools:$arch libpam-cap:$arch libcap-dev:$arch libpam0g-dev:$arch libaudit-dev:$arch libgtk-3-dev:$arch libkrb5-dev:$arch libsystemd-dev:$arch libwrap0-dev:$arch libkrb5-dev:$arch libboost1.74-dev:$arch libboost-dev:$arch libzmq5:$arch libzmq3-dev:$arch libdaemon-dev:$arch libjansson-dev:$arch libmnl-dev:$arch libsensors5:$arch libsensors4-dev:$arch libperl-dev:$arch libmariadb-dev:$arch libmariadb-dev-compat:$arch libpci-dev:$arch libjson-c-dev:$arch libreadline-dev:$arch librtr-dev:$arch librrd-dev:$arch libnetfilter-conntrack-dev:$arch libnetfilter-conntrack3:$arch libnfnetlink-dev:$arch libnftnl-dev:$arch libldap2-dev:$arch libbind-export-dev:$arch check:$arch libboost-atomic-dev:$arch libboost-test-dev:$arch libglib2.0-dev:$arch libexplain-dev:$arch libc-ares-dev:$arch libiptc0:$arch libxtables12:$arch libatm1-dev:$arch libbpf-dev:$arch libdb-dev:$arch pkg-config:$arch libnghttp2-14:$arch librtmp1:$arch libssh2-1:$arch libcjson1:$arch libcjson-dev:$arch libcurl4-openssl-dev:$arch libboost-thread1.74-dev:$arch libboost-thread-dev:$arch libboost-system1.74-dev:$arch libboost-system-dev:$arch libgtest-dev:$arch libgmock-dev:$arch libfido2-dev:$arch libcunit1:$arch libcunit1-dev:$arch libauparse-dev:$arch libnetsnmptrapd40:$arch qtbase5-dev:$arch libboost-log-dev:$arch libboost-filesystem-dev:$arch libboost-program-options-dev:$arch +RUN eatmydata apt-get install -y libelf-dev:$arch libdw-dev:$arch libbz2-dev:$arch liblzo2-dev:$arch libedit-dev:$arch libevent-dev:$arch libopts25-dev:$arch libssl-dev:$arch pps-tools:$arch libpam-cap:$arch libcap-dev:$arch libpam0g-dev:$arch libaudit-dev:$arch libgtk-3-dev:$arch libkrb5-dev:$arch libsystemd-dev:$arch libwrap0-dev:$arch libkrb5-dev:$arch libboost1.74-dev:$arch libboost-dev:$arch libzmq5:$arch libzmq3-dev:$arch libdaemon-dev:$arch libjansson-dev:$arch libmnl-dev:$arch libsensors5:$arch libsensors4-dev:$arch libperl-dev:$arch libmariadb-dev:$arch libmariadb-dev-compat:$arch libpci-dev:$arch libjson-c-dev:$arch libreadline-dev:$arch librtr-dev:$arch librrd-dev:$arch libnetfilter-conntrack-dev:$arch libnetfilter-conntrack3:$arch libnfnetlink-dev:$arch libnftnl-dev:$arch libldap2-dev:$arch libbind-export-dev:$arch check:$arch libboost-atomic-dev:$arch libboost-test-dev:$arch libglib2.0-dev:$arch libexplain-dev:$arch libc-ares-dev:$arch libiptc0:$arch libxtables12:$arch libatm1-dev:$arch libbpf-dev:$arch libdb-dev:$arch pkgconf:$arch libnghttp2-14:$arch librtmp1:$arch libssh2-1:$arch libcjson1:$arch libcjson-dev:$arch libcurl4-openssl-dev:$arch libboost-thread1.74-dev:$arch libboost-thread-dev:$arch libboost-system1.74-dev:$arch libboost-system-dev:$arch libgtest-dev:$arch libgmock-dev:$arch libfido2-dev:$arch libcunit1:$arch libcunit1-dev:$arch libauparse-dev:$arch libnetsnmptrapd40:$arch qtbase5-dev:$arch libboost-log-dev:$arch libboost-filesystem-dev:$arch libboost-program-options-dev:$arch RUN apt-get download libgirepository1.0-dev:$arch && eatmydata dpkg --force-all -i libgirepository1.0-dev* RUN PATH=/python_virtualenv/env3/bin/:$PATH pip3 install pycairo diff --git a/sonic-slave-buster/Dockerfile.j2 b/sonic-slave-buster/Dockerfile.j2 index b65a1a08957c..1f4316dd43a7 100644 --- a/sonic-slave-buster/Dockerfile.j2 +++ b/sonic-slave-buster/Dockerfile.j2 @@ -278,7 +278,7 @@ RUN apt-get update && apt-get install -y eatmydata && eatmydata apt-get install debhelper \ autotools-dev \ libbsd-dev \ - pkg-config \ + pkgconf \ check \ # For mpdecimal docutils-common \ @@ -358,6 +358,10 @@ RUN apt-get update && apt-get install -y eatmydata && eatmydata apt-get install libevent-dev \ # For libyang swig \ + pkgconf \ + tcl-expect \ +# For libyang3-py3 + python3-cffi \ # For build dtb device-tree-compiler \ # For sonic-mgmt-framework @@ -416,7 +420,7 @@ RUN apt-get update && apt-get install -y eatmydata && eatmydata apt-get install libdbus-1-dev \ libgirepository1.0-dev \ libsystemd-dev \ - pkg-config \ + pkgconf \ # For sonic-swss-common build libhiredis-dev \ # For audisp-tacplus @@ -650,7 +654,7 @@ RUN eatmydata apt-get install -y nodejs {%- if CROSS_BUILD_ENVIRON == "y" %} RUN eatmydata apt-get install -y rsync dh-python -RUN eatmydata apt-get install -y libelf-dev:$arch libdw-dev:$arch libbz2-dev:$arch liblzo2-dev:$arch libedit-dev:$arch libevent-dev:$arch libopts25-dev:$arch libssl-dev:$arch pps-tools:$arch libpam-cap:$arch libcap-dev:$arch libpam0g-dev:$arch libaudit-dev:$arch libgtk-3-dev:$arch libkrb5-dev:$arch libsystemd-dev:$arch libwrap0-dev:$arch libkrb5-dev:$arch libboost1.67-dev:$arch libboost-dev:$arch libzmq5:$arch libzmq3-dev:$arch libdaemon-dev:$arch libjansson-dev:$arch libmnl-dev:$arch libsensors5:$arch libsensors4-dev:$arch libperl-dev:$arch libmariadb-dev:$arch libmariadb-dev-compat:$arch libpci-dev:$arch libjson-c3:$arch libjson-c-dev:$arch libreadline-dev:$arch librtr-dev:$arch librrd-dev:$arch libnetfilter-conntrack-dev:$arch libnetfilter-conntrack3:$arch libnfnetlink-dev:$arch libnftnl-dev:$arch libldap2-dev:$arch libbind-export-dev:$arch check:$arch libboost-atomic-dev:$arch libboost-test-dev:$arch libglib2.0-dev:$arch qt5-default:$arch libexplain-dev:$arch libc-ares-dev:$arch libip4tc0:$arch libip6tc0:$arch libiptc0:$arch libxtables12:$arch iptables-dev:$arch libatm1-dev:$arch libdb-dev:$arch pkg-config:$arch libnghttp2-14:$arch librtmp1:$arch libssh2-1:$arch libcjson1:$arch libcjson-dev:$arch libcurl4-openssl-dev:$arch libboost-thread1.67-dev:$arch libboost-thread-dev:$arch libboost-system1.67-dev:$arch libboost-system-dev:$arch libgtest-dev:$arch libgmock-dev:$arch +RUN eatmydata apt-get install -y libelf-dev:$arch libdw-dev:$arch libbz2-dev:$arch liblzo2-dev:$arch libedit-dev:$arch libevent-dev:$arch libopts25-dev:$arch libssl-dev:$arch pps-tools:$arch libpam-cap:$arch libcap-dev:$arch libpam0g-dev:$arch libaudit-dev:$arch libgtk-3-dev:$arch libkrb5-dev:$arch libsystemd-dev:$arch libwrap0-dev:$arch libkrb5-dev:$arch libboost1.67-dev:$arch libboost-dev:$arch libzmq5:$arch libzmq3-dev:$arch libdaemon-dev:$arch libjansson-dev:$arch libmnl-dev:$arch libsensors5:$arch libsensors4-dev:$arch libperl-dev:$arch libmariadb-dev:$arch libmariadb-dev-compat:$arch libpci-dev:$arch libjson-c3:$arch libjson-c-dev:$arch libreadline-dev:$arch librtr-dev:$arch librrd-dev:$arch libnetfilter-conntrack-dev:$arch libnetfilter-conntrack3:$arch libnfnetlink-dev:$arch libnftnl-dev:$arch libldap2-dev:$arch libbind-export-dev:$arch check:$arch libboost-atomic-dev:$arch libboost-test-dev:$arch libglib2.0-dev:$arch qt5-default:$arch libexplain-dev:$arch libc-ares-dev:$arch libip4tc0:$arch libip6tc0:$arch libiptc0:$arch libxtables12:$arch iptables-dev:$arch libatm1-dev:$arch libdb-dev:$arch pkgconf:$arch libnghttp2-14:$arch librtmp1:$arch libssh2-1:$arch libcjson1:$arch libcjson-dev:$arch libcurl4-openssl-dev:$arch libboost-thread1.67-dev:$arch libboost-thread-dev:$arch libboost-system1.67-dev:$arch libboost-system-dev:$arch libgtest-dev:$arch libgmock-dev:$arch RUN eatmydata apt-get install -y -t buster-backports \ libbpf-dev:$arch diff --git a/src/libyang1/Makefile b/src/libyang1/Makefile deleted file mode 100644 index a87f03bf638c..000000000000 --- a/src/libyang1/Makefile +++ /dev/null @@ -1,44 +0,0 @@ -.ONESHELL: -SHELL = /bin/bash -.SHELLFLAGS += -e - -LIBYANG_URL = https://sonicstorage.blob.core.windows.net/debian/pool/main/liby/libyang - -DSC_FILE = libyang_$(LIBYANG1_FULLVERSION).dsc -ORIG_FILE = libyang_$(LIBYANG1_VERSION).orig.tar.gz -DEBIAN_FILE = libyang_$(LIBYANG1_FULLVERSION).debian.tar.xz - -DSC_FILE_URL = $(LIBYANG_URL)/$(DSC_FILE) -ORIG_FILE_URL = $(LIBYANG_URL)/$(ORIG_FILE) -DEBIAN_FILE_URL = $(LIBYANG_URL)/$(DEBIAN_FILE) - -MAIN_TARGET = $(LIBYANG1) -DERIVED_TARGETS = $(LIBYANG1_DEV) $(LIBYANG1_DBG) $(LIBYANG1_CPP) $(LIBYANG1_CPP_DEV) $(LIBYANG1_CPP_DBG) $(YANG_TOOLS) $(LIBYANG1_TOOLS) $(LIBYANG1_TOOLS_DBG) - -$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : - # Obtaining the libyang - rm -fr ./libyang-$(LIBYANG1_VERSION) - - # download debian libyang - wget -NO "$(DSC_FILE)" $(DSC_FILE_URL) - wget -NO "$(ORIG_FILE)" $(ORIG_FILE_URL) - wget -NO "$(DEBIAN_FILE)" $(DEBIAN_FILE_URL) - dpkg-source -x libyang_$(LIBYANG1_FULLVERSION).dsc - - pushd libyang-$(LIBYANG1_VERSION) - sed -i 's/set(LIBYANG_MAJOR_SOVERSION 1)/set(LIBYANG_MAJOR_SOVERSION 2)/' CMakeLists.txt - sed -i 's/libyang1/libyang2/' debian/libyang1.install - # Enable large file support for 32-bit arch - echo 'add_definitions(-D_FILE_OFFSET_BITS=64)' >> CMakeLists.txt - -ifeq ($(CROSS_BUILD_ENVIRON), y) - dpkg-buildpackage -rfakeroot -b -us -uc -a$(CONFIGURED_ARCH) -Pcross,nocheck -j$(SONIC_CONFIG_MAKE_JOBS) --admindir $(SONIC_DPKG_ADMINDIR) -else - dpkg-buildpackage -rfakeroot -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) --admindir $(SONIC_DPKG_ADMINDIR) -endif - popd - - # Move the newly-built .deb packages to the destination directory - mv $* $(DERIVED_TARGETS) $(DEST)/ - -$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/src/libyang2/.gitignore b/src/libyang2/.gitignore deleted file mode 100644 index a0991ff4402b..000000000000 --- a/src/libyang2/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -* -!.gitignore -!Makefile diff --git a/src/libyang2/Makefile b/src/libyang2/Makefile deleted file mode 100644 index 16d80587573e..000000000000 --- a/src/libyang2/Makefile +++ /dev/null @@ -1,49 +0,0 @@ -.ONESHELL: -SHELL = /bin/bash -.SHELLFLAGS += -e - -LIBYANG_URL = https://sonicstorage.blob.core.windows.net/debian/pool/main/liby/libyang - -DSC_FILE = libyang2_$(LIBYANG2_FULLVERSION).dsc -ORIG_FILE = libyang2_$(LIBYANG2_VERSION).orig.tar.xz -DEBIAN_FILE = libyang2_$(LIBYANG2_FULLVERSION).debian.tar.xz - -DSC_FILE_URL = $(LIBYANG_URL)/$(DSC_FILE) -ORIG_FILE_URL = $(LIBYANG_URL)/$(ORIG_FILE) -DEBIAN_FILE_URL = $(LIBYANG_URL)/$(DEBIAN_FILE) - -MAIN_TARGET = $(LIBYANG2) -DERIVED_TARGETS = $(LIBYANG2_DEV) $(LIBYANG2_DBG) $(LIBYANG2_TOOLS) $(LIBYANG2_TOOLS_DBG) - -$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : - # Obtaining the libyang - rm -fr ./libyang2-$(LIBYANG2_VERSION) - - # download debian libyang - wget -NO "$(DSC_FILE)" $(DSC_FILE_URL) - wget -NO "$(ORIG_FILE)" $(ORIG_FILE_URL) - wget -NO "$(DEBIAN_FILE)" $(DEBIAN_FILE_URL) - dpkg-source -x libyang2_$(LIBYANG2_FULLVERSION).dsc - - pushd libyang2-$(LIBYANG2_VERSION) - #The package libyang2.1.148 is taken from debian trixie, which only has dpkg-dev version 1.21.22 - #The bullseye package has dpkg-dev version 1.20.13 - #The VS package has dpkg-dev version 1.19.8 - sed -i 's/dpkg-dev (>= 1.22.5)/dpkg-dev (>= 1.19.8)/' debian/control - #sed -i 's/set(LIBYANG_MAJOR_SOVERSION 1)/set(LIBYANG_MAJOR_SOVERSION 2)/' CMakeLists.txt - #sed -i 's/libyang2/libyang2/' debian/libyang2.install - # Enable large file support for 32-bit arch - echo 'add_definitions(-D_FILE_OFFSET_BITS=64)' >> CMakeLists.txt - -ifeq ($(CROSS_BUILD_ENVIRON), y) - dpkg-buildpackage -rfakeroot -d -b -us -uc -a$(CONFIGURED_ARCH) -Pcross,nocheck -j$(SONIC_CONFIG_MAKE_JOBS) -else - dpkg-buildpackage -rfakeroot -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) --admindir $(SONIC_DPKG_ADMINDIR) -endif - - popd - - # Move the newly-built .deb packages to the destination directory - mv $* $(DERIVED_TARGETS) $(DEST)/ - -$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/src/libyang3-py3/Makefile b/src/libyang3-py3/Makefile new file mode 100644 index 000000000000..db35973f590a --- /dev/null +++ b/src/libyang3-py3/Makefile @@ -0,0 +1,24 @@ +SHELL = /bin/bash +.ONESHELL: +.SHELLFLAGS += -e + +MAIN_TARGET = $(LIBYANG3_PY3) + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + rm -rf ./libyang-python + # Obtain libyang-python + git clone --depth 1 -b v3.0.3 https://github.com/CESNET/libyang-python.git libyang-python + pushd ./libyang-python + + # Apply patch series + QUILT_PATCHES=../patch quilt push -a + + # Build package +ifeq ($(CROSS_BUILD_ENVIRON), y) + dpkg-buildpackage -rfakeroot -d -b -us -uc -a$(CONFIGURED_ARCH) -Pcross,nocheck -j$(SONIC_CONFIG_MAKE_JOBS) +else + dpkg-buildpackage -rfakeroot -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) --admindir $(SONIC_DPKG_ADMINDIR) +endif + popd + + mv $* $(DEST)/ diff --git a/src/libyang3-py3/patch/0001-debian.patch b/src/libyang3-py3/patch/0001-debian.patch new file mode 100644 index 000000000000..7775cdac0dac --- /dev/null +++ b/src/libyang3-py3/patch/0001-debian.patch @@ -0,0 +1,60 @@ +diff -ruN libyang-python.orig/debian/changelog libyang-python.new/debian/changelog +--- libyang-python.orig/debian/changelog 1970-01-01 00:00:00.000000000 +0000 ++++ libyang-python.new/debian/changelog 2025-02-09 12:45:51.113010546 +0000 +@@ -0,0 +1,5 @@ ++libyang-python (3.0.3-1) unstable; urgency=low ++ ++ * source package automatically created by stdeb 0.10.0 ++ ++ -- None Sat, 08 Feb 2025 20:55:02 +0000 +diff -ruN libyang-python.orig/debian/compat libyang-python.new/debian/compat +--- libyang-python.orig/debian/compat 1970-01-01 00:00:00.000000000 +0000 ++++ libyang-python.new/debian/compat 2025-02-09 12:45:51.113010546 +0000 +@@ -0,0 +1 @@ ++13 +diff -ruN libyang-python.orig/debian/control libyang-python.new/debian/control +--- libyang-python.orig/debian/control 1970-01-01 00:00:00.000000000 +0000 ++++ libyang-python.new/debian/control 2025-02-09 12:45:51.113010546 +0000 +@@ -0,0 +1,15 @@ ++Source: libyang-python ++Maintainer: None ++Section: python ++Priority: optional ++Build-Depends: dh-python, python3-setuptools, python3-all-dev, python3-cffi, debhelper (>= 13), libyang-dev ( >= 3.0.3) ++Standards-Version: 3.9.6 ++Homepage: https://github.com/CESNET/libyang-python ++ ++Package: python3-libyang ++Architecture: any ++Depends: ${misc:Depends}, ${python3:Depends}, ${shlibs:Depends} ++Description: CFFI bindings to libyang ++ Python CFFI bindings to libyang ++ https://github.com/CESNET/libyang/ ++ +diff -ruN libyang-python.orig/debian/rules libyang-python.new/debian/rules +--- libyang-python.orig/debian/rules 1970-01-01 00:00:00.000000000 +0000 ++++ libyang-python.new/debian/rules 2025-02-09 12:45:51.113010546 +0000 +@@ -0,0 +1,9 @@ ++#!/usr/bin/make -f ++ ++# This file was automatically generated by stdeb 0.10.0 at ++# Sat, 08 Feb 2025 20:55:02 +0000 ++export PYBUILD_NAME=libyang ++ ++%: ++ dh $@ --with python3 --buildsystem=pybuild ++ +diff -ruN libyang-python.orig/debian/source/format libyang-python.new/debian/source/format +--- libyang-python.orig/debian/source/format 1970-01-01 00:00:00.000000000 +0000 ++++ libyang-python.new/debian/source/format 2025-02-09 12:45:51.113010546 +0000 +@@ -0,0 +1 @@ ++3.0 (quilt) +diff -ruN libyang-python.orig/debian/watch libyang-python.new/debian/watch +--- libyang-python.orig/debian/watch 1970-01-01 00:00:00.000000000 +0000 ++++ libyang-python.new/debian/watch 2025-02-09 12:45:51.113010546 +0000 +@@ -0,0 +1,4 @@ ++# please also check http://pypi.debian.net/libyang/watch ++version=3 ++opts=uversionmangle=s/(rc|a|b|c)/~$1/ \ ++http://pypi.debian.net/libyang/libyang-(.+)\.(?:zip|tgz|tbz|txz|(?:tar\.(?:gz|bz2|xz))) +\ No newline at end of file diff --git a/src/libyang3-py3/patch/0002-pr134-json-string-datatypes.patch b/src/libyang3-py3/patch/0002-pr134-json-string-datatypes.patch new file mode 100644 index 000000000000..75c0eab9a867 --- /dev/null +++ b/src/libyang3-py3/patch/0002-pr134-json-string-datatypes.patch @@ -0,0 +1,85 @@ +diff --git a/cffi/cdefs.h b/cffi/cdefs.h +index 1c1d8f3..89f607b 100644 +--- a/cffi/cdefs.h ++++ b/cffi/cdefs.h +@@ -318,6 +318,7 @@ LY_ERR lyd_print_all(struct ly_out *, const struct lyd_node *, LYD_FORMAT, uint3 + #define LYD_PARSE_OPTS_MASK ... + #define LYD_PARSE_ORDERED ... + #define LYD_PARSE_STRICT ... ++#define LYD_PARSE_JSON_STRING_DATATYPES ... + + #define LYD_VALIDATE_NO_STATE ... + #define LYD_VALIDATE_PRESENT ... +diff --git a/libyang/context.py b/libyang/context.py +index 1b1d4cd..2692eb3 100644 +--- a/libyang/context.py ++++ b/libyang/context.py +@@ -520,6 +520,7 @@ def parse_data( + validate_present: bool = False, + validate_multi_error: bool = False, + store_only: bool = False, ++ json_string_datatypes: bool = False, + ) -> Optional[DNode]: + if self.cdata is None: + raise RuntimeError("context already destroyed") +@@ -531,6 +532,7 @@ def parse_data( + ordered=ordered, + strict=strict, + store_only=store_only, ++ json_string_datatypes=json_string_datatypes, + ) + validation_flgs = validation_flags( + no_state=no_state, +@@ -589,6 +591,7 @@ def parse_data_mem( + validate_present: bool = False, + validate_multi_error: bool = False, + store_only: bool = False, ++ json_string_datatypes: bool = False, + ) -> Optional[DNode]: + return self.parse_data( + fmt, +@@ -604,6 +607,7 @@ def parse_data_mem( + validate_present=validate_present, + validate_multi_error=validate_multi_error, + store_only=store_only, ++ json_string_datatypes=json_string_datatypes, + ) + + def parse_data_file( +@@ -620,6 +624,7 @@ def parse_data_file( + validate_present: bool = False, + validate_multi_error: bool = False, + store_only: bool = False, ++ json_string_datatypes: bool = False, + ) -> Optional[DNode]: + return self.parse_data( + fmt, +@@ -635,6 +640,7 @@ def parse_data_file( + validate_present=validate_present, + validate_multi_error=validate_multi_error, + store_only=store_only, ++ json_string_datatypes=json_string_datatypes, + ) + + def __iter__(self) -> Iterator[Module]: +diff --git a/libyang/data.py b/libyang/data.py +index 19ef0ca..86c26e1 100644 +--- a/libyang/data.py ++++ b/libyang/data.py +@@ -116,6 +116,7 @@ def parser_flags( + ordered: bool = False, + strict: bool = False, + store_only: bool = False, ++ json_string_datatypes: bool = False, + ) -> int: + flags = 0 + if lyb_mod_update: +@@ -132,6 +133,8 @@ def parser_flags( + flags |= lib.LYD_PARSE_STRICT + if store_only: + flags |= lib.LYD_PARSE_STORE_ONLY ++ if json_string_datatypes: ++ flags |= lib.LYD_PARSE_JSON_STRING_DATATYPES + return flags + + diff --git a/src/libyang3-py3/patch/0003-parse_module-memleak.patch b/src/libyang3-py3/patch/0003-parse_module-memleak.patch new file mode 100644 index 000000000000..74e1321649b7 --- /dev/null +++ b/src/libyang3-py3/patch/0003-parse_module-memleak.patch @@ -0,0 +1,40 @@ +From 6550259f36da08b9b4bc7e9c941b2e13e10661a1 Mon Sep 17 00:00:00 2001 +From: Brad House +Date: Wed, 5 Feb 2025 19:38:43 -0500 +Subject: [PATCH] correct memory leak of `struct ly_in *` objects + +`data_load()` returns a reference to `struct ly_in *` which +must be free'd by `lys_in_free()`. This is done in one of three +locations. This corrects this oversight. + +This was found during unit tests of SONiC during porting to +libyang3 from libyang 1.0.73. + +Signed-off-by: Brad House (@bradh352) +--- + libyang/context.py | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/libyang/context.py b/libyang/context.py +index 1b1d4cd..8be232c 100644 +--- a/libyang/context.py ++++ b/libyang/context.py +@@ -325,7 +325,9 @@ def parse_module( + + mod = ffi.new("struct lys_module **") + fmt = schema_in_format(fmt) +- if lib.lys_parse(self.cdata, data[0], fmt, feat, mod) != lib.LY_SUCCESS: ++ rv = lib.lys_parse(self.cdata, data[0], fmt, feat, mod) ++ lib.ly_in_free(data[0], 0) ++ if rv != lib.LY_SUCCESS: + raise self.error("failed to parse module") + + return Module(self, mod[0]) +@@ -489,6 +491,7 @@ def parse_op( + par[0] = parent.cdata + + ret = lib.lyd_parse_op(self.cdata, par[0], data[0], fmt, dtype, tree, op) ++ lib.ly_in_free(data[0], 0) + if ret != lib.LY_SUCCESS: + raise self.error("failed to parse input data") + diff --git a/src/libyang3-py3/patch/0004-pr132-backlinks.patch b/src/libyang3-py3/patch/0004-pr132-backlinks.patch new file mode 100644 index 000000000000..fb889e8a469a --- /dev/null +++ b/src/libyang3-py3/patch/0004-pr132-backlinks.patch @@ -0,0 +1,322 @@ +From ebb79c5fec9635b5efb7a24daf1537ba91491f6a Mon Sep 17 00:00:00 2001 +From: Brad House +Date: Sun, 16 Feb 2025 11:04:50 -0500 +Subject: [PATCH] schema/context: restore some backlinks support + +In libyang v1 the schema nodes had a backlinks member to be able to +look up dependents of the node. SONiC depends on this to provide +functionality it uses and it needs to be exposed via the python +module. + +In theory, exposing the 'dfs' functions could make this work, but +it would likely be cost prohibitive since walking the tree would +be expensive to create a python node for evaluation in native +python. + +Instead this PR depends on the this libyang PR: +https://github.com/CESNET/libyang/pull/2352 +And adds thin wrappers. + +This implementation provides 2 python functions: + * Context.find_backlinks_paths() - This function can + take the path of the base node and find all dependents. If + no path is specified, then it will return all nodes that contain + a leafref reference. + * Context.find_leafref_path_target_paths() - This function takes + an xpath, then returns all target nodes the xpath may reference. + Typically only one will be returned, but multiples may be in the + case of a union. + +A user can build a cache by combining Context.find_backlinks_paths() +with no path set and building a reverse table using +Context.find_leafref_path_target_paths() + +Signed-off-by: Brad House +--- + cffi/cdefs.h | 2 + + libyang/context.py | 98 +++++++++++++++++++ + tests/test_schema.py | 58 +++++++++++ + .../yang/yolo/yolo-leafref-search-extmod.yang | 39 ++++++++ + tests/yang/yolo/yolo-leafref-search.yang | 36 +++++++ + 5 files changed, 233 insertions(+) + create mode 100644 tests/yang/yolo/yolo-leafref-search-extmod.yang + create mode 100644 tests/yang/yolo/yolo-leafref-search.yang + +diff --git a/cffi/cdefs.h b/cffi/cdefs.h +index aa75004..e7dc978 100644 +--- a/cffi/cdefs.h ++++ b/cffi/cdefs.h +@@ -861,6 +861,8 @@ const struct lysc_node* lys_find_child(const struct lysc_node *, const struct ly + const struct lysc_node* lysc_node_child(const struct lysc_node *); + const struct lysc_node_action* lysc_node_actions(const struct lysc_node *); + const struct lysc_node_notif* lysc_node_notifs(const struct lysc_node *); ++LY_ERR lysc_node_lref_targets(const struct lysc_node *, struct ly_set **); ++LY_ERR lysc_node_lref_backlinks(const struct ly_ctx *, const struct lysc_node *, ly_bool, struct ly_set **); + + typedef enum { + LYD_PATH_STD, +diff --git a/libyang/context.py b/libyang/context.py +index fb4a330..d6eb7a3 100644 +--- a/libyang/context.py ++++ b/libyang/context.py +@@ -646,6 +646,104 @@ def parse_data_file( + json_null=json_null, + ) + ++ def find_leafref_path_target_paths(self, leafref_path: str) -> list[str]: ++ """ ++ Fetch all leafref targets of the specified path ++ ++ This is an enhanced version of lysc_node_lref_target() which will return ++ a set of leafref target paths retrieved from the specified schema path. ++ While lysc_node_lref_target() will only work on nodetype of LYS_LEAF and ++ LYS_LEAFLIST this function will also evaluate other datatypes that may ++ contain leafrefs such as LYS_UNION. This does not, however, search for ++ children with leafref targets. ++ ++ :arg self ++ This instance on context ++ :arg leafref_path: ++ Path to node to search for leafref targets ++ :returns List of target paths that the leafrefs of the specified node ++ point to. ++ """ ++ if self.cdata is None: ++ raise RuntimeError("context already destroyed") ++ if leafref_path is None: ++ raise RuntimeError("leafref_path must be defined") ++ ++ out = [] ++ ++ node = lib.lys_find_path(self.cdata, ffi.NULL, str2c(leafref_path), 0) ++ if node == ffi.NULL: ++ raise self.error("leafref_path not found") ++ ++ node_set = ffi.new("struct ly_set **") ++ if (lib.lysc_node_lref_targets(node, node_set) != lib.LY_SUCCESS or ++ node_set[0] == ffi.NULL or node_set[0].count == 0): ++ raise self.error("leafref_path does not contain any leafref targets") ++ ++ node_set = node_set[0] ++ for i in range(node_set.count): ++ path = lib.lysc_path(node_set.snodes[i], lib.LYSC_PATH_DATA, ffi.NULL, 0); ++ out.append(c2str(path)) ++ lib.free(path) ++ ++ lib.ly_set_free(node_set, ffi.NULL) ++ ++ return out ++ ++ ++ def find_backlinks_paths(self, match_path: str = None, match_ancestors: bool = False) -> list[str]: ++ """ ++ Search entire schema for nodes that contain leafrefs and return as a ++ list of schema node paths. ++ ++ Perform a complete scan of the schema tree looking for nodes that ++ contain leafref entries. When a node contains a leafref entry, and ++ match_path is specified, determine if reference points to match_path, ++ if so add the node's path to returned list. If no match_path is ++ specified, the node containing the leafref is always added to the ++ returned set. When match_ancestors is true, will evaluate if match_path ++ is self or an ansestor of self. ++ ++ This does not return the leafref targets, but the actual node that ++ contains a leafref. ++ ++ :arg self ++ This instance on context ++ :arg match_path: ++ Target path to use for matching ++ :arg match_ancestors: ++ Whether match_path is a base ancestor or an exact node ++ :returns List of paths. Exception of match_path is not found or if no ++ backlinks are found. ++ """ ++ if self.cdata is None: ++ raise RuntimeError("context already destroyed") ++ out = [] ++ ++ match_node = ffi.NULL ++ if match_path is not None and match_path == "/" or match_path == "": ++ match_path = None ++ ++ if match_path: ++ match_node = lib.lys_find_path(self.cdata, ffi.NULL, str2c(match_path), 0) ++ if match_node == ffi.NULL: ++ raise self.error("match_path not found") ++ ++ node_set = ffi.new("struct ly_set **") ++ if (lib.lysc_node_lref_backlinks(self.cdata, match_node, match_ancestors, node_set) ++ != lib.LY_SUCCESS or node_set[0] == ffi.NULL or node_set[0].count == 0): ++ raise self.error("backlinks not found") ++ ++ node_set = node_set[0] ++ for i in range(node_set.count): ++ path = lib.lysc_path(node_set.snodes[i], lib.LYSC_PATH_DATA, ffi.NULL, 0); ++ out.append(c2str(path)) ++ lib.free(path) ++ ++ lib.ly_set_free(node_set, ffi.NULL) ++ ++ return out ++ + def __iter__(self) -> Iterator[Module]: + """ + Return an iterator that yields all implemented modules from the context +diff --git a/tests/test_schema.py b/tests/test_schema.py +index a310aad..4aae73a 100644 +--- a/tests/test_schema.py ++++ b/tests/test_schema.py +@@ -801,6 +801,64 @@ def test_leaf_list_parsed(self): + self.assertFalse(pnode.ordered()) + + ++# ------------------------------------------------------------------------------------- ++class BacklinksTest(unittest.TestCase): ++ def setUp(self): ++ self.ctx = Context(YANG_DIR) ++ self.ctx.load_module("yolo-leafref-search") ++ self.ctx.load_module("yolo-leafref-search-extmod") ++ def tearDown(self): ++ self.ctx.destroy() ++ self.ctx = None ++ def test_backlinks_all_nodes(self): ++ expected = [ ++ "/yolo-leafref-search-extmod:my_extref_list/my_extref", ++ "/yolo-leafref-search:refstr", ++ "/yolo-leafref-search:refnum", ++ "/yolo-leafref-search-extmod:my_extref_list/my_extref_union" ++ ] ++ refs = self.ctx.find_backlinks_paths() ++ expected.sort() ++ refs.sort() ++ self.assertEqual(expected, refs) ++ def test_backlinks_one(self): ++ expected = [ ++ "/yolo-leafref-search-extmod:my_extref_list/my_extref", ++ "/yolo-leafref-search:refstr", ++ "/yolo-leafref-search-extmod:my_extref_list/my_extref_union" ++ ] ++ refs = self.ctx.find_backlinks_paths( ++ match_path="/yolo-leafref-search:my_list/my_leaf_string" ++ ) ++ expected.sort() ++ refs.sort() ++ self.assertEqual(expected, refs) ++ def test_backlinks_children(self): ++ expected = [ ++ "/yolo-leafref-search-extmod:my_extref_list/my_extref", ++ "/yolo-leafref-search:refstr", ++ "/yolo-leafref-search:refnum", ++ "/yolo-leafref-search-extmod:my_extref_list/my_extref_union" ++ ] ++ refs = self.ctx.find_backlinks_paths( ++ match_path="/yolo-leafref-search:my_list", ++ match_ancestors=True ++ ) ++ expected.sort() ++ refs.sort() ++ self.assertEqual(expected, refs) ++ def test_backlinks_leafref_target_paths(self): ++ expected = [ ++ "/yolo-leafref-search:my_list/my_leaf_string" ++ ] ++ refs = self.ctx.find_leafref_path_target_paths( ++ "/yolo-leafref-search-extmod:my_extref_list/my_extref" ++ ) ++ expected.sort() ++ refs.sort() ++ self.assertEqual(expected, refs) ++ ++ + # ------------------------------------------------------------------------------------- + class ChoiceTest(unittest.TestCase): + def setUp(self): +diff --git a/tests/yang/yolo/yolo-leafref-search-extmod.yang b/tests/yang/yolo/yolo-leafref-search-extmod.yang +new file mode 100644 +index 0000000..046ceec +--- /dev/null ++++ b/tests/yang/yolo/yolo-leafref-search-extmod.yang +@@ -0,0 +1,39 @@ ++module yolo-leafref-search-extmod { ++ yang-version 1.1; ++ namespace "urn:yang:yolo:leafref-search-extmod"; ++ prefix leafref-search-extmod; ++ ++ import wtf-types { prefix types; } ++ ++ import yolo-leafref-search { ++ prefix leafref-search; ++ } ++ ++ revision 2025-02-11 { ++ description ++ "Initial version."; ++ } ++ ++ list my_extref_list { ++ key my_leaf_string; ++ leaf my_leaf_string { ++ type string; ++ } ++ leaf my_extref { ++ type leafref { ++ path "/leafref-search:my_list/leafref-search:my_leaf_string"; ++ } ++ } ++ leaf my_extref_union { ++ type union { ++ type leafref { ++ path "/leafref-search:my_list/leafref-search:my_leaf_string"; ++ } ++ type leafref { ++ path "/leafref-search:my_list/leafref-search:my_leaf_number"; ++ } ++ type types:number; ++ } ++ } ++ } ++} +diff --git a/tests/yang/yolo/yolo-leafref-search.yang b/tests/yang/yolo/yolo-leafref-search.yang +new file mode 100644 +index 0000000..5f4af48 +--- /dev/null ++++ b/tests/yang/yolo/yolo-leafref-search.yang +@@ -0,0 +1,36 @@ ++module yolo-leafref-search { ++ yang-version 1.1; ++ namespace "urn:yang:yolo:leafref-search"; ++ prefix leafref-search; ++ ++ import wtf-types { prefix types; } ++ ++ revision 2025-02-11 { ++ description ++ "Initial version."; ++ } ++ ++ list my_list { ++ key my_leaf_string; ++ leaf my_leaf_string { ++ type string; ++ } ++ leaf my_leaf_number { ++ description ++ "A number."; ++ type types:number; ++ } ++ } ++ ++ leaf refstr { ++ type leafref { ++ path "../my_list/my_leaf_string"; ++ } ++ } ++ ++ leaf refnum { ++ type leafref { ++ path "../my_list/my_leaf_number"; ++ } ++ } ++} diff --git a/src/libyang3-py3/patch/series b/src/libyang3-py3/patch/series new file mode 100644 index 000000000000..933279b013b7 --- /dev/null +++ b/src/libyang3-py3/patch/series @@ -0,0 +1,4 @@ +0001-debian.patch +0002-pr134-json-string-datatypes.patch +0003-parse_module-memleak.patch +0004-pr132-backlinks.patch diff --git a/src/libyang1/.gitignore b/src/libyang3/.gitignore similarity index 58% rename from src/libyang1/.gitignore rename to src/libyang3/.gitignore index a0991ff4402b..644cdde57ba8 100644 --- a/src/libyang1/.gitignore +++ b/src/libyang3/.gitignore @@ -1,3 +1,5 @@ * !.gitignore !Makefile +!patch +!patch/** diff --git a/src/libyang3/Makefile b/src/libyang3/Makefile new file mode 100644 index 000000000000..a562daa5a6f5 --- /dev/null +++ b/src/libyang3/Makefile @@ -0,0 +1,36 @@ +.ONESHELL: +SHELL = /bin/bash +.SHELLFLAGS += -e + +LIBYANG_URL = http://debian-archive.trafficmanager.net/debian/pool/main/liby/libyang + +MAIN_TARGET = $(LIBYANG3) +DERIVED_TARGETS = $(LIBYANG3_DEV) $(LIBYANG3_DBG) $(LIBYANG3_TOOLS) $(LIBYANG3_TOOLS_DBG) + +$(addprefix $(DEST)/, $(MAIN_TARGET)): $(DEST)/% : + # Obtaining the libyang + rm -fr ./libyang-$(LIBYANG3_VERSION) + + # download debian libyang + dget -u $(LIBYANG_URL)/libyang_$(LIBYANG3_FULLVERSION).dsc + + pushd libyang-$(LIBYANG3_VERSION) + # The package libyang3.7.8 is taken from debian trixie + + # Enable large file support for 32-bit arch + echo 'add_definitions(-D_FILE_OFFSET_BITS=64)' >> CMakeLists.txt + [ -d ".pc" ] && rm -rf .pc + QUILT_PATCHES=../patch quilt push -a + +ifeq ($(CROSS_BUILD_ENVIRON), y) + dpkg-buildpackage -rfakeroot -d -b -us -uc -a$(CONFIGURED_ARCH) -Pcross,nocheck -j$(SONIC_CONFIG_MAKE_JOBS) +else + dpkg-buildpackage -rfakeroot -b -us -uc -j$(SONIC_CONFIG_MAKE_JOBS) --admindir $(SONIC_DPKG_ADMINDIR) +endif + + popd + + # Move the newly-built .deb packages to the destination directory + mv $* $(DERIVED_TARGETS) $(DEST)/ + +$(addprefix $(DEST)/, $(DERIVED_TARGETS)): $(DEST)/% : $(DEST)/$(MAIN_TARGET) diff --git a/src/libyang3/patch/0001-pr2344-json-strings.patch b/src/libyang3/patch/0001-pr2344-json-strings.patch new file mode 100644 index 000000000000..1f46c0b2025e --- /dev/null +++ b/src/libyang3/patch/0001-pr2344-json-strings.patch @@ -0,0 +1,220 @@ +From 9ba71bf71bf77d4c660dabd1b05b5e5cda77cecf Mon Sep 17 00:00:00 2001 +From: Brad House +Date: Fri, 14 Feb 2025 08:54:10 -0500 +Subject: [PATCH] data: option to allow json int/bool as strings + +Prior to v1.0.212 the default behavior was to allow numbers +and boolean values to be in quotes, which is technically a +violation of the spec. + +This adds a new `LYD_PARSE_JSON_STRING_DATATYPES` parse option +which will restore the prior behavior when enabled. + +SONiC is using v1.0.73 currently and has a large installed base which +may be in violation of the new behavior, so adding such a flag is +required for this usecase. + +Signed-off-by: Brad House +--- + src/parser_data.h | 5 ++++- + src/parser_json.c | 26 ++++++++++++++++---------- + src/plugins_types.c | 9 ++++++--- + src/tree_data.h | 1 + + tests/utests/data/test_parser_json.c | 15 +++++++++++++++ + 5 files changed, 42 insertions(+), 14 deletions(-) + +diff --git a/src/parser_data.h b/src/parser_data.h +index d7fbe1815..c6371ea4a 100644 +--- a/src/parser_data.h ++++ b/src/parser_data.h +@@ -179,7 +179,10 @@ struct ly_in; + #define LYD_PARSE_JSON_NULL 0x4000000 /**< Allow using JSON empty value 'null' within JSON input, such nodes are + silently skipped and treated as non-existent. By default, such values + are invalid. */ +- ++#define LYD_PARSE_JSON_STRING_DATATYPES 0x8000000 /*!**< By default, JSON data values are validated to be in the proper format. ++ For instance numbers are expected to not be enclosed in quotes, nor ++ are boolean values. Setting this option will disable this ++ validation. Prior to v1.0.212 this was the default behavior. */ + #define LYD_PARSE_OPTS_MASK 0xFFFF0000 /**< Mask for all the LYD_PARSE_ options. */ + + /** @} dataparseroptions */ +diff --git a/src/parser_json.c b/src/parser_json.c +index 5c3171231..83830c0d8 100644 +--- a/src/parser_json.c ++++ b/src/parser_json.c +@@ -340,7 +340,7 @@ lydjson_get_snode(struct lyd_json_ctx *lydctx, ly_bool is_attr, const char *pref + /** + * @brief Get the hint for the data type parsers according to the current JSON parser context. + * +- * @param[in] jsonctx JSON parser context. The context is supposed to be on a value. ++ * @param[in] lydctx JSON data parser context. + * @param[in,out] status Pointer to the current context status, + * in some circumstances the function manipulates with the context so the status is updated. + * @param[out] type_hint_p Pointer to the variable to store the result. +@@ -348,8 +348,9 @@ lydjson_get_snode(struct lyd_json_ctx *lydctx, ly_bool is_attr, const char *pref + * @return LY_EINVAL in case of invalid context status not referring to a value. + */ + static LY_ERR +-lydjson_value_type_hint(struct lyjson_ctx *jsonctx, enum LYJSON_PARSER_STATUS *status_p, uint32_t *type_hint_p) ++lydjson_value_type_hint(struct lyd_json_ctx *lydctx, enum LYJSON_PARSER_STATUS *status_p, uint32_t *type_hint_p) + { ++ struct lyjson_ctx *jsonctx = lydctx->jsonctx; + *type_hint_p = 0; + + if (*status_p == LYJSON_ARRAY) { +@@ -383,6 +384,10 @@ lydjson_value_type_hint(struct lyjson_ctx *jsonctx, enum LYJSON_PARSER_STATUS *s + return LY_EINVAL; + } + ++ if (lydctx->parse_opts & LYD_PARSE_JSON_STRING_DATATYPES) { ++ *type_hint_p |= LYD_VALHINT_STRING_DATATYPES; ++ } ++ + return LY_SUCCESS; + } + +@@ -391,15 +396,16 @@ lydjson_value_type_hint(struct lyjson_ctx *jsonctx, enum LYJSON_PARSER_STATUS *s + * + * Checks for all the list's keys. Function does not revert the context state. + * +- * @param[in] jsonctx JSON parser context. ++ * @param[in] lydctx JSON data parser context. + * @param[in] list List schema node corresponding to the input data object. + * @return LY_SUCCESS in case the data are ok for the @p list + * @return LY_ENOT in case the input data are not sufficient to fully parse the list instance. + */ + static LY_ERR +-lydjson_check_list(struct lyjson_ctx *jsonctx, const struct lysc_node *list) ++lydjson_check_list(struct lyd_json_ctx *lydctx, const struct lysc_node *list) + { + LY_ERR rc = LY_SUCCESS; ++ struct lyjson_ctx *jsonctx = lydctx->jsonctx; + enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(jsonctx); + struct ly_set key_set = {0}; + const struct lysc_node *snode; +@@ -451,7 +457,7 @@ lydjson_check_list(struct lyjson_ctx *jsonctx, const struct lysc_node *list) + goto cleanup; + } + +- rc = lydjson_value_type_hint(jsonctx, &status, &hints); ++ rc = lydjson_value_type_hint(lydctx, &status, &hints); + LY_CHECK_GOTO(rc, cleanup); + rc = ly_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, LY_VALUE_JSON, NULL, hints); + LY_CHECK_GOTO(rc, cleanup); +@@ -521,7 +527,7 @@ lydjson_data_check_opaq(struct lyd_json_ctx *lydctx, const struct lysc_node *sno + case LYS_LEAFLIST: + case LYS_LEAF: + /* value may not be valid in which case we parse it as an opaque node */ +- if ((ret = lydjson_value_type_hint(jsonctx, &status, type_hint_p))) { ++ if ((ret = lydjson_value_type_hint(lydctx, &status, type_hint_p))) { + break; + } + +@@ -533,14 +539,14 @@ lydjson_data_check_opaq(struct lyd_json_ctx *lydctx, const struct lysc_node *sno + break; + case LYS_LIST: + /* lists may not have all its keys */ +- if (lydjson_check_list(jsonctx, snode)) { ++ if (lydjson_check_list(lydctx, snode)) { + /* invalid list, parse as opaque if it misses/has invalid some keys */ + ret = LY_ENOT; + } + break; + } + } else if (snode->nodetype & LYD_NODE_TERM) { +- ret = lydjson_value_type_hint(jsonctx, &status, type_hint_p); ++ ret = lydjson_value_type_hint(lydctx, &status, type_hint_p); + } + + /* restore parser */ +@@ -852,7 +858,7 @@ lydjson_metadata(struct lyd_json_ctx *lydctx, const struct lysc_node *snode, str + LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup); + + /* get value hints */ +- LY_CHECK_GOTO(rc = lydjson_value_type_hint(lydctx->jsonctx, &status, &val_hints), cleanup); ++ LY_CHECK_GOTO(rc = lydjson_value_type_hint(lydctx, &status, &val_hints), cleanup); + + if (node->schema) { + /* create metadata */ +@@ -981,7 +987,7 @@ lydjson_create_opaq(struct lyd_json_ctx *lydctx, const char *name, size_t name_l + dynamic = lydctx->jsonctx->dynamic; + lydctx->jsonctx->dynamic = 0; + +- LY_CHECK_RET(lydjson_value_type_hint(lydctx->jsonctx, status_inner_p, &type_hint)); ++ LY_CHECK_RET(lydjson_value_type_hint(lydctx, status_inner_p, &type_hint)); + } + + /* get the module name */ +diff --git a/src/plugins_types.c b/src/plugins_types.c +index d773a8a75..581ef278f 100644 +--- a/src/plugins_types.c ++++ b/src/plugins_types.c +@@ -685,7 +685,8 @@ lyplg_type_check_hints(uint32_t hints, const char *value, size_t value_len, LY_D + case LY_TYPE_INT32: + LY_CHECK_ARG_RET(NULL, base, LY_EINVAL); + +- if (!(hints & (LYD_VALHINT_DECNUM | LYD_VALHINT_OCTNUM | LYD_VALHINT_HEXNUM))) { ++ if (!(hints & (LYD_VALHINT_DECNUM | LYD_VALHINT_OCTNUM | LYD_VALHINT_HEXNUM)) && ++ !(hints & LYD_VALHINT_STRING_DATATYPES)) { + return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid non-number-encoded %s value \"%.*s\".", + lys_datatype2str(type), (int)value_len, value); + } +@@ -695,7 +696,8 @@ lyplg_type_check_hints(uint32_t hints, const char *value, size_t value_len, LY_D + case LY_TYPE_INT64: + LY_CHECK_ARG_RET(NULL, base, LY_EINVAL); + +- if (!(hints & LYD_VALHINT_NUM64)) { ++ if (!(hints & LYD_VALHINT_NUM64) && ++ !(hints & LYD_VALHINT_STRING_DATATYPES)) { + return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid non-num64-encoded %s value \"%.*s\".", + lys_datatype2str(type), (int)value_len, value); + } +@@ -714,7 +716,8 @@ lyplg_type_check_hints(uint32_t hints, const char *value, size_t value_len, LY_D + } + break; + case LY_TYPE_BOOL: +- if (!(hints & LYD_VALHINT_BOOLEAN)) { ++ if (!(hints & LYD_VALHINT_BOOLEAN) && ++ !(hints & LYD_VALHINT_STRING_DATATYPES)) { + return ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "Invalid non-boolean-encoded %s value \"%.*s\".", + lys_datatype2str(type), (int)value_len, value); + } +diff --git a/src/tree_data.h b/src/tree_data.h +index 18bc6791b..ed362a198 100644 +--- a/src/tree_data.h ++++ b/src/tree_data.h +@@ -944,6 +944,7 @@ struct lyd_node_any { + #define LYD_VALHINT_NUM64 0x0010 /**< value is allowed to be an int64 or uint64 */ + #define LYD_VALHINT_BOOLEAN 0x0020 /**< value is allowed to be a boolean */ + #define LYD_VALHINT_EMPTY 0x0040 /**< value is allowed to be empty */ ++#define LYD_VALHINT_STRING_DATATYPES 0x0080 /**< boolean and numeric fields are allowed to be quoted */ + /** + * @} lydvalhints + */ +diff --git a/tests/utests/data/test_parser_json.c b/tests/utests/data/test_parser_json.c +index 1eff7819a..f752164c6 100644 +--- a/tests/utests/data/test_parser_json.c ++++ b/tests/utests/data/test_parser_json.c +@@ -168,6 +168,21 @@ test_leaf(void **state) + PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID, "Invalid non-string-encoded string value \"\".", "/a:foo", 1); + CHECK_PARSE_LYD(data, LYD_PARSE_JSON_NULL, LYD_VALIDATE_PRESENT, tree); + assert_null(tree); ++ ++ /* validate integer in quotes errors out by default */ ++ data = "{\"a:foo3\":\"1234\"}"; ++ PARSER_CHECK_ERROR(data, LYD_PARSE_STRICT, LYD_VALIDATE_PRESENT, tree, LY_EVALID, ++ "Invalid non-number-encoded uint32 value \"1234\".", "/a:foo3", 1); ++ ++ /* validate integers are parsed correctly */ ++ data = "{\"a:foo3\":1234}"; ++ CHECK_PARSE_LYD(data, 0, LYD_VALIDATE_PRESENT, tree); ++ lyd_free_all(tree); ++ ++ /* validate LYD_PARSE_JSON_STRING_DATATYPES parser flag allows integers in quotes */ ++ data = "{\"a:foo3\":\"1234\"}"; ++ CHECK_PARSE_LYD(data, LYD_PARSE_JSON_STRING_DATATYPES, LYD_VALIDATE_PRESENT, tree); ++ lyd_free_all(tree); + } + + static void diff --git a/src/libyang3/patch/0002-pr2352-backlinks.patch b/src/libyang3/patch/0002-pr2352-backlinks.patch new file mode 100644 index 000000000000..6eaab23afbe0 --- /dev/null +++ b/src/libyang3/patch/0002-pr2352-backlinks.patch @@ -0,0 +1,554 @@ +From b6ea2d3a0fd74ce9c7323e07aef957c65597ecd0 Mon Sep 17 00:00:00 2001 +From: Michal Vasko +Date: Mon, 17 Feb 2025 15:16:30 +0100 +Subject: [PATCH 1/3] tree schema UPDATE function for getting all leafref + targets + +Co-authored-by: Brad House +--- + src/tree_schema.h | 14 +++++++- + src/tree_schema_common.c | 76 +++++++++++++++++++++++++++++++++++----- + 2 files changed, 80 insertions(+), 10 deletions(-) + +diff --git a/src/tree_schema.h b/src/tree_schema.h +index 0181bc6f9..c5a464262 100644 +--- a/src/tree_schema.h ++++ b/src/tree_schema.h +@@ -1908,13 +1908,25 @@ LIBYANG_API_DECL struct lysc_must *lysc_node_musts(const struct lysc_node *node) + LIBYANG_API_DECL struct lysc_when **lysc_node_when(const struct lysc_node *node); + + /** +- * @brief Get the target node of a leafref node. ++ * @brief Get the target node of a leafref node. Function ::lysc_node_lref_targets() should be used instead ++ * to get all the leafref targets even for a union node. + * + * @param[in] node Leafref node. + * @return Leafref target, NULL on any error. + */ + LIBYANG_API_DECL const struct lysc_node *lysc_node_lref_target(const struct lysc_node *node); + ++/** ++ * @brief Get the target node(s) of a leafref node or union node with leafrefs. ++ * ++ * @param[in] node Term node to use. ++ * @param[out] set Set with all the leafref targets, may be empty if the node is a different type or the targets ++ * are not found. ++ * @return LY_SUCCESS on success. ++ * @return LY_ERR value on error. ++ */ ++LIBYANG_API_DECL LY_ERR lysc_node_lref_targets(const struct lysc_node *node, struct ly_set **set); ++ + /** + * @brief Callback to be called for every schema node in a DFS traversal. + * +diff --git a/src/tree_schema_common.c b/src/tree_schema_common.c +index e6af579b6..df5e88160 100644 +--- a/src/tree_schema_common.c ++++ b/src/tree_schema_common.c +@@ -1804,21 +1804,24 @@ lysc_node_when(const struct lysc_node *node) + } + } + +-LIBYANG_API_DEF const struct lysc_node * +-lysc_node_lref_target(const struct lysc_node *node) ++/** ++ * @brief Get the target node of a leafref. ++ * ++ * @param[in] node Context node for the leafref. ++ * @param[in] type Leafref type to resolve. ++ * @return Target schema node; ++ * @return NULL if the tearget is not found. ++ */ ++static const struct lysc_node * ++lysc_type_lref_target(const struct lysc_node *node, const struct lysc_type *type) + { + struct lysc_type_leafref *lref; + struct ly_path *p; + const struct lysc_node *target; + +- if (!node || !(node->nodetype & LYD_NODE_TERM)) { +- return NULL; +- } ++ assert(type->basetype == LY_TYPE_LEAFREF); + +- lref = (struct lysc_type_leafref *)((struct lysc_node_leaf *)node)->type; +- if (lref->basetype != LY_TYPE_LEAFREF) { +- return NULL; +- } ++ lref = (struct lysc_type_leafref *)type; + + /* compile the path */ + if (ly_path_compile_leafref(node->module->ctx, node, NULL, lref->path, +@@ -1834,6 +1837,61 @@ lysc_node_lref_target(const struct lysc_node *node) + return target; + } + ++LIBYANG_API_DEF const struct lysc_node * ++lysc_node_lref_target(const struct lysc_node *node) ++{ ++ if (!node || !(node->nodetype & LYD_NODE_TERM) || (((struct lysc_node_leaf *)node)->type->basetype != LY_TYPE_LEAFREF)) { ++ return NULL; ++ } ++ ++ return lysc_type_lref_target(node, ((struct lysc_node_leaf *)node)->type); ++} ++ ++LIBYANG_API_DEF LY_ERR ++lysc_node_lref_targets(const struct lysc_node *node, struct ly_set **set) ++{ ++ LY_ERR rc = LY_SUCCESS; ++ struct lysc_type *type; ++ struct lysc_type_union *type_un; ++ const struct lysc_node *target; ++ LY_ARRAY_COUNT_TYPE u; ++ ++ LY_CHECK_ARG_RET(NULL, node, (node->nodetype & LYD_NODE_TERM), LY_EINVAL); ++ ++ /* allocate return set */ ++ LY_CHECK_RET(ly_set_new(set)); ++ ++ type = ((struct lysc_node_leaf *)node)->type; ++ if (type->basetype == LY_TYPE_UNION) { ++ /* union with possible leafrefs */ ++ type_un = (struct lysc_type_union *)type; ++ ++ LY_ARRAY_FOR(type_un->types, u) { ++ if (type_un->types[u]->basetype != LY_TYPE_LEAFREF) { ++ continue; ++ } ++ ++ target = lysc_type_lref_target(node, type_un->types[u]); ++ if (target) { ++ LY_CHECK_GOTO(rc = ly_set_add(*set, target, 1, NULL), cleanup); ++ } ++ } ++ } else if (type->basetype == LY_TYPE_LEAFREF) { ++ /* leafref */ ++ target = lysc_type_lref_target(node, type); ++ if (target) { ++ LY_CHECK_GOTO(rc = ly_set_add(*set, target, 1, NULL), cleanup); ++ } ++ } ++ ++cleanup: ++ if (rc) { ++ ly_set_free(*set, NULL); ++ *set = NULL; ++ } ++ return rc; ++} ++ + enum ly_stmt + lysp_match_kw(struct ly_in *in, uint64_t *indent) + { + +From b7e024d82f63c9d8e278237ca6c65bb21a6bad45 Mon Sep 17 00:00:00 2001 +From: Michal Vasko +Date: Mon, 17 Feb 2025 15:46:59 +0100 +Subject: [PATCH 2/3] tree schema UPDATE function for getting leafref backlinks + +Meaning all leafrefs that target a specific node. + +Co-authored-by: Brad House +--- + src/tree_schema.h | 16 +++++- + src/tree_schema_common.c | 103 +++++++++++++++++++++++++++++++++++++++ + 2 files changed, 118 insertions(+), 1 deletion(-) + +diff --git a/src/tree_schema.h b/src/tree_schema.h +index c5a464262..baeb261c0 100644 +--- a/src/tree_schema.h ++++ b/src/tree_schema.h +@@ -4,7 +4,7 @@ + * @author Michal Vasko + * @brief libyang representation of YANG schema trees. + * +- * Copyright (c) 2015 - 2022 CESNET, z.s.p.o. ++ * Copyright (c) 2015 - 2025 CESNET, z.s.p.o. + * + * This source code is licensed under BSD 3-Clause License (the "License"). + * You may not use this file except in compliance with the License. +@@ -1927,6 +1927,20 @@ LIBYANG_API_DECL const struct lysc_node *lysc_node_lref_target(const struct lysc + */ + LIBYANG_API_DECL LY_ERR lysc_node_lref_targets(const struct lysc_node *node, struct ly_set **set); + ++/** ++ * @brief Get all the leafref (or union with leafrefs) nodes that target a specific node. ++ * ++ * @param[in] ctx Context to use, may not be set if @p node is. ++ * @param[in] node Leafref target node to use for matching. If not set, all the leafref nodes are just collected. ++ * @param[in] match_ancestors If set, @p node is considered a match not only when a leafref targets it directly but ++ * even when an ancestor (parent) node of @p node is a target of the leafref. ++ * @param[out] set Set of matching leafref nodes. ++ * @return LY_SUCCESS on success. ++ * @return LY_ERR value on error. ++ */ ++LIBYANG_API_DECL LY_ERR lysc_node_lref_backlinks(const struct ly_ctx *ctx, const struct lysc_node *node, ++ ly_bool match_ancestors, struct ly_set **set); ++ + /** + * @brief Callback to be called for every schema node in a DFS traversal. + * +diff --git a/src/tree_schema_common.c b/src/tree_schema_common.c +index df5e88160..d62b01db8 100644 +--- a/src/tree_schema_common.c ++++ b/src/tree_schema_common.c +@@ -1892,6 +1892,109 @@ lysc_node_lref_targets(const struct lysc_node *node, struct ly_set **set) + return rc; + } + ++struct lysc_node_lref_backlings_arg { ++ const struct lysc_node *node; ++ ly_bool match_ancestors; ++ struct ly_set *set; ++}; ++ ++static LY_ERR ++lysc_node_lref_backlinks_clb(struct lysc_node *node, void *data, ly_bool *dfs_continue) ++{ ++ LY_ERR rc = LY_SUCCESS; ++ struct lysc_node_lref_backlings_arg *arg = data; ++ struct ly_set *set = NULL; ++ const struct lysc_node *par; ++ uint32_t i; ++ ++ (void)dfs_continue; ++ ++ if (!(node->nodetype & LYD_NODE_TERM)) { ++ /* skip */ ++ goto cleanup; ++ } ++ ++ /* get all the leafref targets */ ++ LY_CHECK_GOTO(rc = lysc_node_lref_targets(node, &set), cleanup); ++ ++ /* ignore node if has no leafref targets */ ++ if (!set->count) { ++ goto cleanup; ++ } ++ ++ /* if just collecting leafrefs, we are done */ ++ if (!arg->node) { ++ rc = ly_set_add(arg->set, node, 1, NULL); ++ goto cleanup; ++ } ++ ++ /* check that the node (or the ancestor of) is the target of this leafref */ ++ for (i = 0; i < set->count; ++i) { ++ for (par = set->snodes[i]; par; par = par->parent) { ++ if (par == arg->node) { ++ /* match */ ++ break; ++ } ++ ++ if (!arg->match_ancestors) { ++ /* not a match */ ++ par = NULL; ++ break; ++ } ++ } ++ ++ if (par) { ++ /* add into the set, matches */ ++ LY_CHECK_GOTO(rc = ly_set_add(arg->set, node, 1, NULL), cleanup); ++ break; ++ } ++ } ++ ++cleanup: ++ ly_set_free(set, NULL); ++ return rc; ++} ++ ++LIBYANG_API_DEF LY_ERR ++lysc_node_lref_backlinks(const struct ly_ctx *ctx, const struct lysc_node *node, ly_bool match_ancestors, ++ struct ly_set **set) ++{ ++ LY_ERR rc = LY_SUCCESS; ++ struct lysc_node_lref_backlings_arg arg = {0}; ++ uint32_t idx = 0; ++ const struct lys_module *mod; ++ ++ LY_CHECK_ARG_RET(NULL, ctx || node, set, LY_EINVAL); ++ ++ if (!ctx) { ++ ctx = node->module->ctx; ++ } ++ ++ /* allocate return set */ ++ LY_CHECK_RET(ly_set_new(set)); ++ ++ /* prepare the arg */ ++ arg.node = node; ++ arg.match_ancestors = match_ancestors; ++ arg.set = *set; ++ ++ /* iterate across all loaded modules */ ++ while ((mod = ly_ctx_get_module_iter(ctx, &idx))) { ++ if (!mod->compiled) { ++ continue; ++ } ++ ++ LY_CHECK_GOTO(rc = lysc_module_dfs_full(mod, lysc_node_lref_backlinks_clb, &arg), cleanup); ++ } ++ ++cleanup: ++ if (rc) { ++ ly_set_free(*set, NULL); ++ *set = NULL; ++ } ++ return rc; ++} ++ + enum ly_stmt + lysp_match_kw(struct ly_in *in, uint64_t *indent) + { + +From 2f373f8677023e66c163617da4f11e78b61fa86d Mon Sep 17 00:00:00 2001 +From: Michal Vasko +Date: Mon, 17 Feb 2025 16:02:54 +0100 +Subject: [PATCH 3/3] tests UPDATE new leafref backlinks test + +Co-authored-by: Brad House +--- + tests/utests/schema/test_schema.c | 220 ++++++++++++++++++++++++++++++ + 1 file changed, 220 insertions(+) + +diff --git a/tests/utests/schema/test_schema.c b/tests/utests/schema/test_schema.c +index cba2b2d45..45189e4b4 100644 +--- a/tests/utests/schema/test_schema.c ++++ b/tests/utests/schema/test_schema.c +@@ -1887,6 +1887,225 @@ test_lysc_path(void **state) + free(path); + } + ++/* TEST */ ++static ly_bool ++compare_str_nodeset(struct ly_set *expected, struct ly_set *received) ++{ ++ ly_bool is_error = 0; ++ size_t r; ++ size_t e; ++ ++ for (e = 0; expected && e < expected->count; e++) { ++ const char *epath = expected->objs[e]; ++ ly_bool found = 0; ++ ++ for (r = 0; received && (r < received->count); r++) { ++ const char *rpath = received->objs[r]; ++ ++ if (!strcmp(epath, rpath)) { ++ found = 1; ++ break; ++ } ++ } ++ ++ if (!found) { ++ fprintf(stderr, "< %s\n", epath); ++ is_error = 1; ++ } ++ } ++ ++ /* If the count was equal and there was no error, no need to scan again */ ++ if (expected && received && (expected->count == received->count) && !is_error) { ++ return 1; ++ } ++ ++ for (r = 0; received && (r < received->count); r++) { ++ ly_bool found = 0; ++ const char *rpath = received->objs[r]; ++ ++ for (e = 0; expected && (e < expected->count) && !found; e++) { ++ char *epath = expected->objs[e]; ++ ++ if (!strcmp(epath, rpath)) { ++ found = 1; ++ break; ++ } ++ } ++ if (!found) { ++ fprintf(stderr, "> %s\n", rpath); ++ } ++ } ++ ++ return 0; ++} ++ ++static struct ly_set * ++strlist_to_pathset(const char **pathlist) ++{ ++ struct ly_set *set = NULL; ++ uint32_t i; ++ ++ if (!pathlist || !pathlist[0]) { ++ return NULL; ++ } ++ ++ ly_set_new(&set); ++ ++ for (i = 0; pathlist[i]; i++) { ++ ly_set_add(set, pathlist[i], 0, NULL); ++ } ++ ++ return set; ++} ++ ++static struct ly_set * ++lysc_nodeset_to_pathset(struct ly_set *nodeset) ++{ ++ struct ly_set *set = NULL; ++ uint32_t i; ++ ++ if (!nodeset || !nodeset->count) { ++ return NULL; ++ } ++ ++ ly_set_new(&set); ++ ++ for (i = 0; i < nodeset->count; i++) { ++ char *path = lysc_path(nodeset->snodes[i], LYSC_PATH_DATA, NULL, 0); ++ ++ ly_set_add(set, path, 0, NULL); ++ } ++ ++ return set; ++} ++ ++static void ++test_lysc_backlinks(void **state) ++{ ++ const char *expect1[] = { ++ /* Built-ins, not sure how to exclude those when not limiting by ++ * path */ ++ "/ietf-yang-library:yang-library/module-set/module/deviation", ++ "/ietf-yang-library:yang-library/schema/module-set", ++ "/ietf-yang-library:yang-library/datastore/schema", ++ "/ietf-yang-library:yang-library-update/content-id", ++ "/ietf-yang-library:yang-library-change/module-set-id", ++ /* Normal expected */ ++ "/b:my_extref_list/my_extref", ++ "/a:refstr", ++ "/a:refnum", ++ "/b:my_extref_union", ++ NULL ++ }; ++ ++ const char *expect2[] = { ++ "/b:my_extref_list/my_extref", ++ "/a:refstr", ++ "/b:my_extref_union", ++ NULL ++ }; ++ ++ const char *expect3[] = { ++ "/b:my_extref_list/my_extref", ++ "/a:refstr", ++ "/a:refnum", ++ "/b:my_extref_union", ++ NULL ++ }; ++ ++ struct { ++ const char *match_path; ++ ly_bool match_ancestors; ++ const char **expected_paths; ++ } tests[] = { ++ {NULL, 0, expect1}, ++ {"/a:my_list/my_leaf_string", 0, expect2}, ++ {"/a:my_list", 1, expect3} ++ }; ++ const char *str; ++ uint32_t i; ++ ++ str = "module a {\n" ++ " namespace urn:a;\n" ++ " prefix a;\n" ++ " list my_list {\n" ++ " key my_leaf_string;\n" ++ " leaf my_leaf_string {\n" ++ " type string;\n" ++ " }\n" ++ " leaf my_leaf_number {\n" ++ " type uint32;\n" ++ " }\n" ++ " }\n" ++ " leaf refstr {\n" ++ " type leafref {\n" ++ " path \"../my_list/my_leaf_string\";\n" ++ " }\n" ++ " }\n" ++ " leaf refnum {\n" ++ " type leafref {\n" ++ " path \"../my_list/my_leaf_number\";\n" ++ " }\n" ++ " }\n" ++ "}\n"; ++ ++ assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_SUCCESS); ++ CHECK_LOG_CTX(NULL, NULL, 0); ++ ++ str = "module b {\n" ++ " namespace urn:b;\n" ++ " prefix b;\n" ++ " import a {\n" ++ " prefix a;\n" ++ " }\n" ++ " list my_extref_list {\n" ++ " key my_leaf_string;\n" ++ " leaf my_leaf_string {\n" ++ " type string;\n" ++ " }\n" ++ " leaf my_extref {\n" ++ " type leafref {\n" ++ " path \"/a:my_list/a:my_leaf_string\";\n" ++ " }\n" ++ " }\n" ++ " }\n" ++ " leaf my_extref_union {\n" ++ " type union {\n" ++ " type leafref {\n" ++ " path \"/a:my_list/a:my_leaf_string\";\n" ++ " }\n" ++ " type leafref {\n" ++ " path \"/a:my_list/a:my_leaf_number\";\n" ++ " }\n" ++ " type uint32;\n" ++ " }\n" ++ " }\n" ++ "}\n"; ++ ++ assert_int_equal(lys_parse_mem(UTEST_LYCTX, str, LYS_IN_YANG, NULL), LY_SUCCESS); ++ CHECK_LOG_CTX(NULL, NULL, 0); ++ ++ for (i = 0; i < sizeof tests / sizeof *tests; i++) { ++ const struct lysc_node *node = NULL; ++ struct ly_set *set = NULL, *expected = NULL, *received = NULL; ++ ++ if (tests[i].match_path) { ++ node = lys_find_path(UTEST_LYCTX, NULL, tests[i].match_path, 0); ++ assert_non_null(node); ++ } ++ ++ assert_int_equal(LY_SUCCESS, lysc_node_lref_backlinks(UTEST_LYCTX, node, tests[i].match_ancestors, &set)); ++ ++ expected = strlist_to_pathset(tests[i].expected_paths); ++ received = lysc_nodeset_to_pathset(set); ++ assert_int_equal(1, compare_str_nodeset(expected, received)); ++ ++ ly_set_free(expected, NULL); ++ ly_set_free(received, free); ++ ly_set_free(set, NULL); ++ } ++} ++ + int + main(void) + { +@@ -1909,6 +2128,7 @@ main(void) + UTEST(test_extension_compile), + UTEST(test_ext_recursive), + UTEST(test_lysc_path), ++ UTEST(test_lysc_backlinks), + }; + + return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/src/libyang3/patch/0003-minmax-errpath-3adb304.patch b/src/libyang3/patch/0003-minmax-errpath-3adb304.patch new file mode 100644 index 000000000000..cb516fb9b862 --- /dev/null +++ b/src/libyang3/patch/0003-minmax-errpath-3adb304.patch @@ -0,0 +1,158 @@ +From 3adb3044f9a3e67f88d8bf3286b6ada8bccb09e8 Mon Sep 17 00:00:00 2001 +From: Michal Vasko +Date: Mon, 24 Feb 2025 10:15:19 +0100 +Subject: [PATCH] validation UPDATE improve list min/max log path + +Fixes #2353 +--- + src/validation.c | 66 ++++++++++++++++++++--------- + tests/utests/data/test_validation.c | 6 +-- + tests/utests/node/list.c | 4 +- + 3 files changed, 50 insertions(+), 26 deletions(-) + +diff --git a/src/validation.c b/src/validation.c +index bea1047d5..a21d8f034 100644 +--- a/src/validation.c ++++ b/src/validation.c +@@ -1140,13 +1140,17 @@ static LY_ERR + lyd_validate_minmax(const struct lyd_node *first, const struct lyd_node *parent, const struct lysc_node *snode, + uint32_t min, uint32_t max, uint32_t val_opts) + { ++ LY_ERR rc = LY_SUCCESS; + uint32_t count = 0; +- struct lyd_node *iter; ++ struct lyd_node *iter, *last_iter = NULL; + const struct lysc_when *disabled; ++ char *log_path; ++ int r; + + assert(min || max); + + LYD_LIST_FOR_INST(first, snode, iter) { ++ last_iter = iter; + ++count; + + if (min && (count == min)) { +@@ -1182,32 +1186,52 @@ lyd_validate_minmax(const struct lyd_node *first, const struct lyd_node *parent, + max = 0; + } + +- if (min) { +- if (val_opts & LYD_VALIDATE_OPERATIONAL) { +- /* only a warning */ +- LOG_LOCSET(snode, NULL); +- LOGWRN(snode->module->ctx, "Too few \"%s\" instances.", snode->name); +- LOG_LOCBACK(1, 0); ++ if (min || max) { ++ /* set log path */ ++ if (last_iter) { ++ /* standard data path */ ++ LOG_LOCSET(NULL, last_iter); + } else { +- LOG_LOCSET(snode, NULL); +- LOGVAL_APPTAG(snode->module->ctx, "too-few-elements", LY_VCODE_NOMIN, snode->name); +- LOG_LOCBACK(1, 0); +- return LY_EVALID; ++ /* data path with last schema node name or only the schema node if !parent */ ++ if (lyd_node_module(parent) != snode->module) { ++ r = asprintf(&log_path, "/%s:%s", snode->module->name, snode->name); ++ } else { ++ r = asprintf(&log_path, "/%s", snode->name); ++ } ++ if (r == -1) { ++ LOGMEM_RET(snode->module->ctx); ++ } ++ ly_log_location(NULL, parent, log_path, NULL); ++ free(log_path); + } +- } else if (max) { +- if (val_opts & LYD_VALIDATE_OPERATIONAL) { +- /* only a warning */ +- LOG_LOCSET(NULL, iter); +- LOGWRN(snode->module->ctx, "Too many \"%s\" instances.", snode->name); ++ ++ if (min) { ++ if (val_opts & LYD_VALIDATE_OPERATIONAL) { ++ /* only a warning */ ++ LOGWRN(snode->module->ctx, "Too few \"%s\" instances.", snode->name); ++ } else { ++ LOGVAL_APPTAG(snode->module->ctx, "too-few-elements", LY_VCODE_NOMIN, snode->name); ++ rc = LY_EVALID; ++ } ++ } else if (max) { ++ if (val_opts & LYD_VALIDATE_OPERATIONAL) { ++ /* only a warning */ ++ LOGWRN(snode->module->ctx, "Too many \"%s\" instances.", snode->name); ++ } else { ++ LOGVAL_APPTAG(snode->module->ctx, "too-many-elements", LY_VCODE_NOMAX, snode->name); ++ rc = LY_EVALID; ++ } ++ } ++ ++ /* revert log path */ ++ if (last_iter) { + LOG_LOCBACK(0, 1); + } else { +- LOG_LOCSET(NULL, iter); +- LOGVAL_APPTAG(snode->module->ctx, "too-many-elements", LY_VCODE_NOMAX, snode->name); +- LOG_LOCBACK(0, 1); +- return LY_EVALID; ++ ly_log_location_revert(0, parent ? 1 : 0, 1, 0); + } + } +- return LY_SUCCESS; ++ ++ return rc; + } + + /** +diff --git a/tests/utests/data/test_validation.c b/tests/utests/data/test_validation.c +index 4a505fe75..694501604 100644 +--- a/tests/utests/data/test_validation.c ++++ b/tests/utests/data/test_validation.c +@@ -277,12 +277,12 @@ test_minmax(void **state) + CHECK_PARSE_LYD_PARAM("mate" + "", + LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); +- CHECK_LOG_CTX_APPTAG("Too few \"l\" instances.", "/c:choic/b/l", 0, "too-few-elements"); ++ CHECK_LOG_CTX_APPTAG("Too few \"l\" instances.", "/c:l[.='mate']", 0, "too-few-elements"); + + CHECK_PARSE_LYD_PARAM("val1" + "val2", + LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); +- CHECK_LOG_CTX_APPTAG("Too few \"l\" instances.", "/c:choic/b/l", 0, "too-few-elements"); ++ CHECK_LOG_CTX_APPTAG("Too few \"l\" instances.", "/c:l[.='val2']", 0, "too-few-elements"); + + LYD_TREE_CREATE("val1" + "val2" +@@ -1259,7 +1259,7 @@ test_multi_error(void **state) + CHECK_PARSE_LYD_PARAM(data, LYD_JSON, LYD_PARSE_ONLY, 0, LY_SUCCESS, tree); + assert_int_equal(LY_EVALID, lyd_validate_all(&tree, NULL, LYD_VALIDATE_PRESENT | LYD_VALIDATE_MULTI_ERROR, NULL)); + lyd_free_tree(tree); +- CHECK_LOG_CTX_APPTAG("Too few \"ll\" instances.", "/ii:cont/ll", 0, "too-few-elements"); ++ CHECK_LOG_CTX_APPTAG("Too few \"ll\" instances.", "/ii:cont/ll[.='25']", 0, "too-few-elements"); + CHECK_LOG_CTX_APPTAG("l leaf is not left", "/ii:cont/l3", 0, "not-left"); + CHECK_LOG_CTX_APPTAG("Must condition \"../l = 'right'\" not satisfied.", "/ii:cont/l2", 0, "must-violation"); + CHECK_LOG_CTX_APPTAG("Duplicate instance of \"l\".", "/ii:cont/l", 0, NULL); +diff --git a/tests/utests/node/list.c b/tests/utests/node/list.c +index 4a69dbbd0..39d026b68 100644 +--- a/tests/utests/node/list.c ++++ b/tests/utests/node/list.c +@@ -1051,7 +1051,7 @@ test_xml(void **state) + ""; + CHECK_PARSE_LYD_PARAM(data, LYD_XML, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + assert_null(tree); +- CHECK_LOG_CTX("Too few \"user\" instances.", "/T2:user", 0); ++ CHECK_LOG_CTX("Too few \"user\" instances.", "/T2:user[uid='1']", 0); + + data = + "" +@@ -1347,7 +1347,7 @@ test_json(void **state) + "]}"; + CHECK_PARSE_LYD_PARAM(data, LYD_JSON, 0, LYD_VALIDATE_PRESENT, LY_EVALID, tree); + assert_null(tree); +- CHECK_LOG_CTX("Too few \"user\" instances.", "/T2:user", 0); ++ CHECK_LOG_CTX("Too few \"user\" instances.", "/T2:user[uid='4']", 0); + + data = + "{\"T2:user\": [" diff --git a/src/libyang3/patch/0004-union-apptag-529a594.patch b/src/libyang3/patch/0004-union-apptag-529a594.patch new file mode 100644 index 000000000000..101d10cc10c0 --- /dev/null +++ b/src/libyang3/patch/0004-union-apptag-529a594.patch @@ -0,0 +1,56 @@ +From 529a594aafd191bb879e13492014136d9be8ddca Mon Sep 17 00:00:00 2001 +From: Michal Vasko +Date: Tue, 25 Feb 2025 15:46:58 +0100 +Subject: [PATCH] union UPDATE use err-app-tag if suitable + +Refs #2356 + +Co-authored-by: Brad House +--- + src/plugins_types/union.c | 20 ++++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +diff --git a/src/plugins_types/union.c b/src/plugins_types/union.c +index 64281c61e..61dde35d9 100644 +--- a/src/plugins_types/union.c ++++ b/src/plugins_types/union.c +@@ -267,8 +267,9 @@ union_find_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct + LY_ARRAY_COUNT_TYPE u; + struct ly_err_item **errs = NULL, *e; + uint32_t *prev_lo, temp_lo = 0; +- char *msg = NULL; ++ char *msg = NULL, *err_app_tag = NULL; + int msg_len = 0; ++ ly_bool use_err_app_tag = 0; + + *err = NULL; + +@@ -306,12 +307,27 @@ union_find_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, struct + continue; + } + ++ /* use an app-tag if all the types set it or set none */ ++ if (errs[u]->apptag) { ++ if (!err_app_tag) { ++ err_app_tag = strdup(errs[u]->apptag); ++ LY_CHECK_ERR_GOTO(!err_app_tag, ret = LY_EMEM, cleanup); ++ use_err_app_tag = 1; ++ } else if (strcmp(errs[u]->apptag, err_app_tag)) { ++ use_err_app_tag = 0; ++ } ++ } ++ + msg = ly_realloc(msg, msg_len + 4 + strlen(type_u->types[u]->plugin->id) + 2 + strlen(errs[u]->msg) + 2); + LY_CHECK_ERR_GOTO(!msg, ret = LY_EMEM, cleanup); + msg_len += sprintf(msg + msg_len, " %s: %s\n", type_u->types[u]->plugin->id, errs[u]->msg); + } + +- ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, NULL, "%s", msg); ++ if (!use_err_app_tag) { ++ free(err_app_tag); ++ err_app_tag = NULL; ++ } ++ ret = ly_err_new(err, LY_EVALID, LYVE_DATA, NULL, err_app_tag, "%s", msg); + } else if (type_idx) { + *type_idx = u; + } diff --git a/src/libyang3/patch/0005-pr2360-validate-union-errors.patch b/src/libyang3/patch/0005-pr2360-validate-union-errors.patch new file mode 100644 index 000000000000..eee0ef204a50 --- /dev/null +++ b/src/libyang3/patch/0005-pr2360-validate-union-errors.patch @@ -0,0 +1,366 @@ +From 7e3672c4b9863d2ea82546751c25d44a066a5ec1 Mon Sep 17 00:00:00 2001 +From: Brad House +Date: Fri, 28 Feb 2025 10:20:07 -0500 +Subject: [PATCH 1/5] validate: unions with leafrefs may return misleading + error codes + +When a leafref is not found in a union, it should not return an error +indicating the value for the leafref wouldn't match the restrictions +for a target but instead just say the leafref target wasn't found. + +The only data that should indicate the error message for data type +restrictions is data associated with the target itself, not leafrefs. + +Signed-off-by: Brad House +--- + src/plugins_types/union.c | 33 +++++++++++++++++++++++++++++++++ + tests/utests/types/union.c | 7 ++++--- + 2 files changed, 37 insertions(+), 3 deletions(-) + +diff --git a/src/plugins_types/union.c b/src/plugins_types/union.c +index 61dde35d9..e1bb1a26d 100644 +--- a/src/plugins_types/union.c ++++ b/src/plugins_types/union.c +@@ -150,6 +150,31 @@ lyb_parse_union(const void *lyb_data, size_t lyb_data_len, uint32_t *type_idx, c + } + } + ++static void ++union_lref_error_rewrite(const struct lyd_node *ctx_node, struct ly_err_item *err, struct lysc_type *type, const void *value, size_t value_len) ++{ ++ struct lysc_type_leafref *lref; ++ char *valstr = NULL; ++ ++ if ((err == NULL) || (type->basetype != LY_TYPE_LEAFREF)) { ++ return; ++ } ++ ++ lref = (struct lysc_type_leafref *)type; ++ free(err->apptag); ++ err->apptag = strdup("instance-required"); ++ ++ free(err->msg); ++ ++ if (lyd_get_value(ctx_node) != NULL) { ++ valstr = strdup(lyd_get_value(ctx_node)); ++ } else { ++ valstr = strndup((const char *)value, value_len); ++ } ++ asprintf(&err->msg, LY_ERRMSG_NOLREF_VAL, valstr, lyxp_get_expr(lref->path)); ++ free(valstr); ++} ++ + /** + * @brief Store (and validate) subvalue as a specific type. + * +@@ -190,6 +215,9 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint3 + if ((rc != LY_SUCCESS) && (rc != LY_EINCOMPLETE)) { + /* clear any leftover/freed garbage */ + memset(&subvalue->value, 0, sizeof subvalue->value); ++ ++ /* if this is a leafref, lets make sure we propagate the appropriate error, and not a type validation failure */ ++ union_lref_error_rewrite(ctx_node, *err, type_u->types[ti], value, value_len); + return rc; + } + +@@ -228,6 +256,11 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint3 + if ((rc != LY_SUCCESS) && (rc != LY_EINCOMPLETE)) { + /* clear any leftover/freed garbage */ + memset(&subvalue->value, 0, sizeof subvalue->value); ++ ++ /* if this is a leafref, lets make sure we propagate the appropriate error, and not a type validation failure */ ++ if (type->basetype == LY_TYPE_LEAFREF) { ++ union_lref_error_rewrite(ctx_node, *err, type, value, value_len); ++ } + return rc; + } + +diff --git a/tests/utests/types/union.c b/tests/utests/types/union.c +index c2541aaaf..257776b11 100644 +--- a/tests/utests/types/union.c ++++ b/tests/utests/types/union.c +@@ -105,8 +105,8 @@ test_data_xml(void **state) + TEST_ERROR_XML2("", + "defs", "", "un1", "123456789012345678901", LY_EVALID); + CHECK_LOG_CTX("Invalid union value \"123456789012345678901\" - no matching subtype found:\n" +- " libyang 2 - leafref, version 1: Invalid type int8 value \"123456789012345678901\".\n" +- " libyang 2 - leafref, version 1: Invalid type int64 value \"123456789012345678901\".\n" ++ " libyang 2 - leafref, version 1: Invalid leafref value \"123456789012345678901\" - no target instance \"/int8\" with the same value.\n" ++ " libyang 2 - leafref, version 1: Invalid leafref value \"123456789012345678901\" - no target instance \"/int64\" with the same value.\n" + " libyang 2 - identityref, version 1: Invalid identityref \"123456789012345678901\" value - identity not found in module \"defs\".\n" + " libyang 2 - instance-identifier, version 1: Invalid instance-identifier \"123456789012345678901\" value - syntax error.\n" + " libyang 2 - string, version 1: Unsatisfied length - string \"123456789012345678901\" length is not allowed.\n", +@@ -295,7 +295,8 @@ test_validation(void **state) + assert_int_equal(LY_EVALID, lyd_validate_all(&tree, NULL, LYD_VALIDATE_PRESENT, NULL)); + CHECK_LOG_CTX("Invalid LYB union value - no matching subtype found:\n" + " libyang 2 - leafref, version 1: Invalid leafref value \"one\" - no target instance \"../../a/name\" with the same value.\n" +- " libyang 2 - leafref, version 1: Invalid type uint32 value \"one\".\n", "/lref:test/community[name='test']/view", 0); ++ " libyang 2 - leafref, version 1: Invalid leafref value \"one\" - no target instance \"../../b/name\" with the same value.\n", ++ "/lref:test/community[name='test']/view", 0); + + lyd_free_all(tree); + } + +From f21bdb7ae93b1076e642bfa22515cc6ddeb3b51a Mon Sep 17 00:00:00 2001 +From: Brad House +Date: Mon, 3 Mar 2025 05:48:58 -0500 +Subject: [PATCH 2/5] fixes as per @michalvasko + +--- + src/plugins_types/union.c | 21 ++++++++++++++------- + 1 file changed, 14 insertions(+), 7 deletions(-) + +diff --git a/src/plugins_types/union.c b/src/plugins_types/union.c +index e1bb1a26d..0adf5ab2b 100644 +--- a/src/plugins_types/union.c ++++ b/src/plugins_types/union.c +@@ -150,17 +150,26 @@ lyb_parse_union(const void *lyb_data, size_t lyb_data_len, uint32_t *type_idx, c + } + } + ++/** ++ * @brief For leafref failures, ensure the appropriate error is propagated, not a type validation failure. ++ * ++ * @param[in] ctx_node Context node for prefix resolution. ++ * @param[in,out] err Error record to be updated ++ * @param[in] type leafref type used to extract target path ++ * @param[in] value value attempting to be stored ++ * @param[in] value_len Length of value that was attempted to be stored. ++ */ + static void +-union_lref_error_rewrite(const struct lyd_node *ctx_node, struct ly_err_item *err, struct lysc_type *type, const void *value, size_t value_len) ++union_update_lref_err(const struct lyd_node *ctx_node, struct ly_err_item *err, const struct lysc_type *type, const void *value, size_t value_len) + { +- struct lysc_type_leafref *lref; ++ const struct lysc_type_leafref *lref; + char *valstr = NULL; + + if ((err == NULL) || (type->basetype != LY_TYPE_LEAFREF)) { + return; + } + +- lref = (struct lysc_type_leafref *)type; ++ lref = (const struct lysc_type_leafref *)type; + free(err->apptag); + err->apptag = strdup("instance-required"); + +@@ -217,7 +226,7 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint3 + memset(&subvalue->value, 0, sizeof subvalue->value); + + /* if this is a leafref, lets make sure we propagate the appropriate error, and not a type validation failure */ +- union_lref_error_rewrite(ctx_node, *err, type_u->types[ti], value, value_len); ++ union_update_lref_err(ctx_node, *err, type_u->types[ti], value, value_len); + return rc; + } + +@@ -258,9 +267,7 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint3 + memset(&subvalue->value, 0, sizeof subvalue->value); + + /* if this is a leafref, lets make sure we propagate the appropriate error, and not a type validation failure */ +- if (type->basetype == LY_TYPE_LEAFREF) { +- union_lref_error_rewrite(ctx_node, *err, type, value, value_len); +- } ++ union_update_lref_err(ctx_node, *err, type, value, value_len); + return rc; + } + + +From d2752709457bbff4dc12eb36dfd67a034e557a6d Mon Sep 17 00:00:00 2001 +From: Brad House +Date: Mon, 3 Mar 2025 06:51:55 -0500 +Subject: [PATCH 3/5] do not use lyd_value() + +--- + src/plugins_types/union.c | 25 ++++++++++--------------- + 1 file changed, 10 insertions(+), 15 deletions(-) + +diff --git a/src/plugins_types/union.c b/src/plugins_types/union.c +index 0adf5ab2b..0c126f6ae 100644 +--- a/src/plugins_types/union.c ++++ b/src/plugins_types/union.c +@@ -153,14 +153,13 @@ lyb_parse_union(const void *lyb_data, size_t lyb_data_len, uint32_t *type_idx, c + /** + * @brief For leafref failures, ensure the appropriate error is propagated, not a type validation failure. + * +- * @param[in] ctx_node Context node for prefix resolution. + * @param[in,out] err Error record to be updated + * @param[in] type leafref type used to extract target path + * @param[in] value value attempting to be stored + * @param[in] value_len Length of value that was attempted to be stored. + */ + static void +-union_update_lref_err(const struct lyd_node *ctx_node, struct ly_err_item *err, const struct lysc_type *type, const void *value, size_t value_len) ++union_update_lref_err(struct ly_err_item *err, const struct lysc_type *type, const void *value, size_t value_len) + { + const struct lysc_type_leafref *lref; + char *valstr = NULL; +@@ -174,12 +173,7 @@ union_update_lref_err(const struct lyd_node *ctx_node, struct ly_err_item *err, + err->apptag = strdup("instance-required"); + + free(err->msg); +- +- if (lyd_get_value(ctx_node) != NULL) { +- valstr = strdup(lyd_get_value(ctx_node)); +- } else { +- valstr = strndup((const char *)value, value_len); +- } ++ valstr = strndup((const char *)value, value_len); + asprintf(&err->msg, LY_ERRMSG_NOLREF_VAL, valstr, lyxp_get_expr(lref->path)); + free(valstr); + } +@@ -226,8 +220,8 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint3 + memset(&subvalue->value, 0, sizeof subvalue->value); + + /* if this is a leafref, lets make sure we propagate the appropriate error, and not a type validation failure */ +- union_update_lref_err(ctx_node, *err, type_u->types[ti], value, value_len); +- return rc; ++ union_update_lref_err(*err, type_u->types[ti], value, value_len); ++ goto cleanup; + } + + assert(subvalue->value.realtype); +@@ -256,9 +250,6 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint3 + if (options & LYPLG_TYPE_STORE_ONLY) { + opts |= LYPLG_TYPE_STORE_ONLY; + } +- if (dynamic) { +- opts |= LYPLG_TYPE_STORE_DYNAMIC; +- } + + rc = type->plugin->store(ctx, type, value, value_len, opts, format, prefix_data, subvalue->hints, + subvalue->ctx_node, &subvalue->value, unres, err); +@@ -267,8 +258,8 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint3 + memset(&subvalue->value, 0, sizeof subvalue->value); + + /* if this is a leafref, lets make sure we propagate the appropriate error, and not a type validation failure */ +- union_update_lref_err(ctx_node, *err, type, value, value_len); +- return rc; ++ union_update_lref_err(*err, type, value, value_len); ++ goto cleanup; + } + + if (validate && (rc == LY_EINCOMPLETE)) { +@@ -280,6 +271,10 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint3 + } + } + ++cleanup: ++ if (dynamic) { ++ free((void *)value); ++ } + return rc; + } + + +From 400b42a9075fe67b54b4bd6c6751e24cb46a0b36 Mon Sep 17 00:00:00 2001 +From: Brad House +Date: Mon, 3 Mar 2025 06:57:03 -0500 +Subject: [PATCH 4/5] reference RFC in doxygen + +--- + src/plugins_types/union.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/src/plugins_types/union.c b/src/plugins_types/union.c +index 0c126f6ae..1f60d8c43 100644 +--- a/src/plugins_types/union.c ++++ b/src/plugins_types/union.c +@@ -153,6 +153,8 @@ lyb_parse_union(const void *lyb_data, size_t lyb_data_len, uint32_t *type_idx, c + /** + * @brief For leafref failures, ensure the appropriate error is propagated, not a type validation failure. + * ++ * RFC7950 Section 15.5 defines the appropriate error app tag of "require-instance". ++ * + * @param[in,out] err Error record to be updated + * @param[in] type leafref type used to extract target path + * @param[in] value value attempting to be stored + +From e3cd01a4985d3eb5ed1c35793d1742c3960108ca Mon Sep 17 00:00:00 2001 +From: Brad House +Date: Mon, 3 Mar 2025 07:02:41 -0500 +Subject: [PATCH 5/5] error checking for OOM + +--- + src/plugins_types/union.c | 32 ++++++++++++++++++++++++++------ + 1 file changed, 26 insertions(+), 6 deletions(-) + +diff --git a/src/plugins_types/union.c b/src/plugins_types/union.c +index 1f60d8c43..0da238235 100644 +--- a/src/plugins_types/union.c ++++ b/src/plugins_types/union.c +@@ -159,25 +159,39 @@ lyb_parse_union(const void *lyb_data, size_t lyb_data_len, uint32_t *type_idx, c + * @param[in] type leafref type used to extract target path + * @param[in] value value attempting to be stored + * @param[in] value_len Length of value that was attempted to be stored. ++ * @return LY_ERR value. Only possible errors are LY_SUCCESS and LY_EMEM. + */ +-static void ++static LY_ERR + union_update_lref_err(struct ly_err_item *err, const struct lysc_type *type, const void *value, size_t value_len) + { + const struct lysc_type_leafref *lref; + char *valstr = NULL; ++ int msg_len; + + if ((err == NULL) || (type->basetype != LY_TYPE_LEAFREF)) { +- return; ++ return LY_SUCCESS; + } + + lref = (const struct lysc_type_leafref *)type; + free(err->apptag); + err->apptag = strdup("instance-required"); ++ if (err->apptag == NULL) { ++ return LY_EMEM; ++ } + + free(err->msg); ++ err->msg = NULL; + valstr = strndup((const char *)value, value_len); +- asprintf(&err->msg, LY_ERRMSG_NOLREF_VAL, valstr, lyxp_get_expr(lref->path)); ++ if (valstr == NULL) { ++ return LY_EMEM; ++ } ++ ++ msg_len = asprintf(&err->msg, LY_ERRMSG_NOLREF_VAL, valstr, lyxp_get_expr(lref->path)); + free(valstr); ++ if (msg_len == -1) { ++ return LY_EMEM; ++ } ++ return LY_SUCCESS; + } + + /** +@@ -200,7 +214,7 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint3 + uint32_t options, ly_bool validate, const struct lyd_node *ctx_node, const struct lyd_node *tree, + struct lys_glob_unres *unres, struct ly_err_item **err) + { +- LY_ERR rc = LY_SUCCESS; ++ LY_ERR urc, rc = LY_SUCCESS; + struct lysc_type *type = type_u->types[type_idx]; + const void *value = NULL; + size_t value_len = 0; +@@ -222,7 +236,10 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint3 + memset(&subvalue->value, 0, sizeof subvalue->value); + + /* if this is a leafref, lets make sure we propagate the appropriate error, and not a type validation failure */ +- union_update_lref_err(*err, type_u->types[ti], value, value_len); ++ urc = union_update_lref_err(*err, type_u->types[ti], value, value_len); ++ if (urc != LY_SUCCESS) { ++ rc = urc; ++ } + goto cleanup; + } + +@@ -260,7 +277,10 @@ union_store_type(const struct ly_ctx *ctx, struct lysc_type_union *type_u, uint3 + memset(&subvalue->value, 0, sizeof subvalue->value); + + /* if this is a leafref, lets make sure we propagate the appropriate error, and not a type validation failure */ +- union_update_lref_err(*err, type, value, value_len); ++ urc = union_update_lref_err(*err, type, value, value_len); ++ if (urc != LY_SUCCESS) { ++ rc = urc; ++ } + goto cleanup; + } + diff --git a/src/libyang3/patch/0006-pr2361-union-sort-assert.patch b/src/libyang3/patch/0006-pr2361-union-sort-assert.patch new file mode 100644 index 000000000000..a72cdb9e10d5 --- /dev/null +++ b/src/libyang3/patch/0006-pr2361-union-sort-assert.patch @@ -0,0 +1,45 @@ +From 18dd3a625f408e0b22258fcf30be25a94abf7d3e Mon Sep 17 00:00:00 2001 +From: Brad House +Date: Mon, 3 Mar 2025 06:16:41 -0500 +Subject: [PATCH] union: fix assert in sort + +An assert was being hit in lyplg_type_sort_union() when evaluating +leafrefs due to not using the realtype node. + +Signed-off-by: Michal Vasko +Signed-off-by: Brad House +--- + src/plugins_types/union.c | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/src/plugins_types/union.c b/src/plugins_types/union.c +index 61dde35d9..74ac0d64f 100644 +--- a/src/plugins_types/union.c ++++ b/src/plugins_types/union.c +@@ -515,6 +515,7 @@ lyplg_type_sort_union(const struct ly_ctx *ctx, const struct lyd_value *val1, co + int rc = LY_SUCCESS; + LY_ARRAY_COUNT_TYPE u; + struct lysc_type **types; ++ struct lysc_type *type; + + if (val1->subvalue->value.realtype == val2->subvalue->value.realtype) { + return val1->subvalue->value.realtype->plugin->sort(ctx, &val1->subvalue->value, &val2->subvalue->value); +@@ -523,10 +524,16 @@ lyplg_type_sort_union(const struct ly_ctx *ctx, const struct lyd_value *val1, co + /* compare according to the order of types */ + types = ((struct lysc_type_union *)val1->realtype)->types; + LY_ARRAY_FOR(types, u) { +- if (types[u] == val1->subvalue->value.realtype) { ++ if (types[u]->basetype == LY_TYPE_LEAFREF) { ++ type = ((struct lysc_type_leafref *)types[u])->realtype; ++ } else { ++ type = types[u]; ++ } ++ ++ if (type == val1->subvalue->value.realtype) { + rc = 1; + break; +- } else if (types[u] == val2->subvalue->value.realtype) { ++ } else if (type == val2->subvalue->value.realtype) { + rc = -1; + break; + } diff --git a/src/libyang3/patch/series b/src/libyang3/patch/series new file mode 100644 index 000000000000..c519c189b856 --- /dev/null +++ b/src/libyang3/patch/series @@ -0,0 +1,6 @@ +0001-pr2344-json-strings.patch +0002-pr2352-backlinks.patch +0003-minmax-errpath-3adb304.patch +0004-union-apptag-529a594.patch +0005-pr2360-validate-union-errors.patch +0006-pr2361-union-sort-assert.patch diff --git a/src/sonic-frr/patch/0081-backport-libyang3.patch b/src/sonic-frr/patch/0081-backport-libyang3.patch new file mode 100644 index 000000000000..ad61de12eb84 --- /dev/null +++ b/src/sonic-frr/patch/0081-backport-libyang3.patch @@ -0,0 +1,230 @@ +diff --git a/debian/control b/debian/control +index 4784e6b23..ef8895a41 100644 +--- a/debian/control ++++ b/debian/control +@@ -23,7 +23,7 @@ Build-Depends: bison, + librtr-dev (>= 0.8.0~) , + libsnmp-dev, + libssh-dev , +- libyang2-dev (>= 2.1.128), ++ libyang2-dev (>= 2.1.128) | libyang-dev ( >= 3.0.3), + lsb-base, + pkg-config, + protobuf-c-compiler, +diff --git a/lib/vty.c b/lib/vty.c +index 1c9cff478..d3e617f88 100644 +--- a/lib/vty.c ++++ b/lib/vty.c +@@ -39,6 +39,7 @@ + #include "libfrr.h" + #include "frrstr.h" + #include "lib_errors.h" ++#include + #include "northbound_cli.h" + #include "printfrr.h" + #include "json.h" +@@ -3668,15 +3669,24 @@ static ssize_t vty_mgmt_libyang_print(void *user_data, const void *buf, + } + + static void vty_out_yang_error(struct vty *vty, LYD_FORMAT format, +- struct ly_err_item *ei) ++ const struct ly_err_item *ei) + { ++#if (LY_VERSION_MAJOR < 3) ++#define data_path path ++#else ++#define data_path data_path ++#endif + bool have_apptag = ei->apptag && ei->apptag[0] != 0; +- bool have_path = ei->path && ei->path[0] != 0; ++ bool have_path = ei->data_path && ei->data_path[0] != 0; + bool have_msg = ei->msg && ei->msg[0] != 0; + const char *severity = NULL; + const char *evalid = NULL; + const char *ecode = NULL; ++#if (LY_VERSION_MAJOR < 3) + LY_ERR err = ei->no; ++#else ++ LY_ERR err = ei->err; ++#endif + + if (ei->level == LY_LLERR) + severity = "error"; +@@ -3701,7 +3711,8 @@ static void vty_out_yang_error(struct vty *vty, LYD_FORMAT format, + vty_out(vty, "%s\n", + evalid); + if (have_path) +- vty_out(vty, "%s\n", ei->path); ++ vty_out(vty, "%s\n", ++ ei->data_path); + if (have_apptag) + vty_out(vty, "%s\n", + ei->apptag); +@@ -3720,7 +3731,7 @@ static void vty_out_yang_error(struct vty *vty, LYD_FORMAT format, + if (evalid) + vty_out(vty, ", \"error-validation\": \"%s\"", evalid); + if (have_path) +- vty_out(vty, ", \"error-path\": \"%s\"", ei->path); ++ vty_out(vty, ", \"error-path\": \"%s\"", ei->data_path); + if (have_apptag) + vty_out(vty, ", \"error-app-tag\": \"%s\"", ei->apptag); + if (have_msg) +@@ -3737,18 +3748,19 @@ static void vty_out_yang_error(struct vty *vty, LYD_FORMAT format, + if (evalid) + vty_out(vty, " invalid: %s", evalid); + if (have_path) +- vty_out(vty, " path: %s", ei->path); ++ vty_out(vty, " path: %s", ei->data_path); + if (have_apptag) + vty_out(vty, " app-tag: %s", ei->apptag); + if (have_msg) + vty_out(vty, " msg: %s", ei->msg); + break; + } ++#undef data_path + } + + static uint vty_out_yang_errors(struct vty *vty, LYD_FORMAT format) + { +- struct ly_err_item *ei = ly_err_first(ly_native_ctx); ++ const struct ly_err_item *ei = ly_err_first(ly_native_ctx); + uint count; + + if (!ei) +diff --git a/lib/yang.c b/lib/yang.c +index 03044fc29..2c09d37ba 100644 +--- a/lib/yang.c ++++ b/lib/yang.c +@@ -11,6 +11,7 @@ + #include "lib_errors.h" + #include "yang.h" + #include "yang_translator.h" ++#include + #include "northbound.h" + + #include "lib/config_paths.h" +@@ -18,6 +19,17 @@ + DEFINE_MTYPE_STATIC(LIB, YANG_MODULE, "YANG module"); + DEFINE_MTYPE_STATIC(LIB, YANG_DATA, "YANG data structure"); + ++/* Safe to remove after libyang 2.2.8 */ ++#if (LY_VERSION_MAJOR < 3) ++#define yang_lyd_find_xpath3(ctx_node, tree, xpath, format, prefix_data, vars, \ ++ set) \ ++ lyd_find_xpath3(ctx_node, tree, xpath, vars, set) ++#else ++#define yang_lyd_find_xpath3(ctx_node, tree, xpath, format, prefix_data, vars, \ ++ set) \ ++ lyd_find_xpath3(ctx_node, tree, xpath, LY_VALUE_JSON, NULL, vars, set) ++#endif ++ + /* libyang container. */ + struct ly_ctx *ly_native_ctx; + +@@ -691,7 +703,12 @@ struct yang_data *yang_data_list_find(const struct list *list, + } + + /* Make libyang log its errors using FRR logging infrastructure. */ +-static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path) ++static void ly_zlog_cb(LY_LOG_LEVEL level, const char *msg, const char *data_path ++#if !(LY_VERSION_MAJOR < 3) ++ , ++ const char *schema_path, uint64_t line ++#endif ++) + { + int priority = LOG_ERR; + +@@ -708,8 +725,14 @@ static void ly_log_cb(LY_LOG_LEVEL level, const char *msg, const char *path) + break; + } + +- if (path) +- zlog(priority, "libyang: %s (%s)", msg, path); ++ if (data_path) ++ zlog(priority, "libyang: %s (%s)", msg, data_path); ++#if !(LY_VERSION_MAJOR < 3) ++ else if (schema_path) ++ zlog(priority, "libyang %s (%s)\n", msg, schema_path); ++ else if (line) ++ zlog(priority, "libyang %s (line %" PRIu64 ")\n", msg, line); ++#endif + else + zlog(priority, "libyang: %s", msg); + } +@@ -736,7 +759,8 @@ LY_ERR yang_parse_notification(const char *xpath, LYD_FORMAT format, + return err; + } + +- err = lyd_find_xpath3(NULL, tree, xpath, NULL, &set); ++ err = yang_lyd_find_xpath3(NULL, tree, xpath, LY_VALUE_JSON, NULL, NULL, ++ &set); + if (err) { + zlog_err("Failed to parse notification: %s", ly_last_errmsg()); + lyd_free_all(tree); +@@ -795,7 +819,7 @@ char *yang_convert_lyd_format(const char *data, size_t data_len, + + assert(out_format != LYD_LYB); + +- if (in_format != LYD_LYB && !MGMT_MSG_VALIDATE_NUL_TERM(data, data_len)) { ++ if (in_format != LYD_LYB && (!data_len || data[data_len - 1] != 0)) { + zlog_err("Corrupt input data, no NUL terminating byte"); + return NULL; + } +@@ -829,23 +853,29 @@ char *yang_convert_lyd_format(const char *data, size_t data_len, + + const char *yang_print_errors(struct ly_ctx *ly_ctx, char *buf, size_t buf_len) + { +- struct ly_err_item *ei; ++ const struct ly_err_item *ei; + + ei = ly_err_first(ly_ctx); + if (!ei) + return ""; + + strlcpy(buf, "YANG error(s):\n", buf_len); ++#if (LY_VERSION_MAJOR < 3) ++#define data_path path ++#else ++#define data_path data_path ++#endif + for (; ei; ei = ei->next) { +- if (ei->path) { ++ if (ei->data_path) { + strlcat(buf, " Path: ", buf_len); +- strlcat(buf, ei->path, buf_len); ++ strlcat(buf, ei->data_path, buf_len); + strlcat(buf, "\n", buf_len); + } + strlcat(buf, " Error: ", buf_len); + strlcat(buf, ei->msg, buf_len); + strlcat(buf, "\n", buf_len); + } ++#undef data_path + + ly_err_clean(ly_ctx, NULL); + +@@ -897,7 +927,12 @@ struct ly_ctx *yang_ctx_new_setup(bool embedded_modules, bool explicit_compile) + void yang_init(bool embedded_modules, bool defer_compile) + { + /* Initialize libyang global parameters that affect all containers. */ +- ly_set_log_clb(ly_log_cb, 1); ++ ly_set_log_clb(ly_zlog_cb ++#if (LY_VERSION_MAJOR < 3) ++ , ++ 1 ++#endif ++ ); + ly_log_options(LY_LOLOG | LY_LOSTORE); + + /* Initialize libyang container for native models. */ +@@ -1209,7 +1244,8 @@ LY_ERR yang_lyd_trim_xpath(struct lyd_node **root, const char *xpath) + + *root = lyd_first_sibling(*root); + +- err = lyd_find_xpath3(NULL, *root, xpath, NULL, &set); ++ err = yang_lyd_find_xpath3(NULL, *root, xpath, LY_VALUE_JSON, NULL, ++ NULL, &set); + if (err) { + flog_err_sys(EC_LIB_LIBYANG, + "cannot obtain specific result for xpath \"%s\": %s", diff --git a/src/sonic-frr/patch/series b/src/sonic-frr/patch/series index c18d0159c6c6..e7c69db36456 100644 --- a/src/sonic-frr/patch/series +++ b/src/sonic-frr/patch/series @@ -61,5 +61,6 @@ 0078-vtysh-de-conditionalize-and-reorder-install-node.patch 0079-staticd-add-support-for-srv6.patch 0080-SRv6-vpn-route-and-sidlist-install.patch +0081-backport-libyang3.patch 0082-Revert-bgpd-upon-if-event-evaluate-bnc-with-matching.patch 0083-staticd-add-cli-to-support-steering-of-ipv4-traffic-over-srv6-sid-list.patch diff --git a/src/sonic-yang-models/tests/yang_model_tests/test_yang_model.py b/src/sonic-yang-models/tests/yang_model_tests/test_yang_model.py index 22cad816b115..46a2f63ef4ce 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/test_yang_model.py +++ b/src/sonic-yang-models/tests/yang_model_tests/test_yang_model.py @@ -39,17 +39,27 @@ class Test_yang_models: def initTest(self): self.defaultYANGFailure = { 'Must': ['Must condition', 'not satisfied'], - 'InvalidValue': ['Invalid value'], - 'LeafRef': ['Leafref', 'non-existing'], + 'InvalidValue': ['Invalid value'], # libyang3: ['Invalid', 'value', 'Data path'] + 'LeafRef': ['Leafref', 'non-existing'], #libyang3: ['Invalid leafref', 'no target instance'] 'When': ['When condition', 'not satisfied'], - 'Pattern': ['pattern', 'does not satisfy'], - 'Mandatory': ['required element', 'Missing'], + 'Pattern': ['pattern', 'does not satisfy'], #libyang3: ['pattern', 'Unsatisfied pattern'] + 'Mandatory': ['required element', 'Missing'], #libyang3: ['Mandatory node', 'does not exist'] 'Verify': ['verified'], - 'Range': ['does not satisfy', 'range'], + 'Range': ['does not satisfy', 'range'], #libyang3: ['Unsatisfied range'] 'MinElements': ['Too few'], 'MaxElements': ['Too many'], 'UnknownElement': ['Unknown element'], - 'None': [] + 'None': [], +# New keys are needed for libyang3's messages which are different. Go +# ahead and add them now with the libyang1 values (which are duplicates +# of the above). This will make migrating to libyang3 easier with less +# code review. + 'Length': ['does not satisfy', 'range'], # libyang3: ['Unsatisfied length'] + 'DecimalFractionExceed': ['Invalid value'], # libyang3: ['Value', 'exceeds defined number', 'fraction digits'] + 'Bounds': ['Invalid value'], #libyang3 ['Value', 'out of type', 'min/max bounds'], + 'ListKey': ['Missing required element'], #libyang3 ['List instance is missing its key'] + 'DateTime': ['pattern', 'does not satisfy'], #libyang3: ['Invalid date-and-time'] + 'IPv4': ['pattern', 'does not satisfy'], #libyang3 ['Failed to convert IPv4 address'], } self.ExceptionTests = { } diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/asic-sensors.json b/src/sonic-yang-models/tests/yang_model_tests/tests/asic-sensors.json index 227904f40085..d94587f6ac7c 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/asic-sensors.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/asic-sensors.json @@ -4,7 +4,7 @@ }, "ASIC_SENSORS_INVALID_POLLER_INTERVAL": { "desc": "Configure an invalid ASIC Sensors polling interval", - "eStrKey" : "Pattern" + "eStrKey" : "Range" }, "ASIC_SENSORS_INVALID_POLLER_ADMIN_STATUS": { "desc": "Configure an invalid ASIC Sensors polling admin status", diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/auto_techsupport.json b/src/sonic-yang-models/tests/yang_model_tests/tests/auto_techsupport.json index a335dcfd389c..dc6af878a9e4 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/auto_techsupport.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/auto_techsupport.json @@ -12,14 +12,14 @@ }, "AUTO_TECHSUPPORT_OUT_OF_RANGE_DECIMAL": { "desc" : "Configure a value for core-uage outside the range [0, 100)", - "eStr": "Value \"100.00\" does not satisfy the constraint \"0..99.99\" (range, length, or pattern)." + "eStrKey": "Range" }, "AUTO_TECHSUPPORT_VALID_DECIMAL_VALUE": { "desc" : "Configure a value for max_techsupport_size inside the range [0, 100)" }, "AUTO_TECHSUPPORT_INVALID_FRACTION_DIGITS": { "desc" : "Configure a value for max_techsupport_size inside the range [0, 100) but with 3 fractional digits", - "eStrKey": "InvalidValue" + "eStrKey": "DecimalFractionExceed" }, "AUTO_TECHSUPPORT_RATE_LIMIT_INTERVAL_TEST": { "desc" : "Configure and test the valid configuration" @@ -29,13 +29,13 @@ }, "AUTO_TECHSUPPORT_INVALID_AVAILABLE_MEM_THRESHOLD": { "desc" : "Configure a value for available_mem_threshold inside the range [0, 100) but with 3 fractional digits", - "eStrKey": "InvalidValue" + "eStrKey": "DecimalFractionExceed" }, "AUTO_TECHSUPPORT_GLOBAL_MEM_THRESHOLD_VALID": { "desc" : "Configure and test the valid configuration" }, "AUTO_TECHSUPPORT_GLOBAL_MEM_THRESHOLD_INVALID_THRESHOLD": { "desc" : "Configure a value for available_mem_threshold inside the range [0, 100) but with 3 fractional digits", - "eStrKey": "InvalidValue" + "eStrKey": "DecimalFractionExceed" } } diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/bgp.json b/src/sonic-yang-models/tests/yang_model_tests/tests/bgp.json index 476c9c2d47cc..0118a5f1b1a8 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/bgp.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/bgp.json @@ -51,8 +51,7 @@ }, "BGP_NEIGHBOR_NEG_INVALID_NAME": { "desc": "Incorrect neighbor name.", - "eStrKey": "InvalidValue", - "eStr": ["neighbor"] + "eStrKey": "InvalidValue" }, "BGP_NEIGHBOR_NEG_INVALID_ASN": { "desc": "Invalid local AS number.", @@ -78,7 +77,7 @@ }, "BGP_NEIGHBOR_AF_NEG_INVALID_MAXTHRESHOLD": { "desc": "Invalid maximum prefix warning threshold in neighbor AF.", - "eStrKey" : "Pattern" + "eStrKey" : "Range" }, "BGP_NEIGHBOR_AF_NEG_INVALID_SOFT_RECFG_IN": { "desc": "Invalid boolean value for soft reconfiguration-in in neighbor AF.", @@ -118,11 +117,11 @@ }, "BGP_PEERGROUP_INVALID_HOPS": { "desc": "Invalid TTL hops for peergroup.", - "eStrKey" : "Pattern" + "eStrKey" : "Range" }, "BGP_PEERGROUP_AF_INVALID_MAXTHRESHOLD": { "desc": "Invalid maximum prefix warning threshold in peergroup AF.", - "eStrKey" : "Pattern" + "eStrKey" : "Range" }, "BGP_PEERGROUP_AF_INVALID_SOFT_RECFG_IN": { "desc": "Invalid boolean value for soft reconfiguration-in in peergroup AF.", @@ -157,7 +156,7 @@ }, "BGP_NEIGHBOR_NEG_INVALID_HOPS": { "desc": "Invalid TTL hops for unnumbered interface neigbhor.", - "eStrKey" : "Pattern" + "eStrKey" : "Range" }, "BGP_MONITORS_ALL_VALID": { "desc": "Configure BGP monitor table." diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/buffer_pool.json b/src/sonic-yang-models/tests/yang_model_tests/tests/buffer_pool.json index ff35fc7357d1..f8557fb25031 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/buffer_pool.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/buffer_pool.json @@ -48,7 +48,7 @@ }, "BUFFER_POOL_WRONG_PERCENTAGE_NEGATIVE_VALUE": { "desc": "BUFFER_POOL_WRONG_PERCENTAGE_NEGATIVE_VALUE pattern failure.", - "eStr": "Invalid value" + "eStrKey": "Bounds" }, "BUFFER_POOL_WRONG_PERCENTAGE_NOT_A_NUMBER_VALUE": { "desc": "BUFFER_POOL_WRONG_PERCENTAGE_NOT_A_NUMBER_VALUE pattern failure.", diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/device_metadata.json b/src/sonic-yang-models/tests/yang_model_tests/tests/device_metadata.json index 6ca674f7e554..aff9dd38e3fc 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/device_metadata.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/device_metadata.json @@ -80,7 +80,7 @@ }, "DEVICE_METADATA_INCORRECT_BUFFER_MODEL_PATTERN": { "desc": "DEVICE_METADATA wrong value for BUFFER_MODEL field.", - "eStr": ["pattern", "does not satisfy"] + "eStrKey": "Pattern" }, "DEVICE_METADATA_FRR_MGMT_FWK_CONFIG": { "desc": "Verifying FRR MGMT framework configuration." @@ -121,7 +121,7 @@ }, "DEVICE_METADATA_INVALID_PEER_SWITCH": { "desc": "Verifying test fails with hostname that is too long", - "eStrKey": "Range" + "eStrKey": "Length" }, "DEVICE_METADATA_VALID_STORAGE_DEVICE": { "desc": "Verifying valid storage device value" @@ -172,7 +172,7 @@ }, "DEVICE_METADATA_INVALID_TIMEZONE": { "desc": "Verifying invalid timezone value", - "eStrKey": "Range" + "eStrKey": "Length" }, "DEVICE_METADATA_VALID_CREATE_ONLY_CONFIG_DB_BUFFERS": { "desc": "Verifying the create_only_config_db_buffers value" diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/dhcp_server_ipv4.json b/src/sonic-yang-models/tests/yang_model_tests/tests/dhcp_server_ipv4.json index 3e7829b41b08..0f99827112a4 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/dhcp_server_ipv4.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/dhcp_server_ipv4.json @@ -12,7 +12,7 @@ }, "DHCP_SERVER_IPV4_INCORRECT_NETMASK": { "desc": "Add netmask which is not in correct ip-prefix format.", - "eStrKey": "Pattern" + "eStrKey": "IPv4" }, "DHCP_SERVER_IPV4_STATE_WRONG_VALUE": { "desc": "Configure wrong value for state.", diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/fine-grained-ecmp.json b/src/sonic-yang-models/tests/yang_model_tests/tests/fine-grained-ecmp.json index 2eed9fb8f34f..e81189ebea4e 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/fine-grained-ecmp.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/fine-grained-ecmp.json @@ -38,15 +38,15 @@ }, "FG_NHG_MEMBER_TEST_MISSING_FG_NHG_REF": { "desc": "Fine-grained ECMP next-hop member configuration with missing FG_NHG reference in FG_NHG_MEMBER_LIST table.", - "eStr": "Missing required element \"FG_NHG\" in \"FG_NHG_MEMBER_LIST\". " + "eStrKey": "Mandatory" }, "FG_NHG_PREFIX_TEST_MISSING_FG_NHG_REF": { "desc": "Fine-grained ECMP prefix configuration with missing FG_NHG reference in FG_NHG_PREFIX_LIST table.", - "eStr": "Missing required element \"FG_NHG\" in \"FG_NHG_PREFIX_LIST\". " + "eStrKey": "Mandatory" }, "FG_NHG_MEMBER_TEST_MISSING_BANK": { "desc": "Fine-grained ECMP next-hop member configuration with missing bank in FG_NHG_MEMBER_LIST table.", - "eStr": "Missing required element \"bank\"" + "eStrKey": "Mandatory" }, "FG_NHG_PREFIX_TEST_DUPLICATE_ENTRY": { "desc": "Fine-grained ECMP prefix configuration with duplicate entry in FG_NHG_PREFIX_LIST table.", @@ -56,4 +56,4 @@ "desc": "Fine-grained ECMP next-hop member configuration with duplicate member in FG_NHG_MEMBER_LIST table.", "eStr": "Duplicated instance of \"FG_NHG_MEMBER_LIST\" list." } -} \ No newline at end of file +} diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/flex_counter.json b/src/sonic-yang-models/tests/yang_model_tests/tests/flex_counter.json index a508400f26d5..ea3e7ded392b 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/flex_counter.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/flex_counter.json @@ -4,16 +4,14 @@ }, "FLEX_COUNTER_TABLE_WITH_INVALID_POLL_INTERVAL": { "desc": "Out of range poll interval.", - "eStrKey": "Range", - "eStr": "100..4294967295" + "eStrKey": "Range" }, "FLEX_COUNTER_TABLE_WITH_VALID_BULK_CHUNK_SIZE": { "desc": "FLEX_COUNTER_TABLE_WITH_VALID_BULK_CHUNK_SIZE no failure." }, "FLEX_COUNTER_TABLE_WITH_INVALID_BULK_CHUNK_SIZE": { "desc": "Out of range bulk chunk size.", - "eStrKey": "Range", - "eStr": "1..4294967295" + "eStrKey": "Range" }, "FLOW_COUNTER_ROUTE_PATTERN_TABLE_WITH_VRF": { "desc": "FLOW_COUNTER_ROUTE_PATTERN_TABLE_WITH_VRF no failure." @@ -23,7 +21,6 @@ }, "FLOW_COUNTER_ROUTE_PATTERN_TABLE_WITH_INVALID_MAX_MATCH_COUNT": { "desc": "Out of range max_match_count.", - "eStrKey": "Range", - "eStr": "1..50" + "eStrKey": "Range" } } diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/kdump.json b/src/sonic-yang-models/tests/yang_model_tests/tests/kdump.json index 9f9525c2231d..8f065dc4f256 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/kdump.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/kdump.json @@ -10,11 +10,11 @@ }, "KDUMP_WITH_INVALID_NUM_DUMPS": { "desc": "Configuring kdump config with a invalid number of allowed kdumps.", - "eStr": ["pattern", "does not satisfy"] + "eStrKey": "Range" }, "KDUMP_WITH_INVALID_MEMORY": { "desc": "Configuring kdump config with invalid memory config.", - "eStr": ["pattern", "does not satisfy"] + "eStrKey": "Pattern" }, "KDUMP_WITH_VALID_REMOTE_VALUES": { "desc": "Configuring the kdump with valid remote ssh values." diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/kubernetes_master.json b/src/sonic-yang-models/tests/yang_model_tests/tests/kubernetes_master.json index 6518f425da16..832798db21bc 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/kubernetes_master.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/kubernetes_master.json @@ -12,7 +12,7 @@ }, "KUBERNETES_MASTER_INVALID_PORT": { "desc": "Configure invalid PORT in kubernetes_master.", - "eStrKey": "InvalidValue" + "eStrKey": "Bounds" }, "KUBERNETES_MASTER_INVALID_IP" : { "desc": "Configure invalid IP in kubernetes_master.", diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/memory_statistics.json b/src/sonic-yang-models/tests/yang_model_tests/tests/memory_statistics.json index e466e9cf92c6..2faaa4d4a4e7 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/memory_statistics.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/memory_statistics.json @@ -4,15 +4,13 @@ }, "MEMORY_STATISTICS_WITH_INVALID_SAMPLING_INTERVAL": { "desc": "Configuring memory statistics with an invalid sampling_interval ( out of acceptable range).", - "eStrKey": "Range", - "eStr": "3..15" + "eStrKey": "Range" }, "MEMORY_STATISTICS_WITH_INVALID_RETENTION_PERIOD": { "desc": "Configuring memory statistics with an invalid retention_period (out of acceptable range).", - "eStrKey": "Range", - "eStr": "1..30" + "eStrKey": "Range" }, "MEMORY_STATISTICS_WITH_ENABLE_FEATURE": { "desc": "Enabling memory statistics feature with valid values." } -} \ No newline at end of file +} diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/mgmt_port.json b/src/sonic-yang-models/tests/yang_model_tests/tests/mgmt_port.json index 3530c7754b51..e279875b62b4 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/mgmt_port.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/mgmt_port.json @@ -15,13 +15,11 @@ }, "MGMT_PORT_INVALID_SPEED": { "desc": "INVALID SPEED", - "eStrKey": "Range", - "eStr": ["10|100|1000"] + "eStrKey": "Range" }, "MGMT_PORT_INVALID_MTU": { "desc": "INVALID MTU", - "eStrKey": "Range", - "eStr": "1500..9216" + "eStrKey": "Range" }, "MGMT_PORT_DEFAULT_MTU": { "desc": "VALIDATE DEFAULT MTU", diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/mirror_session.json b/src/sonic-yang-models/tests/yang_model_tests/tests/mirror_session.json index 5bc6b54a0443..239b6a724376 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/mirror_session.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/mirror_session.json @@ -60,7 +60,7 @@ }, "MIRROR_ERSPAN_ENTRY_WRONG_TTL": { "desc": "Configuring ERSPAN entry with invalid ttl", - "eStr": "Invalid ttl value" + "eStrKey": "Bounds" }, "MIRROR_ERSPAN_ENTRY_WRONG_TTL_TYPE": { "desc": "Configuring ERSPAN entry with invalid ttl", diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/nat.json b/src/sonic-yang-models/tests/yang_model_tests/tests/nat.json index 2d69dacb7379..9b211c110c38 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/nat.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/nat.json @@ -13,8 +13,7 @@ }, "STATIC_NAPT_ENTRY_WRONG_GLOBAL_L4_PORT": { "desc": "Configuring a wrong global l4 port in Static NAPT table.", - "eStrKey": "InvalidValue", - "eStr": ["global_l4_port"] + "eStrKey": "Bounds" }, "STATIC_NAPT_ENTRY_WITHOUT_LOCAL_IP": { "desc": "Configuring a Static NAPT table without local ip.", @@ -26,7 +25,7 @@ }, "STATIC_NAPT_ENTRY_INVALID_TWICE_NAT_ID": { "desc": "Configuring a invalid twice nat id in Static NAPT table.", - "eStrKey": "InvalidValue" + "eStrKey": "Bounds" }, "STATIC_NAT_ENTRY_WITH_VALID_VALUES": { "desc": "Configuring the Static NAT table with valid values." @@ -41,7 +40,7 @@ }, "STATIC_NAT_ENTRY_INVALID_TWICE_NAT_ID": { "desc": "Configuring a invalid twice nat id in Static NAT table.", - "eStrKey": "InvalidValue" + "eStrKey": "Bounds" }, "NAT_GLOBAL_WITH_VALID_VALUES": { "desc": "Configuring a NAT Global table with valid values." @@ -92,7 +91,7 @@ }, "NAT_BINDING_WITH_INVALID_TWICE_NAT_ID": { "desc": "Configuring a invalid twice nat id in NAT Binding table.", - "eStrKey": "InvalidValue" + "eStrKey": "Bounds" }, "NAT_BINDING_WITHOUT_ACL_TABLE": { "desc": "Configuring a NAT Binding table without acl." diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/neigh.json b/src/sonic-yang-models/tests/yang_model_tests/tests/neigh.json index 33f87167d680..6d041311ac10 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/neigh.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/neigh.json @@ -5,11 +5,11 @@ "NEIGH_MISSING_IP": { "desc": "Load NEIGH missing IP address", - "eStr": ["Invalid JSON data"] + "eStrKey": "ListKey" }, "NEIGH_INVALID_VLAN": { "desc": "Load NEIGH missing VLAN", - "eStr": ["does not satisfy the constraint"] + "eStrKey": "Pattern" } } diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/ntp.json b/src/sonic-yang-models/tests/yang_model_tests/tests/ntp.json index f380162b83db..1be07b0225f5 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/ntp.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/ntp.json @@ -122,7 +122,7 @@ }, "NTP_KEY_ID_INVALID": { "desc": "NTP authentication keys invalid key id", - "eStrKey": "InvalidValue" + "eStrKey": "Bounds" }, "NTP_KEY_TRUSTED_INVALID": { "desc": "NTP authentication keys invalid trustiness", @@ -134,6 +134,6 @@ }, "NTP_KEY_VALUE_INVALID": { "desc": "NTP authentication keys bad key value", - "eStrKey": "Range" + "eStrKey": "Length" } } diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/nvgre.json b/src/sonic-yang-models/tests/yang_model_tests/tests/nvgre.json index e776b0d9064f..a1eccae226a8 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/nvgre.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/nvgre.json @@ -15,11 +15,11 @@ "NVGRE_TUNNEL_MAP_INVALID_VLAN_ID": { "desc": "Invalid VLAN ID", - "eStrKey": "Pattern" + "eStrKey": "Range" }, "NVGRE_TUNNEL_MAP_INVALID_VSID": { "desc": "INVALID VSID value for NVGRE_TUNNEL_MAP", - "eStrKey": "Pattern" + "eStrKey": "Range" } -} \ No newline at end of file +} diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/password_hardening.json b/src/sonic-yang-models/tests/yang_model_tests/tests/password_hardening.json index 4bcde92849f1..fe5d9ea88b31 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/password_hardening.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/password_hardening.json @@ -15,18 +15,18 @@ }, "PASSWORD_BAD_HISTORY_CNT": { "desc": "Configure password history_cnt with out of range value", - "eStrKey" : "InvalidValue" + "eStrKey" : "Bounds" }, "PASSWORD_BAD_LEN_MIN": { "desc": "Configure password len-min with out of range value", - "eStrKey" : "Pattern" + "eStrKey" : "Range" }, "PASSWORD_BAD_EXPIRATION": { "desc": "Configure password expiration with out of range value", - "eStrKey" : "Pattern" + "eStrKey" : "Range" }, "PASSWORD_BAD_EXPIRATION_WARN": { "desc": "Configure password expiration-warning with out of range value", - "eStrKey" : "Pattern" + "eStrKey" : "Range" } -} \ No newline at end of file +} diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/pbh.json b/src/sonic-yang-models/tests/yang_model_tests/tests/pbh.json index cb3a0a99fae4..51c2982d2d20 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/pbh.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/pbh.json @@ -12,7 +12,7 @@ }, "PBH_TABLE_INVALID_DESCRIPTION": { "desc": "Configure invalid DESCRIPTION in PBH_TABLE.", - "eStrKey": "Range" + "eStrKey": "Length" }, "PBH_RULE_INVALID_TABLE": { "desc": "Configure non-existing PBH_TABLE in PBH_RULE.", @@ -20,7 +20,7 @@ }, "PBH_RULE_INVALID_PRIORITY": { "desc": "Configure invalid PRIORITY in PBH_RULE.", - "eStrKey": "InvalidValue" + "eStrKey": "Bounds" }, "PBH_RULE_INVALID_GRE_KEY": { "desc": "Configure invalid GRE_KEY in PBH_RULE.", @@ -102,6 +102,6 @@ }, "PBH_HASH_FIELD_INVALID_SEQUENCE_ID": { "desc": "Configure invalid SEQUENCE_ID in PBH_HASH_FIELD.", - "eStrKey": "InvalidValue" + "eStrKey": "Bounds" } } diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/peer-switch.json b/src/sonic-yang-models/tests/yang_model_tests/tests/peer-switch.json index b8ee10dbdf9c..a4df44f176e5 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/peer-switch.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/peer-switch.json @@ -4,7 +4,7 @@ }, "PEER_SWITCH_MISSING_DEVICE__NAME": { "desc": "Load PEER_SWITCH missing PEER Device name.", - "eStrKey": "Mandatory" + "eStrKey": "ListKey" }, "PEER_SWITCH_INVALID_IP_ADDRESS": { "desc": "Load PEER_SWITCH with invalid IPv4 Address.", diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/port.json b/src/sonic-yang-models/tests/yang_model_tests/tests/port.json index 3c0d59cc247d..db68bd865b62 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/port.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/port.json @@ -36,15 +36,14 @@ }, "PORT_INVALID_AUTONEG_TEST": { "desc": "PORT_INVALID_AUTONEG_TEST must condition failure.", - "eStrKey" : "Pattern", - "eStr": ["on|off"] + "eStrKey" : "Pattern" }, "PORT_VALID_SPEEDS_TEST_1": { "desc": "PORT_VALID_SPEEDS_TEST_1 no failure." }, "PORT_INVALID_SPEEDS_TEST_1": { "desc": "PORT_INVALID_SPEEDS_TEST_1 InvalidValue condition failure.", - "eStr": ["pattern", "does not satisfy"] + "eStrKey": "Range" }, "PORT_VALID_ADVSPEEDS_TEST_1": { "desc": "PORT_VALID_ADVSPEEDS_TEST_1 no failure." @@ -117,8 +116,7 @@ }, "PORT_INVALID_LINK_TRAINING_TEST": { "desc": "PORT_INVALID_LINK_TRAINING_TEST must condition failure.", - "eStrKey" : "Pattern", - "eStr": ["on|off"] + "eStrKey" : "Pattern" }, "PORT_INVALID_TPID_TEST": { "desc": "PORT_INVALID_TPID_TEST invalid tpid value failure.", @@ -144,24 +142,21 @@ }, "PORT_INVALID_SUBPORT_NUMBER": { "desc": "Out of range subport number", - "eStrKey": "Range", - "eStr": "0..8" + "eStrKey": "Range" }, "PORT_VALID_DOM_POLLING": { "desc": "PORT_VALID_DOM_POLLING no failure." }, "PORT_INVALID_DOM_POLLING": { "desc": "PORT_INVALID_DOM_POLLING invalid condition failure.", - "eStrKey" : "InvalidValue", - "eStr": ["dom_polling"] + "eStrKey" : "InvalidValue" }, "PORT_AUTO_FEC_TEST": { "desc": "PORT_AUTO_FEC_TEST validate auto mode in fec." }, "PORT_NO_LANES_NEGATIVE_TEST": { "desc": "PORT_NO_LANES_NEGATIVE_TEST no lanes.", - "eStrKey": "Mandatory", - "eStr": ["Missing"] + "eStrKey": "Mandatory" }, "PORT_VOQ_CHASSIS_WITH_NO_LANES": { "desc": "PORT_VOQ_CHASSIS_WITH_NO_LANES no failure." diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/portchannel.json b/src/sonic-yang-models/tests/yang_model_tests/tests/portchannel.json index b2044e02d134..ac1cdd4d5dc5 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/portchannel.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/portchannel.json @@ -7,7 +7,7 @@ }, "PORT_CHANNEL_OUT_OF_RANGE_MIN_LINKS": { "desc": "Configure PortChannel with greater than maximum valid value of min-links.", - "eStr": ["Value", "does not satisfy the constraint"] + "eStrKey": "Range" }, "PORT_CHANNEL_WRONG_PATTERN": { "desc": "INCORRECT PORTCHANNEL_NAME IN PORT_CHANNEL TABLE.", @@ -59,13 +59,11 @@ }, "PORTCHANNEL_INTERFACE_LIST_VRF_TEST_ON_NON_EXIST_PO": { "desc": "Configure vrf name on a non existent PortChannel.", - "eStrKey": "LeafRef", - "eStr": ["sonic-portchannel:name"] + "eStrKey": "LeafRef" }, "PORTCHANNEL_INTERFACE_LIST_NON_EXIST_VRF_TEST": { "desc": "Configure a non existent Vrf in PORTCHANNEL_INTERFACE table.", - "eStrKey": "LeafRef", - "eStr": ["sonic-vrf:name"] + "eStrKey": "LeafRef" }, "PORTCHANNEL_INTERFACE_WRONG_NAT_ZONE_RANGE": { "desc": "Configure wrong value for nat zone.", diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/qos.json b/src/sonic-yang-models/tests/yang_model_tests/tests/qos.json index 3b0199106472..c43190898442 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/qos.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/qos.json @@ -11,7 +11,7 @@ "SCHEDULER_INVALID_WEIGHT": { "desc": "Configure outof range weight in SCHEDULER table.", - "eStrKey" : "Pattern" + "eStrKey" : "Range" }, "SCHEDULER_INVALID_METER_TYPE": { @@ -49,7 +49,7 @@ "WRED_PROFILE_INVALID_DROP_PROBABILITY": { "desc": "Configure invalid drop probability in WRED profile.", - "eStrKey" : "Pattern" + "eStrKey" : "Range" }, "WRED_PROFILE_INVALID_GREEN_THRESHOLD": { diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/restapi.json b/src/sonic-yang-models/tests/yang_model_tests/tests/restapi.json index 42ce64ba330f..22f44f211cf0 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/restapi.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/restapi.json @@ -1,11 +1,11 @@ { "RESTAPI_TABLE_WITH_INCORRECT_CERT": { "desc": "RESTAPI TABLE_WITH_INCORRECT_CERT failure.", - "eStr": ["Value", "does not satisfy the constraint"] + "eStrKey": "Pattern" }, "RESTAPI_TABLE_WITH_INCORRECT_CLIENT": { "desc": "RESTAPI TABLE_WITH_INCORRECT_CLIENT failure.", - "eStr": ["Value", "does not satisfy the constraint"] + "eStrKey": "Pattern" }, "RESTAPI_TABLE_WITH_VALID_CONFIG": { "desc": "RESTAPI TABLE WITH VALID CONFIG." diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/route_filter.json b/src/sonic-yang-models/tests/yang_model_tests/tests/route_filter.json index a1993ff52316..36c9d6e3ac98 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/route_filter.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/route_filter.json @@ -17,8 +17,7 @@ }, "ROUTE_MAP_INVALID_STMT": { "desc": "Configure route map table with wrong value for stmt_name.", - "eStrKey": "InvalidValue", - "eStr": ["stmt_name"] + "eStrKey": "Bounds" }, "ROUTE_MAP_INVALID_OPERATION_TYPE": { "desc": "Configure route map table with invalid route operation type.", diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/serial_console.json b/src/sonic-yang-models/tests/yang_model_tests/tests/serial_console.json index 76e39bb17944..c4634a8320f9 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/serial_console.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/serial_console.json @@ -4,7 +4,7 @@ }, "SERIAL_CONSOLE_INVALID_INACTIVITY_TIMEOUT": { "desc": "SERIAL_CONSOLE attribute 'inactivity_timeout' set to invalid value (out of allowed range of [0, 35000] minutes).", - "eStr": "does not satisfy the constraint \"0..35000\"" + "eStrKey": "Range" }, "SERIAL_CONSOLE_INVALID_SYSRQ" : { "desc": "SERIAL_CONSOLE attribute 'sysrq' set to invalid value", diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/sflow.json b/src/sonic-yang-models/tests/yang_model_tests/tests/sflow.json index b98cc85fd390..598906e0388a 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/sflow.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/sflow.json @@ -4,7 +4,7 @@ }, "SFLOW_COLLECTOR_WRONG_NAME_TEST": { "desc": "Configure a collector with incorrect name in SFLOW_COLLECTOR table.", - "eStr" : ["not", "satisfy", "the", "constraint", "1..64"] + "eStrKey" : "Length" }, "SFLOW_TEST_WITHOUT_COLLECTOR_IP": { "desc": "Configure a collector without collector IP attribute in SFLOW_COLLECTOR table.", @@ -12,7 +12,7 @@ }, "SFLOW_TEST_EXCEEDING_MAX_ELEMENTS": { "desc": "Configure collectors above the specified limit in SFLOW_COLLECTOR table.", - "eStr": ["Too many \"SFLOW_COLLECTOR_LIST\" elements"] + "eStrKey": "MaxElements" }, "SFLOW_TEST_WITH_COLLECTOR_DEFAULT_VRF": { "desc": "Configure a collector in SFLOW_COLLECTOR table with default VRF." diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/snmp.json b/src/sonic-yang-models/tests/yang_model_tests/tests/snmp.json index 95e9b7ba9f80..b00e48e71f90 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/snmp.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/snmp.json @@ -4,22 +4,22 @@ }, "SNMP_SYSTEM_CONTACT_NEG_TEST": { "desc": "Load SNMP sysContact with empty string", - "eStrKey": "Range" + "eStrKey": "Length" }, "SNMP_SYSTEM_LOCATION_NEG_TEST": { "desc": "Load SNMP sysContact with empty string", - "eStrKey": "Range" + "eStrKey": "Length" }, "SNMP_COMMUNITY_TEST": { "desc": "Load SNMP community string." }, "SNMP_COMMUNITY_MIN_NEG_TEST": { "desc": "Load SNMP community string of length < 3.", - "eStrKey": "Range" + "eStrKey": "Length" }, "SNMP_COMMUNITY_MAX_NEG_TEST": { "desc": "Load SNMP community string of lenth > 32.", - "eStrKey": "Range" + "eStrKey": "Length" }, "SNMP_COMMUNITY_WRONG_TYPE_TEST": { "desc": "Load SNMP community string with un supported type.", @@ -33,7 +33,7 @@ }, "SNMP_USER_NAME_MIN_NEG_TEST": { "desc": "Load SNMP user with name < 4", - "eStrKey": "Range" + "eStrKey": "Length" }, "SNMP_USER_NAME_INVALID_NEG_TEST": { "desc": "Load SNMP user with invalid value", @@ -112,7 +112,7 @@ }, "SNMP_USER_PRIV_LONG_ENCRYPT_PASS_NEG_TEST": { "desc": "Load SNMP user with user type Priv with long encryption password", - "eStrKey": "Range" + "eStrKey": "Length" }, "SNMP_AGENT_ADDRESS_CONFIG": { "desc": "Load SNMP agent address config" @@ -128,11 +128,11 @@ }, "SNMP_AGENT_ADDRESS_CONFIG_NO_VRF": { "desc": "Load SNMP agent address config with no vrf", - "eStr": ["Missing required element"] + "eStrKey": "ListKey" }, "SNMP_AGENT_ADDRESS_CONFIG_INVALID_PORT": { "desc": "Load SNMP agent address config with invalid port", - "eStrKey": "InvalidValue" + "eStrKey": "Bounds" }, "SNMP_AGENT_ADDRESS_CONFIG_DUPLICATE_IP_PORT": { "desc": "Load two SNMP agent address config same ip and port", diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-bgp.json b/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-bgp.json index 6749860b2f7f..edf2e74264a4 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-bgp.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-bgp.json @@ -9,7 +9,7 @@ }, "SONIC_EVENTS_BGP_BGP_STATE_INCORRECT_TIMESTAMP": { "desc": "BGP_STATE_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_BGP_BGP_STATE_VALID": { "desc": "VALID BGP STATE EVENT." @@ -32,14 +32,14 @@ }, "SONIC_EVENTS_BGP_NOTIFICATION_INCORRECT_TIMESTAMP": { "desc": "BGP_NOTIFICATION_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_BGP_NOTIFICATION_VALID": { "desc": "VALID BGP NOTIFICATION." }, "SONIC_EVENTS_BGP_ZEBRA_NO_BUFF_INCORRECT_TIMESTAMP": { "desc": "ZEBRA_NO_BUFF_EVENT_INCORRECT_TIMESTAMP.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_BGP_ZEBRA_NO_BUFF_VALID": { "desc": "VALID ZEBRA_NO_BUFF EVENT." diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-dhcp-relay.json b/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-dhcp-relay.json index a4f17ae9e841..8ed60f46b7a0 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-dhcp-relay.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-dhcp-relay.json @@ -5,7 +5,7 @@ }, "SONIC_EVENTS_DHCP_RELAY_DHCP_RELAY_DISCARD_INCORRECT_TIMESTAMP": { "desc": "DHCP_RELAY_DISCARD_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_DHCP_RELAY_DHCP_RELAY_DISCARD_VALID": { "desc": "VALID DHCP_RELAY_DISCARD EVENT." @@ -20,7 +20,7 @@ }, "SONIC_EVENTS_DHCP_RELAY_DHCP_RELAY_DISPARITY_INCORRECT_TIMESTAMP": { "desc": "DHCP_RELAY_DISPARITY_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_DHCP_RELAY_DHCP_RELAY_DISPARITY_VALID": { "desc": "VALID DHCP_RELAY_DISPARITY EVENT." @@ -35,7 +35,7 @@ }, "SONIC_EVENTS_DHCP_RELAY_DHCP_RELAY_BIND_FAILURE_INCORRECT_TIMESTAMP": { "desc": "DHCP_RELAY_BIND_FAILURE_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_DHCP_RELAY_DHCP_RELAY_BIND_FAILURE_VALID": { "desc": "VALID DHCP_RELAY_BIND_FAILURE EVENT." diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-host.json b/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-host.json index b26d8e68a531..ad18f6cc1c5e 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-host.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-host.json @@ -9,7 +9,7 @@ }, "SONIC_EVENTS_HOST_DISK_USAGE_INCORRECT_TIMESTAMP": { "desc": "DISK_USAGE_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_HOST_DISK_USAGE_VALID": { "desc": "VALID DISK_USAGE EVENT." @@ -24,7 +24,7 @@ }, "SONIC_EVENTS_HOST_MEMORY_USAGE_INCORRECT_TIMESTAMP": { "desc": "MEMORY_USAGE_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_HOST_MEMORY_USAGE_VALID": { "desc": "VALID MEMORY_USAGE EVENT." @@ -39,14 +39,14 @@ }, "SONIC_EVENTS_HOST_CPU_USAGE_INCORRECT_TIMESTAMP": { "desc": "CPU_USAGE_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_HOST_CPU_USAGE_VALID": { "desc": "VALID CPU_USAGE EVENT." }, "SONIC_EVENTS_HOST_EVENT_SSHD_INCORRECT_TIMESTAMP": { "desc": "EVENT_SSHD_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_HOST_EVENT_SSHD_VALID": { "desc": "VALID EVENT_SSHD EVENT." @@ -57,7 +57,7 @@ }, "SONIC_EVENTS_HOST_EVENT_DISK_INCORRECT_TIMESTAMP": { "desc": "EVENT_DISK_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_HOST_EVENT_DISK_VALID": { "desc": "VALID EVENT_DISK EVENT." @@ -68,21 +68,21 @@ }, "SONIC_EVENTS_HOST_EVENT_KERNEL_INCORRECT_TIMESTAMP": { "desc": "EVENT_KERNEL_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_HOST_EVENT_KERNEL_VALID": { "desc": "VALID EVENT_KERNEL EVENT." }, "SONIC_EVENTS_HOST_EVENT_DOWN_CTR_INCORRECT_TIMESTAMP": { "desc": "EVENT_DOWN_CTR_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_HOST_EVENT_DOWN_CTR_VALID": { "desc": "VALID EVENT_DOWN_CTR EVENT." }, "SONIC_EVENTS_HOST_EVENT_STOPPED_CTR_INCORRECT_TIMESTAMP": { "desc": "EVENT_STOPPED_CTR_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_HOST_EVENT_STOPPED_CTR_VALID": { "desc": "VALID EVENT_STOPPED_CTR EVENT." @@ -93,21 +93,21 @@ }, "SONIC_EVENTS_HOST_WATCHDOG_TIMEOUT_INCORRECT_TIMESTAMP": { "desc": "WATCHDOG_TIMEOUT_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_HOST_WATCHDOG_TIMEOUT_VALID": { "desc": "VALID WATCHDOG_TIMEOUT EVENT." }, "SONIC_EVENTS_HOST_EVENT_SEU_INCORRECT_TIMESTAMP": { "desc": "EVENT_SEU_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_HOST_EVENT_SEU_VALID": { "desc": "VALID EVENT_SEU EVENT." }, "SONIC_EVENTS_HOST_INVALID_FREELIST_INCORRECT_TIMESTAMP": { "desc": "INVALID_FREELIST_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_HOST_INVALID_FREELIST_VALID": { "desc": "VALID INVALID_FREELIST EVENT." @@ -132,7 +132,7 @@ }, "SONIC_EVENTS_HOST_MEM_THRESHOLD_EXCEEDED_INCORRECT_TIMESTAMP": { "desc": "MEM_THRESHOLD_EXCEEDED_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_HOST_MEM_THRESHOLD_EXCEEDED_VALID": { "desc": "VALID MEM_THRESHOLD_EXCEEDED EVENT." @@ -155,7 +155,7 @@ }, "SONIC_EVENTS_HOST_PROCESS_EXITED_UNEXPECTEDLY_INCORRECT_TIMESTAMP": { "desc": "PROCESS_EXITED_UNEXPECTEDLY_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_HOST_PROCESS_EXITED_UNEXPECTEDLY_VALID": { "desc": "VALID_PROCESS_EXITED_UNEXPECTEDLY EVENT." @@ -178,7 +178,7 @@ }, "SONIC_EVENTS_HOST_PROCESS_NOT_RUNNING_INCORRECT_TIMESTAMP": { "desc": "PROCESS_NOT_RUNNING_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_HOST_PROCESS_NOT_RUNNING_VALID": { "desc": "VALID_PROCESS_NOT_RUNNING EVENT." diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-swss.json b/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-swss.json index a6c3d9332c08..693789ceb52b 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-swss.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-swss.json @@ -9,7 +9,7 @@ }, "SONIC_EVENTS_SWSS_IF_STATE_INCORRECT_TIMESTAMP": { "desc": "IF_STATE_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_SWSS_IF_STATE_VALID": { "desc": "VALID IF_STATE EVENT." @@ -32,7 +32,7 @@ }, "SONIC_EVENTS_SWSS_PFC_STORM_INCORRECT_TIMESTAMP": { "desc": "PFC_STORM_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_SWSS_PFC_STORM_VALID": { "desc": "VALID IF_STATE EVENT." @@ -65,7 +65,7 @@ }, "SONIC_EVENTS_SWSS_CHK_CRM_THRESHOLD_INCORRECT_TIMESTAMP": { "desc": "CHK_CRM_THRESHOLD_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_SWSS_CHK_CRM_THRESHOLD_VALID": { "desc": "VALID CHK_CRM_THRESHOLD EVENT." @@ -88,7 +88,7 @@ }, "SONIC_EVENTS_SWSS_SELECT_OPERATION_FAILURE_INCORRECT_TIMESTAMP": { "desc": "SELECT_OPERATION_FAILURE_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_SWSS_SELECT_OPERATION_FAILURE_VALID": { "desc": "VALID SELECT_OPERATION_FAILURE EVENT." diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-syncd.json b/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-syncd.json index daa50cc1a086..d72750766afe 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-syncd.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/sonic-events-syncd.json @@ -5,7 +5,7 @@ }, "SONIC_EVENTS_SYNCD_SYNCD_FAILURE_INCORRECT_TIMESTAMP": { "desc": "SYNCD_FAILURE_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_SYNCD_SYNCD_FAILURE_VALID": { "desc": "VALID SYNCD_FAILURE EVENT." @@ -20,7 +20,7 @@ }, "SONIC_EVENTS_SYNCD_ALPM_PARITY_ERROR_INCORRECT_TIMESTAMP": { "desc": "ALPM_PARITY_ERROR_EVENT_INCORRECT_TIMESTAMP failure.", - "eStrKey": "Pattern" + "eStrKey": "DateTime" }, "SONIC_EVENTS_SYNCD_ALPM_PARITY_ERROR_VALID": { "desc": "VALID ALPM_PARITY_ERROR_EVENT." diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/ssh-server.json b/src/sonic-yang-models/tests/yang_model_tests/tests/ssh-server.json index e7bc0af10acb..b67c7b66edb2 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/ssh-server.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/ssh-server.json @@ -7,13 +7,11 @@ }, "SSH_SERVER_INVALID_AUTH_RETRIES": { "desc": "Configure invalid number of authentication retries in SSH_SERVER.", - "eStrKey" : "Pattern", - "eStr": ["1..100"] + "eStrKey" : "Range" }, "SSH_SERVER_INVALID_LOGIN_TIMEOUT": { "desc": "Configure invalid login timeout value in SSH_SERVER.", - "eStrKey" : "Pattern", - "eStr": ["1..600"] + "eStrKey" : "Range" }, "SSH_SERVER_INVALID_PORTS_1": { "desc": "Configure invalid port value in SSH_SERVER.", @@ -25,10 +23,10 @@ }, "SSH_SERVER_INVALID_INACTIVITY_TIMEOUT": { "desc": "Configure invalid inactivity_timeout value in SSH_SERVER.", - "eStr": "does not satisfy the constraint \"0..35000\"" + "eStrKey": "Range" }, "SSH_SERVER_INVALID_MAX_SESSIONS": { "desc": "Configure invalid max_sessions value in SSH_SERVER.", - "eStr": "does not satisfy the constraint \"0..100\"" + "eStrKey": "Range" } } diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/stormond.json b/src/sonic-yang-models/tests/yang_model_tests/tests/stormond.json index de8c699c49d0..ac73bedfcfb6 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/stormond.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/stormond.json @@ -4,7 +4,7 @@ }, "STORMOND_INVALID_POLLING_INTERVAL": { "desc": "Configure an invalid daemon polling interval", - "eStrKey" : "InvalidValue" + "eStrKey" : "Bounds" }, "STORMOND_INVALID_SYNC_INTERVAL": { "desc": "Configure an invalid fsstats file sync interval", @@ -26,4 +26,4 @@ "desc": "Configure an empty file sync interval", "eStrKey" : "InvalidValue" } -} \ No newline at end of file +} diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/suppress_asic_sdk_health_event.json b/src/sonic-yang-models/tests/yang_model_tests/tests/suppress_asic_sdk_health_event.json index a96a95deb280..2f2c0d468e97 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/suppress_asic_sdk_health_event.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/suppress_asic_sdk_health_event.json @@ -14,7 +14,7 @@ }, "SUPPRESS_ASIC_SDK_HEALTH_EVENT_LIST_NEGATIVE_MAX_EVENTS": { "desc": "Load suppress ASIC/SDK health event list missing name.", - "eStrKey": "InvalidValue" + "eStrKey": "Bounds" }, "SUPPRESS_ASIC_SDK_HEALTH_EVENT_LIST_INVALID_MAX_EVENTS": { "desc": "Load suppress ASIC/SDK health event list missing name.", diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/syslog.json b/src/sonic-yang-models/tests/yang_model_tests/tests/syslog.json index 4b2eb0ae1da2..eff13fca7ce0 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/syslog.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/syslog.json @@ -12,7 +12,7 @@ }, "SYSLOG_SERVER_INVALID_PORT": { "desc": "Configure invalid PORT in SYSLOG_SERVER.", - "eStrKey": "InvalidValue" + "eStrKey": "Bounds" }, "SYSLOG_SERVER_INVALID_VRF": { "desc": "Configure invalid VRF in SYSLOG_SERVER.", @@ -38,11 +38,11 @@ }, "SYSLOG_CONFIG_INVALID_INTERVAL": { "desc": "Configure invalid rate limit interval in SYSLOG_CONFIG.", - "eStrKey": "InvalidValue" + "eStrKey": "Bounds" }, "SYSLOG_CONFIG_INVALID_BURST": { "desc": "Configure invalid rate limit burst in SYSLOG_CONFIG.", - "eStrKey": "InvalidValue" + "eStrKey": "Bounds" }, "SYSLOG_CONFIG_FEATURE_VALID": { "desc": "Configure SYSLOG_CONFIG_FEATURE." @@ -53,11 +53,11 @@ }, "SYSLOG_CONFIG_FEATURE_INVALID_INTERVAL": { "desc": "Configure invalid rate_limit_interval in SYSLOG_CONFIG_FEATURE.", - "eStrKey": "InvalidValue" + "eStrKey": "Bounds" }, "SYSLOG_CONFIG_FEATURE_INVALID_BURST": { "desc": "Configure invalid rate_limit_burst in SYSLOG_CONFIG_FEATURE.", - "eStrKey": "InvalidValue" + "eStrKey": "Bounds" }, "SYSLOG_SERVER_HOSTNAME": { "desc": "Load syslog server table with hostname" diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/system_port.json b/src/sonic-yang-models/tests/yang_model_tests/tests/system_port.json index 727373ade25a..43e40666f23a 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/system_port.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/system_port.json @@ -4,6 +4,6 @@ }, "SYSTEM_PORT_WRONG_SPEED_PATTERN": { "desc": "Configure SYSTEM_PORT wrong speed.", - "eStr": ["pattern", "does not satisfy"] + "eStrKey": "Range" } } diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/tunnel.json b/src/sonic-yang-models/tests/yang_model_tests/tests/tunnel.json index b414b639aa35..268aea1aae13 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/tunnel.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/tunnel.json @@ -4,15 +4,15 @@ }, "TUNNEL_INVALID_ADDR": { "desc": "Load TUNNEL with invalid IPv4 Address.", - "eStr": ["does not satisfy the constraint"] + "eStrKey": "Pattern" }, "TUNNEL_SRC_IP_NOT_PEER_SWITCH": { "desc": "Load TUNNEL with wrong IPv4 Address.", - "eStr": ["points to a non-existing leaf."] + "eStrKey": "LeafRef" }, "TUNNEL_MISSING_MUX_TUNNEL": { "desc": "Load MUX_TUNNEL missing name.", - "eStr": ["Missing required element"] + "eStrKey": "ListKey" } } diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests/vnet.json b/src/sonic-yang-models/tests/yang_model_tests/tests/vnet.json index 555ceea7d28a..c91cc9999347 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests/vnet.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests/vnet.json @@ -7,22 +7,22 @@ }, "VNET_INVALID_VALUE_TEST1": { "desc": "Invalid values in parameters.", - "eStr": [ "Invalid VRF name" ] + "eStr": "Invalid VRF name" }, "VNET_INVALID_VALUE_TEST2": { "desc": "Invalid values in parameters.", - "eStr": [ "Invalid value" ] + "eStrKey": "Bounds" }, "VNET_INVALID_VALUE_TEST3": { "desc": "Invalid values in parameters.", - "eStr": [ "does not satisfy the constraint" ] + "eStrKey": "Pattern" }, "VNET_INVALID_VALUE_TEST4": { "desc": "Invalid values in parameters.", - "eStr": [ "does not satisfy the constraint" ] + "eStrKey": "Pattern" }, "VNET_INVALID_VXLAN_VTEP": { "desc": "Missing Vxlan_TUNNEL configuration", - "eStr" : [ "points to a non-existing leaf" ] + "eStrKey" : "LeafRef" } -} \ No newline at end of file +} diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests_config/neigh.json b/src/sonic-yang-models/tests/yang_model_tests/tests_config/neigh.json index 165bbb6b8649..26112109f0a1 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests_config/neigh.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests_config/neigh.json @@ -28,7 +28,7 @@ } }, - "NEIGH_MISSING_IPV4": { + "NEIGH_MISSING_IP": { "sonic-vlan:sonic-vlan": { "sonic-vlan:VLAN": { "VLAN_LIST": [ diff --git a/src/sonic-yang-models/tests/yang_model_tests/tests_config/port.json b/src/sonic-yang-models/tests/yang_model_tests/tests_config/port.json index 005961c1daae..fb49b38e8fb7 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/tests_config/port.json +++ b/src/sonic-yang-models/tests/yang_model_tests/tests_config/port.json @@ -180,7 +180,7 @@ "lanes": "65", "speed": 25000, "tpid": "0x8100", - "autoneg": 0, + "autoneg": "invalid", "mode":"trunk" } ] @@ -583,7 +583,7 @@ "lanes": "65", "speed": 25000, "tpid": "0x8100", - "link_training": 0 + "link_training": "invalid" } ] } From 071b6445c5e4c09b63f98c6ba4b65e071ff7819c Mon Sep 17 00:00:00 2001 From: Brad House Date: Wed, 5 Feb 2025 21:14:24 -0500 Subject: [PATCH 2/5] IGNORE THIS COMMIT: merge libyang3 step 2 (PR #21719) --- rules/sonic-yang-models-py3.mk | 4 +- .../tests/yang_model_pytests/conftest.py | 23 ++--- .../tests/yang_model_pytests/test_crm.py | 6 +- .../tests/yang_model_pytests/test_dash_crm.py | 6 +- .../yang_model_pytests/test_smart_switch.py | 20 ++--- .../tests/yang_model_tests/test_yang_model.py | 90 ++++++++++++------- .../yang-models/sonic-bgp-allowed-prefix.yang | 8 ++ .../yang-models/sonic-bgp-common.yang | 2 + .../yang-models/sonic-bgp-global.yang | 1 + .../yang-models/sonic-bgp-peerrange.yang | 1 + .../yang-models/sonic-bgp-sentinel.yang | 1 + ...sonic-buffer-port-egress-profile-list.yang | 1 + ...onic-buffer-port-ingress-profile-list.yang | 1 + .../yang-models/sonic-dash.yang | 6 ++ .../yang-models/sonic-device_metadata.yang | 31 +++---- .../yang-models/sonic-dhcp-server-ipv4.yang | 4 + .../yang-models/sonic-dhcpv6-relay.yang | 1 + .../yang-models/sonic-hash.yang | 2 + .../yang-models/sonic-mgmt_interface.yang | 2 +- .../yang-models/sonic-ntp.yang | 2 +- .../yang-models/sonic-pbh.yang | 2 + .../yang-models/sonic-port.yang | 2 + .../yang-models/sonic-route-common.yang | 1 + .../yang-models/sonic-route-map.yang | 4 + .../sonic-routing-policy-sets.yang | 3 + .../sonic-suppress-asic-sdk-health-event.yang | 1 + .../yang-models/sonic-vlan.yang | 2 + .../yang-templates/sonic-acl.yang.j2 | 5 ++ .../yang-templates/sonic-policer.yang.j2 | 1 - 29 files changed, 152 insertions(+), 81 deletions(-) diff --git a/rules/sonic-yang-models-py3.mk b/rules/sonic-yang-models-py3.mk index d5e64ac07584..8125b1d580c0 100644 --- a/rules/sonic-yang-models-py3.mk +++ b/rules/sonic-yang-models-py3.mk @@ -1,9 +1,7 @@ SONIC_YANG_MODELS_PY3 = sonic_yang_models-1.0-py3-none-any.whl $(SONIC_YANG_MODELS_PY3)_SRC_PATH = $(SRC_PATH)/sonic-yang-models $(SONIC_YANG_MODELS_PY3)_PYTHON_VERSION = 3 -$(SONIC_YANG_MODELS_PY3)_DEBS_DEPENDS = $(LIBYANG) $(LIBYANG_CPP) \ - $(LIBYANG_PY3) \ - $(LIBYANG3) \ +$(SONIC_YANG_MODELS_PY3)_DEBS_DEPENDS = $(LIBYANG3) \ $(LIBYANG3_PY3) SONIC_PYTHON_WHEELS += $(SONIC_YANG_MODELS_PY3) diff --git a/src/sonic-yang-models/tests/yang_model_pytests/conftest.py b/src/sonic-yang-models/tests/yang_model_pytests/conftest.py index 59d55ebfbb8c..8116cc7102de 100644 --- a/src/sonic-yang-models/tests/yang_model_pytests/conftest.py +++ b/src/sonic-yang-models/tests/yang_model_pytests/conftest.py @@ -1,37 +1,38 @@ import os import pytest -import yang as ly +import libyang as ly from json import dumps from glob import glob - class YangModel: def __init__(self) -> None: cur_dir = os.path.dirname(os.path.abspath(__file__)) project_root = os.path.abspath(os.path.join(cur_dir, '..', '..')) self.model_dir = os.path.join(project_root, 'yang-models') - self._load_model() + def __del__(self) -> None: + self.ctx.destroy() + self.ctx = None + def _load_model(self) -> None: self.ctx = ly.Context(self.model_dir) yang_files = glob(self.model_dir +"/*.yang") - for file in yang_files: - m = self.ctx.parse_module_path(file, ly.LYS_IN_YANG) - if not m: - raise RuntimeError("Failed to parse '{file}' model") + with open(file, 'r') as f: + m = self.ctx.parse_module_file(f, "yang") + if not m: + raise RuntimeError("Failed to parse '{file}' model") def _load_data(self, data) -> None: - self.ctx.parse_data_mem(dumps(data), ly.LYD_JSON, - ly.LYD_OPT_CONFIG | ly.LYD_OPT_STRICT) + dnode = self.ctx.parse_data_mem(dumps(data), "json", strict=True, no_state=True, json_string_datatypes=True) + dnode.free() def load_data(self, data, expected_error=None) -> None: if expected_error: - with pytest.raises(RuntimeError) as exc_info: + with pytest.raises(Exception) as exc_info: self._load_data(data) - assert expected_error in str(exc_info) else: self._load_data(data) diff --git a/src/sonic-yang-models/tests/yang_model_pytests/test_crm.py b/src/sonic-yang-models/tests/yang_model_pytests/test_crm.py index ada390c618b9..0d0f84815147 100644 --- a/src/sonic-yang-models/tests/yang_model_pytests/test_crm.py +++ b/src/sonic-yang-models/tests/yang_model_pytests/test_crm.py @@ -61,8 +61,8 @@ def test_crm_valid_data(self, yang_model, resource, threshold): @pytest.mark.parametrize( "high, low, error_message", [ - (-1, 70, 'Invalid value "-1"'), - (100, -70, 'Invalid value "-70"'), + (-1, 70, 'Value "-1" is out of type uint16 min/max bounds'), + (100, -70, 'Value "-70" is out of type uint16 min/max bounds'), (10, 70, 'high_threshold should be more than low_threshold')] ) def test_crm_thresholds(self, yang_model, resource, threshold, high, low, error_message): @@ -82,7 +82,7 @@ def test_crm_thresholds(self, yang_model, resource, threshold, high, low, error_ @pytest.mark.parametrize( "high, low, th_type, error_message", [ - (100, 70, 'wrong', 'Value "wrong" does not satisfy the constraint'), + (100, 70, 'wrong', 'Unsatisfied pattern'), (110, 20, 'percentage', 'Must condition')] ) def test_crm_threshold_type(self, yang_model, resource, high, low, th_type, error_message): diff --git a/src/sonic-yang-models/tests/yang_model_pytests/test_dash_crm.py b/src/sonic-yang-models/tests/yang_model_pytests/test_dash_crm.py index ead37b98fdd9..6d634371b0ac 100644 --- a/src/sonic-yang-models/tests/yang_model_pytests/test_dash_crm.py +++ b/src/sonic-yang-models/tests/yang_model_pytests/test_dash_crm.py @@ -68,8 +68,8 @@ def test_dash_crm_valid_data(self, yang_model, data, resource, threshold): @pytest.mark.parametrize( "high, low, error_message", [ - (-1, 70, 'Invalid value "-1"'), - (100, -70, 'Invalid value "-70"'), + (-1, 70, 'Value "-1" is out of type uint16 min/max bounds'), + (100, -70, 'Value "-70" is out of type uint16 min/max bounds'), (10, 70, 'high_threshold should be more than low_threshold')] ) def test_dash_crm_thresholds(self, yang_model, data, resource, threshold, high, low, error_message): @@ -87,7 +87,7 @@ def test_dash_crm_thresholds(self, yang_model, data, resource, threshold, high, @pytest.mark.parametrize( "high, low, th_type, error_message", [ - (100, 70, 'wrong', 'Value "wrong" does not satisfy the constraint'), + (100, 70, 'wrong', 'Unsatisfied pattern'), (110, 20, 'percentage', 'Must condition')] ) def test_dash_crm_threshold_type(self, yang_model, data, resource, high, low, th_type, error_message): diff --git a/src/sonic-yang-models/tests/yang_model_pytests/test_smart_switch.py b/src/sonic-yang-models/tests/yang_model_pytests/test_smart_switch.py index 4258e5e80641..4bcbc7f55d04 100644 --- a/src/sonic-yang-models/tests/yang_model_pytests/test_smart_switch.py +++ b/src/sonic-yang-models/tests/yang_model_pytests/test_smart_switch.py @@ -32,7 +32,7 @@ def test_valid_data(self, yang_model): @pytest.mark.parametrize( "bridge_name, error_message", [ ("bridge-midplane", None), - ("wrong_name", 'Value "wrong_name" does not satisfy the constraint "bridge-midplane"')] + ("wrong_name", 'Unsatisfied pattern')] ) def test_bridge_name(self, yang_model, bridge_name, error_message): data = { @@ -51,7 +51,7 @@ def test_bridge_name(self, yang_model, bridge_name, error_message): @pytest.mark.parametrize( "ip_prefix, error_message", [ ("169.254.200.254/24", None), - ("169.254.xyz.254/24", 'Value "169.254.xyz.254/24" does not satisfy the constraint')] + ("169.254.xyz.254/24", 'Unsatisfied pattern')] ) def test_bridge_ip_prefix(self, yang_model, ip_prefix, error_message): data = { @@ -70,7 +70,7 @@ def test_bridge_ip_prefix(self, yang_model, ip_prefix, error_message): @pytest.mark.parametrize( "dpu_name, error_message", [ ("dpu0", None), - ("xyz", 'Value "xyz" does not satisfy the constraint "dpu[0-9]+')] + ("xyz", 'Unsatisfied pattern')] ) def test_dpu_name(self, yang_model, dpu_name, error_message): data = { @@ -91,7 +91,7 @@ def test_dpu_name(self, yang_model, dpu_name, error_message): @pytest.mark.parametrize( "midplane_interface, error_message", [ ("dpu0", None), - ("xyz", 'Value "xyz" does not satisfy the constraint "dpu[0-9]+')] + ("xyz", 'Unsatisfied pattern')] ) def test_dpu_midplane_interface(self, yang_model, midplane_interface, error_message): data = { @@ -112,7 +112,7 @@ def test_dpu_midplane_interface(self, yang_model, midplane_interface, error_mess @pytest.mark.parametrize( "port_name, error_message", [ ("dpu0", None), - ("dp0rt0", 'Value "dp0rt0" does not satisfy the constraint "[a-zA-Z]+[0-9]+"')] + ("dp0rt0", 'Unsatisfied pattern')] ) def test_dpu_port_name(self, yang_model, port_name, error_message): data = { @@ -139,7 +139,7 @@ def test_dpu_port_name(self, yang_model, port_name, error_message): @pytest.mark.parametrize( "vip_ipv4, error_message", [ ("192.168.1.1", None), - ("192.168.1.xyz", 'Value "192.168.1.xyz" does not satisfy the constraint')] + ("192.168.1.xyz", 'Unsatisfied pattern')] ) def test_dpu_port_vip_ipv4(self, yang_model, vip_ipv4, error_message): data = { @@ -166,7 +166,7 @@ def test_dpu_port_vip_ipv4(self, yang_model, vip_ipv4, error_message): @pytest.mark.parametrize( "vip_ipv6, error_message", [ ("2001:db8::1", None), - ("2001:db8::xyz", 'Value "2001:db8::xyz" does not satisfy the constraint')] + ("2001:db8::xyz", 'Unsatisfied pattern')] ) def test_dpu_port_vip_ipv6(self, yang_model, vip_ipv6, error_message): data = { @@ -193,7 +193,7 @@ def test_dpu_port_vip_ipv6(self, yang_model, vip_ipv6, error_message): @pytest.mark.parametrize( "pa_ipv4, error_message", [ ("192.168.1.2", None), - ("192.168.1.xyz", 'Value "192.168.1.xyz" does not satisfy the constraint')] + ("192.168.1.xyz", 'Unsatisfied pattern')] ) def test_dpu_port_pa_ipv4(self, yang_model, pa_ipv4, error_message): data = { @@ -220,7 +220,7 @@ def test_dpu_port_pa_ipv4(self, yang_model, pa_ipv4, error_message): @pytest.mark.parametrize( "pa_ipv6, error_message", [ ("2001:db8::2", None), - ("2001:db8::xyz", 'Value "2001:db8::xyz" does not satisfy the constraint')] + ("2001:db8::xyz", 'Unsatisfied pattern')] ) def test_dpu_port_pa_ipv6(self, yang_model, pa_ipv6, error_message): data = { @@ -247,7 +247,7 @@ def test_dpu_port_pa_ipv6(self, yang_model, pa_ipv6, error_message): @pytest.mark.parametrize( "gnmi_port, error_message", [ (8080, None), - (99999, 'Invalid value "99999" in "gnmi_port" element.')] + (99999, 'Value "99999" is out of type uint16 min/max bounds')] ) def test_dpu_port_gnmi(self, yang_model, gnmi_port, error_message): data = { diff --git a/src/sonic-yang-models/tests/yang_model_tests/test_yang_model.py b/src/sonic-yang-models/tests/yang_model_tests/test_yang_model.py index 46a2f63ef4ce..7467a7c6772b 100644 --- a/src/sonic-yang-models/tests/yang_model_tests/test_yang_model.py +++ b/src/sonic-yang-models/tests/yang_model_tests/test_yang_model.py @@ -1,11 +1,12 @@ # This script is used to -import yang as ly +import libyang as ly import logging import argparse import sys import ijson import json +import pytest #import sonic_yang as sy from glob import glob from os import listdir @@ -39,30 +40,27 @@ class Test_yang_models: def initTest(self): self.defaultYANGFailure = { 'Must': ['Must condition', 'not satisfied'], - 'InvalidValue': ['Invalid value'], # libyang3: ['Invalid', 'value', 'Data path'] - 'LeafRef': ['Leafref', 'non-existing'], #libyang3: ['Invalid leafref', 'no target instance'] + 'InvalidValue': ['Invalid', 'value', 'Data path'], + 'LeafRef': ['Invalid leafref', 'no target instance'], 'When': ['When condition', 'not satisfied'], - 'Pattern': ['pattern', 'does not satisfy'], #libyang3: ['pattern', 'Unsatisfied pattern'] - 'Mandatory': ['required element', 'Missing'], #libyang3: ['Mandatory node', 'does not exist'] + 'Pattern': ['pattern', 'Unsatisfied pattern'], + 'Mandatory': ['Mandatory node', 'does not exist'], 'Verify': ['verified'], - 'Range': ['does not satisfy', 'range'], #libyang3: ['Unsatisfied range'] + 'Range': ['Unsatisfied range'], 'MinElements': ['Too few'], 'MaxElements': ['Too many'], - 'UnknownElement': ['Unknown element'], + 'UnknownElement': ['not found as a child'], 'None': [], -# New keys are needed for libyang3's messages which are different. Go -# ahead and add them now with the libyang1 values (which are duplicates -# of the above). This will make migrating to libyang3 easier with less -# code review. - 'Length': ['does not satisfy', 'range'], # libyang3: ['Unsatisfied length'] - 'DecimalFractionExceed': ['Invalid value'], # libyang3: ['Value', 'exceeds defined number', 'fraction digits'] - 'Bounds': ['Invalid value'], #libyang3 ['Value', 'out of type', 'min/max bounds'], - 'ListKey': ['Missing required element'], #libyang3 ['List instance is missing its key'] - 'DateTime': ['pattern', 'does not satisfy'], #libyang3: ['Invalid date-and-time'] - 'IPv4': ['pattern', 'does not satisfy'], #libyang3 ['Failed to convert IPv4 address'], + 'Length': ['Unsatisfied length'], + 'DecimalFractionExceed': ['Value', 'exceeds defined number', 'fraction digits'], + 'Bounds': ['Value', 'out of type', 'min/max bounds'], + 'ListKey': ['List instance is missing its key'], + 'DateTime': ['Invalid date-and-time'], + 'IPv4': ['Failed to convert IPv4 address'], } self.ExceptionTests = { } + self.FailedTests = [] for test_file in glob("./tests/yang_model_tests/tests/*.json"): try: @@ -122,11 +120,12 @@ def loadYangModel(self, yangDir): # load yang modules for file in yangFiles: log.debug(file) - m = self.ctx.parse_module_path(file, ly.LYS_IN_YANG) - if m is not None: - log.info("module: {} is loaded successfully".format(m.name())) - else: - log.info("Could not load module: {}".format(file)) + with open(file, 'r') as f: + m = self.ctx.parse_module_file(f, "yang") + if m is not None: + log.info("module: {} is loaded successfully".format(m.name())) + else: + log.info("Could not load module: {}".format(file)) except Exception as e: printExceptionDetails() @@ -178,26 +177,35 @@ def logStartTest(self, desc): """ def loadConfigData(self, jInput, verify=None): s = "" + node = None + try: + node = self.ctx.parse_data_mem(jInput, "json", strict=True, no_state=True, json_string_datatypes=True) + except Exception as e: + printExceptionDetails() + s = str(e) + log.info(s) + return s + try: - node = self.ctx.parse_data_mem(jInput, ly.LYD_JSON, \ - ly.LYD_OPT_CONFIG | ly.LYD_OPT_STRICT) # verify the data tree if asked if verify is not None: xpath = verify['xpath'] log.info("Verify xpath: {}".format(xpath)) - set = node.find_path(xpath) - for dnode in set.data(): + nodes = node.find_all(xpath) + for dnode in nodes: if (xpath == dnode.path()): log.info("Verify dnode: {}".format(dnode.path())) - data = dnode.print_mem(ly.LYD_JSON, ly.LYP_WITHSIBLINGS \ - | ly.LYP_FORMAT | ly.LYP_WD_ALL) + data = dnode.print_mem("json", with_siblings=True, pretty=True, include_implicit_defaults=True) data = json.loads(data) - log.info("Verify data: {}".format(data)) + log.info("Verify path value {} is {} in {}".format(verify['key'], verify['value'], data)) + assert (verify['key'] in data) assert (data[verify['key']] == verify['value']) s = 'verified' except Exception as e: - s = str(e) - log.info(s) + printExceptionDetails() + + node.free() + return s """ @@ -221,9 +229,12 @@ def runExceptionTest(self, test): log.info(desc + " Passed\n") return PASS else: - raise Exception("Mismatch {} and {}".format(eStr, s)) + errstr = "{}: Mismatch {} and {}".format(test, eStr, s) + self.FailedTests.append(errstr) + raise Exception(errstr) except Exception as e: printExceptionDetails() + log.info(desc + " Failed\n") return FAIL @@ -253,7 +264,9 @@ def runVlanSpecialTest(self, test): log.debug(jInput) s = self.loadConfigData(json.dumps(jInput)) if s!="": - raise Exception("{} in not empty".format(s)) + errstr="{}[{}]: {} in not empty".format(test,i,s) + self.FailedTests.append(errstr) + raise Exception(errstr) return PASS except Exception as e: printExceptionDetails() @@ -282,6 +295,17 @@ def test_run_tests(self): ret = FAIL * len(self.tests) printExceptionDetails() + if len(self.FailedTests): + print("{} Failures:".format(len(self.FailedTests))) + log.error("{} Failures:".format(len(self.FailedTests))) + for x in self.FailedTests: + print(x) + log.error(x) + + if self.ctx: + self.ctx.destroy() + self.ctx = None + assert ret == 0 return # End of Class diff --git a/src/sonic-yang-models/yang-models/sonic-bgp-allowed-prefix.yang b/src/sonic-yang-models/yang-models/sonic-bgp-allowed-prefix.yang index ace3ddc2f1d0..02ab19474264 100644 --- a/src/sonic-yang-models/yang-models/sonic-bgp-allowed-prefix.yang +++ b/src/sonic-yang-models/yang-models/sonic-bgp-allowed-prefix.yang @@ -96,11 +96,13 @@ module sonic-bgp-allowed-prefix { leaf-list prefixes_v4 { type bgp-allowed-ipv4-prefix; + ordered-by user; description "BGP V4 allowed prefix list"; } leaf-list prefixes_v6 { type bgp-allowed-ipv6-prefix; + ordered-by user; description "BGP V6 allowed prefix list"; } } @@ -139,11 +141,13 @@ module sonic-bgp-allowed-prefix { leaf-list prefixes_v4 { type bgp-allowed-ipv4-prefix; + ordered-by user; description "BGP V4 allowed prefix list"; } leaf-list prefixes_v6 { type bgp-allowed-ipv6-prefix; + ordered-by user; description "BGP V6 allowed prefix list"; } } @@ -175,11 +179,13 @@ module sonic-bgp-allowed-prefix { leaf-list prefixes_v4 { type bgp-allowed-ipv4-prefix; + ordered-by user; description "BGP V4 allowed prefix list"; } leaf-list prefixes_v6 { type bgp-allowed-ipv6-prefix; + ordered-by user; description "BGP V6 allowed prefix list"; } } @@ -223,11 +229,13 @@ module sonic-bgp-allowed-prefix { leaf-list prefixes_v4 { type bgp-allowed-ipv4-prefix; + ordered-by user; description "BGP V4 allowed prefix list"; } leaf-list prefixes_v6 { type bgp-allowed-ipv6-prefix; + ordered-by user; description "BGP V6 allowed prefix list"; } } diff --git a/src/sonic-yang-models/yang-models/sonic-bgp-common.yang b/src/sonic-yang-models/yang-models/sonic-bgp-common.yang index e035c1be261c..84c6a8ff7457 100644 --- a/src/sonic-yang-models/yang-models/sonic-bgp-common.yang +++ b/src/sonic-yang-models/yang-models/sonic-bgp-common.yang @@ -386,6 +386,7 @@ module sonic-bgp-common { type leafref { path "/rmap:sonic-route-map/rmap:ROUTE_MAP_SET/rmap:ROUTE_MAP_SET_LIST/rmap:name"; } + ordered-by user; description "Route-map filter for incoming routes"; max-elements 1; } @@ -394,6 +395,7 @@ module sonic-bgp-common { type leafref { path "/rmap:sonic-route-map/rmap:ROUTE_MAP_SET/rmap:ROUTE_MAP_SET_LIST/rmap:name"; } + ordered-by user; description "Route-map filter for outgoing routes"; max-elements 1; } diff --git a/src/sonic-yang-models/yang-models/sonic-bgp-global.yang b/src/sonic-yang-models/yang-models/sonic-bgp-global.yang index d717803184fc..efd4d5515579 100644 --- a/src/sonic-yang-models/yang-models/sonic-bgp-global.yang +++ b/src/sonic-yang-models/yang-models/sonic-bgp-global.yang @@ -304,6 +304,7 @@ module sonic-bgp-global { type uint32 { range "1..4294967295"; } + ordered-by user; description "Peer ASs in BGP confederation"; } diff --git a/src/sonic-yang-models/yang-models/sonic-bgp-peerrange.yang b/src/sonic-yang-models/yang-models/sonic-bgp-peerrange.yang index 01348096ccab..6e7a098a6c3b 100644 --- a/src/sonic-yang-models/yang-models/sonic-bgp-peerrange.yang +++ b/src/sonic-yang-models/yang-models/sonic-bgp-peerrange.yang @@ -56,6 +56,7 @@ module sonic-bgp-peerrange { leaf-list ip_range { type stypes:sonic-ip-prefix; + ordered-by user; description "A range of addresses"; } } diff --git a/src/sonic-yang-models/yang-models/sonic-bgp-sentinel.yang b/src/sonic-yang-models/yang-models/sonic-bgp-sentinel.yang index 747aadd2f89e..c9ce07f8fb9b 100644 --- a/src/sonic-yang-models/yang-models/sonic-bgp-sentinel.yang +++ b/src/sonic-yang-models/yang-models/sonic-bgp-sentinel.yang @@ -50,6 +50,7 @@ module sonic-bgp-sentinel { leaf-list ip_range { type stypes:sonic-ip-prefix; + ordered-by user; description "A range of addresses"; } } diff --git a/src/sonic-yang-models/yang-models/sonic-buffer-port-egress-profile-list.yang b/src/sonic-yang-models/yang-models/sonic-buffer-port-egress-profile-list.yang index 6c1a75fbfd30..45c1584d0e90 100644 --- a/src/sonic-yang-models/yang-models/sonic-buffer-port-egress-profile-list.yang +++ b/src/sonic-yang-models/yang-models/sonic-buffer-port-egress-profile-list.yang @@ -46,6 +46,7 @@ module sonic-buffer-port-egress-profile-list { type leafref { path "/bpf:sonic-buffer-profile/bpf:BUFFER_PROFILE/bpf:BUFFER_PROFILE_LIST/bpf:name"; } + ordered-by user; description "a list of references to BUFFER_PROFILE_TABLE object for a port"; } diff --git a/src/sonic-yang-models/yang-models/sonic-buffer-port-ingress-profile-list.yang b/src/sonic-yang-models/yang-models/sonic-buffer-port-ingress-profile-list.yang index 01a7f6bb6e21..0094ac73480c 100644 --- a/src/sonic-yang-models/yang-models/sonic-buffer-port-ingress-profile-list.yang +++ b/src/sonic-yang-models/yang-models/sonic-buffer-port-ingress-profile-list.yang @@ -46,6 +46,7 @@ module sonic-buffer-port-ingress-profile-list { type leafref { path "/bpf:sonic-buffer-profile/bpf:BUFFER_PROFILE/bpf:BUFFER_PROFILE_LIST/bpf:name"; } + ordered-by user; description "a list of references to BUFFER_PROFILE_TABLE object for a port"; } diff --git a/src/sonic-yang-models/yang-models/sonic-dash.yang b/src/sonic-yang-models/yang-models/sonic-dash.yang index 806a05e881f3..0c6574865f9b 100644 --- a/src/sonic-yang-models/yang-models/sonic-dash.yang +++ b/src/sonic-yang-models/yang-models/sonic-dash.yang @@ -64,6 +64,7 @@ module sonic-dash { leaf-list address_spaces { type stypes:sonic-ip-prefix; + ordered-by user; } } /* end of list DASH_VNET_LIST */ @@ -270,14 +271,17 @@ module sonic-dash { leaf-list ip_protocol { description "IP Protocol (tcp or udp or icmp etc)"; type stypes:ip-protocol-type; + ordered-by user; } leaf-list src_addr { type stypes:sonic-ip-prefix; + ordered-by user; } leaf-list dst_addr { type stypes:sonic-ip-prefix; + ordered-by user; } leaf-list src_port { @@ -285,6 +289,7 @@ module sonic-dash { type string { pattern '([0-9]{1,4}|[0-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-2][0-9]{2}|[6][5][3][0-5]{2}|[6][5][3][6][0-5])-([0-9]{1,4}|[0-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-2][0-9]{2}|[6][5][3][0-5]{2}|[6][5][3][6][0-5])'; } + ordered-by user; } leaf-list dst_port { @@ -292,6 +297,7 @@ module sonic-dash { type string { pattern '([0-9]{1,4}|[0-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-2][0-9]{2}|[6][5][3][0-5]{2}|[6][5][3][6][0-5])-([0-9]{1,4}|[0-5][0-9]{4}|[6][0-4][0-9]{3}|[6][5][0-2][0-9]{2}|[6][5][3][0-5]{2}|[6][5][3][6][0-5])'; } + ordered-by user; } } /* end of list DASH_ACL_RULE_LIST */ diff --git a/src/sonic-yang-models/yang-models/sonic-device_metadata.yang b/src/sonic-yang-models/yang-models/sonic-device_metadata.yang index 7a423b54a6de..34a5e959d642 100644 --- a/src/sonic-yang-models/yang-models/sonic-device_metadata.yang +++ b/src/sonic-yang-models/yang-models/sonic-device_metadata.yang @@ -34,7 +34,7 @@ module sonic-device_metadata { description "DEVICE_METADATA part of config_db.json"; - container localhost{ + container localhost { leaf hwsku { type stypes:hwsku; @@ -47,6 +47,20 @@ module sonic-device_metadata { description "asic_id is unique identifier of the asic used by SAI for initialization."; } + leaf hostname { + type stypes:hostname; + } + + leaf platform { + type string { + length 1..255; + } + } + + leaf mac { + type yang:mac-address; + } + leaf default_bgp_status { type enumeration { enum up; @@ -67,20 +81,6 @@ module sonic-device_metadata { default "unified"; } - leaf hostname { - type stypes:hostname; - } - - leaf platform { - type string { - length 1..255; - } - } - - leaf mac { - type yang:mac-address; - } - leaf default_pfcwd_status { type enumeration { enum disable; @@ -257,6 +257,7 @@ module sonic-device_metadata { leaf-list supporting_bulk_counter_groups { type string; + ordered-by user; description "This field contains a list of counter groups that support bulk operation."; } diff --git a/src/sonic-yang-models/yang-models/sonic-dhcp-server-ipv4.yang b/src/sonic-yang-models/yang-models/sonic-dhcp-server-ipv4.yang index d3aa89862686..fd1e4233deee 100644 --- a/src/sonic-yang-models/yang-models/sonic-dhcp-server-ipv4.yang +++ b/src/sonic-yang-models/yang-models/sonic-dhcp-server-ipv4.yang @@ -96,6 +96,7 @@ module sonic-dhcp-server-ipv4 { type leafref { path "/dhcp-server-ipv4:sonic-dhcp-server-ipv4/dhcp-server-ipv4:DHCP_SERVER_IPV4_CUSTOMIZED_OPTIONS/dhcp-server-ipv4:DHCP_SERVER_IPV4_CUSTOMIZED_OPTIONS_LIST/dhcp-server-ipv4:name"; } + ordered-by user; } leaf state { @@ -186,6 +187,7 @@ module sonic-dhcp-server-ipv4 { leaf-list range { description "Range of IPs"; type inet:ipv4-address; + ordered-by user; } must "((count(range) <= 2) and (count(range) >= 1))"; @@ -232,6 +234,7 @@ module sonic-dhcp-server-ipv4 { error-message "Statement of 'ips' and 'ranges' cannot both exist"; } type inet:ipv4-address; + ordered-by user; } leaf-list ranges { @@ -242,6 +245,7 @@ module sonic-dhcp-server-ipv4 { type leafref { path "/dhcp-server-ipv4:sonic-dhcp-server-ipv4/dhcp-server-ipv4:DHCP_SERVER_IPV4_RANGE/dhcp-server-ipv4:DHCP_SERVER_IPV4_RANGE_LIST/dhcp-server-ipv4:name"; } + ordered-by user; } } /* end of DHCP_SERVER_IPV4_PORT_LIST */ diff --git a/src/sonic-yang-models/yang-models/sonic-dhcpv6-relay.yang b/src/sonic-yang-models/yang-models/sonic-dhcpv6-relay.yang index cd32ca96662f..eae5ec5acdc1 100644 --- a/src/sonic-yang-models/yang-models/sonic-dhcpv6-relay.yang +++ b/src/sonic-yang-models/yang-models/sonic-dhcpv6-relay.yang @@ -37,6 +37,7 @@ module sonic-dhcpv6-relay { leaf-list dhcpv6_servers { description "Configure the dhcp v6 servers"; type inet:ipv6-address; + ordered-by user; } leaf rfc6939_support { diff --git a/src/sonic-yang-models/yang-models/sonic-hash.yang b/src/sonic-yang-models/yang-models/sonic-hash.yang index d95f82406927..45f0f9b59167 100644 --- a/src/sonic-yang-models/yang-models/sonic-hash.yang +++ b/src/sonic-yang-models/yang-models/sonic-hash.yang @@ -54,11 +54,13 @@ module sonic-hash { leaf-list ecmp_hash { description "Hash fields for hashing packets going through ECMP"; type hash:hash-field; + ordered-by user; } leaf-list lag_hash { description "Hash fields for hashing packets going through LAG"; type hash:hash-field; + ordered-by user; } leaf ecmp_hash_algorithm { diff --git a/src/sonic-yang-models/yang-models/sonic-mgmt_interface.yang b/src/sonic-yang-models/yang-models/sonic-mgmt_interface.yang index d45c40327031..aec3f85b2110 100644 --- a/src/sonic-yang-models/yang-models/sonic-mgmt_interface.yang +++ b/src/sonic-yang-models/yang-models/sonic-mgmt_interface.yang @@ -55,7 +55,7 @@ module sonic-mgmt_interface { type stypes:sonic-ip-prefix; type inet:ip-address; } - + ordered-by user; description "This configuration allows addtional routes to be added to default VRF table or mgmt VRF table, based on if Management VRF is configured. diff --git a/src/sonic-yang-models/yang-models/sonic-ntp.yang b/src/sonic-yang-models/yang-models/sonic-ntp.yang index 2591f8c7a58b..dce4cd4675b9 100644 --- a/src/sonic-yang-models/yang-models/sonic-ntp.yang +++ b/src/sonic-yang-models/yang-models/sonic-ntp.yang @@ -109,7 +109,7 @@ module sonic-ntp { pattern 'eth0'; } } - + ordered-by user; description "This is the interface whose IP address is used as the source IP address for generating NTP traffic. User is required to make sure that the NTP server diff --git a/src/sonic-yang-models/yang-models/sonic-pbh.yang b/src/sonic-yang-models/yang-models/sonic-pbh.yang index d0c395d4e6a3..af754972f476 100644 --- a/src/sonic-yang-models/yang-models/sonic-pbh.yang +++ b/src/sonic-yang-models/yang-models/sonic-pbh.yang @@ -120,6 +120,7 @@ module sonic-pbh { type leafref { path "/pbh:sonic-pbh/pbh:PBH_HASH_FIELD/pbh:PBH_HASH_FIELD_LIST/pbh:hash_field_name"; } + ordered-by user; } } @@ -248,6 +249,7 @@ module sonic-pbh { path "/lag:sonic-portchannel/lag:PORTCHANNEL/lag:PORTCHANNEL_LIST/lag:name"; } } + ordered-by user; } leaf description { diff --git a/src/sonic-yang-models/yang-models/sonic-port.yang b/src/sonic-yang-models/yang-models/sonic-port.yang index 528f661b8fcf..d166c638918e 100644 --- a/src/sonic-yang-models/yang-models/sonic-port.yang +++ b/src/sonic-yang-models/yang-models/sonic-port.yang @@ -136,6 +136,7 @@ module sonic-port{ pattern "all"; } } + ordered-by user; } must "(count(adv_speeds[text()='all']) = 0) or (count(adv_speeds) = 1)"; @@ -155,6 +156,7 @@ module sonic-port{ pattern "all"; } } + ordered-by user; } must "(count(adv_interface_types[text()='all']) = 0) or (count(adv_interface_types) = 1)"; diff --git a/src/sonic-yang-models/yang-models/sonic-route-common.yang b/src/sonic-yang-models/yang-models/sonic-route-common.yang index df0eae8f4ea9..5f16138611de 100644 --- a/src/sonic-yang-models/yang-models/sonic-route-common.yang +++ b/src/sonic-yang-models/yang-models/sonic-route-common.yang @@ -61,6 +61,7 @@ module sonic-route-common { type leafref { path "/rmap:sonic-route-map/rmap:ROUTE_MAP_SET/rmap:ROUTE_MAP_SET_LIST/rmap:name"; } + ordered-by user; max-elements 1; description "Router filter to apply while redistributing the routes from another protocol."; } diff --git a/src/sonic-yang-models/yang-models/sonic-route-map.yang b/src/sonic-yang-models/yang-models/sonic-route-map.yang index 3a5d1f256fd3..fd88227a3bb7 100644 --- a/src/sonic-yang-models/yang-models/sonic-route-map.yang +++ b/src/sonic-yang-models/yang-models/sonic-route-map.yang @@ -210,6 +210,7 @@ module sonic-route-map { pattern 'Vlan([0-9]{1,3}|[1-3][0-9]{3}|[4][0][0-8][0-9]|[4][0][9][0-4])'; } } + ordered-by user; description "IP addresse or interface for match operation."; max-elements 1; @@ -217,6 +218,7 @@ module sonic-route-map { leaf-list match_tag { type uint32; + ordered-by user; description "Value of the tag match member"; max-elements 1; @@ -326,6 +328,7 @@ module sonic-route-map { leaf-list set_community_inline { type string; + ordered-by user; description "Set community string"; } @@ -338,6 +341,7 @@ module sonic-route-map { leaf-list set_ext_community_inline { type string; + ordered-by user; description "Set extended community string"; } diff --git a/src/sonic-yang-models/yang-models/sonic-routing-policy-sets.yang b/src/sonic-yang-models/yang-models/sonic-routing-policy-sets.yang index cf469730f680..362211048034 100644 --- a/src/sonic-yang-models/yang-models/sonic-routing-policy-sets.yang +++ b/src/sonic-yang-models/yang-models/sonic-routing-policy-sets.yang @@ -150,6 +150,7 @@ module sonic-routing-policy-sets { leaf-list community_member { type string; + ordered-by user; description "members of the community set."; } @@ -190,6 +191,7 @@ module sonic-routing-policy-sets { leaf-list community_member { type string; + ordered-by user; description "members of the community set."; } @@ -214,6 +216,7 @@ module sonic-routing-policy-sets { leaf-list as_path_set_member { type string; + ordered-by user; description "AS path expression -- list of ASes in the set"; } diff --git a/src/sonic-yang-models/yang-models/sonic-suppress-asic-sdk-health-event.yang b/src/sonic-yang-models/yang-models/sonic-suppress-asic-sdk-health-event.yang index 650911cc8261..fe6cb43c16e1 100644 --- a/src/sonic-yang-models/yang-models/sonic-suppress-asic-sdk-health-event.yang +++ b/src/sonic-yang-models/yang-models/sonic-suppress-asic-sdk-health-event.yang @@ -51,6 +51,7 @@ module sonic-suppress-asic-sdk-health-event { enum cpu_hw; enum asic_hw; } + ordered-by user; description "Category of the ASIC/SDK health event to suppress"; } } diff --git a/src/sonic-yang-models/yang-models/sonic-vlan.yang b/src/sonic-yang-models/yang-models/sonic-vlan.yang index 5d6f898c768c..92ea9085e895 100644 --- a/src/sonic-yang-models/yang-models/sonic-vlan.yang +++ b/src/sonic-yang-models/yang-models/sonic-vlan.yang @@ -218,11 +218,13 @@ module sonic-vlan { leaf-list dhcp_servers { description "Configure the dhcp v4 servers"; type inet:ip-address; + ordered-by user; } leaf-list dhcpv6_servers { description "Configure the dhcp v6 servers"; type inet:ipv6-address; + ordered-by user; } leaf mtu { diff --git a/src/sonic-yang-models/yang-templates/sonic-acl.yang.j2 b/src/sonic-yang-models/yang-templates/sonic-acl.yang.j2 index f1a0629f3222..621b9ff2ca6f 100644 --- a/src/sonic-yang-models/yang-templates/sonic-acl.yang.j2 +++ b/src/sonic-yang-models/yang-templates/sonic-acl.yang.j2 @@ -302,11 +302,13 @@ module sonic-acl { leaf-list MATCHES { type string; + ordered-by user; min-elements 1; } leaf-list ACTIONS { type string; + ordered-by user; default ""; } @@ -315,6 +317,7 @@ module sonic-acl { enum PORT; enum PORTCHANNEL; } + ordered-by user; min-elements 1; } } @@ -357,6 +360,7 @@ module sonic-acl { leaf-list services { type string; + ordered-by user; } /* Validating 'services' exist if ACL type is 'CTRLPLANE' */ @@ -375,6 +379,7 @@ module sonic-acl { pattern ""; } } + ordered-by user; /* Today in SONiC, we do not delete the list once * created, instead we set to empty list. Due to that * below default values are needed. diff --git a/src/sonic-yang-models/yang-templates/sonic-policer.yang.j2 b/src/sonic-yang-models/yang-templates/sonic-policer.yang.j2 index 07b40ea742c1..0b65d2c1f4cd 100644 --- a/src/sonic-yang-models/yang-templates/sonic-policer.yang.j2 +++ b/src/sonic-yang-models/yang-templates/sonic-policer.yang.j2 @@ -66,7 +66,6 @@ module sonic-policer { error-message "cbs must be greater than or equal to cir"; } type uint64; - default 0; description "Committed burst size for the dual-rate token bucket policer. This value represents the depth of the token From e26017c3169b92d5a5b7ada8e42b13f2d50e77b2 Mon Sep 17 00:00:00 2001 From: Brad House Date: Tue, 11 Feb 2025 08:26:28 -0500 Subject: [PATCH 3/5] IGNORE THIS COMMIT: merge libyang3 step 3 (PR sonic-net#21716) --- rules/sonic-yang-mgmt-py3.mk | 6 +- src/sonic-yang-mgmt/sonic_yang.py | 363 ++++++++---------- src/sonic-yang-mgmt/sonic_yang_ext.py | 17 +- .../libyang-python-tests/config_data.json | 4 +- .../test-yang-structure.yang | 2 +- .../libyang-python-tests/test_SonicYang.json | 102 +++-- .../libyang-python-tests/test_sonic_yang.py | 20 +- 7 files changed, 260 insertions(+), 254 deletions(-) diff --git a/rules/sonic-yang-mgmt-py3.mk b/rules/sonic-yang-mgmt-py3.mk index 877fc6de3952..9d1760c05b26 100644 --- a/rules/sonic-yang-mgmt-py3.mk +++ b/rules/sonic-yang-mgmt-py3.mk @@ -3,9 +3,9 @@ SONIC_YANG_MGMT_PY3 = sonic_yang_mgmt-1.0-py3-none-any.whl $(SONIC_YANG_MGMT_PY3)_SRC_PATH = $(SRC_PATH)/sonic-yang-mgmt $(SONIC_YANG_MGMT_PY3)_PYTHON_VERSION = 3 -$(SONIC_YANG_MGMT_PY3)_DEBS_DEPENDS = $(LIBYANG) $(LIBYANG_CPP) $(LIBYANG_PY3) +$(SONIC_YANG_MGMT_PY3)_DEBS_DEPENDS = $(LIBYANG3) $(LIBYANG3_PY3) $(SONIC_YANG_MGMT_PY3)_DEPENDS = $(SONIC_YANG_MODELS_PY3) -$(SONIC_YANG_MGMT_PY3)_RDEPENDS = $(SONIC_YANG_MODELS_PY3) $(LIBYANG) \ - $(LIBYANG_CPP) $(LIBYANG_PY3) +$(SONIC_YANG_MGMT_PY3)_RDEPENDS = $(SONIC_YANG_MODELS_PY3) $(LIBYANG3) \ + $(LIBYANG3_PY3) SONIC_PYTHON_WHEELS += $(SONIC_YANG_MGMT_PY3) diff --git a/src/sonic-yang-mgmt/sonic_yang.py b/src/sonic-yang-mgmt/sonic_yang.py index 9af9217ad34b..a354ee7fad2c 100644 --- a/src/sonic-yang-mgmt/sonic_yang.py +++ b/src/sonic-yang-mgmt/sonic_yang.py @@ -1,4 +1,4 @@ -import yang as ly +import libyang as ly import syslog from json import dump @@ -12,7 +12,7 @@ """ class SonicYang(SonicYangExtMixin): - def __init__(self, yang_dir, debug=False, print_log_enabled=True, sonic_yang_options=0): + def __init__(self, yang_dir, debug=False, print_log_enabled=True): self.yang_dir = yang_dir self.ctx = None self.module = None @@ -22,10 +22,6 @@ def __init__(self, yang_dir, debug=False, print_log_enabled=True, sonic_yang_opt self.SYSLOG_IDENTIFIER = "sonic_yang" self.DEBUG = debug self.print_log_enabled = print_log_enabled - if not print_log_enabled: - # The default libyang log options are ly.LY_LOLOG|ly.LY_LOSTORE_LAST. - # Removing ly.LY_LOLOG will stop libyang from printing the logs. - ly.set_log_options(ly.LY_LOSTORE_LAST) # yang model files, need this map it to module self.yangFiles = list() @@ -48,19 +44,26 @@ def __init__(self, yang_dir, debug=False, print_log_enabled=True, sonic_yang_opt # ['PORT', 'Ethernet0', 'speed'] self.elementPath = [] try: - self.ctx = ly.Context(yang_dir, sonic_yang_options) + self.ctx = ly.Context(yang_dir) except Exception as e: self.fail(e) return def __del__(self): - pass + if self.root: + self.root.free() + self.root = None + if self.ctx: + self.ctx.destroy() + self.ctx = None def sysLog(self, debug=syslog.LOG_INFO, msg=None, doPrint=False): # log debug only if enabled if self.DEBUG == False and debug == syslog.LOG_DEBUG: return + if msg is None: + return if doPrint and self.print_log_enabled: print("{}({}):{}".format(self.SYSLOG_IDENTIFIER, debug, msg)) syslog.openlog(self.SYSLOG_IDENTIFIER) @@ -80,7 +83,8 @@ def fail(self, e): """ def _load_schema_module(self, yang_file): try: - return self.ctx.parse_module_path(yang_file, ly.LYS_IN_YANG) + with open(yang_file, 'r') as f: + return self.ctx.parse_module_file(f, "yang") except Exception as e: self.sysLog(msg="Failed to load yang module file: " + yang_file, debug=syslog.LOG_ERR, doPrint=True) self.fail(e) @@ -110,27 +114,6 @@ def _load_schema_modules(self, yang_dir): except Exception as e: self.fail(e) - """ - load_schema_modules_ctx(): load all Yang model files in the directory to context: ctx - input: yang_dir, context - returns: Exception if error, returrns context object if no error - """ - def _load_schema_modules_ctx(self, yang_dir=None): - if not yang_dir: - yang_dir = self.yang_dir - - ctx = ly.Context(yang_dir) - - py = glob(yang_dir+"/*.yang") - for file in py: - try: - ctx.parse_module_path(str(file), ly.LYS_IN_YANG) - except Exception as e: - self.sysLog(msg="Failed to parse yang module file: " + file, debug=syslog.LOG_ERR, doPrint=True) - self.fail(e) - - return ctx - """ load_data_file(): load a Yang data json file input: data_file - the full path of the yang json data file to be loaded @@ -138,7 +121,8 @@ def _load_schema_modules_ctx(self, yang_dir=None): """ def _load_data_file(self, data_file): try: - data_node = self.ctx.parse_data_path(data_file, ly.LYD_JSON, ly.LYD_OPT_CONFIG | ly.LYD_OPT_STRICT) + with open(data_file, 'r') as f: + data_node = self.ctx.parse_data_file(f, "json", no_state=True, strict=True, json_string_datatypes=True) except Exception as e: self.sysLog(msg="Failed to load data file: " + str(data_file), debug=syslog.LOG_ERR, doPrint=True) self.fail(e) @@ -169,8 +153,8 @@ def _get_module(self, module_name): returns: returns (context, root) if no error, or Exception if failed """ def _load_data_model(self, yang_dir, yang_files, data_files, output=None): - if (self.ctx is None): - self.ctx = ly.Context(yang_dir) + if not self.ctx: + raise Exception('ctx not initialized') try: self._load_schema_module_list(yang_files) @@ -197,9 +181,9 @@ def _load_data_model(self, yang_dir, yang_files, data_files, output=None): """ def _print_data_mem(self, option): if (option == "JSON"): - mem = self.root.print_mem(ly.LYD_JSON, ly.LYP_WITHSIBLINGS | ly.LYP_FORMAT) + mem = self.root.print_mem("json", with_siblings=True, pretty=True) else: - mem = self.root.print_mem(ly.LYD_XML, ly.LYP_WITHSIBLINGS | ly.LYP_FORMAT) + mem = self.root.print_mem("yang", with_siblings=True, pretty=True) return mem @@ -208,7 +192,7 @@ def _print_data_mem(self, option): input: outfile - full path of the file to save the data tree to """ def _save_data_file_json(self, outfile): - mem = self.root.print_mem(ly.LYD_JSON, ly.LYP_FORMAT) + mem = self.root.print_mem("json", pretty=True) with open(outfile, 'w') as out: dump(mem, out, indent=4) @@ -228,10 +212,9 @@ def _get_module_tree(self, module_name, format): else: if (module is not None): if (format == "XML"): - #libyang bug with format - result = module.print_mem(ly.LYD_JSON, ly.LYP_FORMAT) + result = module.print_mem("yin") else: - result = module.print_mem(ly.LYD_XML, ly.LYP_FORMAT) + result = module.print_mem("json") return result @@ -250,7 +233,7 @@ def _validate_data(self, node=None, ctx=None): ctx = self.ctx try: - node.validate(ly.LYD_OPT_CONFIG, ctx) + node.validate(no_state=True) except Exception as e: self.fail(e) @@ -314,7 +297,7 @@ def _get_parent_data_xpath(self, data_xpath): def _new_data_node(self, xpath, value): val = str(value) try: - data_node = self.root.new_path(self.ctx, xpath, val, 0, 0) + data_node = self.ctx.create_data_path(xpath, parent=self.root, value=val, update=False, force_return_value=False) except Exception as e: self.sysLog(msg="Failed to add data node for path: " + str(xpath), debug=syslog.LOG_ERR, doPrint=True) self.fail(e) @@ -330,13 +313,13 @@ def _new_data_node(self, xpath, value): """ def _find_data_node(self, data_xpath): try: - set = self.root.find_path(data_xpath) + set = self.root.find_all(data_xpath) except Exception as e: self.sysLog(msg="Failed to find data node from xpath: " + str(data_xpath), debug=syslog.LOG_ERR, doPrint=True) self.fail(e) else: if set is not None: - for data_node in set.data(): + for data_node in set: if (data_xpath == data_node.path()): return data_node return None @@ -350,17 +333,13 @@ def _find_data_node(self, data_xpath): def _find_schema_node(self, schema_xpath): try: schema_set = self.ctx.find_path(schema_xpath) - for schema_node in schema_set.schema(): - if (schema_xpath == schema_node.path()): + for schema_node in schema_set: + if (schema_xpath == schema_node.schema_path()): return schema_node except Exception as e: self.fail(e) return None - else: - for schema_node in schema_set.schema(): - if schema_xapth == schema_node.path(): - return schema_node - return None + return None """ find_data_node_schema_xpath(): find the xpath of the schema node from data xpath data xpath example: @@ -372,14 +351,14 @@ def _find_schema_node(self, schema_xpath): def _find_data_node_schema_xpath(self, data_xpath): path = "" try: - set = self.root.find_path(data_xpath) + data_node = self._find_data_node(data_xpath) + if data_node != None: + path = data_node.schema().schema_path() + + return path except Exception as e: self.fail(e) - else: - for data_node in set.data(): - if data_xpath == data_node.path(): - return data_node.schema().path() - return path + return None """ add_node(): add a node to Yang schema or data tree @@ -397,22 +376,22 @@ def _add_data_node(self, data_xpath, value): """ merge_data(): merge a data file to the existing data tree - input: yang model directory and full path of the data json file to be merged + input: full path of the data json file to be merged into the existing root returns: Exception if failed """ - def _merge_data(self, data_file, yang_dir=None): - #load all yang models to ctx - if not yang_dir: - yang_dir = self.yang_dir + def _merge_data(self, data_file): + if not self.ctx: + raise Exception('ctx not initialized') - try: - ctx = self._load_schema_modules_ctx(yang_dir) + if not self.root: + raise Exception('no root initialized') + try: #source data node - source_node = ctx.parse_data_path(str(data_file), ly.LYD_JSON, ly.LYD_OPT_CONFIG | ly.LYD_OPT_STRICT) - - #merge - self.root.merge(source_node, 0) + with open(str(data_file), 'r') as f: + source_node = self.ctx.parse_data_file(f, "json", no_state=True, strict=True, json_string_datatypes=True) + #merge + self.root.merge(source_node, destruct=True, with_siblings=True) except Exception as e: self.fail(e) @@ -421,22 +400,13 @@ def _merge_data(self, data_file, yang_dir=None): input: xpath of the schema/data node returns: True - success False - failed """ - def _deleteNode(self, xpath=None, node=None): - if node is None: - node = self._find_data_node(xpath) - - if (node): - node.unlink() - dnode = self._find_data_node(xpath) - if (dnode is None): - #deleted node not found - return True - else: - self.sysLog(msg='Could not delete Node', debug=syslog.LOG_ERR, doPrint=True) - return False - else: - self.sysLog(msg="failed to find node, xpath: " + xpath, debug=syslog.LOG_ERR, doPrint=True) + def _deleteNode(self, xpath): + dnode = self._find_data_node(xpath) + if (dnode): + dnode.unlink() + return True + self.sysLog(msg='Could not delete Node: {}'.format(xpath), debug=syslog.LOG_ERR, doPrint=True) return False """ @@ -453,9 +423,9 @@ def _find_data_node_value(self, data_xpath): self.fail(e) else: if (data_node is not None): - subtype = data_node.subtype() + subtype = data_node.schema().type() if (subtype is not None): - value = subtype.value_str() + value = data_node.value() return value return output @@ -466,7 +436,7 @@ def _find_data_node_value(self, data_xpath): """ def _set_data_node_value(self, data_xpath, value): try: - self.root.new_path(self.ctx, data_xpath, str(value), ly.LYD_ANYDATA_STRING, ly.LYD_PATH_OPT_UPDATE) + self.ctx.create_data_path(data_xpath, parent=self.root, value=str(value), update=True, force_return_value=False) except Exception as e: self.sysLog(msg="set data node value failed for xpath: " + str(data_xpath), debug=syslog.LOG_ERR, doPrint=True) self.fail(e) @@ -478,75 +448,114 @@ def _set_data_node_value(self, data_xpath, value): """ def _find_data_nodes(self, data_xpath): list = [] - node = self.root.child() + node = next(self.root.children()) try: - node_set = node.find_path(data_xpath); + node_set = node.find_all(data_xpath); except Exception as e: self.fail(e) else: if node_set is None: raise Exception('data node not found') - for data_set in node_set.data(): - data_set.schema() + for data_set in node_set: list.append(data_set.path()) return list + """ find_schema_dependencies(): find the schema dependencies from schema xpath - input: schema_xpath of the schema node + input: match_path target node path to use as a filter + match_ancestors whether or not to treat the specified path as + an ancestor rather than a full path. returns: - list of xpath of the dependencies - - Exception if schema node not found """ - def _find_schema_dependencies(self, schema_xpath): - ref_list = [] + def _find_schema_dependencies(self, match_path, match_ancestors: bool=False): + return self.ctx.find_backlinks_paths(match_path, match_ancestors=match_ancestors) + + """ + load_module_str_name(): load a module based on the provided string and return + the loaded module name. This is needed by + sonic-yang-modules to prevent direct dependency on + libyang. + input: yang_module_str yang-formatted module + returns: module name on success, exception on failure + """ + def load_module_str_name(yang_module_str): try: - schema_node = self._find_schema_node(schema_xpath) + module = self.ctx.parse_module_str(yang_module_str) except Exception as e: - self.sysLog(msg="Cound not find the schema node from xpath: " + str(schema_xpath), debug=syslog.LOG_ERR, doPrint=True) - self.fail(e) - return ref_list - - schema_node = ly.Schema_Node_Leaf(schema_node) - backlinks = schema_node.backlinks() - if backlinks.number() > 0: - for link in backlinks.schema(): - self.sysLog(msg="backlink schema: {}".format(link.path()), doPrint=True) - ref_list.append(link.path()) - return ref_list + self.fail(e); + else: + return module.name() + + return None """ - find_data_dependencies(): find the data dependencies from data xpath - input: data_xpath - xpath of data node. (Public) + find_data_dependencies(): find the data dependencies from data xpath (Public) + input: data_xpath - xpath to search. If it references an exact data node + only the references to that data node will be returned. + If a path contains multiple data nodes, then all references + to all child nodes will be returned. If set to None (or "" or "/"), + will return all references, globally. returns: - list of xpath - Exception if error """ def find_data_dependencies(self, data_xpath): ref_list = [] + required_value = None + base_dnode = None + nodes = [] node = self.root - try: - data_node = self._find_data_node(data_xpath) - except Exception as e: - self.sysLog(msg="find_data_dependencies(): Failed to find data node from xpath: {}".format(data_xapth), debug=syslog.LOG_ERR, doPrint=True) - return ref_list + if data_xpath is not None and (len(data_xpath) == 0 or data_xpath == "/"): + data_xpath = None + + if data_xpath is not None: + try: + dnode_list = list(self.root.find_all(data_xpath)) + except Exception as e: + self.sysLog(msg="find_data_dependencies(): Failed to find data node from xpath: {}".format(data_xapth), debug=syslog.LOG_ERR, doPrint=True) + return ref_list + + if len(dnode_list) == 0: + raise Exception("no data nodes found for xpath specified") + + # If exactly 1 node and its a data node, we need to match the value. + if len(dnode_list) == 1: + base_dnode = dnode_list[0] + try: + required_value = self._find_data_node_value(data_xpath) + except Exception as e: + pass + + # Get a list of all schema leafrefs pointing to this node (or these data nodes). + lreflist = [] try: - value = str(self._find_data_node_value(data_xpath)) - - schema_node = ly.Schema_Node_Leaf(data_node.schema()) - backlinks = schema_node.backlinks() - if backlinks is not None and backlinks.number() > 0: - for link in backlinks.schema(): - node_set = node.find_path(link.path()) - for data_set in node_set.data(): - data_set.schema() - casted = data_set.subtype() - if value == casted.value_str(): - ref_list.append(data_set.path()) + search_xpath = data_xpath + match_ancestors = True + if required_value is not None: + search_xpath = base_dnode.schema().schema_path() + match_ancestors = False + + lreflist = self._find_schema_dependencies(match_path=search_xpath, match_ancestors=match_ancestors) + if lreflist is None: + raise Exception("no schema backlinks found") except Exception as e: self.sysLog(msg='Failed to find node or dependencies for {}'.format(data_xpath), debug=syslog.LOG_ERR, doPrint=True) - raise SonicYangException("Failed to find node or dependencies for \ - {}\n{}".format(data_xpath, str(e))) + lreflist = [] + # Exception not expected by existing tests if backlinks not found, so don't raise. + # raise SonicYangException("Failed to find node or dependencies for {}\n{}".format(data_xpath, str(e))) + + # For all found data nodes, emit the path to the data node. If we need to + # restrict to a value, do so. + for lref in lreflist: + try: + data_set = self.root.find_all(lref) + for dnode in data_set: + if required_value is None or dnode.value() == required_value: + ref_list.append(dnode.path()) + except Exception as e: + pass return ref_list @@ -565,53 +574,13 @@ def _get_module_prefix(self, module_name): else: return module.prefix() - """ - str_to_type: map string to type of node - input: string - output: type - """ - def _str_to_type(self, type_str): - mapped_type = { - "LY_TYPE_DER":ly.LY_TYPE_DER, - "LY_TYPE_BINARY":ly.LY_TYPE_BINARY, - "LY_TYPE_BITS":ly.LY_TYPE_BITS, - "LY_TYPE_BOOL":ly.LY_TYPE_BOOL, - "LY_TYPE_DEC64":ly.LY_TYPE_DEC64, - "LY_TYPE_EMPTY":ly.LY_TYPE_EMPTY, - "LY_TYPE_ENUM":ly.LY_TYPE_ENUM, - "LY_TYPE_IDENT":ly.LY_TYPE_IDENT, - "LY_TYPE_INST":ly.LY_TYPE_INST, - "LY_TYPE_LEAFREF":ly.LY_TYPE_LEAFREF, - "LY_TYPE_STRING":ly.LY_TYPE_STRING, - "LY_TYPE_UNION":ly.LY_TYPE_UNION, - "LY_TYPE_INT8":ly.LY_TYPE_INT8, - "LY_TYPE_UINT8":ly.LY_TYPE_UINT8, - "LY_TYPE_INT16":ly.LY_TYPE_INT16, - "LY_TYPE_UINT16":ly.LY_TYPE_UINT16, - "LY_TYPE_INT32":ly.LY_TYPE_INT32, - "LY_TYPE_UINT32":ly.LY_TYPE_UINT32, - "LY_TYPE_INT64":ly.LY_TYPE_INT64, - "LY_TYPE_UINT64":ly.LY_TYPE_UINT64, - "LY_TYPE_UNKNOWN":ly.LY_TYPE_UNKNOWN - } - - if type_str not in mapped_type: - return ly.LY_TYPE_UNKNOWN - - return mapped_type[type_str] - def _get_data_type(self, schema_xpath): - try: - schema_node = self._find_schema_node(schema_xpath) - except Exception as e: - self.sysLog(msg="get_data_type(): Failed to find schema node from xpath: {}".format(schema_xpath), debug=syslog.LOG_ERR, doPrint=True) - self.fail(e) - return None + schema_node = self._find_schema_node(schema_xpath) - if (schema_node is not None): - return schema_node.subtype().type().base() + if (schema_node is None): + return None - return ly.LY_TYPE_UNKNOWN + return schema_node.type().basename() """ get_leafref_type: find the type of node that leafref references to @@ -620,16 +589,15 @@ def _get_data_type(self, schema_xpath): """ def _get_leafref_type(self, data_xpath): data_node = self._find_data_node(data_xpath) - if (data_node is not None): - subtype = data_node.subtype() - if (subtype is not None): - if data_node.schema().subtype().type().base() != ly.LY_TYPE_LEAFREF: + if data_node is not None: + if data_node.schema() is not None: + if data_node.schema().type().base() != ly.Type.LEAFREF: self.sysLog(msg="get_leafref_type() node type for data xpath: {} is not LEAFREF".format(data_xpath), debug=syslog.LOG_ERR, doPrint=True) - return ly.LY_TYPE_UNKNOWN + return None else: - return subtype.value_type() + return data_node.schema().type().leafref_type().basename() - return ly.LY_TYPE_UNKNOWN + return None """ get_leafref_path(): find the leafref path @@ -637,16 +605,16 @@ def _get_leafref_type(self, data_xpath): output: path value of the leafref node """ def _get_leafref_path(self, schema_xpath): - schema_node = self._find_schema_node(schema_xpath) - if (schema_node is not None): - subtype = schema_node.subtype() - if (subtype is not None): - if subtype.type().base() != ly.LY_TYPE_LEAFREF: - return None - else: - return subtype.type().info().lref().path() + try: + schemas = self.ctx.find_path(schema_xpath) - return None + for schema_node in schemas: + if schema_node.type().base() == ly.Type.LEAFREF: + leafref_path = schema_node.type().leafref_path() + return leafref_path + except Exception as e: + self.fail(e) + return None """ get_leafref_type_schema: find the type of node that leafref references to @@ -655,16 +623,15 @@ def _get_leafref_path(self, schema_xpath): """ def _get_leafref_type_schema(self, schema_xpath): schema_node = self._find_schema_node(schema_xpath) - if (schema_node is not None): - subtype = schema_node.subtype() - if (subtype is not None): - if subtype.type().base() != ly.LY_TYPE_LEAFREF: - return None - else: - subtype.type().info().lref().path() - target = subtype.type().info().lref().target() - target_path = target.path() - target_type = self._get_data_type(target_path) - return target_type + if (schema_node is None): + return None - return None + + subtype = schema_node.type() + if (subtype is None): + return None + + if subtype.base() != ly.Type.LEAFREF: + return None + + return subtype.leafref_type().basename() diff --git a/src/sonic-yang-mgmt/sonic_yang_ext.py b/src/sonic-yang-mgmt/sonic_yang_ext.py index bb8163265987..cbc2797d3a53 100644 --- a/src/sonic-yang-mgmt/sonic_yang_ext.py +++ b/src/sonic-yang-mgmt/sonic_yang_ext.py @@ -2,7 +2,7 @@ # class sonic_yang. A separate file is used to avoid a single large file. from __future__ import print_function -import yang as ly +import libyang as ly import syslog from json import dump, dumps, loads from xmltodict import parse @@ -86,7 +86,7 @@ def _loadJsonYangModel(self): for f in self.yangFiles: m = self.ctx.get_module(f) if m is not None: - xml = m.print_mem(ly.LYD_JSON, ly.LYP_FORMAT) + xml = m.print_mem("yin") self.yJson.append(parse(xml)) self.sysLog(msg="Parsed Json for {}".format(m.name())) except Exception as e: @@ -328,7 +328,7 @@ def _fillLeafDictUses(self, uses_s, table, leafDict): Parameters: uses_s (str): uses statement in yang module. table (str): config DB table, this table is being translated. - leafDict (dict): dict with leaf(s) information for List\Container + leafDict (dict): dict with leaf(s) information for List Container corresponding to config DB table. Returns: @@ -369,7 +369,7 @@ def _createLeafDict(self, model, table): table (str): config DB table, this table is being translated. Returns: - leafDict (dict): dict with leaf(s) information for List\Container + leafDict (dict): dict with leaf(s) information for List Container corresponding to config DB table. ''' leafDict = dict() @@ -1174,8 +1174,7 @@ def loadData(self, configdbJson, debug=False): self._xlateConfigDB(xlateFile=xlateFile) #print(self.xlateJson) self.sysLog(msg="Try to load Data in the tree") - self.root = self.ctx.parse_data_mem(dumps(self.xlateJson), \ - ly.LYD_JSON, ly.LYD_OPT_CONFIG|ly.LYD_OPT_STRICT) + self.root = self.ctx.parse_data_mem(dumps(self.xlateJson), "json", no_state=True, strict=True, json_string_datatypes=True) except Exception as e: self.root = None @@ -1195,7 +1194,7 @@ def getData(self, debug=False): revXlateFile = None if debug: revXlateFile = "revXlateConfig.json" - self.xlateJson = loads(self._print_data_mem('JSON')) + self.xlateJson = loads(self._print_data_mem("JSON")) # reset reverse xlate self.revXlateJson = dict() # result will be stored self.revXlateJson @@ -1229,13 +1228,13 @@ def deleteNode(self, xpath): # try to delete parent nodeP = self._find_parent_data_node(xpath) xpathP = nodeP.path() - if self._deleteNode(xpath=xpathP, node=nodeP) == False: + if self._deleteNode(xpath=xpathP) == False: raise Exception('_deleteNode failed') else: return True # delete non key element - if self._deleteNode(xpath=xpath, node=node) == False: + if self._deleteNode(xpath=xpath) == False: raise Exception('_deleteNode failed') except Exception as e: self.sysLog(msg="deleteNode:{}".format(str(e)), \ diff --git a/src/sonic-yang-mgmt/tests/libyang-python-tests/config_data.json b/src/sonic-yang-mgmt/tests/libyang-python-tests/config_data.json index 154ef21b494d..9da360e84d7e 100644 --- a/src/sonic-yang-mgmt/tests/libyang-python-tests/config_data.json +++ b/src/sonic-yang-mgmt/tests/libyang-python-tests/config_data.json @@ -267,7 +267,7 @@ "fc02:2000::2" ], "container-in-list-test": { - "leaf-1": true, + "leaf-1": "up", "leaf-2": "test1", "mc-case-leaf-1": 55, "mc-case-leaf-3": 1234 @@ -281,7 +281,7 @@ "2002:2001::2" ], "container-in-list-test": { - "leaf-1": false, + "leaf-1": "down", "leaf-2": "test2", "mc-case-leaf-2": 77, "mc-case-leaf-3": 4321 diff --git a/src/sonic-yang-mgmt/tests/libyang-python-tests/sample-yang-models/test-yang-structure.yang b/src/sonic-yang-mgmt/tests/libyang-python-tests/sample-yang-models/test-yang-structure.yang index 1f57ae337a47..43d4309cc3e2 100755 --- a/src/sonic-yang-mgmt/tests/libyang-python-tests/sample-yang-models/test-yang-structure.yang +++ b/src/sonic-yang-mgmt/tests/libyang-python-tests/sample-yang-models/test-yang-structure.yang @@ -45,7 +45,7 @@ module test-yang-structure { leaf leaf-1 { description "test leaf in container"; type string { - pattern "false|true"; + pattern "down|up"; } } diff --git a/src/sonic-yang-mgmt/tests/libyang-python-tests/test_SonicYang.json b/src/sonic-yang-mgmt/tests/libyang-python-tests/test_SonicYang.json index 2376c357b757..eddaf49f8b91 100644 --- a/src/sonic-yang-mgmt/tests/libyang-python-tests/test_SonicYang.json +++ b/src/sonic-yang-mgmt/tests/libyang-python-tests/test_SonicYang.json @@ -25,25 +25,25 @@ ], "data_type" : [ { - "data_type" : "LY_TYPE_STRING", - "xpath" : "/test-port:port/test-port:PORT/test-port:PORT_LIST/test-port:port_name" + "data_type" : "string", + "xpath" : "/test-port:port/PORT/PORT_LIST/port_name" }, { - "data_type" : "LY_TYPE_LEAFREF", - "xpath" : "/test-vlan:vlan/test-vlan:VLAN_INTERFACE/test-vlan:VLAN_INTERFACE_LIST/test-vlan:vlanid" + "data_type" : "leafref", + "xpath" : "/test-vlan:vlan/VLAN_INTERFACE/VLAN_INTERFACE_LIST/vlanid" } ], "delete_nodes" : [ { - "valid" : "False", + "valid" : false, "xpath" : "/test-port:port/PORT/PORT_LIST[port_name='Ethernet10']/speed" }, { - "valid" : "True", + "valid" : true, "xpath" : "/test-port:port/PORT/PORT_LIST[port_name='Ethernet9']/mtu" }, { - "valid" : "False", + "valid" : false, "xpath" : "/test-port:port/PORT/PORT_LIST[port_name='Ethernet20']/mtu" } ], @@ -56,6 +56,52 @@ ], "xpath" : "/test-port:port/PORT/PORT_LIST[port_name='Ethernet8']/port_name" }, + { + "dependencies" : [ + "/test-acl:acl/ACL_RULE/ACL_RULE_LIST[ACL_TABLE_NAME='PACL-V6'][RULE_NAME='Rule_20']/ACL_TABLE_NAME", + "/test-acl:acl/ACL_RULE/ACL_RULE_LIST[ACL_TABLE_NAME='PACL-test'][RULE_NAME='rule_20']/ACL_TABLE_NAME", + "/test-acl:acl/ACL_RULE/ACL_RULE_LIST[ACL_TABLE_NAME='PACL-V4'][RULE_NAME='Rule_20']/ACL_TABLE_NAME", + "/test-acl:acl/ACL_RULE/ACL_RULE_LIST[ACL_TABLE_NAME='PACL-V4'][RULE_NAME='Rule_40']/ACL_TABLE_NAME" + ], + "xpath" : "/test-acl:acl/ACL_TABLE" + }, + { + "dependencies" : [ + "/test-acl:acl/ACL_TABLE/ACL_TABLE_LIST[ACL_TABLE_NAME='PACL-V6']/ports[.='Ethernet8']", + "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='111'][port='Ethernet2']/port", + "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='111'][port='Ethernet3']/vlanid", + "/test-vlan:vlan/VLAN_INTERFACE/VLAN_INTERFACE_LIST[vlanid='555'][ip-prefix='fe80::/10']/vlanid", + "/test-interface:interface/INTERFACE/INTERFACE_LIST[interface='Ethernet8'][ip-prefix='10.1.1.64/26']/interface", + "/test-vlan:vlan/VLAN_INTERFACE/VLAN_INTERFACE_LIST[vlanid='111'][ip-prefix='2000:f500:45:6709::/64']/vlanid", + "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='111'][port='Ethernet5']/vlanid", + "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='111'][port='Ethernet1']/port", + "/test-acl:acl/ACL_TABLE/ACL_TABLE_LIST[ACL_TABLE_NAME='PACL-V4']/ports[.='Ethernet0']", + "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='111'][port='Ethernet6']/port", + "/test-acl:acl/ACL_TABLE/ACL_TABLE_LIST[ACL_TABLE_NAME='PACL-V4']/ports[.='Ethernet2']", + "/test-acl:acl/ACL_TABLE/ACL_TABLE_LIST[ACL_TABLE_NAME='PACL-V6']/ports[.='Ethernet7']", + "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='111'][port='Ethernet3']/port", + "/test-interface:interface/INTERFACE/INTERFACE_LIST[interface='Ethernet8'][ip-prefix='2000:f500:40:a749::/126']/interface", + "/test-acl:acl/ACL_RULE/ACL_RULE_LIST[ACL_TABLE_NAME='PACL-test'][RULE_NAME='rule_20']/ACL_TABLE_NAME", + "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='111'][port='Ethernet0']/port", + "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='111'][port='Ethernet5']/port", + "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='111'][port='Ethernet1']/vlanid", + "/test-vlan:vlan/VLAN_INTERFACE/VLAN_INTERFACE_LIST[vlanid='111'][ip-prefix='fe80::/10']/vlanid", + "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='111'][port='Ethernet4']/port", + "/test-acl:acl/ACL_RULE/ACL_RULE_LIST[ACL_TABLE_NAME='PACL-V4'][RULE_NAME='Rule_20']/ACL_TABLE_NAME", + "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='111'][port='Ethernet2']/vlanid", + "/test-acl:acl/ACL_TABLE/ACL_TABLE_LIST[ACL_TABLE_NAME='PACL-V6']/ports[.='Ethernet9']", + "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='111'][port='Ethernet6']/vlanid", + "/test-acl:acl/ACL_RULE/ACL_RULE_LIST[ACL_TABLE_NAME='PACL-V4'][RULE_NAME='Rule_40']/ACL_TABLE_NAME", + "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='111'][port='Ethernet0']/vlanid", + "/test-acl:acl/ACL_RULE/ACL_RULE_LIST[ACL_TABLE_NAME='PACL-V6'][RULE_NAME='Rule_20']/ACL_TABLE_NAME", + "/test-vlan:vlan/VLAN_INTERFACE/VLAN_INTERFACE_LIST[vlanid='111'][ip-prefix='10.1.1.64/26']/vlanid", + "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='111'][port='Ethernet4']/vlanid", + "/test-acl:acl/ACL_TABLE/ACL_TABLE_LIST[ACL_TABLE_NAME='PACL-V4']/ports[.='Ethernet1']", + "/test-vlan:vlan/VLAN_INTERFACE/VLAN_INTERFACE_LIST[vlanid='555'][ip-prefix='2000:f500:41:4e9::/64']/vlanid", + "/test-vlan:vlan/VLAN_INTERFACE/VLAN_INTERFACE_LIST[vlanid='555'][ip-prefix='10.1.5.64/26']/vlanid" + ], + "xpath" : "/" + }, { "dependencies" : [], "xpath" : "/test-port:port/PORT/PORT_LIST[port_name='Ethernet8']/alias" @@ -67,11 +113,11 @@ "xpath" : "/test-vlan:vlan/test-vlan:VLAN_INTERFACE/test-vlan:VLAN_INTERFACE_LIST/test-vlan:vlanid" }, { - "leafref_path" : "/test-port:port/test-port:PORT/test-port:PORT_LIST/test-port:port_name", + "leafref_path" : "/port:port/port:PORT/port:PORT_LIST/port:port_name", "xpath" : "/test-interface:interface/test-interface:INTERFACE/test-interface:INTERFACE_LIST/test-interface:interface" }, { - "leafref_path" : "/test-port:port/test-port:PORT/test-port:PORT_LIST/test-port:port_name", + "leafref_path" : "/port:port/port:PORT/port:PORT_LIST/port:port_name", "xpath" : "/test-vlan:vlan/test-vlan:VLAN_MEMBER/test-vlan:VLAN_MEMBER_LIST/test-vlan:port" }, { @@ -81,38 +127,38 @@ ], "leafref_type" : [ { - "data_type" : "LY_TYPE_UINT16", + "data_type" : "uint16", "xpath" : "/test-vlan:vlan/VLAN_INTERFACE/VLAN_INTERFACE_LIST[vlanid='111'][ip-prefix='2000:f500:45:6709::/64']/vlanid" }, { - "data_type" : "LY_TYPE_STRING", + "data_type" : "string", "xpath" : "/test-interface:interface/INTERFACE/INTERFACE_LIST[interface='Ethernet8'][ip-prefix='2000:f500:40:a749::/126']/interface" }, { - "data_type" : "LY_TYPE_STRING", + "data_type" : "string", "xpath" : "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='111'][port='Ethernet0']/port" }, { - "data_type" : "LY_TYPE_UINT16", + "data_type" : "uint16", "xpath" : "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST[vlanid='111'][port='Ethernet0']/vlanid" } ], "leafref_type_schema" : [ { - "data_type" : "LY_TYPE_UINT16", - "xpath" : "/test-vlan:vlan/test-vlan:VLAN_INTERFACE/test-vlan:VLAN_INTERFACE_LIST/test-vlan:vlanid" + "data_type" : "uint16", + "xpath" : "/test-vlan:vlan/VLAN_INTERFACE/VLAN_INTERFACE_LIST/vlanid" }, { - "data_type" : "LY_TYPE_STRING", - "xpath" : "/test-interface:interface/test-interface:INTERFACE/test-interface:INTERFACE_LIST/test-interface:interface" + "data_type" : "string", + "xpath" : "/test-interface:interface/INTERFACE/INTERFACE_LIST/interface" }, { - "data_type" : "LY_TYPE_STRING", - "xpath" : "/test-vlan:vlan/test-vlan:VLAN_MEMBER/test-vlan:VLAN_MEMBER_LIST/test-vlan:port" + "data_type" : "string", + "xpath" : "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST/port" }, { - "data_type" : "LY_TYPE_UINT16", - "xpath" : "/test-vlan:vlan/test-vlan:VLAN_MEMBER/test-vlan:VLAN_MEMBER_LIST/test-vlan:vlanid" + "data_type" : "uint16", + "xpath" : "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST/vlanid" } ], "members" : [ @@ -257,21 +303,21 @@ "schema_dependencies" : [ { "schema_dependencies" : [ - "/test-acl:acl/test-acl:ACL_TABLE/test-acl:ACL_TABLE_LIST/test-acl:ports", - "/test-portchannel:portchannel/test-portchannel:PORTCHANNEL/test-portchannel:PORTCHANNEL_LIST/test-portchannel:members", - "/test-interface:interface/test-interface:INTERFACE/test-interface:INTERFACE_LIST/test-interface:interface", - "/test-vlan:vlan/test-vlan:VLAN_MEMBER/test-vlan:VLAN_MEMBER_LIST/test-vlan:port" + "/test-acl:acl/ACL_TABLE/ACL_TABLE_LIST/ports", + "/test-portchannel:portchannel/PORTCHANNEL/PORTCHANNEL_LIST/members", + "/test-interface:interface/INTERFACE/INTERFACE_LIST/interface", + "/test-vlan:vlan/VLAN_MEMBER/VLAN_MEMBER_LIST/port" ], - "xpath" : "/test-port:port/test-port:PORT/test-port:PORT_LIST/test-port:port_name" + "xpath" : "/test-port:port/PORT/PORT_LIST/port_name" } ], "schema_nodes" : [ { - "value" : "/test-vlan:vlan/test-vlan:VLAN_INTERFACE/test-vlan:VLAN_INTERFACE_LIST/test-vlan:family", + "value" : "/test-vlan:vlan/VLAN_INTERFACE/VLAN_INTERFACE_LIST/family", "xpath" : "/test-vlan:vlan/VLAN_INTERFACE/VLAN_INTERFACE_LIST[vlanid='111'][ip-prefix='10.1.1.64/26']/family" }, { - "value" : "/test-port:port/test-port:PORT/test-port:PORT_LIST/test-port:speed", + "value" : "/test-port:port/PORT/PORT_LIST/speed", "xpath" : "/test-port:port/PORT/PORT_LIST[port_name='Ethernet9']/speed" } ], diff --git a/src/sonic-yang-mgmt/tests/libyang-python-tests/test_sonic_yang.py b/src/sonic-yang-mgmt/tests/libyang-python-tests/test_sonic_yang.py index 86b27ef174e5..c8f76a1f2088 100644 --- a/src/sonic-yang-mgmt/tests/libyang-python-tests/test_sonic_yang.py +++ b/src/sonic-yang-mgmt/tests/libyang-python-tests/test_sonic_yang.py @@ -153,8 +153,6 @@ def test_find_data_node_value(self, data, yang_s): for node in data['node_values']: xpath = str(node['xpath']) value = str(node['value']) - print(xpath) - print(value) val = yang_s._find_data_node_value(xpath) assert str(val) == str(value) @@ -162,7 +160,8 @@ def test_find_data_node_value(self, data, yang_s): def test_delete_node(self, data, yang_s): for node in data['delete_nodes']: xpath = str(node['xpath']) - yang_s._deleteNode(xpath) + rv = yang_s._deleteNode(xpath) + assert rv == node['valid'] #test set node's value def test_set_datanode_value(self, data, yang_s): @@ -218,8 +217,7 @@ def test_find_schema_dependencies(self, yang_s, data): def test_merge_data_tree(self, data, yang_s): data_merge_file = data['data_merge_file'] yang_dir = str(data['yang_dir']) - yang_s._merge_data(data_merge_file, yang_dir) - #yang_s.root.print_mem(ly.LYD_JSON, ly.LYP_FORMAT) + yang_s._merge_data(data_merge_file) #test get module prefix def test_get_module_prefix(self, yang_s, data): @@ -234,17 +232,15 @@ def test_get_data_type(self, yang_s, data): for node in data['data_type']: xpath = str(node['xpath']) expected = node['data_type'] - expected_type = yang_s._str_to_type(expected) data_type = yang_s._get_data_type(xpath) - assert expected_type == data_type + assert expected == data_type def test_get_leafref_type(self, yang_s, data): for node in data['leafref_type']: xpath = str(node['xpath']) expected = node['data_type'] - expected_type = yang_s._str_to_type(expected) data_type = yang_s._get_leafref_type(xpath) - assert expected_type == data_type + assert expected == data_type def test_get_leafref_path(self, yang_s, data): for node in data['leafref_path']: @@ -257,9 +253,8 @@ def test_get_leafref_type_schema(self, yang_s, data): for node in data['leafref_type_schema']: xpath = str(node['xpath']) expected = node['data_type'] - expected_type = yang_s._str_to_type(expected) data_type = yang_s._get_leafref_type_schema(xpath) - assert expected_type == data_type + assert expected == data_type """ This is helper function to load YANG models for tests cases, which works @@ -345,8 +340,7 @@ def test_xlate_rev_xlate(self, sonic_yang_data): # print for better debugging, in case of failure. from jsondiff import diff print(diff(syc.jIn, syc.revXlateJson, syntax='symmetric')) - # make it fail - assert False == True + raise Exception("Xlate and Rev Xlate failed") return From 24b633d13b50660ba9ba5e43f8e71310e0c370bf Mon Sep 17 00:00:00 2001 From: Brad House Date: Wed, 12 Feb 2025 11:03:16 -0500 Subject: [PATCH 4/5] update dependencies to include libyang3 libyang1 and libyang3 can coexist (except for the dev packages). Even if a package doesn't directly depend on libyang, full dependency tracking isn't smart enough to pull in deps of an actual specified dependency, so we need to tag all users of libyang as also a user of libyang3 (including python bindings if they were previously specified). In a future commit we will remove all libyang1 references. --- files/build_templates/sonic_debian_extension.j2 | 2 +- platform/vs/docker-sonic-vs.mk | 2 ++ rules/docker-bmp.mk | 5 +++-- rules/docker-config-engine-bookworm.mk | 2 ++ rules/docker-config-engine-bullseye.mk | 2 ++ rules/docker-config-engine-buster.mk | 2 ++ rules/docker-macsec.mk | 2 +- rules/sonic-config.mk | 7 +++---- rules/sonic-mgmt-common.mk | 4 ++-- rules/sonic-utilities.mk | 2 ++ rules/sonic_bgpcfgd.mk | 2 ++ rules/swss-common.mk | 5 +++-- 12 files changed, 25 insertions(+), 12 deletions(-) diff --git a/files/build_templates/sonic_debian_extension.j2 b/files/build_templates/sonic_debian_extension.j2 index e959fb24f931..ac7ea98396f8 100644 --- a/files/build_templates/sonic_debian_extension.j2 +++ b/files/build_templates/sonic_debian_extension.j2 @@ -162,7 +162,7 @@ if [[ $CONFIGURED_ARCH == armhf || $CONFIGURED_ARCH == arm64 ]]; then fi # Install sonic-yang-models Python 3 package, install dependencies -sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/libyang_*.deb $debs_path/libyang-cpp_*.deb $debs_path/python3-yang_*.deb || \ +sudo dpkg --root=$FILESYSTEM_ROOT -i $debs_path/libyang_*.deb $debs_path/libyang-cpp_*.deb $debs_path/python3-yang_*.deb $debs_path/libyang3_*.deb $debs_path/python3-libyang_*.deb || \ sudo LANG=C DEBIAN_FRONTEND=noninteractive chroot $FILESYSTEM_ROOT apt-get -y install -f SONIC_YANG_MODEL_PY3_WHEEL_NAME=$(basename {{sonic_yang_models_py3_wheel_path}}) sudo cp {{sonic_yang_models_py3_wheel_path}} $FILESYSTEM_ROOT/$SONIC_YANG_MODEL_PY3_WHEEL_NAME diff --git a/platform/vs/docker-sonic-vs.mk b/platform/vs/docker-sonic-vs.mk index 3e66e94546ad..878163078a60 100644 --- a/platform/vs/docker-sonic-vs.mk +++ b/platform/vs/docker-sonic-vs.mk @@ -10,6 +10,8 @@ $(DOCKER_SONIC_VS)_DEPENDS += $(SYNCD_VS) \ $(LIBYANG) \ $(LIBYANG_CPP) \ $(LIBYANG_PY3) \ + $(LIBYANG3) \ + $(LIBYANG3_PY3) \ $(SONIC_UTILITIES_DATA) \ $(SONIC_HOST_SERVICES_DATA) diff --git a/rules/docker-bmp.mk b/rules/docker-bmp.mk index 95ad79799e65..48501efcfa68 100644 --- a/rules/docker-bmp.mk +++ b/rules/docker-bmp.mk @@ -13,7 +13,8 @@ $(DOCKER_BMP)_PYTHON_WHEELS = $(SONIC_BMPCFGD) $(DOCKER_BMP)_INSTALL_DEBS = $(LIBSWSSCOMMON) \ $(SONIC_BMPD) \ $(PYTHON3_SWSSCOMMON) \ - $(LIBYANG_PY3) + $(LIBYANG_PY3) \ + $(LIBYANG3_PY3) $(DOCKER_BMP)_DBG_DEPENDS = $($(DOCKER_CONFIG_ENGINE_BOOKWORM)_DBG_DEPENDS) @@ -43,4 +44,4 @@ $(DOCKER_BMP)_RUN_OPT += -v /etc/localtime:/etc/localtime:ro $(DOCKER_BMP)_RUN_OPT += -v /var/run/dbus:/var/run/dbus:rw $(DOCKER_BMP)_FILES += $(SUPERVISOR_PROC_EXIT_LISTENER_SCRIPT) -$(DOCKER_BMP)_BASE_IMAGE_FILES += monit_bmp:/etc/monit/conf.d \ No newline at end of file +$(DOCKER_BMP)_BASE_IMAGE_FILES += monit_bmp:/etc/monit/conf.d diff --git a/rules/docker-config-engine-bookworm.mk b/rules/docker-config-engine-bookworm.mk index 35145d890614..60606ab70b6c 100644 --- a/rules/docker-config-engine-bookworm.mk +++ b/rules/docker-config-engine-bookworm.mk @@ -7,6 +7,8 @@ $(DOCKER_CONFIG_ENGINE_BOOKWORM)_DEPENDS += $(LIBSWSSCOMMON) \ $(LIBYANG) \ $(LIBYANG_CPP) \ $(LIBYANG_PY3) \ + $(LIBYANG3) \ + $(LIBYANG3_PY3) \ $(PYTHON3_SWSSCOMMON) \ $(SONIC_DB_CLI) \ $(SONIC_EVENTD) diff --git a/rules/docker-config-engine-bullseye.mk b/rules/docker-config-engine-bullseye.mk index aa91a56279ce..2211519c873a 100644 --- a/rules/docker-config-engine-bullseye.mk +++ b/rules/docker-config-engine-bullseye.mk @@ -7,6 +7,8 @@ $(DOCKER_CONFIG_ENGINE_BULLSEYE)_DEPENDS += $(LIBSWSSCOMMON) \ $(LIBYANG) \ $(LIBYANG_CPP) \ $(LIBYANG_PY3) \ + $(LIBYANG3) \ + $(LIBYANG3_PY3) \ $(PYTHON3_SWSSCOMMON) \ $(SONIC_DB_CLI) \ $(SONIC_EVENTD) diff --git a/rules/docker-config-engine-buster.mk b/rules/docker-config-engine-buster.mk index 9f4035d6aa24..1f9b2f533b4e 100644 --- a/rules/docker-config-engine-buster.mk +++ b/rules/docker-config-engine-buster.mk @@ -7,6 +7,8 @@ $(DOCKER_CONFIG_ENGINE_BUSTER)_DEPENDS += $(LIBSWSSCOMMON) \ $(LIBYANG) \ $(LIBYANG_CPP) \ $(LIBYANG_PY3) \ + $(LIBYANG3) \ + $(LIBYANG3_PY3) \ $(PYTHON3_SWSSCOMMON) \ $(SONIC_DB_CLI) $(DOCKER_CONFIG_ENGINE_BUSTER)_PYTHON_WHEELS += $(SONIC_PY_COMMON_PY3) \ diff --git a/rules/docker-macsec.mk b/rules/docker-macsec.mk index 682ef619e9be..f7f319cbbb95 100644 --- a/rules/docker-macsec.mk +++ b/rules/docker-macsec.mk @@ -15,7 +15,7 @@ $(DOCKER_MACSEC)_DBG_IMAGE_PACKAGES = $($(DOCKER_SWSS_LAYER_BOOKWORM)_DBG_IMAGE_ $(DOCKER_MACSEC)_LOAD_DOCKERS += $(DOCKER_SWSS_LAYER_BOOKWORM) $(DOCKER_MACSEC)_INSTALL_PYTHON_WHEELS = $(SONIC_UTILITIES_PY3) -$(DOCKER_MACSEC)_INSTALL_DEBS = $(PYTHON3_SWSSCOMMON) $(LIBYANG_PY3) +$(DOCKER_MACSEC)_INSTALL_DEBS = $(PYTHON3_SWSSCOMMON) $(LIBYANG_PY3) $(LIBYANG3_PY3) SONIC_DOCKER_IMAGES += $(DOCKER_MACSEC) SONIC_BOOKWORM_DOCKERS += $(DOCKER_MACSEC) diff --git a/rules/sonic-config.mk b/rules/sonic-config.mk index ba146df70577..d65805bc96c5 100644 --- a/rules/sonic-config.mk +++ b/rules/sonic-config.mk @@ -16,10 +16,9 @@ $(SONIC_CONFIG_ENGINE_PY3)_SRC_PATH = $(SRC_PATH)/sonic-config-engine $(SONIC_CONFIG_ENGINE_PY3)_DEPENDS += $(SONIC_PY_COMMON_PY3) \ $(SONIC_YANG_MGMT_PY3) \ $(SONIC_YANG_MODELS_PY3) -$(SONIC_CONFIG_ENGINE_PY3)_DEBS_DEPENDS += $(LIBYANG) \ - $(LIBYANG_CPP) \ - $(LIBYANG_PY3) \ - $(PYTHON3_SWSSCOMMON) +$(SONIC_CONFIG_ENGINE_PY3)_DEBS_DEPENDS += $(LIBYANG3) \ + $(LIBYANG3_PY3) \ + $(PYTHON3_SWSSCOMMON) ifeq ($(ENABLE_PY2_MODULES), y) # Synthetic dependency to avoid building the Python 2 and 3 packages # simultaneously and any potential conflicts which may arise diff --git a/rules/sonic-mgmt-common.mk b/rules/sonic-mgmt-common.mk index 41441ab3ee94..1764e423175b 100644 --- a/rules/sonic-mgmt-common.mk +++ b/rules/sonic-mgmt-common.mk @@ -3,8 +3,8 @@ MGMT_COMMON_VERSION = 1.0.0 SONIC_MGMT_COMMON = sonic-mgmt-common_$(MGMT_COMMON_VERSION)_$(CONFIGURED_ARCH).deb $(SONIC_MGMT_COMMON)_SRC_PATH = $(SRC_PATH)/sonic-mgmt-common -$(SONIC_MGMT_COMMON)_DEPENDS = $(LIBYANG_DEV) $(LIBYANG) -$(SONIC_MGMT_COMMON)_RDEPENDS = $(LIBYANG) +$(SONIC_MGMT_COMMON)_DEPENDS = $(LIBYANG_DEV) $(LIBYANG) $(LIBYANG3) +$(SONIC_MGMT_COMMON)_RDEPENDS = $(LIBYANG) $(LIBYANG3) $(SONIC_MGMT_COMMON)_WHEEL_DEPENDS = $(SONIC_YANG_MODELS_PY3) SONIC_DPKG_DEBS += $(SONIC_MGMT_COMMON) diff --git a/rules/sonic-utilities.mk b/rules/sonic-utilities.mk index d0dec73e90e5..1217c7cd951a 100644 --- a/rules/sonic-utilities.mk +++ b/rules/sonic-utilities.mk @@ -19,6 +19,8 @@ $(SONIC_UTILITIES_PY3)_DEPENDS += $(SONIC_PY_COMMON_PY3) \ $(SONIC_UTILITIES_PY3)_DEBS_DEPENDS = $(LIBYANG) \ $(LIBYANG_CPP) \ $(LIBYANG_PY3) \ + $(LIBYANG3) \ + $(LIBYANG3_PY3) \ $(LIBSWSSCOMMON) \ $(PYTHON3_SWSSCOMMON) ifeq ($(CONFIGURED_PLATFORM),nvidia-bluefield) diff --git a/rules/sonic_bgpcfgd.mk b/rules/sonic_bgpcfgd.mk index 9abab06800c8..8881fb67caf6 100644 --- a/rules/sonic_bgpcfgd.mk +++ b/rules/sonic_bgpcfgd.mk @@ -13,6 +13,8 @@ $(SONIC_BGPCFGD)_DEPENDS += $(SONIC_CONFIG_ENGINE_PY3) \ $(SONIC_BGPCFGD)_DEBS_DEPENDS += $(LIBYANG) \ $(LIBYANG_CPP) \ $(LIBYANG_PY3) \ + $(LIBYANG3) \ + $(LIBYANG3_PY3) \ $(PYTHON3_SWSSCOMMON) $(SONIC_BGPCFGD)_PYTHON_VERSION = 3 SONIC_PYTHON_WHEELS += $(SONIC_BGPCFGD) diff --git a/rules/swss-common.mk b/rules/swss-common.mk index 5d657d5e500b..12a10b3186ee 100644 --- a/rules/swss-common.mk +++ b/rules/swss-common.mk @@ -9,9 +9,10 @@ $(LIBSWSSCOMMON)_VERSION = $(LIBSWSSCOMMON_VERSION) $(LIBSWSSCOMMON)_NAME = $(LIBSWSSCOMMON_NAME) $(LIBSWSSCOMMON)_DEPENDS += $(LIBNL3_DEV) $(LIBNL_GENL3_DEV) \ $(LIBNL_ROUTE3_DEV) $(LIBNL_NF3_DEV) \ - $(LIBNL_CLI_DEV) $(LIBYANG_DEV) $(LIBYANG) + $(LIBNL_CLI_DEV) $(LIBYANG_DEV) $(LIBYANG) $(LIBYANG3) $(LIBSWSSCOMMON)_RDEPENDS += $(LIBNL3) $(LIBNL_GENL3) \ - $(LIBNL_ROUTE3) $(LIBNL_NF3) $(LIBNL_CLI) $(LIBYANG) + $(LIBNL_ROUTE3) $(LIBNL_NF3) $(LIBNL_CLI) $(LIBYANG) \ + $(LIBYANG3) SONIC_DPKG_DEBS += $(LIBSWSSCOMMON) LIBSWSSCOMMON_DEV = $(LIBSWSSCOMMON_NAME)-dev_$(LIBSWSSCOMMON_VERSION)_$(CONFIGURED_ARCH).deb From 0b19bc480aebb80fefb57097e5f6a1b5c8cc0cba Mon Sep 17 00:00:00 2001 From: Brad House Date: Wed, 12 Feb 2025 19:45:43 -0500 Subject: [PATCH 5/5] libyang3-py3 needs python3-cffi installed in dockers --- dockers/docker-config-engine-bookworm/Dockerfile.j2 | 3 ++- dockers/docker-config-engine-bullseye/Dockerfile.j2 | 3 ++- dockers/docker-config-engine-buster/Dockerfile.j2 | 3 ++- dockers/docker-config-engine/Dockerfile.j2 | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/dockers/docker-config-engine-bookworm/Dockerfile.j2 b/dockers/docker-config-engine-bookworm/Dockerfile.j2 index c7c1d9cdc825..d437b7c91794 100644 --- a/dockers/docker-config-engine-bookworm/Dockerfile.j2 +++ b/dockers/docker-config-engine-bookworm/Dockerfile.j2 @@ -9,7 +9,8 @@ RUN apt-get update && \ apt-utils \ build-essential \ python3-dev \ - python3-yaml + python3-yaml \ + python3-cffi {%- if CONFIGURED_ARCH == "armhf" or CONFIGURED_ARCH == "arm64" %} RUN apt-get install -y \ diff --git a/dockers/docker-config-engine-bullseye/Dockerfile.j2 b/dockers/docker-config-engine-bullseye/Dockerfile.j2 index 700af660a91d..9bf79443c33d 100644 --- a/dockers/docker-config-engine-bullseye/Dockerfile.j2 +++ b/dockers/docker-config-engine-bullseye/Dockerfile.j2 @@ -8,7 +8,8 @@ RUN apt-get update && \ apt-get install -y \ apt-utils \ build-essential \ - python3-dev + python3-dev \ + python3-cffi {%- if CONFIGURED_ARCH == "armhf" or CONFIGURED_ARCH == "arm64" %} RUN apt-get install -y \ diff --git a/dockers/docker-config-engine-buster/Dockerfile.j2 b/dockers/docker-config-engine-buster/Dockerfile.j2 index cfa61bc0ba8c..df713b3d1b7b 100644 --- a/dockers/docker-config-engine-buster/Dockerfile.j2 +++ b/dockers/docker-config-engine-buster/Dockerfile.j2 @@ -8,7 +8,8 @@ RUN apt-get update && \ apt-get install -y \ apt-utils \ build-essential \ - python3-dev + python3-dev \ + python3-cffi {%- if CONFIGURED_ARCH == "armhf" or CONFIGURED_ARCH == "arm64" %} RUN apt-get install -y \ diff --git a/dockers/docker-config-engine/Dockerfile.j2 b/dockers/docker-config-engine/Dockerfile.j2 index c470102fa4c4..0f78efeed481 100644 --- a/dockers/docker-config-engine/Dockerfile.j2 +++ b/dockers/docker-config-engine/Dockerfile.j2 @@ -6,7 +6,7 @@ ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update # Dependencies for sonic-cfggen -RUN apt-get install -y build-essential python-dev +RUN apt-get install -y build-essential python-dev python3-cffi # Install python-redis RUN pip install redis>=3.5.3