Repository: mantl/mantl

Issue:
Unblocking Neutron ports fails when public_url is unset (or Neutron is named differently)
I am trying to install mantl on openstack and am using the sample.yml playbook. When I run the playbook, it fails here

```
TASK: [calico | unlock neutron ports to allow calico traffic] *****************
failed: [mantl-worker-001] => (item=mantl-edge-01) => {"changed": false, "cmd": "/usr/local/bin/neutron_port_update.py \"192.168.0.0/16\" \"fa:16:3e:47:b1:91\"", "delta": "0:00:00.329717", "end": "2016-06-15 21:18:58.223490", "failed": true, "failed_when_result": true, "item": "mantl-edge-01", "rc": 1, "start": "2016-06-15 21:18:57.893773", "stdout_lines": [], "warnings": []}
stderr: Traceback (most recent call last):
  File "/usr/local/bin/neutron_port_update.py", line 128, in <module>
    ports = list_ports(token, public_url)
  File "/usr/local/bin/neutron_port_update.py", line 82, in list_ports
    auth_url = public_url + "v2.0/ports"
TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'
```

It seems that public_url is unset. I manually ran neutron_port_update.py, and tried to debug it. public_url gets set by neutron_public_url, and it appears that is looking for an endpoint named neutron. I have attached the json input and there is no endpoint with that name.

[parsed_json.txt](https://github.com/CiscoCloud/mantl/files/317249/parsed_json.txt)

Unblocking Neutron ports fails when public_url is unset (or Neutron is named differently)
I am trying to install mantl on openstack and am using the sample.yml playbook. When I run the playbook, it fails here

```
TASK: [calico | unlock neutron ports to allow calico traffic] *****************
failed: [mantl-worker-001] => (item=mantl-edge-01) => {"changed": false, "cmd": "/usr/local/bin/neutron_port_update.py \"192.168.0.0/16\" \"fa:16:3e:47:b1:91\"", "delta": "0:00:00.329717", "end": "2016-06-15 21:18:58.223490", "failed": true, "failed_when_result": true, "item": "mantl-edge-01", "rc": 1, "start": "2016-06-15 21:18:57.893773", "stdout_lines": [], "warnings": []}
stderr: Traceback (most recent call last):
  File "/usr/local/bin/neutron_port_update.py", line 128, in <module>
    ports = list_ports(token, public_url)
  File "/usr/local/bin/neutron_port_update.py", line 82, in list_ports
    auth_url = public_url + "v2.0/ports"
TypeError: unsupported operand type(s) for +: 'NoneType' and 'str'
```

It seems that public_url is unset. I manually ran neutron_port_update.py, and tried to debug it. public_url gets set by neutron_public_url, and it appears that is looking for an endpoint named neutron. I have attached the json input and there is no endpoint with that name.

[parsed_json.txt](https://github.com/CiscoCloud/mantl/files/317249/parsed_json.txt)



Discussion:
On Cisco Metapod neutron is called "Network Service"

Thje output of a `openstack catalog list`

```
| neutron    | network       | RegionOne                                                                    |
|            |               |   internal: http://10.51.8.150:9696                                          |
|            |               | RegionOne                                                                    |
|            |               |   public: http://10.51.8.150:9696                                            |
|            |               | RegionOne                                                                    |
|            |               |   admin: http://10.51.8.150:9696                                             |
```

On Cisco Metapod at least:

```
| Network Service        | network        | RegionOne                                                                                      |
|                        |                |   publicURL: https://api-xxx.client.metacloud.net:9696/                                    |
|                        |                |   internalURL: http://api.xxx.mc.metacloud.in:9696/                                        |
|                        |                |   adminURL: http://api.xxx.mc.metacloud.in:9696/                                           |
```

The fix was to edit `roles/calico/files/neutron_port_update.py`:

```
def neutron_public_url(catalog):
    """Get Neutron publicURL"""

    for i in catalog['access']['serviceCatalog']:
        if i['name'] == 'Network Service':
            for endpoint in i['endpoints']:
                return endpoint['publicURL']
```

Check your own environment as making that change should deploy it.

@mattsday We'd love to see a PR for the fix as long as it still works when Neutron is named "Neutron" :smile: 

I suspect the fix would be instead to match on the _type_ instead of the _name_ (haven't tested though!):

```
def neutron_public_url(catalog):
    """Get Neutron publicURL"""

    for i in catalog['access']['serviceCatalog']:
        if i['type'] == 'network':
            for endpoint in i['endpoints']:
```

Will test it tonight or tomorrow against both Metapod and an RDO OpenStack & issue a PR if it works ;-)

On Cisco Metapod neutron is called "Network Service"

Thje output of a `openstack catalog list`

```
| neutron    | network       | RegionOne                                                                    |
|            |               |   internal: http://10.51.8.150:9696                                          |
|            |               | RegionOne                                                                    |
|            |               |   public: http://10.51.8.150:9696                                            |
|            |               | RegionOne                                                                    |
|            |               |   admin: http://10.51.8.150:9696                                             |
```

On Cisco Metapod at least:

```
| Network Service        | network        | RegionOne                                                                                      |
|                        |                |   publicURL: https://api-xxx.client.metacloud.net:9696/                                    |
|                        |                |   internalURL: http://api.xxx.mc.metacloud.in:9696/                                        |
|                        |                |   adminURL: http://api.xxx.mc.metacloud.in:9696/                                           |
```

The fix was to edit `roles/calico/files/neutron_port_update.py`:

```
def neutron_public_url(catalog):
    """Get Neutron publicURL"""

    for i in catalog['access']['serviceCatalog']:
        if i['name'] == 'Network Service':
            for endpoint in i['endpoints']:
                return endpoint['publicURL']
```

Check your own environment as making that change should deploy it.

@mattsday We'd love to see a PR for the fix as long as it still works when Neutron is named "Neutron" :smile: 

I suspect the fix would be instead to match on the _type_ instead of the _name_ (haven't tested though!):

```
def neutron_public_url(catalog):
    """Get Neutron publicURL"""

    for i in catalog['access']['serviceCatalog']:
        if i['type'] == 'network':
            for endpoint in i['endpoints']:
```

Will test it tonight or tomorrow against both Metapod and an RDO OpenStack & issue a PR if it works ;-)


Resolving patch:
diff --git a/roles/calico/files/neutron_port_update.py b/roles/calico/files/neutron_port_update.py
--- a/roles/calico/files/neutron_port_update.py
+++ b/roles/calico/files/neutron_port_update.py
@@ -71,7 +71,7 @@ def neutron_public_url(catalog):
     """Get Neutron publicURL"""
 
     for i in catalog['access']['serviceCatalog']:
-        if i['name'] == 'neutron':
+        if i['type'] == 'network':
             for endpoint in i['endpoints']:
                 return endpoint['publicURL']
 


Test patch: