diff options
author | lin-hua-cheng <lin-hua.cheng@hp.com> | 2013-02-13 22:52:05 -0600 |
---|---|---|
committer | Lin Hua Cheng <lin-hua.cheng@hp.com> | 2013-06-20 23:28:31 -0700 |
commit | 2239c3b27c657dc0ffe2dbd0f95325e0ed7ae7c5 (patch) | |
tree | 9972797a6e5bd27f6262d86d01f9f50d95264ff7 /keystoneclient/service_catalog.py | |
parent | abe6781913a7a4e376c0798e2e962ef16e9a48e6 (diff) | |
download | python-keystoneclient-2239c3b27c657dc0ffe2dbd0f95325e0ed7ae7c5.tar.gz |
Implements v3 auth client.
Added support for domain scoping.
Enhancement on AccessInfo to support reading v2/v3 token information.
Enhancement on ServiceCatalog for reading/filtering v2/v3 service
catalog information.
Change-Id: Ibb678b9933d3673e37d0fba857a152a3c5d2b4f4
Diffstat (limited to 'keystoneclient/service_catalog.py')
-rw-r--r-- | keystoneclient/service_catalog.py | 211 |
1 files changed, 192 insertions, 19 deletions
diff --git a/keystoneclient/service_catalog.py b/keystoneclient/service_catalog.py index 2938af3..b73f67a 100644 --- a/keystoneclient/service_catalog.py +++ b/keystoneclient/service_catalog.py @@ -23,9 +23,15 @@ from keystoneclient import exceptions class ServiceCatalog(object): """Helper methods for dealing with a Keystone Service Catalog.""" - def __init__(self, resource_dict, region_name=None): - self.catalog = resource_dict - self.region_name = region_name + @classmethod + def factory(cls, resource_dict, token=None, region_name=None): + """Create ServiceCatalog object given a auth token.""" + if ServiceCatalogV3.is_valid(resource_dict): + return ServiceCatalogV3(token, resource_dict, region_name) + elif ServiceCatalogV2.is_valid(resource_dict): + return ServiceCatalogV2(resource_dict, region_name) + else: + raise NotImplementedError('Unrecognized auth response') def get_token(self): """Fetch token details from service catalog. @@ -36,8 +42,71 @@ class ServiceCatalog(object): - `expires`: Token's expiration - `user_id`: Authenticated user's ID - `tenant_id`: Authorized project's ID + - `domain_id`: Authorized domain's ID + + """ + raise NotImplementedError() + + def get_endpoints(self, service_type=None, endpoint_type=None): + """Fetch and filter endpoints for the specified service(s). + + Returns endpoints for the specified service (or all) and + that contain the specified type (or all). + """ + raise NotImplementedError() + + def get_urls(self, attr=None, filter_value=None, + service_type='identity', endpoint_type='publicURL'): + """Fetch endpoint urls from the service catalog. + + Fetch the endpoints from the service catalog for a particular + endpoint attribute. If no attribute is given, return the first + endpoint of the specified type. + + :param string attr: Endpoint attribute name. + :param string filter_value: Endpoint attribute value. + :param string service_type: Service type of the endpoint. + :param string endpoint_type: Type of endpoint. + Possible values: public or publicURL, + internal or internalURL, + admin or adminURL + :param string region_name: Region of the endpoint. + + :returns: tuple of urls or None (if no match found) + """ + raise NotImplementedError() + + def url_for(self, attr=None, filter_value=None, + service_type='identity', endpoint_type='publicURL'): + """Fetch an endpoint from the service catalog. + + Fetch the specified endpoint from the service catalog for + a particular endpoint attribute. If no attribute is given, return + the first endpoint of the specified type. + Valid endpoint types: `public` or `publicURL`, + `internal` or `internalURL`, + `admin` or 'adminURL` """ + raise NotImplementedError() + + +class ServiceCatalogV2(ServiceCatalog): + """An object for encapsulating the service catalog using raw v2 auth token + from Keystone.""" + + def __init__(self, resource_dict, region_name=None): + self.catalog = resource_dict + self.region_name = region_name + + @classmethod + def is_valid(cls, resource_dict): + # This class is also used for reading token info of an unscoped token. + # Unscoped token does not have 'serviceCatalog' in V2, checking this + # will not work. Use 'token' attribute instead. + return 'token' in resource_dict + + def get_token(self): token = {'id': self.catalog['token']['id'], 'expires': self.catalog['token']['expires']} try: @@ -48,23 +117,50 @@ class ServiceCatalog(object): pass return token - def url_for(self, attr=None, filter_value=None, - service_type='identity', endpoint_type='publicURL'): - """Fetch an endpoint from the service catalog. + def get_endpoints(self, service_type=None, endpoint_type=None): + if endpoint_type and 'URL' not in endpoint_type: + endpoint_type = endpoint_type + 'URL' - Fetch the specified endpoint from the service catalog for - a particular endpoint attribute. If no attribute is given, return - the first endpoint of the specified type. + sc = {} + for service in self.catalog.get('serviceCatalog', []): + if service_type and service_type != service['type']: + continue + sc[service['type']] = [] + for endpoint in service['endpoints']: + if endpoint_type and endpoint_type not in endpoint.keys(): + continue + sc[service['type']].append(endpoint) + return sc - Valid endpoint types: `publicURL`, `internalURL`, `adminURL` + def get_urls(self, attr=None, filter_value=None, + service_type='identity', endpoint_type='publicURL'): + sc_endpoints = self.get_endpoints(service_type=service_type, + endpoint_type=endpoint_type) + endpoints = sc_endpoints.get(service_type) + if not endpoints: + return - See tests for a sample service catalog. - """ + if endpoint_type and 'URL' not in endpoint_type: + endpoint_type = endpoint_type + 'URL' + + return tuple(endpoint[endpoint_type] + for endpoint in endpoints + if (endpoint_type in endpoint + and (not self.region_name + or endpoint.get('region') == self.region_name) + and (not filter_value + or endpoint.get(attr) == filter_value))) + + def url_for(self, attr=None, filter_value=None, + service_type='identity', endpoint_type='publicURL'): catalog = self.catalog.get('serviceCatalog', []) if not catalog: raise exceptions.EmptyCatalog('The service catalog is empty.') + if 'URL' not in endpoint_type: + endpoint_type = endpoint_type + 'URL' + for service in catalog: if service['type'] != service_type: continue @@ -80,19 +176,96 @@ class ServiceCatalog(object): raise exceptions.EndpointNotFound('%s endpoint for %s not found.' % (endpoint_type, service_type)) - def get_endpoints(self, service_type=None, endpoint_type=None): - """Fetch and filter endpoints for the specified service(s). - Returns endpoints for the specified service (or all) and - that contain the specified type (or all). - """ +class ServiceCatalogV3(ServiceCatalog): + """An object for encapsulating the service catalog using raw v3 auth token + from Keystone.""" + + def __init__(self, token, resource_dict, region_name=None): + self._auth_token = token + self.catalog = resource_dict + self.region_name = region_name + + @classmethod + def is_valid(cls, resource_dict): + # This class is also used for reading token info of an unscoped token. + # Unscoped token does not have 'catalog', checking this + # will not work. Use 'methods' attribute instead. + return 'methods' in resource_dict + + def get_token(self): + token = {'id': self._auth_token, + 'expires': self.catalog['expires_at']} + try: + token['user_id'] = self.catalog['user']['id'] + domain = self.catalog.get('domain') + if domain: + token['domain_id'] = domain['id'] + project = self.catalog.get('project') + if project: + token['tenant_id'] = project['id'] + except Exception: + # just leave the domain, project and user out if it doesn't exist + pass + return token + + def get_endpoints(self, service_type=None, endpoint_type=None): + if endpoint_type: + endpoint_type = endpoint_type.rstrip('URL') sc = {} - for service in self.catalog.get('serviceCatalog', []): + for service in self.catalog.get('catalog', []): if service_type and service_type != service['type']: continue sc[service['type']] = [] for endpoint in service['endpoints']: - if endpoint_type and endpoint_type not in endpoint.keys(): + if endpoint_type and endpoint_type != endpoint['interface']: continue sc[service['type']].append(endpoint) return sc + + def get_urls(self, attr=None, filter_value=None, + service_type='identity', endpoint_type='public'): + if endpoint_type: + endpoint_type = endpoint_type.rstrip('URL') + sc_endpoints = self.get_endpoints(service_type=service_type, + endpoint_type=endpoint_type) + endpoints = sc_endpoints.get(service_type) + if not endpoints: + return None + + urls = list() + for endpoint in endpoints: + if (endpoint['interface'] == endpoint_type + and (not self.region_name + or endpoint.get('region') == self.region_name) + and (not filter_value + or endpoint.get(attr) == filter_value)): + urls.append(endpoint['url']) + return tuple(urls) + + def url_for(self, attr=None, filter_value=None, + service_type='identity', endpoint_type='public'): + catalog = self.catalog.get('catalog', []) + + if not catalog: + raise exceptions.EmptyCatalog('The service catalog is empty.') + + if endpoint_type: + endpoint_type = endpoint_type.rstrip('URL') + + for service in catalog: + if service['type'] != service_type: + continue + + endpoints = service['endpoints'] + for endpoint in endpoints: + if endpoint.get('interface') != endpoint_type: + continue + if (self.region_name and + endpoint.get('region') != self.region_name): + continue + if not filter_value or endpoint.get(attr) == filter_value: + return endpoint['url'] + + raise exceptions.EndpointNotFound('%s endpoint for %s not found.' % + (endpoint_type, service_type)) |