From 8616633584a5735692391910eb53cffcfce2034e Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Mon, 2 May 2016 16:29:36 +0200 Subject: [PATCH 01/32] better deltatime --- hbdclass.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/hbdclass.py b/hbdclass.py index 1374338..f655ea0 100644 --- a/hbdclass.py +++ b/hbdclass.py @@ -65,7 +65,8 @@ class Connection: d['statetime'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.statetime)) delta = now - self.statetime if delta > 86400: - d['deltastatetime'] = time.strftime("%d %H:%M:%S", time.gmtime(delta)) +# d['deltastatetime'] = time.strftime("%d %H:%M:%S", time.gmtime(delta)) + d['deltastatetime'] = "%0.1f days" % (delta / 86400.) elif delta > 3600: d['deltastatetime'] = time.strftime("%H:%M:%S", time.gmtime(delta)) elif delta > 60: From 38db646c2a7ccb2c3c615b6e2865e6daf335474f Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Tue, 3 May 2016 02:39:04 +0200 Subject: [PATCH 02/32] fix for dropped pkts on Linux --- hbc | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/hbc b/hbc index 2b2c33c..d79ab2f 100755 --- a/hbc +++ b/hbc @@ -99,7 +99,7 @@ class Conn: try: self.sock.sendto(m, (self.addr, self.port)) except socket.error as e: - if not warned1: print "socket error: %s %s:%s" % (e, self.addr, self.port) + if not warned1: log("socket error: %s %s:%s" % (e, self.addr, self.port)) warned1 = True return self.send += 1 @@ -295,7 +295,7 @@ def process(): running = False break except SystemExit: - log('daemon exit, running=: %s' % running) + log('daemon exit, running was %s' % running) if running: running = False break @@ -327,10 +327,13 @@ def process(): if not running: break for conn in conns: -# msg={'interval': interval, 'acks': conns[conn].ackcount, 'rtt': conns[conn].rtts[-1]} msg={'acks': conns[conn].ackcount, 'rtt': conns[conn].rtts[-1]} conns[conn].sendto(msg) - nextReport = time.time() + interval + time.sleep(0.1) #N.B. Linux (i.e. Rasperry Pi 3 drops the second pkg unless delayed + if nextReport + interval >= time.time(): + nextReport += interval + else: + nextReport = time.time() + interval if verbose: log( "process: done running") @@ -472,11 +475,11 @@ if not msgonly: conns = {} while True: - log(" create connections") + if verbose: log("create connections") createConnections(hb_hosts) if len(conns) != 0: break - log(" no connections yet, sleep a bit") + if verbose: log("no connections yet, sleep a bit") time.sleep(2) if verbose: From 7aa3e0a98a4a944a515bc4ab9b013dab78f43026 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Tue, 3 May 2016 02:39:26 +0200 Subject: [PATCH 03/32] better? relative time --- hbdclass.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/hbdclass.py b/hbdclass.py index f655ea0..9042a81 100644 --- a/hbdclass.py +++ b/hbdclass.py @@ -68,11 +68,16 @@ class Connection: # d['deltastatetime'] = time.strftime("%d %H:%M:%S", time.gmtime(delta)) d['deltastatetime'] = "%0.1f days" % (delta / 86400.) elif delta > 3600: - d['deltastatetime'] = time.strftime("%H:%M:%S", time.gmtime(delta)) +# d['deltastatetime'] = time.strftime("%H:%M:%S", time.gmtime(delta)) + d['deltastatetime'] = time.strftime("%k:%M hrs", time.gmtime(delta)) +# d['deltastatetime'] = "%0.1f hrs" % (delta / 3600.) elif delta > 60: - d['deltastatetime'] = time.strftime("%M:%S", time.gmtime(delta)) +# d['deltastatetime'] = time.strftime("%M:%S", time.gmtime(delta)) + d['deltastatetime'] = time.strftime("%M:%S mins", time.gmtime(delta)) +# d['deltastatetime'] = "%0.1f mins" % (delta / 60.) else: - d['deltastatetime'] = time.strftime("%S", time.gmtime(delta)) +# d['deltastatetime'] = time.strftime("%S", time.gmtime(delta)) + d['deltastatetime'] = "%i secs" % (delta) else: d['addr'] = '' From a585fdf54b9e023f1ec8ec9f486294f62bb9cf37 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Tue, 3 May 2016 18:31:14 +0200 Subject: [PATCH 04/32] bump hbc to ver 3 --- hbc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hbc b/hbc index d79ab2f..8c282f5 100755 --- a/hbc +++ b/hbc @@ -58,7 +58,7 @@ daemon.get_maximum_file_descriptors = get_maximum_file_descriptors PORT = 50003 INTERVAL = 10 PIDFILE = '/tmp/hbc.pid' -VER = 2 +VER = 3 MAXRECV = 32767 running = True From c3eb0f03fc7582c60b4e85e0d5e5399014291ccc Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Tue, 3 May 2016 18:31:34 +0200 Subject: [PATCH 05/32] update All hosts --- hbd | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/hbd b/hbd index 66af86d..9c7c6b8 100755 --- a/hbd +++ b/hbd @@ -622,16 +622,25 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler): log(uname, ll) elif qr.path == "/u": # update - uname=qa.get('h',[None])[0] + uname=urllib.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 not Host.hosts.has_key(uname): + elif uname != 'All' and not Host.hosts.has_key(uname): code, res=self.builderror(400, 'Data error', "h=%s not found" % uname) else: - err = updatecode(ucode, urllib.unquote(uname)) res=self.buildhead() - res.append("3 Done: %s" % err if err else "OK") + if uname != 'All': + names = [uname] + else: + names = [] + for n in Host.hosts: + if Host.hosts[n].cver >= 2: # earliest version that supports update + names.append(n) + for n in names: + err = updatecode(ucode, n) + res.append("update started for %s: %s
" % (n, err if err else "OK")) + res.append("Done") elif qr.path == "/api/0/hosts": # api access to host table headerdict = {"Content-Type": "application/json; charset=utf-8" } From e4b3478dff91263c5aa90bfa486e8e5863d1e793 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Wed, 18 May 2016 10:33:37 -0400 Subject: [PATCH 06/32] remove dependencies on daemon and lockfile --- hbc | 197 +++++++++++++++++++++++++----------------------------------- 1 file changed, 83 insertions(+), 114 deletions(-) diff --git a/hbc b/hbc index 8c282f5..02217d7 100755 --- a/hbc +++ b/hbc @@ -17,48 +17,13 @@ import zlib import subprocess import syslog -try: - import lockfile - import daemon - import daemon.pidfile -except: - print """ - require on Linux - python-filelock - python-daemon vs 1.61 or > - run sudo easy_install-2.7 lockfile python-daemon - on *bsd - py27-lockfile - py27-daemon - run sudo pkg install -y py27-lockfile py27-daemon -""" - sys.exit(1) - - -# N.B. daemon tries to close resource.RLIMIT_NOFILE file descriptors -# which on FreeBSD in close to a million -# hack: replace the function in daemon with ths one: - - - -def log(msg): - if fdaemon: - syslog.syslog(syslog.LOG_ERR, msg) - else: - print msg - - -def get_maximum_file_descriptors(): - return 2048 - -daemon.get_maximum_file_descriptors = get_maximum_file_descriptors - +import syslog PORT = 50003 INTERVAL = 10 PIDFILE = '/tmp/hbc.pid' -VER = 3 +VER = 4 MAXRECV = 32767 running = True @@ -66,8 +31,8 @@ dorestart = False warned1 = False class NullDevice: - def write(self, s): - pass + def write(self, s): + pass class Conn: @@ -84,7 +49,7 @@ class Conn: self.rtts = [0] self.sock=socket.socket(af, socket.SOCK_DGRAM) self.sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, \ - self.sock.getsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR) | 1) + self.sock.getsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR) | 1) def sendto(self, msg, ID = 'HTB'): # default ID is HearTBeat global warned1 @@ -175,9 +140,10 @@ def syslogtrace(note): logm = '%s hbc died: \n%s' % (note, traceback.format_exc()) log(logm) for l in logm.split('\n'): - log(' tb: %s' % l) - - + syslog.syslog(syslog.LOG_ERR, ' tb: %s' % l) + if verbose: + print logm + conId = 1 def createConnections(hosts): @@ -185,7 +151,7 @@ def createConnections(hosts): for host in hosts: if verbose: log("createConnections for %s" % host) try: - rs=socket.getaddrinfo(host, hb_port, 0, 0, socket.SOL_UDP) + rs=socket.getaddrinfo(host, hb_port, 0, 0, socket.SOL_UDP) except socket.gaierror: logm = '%s hbc died: \n%s' % ('createConnections', traceback.format_exc()) if verbose: log(logm) @@ -197,7 +163,7 @@ def createConnections(hosts): elif r[0] == 2: af=socket.AF_INET else: - log("dont know this net type: %s" % r[0][0]) + print "dont know this net type: %s" % r[0][0] sys.exit(1) addr = r[4][0] @@ -226,7 +192,7 @@ def doupdate(conn, msgDict): code = msgDict['code'].decode('base64') csum = msgDict['csum'] except: - fail = "csum/code missing" + fail = "csum/code missing" if not fail: fail = doupdateone(code, csum) @@ -244,10 +210,10 @@ def doupdateone(code, csum): m.update(code) icsum = m.hexdigest() if icsum != csum: - return "checksum error" + return "checksum error" fn = sys.argv[0] - ofn = "%.sav" % fn + ofn = "%.sav" % fn try: shutil.copy2(fn, ofn) except Exception as e: @@ -264,7 +230,9 @@ def doupdateone(code, csum): def restart(): - log('restart %s' % (sys.argv[0])) + if verbose: + print "restart: execv %s %s" % (sys.argv[0], [sys.argv[0]]+cmdargs) + syslog.syslog(syslog.LOG_ERR, 'restart %s' % (sys.argv[0])) e = "fallthrough" try: os.execv(sys.argv[0], [sys.argv[0]]+cmdargs) @@ -310,17 +278,17 @@ def process(): if verbose: print "sock.recvfrom: %s (%s) %s" % (addr, len(data), data[:4]) msgDict = stodict(data) if verbose: print "sock.recvfrom: %s (%s) %s" % (addr, len(data), str(msgDict)[:80]) - if msgDict['ID'] == "ACK": + if msgDict['ID'] == "ACK": conns[conn].ack(msgDict) - elif msgDict['ID'] == "UPD": + elif msgDict['ID'] == "UPD": if doupdate(conn, msgDict) == None: if verbose: print "process: restart after update" dorestart = True break - elif msgDict['ID'] == "CMD": + elif msgDict['ID'] == "CMD": doexec(conn, msgDict['cmd']) else: - doexec(conn, data) # deprecated until no more VER - hbc + doexec(conn, data) # deprecated until no more VER - hbc if dorestart: running = False break @@ -341,7 +309,7 @@ def cleanup(): global running if verbose: log('cleanup') running = False - for conn in conns: + for conn in conns: msg={'shutdown': 1, 'acks': conns[conn].ackcount} conns[conn].sendto(msg) conns[conn].close() @@ -350,16 +318,60 @@ def cleanup(): def closeall(): - if verbose: log('closecall') - for conn in conns: + if verbose: syslog.syslog(syslog.LOG_ERR, 'closecall') + for conn in conns: conns[conn].close() +def daemonize(working_dir="/", stdin='/dev/zero', stdout='/dev/null', stderr='/dev/null'): + """ + Does the UNIX double-fork magic, see Stevens' "Advanced Programming in the + UNIX Environment" for details (ISBN 0201563177) + http://www.yendor.com/programming/unix/apue/proc/fork2.c + """ + + try: + # first fork + pid = os.fork() + if pid > 0: + # exit from first parent + os._exit(0) + except OSError, e: + sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) + os._exit(1) + + # decouple from parent environment + os.chdir(working_dir) + os.setsid() + os.umask(0) + # second fork + try: + pid = os.fork() + if pid > 0: + # exit from second parent + os._exit(0) + except OSError, e: + sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) + sys.exit(1) + + # redirects standard file descriptors + sys.stdout.flush() + sys.stderr.flush() + si = file(stdin, 'r') + so = file(stdout, 'a+') + se = file(stderr, 'a+', 0) + os.dup2(si.fileno(), sys.stdin.fileno()) + os.dup2(so.fileno(), sys.stdout.fileno()) + os.dup2(se.fileno(), sys.stderr.fileno()) + + + msgonly=False helpflag=False verbose=False fdaemon=False -optlist=[] +daemonized = False +optlist=[] args=[] msgboot={} home=os.environ['HOME'] @@ -368,9 +380,9 @@ cmdargs = [] try: - optlist, args = getopt.getopt(sys.argv[1:], 'bc:dhm:v') + optlist, args = getopt.getopt(sys.argv[1:], 'bc:dhm:v') except: - helpflag=True + helpflag=True for o,a in optlist: if o == '-b': @@ -442,7 +454,7 @@ if f: if r[0] == 'hb_hosts': hb_hosts=eval(r[1]) if verbose: - print "notice: cfg hb_hosts: %s" % hb_hosts + print "notice: cfg hb_hosts: %s" % hb_hosts elif r[0] == 'interval': interval=eval(r[1]) elif r[0] == 'hb_port': @@ -487,7 +499,7 @@ if verbose: if len(msgboot) > 0: if verbose: print "on boot" - msgboot['acks'] = 0 + msgboot['acks'] = 0 for conn in conns: conns[conn].sendto(msgboot) @@ -497,63 +509,20 @@ if msgonly: sys.exit(0) # - syslog.openlog('hbc', syslog.LOG_PID, syslog.LOG_DAEMON) if fdaemon: + print "daemoinizing." + daemonize() + daemonized = True + syslog.syslog(syslog.LOG_ERR, 'starting heartbeat to %s' % ','.join(hb_hosts)) - pidfile = daemon.pidfile.TimeoutPIDLockFile(PIDFILE, acquire_timeout=-1) - try: - opid = pidfile.read_pid() - except: - opid = None +running = True +try: + process() +except: + syslogtrace('process') + if verbose: print "err: process exit: %s" % e - if opid: - try: - os.kill(opid, 0) - is_running = True - except: - is_running = False - if verbose: print "is_running %s" % is_running - if is_running: - print "process still alive %s" % opid - sys.exit(1) - print "warning: stale pid file removed" - os.unlink(PIDFILE) - - print "daemoinizing... %s" % os.getpid() - context = daemon.DaemonContext( - working_directory='/tmp', - umask=0o022, - pidfile=pidfile, - detach_process=True, -# initgroups=False, - ) - - context.signal_map = { -# signal.SIGHUP: cleanup, - signal.SIGTERM: 'terminate', -# signal.SIGUSR1: reload_program_config, - } - - context.files_preserve = [] - for conn in conns: - context.files_preserve += [conns[conn].sock, conns[conn].sock.fileno()] - with context: - log('starting heartbeat to %s' % ','.join(hb_hosts)) - running = True - try: - process() - except: - syslogtrace('process') - -else: - running = True - try: - if verbose: print "starting loop process" - process() - except Exception as e: - if verbose: print "err: process exit: %s" % e - syslogtrace('process') if verbose: log( "main: cleanup") cleanup() if dorestart: From 5ab955dffdb05e25493ebd5b1fb3891023be85dc Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Wed, 18 May 2016 10:44:18 -0400 Subject: [PATCH 07/32] user proper id --- hbc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hbc b/hbc index 02217d7..f23e111 100755 --- a/hbc +++ b/hbc @@ -213,7 +213,7 @@ def doupdateone(code, csum): return "checksum error" fn = sys.argv[0] - ofn = "%.sav" % fn + ofn = "%s.sav" % fn try: shutil.copy2(fn, ofn) except Exception as e: From 92862d8849bb7e9f374a7f1b35f6c2307676b72f Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Wed, 18 May 2016 16:45:42 +0200 Subject: [PATCH 08/32] re-add log function --- hbc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hbc b/hbc index f23e111..bcc7e62 100755 --- a/hbc +++ b/hbc @@ -30,6 +30,13 @@ running = True dorestart = False warned1 = False +def log(msg): + if fdaemon: + syslog.syslog(syslog.LOG_ERR, msg) + else: + print msg + + class NullDevice: def write(self, s): pass From 7e122aa2d14bb867f3314d630325d595269b5007 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Thu, 16 Jun 2016 17:07:39 +0200 Subject: [PATCH 09/32] fix loggin of hostname --- hbd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hbd b/hbd index 9c7c6b8..60aaf5c 100755 --- a/hbd +++ b/hbd @@ -327,7 +327,7 @@ def log(host, m, service=None): msg = "%s: %s%s%s\n" % (ts, hst, srv, m) msgs.append(msg) if logfmt == "msg": - m2 = "%d|%s|%s\n" % (now, service, m) + m2 = "%d|%s|%s\n" % (now, hst, m) else: m2 = msg logf.write(m2) From c8a59483532bb157b05da63c4af314c300c2f007 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Mon, 27 Jun 2016 20:52:55 +0200 Subject: [PATCH 10/32] change overdue state to unknown anfetr 7 days --- hbd | 3 +++ hbdclass.py | 11 ++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/hbd b/hbd index 60aaf5c..e86fcd7 100755 --- a/hbd +++ b/hbd @@ -55,6 +55,7 @@ verbose = False INTERVAL = 10 GRACE = 2 +DROPOVERDUE = 7*24*3600 os.environ['TZ'] = 'EST5EDT' @@ -305,6 +306,8 @@ def checkoverdue(): if conn.state == Connection.up and (now - conn.lastbeat) > timeout: conn.newstate(Connection.overdue, now, grace) pmsg.append(conn.afam) + if conn.state == Connection.overdue and (now - conn.lastbeat) > DROPOVERDUE: + conn.newstate(Connection.unknown, conn.lastbeat) if pmsg != []: if h in watchhosts: email("overdue", "%s overdue" % " and ".join(pmsg)) diff --git a/hbdclass.py b/hbdclass.py index 9042a81..b131354 100644 --- a/hbdclass.py +++ b/hbdclass.py @@ -51,6 +51,8 @@ class Connection: d['addr'] = self.addr if self.rtts[-1]: d['rtt'] = "%0.1f" % self.rtts[-1] + elif self.state == Connection.unknown: + d['rtt'] = "" else: d['rtt'] = "?" d['lastbeat'] = self.lastbeat @@ -60,11 +62,16 @@ class Connection: d['state'] = self.state if self.state == Connection.up: d['rttstate'] = d['rtt'] + elif self.state == Connection.overdue: + d['rttstate'] = '' else: d['rttstate'] = d['state'] d['statetime'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.statetime)) delta = now - self.statetime - if delta > 86400: + + if self.state == Connection.unknown: + d['deltastatetime'] = '' + elif delta > 86400: # d['deltastatetime'] = time.strftime("%d %H:%M:%S", time.gmtime(delta)) d['deltastatetime'] = "%0.1f days" % (delta / 86400.) elif delta > 3600: @@ -257,6 +264,8 @@ class Host: state += " %5.1f" % (self.connections[x].rtts[-1]) except: state += " %5s" % (self.connections[x].rtts[-1]) + elif self.state in ["unknown", "UNKNOWN"]: + state = "" else: state = "%s" % self.state return state From d3c266de90caac09562ba29d9ad75a5b89875cd8 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Mon, 11 Jul 2016 15:54:52 -0400 Subject: [PATCH 11/32] reopen UDP socket periodically --- hbc | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/hbc b/hbc index bcc7e62..a7e93ac 100755 --- a/hbc +++ b/hbc @@ -22,6 +22,7 @@ import syslog PORT = 50003 INTERVAL = 10 +REOPENC = 6 PIDFILE = '/tmp/hbc.pid' VER = 4 MAXRECV = 32767 @@ -54,13 +55,22 @@ class Conn: self.send = 0 self.lastsend = 0 # time() last msg was sent self.rtts = [0] - self.sock=socket.socket(af, socket.SOCK_DGRAM) + self.sock = None + + + def open(self): + self.sock=socket.socket(self.af, socket.SOCK_DGRAM) self.sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, \ self.sock.getsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR) | 1) + def sendto(self, msg, ID = 'HTB'): # default ID is HearTBeat global warned1 + if self.send % REOPENC == 0: + self.close() + if not self.sock: + self.open() msg['name'] = shortname(iam) msg['id'] = self.conId msg['ver'] = VER @@ -73,6 +83,7 @@ class Conn: except socket.error as e: if not warned1: log("socket error: %s %s:%s" % (e, self.addr, self.port)) warned1 = True + self.close() return self.send += 1 self.lastsend = time.time() @@ -252,15 +263,16 @@ def restart(): def process(): global running, dorestart - ifiles = {} - conIds = {} - for conn in conns: - ifiles[conns[conn].sock.fileno()] = conns[conn].sock - conIds[conns[conn].sock.fileno()] = conn nextReport = time.time() while running: while time.time() < nextReport: + ifiles = {} + conIds = {} + for conn in conns: + ifiles[conns[conn].sock.fileno()] = conns[conn].sock + conIds[conns[conn].sock.fileno()] = conn + sleep=nextReport - time.time() if sleep <= 0: break From e306e4d5f691fd185cf22b39543e41263227099f Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Mon, 11 Jul 2016 16:01:26 -0400 Subject: [PATCH 12/32] ingore closed connections --- hbc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hbc b/hbc index a7e93ac..b21cd45 100755 --- a/hbc +++ b/hbc @@ -270,8 +270,9 @@ def process(): ifiles = {} conIds = {} for conn in conns: - ifiles[conns[conn].sock.fileno()] = conns[conn].sock - conIds[conns[conn].sock.fileno()] = conn + if conns[conn].sock: + ifiles[conns[conn].sock.fileno()] = conns[conn].sock + conIds[conns[conn].sock.fileno()] = conn sleep=nextReport - time.time() if sleep <= 0: From 5808bbc791c997bd21616a01946de81709658679 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Tue, 16 Aug 2016 21:45:10 +0200 Subject: [PATCH 13/32] ignore (for now) failed return packets --- hbd | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hbd b/hbd index e86fcd7..50a12c2 100755 --- a/hbd +++ b/hbd @@ -443,7 +443,10 @@ def readsock(sock): rmsg = 'ACK' else: opkt = dicttos('ACK', rmsg, host.cver > 1) # clients w/ ver 2+ can cope - ss=sock.sendto(opkt, addr) + try: + 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]) # send any commands we have queued From e69de2472a6dc97ffc9b35393d14ce94361abe01 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Thu, 18 May 2017 17:02:15 -0400 Subject: [PATCH 14/32] allow comments in config file --- hbd | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/hbd b/hbd index 50a12c2..4689ffa 100755 --- a/hbd +++ b/hbd @@ -824,14 +824,21 @@ except: if f: while 1: - l = f.readline() - if len(l) == 0: + ls = f.readline() + if len(ls) == 0: break + l = ls[:-1].strip() + if len(l) == 0 or l[0] == "#": + continue if verbose: - print " %s" % l[:-1] - r = l[:-1].split('=') + print " %s" % l + r = l.split('=') o = r[0].strip() - a = eval(r[1].strip()) + try: + a = eval(r[1].strip()) + except Exception as e: + print "error: %s" % str(r) + sys.exit(1) if o == 'interval': interval = a elif o == 'grace': From 64e5f6a04f90c9dacc4d9d1e06ab69485466852b Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Fri, 1 Sep 2017 13:08:08 -0400 Subject: [PATCH 15/32] check msg --- hbc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hbc b/hbc index b21cd45..422444c 100755 --- a/hbc +++ b/hbc @@ -298,7 +298,9 @@ def process(): if verbose: print "sock.recvfrom: %s (%s) %s" % (addr, len(data), data[:4]) msgDict = stodict(data) if verbose: print "sock.recvfrom: %s (%s) %s" % (addr, len(data), str(msgDict)[:80]) - if msgDict['ID'] == "ACK": + if msgDict == None: + print "bad backet from %s (%s) %s" % (addr, len(data), data) + elif msgDict['ID'] == "ACK": conns[conn].ack(msgDict) elif msgDict['ID'] == "UPD": if doupdate(conn, msgDict) == None: From cddcc3e04e22b5b89f164b62607011831e238660 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Sat, 16 Sep 2017 09:40:27 -0400 Subject: [PATCH 16/32] better type for concat --- hbc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hbc b/hbc index b21cd45..84ad725 100755 --- a/hbc +++ b/hbc @@ -198,7 +198,7 @@ def doexec(conn, data): fail = "CalledProcessError" except Exception as e: syslogtrace('System') - ro = None + ro = "N/A" fail = "cmd failed: %s" % e msg={'service': 'command', 'msg': fail+" "+ro} conns[conn].sendto(msg) From 973ad7dd2889cb48dfffbe465f85aaa3896c3c1f Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Sat, 16 Sep 2017 15:44:32 +0200 Subject: [PATCH 17/32] ver 5 --- hbc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hbc b/hbc index f2c331f..1cb602a 100755 --- a/hbc +++ b/hbc @@ -24,7 +24,7 @@ PORT = 50003 INTERVAL = 10 REOPENC = 6 PIDFILE = '/tmp/hbc.pid' -VER = 4 +VER = 5 MAXRECV = 32767 running = True From c1334fead9c71ab7775b352e12f0bfaea458da2c Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Mon, 11 Dec 2017 15:06:58 -0500 Subject: [PATCH 18/32] send shutdown on sigterm --- hbc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hbc b/hbc index 1cb602a..62d2251 100755 --- a/hbc +++ b/hbc @@ -37,6 +37,9 @@ def log(msg): else: print msg +def handler(signum, frame): + if signum == signal.SIGTERM: + cleanup() class NullDevice: def write(self, s): @@ -329,6 +332,8 @@ def process(): def cleanup(): global running + if not running: + return if verbose: log('cleanup') running = False for conn in conns: @@ -538,6 +543,7 @@ if fdaemon: daemonized = True syslog.syslog(syslog.LOG_ERR, 'starting heartbeat to %s' % ','.join(hb_hosts)) +signal.signal(signal.SIGTERM, handler) running = True try: process() From 6902e2a80cb9cea535bbe99d34839a3f65f5111c Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Wed, 17 Jan 2018 00:01:49 +0100 Subject: [PATCH 19/32] improve debug output --- hbd | 10 +++++++--- hbdclass.py | 9 ++++++++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/hbd b/hbd index 4689ffa..3d19ddc 100755 --- a/hbd +++ b/hbd @@ -316,8 +316,9 @@ def checkoverdue(): def log(host, m, service=None): - if DEBUG > 0: print "Log: %s" % m - ts = time.strftime("%b %d %H:%M:%S", time.localtime(time.time())) + 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: srv = "service %s: " % service else: @@ -374,6 +375,7 @@ def readsock(sock): 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)) newh=True else: @@ -612,6 +614,7 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler): code, res=self.builderror(400, 'Data error', "h=%s not found" % uname) else: log(uname, "dropped") +# for addr in Host.hosts[uname].0i del Host.hosts[uname] res=self.buildhead() res.append("Done") @@ -884,7 +887,8 @@ if 1 and os.path.exists(pickfile): except: lastfm = ["","",""] pickf.close() - except: + except Exception as e: + print "load pickled failed: %s" % e os.unlink(pickfile) Connection.htab = {} for h in Host.hosts.keys(): diff --git a/hbdclass.py b/hbdclass.py index b131354..0355b25 100644 --- a/hbdclass.py +++ b/hbdclass.py @@ -13,7 +13,13 @@ num = 0 MAXRTTS = 10 -# +DEBUG=1 + +def log(host, m): + if DEBUG: + print "class log: %s %s" % (host, m) + + class Connection: # map of addrs to names @@ -38,6 +44,7 @@ class Connection: r = "new addr %s" % (addr) Connection.htab[addr] = self.host.name if self.host.isDynDns(): + log(self.host.name, "dns update %s" % self.addr) Host.dnsQ.put((self.host.name, self.addr)) def registerDns(self): From 26efe2d4c9eddf18b41731891035c29a2df967c8 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Tue, 23 Jan 2018 07:28:53 -0500 Subject: [PATCH 20/32] ignore malformed msgs --- hbd | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/hbd b/hbd index 3d19ddc..1bc1396 100755 --- a/hbd +++ b/hbd @@ -362,7 +362,10 @@ def readsock(sock): data, addrp = sock.recvfrom(MAXRECV) now = time.time() if DEBUG > 2: sys.stderr.write("readsock = %s, %s\n" % (data,addrp)) - msg = stodict(data) + try: + msg = stodict(data) + except: + return if not msg: # Old hbc client if verbose: print "old hbc:", data oldclient = True From cb737ac29af482b4f4b81183e0fe70367725a07a Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Sun, 4 Mar 2018 16:51:48 +0100 Subject: [PATCH 21/32] flag dyn hosts --- hbdclass.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/hbdclass.py b/hbdclass.py index 0355b25..50da640 100644 --- a/hbdclass.py +++ b/hbdclass.py @@ -179,6 +179,8 @@ class Host: def statedict(self): d = {} d['name'] = self.name + if self.dyn: + d['name'] += "*" d['dyn'] = str(self.dyn) d['ver'] = str(self.cver) d['num'] = self.num From cd5dfb515bfe0add25f47a1a6dc8ac545e657184 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Tue, 5 Mar 2019 15:14:32 -0500 Subject: [PATCH 22/32] str for Conn --- hbc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/hbc b/hbc index 62d2251..97d9300 100755 --- a/hbc +++ b/hbc @@ -1,6 +1,6 @@ #!/usr/bin/env python # $Id: hbc,v 1.9 2012/03/29 02:08:36 andreas Exp $ - +# NEW import sys import time import socket @@ -61,6 +61,10 @@ class Conn: self.sock = None + def __str__(self): + return "Con(%s, %s %s)" % (self.addr, self.port, self.af) + + def open(self): self.sock=socket.socket(self.af, socket.SOCK_DGRAM) self.sock.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR, \ @@ -189,6 +193,8 @@ def createConnections(hosts): addr = r[4][0] conns[conId] = Conn(conId, addr, hb_port, af) + if verbose: + print "cons[%s] = %s" % (conId, str(conns[conId])) conId += 1 From 656f9c07844b42833f8ad418fe3e9123608f126c Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Sat, 21 Sep 2019 18:23:18 +0200 Subject: [PATCH 23/32] use python2 --- hbc | 2 +- hbd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hbc b/hbc index 97d9300..cb30a60 100755 --- a/hbc +++ b/hbc @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # $Id: hbc,v 1.9 2012/03/29 02:08:36 andreas Exp $ # NEW import sys diff --git a/hbd b/hbd index 1bc1396..ee526db 100755 --- a/hbd +++ b/hbd @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # $Id: hbd,v 1.38 2013/07/14 02:25:05 andreas Exp $ # Wait for heartbeat messages and act on them (or their absence) # From 778c874cee5a0fe9caca424bfe91391724b8f48b Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Mon, 16 Dec 2019 12:03:32 -0500 Subject: [PATCH 24/32] move to python 3 --- hbd | 200 ++++++++++++++++++++++++++++++------------------------------ 1 file changed, 101 insertions(+), 99 deletions(-) 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) From 8d9af901684014a3c1ecaddcafee72ea9abd71b5 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Mon, 16 Dec 2019 12:03:43 -0500 Subject: [PATCH 25/32] move to python 3, fix rtt --- hbc | 147 +++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 87 insertions(+), 60 deletions(-) diff --git a/hbc b/hbc index cb30a60..abe2b4d 100755 --- a/hbc +++ b/hbc @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python # $Id: hbc,v 1.9 2012/03/29 02:08:36 andreas Exp $ # NEW import sys @@ -11,7 +11,7 @@ import string import select import errno import traceback -import md5 +from hashlib import md5 import shutil import zlib import subprocess @@ -35,7 +35,7 @@ def log(msg): if fdaemon: syslog.syslog(syslog.LOG_ERR, msg) else: - print msg + print(msg) def handler(signum, frame): if signum == signal.SIGTERM: @@ -82,7 +82,7 @@ class Conn: msg['id'] = self.conId msg['ver'] = VER msg['time'] = time.time() - m = dicttos(ID, msg, True) # always compress + m = dicttos(ID, msg) # always compress if verbose: log("conn.send('%s', (%s:%s) %s)" % (msg, self.addr, self.port, len(m))) try: @@ -93,14 +93,20 @@ class Conn: self.close() return self.send += 1 - self.lastsend = time.time() + self.lastsend = msg['time'] + print("RTT self.lastsend %s" % self.lastsend) - def ack(self, msgDict): - self.lastack = time.time() - self.lastacksent = float(msgDict.get('time','0')) - if verbose: log("ack RTT: %0.1f ms" % ((self.lastack - self.lastsend) * 1000.0)) - self.rtts.append((self.lastack - self.lastsend) * 1000.0) + def ack(self, msgDict, now): + try: + self.lastack = msgDict['time'] + mul = 2 + except: + self.lastack = now + mul = 1 + rtt = (self.lastack - self.lastsend) * mul + if verbose: log("ack RTT: %0.1f ms (now %s)" % (rtt * 1000.0, now)) + self.rtts.append(rtt * 1000.0) if len(self.rtts) > 10: del self.rtts[0] self.ackcount += 1 @@ -113,11 +119,11 @@ class Conn: def shortname(name): - r = string.split(name, '.') + r = name.split('.') return r[0] -def dicttos(ID, d, compress=False): +def dicttos(ID, d): s = [] for k in d: if type(d[k]) == type(1.2): @@ -125,15 +131,35 @@ def dicttos(ID, d, compress=False): else: s.append("%s=%s" % (k, d[k])) pk = ";".join(s) - if compress: - zpk = zlib.compress(pk, 6) - ID = "!"+ID - else: - zpk = pk - return ID + ":" + zpk - + zpk = zlib.compress(pk.encode(), 6) + ID = "!" + ID + ":" + return ID.encode() + zpk def stodict(msg): + d = {} + 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(';') + for v in r: + vr = v.split('=', 1) + k = vr[0].strip() + if len(vr) == 1: + d[k] = None + else: + v = vr[1].strip() + if v[0].isdigit(): + v = eval(v) + d[k] = v + print("DBG: msg is %s" % d) + return d + + +def XXstodict(msg): d = {} r0 = msg.split(':',1) if len(r0) == 1: @@ -167,7 +193,7 @@ def syslogtrace(note): for l in logm.split('\n'): syslog.syslog(syslog.LOG_ERR, ' tb: %s' % l) if verbose: - print logm + print(logm) conId = 1 @@ -188,13 +214,13 @@ def createConnections(hosts): elif r[0] == 2: af=socket.AF_INET else: - print "dont know this net type: %s" % r[0][0] + print("dont know this net type: %s" % r[0][0]) sys.exit(1) addr = r[4][0] conns[conId] = Conn(conId, addr, hb_port, af) if verbose: - print "cons[%s] = %s" % (conId, str(conns[conId])) + print("cons[%s] = %s" % (conId, str(conns[conId]))) conId += 1 @@ -258,14 +284,14 @@ def doupdateone(code, csum): def restart(): if verbose: - print "restart: execv %s %s" % (sys.argv[0], [sys.argv[0]]+cmdargs) + print("restart: execv %s %s" % (sys.argv[0], [sys.argv[0]]+cmdargs)) syslog.syslog(syslog.LOG_ERR, 'restart %s' % (sys.argv[0])) e = "fallthrough" try: os.execv(sys.argv[0], [sys.argv[0]]+cmdargs) except Exception as e: pass - print "should not be here:", str(e) + print("should not be here:", str(e)) log('restart failed: %s' % e) @@ -287,7 +313,8 @@ def process(): if sleep <= 0: break try: - r=select.select(ifiles.keys(),[],[],sleep) + r=select.select(list(ifiles.keys()),[],[],sleep) + now = time.time() # nb: delay from actual packet arrival to select is ca. 105ms! except KeyboardInterrupt: running = False break @@ -304,16 +331,16 @@ def process(): for rfh in r[0]: conn = conIds[rfh] data, addr = ifiles[rfh].recvfrom(MAXRECV) - if verbose: print "sock.recvfrom: %s (%s) %s" % (addr, len(data), data[:4]) +# if verbose: print("sock.recvfrom: %s (%s) %s" % (addr, len(data), data[:4])) msgDict = stodict(data) - if verbose: print "sock.recvfrom: %s (%s) %s" % (addr, len(data), str(msgDict)[:80]) + if verbose: print("sock.recvfrom: %s (%s) %s" % (addr, len(data), str(msgDict)[:80])) if msgDict == None: - print "bad backet from %s (%s) %s" % (addr, len(data), data) + print("bad backet from %s (%s) %s" % (addr, len(data), data)) elif msgDict['ID'] == "ACK": - conns[conn].ack(msgDict) + conns[conn].ack(msgDict, now) elif msgDict['ID'] == "UPD": if doupdate(conn, msgDict) == None: - if verbose: print "process: restart after update" + if verbose: print("process: restart after update") dorestart = True break elif msgDict['ID'] == "CMD": @@ -369,7 +396,7 @@ def daemonize(working_dir="/", stdin='/dev/zero', stdout='/dev/null', stderr='/d if pid > 0: # exit from first parent os._exit(0) - except OSError, e: + except OSError as e: sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror)) os._exit(1) @@ -383,7 +410,7 @@ def daemonize(working_dir="/", stdin='/dev/zero', stdout='/dev/null', stderr='/d if pid > 0: # exit from second parent os._exit(0) - except OSError, e: + except OSError as e: sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror)) sys.exit(1) @@ -438,20 +465,20 @@ for o,a in optlist: cmdargs += args -if verbose: print "cmdargs for restart are %s" % cmdargs +if verbose: print("cmdargs for restart are %s" % cmdargs) if helpflag: - print "hbc HeartBeatClient" - print "usage: hbc [-bdhv] [-c configfile] [-m msg][host1 [..]]" - print - print " -b indicate machine boot" - print " -c configfile" - print " -d daemonize" - print " -h this help" - print " -m send a message" - print " -v verbose" - print - print """ config file can contain + print("hbc HeartBeatClient") + print("usage: hbc [-bdhv] [-c configfile] [-m msg][host1 [..]]") + print() + print(" -b indicate machine boot") + print(" -c configfile") + print(" -d daemonize") + print(" -h this help") + print(" -m send a message") + print(" -v verbose") + print() + print(""" config file can contain hb_hosts=('host1', 'host2', ..._ hb_port=50003 interval=20 @@ -459,7 +486,7 @@ logfile=... logfmt={|test|msg} grace=SECONDS reportstrict={True|False} -""" +""") sys.exit(1) @@ -473,9 +500,9 @@ iam=socket.gethostname() try: f=open(configfile,"r") - if verbose: print "notice: using config file %s" % configfile + if verbose: print("notice: using config file %s" % configfile) except: - if verbose: print "warning: running without config file: %s" % configfile + if verbose: print("warning: running without config file: %s" % configfile) f=None if f: @@ -487,14 +514,14 @@ if f: if r[0] == 'hb_hosts': hb_hosts=eval(r[1]) if verbose: - print "notice: cfg hb_hosts: %s" % hb_hosts + print("notice: cfg hb_hosts: %s" % hb_hosts) elif r[0] == 'interval': interval=eval(r[1]) elif r[0] == 'hb_port': hb_port=eval(r[1]) elif r[0] == 'name': iam=eval(r[1]) - if verbose: print "name set to %s" % iam + if verbose: print("name set to %s" % iam) f.close() if len(args) != 0: @@ -502,17 +529,17 @@ if len(args) != 0: if len(hb_hosts) == 0: - print "no hb server specified" + print("no hb server specified") sys.exit(1) # if verbose: - print "notice: hb_hosts: %s" % str(hb_hosts) - print "notice: hb_port: %s" % hb_port - print "notice: interval: %s" % interval - print "notice: iam: %s" % iam - print "notice: msgonly: %s" % msgonly - print "notice: msgboot: %s" % msgboot + print("notice: hb_hosts: %s" % str(hb_hosts)) + print("notice: hb_port: %s" % hb_port) + print("notice: interval: %s" % interval) + print("notice: iam: %s" % iam) + print("notice: msgonly: %s" % msgonly) + print("notice: msgboot: %s" % msgboot) if not msgonly: msgboot['interval'] = interval @@ -531,20 +558,20 @@ if verbose: log("%s connections created" % (len(conns))) if len(msgboot) > 0: - if verbose: print "on boot" + if verbose: print("on boot") msgboot['acks'] = 0 for conn in conns: conns[conn].sendto(msgboot) if msgonly: - if verbose: print "msgboot done msgonly=%s" % msgonly + if verbose: print("msgboot done msgonly=%s" % msgonly) closeall() sys.exit(0) # syslog.openlog('hbc', syslog.LOG_PID, syslog.LOG_DAEMON) if fdaemon: - print "daemoinizing." + print("daemoinizing.") daemonize() daemonized = True syslog.syslog(syslog.LOG_ERR, 'starting heartbeat to %s' % ','.join(hb_hosts)) @@ -555,7 +582,7 @@ try: process() except: syslogtrace('process') - if verbose: print "err: process exit: %s" % e + if verbose: print("err: process exit: %s" % e) if verbose: log( "main: cleanup") cleanup() From 1dde8df0a7ced6b1c8c74f9656f27772d06abf7c Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Mon, 16 Dec 2019 12:04:04 -0500 Subject: [PATCH 26/32] move to python 3 --- hbdclass.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hbdclass.py b/hbdclass.py index 50da640..dff4cb1 100644 --- a/hbdclass.py +++ b/hbdclass.py @@ -17,7 +17,7 @@ DEBUG=1 def log(host, m): if DEBUG: - print "class log: %s %s" % (host, m) + print("class log: %s %s" % (host, m)) class Connection: @@ -268,7 +268,7 @@ class Host: state = "%s" % self.state elif self.state in ["up", "UP"]: state = "" - for x in self.connections.keys(): + for x in list(self.connections.keys()): try: state += " %5.1f" % (self.connections[x].rtts[-1]) except: @@ -285,7 +285,7 @@ class Host: if self.upcount > 0: # return "(%0.1f%%) %s %s %s " % ((self.doesack * 100.0) / self.upcount, self.doesack, self.upcount, self.hdwcounts) r = "" - for v in xrange(3): + for v in range(3): a,u = self.hdwcounts[v] if (self.upcount - u) != 0: vs = "%0.0f" % (100.0 - (((self.doesack - a) * 100.0) / (self.upcount - u))) @@ -338,7 +338,7 @@ class Host: res = [] res.append('') res.append(ubHost.htmltable('th', ubHost.headerdict(), short)) - hosts_sorted = Host.hosts.keys() + hosts_sorted = list(Host.hosts.keys()) if len(hosts_sorted): hosts_sorted.sort() for h in hosts_sorted: From 5a095090a01d4c9c48faf63703ae96408cf4cb4c Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Mon, 16 Dec 2019 12:04:13 -0500 Subject: [PATCH 27/32] move to python 3 --- pushHeartbeat.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pushHeartbeat.py b/pushHeartbeat.py index 3fbd44e..4c2db66 100755 --- a/pushHeartbeat.py +++ b/pushHeartbeat.py @@ -1,12 +1,12 @@ #!/usr/bin/python import sys -import httplib, urllib +import http.client, urllib.request, urllib.parse, urllib.error def pushover(msg): - conn = httplib.HTTPSConnection("api.pushover.net:443") + conn = http.client.HTTPSConnection("api.pushover.net:443") conn.request("POST", "/1/messages.json", - urllib.urlencode({ + urllib.parse.urlencode({ "token": "ac7NLX2rPjXFareeDgLpXNoDf4iFmf", "user": "uDhH33UjQQDYtNzJb1ThRiWb9ingGK", "message": msg, @@ -18,6 +18,6 @@ def pushover(msg): v=" ".join(sys.argv[1:]) if pushover(v): - print "delivered" + print("delivered") else: - print "NOT delivered" + print("NOT delivered") From 43910bd3c49191f6655d156a3452f51337b05dc1 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Mon, 16 Dec 2019 12:04:24 -0500 Subject: [PATCH 28/32] move to python 3 --- pushNagios.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pushNagios.py b/pushNagios.py index 52e19bb..197560f 100755 --- a/pushNagios.py +++ b/pushNagios.py @@ -1,13 +1,13 @@ #!/usr/bin/python import sys -import httplib, urllib +import http.client, urllib.request, urllib.parse, urllib.error import getopt def pushover(msg, title=""): - conn = httplib.HTTPSConnection("api.pushover.net:443") + conn = http.client.HTTPSConnection("api.pushover.net:443") conn.request("POST", "/1/messages.json", - urllib.urlencode({ + urllib.parse.urlencode({ "token": "aNY2xeYydxzabzihTjb3P2LMHhqhr2", "user": "uDhH33UjQQDYtNzJb1ThRiWb9ingGK", "message": msg, @@ -29,7 +29,7 @@ title="Nagios" optslist, args = [], [] try: optslist, args = getopt.getopt(sys.argv[1:], 'ht:v') -except getopt.error, cause: +except getopt.error as cause: helpflag=True lastyear=0 @@ -44,6 +44,6 @@ v=" ".join(args) rc=pushover(v, title) if verbose: if rc: - print "delivered" + print("delivered") else: - print "NOT delivered" + print("NOT delivered") From 7cf8f16dcfc62c4b2aca62fd248babdd331986f7 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Mon, 16 Dec 2019 12:20:43 -0500 Subject: [PATCH 29/32] file->open and clean debug statements --- hbc | 9 ++++----- hbd | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/hbc b/hbc index abe2b4d..107b29d 100755 --- a/hbc +++ b/hbc @@ -94,7 +94,6 @@ class Conn: return self.send += 1 self.lastsend = msg['time'] - print("RTT self.lastsend %s" % self.lastsend) def ack(self, msgDict, now): @@ -155,7 +154,7 @@ def stodict(msg): if v[0].isdigit(): v = eval(v) d[k] = v - print("DBG: msg is %s" % d) + if verbose: print("DBG: msg is %s" % d) return d @@ -417,9 +416,9 @@ def daemonize(working_dir="/", stdin='/dev/zero', stdout='/dev/null', stderr='/d # redirects standard file descriptors sys.stdout.flush() sys.stderr.flush() - si = file(stdin, 'r') - so = file(stdout, 'a+') - se = file(stderr, 'a+', 0) + si = open(stdin, 'r') + so = open(stdout, 'a+') + se = open(stderr, 'a+') os.dup2(si.fileno(), sys.stdin.fileno()) os.dup2(so.fileno(), sys.stdout.fileno()) os.dup2(se.fileno(), sys.stderr.fileno()) diff --git a/hbd b/hbd index 3587eb4..cde4f97 100755 --- a/hbd +++ b/hbd @@ -2,7 +2,7 @@ # $Id: hbd,v 1.38 2013/07/14 02:25:05 andreas Exp $ # Wait for heartbeat messages and act on them (or their absence) # -VER = 3.00 +VER = 4.00 import time import os From 83a43a1897a3e979d1a28ea544a42e991af36e61 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Mon, 16 Dec 2019 13:42:11 -0500 Subject: [PATCH 30/32] fix debugs --- hbc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hbc b/hbc index 107b29d..2249b2f 100755 --- a/hbc +++ b/hbc @@ -93,7 +93,7 @@ class Conn: self.close() return self.send += 1 - self.lastsend = msg['time'] + self.lastsend = time.time() def ack(self, msgDict, now): @@ -154,7 +154,7 @@ def stodict(msg): if v[0].isdigit(): v = eval(v) d[k] = v - if verbose: print("DBG: msg is %s" % d) + if verbose: print("msg is %s" % d) return d From 17083f186ddbcabbc69f3940ca973ed45d1d8818 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Mon, 16 Dec 2019 19:42:47 +0100 Subject: [PATCH 31/32] more 2to3 fallout --- hbd | 113 +++++++++++++++++++++++++++------------------------- hbdclass.py | 6 ++- 2 files changed, 63 insertions(+), 56 deletions(-) diff --git a/hbd b/hbd index cde4f97..50d6023 100755 --- a/hbd +++ b/hbd @@ -29,13 +29,15 @@ import zlib from subprocess import Popen, STDOUT, PIPE -from hbdclass import * +#from hbdclass import * +import hbdclass SEND_EMAIL=False SEND_PUSHOVER=True -DEBUG = 3 +DEBUG = 2 +hbdclass.DEBUG = DEBUG MAXRECV = 32767 LOGFILE = "/home/andreas/public_html/messages/andreas" @@ -247,7 +249,7 @@ answer except: return "nsupdate: some error occured" - (output, err) = p.communicate(nsup) + (output, err) = p.communicate(nsup.encode()) if output.find('status: NOERROR') >= 0: return None return output @@ -267,11 +269,11 @@ def dur(sec): def fixsort(): - s = list(Host.hosts.keys()) + s = list(hbdclass.Host.hosts.keys()) s.sort() x = 0 for n in s: - Host.hosts[n].num = x + hbdclass.Host.hosts[n].num = x x += 1 # @@ -296,18 +298,18 @@ def initlog(logfile): # def checkoverdue(): now = time.time() - for h in list(Host.hosts.keys()): + for h in list(hbdclass.Host.hosts.keys()): pmsg = [] - for c in Host.hosts[h].connections: - conn = Host.hosts[h].connections[c] - if conn.state == Connection.down: + for c in hbdclass.Host.hosts[h].connections: + conn = hbdclass.Host.hosts[h].connections[c] + if conn.state == hbdclass.Connection.down: continue - timeout = Host.hosts[h].interval + grace - if conn.state == Connection.up and (now - conn.lastbeat) > timeout: - conn.newstate(Connection.overdue, now, grace) + timeout = hbdclass.Host.hosts[h].interval + grace + if conn.state == hbdclass.Connection.up and (now - conn.lastbeat) > timeout: + conn.newstate(hbdclass.Connection.overdue, now, grace) pmsg.append(conn.afam) - if conn.state == Connection.overdue and (now - conn.lastbeat) > DROPOVERDUE: - conn.newstate(Connection.unknown, conn.lastbeat) + if conn.state == hbdclass.Connection.overdue and (now - conn.lastbeat) > DROPOVERDUE: + conn.newstate(hbdclass.Connection.unknown, conn.lastbeat) if pmsg != []: if h in watchhosts: email("overdue", "%s overdue" % " and ".join(pmsg)) @@ -316,7 +318,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: @@ -341,7 +343,7 @@ def log(host, m, service=None): def dnsupdatethread(): while True: - name, addr = Host.dnsQ.get() + name, addr = hbdclass.Host.dnsQ.get() m = "changed address to %s" % (addr) err = nsupdate(name, addr) if err: @@ -349,7 +351,7 @@ def dnsupdatethread(): email("error: nsupdate failed", "%s: %s" % (name, m)) else: m += ", DNS updated." - Host.dnsQ.task_done() + hbdclass.Host.dnsQ.task_done() log(name, m) # @@ -377,17 +379,20 @@ def readsock(sock): addr = addrp[0:2] name = shortname(msg.get('name', "unknown")) - if not name in Host.hosts: # was: hosts.has_key(name): - host = Host(name) + if not name in hbdclass.Host.hosts: # was: hosts.has_key(name): + host = hbdclass.Host(name) host.dyn = name in dyndnshosts - if verbose: print(("XX: New host, num now %s" % (len(Host.hosts)))) + if verbose: print(("XX: New host, num now %s" % (len(hbdclass.Host.hosts)))) newh=True else: - host = Host.hosts[name] + host = hbdclass.Host.hosts[name] newh=False cid = msg.get('id', 0) - rtt = msg.get('rtt',None) + try: + rtt = float(msg.get('rtt',None)) + except: + rtt = None if msg['ID'] == 'HTB': host.doesack = msg.get('acks', -1) @@ -417,9 +422,9 @@ def readsock(sock): email("address change", "%s %s" % (host.name, res)) pushover("%s %s" % (host.name, res)) - if conn.getstate() != Connection.up: # XXX and interval > 0: + if conn.getstate() != hbdclass.Connection.up: # XXX and interval > 0: lasts = conn.state - d = conn.newstate(Connection.up, now) + d = conn.newstate(hbdclass.Connection.up, now) m = "%s back after being %s for %s" % (conn.afam, lasts, dur(d)) log(name, m) if name in watchhosts: @@ -437,7 +442,7 @@ def readsock(sock): if name in watchhosts: email("shutdown", "%s %s shutdown" % (name, conn.afam)) pushover("%s %s shutdown" % (name, conn.afam)) - conn.newstate(Connection.down, now) + conn.newstate(hbdclass.Connection.down, now) if interval > 0: host.interval = interval @@ -500,7 +505,7 @@ def updatecode(ucode, uname): m.update(new_code) icsum = m.hexdigest() rmsg = {'csum': icsum, 'code': new_code.encode('base64','strict') } - Host.hosts[uname].cmds.append(('UPD',rmsg)) + hbdclass.Host.hosts[uname].cmds.append(('UPD',rmsg)) return fail # @@ -538,7 +543,7 @@ class HttpHandler(http.server.BaseHTTPRequestHandler): 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("Accept-Ranges","bytes") -# self.send_header("Connection","close") +# self.send_header("hbdclass.Connection","close") for h in headerdict: self.send_header(h, headerdict[h]) self.end_headers() @@ -562,10 +567,8 @@ class HttpHandler(http.server.BaseHTTPRequestHandler): def buildpage(self): res=self.buildhead(refresh=60, extras=tcss) res.append("

Heartbeat status %s

" % VER) - - - res += ubHost.buildhosttable() - res += ubHost.buildmsgtable(msgs) + res += hbdclass.ubHost.buildhosttable() + res += hbdclass.ubHost.buildmsgtable(msgs) res.append('

%s (%s)

' % (time.strftime("%H:%M:%S", time.localtime(now)), os.environ.get('TZ', 'CET-1CDT'))) res.append("") return res @@ -604,10 +607,10 @@ class HttpHandler(http.server.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 uname not in Host.hosts: + elif uname not in hbdclass.Host.hosts: code, res=self.builderror(400, 'Data error', "h=%s not found" % uname) else: - 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.append("cmd %s queued for host %s" % (uname, ucmd)) @@ -615,12 +618,12 @@ class HttpHandler(http.server.BaseHTTPRequestHandler): uname=qa.get('h',[None])[0] if not uname: code, res=self.builderror(400, 'Argument error', "need h= argument") - if not uname in Host.hosts: + if not uname in hbdclass.Host.hosts: code, res=self.builderror(400, 'Data error', "h=%s not found" % uname) else: log(uname, "dropped") -# for addr in Host.hosts[uname].0i - del Host.hosts[uname] +# for addr in hbdclass.Host.hosts[uname].0i + del hbdclass.Host.hosts[uname] res=self.buildhead() res.append("Done") @@ -628,10 +631,10 @@ class HttpHandler(http.server.BaseHTTPRequestHandler): uname=qa.get('h',[None])[0] if not uname: code, res=self.builderror(400, 'Argument error', "need h= argument") - if not uname in Host.hosts: + if not uname in hbdclass.Host.hosts: code, res=self.builderror(400, 'Data error', "h=%s not found" % uname) else: - ll = Host.hosts[uname].registerDns() + ll = hbdclass.Host.hosts[uname].registerDns() res.append(ll) log(uname, ll) @@ -640,7 +643,7 @@ class HttpHandler(http.server.BaseHTTPRequestHandler): 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 uname not in Host.hosts: + elif uname != 'All' and uname not in hbdclass.Host.hosts: code, res=self.builderror(400, 'Data error', "h=%s not found" % uname) else: res=self.buildhead() @@ -648,8 +651,8 @@ class HttpHandler(http.server.BaseHTTPRequestHandler): names = [uname] else: names = [] - for n in Host.hosts: - if Host.hosts[n].cver >= 2: # earliest version that supports update + for n in hbdclass.Host.hosts: + if hbdclass.Host.hosts[n].cver >= 2: # earliest version that supports update names.append(n) for n in names: err = updatecode(ucode, n) @@ -659,8 +662,8 @@ class HttpHandler(http.server.BaseHTTPRequestHandler): elif qr.path == "/api/0/hosts": # api access to host table headerdict = {"Content-Type": "application/json; charset=utf-8" } l=[] - for h in Host.hosts: - l.append(Host.hosts[h].jsons()) + for h in hbdclass.Host.hosts: + l.append(hbdclass.Host.hosts[h].jsons()) res=["["+",".join(l)+"]"] elif qr.path == "/api/0/messages": # api access to host table @@ -745,7 +748,7 @@ def saveandrestart(): def pickleit(): pickf = open(pickfile, 'wb') pick = pickle.Pickler(pickf) - pick.dump(Host.hosts) + pick.dump(hbdclass.Host.hosts) pick.dump(msgs) pick.dump(lastfm) pickf.close() @@ -885,7 +888,7 @@ if 1 and os.path.exists(pickfile): pickf = open(pickfile, 'rb') pick = pickle.Unpickler(pickf) try: - Host.hosts = pick.load() + hbdclass.Host.hosts = pick.load() msgs = pick.load() try: lastfm = pick.load() @@ -895,14 +898,14 @@ if 1 and os.path.exists(pickfile): except Exception as e: print(("load pickled failed: %s" % e)) os.unlink(pickfile) - Connection.htab = {} - for h in list(Host.hosts.keys()): - Host.hosts[h].dyn = h in dyndnshosts - Host.hosts[h].fixup() + hbdclass.Connection.htab = {} + for h in list(hbdclass.Host.hosts.keys()): + hbdclass.Host.hosts[h].dyn = h in dyndnshosts + hbdclass.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 h in hbdclass.Host.hosts: + del hbdclass.Host.hosts[h] + if verbose: print(("%s pickled hosts loaded" % len(hbdclass.Host.hosts))) else: if verbose: print("no pickled data") @@ -960,7 +963,7 @@ servthread = threading.Thread(target=serv.serve_forever) servthread.daemon = True servthread.start() -Host.dnsQ = queue.Queue() +hbdclass.Host.dnsQ = queue.Queue() dnsT = threading.Thread(target=dnsupdatethread) dnsT.daemon = True dnsT.start() @@ -1010,8 +1013,8 @@ while running: ts=time.strftime(tsfm[v], time.localtime(now)) if ts != lastfm[v]: lastfm[v]=ts - for h in list(Host.hosts.keys()): - Host.hosts[h].hdwcounts[v] = [Host.hosts[h].doesack, Host.hosts[h].upcount] + for h in list(hbdclass.Host.hosts.keys()): + hbdclass.Host.hosts[h].hdwcounts[v] = [hbdclass.Host.hosts[h].doesack, hbdclass.Host.hosts[h].upcount] if now >= rnext and now >= firstcheck: rnext = now+1 diff --git a/hbdclass.py b/hbdclass.py index dff4cb1..f2661ff 100644 --- a/hbdclass.py +++ b/hbdclass.py @@ -13,7 +13,7 @@ num = 0 MAXRTTS = 10 -DEBUG=1 +DEBUG=2 def log(host, m): if DEBUG: @@ -335,6 +335,8 @@ class Host: def buildhosttable(self, short=False): + if DEBUG > 1: + print("DBG buildhosttable: start") res = [] res.append('
') res.append(ubHost.htmltable('th', ubHost.headerdict(), short)) @@ -344,6 +346,8 @@ class Host: for h in hosts_sorted: res.append(ubHost.htmltable('td', Host.hosts[h].statedict(), short)) res.append("
") + if DEBUG > 1: + print("DBG buildhosttable: %s" % res) return res From 8da1d8c38bfdd5f320a0456b3ce714c03cdecf36 Mon Sep 17 00:00:00 2001 From: Andreas Wrede Date: Mon, 16 Dec 2019 19:43:37 +0100 Subject: [PATCH 32/32] turn debugging off --- hbd | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hbd b/hbd index 50d6023..8e3d5a8 100755 --- a/hbd +++ b/hbd @@ -36,7 +36,7 @@ import hbdclass SEND_EMAIL=False SEND_PUSHOVER=True -DEBUG = 2 +DEBUG = 0 hbdclass.DEBUG = DEBUG MAXRECV = 32767