Where it earns its place in production, where it bites, and how to run your first change safely.
netdaemons.com · Network Engineering Deep Dives · Article #31 · 25 September 2026

Two access switches that should be identical never stay that way. One misses an NTP line during a late-night change, the other picks up a stray ACL entry, and nobody notices until an audit or an outage exposes the difference. Network automation with Ansible attacks the cause: a reviewed, version-controlled statement of intended state, applied and re-checked the same way on every device.
Get it wrong and you inherit new failure modes: playbooks that report a change on every run, check-mode output trusted more than it deserves, credentials in plain text, and a fleet-wide push with no canary. Get it right and a change window becomes a diff review, compliance becomes a scheduled job, and a new site becomes a template render instead of a two-day copy-paste.
| Disclaimer: General: Researched by the NetDaemons team at time of writing (September 2026). Ansible, its collections and network operating systems change often, so options and output can differ from what is shown; verify against current vendor and Ansible documentation, and test in a lab before production. Pricing: No prices are stated; course and exam fees vary by provider, region, tax and currency. Availability: Courses, sandbox slots and lab images are subject to provider availability. Verdicts: Recommendations are the independent opinion of the NetDaemons team; readers decide for themselves. This article contains no affiliate links. |
The Concept: What Network Automation with Ansible Actually Automates
Ansible is push-based and agentless. A control node reads an inventory (which devices), runs a playbook (what to do) and executes modules (units of work) against each device. Most network operating systems cannot run Python, so network modules execute on the control node and reach the device over SSH (CLI, or NETCONF per RFC 6241 and RFC 6242) or an HTTPS API.
What matters to an engineer is where idempotence (a second run changes nothing) comes from. A network module must compare your intent with the device’s configuration, and how it does that depends on the module family:
- Command and config modules (ios_command, ios_config) work on text. ios_config compares your lines with the running configuration as text, so syntax must match exactly.
- Resource modules (ios_vlans, ios_interfaces) take structured data and a state: merged, replaced, overridden, deleted, gathered, rendered or parsed. The last three change nothing on the device.
Our position: use a resource module wherever one exists, and keep ios_config for the long tail. Structured data is easier to review, test and compare than CLI text.
How It Actually Works
Three variables carry the network-specific weight: ansible_connection (how to talk to the device), ansible_network_os (which collection’s modules apply) and the credentials.
| Connection value | Protocol | Notes |
| ansible.netcommon.network_cli | CLI over SSH | The most common method. Needs an SSH library on the control node. |
| ansible.netcommon.netconf | XML over SSH | NETCONF (RFC 6241, RFC 6242). Junos configuration modules rely on it. |
| ansible.netcommon.httpapi | API over HTTP/HTTPS | For platforms with a web API, such as Arista eAPI. |
Install the SSH library explicitly: pip install ansible ansible-pylibssh. The ansible package does not pull one in for network_cli, and the plugin’s paramiko fallback is deprecated. Then set the platform once, in group variables:
# group_vars/ios.yml
ansible_connection: ansible.netcommon.network_cli
ansible_network_os: cisco.ios.ios
ansible_become: true
ansible_become_method: enable
ansible_command_timeout: 60
The working loop is dry run, canary, apply, verify:
ansible-playbook -i inventory.yml site.yml –limit sw01 –check –diff
ansible-playbook -i inventory.yml site.yml –limit sw01
ansible-playbook -i inventory.yml site.yml
Check mode asks each module what it would change without changing anything. Treat it as a hint, not a guarantee: diff detail in check mode varies by module, platform and version. Add backup: true to save the running configuration to the control node before each change, and diff_against: intended to turn the same module into a drift detector.
The uses that pay off first are the low-risk ones: scheduled configuration backups, read-only fact gathering, management baselines (NTP, AAA, logging), VLAN and interface standardisation through resource modules, and drift reports. A multi-vendor estate keeps one playbook shape and swaps the collection per platform.
Three questions come up constantly. Where do I start? With backups and read-only facts, where a failure costs nothing. Ansible or Python? Ansible for repeatable state; Python libraries such as Netmiko and NAPALM for one-off logic. They combine well. Rollback? On IOS that is your job: backup gives you the file, and the restore play is one you must test. Junos offers confirm, covered below.
Where Engineers Get This Wrong
- Abbreviated commands. shut instead of shutdown makes the module see a difference on every run. The ios_config documentation says abbreviated commands are not idempotent, and Ansible’s network FAQ explains the resulting changed=true.
- Overridden state on a whole resource. Ansible’s documentation warns it can cut your own access, for example by overriding the management interface. Prefer merged, or replaced scoped to named instances.
- Trusting check mode. Verify it per platform, as the callout below shows.
- The 30-second command timeout. Saving a large configuration can exceed it. Ansible’s troubleshooting guide uses copy running-config startup-config with ansible_command_timeout: 60 as its example.
- Jump hosts and repeated running-config pulls. With a jump host, Ansible opens a new SSH connection for every task, and show running-config is the most resource-intensive command you can send. Ansible’s network FAQ flags both.
- Plain-text credentials. Use ansible-vault encrypt_string or your controller’s credential store, and keep the vault password out of Git.
| Industry pattern — public reports. The same complaints recur in public trackers and forums. An older GitHub issue describes ios_config reporting a change on every run although the device already held the line. A Cisco Community thread reports save_when: modified writing the configuration on every run. An ansible.netcommon issue reports check mode with –diff warning that it cannot diff against the running configuration. A DEV Community walkthrough advises re-running a playbook and treating any second-run change as non-idempotent. Some reports predate current module versions; the lesson stands: test idempotence and dry-run behaviour per module and release. |
Design Considerations for Production Networks
Source of truth and Git. Keep inventory, variables and playbooks in Git; Ansible’s own guide recommends it for the audit trail and for rolling back mistakes. At scale, generate inventory from a source of truth such as NetBox, which has a collection in the Ansible index.
Scale. The default is five forks, so fifty devices run in batches of five. Raise –forks to what your control node’s memory and CPU allow. Use strategy: free when one slow device stalls every task, and keep the default linear strategy when each task must succeed everywhere first. serial batches set your blast radius.
Control-plane redundancy. The control node is a single point of failure for change, not for traffic. Run from a controller or an execution environment (a container image with pinned Ansible and collection versions) so an upgrade never changes behaviour mid-quarter.
Vendor behaviour differs. On classic IOS and IOS-XE CLI, each line applies to the running configuration immediately; a bad line bites at once. Junos stages changes in a candidate configuration, and junos_config exposes commit confirmed through confirm (minutes), which needs NETCONF enabled. Resource-module coverage also varies by platform, so read the platform page before reusing a pattern from another vendor.
A moving target. Collections release on their own schedule, separate from ansible-core, so behaviour changes with collection versions. Two current examples: the paramiko fallback in network_cli is deprecated in favour of ansible-pylibssh, and ios_config will stop rendering Jinja2 in src from January 2028, so pass rendered text through content instead. Pin versions and read changelogs before upgrading.
A Real-World Scenario
Worked example, not a customer deployment: baseline NTP and syslog on a campus of IOS-XE access switches, then watch for drift. Addresses come from the RFC 5737 documentation range.
# baseline.yml
—
– name: Management baseline
hosts: access_switches
gather_facts: false
serial: [1, “25%”, “100%”]
max_fail_percentage: 0
tasks:
– name: Apply NTP and syslog
cisco.ios.ios_config:
lines:
– ntp server 192.0.2.123
– logging host 192.0.2.50
backup: true
save_when: changed
– name: Verify the NTP server is configured
cisco.ios.ios_command:
commands: show ntp associations
wait_for: result[0] contains 192.0.2.123
retries: 6
interval: 10
Run it in this order: commit to Git and run ansible-playbook –syntax-check; dry-run one switch with –limit sw01 –check –diff; apply to that switch and read the file in backup/; run it again and require changed=0; then run the group. serial sends one switch, then 25%, then the rest, and max_fail_percentage: 0 stops the rollout at the first failure. The verify task is a presence check, not a synchronisation check; tighten wait_for once you know your output.
Then schedule the drift check nightly, with –diff so the result is readable:
– name: Compare running-config with the intended config
cisco.ios.ios_config:
diff_against: intended
intended_config: “{{ lookup(‘file’, ‘master.cfg’) }}”
Certification Angle
Red Hat EX457 (exam page; Certified Specialist in Ansible Network Automation) is a hands-on, performance-based exam with no internet access, so practise reading module documentation offline with ansible-doc and confirm on Red Hat’s page which tooling the exam provides. Cisco 300-435 ENAUTO (exam page) counts as a concentration exam for CCNP Enterprise, according to Cisco, and covers programmability broadly; check its current topics for how much Ansible it examines. Juniper’s DevOps track (JNCIA-DevOps, JNCIS-DevOps) covers Junos automation, and Global Knowledge lists Ansible among the JNCIS-DevOps objectives.
Exams test tool concepts: inventory, variables, module families, idempotence. Production also needs canaries, rollback, credential handling and drift control, which no exam scores well. If you are studying, know the resource-module states cold, along with –check semantics, vault and group_vars precedence. Take EX457 only if the employers you target ask for it.
Recommended Study and Lab Resources
- Ansible Network Getting Started and Network Advanced Topics — free and maintained by the project. Read “How Network Automation is Different” and your OS’s platform page before anything else.
- Cisco DevNet Sandbox — free hosted labs, reached over VPN for reservation labs. The Cisco Modeling Labs sandbox loads an IOS-XE, IOS-XR, NX-OS and ASA topology, enough to rehearse every play above. Sessions are time-limited.
- Red Hat DO457 — the course behind EX457, covering Git, roles and automation controller across Cisco, Juniper and Arista. Its page says it is based on Ansible Automation Platform 2.3, so check the current version before paying.
Team NetDaemons Verdict
The following reflects the independent assessment of the NetDaemons team.
| NetDaemons take: A playbook earns trust on its second run, not its first. This week, pick one lab device, run one change twice, and do not widen the scope until the second run reports changed=0. |
Related Articles
- Best Network Certifications 2026: CCNA vs JNCIA vs CompTIA Network+ — netdaemons.com
- What is SD-WAN? Complete Guide for Global IT Managers — netdaemons.com
- How to Set Up a VLAN at Home: Engineer’s Step-by-Step — netdaemons.com
- Network Automation With Python — Coming Soon
netdaemons.com · Network Engineering Deep Dives · September 2026 · See full disclaimer above. Software behaviour and course details change — verify against current documentation. This article contains no affiliate links.



