formating

This commit is contained in:
2022-01-20 20:14:59 -05:00
parent 6caf808301
commit e911fc4420
4 changed files with 940 additions and 841 deletions
+281 -184
View File
@@ -72,7 +72,7 @@ INTERVAL = 10
GRACE = 2 GRACE = 2
DROPOVERDUE = 7 * 24 * 3600 DROPOVERDUE = 7 * 24 * 3600
os.environ['TZ'] = 'EST5EDT' os.environ["TZ"] = "EST5EDT"
tsfm = ["%H", "%d", "%U"] tsfm = ["%H", "%d", "%U"]
lastfm = ["", "", ""] lastfm = ["", "", ""]
@@ -121,7 +121,7 @@ def handler(signum, frame):
def shortname(name): def shortname(name):
r = name.split('.') r = name.split(".")
return r[0] return r[0]
@@ -161,14 +161,14 @@ def stodict(msg):
d = {} d = {}
if len(msg) > 0 and chr(msg[0]) == "!": if len(msg) > 0 and chr(msg[0]) == "!":
pk = zlib.decompress(msg[5:]).decode() pk = zlib.decompress(msg[5:]).decode()
d['ID'] = msg[1:4].decode() d["ID"] = msg[1:4].decode()
else: else:
r0 = msg.split(':',1) r0 = msg.split(":", 1)
pk = r0[1] pk = r0[1]
d['ID'] = r0[0] d["ID"] = r0[0]
r = pk.split(';') r = pk.split(";")
for v in r: for v in r:
vr = v.split('=', 1) vr = v.split("=", 1)
k = vr[0].strip() k = vr[0].strip()
if len(vr) == 1: if len(vr) == 1:
d[k] = None d[k] = None
@@ -181,7 +181,7 @@ def stodict(msg):
def oldmtodict(msg): def oldmtodict(msg):
return stodict('HTB:'+msg) return stodict("HTB:" + msg)
def email(s, msg): def email(s, msg):
@@ -192,10 +192,17 @@ def email(s, msg):
fromemail = "aew.heartbeat@wrede.ca" fromemail = "aew.heartbeat@wrede.ca"
subj = "Info from %s: %s" % (NAME, s) subj = "Info from %s: %s" % (NAME, s)
date = time.strftime("%a, %d %b %Y %H:%M:%S %z", time.localtime()) date = time.strftime("%a, %d %b %Y %H:%M:%S %z", time.localtime())
body = "To: %s\nFrom: %s\nSubject: %s\nDate: %s\n\n%s" % (toaddrs[0], fromemail, subj, date, msg) body = "To: %s\nFrom: %s\nSubject: %s\nDate: %s\n\n%s" % (
toaddrs[0],
fromemail,
subj,
date,
msg,
)
try: try:
server = smtplib.SMTP(SMTPSERVER) server = smtplib.SMTP(SMTPSERVER)
if DEBUG > 0: server.set_debuglevel(1) if DEBUG > 0:
server.set_debuglevel(1)
server.sendmail(fromemail, toaddrs, body) server.sendmail(fromemail, toaddrs, body)
except smtplib.SMTPRecipientsRefused as errs: except smtplib.SMTPRecipientsRefused as errs:
log(None, "cannot send email: %s\n" % (errs)) log(None, "cannot send email: %s\n" % (errs))
@@ -209,6 +216,7 @@ def email(s, msg):
pass pass
return ret return ret
def pushmsg(msg): def pushmsg(msg):
if pushsrv in ["all", "pushover"]: if pushsrv in ["all", "pushover"]:
pushover(msg) pushover(msg)
@@ -225,37 +233,41 @@ def pushover(msg):
return return
conn = http.client.HTTPSConnection("api.pushover.net:443") conn = http.client.HTTPSConnection("api.pushover.net:443")
try: try:
conn.request("POST", "/1/messages.json", conn.request(
urllib.parse.urlencode({ "POST",
"/1/messages.json",
urllib.parse.urlencode(
{
"token": "ac7NLX2rPjXFareeDgLpXNoDf4iFmf", "token": "ac7NLX2rPjXFareeDgLpXNoDf4iFmf",
"user": "uDhH33UjQQDYtNzJb1ThRiWb9ingGK", "user": "uDhH33UjQQDYtNzJb1ThRiWb9ingGK",
"message": msg, }), { "Content-type": "application/x-www-form-urlencoded" }) "message": msg,
}
),
{"Content-type": "application/x-www-form-urlencoded"},
)
conn.getresponse() conn.getresponse()
except: except:
pass pass
CHANNEL = "Monitoring" CHANNEL = "Monitoring"
TOKEN = "rxz6b3886iygxnhbzpmgbsrocy" TOKEN = "rxz6b3886iygxnhbzpmgbsrocy"
HOST = "192.168.10.101" HOST = "192.168.10.101"
ICON = "https://in-transit.ca/HeartBeat.png" ICON = "https://in-transit.ca/HeartBeat.png"
USERNAME = "admin" USERNAME = "admin"
def pushmattermost(msg): def pushmattermost(msg):
ses = { ses = {
'url': HOST, "url": HOST,
'scheme':'http', "scheme": "http",
'basepath': '/api/v4', "basepath": "/api/v4",
'port':8065, "port": 8065,
} }
mm = Driver(ses) mm = Driver(ses)
msg = { msg = {"text": msg, "channel": CHANNEL, "username": USERNAME, "icon_url": ICON}
"text": msg,
"channel": CHANNEL,
"username": USERNAME,
"icon_url": ICON
}
try: try:
rc = mm.webhooks.call_webhook(TOKEN, msg) rc = mm.webhooks.call_webhook(TOKEN, msg)
@@ -264,21 +276,30 @@ def pushmattermost(msg):
if not rc: if not rc:
print(rc) print(rc)
USER = "+16472472447" USER = "+16472472447"
RECIPIENT = "+14168226179" RECIPIENT = "+14168226179"
def pushsignal(msg, title="hbd", recipient=RECIPIENT): def pushsignal(msg, title="hbd", recipient=RECIPIENT):
message = f'{title}: {msg}' message = f"{title}: {msg}"
CLI = [ CLI = [
"/usr/local/bin/sudo", "-u", "andreas", "/usr/local/bin/sudo",
"/usr/local/bin/signal-cli", "-u", USER, "-u",
"send", "-m", message, "andreas",
"/usr/local/bin/signal-cli",
"-u",
USER,
"send",
"-m",
message,
# "-g", GROUP, # "-g", GROUP,
recipient, recipient,
] ]
if verbose: print(f"DBG cli: {CLI}") if verbose:
print(f"DBG cli: {CLI}")
res = subprocess.run(CLI, shell=False, capture_output=True) res = subprocess.run(CLI, shell=False, capture_output=True)
rc = res.returncode == 0 rc = res.returncode == 0
print(res.stdout.decode()) print(res.stdout.decode())
@@ -286,7 +307,8 @@ def pushsignal(msg, title="hbd", recipient=RECIPIENT):
if not rc: if not rc:
print(f"signalcli failed: {res.stderr.decode()}") print(f"signalcli failed: {res.stderr.decode()}")
else: else:
if verbose: print(f"signalcli msg sent, res {res.stdout.decode()}") if verbose:
print(f"signalcli msg sent, res {res.stdout.decode()}")
return rc return rc
@@ -294,33 +316,41 @@ def pushsignal(msg, title="hbd", recipient=RECIPIENT):
# return: None if ok, else error text # return: None if ok, else error text
def nsupdate(hostname, newip, dyndomain): def nsupdate(hostname, newip, dyndomain):
D = {} D = {}
D['domain'] = dyndomain D["domain"] = dyndomain
D['fqdn'] = "%s.dy.%s" % (hostname, dyndomain) D["fqdn"] = "%s.dy.%s" % (hostname, dyndomain)
D['dnsttl'] = '5' D["dnsttl"] = "5"
D['newip'] = newip D["newip"] = newip
D['ts'] = time.strftime('%Y-%m-%d.%H:%M:%S', time.gmtime()) D["ts"] = time.strftime("%Y-%m-%d.%H:%M:%S", time.gmtime())
if newip.find(":") > 0: if newip.find(":") > 0:
nsup = """update delete %(fqdn)s AAAA nsup = (
"""update delete %(fqdn)s AAAA
update add %(fqdn)s %(dnsttl)s AAAA %(newip)s update add %(fqdn)s %(dnsttl)s AAAA %(newip)s
update delete %(fqdn)s TXT update delete %(fqdn)s TXT
update add %(fqdn)s %(dnsttl)s TXT "Created: %(ts)s" update add %(fqdn)s %(dnsttl)s TXT "Created: %(ts)s"
send send
answer answer
""" % D """
% D
)
else: else:
nsup = """update delete %(fqdn)s A nsup = (
"""update delete %(fqdn)s A
update add %(fqdn)s %(dnsttl)s A %(newip)s update add %(fqdn)s %(dnsttl)s A %(newip)s
update delete %(fqdn)s TXT update delete %(fqdn)s TXT
update add %(fqdn)s %(dnsttl)s TXT "Created: %(ts)s" update add %(fqdn)s %(dnsttl)s TXT "Created: %(ts)s"
send send
answer answer
""" % D """
% D
)
if DEBUG > 0: log(None, "DBG: nsup %s" % nsup) if DEBUG > 0:
log(None, "DBG: nsup %s" % nsup)
cmd = [nsupdate_bin, "-k", "/etc/dhcpc/Kdy.%(domain)s.+157+00000." % D, "-v"] cmd = [nsupdate_bin, "-k", "/etc/dhcpc/Kdy.%(domain)s.+157+00000." % D, "-v"]
if DEBUG > 0: log(None, "DBG: cmd %s" % cmd) if DEBUG > 0:
log(None, "DBG: cmd %s" % cmd)
try: try:
p = Popen(cmd, shell=False, bufsize=1, stdin=PIPE, stdout=PIPE, stderr=STDOUT) p = Popen(cmd, shell=False, bufsize=1, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
except OSError as e: except OSError as e:
@@ -329,7 +359,7 @@ answer
return "nsupdate: some error occured" return "nsupdate: some error occured"
(output, err) = p.communicate(nsup.encode()) (output, err) = p.communicate(nsup.encode())
if output.decode().find('status: NOERROR') >= 0: if output.decode().find("status: NOERROR") >= 0:
return None return None
return output.decode() + err.decode() return output.decode() + err.decode()
@@ -355,9 +385,11 @@ def fixsort():
hbdclass.Host.hosts[n].num = x hbdclass.Host.hosts[n].num = x
x += 1 x += 1
# #
def on_exit(): def on_exit():
if DEBUG > 0: sys.stderr.write("on_exit\n") if DEBUG > 0:
sys.stderr.write("on_exit\n")
try: try:
logf.close() logf.close()
except: except:
@@ -391,18 +423,22 @@ def checkoverdue():
if conn.state == hbdclass.Connection.up and (now - conn.lastbeat) > timeout: if conn.state == hbdclass.Connection.up and (now - conn.lastbeat) > timeout:
conn.newstate(hbdclass.Connection.overdue, now, grace) conn.newstate(hbdclass.Connection.overdue, now, grace)
pmsg.append(conn.afam) pmsg.append(conn.afam)
if conn.state == hbdclass.Connection.overdue and (now - conn.lastbeat) > DROPOVERDUE: if (
conn.state == hbdclass.Connection.overdue
and (now - conn.lastbeat) > DROPOVERDUE
):
conn.newstate(hbdclass.Connection.unknown, conn.lastbeat) conn.newstate(hbdclass.Connection.unknown, conn.lastbeat)
if pmsg != []: if pmsg != []:
if h in watchhosts: if h in watchhosts:
email("overdue", "%s overdue" % " and ".join(pmsg)) email("overdue", "%s overdue" % " and ".join(pmsg))
pushmsg("%s %s overdue" % (h, " and ".join(pmsg))) pushmsg("%s %s overdue" % (h, " and ".join(pmsg)))
log(h, "%s overdue" % " and ".join(pmsg)) log(h, "%s overdue" % " and ".join(pmsg))
msg_to_websockets('host', hbdclass.Host.hosts[h].stateinfo()) msg_to_websockets("host", hbdclass.Host.hosts[h].stateinfo())
def log(host, m, service=None): def log(host, m, service=None):
if DEBUG > 0: print("Log: %s %s" % (host, m)) if DEBUG > 0:
print("Log: %s %s" % (host, m))
now = time.time() now = time.time()
ts = time.strftime("%b %d %H:%M:%S", time.localtime(now)) ts = time.strftime("%b %d %H:%M:%S", time.localtime(now))
if service: if service:
@@ -415,13 +451,13 @@ def log(host, m, service=None):
hst = "" hst = ""
msg = "%s: %s%s%s" % (ts, hst, srv, m) msg = "%s: %s%s%s" % (ts, hst, srv, m)
msgs.append(msg+'\n') msgs.append(msg + "\n")
msg_to_websockets('message', msg) msg_to_websockets("message", msg)
if logfmt == "msg": if logfmt == "msg":
m2 = "%d|%s|%s\n" % (now, hst, m) m2 = "%d|%s|%s\n" % (now, hst, m)
else: else:
m2 = msg+'\n' m2 = msg + "\n"
logf.write(m2) logf.write(m2)
logf.flush() logf.flush()
pickleit() pickleit()
@@ -441,52 +477,59 @@ def dnsupdatethread():
hbdclass.Host.dnsQ.task_done() hbdclass.Host.dnsQ.task_done()
log(name, m) log(name, m)
# #
# #
# #
# #
def readsock(sock): def readsock(sock):
global now global now
if DEBUG > 3: sys.stderr.write("readsock recfrom start") if DEBUG > 3:
sys.stderr.write("readsock recfrom start")
now = time.time() now = time.time()
data, addrp = sock.recvfrom(MAXRECV) data, addrp = sock.recvfrom(MAXRECV)
if DEBUG > 3: sys.stderr.write("readsock = %s, %s\n" % (data,addrp)) if DEBUG > 3:
sys.stderr.write("readsock = %s, %s\n" % (data, addrp))
try: try:
msg = stodict(data) msg = stodict(data)
except: except:
return return
if DEBUG > 3: sys.stderr.write("msg is %s" % str(msg)) if DEBUG > 3:
sys.stderr.write("msg is %s" % str(msg))
if not msg: # Old hbc client if not msg: # Old hbc client
if verbose: print(("old hbc:", data)) if verbose:
print(("old hbc:", data))
msg = oldmtodict(data) msg = oldmtodict(data)
if DEBUG > 2: print(("readsock = %s, %s" % (msg,addrp))) if DEBUG > 2:
print(("readsock = %s, %s" % (msg, addrp)))
addr = addrp[0:2] addr = addrp[0:2]
name = shortname(msg.get('name', "unknown")) name = shortname(msg.get("name", "unknown"))
if not name in hbdclass.Host.hosts: # was: hosts.has_key(name): if not name in hbdclass.Host.hosts: # was: hosts.has_key(name):
host = hbdclass.Host(name) host = hbdclass.Host(name)
host.dyn = name in dyndnshosts host.dyn = name in dyndnshosts
if verbose: print(("XX: New host, num now %s" % (len(hbdclass.Host.hosts)))) if verbose:
print(("XX: New host, num now %s" % (len(hbdclass.Host.hosts))))
newh = True newh = True
else: else:
host = hbdclass.Host.hosts[name] host = hbdclass.Host.hosts[name]
newh = False newh = False
cid = msg.get('id', 0) cid = msg.get("id", 0)
try: try:
rtt = float(msg.get('rtt',None)) rtt = float(msg.get("rtt", None))
except: except:
rtt = None rtt = None
if msg['ID'] == 'HTB': if msg["ID"] == "HTB":
host.doesack = msg.get('acks', -1) host.doesack = msg.get("acks", -1)
host.setcver(msg.get('ver', 0)) host.setcver(msg.get("ver", 0))
interval = int(msg.get('interval', 0)) interval = int(msg.get("interval", 0))
shutdown = msg.get('shutdown', 0) shutdown = msg.get("shutdown", 0)
service = msg.get('service', "unknown") service = msg.get("service", "unknown")
message = msg.get('msg', None) message = msg.get("msg", None)
boot = msg.get('boot', 0) boot = msg.get("boot", 0)
conn, res = host.conndata(cid, addr[0], rtt, now) conn, res = host.conndata(cid, addr[0], rtt, now)
if res: if res:
@@ -507,7 +550,6 @@ def readsock(sock):
email("msg", message) email("msg", message)
pushmsg(message) pushmsg(message)
if conn.getstate() != hbdclass.Connection.up: # XXX and interval > 0: if conn.getstate() != hbdclass.Connection.up: # XXX and interval > 0:
lasts = conn.state lasts = conn.state
d = conn.newstate(hbdclass.Connection.up, now) d = conn.newstate(hbdclass.Connection.up, now)
@@ -522,7 +564,6 @@ def readsock(sock):
else: else:
host.upcount += 1 host.upcount += 1
if shutdown: if shutdown:
log(name, "%s shutdown" % conn.afam) log(name, "%s shutdown" % conn.afam)
if name in watchhosts: if name in watchhosts:
@@ -533,29 +574,30 @@ def readsock(sock):
if interval > 0: if interval > 0:
host.interval = interval host.interval = interval
rmsg = {'time': time.time()} rmsg = {"time": time.time()}
op = 'ACK' op = "ACK"
if host.cver < 1: if host.cver < 1:
opkt = 'ACK' opkt = "ACK"
rmsg = 'ACK' rmsg = "ACK"
else: else:
opkt = dicttos('ACK', rmsg, host.cver > 1) # clients w/ ver 2+ can cope opkt = dicttos("ACK", rmsg, host.cver > 1) # clients w/ ver 2+ can cope
try: try:
ss = sock.sendto(opkt, addr) ss = sock.sendto(opkt, addr)
except: except:
pass # XXX return pkg failes pass # XXX return pkg failes
if DEBUG > 2: print(("sendto1: %s (%s) %s %s" % (addr, len(opkt), op, str(rmsg)[:50]))) if DEBUG > 2:
print(("sendto1: %s (%s) %s %s" % (addr, len(opkt), op, str(rmsg)[:50])))
# send any commands we have queued # send any commands we have queued
while len(host.cmds): while len(host.cmds):
op, rmsg = host.cmds[0] op, rmsg = host.cmds[0]
if op == 'CMD': if op == "CMD":
email("%s cmd exec" % name, "command '%s' sent" % rmsg) email("%s cmd exec" % name, "command '%s' sent" % rmsg)
del host.cmds[0] del host.cmds[0]
log(name, "command sent") log(name, "command sent")
if host.cver < 1: if host.cver < 1:
rmsg = rmsg['cmd'] rmsg = rmsg["cmd"]
elif op == 'UPD': elif op == "UPD":
del host.cmds[0] del host.cmds[0]
log(name, "update initiated") log(name, "update initiated")
if host.cver < 1: if host.cver < 1:
@@ -572,10 +614,12 @@ def readsock(sock):
print(("opkt len is %s" % len(opkt))) print(("opkt len is %s" % len(opkt)))
print(("cannot send: %s" % e)) print(("cannot send: %s" % e))
if verbose: print(("sendto2: %s (%s) %s %s" % (addr, len(opkt), op, str(rmsg)[:50]))) if verbose:
if DEBUG > 2: print(("msg from %s,%s, sent %s bytes back" % (addr[0], addr[1], ss))) print(("sendto2: %s (%s) %s %s" % (addr, len(opkt), op, str(rmsg)[:50])))
if DEBUG > 2:
print(("msg from %s,%s, sent %s bytes back" % (addr[0], addr[1], ss)))
msg_to_websockets('host', host.stateinfo()) msg_to_websockets("host", host.stateinfo())
def updatecode(ucode, uname): def updatecode(ucode, uname):
@@ -592,17 +636,21 @@ def updatecode(ucode, uname):
new_codeE = new_code.encode() new_codeE = new_code.encode()
m.update(new_codeE) m.update(new_codeE)
icsum = m.hexdigest() icsum = m.hexdigest()
rmsg = {'csum': icsum, 'code': codecs.encode(new_codeE, 'base64') } rmsg = {"csum": icsum, "code": codecs.encode(new_codeE, "base64")}
hbdclass.Host.hosts[uname].cmds.append(('UPD',rmsg)) hbdclass.Host.hosts[uname].cmds.append(("UPD", rmsg))
return fail return fail
# #
# Web Server # Web Server
# #
class HttpServer(socketserver.ThreadingMixIn, http.server.HTTPServer): class HttpServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
allow_reuse_address = True allow_reuse_address = True
def threaded(self): def threaded(self):
pass pass
# #
# #
class HttpHandler(http.server.BaseHTTPRequestHandler): class HttpHandler(http.server.BaseHTTPRequestHandler):
@@ -612,7 +660,6 @@ class HttpHandler(http.server.BaseHTTPRequestHandler):
def version_string(self): def version_string(self):
return self.server_version return self.server_version
def handle(self): def handle(self):
# return http.server.BaseHTTPRequestHandler.handle(self) # return http.server.BaseHTTPRequestHandler.handle(self)
try: try:
@@ -622,27 +669,27 @@ class HttpHandler(http.server.BaseHTTPRequestHandler):
self.close_connection = 1 self.close_connection = 1
return return
def do_HEAD(self): def do_HEAD(self):
self.setheaders(200) self.setheaders(200)
def setheaders(self, code, headerdict={}): def setheaders(self, code, headerdict={}):
self.send_response(code) self.send_response(code)
self.send_header("Last-Modified", time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now))) self.send_header(
"Last-Modified",
time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)),
)
# self.send_header("Accept-Ranges","bytes") # self.send_header("Accept-Ranges","bytes")
# self.send_header("hbdclass.Connection","close") # self.send_header("hbdclass.Connection","close")
for h in headerdict: for h in headerdict:
self.send_header(h, headerdict[h]) self.send_header(h, headerdict[h])
self.end_headers() self.end_headers()
def buildhead(self, title="Heartbeat", refresh=None, extras=None): def buildhead(self, title="Heartbeat", refresh=None, extras=None):
res = [] res = []
res.append('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">') res.append('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">')
res.append("<html>") res.append("<html>")
res.append("<head>") res.append("<head>")
res.append('<title>%s</title>' % (title)) res.append("<title>%s</title>" % (title))
if refresh: if refresh:
res.append("<meta http-equiv = Refresh content = %d>\n" % refresh) res.append("<meta http-equiv = Refresh content = %d>\n" % refresh)
if extras: if extras:
@@ -651,63 +698,74 @@ class HttpHandler(http.server.BaseHTTPRequestHandler):
res.append('<body BGCOLOR = "#FFFFFF" LINK = "#008000" VLINK = "#008000">') res.append('<body BGCOLOR = "#FFFFFF" LINK = "#008000" VLINK = "#008000">')
return res return res
def buildpage(self): def buildpage(self):
res = self.buildhead(refresh=60, extras=tcss) res = self.buildhead(refresh=60, extras=tcss)
res.append("<H2>Heartbeat status %s</h2>" % VER) res.append("<H2>Heartbeat status %s</h2>" % VER)
res += hbdclass.ubHost.buildhosttable() res += hbdclass.ubHost.buildhosttable()
res += hbdclass.ubHost.buildmsgtable(msgs) res += hbdclass.ubHost.buildmsgtable(msgs)
res.append('<p> %s (%s)</p>' % (time.strftime("%H:%M:%S", time.localtime(now)), os.environ.get('TZ', 'CET-1CDT'))) res.append(
"<p> %s (%s)</p>"
% (
time.strftime("%H:%M:%S", time.localtime(now)),
os.environ.get("TZ", "CET-1CDT"),
)
)
res.append("</body></html>") res.append("</body></html>")
return res return res
def builderror(self, code, cause, lcause): def builderror(self, code, cause, lcause):
res = [] res = []
res.append('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">') res.append('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">')
res.append('<html><head>') res.append("<html><head>")
res.append('<title>%s %s</title>' % (code, cause)) res.append("<title>%s %s</title>" % (code, cause))
res.append('</head><body>') res.append("</head><body>")
res.append('<h1>%s</h1>' % (cause)) res.append("<h1>%s</h1>" % (cause))
res.append('<p>%s</p>' % lcause) res.append("<p>%s</p>" % lcause)
res.append('<hr>') res.append("<hr>")
res.append('<address>hbd (Unix) Server at %s:%s</address>' % (hbd_host, hbd_port)) res.append(
res.append('</body></html>') "<address>hbd (Unix) Server at %s:%s</address>" % (hbd_host, hbd_port)
)
res.append("</body></html>")
return code, res return code, res
def do_GET(self): def do_GET(self):
global sig global sig
code = 200 code = 200
xsig = 0 xsig = 0
rqAcceptEncoding = self.headers.get('Accept-encoding',{}) rqAcceptEncoding = self.headers.get("Accept-encoding", {})
headerdict = {"Content-Type": "text/html; charset = ISO-8859-1"} headerdict = {"Content-Type": "text/html; charset = ISO-8859-1"}
if DEBUG > 2: sys.stderr.write("handle\n") if DEBUG > 2:
sys.stderr.write("handle\n")
qr = urllib.parse.urlparse(self.path) qr = urllib.parse.urlparse(self.path)
qa = urllib.parse.parse_qs(qr.query) qa = urllib.parse.parse_qs(qr.query)
if DEBUG > 2: sys.stderr.write("handle = %s\n" % (qr.geturl())) if DEBUG > 2:
sys.stderr.write("handle = %s\n" % (qr.geturl()))
if qr.path == "/": if qr.path == "/":
res = self.buildpage() res = self.buildpage()
elif qr.path == "/c": # command on host /c?h=melschserver&c=sudo%20ls elif qr.path == "/c": # command on host /c?h=melschserver&c=sudo%20ls
uname=qa.get('h',[None])[0] uname = qa.get("h", [None])[0]
ucmd=qa.get('c', [None])[0] ucmd = qa.get("c", [None])[0]
if not ucmd or not uname: if not ucmd or not uname:
code, res=self.builderror(400, 'Argument error', "need h= and c= arguments") code, res = self.builderror(
400, "Argument error", "need h= and c= arguments"
)
elif uname not in hbdclass.Host.hosts: elif uname not in hbdclass.Host.hosts:
code, res=self.builderror(400, 'Data error', "h=%s not found" % uname) code, res = self.builderror(400, "Data error", "h=%s not found" % uname)
else: else:
hbdclass.Host.hosts[uname].cmds.append(('CMD', {'cmd': urllib.parse.unquote(ucmd)})) hbdclass.Host.hosts[uname].cmds.append(
("CMD", {"cmd": urllib.parse.unquote(ucmd)})
)
res = self.buildhead() res = self.buildhead()
res.append("cmd %s queued for host %s" % (uname, ucmd)) res.append("cmd %s queued for host %s" % (uname, ucmd))
elif qr.path == "/d": # drop host /d?h=melschserver elif qr.path == "/d": # drop host /d?h=melschserver
uname=qa.get('h',[None])[0] uname = qa.get("h", [None])[0]
if not uname: if not uname:
code, res=self.builderror(400, 'Argument error', "need h= argument") code, res = self.builderror(400, "Argument error", "need h= argument")
if not uname in hbdclass.Host.hosts: if not uname in hbdclass.Host.hosts:
code, res=self.builderror(400, 'Data error', "h=%s not found" % uname) code, res = self.builderror(400, "Data error", "h=%s not found" % uname)
else: else:
log(uname, "dropped") log(uname, "dropped")
# for addr in hbdclass.Host.hosts[uname].0i # for addr in hbdclass.Host.hosts[uname].0i
@@ -717,35 +775,41 @@ class HttpHandler(http.server.BaseHTTPRequestHandler):
res.append("Done") res.append("Done")
elif qr.path == "/n": # register name elif qr.path == "/n": # register name
uname=qa.get('h',[None])[0] uname = qa.get("h", [None])[0]
if not uname: if not uname:
code, res=self.builderror(400, 'Argument error', "need h= argument") code, res = self.builderror(400, "Argument error", "need h= argument")
if not uname in hbdclass.Host.hosts: if not uname in hbdclass.Host.hosts:
code, res=self.builderror(400, 'Data error', "h=%s not found" % uname) code, res = self.builderror(400, "Data error", "h=%s not found" % uname)
else: else:
ll = hbdclass.Host.hosts[uname].registerDns() ll = hbdclass.Host.hosts[uname].registerDns()
res.append(ll) res.append(ll)
log(uname, ll) log(uname, ll)
elif qr.path == "/u": # update elif qr.path == "/u": # update
uname=urllib.parse.unquote(qa.get('h',[None])[0]) uname = urllib.parse.unquote(qa.get("h", [None])[0])
ucode=qa.get('c', [None])[0] ucode = qa.get("c", [None])[0]
if not ucode or not uname: if not ucode or not uname:
code, res=self.builderror(400, 'Argument error', "need h= and c= arguments") code, res = self.builderror(
elif uname != 'All' and uname not in hbdclass.Host.hosts: 400, "Argument error", "need h= and c= arguments"
code, res=self.builderror(400, 'Data error', "h=%s not found" % uname) )
elif uname != "All" and uname not in hbdclass.Host.hosts:
code, res = self.builderror(400, "Data error", "h=%s not found" % uname)
else: else:
res = self.buildhead() res = self.buildhead()
if uname != 'All': if uname != "All":
names = [uname] names = [uname]
else: else:
names = [] names = []
for n in hbdclass.Host.hosts: for n in hbdclass.Host.hosts:
if hbdclass.Host.hosts[n].cver >= 2: # earliest version that supports update if (
hbdclass.Host.hosts[n].cver >= 2
): # earliest version that supports update
names.append(n) names.append(n)
for n in names: for n in names:
err = updatecode(ucode, n) err = updatecode(ucode, n)
res.append("update started for %s: %s<br>" % (n, err if err else "OK")) res.append(
"update started for %s: %s<br>" % (n, err if err else "OK")
)
res.append("Done") res.append("Done")
elif qr.path == "/api/0/hosts": # api access to host table elif qr.path == "/api/0/hosts": # api access to host table
@@ -767,17 +831,18 @@ class HttpHandler(http.server.BaseHTTPRequestHandler):
log(None, "restart request") log(None, "restart request")
else: else:
code, res=self.builderror(404, "Not Found", "requested URL was not found on this server.") code, res = self.builderror(
404, "Not Found", "requested URL was not found on this server."
)
if "deflate" in rqAcceptEncoding:
if 'deflate' in rqAcceptEncoding: headerdict["Content-Encoding"] = "deflate"
headerdict['Content-Encoding'] = "deflate"
towrite = zlib.compress("\n".join(res).encode(), 6) towrite = zlib.compress("\n".join(res).encode(), 6)
else: else:
towrite = "\n".join(res) towrite = "\n".join(res)
headerdict['Content-Length'] = len(towrite) headerdict["Content-Length"] = len(towrite)
headerdict['Cache-Control'] = 'private, must-revalidate, max-age=0' headerdict["Cache-Control"] = "private, must-revalidate, max-age=0"
headerdict['Expires'] = 'Thu, 01 Jan 1970 00:00:00 GMT' headerdict["Expires"] = "Thu, 01 Jan 1970 00:00:00 GMT"
self.setheaders(code, headerdict) self.setheaders(code, headerdict)
self.wfile.write(towrite) self.wfile.write(towrite)
@@ -787,7 +852,8 @@ class HttpHandler(http.server.BaseHTTPRequestHandler):
def setrunning(new): def setrunning(new):
global running global running
if DEBUG > 0: sys.stderr.write("running is now = %s\n" % (new)) if DEBUG > 0:
sys.stderr.write("running is now = %s\n" % (new))
running = new running = new
@@ -802,12 +868,15 @@ def closeup():
except: except:
pass pass
if DEBUG > 0: sys.stderr.write("asking http server to stop\n") if DEBUG > 0:
sys.stderr.write("asking http server to stop\n")
try: try:
serv.shutdown() serv.shutdown()
if DEBUG > 0: sys.stderr.write("http server stopped\n") if DEBUG > 0:
sys.stderr.write("http server stopped\n")
except Exception as e: except Exception as e:
if DEBUG > 0: sys.stderr.write("http server did NOT stop: %s\n" % str(e)) if DEBUG > 0:
sys.stderr.write("http server did NOT stop: %s\n" % str(e))
try: try:
serv.server_close() serv.server_close()
@@ -825,17 +894,19 @@ def closeup():
def restart(): def restart():
if verbose: print(("execv %s %s" % (sys.argv[0], [sys.argv[0]]+cmdargs))) if verbose:
print(("execv %s %s" % (sys.argv[0], [sys.argv[0]] + cmdargs)))
os.execv(sys.argv[0], [sys.argv[0]] + cmdargs) os.execv(sys.argv[0], [sys.argv[0]] + cmdargs)
print("should not be here") print("should not be here")
def saveandrestart(): def saveandrestart():
closeup() closeup()
restart() restart()
def pickleit(): def pickleit():
pickf = open(pickfile, 'wb') pickf = open(pickfile, "wb")
pick = pickle.Pickler(pickf) pick = pickle.Pickler(pickf)
pick.dump(hbdclass.Host.hosts) pick.dump(hbdclass.Host.hosts)
pick.dump(msgs) pick.dump(msgs)
@@ -847,32 +918,41 @@ def pickleit():
ws_connections = {} ws_connections = {}
async def ws_serve(websocket, path): async def ws_serve(websocket, path):
ws_connections[websocket] = path ws_connections[websocket] = path
remote_address = websocket.remote_address remote_address = websocket.remote_address
if verbose: print(f"DBG ws_serve: {remote_address}: {path}") if verbose:
print(f"DBG ws_serve: {remote_address}: {path}")
while True: while True:
try: try:
name = await websocket.recv() name = await websocket.recv()
if verbose: print(f"DBG ws_serve: receive {name}") if verbose:
print(f"DBG ws_serve: receive {name}")
except ( except (
websockets.exceptions.ConnectionClosedOK, websockets.exceptions.ConnectionClosedOK,
websockets.exceptions.ConnectionClosedError) as e: websockets.exceptions.ConnectionClosedError,
if verbose: print(f'ws closed: {e}') ) as e:
if verbose:
print(f"ws closed: {e}")
break break
if verbose: print(f"initial {name} at {path}") if verbose:
print(f"initial {name} at {path}")
# send initial set of hosts and messages # send initial set of hosts and messages
# hosts in sorted order # hosts in sorted order
for h in sorted(hbdclass.Host.hosts): for h in sorted(hbdclass.Host.hosts):
jmsg = json.dumps({'type': 'host', 'data': hbdclass.Host.hosts[h].stateinfo() }) jmsg = json.dumps(
{"type": "host", "data": hbdclass.Host.hosts[h].stateinfo()}
)
await websocket.send(jmsg) await websocket.send(jmsg)
# messages in reverse order # messages in reverse order
for m in msgs[len(msgs) - 20 :]: for m in msgs[len(msgs) - 20 :]:
jmsg = json.dumps({'type': 'message', 'data': m }) jmsg = json.dumps({"type": "message", "data": m})
await websocket.send(jmsg) await websocket.send(jmsg)
if verbose: print(f"DBG ws_serve: close {remote_address}") if verbose:
print(f"DBG ws_serve: close {remote_address}")
await websocket.wait_closed() await websocket.wait_closed()
@@ -881,7 +961,7 @@ def websocketupdater():
def msg_to_websockets(typ: str, msg: str): def msg_to_websockets(typ: str, msg: str):
jmsg = json.dumps({'type': typ, 'data': msg}) jmsg = json.dumps({"type": typ, "data": msg})
to_close = [] to_close = []
for ws in ws_connections: for ws in ws_connections:
if ws.closed: if ws.closed:
@@ -897,6 +977,8 @@ def msg_to_websockets(typ: str, msg: str):
asyncio.run_coroutine_threadsafe(ws.wait_closed(), loop) asyncio.run_coroutine_threadsafe(ws.wait_closed(), loop)
if ws in ws_connections: if ws in ws_connections:
del ws_connections[ws] del ws_connections[ws]
# #
# Main # Main
# #
@@ -907,35 +989,35 @@ pushsrv = "pushover" # mattermost
dyndomains = ["wrede.org"] dyndomains = ["wrede.org"]
optlist = [] optlist = []
args = [] args = []
home = os.environ['HOME'] home = os.environ["HOME"]
cmdargs = [] cmdargs = []
configfile = "%s/.hbrc" % home configfile = "%s/.hbrc" % home
try: try:
optlist, args = getopt.getopt(sys.argv[1:], 'c:dfh:p:vx') optlist, args = getopt.getopt(sys.argv[1:], "c:dfh:p:vx")
except: except:
helpflag = True helpflag = True
for o, a in optlist: for o, a in optlist:
if o == '-c': if o == "-c":
configfile = a configfile = a
cmdargs += [o, a] cmdargs += [o, a]
if o == '-f': if o == "-f":
foreground = True foreground = True
cmdargs += [o] cmdargs += [o]
elif o == '-h': elif o == "-h":
helpflag = True helpflag = True
elif o == '-v': elif o == "-v":
verbose = True verbose = True
cmdargs += [o] cmdargs += [o]
elif o == '-p': elif o == "-p":
if a in PUSHSRVS: if a in PUSHSRVS:
pushsrv = a pushsrv = a
cmdargs += [o, a] cmdargs += [o, a]
else: else:
print("invalid push service, use of of %s" % PUSHSRVS) print("invalid push service, use of of %s" % PUSHSRVS)
helpflag = True helpflag = True
elif o == '-x': elif o == "-x":
DEBUG += 1 DEBUG += 1
cmdargs += [o] cmdargs += [o]
@@ -951,7 +1033,8 @@ if helpflag:
print(" -v verbose") print(" -v verbose")
print(" -x increase debug lvl") print(" -x increase debug lvl")
print() print()
print(""" config file can contain print(
""" config file can contain
logfile = /var/log/heartbeat.log logfile = /var/log/heartbeat.log
logfmt = [text|msg] logfmt = [text|msg]
hb_port = 50003 hb_port = 50003
@@ -959,7 +1042,8 @@ interval = 20
hbd_port = 50004 hbd_port = 50004
hbd_host = www.domain.com hbd_host = www.domain.com
grace = 2 grace = 2
""") """
)
sys.exit(1) sys.exit(1)
@@ -997,40 +1081,40 @@ if f:
continue continue
if verbose: if verbose:
print((" %s" % l)) print((" %s" % l))
r = l.split('=') r = l.split("=")
o = r[0].strip() o = r[0].strip()
try: try:
a = eval(r[1].strip()) a = eval(r[1].strip())
except Exception as e: except Exception as e:
print(("error: %s" % str(r))) print(("error: %s" % str(r)))
sys.exit(1) sys.exit(1)
if o == 'interval': if o == "interval":
interval = a interval = a
elif o == 'grace': elif o == "grace":
grace = a grace = a
elif o == 'hbd_port': elif o == "hbd_port":
hbd_port = a hbd_port = a
elif o == 'hbd_host': elif o == "hbd_host":
hbd_host = a hbd_host = a
elif o == 'pickfile': elif o == "pickfile":
pickfile = a pickfile = a
elif o == 'hb_port': elif o == "hb_port":
hb_port = a hb_port = a
elif o == 'logfile': elif o == "logfile":
logfile = a logfile = a
elif o == 'logfmt': elif o == "logfmt":
logfmt = a logfmt = a
elif o == 'watchhosts': elif o == "watchhosts":
watchhosts = a watchhosts = a
elif o == 'dyndnshosts': elif o == "dyndnshosts":
dyndnshosts = a dyndnshosts = a
elif o == 'drophosts': elif o == "drophosts":
drophosts = a drophosts = a
elif o == 'nsupdate_bin': elif o == "nsupdate_bin":
nsupdate_bin = a nsupdate_bin = a
elif o == 'pushsrv': elif o == "pushsrv":
pushsrv = a pushsrv = a
elif o == 'dyndomains': elif o == "dyndomains":
dyndomains = a dyndomains = a
f.close() f.close()
@@ -1052,8 +1136,9 @@ if verbose:
logf = initlog(logfile) logf = initlog(logfile)
if 1 and os.path.exists(pickfile): if 1 and os.path.exists(pickfile):
if verbose: print(("opening pickls %s" % pickfile)) if verbose:
pickf = open(pickfile, 'rb') print(("opening pickls %s" % pickfile))
pickf = open(pickfile, "rb")
pick = pickle.Unpickler(pickf) pick = pickle.Unpickler(pickf)
try: try:
hbdclass.Host.hosts = pick.load() hbdclass.Host.hosts = pick.load()
@@ -1074,9 +1159,11 @@ if 1 and os.path.exists(pickfile):
for h in drophosts: for h in drophosts:
if h in hbdclass.Host.hosts: if h in hbdclass.Host.hosts:
del hbdclass.Host.hosts[h] del hbdclass.Host.hosts[h]
if verbose: print(("%s pickled hosts loaded" % len(hbdclass.Host.hosts))) if verbose:
print(("%s pickled hosts loaded" % len(hbdclass.Host.hosts)))
else: else:
if verbose: print("no pickled data") if verbose:
print("no pickled data")
now = time.time() now = time.time()
@@ -1136,12 +1223,14 @@ ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
wss_pem = pathlib.Path(WSS_PEM) wss_pem = pathlib.Path(WSS_PEM)
wss_key = pathlib.Path(WSS_KEY) wss_key = pathlib.Path(WSS_KEY)
ssl_context.load_cert_chain(wss_pem, keyfile=wss_key) ssl_context.load_cert_chain(wss_pem, keyfile=wss_key)
wss_start_server = websockets.serve(ws_serve, hbd_host, WSSPORT, wss_start_server = websockets.serve(
ssl=ssl_context, loop=loop, subprotocols=["hbd"]) ws_serve, hbd_host, WSSPORT, ssl=ssl_context, loop=loop, subprotocols=["hbd"]
)
loop.run_until_complete(wss_start_server) loop.run_until_complete(wss_start_server)
ws_start_server = websockets.serve(ws_serve, hbd_host, WSPORT, ws_start_server = websockets.serve(
loop = loop, subprotocols=["hbd"]) ws_serve, hbd_host, WSPORT, loop=loop, subprotocols=["hbd"]
)
loop.run_until_complete(ws_start_server) loop.run_until_complete(ws_start_server)
servthread = threading.Thread(target=serv.serve_forever) servthread = threading.Thread(target=serv.serve_forever)
@@ -1167,7 +1256,8 @@ firstcheck = int(now) + 15
while running: while running:
sr = None sr = None
if DEBUG > 3: sys.stderr.write("about to sleep = %s\n" % (sleep)) if DEBUG > 3:
sys.stderr.write("about to sleep = %s\n" % (sleep))
try: try:
sr = select.select(ilist, [], [], sleep) sr = select.select(ilist, [], [], sleep)
now = time.time() now = time.time()
@@ -1183,9 +1273,11 @@ while running:
continue continue
continue continue
except Exception as e: except Exception as e:
if DEBUG > 2: sys.stderr.write("select exception %s\n" % (str(e))) if DEBUG > 2:
sys.stderr.write("select exception %s\n" % (str(e)))
sys.exit(1) sys.exit(1)
if DEBUG > 3: sys.stderr.write("woke from sleep = %s (%s)\n" % (str(sr), str(ilist))) if DEBUG > 3:
sys.stderr.write("woke from sleep = %s (%s)\n" % (str(sr), str(ilist)))
for fh in sr[0]: for fh in sr[0]:
if fh in [sock, sock6]: if fh in [sock, sock6]:
readsock(fh) readsock(fh)
@@ -1193,7 +1285,8 @@ while running:
# serv.handle_request() # serv.handle_request()
else: else:
sys.stderr.write("what happend just now?\n") sys.stderr.write("what happend just now?\n")
if DEBUG > 3: sys.stderr.write("done handling, running is %s, sig is %s\n" % (running, sig)) if DEBUG > 3:
sys.stderr.write("done handling, running is %s, sig is %s\n" % (running, sig))
# check hour/day/week # check hour/day/week
for v in range(3): for v in range(3):
@@ -1202,7 +1295,10 @@ while running:
if ts != lastfm[v]: if ts != lastfm[v]:
lastfm[v] = ts lastfm[v] = ts
for h in list(hbdclass.Host.hosts.keys()): for h in list(hbdclass.Host.hosts.keys()):
hbdclass.Host.hosts[h].hdwcounts[v] = [hbdclass.Host.hosts[h].doesack, hbdclass.Host.hosts[h].upcount] hbdclass.Host.hosts[h].hdwcounts[v] = [
hbdclass.Host.hosts[h].doesack,
hbdclass.Host.hosts[h].upcount,
]
if now >= rnext and now >= firstcheck: if now >= rnext and now >= firstcheck:
rnext = now + 1 rnext = now + 1
@@ -1212,13 +1308,14 @@ while running:
if sleep < 0: if sleep < 0:
sys.stderr.write("sleep is negative! %s next = %s\n" % (sleep, rnext)) sys.stderr.write("sleep is negative! %s next = %s\n" % (sleep, rnext))
sleep = 0 sleep = 0
if DEBUG > 3: sys.stderr.write("sleep = %s next = %s\n" % (sleep, rnext)) if DEBUG > 3:
sys.stderr.write("sleep = %s next = %s\n" % (sleep, rnext))
if sig != 0: if sig != 0:
setrunning(False) setrunning(False)
if sig == signal.SIGHUP: if sig == signal.SIGHUP:
if DEBUG > 0: sys.stderr.write("signal 1 saveandrestart\n") if DEBUG > 0:
sys.stderr.write("signal 1 saveandrestart\n")
saveandrestart() saveandrestart()
+3 -1
View File
@@ -1,6 +1,7 @@
import asyncio import asyncio
import websockets import websockets
async def hello(): async def hello():
uri = "ws://localhost:50005/messages" uri = "ws://localhost:50005/messages"
async with websockets.connect(uri) as websocket: async with websockets.connect(uri) as websocket:
@@ -15,6 +16,7 @@ async def hello():
if greeting == "bye": if greeting == "bye":
break break
print('out of here') print("out of here")
asyncio.get_event_loop().run_until_complete(hello()) asyncio.get_event_loop().run_until_complete(hello())