Repository: ansible/ansible

Issue:
Bug with static binding of EPG to VPC (aci_static_binding_to_epg)

##### ISSUE TYPE

 - Bug Report


##### COMPONENT NAME
aci_static_binding_to_epg

##### ANSIBLE VERSION

```
ansible 2.5.0
  config file = /etc/ansible/ansible.cfg
  configured module search path = [u'/root/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python2.7/dist-packages/ansible
  executable location = /usr/bin/ansible
  python version = 2.7.12 (default, Dec  4 2017, 14:50:18) [GCC 5.4.0 20160609]

```

##### CONFIGURATION


##### OS / ENVIRONMENT

Distributor ID: Ubuntu
Description:    Ubuntu 16.04.4 LTS
Release:        16.04
Codename:       xenial

Cisco APIC version 3.1(2m)

##### SUMMARY
When trying to configure static binding under epg of type Virtual Port Channel (VPC) the ansible playbook keeps giving the error as below:

TASK [Deploy Static Path binding for given EPG] *********************************************************************************
failed: [10.255.193.234 -> localhost] (item={u'ap': u'test-ap-1', u'encapid': 100, u'leafs': u'101-102', u'interface': u'vPC_TESTSVR777', u'epg': u'WEB-1', u'tenant': u'test-tn-1'}) => {"changed": false, "item": {"ap": "test-ap-1", "encapid": 100, "epg": "WEB-1", "interface": "vPC_TESTSVR777", "leafs": "101-102", "tenant": "test-tn-1"}, "msg": "A interface_type of \"vpc\" requires 2 leafs"}

"msg": "A interface_type of \"vpc\" requires 2 leafs"

This is even after specifying: "leafs": "101-102"


##### STEPS TO REPRODUCE

Create a normal ACI playbook after creating a tenant/VRF/BD/AP/EPG

Run the static binding module as below.

```yaml

  - name: Deploy Static Path binding for given EPG
    aci_static_binding_to_epg:
        <<: *aci_login
        tenant: "{{ item.tenant }}"
        ap: "{{ item.ap }}"
        epg: "{{ item.epg }}"
        encap_id: "{{ item.encapid }}"
        deploy_immediacy: lazy
        interface_mode: trunk
        interface_type: vpc
        pod_id: 1
        leafs: "{{ item.leafs }}"
        interface: "{{ item.interface }}"
        state: present
    delegate_to: localhost
    with_items:
      - tenant: test-tn-1
        ap: test-ap-1
        epg: WEB-1
        encapid: 100
        leafs: 101-102
        interface: 'vPC_TESTSVR777'


```



##### EXPECTED RESULTS
Configuration should have been successfully sent to the APIC controlller for the static binding for EPG.

##### ACTUAL RESULTS

```
TASK [Deploy Static Path binding for given EPG] *********************************************************************************
task path: /etc/ansible/playbooks/create-epgbindings.yml:31
Using module file /usr/lib/python2.7/dist-packages/ansible/modules/network/aci/aci_static_binding_to_epg.py
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: root
<localhost> EXEC /bin/sh -c 'echo ~ && sleep 0'
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo /root/.ansible/tmp/ansible-tmp-1524788666.41-61846862726450 `" && echo ansible-tmp-1524788666.41-61846862726450="` echo /root/.ansible/tmp/ansible-tmp-1524788666.41-61846862726450 `" ) && sleep 0'
<localhost> PUT /root/.ansible/tmp/ansible-local-115400jLATn/tmpatys4S TO /root/.ansible/tmp/ansible-tmp-1524788666.41-61846862726450/aci_static_binding_to_epg.py
<localhost> EXEC /bin/sh -c 'chmod u+x /root/.ansible/tmp/ansible-tmp-1524788666.41-61846862726450/ /root/.ansible/tmp/ansible-tmp-1524788666.41-61846862726450/aci_static_binding_to_epg.py && sleep 0'
<localhost> EXEC /bin/sh -c '/usr/bin/python /root/.ansible/tmp/ansible-tmp-1524788666.41-61846862726450/aci_static_binding_to_epg.py && sleep 0'
<localhost> EXEC /bin/sh -c 'rm -f -r /root/.ansible/tmp/ansible-tmp-1524788666.41-61846862726450/ > /dev/null 2>&1 && sleep 0'
failed: [10.1.1.1 -> localhost] (item={u'ap': u'test-ap-1', u'encapid': 100, u'leafs': u'101-102', u'interface': u'vPC_TESTSVR777', u'epg': u'WEB-1', u'tenant': u'test-tn-1'}) => {
    "changed": false,
    "invocation": {
        "module_args": {
            "ap": "test-ap-1",
            "certificate_name": null,
            "deploy_immediacy": "lazy",
            "encap_id": 100,
            "epg": "WEB-1",
            "extpaths": null,
            "host": "10.1.1.1",
            "hostname": "10.1.1.1",
            "interface": "vPC_TESTSVR777",
            "interface_mode": "trunk",
            "interface_type": "vpc",
            "leafs": [
                "101-102"
            ],
            "output_level": null,
            "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "pod_id": 1,
            "port": null,
            "primary_encap_id": null,
            "private_key": null,
            "state": "present",
            "tenant": "test-tn-1",
            "timeout": 30,
            "use_proxy": true,
            "use_ssl": true,
            "username": "test-ans",
            "validate_certs": false
        }
    },
    "item": {
        "ap": "test-ap-1",
        "encapid": 100,
        "epg": "WEB-1",
        "interface": "vPC_TESTSVR777",
        "leafs": "101-102",
        "tenant": "test-tn-1"
    },
    "msg": "A interface_type of \"vpc\" requires 2 leafs"
}
        to retry, use: --limit @/etc/ansible/playbooks/create-epgbindings.retry

PLAY RECAP **********************************************************************************************************************
10.1.1.1             : ok=1    changed=0    unreachable=0    failed=1


```



Discussion:
Files identified in the description:
* [lib/ansible/modules/network/aci/aci_static_binding_to_epg.py](https://github.com/ansible/ansible/blob/devel/lib/ansible/modules/network/aci/aci_static_binding_to_epg.py)

If these files are inaccurate, please update the `component name` section of the description or use the `!component` bot command.

[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: components_banner --->
cc @brunocalogero @dagwieers @jmcgill298 @schunduri
[click here for bot help](https://github.com/ansible/ansibullbot/blob/master/ISSUE_HELP.md)
<!--- boilerplate: notify --->
I have found the issue.

Document states below:

When interface_type is vpc, then leafs is a list with both leaf IDs.
The leafs value is usually something like '101' or '101-102' depending on connection_type


This needs to be amended.

Correct attributes needs to be:
leafs: 101,102



@micruzz82 Thanks for figuring this out, would you be interested in sending a pull request to fix the docs? Thanks!
So `101,102` works because Ansible is *smart* and assumes the comma is a list delimiter. However it is always better to write: `[ 101, 102 ]`, or as a YAML list (multi-line).

The parameter documentation itself is clear, but we may want to extend the examples.

And I wonder if we want to support 101-102 as well though, since it is a common thing to do, and it is easy to convert it internally. @brunocalogero @jmcgill298 What do you both think ?
`101-102` is how it appears in the APIC I believe. `When C(interface_type) is C(vpc), then C(leafs) is a list with both leaf IDs.` is the line meant to indicate that it should be written in an acceptable yaml list format (as above or  lines with `-` for entries). I can see that this could be confusing, and should be updated.

@dagwieers It probably would make sense to convert a string of `node1-node2` to a two item list

Resolving patch:
diff --git a/lib/ansible/modules/network/aci/aci_static_binding_to_epg.py b/lib/ansible/modules/network/aci/aci_static_binding_to_epg.py
--- a/lib/ansible/modules/network/aci/aci_static_binding_to_epg.py
+++ b/lib/ansible/modules/network/aci/aci_static_binding_to_epg.py
@@ -308,8 +308,11 @@ def main():
     pod_id = module.params['pod_id']
     leafs = module.params['leafs']
     if leafs is not None:
-        # Users are likely to use integers for leaf IDs, which would raise an exception when using the join method
-        leafs = [str(leaf) for leaf in module.params['leafs']]
+        # Process leafs, and support dash-delimited leafs
+        leafs = []
+        for leaf in module.params['leafs']:
+            # Users are likely to use integers for leaf IDs, which would raise an exception when using the join method
+            leafs.extend(str(leaf).split('-'))
         if len(leafs) == 1:
             if interface_type != 'vpc':
                 leafs = leafs[0]


Test patch: