Repository: ansible/ansible

Issue:
asa_acl does not perform before or after commands
<!---
Verify first that your issue/request is not already reported on GitHub.
Also test if the latest release, and master branch are affected too.
-->

##### ISSUE TYPE
<!--- Pick one below and delete the rest: -->
 - Bug Report


##### COMPONENT NAME
asa_acl

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.2.1.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = Default w/o overrides
```

##### CONFIGURATION
<!---
Mention any settings you have changed/added/removed in ansible.cfg
(or using the ANSIBLE_* environment variables).
-->

##### OS / ENVIRONMENT
<!---
RHEL 7.3
-->

##### SUMMARY
asa_acl does not perform before or after commands

##### STEPS TO REPRODUCE
<!---
For bugs, show exactly how to reproduce the problem, using a minimal test-case.
For new features, show how the feature would be used.
-->

<!--- Paste example playbooks or commands between quotes below -->
```yaml
- name: Cisco ASA access-list config
  connection: local
  hosts: 192.168.10.10
  gather_facts: false
  vars:
    cli:
      username: someuser
      password: XXXXXX
      host: 192.168.10.10
      authorize: yes
      auth_pass: XXXXXX
  tasks:
    - name: configure access-list
      asa_acl:
        lines:
          - access-list TEMPACL extended permit tcp any any eq 443
          - access-list TEMPACL extended permit udp any any eq domain
          - access-list TEMPACL extended deny ip any any
        before: clear configure access-list TEMPACL
        after: write mem
        match: strict
        replace: block
        provider: "{{ cli }}" 
      register: result

    - asa_command:
        commands:
          - wr mem
        provider: "{{ cli }}"

    - debug: var=result

```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->

<!--- Paste verbatim command output between quotes below -->
```
Using /etc/ansible/ansible.cfg as config file

PLAYBOOK: testacl.yml **********************************************************
1 plays in testacl.yml

PLAY [Cisco ASA access-list config] ********************************************

TASK [configure access-list] ***************************************************
task path: /home/someuser/testacl.yml:13
Using module file /usr/lib/python2.7/site-packages/ansible/modules/extras/network/asa/asa_acl.py
<192.168.10.10> ESTABLISH LOCAL CONNECTION FOR USER: root
<192.168.10.10> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo ~/.ansible/tmp/ansible-tmp-1487629270.81-201418757310507 `" && echo ansible-tmp-1487629270.81-201418757310507="` echo ~/.ansible/tmp/ansible-tmp-1487629270.81-201418757310507 `" ) && sleep 0'
<192.168.10.10> PUT /tmp/tmpxr6ugv TO /root/.ansible/tmp/ansible-tmp-1487629270.81-201418757310507/asa_acl.py
<192.168.10.10> EXEC /bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1487629270.81-201418757310507/ /root/.ansible/tmp/ansible-tmp-1487629270.81-201418757310507/asa_acl.py && sleep 0'
<192.168.10.10> EXEC /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1487629270.81-201418757310507/asa_acl.py; rm -rf "/root/.ansible/tmp/ansible-tmp-1487629270.81-201418757310507/" > /dev/null 2>&1 && sleep 0'
changed: [192.168.10.10] => {
    "changed": true, 
    "invocation": {
        "module_args": {
            "after": [
                "write mem"
            ], 
            "auth_pass": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", 
            "authorize": true, 
            "before": [
                "clear configure access-list TEMPACL"
            ], 
            "config": null, 
            "context": null, 
            "force": false, 
            "host": "192.168.10.10", 
            "lines": [
                "access-list TEMPACL extended permit tcp any any eq 443", 
                "access-list TEMPACL extended permit udp any any eq domain", 
                "access-list TEMPACL extended deny ip any any"
            ], 
            "match": "strict", 
            "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", 
            "port": null, 
            "provider": {
                "auth_pass": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", 
                "authorize": true, 
                "host": "192.168.10.10", 
                "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", 
                "username": "someuser"
            }, 
            "replace": "block", 
            "ssh_keyfile": null, 
            "timeout": 10, 
            "transport": null, 
            "username": "someuser"
        }, 
        "module_name": "asa_acl"
    }, 
    "responses": [
        "access-list TEMPACL extended permit tcp any ad permit tcp any an                          eq 443access-list TEMPACL extended permit tcp any $\n", 
        ""
    ], 
    "updates": [
        "access-list TEMPACL extended permit tcp any any eq 443"
    ]
}

TASK [asa_command] *************************************************************
task path: /home/someuser/testacl.yml:26
Using module file /usr/lib/python2.7/site-packages/ansible/modules/extras/network/asa/asa_command.py
<192.168.10.10> ESTABLISH LOCAL CONNECTION FOR USER: root
<192.168.10.10> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo ~/.ansible/tmp/ansible-tmp-1487629271.7-10904289136330 `" && echo ansible-tmp-1487629271.7-10904289136330="` echo ~/.ansible/tmp/ansible-tmp-1487629271.7-10904289136330 `" ) && sleep 0'
<192.168.10.10> PUT /tmp/tmplMVoyP TO /root/.ansible/tmp/ansible-tmp-1487629271.7-10904289136330/asa_command.py
<192.168.10.10> EXEC /bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1487629271.7-10904289136330/ /root/.ansible/tmp/ansible-tmp-1487629271.7-10904289136330/asa_command.py && sleep 0'
<192.168.10.10> EXEC /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1487629271.7-10904289136330/asa_command.py; rm -rf "/root/.ansible/tmp/ansible-tmp-1487629271.7-10904289136330/" > /dev/null 2>&1 && sleep 0'
ok: [192.168.10.10] => {
    "changed": false, 
    "invocation": {
        "module_args": {
            "auth_pass": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", 
            "authorize": true, 
            "commands": [
                "wr mem"
            ], 
            "context": null, 
            "host": "192.168.10.10", 
            "interval": 1, 
            "match": "all", 
            "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", 
            "port": null, 
            "provider": {
                "auth_pass": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", 
                "authorize": true, 
                "host": "192.168.10.10", 
                "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", 
                "username": "someuser"
            }, 
            "retries": 10, 
            "ssh_keyfile": null, 
            "timeout": 10, 
            "transport": null, 
            "username": "someuser", 
            "wait_for": null
        }, 
        "module_name": "asa_command"
    }, 
    "stdout": [
        "Building configuration...\nCryptochecksum: 299d190b 5e065890 14662168 a1b7fa8b \n\n106619 bytes copied in 0.170 secs\n[OK]\n"
    ], 
    "stdout_lines": [
        [
            "Building configuration...", 
            "Cryptochecksum: 299d190b 5e065890 14662168 a1b7fa8b ", 
            "", 
            "106619 bytes copied in 0.170 secs", 
            "[OK]", 
            ""
        ]
    ], 
    "warnings": []
}

TASK [debug] *******************************************************************
task path: /home/someuser/testacl.yml:31
ok: [192.168.10.10] => {
    "result": {
        "changed": true, 
        "responses": [
            "access-list TEMPACL extended permit tcp any ad permit tcp any an                          eq 443access-list TEMPACL extended permit tcp any $\n", 
            ""
        ], 
        "updates": [
            "access-list TEMPACL extended permit tcp any any eq 443"
        ]
    }
}

PLAY RECAP *********************************************************************
192.168.10.10                : ok=3    changed=1    unreachable=0    failed=0   

```



Discussion:
cc @gundalow @Qalthos @privateip
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
@kev111 Can you provide an example playbook and 'ansible-playbook -vvv' output when running the playbook?
ok i updated the original post.
Hello,

is this issue Fixed, having exactly same issue, @kev111 how did you fix it ?

I am running Ansible 2.2.1.0
No, it's not fixed.  I don't think the before and after are actually implemented.  I fixed it by just using asa_command before and after my asa_acl block.
Yes, not working in my scenario as well, here is the output.

- name: Cisco ASA access-list config
  connection: local
  hosts: 192.168.124.252
  gather_facts: false
  vars:
    cli:
      username: cisco
      password: cisco
      host: 192.168.124.252
      authorize: yes
      auth_pass: cisco
  tasks:
    - name: configure access-list
      asa_acl:
        lines:
          - access-list TEMPACL extended permit tcp any any eq ftp
          - access-list TEMPACL extended permit udp any any eq snmp
        before: no access-list TEMPACL extended deny ip any any
        after: access-list TEMPACL extended deny ip any any
        provider: "{{ cli }}" 
      register: result
    - debug: var=result


ansible-playbook asa.yml -i host -vvv
Using /etc/ansible/ansible.cfg as config file

PLAYBOOK: asa.yml **************************************************************
1 plays in asa.yml

PLAY [Cisco ASA access-list config] ********************************************

TASK [configure access-list] ***************************************************
task path: /home/beta/tmp/asa.yml:13
Using module file /usr/local/lib/python2.7/dist-packages/ansible/modules/extras/network/asa/asa_acl.py
<192.168.124.252> ESTABLISH LOCAL CONNECTION FOR USER: beta
<192.168.124.252> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo ~/.ansible/tmp/ansible-tmp-1490278827.52-74173465062208 `" && echo ansible-tmp-1490278827.52-74173465062208="` echo ~/.ansible/tmp/ansible-tmp-1490278827.52-74173465062208 `" ) && sleep 0'
<192.168.124.252> PUT /tmp/tmptmyVQR TO /home/beta/.ansible/tmp/ansible-tmp-1490278827.52-74173465062208/asa_acl.py
<192.168.124.252> EXEC /bin/sh -c 'chmod u+x /home/beta/.ansible/tmp/ansible-tmp-1490278827.52-74173465062208/ /home/beta/.ansible/tmp/ansible-tmp-1490278827.52-74173465062208/asa_acl.py && sleep 0'
<192.168.124.252> EXEC /bin/sh -c '/usr/bin/python /home/beta/.ansible/tmp/ansible-tmp-1490278827.52-74173465062208/asa_acl.py; rm -rf "/home/beta/.ansible/tmp/ansible-tmp-1490278827.52-74173465062208/" > /dev/null 2>&1 && sleep 0'
changed: [192.168.124.252] => {
    "changed": true, 
    "invocation": {
        "module_args": {
            "after": [
                "access-list TEMPACL extended deny ip any any"
            ], 
            "auth_pass": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", 
            "authorize": true, 
            "before": [
                "no access-list TEMPACL extended deny ip any any"
            ], 
            "config": null, 
            "context": null, 
            "force": false, 
            "host": "192.168.124.252", 
            "lines": [
                "access-list TEMPACL extended permit tcp any any eq ftp", 
                "access-list TEMPACL extended permit udp any any eq snmp"
            ], 
            "match": "line", 
            "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", 
            "port": null, 
            "provider": {
                "auth_pass": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", 
                "authorize": true, 
                "host": "192.168.124.252", 
                "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", 
                "username": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
            }, 
            "replace": "line", 
            "ssh_keyfile": null, 
            "timeout": 10, 
            "transport": null, 
            "username": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER"
        }, 
        "module_name": "asa_acl"
    }, 
    "responses": [
        "", 
        "", 
        ""
    ], 
    "updates": [
        "access-list TEMPACL extended permit tcp any any eq ftp", 
        "access-list TEMPACL extended permit udp any any eq snmp"
    ]
}

TASK [debug] *******************************************************************
task path: /home/beta/tmp/asa.yml:22
ok: [192.168.124.252] => {
    "result": {
        "changed": true, 
        "responses": [
            "", 
            "", 
            ""
        ], 
        "updates": [
            "access-list TEMPACL extended permit tcp any any eq ftp", 
            "access-list TEMPACL extended permit udp any any eq snmp"
        ]
    }
}

PLAY RECAP *********************************************************************
192.168.124.252            : ok=2    changed=1    unreachable=0    failed=0   
it would have been really nice if implemented as we have to make sure deny any any log should always be at the end.
needs_contributor thank you for the bug report, this is a community maintained module and we need a contributor to provide a fix for the issue.
cc @ogenstad
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
I can Help, let me review the code
@compyy That's great, thanks, just need someone to write the code first :)

Resolving patch:
diff --git a/lib/ansible/modules/network/asa/asa_acl.py b/lib/ansible/modules/network/asa/asa_acl.py
--- a/lib/ansible/modules/network/asa/asa_acl.py
+++ b/lib/ansible/modules/network/asa/asa_acl.py
@@ -208,8 +208,15 @@ def main():
         commands = str(candidate).split('\n')
 
     if commands:
+        if module.params['before']:
+            commands[:0] = module.params['before']
+
+        if module.params['after']:
+            commands.extend(module.params['after'])
+
         if not module.check_mode:
             load_config(module, commands)
+
         result['changed'] = True
 
     result['updates'] = commands


Test patch: