Instiq
Chapter 5 · Infrastructure and Automation·v1.0.0·Updated 7/20/2026·~17 min

What's changed: Initial version

5.3Reading automation workflows

Key points

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_config has backup: yes, the intent is to back up the current config before applying the change. A loop: or with_items: means repeating the same work over multiple VLANs/IFs/devices. Many modules are idempotent, reporting changed: false and 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 unconditional save_when: always or a device reload includes 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. A for 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() or if resp.status_code 200: shows error handling is considered. Aggregating/printing results received via resp.json() indicates a collection/reporting script, while building a body and post/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 ... done runs work for each device in a list. If it uses ssh/scp inside and dumps show run output to a file, it is a config backup; if it collects ping results, it is liveness monitoring/collection.
  • Read the artifact from redirects and dates: > backup-$(date +%F).cfg generates a dated backup file. If run periodically via crontab, it is scheduled backup operations. Also check for destructive signs (rm -rf, overwriting an existing file with >).
Exam point

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.

ElementIntent it revealsWhat to watch for
`hosts:` / loop targetWhich device group it applies to (scope)Is the scope too broad?
Module nameios_config = deliver / ios_command = fetch / ios_facts = gatherChange-making or read-only?
`backup: yes`Back up current config before applyIs 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?
Warning

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.

Reading Ansible playbooks, Python, and bash from their elements.
Reading intent from module names, methods, conditions

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" from backup/loop/when/save_when
  • An idempotent module finishes normally with changed: false if 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: always or reload

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?

Check your understandingPractice questions for Chapter 5: Infrastructure and Automation

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.