Debugging Ansible modules

ansible register
ansible debug stdout
ansible debug pretty print
ansible when
ansible debug with_items
ansible debug multiple lines
ansible debug when condition
ansible debug environment variable

I tried to write an Ansible module. My module is buggy. When I run it from a playbook I get the following unreadable output:

$ ansible-playbook lacp.yml 

PLAY [xxxxxxxx] ****************************************************************

TASK [Test that my module works] ***********************************************
fatal: [xxxxxxxx]: FAILED! => {"changed": false, "failed": true, "module_stderr": "couldn't set locale correctly\ncouldn't set locale correctly\ncouldn't set locale correctly\nTraceback (most recent call last):\n  File \"/tmp/ansible_vHkWq8/ansible_module_lacp.py\", line 27, in <module>\n    main()\n  File \"/tmp/ansible_vHkWq8/ansible_module_lacp.py\", line 14, in main\n    m = re.match('^key: ([0-9]+) ', dladm.readline())\nAttributeError: 'Popen' object has no attribute 'readline'\ndladm: insufficient privileges\n", "module_stdout": "", "msg": "MODULE FAILURE", "parsed": false}

NO MORE HOSTS LEFT *************************************************************
 [WARNING]: Could not create retry file 'lacp.retry'.         [Errno 2] No such file or directory: ''


PLAY RECAP *********************************************************************
xxxxxxxx                   : ok=0    changed=0    unreachable=0    failed=1   

How to stop Ansible quoting error messages with JSON? Or is there another way to debug Ansible modules?

How to stop Ansible quoting error messages with JSON?

You can use human_log.py plugin to force Ansible to interpret and print newline characters in its output.

You put the file into /path/to/callback_plugins/ directory and add the following to the ansible.cfg:

[defaults]
callback_plugins = /path/to/callback_plugins/

The detailed instructions are in the Human-Readable Ansible Playbook Log Output Using Callback Plugin blog post.

debug – Print statements during execution, Synopsis¶. This module prints statements during execution and can be useful for debugging variables or expressions without necessarily halting the playbook. This module prints statements during execution and can be useful for debugging variables or expressions without necessarily halting the playbook. Useful for debugging together with the ‘when:’ directive. This module is also supported for Windows targets.

You can look into this and this callback plugins (for Ansible 2.x). You will need to modify them a bit, because they don't convert module_stderr out of the box.

Also you may want to execute playbook with ANSIBLE_KEEP_REMOTE_FILES=1, then ssh to the remote box and debug your module in-place, then save to ansible library.

Playbook Debugger, Ansible includes a debugger as part of the strategy plugins. You can then, for example, check or set the value of variables, update module arguments, and  Developing Ansible modules is easy, but often it isn’t necessary. Before you start writing a new module, ask: Does a similar module already exist? An existing module may cover the functionality you want. Ansible Core includes thousands of modules. Search our list of existing modules to see if there’s a module that does what you need.

Debugging Ansible modules will quickly become next to impossible and very, very time consuming without following the recommended approach.

The recommended approach is to build your Ansible stuff using very small steps. That way you can more easily guess what is wrong as you add stuff to what you know and have verified to work.

So when you state that the module is buggy, you have gone to far. You will be searching for a needle in the haystack that Ansible without question is.

Refactoring is not really a practical option. You basically start fresh, recreating your code step by step.

I hope you noticed that Ansible doesn't even bother to format error output in a human readable way. In a way on error Ansible outputs the same message: something went wrong.

Let's say I have this Ansible task

- name: Mymodule
  mymodule:
    something: "something"

My module also is simple enough

#!/usr/bin/python

from ansible.module_utils.basic import *

    def somefunction(data):
      has_changed = False
      meta = { "something": "something"}
      return (has_changed, meta)
    def main():

      fields = {
        "something": {"required": True, "type": "str"}, 
        "state": {
              "default": "perform", 
              "choices": ["perform"],  
              "type": "str" 
            },        
          }
      choice_map = {
        "perform2": somefunction,
      }

      module = AnsibleModule(argument_spec=fields)
      has_changed, result = choice_map.get(module.params['state'])(module.params)
      module.exit_json(changed=has_changed, meta=result)

    if __name__ == '__main__':
        main()

Ansible will produce the following error message

TASK [backup : Mymodule] ******************************************************* fatal: [myapp]: FAILED! => {"changed": false, "module_stderr": "Shared connection to 127.0.0.1 closed.\r\n", "module_stdout": "Traceback (most recent call last):\r\n File \"/home/vagrant/.ansible/tmp/ansible-tmp-1570188887.99-191548982937437/AnsiballZ_mymodule.py\", line 114, in \r\n _ansiballz_main()\r\n File \"/home/vagrant/.ansible/tmp/ansible-tmp-1570188887.99-191548982937437/AnsiballZ_mymodule.py\", line 106, in _ansiballz_main\r\n invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\r\n File \"/home/vagrant/.ansible/tmp/ansible-tmp-1570188887.99-191548982937437/AnsiballZ_mymodule.py\", line 49, in invoke_module\r\n imp.load_module('main', mod, module, MOD_DESC)\r\n File \"/tmp/ansible_mymodule_payload_XTaVPp/main.py\", line 29, in \r\n File \"/tmp/ansible_mymodule_payload_XTaVPp/main.py\", line 25, in main\r\nTypeError: 'NoneType' object is not callable\r\n", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}

The "message" we should focus on is

TypeError: 'NoneType' object is not callable

It is caused by the wrong action perform2. It should be perform. A simple typo.

      choice_map = {
        "perform2": somefunction,
      }

The typo is in module file mymodule.py on line 21. The files and lines 114, 106, 49, 29, 25 might be useful in someway but how these files are useful is not clear at all.

This is just a very simple example to illustrate the point of the haystack. Ansible does not format the error message in human readable way. Reporting on the problem file and line number is also not an exact science. And the error message is not useful. The error message should be that my choice_map is referencing a non-existing action. It could list the available choices.

IMHO this is a common problem with Ansible. A typing mistake can take a hour to fix.

The only way to workaround this limitation is to build up provision step by step. Baby steps.

Ansible Module Development Walkthrough, Playbook module testing; Debugging (local); Debugging (remote); Unit testing; Integration testing (coming soon); Communication and  The Ansible Debug Module When you are working with Ansible playbooks, it’s great to have some debug options. Ansible provides a debug module that makes this task easier. It’s a handy tool to figure out any problem areas.

debug, This module prints statements during execution and can be useful for debugging variables or expressions without necessarily halting the  Debugging Ansible modules will quickly become next to impossible and very, very time consuming without following the recommended approach. The recommended approach is to build your Ansible stuff using very small steps. That way you can more easily guess what is wrong as you add stuff to what you know and have verified to work.

The Ansible Debug Module – Linux Hint, This module prints statements during execution and can be useful for debugging variables or expressions without necessarily halting the  Now let’s prepare to debug the playbook by enabling the environment variable and then running the playbook. $ ANSIBLE_KEEP_REMOTE_FILES=1$ ansible-playbook local test.yml<results>$ cd~/.ansible/temp$ cd<most recent temp folder>$ python fail.py explode$ ls-ldebug_dir$ cat debug_dir/args.

Debugging ansible modules, The debugger is invoked since the wrong_var variable is undefined. Let's change the module's arguments and run the task again. Ansible module development: getting started¶ A module is a reusable, standalone script that Ansible runs on your behalf, either locally or remotely. Modules interact with your local machine, an API, or a remote system to perform specific tasks like changing a database password or spinning up a cloud instance.