ufes-20191-redes-mininet/proj-impl/topoautotest.py

195 lines
5.2 KiB
Python
Executable File

#!/usr/bin/env python3
# -*- encoding: utf-8 -*-
import sys
import json
import importlib
from subprocess import run, PIPE
from time import sleep
from pathlib import Path
def wait():
print('*** Waiting', file=sys.stderr)
sleep(2)
def speed_parser_iperf(iperfstdout):
speed, unit = iperfstdout.splitlines()[-1].split('/')[0].split(' ')[-2:]
speed = float(speed)
multiplier = {
'bits': 10**0,
'kbits': 10**3,
'mbits': 10**6,
'gbits': 10**9,
'tbits': 10**12,
}.get(unit.lower(), 1)
return int(speed*multiplier)
def make_host_pairs(hosts):
s = len(hosts)//2
r = hosts[-s:]
rs = len(r)
l = hosts[:-s][:rs]
return list(zip(l, list(reversed(r))))
def test_ping_sync(src, dst):
print(f'*** Pinging {src.IP()} -> {dst.IP()}', file=sys.stderr)
k = src.pexec('ping', dst.IP(), '-c', str(10))
_, avg, __, dev = (
list(map(
float,
k[0].splitlines()[-1].split('=')[1].strip().split(' ')[0].split('/')
))
)
return dict(avg=avg, mdev=dev)
def test_iperf_sync(src, dst):
print(f'*** Iperfing {src.IP()} -> {dst.IP()}', file=sys.stderr)
s = dst.popen('iperf', '-s')
k = src.pexec('iperf', '-c', dst.IP())
s.kill()
if k[0]=='':
raise Exception(k[1])
return speed_parser_iperf(k[0])
def do_sequential_tests(pingpair, iperfpairs):
print(f'*** Performing sequential tests', file=sys.stderr)
iperfres = list()
for iperfpair in iperfpairs:
iperfres.append(test_iperf_sync(*iperfpair))
wait()
pingres = test_ping_sync(*pingpair)
wait()
return dict(ping=pingres, iperfs=iperfres)
class IperfWaiter:
def __init__(self, *x):
self._x = x
def __call__(self):
s, k, *_ = self._x
k.wait()
k = (k.stdout.read().decode(), )
s.kill()
return speed_parser_iperf(k[0])
def test_iperf_async(src, dst):
print(f'*** Iperfing {src.IP()} -> {dst.IP()}', file=sys.stderr)
s = dst.popen('iperf', '-s')
k = src.popen('iperf', '-c', dst.IP())
return IperfWaiter(s, k)
class PingWaiter:
def __init__(self, *x):
self._x = x
def __call__(self):
k, *_ = self._x
k.wait()
k = (k.stdout.read().decode(), )
_, avg, __, dev = (
list(map(
float,
k[0].splitlines()[-1].split('=')[1].strip().split(' ')[0].split('/')
))
)
return dict(avg=avg, mdev=dev)
def test_ping_async(src, dst):
print(f'*** Pinging {src.IP()} -> {dst.IP()}', file=sys.stderr)
k = src.popen('ping', dst.IP(), '-c', str(10))
return PingWaiter(k)
def do_parallel_tests(pingpair, iperfpairs):
print(f'*** Performing parallel tests', file=sys.stderr)
iperfres = list()
for iperfpair in iperfpairs:
iperfres.append(test_iperf_async(*iperfpair))
pingres = test_ping_async(*pingpair)
pingres = pingres()
iperfres = [r() for r in iperfres]
# wait()
return dict(ping=pingres, iperfs=iperfres)
def do_tests(topo, hosts, net):
print(f'*** Controller is starting up', file=sys.stderr)
for _ in range(max(2, len(topo[1])/4)//2):
wait()
pairs = make_host_pairs(hosts)
pingpair, *iperfpairs = pairs
seqres = None
seqres = do_sequential_tests(pingpair, iperfpairs)
pllres = do_parallel_tests(pingpair, iperfpairs)
return dict(
sequential=seqres,
parallel=pllres
)
def main(topo, mod, resultspath, returns_result=False):
print(f'*** Creating network', file=sys.stderr)
net = mod.myNetwork()
try:
x = {h.name: h for h in net.hosts}
hosts = [x[h] for h in topo[0]]
res = do_tests(topo, hosts, net)
pingpair, *iperfpairs = make_host_pairs(topo[0])
res = dict(
pairs=dict(
ping=pingpair,
iperf=iperfpairs
),
**res
)
net.stop()
if returns_result:
return res
else:
resultspath.write_text(json.dumps(
res,
indent=4
))
except:
print("*** Aborted application", file=sys.stderr)
run(['mn', '-c'], stderr=PIPE, stdout=PIPE)
if returns_result:
return None
raise
if __name__ == "__main__":
if len(sys.argv) < 2:
print('Usage:')
print(f' {sys.argv[0]} <toponame>')
print()
print(' Where toponame is will be resolved to')
print(' toponame.json and toponame.state')
else:
modname = f'{sys.argv[1]}'
commentedname = modname+(
'.' if len(sys.argv) > 2 else ''
)+'.'.join(sys.argv[2:])
modfile = Path(f'{modname}.py')
topopath = Path(f'{modname}.json')
resultspath = Path(f'{commentedname}.autotest.json')
if not topopath.exists():
print(f'Topology {topopath}.json does not exist.')
if not modfile.exists():
print(f'Topology {topopath}.py does not exist.')
print(f'You might want to use toporender.py to generate required files.')
else:
topo = json.loads(topopath.read_text())
mod = importlib.import_module(modname)
main(topo, mod, resultspath)