mirror of
https://gitlab.nic.cz/labs/bird.git
synced 2024-12-22 09:41:54 +00:00
Flock tests: show ospf topology (used in ospf-base)
This commit is contained in:
parent
c1bfc76a35
commit
8bb709187d
344
flock/ospf-base/dump-0003-ospf-neighbors.yaml
Normal file
344
flock/ospf-base/dump-0003-ospf-neighbors.yaml
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
m1:
|
||||||
|
ospf4:
|
||||||
|
ospf4:
|
||||||
|
neighbors:
|
||||||
|
192.0.2.1:
|
||||||
|
interface: ve31
|
||||||
|
ip: 192.0.2.1
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.18:
|
||||||
|
interface: ve12
|
||||||
|
ip: 192.0.2.18
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
ospf6:
|
||||||
|
ospf6:
|
||||||
|
neighbors:
|
||||||
|
192.0.2.1:
|
||||||
|
interface: ve31
|
||||||
|
ip: fe80::ac55:22ff:fe32:3610
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.18:
|
||||||
|
interface: ve12
|
||||||
|
ip: fe80::5c38:8eff:fe25:1d68
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
m2:
|
||||||
|
ospf4:
|
||||||
|
ospf4:
|
||||||
|
neighbors:
|
||||||
|
192.0.2.1:
|
||||||
|
interface: ve23
|
||||||
|
ip: 192.0.2.34
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.2:
|
||||||
|
interface: ve12
|
||||||
|
ip: 192.0.2.17
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
ospf6:
|
||||||
|
ospf6:
|
||||||
|
neighbors:
|
||||||
|
192.0.2.1:
|
||||||
|
interface: ve23
|
||||||
|
ip: fe80::7cda:1aff:feae:9831
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.2:
|
||||||
|
interface: ve12
|
||||||
|
ip: fe80::4cfd:f0ff:fe23:167
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
m3:
|
||||||
|
ospf4:
|
||||||
|
ospf4:
|
||||||
|
neighbors:
|
||||||
|
192.0.2.18:
|
||||||
|
interface: ve23
|
||||||
|
ip: 192.0.2.33
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.2:
|
||||||
|
interface: ve31
|
||||||
|
ip: 192.0.2.2
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.49:
|
||||||
|
interface: multi
|
||||||
|
ip: 192.0.2.99
|
||||||
|
position: "Other\t"
|
||||||
|
priority: '1'
|
||||||
|
state: 2-Way
|
||||||
|
192.0.2.82:
|
||||||
|
interface: multi
|
||||||
|
ip: 192.0.2.100
|
||||||
|
position: BDR
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.98:
|
||||||
|
interface: multi
|
||||||
|
ip: 192.0.2.98
|
||||||
|
position: DR
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
ospf6:
|
||||||
|
ospf6:
|
||||||
|
neighbors:
|
||||||
|
192.0.2.18:
|
||||||
|
interface: ve23
|
||||||
|
ip: fe80::8c41:8bff:fe8f:9446
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.2:
|
||||||
|
interface: ve31
|
||||||
|
ip: fe80::5c82:ccff:fe47:46df
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.49:
|
||||||
|
interface: multi
|
||||||
|
ip: fe80::5c5b:1eff:fe50:3793
|
||||||
|
position: "Other\t"
|
||||||
|
priority: '1'
|
||||||
|
state: 2-Way
|
||||||
|
192.0.2.82:
|
||||||
|
interface: multi
|
||||||
|
ip: fe80::9ce1:eaff:fe4b:b4f9
|
||||||
|
position: BDR
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.98:
|
||||||
|
interface: multi
|
||||||
|
ip: fe80::2cf6:51ff:feaa:3b4f
|
||||||
|
position: DR
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
m4:
|
||||||
|
ospf4:
|
||||||
|
ospf4:
|
||||||
|
neighbors:
|
||||||
|
192.0.2.1:
|
||||||
|
interface: multi
|
||||||
|
ip: 192.0.2.97
|
||||||
|
position: "Other\t"
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.49:
|
||||||
|
interface: multi
|
||||||
|
ip: 192.0.2.99
|
||||||
|
position: "Other\t"
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.82:
|
||||||
|
interface: multi
|
||||||
|
ip: 192.0.2.100
|
||||||
|
position: BDR
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
ospf6:
|
||||||
|
ospf6:
|
||||||
|
neighbors:
|
||||||
|
192.0.2.1:
|
||||||
|
interface: multi
|
||||||
|
ip: fe80::dc8f:6bff:fe0f:6ad9
|
||||||
|
position: "Other\t"
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.49:
|
||||||
|
interface: multi
|
||||||
|
ip: fe80::5c5b:1eff:fe50:3793
|
||||||
|
position: "Other\t"
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.82:
|
||||||
|
interface: multi
|
||||||
|
ip: fe80::9ce1:eaff:fe4b:b4f9
|
||||||
|
position: BDR
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
m5:
|
||||||
|
ospf4:
|
||||||
|
ospf4:
|
||||||
|
neighbors:
|
||||||
|
192.0.2.1:
|
||||||
|
interface: multi
|
||||||
|
ip: 192.0.2.97
|
||||||
|
position: "Other\t"
|
||||||
|
priority: '1'
|
||||||
|
state: 2-Way
|
||||||
|
192.0.2.50:
|
||||||
|
interface: ve57
|
||||||
|
ip: 192.0.2.50
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.82:
|
||||||
|
interface: multi
|
||||||
|
ip: 192.0.2.100
|
||||||
|
position: BDR
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.98:
|
||||||
|
interface: multi
|
||||||
|
ip: 192.0.2.98
|
||||||
|
position: DR
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
ospf6:
|
||||||
|
ospf6:
|
||||||
|
neighbors:
|
||||||
|
192.0.2.1:
|
||||||
|
interface: multi
|
||||||
|
ip: fe80::dc8f:6bff:fe0f:6ad9
|
||||||
|
position: "Other\t"
|
||||||
|
priority: '1'
|
||||||
|
state: 2-Way
|
||||||
|
192.0.2.50:
|
||||||
|
interface: ve57
|
||||||
|
ip: fe80::9c97:afff:fe62:f695
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.82:
|
||||||
|
interface: multi
|
||||||
|
ip: fe80::9ce1:eaff:fe4b:b4f9
|
||||||
|
position: BDR
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.98:
|
||||||
|
interface: multi
|
||||||
|
ip: fe80::2cf6:51ff:feaa:3b4f
|
||||||
|
position: DR
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
m6:
|
||||||
|
ospf4:
|
||||||
|
ospf4:
|
||||||
|
neighbors:
|
||||||
|
192.0.2.1:
|
||||||
|
interface: multi
|
||||||
|
ip: 192.0.2.97
|
||||||
|
position: "Other\t"
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.49:
|
||||||
|
interface: multi
|
||||||
|
ip: 192.0.2.99
|
||||||
|
position: "Other\t"
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.66:
|
||||||
|
interface: ve86
|
||||||
|
ip: 192.0.2.81
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.98:
|
||||||
|
interface: multi
|
||||||
|
ip: 192.0.2.98
|
||||||
|
position: DR
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
ospf6:
|
||||||
|
ospf6:
|
||||||
|
neighbors:
|
||||||
|
192.0.2.1:
|
||||||
|
interface: multi
|
||||||
|
ip: fe80::dc8f:6bff:fe0f:6ad9
|
||||||
|
position: "Other\t"
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.49:
|
||||||
|
interface: multi
|
||||||
|
ip: fe80::5c5b:1eff:fe50:3793
|
||||||
|
position: "Other\t"
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.66:
|
||||||
|
interface: ve86
|
||||||
|
ip: fe80::6cc9:f2ff:feb9:754f
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.98:
|
||||||
|
interface: multi
|
||||||
|
ip: fe80::2cf6:51ff:feaa:3b4f
|
||||||
|
position: DR
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
m7:
|
||||||
|
ospf4:
|
||||||
|
ospf4:
|
||||||
|
neighbors:
|
||||||
|
192.0.2.49:
|
||||||
|
interface: ve57
|
||||||
|
ip: 192.0.2.49
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.66:
|
||||||
|
interface: ve78
|
||||||
|
ip: 192.0.2.66
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
ospf6:
|
||||||
|
ospf6:
|
||||||
|
neighbors:
|
||||||
|
192.0.2.49:
|
||||||
|
interface: ve57
|
||||||
|
ip: fe80::2c33:44ff:fe0f:454b
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.66:
|
||||||
|
interface: ve78
|
||||||
|
ip: fe80::8c67:1aff:fe6f:1193
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
m8:
|
||||||
|
ospf4:
|
||||||
|
ospf4:
|
||||||
|
neighbors:
|
||||||
|
192.0.2.50:
|
||||||
|
interface: ve78
|
||||||
|
ip: 192.0.2.65
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.82:
|
||||||
|
interface: ve86
|
||||||
|
ip: 192.0.2.82
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
ospf6:
|
||||||
|
ospf6:
|
||||||
|
neighbors:
|
||||||
|
192.0.2.50:
|
||||||
|
interface: ve78
|
||||||
|
ip: fe80::ac21:71ff:fea9:abe
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
||||||
|
192.0.2.82:
|
||||||
|
interface: ve86
|
||||||
|
ip: fe80::5cf4:d5ff:fe79:c89
|
||||||
|
position: PtP
|
||||||
|
priority: '1'
|
||||||
|
state: Full
|
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/python3
|
#!/usr/bin/python3
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
from python.BIRD.Test import Test, BIRDInstance, DumpRIB, DumpLinuxKRT
|
from python.BIRD.Test import Test, BIRDInstance, DumpRIB, DumpLinuxKRT, DumpOSPFNeighbors
|
||||||
from python.BIRD.LogChecker import LogExpectedStub
|
from python.BIRD.LogChecker import LogExpectedStub
|
||||||
|
|
||||||
class ThisTest(Test):
|
class ThisTest(Test):
|
||||||
@ -35,4 +35,5 @@ class ThisTest(Test):
|
|||||||
await asyncio.gather(*[
|
await asyncio.gather(*[
|
||||||
DumpRIB(self, 30, "rib-startup")(),
|
DumpRIB(self, 30, "rib-startup")(),
|
||||||
DumpLinuxKRT(self, 30, "fib-startup")(),
|
DumpLinuxKRT(self, 30, "fib-startup")(),
|
||||||
|
DumpOSPFNeighbors(self, 30, "ospf-neighbors", protocols=["ospf4", "ospf6"])(),
|
||||||
])
|
])
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
from . import ShowRoute
|
from .ShowRoute import ShowRouteParser
|
||||||
|
from .ShowOSPF import ShowOSPFNeighborsParser
|
||||||
|
|
||||||
class Transport:
|
class Transport:
|
||||||
pass
|
pass
|
||||||
@ -24,6 +25,16 @@ class CLI:
|
|||||||
async def disable(self, proto: str):
|
async def disable(self, proto: str):
|
||||||
return await self.transport.send_cmd("disable", proto)
|
return await self.transport.send_cmd("disable", proto)
|
||||||
|
|
||||||
|
async def cmd_send_parse(self, parser, *cmd):
|
||||||
|
result = await self.transport.send_cmd(*cmd)
|
||||||
|
if len(result["err"]):
|
||||||
|
raise Exception(f"Command {cmd} returned {result['err'].decode()}, stdout={result['out'].decode()}")
|
||||||
|
|
||||||
|
for line in result["out"].decode().split("\n"):
|
||||||
|
parser = parser.parse(line)
|
||||||
|
|
||||||
|
return parser.parse(None).result
|
||||||
|
|
||||||
async def show_route(self, table=["all"], args=[]):
|
async def show_route(self, table=["all"], args=[]):
|
||||||
cmd = [ "show", "route" ]
|
cmd = [ "show", "route" ]
|
||||||
for t in table:
|
for t in table:
|
||||||
@ -31,9 +42,8 @@ class CLI:
|
|||||||
cmd.append(t)
|
cmd.append(t)
|
||||||
|
|
||||||
cmd += args
|
cmd += args
|
||||||
|
return await self.cmd_send_parse(ShowRouteParser(), *cmd)
|
||||||
|
|
||||||
result = await self.transport.send_cmd(*cmd)
|
async def show_ospf_neighbors(self, proto: str):
|
||||||
if len(result["err"]):
|
return await self.cmd_send_parse(ShowOSPFNeighborsParser(),
|
||||||
raise Exception(f"Command {cmd} returned {result['err'].decode()}, stdout={result['out'].decode()}")
|
"show", "ospf", "neighbors", proto)
|
||||||
|
|
||||||
return ShowRoute.parse(result["out"].decode())
|
|
||||||
|
68
python/BIRD/CLIParser.py
Normal file
68
python/BIRD/CLIParser.py
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
class ParserException(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def subparser(base):
|
||||||
|
def decorator(cls):
|
||||||
|
base.subparsers = { **base.subparsers, cls.entryRegex: cls }
|
||||||
|
return cls
|
||||||
|
return decorator
|
||||||
|
|
||||||
|
class CLIParser:
|
||||||
|
subparsers = {}
|
||||||
|
def __init__(self, groups=None, parent=None):
|
||||||
|
self.result = {}
|
||||||
|
self.parent = parent
|
||||||
|
self.cur = None
|
||||||
|
|
||||||
|
if parent is None:
|
||||||
|
assert(groups is None)
|
||||||
|
return
|
||||||
|
|
||||||
|
self.enter(groups)
|
||||||
|
|
||||||
|
def parse(self, line: str):
|
||||||
|
assert(self.cur == None)
|
||||||
|
if line is not None:
|
||||||
|
for k,v in self.subparsers.items():
|
||||||
|
if m := k.match(line):
|
||||||
|
self.cur = (c := v(groups=m.groups(), parent=self))
|
||||||
|
while c.cur is not None:
|
||||||
|
c = c.cur
|
||||||
|
return c
|
||||||
|
elif self.parent is None:
|
||||||
|
return self
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.exit()
|
||||||
|
self.parent.cur = None
|
||||||
|
return self.parent.parse(line)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Failed to parse line: {line}")
|
||||||
|
raise e
|
||||||
|
|
||||||
|
def exit(self):
|
||||||
|
raise ParserException(f"Failed to match line to all regexes")
|
||||||
|
|
||||||
|
@subparser(CLIParser)
|
||||||
|
class VersionParser(CLIParser):
|
||||||
|
entryRegex = re.compile("BIRD ([0-9a-z._-]+) ready.")
|
||||||
|
def enter(self, groups):
|
||||||
|
self.version ,= groups
|
||||||
|
|
||||||
|
def exit(self):
|
||||||
|
if "version" in self.parent.result:
|
||||||
|
raise ParserException(f"Duplicate version line")
|
||||||
|
|
||||||
|
self.parent.result["version"] = self.version
|
||||||
|
|
||||||
|
@subparser(CLIParser)
|
||||||
|
class NothingParser(CLIParser):
|
||||||
|
entryRegex = re.compile("^$")
|
||||||
|
def enter(self, _):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def exit(self):
|
||||||
|
pass
|
34
python/BIRD/ShowOSPF.py
Normal file
34
python/BIRD/ShowOSPF.py
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import re
|
||||||
|
from .CLIParser import CLIParser, subparser, ParserException
|
||||||
|
|
||||||
|
class ShowOSPFNeighborsParser(CLIParser):
|
||||||
|
pass
|
||||||
|
|
||||||
|
@subparser(ShowOSPFNeighborsParser)
|
||||||
|
class ShowOSPFNeighborsProtocolParser(CLIParser):
|
||||||
|
entryRegex = re.compile("^(.*):$")
|
||||||
|
def enter(self, groups):
|
||||||
|
self.name ,= groups
|
||||||
|
|
||||||
|
def exit(self):
|
||||||
|
self.parent.result[self.name] = self.result
|
||||||
|
|
||||||
|
@subparser(ShowOSPFNeighborsProtocolParser)
|
||||||
|
class ShowOSPFNeighborsHeaderParser(CLIParser):
|
||||||
|
entryRegex = re.compile("^Router ID Pri State DTime Interface Router IP$")
|
||||||
|
def enter(self, _):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def exit(self):
|
||||||
|
self.parent.result["neighbors"] = self.result
|
||||||
|
|
||||||
|
@subparser(ShowOSPFNeighborsHeaderParser)
|
||||||
|
class ShowOSPFNeighborsHeaderParser(CLIParser):
|
||||||
|
entryRegex = re.compile("([^ ]+)\s+([^ ]+)\s+([^/]+)/([^ ]+)\s+([^ ]+)\s+([^ ]+)\s+([^ ]+)$")
|
||||||
|
def enter(self, groups):
|
||||||
|
self.id, *rest = groups
|
||||||
|
self.result = dict(zip(
|
||||||
|
["priority", "state", "position", "timeout", "interface", "ip"], rest))
|
||||||
|
|
||||||
|
def exit(self):
|
||||||
|
self.parent.result[self.id] = self.result
|
@ -1,77 +1,11 @@
|
|||||||
import re
|
import re
|
||||||
|
from .CLIParser import CLIParser, subparser, ParserException
|
||||||
class ParserException(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def subparser(base):
|
|
||||||
def decorator(cls):
|
|
||||||
base.subparsers = { **base.subparsers, cls.entryRegex: cls }
|
|
||||||
return cls
|
|
||||||
return decorator
|
|
||||||
|
|
||||||
class CLIParser:
|
|
||||||
subparsers = {}
|
|
||||||
def __init__(self, groups=None, parent=None):
|
|
||||||
self.result = {}
|
|
||||||
self.parent = parent
|
|
||||||
self.cur = None
|
|
||||||
|
|
||||||
if parent is None:
|
|
||||||
assert(groups is None)
|
|
||||||
return
|
|
||||||
|
|
||||||
self.enter(groups)
|
|
||||||
|
|
||||||
def parse(self, line: str):
|
|
||||||
assert(self.cur == None)
|
|
||||||
if line is not None:
|
|
||||||
for k,v in self.subparsers.items():
|
|
||||||
if m := k.match(line):
|
|
||||||
self.cur = (c := v(groups=m.groups(), parent=self))
|
|
||||||
while c.cur is not None:
|
|
||||||
c = c.cur
|
|
||||||
return c
|
|
||||||
elif self.parent is None:
|
|
||||||
return self
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.exit()
|
|
||||||
self.parent.cur = None
|
|
||||||
return self.parent.parse(line)
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Failed to parse line: {line}")
|
|
||||||
raise e
|
|
||||||
|
|
||||||
def exit(self):
|
|
||||||
raise ParserException(f"Failed to match line to all regexes")
|
|
||||||
|
|
||||||
@subparser(CLIParser)
|
|
||||||
class VersionParser(CLIParser):
|
|
||||||
entryRegex = re.compile("BIRD ([0-9a-z._-]+) ready.")
|
|
||||||
def enter(self, groups):
|
|
||||||
self.version ,= groups
|
|
||||||
|
|
||||||
def exit(self):
|
|
||||||
if "version" in self.parent.result:
|
|
||||||
raise ParserException(f"Duplicate version line")
|
|
||||||
|
|
||||||
self.parent.result["version"] = self.version
|
|
||||||
|
|
||||||
class ShowRouteParser(CLIParser):
|
class ShowRouteParser(CLIParser):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.result["tables"] = {}
|
self.result["tables"] = {}
|
||||||
|
|
||||||
@subparser(ShowRouteParser)
|
|
||||||
class NothingParser(CLIParser):
|
|
||||||
entryRegex = re.compile("^$")
|
|
||||||
def enter(self, _):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def exit(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
@subparser(ShowRouteParser)
|
@subparser(ShowRouteParser)
|
||||||
class TableParser(CLIParser):
|
class TableParser(CLIParser):
|
||||||
entryRegex = re.compile("^Table (.*):$")
|
entryRegex = re.compile("^Table (.*):$")
|
||||||
@ -153,12 +87,3 @@ class InternalRouteHandlingValuesParser(CLIParser):
|
|||||||
if k in self.parent.result:
|
if k in self.parent.result:
|
||||||
raise ParserException(f"Duplicate internal value {k} in route")
|
raise ParserException(f"Duplicate internal value {k} in route")
|
||||||
self.parent.result[k] = v
|
self.parent.result[k] = v
|
||||||
|
|
||||||
def parse(data: str):
|
|
||||||
parser = ShowRouteParser()
|
|
||||||
for line in data.split("\n"):
|
|
||||||
parser = parser.parse(line)
|
|
||||||
|
|
||||||
parser = parser.parse(None)
|
|
||||||
|
|
||||||
return parser.result
|
|
||||||
|
@ -239,6 +239,7 @@ class DumpCheck:
|
|||||||
seen = []
|
seen = []
|
||||||
try:
|
try:
|
||||||
async with asyncio.timeout(self.check_timeout) as to:
|
async with asyncio.timeout(self.check_timeout) as to:
|
||||||
|
i = 0
|
||||||
while True:
|
while True:
|
||||||
dump = await self.obtain()
|
dump = await self.obtain()
|
||||||
try:
|
try:
|
||||||
@ -252,6 +253,8 @@ class DumpCheck:
|
|||||||
print(f"Differs at {' -> '.join([str(s) for s in reversed(d.tree)])}: {d.a} != {d.b}")
|
print(f"Differs at {' -> '.join([str(s) for s in reversed(d.tree)])}: {d.a} != {d.b}")
|
||||||
|
|
||||||
seen.append(dump)
|
seen.append(dump)
|
||||||
|
i += 1
|
||||||
|
print('\-|/'[i % 4] + "\010", end='', flush=True)
|
||||||
await asyncio.sleep(self.check_retry_timeout)
|
await asyncio.sleep(self.check_retry_timeout)
|
||||||
|
|
||||||
except TimeoutError as e:
|
except TimeoutError as e:
|
||||||
@ -302,6 +305,27 @@ class DumpRIB(DumpOnMachines):
|
|||||||
del r[k]
|
del r[k]
|
||||||
return d
|
return d
|
||||||
|
|
||||||
|
class DumpOSPFNeighbors(DumpOnMachines):
|
||||||
|
def __init__(self, *args, protocols, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
self.protocols = protocols
|
||||||
|
|
||||||
|
async def obtain_on_machine(self, mach):
|
||||||
|
d = await dict_gather({
|
||||||
|
p: mach.show_ospf_neighbors(proto=p)
|
||||||
|
for p in self.protocols
|
||||||
|
})
|
||||||
|
|
||||||
|
for p in d.values():
|
||||||
|
assert("version" in p)
|
||||||
|
del p["version"]
|
||||||
|
for pp in p.values():
|
||||||
|
for n in pp["neighbors"].values():
|
||||||
|
assert("timeout" in n)
|
||||||
|
del n["timeout"]
|
||||||
|
|
||||||
|
return d
|
||||||
|
|
||||||
class DumpLinuxKRT(DumpOnMachines):
|
class DumpLinuxKRT(DumpOnMachines):
|
||||||
def __init__(self, *args, cmdargs=None, **kwargs):
|
def __init__(self, *args, cmdargs=None, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
@ -456,35 +480,6 @@ 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.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
|
||||||
|
Loading…
Reference in New Issue
Block a user