0
0
mirror of https://gitlab.nic.cz/labs/bird.git synced 2024-10-18 09:58:43 +00:00

Flock tests: saving Linux KRT contents (used in ospf-base)

This commit is contained in:
Maria Matejka 2024-07-25 13:32:55 +02:00
parent 6a52780652
commit f7f06db288
5 changed files with 1215 additions and 6 deletions

1
.gitignore vendored
View File

@ -14,3 +14,4 @@
/sysdep/autoconf.h.in~ /sysdep/autoconf.h.in~
/cscope.* /cscope.*
*.tar.gz *.tar.gz
__pycache__

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
#!/usr/bin/python3 #!/usr/bin/python3
import asyncio import asyncio
from python.BIRD.Test import Test, BIRDInstance, DumpRIB from python.BIRD.Test import Test, BIRDInstance, DumpRIB, DumpLinuxKRT
from python.BIRD.LogChecker import LogExpectedStub from python.BIRD.LogChecker import LogExpectedStub
class ThisTest(Test): class ThisTest(Test):
@ -32,4 +32,7 @@ class ThisTest(Test):
async def test(self): async def test(self):
# Startup check # Startup check
await DumpRIB(self, 30, "startup")() await asyncio.gather(*[
DumpRIB(self, 30, "rib-startup")(),
DumpLinuxKRT(self, 30, "fib-startup")(),
])

View File

@ -1,6 +1,7 @@
import asyncio import asyncio
import ipaddress import ipaddress
import jinja2 import jinja2
import json
import os import os
import pathlib import pathlib
import sys import sys
@ -17,6 +18,7 @@ from flock.Hypervisor import Hypervisor
from flock.Machine import Machine from flock.Machine import Machine
from .CLI import CLI, Transport from .CLI import CLI, Transport
from .LogChecker import LogChecker, LogExpectedFuture from .LogChecker import LogChecker, LogExpectedFuture
from .Aux import dict_gather, dict_expand
# TODO: move this to some aux file # TODO: move this to some aux file
class Differs(Exception): class Differs(Exception):
@ -32,6 +34,56 @@ class Differs(Exception):
else: else:
return False return False
class ComparableDict(dict):
def __lt__(self, other):
if type(other) is dict:
return self < ComparableDict(other)
elif type(other) is ComparableDict:
sk = sorted(list(self.keys()))
ok = sorted(list(other.keys()))
if sk == ok:
for k in sk:
if self[k] < other[k]:
return True
if self[k] > other[k]:
return False
return False
else:
return sk < ok
else:
raise TypeError("Inequality impossible between ComparableDict and non-dict")
def __gt__(self, other):
if type(other) is dict:
return ComparableDict(other) < self
else:
return other < self
def __le__(self, other):
if self == other:
return True
else:
return self < other
def __ge__(self, other):
if self == other:
return True
else:
return self > other
def sort_arrays(a):
if type(a) is str:
return a
if type(a) is int:
return a
try:
return { k: sort_arrays(v) for k,v in a.items() }
except AttributeError:
return sorted([sort_arrays(v) for v in a ], key=lambda v: ComparableDict(v) if type(v) is dict else v)
def deep_eq(a, b, deep=False): def deep_eq(a, b, deep=False):
if a == b: if a == b:
return True return True
@ -224,6 +276,7 @@ class BIRDInstance(CLI):
class DumpCheck: class DumpCheck:
def __init__(self, test, timeout, name, check_timeout=None, check_id=None, check_retry_timeout=0.5): def __init__(self, test, timeout, name, check_timeout=None, check_id=None, check_retry_timeout=0.5):
self.test = test
self.timeout = timeout self.timeout = timeout
self.check_timeout = timeout if check_timeout is None else check_timeout self.check_timeout = timeout if check_timeout is None else check_timeout
self.check_retry_timeout = check_retry_timeout self.check_retry_timeout = check_retry_timeout
@ -298,15 +351,15 @@ class DumpCheck:
return False return False
class DumpOnMachines(DumpCheck): class DumpOnMachines(DumpCheck):
def __init__(self, test, *args, machines=None, **kwargs): def __init__(self, *args, machines=None, **kwargs):
super().__init__(test, *args, **kwargs) super().__init__(*args, **kwargs)
# Collect machines to dump # Collect machines to dump
if machines is None: if machines is None:
self.machines = test.machine_index.values() self.machines = self.test.machine_index.values()
else: else:
self.machines = [ self.machines = [
m if isinstance(m, CLI) else test.machine_index[m] m if isinstance(m, CLI) else self.test.machine_index[m]
for m in machines for m in machines
] ]
@ -337,7 +390,27 @@ class DumpRIB(DumpOnMachines):
del r[k] del r[k]
return d return d
class DumpLinuxKRT(DumpOnMachines):
def __init__(self, *args, cmdargs=None, **kwargs):
super().__init__(*args, **kwargs)
if cmdargs is None:
self.cmdargs = []
else:
self.cmdargs = cmdargs
async def obtain_on_machine(self, mach):
raw = await dict_gather({
fam:
self.test.hypervisor.control_socket.send_cmd(
"run_in", mach.mach.name, "ip", "-j", f"-{fam}", "route", "show", *self.cmdargs)
for fam in ("4", "6", "M")
})
for k,v in raw.items():
if v["ret"] != 0 or len(v["err"]) != 0:
raise Exception(f"Failed to gather krt dump for {k}: ret={v['ret']}, {v['err']}")
return { k: sort_arrays(json.loads(v["out"])) for k,v in raw.items() }
class Test: class Test:
ipv6_prefix = ipaddress.ip_network("2001:db8::/32") ipv6_prefix = ipaddress.ip_network("2001:db8::/32")
@ -470,6 +543,36 @@ class Test:
await self.cleanup() await self.cleanup()
async def krt_dump(self, timeout, name, *args, full=True, machines=None, check_timeout=10, check_retry_timeout=0.5):
# Collect machines to dump
if machines is None:
machines = self.machine_index.values()
else:
machines = [
m if isinstance(m, CLI) else self.machine_index[m]
for m in machines
]
raw = await dict_gather({
(mach.mach.name, fam):
mach.mach.hypervisor.control_socket.send_cmd(
"run_in", mach.mach.name, "ip", "-j", f"-{fam}", "route", "show", *args)
for mach in machines
for fam in ("4", "6", "M")
})
for k,v in raw.items():
if v["ret"] != 0 or len(v["err"]) != 0:
raise Exception(f"Failed to gather krt dump for {k}: ret={v['ret']}, {v['err']}")
dump = dict_expand({ k: json.loads(v["out"]) for k,v in raw.items()})
print(dump)
name = "krt.yaml"
with open(name, "w") as y:
yaml.dump(dump, y)
if __name__ == "__main__": if __name__ == "__main__":
name = sys.argv[1] name = sys.argv[1]
mode = Test.CHECK mode = Test.CHECK