Ansible IOS VLAN
Back to it finally. Going to take a look at the Ansible module ios_vlan. The purpose of this is to provide a declarative module for managing VLANs on IOS devices. In this I will be using IOSv-L2 images. There are a few interesting quirks (as I will call it) within the parameters for the module.
Module Documentation#
First, the module documentation page is here.
Getting Started with the module#
VLANs pre-module work#
Starting out the switch is pretty bare as it relates to the number of VLANs. There is VLAN2 defined on the switch that has an uplink to the edge (of the lab) router. The base VLANs are the only other ones on the device:
Building the Play#
The module has the following parameters, required ones in bold. This skips over the deprecated parameters:
- aggregate: List of VLANs definitions
- associated_interfaces: Checks for the operational state of the interface
- delay: default to 10 seconds, how long to wait for the declarative state to be seen
- interfaces: a list of interfaces that should have the VLAN assigned to it
- name: Name of the VLAN
- purge: Purge VLANs not defined in the aggregate parameter
- state: present/absent/active/suspend - the state that it should be in
- vlan_id: ID of the VLAN
So what does aggregate mean? It sounds like that if you wanted to have a large list of VLANs, this is the way to go with a task. First attempt at seeing what it does, the following playbook was setup
---
# yamllint disable rule:truthy
# yamllint disable rule:line-length
- name: Switch config
connection: network_cli
hosts: sw19
gather_facts: no
become: yes
become_method: enable
tasks:
- name: IOS >> VLAN Updates
ios_vlan:
aggregate:
- 2
- 5
vlan_id: 5
name: TEST VLAN 5
state: present
register: command_output
- name: DEBUG >> VLAN Update
debug:
msg: "{{ command_output }}"
When executing it came across an error that gave some more insight that was not portrayed on the module definition page.
Modifying the playbook with the fatal error message out. It now looks like this:
---
# yamllint disable rule:truthy
# yamllint disable rule:line-length
- name: Switch config
connection: network_cli
hosts: sw19
gather_facts: no
become: yes
become_method: enable
tasks:
- name: IOS >> VLAN Updates
ios_vlan:
aggregate:
- { 'vlan_id': 2, 'name': 'TRANSIT' }
- { 'vlan_id': 5, 'name': 'Test VLAN' }
state: present
register: command_output
- name: DEBUG >> VLAN Update
debug:
msg: "{{ command_output }}"
This will now deploy in aggregate all of the VLANs that are being defined in the list of dictionaries. Looking at the output this is what is now on the switch:
Changing the VLANs on the device#
Removing a VLAN that is not supposed to be on the device is incredibly simple with this aggregate feature as well. If we change the play to looking like this
---
# yamllint disable rule:truthy
# yamllint disable rule:line-length
- name: Switch config
connection: network_cli
hosts: sw19
gather_facts: no
become: yes
become_method: enable
tasks:
- name: IOS >> VLAN Updates
ios_vlan:
aggregate:
- { 'vlan_id': 2, 'name': 'TRANSIT', state: present }
- { 'vlan_id': 5, 'name': 'Test VLAN', state: absent }
register: command_output
- name: DEBUG >> VLAN Update
debug:
msg: "{{ command_output }}"
The resulting play execution shows that the VLAN is removed from the command output.
Adding a VLAN and assigning to Interface#
Want to create an interface and assign it to a VLAN quickly? Here is where the ios_vlan module may be able to help very quickly. In the lab it is very simple as there are only a few interfaces on the layer 2 switch that we have.
Play Definition#
---
# yamllint disable rule:truthy
# yamllint disable rule:line-length
- name: Switch config
connection: network_cli
hosts: sw19
gather_facts: no
become: yes
become_method: enable
tasks:
- name: IOS >> VLAN Updates
ios_vlan:
vlan_id: 12
name: test-vlan
interfaces:
- GigabitEthernet1/2
register: command_output
- name: DEBUG >> VLAN Update
debug:
msg: "{{ command_output }}"
Playbook Execution - Adding a VLAN#
This play execution will both add a VLAN to the switch, and assign the interfaces to the VLAN as an access port. With the output from the execution the module registers each of the commands that are being issued to the switch. This shows the VLAN is first created, then goes into the interface assigned as a parameter. Lastly it sets that interface to being an access interface in the VLAN.
IOS_VLAN - Purge Parameter#
Originally when looking at this module I kind of passed over purge parameter. It was mentioned that this is used with conjunction of the aggregrate parameter. My original thinking when I read aggregate was that this was somehow related to Link Aggregation Control Protocol. Now with looking at the module much more in depth, I see that was a wrong assumption (in case it was for others). This adds significant power, to make sure that a switch is configured the way that you define within a play/task and stays configured that way. If some rogue actor has added a VLAN, how will you ever know. So for this next test, I went and created three manual VLANs on the switch for VLANs 10, 13, and 100.
Play Setup - Purge VLANs#
---
# yamllint disable rule:truthy
# yamllint disable rule:line-length
- name: Switch config
connection: network_cli
hosts: sw19
gather_facts: no
become: yes
become_method: enable
tasks:
- name: IOS >> VLAN Updates
ios_vlan:
aggregate:
- { 'vlan_id': 2, 'name': 'TRANSIT', state: present }
- { 'vlan_id': 5, 'name': 'Test VLAN', state: present }
- { 'vlan_id': 12, 'name': 'THE TEST VLAN', state: present }
purge: yes
register: command_output
- name: DEBUG >> VLAN Update
debug:
msg: "{{ command_output }}"
PLAY EXECUTION#
Below you will find the play execution and the resulting commands sent to the switch. To show this I did have to run the playbook twice as the bug that I found did not run properly the first time.
One important note that I did find when testing this playbook, at least within Ansible version 2.7.5 to use the purge function, you must use the keyword yes instead of true. If you use true the purge function will not work.
Resulting VLAN Configuration#
Summary#
In summary there are some pieces that need to get worked out. This was the first time that I had taken a look at the module. For the work that I've done previously I was just using Jinja2 templates to assign VLAN configuration to an interface. Looking closer at this module there is a lot of power to make sure that the proper VLANs are configured everywhere that you need, and be able to eliminate others. This module is definitely something that you should keep in your pocket.
Share on Share on Share on Share on Share on