Merge branch 'master' of git.wrede.ca:andreas/heartbeat

untobandle
This commit is contained in:
2015-02-14 17:24:31 -05:00
+88 -205
View File
@@ -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 = 1.52
VER = 1.62
import time
import os
@@ -50,7 +50,6 @@ verbose = False
INTERVAL = 10
GRACE = 2
visual = 0
os.environ['TZ'] = 'EST5EDT'
stdscr = None
@@ -101,16 +100,22 @@ class Host:
self.interval = 0
self.doesack = -1
self.cmds = []
self.hdwcounts = [0,0,0]
num += 1
# called when reloading class from pickle
# 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 = [0,0,0]
def getstate(self):
return self.state
@@ -120,7 +125,10 @@ class Host:
else:
state = "%s" % self.state
if self.doesack != -1:
return "%s(%s)" % (state, self.doesack)
if self.upcount > 0:
return "%s(%0.1f%%) %s %s " % (state, (self.doesack * 100.0) / self.upcount, self.doesack, self.upcount)
else:
return "%s(%s)" % (state, self.doesack)
return state
# set new state, return number of secs in previous state
@@ -129,8 +137,6 @@ class Host:
now = time.time()-when
s = now-self.statetime
self.statetime = now
if visual:
displaystatetime(self.name)
return s
@@ -165,13 +171,15 @@ def pushover(msg):
if not SEND_PUSHOVER:
return
conn = httplib.HTTPSConnection("api.pushover.net:443")
conn.request("POST", "/1/messages.json",
urllib.urlencode({
"token": "ac7NLX2rPjXFareeDgLpXNoDf4iFmf",
"user": "uDhH33UjQQDYtNzJb1ThRiWb9ingGK",
"message": msg,
}), { "Content-type": "application/x-www-form-urlencoded" })
conn.getresponse()
try:
conn.request("POST", "/1/messages.json",
urllib.urlencode({
"token": "ac7NLX2rPjXFareeDgLpXNoDf4iFmf",
"user": "uDhH33UjQQDYtNzJb1ThRiWb9ingGK",
"message": msg, }), { "Content-type": "application/x-www-form-urlencoded" })
conn.getresponse()
except:
pass
# nsupdate: set the DNS A record for a fqdn
@@ -226,8 +234,6 @@ def addhost(name, addr):
if sname in hosts: # was: hosts.has_key(sname):
del htab[hosts[sname].addr]
hosts[sname].addr = addr
if visual:
displayaddr(sname)
htab[addr] = sname
m = "%s, changed address to %s" % (sname, addr)
log(m)
@@ -240,14 +246,10 @@ def addhost(name, addr):
hosts[n].num = x
x += 1
htab[addr] = sname
if visual:
display()
#
def on_exit():
if visual:
exitcurses()
if DEBUG:
sys.stderr.write("on_exit\n")
logf.close()
@@ -259,33 +261,6 @@ def initlog(logfile):
#
#
def initwin():
global win, msgw, msgwB, msgwHeight
maxY, maxX = stdscr.getmaxyx()
begin_x = 0
begin_y = 2
height = len(htab)+2
if DEBUG:
log("initwin called with %d" % height)
win = curses.newwin(height, maxX, begin_y, begin_x)
a = win.border(0, 0, 0, 0, 0, 0, curses.ACS_LTEE, curses.ACS_RTEE)
msgwB = curses.newwin(0, 0, height+1, begin_x)
msgwB.border(0, 0, 0, 0, curses.ACS_LTEE, curses.ACS_RTEE)
msgwHeight = maxY-height-3
msgw = curses.newwin(msgwHeight, maxX-2, height+2, begin_x+1)
msgw.setscrreg(0, msgwHeight-1)
msgw.scrollok(1)
stdscr.addstr(0, 0, "hbd Version %s" % VER, curses.A_BOLD)
stdscr.refresh()
msgwB.refresh()
#
def checkoverdue():
@@ -302,73 +277,6 @@ def checkoverdue():
log(m)
#
#
def displaytime():
maxY, maxX = stdscr.getmaxyx()
stdscr.addstr(0, maxX-8, time.strftime("%H:%M:%S", time.localtime(now)), curses.A_BOLD)
for h in hosts.keys():
d = hosts[h].getstate()
attr = 0
if verbose and hosts[h].state != Host.down:
d = dur(now-hosts[h].lastbeat)
if hosts[h].state == Host.overdue:
attr = curses.A_BOLD
win.addstr(hosts[h].num+1, 25, "%8s" % d, attr)
win.refresh()
stdscr.refresh()
#
#
def displaystatetime(h, refresh=1):
win.addstr(hosts[h].num+1, 60, "%-17s" % time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(hosts[h].statetime)))
if refresh:
win.refresh()
#
#
def displayaddr(h, refresh=1):
win.addstr(hosts[h].num+1, 35, "%-16s" % hosts[h].addr)
if refresh:
win.refresh()
#
#
def displaybody():
for h in hosts.keys():
win.addstr(hosts[h].num+1, 1, "%-25s" % (h))
if hosts[h].addr is not None:
displayaddr(h, 0)
if hosts[h].statetime is not None:
displaystatetime(h, 0)
win.refresh()
#
#
def displaymsgs():
global msgw, msgs
y = 0
for m in msgs[len(msgs)-msgwHeight:]:
msgw.addstr(y, 0, m)
y += 1
msgw.refresh()
#
#
def display():
if visual:
initwin()
displaytime()
displaybody()
displaymsgs()
def log(m, service="heartbeat"):
if DEBUG: print "Log: %s" % m
msg = time.strftime("%b %d %H:%M:%S", time.localtime(time.time()))+": "+m+"\n"
@@ -394,8 +302,11 @@ def log(m, service="heartbeat"):
def fromaddr(name, addr, boot, interval, acks):
global htab
newh=False
if not name in hosts: # was: hosts.has_key(name):
addhost(name, addr)
newh=True
host = hosts[name]
host.doesack = acks
if host.addr != addr:
@@ -425,7 +336,10 @@ def fromaddr(name, addr, boot, interval, acks):
if name in watchhosts:
email("back", name)
pushover("%s is back" % name)
host.upcount += 1
if boot or newh:
host.upcount = host.doesack
else:
host.upcount += 1
#
@@ -524,24 +438,6 @@ def readsock(sock):
#
#
#
def initcurses():
global stdscr
stdscr = curses.initscr()
curses.noecho()
curses.cbreak()
stdscr.keypad(1)
if DEBUG:
sys.stderr.write("curses init done: %s\n" % stdscr)
def exitcurses():
curses.nocbreak()
stdscr.keypad(0)
curses.echo()
curses.endwin()
class HtmlServer(SocketServer.TCPServer):
allow_reuse_address = True
#
@@ -577,7 +473,19 @@ class HtmlHandler(SocketServer.BaseRequestHandler):
res.append("</body></html>")
return res
def builderror(self, code, cause, lcause):
res=[]
res.append('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">')
res.append('<html><head>')
res.append('<title>%s %s</title>' % (code, cause))
res.append('</head><body>')
res.append('<h1>%s</h1>' % (cause))
res.append('<p>%s</p>' % lcause)
res.append('<hr>')
res.append('<address>hbd (Unix) Server at %s Port %s</address>' % (hbd_host, hbd_port))
res.append('</body></html>')
return res
def handle(self):
global sig, running
headers=[]
@@ -612,35 +520,50 @@ class HtmlHandler(SocketServer.BaseRequestHandler):
elif upar[0] == "/c": # command on host /c?h=melschserver&c=sudo%20ls
uname=""
ucmd=""
if uarg[0][:2] == "h=":
uname=uarg[0][2:]
if uarg[1][:2] == "c=":
ucmd=uarg[1][2:]
if ucmd != "" and uname != "" and hosts.has_key(uname):
hosts[uname].cmds.append(urllib.unquote(ucmd))
res=self.buildhead()
res.append("2Done")
if len(uarg) != 2 or len(uarg[0]) < 3 or len(uarg[1]) < 3:
code=400
cause='Argument error'
res=self.builderror(code, cause, "need h= and c= arguments")
else:
if uarg[0][:2] == "h=":
uname=uarg[0][2:]
if uarg[1][:2] == "c=":
ucmd=uarg[1][2:]
if ucmd != "" and uname != "" and hosts.has_key(uname):
hosts[uname].cmds.append(urllib.unquote(ucmd))
res=self.buildhead()
res.append("2Done")
elif upar[0] == "/d": # drop host /d?h=melschserver
if uarg[0][:2] == "h=":
uname=uarg[0][2:]
if uname != "" and hosts.has_key(uname):
del hosts[uname]
log("%s dropped" % uname)
res=self.buildhead()
res.append("Done")
elif upar[0] == "/n": # register name
res=self.buildhead()
if uarg[0][:2] == "h=":
uname=uarg[0][2:]
if uname != "" and hosts.has_key(uname):
err = nsupdate(uname, hosts[uname].addr)
ll="nsupdate request: %s" % err
if len(uarg) != 1 or len(uarg[0]) < 3:
code=400
cause='Argument error'
res=self.builderror(code, cause, "need h= argument")
else:
ll="name %s not found" % uname
res.append(ll)
log(ll)
if uarg[0][:2] == "h=":
uname=uarg[0][2:]
if uname != "" and hosts.has_key(uname):
del hosts[uname]
log("%s dropped" % uname)
res=self.buildhead()
res.append("Done")
elif upar[0] == "/n": # register name
if len(uarg) != 1 or len(uarg[0]) < 3:
code=400
cause='Argument error'
res=self.builderror(code, cause, "need h= argument")
else:
res=self.buildhead()
if uarg[0][:2] == "h=":
uname=uarg[0][2:]
if uname != "" and hosts.has_key(uname):
err = nsupdate(uname, hosts[uname].addr)
ll="nsupdate request: %s" % err
else:
ll="name %s not found" % uname
res.append(ll)
log(ll)
elif upar[0] == "/r": # restart
res=self.buildhead()
@@ -650,18 +573,10 @@ class HtmlHandler(SocketServer.BaseRequestHandler):
log("restart request")
else:
code = 404
cause = "Not Found"
res=[]
res.append('<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">')
res.append('<html><head>')
res.append('<title>%s %s</title>' % (code, cause))
res.append('</head><body>')
res.append('<h1>%s</h1>' % (cause))
res.append('<p>The requested URL %s was not found on this server.</p>' % uri)
res.append('<hr>')
res.append('<address>hbd (Unix) Server at %s Port %s</address>' % (hbd_host, hbd_port))
res.append('</body></html>')
code=404
cause="Not Found"
res=self.builderror(code, cause, "The requested URL was not found on this server.")
self.request.send("HTTP/1.0 %s %s\r\n" % (code, cause))
for h in headers:
@@ -676,6 +591,7 @@ class HtmlHandler(SocketServer.BaseRequestHandler):
def saveandrestart():
sock.close()
sock6.close()
# serv.shutdown() #N.B. dont shutdown() as we don't use serv_forever
serv.server_close()
log("restarting")
@@ -712,10 +628,7 @@ for o, a in optlist:
if o == '-c':
configfile = a
cmdargs += [o, a]
if o == '-d':
visual = True
cmdargs += [o]
elif o == '-f':
if o == '-f':
forground = True
cmdargs += [o]
elif o == '-h':
@@ -750,8 +663,6 @@ grace = 2
sys.exit(1)
if visual:
forground = True
#
# set defaults
@@ -833,11 +744,6 @@ if os.path.exists(PICKFILE):
now = time.time()
startsec = int(now) % interval
if visual:
import curses
initcurses()
display()
stdscr.nodelay(1)
log("Starting %s" % VER)
atexit.register(on_exit)
@@ -884,21 +790,6 @@ signal.signal(signal.SIGHUP, handler)
next = int(now)+15 # 15 seconds time to settle after (re-)start
sleep = next - now
while running:
if visual:
c = stdscr.getch()
if c == ord('c'):
msgs = []
display()
elif c == ord('q'):
break # Exit the while()
elif c == ord('d'):
DEBUG = not DEBUG
elif c == ord('v'):
verbose = not verbose
# elif c == ord('p'):
# PrintDocument()
# elif c == ord('x'):
# x = y = 0
if DEBUG:
sys.stderr.write("about to sleep = %s\n" % (sleep))
@@ -912,10 +803,6 @@ while running:
print select.error, value
#raise os.error, value
continue
if visual:
exitcurses()
initcurses()
display()
continue
except:
sys.exit(1)
@@ -929,10 +816,6 @@ while running:
if now >= next:
next = now+1
checkoverdue()
if visual:
stdscr.move(1, 0)
stdscr.clrtoeol()
displaytime()
sleep = next-now
if sleep < 0: