1 # Utility library for spawning remote asynchronous tasks
2 from nepi.util import server
7 Special value that when given to remote_spawn in stderr causes stderr to
8 redirect to whatever stdout was redirected to.
13 Process is still running
23 Process hasn't started running yet (this should be very rare)
26 def remote_spawn(command, pidfile, stdout='/dev/null', stderr=STDOUT, stdin='/dev/null', home=None, create_home=False, sudo=False,
27 host = None, port = None, user = None, agent = None,
28 ident_key = None, server_key = None,
31 Spawn a remote command such that it will continue working asynchronously.
34 command: the command to run - it should be a single line.
36 pidfile: path of a (ideally unique to this task) pidfile for tracking the process.
38 stdout: path of a file to redirect standard output to - must be a string.
40 stderr: path of a file to redirect standard error to - string or the special STDOUT value
41 to redirect to the same file stdout was redirected to. Defaults to STDOUT.
42 stdin: path of a file with input to be piped into the command's standard input
44 home: path of a folder to use as working directory - should exist, unless you specify create_home
46 create_home: if True, the home folder will be created first with mkdir -p
48 sudo: whether the command needs to be executed as root
50 host/port/user/agent/ident_key: see nepi.util.server.popen_ssh_command
53 (stdout, stderr), process
55 Of the spawning process, which only captures errors at spawning time.
56 Usually only useful for diagnostics.
58 # Start process in a "daemonized" way, using nohup and heavy
59 # stdin/out redirection to avoid connection issues
65 daemon_command = '{ { %(command)s > %(stdout)s 2>%(stderr)s < %(stdin)s & } ; echo $! 1 > %(pidfile)s ; }' % {
67 'pidfile' : server.shell_escape(pidfile),
74 cmd = "%(create)s%(gohome)s rm -f %(pidfile)s ; %(sudo)s nohup bash -c %(command)s " % {
75 'command' : server.shell_escape(daemon_command),
77 'sudo' : 'sudo -S' if sudo else '',
79 'pidfile' : server.shell_escape(pidfile),
80 'gohome' : 'cd %s ; ' % (server.shell_escape(home),) if home else '',
81 'create' : 'mkdir -p %s ; ' % (server.shell_escape,) if create_home else '',
83 (out,err),proc = server.popen_ssh_command(
89 ident_key = ident_key,
90 server_key = server_key,
95 raise RuntimeError, "Failed to set up application: %s %s" % (out,err,)
100 def remote_check_pid(pidfile,
101 host = None, port = None, user = None, agent = None,
102 ident_key = None, server_key = None):
104 Check the pidfile of a process spawned with remote_spawn.
107 pidfile: the pidfile passed to remote_span
109 host/port/user/agent/ident_key: see nepi.util.server.popen_ssh_command
113 A (pid, ppid) tuple useful for calling remote_status and remote_kill,
114 or None if the pidfile isn't valid yet (maybe the process is still starting).
117 (out,err),proc = server.popen_ssh_command(
118 "cat %(pidfile)s" % {
125 ident_key = ident_key,
126 server_key = server_key
134 return map(int,out.strip().split(' ',1))
136 # Ignore, many ways to fail that don't matter that much
141 def remote_status(pid, ppid,
142 host = None, port = None, user = None, agent = None,
143 ident_key = None, server_key = None):
145 Check the status of a process spawned with remote_spawn.
148 pid/ppid: pid and parent-pid of the spawned process. See remote_check_pid
150 host/port/user/agent/ident_key: see nepi.util.server.popen_ssh_command
154 One of NOT_STARTED, RUNNING, FINISHED
157 (out,err),proc = server.popen_ssh_command(
158 "ps --ppid %(ppid)d -o pid | grep -c %(pid)d ; true" % {
166 ident_key = ident_key,
167 server_key = server_key
176 status = bool(int(out.strip()))
178 # Ignore, many ways to fail that don't matter that much
180 return RUNNING if status else FINISHED
184 def remote_kill(pid, ppid, sudo = False,
185 host = None, port = None, user = None, agent = None,
186 ident_key = None, server_key = None,
189 Kill a process spawned with remote_spawn.
191 First tries a SIGTERM, and if the process does not end in 10 seconds,
195 pid/ppid: pid and parent-pid of the spawned process. See remote_check_pid
197 sudo: whether the command was run with sudo - careful killing like this.
199 host/port/user/agent/ident_key: see nepi.util.server.popen_ssh_command
203 Nothing, should have killed the process
207 %(sudo)s kill -- -%(pid)d || /bin/true
208 %(sudo)s kill %(pid)d || /bin/true
209 for x in 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 ; do
211 if [ `ps --ppid %(ppid)d -o pid | grep -c %(pid)d` == '0' ]; then
214 %(sudo)s kill -- -%(pid)d || /bin/true
215 %(sudo)s kill %(pid)d || /bin/true
219 if [ `ps --ppid %(ppid)d -o pid | grep -c %(pid)d` != '0' ]; then
220 %(sudo)s kill -9 -- -%(pid)d || /bin/true
221 %(sudo)s kill -9 %(pid)d || /bin/true
225 cmd = "( %s ) >/dev/null 2>/dev/null </dev/null &" % (cmd,)
227 (out,err),proc = server.popen_ssh_command(
231 'sudo' : 'sudo -S' if sudo else ''
237 ident_key = ident_key,
238 server_key = server_key
241 # wait, don't leave zombies around