73 lines
2.0 KiB
Python
73 lines
2.0 KiB
Python
#!/usr/bin/env python3
|
|
"""Asynchronous network monitoring script, reports current state every 5 seconds."""
|
|
|
|
from ipaddress import (
|
|
IPv4Address as IPAddress,
|
|
IPv4Network as IPNetwork,
|
|
IPv4Interface as IPInterface,
|
|
AddressValueError,
|
|
)
|
|
|
|
from dbus_fast.aio import MessageBus
|
|
from dbus_fast import Variant, BusType
|
|
import re
|
|
import asyncio
|
|
from subprocess import PIPE
|
|
import functools
|
|
|
|
MONITOR_IPS = {"ezrinet": IPAddress("10.242.3.1"), "internet": IPAddress("1.1.1.1")}
|
|
|
|
INTERFACE_IGNORE_PATTERNS = [
|
|
re.compile(r"^vb-"),
|
|
re.compile(r"^vz-"),
|
|
re.compile(r"^virbr[0-9]+"),
|
|
re.compile(r"^lo$"),
|
|
]
|
|
|
|
|
|
def timer(interval: float, initial_delay: float = 0):
|
|
"""Decorate a function or coroutine to run it on the given interval."""
|
|
|
|
def decorator(func):
|
|
|
|
async def do_interval():
|
|
try:
|
|
await asyncio.sleep(initial_delay)
|
|
while True:
|
|
await func()
|
|
await asyncio.sleep(interval)
|
|
except asyncio.CancelledError:
|
|
return
|
|
|
|
def start():
|
|
loop = asyncio.get_running_loop()
|
|
if "_timer_task" in func.__dict__:
|
|
raise Exception("Timer is already running.")
|
|
func.__dict__["_timer_task"] = loop.create_task(do_interval())
|
|
|
|
func.__dict__["start"] = start
|
|
return func
|
|
|
|
return decorator
|
|
|
|
|
|
async def ping(address: IPAddress) -> tuple[bool, float | None]:
|
|
"""Ping a host and return a tuple of [success, ping time]."""
|
|
proc = await asyncio.create_subprocess_exec(
|
|
"ping", "-c1", "-w1", "-n", str(address), stdout=PIPE
|
|
)
|
|
stdout, stderr = await proc.communicate()
|
|
|
|
_match = re.search(
|
|
r"icmp_seq=1 ttl=[0-9]+ time=([0-9]+\.?[0-9]*) ms", stdout.decode("utf-8")
|
|
)
|
|
if _match is None:
|
|
return (False, None)
|
|
else:
|
|
return (True, float(_match.group(1)))
|
|
|
|
|
|
@timer(5)
|
|
async def ping_checks():
|
|
"""Recurring ping checks for configured IP addresses."""
|