What's changed: Initial version
5.3Reading automation workflows
Builds the ability to read a given Python (requests/SDK) script, Ansible playbook, or bash script and determine "what it automates, on which devices, and how." From hosts/tasks/modules/loops/backup/when conditions you judge whether it is idempotent config delivery, information gathering, or backup, and learn to spot dangerous operations (unconditional save/reload).
The exam asks not "what is Ansible" but what the playbook or script in front of you actually does. Even if you cannot write code, if you cannot read it you can neither review nor troubleshoot. This section reads three kinds—Ansible playbook, Python, and bash—from their elements (targets, modules, loops, conditions), so you can judge whether it is idempotent config delivery, information gathering, or backup, and whether a dangerous operation is mixed in.
5.3.1Reading an Ansible playbook
- A playbook's skeleton is
hosts:(target group) ->tasks:(work run in order). Each task's module name decides what it does:ios_config= push configuration,ios_command= run a command and capture output,ios_facts= gather device info.name:is a descriptive label, so reading the module name first is the key. - If
ios_confighasbackup: yes, the intent is to back up the current config before applying the change. Aloop:orwith_items:means repeating the same work over multiple VLANs/IFs/devices. Many modules are idempotent, reportingchanged: falseand not double-applying when the desired state already holds. when:is conditional execution (e.g.,when: ansible_net_version is version('17.3', '<')applies only to older IOS-XE). Read for dangerous operations too: an unconditionalsave_when: alwaysor a devicereloadincludes an irreversible/high-impact write or reboot, deserving special scrutiny in review.
5.3.2Reading Python (requests/SDK)
- Read intent from the HTTP method:
requests.get(...)= fetch info (read-only, safe),requests.post(...)= create,requests.put(...)= replace,requests.delete(...)= delete. Afor device in devices:loop repeating the same call across devices reveals a cross-device bulk operation. - Read how success/failure is handled from response processing:
resp.raise_for_status()orif resp.status_code 200:shows error handling is considered. Aggregating/printing results received viaresp.json()indicates a collection/reporting script, while building a body andpost/put-ing indicates a change-making script.
5.3.3Reading a bash script
- In bash, look at loops plus external commands:
for ip in $(cat devices.txt); do ... doneruns work for each device in a list. If it usesssh/scpinside and dumpsshow runoutput to a file, it is a config backup; if it collectspingresults, it is liveness monitoring/collection. - Read the artifact from redirects and dates:
> backup-$(date +%F).cfggenerates a dated backup file. If run periodically viacrontab, it is scheduled backup operations. Also check for destructive signs (rm -rf, overwriting an existing file with>).
Most-tested: read a playbook's intent from hosts plus task module names (ios_config = deliver / ios_command = fetch / ios_facts = gather); backup: yes = back up before apply; loop = repeat over multiple targets; when = conditional execution; most are idempotent with changed: false; in Python get = read vs. post/put = change, and bash uses for plus ssh/scp for bulk work. You are asked to read code and say what it automates, more than to write it.
A colleague asks you to review this Ansible playbook: against - hosts: access_switches, there are two tasks:. The first, name: Configure guest VLAN, gives the ios_config module lines: (vlan 30 / name GUEST) with backup: yes, iterating a list of target VLANs via loop:. The second, name: Save if changed, takes the result of ios_config with save_when: changed. Reading what it automates: it is a workflow that "standardizes and idempotently distributes a guest VLAN to the access switches, saves the config only if a change occurred, and backs up the current config before applying." Because ios_config is idempotent, devices already correctly having VLAN 30 report changed: false and are not saved—a safe design. If the colleague then says "to be safe, make the second task save_when: always so it always saves, and add a reload while we are at it," as a reviewer you should stop it. save_when: always runs a write every time even with no change, undermining idempotency's benefit (do nothing if unchanged), and an unconditional reload mixes a hugely impactful, irreversible reboot of every access switch into what should be a non-disruptive VLAN addition. The reading method is to walk hosts (to whom), module names (what), and backup/loop/when/save_when (how, under what condition) in order, and to articulate the net effect of this code and any danger mixed in. Were this Python, you would read get vs. post/put for read/change; were it bash, for plus ssh for bulk backup vs. collection—the same framework.
| Element | Intent it reveals | What to watch for |
|---|---|---|
| `hosts:` / loop target | Which device group it applies to (scope) | Is the scope too broad? |
| Module name | ios_config = deliver / ios_command = fetch / ios_facts = gather | Change-making or read-only? |
| `backup: yes` | Back up current config before apply | Is a recovery path provided? |
| Idempotency/`changed` | No change if desired state holds (changed: false) | Do not misread no-change as failure |
| `save_when: always` / `reload` | Write every time / reboot (high impact) | Irreversible or excessive? |
Trap: "changed: false appeared, so the playbook failed" is wrong—an idempotent module makes no change and finishes normally when the desired state already matches (indeed a sign of safety). Also insufficient: "read name: to know what it does"—name: is only a descriptive label, and the real behavior is decided by the module name (ios_config/ios_command, etc.). An unconditional save_when: always or reload is high-impact, so flag in review that it writes/reboots every time even with no change.
5.3.4Section summary
- Read a playbook's intent from
hosts(targets) plus task module names (ios_config = deliver / ios_command = fetch / ios_facts = gather), and grasp "how" frombackup/loop/when/save_when - An idempotent module finishes normally with
changed: falseif the desired state holds (not a failure); do not misread no-change as failure - In Python, get = read / post/put = change; in bash, for plus ssh/scp for bulk backup/collection. In review, spot high-impact operations like an unconditional
save_when: alwaysorreload
Sign in to track progress — Log in.
Quick check
(just a quick review)Q1. An Ansible playbook applies, against `- hosts: access_switches`, the `ios_config` module with `vlan 30` / `name GUEST`, `backup: yes`, and a `loop:` over a VLAN list, followed by a task with `save_when: changed`. Which best describes what it automates?
Q2. An Ansible run reports "changed: false" for 7 of 10 targets and "changed: true" for 3, using an idempotent module to distribute config. What is the most appropriate interpretation?
Q3. While reviewing a VLAN-addition playbook, a colleague proposes "to be sure, set the save task to `save_when: always` and append a `reload` (reboot) of all target devices." What is the most appropriate reviewer judgment?
Keep track of your progress
The full study guide is free to read. Sign up free to practice with the question bank, track what you have read, review your mistakes, and highlight passages.

