@ -18,6 +18,7 @@ import traceback
import signal
import time
import syslog
import multiprocessing
from ansible . module_utils . _text import to_text
@ -26,6 +27,9 @@ PY3 = sys.version_info[0] == 3
syslog . openlog ( ' ansible- %s ' % os . path . basename ( __file__ ) )
syslog . syslog ( syslog . LOG_NOTICE , ' Invoked with %s ' % " " . join ( sys . argv [ 1 : ] ) )
# pipe for communication between forked process and parent
ipc_watcher , ipc_notifier = multiprocessing . Pipe ( )
def notice ( msg ) :
syslog . syslog ( syslog . LOG_NOTICE , msg )
@ -129,6 +133,11 @@ def _run_module(wrapped_cmd, jid, job_path):
jobfile = open ( tmp_job_path , " w " )
result = { }
# signal grandchild process started and isolated from being terminated
# by the connection being closed sending a signal to the job group
ipc_notifier . send ( True )
ipc_notifier . close ( )
outdata = ' '
filtered_outdata = ' '
stderr = ' '
@ -140,6 +149,7 @@ def _run_module(wrapped_cmd, jid, job_path):
if interpreter :
cmd = interpreter + cmd
script = subprocess . Popen ( cmd , shell = False , stdin = None , stdout = subprocess . PIPE , stderr = subprocess . PIPE )
( outdata , stderr ) = script . communicate ( )
if PY3 :
outdata = outdata . decode ( ' utf-8 ' , ' surrogateescape ' )
@ -241,15 +251,32 @@ if __name__ == '__main__':
# to initialize PRIOR to ansible trying to clean up the launch directory (and argsfile)
# this probably could be done with some IPC later. Modules should always read
# the argsfile at the very first start of their execution anyway
# close off notifier handle in grandparent, probably unnecessary as
# this process doesn't hang around long enough
ipc_notifier . close ( )
# allow waiting up to 2.5 seconds in total should be long enough for worst
# loaded environment in practice.
retries = 25
while retries > 0 :
if ipc_watcher . poll ( 0.1 ) :
break
else :
retries = retries - 1
continue
notice ( " Return async_wrapper task started. " )
print ( json . dumps ( { " started " : 1 , " finished " : 0 , " ansible_job_id " : jid , " results_file " : job_path ,
" _ansible_suppress_tmpdir_delete " : not preserve_tmp } ) )
sys . stdout . flush ( )
time . sleep ( 1 )
sys . exit ( 0 )
else :
# The actual wrapper process
# close off the receiving end of the pipe from child process
ipc_watcher . close ( )
# Daemonize, so we keep on running
daemonize_self ( )
@ -258,6 +285,10 @@ if __name__ == '__main__':
sub_pid = os . fork ( )
if sub_pid :
# close off inherited pipe handles
ipc_watcher . close ( )
ipc_notifier . close ( )
# the parent stops the process after the time limit
remaining = int ( time_limit )