We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN 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)


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `roles/calico/files/neutron_port_update.py`
Content:
```
1 #!/usr/bin/env python
2 # This script updates the allowed address pairs in Neutron with the
3 # 'neutron port-update' command. This is required by Calico in OpenStack,
4 # otherwise BGP will not be working. We query OpenStack API directly to prevent
5 # installing any dependencies such as python-neutronclient.
6 #
7 # USAGE: script_name arg1 arg2...argN
8 # arg1 - Calico network, i.e. 192.168.0.0/24
9 # arg2...argN - VMs MAC addresses
10 #
11 # Script exit codes (for Ansible)
12 # 0 - port has been updated
13 # 1 - error
14 # 2 - no update to port [default]
15 
16 import json
17 import os
18 import requests
19 import sys
20 
21 def credentials():
22     """Retrieves credentials"""
23 
24     username = os.environ.get('OS_USERNAME')
25     password = os.environ.get('OS_PASSWORD')
26     tenant_name = os.environ.get('OS_TENANT_NAME')
27     auth_url = os.environ.get('OS_AUTH_URL')
28 
29     if not all((username, password, tenant_name, auth_url)):
30         sys.stderr.write("ERROR: Unable to get Keystone credentials\n")
31         exit(1)
32 
33     return {
34         'username': username,
35         'password': password,
36         'tenant_name': tenant_name,
37         'auth_url': auth_url
38     }
39 
40 def get_catalog():
41     """Get service catalog from Keystone with token and all endpoints"""
42 
43     creds = credentials()
44     headers = {'Content-Type': 'application/json'}
45     payload = {
46                 "auth":
47                   {
48                     "tenantName": creds['tenant_name'],
49                     "passwordCredentials": {
50                                              "username": creds['username'],
51                                              "password": creds['password']
52                                            }
53                   }
54               }
55     auth_url = creds['auth_url'] + "/tokens"
56     r = requests.post(auth_url, headers=headers, data=json.dumps(payload))
57 
58     parsed_json = json.loads(r.text)
59     if not parsed_json or 'error' in parsed_json:
60         sys.stderr.write("ERROR: Unable to get authentication token\n")
61         exit(1)
62 
63     return parsed_json
64 
65 def get_token(catalog):
66     """Get Keystone authentication token"""
67 
68     return catalog['access']['token']['id']
69 
70 def neutron_public_url(catalog):
71     """Get Neutron publicURL"""
72 
73     for i in catalog['access']['serviceCatalog']:
74         if i['name'] == 'neutron':
75             for endpoint in i['endpoints']:
76                 return endpoint['publicURL']
77 
78 def list_ports(token, public_url):
79     """List Neutron ports"""
80 
81     headers = {'X-Auth-Token': token}
82     auth_url = public_url + "v2.0/ports"
83     r = requests.get(auth_url, headers=headers)
84 
85     if r.text:
86         parsed_json = json.loads(r.text)
87         return parsed_json['ports']
88     else:
89         sys.stderr.write("ERROR: Unable to retrieve Neutron ports list\n")
90         exit(1)
91 
92 def update_port(token, public_url, port_id, mac_address, calico_network):
93     """Update Neutron port with the allowed address pairs"""
94 
95     headers = {'Content-Type': 'application/json', 'X-Auth-Token': token}
96     payload = {
97                 "port": {
98                           "allowed_address_pairs": [
99                              {
100                                "ip_address": calico_network,
101                                "mac_address": mac_address
102                              }
103                           ]
104                         }
105               }
106     auth_url = public_url + "v2.0/ports/" + port_id
107     r = requests.put(auth_url, headers=headers, data=json.dumps(payload))
108 
109     parsed_json = json.loads(r.text)
110     if r.status_code != 200 or 'NeutronError' in parsed_json:
111         sys.stderr.write("ERROR: Unable to update port: %s\n" % parsed_json['NeutronError'])
112         exit(1)
113     else:
114         return r.status_code
115 
116 if __name__ == "__main__":
117 
118     if len(sys.argv) < 3:
119         sys.stderr.write("ERROR: Please run script with the correct arguments\n")
120         exit(1)
121 
122     calico_network = sys.argv[1]
123     vms_mac_addresses = sys.argv[2:]
124 
125     catalog = get_catalog()
126     token = get_token(catalog)
127     public_url = neutron_public_url(catalog)
128     ports = list_ports(token, public_url)
129 
130     exit_code = 0 # no update to port
131 
132     for port in ports:
133         port_id = port['id']
134         mac_address = port['mac_address']
135         if mac_address in vms_mac_addresses and not port['allowed_address_pairs']:
136             status_code = update_port(token, public_url, port_id, mac_address, calico_network)
137             if status_code == 200:
138                 exit_code = 2 # port has been updated
139 
140     exit(exit_code)
141
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

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 @@
     """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']

{"golden_diff": "diff --git a/roles/calico/files/neutron_port_update.py b/roles/calico/files/neutron_port_update.py\n--- a/roles/calico/files/neutron_port_update.py\n+++ b/roles/calico/files/neutron_port_update.py\n@@ -71,7 +71,7 @@\n     \"\"\"Get Neutron publicURL\"\"\"\n \n     for i in catalog['access']['serviceCatalog']:\n-        if i['name'] == 'neutron':\n+        if i['type'] == 'network':\n             for endpoint in i['endpoints']:\n                 return endpoint['publicURL']\n", "issue": "Unblocking Neutron ports fails when public_url is unset (or Neutron is named differently)\nI am trying to install mantl on openstack and am using the sample.yml playbook. When I run the playbook, it fails here\n\n```\nTASK: [calico | unlock neutron ports to allow calico traffic] *****************\nfailed: [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\": []}\nstderr: Traceback (most recent call last):\n  File \"/usr/local/bin/neutron_port_update.py\", line 128, in <module>\n    ports = list_ports(token, public_url)\n  File \"/usr/local/bin/neutron_port_update.py\", line 82, in list_ports\n    auth_url = public_url + \"v2.0/ports\"\nTypeError: unsupported operand type(s) for +: 'NoneType' and 'str'\n```\n\nIt 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.\n\n[parsed_json.txt](https://github.com/CiscoCloud/mantl/files/317249/parsed_json.txt)\n\nUnblocking Neutron ports fails when public_url is unset (or Neutron is named differently)\nI am trying to install mantl on openstack and am using the sample.yml playbook. When I run the playbook, it fails here\n\n```\nTASK: [calico | unlock neutron ports to allow calico traffic] *****************\nfailed: [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\": []}\nstderr: Traceback (most recent call last):\n  File \"/usr/local/bin/neutron_port_update.py\", line 128, in <module>\n    ports = list_ports(token, public_url)\n  File \"/usr/local/bin/neutron_port_update.py\", line 82, in list_ports\n    auth_url = public_url + \"v2.0/ports\"\nTypeError: unsupported operand type(s) for +: 'NoneType' and 'str'\n```\n\nIt 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.\n\n[parsed_json.txt](https://github.com/CiscoCloud/mantl/files/317249/parsed_json.txt)\n\n", "before_files": [{"content": "#!/usr/bin/env python\n# This script updates the allowed address pairs in Neutron with the\n# 'neutron port-update' command. This is required by Calico in OpenStack,\n# otherwise BGP will not be working. We query OpenStack API directly to prevent\n# installing any dependencies such as python-neutronclient.\n#\n# USAGE: script_name arg1 arg2...argN\n# arg1 - Calico network, i.e. 192.168.0.0/24\n# arg2...argN - VMs MAC addresses\n#\n# Script exit codes (for Ansible)\n# 0 - port has been updated\n# 1 - error\n# 2 - no update to port [default]\n\nimport json\nimport os\nimport requests\nimport sys\n\ndef credentials():\n    \"\"\"Retrieves credentials\"\"\"\n\n    username = os.environ.get('OS_USERNAME')\n    password = os.environ.get('OS_PASSWORD')\n    tenant_name = os.environ.get('OS_TENANT_NAME')\n    auth_url = os.environ.get('OS_AUTH_URL')\n\n    if not all((username, password, tenant_name, auth_url)):\n        sys.stderr.write(\"ERROR: Unable to get Keystone credentials\\n\")\n        exit(1)\n\n    return {\n        'username': username,\n        'password': password,\n        'tenant_name': tenant_name,\n        'auth_url': auth_url\n    }\n\ndef get_catalog():\n    \"\"\"Get service catalog from Keystone with token and all endpoints\"\"\"\n\n    creds = credentials()\n    headers = {'Content-Type': 'application/json'}\n    payload = {\n                \"auth\":\n                  {\n                    \"tenantName\": creds['tenant_name'],\n                    \"passwordCredentials\": {\n                                             \"username\": creds['username'],\n                                             \"password\": creds['password']\n                                           }\n                  }\n              }\n    auth_url = creds['auth_url'] + \"/tokens\"\n    r = requests.post(auth_url, headers=headers, data=json.dumps(payload))\n\n    parsed_json = json.loads(r.text)\n    if not parsed_json or 'error' in parsed_json:\n        sys.stderr.write(\"ERROR: Unable to get authentication token\\n\")\n        exit(1)\n\n    return parsed_json\n\ndef get_token(catalog):\n    \"\"\"Get Keystone authentication token\"\"\"\n\n    return catalog['access']['token']['id']\n\ndef neutron_public_url(catalog):\n    \"\"\"Get Neutron publicURL\"\"\"\n\n    for i in catalog['access']['serviceCatalog']:\n        if i['name'] == 'neutron':\n            for endpoint in i['endpoints']:\n                return endpoint['publicURL']\n\ndef list_ports(token, public_url):\n    \"\"\"List Neutron ports\"\"\"\n\n    headers = {'X-Auth-Token': token}\n    auth_url = public_url + \"v2.0/ports\"\n    r = requests.get(auth_url, headers=headers)\n\n    if r.text:\n        parsed_json = json.loads(r.text)\n        return parsed_json['ports']\n    else:\n        sys.stderr.write(\"ERROR: Unable to retrieve Neutron ports list\\n\")\n        exit(1)\n\ndef update_port(token, public_url, port_id, mac_address, calico_network):\n    \"\"\"Update Neutron port with the allowed address pairs\"\"\"\n\n    headers = {'Content-Type': 'application/json', 'X-Auth-Token': token}\n    payload = {\n                \"port\": {\n                          \"allowed_address_pairs\": [\n                             {\n                               \"ip_address\": calico_network,\n                               \"mac_address\": mac_address\n                             }\n                          ]\n                        }\n              }\n    auth_url = public_url + \"v2.0/ports/\" + port_id\n    r = requests.put(auth_url, headers=headers, data=json.dumps(payload))\n\n    parsed_json = json.loads(r.text)\n    if r.status_code != 200 or 'NeutronError' in parsed_json:\n        sys.stderr.write(\"ERROR: Unable to update port: %s\\n\" % parsed_json['NeutronError'])\n        exit(1)\n    else:\n        return r.status_code\n\nif __name__ == \"__main__\":\n\n    if len(sys.argv) < 3:\n        sys.stderr.write(\"ERROR: Please run script with the correct arguments\\n\")\n        exit(1)\n\n    calico_network = sys.argv[1]\n    vms_mac_addresses = sys.argv[2:]\n\n    catalog = get_catalog()\n    token = get_token(catalog)\n    public_url = neutron_public_url(catalog)\n    ports = list_ports(token, public_url)\n\n    exit_code = 0 # no update to port\n\n    for port in ports:\n        port_id = port['id']\n        mac_address = port['mac_address']\n        if mac_address in vms_mac_addresses and not port['allowed_address_pairs']:\n            status_code = update_port(token, public_url, port_id, mac_address, calico_network)\n            if status_code == 200:\n                exit_code = 2 # port has been updated\n\n    exit(exit_code)\n", "path": "roles/calico/files/neutron_port_update.py"}], "after_files": [{"content": "#!/usr/bin/env python\n# This script updates the allowed address pairs in Neutron with the\n# 'neutron port-update' command. This is required by Calico in OpenStack,\n# otherwise BGP will not be working. We query OpenStack API directly to prevent\n# installing any dependencies such as python-neutronclient.\n#\n# USAGE: script_name arg1 arg2...argN\n# arg1 - Calico network, i.e. 192.168.0.0/24\n# arg2...argN - VMs MAC addresses\n#\n# Script exit codes (for Ansible)\n# 0 - port has been updated\n# 1 - error\n# 2 - no update to port [default]\n\nimport json\nimport os\nimport requests\nimport sys\n\ndef credentials():\n    \"\"\"Retrieves credentials\"\"\"\n\n    username = os.environ.get('OS_USERNAME')\n    password = os.environ.get('OS_PASSWORD')\n    tenant_name = os.environ.get('OS_TENANT_NAME')\n    auth_url = os.environ.get('OS_AUTH_URL')\n\n    if not all((username, password, tenant_name, auth_url)):\n        sys.stderr.write(\"ERROR: Unable to get Keystone credentials\\n\")\n        exit(1)\n\n    return {\n        'username': username,\n        'password': password,\n        'tenant_name': tenant_name,\n        'auth_url': auth_url\n    }\n\ndef get_catalog():\n    \"\"\"Get service catalog from Keystone with token and all endpoints\"\"\"\n\n    creds = credentials()\n    headers = {'Content-Type': 'application/json'}\n    payload = {\n                \"auth\":\n                  {\n                    \"tenantName\": creds['tenant_name'],\n                    \"passwordCredentials\": {\n                                             \"username\": creds['username'],\n                                             \"password\": creds['password']\n                                           }\n                  }\n              }\n    auth_url = creds['auth_url'] + \"/tokens\"\n    r = requests.post(auth_url, headers=headers, data=json.dumps(payload))\n\n    parsed_json = json.loads(r.text)\n    if not parsed_json or 'error' in parsed_json:\n        sys.stderr.write(\"ERROR: Unable to get authentication token\\n\")\n        exit(1)\n\n    return parsed_json\n\ndef get_token(catalog):\n    \"\"\"Get Keystone authentication token\"\"\"\n\n    return catalog['access']['token']['id']\n\ndef neutron_public_url(catalog):\n    \"\"\"Get Neutron publicURL\"\"\"\n\n    for i in catalog['access']['serviceCatalog']:\n        if i['type'] == 'network':\n            for endpoint in i['endpoints']:\n                return endpoint['publicURL']\n\ndef list_ports(token, public_url):\n    \"\"\"List Neutron ports\"\"\"\n\n    headers = {'X-Auth-Token': token}\n    auth_url = public_url + \"v2.0/ports\"\n    r = requests.get(auth_url, headers=headers)\n\n    if r.text:\n        parsed_json = json.loads(r.text)\n        return parsed_json['ports']\n    else:\n        sys.stderr.write(\"ERROR: Unable to retrieve Neutron ports list\\n\")\n        exit(1)\n\ndef update_port(token, public_url, port_id, mac_address, calico_network):\n    \"\"\"Update Neutron port with the allowed address pairs\"\"\"\n\n    headers = {'Content-Type': 'application/json', 'X-Auth-Token': token}\n    payload = {\n                \"port\": {\n                          \"allowed_address_pairs\": [\n                             {\n                               \"ip_address\": calico_network,\n                               \"mac_address\": mac_address\n                             }\n                          ]\n                        }\n              }\n    auth_url = public_url + \"v2.0/ports/\" + port_id\n    r = requests.put(auth_url, headers=headers, data=json.dumps(payload))\n\n    parsed_json = json.loads(r.text)\n    if r.status_code != 200 or 'NeutronError' in parsed_json:\n        sys.stderr.write(\"ERROR: Unable to update port: %s\\n\" % parsed_json['NeutronError'])\n        exit(1)\n    else:\n        return r.status_code\n\nif __name__ == \"__main__\":\n\n    if len(sys.argv) < 3:\n        sys.stderr.write(\"ERROR: Please run script with the correct arguments\\n\")\n        exit(1)\n\n    calico_network = sys.argv[1]\n    vms_mac_addresses = sys.argv[2:]\n\n    catalog = get_catalog()\n    token = get_token(catalog)\n    public_url = neutron_public_url(catalog)\n    ports = list_ports(token, public_url)\n\n    exit_code = 0 # no update to port\n\n    for port in ports:\n        port_id = port['id']\n        mac_address = port['mac_address']\n        if mac_address in vms_mac_addresses and not port['allowed_address_pairs']:\n            status_code = update_port(token, public_url, port_id, mac_address, calico_network)\n            if status_code == 200:\n                exit_code = 2 # port has been updated\n\n    exit(exit_code)\n", "path": "roles/calico/files/neutron_port_update.py"}]}