Skip to main content
RunBook Academy

← All checklists in Ansible

Before deploymentDeployment

Checklist: Inventory readiness

17 items ·13 critical ·2 warn ·2 info

Run this when an inventory is first created, whenever a group is added or restructured, and before any change whose blast radius depends on group membership - which is all of them. It takes a few minutes and it is the cheapest way to find out that the group you are about to target contains four hosts more than you thought.

The commands assume inventories/production/ and inventories/staging/ with group_vars/ inside each. jq is required for the counting checks.

What a failure means

An inventory defect does not look like a defect. It looks like a successful run. A group_vars directory whose name does not match any group loads nothing and reports nothing; a pattern that matches no hosts exits 0 from an ad-hoc command; a stale dynamic inventory returns a plausible list of hosts that is simply out of date.

That is why almost everything here is critical. These are not checks against things going wrong - they are checks against things going quietly right in the wrong place.

Access this needs

Every command is read-only. The two that connect to hosts are the retired-host sweep, which runs the ping module, and the pattern test, which only lists. The ping module executes on the target and changes nothing, but it does open an SSH connection to every host in the inventory, so run it when a fleet-wide connection attempt is acceptable.

Where the evidence goes

Attach the --graph output and the per-group counts to the change record. A count is the thing a reviewer can actually check against the ticket, and it is the number the pre-execution checklist compares against sixty seconds before the run.

Sign-off

  • Operator: _________________ Date: ___________
  • Reviewer: ________________ Date: ___________

Critical13 items

  1. ansible-inventory -i inventories/production --graph
  2. ansible-inventory -i inventories/production --list | jq -r 'to_entries[] | select(.key != "_meta" and .value.hosts) | "\(.key)\t\(.value.hosts | length)"'
  3. ansible-inventory -i inventories/production --list | jq -r '.ungrouped.hosts // [] | .[]'
  4. comm -12 <(ansible -i inventories/production all --list-hosts | tail -n +2 | tr -d ' ' | LC_ALL=C sort) \
             <(ansible -i inventories/staging   all --list-hosts | tail -n +2 | tr -d ' ' | LC_ALL=C sort)
  5. ansible-inventory -i inventories/production --list \
      | jq -r '._meta.hostvars | to_entries[] | select(.value.ansible_host) | "\(.value.ansible_host) \(.key)"' \
      | LC_ALL=C sort \
      | awk '{c[$1]=c[$1]" "$2} END {for (a in c) if (split(c[a],x," ")>1) print "FINDING: " a " is shared by" c[a]}'
  6. comm -23 <(ls inventories/production/group_vars | sed 's/\.ya\?ml$//' | LC_ALL=C sort -u) \
             <(ansible-inventory -i inventories/production --list | jq -r 'keys[]' | grep -v '^_meta$' | LC_ALL=C sort -u)
  7. grep -rIlE '(pass|password|secret|token|api_key|private_key)' \
      inventories/*/group_vars inventories/*/host_vars 2>/dev/null \
      | while read -r f; do
          head -c 14 "$f" | grep -q '\$ANSIBLE_VAULT' \
            || echo "FINDING: $f names a credential and is not vault-encrypted"
        done
  8. cat inventories/production/group_vars/all/*.yml 2>/dev/null || ls inventories/production/group_vars/
  9. ansible-inventory -i inventories/production --host web01.example.com
  10. ansible-inventory -i inventories/production --list --output /dev/null && ansible-config dump | grep -E 'CACHE|INVENTORY'
  11. ansible-inventory -i inventories/production --list | jq '[.[] | objects | .hosts // empty] | flatten | length'
  12. git -C . status --porcelain inventories/ ; git -C . log -1 --format='%H %ci %an' -- inventories/
  13. ansible-playbook -i inventories/production playbooks/deploy.yml --limit web --list-hosts

Warning2 items

  1. ansible-inventory -i inventories/production --list | jq -r '._meta.hostvars | to_entries[] | "\(.key): \(.value | with_entries(select(.key | startswith("ansible_"))))"'
  2. ansible -i inventories/production all -m ansible.builtin.ping --one-line | grep -v 'SUCCESS'

Info2 items

  1. ansible-inventory -i inventories/production --graph