Sergej Khackimullin - Fotolia

An introduction to network automation with Ansible

Ansible is one of the most popular open source network automation tools. Network pros can use it to perform basic network automation tasks, like collecting ARP table data.

Ansible is an automation language, as well as the name of its underlying automation engine. Network automation with Ansible is attractive because of its simplicity and ability to interface with network equipment.

Ansible is easy to learn, which enables users to be productive quickly. Complex tasks require users to incrementally learn more about Ansible's configuration, something network engineers are accustomed to doing. The Ansible documentation is well written, and numerous online tutorial documents and videos are available to aid in getting started.

Ansible uses Secure Socket Shell (SSH) to interact with the network device command-line interface (CLI), eliminating the need for an agent on the network device. It is ideal for collecting and reporting information about the current network state. Additional parsers are available that can aid in creating read/write configuration scenarios.

Using Ansible

If you're just getting started using network automation with Ansible, I recommend reading "Ansible for Network Automation," which contains links to several other documents, including a getting started guide and an advanced topics guide. It also contains a link to a list of all network modules that facilitate interaction with different network devices.

Our example script uses the cli_command module to issue CLI commands to our test device, a Cisco 3560CX switch. The modules specific to a given vendor start with the OS name, such as ios_* or eos_*.

Ansible runs on a control node and communicates with a network device's CLI via the SSH protocol or the network device APIs, if available. No agent is required on the network device. Its operation is controlled by easy-to-read configuration files and by command-line arguments.

The best way to get started with Ansible is to collect basic information from network devices. The example in this article will collect Address Resolution Protocol (ARP) table data so you can compare it with the scripts we used in our previous article, "Network automation with Python, Paramiko, Netmiko and NAPALM."

Ansible directory and file structure

Ansible can run with a simple configuration, but that path leads to a jumble of different constructs. It's much better to build a directory structure that segregates different types of configuration data. For our example, we will use the following directory and file structure:

├── ansible.cfg
├── group_vars
│   ├── IOS_switches.yml
├── host_vars
│   └── test_sw.yml
├── inventory.yml
└── sh_arp.yml

The ansible.cfg file contains Ansible's configuration. Default values are frequently the best choice, so this file may not be needed. It is in INI format, which uses name = value syntax. Device fact gathering is disabled -- i.e., gathering = explicit -- because it is intended for non-network devices. The inventory file name is identified and retries are disabled, as shown below.

     1  [defaults]
     2  gathering = explicit
     3  inventory = inventory.yml
     4  retry_files_enabled = False

The group_vars directory contains variable definitions that apply to different groups. One YAML-formatted file in this directory contains variables for Internetwork Operating System (IOS) switches.

With IOS_switches.yml, we specify the Ansible module network_cli, set the OS to ios and specify the login credentials. The recommended secure configuration uses either Ansible vaults or SSH keys, so the credentials are not kept in a plain-text file. However, including the credentials in a variable file is much simpler for the demonstration below.

     1  ---
     2  # IOS_switches variables
     3  ansible_connection: network_cli
     4  ansible_network_os: ios
     5  ansible_become: yes
     6  ansible_become_method: enable
     7  ansible_become_password: "foobar"
     9  ansible_user: tester
    10  ansible_ssh_pass: foobar

The host_vars directory contains variable definitions that are specific to each device. A good example is a host variable with its management IP address and hostname. Variables that exist in the host files will supersede the same group variables, enabling users to override variables for specific devices.

For example, here is the test_sw.yml structure:

     1  ---
     2  # test_sw variables
     3  ipaddr:
     4  hostname: test_sw

The inventory.yml file lists the inventory of devices, along with device groups, using YAML format. Devices can be contained in multiple groups. The device test_sw is a member of the groups IOS_switches and access.

     1  ---
     2  all:
     3    children:
     4      IOS_switches:
     5        hosts:
     6          test_sw
     7      IOS_routers:
     8        hosts:
     9          router1
    10      access:
    11        hosts:
    12          test_sw
    13      core:
    14        hosts:
    15          router1

The sh_arp.yml file -- in YAML format -- is known as an Ansible playbook. It controls Ansible's execution of the task to show the ARP table and display the output. A playbook can contain multiple plays, and each play can contain multiple tasks.

Below, we name the play Gather ARP data, and the hosts are those listed in the IOS_switches group. This play has two tasks, each with a name. These names are simply text strings that will appear in the output. The ios_command module is used to execute the command show arp. The directive register is used to save the output of ios_command into an Ansible variable named cli_result.

Task 2 simply prints the saved result, referencing the list of stdout_lines that is in the saved cli_result.

     1  ---
     2  - name: Gather ARP data
     3    hosts: IOS_switches
     4    tasks:
     5      - name: "Task 1: Get output of show arp on IOS"
     6        ios_command:
     7          commands: "show arp"
     8        register: cli_result
    10      - name: "Task 2: Display stdout_lines[0]"
    11        debug:
    12          msg: "{{ cli_result.stdout_lines[0] }}"

Below, we run the Ansible script.

     1     $ ansible-playbook sh_arp.yml
     3     PLAY [Gather ARP data] ***************************************************
     5     TASK [Task 1: Get output of show arp on IOS] *****************************
     6     ok: [test_sw]
     8     TASK [Task 2: Display stdout_lines[0]] ***********************************
     9     ok: [test_sw] => {
    10         "msg": [
    11             "Protocol  Address     Age (min)  Hardware Addr   Type   Interface",
    12             "Internet      -   bcc4.933e.49c0  ARPA   Vlan1",
    13             "Internet      5   f894.c220.2177  ARPA   Vlan1",
    14             "Internet      1   88c2.55fb.9ce7  ARPA   Vlan1",
    15             "Internet      0   a860.b60a.7a3a  ARPA   Vlan1"
    16         ]
    17     }
    19     PLAY RECAP ***************************************************************
    20     test_sw                    : ok=2    changed=0    unreachable=0    failed=0  

Run Ansible on many devices

The power of network automation with Ansible isn't running a simple command like show arp on one device, as we've done above. The power comes with running a set of commands on many devices. You can dynamically build the configurations of many devices and store them on a disk for later loading. You can check that your network's connections are done according to the design and that they are functioning correctly. You can make sure device configurations are properly loaded and are consistent across many devices, with consistent quality of service or MPLS route target definitions.

For an easy way to get started with automation, use the above example to run several useful show commands across your network and store the output in files. You can then use simple grep search expressions to search hundreds of files for specific patterns.

A good example is to keep copies of show version for each network device as a way to document the devices on your network and their serial numbers. Another example is to track down where a device is connected in your network by searching for its media access control or IP address in saved output from show arp and show mac address dynamic commands.

The tip of the Ansible iceberg

Ansible can do many more things. Playbooks are great prebuilt tasks, but an ad hoc mode is also available to run the same command across many devices. Filters, parsers and plugins can be used to extend its power. Configuration templating is accomplished by combining Ansible with the Jinja2 templating language.

Another resource includes Nick Russo's tutorial, "Automating Networks with Ansible the Right Way," which describes the process of maintaining MPLS configurations with Ansible.

Ansible is great for network engineers. Playbook configuration is no more difficult to learn than many other networking concepts. It is easily available, easy to learn and powerful. Try network automation with Ansible on some simple read-only tasks, and you'll soon be hooked.

This was last published in February 2020

Dig Deeper on Network automation and intent-based networking