#!/usr/bin/python """Two errands the supervisor in run.sh cannot do in shell: ask, and stop. `peers` reports how many network connections the daemon has, as an exit code the shell can branch on. `shutdown` asks the daemon to stop through its own API, which runs doCleanShutdown -- the database is closed rather than cut off. The streak, the cooldown and the restart itself are deliberately not here. This process is short-lived, so a counter would need a file to live in, and then two places would decide one thing. run.sh counts; this only reports. Exit codes are the interface: 0 the daemon answered and has peers 1 the daemon answered and has none (`peers`) or the shutdown was asked for (`shutdown`) 2 the daemon did not answer at all 2 is not 1 on purpose. A daemon whose API is refusing connections is the trapped node of the startup-VACUUM failure, and restarting it neither cures that nor is harmless: it drops the next VACUUM half-done as well. The supervisor must be able to tell "no peers" from "no answer", and only act on the first. """ import json import os import sys import urllib import xmlrpclib # Credentials go into a URL, so they must be percent-encoded: '@' splits the # userinfo, '#' truncates the rest, '/' and ':' change what is parsed as host # and port. healthy_check.py carries the same six lines for the same reason -- # these are one-shot scripts with no package around them to share a module. API_USER = os.getenv('BITMESSAGE_API_USER', 'bitmessage_api_user') API_PASSWORD = os.getenv('BITMESSAGE_API_PASSWORD', 'bitmessage_api_password') API_PORT = os.getenv('BITMESSAGE_API_PORT', '8442') API_LINK = "http://{}:{}@127.0.0.1:{}/".format( urllib.quote(API_USER, safe=''), urllib.quote(API_PASSWORD, safe=''), API_PORT) NO_ANSWER = 2 def peers(api): """How many peers the daemon holds, printed for the container log.""" count = json.loads(api.clientStatus())['networkConnections'] print "networkConnections:", count return 0 if count > 0 else 1 def shutdown(api): """Ask the daemon to stop itself cleanly (api.py: HandleShutdown).""" api.shutdown() print "shutdown requested" return 1 COMMANDS = {'peers': peers, 'shutdown': shutdown} def main(argv): if len(argv) != 2 or argv[1] not in COMMANDS: print >> sys.stderr, "usage: watchdog.py peers|shutdown" return NO_ANSWER try: return COMMANDS[argv[1]](xmlrpclib.ServerProxy(API_LINK)) except Exception as exc: # the API is down, or answering something else print "no answer from the daemon:", exc return NO_ANSWER if __name__ == '__main__': sys.exit(main(sys.argv))