trakc both IPv4 and 6 addresses
This commit is contained in:
@@ -2,7 +2,7 @@
|
|||||||
# $Id: hbd,v 1.38 2013/07/14 02:25:05 andreas Exp $
|
# $Id: hbd,v 1.38 2013/07/14 02:25:05 andreas Exp $
|
||||||
# Wait for heartbeat messages and act on them (or their absence)
|
# Wait for heartbeat messages and act on them (or their absence)
|
||||||
#
|
#
|
||||||
VER = 2.00
|
VER = 3.00
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
@@ -37,7 +37,9 @@ AEMAIL = ["andreas@wrede.ca"]
|
|||||||
NAME = "heatbeat"
|
NAME = "heatbeat"
|
||||||
SMTPSERVER = "localhost"
|
SMTPSERVER = "localhost"
|
||||||
|
|
||||||
|
# Table of Hosts
|
||||||
hosts = {}
|
hosts = {}
|
||||||
|
# map of addrs to names
|
||||||
htab = {}
|
htab = {}
|
||||||
|
|
||||||
msgs = []
|
msgs = []
|
||||||
@@ -74,26 +76,25 @@ def shortname(name):
|
|||||||
return r[0]
|
return r[0]
|
||||||
|
|
||||||
|
|
||||||
|
def isIPv4(addr):
|
||||||
|
return addr.find('.') > 0
|
||||||
|
|
||||||
class NullDevice:
|
class NullDevice:
|
||||||
def write(self, s):
|
def write(self, s):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
class Addr:
|
|
||||||
def __init__(self, a4, a6):
|
|
||||||
self.a4 = a4
|
|
||||||
self.a6 = a6
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Host:
|
class Host:
|
||||||
up = "up"
|
up = "up"
|
||||||
down = "down"
|
down = "down"
|
||||||
overdue = "overdue"
|
overdue = "overdue"
|
||||||
|
|
||||||
def __init__(self, name, addr):
|
|
||||||
|
def __init__(self, name):
|
||||||
global num
|
global num
|
||||||
self.name = shortname(name)
|
self.name = name
|
||||||
self.addr = addr
|
self.addr4 = None
|
||||||
|
self.addr6 = None
|
||||||
self.num = num
|
self.num = num
|
||||||
self.lastbeat = time.time()
|
self.lastbeat = time.time()
|
||||||
self.upcount = 0
|
self.upcount = 0
|
||||||
@@ -105,6 +106,37 @@ class Host:
|
|||||||
self.cmds = []
|
self.cmds = []
|
||||||
self.hdwcounts = [[0,0],[0,0],[0,0]]
|
self.hdwcounts = [[0,0],[0,0],[0,0]]
|
||||||
num += 1
|
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
|
# called when reloading class from pickle, add new fields here
|
||||||
@@ -119,9 +151,21 @@ class Host:
|
|||||||
except:
|
except:
|
||||||
self.hdwcounts = [[self.doesack,self.upcount],[self.doesack,self.upcount],[self.doesack,self.upcount]]
|
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):
|
def getstate(self):
|
||||||
return self.state
|
return self.state
|
||||||
|
|
||||||
|
|
||||||
def dispstate(self):
|
def dispstate(self):
|
||||||
if self.state in ["down", "overdue"]:
|
if self.state in ["down", "overdue"]:
|
||||||
state = "<b>%s</b>" % self.state
|
state = "<b>%s</b>" % self.state
|
||||||
@@ -129,6 +173,7 @@ class Host:
|
|||||||
state = "%s" % self.state
|
state = "%s" % self.state
|
||||||
return state
|
return state
|
||||||
|
|
||||||
|
|
||||||
def dispstats(self):
|
def dispstats(self):
|
||||||
if self.doesack != -1:
|
if self.doesack != -1:
|
||||||
if self.upcount > 0:
|
if self.upcount > 0:
|
||||||
@@ -148,6 +193,7 @@ class Host:
|
|||||||
return "<td>(%s)</td><td></td><td></td>" % (self.doesack)
|
return "<td>(%s)</td><td></td><td></td>" % (self.doesack)
|
||||||
return '<td align="right">N/A</td><td></td<td></td>>'
|
return '<td align="right">N/A</td><td></td<td></td>>'
|
||||||
|
|
||||||
|
|
||||||
# set new state, return number of secs in previous state
|
# set new state, return number of secs in previous state
|
||||||
def newstate(self, state, when=0):
|
def newstate(self, state, when=0):
|
||||||
self.state = state
|
self.state = state
|
||||||
@@ -255,25 +301,13 @@ def dur(sec):
|
|||||||
return "0:%02d" % s
|
return "0:%02d" % s
|
||||||
|
|
||||||
|
|
||||||
#
|
def fixsort():
|
||||||
def addhost(name, addr):
|
s = hosts.keys()
|
||||||
sname = shortname(name)
|
s.sort()
|
||||||
if sname in hosts: # was: hosts.has_key(sname):
|
x = 0
|
||||||
del htab[hosts[sname].addr]
|
for n in s:
|
||||||
hosts[sname].addr = addr
|
hosts[n].num = x
|
||||||
htab[addr] = sname
|
x += 1
|
||||||
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 on_exit():
|
def on_exit():
|
||||||
@@ -286,7 +320,11 @@ def on_exit():
|
|||||||
|
|
||||||
|
|
||||||
def initlog(logfile):
|
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):
|
def fromaddr(name, addr, boot, interval, acks):
|
||||||
global htab
|
global htab
|
||||||
|
|
||||||
|
|
||||||
newh=False
|
newh=False
|
||||||
if not name in hosts: # was: hosts.has_key(name):
|
if not name in hosts: # was: hosts.has_key(name):
|
||||||
addhost(name, addr)
|
host = Host(name)
|
||||||
newh=True
|
newh=True
|
||||||
host = hosts[name]
|
else:
|
||||||
|
host = hosts[name]
|
||||||
|
|
||||||
host.doesack = acks
|
host.doesack = acks
|
||||||
if host.addr != addr:
|
res = host.newaddr(addr)
|
||||||
if host.addr in htab: # was: htab.has_key(host.addr):
|
if res:
|
||||||
del htab[host.addr]
|
m = "%s %s" % (host.name, res)
|
||||||
host.addr = addr
|
log(m)
|
||||||
htab[addr] = name
|
if name in dyndnshosts and isIPv4(addr): # don't try and cat ptr to IPv6 addr
|
||||||
m = "%s changed address to %s" % (host.name, addr)
|
if DEBUG > 0: print "dbg: dynhost and %s: %s" % (isIPv4(addr), addr)
|
||||||
if name in dyndnshosts and not ":" in addr: # don't try and cat ptr to IPv6 addr
|
|
||||||
dnsQ.put((name, addr))
|
dnsQ.put((name, addr))
|
||||||
else:
|
|
||||||
log(m)
|
|
||||||
if name in watchhosts:
|
if name in watchhosts:
|
||||||
email("address change", m)
|
email("address change", m)
|
||||||
pushover(m)
|
pushover(m)
|
||||||
@@ -507,12 +543,12 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
res=self.buildhead(refresh=60)
|
res=self.buildhead(refresh=60)
|
||||||
res.append("<H2>Heartbeat status %s</h2><h4> %s (%s)</H4>" % (VER, time.strftime("%H:%M:%S", time.localtime(now)), os.environ.get('TZ', 'CET-1CDT')))
|
res.append("<H2>Heartbeat status %s</h2><h4> %s (%s)</H4>" % (VER, time.strftime("%H:%M:%S", time.localtime(now)), os.environ.get('TZ', 'CET-1CDT')))
|
||||||
res.append("<table>")
|
res.append("<table>")
|
||||||
res.append("<tr><th>Host</th><th>State</th><th>Hr</th><th>Dy</th><th>Wk</th><th>IP Addr</th><th>Last change</th></tr>\n")
|
res.append("<tr><th>Host</th><th>State</th><th>Hr</th><th>Dy</th><th>Wk</th><th>IP4 Addr</th><th>IP6 Addr</th><th>Last change</th></tr>\n")
|
||||||
hosts_sorted = hosts.keys()
|
hosts_sorted = hosts.keys()
|
||||||
hosts_sorted.sort()
|
hosts_sorted.sort()
|
||||||
for h in hosts_sorted:
|
for h in hosts_sorted:
|
||||||
res.append("<tr><td>%-24s</td><td>%-7s</td>%s<td>%-16s</td><td>%-17s</td></tr>\n" % \
|
res.append("<tr><td>%-24s</td><td>%-7s</td>%s<td>%-16s</td><td>%-16s</td><td>%-17s</td></tr>\n" % \
|
||||||
(h, hosts[h].dispstate(), hosts[h].dispstats(), hosts[h].addr, time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(hosts[h].statetime))))
|
(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("</table>")
|
res.append("</table>")
|
||||||
res.append("<h4>Log of Events</h4>")
|
res.append("<h4>Log of Events</h4>")
|
||||||
for m in msgs[len(msgs)-30:]:
|
for m in msgs[len(msgs)-30:]:
|
||||||
@@ -780,13 +816,13 @@ if f:
|
|||||||
elif r[0] == 'hbd_port':
|
elif r[0] == 'hbd_port':
|
||||||
hbd_port = eval(r[1])
|
hbd_port = eval(r[1])
|
||||||
elif r[0] == 'hbd_host':
|
elif r[0] == 'hbd_host':
|
||||||
hbd_host = r[1]
|
hbd_host = eval(r[1])
|
||||||
elif r[0] == 'hb_port':
|
elif r[0] == 'hb_port':
|
||||||
hb_port = eval(r[1])
|
hb_port = eval(r[1])
|
||||||
elif r[0] == 'logfile':
|
elif r[0] == 'logfile':
|
||||||
logfile = r[1]
|
logfile = eval(r[1])
|
||||||
elif r[0] == 'logfmt':
|
elif r[0] == 'logfmt':
|
||||||
logfmt = r[1]
|
logfmt = eval(r[1])
|
||||||
elif r[0] == 'watchhosts':
|
elif r[0] == 'watchhosts':
|
||||||
watchhosts = eval(r[1])
|
watchhosts = eval(r[1])
|
||||||
elif r[0] == 'dyndnshosts':
|
elif r[0] == 'dyndnshosts':
|
||||||
@@ -845,7 +881,12 @@ sock6.bind(("", hb_port))
|
|||||||
ilist.append(sock6)
|
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 = threading.Thread(target=serv.serve_forever)
|
||||||
servthread.daemon = True
|
servthread.daemon = True
|
||||||
servthread.start()
|
servthread.start()
|
||||||
|
|||||||
Reference in New Issue
Block a user