diff --git a/hbd b/hbd index ee526db..3587eb4 100755 --- a/hbd +++ b/hbd @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # $Id: hbd,v 1.38 2013/07/14 02:25:05 andreas Exp $ # Wait for heartbeat messages and act on them (or their absence) # @@ -11,19 +11,19 @@ import sys import socket import atexit import select -import SocketServer -import BaseHTTPServer +import socketserver +import http.server import getopt import signal -import cPickle +import pickle import smtplib import traceback -import urllib -import urlparse -import httplib +import urllib.request, urllib.parse, urllib.error +import urllib.parse +import http.client import threading -import Queue -import md5 +import queue +from hashlib import md5 import json import zlib @@ -35,7 +35,7 @@ from hbdclass import * SEND_EMAIL=False SEND_PUSHOVER=True -DEBUG = 0 +DEBUG = 3 MAXRECV = 32767 LOGFILE = "/home/andreas/public_html/messages/andreas" @@ -105,7 +105,7 @@ def handler(signum, frame): def shortname(name): - r = string.split(name, '.') + r = name.split('.') return r[0] @@ -132,22 +132,22 @@ def dicttos(ID, d, compress=False): s.append("%s=%s" % (k, d[k])) pk = ";".join(s) if compress: - zpk = zlib.compress(pk, 6) - ID = "!"+ID + zpk = zlib.compress(pk.encode(), 6) + ID = "!" + ID + ":" + opk = ID.encode() + zpk else: zpk = pk - return ID + ":" + zpk + opk = ID + ":" + zpk + return opk def stodict(msg): d = {} - r0 = msg.split(':',1) - if len(r0) == 1: - return None - if r0[0][0] == '!': # compressed - pk = zlib.decompress(msg[len(r0[0])+1:]) - d['ID'] = r0[0][1:] + if len(msg) > 0 and chr(msg[0]) == "!": + pk = zlib.decompress(msg[5:]).decode() + d['ID'] = msg[1:4].decode() else: + r0 = msg.split(':',1) pk = r0[1] d['ID'] = r0[0] r = pk.split(';') @@ -181,11 +181,11 @@ def email(s, msg): server = smtplib.SMTP(SMTPSERVER) if DEBUG > 0: server.set_debuglevel(1) server.sendmail(fromemail, toaddrs, body) - except smtplib.SMTPRecipientsRefused, errs: + except smtplib.SMTPRecipientsRefused as errs: log(None, "cannot send email: %s\n" % (errs)) ret = "Fail" except: - print("smtp error: "+traceback.format_exc()) + print(("smtp error: "+traceback.format_exc())) saveandrestart() try: server.quit() @@ -197,10 +197,10 @@ def email(s, msg): def pushover(msg): if not SEND_PUSHOVER: return - conn = httplib.HTTPSConnection("api.pushover.net:443") + conn = http.client.HTTPSConnection("api.pushover.net:443") try: conn.request("POST", "/1/messages.json", - urllib.urlencode({ + urllib.parse.urlencode({ "token": "ac7NLX2rPjXFareeDgLpXNoDf4iFmf", "user": "uDhH33UjQQDYtNzJb1ThRiWb9ingGK", "message": msg, }), { "Content-type": "application/x-www-form-urlencoded" }) @@ -242,7 +242,7 @@ answer if DEBUG > 0: log(None, "DBG: cmd %s" % cmd) try: p = Popen(cmd, shell=False, bufsize=1, stdin=PIPE, stdout=PIPE, stderr=STDOUT) - except OSError, e: + except OSError as e: return "nsupdate: execution failed: %s" % e except: return "nsupdate: some error occured" @@ -256,9 +256,9 @@ answer # def dur(sec): sec = int(sec) - h = sec / 3600 - m = (sec - h * 3600) / 60 - s = (sec - h * 3600) % 60 + h = int(sec / 3600) + m = int((sec - h * 3600) / 60) + s = int((sec - h * 3600) % 60) if h > 0: return "%d:%02d:%02d" % (h, m, s) if m > 0: @@ -267,7 +267,7 @@ def dur(sec): def fixsort(): - s = Host.hosts.keys() + s = list(Host.hosts.keys()) s.sort() x = 0 for n in s: @@ -281,7 +281,7 @@ def on_exit(): logf.close() except: pass - print "exit" + print("exit") def initlog(logfile): @@ -296,7 +296,7 @@ def initlog(logfile): # def checkoverdue(): now = time.time() - for h in Host.hosts.keys(): + for h in list(Host.hosts.keys()): pmsg = [] for c in Host.hosts[h].connections: conn = Host.hosts[h].connections[c] @@ -316,7 +316,7 @@ def checkoverdue(): 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() ts = time.strftime("%b %d %H:%M:%S", time.localtime(now)) if service: @@ -359,27 +359,28 @@ def dnsupdatethread(): def readsock(sock): global now if DEBUG > 3: sys.stderr.write("readsock recfrom start") - data, addrp = sock.recvfrom(MAXRECV) now = time.time() - if DEBUG > 2: sys.stderr.write("readsock = %s, %s\n" % (data,addrp)) + data, addrp = sock.recvfrom(MAXRECV) + if DEBUG > 3: sys.stderr.write("readsock = %s, %s\n" % (data,addrp)) try: msg = stodict(data) except: return + if DEBUG > 3: sys.stderr.write("msg is %s" % str(msg)) if not msg: # Old hbc client - if verbose: print "old hbc:", data + if verbose: print(("old hbc:", data)) oldclient = True msg = oldmtodict(data) else: oldclient = False - if DEBUG > 2: print "readsock = %s, %s" % (msg,addrp) + if DEBUG > 2: print(("readsock = %s, %s" % (msg,addrp))) addr = addrp[0:2] name = shortname(msg.get('name', "unknown")) if not name in Host.hosts: # was: hosts.has_key(name): host = Host(name) - host.dyn = h in dyndnshosts - if verbose: print "XX: New host, num now %s" % (len(Host.hosts)) + host.dyn = name in dyndnshosts + if verbose: print(("XX: New host, num now %s" % (len(Host.hosts)))) newh=True else: host = Host.hosts[name] @@ -452,7 +453,7 @@ def readsock(sock): ss=sock.sendto(opkt, addr) except: 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 while len(host.cmds): @@ -477,11 +478,11 @@ def readsock(sock): try: ss=sock.sendto(opkt, addr) except Exception as e: - print "opkt len is %s" % len(opkt) - print "cannot send: %s" % e + print(("opkt len is %s" % len(opkt))) + print(("cannot send: %s" % e)) - if verbose: 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) + if verbose: 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))) @@ -505,13 +506,13 @@ def updatecode(ucode, uname): # # Web Server # -class HttpServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer): +class HttpServer(socketserver.ThreadingMixIn, http.server.HTTPServer): allow_reuse_address = True def threaded(): pass # # -class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler): +class HttpHandler(http.server.BaseHTTPRequestHandler): server_version = "HeartbeatHTTP/%s" % VER @@ -520,8 +521,9 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler): def handle(self): + return http.server.BaseHTTPRequestHandler.handle(self) try: - return BaseHTTPServer.BaseHTTPRequestHandler.handle(self) + return http.server.BaseHTTPRequestHandler.handle(self) except Exception as e: self.log_error("Request went away: %r", e) self.close_connection = 1 @@ -587,11 +589,11 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler): global sig code = 200 xsig = 0 - rqAcceptEncoding = self.headers.getheader('Accept-encoding',{}) + rqAcceptEncoding = self.headers.get('Accept-encoding',{}) headerdict = {"Content-Type": "text/html; charset = ISO-8859-1" } if DEBUG > 2: sys.stderr.write("handle\n") - qr = urlparse.urlparse(self.path) - qa = urlparse.parse_qs(qr.query) + qr = urllib.parse.urlparse(self.path) + qa = urllib.parse.parse_qs(qr.query) if DEBUG > 2: sys.stderr.write("handle = %s\n" % (qr.geturl())) if qr.path == "/": @@ -602,10 +604,10 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler): ucmd=qa.get('c', [None])[0] if not ucmd or not uname: code, res=self.builderror(400, 'Argument error', "need h= and c= arguments") - elif not Host.hosts.has_key(uname): + elif uname not in Host.hosts: code, res=self.builderror(400, 'Data error', "h=%s not found" % uname) else: - Host.hosts[uname].cmds.append(('CMD', {'cmd': urllib.unquote(ucmd)})) + Host.hosts[uname].cmds.append(('CMD', {'cmd': urllib.parse.unquote(ucmd)})) res=self.buildhead() res.append("cmd %s queued for host %s" % (uname, ucmd)) @@ -634,11 +636,11 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler): log(uname, ll) elif qr.path == "/u": # update - uname=urllib.unquote(qa.get('h',[None])[0]) + uname=urllib.parse.unquote(qa.get('h',[None])[0]) ucode=qa.get('c', [None])[0] if not ucode or not uname: code, res=self.builderror(400, 'Argument error', "need h= and c= arguments") - elif uname != 'All' and not Host.hosts.has_key(uname): + elif uname != 'All' and uname not in Host.hosts: code, res=self.builderror(400, 'Data error', "h=%s not found" % uname) else: res=self.buildhead() @@ -678,9 +680,9 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler): if 'deflate' in rqAcceptEncoding: headerdict['Content-Encoding'] = "deflate" - towrite = zlib.compress(string.join(res, "\n"), 6) + towrite = zlib.compress("\n".join(res).encode(), 6) else: - towrite = string.join(res, "\n") + towrite = "\n".join(res) headerdict['Content-Length'] = len(towrite) headerdict['Cache-Control'] = 'private, must-revalidate, max-age=0' headerdict['Expires'] = 'Thu, 01 Jan 1970 00:00:00 GMT' @@ -731,9 +733,9 @@ def closeup(): 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) - print "should not be here" + print("should not be here") def saveandrestart(): closeup() @@ -741,8 +743,8 @@ def saveandrestart(): def pickleit(): - pickf = open(pickfile, 'w') - pick = cPickle.Pickler(pickf) + pickf = open(pickfile, 'wb') + pick = pickle.Pickler(pickf) pick.dump(Host.hosts) pick.dump(msgs) pick.dump(lastfm) @@ -783,17 +785,17 @@ for o, a in optlist: cmdargs += [o] if helpflag: - print "hbc HeartBeatDaemon" - print "usage: hbd [-dfhvx] [-c configfile]" - print - print " -c configfile" - print " -d display" - print " -f run in foreground" - print " -h this help" - print " -v verbose" - print " -x increase debug lvl" - print - print """ config file can contain + print("hbc HeartBeatDaemon") + print("usage: hbd [-dfhvx] [-c configfile]") + print() + print(" -c configfile") + print(" -d display") + print(" -f run in foreground") + print(" -h this help") + print(" -v verbose") + print(" -x increase debug lvl") + print() + print(""" config file can contain logfile = /var/log/heartbeat.log logfmt = [text|msg] hb_port = 50003 @@ -801,7 +803,7 @@ interval = 20 hbd_port = 50004 hbd_host = www.domain.com grace = 2 -""" +""") sys.exit(1) @@ -823,9 +825,9 @@ drophosts = [] try: f = open(configfile, "r") if verbose: - print "notice: using config file %s" % configfile + print(("notice: using config file %s" % configfile)) except: - print "warning: running without config file: %s" % configfile + print(("warning: running without config file: %s" % configfile)) f = None if f: @@ -837,13 +839,13 @@ if f: if len(l) == 0 or l[0] == "#": continue if verbose: - print " %s" % l + print((" %s" % l)) r = l.split('=') o = r[0].strip() try: a = eval(r[1].strip()) except Exception as e: - print "error: %s" % str(r) + print(("error: %s" % str(r))) sys.exit(1) if o == 'interval': interval = a @@ -870,18 +872,18 @@ if f: f.close() if len(args) != 0: - print "error: args" + print("error: args") sys.exit(1) if verbose: - print "notice: logging to %s" % logfile + print(("notice: logging to %s" % logfile)) logf = initlog(logfile) if 1 and os.path.exists(pickfile): - if verbose: print "opening pickls %s" % pickfile - pickf = open(pickfile, 'r') - pick = cPickle.Unpickler(pickf) + if verbose: print(("opening pickls %s" % pickfile)) + pickf = open(pickfile, 'rb') + pick = pickle.Unpickler(pickf) try: Host.hosts = pick.load() msgs = pick.load() @@ -891,18 +893,18 @@ if 1 and os.path.exists(pickfile): lastfm = ["","",""] pickf.close() except Exception as e: - print "load pickled failed: %s" % e + print(("load pickled failed: %s" % e)) os.unlink(pickfile) Connection.htab = {} - for h in Host.hosts.keys(): + for h in list(Host.hosts.keys()): Host.hosts[h].dyn = h in dyndnshosts Host.hosts[h].fixup() for h in drophosts: if h in Host.hosts: del Host.hosts[h] - if verbose: print "%s pickled hosts loaded" % len(Host.hosts) + if verbose: print(("%s pickled hosts loaded" % len(Host.hosts))) else: - if verbose: print "no pickled data" + if verbose: print("no pickled data") now = time.time() @@ -930,7 +932,7 @@ if not forground: pid = os.fork() if pid > 0: if verbose: - print "daemoinizing... pid = %d" % pid + print(("daemoinizing... pid = %d" % pid)) sys.exit(0) verbose = False @@ -951,14 +953,14 @@ if not forground: try: serv = HttpServer((hbd_host, hbd_port), HttpHandler) except: - print "failed to start server on %s:%s" % (hbd_host, hbd_port) + print(("failed to start server on %s:%s" % (hbd_host, hbd_port))) sys.exit(1) servthread = threading.Thread(target=serv.serve_forever) servthread.daemon = True servthread.start() -Host.dnsQ = Queue.Queue() +Host.dnsQ = queue.Queue() dnsT = threading.Thread(target=dnsupdatethread) dnsT.daemon = True dnsT.start() @@ -968,13 +970,13 @@ sig = 0 signal.signal(signal.SIGTERM, handler) signal.signal(signal.SIGHUP, handler) -next = int(now)+15 # 15 seconds time to settle after (re-)start +rnext = int(now)+15 # 15 seconds time to settle after (re-)start sleep = 1 firstcheck = int(now) + 15 while running: sr = None - if DEBUG > 2: sys.stderr.write("about to sleep = %s\n" % (sleep)) + if DEBUG > 3: sys.stderr.write("about to sleep = %s\n" % (sleep)) try: sr = select.select(ilist, [], [], sleep) now = time.time() @@ -983,7 +985,7 @@ while running: running = False closeup() continue - except select.error, value: + except select.error as value: if value[0] != 4: # interrupted system call sys.stderr.write("select err %s %s" % (select.error, value)) #raise os.error, value @@ -992,7 +994,7 @@ while running: except Exception as e: if DEBUG > 2: sys.stderr.write("select exception %s\n" % (str(e))) sys.exit(1) - if DEBUG > 2: 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]: if fh in [sock, sock6]: readsock(fh) @@ -1000,26 +1002,26 @@ while running: # serv.handle_request() else: sys.stderr.write("what happend just now?\n") - if DEBUG > 2: 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 - for v in xrange(3): + for v in range(3): fm=tsfm[v] ts=time.strftime(tsfm[v], time.localtime(now)) if ts != lastfm[v]: lastfm[v]=ts - for h in Host.hosts.keys(): + for h in list(Host.hosts.keys()): Host.hosts[h].hdwcounts[v] = [Host.hosts[h].doesack, Host.hosts[h].upcount] - if now >= next and now >= firstcheck: - next = now+1 + if now >= rnext and now >= firstcheck: + rnext = now+1 checkoverdue() - sleep = next-now + sleep = rnext-now if sleep < 0: - sys.stderr.write("sleep is negative! %s next = %s\n" % (sleep, next)) + sys.stderr.write("sleep is negative! %s next = %s\n" % (sleep, rnext)) sleep = 0 - if DEBUG > 2: sys.stderr.write("sleep = %s next = %s\n" % (sleep, next)) + if DEBUG > 3: sys.stderr.write("sleep = %s next = %s\n" % (sleep, rnext)) if sig != 0: setrunning(False)