Skip to main content
RunBook Academy

AnsibleVIII · Modules and the Module ModelThe module model

Reading module documentation like an operator

Intermediate⏱ ~18 minansible-docjq

What you'll learn

  • Navigate ansible-doc with -l, -s, -t and -j to answer a specific question quickly
  • Read the attributes table and interpret full, partial, none and N/A support
  • Determine before running whether --check and --diff will tell you anything
  • Use ansible-doc -t keyword to look up play and task keywords, not just modules

Prerequisites

Verified against ansible-core 2.21.x · ansible (community package) 14.x · Python (controller) 3.12+ · ansible-lint 26.x · Molecule 26.x · Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL / Rocky / AlmaLinux 9.x · 2026-08-11

Not yet marked complete on this device.

The single highest-value skill in this part is not memorising modules. It is being able to answer, in about ten seconds and without a browser, questions like does this module support check mode, what does it return, and does this option exist in the version I am running.

ansible-doc answers all three from the installed code, which means it is correct for your version rather than for whichever version the website is currently rendering. That distinction matters more than it sounds: a module page on docs.ansible.com describes the latest release, and you are running whatever your controller has.

The four invocations worth knowing

-l — what exists

Read-only / Safeeverything available, with one-line summaries
$ ansible-doc -l
ansible.builtin.add_host               Add a host (and alternatively a grou...
ansible.builtin.apt                    Manages apt-packages
ansible.builtin.apt_key                Add or remove an apt key
ansible.builtin.apt_repository         Add and remove APT repositories
ansible.builtin.assemble               Assemble configuration files from fr...

Illustrative output

On a bare ansible-core 2.21 install this lists 71 modules. That is worth internalising: ansible-core is small, and the thousands of modules people talk about live in collections you install separately.

The argument to -l filters by namespace or collection, which is how you find out what a collection you just installed actually contains:

Read-only / Safewhat did that collection bring
$ ansible-doc -l community.general

Searching by topic is the thing -l does not do well. There is no keyword search, so the usual approach is ansible-doc -l | grep -i firewall, which greps the one-line summaries and is exactly as good as those summaries happen to be.

-s — the snippet

Read-only / Safea playbook snippet with every option commented
$ ansible-doc -s ansible.builtin.ping
- name: Try to connect to host, verify a usable python and return `pong' on success
ping:
    data:                  # Data to return for the `ping' return value. If
                           # this parameter is
                           # set to `crash', the
                           # module will cause
                           # an exception.

One caution: -s emits the short module name, ping: rather than ansible.builtin.ping:. If you paste the snippet directly you have written a short name into a playbook, which the next lesson argues against and which ansible-lint will flag. Add the namespace by hand.

-t — other plugin types

-t defaults to module, and the other values are where a lot of otherwise hard-to-find documentation lives:

become  cache  callback  cliconf  connection  httpapi  inventory
lookup  netconf  shell  vars  module  strategy  test  filter
role  keyword

-t keyword is the one people do not know exists. It documents the play, block and task keywords themselves — the things that are not modules:

Read-only / Safedocumentation for a keyword, not a module
$ ansible-doc -t keyword collections
collections:
applies_to:
- Play
- Role
- Block
- Task
- Handler
description: "List of collection namespaces to search for modules, plugins, and
  roles. ..."
priority: 100
template: static
type: list

Illustrative output

ansible-doc -t keyword -l lists all of them, which is a better reference for “is it serial or batch_size” than any web search.

-j — JSON, for when you are asking about more than one module

Read-only / Safemachine-readable documentation
$ ansible-doc -j ansible.builtin.copy | jq -r '.[].doc.attributes.check_mode.support'
full

This is the invocation that turns “I wonder whether check mode is meaningful in this play” from a research task into a one-liner.

The attributes table

Every module page has an ATTRIBUTES section, below the options and above the examples. Almost nobody reads it. It is the most operationally important part of the page.

Read-only / Safethe section everyone scrolls past
$ ansible-doc ansible.builtin.command | sed -n '/ATTRIBUTES/,/NOTES/p'
ATTRIBUTES:

      check_mode:
      description: Can run in check_mode and return changed status prediction without modifying
        target, if not supported the action will be skipped.
      details: while the command itself is arbitrary and cannot be subject to the check
        mode semantics it adds `creates'/`removes' options as a workaround
      support: partial

      diff_mode:
      description: Will return details on what has changed (or possibly needs changing in
        check_mode), when in diff mode
      support: none

      platform:
      description: Target OS/families that can be operated against
      platforms: posix
      support: full

      raw:
      description: Indicates if an action takes a 'raw' or 'free form' string as an option
        and has it's own special parsing of it
      support: full

The support levels

LevelWhat it means
fullThe capability works as described, with no qualification.
partialIt works in some circumstances. Read the details line — it tells you which.
noneIt does not work. For check_mode, this means the task is skipped in --check.
N/AThe question does not apply to this module, usually because it dispatches to another one.

partial is the level that misleads, because it reads like “mostly works”. For command it means check mode functions only through the creates and removes options, and does nothing at all without them. The details line says exactly that, in eighteen words, and is the reason the attributes table is worth reading rather than skimming.

The attributes you will actually use

AttributeQuestion it answers
check_modeWill --check evaluate this task, or skip it?
diff_modeWill --diff show me the content that changes?
platformWhich OS families does this module claim to support?
actionDoes part of this run on the controller rather than the target?
becomeDoes privilege escalation apply, or is it ignored?
asyncCan this be backgrounded with async and poll?
safe_file_operationsDoes it write atomically, or can a failure leave a partial file?
bypass_host_loopDoes this run once globally rather than per host?
factsDoes it inject facts into the host, as setup does?

action is the one that explains a whole class of confusion, and it has its own lesson later in this part.

The check-mode picture across ansible-core

Because -j makes this answerable, here is the actual distribution across the 70 documented modules in ansible-core 2.21:

check_mode supportCountNotable members
full52file, copy, template, lineinfile, user, cron, apt, systemd
partial8command, shell, script, get_url, unarchive, add_host, group_by, meta
none8raw, uri, expect, tempfile, wait_for, wait_for_connection, include_tasks, import_tasks
N/A2package, service

The majority are full, which is the reassuring half of the picture. The alarming half is the membership of the other two columns: command, shell, script and raw are precisely the modules people reach for when no purpose-built module exists — that is, in the tasks that are hardest to reason about and most in need of a dry run.

diff_mode: full is rarer still: 18 modules, essentially the ones that manage file content (copy, template, lineinfile, blockinfile, replace, assemble, cron, git) plus the package and repository modules.

A worked question

The change window is Thursday. Will --check on this play tell me anything useful?

Read-only / Safeanswer it for every module in the play
$ for m in package template service command; do printf '%-10s %s\n' "$m" "$(ansible-doc -j ansible.builtin.$m | jq -r '.[].doc.attributes.check_mode.support')"; done
package    N/A
template   full
service    N/A
command    partial

Read that as: the template task will be evaluated properly and will show a diff. The command task will be skipped entirely unless it has a creates guard. The package and service tasks depend on what they dispatch to on the target, which on a systemd Debian host means apt (full) and systemd_service (full).

So the check run is informative for three of the four tasks and blind to the fourth — and the fourth is the one running an arbitrary script. That is a useful thing to know before Thursday.

Knowledge check

Knowledge check · 4 questions

  1. Q1. ansible-doc reports check_mode: N/A for ansible.builtin.service. What should you conclude?

  2. Q2. Which of these questions can ansible-doc answer without a browser? Select all that apply.

  3. Q3. A module documenting check_mode: partial requires you to read its details line, because partial describes a specific qualification rather than a general degree of support.

  4. Q4. You paste an `ansible-doc -s` snippet straight into a playbook and ansible-lint complains. Why?

Passing score: 75%. Answers are checked in this browser.