Tentative first version
This commit is contained in:
parent
5be5c4b444
commit
8ecc1f85b7
4 changed files with 90 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1,2 +1,3 @@
|
|||
*.sqlite3
|
||||
*.egg-info
|
||||
__pycache__
|
||||
|
|
66
netmon/entry.py
Normal file
66
netmon/entry.py
Normal file
|
@ -0,0 +1,66 @@
|
|||
from .ping import Ping
|
||||
import time
|
||||
import typing as t
|
||||
import sqlite3
|
||||
import argparse
|
||||
import logging
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def record(target: str, interval: int, outage_interval: int):
|
||||
"""Record errors while pinging `target` each `interval` seconds"""
|
||||
|
||||
ping = Ping(target)
|
||||
db = sqlite3.connect("netmon.sqlite3")
|
||||
|
||||
outage: t.Optional[int] = None
|
||||
|
||||
try:
|
||||
while True:
|
||||
res = ping.ping()
|
||||
if outage is None and not res: # beginning of outage
|
||||
outage = int(time.time())
|
||||
logger.info("Could not reach target.")
|
||||
|
||||
elif outage is not None and res: # end of outage
|
||||
delta = int(time.time() - outage)
|
||||
logger.info(
|
||||
"Could reach target again (out for %d min %d s)",
|
||||
delta // 60,
|
||||
delta % 60,
|
||||
)
|
||||
with db:
|
||||
db.execute(
|
||||
"INSERT INTO errors (from_time, to_time, host) VALUES (?, ?, ?);",
|
||||
(int(outage), int(time.time()), target),
|
||||
)
|
||||
time.sleep(interval if outage is None else outage_interval)
|
||||
except KeyboardInterrupt as exn:
|
||||
if outage is not None:
|
||||
with db:
|
||||
db.execute(
|
||||
"INSERT INTO errors (from_time, to_time, host) VALUES (?, ?, ?);",
|
||||
(int(outage), int(time.time()), target),
|
||||
)
|
||||
raise exn
|
||||
|
||||
|
||||
def entry():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("host", help="Remote host to ping (IP address preferred)")
|
||||
parser.add_argument("-i", "--interval", default=30, help="Time between two pings")
|
||||
parser.add_argument(
|
||||
"-I",
|
||||
"--outage-interval",
|
||||
default=2,
|
||||
help="Time between two pings while the network is down",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
record(args.host, args.interval, args.outage_interval)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
entry()
|
23
netmon/ping.py
Normal file
23
netmon/ping.py
Normal file
|
@ -0,0 +1,23 @@
|
|||
import subprocess
|
||||
|
||||
|
||||
class Ping:
|
||||
host: str
|
||||
_cmd: list[str]
|
||||
|
||||
def __init__(self, host: str):
|
||||
self.host = host
|
||||
self._cmd = ["/usr/bin/ping", "-c", "1", "-W", "1", "-qn", self.host]
|
||||
|
||||
def ping(self) -> bool:
|
||||
try:
|
||||
subprocess.run(
|
||||
self._cmd,
|
||||
shell=False,
|
||||
check=True,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
)
|
||||
return True
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
0
netmon/py.typed
Normal file
0
netmon/py.typed
Normal file
Loading…
Reference in a new issue