Ansible Network Modules: ios_config, Facts and Config Backup - 夜莺博客

Ansible Network Modules: ios_config, Facts and Config Backup

Ansible is the pragmatic entry point to network automation because it needs no agent and no API — just SSH. The failure modes are equally pragmatic: playbooks that are not idempotent, backups that silently overwrite each other, and configurations pushed without a rollback plan. This article shows the inventory and module patterns that hold up in production.

Inventory: network_cli, not SSH

[all:vars]
ansible_connection=ansible.netcommon.network_cli
ansible_user=ansible

[ios]
ios01.example.net
ios02.example.net

[ios:vars]
ansible_network_os=cisco.ios.ios
ansible_become=yes
ansible_become_method=enable
ansible_password=!vault |
  $ANSIBLE_VAULT;1.1;AES256
  3933623163613766396434...

Use ansible_connection=ansible.netcommon.network_cli with a per-platform ansible_network_os, and protect credentials with Ansible Vault instead of a plaintext group_vars file. Install the collection first: ansible-galaxy collection install cisco.ios.

ios_config: parents, lines and idempotency

- name: Configure interface settings
  cisco.ios.ios_config:
    lines:
      - description Uplink to Core
      - ip address 10.0.0.1 255.255.255.0
    parents: interface GigabitEthernet1/0/1

- name: Configure ip helpers on multiple interfaces
  cisco.ios.ios_config:
    lines:
      - ip helper-address 172.26.1.10
      - ip helper-address 172.26.3.8
    parents: "{{ item }}"
  loop:
    - interface Ethernet1
    - interface Ethernet2

- name: Idempotency requires full-form commands
  cisco.ios.ios_config:
    lines:
      - shutdown          # 'shut' would be treated as a new line every run
    parents: interface GigabitEthernet1/0/11

parents is what makes a module call idempotent: the module compares the child lines inside the parent section and only pushes the difference. Two rules follow from that — always use the full command form (abbreviations defeat the comparison), and use match / replace deliberately when you want the device to mirror your list exactly rather than append to it.

Backups that are actually usable

- name: Back up running configuration before any change
  cisco.ios.ios_config:
    backup: true
    backup_options:
      dir_path: /srv/backups/{{ inventory_hostname }}
      filename: "{{ lookup('pipe','date +%Y-%m-%d') }}-running.cfg"
    save_when: modified
  • Always set backup: true on the same task that changes configuration, not in a separate play that might not run.
  • Include a date in filename — the default name is fixed, so a nightly run silently overwrites yesterday’s copy.
  • save_when: modified writes startup-config only when the running config actually changed, which avoids a write on every playbook run.
  • For a fleet-wide backup without changes, use a dedicated playbook that only reads running_config and writes to disk, and keep it under version control.

Facts and conditional operations

- name: Gather facts
  cisco.ios.ios_facts:
    gather_subset: [config, hardware]

- name: Set boot image only when the version differs
  cisco.ios.ios_config:
    lines:
      - no boot system
      - boot system flash bootflash:{{ new_image }}
  when: ansible_net_version != version

- name: Report versions
  ansible.builtin.debug:
    msg: "{{ inventory_hostname }} runs {{ ansible_net_version }}"

Facts landing under ansible_net_* are what turn a playbook into a policy engine: only reload when the image changed, only touch VLANs on devices that are missing them, and only open a change ticket when drift exists. Combine this with diff_against: intended to compare running configuration with a golden file, and you have a compliance report that costs nothing to run nightly.

Related reading: Ansible network automation playbook examples, Ansible facts and configuration backup and Ansible for Cisco network automation 101.

原文链接:https://docs.ansible.com/projects/ansible/latest/collections/cisco/ios/ios_config_module.html