split out classes into a module
This commit is contained in:
@@ -23,10 +23,13 @@ import httplib
|
||||
import threading
|
||||
import Queue
|
||||
import md5
|
||||
import json
|
||||
import zlib
|
||||
|
||||
from subprocess import Popen, STDOUT, PIPE
|
||||
|
||||
from hbdclass import *
|
||||
|
||||
|
||||
SEND_EMAIL=False
|
||||
SEND_PUSHOVER=True
|
||||
@@ -41,11 +44,6 @@ AEMAIL = ["andreas@wrede.ca"]
|
||||
NAME = "heatbeat"
|
||||
SMTPSERVER = "localhost"
|
||||
|
||||
# Table of Hosts
|
||||
hosts = {}
|
||||
# map of addrs to names
|
||||
htab = {}
|
||||
|
||||
msgs = []
|
||||
|
||||
num = 0
|
||||
@@ -64,6 +62,33 @@ os.environ['TZ'] = 'EST5EDT'
|
||||
tsfm=["%H","%d","%U"]
|
||||
lastfm=["","",""]
|
||||
|
||||
|
||||
tcss = """<script src="https://home.wrede.ca/pr/sorttable.js"></script>
|
||||
<style>
|
||||
#ntable {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#ntable td, #ntable th {
|
||||
border: 1px solid #ddd;
|
||||
text-align: left;
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
#ntable tr:nth-child(even){background-color: #f2f2f2}
|
||||
|
||||
#ntable tr:hover {background-color: #ddd;}
|
||||
|
||||
#ntable th {
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
background-color: #9d9d9d;
|
||||
color: white;
|
||||
}
|
||||
</style> """
|
||||
|
||||
|
||||
def handler(signum, frame):
|
||||
global running, sig
|
||||
sig = signum
|
||||
@@ -80,10 +105,6 @@ def shortname(name):
|
||||
return r[0]
|
||||
|
||||
|
||||
def isIPv4(addr):
|
||||
return addr.find('.') > 0
|
||||
|
||||
|
||||
class NullDevice:
|
||||
def write(self, s):
|
||||
pass
|
||||
@@ -143,203 +164,6 @@ def oldmtodict(msg):
|
||||
return stodict('HTB:'+msg)
|
||||
|
||||
|
||||
class Connection:
|
||||
def __init__(self, name, cid, addr):
|
||||
self.name = name
|
||||
self.cid = cid
|
||||
self.addr = addr
|
||||
self.rtts = [0]
|
||||
|
||||
|
||||
class Host:
|
||||
up = "up"
|
||||
down = "down"
|
||||
overdue = "overdue"
|
||||
|
||||
|
||||
def __init__(self, name):
|
||||
global num
|
||||
self.name = name
|
||||
self.addr4 = None
|
||||
self.addr6 = None
|
||||
self.num = num
|
||||
self.lastbeat = time.time()
|
||||
self.upcount = 0
|
||||
self.state = Host.up
|
||||
self.state = "up"
|
||||
self.statetime = self.lastbeat
|
||||
self.interval = 0
|
||||
self.doesack = -1
|
||||
self.cmds = []
|
||||
self.cver = 0
|
||||
self.connections = {}
|
||||
self.latency = 0
|
||||
self.hdwcounts = [[0,0],[0,0],[0,0]]
|
||||
num += 1
|
||||
hosts[name] = self
|
||||
|
||||
|
||||
def setcver(self, cver):
|
||||
self.cver = cver
|
||||
|
||||
|
||||
def isDynDns(self):
|
||||
return self.name in dyndnshosts
|
||||
|
||||
|
||||
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
|
||||
if self.isDynDns():
|
||||
dnsQ.put((self.name, self.addr4))
|
||||
else:
|
||||
r = "new addr %s" % (addr)
|
||||
self.addr4 = addr
|
||||
htab[addr] = self.name
|
||||
if self.isDynDns():
|
||||
dnsQ.put((self.name, self.addr4))
|
||||
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
|
||||
if self.isDynDns():
|
||||
dnsQ.put((self.name, self.addr6))
|
||||
else:
|
||||
r = "new addr %s" % (addr)
|
||||
self.addr6 = addr
|
||||
htab[addr] = self.name
|
||||
if self.isDynDns():
|
||||
dnsQ.put((self.name, self.addr6))
|
||||
return r
|
||||
|
||||
|
||||
# called when reloading class from pickle, add new fields here
|
||||
def fixup(self):
|
||||
try:
|
||||
a=self.cmds
|
||||
except:
|
||||
self.cmds=[]
|
||||
|
||||
try:
|
||||
a=self.hdwcounts
|
||||
except:
|
||||
self.hdwcounts = [[self.doesack,self.upcount],[self.doesack,self.upcount],[self.doesack,self.upcount]]
|
||||
|
||||
try:
|
||||
self.addr=self.addr4
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
self.addr=self.addr6
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
a=self.addr4
|
||||
a=self.addr6
|
||||
except:
|
||||
print "fix %s: addr to addr4/6 fixup" % self.name
|
||||
if isIPv4(self.addr):
|
||||
self.addr4 = self.addr
|
||||
self.addr6 = None
|
||||
else:
|
||||
self.addr4 = None
|
||||
self.addr6 = self.addr
|
||||
del self.addr
|
||||
|
||||
try:
|
||||
a=self.latency
|
||||
except:
|
||||
self.latency = 0
|
||||
|
||||
try:
|
||||
a=self.cver
|
||||
except:
|
||||
self.cver = 0
|
||||
|
||||
try:
|
||||
a=self.connections
|
||||
a.append([])
|
||||
except:
|
||||
self.connections={}
|
||||
|
||||
|
||||
def getstate(self):
|
||||
return self.state
|
||||
|
||||
|
||||
def dispstate(self):
|
||||
if self.state in ["down", "overdue"]:
|
||||
state = "<b>%s</b>" % self.state
|
||||
elif self.state in ["up", "UP"]:
|
||||
state = ""
|
||||
for x in self.connections.keys():
|
||||
try:
|
||||
state += " %5.1f" % (self.connections[x].rtts[-1])
|
||||
except:
|
||||
state += " %5s" % (self.connections[x].rtts[-1])
|
||||
else:
|
||||
state = "%s" % self.state
|
||||
return state
|
||||
|
||||
|
||||
def dispstats(self):
|
||||
return '<td align="right">N/A</td><td></td<td></td>'
|
||||
if self.doesack != -1:
|
||||
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):
|
||||
a,u = self.hdwcounts[v]
|
||||
if (self.upcount - u) != 0:
|
||||
vs = "%0.0f" % (100.0 - (((self.doesack - a) * 100.0) / (self.upcount - u)))
|
||||
if vs == "0":
|
||||
vs=""
|
||||
else:
|
||||
vs="-"
|
||||
r+= '<td align="right">%s</td>' % vs
|
||||
return r
|
||||
else:
|
||||
return "<td>(%s)</td><td></td><td></td>" % (self.doesack)
|
||||
return '<td align="right">N/A</td><td></td<td></td>>'
|
||||
|
||||
|
||||
def htmldisp(self, header=False):
|
||||
if header:
|
||||
return "<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><th>Ver</th></tr>\n"
|
||||
|
||||
else:
|
||||
ipv4addr = self.addr4 if self.addr4 else ""
|
||||
ipv6addr = self.addr6 if self.addr6 else ""
|
||||
lastts = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.statetime))
|
||||
return "<tr><td>%-24s</td><td>%-7s</td>%s<td>%-16s</td><td>%-16s</td><td>%-17s</td><td>%s</td></tr>\n" % \
|
||||
(self.name, self.dispstate(), self.dispstats(), ipv4addr, ipv6addr, lastts, self.cver)
|
||||
|
||||
|
||||
|
||||
# set new state, return number of secs in previous state
|
||||
def newstate(self, state, when=0):
|
||||
self.state = state
|
||||
now = time.time()-when
|
||||
s = now-self.statetime
|
||||
self.statetime = now
|
||||
return s
|
||||
|
||||
|
||||
|
||||
def email(s, msg):
|
||||
if not SEND_EMAIL:
|
||||
return
|
||||
@@ -680,15 +504,22 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
|
||||
|
||||
def do_HEAD(self):
|
||||
self.setheaders()
|
||||
|
||||
|
||||
def setheaders(self, headerdict=None):
|
||||
if not headerdict:
|
||||
headerdict = {"Content-Type": "text/html; charset = ISO-8859-1" }
|
||||
self.send_response(200)
|
||||
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("Content-Type","text/html; charset = ISO-8859-1")
|
||||
for h in headerdict:
|
||||
self.send_header(h, headerdict[h])
|
||||
self.end_headers()
|
||||
|
||||
|
||||
def buildhead(self, title="Heartbeat", refresh=None):
|
||||
def buildhead(self, title="Heartbeat", refresh=None, extras=None):
|
||||
res=[]
|
||||
res.append('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">')
|
||||
res.append("<html>")
|
||||
@@ -696,16 +527,18 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
res.append('<title>%s</title>' % (title))
|
||||
if refresh:
|
||||
res.append("<meta http-equiv = Refresh content = %d>\n" % refresh)
|
||||
if extras:
|
||||
res.append(extras)
|
||||
res.append("</head>")
|
||||
res.append('<body BGCOLOR = "#FFFFFF" LINK = "#008000" VLINK = "#008000">')
|
||||
return res
|
||||
|
||||
|
||||
def buildpage(self):
|
||||
res=self.buildhead(refresh=60)
|
||||
res=self.buildhead(refresh=60, extras=tcss)
|
||||
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 id="ntable" class="sortable">')
|
||||
hosts_sorted = hosts.keys()
|
||||
hosts_sorted.sort()
|
||||
res.append(hosts[hosts_sorted[0]].htmldisp(True))
|
||||
@@ -737,9 +570,8 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
def do_GET(self):
|
||||
global sig
|
||||
xsig = 0
|
||||
self.do_HEAD()
|
||||
headers=[]
|
||||
|
||||
headerdict = None
|
||||
if DEBUG > 2: sys.stderr.write("handle\n")
|
||||
uri = self.path
|
||||
upar=string.split(uri,"?")
|
||||
@@ -830,6 +662,16 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
|
||||
|
||||
|
||||
elif upar[0] == "/api/0/hosts": # api access to host table
|
||||
headerdict = {"Content-Type": "application/json; charset=utf-8" }
|
||||
l=[]
|
||||
for h in hosts:
|
||||
l.append(hosts[h].jsons())
|
||||
res=["[",",".join(l),"]"]
|
||||
elif upar[0] == "/api/0/messages": # api access to host table
|
||||
headerdict = {"Content-Type": "application/json; charset=utf-8" }
|
||||
l=msgs[len(msgs)-30:]
|
||||
res=[json.dumps(l)]
|
||||
elif upar[0] == "/r": # restart
|
||||
res=self.buildhead()
|
||||
res.append("restart request")
|
||||
@@ -851,6 +693,7 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
||||
# self.request.send("%s\r\n" % h)
|
||||
# self.request.send("\r\n")
|
||||
|
||||
self.setheaders(headerdict)
|
||||
tosend += res
|
||||
self.wfile.write(string.join(tosend, "\n"))
|
||||
|
||||
|
||||
+233
@@ -0,0 +1,233 @@
|
||||
|
||||
"""
|
||||
host and connection class shared between hbd and
|
||||
the websit's heartbeat.py
|
||||
|
||||
"""
|
||||
|
||||
import time
|
||||
import json
|
||||
|
||||
# Table of Hosts
|
||||
hosts = {}
|
||||
# map of addrs to names
|
||||
htab = {}
|
||||
|
||||
|
||||
def isIPv4(addr):
|
||||
return addr.find('.') > 0
|
||||
|
||||
|
||||
|
||||
class Connection:
|
||||
def __init__(self, name, cid, addr):
|
||||
self.name = name
|
||||
self.cid = cid
|
||||
self.addr = addr
|
||||
self.rtts = [0]
|
||||
|
||||
def jsons(self):
|
||||
return(json.dumps(self.__dict__))
|
||||
|
||||
|
||||
class Host:
|
||||
up = "up"
|
||||
down = "down"
|
||||
overdue = "overdue"
|
||||
|
||||
|
||||
def __init__(self, name):
|
||||
global num
|
||||
self.name = name
|
||||
self.addr4 = None
|
||||
self.addr6 = None
|
||||
self.num = num
|
||||
self.lastbeat = time.time()
|
||||
self.upcount = 0
|
||||
self.state = Host.up
|
||||
self.state = "up"
|
||||
self.statetime = self.lastbeat
|
||||
self.interval = 0
|
||||
self.doesack = -1
|
||||
self.cmds = []
|
||||
self.cver = 0
|
||||
self.connections = {}
|
||||
self.latency = 0
|
||||
self.hdwcounts = [[0,0],[0,0],[0,0]]
|
||||
num += 1
|
||||
hosts[name] = self
|
||||
|
||||
|
||||
def jsons(self):
|
||||
ddict = {}
|
||||
for d in self.__dict__:
|
||||
if d == 'connections':
|
||||
cl = []
|
||||
for c in self.connections:
|
||||
cl.append(self.connections[c].__dict__)
|
||||
ddict[d] = cl
|
||||
else:
|
||||
ddict[d] = self.__dict__[d]
|
||||
return json.dumps(ddict)
|
||||
|
||||
|
||||
def setcver(self, cver):
|
||||
self.cver = cver
|
||||
|
||||
|
||||
def isDynDns(self):
|
||||
return self.name in dyndnshosts
|
||||
|
||||
|
||||
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
|
||||
if self.isDynDns():
|
||||
dnsQ.put((self.name, self.addr4))
|
||||
else:
|
||||
r = "new addr %s" % (addr)
|
||||
self.addr4 = addr
|
||||
htab[addr] = self.name
|
||||
if self.isDynDns():
|
||||
dnsQ.put((self.name, self.addr4))
|
||||
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
|
||||
if self.isDynDns():
|
||||
dnsQ.put((self.name, self.addr6))
|
||||
else:
|
||||
r = "new addr %s" % (addr)
|
||||
self.addr6 = addr
|
||||
htab[addr] = self.name
|
||||
if self.isDynDns():
|
||||
dnsQ.put((self.name, self.addr6))
|
||||
return r
|
||||
|
||||
|
||||
# called when reloading class from pickle, add new fields here
|
||||
def fixup(self):
|
||||
try:
|
||||
a=self.cmds
|
||||
except:
|
||||
self.cmds=[]
|
||||
|
||||
try:
|
||||
a=self.hdwcounts
|
||||
except:
|
||||
self.hdwcounts = [[self.doesack,self.upcount],[self.doesack,self.upcount],[self.doesack,self.upcount]]
|
||||
|
||||
try:
|
||||
self.addr=self.addr4
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
self.addr=self.addr6
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
try:
|
||||
a=self.addr4
|
||||
a=self.addr6
|
||||
except:
|
||||
print "fix %s: addr to addr4/6 fixup" % self.name
|
||||
if isIPv4(self.addr):
|
||||
self.addr4 = self.addr
|
||||
self.addr6 = None
|
||||
else:
|
||||
self.addr4 = None
|
||||
self.addr6 = self.addr
|
||||
del self.addr
|
||||
|
||||
try:
|
||||
a=self.latency
|
||||
except:
|
||||
self.latency = 0
|
||||
|
||||
try:
|
||||
a=self.cver
|
||||
except:
|
||||
self.cver = 0
|
||||
|
||||
try:
|
||||
a=self.connections
|
||||
a.append([])
|
||||
except:
|
||||
self.connections={}
|
||||
|
||||
|
||||
def getstate(self):
|
||||
return self.state
|
||||
|
||||
|
||||
def dispstate(self):
|
||||
if self.state in ["down", "overdue"]:
|
||||
state = "<b>%s</b>" % self.state
|
||||
elif self.state in ["up", "UP"]:
|
||||
state = ""
|
||||
for x in self.connections.keys():
|
||||
try:
|
||||
state += " %5.1f" % (self.connections[x].rtts[-1])
|
||||
except:
|
||||
state += " %5s" % (self.connections[x].rtts[-1])
|
||||
else:
|
||||
state = "%s" % self.state
|
||||
return state
|
||||
|
||||
|
||||
def dispstats(self):
|
||||
if self.doesack != -1:
|
||||
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):
|
||||
a,u = self.hdwcounts[v]
|
||||
if (self.upcount - u) != 0:
|
||||
vs = "%0.0f" % (100.0 - (((self.doesack - a) * 100.0) / (self.upcount - u)))
|
||||
if vs == "0":
|
||||
vs=""
|
||||
else:
|
||||
vs="-"
|
||||
r+= '<td align="right">%s</td>' % vs
|
||||
return r
|
||||
else:
|
||||
return "<td>(%s)</td><td></td><td></td>" % (self.doesack)
|
||||
return '<td align="right">N/A</td><td></td<td></td>>'
|
||||
|
||||
|
||||
def htmldisp(self, header=False):
|
||||
if header:
|
||||
return "<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><th>Ver</th></tr>\n"
|
||||
|
||||
else:
|
||||
ipv4addr = self.addr4 if self.addr4 else ""
|
||||
ipv6addr = self.addr6 if self.addr6 else ""
|
||||
lastts = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.statetime))
|
||||
return "<tr><td>%-24s</td><td>%-7s</td>%s<td>%-16s</td><td>%-16s</td><td>%-17s</td><td>%s</td></tr>\n" % \
|
||||
(self.name, self.dispstate(), self.dispstats(), ipv4addr, ipv6addr, lastts, self.cver)
|
||||
|
||||
|
||||
|
||||
# set new state, return number of secs in previous state
|
||||
def newstate(self, state, when=0):
|
||||
self.state = state
|
||||
now = time.time()-when
|
||||
s = now-self.statetime
|
||||
self.statetime = now
|
||||
return s
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user