From 864be88ef9b33e1f74e13c225f1a3b4cbf17bce3 Mon Sep 17 00:00:00 2001 From: Yaguang Tang Date: Thu, 20 Mar 2014 18:48:38 +0800 Subject: [PATCH] Make neutronclient parse keystone v3 endpoints correctly Import keystone access module to handle various verion of keystone catalog. Change-Id: Ie8de15da6341cdb3af73c0fa8753f7e754bf6275 Closes-bug: 1295056 --- neutronclient/client.py | 64 +++------------------ neutronclient/tests/unit/test_auth.py | 83 +-------------------------- requirements.txt | 1 + 3 files changed, 10 insertions(+), 138 deletions(-) diff --git a/neutronclient/client.py b/neutronclient/client.py index cd71e1b..7379edb 100644 --- a/neutronclient/client.py +++ b/neutronclient/client.py @@ -21,6 +21,7 @@ except ImportError: import logging import os +from keystoneclient import access import requests from neutronclient.common import exceptions @@ -40,55 +41,6 @@ else: 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): """Handles the REST calls and responses, include authn.""" @@ -219,14 +171,12 @@ class HTTPClient(object): def _extract_service_catalog(self, body): """Set the client's service catalog from the response data.""" - self.service_catalog = ServiceCatalog(body) - try: - sc = self.service_catalog.get_token() - self.auth_token = sc['id'] - self.auth_tenant_id = sc.get('tenant_id') - self.auth_user_id = sc.get('user_id') - except KeyError: - raise exceptions.Unauthorized() + self.auth_ref = access.AccessInfo.factory(body=body) + self.service_catalog = self.auth_ref.service_catalog + self.auth_token = self.auth_ref.auth_token + self.auth_tenant_id = self.auth_ref.tenant_id + self.auth_user_id = self.auth_ref.user_id + if not self.endpoint_url: self.endpoint_url = self.service_catalog.url_for( attr='region', filter_value=self.region_name, diff --git a/neutronclient/tests/unit/test_auth.py b/neutronclient/tests/unit/test_auth.py index 585458e..ae077c8 100644 --- a/neutronclient/tests/unit/test_auth.py +++ b/neutronclient/tests/unit/test_auth.py @@ -18,6 +18,7 @@ import copy import json import uuid +from keystoneclient import exceptions as k_exceptions import mox import requests import testtools @@ -291,86 +292,6 @@ class CLITestAuthKeystone(testtools.TestCase): self.mox.ReplayAll() 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): resources = copy.deepcopy(KS_TOKEN_RESULT) endpoints = resources['access']['serviceCatalog'][0]['endpoints'][0] @@ -415,7 +336,7 @@ class CLITestAuthKeystone(testtools.TestCase): username=USERNAME, tenant_name=TENANT_NAME, password=PASSWORD, auth_url=AUTH_URL, region_name=REGION, endpoint_type='privateURL') - self.assertRaises(exceptions.EndpointTypeNotFound, + self.assertRaises(k_exceptions.EndpointNotFound, self.client._extract_service_catalog, resources) diff --git a/requirements.txt b/requirements.txt index 7c118d3..c09cd7b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,7 @@ cliff>=1.4.3 iso8601>=0.1.9 netaddr>=0.7.6 requests>=1.1 +python-keystoneclient>=0.9.0 simplejson>=2.0.9 six>=1.6.0 Babel>=1.3