#!/usr/bin/env python3 # -*- coding: utf-8 -*- """Ping every collected switch's management IP in parallel. Zabbix host -> switch latency is the only latency that can be measured without touching device config, so this is what drives the node latency colouring. Writes /tmp/latency.tsv -> \\t """ import json import re import subprocess import concurrent.futures as cf import urllib.request import l2cfg TOK = 'd3abb125eb301a021ef80a2847a803a7cd2d0b1d3c8337a14d09db9d571369b5' API = 'http://192.168.87.20:8080/api_jsonrpc.php' OUT = '/tmp/latency.tsv' def call(m, p): d = json.dumps({"jsonrpc": "2.0", "method": m, "params": p, "id": 1}).encode() q = urllib.request.Request(API, data=d, headers={'Content-Type': 'application/json', 'Authorization': 'Bearer ' + TOK}) return json.loads(urllib.request.urlopen(q, timeout=60).read().decode()) def ping(ip): try: r = subprocess.run(['ping', '-c', '3', '-W', '1', '-q', ip], capture_output=True, text=True, timeout=10) m = re.search(r'=\s*[\d.]+/([\d.]+)/', r.stdout) if m: return ip, float(m.group(1)) m = re.search(r'time=([\d.]+)\s*ms', r.stdout) if m: return ip, float(m.group(1)) except Exception: pass return ip, None def main(): hs = l2cfg.hosts(call) ips = sorted({i['ip'] for h in hs for i in (h.get('interfaces') or []) if i.get('ip') and i.get('type') == '2'}) if not ips: ips = sorted({i['ip'] for h in hs for i in (h.get('interfaces') or []) if i.get('ip')}) res = {} with cf.ThreadPoolExecutor(max_workers=40) as ex: for ip, v in ex.map(ping, ips): res[ip] = v with open(OUT, 'w', encoding='utf-8') as f: for ip in ips: v = res.get(ip) f.write('%s\t%s\n' % (ip, '' if v is None else '%.3f' % v)) ok = sum(1 for v in res.values() if v is not None) print('latency: %d/%d reachable' % (ok, len(ips))) if __name__ == '__main__': main()