From 8c9c432847ffcdea25c351449479e77dd2fa36c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mattias=20Walstr=C3=B6m?= Date: Thu, 11 Apr 2024 06:50:30 +0200 Subject: [PATCH] Add a new packet python-statd Actually a part of statd, but had to make a separarate package to get it to work. Statd helper-scripts are now pre-compiled instead of doing it in runtime. Fixes #379 --- package/Config.in | 1 + package/python-statd/Config.in | 6 ++ package/python-statd/python-statd.hash | 1 + package/python-statd/python-statd.mk | 16 +++++ package/statd/Config.in | 1 + package/statd/statd.mk | 2 +- src/statd/LICENSE | 1 - src/statd/Makefile.am | 2 - src/statd/ospf-status | 60 ------------------ src/statd/python/LICENSE | 27 ++++++++ src/statd/python/cli_pretty/__init__.py | 4 ++ .../cli_pretty/cli_pretty.py} | 5 +- src/statd/python/ospf_status/__init__.py | 4 ++ src/statd/python/ospf_status/ospf_status.py | 63 +++++++++++++++++++ src/statd/python/pyproject.toml | 23 +++++++ src/statd/python/yanger/__init__.py | 4 ++ src/statd/{yanger => python/yanger/yanger.py} | 0 test/case/cli/run.sh | 2 +- test/case/cli/sysrepo-emulator.sh | 2 +- test/case/cli_pretty/run.sh | 2 +- 20 files changed, 157 insertions(+), 69 deletions(-) create mode 100644 package/python-statd/Config.in create mode 100644 package/python-statd/python-statd.hash create mode 100644 package/python-statd/python-statd.mk delete mode 100755 src/statd/ospf-status create mode 100644 src/statd/python/LICENSE create mode 100644 src/statd/python/cli_pretty/__init__.py rename src/statd/{cli-pretty => python/cli_pretty/cli_pretty.py} (99%) create mode 100644 src/statd/python/ospf_status/__init__.py create mode 100755 src/statd/python/ospf_status/ospf_status.py create mode 100644 src/statd/python/pyproject.toml create mode 100644 src/statd/python/yanger/__init__.py rename src/statd/{yanger => python/yanger/yanger.py} (100%) diff --git a/package/Config.in b/package/Config.in index 78417372..6c8333dd 100644 --- a/package/Config.in +++ b/package/Config.in @@ -12,6 +12,7 @@ source "$BR2_EXTERNAL_INFIX_PATH/package/keyack/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/klish-plugin-infix/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/klish/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/klish-plugin-sysrepo/Config.in" +source "$BR2_EXTERNAL_INFIX_PATH/package/python-statd/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/libsrx/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/lowdown/Config.in" source "$BR2_EXTERNAL_INFIX_PATH/package/mcd/Config.in" diff --git a/package/python-statd/Config.in b/package/python-statd/Config.in new file mode 100644 index 00000000..d20c9dff --- /dev/null +++ b/package/python-statd/Config.in @@ -0,0 +1,6 @@ +config BR2_PACKAGE_PYTHON_STATD + bool "python-statd" + select BR2_PACKAGE_HOST_PYTHON3 + select BR2_PACKAGE_STATD + help + Python helpers for statd. diff --git a/package/python-statd/python-statd.hash b/package/python-statd/python-statd.hash new file mode 100644 index 00000000..4b8b0bf4 --- /dev/null +++ b/package/python-statd/python-statd.hash @@ -0,0 +1 @@ +sha256 755d3a387cd124ff34e2b73cc58e7cec4d8d85ae6c295e30ffeb8d36eacecb1d LICENSE diff --git a/package/python-statd/python-statd.mk b/package/python-statd/python-statd.mk new file mode 100644 index 00000000..4515925f --- /dev/null +++ b/package/python-statd/python-statd.mk @@ -0,0 +1,16 @@ +PYTHON_STATD_VERSION = 1.0 +PYTHON_STATD_SITE_METHOD = local +PYTHON_STATD_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/statd/python +STATD_LICENSE = BSD-3-Clause +STATD_LICENSE_FILES = LICENSE +PYTHON_STATD_DEPENDENCIES = host-python3 python3 host-python-poetry-core +PYTHON_STATD_SETUP_TYPE = pep517 # poetry + +define PYTHON_STATD_MOVE_BINARIES + mkdir -p $(TARGET_DIR)/usr/libexec/statd + mv $(TARGET_DIR)/usr/bin/yanger $(TARGET_DIR)/usr/libexec/statd/ + mv $(TARGET_DIR)/usr/bin/cli-pretty $(TARGET_DIR)/usr/libexec/statd/ + mv $(TARGET_DIR)/usr/bin/ospf-status $(TARGET_DIR)/usr/libexec/statd/ +endef +PYTHON_STATD_POST_INSTALL_TARGET_HOOKS += PYTHON_STATD_MOVE_BINARIES + $(eval $(python-package)) diff --git a/package/statd/Config.in b/package/statd/Config.in index fea30cff..b401cbac 100644 --- a/package/statd/Config.in +++ b/package/statd/Config.in @@ -5,6 +5,7 @@ config BR2_PACKAGE_STATD select BR2_PACKAGE_SYSREPO select BR2_PACKAGE_LIBSRX select BR2_PACKAGE_LIBITE + select BR2_PACKAGE_PYTHON_STATD help Operational Status Daemon. Responsible for handling sysrepo operational run-time info. Such as interface state and address. diff --git a/package/statd/statd.mk b/package/statd/statd.mk index c1603d67..7244cae6 100644 --- a/package/statd/statd.mk +++ b/package/statd/statd.mk @@ -10,7 +10,7 @@ STATD_SITE = $(BR2_EXTERNAL_INFIX_PATH)/src/statd STATD_LICENSE = BSD-3-Clause STATD_LICENSE_FILES = LICENSE STATD_REDISTRIBUTE = NO -STATD_DEPENDENCIES = sysrepo libev libsrx jansson +STATD_DEPENDENCIES = sysrepo libev libsrx jansson python-statd STATD_AUTORECONF = YES define STATD_CONF_ENV diff --git a/src/statd/LICENSE b/src/statd/LICENSE index 2554e913..7a17cba1 100644 --- a/src/statd/LICENSE +++ b/src/statd/LICENSE @@ -1,4 +1,3 @@ -Copyright (c) 2020 Denis Kalashnikov Copyright (c) 2023 The KernelKit Authors All rights reserved. diff --git a/src/statd/Makefile.am b/src/statd/Makefile.am index 72a36b35..38d2be05 100644 --- a/src/statd/Makefile.am +++ b/src/statd/Makefile.am @@ -1,8 +1,6 @@ DISTCLEANFILES = *~ *.d ACLOCAL_AMFLAGS = -I m4 -pkglibexec_SCRIPTS = cli-pretty yanger ospf-status - sbin_PROGRAMS = statd statd_SOURCES = statd.c shared.c shared.h statd_CPPFLAGS = -D_DEFAULT_SOURCE -D_GNU_SOURCE diff --git a/src/statd/ospf-status b/src/statd/ospf-status deleted file mode 100755 index 6ac996b0..00000000 --- a/src/statd/ospf-status +++ /dev/null @@ -1,60 +0,0 @@ -#!/usr/bin/python3 -# This script is used to transform the output from the show ip ospf commands and order -# them to match the ietf-ospf YANG model. For example, interfaces is ordered under -# area but FRR has areas in interfaces. -# -# This makes the parsing for the operational parts of YANG model more easy -# - -import json -import subprocess - -iface_out=subprocess.check_output("vtysh -c 'show ip ospf interface json'", shell=True) -ospf_out=subprocess.check_output("vtysh -c 'show ip ospf json'", shell=True) -neighbor_out=subprocess.check_output("vtysh -c 'show ip ospf neighbor detail json'", shell=True) -interfaces=json.loads(iface_out) -ospf=json.loads(ospf_out) -neighbors=json.loads(neighbor_out) - -for ifname,iface in interfaces["interfaces"].items(): - iface["name"] = ifname - iface["neighbors"] = [] - for area_id in ospf["areas"]: - area_type="" - - stub=False - if("NSSA" in iface["area"]): - iface_area_id = iface["area"][:-7] - area_type = "nssa-area" - elif("Stub" in iface["area"]): - iface_area_id = iface["area"][:-7] - iface["areaId"] = iface["area"][:-7] - area_type = "stub-area" - else: - iface_area_id = iface["area"] - area_type = "normal-area" - - if(iface_area_id != area_id): - continue - - ospf["areas"][area_id]["area-type"] = area_type - iface["area"] = iface_area_id - - for nbrAddress,nbrDatas in neighbors["neighbors"].items(): - for nbrData in nbrDatas: - nbrIfname=nbrData["ifaceName"].split(":")[0] - if(("NSSA" in nbrData.get("areaId", {})) or ("Stub" in nbrData.get("areaId", {}))): - nbrData["areaId"] = nbrData["areaId"][:-7] - - if ((nbrIfname != ifname) and (area_id != nbrData.get("areaId"))): - #print(f'Continute {ifname} {nbrData.get("areaId")}') - continue - nbrData["neighborIp"] = nbrAddress - iface["neighbors"].append(nbrData) - - if(not ospf["areas"][area_id].get("interfaces", None)): - ospf["areas"][area_id]["interfaces"] = [] - ospf["areas"][area_id]["interfaces"].append(iface) - -print(json.dumps(ospf)) - diff --git a/src/statd/python/LICENSE b/src/statd/python/LICENSE new file mode 100644 index 00000000..7a17cba1 --- /dev/null +++ b/src/statd/python/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2023 The KernelKit Authors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of copyright holders nor the names of + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/statd/python/cli_pretty/__init__.py b/src/statd/python/cli_pretty/__init__.py new file mode 100644 index 00000000..cc914db8 --- /dev/null +++ b/src/statd/python/cli_pretty/__init__.py @@ -0,0 +1,4 @@ +from .cli_pretty import main + +if __name__ == "__main__": + main() diff --git a/src/statd/cli-pretty b/src/statd/python/cli_pretty/cli_pretty.py similarity index 99% rename from src/statd/cli-pretty rename to src/statd/python/cli_pretty/cli_pretty.py index b73cecbc..df45102e 100755 --- a/src/statd/cli-pretty +++ b/src/statd/python/cli_pretty/cli_pretty.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 -import argparse import json -import re +import argparse import sys +import re class Pad: iface = 16 @@ -619,5 +619,6 @@ def main(): print(f"Error, unknown command {args.command}") sys.exit(1) + if __name__ == "__main__": main() diff --git a/src/statd/python/ospf_status/__init__.py b/src/statd/python/ospf_status/__init__.py new file mode 100644 index 00000000..13cdb52c --- /dev/null +++ b/src/statd/python/ospf_status/__init__.py @@ -0,0 +1,4 @@ +from .ospf_status import main + +if __name__ == "__main__": + main() diff --git a/src/statd/python/ospf_status/ospf_status.py b/src/statd/python/ospf_status/ospf_status.py new file mode 100755 index 00000000..07bf843f --- /dev/null +++ b/src/statd/python/ospf_status/ospf_status.py @@ -0,0 +1,63 @@ +#!/usr/bin/python3 +# This script is used to transform the output from the show ip ospf commands and order +# them to match the ietf-ospf YANG model. For example, interfaces is ordered under +# area but FRR has areas in interfaces. +# +# This makes the parsing for the operational parts of YANG model more easy +# + +import json +import subprocess + +def main(): + iface_out=subprocess.check_output("vtysh -c 'show ip ospf interface json'", shell=True) + ospf_out=subprocess.check_output("vtysh -c 'show ip ospf json'", shell=True) + neighbor_out=subprocess.check_output("vtysh -c 'show ip ospf neighbor detail json'", shell=True) + interfaces=json.loads(iface_out) + ospf=json.loads(ospf_out) + neighbors=json.loads(neighbor_out) + + for ifname,iface in interfaces["interfaces"].items(): + iface["name"] = ifname + iface["neighbors"] = [] + for area_id in ospf["areas"]: + area_type="" + + stub=False + if("NSSA" in iface["area"]): + iface_area_id = iface["area"][:-7] + area_type = "nssa-area" + elif("Stub" in iface["area"]): + iface_area_id = iface["area"][:-7] + iface["areaId"] = iface["area"][:-7] + area_type = "stub-area" + else: + iface_area_id = iface["area"] + area_type = "normal-area" + + if(iface_area_id != area_id): + continue + + ospf["areas"][area_id]["area-type"] = area_type + iface["area"] = iface_area_id + + for nbrAddress,nbrDatas in neighbors["neighbors"].items(): + for nbrData in nbrDatas: + nbrIfname=nbrData["ifaceName"].split(":")[0] + if(("NSSA" in nbrData.get("areaId", {})) or ("Stub" in nbrData.get("areaId", {}))): + nbrData["areaId"] = nbrData["areaId"][:-7] + + if ((nbrIfname != ifname) and (area_id != nbrData.get("areaId"))): + #print(f'Continute {ifname} {nbrData.get("areaId")}') + continue + nbrData["neighborIp"] = nbrAddress + iface["neighbors"].append(nbrData) + + if(not ospf["areas"][area_id].get("interfaces", None)): + ospf["areas"][area_id]["interfaces"] = [] + ospf["areas"][area_id]["interfaces"].append(iface) + + print(json.dumps(ospf)) + +if __name__ == "__main__": + main() diff --git a/src/statd/python/pyproject.toml b/src/statd/python/pyproject.toml new file mode 100644 index 00000000..5dc18f68 --- /dev/null +++ b/src/statd/python/pyproject.toml @@ -0,0 +1,23 @@ +[tool.poetry] +name = "infix-yang-tools" +version = "1.0" +description = "Linux to infix-YANG" +license = "MIT" +packages = [ + { include = "yanger/*.py" }, + { include = "cli_pretty/*.py" }, + { include = "ospf_status/*.py" } +] +authors = [ + "KernelKit developers" +] + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + + +[tool.poetry.scripts] +yanger = "yanger:main" +cli-pretty = "cli_pretty:main" +ospf-status = "ospf_status:main" \ No newline at end of file diff --git a/src/statd/python/yanger/__init__.py b/src/statd/python/yanger/__init__.py new file mode 100644 index 00000000..3ab9057f --- /dev/null +++ b/src/statd/python/yanger/__init__.py @@ -0,0 +1,4 @@ +from .yanger import main + +if __name__ == "__main__": + main() diff --git a/src/statd/yanger b/src/statd/python/yanger/yanger.py similarity index 100% rename from src/statd/yanger rename to src/statd/python/yanger/yanger.py diff --git a/test/case/cli/run.sh b/test/case/cli/run.sh index a355c914..a7ca23c5 100755 --- a/test/case/cli/run.sh +++ b/test/case/cli/run.sh @@ -4,7 +4,7 @@ SCRIPT_PATH="$(dirname "$(readlink -f "$0")")" ROOT_PATH="$SCRIPT_PATH/../../../" CLI_OUTPUT_PATH="$SCRIPT_PATH/cli-output/" -CLI_PRETTY_TOOL="$ROOT_PATH/src/statd/cli-pretty" +CLI_PRETTY_TOOL="$ROOT_PATH/src/statd/python/cli_pretty/cli_pretty.py" SR_EMULATOR_TOOL="$SCRIPT_PATH/sysrepo-emulator.sh" CLI_OUTPUT_FILE="$(mktemp)" diff --git a/test/case/cli/sysrepo-emulator.sh b/test/case/cli/sysrepo-emulator.sh index 67651c11..2693f628 100755 --- a/test/case/cli/sysrepo-emulator.sh +++ b/test/case/cli/sysrepo-emulator.sh @@ -3,7 +3,7 @@ SCRIPT_PATH="$(dirname "$(readlink -f "$0")")" ROOT_PATH="$SCRIPT_PATH/../../../" -YANGER_TOOL="$ROOT_PATH/src/statd/yanger" +YANGER_TOOL="$ROOT_PATH/src/statd/python/yanger/yanger.py" INTERFACES="br0 br1 e0 e1 e2 e3 e4" diff --git a/test/case/cli_pretty/run.sh b/test/case/cli_pretty/run.sh index 1d63d4ae..40a6868b 100755 --- a/test/case/cli_pretty/run.sh +++ b/test/case/cli_pretty/run.sh @@ -18,7 +18,7 @@ if [ ! -e "$SCRIPT_PATH/$json" ]; then fi cat "$SCRIPT_PATH/$json" | \ - "$SCRIPT_PATH"/../../../src/statd/cli-pretty \ + "$SCRIPT_PATH"/../../../src/statd/python/cli_pretty/cli_pretty.py \ "$command" $* if [ $? -eq 0 ]; then echo "ok 1 - $json printed without crashing"