From 5be61a701391d2e19f9bda7b3425693e290cccad Mon Sep 17 00:00:00 2001 From: Tobias Waldekranz Date: Tue, 27 Jun 2023 22:57:42 +0200 Subject: [PATCH] test/case: Add ietf_system/upgrade Verifies that RAUC bundles can be installed using NETCONF. We choose to not add this to the "all" suite for now, as the qeneth topologies do not run with full disk emulation. To test locally, configure your "make run" instance to use the UEFI loader, launch `make run`, and then run: make INFIX_TESTS=test/case/ietf_system/upgrade.py test-run --- board/x86_64/board.mk | 1 + .../case/ietf_system/bundles/not-a-bundle.pkg | 0 test/case/ietf_system/bundles/package | 1 + test/case/ietf_system/upgrade.py | 88 +++++++++++++++++++ test/docker/Dockerfile | 1 + test/docker/pip-requirements.txt | 1 + test/env | 10 ++- test/infamy/env.py | 1 + 8 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 test/case/ietf_system/bundles/not-a-bundle.pkg create mode 120000 test/case/ietf_system/bundles/package create mode 100755 test/case/ietf_system/upgrade.py diff --git a/board/x86_64/board.mk b/board/x86_64/board.mk index eb52a727..8b47a1b8 100644 --- a/board/x86_64/board.mk +++ b/board/x86_64/board.mk @@ -3,6 +3,7 @@ INFIX_TESTS ?= $(test-dir)/case/all.yaml test-env = $(test-dir)/env \ -f $(BINARIES_DIR)/infix-x86_64.img \ + -p $(BINARIES_DIR)/infix-x86_64.pkg \ $(1) $(2) test-env-qeneth = $(call test-env,-q $(test-dir)/virt/dual,$(1)) diff --git a/test/case/ietf_system/bundles/not-a-bundle.pkg b/test/case/ietf_system/bundles/not-a-bundle.pkg new file mode 100644 index 00000000..e69de29b diff --git a/test/case/ietf_system/bundles/package b/test/case/ietf_system/bundles/package new file mode 120000 index 00000000..ce024d92 --- /dev/null +++ b/test/case/ietf_system/bundles/package @@ -0,0 +1 @@ +/home/wkz/src/github.com/kernelkit/infix/x-netconf/images/infix-x86_64.pkg \ No newline at end of file diff --git a/test/case/ietf_system/upgrade.py b/test/case/ietf_system/upgrade.py new file mode 100755 index 00000000..831e5ab1 --- /dev/null +++ b/test/case/ietf_system/upgrade.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python3 + +import concurrent.futures +import functools +import http.server +import os +import socket +import time + +import netifaces + +import infamy + +SRVPORT = 8008 + +BUNDLEDIR = os.path.join( + os.path.dirname(__file__), + "bundles" +) + +PKGPATH = os.path.join( + BUNDLEDIR, + "package" +) + +class FileServer(http.server.HTTPServer): + class RequestHandler(http.server.SimpleHTTPRequestHandler): + def log_message(*args, **kwargs): + pass + + address_family = socket.AF_INET6 + + def __init__(self, server_address, directory): + rh = functools.partial(FileServer.RequestHandler, directory=directory) + self.__tp = concurrent.futures.ThreadPoolExecutor(max_workers=1) + super().__init__(server_address, rh) + + def __enter__(self): + self.__tp.submit(self.serve_forever) + + def __exit__(self, _, __, ___): + self.shutdown() + self.__tp.shutdown() + +with infamy.Test() as test: + with test.step("Initialize"): + env = infamy.Env(infamy.std_topology("1x1")) + if not env.args.package: + print("No package supplied") + test.skip() + + try: + os.unlink(PKGPATH) + except FileNotFoundError: + pass + os.symlink(os.path.abspath(env.args.package), PKGPATH) + + target = env.attach("target", "mgmt") + + _, hport = env.ltop.xlate("host", "tgt") + _, tport = env.ltop.xlate("target", "mgmt") + hip = netifaces.ifaddresses(hport)[netifaces.AF_INET6][0]["addr"] + hip = hip.replace(f"%{hport}", f"%{tport}") + + with FileServer(("::", SRVPORT), BUNDLEDIR): + + with test.step(f"Start installation of {os.path.basename(env.args.package)}"): + target.call_dict("infix-system", { + "install-bundle": { + "url": f"http://[{hip}]:{SRVPORT}/package", + } + }) + + with test.step("Wait for upgrade to finish"): + for _ in range(600): + oper = target.get_dict("/system-state/software") + installer = oper["system-state"]["software"]["installer"] + if installer["operation"] == "idle": + if "last-error" in installer: + print("Install failed:", installer["last-error"]) + test.fail() + + test.succeed() + + time.sleep(1) + + print("Timeout, last state:", oper) + test.fail() diff --git a/test/docker/Dockerfile b/test/docker/Dockerfile index 0a64020e..b2f9862b 100644 --- a/test/docker/Dockerfile +++ b/test/docker/Dockerfile @@ -10,6 +10,7 @@ RUN apk add --no-cache \ iputils \ libc-dev \ libyang-dev \ + linux-headers \ python3-dev \ qemu-img \ qemu-system-x86_64 \ diff --git a/test/docker/pip-requirements.txt b/test/docker/pip-requirements.txt index 13364972..447ee7ef 100644 --- a/test/docker/pip-requirements.txt +++ b/test/docker/pip-requirements.txt @@ -1,5 +1,6 @@ libyang==2.7.1 netconf_client==2.2.0 +netifaces==0.11.0 networkx==3.1 pydot==1.4.2 pyyaml==5.4.1 diff --git a/test/env b/test/env index febbf70e..5d284f37 100755 --- a/test/env +++ b/test/env @@ -2,7 +2,7 @@ set -e -INFIX_TEST=ghcr.io/kernelkit/infix-test:0.4 +INFIX_TEST=ghcr.io/kernelkit/infix-test:0.5 extract_yang() { @@ -73,6 +73,9 @@ usage: test/env [] -f -q [...] useful to see how tests will run in a CI setting, where KVM is typically not available + -p + Infix RAUC bundle to use for upgrade tests. + -q Directory containing a topology.dot.in, suitable for consumption by qeneth. A copy of this network is created, and launched. The @@ -95,7 +98,7 @@ qeneth="$ixdir/qeneth/qeneth" containerize=yes [ -c /dev/kvm ] && kvm="--device=/dev/kvm" -while getopts "Cf:hKq:t:" opt; do +while getopts "Cf:hKp:q:t:" opt; do case ${opt} in C) containerize= @@ -109,6 +112,9 @@ while getopts "Cf:hKq:t:" opt; do K) kvm= ;; + p) + INFAMY_ARGS="$INFAMY_ARGS -p $OPTARG" + ;; q) qenethdir="$OPTARG" ;; diff --git a/test/infamy/env.py b/test/infamy/env.py index 5b57578e..df0eae42 100644 --- a/test/infamy/env.py +++ b/test/infamy/env.py @@ -13,6 +13,7 @@ class ArgumentParser(argparse.ArgumentParser): self.add_argument("-d", "--debug", default=False, action="store_true") self.add_argument("-l", "--logical-topology", dest="ltop", default=ltop) + self.add_argument("-p", "--package", default=None) self.add_argument("-y", "--yangdir", default=None) self.add_argument("ptop", nargs=1, metavar="topology")