diff --git a/hbd b/hbd
index 67411e4..9b737d5 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 = 2.00
+VER = 3.00
import time
import os
@@ -37,7 +37,9 @@ AEMAIL = ["andreas@wrede.ca"]
NAME = "heatbeat"
SMTPSERVER = "localhost"
+# Table of Hosts
hosts = {}
+# map of addrs to names
htab = {}
msgs = []
@@ -74,26 +76,25 @@ def shortname(name):
return r[0]
+def isIPv4(addr):
+ return addr.find('.') > 0
+
class NullDevice:
def write(self, s):
pass
-class Addr:
- def __init__(self, a4, a6):
- self.a4 = a4
- self.a6 = a6
-
-
class Host:
up = "up"
down = "down"
overdue = "overdue"
- def __init__(self, name, addr):
+
+ def __init__(self, name):
global num
- self.name = shortname(name)
- self.addr = addr
+ self.name = name
+ self.addr4 = None
+ self.addr6 = None
self.num = num
self.lastbeat = time.time()
self.upcount = 0
@@ -105,6 +106,37 @@ class Host:
self.cmds = []
self.hdwcounts = [[0,0],[0,0],[0,0]]
num += 1
+ hosts[name] = self
+
+
+ def newaddr(self, addr):
+ if isIPv4(addr):
+ if self.addr4:
+ if self.addr4 == addr:
+ r = None
+ else:
+ r = "changed from %s to %s" % (self.addr4, addr)
+ del htab[self.addr4]
+ self.addr4 = addr
+ htab[addr] = self.name
+ else:
+ r = "new addr %s" % (addr)
+ self.addr4 = addr
+ htab[addr] = self.name
+ else:
+ if self.addr6:
+ if self.addr6 == addr:
+ r = None
+ else:
+ r = "changed from %s to %s" % (self.addr6, addr)
+ del htab[self.addr6]
+ self.addr6 = addr
+ htab[addr] = self.name
+ else:
+ r = "new addr %s" % (addr)
+ self.addr6 = addr
+ htab[addr] = self.name
+ return r
# called when reloading class from pickle, add new fields here
@@ -119,9 +151,21 @@ class Host:
except:
self.hdwcounts = [[self.doesack,self.upcount],[self.doesack,self.upcount],[self.doesack,self.upcount]]
+ try:
+ a=self.addr4
+ except:
+ print "fix %s: addr to addr4/6 fixup" % self.name
+ if isIPv4(self.addr):
+ self.addr4 = self.addr
+ else:
+ self.addr6 = self.addr
+ del self.addr
+
+
def getstate(self):
return self.state
+
def dispstate(self):
if self.state in ["down", "overdue"]:
state = "%s" % self.state
@@ -129,6 +173,7 @@ class Host:
state = "%s" % self.state
return state
+
def dispstats(self):
if self.doesack != -1:
if self.upcount > 0:
@@ -148,6 +193,7 @@ class Host:
return "
(%s) | | | " % (self.doesack)
return 'N/A | | >'
+
# set new state, return number of secs in previous state
def newstate(self, state, when=0):
self.state = state
@@ -255,25 +301,13 @@ def dur(sec):
return "0:%02d" % s
-#
-def addhost(name, addr):
- sname = shortname(name)
- if sname in hosts: # was: hosts.has_key(sname):
- del htab[hosts[sname].addr]
- hosts[sname].addr = addr
- htab[addr] = sname
- m = "%s, changed address to %s" % (sname, addr)
- log(m)
- else:
- hosts[sname] = Host(sname, addr)
- s = hosts.keys()
- s.sort()
- x = 0
- for n in s:
- hosts[n].num = x
- x += 1
- htab[addr] = sname
-
+def fixsort():
+ s = hosts.keys()
+ s.sort()
+ x = 0
+ for n in s:
+ hosts[n].num = x
+ x += 1
#
def on_exit():
@@ -286,7 +320,11 @@ def on_exit():
def initlog(logfile):
- return open(logfile, "a")
+ try:
+ return open(logfile, "a+")
+ except:
+ pass
+ return open(logfile, "w")
#
@@ -337,23 +375,21 @@ def dnsupdatethread():
def fromaddr(name, addr, boot, interval, acks):
global htab
-
newh=False
if not name in hosts: # was: hosts.has_key(name):
- addhost(name, addr)
+ host = Host(name)
newh=True
- host = hosts[name]
+ else:
+ host = hosts[name]
+
host.doesack = acks
- if host.addr != addr:
- if host.addr in htab: # was: htab.has_key(host.addr):
- del htab[host.addr]
- host.addr = addr
- htab[addr] = name
- m = "%s changed address to %s" % (host.name, addr)
- if name in dyndnshosts and not ":" in addr: # don't try and cat ptr to IPv6 addr
+ res = host.newaddr(addr)
+ if res:
+ m = "%s %s" % (host.name, res)
+ log(m)
+ if name in dyndnshosts and isIPv4(addr): # don't try and cat ptr to IPv6 addr
+ if DEBUG > 0: print "dbg: dynhost and %s: %s" % (isIPv4(addr), addr)
dnsQ.put((name, addr))
- else:
- log(m)
if name in watchhosts:
email("address change", m)
pushover(m)
@@ -507,12 +543,12 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler):
res=self.buildhead(refresh=60)
res.append("Heartbeat status %s
%s (%s)
" % (VER, time.strftime("%H:%M:%S", time.localtime(now)), os.environ.get('TZ', 'CET-1CDT')))
res.append("")
- res.append("| Host | State | Hr | Dy | Wk | IP Addr | Last change |
\n")
+ res.append("| Host | State | Hr | Dy | Wk | IP4 Addr | IP6 Addr | Last change |
\n")
hosts_sorted = hosts.keys()
hosts_sorted.sort()
for h in hosts_sorted:
- res.append("| %-24s | %-7s | %s%-16s | %-17s |
\n" % \
- (h, hosts[h].dispstate(), hosts[h].dispstats(), hosts[h].addr, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(hosts[h].statetime))))
+ res.append("| %-24s | %-7s | %s%-16s | %-16s | %-17s |
\n" % \
+ (h, hosts[h].dispstate(), hosts[h].dispstats(), hosts[h].addr4, hosts[h].addr6, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(hosts[h].statetime))))
res.append("
")
res.append("Log of Events
")
for m in msgs[len(msgs)-30:]:
@@ -780,13 +816,13 @@ if f:
elif r[0] == 'hbd_port':
hbd_port = eval(r[1])
elif r[0] == 'hbd_host':
- hbd_host = r[1]
+ hbd_host = eval(r[1])
elif r[0] == 'hb_port':
hb_port = eval(r[1])
elif r[0] == 'logfile':
- logfile = r[1]
+ logfile = eval(r[1])
elif r[0] == 'logfmt':
- logfmt = r[1]
+ logfmt = eval(r[1])
elif r[0] == 'watchhosts':
watchhosts = eval(r[1])
elif r[0] == 'dyndnshosts':
@@ -845,7 +881,12 @@ sock6.bind(("", hb_port))
ilist.append(sock6)
-serv = HttpServer((hbd_host, hbd_port), HttpHandler)
+try:
+ serv = HttpServer((hbd_host, hbd_port), HttpHandler)
+except:
+ 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()