When working with a Cisco IOS config, usually things are pretty straightforward and consistent, but then you run into configuring the line section. Normally a line section looks a bit like this:
line vty 0 4
access-class vty-acl in
exec-timeout 15 0
logging synchronous
transport input ssh
line vty 5 15
access-class vty-acl in
exec-timeout 15 0
logging synchronous
transport input ssh
So line vty 0 4 and line vty 5 15 are pretty static and you can write two cisco.ios.ios_config tasks like this:
- name: SET LINE 0 4 ACL
cisco.ios.ios_config:
parents: "line vty 0 4"
lines:
- "access-class vty-acl-new in"
- name: SET LINE 5 15 ACL
cisco.ios.ios_config:
parents: "line vty 5 15"
lines:
- "access-class vty-acl-new in"
From the command line you would set line vty 0 15 to capture all 16 lines, but in ansible that would not be idempotent as a line vty 0 15 doesn't actually exist and ansible would always see it as needed to be added.
Well everything is great until something like say Cisco DNA Center decides to set the terminal length to 0 on just vty 0-1 for some reason. Then you end up with a config like this:
line vty 0 1
access-class vty-acl in
exec-timeout 15 0
logging synchronous
length 0
transport input ssh
line vty 2 4
access-class vty-acl in
exec-timeout 15 0
logging synchronous
transport input ssh
line vty 5 15
access-class vty-acl in
exec-timeout 15 0
logging synchronous
transport input ssh
Now your ansible tasks are broken as line vty 0 4 doesn't exist anymore, you lost idempotency. How I work around this is lookup the lines and loop through them, setting the config like this:
- name: GET VTY INFO
cisco.ios.ios_command:
commands:
- show run | inc line vty
register: get_vty_info
- name: ASSOCIATE ACL WITH VTY
with_items: "{{ get_vty_info.stdout_lines[0] | map('trim') | list }}"
cisco.ios.ios_config:
parents: "{{ item }}"
lines:
- "access-class vty-acl-new in"
So now you can make sure your settings are applied to all line vty entries, no matter how they are broken up.
For work I take it a step further and see if vrf-also is set (we have a few) for the acl and using a template set that for the acl if needed like this:
- name: GET VTY INFO
cisco.ios.ios_command:
commands:
- show run | inc line vty
- show run | inc in vrf-also
register: get_vty_info
- name: SET VRF-ALSO IF NEEDED
set_fact:
vrf_also: "found"
when: get_vty_info.stdout[1] != ""
- name: ASSOCIATE ACL WITH VTY
with_items: "{{ get_vty_info.stdout_lines[0] | map('trim') | list }}"
cisco.ios.ios_config:
parents: "{{ item }}"
lines:
- "{{ lookup('template', 'ios_set_access-class.j2') }}"
ios_set_access-class.j2:
access-class vty-acl-new in{% if vrf_also is defined %} vrf-also{%- endif %}
So now we have a way to set the acl for all the VTYs no mater how the lines are broken up.