AnsiblePilot — Master Ansible Automation

AnsiblePilot is the leading resource for learning Ansible automation, DevOps, and infrastructure as code. Browse over 1,400 tutorials covering Ansible modules, playbooks, roles, collections, and real-world examples. Whether you are a beginner or an experienced engineer, our step-by-step guides help you automate Linux, Windows, cloud, containers, and network infrastructure.

Popular Topics

About Luca Berton

Luca Berton is an Ansible automation expert, author of 8 Ansible books published by Apress and Leanpub including "Ansible for VMware by Examples" and "Ansible for Kubernetes by Example", and creator of the Ansible Pilot YouTube channel. He shares practical automation knowledge through tutorials, books, and video courses to help IT professionals and DevOps engineers master infrastructure automation.

AAP 2.6 Network Automation: Cisco, Arista, Juniper, and Multi-Vendor Management

By Luca Berton · Published 2024-01-01 · Category: troubleshooting

Automate network infrastructure with AAP 2.6. Configure Cisco IOS/NX-OS, Arista EOS, Juniper Junos, and multi-vendor environments.

Network Automation with AAP 2.6

AAP 2.6 provides enterprise-grade network automation for multi-vendor environments. Unlike server automation (SSH-based), network automation uses specialized connection plugins and collections designed for network device APIs and CLIs.

See also: Ansible Network Automation: Configure Cisco, Arista, and Juniper at Scale

Connection Methods

ConnectionProtocolUse Case
ansible.netcommon.network_cliSSH CLITraditional CLI-based devices
ansible.netcommon.netconfNETCONF (SSH)Juniper, Nokia, structured config
ansible.netcommon.httpapiREST APIArista eAPI, Cisco NX-API
ansible.netcommon.libsshSSH (libssh)High-performance SSH

Execution Environment for Network

---
version: 3
images:
  base_image:
    name: registry.redhat.io/ansible-automation-platform-26/ee-minimal-rhel9:latest
dependencies:
  galaxy:
    collections:
      - name: ansible.netcommon
        version: ">=7.0.0"
      - name: ansible.utils
        version: ">=5.0.0"
      - name: cisco.ios
        version: ">=9.0.0"
      - name: cisco.nxos
        version: ">=9.0.0"
      - name: cisco.asa
      - name: arista.eos
        version: ">=10.0.0"
      - name: junipernetworks.junos
        version: ">=9.0.0"
      - name: vyos.vyos
      - name: community.network
  python:
    - paramiko>=3.0
    - netmiko>=4.0
    - ncclient>=0.6
    - jmespath>=1.0
    - netaddr>=1.0
    - textfsm>=1.1
    - ntc-templates>=6.0
    - xmltodict>=0.13
  system:
    - openssh-clients [platform:rpm]
    - libxml2 [platform:rpm]
    - libxslt [platform:rpm]

Inventory for Network Devices

Static Network Inventory

- name: Create network inventory
  ansible.platform.inventory:
    controller_host: "{{ gateway_url }}"
    controller_username: "{{ controller_user }}"
    controller_password: "{{ controller_pass }}"
    name: "Network Infrastructure"
    organization: "Network Operations"
    state: present

# Cisco IOS group
- name: Create Cisco IOS group
  ansible.platform.group:
    name: "cisco_ios"
    inventory: "Network Infrastructure"
    variables:
      ansible_network_os: cisco.ios.ios
      ansible_connection: ansible.netcommon.network_cli
      ansible_become: true
      ansible_become_method: enable
    state: present

# Arista EOS group
- name: Create Arista EOS group
  ansible.platform.group:
    name: "arista_eos"
    inventory: "Network Infrastructure"
    variables:
      ansible_network_os: arista.eos.eos
      ansible_connection: ansible.netcommon.httpapi
      ansible_httpapi_use_ssl: true
      ansible_httpapi_validate_certs: false
      ansible_become: true
      ansible_become_method: enable
    state: present

# Juniper Junos group
- name: Create Juniper Junos group
  ansible.platform.group:
    name: "juniper_junos"
    inventory: "Network Infrastructure"
    variables:
      ansible_network_os: junipernetworks.junos.junos
      ansible_connection: ansible.netcommon.netconf
    state: present

Network Credential

- name: Create network credential
  ansible.platform.credential:
    controller_host: "{{ gateway_url }}"
    controller_username: "{{ controller_user }}"
    controller_password: "{{ controller_pass }}"
    name: "Network SSH"
    organization: "Network Operations"
    credential_type: "Machine"
    inputs:
      username: "ansible"
      password: "{{ vault_network_password }}"
      become_password: "{{ vault_enable_password }}"
    state: present

See also: Using the AAP 2.6 Self-Service Portal for Network Automation

Configuration Backup

Multi-Vendor Backup Playbook

---
- name: Backup network device configurations
  hosts: all
  gather_facts: false

  tasks:
    - name: Backup Cisco IOS
      cisco.ios.ios_config:
        backup: true
        backup_options:
          filename: "{{ inventory_hostname }}_{{ ansible_date_time.date }}.cfg"
          dir_path: /var/backups/network/
      when: ansible_network_os == 'cisco.ios.ios'

    - name: Backup Arista EOS
      arista.eos.eos_config:
        backup: true
        backup_options:
          filename: "{{ inventory_hostname }}_{{ ansible_date_time.date }}.cfg"
          dir_path: /var/backups/network/
      when: ansible_network_os == 'arista.eos.eos'

    - name: Backup Juniper Junos
      junipernetworks.junos.junos_config:
        backup: true
        backup_options:
          filename: "{{ inventory_hostname }}_{{ ansible_date_time.date }}.cfg"
          dir_path: /var/backups/network/
      when: ansible_network_os == 'junipernetworks.junos.junos'

    - name: Push backups to Git
      ansible.builtin.shell: |
        cd /var/backups/network/
        git add -A
        git commit -m "Network backup {{ ansible_date_time.iso8601 }}" || true
        git push
      delegate_to: localhost
      run_once: true

Configuration Management

Cisco IOS Configuration

- name: Configure Cisco IOS switches
  hosts: cisco_ios
  gather_facts: false

  tasks:
    - name: Configure hostname and domain
      cisco.ios.ios_hostname:
        config:
          hostname: "{{ inventory_hostname }}"
          domain_name: example.com

    - name: Configure NTP
      cisco.ios.ios_ntp_global:
        config:
          servers:
            - server: 10.1.1.1
              prefer: true
            - server: 10.1.1.2

    - name: Configure SNMP
      cisco.ios.ios_snmp_server:
        config:
          communities:
            - name: "{{ vault_snmp_community }}"
              ro: true
              acl_v4: SNMP_ACL
          hosts:
            - host: 10.1.1.100
              version: "2c"
              community_string: "{{ vault_snmp_community }}"

    - name: Configure interfaces
      cisco.ios.ios_l3_interfaces:
        config:
          - name: Loopback0
            ipv4:
              - address: "{{ loopback_ip }}/32"
          - name: GigabitEthernet0/1
            ipv4:
              - address: "{{ mgmt_ip }}/24"

    - name: Configure ACLs
      cisco.ios.ios_acls:
        config:
          - afi: ipv4
            acls:
              - name: MGMT_ACCESS
                aces:
                  - grant: permit
                    protocol_options:
                      tcp:
                        ssh: true
                    source:
                      address: 10.0.0.0
                      wildcard_bits: 0.0.0.255
                    destination:
                      any: true
                    sequence: 10
                  - grant: deny
                    source:
                      any: true
                    destination:
                      any: true
                    sequence: 999

Arista EOS Configuration

- name: Configure Arista EOS switches
  hosts: arista_eos
  gather_facts: false

  tasks:
    - name: Configure BGP
      arista.eos.eos_bgp_global:
        config:
          as_number: "{{ bgp_asn }}"
          router_id: "{{ loopback_ip }}"
          neighbors:
            - neighbor_address: "{{ bgp_peer_ip }}"
              remote_as: "{{ bgp_peer_asn }}"
              description: "Uplink to Core"
              send_community:
                standard: true
                extended: true

    - name: Configure VLANs
      arista.eos.eos_vlans:
        config:
          - vlan_id: 100
            name: Management
            state: active
          - vlan_id: 200
            name: Production
            state: active
          - vlan_id: 300
            name: DMZ
            state: active

Juniper Junos Configuration

- name: Configure Juniper Junos
  hosts: juniper_junos
  gather_facts: false

  tasks:
    - name: Configure system settings
      junipernetworks.junos.junos_config:
        lines:
          - set system host-name {{ inventory_hostname }}
          - set system domain-name example.com
          - set system name-server 10.1.1.1
          - set system name-server 10.1.1.2
          - set system ntp server 10.1.1.1 prefer
          - set system syslog host 10.1.1.100 any warning

    - name: Configure firewall filter
      junipernetworks.junos.junos_config:
        src: templates/junos-firewall.j2
        comment: "Ansible managed - {{ ansible_date_time.iso8601 }}"
        confirm: 2  # Auto-rollback after 2 minutes if not confirmed

See also: Ansible NETCONF Connection Plugin: Network Configuration Protocol Complete Guide

Network Compliance Auditing

Compliance Check Playbook

---
- name: Network compliance audit
  hosts: all
  gather_facts: false

  vars:
    compliance_results: []

  tasks:
    - name: Gather device facts
      ansible.netcommon.cli_command:
        command: "{{ show_version_cmd }}"
      register: version_output
      vars:
        show_version_cmd: "{{ 'show version' if ansible_network_os != 'junipernetworks.junos.junos' else 'show version brief' }}"

    - name: Check NTP is configured
      ansible.netcommon.cli_command:
        command: "{{ ntp_cmd }}"
      register: ntp_config
      vars:
        ntp_cmd: "{{ 'show ntp associations' if ansible_network_os == 'cisco.ios.ios' else 'show ntp status' }}"

    - name: Verify SSH is enabled
      ansible.netcommon.cli_command:
        command: "show ip ssh"
      register: ssh_config
      when: ansible_network_os == 'cisco.ios.ios'

    - name: Check running vs startup config
      cisco.ios.ios_command:
        commands:
          - show archive config differences system:running-config nvram:startup-config
      register: config_diff
      when: ansible_network_os == 'cisco.ios.ios'

    - name: Flag unsaved changes
      ansible.builtin.debug:
        msg: "WARNING: {{ inventory_hostname }} has unsaved configuration changes!"
      when:
        - ansible_network_os == 'cisco.ios.ios'
        - config_diff.stdout[0] | length > 0

    - name: Generate compliance report
      ansible.builtin.template:
        src: templates/compliance-report.j2
        dest: "/var/reports/network/{{ inventory_hostname }}_compliance.html"
      delegate_to: localhost

Change Management Workflow

Use AAP workflow templates for network change management:

[Pre-Change Backup] → [Validate Change Request]
                            ↓ success
                    [Approval: Network Lead]
                            ↓ success
                    [Deploy to Lab]
                            ↓ success
                    [Verify Lab]
                         ↓ success      ↓ failure
                [Deploy to Production]  [Rollback Lab]
                     ↓ success   ↓ failure
                [Post-Change Verify] [Rollback Production]
                     ↓ success       ↓ always
                [Close Change Ticket] [Alert Network Team]

Rollback Playbook

- name: Rollback network configuration
  hosts: "{{ target_devices }}"
  gather_facts: false

  tasks:
    - name: Rollback Cisco IOS
      cisco.ios.ios_config:
        replace: config
        src: "/var/backups/network/{{ inventory_hostname }}_{{ rollback_date }}.cfg"
      when: ansible_network_os == 'cisco.ios.ios'

    - name: Rollback Juniper (automatic with commit confirmed)
      junipernetworks.junos.junos_config:
        rollback: 1
        comment: "Rollback initiated by AAP - {{ ansible_date_time.iso8601 }}"
      when: ansible_network_os == 'junipernetworks.junos.junos'

    - name: Verify connectivity after rollback
      ansible.netcommon.cli_command:
        command: "ping {{ mgmt_gateway }} repeat 5"
      register: ping_result
      failed_when: "'!!!!!' not in ping_result.stdout"
      when: ansible_network_os == 'cisco.ios.ios'

Resource Modules (Declarative Approach)

Resource modules provide idempotent, declarative network configuration:

- name: Declarative interface configuration
  cisco.ios.ios_l2_interfaces:
    config:
      - name: GigabitEthernet0/1
        mode: access
        access:
          vlan: 100
      - name: GigabitEthernet0/2
        mode: trunk
        trunk:
          allowed_vlans: "100,200,300"
          native_vlan: 1
    state: replaced  # Ensure exact match

States available for resource modules:

StateBehavior
mergedAdd/update config (default)
replacedReplace specific resource config
overriddenReplace all resources of this type
deletedRemove specific config
gatheredRead current config (no changes)
parsedParse offline config text
renderedGenerate device commands without applying

FAQ

How do I handle devices that don't support collections?

Use ansible.netcommon.cli_command and ansible.netcommon.cli_config for generic CLI-based management. These work with any device that has SSH CLI access.

Can AAP manage network devices through a jump host?

Yes. Use ansible_ssh_common_args: '-o ProxyJump=jumphost.example.com' or configure hop nodes in Automation Mesh to place execution nodes in the same network as the devices.

How do I test network changes safely?

Use Juniper's commit confirmed (auto-rollback timer), Cisco's configure replace with archive, or AAP workflow templates with lab verification before production. Resource modules with state: rendered let you preview commands without applying.

Should I use CLI or API connections?

APIs (NETCONF, eAPI, NX-API) are preferred when available — they provide structured data, transactional commits, and better error handling. CLI is universal but requires parsing unstructured text output.

Can I automate network device firmware upgrades?

Yes. Use ansible.netcommon.net_put or vendor-specific modules to upload firmware, then schedule reboot with verification. Always include rollback procedures and test in lab first.

Conclusion

AAP 2.6 provides a unified platform for multi-vendor network automation. From configuration backup and compliance auditing to automated deployments with change management workflows, AAP transforms network operations from manual CLI sessions into repeatable, auditable, self-service automation.

Category: troubleshooting

Browse all Ansible tutorials · AnsiblePilot Home