Skip to content
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:, 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
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_", 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 ='from ([0-9\.]+).* time=(.*) ms', line)
if m:
row[ip] =
assert ip ==
def traceroute_response(self, ip, data):
for line in data.splitlines():
m ='(\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
def ping_error(self, ip, data):
if ip in self.sources:
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:
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]):
'--first=%s' % n,
'--max-hops=%s' % n,
_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))
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()}
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:'-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
r[ip] = None
if npings == 0:
status('no more pings to send')
def main():
pingSheets = [PingSheet(ip, source=ip) for ip in sys.argv[1:]]
topSheets = [StatsSheet("traceroute_", source=vs) for vs in pingSheets]
You can’t perform that action at this time.