Make neutronclient parse keystone v3 endpoints correctly
Import keystone access module to handle various verion of keystone catalog. Change-Id: Ie8de15da6341cdb3af73c0fa8753f7e754bf6275 Closes-bug: 1295056
This commit is contained in:
@@ -21,6 +21,7 @@ except ImportError:
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
from keystoneclient import access
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
from neutronclient.common import exceptions
|
from neutronclient.common import exceptions
|
||||||
@@ -40,55 +41,6 @@ else:
|
|||||||
logging.getLogger("requests").setLevel(_requests_log_level)
|
logging.getLogger("requests").setLevel(_requests_log_level)
|
||||||
|
|
||||||
|
|
||||||
class ServiceCatalog(object):
|
|
||||||
"""Helper methods for dealing with a Keystone Service Catalog."""
|
|
||||||
|
|
||||||
def __init__(self, resource_dict):
|
|
||||||
self.catalog = resource_dict
|
|
||||||
|
|
||||||
def get_token(self):
|
|
||||||
"""Fetch token details from service catalog."""
|
|
||||||
token = {'id': self.catalog['access']['token']['id'],
|
|
||||||
'expires': self.catalog['access']['token']['expires'], }
|
|
||||||
try:
|
|
||||||
token['user_id'] = self.catalog['access']['user']['id']
|
|
||||||
token['tenant_id'] = (
|
|
||||||
self.catalog['access']['token']['tenant']['id'])
|
|
||||||
except Exception:
|
|
||||||
# just leave the tenant and user out if it doesn't exist
|
|
||||||
pass
|
|
||||||
return token
|
|
||||||
|
|
||||||
def url_for(self, attr=None, filter_value=None,
|
|
||||||
service_type='network', endpoint_type='publicURL'):
|
|
||||||
"""Fetch the URL from the Neutron service for
|
|
||||||
a particular endpoint type. If none given, return
|
|
||||||
publicURL.
|
|
||||||
"""
|
|
||||||
|
|
||||||
catalog = self.catalog['access'].get('serviceCatalog', [])
|
|
||||||
matching_endpoints = []
|
|
||||||
for service in catalog:
|
|
||||||
if service['type'] != service_type:
|
|
||||||
continue
|
|
||||||
|
|
||||||
endpoints = service['endpoints']
|
|
||||||
for endpoint in endpoints:
|
|
||||||
if not filter_value or endpoint.get(attr) == filter_value:
|
|
||||||
matching_endpoints.append(endpoint)
|
|
||||||
|
|
||||||
if not matching_endpoints:
|
|
||||||
raise exceptions.EndpointNotFound()
|
|
||||||
elif len(matching_endpoints) > 1:
|
|
||||||
raise exceptions.AmbiguousEndpoints(
|
|
||||||
matching_endpoints=matching_endpoints)
|
|
||||||
else:
|
|
||||||
if endpoint_type not in matching_endpoints[0]:
|
|
||||||
raise exceptions.EndpointTypeNotFound(type_=endpoint_type)
|
|
||||||
|
|
||||||
return matching_endpoints[0][endpoint_type]
|
|
||||||
|
|
||||||
|
|
||||||
class HTTPClient(object):
|
class HTTPClient(object):
|
||||||
"""Handles the REST calls and responses, include authn."""
|
"""Handles the REST calls and responses, include authn."""
|
||||||
|
|
||||||
@@ -219,14 +171,12 @@ class HTTPClient(object):
|
|||||||
|
|
||||||
def _extract_service_catalog(self, body):
|
def _extract_service_catalog(self, body):
|
||||||
"""Set the client's service catalog from the response data."""
|
"""Set the client's service catalog from the response data."""
|
||||||
self.service_catalog = ServiceCatalog(body)
|
self.auth_ref = access.AccessInfo.factory(body=body)
|
||||||
try:
|
self.service_catalog = self.auth_ref.service_catalog
|
||||||
sc = self.service_catalog.get_token()
|
self.auth_token = self.auth_ref.auth_token
|
||||||
self.auth_token = sc['id']
|
self.auth_tenant_id = self.auth_ref.tenant_id
|
||||||
self.auth_tenant_id = sc.get('tenant_id')
|
self.auth_user_id = self.auth_ref.user_id
|
||||||
self.auth_user_id = sc.get('user_id')
|
|
||||||
except KeyError:
|
|
||||||
raise exceptions.Unauthorized()
|
|
||||||
if not self.endpoint_url:
|
if not self.endpoint_url:
|
||||||
self.endpoint_url = self.service_catalog.url_for(
|
self.endpoint_url = self.service_catalog.url_for(
|
||||||
attr='region', filter_value=self.region_name,
|
attr='region', filter_value=self.region_name,
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import copy
|
|||||||
import json
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
from keystoneclient import exceptions as k_exceptions
|
||||||
import mox
|
import mox
|
||||||
import requests
|
import requests
|
||||||
import testtools
|
import testtools
|
||||||
@@ -291,86 +292,6 @@ class CLITestAuthKeystone(testtools.TestCase):
|
|||||||
self.mox.ReplayAll()
|
self.mox.ReplayAll()
|
||||||
self.client.do_request('/resource', 'GET')
|
self.client.do_request('/resource', 'GET')
|
||||||
|
|
||||||
def test_url_for(self):
|
|
||||||
resources = copy.deepcopy(KS_TOKEN_RESULT)
|
|
||||||
|
|
||||||
endpoints = resources['access']['serviceCatalog'][0]['endpoints'][0]
|
|
||||||
endpoints['publicURL'] = 'public'
|
|
||||||
endpoints['internalURL'] = 'internal'
|
|
||||||
endpoints['adminURL'] = 'admin'
|
|
||||||
catalog = client.ServiceCatalog(resources)
|
|
||||||
|
|
||||||
# endpoint_type not specified
|
|
||||||
url = catalog.url_for(attr='region',
|
|
||||||
filter_value=REGION)
|
|
||||||
self.assertEqual('public', url)
|
|
||||||
|
|
||||||
# endpoint type specified (3 cases)
|
|
||||||
url = catalog.url_for(attr='region',
|
|
||||||
filter_value=REGION,
|
|
||||||
endpoint_type='adminURL')
|
|
||||||
self.assertEqual('admin', url)
|
|
||||||
|
|
||||||
url = catalog.url_for(attr='region',
|
|
||||||
filter_value=REGION,
|
|
||||||
endpoint_type='publicURL')
|
|
||||||
self.assertEqual('public', url)
|
|
||||||
|
|
||||||
url = catalog.url_for(attr='region',
|
|
||||||
filter_value=REGION,
|
|
||||||
endpoint_type='internalURL')
|
|
||||||
self.assertEqual('internal', url)
|
|
||||||
|
|
||||||
# endpoint_type requested does not exist.
|
|
||||||
self.assertRaises(exceptions.EndpointTypeNotFound,
|
|
||||||
catalog.url_for,
|
|
||||||
attr='region',
|
|
||||||
filter_value=REGION,
|
|
||||||
endpoint_type='privateURL')
|
|
||||||
|
|
||||||
# Test scenario with url_for when the service catalog only has publicURL.
|
|
||||||
def test_url_for_only_public_url(self):
|
|
||||||
resources = copy.deepcopy(KS_TOKEN_RESULT)
|
|
||||||
catalog = client.ServiceCatalog(resources)
|
|
||||||
|
|
||||||
# Remove endpoints from the catalog.
|
|
||||||
endpoints = resources['access']['serviceCatalog'][0]['endpoints'][0]
|
|
||||||
del endpoints['internalURL']
|
|
||||||
del endpoints['adminURL']
|
|
||||||
endpoints['publicURL'] = 'public'
|
|
||||||
|
|
||||||
# Use publicURL when specified explicitly.
|
|
||||||
url = catalog.url_for(attr='region',
|
|
||||||
filter_value=REGION,
|
|
||||||
endpoint_type='publicURL')
|
|
||||||
self.assertEqual('public', url)
|
|
||||||
|
|
||||||
# Use publicURL when specified explicitly.
|
|
||||||
url = catalog.url_for(attr='region',
|
|
||||||
filter_value=REGION)
|
|
||||||
self.assertEqual('public', url)
|
|
||||||
|
|
||||||
# Test scenario with url_for when the service catalog only has adminURL.
|
|
||||||
def test_url_for_only_admin_url(self):
|
|
||||||
resources = copy.deepcopy(KS_TOKEN_RESULT)
|
|
||||||
catalog = client.ServiceCatalog(resources)
|
|
||||||
endpoints = resources['access']['serviceCatalog'][0]['endpoints'][0]
|
|
||||||
del endpoints['internalURL']
|
|
||||||
del endpoints['publicURL']
|
|
||||||
endpoints['adminURL'] = 'admin'
|
|
||||||
|
|
||||||
# Use publicURL when specified explicitly.
|
|
||||||
url = catalog.url_for(attr='region',
|
|
||||||
filter_value=REGION,
|
|
||||||
endpoint_type='adminURL')
|
|
||||||
self.assertEqual('admin', url)
|
|
||||||
|
|
||||||
# But not when nothing is specified.
|
|
||||||
self.assertRaises(exceptions.EndpointTypeNotFound,
|
|
||||||
catalog.url_for,
|
|
||||||
attr='region',
|
|
||||||
filter_value=REGION)
|
|
||||||
|
|
||||||
def test_endpoint_type(self):
|
def test_endpoint_type(self):
|
||||||
resources = copy.deepcopy(KS_TOKEN_RESULT)
|
resources = copy.deepcopy(KS_TOKEN_RESULT)
|
||||||
endpoints = resources['access']['serviceCatalog'][0]['endpoints'][0]
|
endpoints = resources['access']['serviceCatalog'][0]['endpoints'][0]
|
||||||
@@ -415,7 +336,7 @@ class CLITestAuthKeystone(testtools.TestCase):
|
|||||||
username=USERNAME, tenant_name=TENANT_NAME, password=PASSWORD,
|
username=USERNAME, tenant_name=TENANT_NAME, password=PASSWORD,
|
||||||
auth_url=AUTH_URL, region_name=REGION, endpoint_type='privateURL')
|
auth_url=AUTH_URL, region_name=REGION, endpoint_type='privateURL')
|
||||||
|
|
||||||
self.assertRaises(exceptions.EndpointTypeNotFound,
|
self.assertRaises(k_exceptions.EndpointNotFound,
|
||||||
self.client._extract_service_catalog,
|
self.client._extract_service_catalog,
|
||||||
resources)
|
resources)
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ cliff>=1.4.3
|
|||||||
iso8601>=0.1.9
|
iso8601>=0.1.9
|
||||||
netaddr>=0.7.6
|
netaddr>=0.7.6
|
||||||
requests>=1.1
|
requests>=1.1
|
||||||
|
python-keystoneclient>=0.9.0
|
||||||
simplejson>=2.0.9
|
simplejson>=2.0.9
|
||||||
six>=1.6.0
|
six>=1.6.0
|
||||||
Babel>=1.3
|
Babel>=1.3
|
||||||
|
|||||||
Reference in New Issue
Block a user