Ansible Playbook for Network OS Upgrade with pre and post checks

You have 100s of network switches or routers that you need to upgrade. How much time would it take for you to do the upgrades? There are a lot number of sub-tasks involved while upgrading IOS image of a Cisco router or a switch.

This time of upgradation can be reduced through automation from various Enterprise Configuration Management tools that also have ability to upgrade network OS. Though these tools give an easy to use graphical interface, but this requires you to have appropriate license and also restricts you to customize your upgrade process.

Ansible is one of the tool that can be used and the upgrade process can also be customized to include any tasks that you want, e.g. taking pre-checks, post-checks and then comparing them and highlighting the differences, etc.

Following is the Ansible-playbook for IOS upgradation, that includes following sub-tasks. More tasks can be included as per need.

IOS upgrade tasks included in the playbook

  1. Verify the current version of OS version
  2. Decide whether to upgrade the IOS of device or not.
  3. Backup the running configuration of device
  4. Take pre and post checks of defined commands.
  5. Upload IOS image file from ftp to the device
  6. Change boot variable on device and save the config.
  7. Reload the device to boot with new IOS image
  8. Compare pre and post-checks and display the difference

First of all create a file that will include variables, which will be referred by the ansible-playbook

vi ios_upgrade_vars.yml

---
# variables used for IOS upgrade playbook
upgrade_ios_version: 16.09.05
upgrade_ios_image: image.bin
ftp_user:
ftp_password:
ftp_server:
precheck_path:
postcheck_path:

Now following is the ansible-playbook to upgrade the IOS.
---
# Ansible Playbook to upgrade Cisco IOS. Created by Prashant Sahu (Network Galaxy) http://www.networkgalaxy.org


- name: Upgrade Cisco IOS
  hosts: ios-xe-01 
  connection: network_cli
  vars_files:
    - ~/ios_upgrade_vars.yml
  tasks:
    - name: Checking current IOS version
      ios_facts:

    - name: Comparing Installed and Expected IOS version
      debug:
        msg:
        -  "Current version is {{ ansible_net_version}}"
        -  "Upgrade image is {{ upgrade_ios_version }}"


    - name: Deciding whether the IOS will be upgraded or not
      debug:
        msg: "{% if ansible_net_version == upgrade_ios_version %} Current IOS version is up to date. Upgrade would be skipped for this host {% else %} Current Image version is different than the upgrade image and will be upgraded {% endif %}"


    - name: End the play for the host if device os version is up to date
      meta: end_host
      when: ansible_net_version == upgrade_ios_version


    - name: Backing up the running configuration to local file
      ios_config:
        backup: yes

    - name: Writing Memory on device
      ios_config:
        save_when: always



    - name: Reading 'show ip route' ouput
      cli_command:
        command: show ip route
      register: ip_route_pre
     
    - name: Copying 'show ip route' ouput to local file
      copy:
        content: "{{ ip_route_pre.stdout }}"
        dest: "{{ precheck_path }}{{ inventory_hostname }}_route-precheck"


    - name: Reading 'show ip interface brief' ouput
      cli_command:
        command: show ip interface brief
      register: interface_ip_pre
     
    - name: Copying 'show ip interface brief' ouput to local file
      copy:
        content: "{{ interface_ip_pre.stdout }}"
        dest: "{{ precheck_path }}{{ inventory_hostname }}_interface-ip-precheck"


    - name: Copying IOS image to bootflash of device. This may take time.....
      ios_command:
        commands: 
          -  command: "copy ftp://{{ftp_user}}:{{ftp_password}}@{{ftp_server}}/{{ upgrade_ios_image }} flash:{{ upgrade_ios_image }}"
             prompt: 'Destination filename [{{ upgrade_ios_image}}]?'
             answer: "\r"
      vars:
        ansible_command_timeout: 600


    - name: Changing Boot Variable to new image
      ios_config:
        parents: boot-start-marker
        commands:
          - boot system flash {{ upgrade_ios_image }}
          - boot system flash {{ ansible_net_image }}
        match: exact
        before:
          - no boot system
        save_when: always



    - name: Reloading the Device
      cli_command:
        command: "reload"
        check_all: True
        prompt:
          - "Save?"
          - "reload?"
          - "confirm"
        answer:
          - 'yes'
          - 'yes'
          - 'y'
     
    - name: reset the connection
      meta: reset_connection
    - name: wait for network device to come back up
      wait_for_connection:
        delay: 100
        connect_timeout: 1200 



    - name: Comparing Installed and Expected IOS version
      debug:
        msg:
          -  Expected image after the upgrade is {{ upgrade_ios_version }}
          -  Current version is {{ ansible_net_version }}



    - name: Upgrade Result
      debug:
        msg: "{% if ansible_net_version == upgrade_ios_version %} IOS Upgrade is complete! {% else %} IOS upgrade is not successul. Please check logs on {{ inventory_hostname }} {% endif %}"


    - name: Reading 'show ip route' ouput
      cli_command:
        command: show ip route
      register: ip_route_post
     
    - name: Copying 'show ip route' ouput to local file
      copy:
        content: "{{ ip_route_post.stdout }}"
        dest: "{{ postcheck_path }}/{{ inventory_hostname }}_route-postcheck"

    - name: Reading 'show ip interface brief' ouput
      cli_command:
        command: show ip interface brief
      register: interface_ip_post
     
    - name: Copying 'show ip interface brief' ouput to local file
      copy:
        content: "{{ interface_ip_post.stdout }}"
        dest: "{{ postcheck_path }}{{ inventory_hostname }}_interface-ip-postcheck"

- name: Comparing Pre and Post outputs
  hosts: localhost
  gather_facts: no
  vars_files:
    - ~/ios_upgrade_vars.yml
  tasks:
    - name: Comparing pre and post routes
      copy:
        src: "{{ postcheck_path }}{{ inventory_hostname }}_route-postcheck"
        dest: "{{ precheck_path }}{{ inventory_hostname }}_route-precheck"
      check_mode: yes
      diff: yes
     
    - name: Comparing pre and post interface IP
      copy:
        src: "{{ postcheck_path }}{{ inventory_hostname }}_interface-ip-postcheck"
        dest: "{{ precheck_path }}{( inventory_hostname }}_interface-ip-precheck"
      check_mode: yes
      diff: yes










Comments

  1. In the task Comparing Pre and Post outputs the inventory_hostname resolves to localhost rather than the network device

    ReplyDelete

Post a Comment

Popular posts from this blog

Specifying SSH port in Ansible Inventory

Ansible-Playbook to display output of multiple show commands (using stdout_lines with Loop)

Filtering Routes in BGP using Route-maps and Prefix-list

VMware NSX Traffic Flow — East-West & North-South

Bypassing Proxy Server in Google Chrome

Export or Backup Azure Network Security Groups into CSV using PowerShell

Ansible-playbook for backing up running config of Cisco IOS