Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1286)

Unified Diff: scripts/slave/daemonizer.py

Issue 1328623004: Add logic to daemonizer to be able to kill what it daemonizes (Closed) Base URL: https://chromium.googlesource.com/chromium/tools/build.git@master
Patch Set: Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: scripts/slave/daemonizer.py
diff --git a/scripts/slave/daemonizer.py b/scripts/slave/daemonizer.py
index 2a75f98f7f4b9fda82b0ea80f3dfb21a5a1dce7d..6c000a0298f1892a227f4ad54d0982c47a556d34 100755
--- a/scripts/slave/daemonizer.py
+++ b/scripts/slave/daemonizer.py
@@ -12,7 +12,7 @@ USAGE:
daemonizer.py [options] -- <script> [args]
- - options are options to this script. Note, currently there are none!
+ - options are options to this script.
- script is the script to daemonize or run in the background
- args are the arguments that one might want to pass the <script>
"""
@@ -20,12 +20,38 @@ USAGE:
# TODO(sivachandra): Enhance this script by enforcing a protocol of
# communication between the parent (this script) and the daemon script.
+import argparse
+import logging
import os
+import signal
import subprocess
import sys
-
-def daemonize():
+def start(cmd, pid_file_path):
luqui 2015/09/08 18:18:10 seems like this action ought to be called 'restart
bpastene 2015/09/08 20:50:47 Done.
+ # Check for the pid_file to see if the daemon's already running
+ # and restart it if it is
+ if (pid_file_path == None):
luqui 2015/09/08 18:18:10 You don't need parens around if's conditional in p
bpastene 2015/09/08 20:50:47 Done.
+ logging.error('pid_file_path arg must be specified when starting a daemon')
+ return 1
+ try:
+ with open(pid_file_path, 'r') as pid_file:
+ pid = int(pid_file.readline())
+ except (IOError, ValueError):
+ pid = None
+
+ if (pid):
luqui 2015/09/08 18:18:10 no parens
bpastene 2015/09/08 20:50:47 Done.
+ logging.info(
+ "%s pid file already exists, attempting to kill process %d",
+ pid_file_path,
+ pid)
+ try:
+ os.kill(pid, signal.SIGTERM)
+ except (OSError):
luqui 2015/09/08 18:18:10 no parens
bpastene 2015/09/08 20:50:47 Done.
+ logging.exception("Unable to kill old daemon process")
+
+ return daemonize(cmd, pid_file_path)
+
+def daemonize(cmd, pid_file_path):
"""This function is based on the Python recipe provided here:
http://www.jejik.com/articles/2007/02/a_simple_unix_linux_daemon_in_python/
"""
@@ -66,28 +92,62 @@ def daemonize():
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
+ proc = subprocess.Popen(cmd)
-def print_usage(err_msg):
- print >> sys.stderr, err_msg
- sys.exit('Usage: daemonizer.py [options] -- arg0 [argN...]')
+ # write pid to file if applicable
+ if (pid_file_path):
+ try:
+ with open(pid_file_path, 'w+') as pid_file:
luqui 2015/09/08 18:18:10 I think you mean 'w' mode instead of 'w+'.
bpastene 2015/09/08 20:50:47 Done.
+ pid_file.write('%s' % str(proc.pid))
+ except (IOError):
+ logging.exception("Unable to write pid to file")
+ proc.communicate()
luqui 2015/09/08 18:18:10 This will make daemonize block, which is the oppos
bpastene 2015/09/08 20:50:47 Previously, it would do just that, and return the
luqui 2015/09/08 21:15:57 Oh I misunderstood, I missed the fork() above. I
+ return proc.returncode
-def main():
+def stop(pid_file_path):
+ if (pid_file_path == None):
+ logging.error("pid_file_path arg must be specified when stopping a daemon")
+ return 1
try:
- idx = sys.argv.index('--')
- except ValueError:
- print_usage('Separator -- not found')
-
- cmd = sys.argv[idx+1:]
- if not cmd:
- print_usage('arg0 not specified for sub command')
-
- # TODO(sivachandra): When required in the future, use optparse to parse args
- # from sys.argv[:idx]
-
- daemonize()
- return subprocess.call(cmd)
+ with open(pid_file_path) as pid_file:
+ pid = int(pid_file.readline())
+ logging.info('Sending SIGTERM to %d', pid)
+ os.kill(pid, signal.SIGTERM)
+ os.remove(pid_file_path)
+ except (IOError, OSError):
+ logging.exception('Error terminating daemon process')
luqui 2015/09/08 18:18:10 Log the exception here so we have some idea what t
bpastene 2015/09/08 20:50:47 logging.exception() automatically logs the excepti
luqui 2015/09/08 21:15:57 Oh cool :-)
+def main():
+ parser = argparse.ArgumentParser(
+ description='Launch, or shutdown, a daemon process.')
+ parser.add_argument(
+ '--action',
+ default='daemonize',
+ choices=['start','stop','daemonize'],
+ help='What action to take. Both start and stop attempt to write & read '
+ 'the pid to a file so it can kill or restart it, while daemonize simply '
+ 'fires and forgets.')
+ parser.add_argument(
+ '--pid-file-path',
+ type=str,
+ default=None,
+ help='Path of tmp file to store the daemon\'s pid.')
+ parser.add_argument(
+ '--', dest='',
+ required=False,
+ help='Optional delimiter dividing daemonizer options with the command. '
+ 'This is here to ensure it\'s backwards compatible with the previous '
+ 'version of daemonizer.')
+ parser.add_argument('cmd', help='Command (+ args) to daemonize', nargs='*')
+ args = parser.parse_args()
+
+ if (args.action == 'start'):
+ return start(args.cmd, args.pid_file_path)
+ elif (args.action == 'daemonize'):
+ return daemonize(args.cmd, None)
+ elif (args.action == 'stop'):
+ return stop(args.pid_file_path)
if __name__ == '__main__':
sys.exit(main())
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698