Kicking the tires with the new Ansible Network Modules

Ansible recently announced support for multi-vendor network modules, natively within Ansible. There are many examples on the Internet where individuals have taken the initiative to create their own modules to work with their favorite vendor. Some of these examples are Arista supplied modules , NX-OS modules - created by Jason Edelman, NTC , and NAPALM . While these are all good, it's nice to see that Ansible is taking some initiative to create some native functionality.

These modules aren't yet in the stable release of Ansible, but they do make an appearance in the development version, so I decided to kick the tires a bit.

First thing I did was set up an development environment using python's virtualenv.
mkdir -p ansible2.0/env
cd ansible2.0
virtualenv env
source env/bin/activate
git clone [email protected]:ansible/ansible.git
cd ansible
git submodule init
git submodule update
python setup.py install

Next, I verified the version of Ansible that I'm running in my development environment, as well as verifying that I have the new modules available to me.
(env)jtdub-macbook:ansible jtdub$ ansible --version
ansible 2.1.0
config file =
configured module search path = Default w/o overrides
(env)jtdub-macbook:ansible jtdub$ ansible-doc --list | egrep ^'ios|eos|junos|nxos'
eos_command Run arbitrary command on EOS device
eos_config Manage Arista EOS configuration sections
eos_eapi Manage and configure EAPI. Requires EOS v4.12 or greater.
eos_template Manage Arista EOS device configurations
ios_command Run arbitrary commands on ios devices.
ios_config Manage Cisco IOS configuration sections
ios_template Manage Cisco IOS device configurations over SSH
iosxr_command Run arbitrary commands on ios devices.
iosxr_config Manage Cisco IOS XR configuration sections
iosxr_template Manage Cisco IOS device configurations over SSH
junos_command Execute arbitrary commands on Juniper JUNOS devices
junos_config Manage Juniper JUNOS configuration sections
junos_template Manage Juniper JUNOS device configurations
nxos_command Run arbitrary command on Cisco NXOS devices
nxos_config Manage Cisco NXOS configuration sections
nxos_nxapi Manage NXAPI configuration on an NXOS device.
nxos_template Manage Cisco NXOS device configurations

At the time of this writing. It looks like the online documentation has been updated, which would infer that the new modules may soon be in the stable release.

So, let's create a sample playbook!

The first thing I did was create an inventory file. I kept it simple and created a file called 'hosts'
[ios]
edge1
aggr1a

Then I created a secrets.yaml file to store my credentials without having to put them in a playbook. While I won't share my credentials here, I will share the format that I used. :)
---
creds:
username: cisco
password: cisco
auth_pass: cisco

Lastly, I created a sample playbook. I wanted a task that  utilized each module type - (ios|eos|junos|nxos)_(command|template|config). Currently, I have easy access to a couple of IOS devices, so I stuck with using those modules, but I played with each ios_(command|config) module. I plan on spending time and playing with the ios_template module more at a later time.

Here is my sample playbook:
---
- hosts: ios
gather_facts: no
connection: local

tasks:
- name: OBTAIN LOGIN CREDENTIALS
include_vars: secrets.yaml

- name: DEFINE PROVIDER
set_fact:
provider:
host: "{{ inventory_hostname }}"
username: "{{ creds['username'] }}"
password: "{{ creds['password'] }}"
auth_pass: "{{ creds['auth_pass'] }}"

- name: RUN 'SHOW VERSION'
ios_command:
provider: "{{ provider }}"
commands:
- show version
register: version

- debug: var=version.stdout_lines

- name: RUN 'SHOW ACCESS-LIST TEST'
ios_command:
provider: "{{ provider }}"
commands:
- show access-list TEST
register: before_acl

- debug: var=before_acl.stdout_lines

- name: CREATE 'TEST' ACCESS-LIST
ios_config:
provider: "{{ provider }}"
authorize: yes
lines:
- 10 permit ip host 1.1.1.1 any
- 20 deny ip any any
parents: ['ip access-list extended TEST']
before: ['no ip access-list extended TEST']
match: exact

- name: RUN 'SHOW ACCESS-LIST TEST'
ios_command:
provider: "{{ provider }}"
commands:
- show access-list TEST
register: after_acl

- debug: var=after_acl.stdout_lines

In this playbook, I first import my secrets.yaml variables, which includes my credentials to log into the devices. I then define the 'provider' variable. The provider variable allows you to create a host, username, password, and auth_pass key value in a single place and call it as a single variable, rather than defining each individually for each task. It's a nice little time saver! Finally, I started doing work on the devices themselves.

Here is my playbook run:
(env)jtdub-macbook:ansible2.0 jtdub$ ansible-playbook -i hosts ios.yaml 

PLAY [ios] *********************************************************************

TASK [OBTAIN LOGIN CREDENTIALS] ************************************************
ok: [edge1]
ok: [aggr1a]

TASK [DEFINE PROVIDER] *********************************************************
ok: [edge1]
ok: [aggr1a]

TASK [RUN 'SHOW VERSION'] ******************************************************
ok: [edge1]
ok: [aggr1a]

TASK [debug] *******************************************************************
ok: [edge1] => {
"version.stdout_lines": [
[
"Cisco IOS Software, C181X Software (C181X-ADVENTERPRISEK9-M), Version 15.1(4)M8, RELEASE SOFTWARE (fc2)",
"Technical Support: http://www.cisco.com/techsupport",
"Copyright (c) 1986-2014 by Cisco Systems, Inc.",
"Compiled Fri 07-Mar-14 07:42 by prod_rel_team",
"",
"ROM: System Bootstrap, Version 12.3(8r)YH13, RELEASE SOFTWARE (fc1)",
"",
"edge1.sat uptime is 3 days, 22 hours, 3 minutes",
"System returned to ROM by reload at 22:18:54 CST Thu Feb 25 2016",
"System restarted at 22:19:35 CST Thu Feb 25 2016",
"System image file is \"flash:c181x-adventerprisek9-mz.151-4.M8.bin\"",
"Last reload type: Normal Reload",
"",
"",
"This product contains cryptographic features and is subject to United",
"States and local country laws governing import, export, transfer and",
"use. Delivery of Cisco cryptographic products does not imply",
"third-party authority to import, export, distribute or use encryption.",
"Importers, exporters, distributors and users are responsible for",
"compliance with U.S. and local country laws. By using this product you",
"agree to comply with applicable laws and regulations. If you are unable",
"to comply with U.S. and local laws, return this product immediately.",
"",
"A summary of U.S. laws governing Cisco cryptographic products may be found at:",
"http://www.cisco.com/wwl/export/crypto/tool/stqrg.html",
"",
"If you require further assistance please contact us by sending email to",
"[email protected]",
"",
"Cisco 1811 (MPC8500) processor (revision 0x400) with 236544K/25600K bytes of memory.",
"Processor board ID FTX15110094, with hardware revision 0000",
"",
"10 FastEthernet interfaces",
"1 Serial interface",
"1 terminal line",
"1 Virtual Private Network (VPN) Module",
"62720K bytes of ATA CompactFlash (Read/Write)",
"",
"",
"License Info:",
"",
"License UDI:",
"",
"-------------------------------------------------",
"Device#\t PID\t\t\tSN",
"-------------------------------------------------",
"*0 \t CISCO1811/K9 FTX15110094 ",
"",
"",
"",
"Configuration register is 0x2102",
""
]
]
}
ok: [aggr1a] => {
"version.stdout_lines": [
[
"Cisco IOS Software, C3750 Software (C3750-IPSERVICESK9-M), Version 12.2(55)SE9, RELEASE SOFTWARE (fc1)",
"Technical Support: http://www.cisco.com/techsupport",
"Copyright (c) 1986-2014 by Cisco Systems, Inc.",
"Compiled Mon 03-Mar-14 22:45 by prod_rel_team",
"Image text-base: 0x01000000, data-base: 0x02F00000",
"",
"ROM: Bootstrap program is C3750 boot loader",
"BOOTLDR: C3750 Boot Loader (C3750-HBOOT-M) Version 12.2(44)SE5, RELEASE SOFTWARE (fc1)",
"",
"aggr1a.sat uptime is 1 week, 3 days, 21 hours, 24 minutes",
"System returned to ROM by power-on",
"System restarted at 22:58:01 CST Thu Feb 18 2016",
"System image file is \"flash:c3750-ipservicesk9-mz.122-55.SE9.bin\"",
"",
"",
"This product contains cryptographic features and is subject to United",
"States and local country laws governing import, export, transfer and",
"use. Delivery of Cisco cryptographic products does not imply",
"third-party authority to import, export, distribute or use encryption.",
"Importers, exporters, distributors and users are responsible for",
"compliance with U.S. and local country laws. By using this product you",
"agree to comply with applicable laws and regulations. If you are unable",
"to comply with U.S. and local laws, return this product immediately.",
"",
"A summary of U.S. laws governing Cisco cryptographic products may be found at:",
"http://www.cisco.com/wwl/export/crypto/tool/stqrg.html",
"",
"If you require further assistance please contact us by sending email to",
"[email protected]",
"",
"cisco WS-C3750-24TS (PowerPC405) processor (revision L0) with 131072K bytes of memory.",
"Processor board ID CAT1042ZGKL",
"Last reset from power-on",
"2 Virtual Ethernet interfaces",
"24 FastEthernet interfaces",
"2 Gigabit Ethernet interfaces",
"The password-recovery mechanism is enabled.",
"",
"512K bytes of flash-simulated non-volatile configuration memory.",
"Base ethernet MAC Address : 00:19:E7:5F:8F:80",
"Motherboard assembly number : 73-9677-10",
"Power supply part number : 341-0034-01",
"Motherboard serial number : CAT10415NLR",
"Power supply serial number : DTH1037117A",
"Model revision number : L0",
"Motherboard revision number : A0",
"Model number : WS-C3750-24TS-S",
"System serial number : CAT1042ZGKL",
"Top Assembly Part Number : 800-25857-02",
"Top Assembly Revision Number : D0",
"Version ID : V05",
"CLEI Code Number : CNMV100CRE",
"Hardware Board Revision Number : 0x01",
"",
"",
"Switch Ports Model SW Version SW Image ",
"------ ----- ----- ---------- ---------- ",
"* 1 26 WS-C3750-24TS 12.2(55)SE9 C3750-IPSERVICESK9-M ",
"",
"",
"Configuration register is 0xF",
""
]
]
}

TASK [RUN 'SHOW ACCESS-LIST TEST'] *********************************************
ok: [edge1]
ok: [aggr1a]

TASK [debug] *******************************************************************
ok: [edge1] => {
"before_acl.stdout_lines": [
[
""
]
]
}
ok: [aggr1a] => {
"before_acl.stdout_lines": [
[
""
]
]
}

TASK [CREATE 'TEST' ACCESS-LIST] ***********************************************
changed: [edge1]
changed: [aggr1a]

TASK [RUN 'SHOW ACCESS-LIST TEST'] *********************************************
ok: [edge1]
ok: [aggr1a]

TASK [debug] *******************************************************************
ok: [edge1] => {
"after_acl.stdout_lines": [
[
"Extended IP access list TEST",
" 10 permit ip host 1.1.1.1 any",
" 20 deny ip any any"
]
]
}
ok: [aggr1a] => {
"after_acl.stdout_lines": [
[
"Extended IP access list TEST",
" 10 permit ip host 1.1.1.1 any",
" 20 deny ip any any"
]
]
}

PLAY RECAP *********************************************************************
aggr1a : ok=9 changed=1 unreachable=0 failed=0
edge1 : ok=9 changed=1 unreachable=0 failed=0

As you can see, I was able to successfully execute a 'show version', verify that I had no access-list called TEST, create it, then verify that it was indeed created.

I'm thrilled that Ansible is finally getting around to recognizing the benefit of supporting the networking community. It's a basic start and it will only get better from here! Soon, I'll post a blog walking through the ios_template module. The documentation on that one looks interesting!