remove dependencies on daemon and lockfile

This commit is contained in:
2016-05-18 10:33:37 -04:00
parent c3eb0f03fc
commit e4b3478dff
+80 -111
View File
@@ -17,48 +17,13 @@ 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
PIDFILE = '/tmp/hbc.pid' PIDFILE = '/tmp/hbc.pid'
VER = 3 VER = 4
MAXRECV = 32767 MAXRECV = 32767
running = True running = True
@@ -66,8 +31,8 @@ dorestart = False
warned1 = False warned1 = False
class NullDevice: class NullDevice:
def write(self, s): def write(self, s):
pass pass
class Conn: class Conn:
@@ -84,7 +49,7 @@ class Conn:
self.rtts = [0] self.rtts = [0]
self.sock=socket.socket(af, socket.SOCK_DGRAM) self.sock=socket.socket(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
@@ -175,8 +140,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
@@ -185,7 +151,7 @@ def createConnections(hosts):
for host in hosts: for host in hosts:
if verbose: log("createConnections for %s" % host) if verbose: log("createConnections for %s" % host)
try: try:
rs=socket.getaddrinfo(host, hb_port, 0, 0, socket.SOL_UDP) rs=socket.getaddrinfo(host, hb_port, 0, 0, socket.SOL_UDP)
except socket.gaierror: except socket.gaierror:
logm = '%s hbc died: \n%s' % ('createConnections', traceback.format_exc()) logm = '%s hbc died: \n%s' % ('createConnections', traceback.format_exc())
if verbose: log(logm) if verbose: log(logm)
@@ -197,7 +163,7 @@ 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]
@@ -226,7 +192,7 @@ def doupdate(conn, msgDict):
code = msgDict['code'].decode('base64') code = msgDict['code'].decode('base64')
csum = msgDict['csum'] csum = msgDict['csum']
except: except:
fail = "csum/code missing" fail = "csum/code missing"
if not fail: if not fail:
fail = doupdateone(code, csum) fail = doupdateone(code, csum)
@@ -244,10 +210,10 @@ def doupdateone(code, csum):
m.update(code) m.update(code)
icsum = m.hexdigest() icsum = m.hexdigest()
if icsum != csum: if icsum != csum:
return "checksum error" return "checksum error"
fn = sys.argv[0] fn = sys.argv[0]
ofn = "%.sav" % fn ofn = "%.sav" % fn
try: try:
shutil.copy2(fn, ofn) shutil.copy2(fn, ofn)
except Exception as e: except Exception as e:
@@ -264,7 +230,9 @@ 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)
@@ -310,14 +278,14 @@ def process():
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['ID'] == "ACK":
conns[conn].ack(msgDict) conns[conn].ack(msgDict)
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":
doexec(conn, msgDict['cmd']) doexec(conn, msgDict['cmd'])
else: else:
doexec(conn, data) # deprecated until no more VER - hbc doexec(conn, data) # deprecated until no more VER - hbc
@@ -341,7 +309,7 @@ def cleanup():
global running global running
if verbose: log('cleanup') if verbose: log('cleanup')
running = False running = False
for conn in conns: for conn in conns:
msg={'shutdown': 1, 'acks': conns[conn].ackcount} msg={'shutdown': 1, 'acks': conns[conn].ackcount}
conns[conn].sendto(msg) conns[conn].sendto(msg)
conns[conn].close() conns[conn].close()
@@ -350,15 +318,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, 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, 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 = file(stdin, 'r')
so = file(stdout, 'a+')
se = file(stderr, 'a+', 0)
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={}
@@ -368,9 +380,9 @@ cmdargs = []
try: try:
optlist, args = getopt.getopt(sys.argv[1:], 'bc:dhm:v') optlist, args = getopt.getopt(sys.argv[1:], 'bc:dhm:v')
except: except:
helpflag=True helpflag=True
for o,a in optlist: for o,a in optlist:
if o == '-b': if o == '-b':
@@ -442,7 +454,7 @@ 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':
@@ -487,7 +499,7 @@ if verbose:
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)
@@ -497,63 +509,20 @@ if msgonly:
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) running = True
try: try:
opid = pidfile.read_pid() process()
except: except:
opid = None syslogtrace('process')
if verbose: print "err: process exit: %s" % e
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
try:
process()
except:
syslogtrace('process')
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: