A green run is not a correct machine — cheat sheet
ansible
# the two tests that matter
ansible-playbook site.yml && ansible-playbook site.yml | tail -1 # second run: changed=0
ansible-playbook site.yml --check --diff # what would change, as a diff
# (shell/command tasks are SKIPPED in check mode; check_mode: false to run read-only ones)
# narrowing down
ansible-playbook site.yml | grep -B1 changed: # which tasks change on a no-op run
ansible-playbook site.yml --list-tasks
ansible-playbook site.yml --start-at-task "Environment file"
ansible-playbook site.yml -l web01 -v # one host, more output
ansible web -m ping ; ansible web -b -m command -a "cat /etc/app/app.env" # ad hoc
# handlers
# notify: Restart app ← must equal the handler's name exactly (or use listen:)
ansible-playbook site.yml --force-handlers # run notified handlers even if the play fails
# - ansible.builtin.meta: flush_handlers ← run pending handlers now, mid-play
# modules that own state instead of commands that guess
# template a whole file you own (with {{ ansible_managed }} at the top)
# lineinfile + regexp one line in a file someone else owns (replaces the LAST match only)
# systemd_service enabled / state: started|restarted, daemon_reload
# command/shell creates:, removes:, changed_when:, register: + when:
# variables, low to high (the four that bite)
# roles/x/defaults/main.yml < inventory group_vars < play vars: < -e (extra vars, strings!)
# roles/x/vars/main.yml outranks inventory — do not put overridable values there
ansible-playbook site.yml -e '{"app_port": 9999}' # JSON keeps the type
ansible web -m ansible.builtin.debug -a "var=app_port"