Fix async to use the new argfiles method (wrapping brain around rock, really must write module development guide)

pull/70/head
Michael DeHaan 13 years ago
parent aeea46678d
commit 696b67f935

@ -40,6 +40,9 @@ import StringIO
# FIXME: stop importing *, use as utils/errors # FIXME: stop importing *, use as utils/errors
from ansible.utils import * from ansible.utils import *
from ansible.errors import * from ansible.errors import *
# should be True except in debug
CLEANUP_FILES = True
################################################ ################################################
@ -221,7 +224,8 @@ class Runner(object):
for filename in files: for filename in files:
if not filename.startswith('/tmp/'): if not filename.startswith('/tmp/'):
raise Exception("not going to happen") raise Exception("not going to happen")
self._exec_command(conn, "rm -rf %s" % filename) if CLEANUP_FILES:
self._exec_command(conn, "rm -rf %s" % filename)
# ***************************************************** # *****************************************************
@ -255,13 +259,15 @@ class Runner(object):
args_fo.flush() args_fo.flush()
args_fo.close() args_fo.close()
args_remote = os.path.join(tmp, 'arguments') args_remote = os.path.join(tmp, 'arguments')
self._transfer_file(conn, args_file, 'arguments') self._transfer_file(conn, args_file, args_remote)
os.unlink(args_file) if CLEANUP_FILES:
os.unlink(args_file)
return args_remote return args_remote
# ***************************************************** # *****************************************************
def _execute_module(self, conn, tmp, remote_module_path, module_args): def _execute_module(self, conn, tmp, remote_module_path, module_args,
async_jid=None, async_module=None, async_limit=None):
''' '''
runs a module that has already been transferred, but first runs a module that has already been transferred, but first
modifies the command using setup_cache variables (see playbook) modifies the command using setup_cache variables (see playbook)
@ -286,7 +292,11 @@ class Runner(object):
args = template.render(inject_vars) args = template.render(inject_vars)
argsfile = self._transfer_argsfile(conn, tmp, args) argsfile = self._transfer_argsfile(conn, tmp, args)
cmd = "%s %s" % (remote_module_path, 'arguments') if async_jid is None:
cmd = "%s %s" % (remote_module_path, argsfile)
else:
args = [str(x) for x in [remote_module_path, async_jid, async_limit, async_module, argsfile]]
cmd = " ".join(args)
result = self._exec_command(conn, cmd) result = self._exec_command(conn, cmd)
return result return result
@ -324,10 +334,11 @@ class Runner(object):
async = self._transfer_module(conn, tmp, 'async_wrapper') async = self._transfer_module(conn, tmp, 'async_wrapper')
module = self._transfer_module(conn, tmp, self.module_name) module = self._transfer_module(conn, tmp, self.module_name)
new_args = [] result = self._execute_module(conn, tmp, async, self.module_args,
new_args = [ self.generated_jid, self.background, module ] async_module=module,
new_args.extend(self.module_args) async_jid=self.generated_jid,
result = self._execute_module(conn, tmp, async, new_args) async_limit=self.background
)
return self._return_from_module(conn, host, result) return self._return_from_module(conn, host, result)
# ***************************************************** # *****************************************************
@ -454,8 +465,7 @@ class Runner(object):
msg = '%s: %s' % (self.module_name, cmd) msg = '%s: %s' % (self.module_name, cmd)
self.remote_log(conn, msg) self.remote_log(conn, msg)
stdin, stdout, stderr = conn.exec_command(cmd) stdin, stdout, stderr = conn.exec_command(cmd)
results = "\n".join(stdout.readlines()) return "\n".join(stdout.readlines())
return results
# ***************************************************** # *****************************************************

@ -30,12 +30,12 @@ import datetime
import traceback import traceback
# =========================================== # ===========================================
# convert arguments of form a=b c=d
# to a dictionary
# FIXME: make more idiomatic
args = " ".join(sys.argv[1:]) # FIXME: better error handling
items = shlex.split(args)
argsfile = sys.argv[1]
items = shlex.split(file(argsfile).read())
params = {} params = {}
for x in items: for x in items:
(k, v) = x.split("=") (k, v) = x.split("=")

@ -66,16 +66,15 @@ def daemonize_self():
if len(sys.argv) < 3: if len(sys.argv) < 3:
print json.dumps({ print json.dumps({
"failed" : True, "failed" : True,
"msg" : "usage: async_wrapper <jid> <module_script> <time_limit> <args>. Humans, do not call directly!" "msg" : "usage: async_wrapper <jid> <time_limit> <modulescript> <argsfile>. Humans, do not call directly!"
}) })
sys.exit(1) sys.exit(1)
jid = sys.argv[1] jid = sys.argv[1]
time_limit = sys.argv[2] time_limit = sys.argv[2]
wrapped_module = sys.argv[3] wrapped_module = sys.argv[3]
args = sys.argv[4:] argsfile = sys.argv[4]
cmd = "%s %s" % (wrapped_module, argsfile)
cmd = "%s %s" % (wrapped_module, " ".join(args))
# setup logging directory # setup logging directory
logdir = os.path.expanduser("~/.ansible_async") logdir = os.path.expanduser("~/.ansible_async")
@ -92,20 +91,20 @@ if not os.path.exists(logdir):
def _run_command(wrapped_cmd, jid, log_path): def _run_command(wrapped_cmd, jid, log_path):
print "RUNNING: %s" % wrapped_cmd
logfile = open(log_path, "w") logfile = open(log_path, "w")
logfile.write(json.dumps({ "started" : 1, "ansible_job_id" : jid })) logfile.write(json.dumps({ "started" : 1, "ansible_job_id" : jid }))
logfile.close() logfile.close()
logfile = open(log_path, "w") logfile = open(log_path, "w")
result = {} result = {}
outdata = ''
try: try:
cmd = shlex.split(wrapped_cmd) cmd = shlex.split(wrapped_cmd)
script = subprocess.Popen(cmd, shell=False, script = subprocess.Popen(cmd, shell=False,
stdin=None, stdout=logfile, stderr=logfile) stdin=None, stdout=logfile, stderr=logfile)
script.communicate() script.communicate()
#result = json.loads(out) outdata = file(log_path).read()
result = json.loads(file(log_path).read()) result = json.loads(outdata)
except (OSError, IOError), e: except (OSError, IOError), e:
result = { result = {
@ -119,6 +118,7 @@ def _run_command(wrapped_cmd, jid, log_path):
result = { result = {
"failed" : 1, "failed" : 1,
"cmd" : wrapped_cmd, "cmd" : wrapped_cmd,
"data" : outdata, # temporary debug only
"msg" : traceback.format_exc() "msg" : traceback.format_exc()
} }
result['ansible_job_id'] = jid result['ansible_job_id'] = jid

@ -30,32 +30,10 @@ import traceback
import shlex import shlex
import os import os
if len(sys.argv) == 1:
print json.dumps({
"failed" : True,
"msg" : "the command module requires arguments (-a)"
})
sys.exit(1)
argfile = sys.argv[1] argfile = sys.argv[1]
if not os.path.exists(argfile):
print json.dumps({
"failed" : True,
"msg" : "Argument file not found"
})
sys.exit(1)
args = open(argfile, 'r').read() args = open(argfile, 'r').read()
args = shlex.split(args) args = shlex.split(args)
if not len(args):
print json.dumps({
"failed" : True,
"msg" : "the command module requires arguments (-a)"
})
sys.exit(1)
startd = datetime.datetime.now() startd = datetime.datetime.now()
try: try:

@ -159,14 +159,18 @@ class TestRunner(unittest.TestCase):
def test_async(self): def test_async(self):
# test async launch and job status # test async launch and job status
# of any particular module # of any particular module
print "firing command..."
result = self._run('command', [ "/bin/sleep", "3" ], background=20) result = self._run('command', [ "/bin/sleep", "3" ], background=20)
print "back..."
assert 'ansible_job_id' in result assert 'ansible_job_id' in result
assert 'started' in result assert 'started' in result
jid = result['ansible_job_id'] jid = result['ansible_job_id']
# no real chance of this op taking a while, but whatever # no real chance of this op taking a while, but whatever
time.sleep(5) time.sleep(5)
# CLI will abstract this, but this is how it works internally # CLI will abstract this, but this is how it works internally
print "checking status..."
result = self._run('async_status', [ "jid=%s" % jid ]) result = self._run('async_status', [ "jid=%s" % jid ])
print "back..."
# TODO: would be nice to have tests for supervisory process # TODO: would be nice to have tests for supervisory process
# killing job after X seconds # killing job after X seconds
assert 'finished' in result assert 'finished' in result

Loading…
Cancel
Save