Merge branch 'master' of git.wrede.ca:andreas/heartbeat
sync
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# $Id: hbc,v 1.9 2012/03/29 02:08:36 andreas Exp $
|
# $Id: hbc,v 1.9 2012/03/29 02:08:36 andreas Exp $
|
||||||
|
# NEW
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import socket
|
import socket
|
||||||
@@ -11,60 +11,36 @@ import string
|
|||||||
import select
|
import select
|
||||||
import errno
|
import errno
|
||||||
import traceback
|
import traceback
|
||||||
import md5
|
from hashlib import md5
|
||||||
import shutil
|
import shutil
|
||||||
import zlib
|
import zlib
|
||||||
import subprocess
|
import subprocess
|
||||||
import syslog
|
import syslog
|
||||||
|
|
||||||
try:
|
import syslog
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
PORT = 50003
|
PORT = 50003
|
||||||
INTERVAL = 10
|
INTERVAL = 10
|
||||||
|
REOPENC = 6
|
||||||
PIDFILE = '/tmp/hbc.pid'
|
PIDFILE = '/tmp/hbc.pid'
|
||||||
VER = 2
|
VER = 5
|
||||||
MAXRECV = 32767
|
MAXRECV = 32767
|
||||||
|
|
||||||
running = True
|
running = True
|
||||||
dorestart = False
|
dorestart = False
|
||||||
warned1 = False
|
warned1 = False
|
||||||
|
|
||||||
|
def log(msg):
|
||||||
|
if fdaemon:
|
||||||
|
syslog.syslog(syslog.LOG_ERR, msg)
|
||||||
|
else:
|
||||||
|
print(msg)
|
||||||
|
|
||||||
|
def handler(signum, frame):
|
||||||
|
if signum == signal.SIGTERM:
|
||||||
|
cleanup()
|
||||||
|
|
||||||
class NullDevice:
|
class NullDevice:
|
||||||
def write(self, s):
|
def write(self, s):
|
||||||
pass
|
pass
|
||||||
@@ -82,35 +58,54 @@ class Conn:
|
|||||||
self.send = 0
|
self.send = 0
|
||||||
self.lastsend = 0 # time() last msg was sent
|
self.lastsend = 0 # time() last msg was sent
|
||||||
self.rtts = [0]
|
self.rtts = [0]
|
||||||
self.sock=socket.socket(af, socket.SOCK_DGRAM)
|
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, \
|
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
|
def sendto(self, msg, ID = 'HTB'): # default ID is HearTBeat
|
||||||
global warned1
|
global warned1
|
||||||
|
|
||||||
|
if self.send % REOPENC == 0:
|
||||||
|
self.close()
|
||||||
|
if not self.sock:
|
||||||
|
self.open()
|
||||||
msg['name'] = shortname(iam)
|
msg['name'] = shortname(iam)
|
||||||
msg['id'] = self.conId
|
msg['id'] = self.conId
|
||||||
msg['ver'] = VER
|
msg['ver'] = VER
|
||||||
msg['time'] = time.time()
|
msg['time'] = time.time()
|
||||||
m = dicttos(ID, msg, True) # always compress
|
m = dicttos(ID, msg) # always compress
|
||||||
if verbose:
|
if verbose:
|
||||||
log("conn.send('%s', (%s:%s) %s)" % (msg, self.addr, self.port, len(m)))
|
log("conn.send('%s', (%s:%s) %s)" % (msg, self.addr, self.port, len(m)))
|
||||||
try:
|
try:
|
||||||
self.sock.sendto(m, (self.addr, self.port))
|
self.sock.sendto(m, (self.addr, self.port))
|
||||||
except socket.error as e:
|
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
|
warned1 = True
|
||||||
|
self.close()
|
||||||
return
|
return
|
||||||
self.send += 1
|
self.send += 1
|
||||||
self.lastsend = time.time()
|
self.lastsend = time.time()
|
||||||
|
|
||||||
|
|
||||||
def ack(self, msgDict):
|
def ack(self, msgDict, now):
|
||||||
self.lastack = time.time()
|
try:
|
||||||
self.lastacksent = float(msgDict.get('time','0'))
|
self.lastack = msgDict['time']
|
||||||
if verbose: log("ack RTT: %0.1f ms" % ((self.lastack - self.lastsend) * 1000.0))
|
mul = 2
|
||||||
self.rtts.append((self.lastack - self.lastsend) * 1000.0)
|
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:
|
if len(self.rtts) > 10:
|
||||||
del self.rtts[0]
|
del self.rtts[0]
|
||||||
self.ackcount += 1
|
self.ackcount += 1
|
||||||
@@ -123,11 +118,11 @@ class Conn:
|
|||||||
|
|
||||||
|
|
||||||
def shortname(name):
|
def shortname(name):
|
||||||
r = string.split(name, '.')
|
r = name.split('.')
|
||||||
return r[0]
|
return r[0]
|
||||||
|
|
||||||
|
|
||||||
def dicttos(ID, d, compress=False):
|
def dicttos(ID, d):
|
||||||
s = []
|
s = []
|
||||||
for k in d:
|
for k in d:
|
||||||
if type(d[k]) == type(1.2):
|
if type(d[k]) == type(1.2):
|
||||||
@@ -135,15 +130,35 @@ def dicttos(ID, d, compress=False):
|
|||||||
else:
|
else:
|
||||||
s.append("%s=%s" % (k, d[k]))
|
s.append("%s=%s" % (k, d[k]))
|
||||||
pk = ";".join(s)
|
pk = ";".join(s)
|
||||||
if compress:
|
zpk = zlib.compress(pk.encode(), 6)
|
||||||
zpk = zlib.compress(pk, 6)
|
ID = "!" + ID + ":"
|
||||||
ID = "!"+ID
|
return ID.encode() + zpk
|
||||||
else:
|
|
||||||
zpk = pk
|
|
||||||
return ID + ":" + zpk
|
|
||||||
|
|
||||||
|
|
||||||
def stodict(msg):
|
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
|
||||||
|
if verbose: print("msg is %s" % d)
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def XXstodict(msg):
|
||||||
d = {}
|
d = {}
|
||||||
r0 = msg.split(':',1)
|
r0 = msg.split(':',1)
|
||||||
if len(r0) == 1:
|
if len(r0) == 1:
|
||||||
@@ -175,8 +190,9 @@ def syslogtrace(note):
|
|||||||
logm = '%s hbc died: \n%s' % (note, traceback.format_exc())
|
logm = '%s hbc died: \n%s' % (note, traceback.format_exc())
|
||||||
log(logm)
|
log(logm)
|
||||||
for l in logm.split('\n'):
|
for l in logm.split('\n'):
|
||||||
log(' tb: %s' % l)
|
syslog.syslog(syslog.LOG_ERR, ' tb: %s' % l)
|
||||||
|
if verbose:
|
||||||
|
print(logm)
|
||||||
|
|
||||||
|
|
||||||
conId = 1
|
conId = 1
|
||||||
@@ -197,11 +213,13 @@ def createConnections(hosts):
|
|||||||
elif r[0] == 2:
|
elif r[0] == 2:
|
||||||
af=socket.AF_INET
|
af=socket.AF_INET
|
||||||
else:
|
else:
|
||||||
log("dont know this net type: %s" % r[0][0])
|
print("dont know this net type: %s" % r[0][0])
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
addr = r[4][0]
|
addr = r[4][0]
|
||||||
conns[conId] = Conn(conId, addr, hb_port, af)
|
conns[conId] = Conn(conId, addr, hb_port, af)
|
||||||
|
if verbose:
|
||||||
|
print("cons[%s] = %s" % (conId, str(conns[conId])))
|
||||||
conId += 1
|
conId += 1
|
||||||
|
|
||||||
|
|
||||||
@@ -214,7 +232,7 @@ def doexec(conn, data):
|
|||||||
fail = "CalledProcessError"
|
fail = "CalledProcessError"
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
syslogtrace('System')
|
syslogtrace('System')
|
||||||
ro = None
|
ro = "N/A"
|
||||||
fail = "cmd failed: %s" % e
|
fail = "cmd failed: %s" % e
|
||||||
msg={'service': 'command', 'msg': fail+" "+ro}
|
msg={'service': 'command', 'msg': fail+" "+ro}
|
||||||
conns[conn].sendto(msg)
|
conns[conn].sendto(msg)
|
||||||
@@ -247,7 +265,7 @@ def doupdateone(code, csum):
|
|||||||
return "checksum error"
|
return "checksum error"
|
||||||
|
|
||||||
fn = sys.argv[0]
|
fn = sys.argv[0]
|
||||||
ofn = "%.sav" % fn
|
ofn = "%s.sav" % fn
|
||||||
try:
|
try:
|
||||||
shutil.copy2(fn, ofn)
|
shutil.copy2(fn, ofn)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -264,38 +282,43 @@ def doupdateone(code, csum):
|
|||||||
|
|
||||||
|
|
||||||
def restart():
|
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"
|
e = "fallthrough"
|
||||||
try:
|
try:
|
||||||
os.execv(sys.argv[0], [sys.argv[0]]+cmdargs)
|
os.execv(sys.argv[0], [sys.argv[0]]+cmdargs)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
pass
|
pass
|
||||||
print "should not be here:", str(e)
|
print("should not be here:", str(e))
|
||||||
log('restart failed: %s' % e)
|
log('restart failed: %s' % e)
|
||||||
|
|
||||||
|
|
||||||
def process():
|
def process():
|
||||||
global running, dorestart
|
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()
|
nextReport = time.time()
|
||||||
|
|
||||||
while running:
|
while running:
|
||||||
while time.time() < nextReport:
|
while time.time() < nextReport:
|
||||||
|
ifiles = {}
|
||||||
|
conIds = {}
|
||||||
|
for conn in conns:
|
||||||
|
if conns[conn].sock:
|
||||||
|
ifiles[conns[conn].sock.fileno()] = conns[conn].sock
|
||||||
|
conIds[conns[conn].sock.fileno()] = conn
|
||||||
|
|
||||||
sleep=nextReport - time.time()
|
sleep=nextReport - time.time()
|
||||||
if sleep <= 0:
|
if sleep <= 0:
|
||||||
break
|
break
|
||||||
try:
|
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:
|
except KeyboardInterrupt:
|
||||||
running = False
|
running = False
|
||||||
break
|
break
|
||||||
except SystemExit:
|
except SystemExit:
|
||||||
log('daemon exit, running=: %s' % running)
|
log('daemon exit, running was %s' % running)
|
||||||
if running:
|
if running:
|
||||||
running = False
|
running = False
|
||||||
break
|
break
|
||||||
@@ -307,14 +330,16 @@ def process():
|
|||||||
for rfh in r[0]:
|
for rfh in r[0]:
|
||||||
conn = conIds[rfh]
|
conn = conIds[rfh]
|
||||||
data, addr = ifiles[rfh].recvfrom(MAXRECV)
|
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)
|
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['ID'] == "ACK":
|
if msgDict == None:
|
||||||
conns[conn].ack(msgDict)
|
print("bad backet from %s (%s) %s" % (addr, len(data), data))
|
||||||
|
elif msgDict['ID'] == "ACK":
|
||||||
|
conns[conn].ack(msgDict, now)
|
||||||
elif msgDict['ID'] == "UPD":
|
elif msgDict['ID'] == "UPD":
|
||||||
if doupdate(conn, msgDict) == None:
|
if doupdate(conn, msgDict) == None:
|
||||||
if verbose: print "process: restart after update"
|
if verbose: print("process: restart after update")
|
||||||
dorestart = True
|
dorestart = True
|
||||||
break
|
break
|
||||||
elif msgDict['ID'] == "CMD":
|
elif msgDict['ID'] == "CMD":
|
||||||
@@ -327,15 +352,20 @@ def process():
|
|||||||
if not running:
|
if not running:
|
||||||
break
|
break
|
||||||
for conn in conns:
|
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]}
|
msg={'acks': conns[conn].ackcount, 'rtt': conns[conn].rtts[-1]}
|
||||||
conns[conn].sendto(msg)
|
conns[conn].sendto(msg)
|
||||||
|
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
|
nextReport = time.time() + interval
|
||||||
|
|
||||||
if verbose: log( "process: done running")
|
if verbose: log( "process: done running")
|
||||||
|
|
||||||
def cleanup():
|
def cleanup():
|
||||||
global running
|
global running
|
||||||
|
if not running:
|
||||||
|
return
|
||||||
if verbose: log('cleanup')
|
if verbose: log('cleanup')
|
||||||
running = False
|
running = False
|
||||||
for conn in conns:
|
for conn in conns:
|
||||||
@@ -347,15 +377,59 @@ def cleanup():
|
|||||||
|
|
||||||
|
|
||||||
def closeall():
|
def closeall():
|
||||||
if verbose: log('closecall')
|
if verbose: syslog.syslog(syslog.LOG_ERR, 'closecall')
|
||||||
for conn in conns:
|
for conn in conns:
|
||||||
conns[conn].close()
|
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 as 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 as 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 = 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())
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
msgonly=False
|
msgonly=False
|
||||||
helpflag=False
|
helpflag=False
|
||||||
verbose=False
|
verbose=False
|
||||||
fdaemon=False
|
fdaemon=False
|
||||||
|
daemonized = False
|
||||||
optlist=[]
|
optlist=[]
|
||||||
args=[]
|
args=[]
|
||||||
msgboot={}
|
msgboot={}
|
||||||
@@ -390,20 +464,20 @@ for o,a in optlist:
|
|||||||
|
|
||||||
|
|
||||||
cmdargs += args
|
cmdargs += args
|
||||||
if verbose: print "cmdargs for restart are %s" % cmdargs
|
if verbose: print("cmdargs for restart are %s" % cmdargs)
|
||||||
|
|
||||||
if helpflag:
|
if helpflag:
|
||||||
print "hbc HeartBeatClient"
|
print("hbc HeartBeatClient")
|
||||||
print "usage: hbc [-bdhv] [-c configfile] [-m msg][host1 [..]]"
|
print("usage: hbc [-bdhv] [-c configfile] [-m msg][host1 [..]]")
|
||||||
print
|
print()
|
||||||
print " -b indicate machine boot"
|
print(" -b indicate machine boot")
|
||||||
print " -c configfile"
|
print(" -c configfile")
|
||||||
print " -d daemonize"
|
print(" -d daemonize")
|
||||||
print " -h this help"
|
print(" -h this help")
|
||||||
print " -m send a message"
|
print(" -m send a message")
|
||||||
print " -v verbose"
|
print(" -v verbose")
|
||||||
print
|
print()
|
||||||
print """ config file can contain
|
print(""" config file can contain
|
||||||
hb_hosts=('host1', 'host2', ..._
|
hb_hosts=('host1', 'host2', ..._
|
||||||
hb_port=50003
|
hb_port=50003
|
||||||
interval=20
|
interval=20
|
||||||
@@ -411,7 +485,7 @@ logfile=...
|
|||||||
logfmt={|test|msg}
|
logfmt={|test|msg}
|
||||||
grace=SECONDS
|
grace=SECONDS
|
||||||
reportstrict={True|False}
|
reportstrict={True|False}
|
||||||
"""
|
""")
|
||||||
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
@@ -425,9 +499,9 @@ iam=socket.gethostname()
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
f=open(configfile,"r")
|
f=open(configfile,"r")
|
||||||
if verbose: print "notice: using config file %s" % configfile
|
if verbose: print("notice: using config file %s" % configfile)
|
||||||
except:
|
except:
|
||||||
if verbose: print "warning: running without config file: %s" % configfile
|
if verbose: print("warning: running without config file: %s" % configfile)
|
||||||
f=None
|
f=None
|
||||||
|
|
||||||
if f:
|
if f:
|
||||||
@@ -439,14 +513,14 @@ if f:
|
|||||||
if r[0] == 'hb_hosts':
|
if r[0] == 'hb_hosts':
|
||||||
hb_hosts=eval(r[1])
|
hb_hosts=eval(r[1])
|
||||||
if verbose:
|
if verbose:
|
||||||
print "notice: cfg hb_hosts: %s" % hb_hosts
|
print("notice: cfg hb_hosts: %s" % hb_hosts)
|
||||||
elif r[0] == 'interval':
|
elif r[0] == 'interval':
|
||||||
interval=eval(r[1])
|
interval=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] == 'name':
|
elif r[0] == 'name':
|
||||||
iam=eval(r[1])
|
iam=eval(r[1])
|
||||||
if verbose: print "name set to %s" % iam
|
if verbose: print("name set to %s" % iam)
|
||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
if len(args) != 0:
|
if len(args) != 0:
|
||||||
@@ -454,17 +528,17 @@ if len(args) != 0:
|
|||||||
|
|
||||||
|
|
||||||
if len(hb_hosts) == 0:
|
if len(hb_hosts) == 0:
|
||||||
print "no hb server specified"
|
print("no hb server specified")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
#
|
#
|
||||||
if verbose:
|
if verbose:
|
||||||
print "notice: hb_hosts: %s" % str(hb_hosts)
|
print("notice: hb_hosts: %s" % str(hb_hosts))
|
||||||
print "notice: hb_port: %s" % hb_port
|
print("notice: hb_port: %s" % hb_port)
|
||||||
print "notice: interval: %s" % interval
|
print("notice: interval: %s" % interval)
|
||||||
print "notice: iam: %s" % iam
|
print("notice: iam: %s" % iam)
|
||||||
print "notice: msgonly: %s" % msgonly
|
print("notice: msgonly: %s" % msgonly)
|
||||||
print "notice: msgboot: %s" % msgboot
|
print("notice: msgboot: %s" % msgboot)
|
||||||
|
|
||||||
if not msgonly:
|
if not msgonly:
|
||||||
msgboot['interval'] = interval
|
msgboot['interval'] = interval
|
||||||
@@ -483,74 +557,32 @@ if verbose:
|
|||||||
log("%s connections created" % (len(conns)))
|
log("%s connections created" % (len(conns)))
|
||||||
|
|
||||||
if len(msgboot) > 0:
|
if len(msgboot) > 0:
|
||||||
if verbose: print "on boot"
|
if verbose: print("on boot")
|
||||||
msgboot['acks'] = 0
|
msgboot['acks'] = 0
|
||||||
for conn in conns:
|
for conn in conns:
|
||||||
conns[conn].sendto(msgboot)
|
conns[conn].sendto(msgboot)
|
||||||
|
|
||||||
if msgonly:
|
if msgonly:
|
||||||
if verbose: print "msgboot done msgonly=%s" % msgonly
|
if verbose: print("msgboot done msgonly=%s" % msgonly)
|
||||||
closeall()
|
closeall()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
#
|
#
|
||||||
|
|
||||||
syslog.openlog('hbc', syslog.LOG_PID, syslog.LOG_DAEMON)
|
syslog.openlog('hbc', syslog.LOG_PID, syslog.LOG_DAEMON)
|
||||||
if fdaemon:
|
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)
|
signal.signal(signal.SIGTERM, handler)
|
||||||
try:
|
|
||||||
opid = pidfile.read_pid()
|
|
||||||
except:
|
|
||||||
opid = None
|
|
||||||
|
|
||||||
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
|
running = True
|
||||||
try:
|
try:
|
||||||
process()
|
process()
|
||||||
except:
|
except:
|
||||||
syslogtrace('process')
|
syslogtrace('process')
|
||||||
|
if verbose: print("err: process exit: %s" % e)
|
||||||
|
|
||||||
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")
|
if verbose: log( "main: cleanup")
|
||||||
cleanup()
|
cleanup()
|
||||||
if dorestart:
|
if dorestart:
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# $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 = 3.00
|
VER = 4.00
|
||||||
|
|
||||||
import time
|
import time
|
||||||
import os
|
import os
|
||||||
@@ -11,31 +11,33 @@ import sys
|
|||||||
import socket
|
import socket
|
||||||
import atexit
|
import atexit
|
||||||
import select
|
import select
|
||||||
import SocketServer
|
import socketserver
|
||||||
import BaseHTTPServer
|
import http.server
|
||||||
import getopt
|
import getopt
|
||||||
import signal
|
import signal
|
||||||
import cPickle
|
import pickle
|
||||||
import smtplib
|
import smtplib
|
||||||
import traceback
|
import traceback
|
||||||
import urllib
|
import urllib.request, urllib.parse, urllib.error
|
||||||
import urlparse
|
import urllib.parse
|
||||||
import httplib
|
import http.client
|
||||||
import threading
|
import threading
|
||||||
import Queue
|
import queue
|
||||||
import md5
|
from hashlib import md5
|
||||||
import json
|
import json
|
||||||
import zlib
|
import zlib
|
||||||
|
|
||||||
from subprocess import Popen, STDOUT, PIPE
|
from subprocess import Popen, STDOUT, PIPE
|
||||||
|
|
||||||
from hbdclass import *
|
#from hbdclass import *
|
||||||
|
import hbdclass
|
||||||
|
|
||||||
|
|
||||||
SEND_EMAIL=False
|
SEND_EMAIL=False
|
||||||
SEND_PUSHOVER=True
|
SEND_PUSHOVER=True
|
||||||
|
|
||||||
DEBUG = 0
|
DEBUG = 0
|
||||||
|
hbdclass.DEBUG = DEBUG
|
||||||
|
|
||||||
MAXRECV = 32767
|
MAXRECV = 32767
|
||||||
LOGFILE = "/home/andreas/public_html/messages/andreas"
|
LOGFILE = "/home/andreas/public_html/messages/andreas"
|
||||||
@@ -55,6 +57,7 @@ verbose = False
|
|||||||
|
|
||||||
INTERVAL = 10
|
INTERVAL = 10
|
||||||
GRACE = 2
|
GRACE = 2
|
||||||
|
DROPOVERDUE = 7*24*3600
|
||||||
|
|
||||||
os.environ['TZ'] = 'EST5EDT'
|
os.environ['TZ'] = 'EST5EDT'
|
||||||
|
|
||||||
@@ -104,7 +107,7 @@ def handler(signum, frame):
|
|||||||
|
|
||||||
|
|
||||||
def shortname(name):
|
def shortname(name):
|
||||||
r = string.split(name, '.')
|
r = name.split('.')
|
||||||
return r[0]
|
return r[0]
|
||||||
|
|
||||||
|
|
||||||
@@ -131,22 +134,22 @@ def dicttos(ID, d, compress=False):
|
|||||||
s.append("%s=%s" % (k, d[k]))
|
s.append("%s=%s" % (k, d[k]))
|
||||||
pk = ";".join(s)
|
pk = ";".join(s)
|
||||||
if compress:
|
if compress:
|
||||||
zpk = zlib.compress(pk, 6)
|
zpk = zlib.compress(pk.encode(), 6)
|
||||||
ID = "!"+ID
|
ID = "!" + ID + ":"
|
||||||
|
opk = ID.encode() + zpk
|
||||||
else:
|
else:
|
||||||
zpk = pk
|
zpk = pk
|
||||||
return ID + ":" + zpk
|
opk = ID + ":" + zpk
|
||||||
|
return opk
|
||||||
|
|
||||||
|
|
||||||
def stodict(msg):
|
def stodict(msg):
|
||||||
d = {}
|
d = {}
|
||||||
r0 = msg.split(':',1)
|
if len(msg) > 0 and chr(msg[0]) == "!":
|
||||||
if len(r0) == 1:
|
pk = zlib.decompress(msg[5:]).decode()
|
||||||
return None
|
d['ID'] = msg[1:4].decode()
|
||||||
if r0[0][0] == '!': # compressed
|
|
||||||
pk = zlib.decompress(msg[len(r0[0])+1:])
|
|
||||||
d['ID'] = r0[0][1:]
|
|
||||||
else:
|
else:
|
||||||
|
r0 = msg.split(':',1)
|
||||||
pk = r0[1]
|
pk = r0[1]
|
||||||
d['ID'] = r0[0]
|
d['ID'] = r0[0]
|
||||||
r = pk.split(';')
|
r = pk.split(';')
|
||||||
@@ -180,11 +183,11 @@ def email(s, msg):
|
|||||||
server = smtplib.SMTP(SMTPSERVER)
|
server = smtplib.SMTP(SMTPSERVER)
|
||||||
if DEBUG > 0: server.set_debuglevel(1)
|
if DEBUG > 0: server.set_debuglevel(1)
|
||||||
server.sendmail(fromemail, toaddrs, body)
|
server.sendmail(fromemail, toaddrs, body)
|
||||||
except smtplib.SMTPRecipientsRefused, errs:
|
except smtplib.SMTPRecipientsRefused as errs:
|
||||||
log(None, "cannot send email: %s\n" % (errs))
|
log(None, "cannot send email: %s\n" % (errs))
|
||||||
ret = "Fail"
|
ret = "Fail"
|
||||||
except:
|
except:
|
||||||
print("smtp error: "+traceback.format_exc())
|
print(("smtp error: "+traceback.format_exc()))
|
||||||
saveandrestart()
|
saveandrestart()
|
||||||
try:
|
try:
|
||||||
server.quit()
|
server.quit()
|
||||||
@@ -196,10 +199,10 @@ def email(s, msg):
|
|||||||
def pushover(msg):
|
def pushover(msg):
|
||||||
if not SEND_PUSHOVER:
|
if not SEND_PUSHOVER:
|
||||||
return
|
return
|
||||||
conn = httplib.HTTPSConnection("api.pushover.net:443")
|
conn = http.client.HTTPSConnection("api.pushover.net:443")
|
||||||
try:
|
try:
|
||||||
conn.request("POST", "/1/messages.json",
|
conn.request("POST", "/1/messages.json",
|
||||||
urllib.urlencode({
|
urllib.parse.urlencode({
|
||||||
"token": "ac7NLX2rPjXFareeDgLpXNoDf4iFmf",
|
"token": "ac7NLX2rPjXFareeDgLpXNoDf4iFmf",
|
||||||
"user": "uDhH33UjQQDYtNzJb1ThRiWb9ingGK",
|
"user": "uDhH33UjQQDYtNzJb1ThRiWb9ingGK",
|
||||||
"message": msg, }), { "Content-type": "application/x-www-form-urlencoded" })
|
"message": msg, }), { "Content-type": "application/x-www-form-urlencoded" })
|
||||||
@@ -241,12 +244,12 @@ answer
|
|||||||
if DEBUG > 0: log(None, "DBG: cmd %s" % cmd)
|
if DEBUG > 0: log(None, "DBG: cmd %s" % cmd)
|
||||||
try:
|
try:
|
||||||
p = Popen(cmd, shell=False, bufsize=1, stdin=PIPE, stdout=PIPE, stderr=STDOUT)
|
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
|
return "nsupdate: execution failed: %s" % e
|
||||||
except:
|
except:
|
||||||
return "nsupdate: some error occured"
|
return "nsupdate: some error occured"
|
||||||
|
|
||||||
(output, err) = p.communicate(nsup)
|
(output, err) = p.communicate(nsup.encode())
|
||||||
if output.find('status: NOERROR') >= 0:
|
if output.find('status: NOERROR') >= 0:
|
||||||
return None
|
return None
|
||||||
return output
|
return output
|
||||||
@@ -255,9 +258,9 @@ answer
|
|||||||
#
|
#
|
||||||
def dur(sec):
|
def dur(sec):
|
||||||
sec = int(sec)
|
sec = int(sec)
|
||||||
h = sec / 3600
|
h = int(sec / 3600)
|
||||||
m = (sec - h * 3600) / 60
|
m = int((sec - h * 3600) / 60)
|
||||||
s = (sec - h * 3600) % 60
|
s = int((sec - h * 3600) % 60)
|
||||||
if h > 0:
|
if h > 0:
|
||||||
return "%d:%02d:%02d" % (h, m, s)
|
return "%d:%02d:%02d" % (h, m, s)
|
||||||
if m > 0:
|
if m > 0:
|
||||||
@@ -266,11 +269,11 @@ def dur(sec):
|
|||||||
|
|
||||||
|
|
||||||
def fixsort():
|
def fixsort():
|
||||||
s = Host.hosts.keys()
|
s = list(hbdclass.Host.hosts.keys())
|
||||||
s.sort()
|
s.sort()
|
||||||
x = 0
|
x = 0
|
||||||
for n in s:
|
for n in s:
|
||||||
Host.hosts[n].num = x
|
hbdclass.Host.hosts[n].num = x
|
||||||
x += 1
|
x += 1
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -280,7 +283,7 @@ def on_exit():
|
|||||||
logf.close()
|
logf.close()
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
print "exit"
|
print("exit")
|
||||||
|
|
||||||
|
|
||||||
def initlog(logfile):
|
def initlog(logfile):
|
||||||
@@ -295,16 +298,18 @@ def initlog(logfile):
|
|||||||
#
|
#
|
||||||
def checkoverdue():
|
def checkoverdue():
|
||||||
now = time.time()
|
now = time.time()
|
||||||
for h in Host.hosts.keys():
|
for h in list(hbdclass.Host.hosts.keys()):
|
||||||
pmsg = []
|
pmsg = []
|
||||||
for c in Host.hosts[h].connections:
|
for c in hbdclass.Host.hosts[h].connections:
|
||||||
conn = Host.hosts[h].connections[c]
|
conn = hbdclass.Host.hosts[h].connections[c]
|
||||||
if conn.state == Connection.down:
|
if conn.state == hbdclass.Connection.down:
|
||||||
continue
|
continue
|
||||||
timeout = Host.hosts[h].interval + grace
|
timeout = hbdclass.Host.hosts[h].interval + grace
|
||||||
if conn.state == Connection.up and (now - conn.lastbeat) > timeout:
|
if conn.state == hbdclass.Connection.up and (now - conn.lastbeat) > timeout:
|
||||||
conn.newstate(Connection.overdue, now, grace)
|
conn.newstate(hbdclass.Connection.overdue, now, grace)
|
||||||
pmsg.append(conn.afam)
|
pmsg.append(conn.afam)
|
||||||
|
if conn.state == hbdclass.Connection.overdue and (now - conn.lastbeat) > DROPOVERDUE:
|
||||||
|
conn.newstate(hbdclass.Connection.unknown, conn.lastbeat)
|
||||||
if pmsg != []:
|
if pmsg != []:
|
||||||
if h in watchhosts:
|
if h in watchhosts:
|
||||||
email("overdue", "%s overdue" % " and ".join(pmsg))
|
email("overdue", "%s overdue" % " and ".join(pmsg))
|
||||||
@@ -313,8 +318,9 @@ def checkoverdue():
|
|||||||
|
|
||||||
|
|
||||||
def log(host, m, service=None):
|
def log(host, m, service=None):
|
||||||
if DEBUG > 0: print "Log: %s" % m
|
if DEBUG > 0: print("Log: %s %s" % (host, m))
|
||||||
ts = time.strftime("%b %d %H:%M:%S", time.localtime(time.time()))
|
now = time.time()
|
||||||
|
ts = time.strftime("%b %d %H:%M:%S", time.localtime(now))
|
||||||
if service:
|
if service:
|
||||||
srv = "service %s: " % service
|
srv = "service %s: " % service
|
||||||
else:
|
else:
|
||||||
@@ -327,7 +333,7 @@ def log(host, m, service=None):
|
|||||||
msg = "%s: %s%s%s\n" % (ts, hst, srv, m)
|
msg = "%s: %s%s%s\n" % (ts, hst, srv, m)
|
||||||
msgs.append(msg)
|
msgs.append(msg)
|
||||||
if logfmt == "msg":
|
if logfmt == "msg":
|
||||||
m2 = "%d|%s|%s\n" % (now, service, m)
|
m2 = "%d|%s|%s\n" % (now, hst, m)
|
||||||
else:
|
else:
|
||||||
m2 = msg
|
m2 = msg
|
||||||
logf.write(m2)
|
logf.write(m2)
|
||||||
@@ -337,7 +343,7 @@ def log(host, m, service=None):
|
|||||||
|
|
||||||
def dnsupdatethread():
|
def dnsupdatethread():
|
||||||
while True:
|
while True:
|
||||||
name, addr = Host.dnsQ.get()
|
name, addr = hbdclass.Host.dnsQ.get()
|
||||||
m = "changed address to %s" % (addr)
|
m = "changed address to %s" % (addr)
|
||||||
err = nsupdate(name, addr)
|
err = nsupdate(name, addr)
|
||||||
if err:
|
if err:
|
||||||
@@ -345,7 +351,7 @@ def dnsupdatethread():
|
|||||||
email("error: nsupdate failed", "%s: %s" % (name, m))
|
email("error: nsupdate failed", "%s: %s" % (name, m))
|
||||||
else:
|
else:
|
||||||
m += ", DNS updated."
|
m += ", DNS updated."
|
||||||
Host.dnsQ.task_done()
|
hbdclass.Host.dnsQ.task_done()
|
||||||
log(name, m)
|
log(name, m)
|
||||||
|
|
||||||
#
|
#
|
||||||
@@ -355,30 +361,38 @@ def dnsupdatethread():
|
|||||||
def readsock(sock):
|
def readsock(sock):
|
||||||
global now
|
global now
|
||||||
if DEBUG > 3: sys.stderr.write("readsock recfrom start")
|
if DEBUG > 3: sys.stderr.write("readsock recfrom start")
|
||||||
data, addrp = sock.recvfrom(MAXRECV)
|
|
||||||
now = time.time()
|
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)
|
msg = stodict(data)
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
if DEBUG > 3: sys.stderr.write("msg is %s" % str(msg))
|
||||||
if not msg: # Old hbc client
|
if not msg: # Old hbc client
|
||||||
if verbose: print "old hbc:", data
|
if verbose: print(("old hbc:", data))
|
||||||
oldclient = True
|
oldclient = True
|
||||||
msg = oldmtodict(data)
|
msg = oldmtodict(data)
|
||||||
else:
|
else:
|
||||||
oldclient = False
|
oldclient = False
|
||||||
if DEBUG > 2: print "readsock = %s, %s" % (msg,addrp)
|
if DEBUG > 2: print(("readsock = %s, %s" % (msg,addrp)))
|
||||||
|
|
||||||
addr = addrp[0:2]
|
addr = addrp[0:2]
|
||||||
name = shortname(msg.get('name', "unknown"))
|
name = shortname(msg.get('name', "unknown"))
|
||||||
if not name in Host.hosts: # was: hosts.has_key(name):
|
if not name in hbdclass.Host.hosts: # was: hosts.has_key(name):
|
||||||
host = Host(name)
|
host = hbdclass.Host(name)
|
||||||
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(hbdclass.Host.hosts))))
|
||||||
newh=True
|
newh=True
|
||||||
else:
|
else:
|
||||||
host = Host.hosts[name]
|
host = hbdclass.Host.hosts[name]
|
||||||
newh=False
|
newh=False
|
||||||
|
|
||||||
cid = msg.get('id', 0)
|
cid = msg.get('id', 0)
|
||||||
rtt = msg.get('rtt',None)
|
try:
|
||||||
|
rtt = float(msg.get('rtt',None))
|
||||||
|
except:
|
||||||
|
rtt = None
|
||||||
|
|
||||||
if msg['ID'] == 'HTB':
|
if msg['ID'] == 'HTB':
|
||||||
host.doesack = msg.get('acks', -1)
|
host.doesack = msg.get('acks', -1)
|
||||||
@@ -408,9 +422,9 @@ def readsock(sock):
|
|||||||
email("address change", "%s %s" % (host.name, res))
|
email("address change", "%s %s" % (host.name, res))
|
||||||
pushover("%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
|
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))
|
m = "%s back after being %s for %s" % (conn.afam, lasts, dur(d))
|
||||||
log(name, m)
|
log(name, m)
|
||||||
if name in watchhosts:
|
if name in watchhosts:
|
||||||
@@ -428,7 +442,7 @@ def readsock(sock):
|
|||||||
if name in watchhosts:
|
if name in watchhosts:
|
||||||
email("shutdown", "%s %s shutdown" % (name, conn.afam))
|
email("shutdown", "%s %s shutdown" % (name, conn.afam))
|
||||||
pushover("%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:
|
if interval > 0:
|
||||||
host.interval = interval
|
host.interval = interval
|
||||||
@@ -440,8 +454,11 @@ def readsock(sock):
|
|||||||
rmsg = 'ACK'
|
rmsg = 'ACK'
|
||||||
else:
|
else:
|
||||||
opkt = dicttos('ACK', rmsg, host.cver > 1) # clients w/ ver 2+ can cope
|
opkt = dicttos('ACK', rmsg, host.cver > 1) # clients w/ ver 2+ can cope
|
||||||
|
try:
|
||||||
ss=sock.sendto(opkt, addr)
|
ss=sock.sendto(opkt, addr)
|
||||||
if DEBUG > 2: print "sendto1: %s (%s) %s %s" % (addr, len(opkt), op, str(rmsg)[:50])
|
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
|
# send any commands we have queued
|
||||||
while len(host.cmds):
|
while len(host.cmds):
|
||||||
@@ -466,11 +483,11 @@ def readsock(sock):
|
|||||||
try:
|
try:
|
||||||
ss=sock.sendto(opkt, addr)
|
ss=sock.sendto(opkt, addr)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print "opkt len is %s" % len(opkt)
|
print(("opkt len is %s" % len(opkt)))
|
||||||
print "cannot send: %s" % e
|
print(("cannot send: %s" % e))
|
||||||
|
|
||||||
if verbose: print "sendto2: %s (%s) %s %s" % (addr, len(opkt), op, str(rmsg)[:50])
|
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 DEBUG > 2: print(("msg from %s,%s, sent %s bytes back" % (addr[0], addr[1], ss)))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -488,19 +505,19 @@ def updatecode(ucode, uname):
|
|||||||
m.update(new_code)
|
m.update(new_code)
|
||||||
icsum = m.hexdigest()
|
icsum = m.hexdigest()
|
||||||
rmsg = {'csum': icsum, 'code': new_code.encode('base64','strict') }
|
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
|
return fail
|
||||||
|
|
||||||
#
|
#
|
||||||
# Web Server
|
# Web Server
|
||||||
#
|
#
|
||||||
class HttpServer(SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
|
class HttpServer(socketserver.ThreadingMixIn, http.server.HTTPServer):
|
||||||
allow_reuse_address = True
|
allow_reuse_address = True
|
||||||
def threaded():
|
def threaded():
|
||||||
pass
|
pass
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
class HttpHandler(http.server.BaseHTTPRequestHandler):
|
||||||
|
|
||||||
server_version = "HeartbeatHTTP/%s" % VER
|
server_version = "HeartbeatHTTP/%s" % VER
|
||||||
|
|
||||||
@@ -509,8 +526,9 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
|
|
||||||
|
|
||||||
def handle(self):
|
def handle(self):
|
||||||
|
return http.server.BaseHTTPRequestHandler.handle(self)
|
||||||
try:
|
try:
|
||||||
return BaseHTTPServer.BaseHTTPRequestHandler.handle(self)
|
return http.server.BaseHTTPRequestHandler.handle(self)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log_error("Request went away: %r", e)
|
self.log_error("Request went away: %r", e)
|
||||||
self.close_connection = 1
|
self.close_connection = 1
|
||||||
@@ -525,7 +543,7 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
self.send_response(code)
|
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("Last-Modified", time.strftime("%a, %d %b %Y %H:%M:%S GMT", time.gmtime(now)))
|
||||||
# self.send_header("Accept-Ranges","bytes")
|
# self.send_header("Accept-Ranges","bytes")
|
||||||
# self.send_header("Connection","close")
|
# self.send_header("hbdclass.Connection","close")
|
||||||
for h in headerdict:
|
for h in headerdict:
|
||||||
self.send_header(h, headerdict[h])
|
self.send_header(h, headerdict[h])
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
@@ -549,10 +567,8 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
def buildpage(self):
|
def buildpage(self):
|
||||||
res=self.buildhead(refresh=60, extras=tcss)
|
res=self.buildhead(refresh=60, extras=tcss)
|
||||||
res.append("<H2>Heartbeat status %s</h2>" % VER)
|
res.append("<H2>Heartbeat status %s</h2>" % VER)
|
||||||
|
res += hbdclass.ubHost.buildhosttable()
|
||||||
|
res += hbdclass.ubHost.buildmsgtable(msgs)
|
||||||
res += ubHost.buildhosttable()
|
|
||||||
res += ubHost.buildmsgtable(msgs)
|
|
||||||
res.append('<p> %s (%s)</p>' % (time.strftime("%H:%M:%S", time.localtime(now)), os.environ.get('TZ', 'CET-1CDT')))
|
res.append('<p> %s (%s)</p>' % (time.strftime("%H:%M:%S", time.localtime(now)), os.environ.get('TZ', 'CET-1CDT')))
|
||||||
res.append("</body></html>")
|
res.append("</body></html>")
|
||||||
return res
|
return res
|
||||||
@@ -576,11 +592,11 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
global sig
|
global sig
|
||||||
code = 200
|
code = 200
|
||||||
xsig = 0
|
xsig = 0
|
||||||
rqAcceptEncoding = self.headers.getheader('Accept-encoding',{})
|
rqAcceptEncoding = self.headers.get('Accept-encoding',{})
|
||||||
headerdict = {"Content-Type": "text/html; charset = ISO-8859-1" }
|
headerdict = {"Content-Type": "text/html; charset = ISO-8859-1" }
|
||||||
if DEBUG > 2: sys.stderr.write("handle\n")
|
if DEBUG > 2: sys.stderr.write("handle\n")
|
||||||
qr = urlparse.urlparse(self.path)
|
qr = urllib.parse.urlparse(self.path)
|
||||||
qa = urlparse.parse_qs(qr.query)
|
qa = urllib.parse.parse_qs(qr.query)
|
||||||
|
|
||||||
if DEBUG > 2: sys.stderr.write("handle = %s\n" % (qr.geturl()))
|
if DEBUG > 2: sys.stderr.write("handle = %s\n" % (qr.geturl()))
|
||||||
if qr.path == "/":
|
if qr.path == "/":
|
||||||
@@ -591,10 +607,10 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
ucmd=qa.get('c', [None])[0]
|
ucmd=qa.get('c', [None])[0]
|
||||||
if not ucmd or not uname:
|
if not ucmd or not uname:
|
||||||
code, res=self.builderror(400, 'Argument error', "need h= and c= arguments")
|
code, res=self.builderror(400, 'Argument error', "need h= and c= arguments")
|
||||||
elif not Host.hosts.has_key(uname):
|
elif uname not in hbdclass.Host.hosts:
|
||||||
code, res=self.builderror(400, 'Data error', "h=%s not found" % uname)
|
code, res=self.builderror(400, 'Data error', "h=%s not found" % uname)
|
||||||
else:
|
else:
|
||||||
Host.hosts[uname].cmds.append(('CMD', {'cmd': urllib.unquote(ucmd)}))
|
hbdclass.Host.hosts[uname].cmds.append(('CMD', {'cmd': urllib.parse.unquote(ucmd)}))
|
||||||
res=self.buildhead()
|
res=self.buildhead()
|
||||||
res.append("cmd %s queued for host %s" % (uname, ucmd))
|
res.append("cmd %s queued for host %s" % (uname, ucmd))
|
||||||
|
|
||||||
@@ -602,11 +618,12 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
uname=qa.get('h',[None])[0]
|
uname=qa.get('h',[None])[0]
|
||||||
if not uname:
|
if not uname:
|
||||||
code, res=self.builderror(400, 'Argument error', "need h= argument")
|
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)
|
code, res=self.builderror(400, 'Data error', "h=%s not found" % uname)
|
||||||
else:
|
else:
|
||||||
log(uname, "dropped")
|
log(uname, "dropped")
|
||||||
del Host.hosts[uname]
|
# for addr in hbdclass.Host.hosts[uname].0i
|
||||||
|
del hbdclass.Host.hosts[uname]
|
||||||
res=self.buildhead()
|
res=self.buildhead()
|
||||||
res.append("Done")
|
res.append("Done")
|
||||||
|
|
||||||
@@ -614,30 +631,39 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
uname=qa.get('h',[None])[0]
|
uname=qa.get('h',[None])[0]
|
||||||
if not uname:
|
if not uname:
|
||||||
code, res=self.builderror(400, 'Argument error', "need h= argument")
|
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)
|
code, res=self.builderror(400, 'Data error', "h=%s not found" % uname)
|
||||||
else:
|
else:
|
||||||
ll = Host.hosts[uname].registerDns()
|
ll = hbdclass.Host.hosts[uname].registerDns()
|
||||||
res.append(ll)
|
res.append(ll)
|
||||||
log(uname, ll)
|
log(uname, ll)
|
||||||
|
|
||||||
elif qr.path == "/u": # update
|
elif qr.path == "/u": # update
|
||||||
uname=qa.get('h',[None])[0]
|
uname=urllib.parse.unquote(qa.get('h',[None])[0])
|
||||||
ucode=qa.get('c', [None])[0]
|
ucode=qa.get('c', [None])[0]
|
||||||
if not ucode or not uname:
|
if not ucode or not uname:
|
||||||
code, res=self.builderror(400, 'Argument error', "need h= and c= arguments")
|
code, res=self.builderror(400, 'Argument error', "need h= and c= arguments")
|
||||||
elif not Host.hosts.has_key(uname):
|
elif uname != 'All' and uname not in hbdclass.Host.hosts:
|
||||||
code, res=self.builderror(400, 'Data error', "h=%s not found" % uname)
|
code, res=self.builderror(400, 'Data error', "h=%s not found" % uname)
|
||||||
else:
|
else:
|
||||||
err = updatecode(ucode, urllib.unquote(uname))
|
|
||||||
res=self.buildhead()
|
res=self.buildhead()
|
||||||
res.append("3 Done: %s" % err if err else "OK")
|
if uname != 'All':
|
||||||
|
names = [uname]
|
||||||
|
else:
|
||||||
|
names = []
|
||||||
|
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)
|
||||||
|
res.append("update started for %s: %s<br>" % (n, err if err else "OK"))
|
||||||
|
res.append("Done")
|
||||||
|
|
||||||
elif qr.path == "/api/0/hosts": # api access to host table
|
elif qr.path == "/api/0/hosts": # api access to host table
|
||||||
headerdict = {"Content-Type": "application/json; charset=utf-8" }
|
headerdict = {"Content-Type": "application/json; charset=utf-8" }
|
||||||
l=[]
|
l=[]
|
||||||
for h in Host.hosts:
|
for h in hbdclass.Host.hosts:
|
||||||
l.append(Host.hosts[h].jsons())
|
l.append(hbdclass.Host.hosts[h].jsons())
|
||||||
res=["["+",".join(l)+"]"]
|
res=["["+",".join(l)+"]"]
|
||||||
|
|
||||||
elif qr.path == "/api/0/messages": # api access to host table
|
elif qr.path == "/api/0/messages": # api access to host table
|
||||||
@@ -657,9 +683,9 @@ class HttpHandler(BaseHTTPServer.BaseHTTPRequestHandler):
|
|||||||
|
|
||||||
if 'deflate' in rqAcceptEncoding:
|
if 'deflate' in rqAcceptEncoding:
|
||||||
headerdict['Content-Encoding'] = "deflate"
|
headerdict['Content-Encoding'] = "deflate"
|
||||||
towrite = zlib.compress(string.join(res, "\n"), 6)
|
towrite = zlib.compress("\n".join(res).encode(), 6)
|
||||||
else:
|
else:
|
||||||
towrite = string.join(res, "\n")
|
towrite = "\n".join(res)
|
||||||
headerdict['Content-Length'] = len(towrite)
|
headerdict['Content-Length'] = len(towrite)
|
||||||
headerdict['Cache-Control'] = 'private, must-revalidate, max-age=0'
|
headerdict['Cache-Control'] = 'private, must-revalidate, max-age=0'
|
||||||
headerdict['Expires'] = 'Thu, 01 Jan 1970 00:00:00 GMT'
|
headerdict['Expires'] = 'Thu, 01 Jan 1970 00:00:00 GMT'
|
||||||
@@ -710,9 +736,9 @@ def closeup():
|
|||||||
|
|
||||||
|
|
||||||
def restart():
|
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)
|
os.execv(sys.argv[0], [sys.argv[0]]+cmdargs)
|
||||||
print "should not be here"
|
print("should not be here")
|
||||||
|
|
||||||
def saveandrestart():
|
def saveandrestart():
|
||||||
closeup()
|
closeup()
|
||||||
@@ -720,9 +746,9 @@ def saveandrestart():
|
|||||||
|
|
||||||
|
|
||||||
def pickleit():
|
def pickleit():
|
||||||
pickf = open(pickfile, 'w')
|
pickf = open(pickfile, 'wb')
|
||||||
pick = cPickle.Pickler(pickf)
|
pick = pickle.Pickler(pickf)
|
||||||
pick.dump(Host.hosts)
|
pick.dump(hbdclass.Host.hosts)
|
||||||
pick.dump(msgs)
|
pick.dump(msgs)
|
||||||
pick.dump(lastfm)
|
pick.dump(lastfm)
|
||||||
pickf.close()
|
pickf.close()
|
||||||
@@ -762,17 +788,17 @@ for o, a in optlist:
|
|||||||
cmdargs += [o]
|
cmdargs += [o]
|
||||||
|
|
||||||
if helpflag:
|
if helpflag:
|
||||||
print "hbc HeartBeatDaemon"
|
print("hbc HeartBeatDaemon")
|
||||||
print "usage: hbd [-dfhvx] [-c configfile]"
|
print("usage: hbd [-dfhvx] [-c configfile]")
|
||||||
print
|
print()
|
||||||
print " -c configfile"
|
print(" -c configfile")
|
||||||
print " -d display"
|
print(" -d display")
|
||||||
print " -f run in foreground"
|
print(" -f run in foreground")
|
||||||
print " -h this help"
|
print(" -h this help")
|
||||||
print " -v verbose"
|
print(" -v verbose")
|
||||||
print " -x increase debug lvl"
|
print(" -x increase debug lvl")
|
||||||
print
|
print()
|
||||||
print """ config file can contain
|
print(""" config file can contain
|
||||||
logfile = /var/log/heartbeat.log
|
logfile = /var/log/heartbeat.log
|
||||||
logfmt = [text|msg]
|
logfmt = [text|msg]
|
||||||
hb_port = 50003
|
hb_port = 50003
|
||||||
@@ -780,7 +806,7 @@ interval = 20
|
|||||||
hbd_port = 50004
|
hbd_port = 50004
|
||||||
hbd_host = www.domain.com
|
hbd_host = www.domain.com
|
||||||
grace = 2
|
grace = 2
|
||||||
"""
|
""")
|
||||||
|
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
@@ -802,21 +828,28 @@ drophosts = []
|
|||||||
try:
|
try:
|
||||||
f = open(configfile, "r")
|
f = open(configfile, "r")
|
||||||
if verbose:
|
if verbose:
|
||||||
print "notice: using config file %s" % configfile
|
print(("notice: using config file %s" % configfile))
|
||||||
except:
|
except:
|
||||||
print "warning: running without config file: %s" % configfile
|
print(("warning: running without config file: %s" % configfile))
|
||||||
f = None
|
f = None
|
||||||
|
|
||||||
if f:
|
if f:
|
||||||
while 1:
|
while 1:
|
||||||
l = f.readline()
|
ls = f.readline()
|
||||||
if len(l) == 0:
|
if len(ls) == 0:
|
||||||
break
|
break
|
||||||
|
l = ls[:-1].strip()
|
||||||
|
if len(l) == 0 or l[0] == "#":
|
||||||
|
continue
|
||||||
if verbose:
|
if verbose:
|
||||||
print " %s" % l[:-1]
|
print((" %s" % l))
|
||||||
r = l[:-1].split('=')
|
r = l.split('=')
|
||||||
o = r[0].strip()
|
o = r[0].strip()
|
||||||
|
try:
|
||||||
a = eval(r[1].strip())
|
a = eval(r[1].strip())
|
||||||
|
except Exception as e:
|
||||||
|
print(("error: %s" % str(r)))
|
||||||
|
sys.exit(1)
|
||||||
if o == 'interval':
|
if o == 'interval':
|
||||||
interval = a
|
interval = a
|
||||||
elif o == 'grace':
|
elif o == 'grace':
|
||||||
@@ -842,38 +875,39 @@ if f:
|
|||||||
f.close()
|
f.close()
|
||||||
|
|
||||||
if len(args) != 0:
|
if len(args) != 0:
|
||||||
print "error: args"
|
print("error: args")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
if verbose:
|
if verbose:
|
||||||
print "notice: logging to %s" % logfile
|
print(("notice: logging to %s" % logfile))
|
||||||
logf = initlog(logfile)
|
logf = initlog(logfile)
|
||||||
|
|
||||||
if 1 and os.path.exists(pickfile):
|
if 1 and os.path.exists(pickfile):
|
||||||
if verbose: print "opening pickls %s" % pickfile
|
if verbose: print(("opening pickls %s" % pickfile))
|
||||||
pickf = open(pickfile, 'r')
|
pickf = open(pickfile, 'rb')
|
||||||
pick = cPickle.Unpickler(pickf)
|
pick = pickle.Unpickler(pickf)
|
||||||
try:
|
try:
|
||||||
Host.hosts = pick.load()
|
hbdclass.Host.hosts = pick.load()
|
||||||
msgs = pick.load()
|
msgs = pick.load()
|
||||||
try:
|
try:
|
||||||
lastfm = pick.load()
|
lastfm = pick.load()
|
||||||
except:
|
except:
|
||||||
lastfm = ["","",""]
|
lastfm = ["","",""]
|
||||||
pickf.close()
|
pickf.close()
|
||||||
except:
|
except Exception as e:
|
||||||
|
print(("load pickled failed: %s" % e))
|
||||||
os.unlink(pickfile)
|
os.unlink(pickfile)
|
||||||
Connection.htab = {}
|
hbdclass.Connection.htab = {}
|
||||||
for h in Host.hosts.keys():
|
for h in list(hbdclass.Host.hosts.keys()):
|
||||||
Host.hosts[h].dyn = h in dyndnshosts
|
hbdclass.Host.hosts[h].dyn = h in dyndnshosts
|
||||||
Host.hosts[h].fixup()
|
hbdclass.Host.hosts[h].fixup()
|
||||||
for h in drophosts:
|
for h in drophosts:
|
||||||
if h in Host.hosts:
|
if h in hbdclass.Host.hosts:
|
||||||
del Host.hosts[h]
|
del hbdclass.Host.hosts[h]
|
||||||
if verbose: print "%s pickled hosts loaded" % len(Host.hosts)
|
if verbose: print(("%s pickled hosts loaded" % len(hbdclass.Host.hosts)))
|
||||||
else:
|
else:
|
||||||
if verbose: print "no pickled data"
|
if verbose: print("no pickled data")
|
||||||
|
|
||||||
|
|
||||||
now = time.time()
|
now = time.time()
|
||||||
@@ -901,7 +935,7 @@ if not forground:
|
|||||||
pid = os.fork()
|
pid = os.fork()
|
||||||
if pid > 0:
|
if pid > 0:
|
||||||
if verbose:
|
if verbose:
|
||||||
print "daemoinizing... pid = %d" % pid
|
print(("daemoinizing... pid = %d" % pid))
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
verbose = False
|
verbose = False
|
||||||
@@ -922,14 +956,14 @@ if not forground:
|
|||||||
try:
|
try:
|
||||||
serv = HttpServer((hbd_host, hbd_port), HttpHandler)
|
serv = HttpServer((hbd_host, hbd_port), HttpHandler)
|
||||||
except:
|
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)
|
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()
|
||||||
|
|
||||||
Host.dnsQ = Queue.Queue()
|
hbdclass.Host.dnsQ = queue.Queue()
|
||||||
dnsT = threading.Thread(target=dnsupdatethread)
|
dnsT = threading.Thread(target=dnsupdatethread)
|
||||||
dnsT.daemon = True
|
dnsT.daemon = True
|
||||||
dnsT.start()
|
dnsT.start()
|
||||||
@@ -939,13 +973,13 @@ sig = 0
|
|||||||
signal.signal(signal.SIGTERM, handler)
|
signal.signal(signal.SIGTERM, handler)
|
||||||
signal.signal(signal.SIGHUP, 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
|
sleep = 1
|
||||||
firstcheck = int(now) + 15
|
firstcheck = int(now) + 15
|
||||||
|
|
||||||
while running:
|
while running:
|
||||||
sr = None
|
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:
|
try:
|
||||||
sr = select.select(ilist, [], [], sleep)
|
sr = select.select(ilist, [], [], sleep)
|
||||||
now = time.time()
|
now = time.time()
|
||||||
@@ -954,7 +988,7 @@ while running:
|
|||||||
running = False
|
running = False
|
||||||
closeup()
|
closeup()
|
||||||
continue
|
continue
|
||||||
except select.error, value:
|
except select.error as value:
|
||||||
if value[0] != 4: # interrupted system call
|
if value[0] != 4: # interrupted system call
|
||||||
sys.stderr.write("select err %s %s" % (select.error, value))
|
sys.stderr.write("select err %s %s" % (select.error, value))
|
||||||
#raise os.error, value
|
#raise os.error, value
|
||||||
@@ -963,7 +997,7 @@ while running:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
if DEBUG > 2: sys.stderr.write("select exception %s\n" % (str(e)))
|
if DEBUG > 2: sys.stderr.write("select exception %s\n" % (str(e)))
|
||||||
sys.exit(1)
|
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]:
|
for fh in sr[0]:
|
||||||
if fh in [sock, sock6]:
|
if fh in [sock, sock6]:
|
||||||
readsock(fh)
|
readsock(fh)
|
||||||
@@ -971,26 +1005,26 @@ while running:
|
|||||||
# serv.handle_request()
|
# serv.handle_request()
|
||||||
else:
|
else:
|
||||||
sys.stderr.write("what happend just now?\n")
|
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
|
# check hour/day/week
|
||||||
for v in xrange(3):
|
for v in range(3):
|
||||||
fm=tsfm[v]
|
fm=tsfm[v]
|
||||||
ts=time.strftime(tsfm[v], time.localtime(now))
|
ts=time.strftime(tsfm[v], time.localtime(now))
|
||||||
if ts != lastfm[v]:
|
if ts != lastfm[v]:
|
||||||
lastfm[v]=ts
|
lastfm[v]=ts
|
||||||
for h in Host.hosts.keys():
|
for h in list(hbdclass.Host.hosts.keys()):
|
||||||
Host.hosts[h].hdwcounts[v] = [Host.hosts[h].doesack, Host.hosts[h].upcount]
|
hbdclass.Host.hosts[h].hdwcounts[v] = [hbdclass.Host.hosts[h].doesack, hbdclass.Host.hosts[h].upcount]
|
||||||
|
|
||||||
if now >= next and now >= firstcheck:
|
if now >= rnext and now >= firstcheck:
|
||||||
next = now+1
|
rnext = now+1
|
||||||
checkoverdue()
|
checkoverdue()
|
||||||
|
|
||||||
sleep = next-now
|
sleep = rnext-now
|
||||||
if sleep < 0:
|
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
|
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:
|
if sig != 0:
|
||||||
setrunning(False)
|
setrunning(False)
|
||||||
|
|||||||
+37
-9
@@ -13,7 +13,13 @@ num = 0
|
|||||||
|
|
||||||
MAXRTTS = 10
|
MAXRTTS = 10
|
||||||
|
|
||||||
#
|
DEBUG=2
|
||||||
|
|
||||||
|
def log(host, m):
|
||||||
|
if DEBUG:
|
||||||
|
print("class log: %s %s" % (host, m))
|
||||||
|
|
||||||
|
|
||||||
class Connection:
|
class Connection:
|
||||||
# map of addrs to names
|
# map of addrs to names
|
||||||
|
|
||||||
@@ -38,6 +44,7 @@ class Connection:
|
|||||||
r = "new addr %s" % (addr)
|
r = "new addr %s" % (addr)
|
||||||
Connection.htab[addr] = self.host.name
|
Connection.htab[addr] = self.host.name
|
||||||
if self.host.isDynDns():
|
if self.host.isDynDns():
|
||||||
|
log(self.host.name, "dns update %s" % self.addr)
|
||||||
Host.dnsQ.put((self.host.name, self.addr))
|
Host.dnsQ.put((self.host.name, self.addr))
|
||||||
|
|
||||||
def registerDns(self):
|
def registerDns(self):
|
||||||
@@ -51,6 +58,8 @@ class Connection:
|
|||||||
d['addr'] = self.addr
|
d['addr'] = self.addr
|
||||||
if self.rtts[-1]:
|
if self.rtts[-1]:
|
||||||
d['rtt'] = "%0.1f" % self.rtts[-1]
|
d['rtt'] = "%0.1f" % self.rtts[-1]
|
||||||
|
elif self.state == Connection.unknown:
|
||||||
|
d['rtt'] = ""
|
||||||
else:
|
else:
|
||||||
d['rtt'] = "?"
|
d['rtt'] = "?"
|
||||||
d['lastbeat'] = self.lastbeat
|
d['lastbeat'] = self.lastbeat
|
||||||
@@ -60,18 +69,29 @@ class Connection:
|
|||||||
d['state'] = self.state
|
d['state'] = self.state
|
||||||
if self.state == Connection.up:
|
if self.state == Connection.up:
|
||||||
d['rttstate'] = d['rtt']
|
d['rttstate'] = d['rtt']
|
||||||
|
elif self.state == Connection.overdue:
|
||||||
|
d['rttstate'] = ''
|
||||||
else:
|
else:
|
||||||
d['rttstate'] = d['state']
|
d['rttstate'] = d['state']
|
||||||
d['statetime'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.statetime))
|
d['statetime'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(self.statetime))
|
||||||
delta = now - self.statetime
|
delta = now - self.statetime
|
||||||
if delta > 86400:
|
|
||||||
d['deltastatetime'] = time.strftime("%d %H:%M:%S", time.gmtime(delta))
|
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:
|
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:
|
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:
|
else:
|
||||||
d['deltastatetime'] = time.strftime("%S", time.gmtime(delta))
|
# d['deltastatetime'] = time.strftime("%S", time.gmtime(delta))
|
||||||
|
d['deltastatetime'] = "%i secs" % (delta)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
d['addr'] = ''
|
d['addr'] = ''
|
||||||
@@ -159,6 +179,8 @@ class Host:
|
|||||||
def statedict(self):
|
def statedict(self):
|
||||||
d = {}
|
d = {}
|
||||||
d['name'] = self.name
|
d['name'] = self.name
|
||||||
|
if self.dyn:
|
||||||
|
d['name'] += "*"
|
||||||
d['dyn'] = str(self.dyn)
|
d['dyn'] = str(self.dyn)
|
||||||
d['ver'] = str(self.cver)
|
d['ver'] = str(self.cver)
|
||||||
d['num'] = self.num
|
d['num'] = self.num
|
||||||
@@ -246,11 +268,13 @@ class Host:
|
|||||||
state = "<b>%s</b>" % self.state
|
state = "<b>%s</b>" % self.state
|
||||||
elif self.state in ["up", "UP"]:
|
elif self.state in ["up", "UP"]:
|
||||||
state = ""
|
state = ""
|
||||||
for x in self.connections.keys():
|
for x in list(self.connections.keys()):
|
||||||
try:
|
try:
|
||||||
state += " %5.1f" % (self.connections[x].rtts[-1])
|
state += " %5.1f" % (self.connections[x].rtts[-1])
|
||||||
except:
|
except:
|
||||||
state += " %5s" % (self.connections[x].rtts[-1])
|
state += " %5s" % (self.connections[x].rtts[-1])
|
||||||
|
elif self.state in ["unknown", "UNKNOWN"]:
|
||||||
|
state = ""
|
||||||
else:
|
else:
|
||||||
state = "%s" % self.state
|
state = "%s" % self.state
|
||||||
return state
|
return state
|
||||||
@@ -261,7 +285,7 @@ class Host:
|
|||||||
if self.upcount > 0:
|
if self.upcount > 0:
|
||||||
# return "(%0.1f%%) %s %s %s " % ((self.doesack * 100.0) / self.upcount, self.doesack, self.upcount, self.hdwcounts)
|
# return "(%0.1f%%) %s %s %s " % ((self.doesack * 100.0) / self.upcount, self.doesack, self.upcount, self.hdwcounts)
|
||||||
r = ""
|
r = ""
|
||||||
for v in xrange(3):
|
for v in range(3):
|
||||||
a,u = self.hdwcounts[v]
|
a,u = self.hdwcounts[v]
|
||||||
if (self.upcount - u) != 0:
|
if (self.upcount - u) != 0:
|
||||||
vs = "%0.0f" % (100.0 - (((self.doesack - a) * 100.0) / (self.upcount - u)))
|
vs = "%0.0f" % (100.0 - (((self.doesack - a) * 100.0) / (self.upcount - u)))
|
||||||
@@ -311,15 +335,19 @@ class Host:
|
|||||||
|
|
||||||
|
|
||||||
def buildhosttable(self, short=False):
|
def buildhosttable(self, short=False):
|
||||||
|
if DEBUG > 1:
|
||||||
|
print("DBG buildhosttable: start")
|
||||||
res = []
|
res = []
|
||||||
res.append('<table id="ntable" class="sortable">')
|
res.append('<table id="ntable" class="sortable">')
|
||||||
res.append(ubHost.htmltable('th', ubHost.headerdict(), short))
|
res.append(ubHost.htmltable('th', ubHost.headerdict(), short))
|
||||||
hosts_sorted = Host.hosts.keys()
|
hosts_sorted = list(Host.hosts.keys())
|
||||||
if len(hosts_sorted):
|
if len(hosts_sorted):
|
||||||
hosts_sorted.sort()
|
hosts_sorted.sort()
|
||||||
for h in hosts_sorted:
|
for h in hosts_sorted:
|
||||||
res.append(ubHost.htmltable('td', Host.hosts[h].statedict(), short))
|
res.append(ubHost.htmltable('td', Host.hosts[h].statedict(), short))
|
||||||
res.append("</table>")
|
res.append("</table>")
|
||||||
|
if DEBUG > 1:
|
||||||
|
print("DBG buildhosttable: %s" % res)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+5
-5
@@ -1,12 +1,12 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import httplib, urllib
|
import http.client, urllib.request, urllib.parse, urllib.error
|
||||||
|
|
||||||
def pushover(msg):
|
def pushover(msg):
|
||||||
conn = httplib.HTTPSConnection("api.pushover.net:443")
|
conn = http.client.HTTPSConnection("api.pushover.net:443")
|
||||||
conn.request("POST", "/1/messages.json",
|
conn.request("POST", "/1/messages.json",
|
||||||
urllib.urlencode({
|
urllib.parse.urlencode({
|
||||||
"token": "ac7NLX2rPjXFareeDgLpXNoDf4iFmf",
|
"token": "ac7NLX2rPjXFareeDgLpXNoDf4iFmf",
|
||||||
"user": "uDhH33UjQQDYtNzJb1ThRiWb9ingGK",
|
"user": "uDhH33UjQQDYtNzJb1ThRiWb9ingGK",
|
||||||
"message": msg,
|
"message": msg,
|
||||||
@@ -18,6 +18,6 @@ def pushover(msg):
|
|||||||
|
|
||||||
v=" ".join(sys.argv[1:])
|
v=" ".join(sys.argv[1:])
|
||||||
if pushover(v):
|
if pushover(v):
|
||||||
print "delivered"
|
print("delivered")
|
||||||
else:
|
else:
|
||||||
print "NOT delivered"
|
print("NOT delivered")
|
||||||
|
|||||||
+6
-6
@@ -1,13 +1,13 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import httplib, urllib
|
import http.client, urllib.request, urllib.parse, urllib.error
|
||||||
import getopt
|
import getopt
|
||||||
|
|
||||||
def pushover(msg, title=""):
|
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",
|
conn.request("POST", "/1/messages.json",
|
||||||
urllib.urlencode({
|
urllib.parse.urlencode({
|
||||||
"token": "aNY2xeYydxzabzihTjb3P2LMHhqhr2",
|
"token": "aNY2xeYydxzabzihTjb3P2LMHhqhr2",
|
||||||
"user": "uDhH33UjQQDYtNzJb1ThRiWb9ingGK",
|
"user": "uDhH33UjQQDYtNzJb1ThRiWb9ingGK",
|
||||||
"message": msg,
|
"message": msg,
|
||||||
@@ -29,7 +29,7 @@ title="Nagios"
|
|||||||
optslist, args = [], []
|
optslist, args = [], []
|
||||||
try:
|
try:
|
||||||
optslist, args = getopt.getopt(sys.argv[1:], 'ht:v')
|
optslist, args = getopt.getopt(sys.argv[1:], 'ht:v')
|
||||||
except getopt.error, cause:
|
except getopt.error as cause:
|
||||||
helpflag=True
|
helpflag=True
|
||||||
|
|
||||||
lastyear=0
|
lastyear=0
|
||||||
@@ -44,6 +44,6 @@ v=" ".join(args)
|
|||||||
rc=pushover(v, title)
|
rc=pushover(v, title)
|
||||||
if verbose:
|
if verbose:
|
||||||
if rc:
|
if rc:
|
||||||
print "delivered"
|
print("delivered")
|
||||||
else:
|
else:
|
||||||
print "NOT delivered"
|
print("NOT delivered")
|
||||||
|
|||||||
Reference in New Issue
Block a user