"""Seed a throwaway GANDALF database with fictional data (documentation IP ranges only).""" # flake8: noqa: E501 (demo data and canned output contain long literal lines) import json import random from datetime import datetime, timedelta, timezone import pymysql random.seed(11) conn = pymysql.connect( host="127.0.0.1", port=3398, user="gandalf", password="demo-only", database="gandalf", autocommit=True, charset="utf8mb4", ) cur = conn.cursor() now = datetime.now(timezone.utc) def ts(h): return (now - timedelta(hours=h)).strftime("%Y-%m-%d %H:%M:%S") def state(k, v): cur.execute( "REPLACE INTO monitor_state (key_name,value) VALUES (%s,%s)", (k, v if isinstance(v, str) else json.dumps(v)) ) # ---- hosts / interfaces: (name, ip, [(iface, speed_mbps, up, kind)]) kind: rj45 | fiber | dac HOSTS = [ ( "compute-storage-01", "192.0.2.4", [("eno1", 1000, True, "rj45"), ("enp1s0f0", 10000, True, "dac"), ("enp1s0f1", 10000, True, "dac")], ), ("compute-storage-gpu-01", "192.0.2.10", [("enp2s0", 1000, True, "rj45"), ("enp4s0", 10000, True, "fiber")]), ("large1", "192.0.2.2", [("enp3s0", 1000, True, "rj45"), ("enp5s0", 10000, True, "fiber")]), ( "storage-01", "192.0.2.11", [("enp5s0", 1000, True, "rj45"), ("enp1s0", 10000, False, "fiber")], ), # regression: link down ( "micro1", "192.0.2.8", [("enp2s0", 1000, True, "rj45"), ("enp3s0", 1000, False, "rj45")], ), # unused bond leg (baseline, not alerted) ("monitor-02", "192.0.2.9", [("enp2s0", 1000, True, "rj45"), ("enp3s0", 1000, True, "rj45")]), ] hosts = {} for name, ip, ifs in HOSTS: st = [u for _, _, u, _ in ifs] status = "up" if all(st) else ("down" if not any(st) else "degraded") hosts[name] = { "ip": ip, "interfaces": {i: ("up" if u else "down") for i, _, u, _ in ifs}, "status": status, "source": "prometheus", } hosts["backup-01"] = {"ip": "198.51.100.20", "interfaces": {}, "status": "up", "source": "ping"} unifi = [ { "name": "Dream Machine Pro", "mac": "aa:bb:cc:00:00:01", "ip": "192.0.2.1", "type": "udm", "model": "UDMPRO", "state": 1, "connected": True, }, { "name": "Pro 24 PoE", "mac": "aa:bb:cc:00:00:02", "ip": "192.0.2.30", "type": "usw", "model": "US24PRO", "state": 1, "connected": True, }, { "name": "USW-Aggregation", "mac": "aa:bb:cc:00:00:03", "ip": "192.0.2.31", "type": "usw", "model": "USL8A", "state": 1, "connected": True, }, { "name": "UNVR Pro", "mac": "aa:bb:cc:00:00:04", "ip": "192.0.2.40", "type": "unvr", "model": "UNVRPRO", "state": 1, "connected": True, }, { "name": "Garage AP", "mac": "aa:bb:cc:00:00:05", "ip": "192.0.2.41", "type": "uap", "model": "U6LR", "state": 0, "connected": False, }, { "name": "Office AP", "mac": "aa:bb:cc:00:00:06", "ip": "192.0.2.42", "type": "uap", "model": "U6PRO", "state": 1, "connected": True, }, ] state("network_snapshot", {"hosts": hosts, "unifi": unifi, "updated": now.isoformat().replace("+00:00", "Z")}) state("last_check", now.strftime("%Y-%m-%d %H:%M:%S UTC")) # ---- per-interface link stats def rate(speed, frac): return speed * 1e6 / 8 * frac link_hosts = {} for name, ip, ifs in HOSTS: d = {} for iface, speed, up, kind in ifs: e = {"host_ip": ip, "link_detected": up, "carrier_changes": random.choice([1, 2, 2, 3]) if up else 9} if up: f = random.uniform(0.01, 0.18) if speed == 1000 else random.uniform(0.04, 0.38) e.update( { "speed_mbps": speed, "duplex": "Full", "auto_neg": True, "tx_bytes_rate": rate(speed, f), "rx_bytes_rate": rate(speed, f * random.uniform(0.5, 1.4)), "tx_errs_rate": 0.0, "rx_errs_rate": 0.0, "tx_drops_rate": 0.0, "rx_drops_rate": 0.0, } ) else: e.update( { "speed_mbps": None, "duplex": None, "auto_neg": True, "tx_bytes_rate": 0, "rx_bytes_rate": 0, "tx_errs_rate": 0, "rx_errs_rate": 0, "tx_drops_rate": 0, "rx_drops_rate": 0, } ) if up and kind == "fiber": e["sfp"] = { "sfp_type": "SFP+ 10GBASE-SR", "vendor": "FS", "part_no": "SFP-10GSR-85", "temp_c": round(random.uniform(38, 47), 1), "tx_power_dbm": round(random.uniform(-2.8, -1.6), 2), "rx_power_dbm": round(random.uniform(-4.5, -3.0), 2), } if up and kind == "dac": e["sfp"] = {"sfp_type": "SFP+ passive DAC", "vendor": "Ubiquiti", "part_no": "UACC-DAC-SFP10-1M"} d[iface] = e link_hosts[name] = d # one marginal fibre (low RX power) for the warning colour link_hosts["large1"]["enp5s0"]["sfp"].update({"rx_power_dbm": -10.9, "temp_c": 58.4}) link_hosts["large1"]["enp5s0"]["carrier_changes"] = 6 # ---- UniFi switch ports (with LLDP neighbours = the hosts above) def port(idx, up, speed, sw_ip, uplink=False, media="GE", lldp=None, poe=None, frac=0.05): def r(): return rate(speed, frac * random.uniform(0.5, 1.5)) if up else 0 p = { "port_idx": idx, "switch_ip": sw_ip, "up": up, "speed_mbps": speed if up else 0, "full_duplex": up, "autoneg": True, "is_uplink": uplink, "media": media, "poe_power": poe[0] if poe else None, "poe_class": poe[1] if poe else None, "poe_max_power": poe[2] if poe else None, "poe_mode": "auto" if poe else "", "lldp": lldp, "tx_bytes": int(random.uniform(1e11, 9e12)) if up else 0, "rx_bytes": int(random.uniform(1e11, 9e12)) if up else 0, "tx_errors": 0, "rx_errors": 0, "tx_dropped": 0, "rx_dropped": 0, "tx_bytes_rate": r(), "rx_bytes_rate": r(), "tx_errs_rate": 0.0, "rx_errs_rate": 0.0, "tx_drops_rate": 0.0, "rx_drops_rate": 0.0, } return p def L(host, iface): return { "chassis_id": "aa:bb:cc:11:22:33", "system_name": host, "port_id": iface, "port_desc": iface, "mgmt_ips": [dict(HOSTS_IP)[host]] if False else [], } HOSTS_IP = {n: ip for n, ip, _ in HOSTS} pro = {} mgmt = [ (1, "compute-storage-01", "eno1"), (2, "compute-storage-gpu-01", "enp2s0"), (3, "large1", "enp3s0"), (4, "storage-01", "enp5s0"), (5, "micro1", "enp2s0"), (6, "monitor-02", "enp2s0"), (7, "monitor-02", "enp3s0"), ] for i in range(1, 25): m = [x for x in mgmt if x[0] == i] if m: pro[f"Port {i}"] = port(i, True, 1000, "192.0.2.30", lldp=L(m[0][1], m[0][2]), frac=0.06) elif i == 8: pro[f"Port {i}"] = port(i, False, 0, "192.0.2.30") # micro1 unused bond leg elif i in (10, 11, 12): pro[f"Port {i}"] = port( i, True, 100 if i == 12 else 1000, "192.0.2.30", lldp=None, poe=(round(random.uniform(3, 9), 1), 4, 30.0), frac=0.02, ) # APs / cameras on PoE elif i == 9: pro[f"Port {i}"] = port( i, True, 1000, "192.0.2.30", lldp={ "chassis_id": "aa:bb:cc:00:00:04", "system_name": "UNVR Pro", "port_id": "eth0", "port_desc": "eth0", "mgmt_ips": [], }, poe=(0.0, 0, 30.0), frac=0.2, ) else: pro[f"Port {i}"] = port(i, False, 0, "192.0.2.30") pro["Port 25"] = port( 25, True, 10000, "192.0.2.30", uplink=True, media="SFP+", lldp={ "chassis_id": "aa:bb:cc:00:00:03", "system_name": "USW-Aggregation", "port_id": "Port 7", "port_desc": "Port 7", "mgmt_ips": [], }, frac=0.08, ) pro["Port 26"] = port(26, False, 0, "192.0.2.30", media="SFP+") agg = {} aggmap = [ (1, "compute-storage-01", "enp1s0f0"), (2, "compute-storage-01", "enp1s0f1"), (3, "compute-storage-gpu-01", "enp4s0"), (4, "large1", "enp5s0"), (5, "storage-01", "enp1s0"), ] for i in range(1, 9): m = [x for x in aggmap if x[0] == i] if i == 5: agg[f"Port {i}"] = port(i, False, 0, "192.0.2.31", media="SFP+", lldp=None) # storage-01 10G link is down elif m: agg[f"Port {i}"] = port(i, True, 10000, "192.0.2.31", media="SFP+", lldp=L(m[0][1], m[0][2]), frac=0.15) elif i == 7: agg[f"Port {i}"] = port( i, True, 10000, "192.0.2.31", uplink=True, media="SFP+", lldp={ "chassis_id": "aa:bb:cc:00:00:02", "system_name": "Pro 24 PoE", "port_id": "Port 25", "port_desc": "Port 25", "mgmt_ips": [], }, frac=0.08, ) else: agg[f"Port {i}"] = port(i, False, 0, "192.0.2.31", media="SFP+") state( "link_stats", { "hosts": link_hosts, "unifi_switches": { "Pro 24 PoE": {"ip": "192.0.2.30", "model": "US24PRO", "ports": pro}, "USW-Aggregation": {"ip": "192.0.2.31", "model": "USL8A", "ports": agg}, }, "updated": now.strftime("%Y-%m-%d %H:%M:%S UTC"), }, ) # ---- events EV = [ # type, sev, source, target, detail, desc, first_seen_h, last_seen_h, resolved_h|None, fails, ticket ( "interface_down", "warning", "prometheus", "storage-01", "enp1s0", "Interface enp1s0 on storage-01 went down (UP -> DOWN regression).", 3.2, 0.0, None, 5, "731905284", ), ( "unifi_device_offline", "warning", "unifi", "Garage AP", "uap / 192.0.2.41", 'UniFi device "Garage AP" has been offline for 3 consecutive checks.', 1.1, 0.0, None, 3, "731905301", ), ( "interface_down", "warning", "prometheus", "compute-storage-01", "enp1s0f1", "Interface enp1s0f1 on compute-storage-01 went down.", 9.0, 7.5, 7.4, 2, None, ), ( "host_unreachable", "warning", "ping", "backup-01", "198.51.100.20", "Host backup-01 stopped answering ping for 2 consecutive checks.", 30.0, 28.0, 27.9, 2, "731881772", ), ( "unifi_device_offline", "warning", "unifi", "Office AP", "uap / 192.0.2.42", 'UniFi device "Office AP" was offline for 3 consecutive checks.', 19.0, 18.0, 17.8, 3, "731890014", ), ] for t, sev, src, tgt, det, desc, f, l, r, fails, tid in EV: cur.execute( "INSERT INTO network_events (event_type,severity,source_type,target_name,target_detail,description,first_seen,last_seen,resolved_at,consecutive_failures,ticket_id) VALUES (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)", (t, sev, src, tgt, det, desc, ts(f), ts(l), ts(r) if r is not None else None, fails, tid), ) # ---- suppressions (one active timed, one manual, one expired in history) SUP = [ ("interface", "micro1", "enp3s0", "Unused bond leg, cable not connected", "alex.rivera", 48, None, 1), ("host", "monitor-02", "", "Planned firmware update window", "alex.rivera", 0.4, 0.6, 1), ("unifi_device", "Office AP", "", "Replacing the access point", "sam.chen", 30, 29, 0), ] for tt, tn, td, reason, by, created_h, exp_in, active in SUP: exp = ( (now + timedelta(hours=exp_in)).strftime("%Y-%m-%d %H:%M:%S") if exp_in and exp_in > 0 else (ts(-exp_in) if exp_in else None) ) cur.execute( "INSERT INTO suppression_rules (target_type,target_name,target_detail,reason,suppressed_by,created_at,expires_at,active) VALUES (%s,%s,%s,%s,%s,%s,%s,%s)", (tt, tn, td, reason, by, ts(created_h), exp, active), ) print("seeded: hosts", len(hosts), "unifi", len(unifi), "events", len(EV), "suppressions", len(SUP))