Browse code

Added "debug: var=variableName" capability.

Michael DeHaan authored on 2013/10/15 10:01:38
Showing 5 changed files
... ...
@@ -16,6 +16,7 @@ Highlighted new features:
16 16
 * The roles search path is now configurable in ansible.cfg.  'roles_path' in the config setting.
17 17
 * Includes with parameters can now be done like roles for consistency:  - { include: song.yml, year:1984, song:'jump' }
18 18
 * The name of each role is now shown before each task if roles are being used
19
+* Adds a "var=" option to the debug module for debugging variable data.  "debug: var=hostvars['hostname']" and "debug: var=foo" are all valid syntax.
19 20
 
20 21
 New modules and plugins:
21 22
 
... ...
@@ -484,7 +484,7 @@ class PlaybookRunnerCallbacks(DefaultRunnerCallbacks):
484 484
 
485 485
         host_result2 = host_result.copy()
486 486
         host_result2.pop('invocation', None)
487
-        verbose_always = host_result2.pop('verbose_always', None)
487
+        verbose_always = host_result2.pop('verbose_always', False)
488 488
         changed = host_result.get('changed', False)
489 489
         ok_or_changed = 'ok'
490 490
         if changed:
... ...
@@ -493,7 +493,7 @@ class PlaybookRunnerCallbacks(DefaultRunnerCallbacks):
493 493
         # show verbose output for non-setup module results if --verbose is used
494 494
         msg = ''
495 495
         if (not self.verbose or host_result2.get("verbose_override",None) is not
496
-                None) and verbose_always is None:
496
+                None) and not verbose_always:
497 497
             if item:
498 498
                 msg = "%s: [%s] => (item=%s)" % (ok_or_changed, host, item)
499 499
             else:
... ...
@@ -502,10 +502,10 @@ class PlaybookRunnerCallbacks(DefaultRunnerCallbacks):
502 502
         else:
503 503
             # verbose ...
504 504
             if item:
505
-                msg = "%s: [%s] => (item=%s) => %s" % (ok_or_changed, host, item, utils.jsonify(host_result2))
505
+                msg = "%s: [%s] => (item=%s) => %s" % (ok_or_changed, host, item, utils.jsonify(host_result2, format=verbose_always))
506 506
             else:
507 507
                 if 'ansible_job_id' not in host_result or 'finished' in host_result2:
508
-                    msg = "%s: [%s] => %s" % (ok_or_changed, host, utils.jsonify(host_result2))
508
+                    msg = "%s: [%s] => %s" % (ok_or_changed, host, utils.jsonify(host_result2, format=verbose_always))
509 509
 
510 510
         if msg != '':
511 511
             if not changed:
... ...
@@ -38,13 +38,21 @@ class ActionModule(object):
38 38
 
39 39
         kv = utils.parse_kv(module_args)
40 40
         args.update(kv)
41
-        if not 'msg' in args:
41
+
42
+        if not 'msg' in args and not 'var' in args:
42 43
             args['msg'] = 'Hello world!'
43 44
 
44
-        if 'fail' in args and utils.boolean(args['fail']):
45
-            result = dict(failed=True, msg=args['msg'])
46
-        else:
47
-            result = dict(msg=args['msg'])
45
+        result = {}
46
+        if 'msg' in args:
47
+            if 'fail' in args and utils.boolean(args['fail']):
48
+                result = dict(failed=True, msg=args['msg'])
49
+            else:
50
+                result = dict(msg=args['msg'])
51
+        elif 'var' in args:
52
+            (intermediate, exception) = utils.safe_eval(args['var'], inject, include_exceptions=True, template_call=True)
53
+            if exception is not None:
54
+                intermediate = "failed to evaluate: %s" % str(exception)
55
+            result[args['var']] = intermediate
48 56
 
49 57
         # force flag to make debug output module always verbose
50 58
         result['verbose_always'] = True
... ...
@@ -896,16 +896,20 @@ def is_list_of_strings(items):
896 896
             return False
897 897
     return True
898 898
 
899
-def safe_eval(str):
899
+def safe_eval(str, locals=None, include_exceptions=False, template_call=False):
900 900
     '''
901 901
     this is intended for allowing things like:
902
-    with_items: {{ a_list_variable }}
902
+    with_items: a_list_variable
903 903
     where Jinja2 would return a string
904 904
     but we do not want to allow it to call functions (outside of Jinja2, where
905 905
     the env is constrained)
906 906
     '''
907 907
     # FIXME: is there a more native way to do this?
908 908
 
909
+    if template_call:
910
+        # for the debug module in Ansible, allow debug of the form foo.bar.baz versus Python dictionary form
911
+        str = template.template(None, "{{ %s }}" % str, locals)
912
+
909 913
     def is_set(var):
910 914
         return not var.startswith("$") and not '{{' in var
911 915
 
... ...
@@ -922,8 +926,18 @@ def safe_eval(str):
922 922
     if re.search(r'import \w+', str):
923 923
         return str
924 924
     try:
925
-        return eval(str)
925
+        result = None
926
+        if not locals:
927
+            result = eval(str)
928
+        else:
929
+            result = eval(str, None, locals)
930
+        if include_exceptions:
931
+            return (result, None)
932
+        else:
933
+            return result
926 934
     except Exception, e:
935
+        if include_exceptions:
936
+            return (str, e)
927 937
         return str
928 938
 
929 939
 
... ...
@@ -35,7 +35,10 @@ options:
35 35
         message.
36 36
     required: false
37 37
     default: "Hello world!"
38
-author: Dag Wieers
38
+  var:
39
+    description:
40
+      - A variable name to debug.  Mutually exclusive with the 'msg' option.
41
+author: Dag Wieers, Michael DeHaan
39 42
 '''
40 43
 
41 44
 EXAMPLES = '''
... ...
@@ -44,4 +47,9 @@ EXAMPLES = '''
44 44
 
45 45
 - debug: msg="System {{ inventory_hostname }} has gateway {{ ansible_default_ipv4.gateway }}"
46 46
   when: ansible_default_ipv4.gateway is defined
47
+
48
+- shell: /usr/bin/uptime
49
+  register: result
50
+- debug: var=result
51
+
47 52
 '''