Files
computer-playbook/docs/contributing/artefact/files/plugins/lookup/users.md
T
kevinveenbirkenbachandClaude Opus 5 fcc98bcad1 fix(docs): require a README behind every directory link
The lint accepted a link that resolved to a file or a directory. myst
builds a document reference only when the target is_file(), so a link to
a directory without a README is a bare file listing on GitHub and a dead
cross-reference in the documentation build. It now reports which of the
two reasons applies.

The tightened rule found 41 links. Where a README backs the directory,
bd15eae9fa's resolver carries the link and it stays. Where none exists,
the link becomes a code span rather than an invented README: 15 of them
point at a role's meta/addons/, whose addon table already sits below the
sentence, and the rest at code directories such as utils/ or
cli/administration/deploy/runner/.

The changed sentences are msgids, so these entries return to the
translator on the next extract.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-25 18:42:23 +02:00

4.1 KiB
Raw Blame History

users lookup 👥

Contributor-facing rules for the users.py lookup plugin. For general documentation rules such as links, writing style, RFC 2119 keywords, and Sphinx behavior, see documentation.md.

Access Pattern 🎯

The users lookup is the ONLY supported runtime entry point for merged user configuration.

  • Runtime consumers (roles, playbooks, templates, filter plugins, lookup plugins, tests) MUST read user data via lookup('users') or a wrapper that calls it.
  • Consumers MUST NOT materialize a top-level users fact via ansible.builtin.set_fact, combine, or any custom aggregation task.
  • Consumers MUST NOT reintroduce group_vars/all/04_users.yml or any equivalent generated dictionary file.

Lookup Forms 🧭

Form Returns
lookup('users') Full merged mapping keyed by the canonical user key.
lookup('users', '<canonical_user_key>') Merged entry for that user. Raises when missing.
lookup('users', '<canonical_user_key>', default_value) Merged entry, or default_value when the entry is missing.

Data Sources 📚

The lookup merges exactly two sources:

  1. Defaults discovered from every roles/*/meta/users.yml in the repository (file root IS the users map; no users: wrapper).
  2. Overrides supplied through the normal Ansible variable users in inventory, group vars, host vars, or role vars.

No intermediate merged users fact exists. No other source is consulted.

Canonical User Key 🔑

  • The canonical key is the mapping key used at the file root of roles/*/meta/users.yml.
  • The canonical key is NOT the rendered username field inside the value.
  • The canonical key is the same identifier that inventory, group vars, host vars, and role vars MUST use when overriding an entry.
  • You MUST NOT introduce a new keying scheme.

Adding a User Entry ➕

You MUST add new user defaults in the owning role:

  1. Create or edit roles/<role_id>/meta/users.yml.

  2. Add the user at the file root, keyed by its canonical key (no users: wrapper):

    # roles/<role_id>/meta/users.yml
    administrator:
      username: administrator
      roles:
        - admin
    
  3. Keep generated fields (UID, GID, email, description, password) unset when the shared aggregation logic SHOULD allocate or template them. Set them explicitly only when the role requires a specific value.

The lookup discovers the entry automatically on the next run. No generator step is required.

Overriding a User Entry 🛠️

You MUST override user values through the normal Ansible variable users:

# group_vars/<group>.yml or host_vars/<host>.yml
users:
  administrator:
    email: admin@example.org
  • Overrides MUST use the canonical user key.
  • Overrides merge recursively on top of role-local defaults.
  • Overrides MUST NOT be written back into roles/*/meta/users.yml; that file is for defaults only.

What Not To Do 🚫

  • You MUST NOT create group_vars/all/04_users.yml or any similar generated users dictionary.
  • You MUST NOT add a make target, script, or role task whose purpose is to generate, render, merge, or rewrite such a file.
  • You MUST NOT key user overrides by username; use the canonical key.
  • You MUST NOT reintroduce default_users or defaults_users references; they do not exist anymore.

Source Of Truth 📌

File Purpose
users.py Runtime entry point for the users lookup.
utils/cache/users/ Shared aggregation helper package that builds and caches defaults, handles reserved users, UID/GID allocation, and uniqueness validation. Placeholder substitution (DOMAIN_PRIMARY / ORGANIZATION / SOFTWARE_NAME) lives in users/placeholders.py.
test_users.py Unit tests covering the full-dict, single-entry, override, strict missing, and non-strict missing cases.

For the related applications pattern see applications.md.