Merge pull request #846 from kernelkit/fix-upgrade-test

Update upgrade test
This commit is contained in:
Mattias Walström
2024-12-06 00:30:22 +01:00
committed by GitHub
8 changed files with 146 additions and 51 deletions
-1
View File
@@ -1 +0,0 @@
/home/wkz/src/github.com/kernelkit/infix/x-netconf/images/infix-x86_64.pkg
+3
View File
@@ -19,3 +19,6 @@
- name: ntp_client
case: ntp_client/test.py
- name: upgrade
case: upgrade/test.py
@@ -18,6 +18,10 @@ endif::topdoc[]
. Set up topology and attach to target DUT
. Start installation of selected package
. Wait for upgrade to finish
. Verify boot order has changed and reboot
. Verify that the partition is the booted
. Restore boot order to original configured
. Verify the boot order is the orignal configured
<<<
+103 -11
View File
@@ -4,11 +4,14 @@ Upgrade
Verify it is possible to upgrade.
"""
# NOTE: THIS TEST IS HARDCODED TO NETCONF
# There is a bug somewhere in the restconf-code (infamy or rousette)
import os
import time
import netifaces
import infamy
import infamy.file_server as srv
from infamy.util import wait_boot, until
SRVPORT = 8008
@@ -17,11 +20,36 @@ BUNDLEDIR = os.path.join(
"bundles"
)
bootloader=None
PKGPATH = os.path.join(
BUNDLEDIR,
"package"
)
class Uboot:
def __init__(self, ssh):
self.ssh=ssh
def get_boot_order(self):
order=self.ssh.runsh("sudo fw_printenv BOOT_ORDER").stdout.split("=")
return order[1].strip()
def set_boot_order(self, order):
return self.ssh.run(f"sudo fw_setenv BOOT_ORDER '{order}'".split()).returncode
class Grub:
def __init__(self, ssh):
self.ssh = ssh
def get_boot_order(self):
lines=self.ssh.runsh("grub-editenv /mnt/aux/grub/grubenv list").stdout.split("\n")
for line in lines:
if "ORDER" in line:
return line.split("=")[1].strip()
def set_boot_order(self, order):
return self.ssh.run(f"sudo grub-editenv /mnt/aux/grub/grubenv set ORDER='{order}'".split()).returncode
with infamy.Test() as test:
with test.step("Set up topology and attach to target DUT"):
env = infamy.Env()
@@ -33,22 +61,55 @@ with infamy.Test() as test:
os.unlink(PKGPATH)
except FileNotFoundError:
pass
#os.unlink(PKGPATH)
os.symlink(os.path.abspath(env.args.package), PKGPATH)
target = env.attach("target", "mgmt")
target = env.attach("target", "mgmt", "netconf")
target_ssh = env.attach("target", "mgmt", "ssh")
if target_ssh.run("test -e /sys/firmware/devicetree/base/chosen/u-boot,version".split()).returncode == 0:
bootloader=Uboot(target_ssh)
elif target_ssh.run("test -e /mnt/aux/grub/grubenv".split()).returncode == 0:
bootloader=Grub(target_ssh)
else:
print("No supported bootloader found")
test.skip()
_, hport = env.ltop.xlate("host", "mgmt")
_, tport = env.ltop.xlate("target", "mgmt")
hip = netifaces.ifaddresses(hport)[netifaces.AF_INET6][0]["addr"]
hip = hip.replace(f"%{hport}", f"%{tport}")
old_bootorder=bootloader.get_boot_order()
print(f"Initial bootorder: {repr(old_bootorder)}")
with srv.FileServer(("::", SRVPORT), BUNDLEDIR):
_, hport = env.ltop.xlate("host", "data")
_, tport = env.ltop.xlate("target", "data")
netns = infamy.IsolatedMacVlan(hport).start()
netns.addip("192.168.0.1")
target.put_config_dicts({
"ietf-interfaces": {
"interfaces": {
"interface": [
{
"name": tport,
"ipv4": {
"address": [
{
"ip": "192.168.0.2",
"prefix-length": 24
}
]
}
}
]
}
}
})
netns.must_reach("192.168.0.2")
with srv.FileServer(netns, "192.168.0.1", SRVPORT, BUNDLEDIR):
with test.step("Start installation of selected package"):
print(f"Installing {os.path.basename(env.args.package)}")
target.call_dict("infix-system", {
"install-bundle": {
"url": f"http://[{hip}]:{SRVPORT}/package",
"url": f"http://192.168.0.1:{SRVPORT}/package",
}
})
@@ -61,9 +122,40 @@ with infamy.Test() as test:
print("Install failed:", installer["last-error"])
test.fail()
test.succeed()
break
time.sleep(1)
else:
print("Timeout, last state:", oper)
test.fail()
print("Timeout, last state:", oper)
test.fail()
with test.step("Verify boot order has changed and reboot"):
assert(old_bootorder != bootloader.get_boot_order())
target.reboot()
if not wait_boot(target, env):
test.fail()
target = env.attach("target", "mgmt", "netconf")
with test.step("Verify that the partition is the booted"):
should_boot=bootloader.get_boot_order().split()[0]
oper = target.get_dict("/system-state/software")
booted = oper["system-state"]["software"]["booted"]
print(f"Should boot: {should_boot}, booted: {booted}")
assert(booted == should_boot)
with test.step("Restore boot order to original configured"):
print(f"Restore boot order to {old_bootorder}")
if bootloader.set_boot_order(old_bootorder) != 0:
test.fail()
target = env.attach("target", "mgmt", "netconf")
target.reboot()
if not wait_boot(target, env):
test.fail()
target = env.attach("target", "mgmt", "netconf")
with test.step("Verify the boot order is the orignal configured"):
order = bootloader.get_boot_order()
assert order == old_bootorder, f"Unexpected bootorder: {repr(order)}"
test.succeed()
@@ -1,23 +0,0 @@
graph "1x1" {
layout="neato";
overlap="false";
esep="+20";
node [shape=record, fontname="DejaVu Sans Mono, Book"];
edge [color="cornflowerblue", penwidth="2", fontname="DejaVu Serif, Book"];
host [
label="host | { <mgmt> mgmt }",
pos="0,12!",
kind="controller",
];
target [
label="{ <mgmt> mgmt } | target",
pos="10,12!",
kind="infix",
];
host:mgmt -- target:mgmt [kind=mgmt, color=lightgrey]
}
+1
View File
@@ -0,0 +1 @@
../../../infamy/topologies/1x2.dot
+31 -13
View File
@@ -5,24 +5,42 @@ import concurrent.futures
import functools
import http.server
import socket
from infamy.util import until
class FileServer(http.server.HTTPServer):
class FileServer:
"""Open web server on (address, port) serving files from directory"""
class RequestHandler(http.server.SimpleHTTPRequestHandler):
def log_message(self, *args, **kwargs):
pass
def __init__(self, netns, address, port, directory):
self.address = address
self.port = port
self.directory = directory
self.netns = netns
self.process = None
self.check_addres = None
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 start(self):
"""start HTTP file server"""
cmd = f"httpd -p {self.address}:{self.port} -f -h {self.directory}"
self.process = self.netns.popen(cmd.split(" "))
if self.address == "[::]":
check_address = "::1"
elif self.address == "0.0.0.0":
check_address = "127.0.0.1"
else:
check_address=self.address
cmd = f"nc -z {check_address} {self.port}".split()
until(lambda: self.netns.run(cmd).returncode == 0)
def stop(self):
"""Stop HTTP file server"""
if self.process:
self.process.terminate()
self.process.wait()
self.process = None
def __enter__(self):
self.__tp.submit(self.serve_forever)
self.start()
def __exit__(self, _, __, ___):
self.shutdown()
self.__tp.shutdown()
self.stop()
+4 -3
View File
@@ -16,7 +16,8 @@ mode-run := -t $(BINARIES_DIR)/qemu.dot
mode := $(mode-$(TEST_MODE))
INFIX_IMAGE_ID := $(call qstrip,$(INFIX_IMAGE_ID))
binaries-$(ARCH) := $(addprefix $(INFIX_IMAGE_ID),.img -disk.img .pkg)
binaries-$(ARCH) := $(addprefix $(INFIX_IMAGE_ID),.img -disk.img)
pkg-$(ARCH) := -p $(O)/images/$(addprefix $(INFIX_IMAGE_ID),.pkg)
binaries-x86_64 += OVMF.fd
binaries := $(foreach bin,$(binaries-$(ARCH)),-f $(BINARIES_DIR)/$(bin))
@@ -26,10 +27,10 @@ export INFAMY_ARGS := --transport=netconf
endif
test:
$(test-dir)/env -r $(base) $(mode) $(binaries) $(ninepm) $(TESTS)
$(test-dir)/env -r $(base) $(mode) $(binaries) $(pkg-$(ARCH)) $(ninepm) $(TESTS)
test-sh:
$(test-dir)/env $(base) $(mode) $(binaries) -i /bin/sh
$(test-dir)/env $(base) $(mode) $(binaries) $(pkg-$(ARCH)) -i /bin/sh
test-spec:
@esc_infix_name="$(echo $(INFIX_NAME) | sed 's/\//\\\//g')"; \