CertGrid CertGrid
Hands-on Lab·Ansible

Finding Ansible Modules with ansible-doc

The exam allows documentation, and `ansible-doc` is faster than any of it - it reads the modules actually installed on the machine in front of you, so it can never describe a version you are not running. Three uses cover almost everything: listing to find a module, `-s` for the parameter summary, and the EXAMPLES section for something you can paste.

Ad-hoc Commands and Modules Guide 8 of 45 Beginner

Written against the versions above. `ansible-doc -l` lists every module from every installed collection. Adding a collection name narrows it: `ansible-doc -l ansible.builtin` is the subset you can rely on being present anywhere, which matters when writing something portable.

Documentation is read on the control node. Nothing here touches a managed node.
Server NameIP AddressOSRolesCPURAMHDD
ANS-CTL01192.168.0.36Ubuntu 26.04 LTSAnsible Control Node2 Core3 GB50 GB

Before you start

  1. The configuration this guide assumes

    Everything below runs from the home directory on ANS-CTL01, where two files sit side by side.

    ~/ansible.cfg - found because Ansible looks for ./ansible.cfg in the current directory:

    [defaults]
    inventory = ./inventory.ini
    host_key_checking = False
    remote_user = sysadmin
    result_format = yaml

    result_format = yaml rather than the stdout_callback = yaml that older material recommends: that callback lived in community.general and was removed in version 12.0.0, so a playbook run against this config errors out with "The 'community.general.yaml' callback plugin has been removed." The built-in option replaces it and produces the same readable output.

    ~/inventory.ini - two groups and a parent group, so host patterns have something to select:

    [web]
    ans-a01
    
    [db]
    ans-b01
    
    [production:children]
    web
    db
    
    [web:vars]
    app_port=8080
    
    [all:vars]
    ansible_python_interpreter=/usr/bin/python3

    The short names resolve because /etc/hosts on all three machines carries them, and the control node reaches both managed nodes with an ed25519 key and passwordless sudo.

    If any of this is unfamiliar, build it first: guide 3, guide 4 and guide 5 cover the three pieces in order.

    The last two commands are the check worth running before anything else in this path: pong from both hosts, and root when escalation is on.

    bash Example session
    cat ~/ansible.cfg[defaults]inventory = ./inventory.inihost_key_checking = Falseremote_user = sysadminresult_format = yamlcat ~/inventory.ini[web]ans-a01 [db]ans-b01 [production:children]webdb [web:vars]app_port=8080 [all:vars]ansible_python_interpreter=/usr/bin/python3grep -E "ans-(ctl|a|b)01" /etc/hosts192.168.0.36 ans-ctl01192.168.0.37 ans-a01192.168.0.38 ans-b01ls -l ~/.ssh/id_ed25519 ~/.ssh/id_ed25519.pub-rw------- 1 sysadmin sysadmin 411 Aug 23 07:06 /home/sysadmin/.ssh/id_ed25519-rw-r--r-- 1 sysadmin sysadmin  99 Aug 23 07:06 /home/sysadmin/.ssh/id_ed25519.pubansible-inventory --graph@all:  |--@ungrouped:  |--@production:  |  |--@web:  |  |  |--ans-a01  |  |--@db:  |  |  |--ans-b01ansible all -m ansible.builtin.pingans-a01 | SUCCESS => {    "changed": false,    "ping": "pong"}ans-b01 | SUCCESS => {    "changed": false,    "ping": "pong"}ansible all -m ansible.builtin.command -a "id -un" --becomeans-a01 | CHANGED | rc=0 >>rootans-b01 | CHANGED | rc=0 >>root

    Expected resultBoth config files as shown, and pong plus root from both managed nodes.

    Success conditionYour control node matches the one every command in this guide was run on.

  2. How many modules are there

    ansible-doc -l | wc -l

    Several thousand, across every installed collection. Narrowed to the one that is always present:

    ansible-doc -l ansible.builtin | wc -l

    a few hundred. That subset is the one worth knowing, because ansible.builtin ships with the engine and is available on any control node you are put in front of.

    The listing is two columns - name and a one-line description - which is what makes it searchable.

    bash Example session
    ansible-doc -l 2>/dev/null | wc -l9451ansible-doc -l ansible.builtin 2>/dev/null | wc -l71ansible-doc -l ansible.builtin 2>/dev/null | head -8ansible.builtin.add_host               Add a host (and alternatively a grou...ansible.builtin.apt                    Manages apt-packagesansible.builtin.apt_key                Add or remove an apt keyansible.builtin.apt_repository         Add and remove APT repositoriesansible.builtin.assemble               Assemble configuration files from fr...ansible.builtin.assert                 Asserts given expressions are trueansible.builtin.async_status           Obtain status of asynchronous taskansible.builtin.blockinfile            Insert/update/remove a text block su...

    Expected resultA total, a builtin count, and the start of the list.

    Success conditionYou know how much is installed and which part is portable.

  3. Finding one by what it does

    The descriptions are the searchable part, so grep them:

    ansible-doc -l | grep -i firewall
    ansible-doc -l ansible.builtin | grep -iE 'user|group'

    This is the fastest way to answer 'is there a module for this', which is the question that matters most under time pressure. Reaching for shell because you could not remember a module name is how playbooks end up non-idempotent.

    Worth knowing where things live: users, groups, files, services and packages are in ansible.builtin; firewall and SELinux modules are in ansible.posix; a great deal else is in community.general.

    bash Example session
    ansible-doc -l 2>/dev/null | grep -iE "^ansible.posix|firewall" | head -6ansible.posix.acl                                                                                                                ...ansible.posix.at                                                                                                                 Schedule the ex...ansible.posix.authorized_key                                                                                                     ...ansible.posix.firewalld                                                                                                          ...ansible.posix.firewalld_info                                                                                                     ...ansible.posix.mount                                                                                                              ...ansible-doc -l ansible.builtin 2>/dev/null | grep -iE "user|group" | head -6ansible.builtin.group                  Add or remove groupsansible.builtin.group_by               Create Ansible groups based on factsansible.builtin.user                   Manage user accounts

    Expected resultMatching module names with their descriptions.

    Success conditionYou can find a module from a description of the job.

  4. Reading one

    The full page gives you the description, every parameter, defaults, choices, and which version added what. It is long.

    -s gives the part you usually want:

    ansible-doc -s ansible.builtin.file

    A ready-made YAML snippet with every parameter commented. Delete the lines you do not need and you have a valid task. Under exam pressure this is the single most useful form of the command - it is faster than remembering whether the parameter is path or dest, and it cannot be out of date.

    bash Example session
    ansible-doc ansible.builtin.file 2>/dev/null | head -22> MODULE ansible.builtin.file (/usr/lib/python3/dist-packages/ansible/modules/file.py)   Set attributes of files, directories, or symlinks and their targets.  Alternatively, remove files, symlinks or directories.  Many other modules support the same options as the  ansible.builtin.file module - including ansible.builtin.copy,  ansible.builtin.template, and ansible.builtin.assemble.  For Windows targets, use the ansible.windows.win_file module  instead. OPTIONS (red indicates it is required):    access_time  This parameter indicates the time the file's access                time should be set to.                Should be `preserve' when no modification is required,                `YYYYMMDDHHMM.SS' when using default time format, or                `now'.                Default is `None' meaning that `preserve' is the                default for `state=[file,directory,link,hard]' and                `now' is default for `state=touch'.        default: null        type: stransible-doc -s ansible.builtin.file 2>/dev/null | head -20- name: Manage files and file properties  file:      access_time:           # This parameter indicates the time the file's                             # access time should                             # be set to. Should                             # be `preserve' when                             # no modification is                             # required,                             # `YYYYMMDDHHMM.SS'                             # when using default                             # time format, or                             # `now'. Default is                             # `None' meaning that                             # `preserve' is the                             # default for                             # `state=[file,directory,link,hard]'                             # and `now' is                             # default for                             # `state=touch'.      access_time_format:    # When used with `access_time', indicates the time

    Expected resultThe full page, then the same module as a YAML skeleton.

    Success conditionYou can produce a correct task without recalling a parameter name.

  5. The examples are the fast path

    Every well-written module ends with worked examples:

    ansible-doc ansible.builtin.copy | sed -n '/^EXAMPLES/,/^RETURN/p'

    These are usually closer to what you want than the parameter list, because they show parameters in combination - which ones go together, and which are mutually exclusive.

    After EXAMPLES comes RETURN, describing what the module puts into a registered variable. That is the section to read when you are about to use register: and need to know whether the field is stdout, stdout_lines or something module-specific.

    bash
    ansible-doc ansible.builtin.copy 2>/dev/null | sed -n '/^EXAMPLES/,/^RETURN/p' | head -18

    Expected resultWorked examples from the module itself.

    Success conditionYou can copy a working task rather than composing one.

  6. Plugins are documented too, and so are short names

    Modules are not the only thing with documentation:

    ansible-doc -t lookup -l
    ansible-doc -t filter -l | wc -l

    -t lookup covers lookup('file', ...) - the one used in guide 5 - and -t filter lists the Jinja2 filters available in templates. Both are hard to search for online and trivial to list here.

    Finally, the short name works:

    ansible-doc -s copy

    resolves to ansible.builtin.copy, and the full page confirms which module it picked. Short names are fine for ansible.builtin; for anything else, write the full name, because two collections may define the same short name and the winner depends on configuration.

    bash Example session
    ansible-doc -t lookup -l 2>/dev/null | head -6amazon.aws.aws_account_attribute                     Look up AWS account at...amazon.aws.aws_collection_constants                  expose various collect...amazon.aws.aws_service_ip_ranges                     Look up the IP ranges ...amazon.aws.secretsmanager_secret                     Look up secrets stored...amazon.aws.ssm_parameter                             gets the value for a S...ansible.builtin.config                               Display the 'resolved'...ansible-doc -t lookup ansible.builtin.file 2>/dev/null | sed -n '/^EXAMPLES/,$p' | head -8ansible-doc -t filter -l 2>/dev/null | wc -l259ansible-doc -s copy 2>/dev/null | head -6- name: Copy files to remote locations  copy:      attributes:            # The attributes the resulting filesystem object                             # should have. To get                             # supported flags                             # look at the manansible-doc ansible.builtin.copy 2>/dev/null | grep -m1 "^> "> MODULE ansible.builtin.copy (/usr/lib/python3/dist-packages/ansible/modules/copy.py)

    Expected resultLookup and filter listings, and a short name resolving to a full one.

    Success conditionYou can look up any plugin type, not just modules.

Troubleshooting

Official sources