Ansible Network Examples

This document describes some examples of using Ansible to manage your network infrastructure.

Prerequisites

This example requires the following:

  • Ansible 2.5 (or higher) installed. See Installation Guide for more information.
  • One or more network devices that are compatible with Ansible.
  • Basic understanding of YAML YAML Syntax.
  • Basic understanding of Jinja2 templates. See Templating (Jinja2) for more information.
  • Basic Linux command line use.
  • Basic knowledge of network switch & router configurations.

Groups and variables in an inventory file

An inventory file is a YAML or INI-like configuration file that defines the mapping of hosts into groups.

In our example, the inventory file defines the groups eos, ios, vyos and a “group of groups” called switches. Further details about subgroups and inventory files can be found in the Ansible inventory Group documentation.

Because Ansible is a flexible tool, there are a number of ways to specify connection information and credentials. We recommend using the [my_group:vars] capability in your inventory file. Here’s what it would look like if you specified your SSH passwords (encrypted with Ansible Vault) among your variables:

  1. [all:vars]
  2. # these defaults can be overridden for any group in the [group:vars] section
  3. ansible_connection=network_cli
  4. ansible_user=ansible
  5.  
  6. [switches:children]
  7. eos
  8. ios
  9. vyos
  10.  
  11. [eos]
  12. veos01 ansible_host=veos-01.example.net
  13. veos02 ansible_host=veos-02.example.net
  14. veos03 ansible_host=veos-03.example.net
  15. veos04 ansible_host=veos-04.example.net
  16.  
  17. [eos:vars]
  18. ansible_become=yes
  19. ansible_become_method=enable
  20. ansible_network_os=eos
  21. ansible_user=my_eos_user
  22. ansible_password= !vault |
  23. $ANSIBLE_VAULT;1.1;AES256
  24. 37373735393636643261383066383235363664386633386432343236663533343730353361653735
  25. 6131363539383931353931653533356337353539373165320a316465383138636532343463633236
  26. 37623064393838353962386262643230303438323065356133373930646331623731656163623333
  27. 3431353332343530650a373038366364316135383063356531633066343434623631303166626532
  28. 9562
  29.  
  30. [ios]
  31. ios01 ansible_host=ios-01.example.net
  32. ios02 ansible_host=ios-02.example.net
  33. ios03 ansible_host=ios-03.example.net
  34.  
  35. [ios:vars]
  36. ansible_become=yes
  37. ansible_become_method=enable
  38. ansible_network_os=ios
  39. ansible_user=my_ios_user
  40. ansible_password= !vault |
  41. $ANSIBLE_VAULT;1.1;AES256
  42. 34623431313336343132373235313066376238386138316466636437653938623965383732373130
  43. 3466363834613161386538393463663861636437653866620a373136356366623765373530633735
  44. 34323262363835346637346261653137626539343534643962376139366330626135393365353739
  45. 3431373064656165320a333834613461613338626161633733343566666630366133623265303563
  46. 8472
  47.  
  48. [vyos]
  49. vyos01 ansible_host=vyos-01.example.net
  50. vyos02 ansible_host=vyos-02.example.net
  51. vyos03 ansible_host=vyos-03.example.net
  52.  
  53. [vyos:vars]
  54. ansible_network_os=vyos
  55. ansible_user=my_vyos_user
  56. ansible_password= !vault |
  57. $ANSIBLE_VAULT;1.1;AES256
  58. 39336231636137663964343966653162353431333566633762393034646462353062633264303765
  59. 6331643066663534383564343537343334633031656538370a333737656236393835383863306466
  60. 62633364653238323333633337313163616566383836643030336631333431623631396364663533
  61. 3665626431626532630a353564323566316162613432373738333064366130303637616239396438
  62. 9853

If you use ssh-agent, you do not need the ansiblepassword lines. If you use ssh keys, but not ssh-agent, and you have multiple keys, specify the key to use for each connection in the [group:vars] section with ansible_ssh_private_key_file=/path/to/correct/key. For more information on ansible_ssh options see Connecting to hosts: behavioral inventory parameters.

Warning

Never store passwords in plain text.

Ansible vault for password encryption

The “Vault” feature of Ansible allows you to keep sensitive data such as passwords or keys in encrypted files, rather than as plain text in your playbooks or roles. These vault files can then be distributed or placed in source control. See Using Vault in playbooks for more information.

Common inventory variables

The following variables are common for all platforms in the inventory, though they can be overwritten for a particular inventory group or host.

ansibleconnection:
Ansible uses the ansible-connection setting to determine how to connect to a remote device. When working with Ansible Networking, set this to network_cli so Ansible treats the remote node as a network device with a limited execution environment. Without this setting, Ansible would attempt to use ssh to connect to the remote and execute the Python script on the network device, which would fail because Python generally isn’t available on network devices.
ansible_network_os:
Informs Ansible which Network platform this hosts corresponds to. This is required when using network_cli or netconf.
ansible_user:The user to connect to the remote device (switch) as. Without this the user that is running ansible-playbook would be used.Specifies which user on the network device the connection
ansible_password:
The corresponding password for ansible_user to log in as. If not specified SSH key will be used.
ansible_become:If enable mode (privilege mode) should be used, see the next section.
ansible_become_method:
Which type of _become should be used, for network_cli the only valid choice is enable.

Privilege escalation

Certain network platforms, such as Arista EOS and Cisco IOS, have the concept of different privilege modes. Certain network modules, such as those that modify system state including users, will only work in high privilege states. Ansible supports become when using connection: network_cli. This allows privileges to be raised for the specific tasks that need them. Adding become: yes and become_method: enable informs Ansible to go into privilege mode before executing the task, as shown here:

  1. [eos:vars]
  2. ansible_connection=network_cli
  3. ansible_network_os=eos
  4. ansible_become=yes
  5. ansible_become_method=enable

For more information, see the using become with network modules guide.

Jump hosts

If the Ansible Controller doesn’t have a direct route to the remote device and you need to use a Jump Host, please see the Ansible Network Proxy Command guide for details on how to achieve this.

Example 1: collecting facts and creating backup files with a playbook

Ansible facts modules gather system information ‘facts’ that are available to the rest of your playbook.

Ansible Networking ships with a number of network-specific facts modules. In this example, we use the _facts modules eos_facts, ios_facts and vyos_facts to connect to the remote networking device. As the credentials are not explicitly passed via module arguments, Ansible uses the username and password from the inventory file.

Ansible’s “Network Fact modules” gather information from the system and store the results in facts prefixed with ansiblenet. The data collected by these modules is documented in the Return Values section of the module docs, in this case eos_facts and vyos_facts. We can use the facts, such as ansible_net_version late on in the “Display some facts” task.

To ensure we call the correct mode (*_facts) the task is conditionally run based on the group defined in the inventory file, for more information on the use of conditionals in Ansible Playbooks see The When Statement.

In this example, we will create an inventory file containing some network switches, then run a playbook to connect to the network devices and return some information about them.

Step 1: Creating the inventory

First, create a file called inventory, containing:

  1. [switches:children]
  2. eos
  3. ios
  4. vyos
  5.  
  6. [eos]
  7. eos01.example.net
  8.  
  9. [ios]
  10. ios01.example.net
  11.  
  12. [vyos]
  13. vyos01.example.net

Step 2: Creating the playbook

Next, create a playbook file called facts-demo.yml containing the following:

  1. - name: "Demonstrate connecting to switches"
  2. hosts: switches
  3. gather_facts: no
  4.  
  5. tasks:
  6. ###
  7. # Collect data
  8. #
  9. - name: Gather facts (eos)
  10. eos_facts:
  11. when: ansible_network_os == 'eos'
  12.  
  13. - name: Gather facts (ops)
  14. ios_facts:
  15. when: ansible_network_os == 'ios'
  16.  
  17. - name: Gather facts (vyos)
  18. vyos_facts:
  19. when: ansible_network_os == 'vyos'
  20.  
  21. ###
  22. # Demonstrate variables
  23. #
  24. - name: Display some facts
  25. debug:
  26. msg: "The hostname is {{ ansible_net_hostname }} and the OS is {{ ansible_net_version }}"
  27.  
  28. - name: Facts from a specific host
  29. debug:
  30. var: hostvars['vyos01.example.net']
  31.  
  32. - name: Write facts to disk using a template
  33. copy:
  34. content: |
  35. #jinja2: lstrip_blocks: True
  36. EOS device info:
  37. {% for host in groups['eos'] %}
  38. Hostname: {{ hostvars[host].ansible_net_hostname }}
  39. Version: {{ hostvars[host].ansible_net_version }}
  40. Model: {{ hostvars[host].ansible_net_model }}
  41. Serial: {{ hostvars[host].ansible_net_serialnum }}
  42. {% endfor %}
  43.  
  44. IOS device info:
  45. {% for host in groups['ios'] %}
  46. Hostname: {{ hostvars[host].ansible_net_hostname }}
  47. Version: {{ hostvars[host].ansible_net_version }}
  48. Model: {{ hostvars[host].ansible_net_model }}
  49. Serial: {{ hostvars[host].ansible_net_serialnum }}
  50. {% endfor %}
  51.  
  52. VyOS device info:
  53. {% for host in groups['vyos'] %}
  54. Hostname: {{ hostvars[host].ansible_net_hostname }}
  55. Version: {{ hostvars[host].ansible_net_version }}
  56. Model: {{ hostvars[host].ansible_net_model }}
  57. Serial: {{ hostvars[host].ansible_net_serialnum }}
  58. {% endfor %}
  59. dest: /tmp/switch-facts
  60. run_once: yes
  61.  
  62. ###
  63. # Get running configuration
  64. #
  65.  
  66. - name: Backup switch (eos)
  67. eos_config:
  68. backup: yes
  69. register: backup_eos_location
  70. when: ansible_network_os == 'eos'
  71.  
  72. - name: backup switch (vyos)
  73. vyos_config:
  74. backup: yes
  75. register: backup_vyos_location
  76. when: ansible_network_os == 'vyos'
  77.  
  78. - name: Create backup dir
  79. file:
  80. path: "/tmp/backups/{{ inventory_hostname }}"
  81. state: directory
  82. recurse: yes
  83.  
  84. - name: Copy backup files into /tmp/backups/ (eos)
  85. copy:
  86. src: "{{ backup_eos_location.backup_path }}"
  87. dest: "/tmp/backups/{{ inventory_hostname }}/{{ inventory_hostname }}.bck"
  88. when: ansible_network_os == 'eos'
  89.  
  90. - name: Copy backup files into /tmp/backups/ (vyos)
  91. copy:
  92. src: "{{ backup_vyos_location.backup_path }}"
  93. dest: "/tmp/backups/{{ inventory_hostname }}/{{ inventory_hostname }}.bck"
  94. when: ansible_network_os == 'vyos'

Step 3: Running the playbook

To run the playbook, run the following from a console prompt:

  1. ansible-playbook -i inventory facts-demo.yml

This should return output similar to the following:

  1. PLAY RECAP
  2. eos01.example.net : ok=7 changed=2 unreachable=0 failed=0
  3. ios01.example.net : ok=7 changed=2 unreachable=0 failed=0
  4. vyos01.example.net : ok=6 changed=2 unreachable=0 failed=0

Step 4: Examining the playbook results

Next, look at the contents of the file we created containing the switch facts:

  1. cat /tmp/switch-facts

You can also look at the backup files:

  1. find /tmp/backups

If ansible-playbook fails, please follow the debug steps in Network Debug and Troubleshooting Guide.

Example 2: simplifying playbooks with network agnostic modules

(This example originally appeared in the Deep Dive on cli_command for Network Automation blog post by Sean Cavanaugh -@IPvSean).

If you have two or more network platforms in your environment, you can use the network agnostic modules to simplify your playbooks. You can use network agnostic modules such as cli_command or cli_config in place of the platform-specific modules such as eos_config, ios_config, and junos_config. This reduces the number of tasks and conditionals you need in your playbooks.

Note

Network agnostic modules require the network_cli connection plugin.

Sample playbook with platform-specific modules

This example assumes three platforms, Arista EOS, Cisco NXOS, and Juniper JunOS. Without the network agnostic modules, a sample playbook might contain the following three tasks with platform-specific commands:

  1. ---
  2. - name: Run Arista command
  3. eos_command:
  4. commands: show ip int br
  5. when: ansible_network_os == 'eos'
  6.  
  7. - name: Run Cisco NXOS command
  8. nxos_command:
  9. commands: show ip int br
  10. when: ansible_network_os == 'nxos'
  11.  
  12. - name: Run Vyos command
  13. vyos_command:
  14. commands: show interface
  15. when: ansible_network_os == 'vyos'

Simplified playbook with cli_command network agnostic module

You can replace these platform-specific modules with the network agnostic cli_command module as follows:

  1. ---
  2. - hosts: network
  3. gather_facts: false
  4. connection: network_cli
  5.  
  6. tasks:
  7. - name: Run cli_command on Arista and display results
  8. block:
  9. - name: Run cli_command on Arista
  10. cli_command:
  11. command: show ip int br
  12. register: result
  13.  
  14. - name: Display result to terminal window
  15. debug:
  16. var: result.stdout_lines
  17. when: ansible_network_os == 'eos'
  18.  
  19. - name: Run cli_command on Cisco IOS and display results
  20. block:
  21. - name: Run cli_command on Cisco IOS
  22. cli_command:
  23. command: show ip int br
  24. register: result
  25.  
  26. - name: Display result to terminal window
  27. debug:
  28. var: result.stdout_lines
  29. when: ansible_network_os == 'ios'
  30.  
  31. - name: Run cli_command on Vyos and display results
  32. block:
  33. - name: Run cli_command on Vyos
  34. cli_command:
  35. command: show interfaces
  36. register: result
  37.  
  38. - name: Display result to terminal window
  39. debug:
  40. var: result.stdout_lines
  41. when: ansible_network_os == 'vyos'

If you use groups and group_vars by platform type, this playbook can be further simplified to :

  1. ---
  2. - name: Run command and print to terminal window
  3. hosts: routers
  4. gather_facts: false
  5.  
  6. tasks:
  7. - name: Run show command
  8. cli_command:
  9. command: "{{show_interfaces}}"
  10. register: command_output

You can see a full example of this using group_vars and also a configuration backup example at Network agnostic examples.

Using multiple prompts with the cli_command

The cli_command also supports multiple prompts.

  1. ---
  2. - name: Change password to default
  3. cli_command:
  4. command: "{{ item }}"
  5. prompt:
  6. - "New password"
  7. - "Retype new password"
  8. answer:
  9. - "mypassword123"
  10. - "mypassword123"
  11. check_all: True
  12. loop:
  13. - "configure"
  14. - "rollback"
  15. - "set system root-authentication plain-text-password"
  16. - "commit"

See the cli_command for full documentation on this command.

Implementation Notes

Demo variables

Although these tasks are not needed to write data to disk, they are used in this example to demonstrate some methods of accessing facts about the given devices or a named host.

Ansible hostvars allows you to access variables from a named host. Without this we would return the details for the current host, rather than the named host.

For more information, see Accessing information about other hosts with magic variables.

Get running configuration

The eos_config and vyos_config modules have a backup: option that when set will cause the module to create a full backup of the current running-config from the remote device before any changes are made. The backup file is written to the backup folder in the playbook root directory. If the directory does not exist, it is created.

To demonstrate how we can move the backup file to a different location, we register the result and move the file to the path stored in backup_path.

Note that when using variables from tasks in this way we use double quotes (") and double curly-brackets ({{…}} to tell Ansible that this is a variable.

Troubleshooting

If you receive an connection error please double check the inventory and playbook for typos or missing lines. If the issue still occurs follow the debug steps in Network Debug and Troubleshooting Guide.

See also