Add a debug attribute to Runner/Playbook.
This prints the stderr of the executed modules on local stderr. Most methods on Runner now return a fourth "err" parameter.
This commit is contained in:
parent
6275e57718
commit
74ae4b29ad
3 changed files with 50 additions and 31 deletions
|
@ -19,6 +19,7 @@
|
|||
#######################################################
|
||||
|
||||
import utils
|
||||
import sys
|
||||
|
||||
#######################################################
|
||||
|
||||
|
@ -146,6 +147,9 @@ class PlaybookRunnerCallbacks(DefaultRunnerCallbacks):
|
|||
else:
|
||||
print "ok: [%s] => %s\n" % (host, invocation)
|
||||
|
||||
def on_error(self, host, err):
|
||||
print >>sys.stderr, "stderr: [%s] => %s\n" % (host, err)
|
||||
|
||||
def on_skipped(self, host):
|
||||
print "skipping: [%s]\n" % host
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ class PlayBook(object):
|
|||
remote_port = C.DEFAULT_REMOTE_PORT,
|
||||
override_hosts = None,
|
||||
extra_vars = None,
|
||||
debug = False,
|
||||
verbose = False,
|
||||
callbacks = None,
|
||||
runner_callbacks = None,
|
||||
|
@ -72,6 +73,7 @@ class PlayBook(object):
|
|||
self.remote_user = remote_user
|
||||
self.remote_pass = remote_pass
|
||||
self.remote_port = remote_port
|
||||
self.debug = debug
|
||||
self.verbose = verbose
|
||||
self.callbacks = callbacks
|
||||
self.runner_callbacks = runner_callbacks
|
||||
|
@ -270,7 +272,7 @@ class PlayBook(object):
|
|||
remote_port=self.remote_port,
|
||||
setup_cache=SETUP_CACHE, basedir=self.basedir,
|
||||
conditional=only_if, callbacks=self.runner_callbacks,
|
||||
extra_vars=self.extra_vars, sudo=sudo
|
||||
extra_vars=self.extra_vars, debug=self.debug, sudo=sudo
|
||||
)
|
||||
|
||||
if async_seconds == 0:
|
||||
|
|
|
@ -74,7 +74,7 @@ class Runner(object):
|
|||
remote_user=C.DEFAULT_REMOTE_USER, remote_pass=C.DEFAULT_REMOTE_PASS,
|
||||
remote_port=C.DEFAULT_REMOTE_PORT, background=0, basedir=None, setup_cache=None,
|
||||
transport='paramiko', conditional='True', groups={}, callbacks=None, verbose=False,
|
||||
sudo=False, extra_vars=None):
|
||||
debug=False, sudo=False, extra_vars=None):
|
||||
|
||||
if setup_cache is None:
|
||||
setup_cache = {}
|
||||
|
@ -103,6 +103,7 @@ class Runner(object):
|
|||
self.module_args = module_args
|
||||
self.extra_vars = extra_vars
|
||||
self.timeout = timeout
|
||||
self.debug = debug
|
||||
self.verbose = verbose
|
||||
self.remote_user = remote_user
|
||||
self.remote_pass = remote_pass
|
||||
|
@ -227,16 +228,18 @@ class Runner(object):
|
|||
|
||||
# *****************************************************
|
||||
|
||||
def _return_from_module(self, conn, host, result, executed=None):
|
||||
def _return_from_module(self, conn, host, result, err, executed=None):
|
||||
''' helper function to handle JSON parsing of results '''
|
||||
|
||||
try:
|
||||
result = utils.parse_json(result)
|
||||
if executed is not None:
|
||||
result['invocation'] = executed
|
||||
return [ host, True, result ]
|
||||
if 'stderr' in result:
|
||||
err="%s%s"%(err,result['stderr'])
|
||||
return [host, True, result, err]
|
||||
except Exception, e:
|
||||
return [ host, False, "%s/%s/%s" % (str(e), result, executed) ]
|
||||
return [host, False, "%s/%s/%s" % (str(e), result, executed), err]
|
||||
|
||||
# *****************************************************
|
||||
|
||||
|
@ -337,7 +340,7 @@ class Runner(object):
|
|||
inject = self.setup_cache.get(conn.host,{})
|
||||
conditional = utils.double_template(self.conditional, inject)
|
||||
if not eval(conditional):
|
||||
return [ utils.smjson(dict(skipped=True)), 'skipped' ]
|
||||
return [ utils.smjson(dict(skipped=True)), None, 'skipped' ]
|
||||
|
||||
if Runner._external_variable_script is not None:
|
||||
self._add_variables_from_script(conn, inject)
|
||||
|
@ -354,7 +357,8 @@ class Runner(object):
|
|||
cmd = "%s %s" % (remote_module_path, argsfile)
|
||||
else:
|
||||
cmd = " ".join([str(x) for x in [remote_module_path, async_jid, async_limit, async_module, argsfile]])
|
||||
return [ self._exec_command(conn, cmd, tmp, sudoable=True), client_executed_str ]
|
||||
res, err = self._exec_command(conn, cmd, tmp, sudoable=True)
|
||||
return ( res, err, client_executed_str )
|
||||
|
||||
# *****************************************************
|
||||
|
||||
|
@ -387,12 +391,12 @@ class Runner(object):
|
|||
self.module_args += " #USE_SHELL"
|
||||
|
||||
module = self._transfer_module(conn, tmp, module_name)
|
||||
(result, executed) = self._execute_module(conn, tmp, module, self.module_args)
|
||||
(result, err, executed) = self._execute_module(conn, tmp, module, self.module_args)
|
||||
|
||||
if module_name == 'setup':
|
||||
self._add_result_to_setup_cache(conn, result)
|
||||
|
||||
return self._return_from_module(conn, host, result, executed)
|
||||
return self._return_from_module(conn, host, result, err, executed)
|
||||
|
||||
# *****************************************************
|
||||
|
||||
|
@ -408,13 +412,13 @@ class Runner(object):
|
|||
|
||||
async = self._transfer_module(conn, tmp, 'async_wrapper')
|
||||
module = self._transfer_module(conn, tmp, module_name)
|
||||
(result, executed) = self._execute_module(conn, tmp, async, module_args,
|
||||
(result, err, executed) = self._execute_module(conn, tmp, async, module_args,
|
||||
async_module=module,
|
||||
async_jid=self.generated_jid,
|
||||
async_limit=self.background
|
||||
)
|
||||
|
||||
return self._return_from_module(conn, host, result, executed)
|
||||
return self._return_from_module(conn, host, result, err, executed)
|
||||
|
||||
# *****************************************************
|
||||
|
||||
|
@ -436,30 +440,30 @@ class Runner(object):
|
|||
|
||||
# run the copy module
|
||||
args = "src=%s dest=%s" % (tmp_src, dest)
|
||||
(result1, executed) = self._execute_module(conn, tmp, module, args)
|
||||
(host, ok, data) = self._return_from_module(conn, host, result1, executed)
|
||||
(result1, err, executed) = self._execute_module(conn, tmp, module, args)
|
||||
(host, ok, data, err) = self._return_from_module(conn, host, result1, err, executed)
|
||||
|
||||
if ok:
|
||||
return self._chain_file_module(conn, tmp, data, options, executed)
|
||||
return self._chain_file_module(conn, tmp, data, err, options, executed)
|
||||
else:
|
||||
return (host, ok, data)
|
||||
return (host, ok, data, err)
|
||||
|
||||
# *****************************************************
|
||||
|
||||
def _chain_file_module(self, conn, tmp, data, options, executed):
|
||||
def _chain_file_module(self, conn, tmp, data, err, options, executed):
|
||||
''' handles changing file attribs after copy/template operations '''
|
||||
|
||||
old_changed = data.get('changed', False)
|
||||
module = self._transfer_module(conn, tmp, 'file')
|
||||
args = ' '.join([ "%s=%s" % (k,v) for (k,v) in options.items() ])
|
||||
(result2, executed2) = self._execute_module(conn, tmp, module, args)
|
||||
results2 = self._return_from_module(conn, conn.host, result2, executed)
|
||||
(host, ok, data2) = results2
|
||||
(result2, err2, executed2) = self._execute_module(conn, tmp, module, args)
|
||||
results2 = self._return_from_module(conn, conn.host, result2, err2, executed)
|
||||
(host, ok, data2, err2) = results2
|
||||
new_changed = data2.get('changed', False)
|
||||
data.update(data2)
|
||||
if old_changed or new_changed:
|
||||
data['changed'] = True
|
||||
return (host, ok, data)
|
||||
return (host, ok, data, "%s%s"%(err,err2))
|
||||
|
||||
# *****************************************************
|
||||
|
||||
|
@ -487,19 +491,19 @@ class Runner(object):
|
|||
|
||||
# run the template module
|
||||
args = "src=%s dest=%s metadata=%s" % (temppath, dest, metadata)
|
||||
(result1, executed) = self._execute_module(conn, tmp, template_module, args)
|
||||
(host, ok, data) = self._return_from_module(conn, host, result1, executed)
|
||||
(result1, err, executed) = self._execute_module(conn, tmp, template_module, args)
|
||||
(host, ok, data, err) = self._return_from_module(conn, host, result1, err, executed)
|
||||
|
||||
if ok:
|
||||
return self._chain_file_module(conn, tmp, data, options, executed)
|
||||
return self._chain_file_module(conn, tmp, data, err, options, executed)
|
||||
else:
|
||||
return (host, ok, data)
|
||||
return (host, ok, data, err)
|
||||
|
||||
# *****************************************************
|
||||
|
||||
def _executor(self, host):
|
||||
try:
|
||||
(host, ok, data) = self._executor_internal(host)
|
||||
(host, ok, data, err) = self._executor_internal(host)
|
||||
if not ok:
|
||||
self.callbacks.on_unreachable(host, data)
|
||||
return (host, ok, data)
|
||||
|
@ -517,7 +521,7 @@ class Runner(object):
|
|||
|
||||
ok, conn = self._connect(host)
|
||||
if not ok:
|
||||
return [ host, False, conn ]
|
||||
return [ host, False, conn , None]
|
||||
|
||||
cache = self.setup_cache.get(host, {})
|
||||
module_name = utils.template(self.module_name, cache)
|
||||
|
@ -538,7 +542,7 @@ class Runner(object):
|
|||
self._delete_remote_files(conn, tmp)
|
||||
conn.close()
|
||||
|
||||
(host, connect_ok, data) = result
|
||||
(host, connect_ok, data, err) = result
|
||||
if not connect_ok:
|
||||
self.callbacks.on_unreachable(host, data)
|
||||
else:
|
||||
|
@ -549,6 +553,9 @@ class Runner(object):
|
|||
else:
|
||||
self.callbacks.on_ok(host, data)
|
||||
|
||||
if self.debug and err:
|
||||
self.callbacks.on_error(host, err)
|
||||
|
||||
return result
|
||||
|
||||
# *****************************************************
|
||||
|
@ -561,17 +568,23 @@ class Runner(object):
|
|||
conn.exec_command('/usr/bin/logger -t ansible -p auth.info "%s"' % msg, None)
|
||||
# now run actual command
|
||||
stdin, stdout, stderr = conn.exec_command(cmd, tmp, sudoable=sudoable)
|
||||
if type(stdout) != str:
|
||||
return "\n".join(stdout.readlines())
|
||||
|
||||
if type(stderr) != str:
|
||||
err="\n".join(stderr.readlines())
|
||||
else:
|
||||
return stdout
|
||||
err=stderr
|
||||
|
||||
if type(stdout) != str:
|
||||
return "\n".join(stdout.readlines()), err
|
||||
else:
|
||||
return stdout, err
|
||||
|
||||
# *****************************************************
|
||||
|
||||
def _get_tmp_path(self, conn):
|
||||
''' gets a temporary path on a remote box '''
|
||||
|
||||
result = self._exec_command(conn, "mktemp -d /tmp/ansible.XXXXXX", None, sudoable=False)
|
||||
result, err = self._exec_command(conn, "mktemp -d /tmp/ansible.XXXXXX", None, sudoable=False)
|
||||
cleaned = result.split("\n")[0].strip() + '/'
|
||||
return cleaned
|
||||
|
||||
|
|
Loading…
Reference in a new issue