Use os.rename() in async_wrapper

Because the async_status module will read from the same file that
the async_wrapper module is writing, it's possible that the file
may not be fully synced during a read, causing spurious failures.
Use a temp file to do an atomic operation on the file. We can't
use atomic_move() here as that doesn't work properly under async.

Also, let's not read concurrently from the same file the subprocess
is writing to. Instead, capture stdout/stderr via PIPE and write to
the file to avoid nasty races.
This commit is contained in:
David Shrewsbury 2016-06-23 17:14:59 -04:00
parent 4fe583e29b
commit 4e239f6ce0

View file

@ -72,19 +72,23 @@ def daemonize_self():
def _run_module(wrapped_cmd, jid, job_path):
jobfile = open(job_path, "w")
tmp_job_path = job_path + ".tmp"
jobfile = open(tmp_job_path, "w")
jobfile.write(json.dumps({ "started" : 1, "ansible_job_id" : jid }))
jobfile.close()
jobfile = open(job_path, "w")
os.rename(tmp_job_path, job_path)
jobfile = open(tmp_job_path, "w")
result = {}
outdata = ''
try:
cmd = shlex.split(wrapped_cmd)
script = subprocess.Popen(cmd, shell=False, stdin=None, stdout=jobfile, stderr=jobfile)
script.communicate()
outdata = file(job_path).read()
script = subprocess.Popen(cmd, shell=False, stdin=None, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(outdata, stderr) = script.communicate()
result = json.loads(outdata)
if stderr:
result['stderr'] = stderr
jobfile.write(json.dumps(result))
except (OSError, IOError):
e = sys.exc_info()[1]
@ -95,6 +99,7 @@ def _run_module(wrapped_cmd, jid, job_path):
}
result['ansible_job_id'] = jid
jobfile.write(json.dumps(result))
except:
result = {
"failed" : 1,
@ -104,7 +109,9 @@ def _run_module(wrapped_cmd, jid, job_path):
}
result['ansible_job_id'] = jid
jobfile.write(json.dumps(result))
jobfile.close()
os.rename(tmp_job_path, job_path)
####################