Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
executable file 151 lines (119 sloc) 5.11 KB
#!/usr/bin/env python3
import sys
from statistics import mean
from vdtui import *
import sh
option('ping_count', 3, 'send this many pings to each host')
option('ping_interval', 0.1, 'wait between ping rounds, in seconds')
globalCommand('^C', 'for s in topSheets: s.stop = True; status("user stopped")', 'stop pinging')
globalCommand('^S', 'save_tsv(sheet, input("save tsv to: ", value=name+".tsv"))', 'save this sheet as tsv')
options.false_is_null = True
# rowdef: ColumnPing
class StatsSheet(Sheet):
columns = [
Column('hop', type=int, width=5, getter=lambda col,r: col.sheet.source.sources.index(r.ip)+1),
Column('hostname', getter=lambda col,r: r.name, width=40),
Column('ip', getter=lambda col,r: r.ip, width=17),
Column('avg_ms', type=float, fmtstr='{:.1f}', getter=lambda col,r: mean(r.getValues(col.sheet.source.rows))),
Column('max_ms', type=float, fmtstr='{:.1f}', getter=lambda col,r: max(r.getValues(col.sheet.source.rows))),
Column('count', type=int, getter=lambda col,r: len(list(r.getValues(col.sheet.source.rows)))),
]
def reload(self):
sheet = self.source
sheet.reload()
self.rows = sheet.columns
def ColumnPing(name, ip):
c = Column(name, getter=lambda col,r: r.get(ip), type=float, fmtstr='{:0.1f}')
c.ip = ip
return c
class PingSheet(Sheet):
commands = [
Command('T', 'vd.push(StatsSheet("traceroute_"+sheet.name, source=sheet))', 'push traceroute sheet with summary pingtimes')
]
def __init__(self, name, source=None, **kwargs):
super().__init__(name, source=source, **kwargs)
self.sources = [source]
def ping_response(self, row, ip, data):
for line in data.splitlines():
m = re.search(r'from ([0-9\.]+).* time=(.*) ms', line)
if m:
row[ip] = m.group(2)
assert ip == m.group(1)
def traceroute_response(self, ip, data):
for line in data.splitlines():
m = re.search(r'(\d+) (\S+) \((\S+)\) (.*) ms', line)
if m:
ttl, hostname, inner_ip, latency_ms = m.groups()
self.routes[ip][int(ttl)-1] = inner_ip
if inner_ip == ip:
return # traceroute work is done, let ping do the rest
if inner_ip not in self.sources:
self.sources.insert(-1, inner_ip)
self.columns.insert(-1, ColumnPing(hostname, inner_ip))
self.send_trace(ip, int(ttl)+1) # get next hop
break
def ping_error(self, ip, data):
if ip in self.sources:
self.sources.remove(ip)
status("%s removed" % ip)
def update_traces(self, row, ip):
rtes = self.routes.get(ip)
if rtes is None:
rtes = []
self.routes[ip] = rtes
if ip in rtes:
return
for i, inner_ip in enumerate(rtes):
if inner_ip is None:
self.send_trace(ip, i+1)
self.send_trace(ip, len(rtes)+1) # and one more for the road
def send_trace(self, ip, n):
while n > len(self.routes[ip]):
self.routes[ip].append(None)
sh.traceroute('--sim-queries=1',
'--queries=1',
'--first=%s' % n,
'--max-hops=%s' % n,
ip,
_bg=True, _bg_exc=False,
_out=lambda data,self=self,ip=ip,a=1: self.traceroute_response(ip, data),
_err=lambda data,self=self,ip=ip,a=1: self.ping_error(ip, data))
@async
def reload(self):
self.stop = False
self.start_time = time.time()
self.columns = [
# Column('time', type=float, getter=lambda r,self=self: r['time']-self.start_time),
]
for ip in self.sources:
self.columns.append(ColumnPing(ip, ip))
self.routes = {}
self.rows = []
pings_sent = {}
ping_count = options.ping_count
while not self.stop:
r = {'time':time.time()}
self.rows.append(r)
if self.cursorRowIndex == len(self.rows)-2:
self.cursorRowIndex = len(self.rows)-1
npings = 0 # this loop
for ip in self.sources:
self.update_traces(r, ip)
pings_sent[ip] = pings_sent.get(ip, 0)+1
if ping_count and pings_sent[ip] <= ping_count:
sh.ping('-c', '1', ip, _bg=True, _bg_exc=False, _timeout=30,
_out=lambda data,self=self,r=r,ip=ip: self.ping_response(r,ip,data))
# _err=lambda data,self=self,ip=ip,a=1: self.ping_error(ip, data))
npings += 1
else:
r[ip] = None
if npings == 0:
status('no more pings to send')
break
time.sleep(options.ping_interval)
def main():
run(*topSheets)
pingSheets = [PingSheet(ip, source=ip) for ip in sys.argv[1:]]
topSheets = [StatsSheet("traceroute_"+vs.name, source=vs) for vs in pingSheets]
addGlobals(globals())
main()
You can’t perform that action at this time.