--diff, and Producing Evidence for Change Review
Scenario: A change request says 'update nginx configuration'. The reviewer approves it. The change also rotated a TLS cipher list and disabled HTTP/2, because nobody looked at the rendered output.
New words, in plain English
--diff- shows the actual before/after content of every file a task would change.no_log- suppresses a task's output, used to keep secrets out of logs.- Change evidence - an artefact showing precisely what a change does, produced by the tooling rather than written by hand.
--limitcanary - applying a change to one host first to observe the result.
--check --diff produces something a description cannot: the exact bytes that will change, on each host, generated from the real current state.
Used properly this replaces a whole class of review theatre. Instead of "update nginx configuration", the change record carries the rendered diff - and the reviewer can see the cipher change and the HTTP/2 line that the summary omitted.
The practical workflow for anything risky:
--check --diff --limit web01- see what it would do to one host.--limit web01- do it to that one host, and observe the service.- Full run, with
serialset, so the blast radius stays bounded.
One caveat: --diff prints file contents, which will include secrets if your templates render them. no_log: true on a task suppresses its output entirely - necessary for credential-handling tasks, and painful when debugging, so apply it to the specific task rather than the whole play.
Analogy: A change description is the estate agent's summary. --diff is the survey. Approving the summary without reading the survey is how people discover the subsidence after they have moved in.
A worked example
# Generate reviewable evidence, changing nothing
ansible-playbook site.yml --check --diff --limit web01
# TASK [Render the nginx configuration] ****************
# --- before: /etc/nginx/nginx.conf
# +++ after: /etc/nginx/nginx.conf
# @@ -12,7 +12,7 @@
# - ssl_ciphers HIGH:!aNULL:!MD5;
# + ssl_ciphers ECDHE-RSA-AES256-GCM-SHA384;
# - listen 443 ssl http2;
# + listen 443 ssl;
# changed: [web01]
# Keep credentials out of the diff and the log
- name: Deploy the API credential
ansible.builtin.template:
src: creds.j2
dest: /etc/app/creds
mode: "0600"
no_log: true
In CI, running --check --diff on every pull request and attaching the output to the review turns "what does this change do?" into a mechanical answer. Where the estate is large, running it against a representative subset with --limit keeps it fast enough to be habitual.
Be aware that --check cannot predict everything. A task whose behaviour depends on the result of an earlier task that was skipped in check mode will report inaccurately, and a module that does not support check mode is simply skipped. Read the dry run as strong evidence, not as proof.
Tip: Attach the --check --diff output to the change request. It is generated evidence rather than a written claim, and it takes no extra effort to produce.
Goal: Put this to work in the ansible-check-mode-safety lab. Open/labs/ansible, pickansible-check-mode-safety, and fix the real broken project - Ansible really does SSH into four managed hosts and converge them.