Pitfalls with Ansible and Cisco ios_config module
Ansible’s ios_config is a real lifesaver for cisco based configuration management. But here are some things which I encountered and want to share.
IP Access list
Here we’ve a simple task which creates an access list
1
2
3
4
5
6
7
8
9
10
11
- name: configure acl
ios_config:
lines:
- 'deny tcp any 10.0.0.0 0.0.255.255'
- 'permit tcp any any'
- 'permit icmp any any'
parents: 'ip access-list extended vlan90_in'
before: 'no ip access-list extended vlan90_in'
match: 'exact'
provider: ""
replace: 'line'
Executing the playbook reveals nothing special:
1
2
3
4
5
6
7
8
9
ansible-playbook -D switch playbooks/acl.yml
PLAY [acl] *********************************************************
TASK [ switch : configure acl] *********************************************
changed: [switch] => (item={'key': u'vlan90_in', 'value': {u'lines': [u'deny tcp any 10.0.0.0 0.0.255.255', u'permit tcp any any', u'permit icmp any any']}})
PLAY RECAP *********************************************************************
switch : ok=0 changed=1 unreachable=0 failed=0
Doing it again although looks more interesting. We changed nothing but ios_config module thinks different. That’s not what we want.
1
2
3
4
5
6
7
8
9
ansible-playbook -D switch playbooks/acl.yml
PLAY [acl] *********************************************************
TASK [ switch : configure acl] *********************************************
changed: [switch] => (item={'key': u'vlan90_in', 'value': {u'lines': [u'deny tcp any 10.0.0.0 0.0.255.255', u'permit tcp any any', u'permit icmp any any']}})
PLAY RECAP *********************************************************************
switch : ok=0 changed=1 unreachable=0 failed=0
Let’s see how the json output looks like
1
2
3
4
5
6
7
8
9
10
11
12
13
ansible-playbook -D switch playbooks/acl.yml -vvv
...
"item": {
"key": "vlan90_in",
"value": {
"lines": [
"deny tcp any 10.0.0.0 0.0.255.255",
"permit tcp any any",
"permit icmp any any"
]
}
},
...
On the module page we can read following for the line
option
The ordered set of commands that should be configured in the section. The commands must be the exact same commands as found in the device running-config. Be sure to note the configuration command syntax as some commands are automatically modified by the device config parser.
Comparing the ansible task and the running config reveals the truth
1
2
3
4
5
# running-config
ip access-list extended vlan90_in
deny tcp any 10.0.0.0 0.0.255.255
permit tcp any any
permit icmp any any
For the deny acl entry the cisco parser adds some whitespaces between deny and tcp and this is recognized by the ansible module. The lines need to match exactly with the running config as stated in the module text.
1
2
3
4
5
6
7
8
9
10
11
- name: configure acl
ios_config:
lines:
- 'deny tcp any 10.0.0.0 0.0.255.255'
- 'permit tcp any any'
- 'permit icmp any any'
parents: 'ip access-list extended vlan90_in'
before: 'no ip access-list extended vlan90_in'
match: 'exact'
provider: ""
replace: 'line'
Rerunning the playbook gives us the result we want
1
2
3
4
5
6
7
8
9
ansible-playbook -D switch playbooks/acl.yml
PLAY [acl] *********************************************************
TASK [ switch : configure acl] *********************************************
ok: [switch] => (item={'key': u'vlan90_in', 'value': {u'lines': [u'deny tcp any 10.0.0.0 0.0.255.255', u'permit tcp any any', u'permit icmp any any']}})
PLAY RECAP *********************************************************************
switch : ok=1 changed=0 unreachable=0 failed=0
Switch interface
We configure an interface with a jinja template
1
2
3
4
5
- name: configure interface
ios_config:
src: 'interface.j2'
provider: ""
defaults: 'yes'
1
2
3
4
5
{# interface.j2 #}
interface TenGigabitEthernet1/1
description *** test ***
switchport mode trunk
no shutdown
If you would run this task/playbook the second time it will again give you the changed
status. Checking the switch config shows that the interface section intends the options with one whitespace
1
2
3
4
# running-config
interface TenGigabitEthernet1/1
description *** test ***
switchport mode trunk
Maybe you noticed the ios_config option defaults
in the task I used
This argument specifies whether or not to collect all defaults when getting the remote device running config. When enabled, the module will get the current config by issuing the command show running-config all.
This can be a very powerful option but gives us also more to think when defining more options at the template.
Adding the native vlan for the trunk to the template will again cripple the idempotency.
1
2
3
4
5
6
{# interface.j2 #}
interface TenGigabitEthernet1/1
description *** test ***
switchport mode trunk
switchport trunk native vlan 100
no shutdown
If you run show running-config all
at the switch the switchport trunk native vlan
option comes before switchport mode trunk
.
You also need to consider the order to make it correct.
Tested with:
- Ansible 2.2.1
- Cisco Catalyst 4500X, IOS-XE 03.06.03