From 45a455a805bf9cca45a5446f666ac4ab9e910ee8 Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Mon, 26 Mar 2012 21:17:11 -0400 Subject: [PATCH] Make /usr/bin/ansible output realtime and also delete some code! --- bin/ansible | 76 +++++++++++++--------------------------- lib/ansible/callbacks.py | 25 +++++++++++++ lib/ansible/runner.py | 5 ++- lib/ansible/utils.py | 12 ++----- 4 files changed, 55 insertions(+), 63 deletions(-) diff --git a/bin/ansible b/bin/ansible index 5b64c6e7128..11dbd0c9723 100755 --- a/bin/ansible +++ b/bin/ansible @@ -40,7 +40,8 @@ class Cli(object): def __init__(self): self.stats = callbacks.AggregateStats() - self.callbacks = callbacks.DefaultRunnerCallbacks() + self.callbacks = callbacks.CliRunnerCallbacks() + self.silent_callbacks = callbacks.DefaultRunnerCallbacks() # ---------------------------------------------- @@ -73,7 +74,8 @@ class Cli(object): parser.add_option('-u', '--user', default=C.DEFAULT_REMOTE_USER, dest='remote_user', help='connect as this user') options, args = parser.parse_args() - + self.callbacks.options = options + if len(args) == 0 or len(args) > 1: parser.print_help() sys.exit(1) @@ -88,20 +90,20 @@ class Cli(object): sshpass = None if options.ask_pass: sshpass = getpass.getpass(prompt="SSH password: ") + + if options.tree: + utils.prepare_writeable_dir(options.tree) + + if options.seconds: + print "background launch...\n\n" runner = ansible.runner.Runner( - module_name=options.module_name, - module_path=options.module_path, + module_name=options.module_name, module_path=options.module_path, module_args=shlex.split(options.module_args), - remote_user=options.remote_user, - remote_pass=sshpass, - host_list=options.inventory, - timeout=options.timeout, - forks=options.forks, - background=options.seconds, - pattern=pattern, - callbacks=self.callbacks, - verbose=True, + remote_user=options.remote_user, remote_pass=sshpass, + host_list=options.inventory, timeout=options.timeout, + forks=options.forks, background=options.seconds, pattern=pattern, + callbacks=self.callbacks, verbose=True, ) return (runner, runner.run()) @@ -110,17 +112,11 @@ class Cli(object): def get_polling_runner(self, old_runner, hosts, jid): return ansible.runner.Runner( - module_name='async_status', - module_path=old_runner.module_path, - module_args=[ "jid=%s" % jid ], - remote_user=old_runner.remote_user, - remote_pass=old_runner.remote_pass, - host_list=hosts, - timeout=old_runner.timeout, - forks=old_runner.forks, - pattern='*', - callbacks=self.callbacks, - verbose=True, + module_name='async_status', module_path=old_runner.module_path, + module_args=[ "jid=%s" % jid ], remote_user=old_runner.remote_user, + remote_pass=old_runner.remote_pass, host_list=hosts, + timeout=old_runner.timeout, forks=old_runner.forks, + pattern='*', callbacks=self.silent_callbacks, verbose=True, ) # ---------------------------------------------- @@ -134,13 +130,11 @@ class Cli(object): # ---------------------------------------------- - def output(self, runner, results, options, args): + def poll_if_needed(self, runner, results, options, args): ''' summarize results from Runner ''' if results is None: exit("No hosts matched") - if options.tree: - utils.prepare_writeable_dir(options.tree) # BACKGROUND POLL LOGIC when -B and -P are specified # FIXME: refactor @@ -163,33 +157,11 @@ class Cli(object): # override last result with current status result for report results['contacted'][host] = host_result print utils.async_poll_status(jid, host, clock, host_result) + for (host, host_result) in poll_results['dark'].iteritems(): + print "FAILED: %s => %s" % (host, host_result) clock = clock - options.poll_interval time.sleep(options.poll_interval) poll_hosts = self.hosts_to_poll(poll_results) - for (host, host_result) in results['contacted'].iteritems(): - if 'started' in host_result: - results['contacted'][host] = { 'failed' : 1, 'rc' : None, 'msg' : 'timed out' } - - buf = '' - for hostname in utils.contacted_hosts(results): - msg = utils.host_report_msg( - hostname, - options.module_name, - utils.contacted_host_result(results, hostname), - options.one_line - ) - if options.tree: - utils.write_tree_file(options.tree, hostname, utils.bigjson(utils.contacted_host_result(results, hostname))) - buf += msg - - # TODO: remove, callbacks now do this - if utils.has_dark_hosts(results): - buf += utils.dark_hosts_msg(results) - - if not utils.has_hosts(results): - print "ERROR: no hosts matched" - - print buf ######################################################## @@ -203,5 +175,5 @@ if __name__ == '__main__': print "ERROR: %s" % str(e) sys.exit(1) else: - cli.output(runner, results, options, args) + cli.poll_if_needed(runner, results, options, args) diff --git a/lib/ansible/callbacks.py b/lib/ansible/callbacks.py index a332d740470..184768bc7af 100755 --- a/lib/ansible/callbacks.py +++ b/lib/ansible/callbacks.py @@ -83,6 +83,31 @@ class DefaultRunnerCallbacks(object): def on_unreachable(self, host, res): pass +class CliRunnerCallbacks(DefaultRunnerCallbacks): + + def __init__(self): + # set by /usr/bin/ansible later + self.options = None + + def on_failed(self, host, res): + self._on_any(host,res) + + def on_ok(self, host, res): + self._on_any(host,res) + + def on_unreachable(self, host, res): + print "%s | FAILED => %s" % (host, res) + if self.options.tree: + utils.write_tree_file(self.options.tree, host, dict(failed=True, msg=res)) + + def on_skipped(self, host): + pass + + def _on_any(self, host, result): + print utils.host_report_msg(host, self.options.module_name, result, self.options.one_line) + if self.options.tree: + utils.write_tree_file(self.options.tree, host, utils.bigjson(result)) + class PlaybookRunnerCallbacks(DefaultRunnerCallbacks): def __init__(self, stats): diff --git a/lib/ansible/runner.py b/lib/ansible/runner.py index 49f17bb4d32..87b332a89a1 100755 --- a/lib/ansible/runner.py +++ b/lib/ansible/runner.py @@ -494,7 +494,10 @@ class Runner(object): def _executor(self, host): try: - return self._executor_internal(host) + (host, ok, data) = self._executor_internal(host) + if not ok: + self.callbacks.on_unreachable(host, data) + return (host, ok, data) except errors.AnsibleError, ae: msg = str(ae) self.callbacks.on_unreachable(host, msg) diff --git a/lib/ansible/utils.py b/lib/ansible/utils.py index 58a1ec81d95..ec2924a4e0d 100755 --- a/lib/ansible/utils.py +++ b/lib/ansible/utils.py @@ -135,7 +135,7 @@ def host_report_msg(hostname, module_name, result, oneline): ''' summarize the JSON results for a particular host ''' buf = '' failed = is_failed(result) - if module_name in [ 'command', 'shell' ]: + if module_name in [ 'command', 'shell' ] and 'ansible_job_id' not in result: if not failed: buf = command_success_msg(hostname, result, oneline) else: @@ -147,15 +147,7 @@ def host_report_msg(hostname, module_name, result, oneline): buf = regular_failure_msg(hostname, result, oneline) return buf -def dark_hosts_msg(results): - ''' summarize the results of all uncontactable hosts ''' - buf = '' - if len(results['dark'].keys()) > 0: - buf += "\n*** Hosts with fatal errors: ***\n" - for hostname in results['dark'].keys(): - buf += "%s: %s\n" % (hostname, results['dark'][hostname]) - buf += "\n" - return buf +# FIXME: needed? ... may be able to eliminate many of these... def has_dark_hosts(results): ''' are there any uncontactable hosts? '''