module_utils

module_utils #

When writing extensions in Python, you can write all of the code in the extension file itself. For instance, when writing a filter, you can put all of the code in a file in the filter_plugins/ directory.

However, if you’re writing a large extension, or even want to split up your extension into several Python files, you can add files to module_utils and import them.

Example #

That might look like this:

module_utils/example_lib.py #

"""Example library

Imagine that it is documented here.
"""


def important_function_that_works_well(arg1):
    """I hope you tested this.

    ........... You didn't write any tests for this, did you. DID YOU.
    """
    return f"{arg1} is my argument, wow what a useful function"

library/example_task.py #

#!/usr/bin/env python

DOCUMENTATION = """
module: example_task
short_description: Get some really useful data from a library function
version_added: "0.1"
author: Micah R Ledbetter
"""

from ansible.module_utils import example_lib
from ansible.module_utils.basic import AnsibleModule


def main():

    module = AnsibleModule(
        argument_spec={
            "arg1": {"type": "str"},
        }
    )
    arg1 = module.params["arg1"]

    try:
        module.exit_json(
            changed=False, result=example_lib.important_function_that_works_well(arg1)
        )
    except Exception as err:
        module.fail_json(msg=str(err))


if __name__ == "__main__":
    main()

example-playbook.yml #

---

- hosts:
    - host1.example.com
  tasks:
    - name: Do an example task
      example_task:
        arg1: "foobar"
      register: example_result
    - name: Show the example result
      debug:
        var: example_result

Example run log #

It might look like this. Some of Ansible’s output has been elided for clarity.

$ ansible-playbook example-playbook.yml

TASK [Do an example task] *****************************************************
ok: [host1.example.com]
Thursday 09 September 2021  17:00:20 -0500 (0:00:00.212)       0:00:05.522 ****

TASK [Show the example result] ************************************************
ok: [host1.example.com] =>
  example_result:
    changed: false
    result: "foobar is my argument, wow what a useful function"
Thursday 09 September 2021  17:00:20 -0500 (0:00:00.212)       0:00:05.522 ****

module_utils subdirectories #

You can also use subdirectories of module_utils. For instance, module_utils/example_subdir/example_lib.py can be imported in the task as from ansible.module_utils.example_subdir import example_lib.

Other topics #

TODO

Implement sections for testing, mypy, black, setup.py, commandline scripts, etc etc etc

  • Include tests
  • Type checked with mypy etc
  • Linted with black etc
  • Writing and runing tests
  • Installed with setup.py according to good Python practice
  • Include commandline scripts that can call to exercise sections of the code as appropriate
  • Show how to install them in to a venv with pip -e
  • Referencing packages in module_utils in modules and plugins
  • When to promote the generic code to a separate Python package, published to a pip server, and versioned, which can then be deployed to the Ansible controller for use