Example Ansible Playbook for Updating Cisco IOS Switches

I’m going to assume that if you’re here, you already know what Ansible is. If not, head over to https://www.ansible.com/integrations/networks and check it out.

In short and sweet terms, Ansible is a software that runs on Linux (sorry windows peeps) which helps Engineers automate tasks using a more human readable instruction language called YAML. Instead of scripts you write Playbooks with Ansible uses to run Python code on the back end.

In Networking, we can use Ansible for anything from automating configuration of networking equipment to automating routine maintenance tasks like updating IOS, NXOS, and ASA software.

If Ansible seems  overwhelming and you just want a reliable way to automate updating your Cisco (and other vendor) networking hardware then I recommend checking out Solarwinds Network Configuration Manager. Not only can it be used to automate updating, it also backs up your configs and performs vulnerability checks.

For those of you that already know what Ansible is and are looking for an example playbook that will help you automate updating your Cisco IOS equipment, you’re in the right place. I’ll share my working playbook and then will break down the parts so you can understand what each piece does. This should help you tailor it to your needs.

Example Ansible Playbook for Updating Cisco IOS Switches and Routers Using TFTP

---
- name: UPGRADE SUP8L-E SWITCH FIRMWARE
  hosts: switches
  connection: network_cli
  gather_facts: no

  vars_prompt:
   - name: "compliant_ios_version"
     prompt: "What is the compliant IOS version?"
     private: no

   - name: "new_ios_bin"
     prompt: "What is the name of the new IOS file?"
     private: no

   - name: "new_ios_md5"
     prompt: "What is the MD5 value of the new IOS file?"
     private: no

   - name: "should_reboot"
     prompt: "Do you want Ansible to reboot the hosts? (YES or NO)"
     private: no

  tasks:
    - name: GATHER SWITCH FACTS
      ios_facts:

    - name: UPGRADE IOS IMAGE IF NOT COMPLIANT
      block:
      - name: COPY OVER IOS IMAGE
        ios_command:
           commands:
              - command: "copy tftp://xxx.xxx.xxx.xxx/{{ new_ios_bin }} bootflash:"
                prompt: '[{{ new_ios_bin }}]'
              answer: "\r"
        vars:
          ansible_command_timeout: 1800

      - name: CHECK MD5 HASH
        ios_command:
           commands:
              - command: "verify /md5 bootflash:{{ new_ios_bin }}"
        register: md5_result
        vars:
          ansible_command_timeout: 300

      - name: CONTINUE UPGRADE IF MD5 HASH MATCHES
        block:
        - name: SETTING BOOT IMAGE
          ios_config:
            lines:
            - no boot system
            - boot system flash bootflash:{{ new_ios_bin }}
            match: none
            save_when: always

        - name: REBOOT SWITCH IF INSTRUCTED
          block:
          - name: REBOOT SWITCH
            ios_command:
               commands:
                  - command: "reload"
                    prompt: '[confirm]'
                    answer: "\r"
            vars:
              ansible_command_timeout: 30

          - name: WAIT FOR SWITCH TO RETURN
            wait_for:
              host: "{{inventory_hostname}}"
              port: 22
              delay: 60
              timeout: 600
            delegate_to: localhost

          - name: GATHER ROUTER FACTS FOR VERIFICATION
            ios_facts:

          - name: ASSERT THAT THE IOS VERSION IS CORRECT
            assert:
              that:
                - compliant_ios_version == ansible_net_version
              msg: "IOS version does not match compliant version. Upgrade unsuccessful."

          when: should_reboot == "YES"

        when: '"new_ios_md5" in md5_result.stdout[0]'

      when: ansible_net_version != compliant_ios_version
...

When this playbook is ran it prompts for your input for the version of IOS that your hardware should have, what the file name of your new IOS file is on your TFTP server, what the MD5 value is that Cisco provides, and whether or not you want the play to reload the switch to complete the update.

Let’s look at how all of this is accomplished.

---
- name: UPGRADE SUP8L-E SWITCH IOS SOFTWARE
  hosts: switches
  connection: network_cli
  gather_facts: no

This section tells Ansible to connect to and run the play on all of the hosts in the group switches using the network_cli connection method. Network_cli uses SSH by default and credentials that I encrypted using Ansible Vault and stored in a hosts variable file on the Ansible server.

  vars_prompt:
   - name: "compliant_ios_version"
     prompt: "What is the compliant IOS version?"
     private: no

   - name: "new_ios_bin"
     prompt: "What is the name of the new IOS file?"
     private: no

   - name: "new_ios_md5"
     prompt: "What is the MD5 value of the new IOS file?"
     private: no

   - name: "should_reboot"
     prompt: "Do you want Ansible to reboot the hosts? (YES or NO)"
     private: no

Here we are prompting the user for input that we store in variables to call throughout the playbook. By setting private to no we are allowing the user to see what they are typing in the prompt.

tasks:
    - name: GATHER SWITCH FACTS
      ios_facts:

Here we are starting our task and telling Ansible to gather facts about our switch that it can use later on in the play, such as pulling the current version number to compare against the version we gave during the prompt earlier so Ansible knows if it should bother updating this switch or move on.

    - name: UPGRADE IOS IMAGE IF NOT COMPLIANT
      block:
      - name: COPY OVER IOS IMAGE
        ios_command:
           commands:
              - command: "copy tftp://xxx.xxx.xxx.xxx/{{ new_ios_bin }} bootflash:"
                prompt: '[{{ new_ios_bin }}]'
              answer: "\r"
        vars:
          ansible_command_timeout: 1800

Here we are running cli commands on the Cisco switch with Ansible to instruct the switch to connect to our TFTP server and pull down the IOS image we specified at the prompt. Ansible expects a prompt to confirm filename that should be saved on flash and answers by entering a carriage return “\r”.

Here you could use any connection method you wanted since you’re just telling the switch what to do. In my lab I’m just using the Free Solarwinds TFTP Server but you could user their Free SFTP/SCP server as well which would be more secure.

      - name: CHECK MD5 HASH
        ios_command:
           commands:
              - command: "verify /md5 bootflash:{{ new_ios_bin }}"
        register: md5_result
        vars:
          ansible_command_timeout: 300

Ansible then tells the switch to compute the md5 value of the newly copied filename and registers it as a list variable to be used later.

      - name: CONTINUE UPGRADE IF MD5 HASH MATCHES
        block:
        - name: SETTING BOOT IMAGE
          ios_config:
            lines:
            - no boot system
            - boot system flash bootflash:{{ new_ios_bin }}
            match: none
            save_when: always

Here we have created a block which correlated with a conditional when statement near the end of the playbook that tells ansible to proceed if the md5 value we gave matches the one computed by the switch. When it proceeds it then uses the ios_config module to remove any lines from the config that specify a boot image and then specifies a the new boot image. Finally, it saves the config after the change is made.

        - name: REBOOT SWITCH IF INSTRUCTED
          block:
          - name: REBOOT SWITCH
            ios_command:
               commands:
                  - command: "reload"
                    prompt: '[confirm]'
                    answer: "\r"
            vars:
              ansible_command_timeout: 30

Here we have another block started which matches a conditional when toward the bottom that tells Ansible to proceed with reloading the device if we answered YES to the reboot question at the start of the play. Ansible anticipates a prompt to confirm intent to reload and answers with a carriage return.

          - name: WAIT FOR SWITCH TO RETURN
            wait_for:
              host: "{{inventory_hostname}}"
              port: 22
              delay: 60
              timeout: 600
            delegate_to: localhost

Here we tell Ansible to take a 60 second coffee break while the switch is reloading and then to begin poling the switch on port 22 to check for availability. Your Ansible server will need to be able to resolve the DNS hostname of your switch for this to work as written.

          - name: GATHER SWITCH FACTS FOR VERIFICATION
            ios_facts:

          - name: ASSERT THAT THE IOS VERSION IS CORRECT
            assert:
              that:
                - compliant_ios_version == ansible_net_version
              msg: "IOS version does not match compliant version. Upgrade unsuccessful."

Once Ansible sees the switch is back up, it pulls the ios_facts again and then compares the current running version to the version we gave in the beginning. If it matches, the play completes. If it doesn’t mtch Ansible displays a message telling you the upgrade was not successful.

          when: should_reboot == "YES"

        when: '"new_ios_md5" in md5_result.stdout[0]'

      when: ansible_net_version != compliant_ios_version
...

These when statements correlate with the blocks we configured earlier. Ansible makes sure the switch isn’t running the same version that we gave in the beginning before running the tasks. It makes sure the md5 value we gave matches the computed value before reloading so we don’t brick our switch. It then makes sure you want to Ansible to reload your switches for you.

Hopefully this example is helpful and at least gets you pointed in the right direction for building your own play!

Another option would be to check out Solarwinds Network Config Manager which I’ve also linked below. Not only does it help you backup your network device configurations, but it can also be used to automate updating your switch and router gear’s software and firmware. It also checks for posted security vulnerabilities in your hardware and software versions. Plus you can define standard config settings and NCM will check all your devices and tell you which are and are not compliant.

Recommended for You: Solarwinds Network Configuration Manager (NCM)

What would you do if one of your pieces of networking equipment failed? Could you rebuild it quickly? Do you know exactly what configuration it had? What ports were on what vlan? What about port channels?

You get the point.

Automate backing up configurations and updating of all your switching, routing, and firewall equipment without needing to know a single line of code with Solarwinds Network Configuration Manager.

This is one of those tools that pays for itself in man hours the first time you need to rely on it. Plus, you’ll sleep easier knowing you really have backed up all the things.

Leave a Reply

Your email address will not be published. Required fields are marked *