'name:' and debug is not printed in ansible-playbook stdout when running role with 'include_role:'

Hi,
I have created a reusable Ansible Role that is being used like a function() to manage ACLs on Cisco IOS, in such a way that the ACL rules are individually removed and added using sequence numbers (ordering matches the list order explicitly).

Everything is working great, but the task in the main playbook which invokes the ‘include_rule:’ module is not printing its ‘name:’. In fact the first ‘name:’ which is printed is for the second task within the role!

Ideally we want all the task ‘names:’ to be printed, including the name of the task calling ‘include_rule:’, so you can print something like “Deploying ACL foo for bar… etc” before printing the generic task names within the role.

You can see in my code snips below that I am using a simple list-of-dicts for the sources to permit instead of explicit ACL lines (allows the list to be used as a source for many contexts etc)

NB; It supports standard and extended ACLs, both numbered and named, and works with IOS 12 and 15.

Example all.yml section

mgmt_access_sources:
  - { ip: 1.2.3.4, wildcard: 0.0.0.0, subnet: 255.255.255.255 }
  - { ip: 172.16.75.0, wildcard: 0.0.0.255, subnet: 255.255.255.0 }
  - { ip: 192.168.0.0, wildcard: 0.0.255.255, subnet: 255.255.0.0 }
etc..

Example playbook section using the ACL managment Role to manage the VTY ACL

# MANAGE VTY ACCESS ACL
- name: 'Register list "mgmt_access_sources" as a fact for vty_acl_lines.j2 template'
  set_fact:
    mgmt_access_sources: "{{ mgmt_access_sources }}"
  tags: ["ios", "switch_access", "switch_access_vty_acl"]
- name: 'Manage VTY ACL'
  include_role:
    name: ios_acl
  vars:
  - ios_acl_rules: "{{ lookup('template', 'vty_acl_lines.j2').split('\n') | select('match', '.+') | list }}"  # Build complete ACL rules list from mgmt_access_sources
  - ios_acl_name: "VTY-ACCESS"
  - ios_acl_type: "extended"
  tags: ["ios", "switch_access", "switch_access_vty_acl"]

vty_acl_lines.j2 (Example Template to build ACL rules)

{% for source in mgmt_access_sources %}
{% if source.ip is defined and source.wildcard is defined and source.wildcard == "0.0.0.0" %}permit tcp host {{ source.ip }} any eq 22
{% elif source.ip is defined and source.wildcard is defined and source.wildcard != "0.0.0.0" %}permit tcp {{ source.ip }} {{ source.wildcard }} any eq 22
{% endif %}
{% endfor %}

ios_acl.yml (ACL management Role)

---
- name: 'Check ios_acl vars'
  fail: msg="ios_acl vars are not sane ios_acl_name {{ ios_acl_name }} ios_acl_type {{ ios_acl_type }} ios_acl_rules {{ ios_acl_rules }}"
  when: ios_acl_name is not defined or ios_acl_name == '' or ios_acl_type is not defined or ios_acl_type == '' or ios_acl_rules is not defined or ios_acl_rules | length < 1
  tags: [ "ios", "ios_acl" ]

- name: "Get current access-list state"
  ios_command:
    commands:
      - "show access-lists {{ ios_acl_name }} | include ^\ +[1-9]"
  register: acl_config
  tags: [ "ios", "ios_acl" ]

- name: 'Register intended ios_acl_rules as fact for ios_acl.j2 template'
  set_fact:
    ios_acl_rules: "{{ ios_acl_rules }}"
  when: acl_config.stdout is defined and acl_config.stdout != '' and acl_config.stdout != None
  tags: [ "ios", "ios_acl" ]

- name: "Remove existing access-list lines not in intended ACL"
  with_items: "{{ acl_config.stdout_lines[0] |\
                      regex_replace('[ \t]{2}') |\
                      regex_replace(' [(].{9,30}[)]') |\
                      regex_replace(', wildcard bits') }}"
  ios_config:
    lines: "no {{ item }}"
    parents: "ip access-list {{ ios_acl_type }} {{ ios_acl_name }}"
  when: "item not in lookup('template', 'ios_acl.j2') and acl_config.stdout_lines[0][0] is defined and acl_config.stdout_lines[0][0] != '' and acl_config.stdout_lines[0][0] != None"
  tags: [ "ios", "ios_acl" ]

- name: "Insert new access-list lines not in existing ACL"
  with_items: "{{ lookup('template', 'ios_acl.j2').split('\n') | select('match', '.+') | list }}"
  ios_config:
    lines: "{{ item }}"
    parents: "ip access-list {{ ios_acl_type }} {{ ios_acl_name }}"
  when: "(item not in acl_config.stdout_lines[0] |\
                      regex_replace('[ \t]{2}') |\
                      regex_replace(' [(].{9,30}[)]') |\
                      regex_replace(', wildcard bits'))"
  tags: [ "ios", "ios_acl" ]

ios_acl.j2 (Role’s Template)

{% for line in ios_acl_rules %}{{ loop.index * 10 }} {{ line }}
{% endfor %}

Below you can see the ansible-playbook stdout which shows it is working and is selectively removing and adding lines, which greatly reduces the risk of chopping off the branch you are sat on… I would also recomend adding an extra check to never negate the ACL line for the Ansible control servers public IP/your office etc…

But you can see that is jumps from task “switch_access : Register list "mgmt_access_sources” as a fact for vty_acl_lines.j2 template" to task “ios_acl : Get current access-list state”. I have confirmed the tasts which do not print are being run correctly, their stdout is just lost.

So, what happend to printing “switch_access : Manage VTY ACL” and “ios_acl : Check ios_acl vars”?!

The issue is positional, and is not an issue with these specific tasks. If I add another random task before “Check ios_acl vars”, I then do see “Check ios_acl vars” printed…

The issue persists on Linux and OSX (Ansible 2.7.4).

Ansible Playbook STDOUT;
TASK [switch_access : Register list “mgmt_access_sources” as a fact for vty_acl_lines.j2 template] ***************************************************************************************************************************************************************************
task path: /local/CAN-Ansible-Playbooks/Network/roles/switch_access/tasks/main.yml:59
ok: [byf-lab-sw-1] => {“ansible_facts”: {“mgmt_access_sources”: [{“ip”: “1.2.3.4”, “subnet”: “255.255.255.255”, “wildcard”: “0.0.0.0”}, {“ip”: “172.16.75.0”, “subnet”: “255.255.255.0”, “wildcard”: “0.0.0.255”}, {“ip”: “192.168.0.0”, “subnet”: “255.255.0.0”, “wildcard”: “0.0.255.255”}]}, “changed”: false}
ok: [byf-lab-sw-2] => {“ansible_facts”: {“mgmt_access_sources”: [{“ip”: “1.2.3.4”, “subnet”: “255.255.255.255”, “wildcard”: “0.0.0.0”}, {“ip”: “172.16.75.0”, “subnet”: “255.255.255.0”, “wildcard”: “0.0.0.255”}, {“ip”: “192.168.0.0”, “subnet”: “255.255.0.0”, “wildcard”: “0.0.255.255”}]}, “changed”: false}
Wednesday 19 December 2018 18:25:16 +0000 (0:00:01.429) 0:01:57.409 ****

TASK [ios_acl : Get current access-list state] *******************************************************************************************************************************************************************************************************************************
task path: /local/CAN-Ansible-Playbooks/Network/roles/ios_acl/tasks/main.yml:7
ok: [byf-lab-sw-2] => {}
ok: [byf-lab-sw-1] => {}
Wednesday 19 December 2018 18:25:18 +0000 (0:00:02.033) 0:01:59.718 ****

TASK [ios_acl : Register intended ios_acl_rules as fact for ios_acl.j2 template] *********************************************************************************************************************************************************************************************
task path: /local/CAN-Ansible-Playbooks/Network/roles/ios_acl/tasks/main.yml:21
ok: [byf-lab-sw-1] => {“ansible_facts”: {“ios_acl_rules”: [“permit tcp host 1.2.3.4 any eq 22”, “permit tcp 172.16.75.0 0.0.0.255 any eq 22”, “permit tcp 192.168.0.0 0.0.255.255 any eq 22”]}, “changed”: false}
ok: [byf-lab-sw-2] => {“ansible_facts”: {“ios_acl_rules”: [“permit tcp host 1.2.3.4 any eq 22”, “permit tcp 172.16.75.0 0.0.0.255 any eq 22”, “permit tcp 192.168.0.0 0.0.255.255 any eq 22”]}, “changed”: false}
Wednesday 19 December 2018 18:25:20 +0000 (0:00:01.452) 0:02:01.170 ****

TASK [ios_acl : Remove existing access-list lines not in intended ACL] *******************************************************************************************************************************************************************************************************
task path: /local/CAN-Ansible-Playbooks/Network/roles/ios_acl/tasks/main.yml:27
changed: [byf-lab-sw-2] => (item=10 permit tcp host any eq 22) => {“banners”: {}, “changed”: true, “commands”: [“ip access-list extended VTY-ACCESS”, “no 10 permit tcp host any eq 22”], “item”: “10 permit tcp host any eq 22”, “updates”: [“ip access-list extended VTY-ACCESS”, “no 10 permit tcp host any eq 22”]}
changed: [byf-lab-sw-2] => (item=20 permit tcp host any eq 22) => {“banners”: {}, “changed”: true, “commands”: [“ip access-list extended VTY-ACCESS”, “no 20 permit tcp host any eq 22”], “item”: “20 permit tcp host any eq 22”, “updates”: [“ip access-list extended VTY-ACCESS”, “no 20 permit tcp host any eq 22”]}
changed: [byf-lab-sw-1] => (item=10 permit tcp host any eq 22) => {“banners”: {}, “changed”: true, “commands”: [“ip access-list extended VTY-ACCESS”, “no 10 permit tcp host any eq 22”], “item”: “10 permit tcp host any eq 22”, “updates”: [“ip access-list extended VTY-ACCESS”, “no 10 permit tcp host any eq 22”]}
changed: [byf-lab-sw-2] => (item=30 permit tcp host any eq 22) => {“banners”: {}, “changed”: true, “commands”: [“ip access-list extended VTY-ACCESS”, “no 30 permit tcp host any eq 22”], “item”: “30 permit tcp host any eq 22”, “updates”: [“ip access-list extended VTY-ACCESS”, “no 30 permit tcp host any eq 22”]}
changed: [byf-lab-sw-2] => (item=40 permit tcp host 1.2.3.4 any eq 22) => {“banners”: {}, “changed”: true, “commands”: [“ip access-list extended VTY-ACCESS”, “no 40 permit tcp host 1.2.3.4 any eq 22”], “item”: “40 permit tcp host 1.2.3.4 any eq 22”, “updates”: [“ip access-list extended VTY-ACCESS”, “no 40 permit tcp host 1.2.3.4 any eq 22”]}
changed: [byf-lab-sw-1] => (item=20 permit tcp host any eq 22) => {“banners”: {}, “changed”: true, “commands”: [“ip access-list extended VTY-ACCESS”, “no 20 permit tcp host any eq 22”], “item”: “20 permit tcp host any eq 22”, “updates”: [“ip access-list extended VTY-ACCESS”, “no 20 permit tcp host any eq 22”]}
changed: [byf-lab-sw-2] => (item=50 permit tcp 0.0.0.127 any eq 22) => {“banners”: {}, “changed”: true, “commands”: [“ip access-list extended VTY-ACCESS”, “no 50 permit tcp 0.0.0.127 any eq 22”], “item”: “50 permit tcp 0.0.0.127 any eq 22”, “updates”: [“ip access-list extended VTY-ACCESS”, “no 50 permit tcp 0.0.0.127 any eq 22”]}
changed: [byf-lab-sw-1] => (item=30 permit tcp host any eq 22) => {“banners”: {}, “changed”: true, “commands”: [“ip access-list extended VTY-ACCESS”, “no 30 permit tcp host any eq 22”], “item”: “30 permit tcp host any eq 22”, “updates”: [“ip access-list extended VTY-ACCESS”, “no 30 permit tcp host any eq 22”]}
changed: [byf-lab-sw-1] => (item=40 permit tcp 0.0.0.127 any eq 22) => {“banners”: {}, “changed”: true, “commands”: [“ip access-list extended VTY-ACCESS”, “no 40 permit tcp 0.0.0.127 any eq 22”], “item”: “40 permit tcp 0.0.0.127 any eq 22”, “updates”: [“ip access-list extended VTY-ACCESS”, “no 40 permit tcp 0.0.0.127 any eq 22”]}
changed: [byf-lab-sw-1] => (item=50 permit tcp host 1.2.3.4 any eq 22) => {“banners”: {}, “changed”: true, “commands”: [“ip access-list extended VTY-ACCESS”, “no 50 permit tcp host 1.2.3.4 any eq 22”], “item”: “50 permit tcp host 1.2.3.4 any eq 22”, “updates”: [“ip access-list extended VTY-ACCESS”, “no 50 permit tcp host 1.2.3.4 any eq 22”]}
Wednesday 19 December 2018 18:27:18 +0000 (0:01:58.338) 0:03:59.509 ****

TASK [ios_acl : Insert new access-list lines not in existing ACL] ************************************************************************************************************************************************************************************************************
task path: /local/CAN-Ansible-Playbooks/Network/roles/ios_acl/tasks/main.yml:38
changed: [byf-lab-sw-2] => (item=10 permit tcp host 1.2.3.4 any eq 22) => {“banners”: {}, “changed”: true, “commands”: [“ip access-list extended VTY-ACCESS”, “10 permit tcp host 1.2.3.4 any eq 22”], “item”: “10 permit tcp host 1.2.3.4 any eq 22”, “updates”: [“ip access-list extended VTY-ACCESS”, “10 permit tcp host 1.2.3.4 any eq 22”]}
changed: [byf-lab-sw-1] => (item=10 permit tcp host 1.2.3.4 any eq 22) => {“banners”: {}, “changed”: true, “commands”: [“ip access-list extended VTY-ACCESS”, “10 permit tcp host 1.2.3.4 any eq 22”], “item”: “10 permit tcp host 1.2.3.4 any eq 22”, “updates”: [“ip access-list extended VTY-ACCESS”, “10 permit tcp host 1.2.3.4 any eq 22”]}
changed: [byf-lab-sw-2] => (item=20 permit tcp 172.16.75.0 0.0.0.255 any eq 22) => {“banners”: {}, “changed”: true, “commands”: [“ip access-list extended VTY-ACCESS”, “20 permit tcp 172.16.75.0 0.0.0.255 any eq 22”], “item”: “20 permit tcp 172.16.75.0 0.0.0.255 any eq 22”, “updates”: [“ip access-list extended VTY-ACCESS”, “20 permit tcp 172.16.75.0 0.0.0.255 any eq 22”]}
changed: [byf-lab-sw-2] => (item=30 permit tcp 192.168.0.0 0.0.255.255 any eq 22) => {“banners”: {}, “changed”: true, “commands”: [“ip access-list extended VTY-ACCESS”, “30 permit tcp 192.168.0.0 0.0.255.255 any eq 22”], “item”: “30 permit tcp 192.168.0.0 0.0.255.255 any eq 22”, “updates”: [“ip access-list extended VTY-ACCESS”, “30 permit tcp 192.168.0.0 0.0.255.255 any eq 22”]}
changed: [byf-lab-sw-1] => (item=20 permit tcp 172.16.75.0 0.0.0.255 any eq 22) => {“banners”: {}, “changed”: true, “commands”: [“ip access-list extended VTY-ACCESS”, “20 permit tcp 172.16.75.0 0.0.0.255 any eq 22”], “item”: “20 permit tcp 172.16.75.0 0.0.0.255 any eq 22”, “updates”: [“ip access-list extended VTY-ACCESS”, “20 permit tcp 172.16.75.0 0.0.0.255 any eq 22”]}
changed: [byf-lab-sw-1] => (item=30 permit tcp 192.168.0.0 0.0.255.255 any eq 22) => {“banners”: {}, “changed”: true, “commands”: [“ip access-list extended VTY-ACCESS”, “30 permit tcp 192.168.0.0 0.0.255.255 any eq 22”], “item”: “30 permit tcp 192.168.0.0 0.0.255.255 any eq 22”, “updates”: [“ip access-list extended VTY-ACCESS”, “30 permit tcp 192.168.0.0 0.0.255.255 any eq 22”]}
Wednesday 19 December 2018 18:27:43 +0000 (0:00:24.506) 0:04:24.016 ****

Thanks in advance for your time and help :slight_smile:

Kind regards, Andrew Lemin

Hi,

Just for others who might have the same issue;
So I did some debugging and skimmed over bits of the source, and I confirmed it is just a cosmetic logging issue, rather than silently failing tasks.

It seems that ‘display_skipped_hosts = False’ behaves inconsistently with the ‘include_role:’ module :frowning: and I suspect in a couple of other places too.

Some docs mention that the task header’s ‘name:’ should always be shown, but sadly this is not true for this module.

# By default, ansible-playbook will display "Skipping [host]" if it determines a task
# should not be run on a host.  Set this to "False" if you don't want to see these "Skipping"
# messages. NOTE: the task header will still be shown regardless of whether or not the
# task is skipped.
display_skipped_hosts = False

Changed this back to ‘display_skipped_hosts = True’, and everything started to display properly again.

Cheers Andy.

Hi,

If anyone else is using this example for managing Cisco IOS ACL’s, I found a minor bug with the regular expression during some regression tests.

regex_replace(' [(].{9,30}[)]') |\

should be changed to

regex_replace(' [(].{7,30}[)]') |\

The length range for the greedy match missed the shortest variant; ‘(1 match)’ Opps :wink:

I might convert this to a proper module and share on the Ansible Galaxy https://galaxy.ansible.com/docs/finding/search.html#search if I find some spare time.
This was done in a role since ‘include_role:’ just to keep the logic readable for team members learning Ansible and not familiar with Python etc.
Cheers, Andy Lemin