From a5f4ca50b8075468d468c805538933827eb1dd20 Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Tue, 20 Mar 2012 22:29:21 -0400 Subject: [PATCH] Ratchet up logging a few notches prior to controlling w/ verbosity settings --- bin/ansible-playbook | 23 +++++++++++++---- examples/playbooks/playbook3.yml | 3 +++ lib/ansible/runner.py | 42 +++++++++++++++++++------------- lib/ansible/utils.py | 17 ++++++++++--- library/yum | 2 +- test/TestPlayBook.py | 5 +++- test/playbook1.events | 35 +++++++++++++++++++++----- 7 files changed, 94 insertions(+), 33 deletions(-) diff --git a/bin/ansible-playbook b/bin/ansible-playbook index cb51720d17..430a0c7dec 100755 --- a/bin/ansible-playbook +++ b/bin/ansible-playbook @@ -53,10 +53,18 @@ class PlaybookCallbacks(object): print "unreachable: [%s] => %s" % (host, msg) def on_failed(self, host, results): - print "failed: [%s] => %s\n" % (host, utils.smjson(results)) - + invocation = results.get('invocation',None) + if not invocation or invocation.startswith('setup ') or invocation.startswith('async_status '): + print "failed: [%s] => %s\n" % (host, utils.smjson(results)) + else: + print "failed: [%s] => %s => %s\n" % (host, invocation, utils.smjson(results)) + def on_ok(self, host, host_result): - print "ok: [%s]\n" % (host) + invocation = host_result.get('invocation',None) + if not invocation or invocation.startswith('setup ') or invocation.startswith('async_status '): + print "ok: [%s]\n" % (host) + else: + print "ok: [%s] => %s\n" % (host, invocation) def on_import_for_host(self, host, imported_file): print "%s: importing %s" % (host, imported_file) @@ -118,7 +126,7 @@ def main(args): ) try: pb.run() - except errors.AnsibleError as e: + except errors.AnsibleError, e: print >>sys.stderr, "ERROR: %s" % e return 1 @@ -126,4 +134,9 @@ def main(args): if __name__ == "__main__": - sys.exit(main(sys.argv[1:])) + try: + sys.exit(main(sys.argv[1:])) + except errors.AnsibleError, e: + print >>sys.stderr, "ERROR: %s" % e + sys.exit(1) + diff --git a/examples/playbooks/playbook3.yml b/examples/playbooks/playbook3.yml index ed5c8eb00a..968a8bf3da 100644 --- a/examples/playbooks/playbook3.yml +++ b/examples/playbooks/playbook3.yml @@ -44,5 +44,8 @@ action: $packager pkg=$apache state=latest - name: ensure apache is running action: service name=$apache state=running + - name: fail + action: command /bin/false + diff --git a/lib/ansible/runner.py b/lib/ansible/runner.py index 45bab33a78..0607bd3918 100755 --- a/lib/ansible/runner.py +++ b/lib/ansible/runner.py @@ -219,15 +219,19 @@ class Runner(object): # ***************************************************** - def _return_from_module(self, conn, host, result): + def _return_from_module(self, conn, host, result, executed=None): ''' helper function to handle JSON parsing of results ''' try: # try to parse the JSON response - return [ host, True, utils.parse_json(result) ] + result = utils.parse_json(result) + if executed is not None: + result['invocation'] = executed + return [ host, True, result ] except Exception, e: - # it failed, say so, but return the string anyway - return [ host, False, "%s/%s" % (str(e), result) ] + # it failed to parse, say so, but return the string anyway so + # it can be debugged + return [ host, False, "%s/%s/%s" % (str(e), result, executed) ] # ***************************************************** @@ -301,6 +305,7 @@ class Runner(object): if not eval(conditional): return utils.smjson(dict(skipped=True)) + # if the host file was an external script, execute it with the hostname # as a first parameter to get the variables to use for the host inject2 = {} @@ -340,6 +345,8 @@ class Runner(object): args = "%s metadata=~/.ansible/setup" % args args = utils.template(args, inject_vars) + module_name_tail = remote_module_path.split("/")[-1] + client_executed_str = "%s %s" % (module_name_tail, args.strip()) argsfile = self._transfer_argsfile(conn, tmp, args) if async_jid is None: @@ -348,7 +355,7 @@ class Runner(object): 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) - return result + return [ result, client_executed_str ] # ***************************************************** @@ -366,7 +373,7 @@ class Runner(object): module_args.append("#USE_SHELL") module = self._transfer_module(conn, tmp, module_name) - result = self._execute_module(conn, tmp, module, module_args) + (result, executed) = self._execute_module(conn, tmp, module, module_args) # when running the setup module, which pushes vars to the host and ALSO # returns them (+factoids), store the variables that were returned such that commands @@ -388,7 +395,7 @@ class Runner(object): if not k in self.setup_cache[host]: self.setup_cache[host][k] = v - return self._return_from_module(conn, host, result) + return self._return_from_module(conn, host, result, executed) # ***************************************************** @@ -407,12 +414,13 @@ class Runner(object): async = self._transfer_module(conn, tmp, 'async_wrapper') module = self._transfer_module(conn, tmp, module_name) - result = self._execute_module(conn, tmp, async, module_args, + (result, 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) + + return self._return_from_module(conn, host, result, executed) # ***************************************************** @@ -448,8 +456,8 @@ class Runner(object): # run the copy module args = [ "src=%s" % tmp_src, "dest=%s" % dest ] - result1 = self._execute_module(conn, tmp, module, args) - results1 = self._return_from_module(conn, host, result1) + (result1, executed) = self._execute_module(conn, tmp, module, args) + results1 = self._return_from_module(conn, host, result1, executed) (host, ok, data) = results1 # magically chain into the file module @@ -458,8 +466,8 @@ class Runner(object): old_changed = data.get('changed', False) module = self._transfer_module(conn, tmp, 'file') args = [ "%s=%s" % (k,v) for (k,v) in options.items() ] - result2 = self._execute_module(conn, tmp, module, args) - results2 = self._return_from_module(conn, host, result2) + (result2, executed2) = self._execute_module(conn, tmp, module, args) + results2 = self._return_from_module(conn, host, result2, executed) (host, ok, data2) = results2 new_changed = data2.get('changed', False) data.update(data2) @@ -498,8 +506,8 @@ class Runner(object): # run the template module args = [ "src=%s" % temppath, "dest=%s" % dest, "metadata=%s" % metadata ] - result1 = self._execute_module(conn, tmp, template_module, args) - results1 = self._return_from_module(conn, host, result1) + (result1, executed) = self._execute_module(conn, tmp, template_module, args) + results1 = self._return_from_module(conn, host, result1, executed) (host, ok, data) = results1 # magically chain into the file module @@ -508,8 +516,8 @@ class Runner(object): old_changed = data.get('changed', False) module = self._transfer_module(conn, tmp, 'file') args = [ "%s=%s" % (k,v) for (k,v) in options.items() ] - result2 = self._execute_module(conn, tmp, module, args) - results2 = self._return_from_module(conn, host, result2) + (result2, executed2) = self._execute_module(conn, tmp, module, args) + results2 = self._return_from_module(conn, host, result2, executed) (host, ok, data2) = results2 new_changed = data2.get('changed', False) data.update(data2) diff --git a/lib/ansible/utils.py b/lib/ansible/utils.py index 6b95181281..0b09e68fdb 100755 --- a/lib/ansible/utils.py +++ b/lib/ansible/utils.py @@ -46,11 +46,19 @@ def exit(msg, rc=1): def bigjson(result): ''' format JSON output (uncompressed) ''' - return json.dumps(result, sort_keys=True, indent=4) + # hide some internals magic from command line userland + result2 = result.copy() + if 'invocation' in result2: + del result2['invocation'] + return json.dumps(result2, sort_keys=True, indent=4) def smjson(result): ''' format JSON output (compressed) ''' - return json.dumps(result, sort_keys=True) + # hide some internals magic from command line userland + result2 = result.copy() + if 'invocation' in result2: + del result2['invocation'] + return json.dumps(result2, sort_keys=True) def task_start_msg(name, conditional): if conditional: @@ -273,7 +281,10 @@ def parse_yaml(data): return yaml.load(data) def parse_yaml_from_file(path): - data = file(path).read() + try: + data = file(path).read() + except IOError: + raise errors.AnsibleError("file not found: %s" % path) return parse_yaml(data) diff --git a/library/yum b/library/yum index a6e275b9a3..5ef8b7818c 100755 --- a/library/yum +++ b/library/yum @@ -299,7 +299,7 @@ def main(): if 'list' in params: my = yum_base(conf_file=params['conf_file'], cachedir=True) - results = list_stuff(my, params['list']) + results = dict(results=list_stuff(my, params['list'])) elif 'state' in params: if 'pkg' not in params: results['msg'] = "No pkg specified" diff --git a/test/TestPlayBook.py b/test/TestPlayBook.py index 14560d7379..572813c67a 100644 --- a/test/TestPlayBook.py +++ b/test/TestPlayBook.py @@ -49,9 +49,12 @@ class TestCallbacks(object): def on_ok(self, host, host_result): # delete certain info from host_result to make test comparisons easier - for k in [ 'ansible_job_id', 'md5sum', 'delta', 'start', 'end' ]: + for k in [ 'ansible_job_id', 'invocation', 'md5sum', 'delta', 'start', 'end' ]: if k in host_result: del host_result[k] + for k in host_result.keys(): + if k.startswith('facter_') or k.startswith('ohai_'): + del host_result[k] self.events.append([ 'ok', [ host, host_result ]]) def on_play_start(self, pattern): diff --git a/test/playbook1.events b/test/playbook1.events index b5c9c11cce..a4385a7d8f 100644 --- a/test/playbook1.events +++ b/test/playbook1.events @@ -8,10 +8,17 @@ ] ], [ - "primary_setup" - ], - [ - "secondary_setup" + "ok", + [ + "127.0.0.1", + { + "answer": "Wuh, I think so, Brain, but if we didn't have ears, we'd look like weasels.", + "changed": true, + "metadata": "/etc/ansible/setup", + "port": "5150", + "written": "/etc/ansible/setup" + } + ] ], [ "import", @@ -24,7 +31,23 @@ "import", [ "127.0.0.1", - "/home/mdehaan/ansible/test/CentOS.yml" + "/home/mdehaan/ansible/test/default_os.yml" + ] + ], + [ + "ok", + [ + "127.0.0.1", + { + "answer": "Wuh, I think so, Brain, but if we didn't have ears, we'd look like weasels.", + "changed": true, + "cow": "moo", + "duck": "quack", + "metadata": "/etc/ansible/setup", + "port": "5150", + "testing": "default", + "written": "/etc/ansible/setup" + } ] ], [ @@ -235,7 +258,7 @@ "changed": 2, "dark": 0, "failed": 0, - "resources": 9, + "resources": 9, "skipped": 0 } }