Hello everyone,
I’d like to propose way for roles to document the variables they set, rendered as a table on the role’s documentation page the same way modules document their return values today.
I initiated this in antsibull-docs#491, where @felixfontein pointed out that this is an ecosystem decision that needs buy-in from the Core team, not something antsibull-docs can decide on its own.
The problem
Modules can declare RETURN: and users get a nice, typed “Return Values” table in the docs, plus RV() cross-reference markup. Roles have no equivalent. A role that sets facts/variables (via set_fact) has no structured, typed way to document them.
A weak workaround I found is writing bullet lists into the notes: section of meta/argument_specs.yml.
Here are some examples of return variables that we have in our roles:
notes:
- "B(Variables):"
- >
• C(bootloader_reboot_required) — V(true) means the host must reboot to
apply the role's changes. The role sets this when O(bootloader_reboot_ok)
is V(false) and it made changes.
- >
• C(bootloader_facts) — boot information for all kernels. The role returns
this when O(bootloader_gather_facts) is V(true). Each entry is a dict with
C(kernel), C(args), C(root), and C(default) keys.
notes:
- "B(Variables):"
- >
• C(ha_cluster_facts) — the exported current cluster configuration,
populated when O(ha_cluster_export_configuration) is V(true). The exported
dictionary may not be complete and manual modification is expected; most
notably you must set O(ha_cluster_hacluster_password). Depending on the
C(pcs) version installed on managed nodes, certain variables may not be
present in the export.
- "The following variables are present in the export:"
- "• C(ha_cluster_enable_repos) — RHEL and CentOS only."
- "• C(ha_cluster_enable_repos_resilient_storage) — RHEL and CentOS only."
- >
• C(ha_cluster_manage_firewall) — requires C(python3-firewall) to be
installed on managed nodes.
- >
• C(ha_cluster_manage_selinux) — requires C(python3-policycoreutils) to be
installed on managed nodes.
- "• C(ha_cluster_cluster_present) — whether a cluster is configured."
- "• C(ha_cluster_start_on_boot) — whether cluster services start on boot."
- "• C(ha_cluster_install_cloud_agents) — RHEL and CentOS only."
notes:
- "B(Variables):"
- >
• C(podman_version) — the version string of the podman version in use.
Useful in templates, for example
C(podman_version is version("4.5", ">=")).
- >
• C(podman_subuid_info) — the subuid ranges for the users managed by the
role, extracted from C(getsubids) if available, or from F(/etc/subuid).
A dict keyed by user name; each value is a dict with C(start) (int) and
C(range) (int).
- >
• C(podman_subgid_info) — the subgid ranges for the groups managed by the
role, extracted from C(getsubids) if available, or from F(/etc/subgid).
A dict keyed by group name; each value is a dict with C(start) (int) and
C(range) (int).
- >
• C(podman_use_new_toml_formatter) — whether the role used the new TOML
formatter when rendering configuration files.
This has no type/returned/sample columns, no anchors, no RV() targets, and is easy to let drift out of date.
Proposed approach
Allow an optional return: key per entry point in meta/argument_specs.yml, using the same structure as module RETURN::.
Here’s an example of how the bootloader role return would look like:
argument_specs:
main:
short_description: ...
options: ...
return:
bootloader_reboot_required:
description:
- V(true) means the host must reboot to apply the role's changes.
- The role sets this when O(bootloader_reboot_ok) is V(false) and it
made changes.
type: bool
returned: always
sample: true
bootloader_facts:
description:
- Boot information for all kernels.
type: list
elements: dict
returned: When O(bootloader_gather_facts) is V(true).
contains:
kernel:
description: Path to the kernel image.
type: str
args:
description: The kernel command-line arguments.
type: str
root:
description: The root device for this boot entry.
type: str
default:
description: Whether this is the default boot entry.
type: bool
sample:
- kernel: /boot/vmlinuz-6.9.0
args: "ro crashkernel=1G-4G:192M"
root: UUID=1aefe582
default: true
Key points:
- Fully optional — roles without a return: block are completely unaffected.
- Rendered as a dedicated table on the role page. I’d suggest titling it “Return Variables” rather than modules’ “Return Values”, since a role sets variables rather than returning a structured result.
- RV(fqcn#role:entrypoint:name) markup already supports roles (groundwork was added in antsibull-docs #113 “in case they are ever added”), so references would resolve once the data exists.
Where the changes would land
I’ve already prototyped this end to end. The notable finding: the data path mostly works already.
- ansible-core — ansible-doc -t role --json already passes a return: key through untouched (the role doc builder copies the whole entry-point spec), so no change is strictly required for the data to reach doc tooling. Two things would be nice-to-have and are really the Core team’s call: (a) rendering the section in ansible-doc’s text output, and (b) officially documenting/“blessing” the return: key in the role arg-spec format.
- antsibull-docs — needs to parse and render the return: block. Prototyped in antsibull-docs#491.
- ansible-lint — its role-arg-spec.json schema currently has additionalProperties: false and no return property, so it rejects the key. This would need an optional return property added, otherwise roles using it fail schema[role-arg-spec].
I ealize why the decision to avoid adding return: for roles was made - they don’t return values the way modules do, however in linux-system-role it’s a common practice for the roles to set Variables for users to see the current configuration, or whether reboot is needed, or other extra info. I think it’s the time to add this support.
If there’s agreement on the direction, I’m happy to open PRs with the implementation across the three repos (antsibull-docs, ansible-lint schema, and any ansible-core doc/text-output changes).
What do you think? Do you have any concerns about adding return: for roles?
Thank you