Cisco ACL Idempotency Not Working

I have a simple ACL for a Cisco router. I cannot figure out how to make the playbook idempotent. It always detects a change.

- name: Create new vty acl
  cisco.ios.ios_config:
    lines:
    - 5 permit tcp 172.16.0.0 0.15.255.255 any eq 22
    parents: ip access-list extended vty-acl-in
    before: no ip access-list extended vty-acl-in
    match: exact
    replace: block

[WARNING]: ansible-pylibssh not installed, falling back to paramiko
redirecting (type: action) cisco.ios.ios_config to cisco.ios.ios
[WARNING]: To ensure idempotency and correct diff the input configuration lines should be similar to how they appear if present in the running configuration on device
changed: [rtr2] => {“banners”: {}, “changed”: true, “commands”: [“no ip access-list extended vty-acl-in”, “ip access-list extended vty-acl-in”, “5 permit tcp 172.16.0.0 0.15.255.255 any eq 22”], “updates”: [“no ip access-list extended vty-acl-in”, “ip access-list extended vty-acl-in”, “5 permit tcp 172.16.0.0 0.15.255.255 any eq 22”]}

PLAY RECAP **************************************************************************************************************************************************************
rtr2 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

sh ver
Cisco IOS Software, Linux Software (I86BI_LINUX-ADVENTERPRISEK9-M), Version 15.4(1)T, DEVELOPMENT TEST SOFTWARE
Technical Support: Support - Cisco Support and Downloads – Documentation, Tools, Cases - Cisco
Copyright (c) 1986-2013 by Cisco Systems, Inc.
Compiled Sat 23-Nov-13 03:28 by prod_rel_team

ansible --version
ansible [core 2.16.9]

1 Like

Hey asdfnk143,

Something that comes to mind when looking at your playbook snip here is that you are specifying a before action to remove the ACL and then implement it. Ansible may be detecting that as a change, since inherently it is changing something.

Furthermore,

Have you tried to implement this ACL using the cisco.ios.ios_aclsl module, instead of the cisco.ios.ios_config module? The ACL module can be found here.

At the bottom of the module, before the examples section, there is a “state” section, which specifies how ansible should treat implementing it’s config:

Here is some code from my github I pulled. It’s for a standard acl config, but this should give you a good idea of what’s going on :slight_smile:

    - name: Create new vty acl
      cisco.ios.ios_acls:
        config:
          - afi: ipv4
            acls:
              - name: vty-acl
                acl_type: standard
                aces:
                  - grant: permit
                    sequence: 10
                    source:
                      address: 172.16.0.0
                      wildcard_bits: 0.15.255.255   

Let me know if any of that helps, I’m just a network engineer working on rolling out automation to my company , not an Ansible expert (yet :wink: )

Hey @Jonathan thanks for looking at my issue. I’ve tried the acl module and the config module and still no lucky. I tried your code with the standard acl and it’s still saying changed on subsequent runs of the play. This other forum post said to include the before: no acl format but that doesn’t work for me either? https://github.com/ansible/ansible/issues/47067

1 Like

This is not idempotent either,

- name: Create IOS Mgmt ACL
  cisco.ios.ios_acls:
    state: replaced
    config:
    - afi: ipv4
      acls:
      - name: vty-acl-in
        acl_type: extended
        aces:
        - destination:
            any: true
            port_protocol:
              eq: '22'
          grant: permit
          protocol: tcp
          source:
            address: 172.16.0.0
            wildcard_bits: 0.3.255.255
          sequence: 5
  register: acl_result
1 Like

So I tried running the apparent “fix” in the github post, and it seemed to make things worse.

Here is the code for reference:

- name: ACL Playbook to test idempotency

  hosts: LAB
  #serial: 1

  gather_facts: no

  vars:
    Ansible_test:
      - "10 permit 10.10.1.0 0.0.0.255"
      - "15 permit 10.10.80.0 0.0.0.255"
      - "20 deny any log"

  tasks:
   - name: Configure test ACL
     cisco.ios.ios_config:
      lines: "{{ Ansible_test }}"
      parents: ip access-list standard Ansible-test
      match: line
      replace: block
      before: no ip access-list standard Ansible-test
     register: result

Before I ran the playbook as written above, the first of my switches in my lab would always come back as “ok” (i.e not changed). Now when running this version of the playbook I get all three switches firing off as “changed”.

I can confirm that when I ran my version, Ansible did register the “before: no ip access-list standard Ansible-test” did register as a change when I viewed the results using very very very very verbose mode -vvvv on my playbook run.

More to follow I’m sure…

This may be related to what version of IOS you/we are running, here is a list of the versions in my lab below:

C9200L-24P-4G      17.06.04
WS-C2960X-24PS-L          15.2(7)E7
WS-C2960CX-8PC-L          15.2(7)E9

My C9200L is the only switch that is behaving with Ansible.

Just got the github example play to be idempotent with a virtual router IOSv 15.9(3)M6. I am still trying to make it work for extended acls though. The difference being standard acls can have the acl name and rule in one line vs the extended acl declares the acl name then you go into the sub-config of that acl and declare your aces.

- name: "Ensure access_list mgmt_acl_90"
  ios_config:
    save_when: "modified"
    lines:
    - "access-list 90 permit 172.16.0.0 0.3.255.255"
    match: line
    replace: block
    before: "no access-list 90"
  register: result

I tried using the “diff_ignore_lines” option with no success,

diff_ignore_lines: [ "no ip access-list extended vty-acl", "ip access-list extended vty-acl"]

Extended ACL play with ios_acls module, not idempotent,

- name: Create IOS Mgmt ACL
  cisco.ios.ios_acls:
    state: replaced
    config:
    - afi: ipv4
      acls:
      - name: vty-acl-in
        acl_type: extended
        aces:
        - destination:
            any: true
            port_protocol:
              eq: '22'
          grant: permit
          protocol: tcp
          source:
            address: 172.16.0.0
            wildcard_bits: 0.3.255.255
          sequence: 5
  register: acl_result

Extended ACL play with config module, not idempotent,

- name: load new acl into device
  ios_config:
    lines:
    - 10 permit tcp 172.16.0.0 0.3.255.255 any eq 22
    parents: ip access-list extended test
    before: no ip access-list extended test
    match: exact

Tried several permutations of the following to get extended acl to be idempotent,

- name: load new acl into device
  ios_config:
    lines:
    - 10 permit tcp 172.16.0.0 0.3.255.255 any eq 22
    parents: ip access-list extended test
    before: no ip access-list extended test
    match: line
    diff_ignore_lines: ["no ip access-list extended test"]
    diff_against: running

The verbose output seems like it should ignore but it’s not?

changed: [rtr1] => {
    "banners": {},
    "changed": true,
    "commands": [
        "no ip access-list extended test",
        "ip access-list extended test",
        "10 permit tcp 172.16.0.0 0.3.255.255 any eq 22"
    ],
    "invocation": {
        "module_args": {
            "after": null,
            "backup": false,
            "backup_options": null,
            "before": [
                "no ip access-list extended test"
            ],
            "defaults": false,
            "diff_against": "startup",
            "diff_ignore_lines": [
                "no ip access-list extended test"
            ],
            "intended_config": null,
            "lines": [
                "10 permit tcp 172.16.0.0 0.3.255.255 any eq 22"
            ],
            "match": "line",
            "multiline_delimiter": "@",
            "parents": [
                "ip access-list extended test"
            ],
            "replace": "line",
            "running_config": null,
            "save_when": "never",
            "src": null
        }
    },
    "updates": [
        "no ip access-list extended test",
        "ip access-list extended test",
        "10 permit tcp 172.16.0.0 0.3.255.255 any eq 22"
    ]
}

I give up on using “ip access-list” standard or extended acl versions. Idempotency seems to only work with “access-list 1” type.

Putting a couple more reference links of what other people have used but none seem to be idempotent.

1 Like