Repository: ansible/ansible

Issue:
(P1)nxos_acl: module errors out if 0 or 1 access lists are configured
<!---
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
<!--- Name of the module/plugin/task/feature -->
- nxos_acl

##### ANSIBLE VERSION
<!--- Paste verbatim output from “ansible --version” between quotes below -->
```
ansible 2.4.0 (devel bc30dddb81) last updated 2017/07/19 10:17:46 (GMT -400)
  config file = None
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /root/agents-ci/ansible/lib/ansible
  executable location = /root/agents-ci/ansible/bin/ansible
  python version = 2.7.6 (default, Oct 26 2016, 20:30:19) [GCC 4.8.4]
```

##### OS / ENVIRONMENT
<!---
Mention the OS you are running Ansible from, and the OS you are
managing, or say “N/A” for anything that is not platform-specific.
Also mention the specific version of what you are trying to control,
e.g. if this is a network bug the version of firmware on the network device.
-->
- Ansible Server : Ubuntu 14.04
- Device: Nexus 3548

##### SUMMARY
<!--- Explain the problem briefly -->

##### 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.
-->
Problem is exposed by the 3548 which has no access lists configured by default (unlike other platforms). 

<!--- Paste example playbooks or commands between quotes below -->
```yaml
- name: "Setup: Cleanup possibly existing acl."
  nxos_acl: &remove
    name: TEST_ACL
    seq: 10
    state: absent
    provider: "{{ cli }}"
```

<!--- You can also paste gist.github.com links for larger files -->

##### EXPECTED RESULTS
<!--- What did you expect to happen when running the steps above? -->
The module not to error out

##### ACTUAL RESULTS
<!--- What actually happened? If possible run with extra verbosity (-vvvv) -->
Traceback when there are 0 ip access-lists configured:
```
The full traceback is:
Traceback (most recent call last):
  File "/tmp/ansible_1uaQuc/ansible_module_nxos_acl.py", line 559, in <module>
    main()
  File "/tmp/ansible_1uaQuc/ansible_module_nxos_acl.py", line 500, in main
    existing_core, acl = get_acl(module, name, seq)
  File "/tmp/ansible_1uaQuc/ansible_module_nxos_acl.py", line 243, in get_acl
    all_acl_body = body['TABLE_ip_ipv6_mac']['ROW_ip_ipv6_mac']
TypeError: string indices must be integers, not str
```

Traceback when 1 access-list is configured:
```
The full traceback is:
Traceback (most recent call last):
  File "/tmp/ansible_aFXMVF/ansible_module_nxos_acl.py", line 559, in <module>
    main()
  File "/tmp/ansible_aFXMVF/ansible_module_nxos_acl.py", line 500, in main
    existing_core, acl = get_acl(module, name, seq)
  File "/tmp/ansible_aFXMVF/ansible_module_nxos_acl.py", line 246, in get_acl
    if acl.get('acl_name') == acl_name:
AttributeError: 'unicode' object has no attribute 'get'
```


Discussion:
cc @GGabriele @jedelman8 @mikewiebe @privateip @rcarrillocruz @trishnaguha
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
Can you show me what `show ip access-list | json` replies with in each case?

Resolving patch:
diff --git a/lib/ansible/modules/network/nxos/nxos_acl.py b/lib/ansible/modules/network/nxos/nxos_acl.py
--- a/lib/ansible/modules/network/nxos/nxos_acl.py
+++ b/lib/ansible/modules/network/nxos/nxos_acl.py
@@ -239,11 +239,20 @@ def get_acl(module, acl_name, seq_number):
     acl_body = {}
 
     body = execute_show_command(command, module)[0]
-    all_acl_body = body['TABLE_ip_ipv6_mac']['ROW_ip_ipv6_mac']
+    if body:
+        all_acl_body = body['TABLE_ip_ipv6_mac']['ROW_ip_ipv6_mac']
+    else:
+        # no access-lists configured on the device
+        return {}, []
 
-    for acl in all_acl_body:
-        if acl.get('acl_name') == acl_name:
-            acl_body = acl
+    if isinstance(all_acl_body, dict):
+        # Only 1 ACL configured.
+        if all_acl_body.get('acl_name') == acl_name:
+            acl_body = all_acl_body
+    else:
+        for acl in all_acl_body:
+            if acl.get('acl_name') == acl_name:
+                acl_body = acl
 
     try:
         acl_entries = acl_body['TABLE_seqno']['ROW_seqno']


Test patch: