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,)
99 def remote_check_pid(pidfile,
100 host = None, port = None, user = None, agent = None,
101 ident_key = None, server_key = None):
103 Check the pidfile of a process spawned with remote_spawn.
106 pidfile: the pidfile passed to remote_span
108 host/port/user/agent/ident_key: see nepi.util.server.popen_ssh_command
112 A (pid, ppid) tuple useful for calling remote_status and remote_kill,
113 or None if the pidfile isn't valid yet (maybe the process is still starting).
116 (out,err),proc = server.popen_ssh_command(
117 "cat %(pidfile)s" % {
124 ident_key = ident_key,
125 server_key = server_key
133 return map(int,out.strip().split(' ',1))
135 # Ignore, many ways to fail that don't matter that much
139 def remote_status(pid, ppid,
140 host = None, port = None, user = None, agent = None,
141 ident_key = None, server_key = None):
143 Check the status of a process spawned with remote_spawn.
146 pid/ppid: pid and parent-pid of the spawned process. See remote_check_pid
148 host/port/user/agent/ident_key: see nepi.util.server.popen_ssh_command
152 One of NOT_STARTED, RUNNING, FINISHED
155 (out,err),proc = server.popen_ssh_command(
156 "ps --ppid %(ppid)d -o pid | grep -c %(pid)d ; true" % {
164 ident_key = ident_key,
165 server_key = server_key
174 status = bool(int(out.strip()))
176 # Ignore, many ways to fail that don't matter that much
178 return RUNNING if status else FINISHED
181 def remote_kill(pid, ppid, sudo = False,
182 host = None, port = None, user = None, agent = None,
183 ident_key = None, server_key = None,
186 Kill a process spawned with remote_spawn.
188 First tries a SIGTERM, and if the process does not end in 10 seconds,
192 pid/ppid: pid and parent-pid of the spawned process. See remote_check_pid
194 sudo: whether the command was run with sudo - careful killing like this.
196 host/port/user/agent/ident_key: see nepi.util.server.popen_ssh_command
200 Nothing, should have killed the process
204 %(sudo)s kill %(pid)d
205 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
207 if [ `ps --ppid %(ppid)d -o pid | grep -c %(pid)d` == '0' ]; then
212 if [ `ps --ppid %(ppid)d -o pid | grep -c %(pid)d` != '0' ]; then
213 %(sudo)s kill -9 -- -%(pid)d || /bin/true
214 %(sudo)s kill -9 %(pid)d || /bin/true
218 cmd = "( %s ) >/dev/null 2>/dev/null </dev/null &" % (cmd,)
220 (out,err),proc = server.popen_ssh_command(
224 'sudo' : 'sudo -S' if sudo else ''
230 ident_key = ident_key,
231 server_key = server_key
234 # wait, don't leave zombies around