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: `publicURL`, `internalURL`, `adminURL` See tests for a sample service catalog. """ catalog = self.catalog.get('serviceCatalog', []) if not catalog: raise exceptions.EmptyCatalog('The service catalog is empty.') 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: return endpoint[endpoint_type] raise exceptions.EndpointNotFound('Endpoint not found.')
def test_is_object_store_present(self): def url_for_side_effect(service_type, endpoint_type, region_name): return { 'TestRegion': { 'identity': { 'publicURL': 'https://10.5.2.42:443/swift/v1', 'internalURL': 'https://10.5.2.42:443/swift/v1', 'adminURL': 'https://10.5.2.42:443/swift/v1', }, 'image': { 'publicURL': 'https://10.5.2.43:443/swift/v1', 'internalURL': 'https://10.5.2.43:443/swift/v1', 'adminURL': 'https://10.5.2.43:443/swift/v1', }, 'object-store': { 'publicURL': 'https://10.5.2.44:443/swift/v1', 'internalURL': 'https://10.5.2.44:443/swift/v1', 'adminURL': 'https://10.5.2.44:443/swift/v1', }, } }[region_name][service_type][endpoint_type] ksc = mock.MagicMock() ksc.service_catalog.url_for.side_effect = url_for_side_effect self.assertTrue(gss.is_object_store_present(ksc, 'TestRegion')) # Endpoints not found or service not present at all. ksc.service_catalog.url_for.side_effect = mock.MagicMock( side_effect=keystone_exceptions.EndpointNotFound('foo')) self.assertFalse(gss.is_object_store_present(ksc, 'TestRegion'))
def test_get_object_store_endpoints(self): def url_for_side_effect(service_type, endpoint_type, region_name): return { 'TestRegion': { 'identity': { 'publicURL': 'https://10.5.2.42:443/swift/v1', 'internalURL': 'https://10.5.2.42:443/swift/v1', 'adminURL': 'https://10.5.2.42:443/swift/v1', }, 'image': { 'publicURL': 'https://10.5.2.43:443/swift/v1', 'internalURL': 'https://10.5.2.43:443/swift/v1', 'adminURL': 'https://10.5.2.43:443/swift/v1', }, 'object-store': { 'publicURL': 'https://10.5.2.44:443/swift/v1', 'internalURL': 'https://10.5.2.44:443/swift/v1', 'adminURL': 'https://10.5.2.44:443/swift/v1', }, } }[region_name][service_type][endpoint_type] ksc = mock.MagicMock() ksc.service_catalog.url_for.side_effect = url_for_side_effect self.assertEqual(gss.get_object_store_endpoints(ksc, 'TestRegion'), [ 'https://10.5.2.44:443/swift/v1', 'https://10.5.2.44:443/swift/v1', 'https://10.5.2.44:443/swift/v1' ]) ksc.service_catalog.url_for.side_effect = mock.MagicMock( side_effect=keystone_exceptions.EndpointNotFound('foo')) self.assertEqual(gss.get_object_store_endpoints(ksc, 'TestRegion'), [])
def url_for(self, attr=None, filter_value=None, service_type='identity', endpoint_type='public'): catalog = self.get_data() 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))
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 endpoints = service['endpoints'] for endpoint in endpoints: if (self.region_name and endpoint.get('region') != self.region_name): continue if not filter_value or endpoint.get(attr) == filter_value: return endpoint[endpoint_type] raise exceptions.EndpointNotFound('%s endpoint for %s not found.' % (endpoint_type, service_type))
def url_for(self, **kwargs): if self.only_services is not None: if 'service_type' in kwargs and \ kwargs['service_type'] not in self.only_services: # keystone client throws keystone exceptions, not cinder # exceptions. raise exceptions.EndpointNotFound() return 'http://example.com:1234/v1'
def get_ironicclient(): session = _get_session() try: return ironic_client.get_client( '1', session=session, os_region_name=CONF.service_credentials.os_region_name, os_endpoint_type=CONF.service_credentials.os_endpoint_type, os_ironic_api_version=IRONIC_API_VERSION) except ironic_exceptions.AmbiguousAuthSystem: raise keystone_exceptions.EndpointNotFound()
def url_for(self, **kwargs): def get_endpoint(): auth_plugin = self.context.auth_plugin return auth_plugin.get_endpoint(self._keystone_session, **kwargs) # NOTE(jamielennox): use the session defined by the keystoneclient # options as traditionally the token was always retrieved from # keystoneclient. try: kwargs.setdefault('interface', kwargs.pop('endpoint_type')) except KeyError: pass reg = self.context.region_name or cfg.CONF.region_name_for_services kwargs.setdefault('region_name', reg) try: url = get_endpoint() except exceptions.EmptyCatalog: kc = self.clients.client('keystone').client auth_plugin = self.context.auth_plugin endpoint = auth_plugin.get_endpoint(None, interface=auth.AUTH_INTERFACE) token = auth_plugin.get_token(None) project_id = auth_plugin.get_project_id(None) if kc.version == 'v3': token_obj = v3.Token(endpoint, token, project_id=project_id) catalog_key = 'catalog' access_key = 'token' elif kc.version == 'v2.0': endpoint = endpoint.replace('v3', 'v2.0') token_obj = v2.Token(endpoint, token, tenant_id=project_id) catalog_key = 'serviceCatalog' access_key = 'access' else: raise exceptions.Error(_("Unknown Keystone version")) auth_ref = token_obj.get_auth_ref(self._keystone_session) if catalog_key in auth_ref: cxt = self.context.to_dict() access_info = cxt['auth_token_info'][access_key] access_info[catalog_key] = auth_ref[catalog_key] self.context = context.RequestContext.from_dict(cxt) url = get_endpoint() # NOTE(jamielennox): raising exception maintains compatibility with # older keystoneclient service catalog searching. if url is None: raise exceptions.EndpointNotFound() return url
def get_service_endpoints_side_effect(ksc, service_type, region_name): if service_type == 'object-store': raise keystone_exceptions.EndpointNotFound('foo') return { 'identity': { 'publicURL': 'https://192.0.2.42:5000/v3', 'internalURL': 'https://192.0.2.43:5000/v3', 'adminURL': 'https://192.0.2.44:35357/v3', }, 'image': { 'publicURL': 'https://192.0.2.45:9292', 'internalURL': 'https://192.0.2.45:9292', 'adminURL': 'https://192.0.2.47:9292', }, }[service_type]
def url_for(self, attr=None, filter_value=None, service_type='identity', endpoint_type='publicURL', region_name=None, service_name=None): """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` :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. :param string region_name: Region of the endpoint. :param string service_name: The assigned name of the service. : """ if not self.get_data(): raise exceptions.EmptyCatalog('The service catalog is empty.') urls = self.get_urls(attr=attr, filter_value=filter_value, service_type=service_type, endpoint_type=endpoint_type, region_name=region_name, service_name=service_name) try: return urls[0] except Exception: pass msg = '%s endpoint for %s service' % (endpoint_type, service_type) if service_name: msg += ' named %s' % service_name if region_name: msg += ' in %s region' % region_name msg += ' not found' raise exceptions.EndpointNotFound(msg)
def url_for(self, **kwargs): # NOTE(jamielennox): use the session defined by the keystoneclient # options as traditionally the token was always retrieved from # keystoneclient. try: kwargs.setdefault('interface', kwargs.pop('endpoint_type')) except KeyError: pass reg = self.context.region_name or cfg.CONF.region_name_for_services kwargs.setdefault('region_name', reg) url = self.context.auth_plugin.get_endpoint(self._keystone_session, **kwargs) # NOTE(jamielennox): raising exception maintains compatibility with # older keystoneclient service catalog searching. if url is None: raise exceptions.EndpointNotFound() return url
def url_for(self, attr=None, filter_value=None, service_type='identity', endpoint_type='publicURL', region_name=None): """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` """ if not self.get_data(): raise exceptions.EmptyCatalog('The service catalog is empty.') urls = self.get_urls(attr=attr, filter_value=filter_value, service_type=service_type, endpoint_type=endpoint_type, region_name=region_name) try: return urls[0] except Exception: pass msg = '%(endpoint)s endpoint for %(service)s%(region)s not found' region = ' in %s region' % region_name if region_name else '' msg = msg % { 'endpoint': endpoint_type, 'service': service_type, 'region': region } raise exceptions.EndpointNotFound(msg)
def url_for(self, **kwargs): if cfg.CONF.FusionSphere.pubcloud: return self.clients.client('keystone').url_for(**kwargs) def get_endpoint(): auth_plugin = self.context.auth_plugin return auth_plugin.get_endpoint(self._keystone_session, **kwargs) # NOTE(jamielennox): use the session defined by the keystoneclient # options as traditionally the token was always retrieved from # keystoneclient. try: kwargs.setdefault('interface', kwargs.pop('endpoint_type')) except KeyError: pass reg = self.context.region_name or cfg.CONF.region_name_for_services kwargs.setdefault('region_name', reg) url = None try: url = get_endpoint() except exceptions.EmptyCatalog: kwargs.pop('interface') admin_client = self.clients.client('keystone').admin_client admin_url = admin_client.service_catalog.url_for(**kwargs) admin_project_id = admin_client.auth_ref.project_id user_project_id = self.context.tenant_id url = admin_url.replace(admin_project_id, user_project_id) LOG.info(_LI('Catalog is empty, use admin to get url %(url)s'), {'url': url}) # NOTE(jamielennox): raising exception maintains compatibility with # older keystoneclient service catalog searching. if url is None: raise exceptions.EndpointNotFound() return url
def _throw_endpoint_error(self, endpoint_type, service_name, region_name, service_type): MSG = '{endpoint_type}s endpoint for {service_type}s service ' if service_name and region_name: msg = MSG + ('named {service_name}s in {region_name}s ' 'region not found' ).format(endpoint_type=endpoint_type, service_type=service_type, service_name=service_name, region_name=region_name) elif service_name: msg = MSG + 'named {service_name}s not found'.format( endpoint_type=endpoint_type, service_type=service_type, service_name=service_name) elif region_name: msg = MSG + 'in (region_name)s region not found'.format( endpoint_type=endpoint_type, service_type=service_type, region_name=region_name) else: msg = MSG + 'not found'.format(endpoint_type=endpoint_type, service_type=service_type) raise ks_error.EndpointNotFound(_(msg))
def mock_no_neutron(self): mock_create = self.patch( 'heat.engine.clients.os.neutron.NeutronClientPlugin._create') mock_create.side_effect = keystone_exc.EndpointNotFound()
def request(self, url, method, json=None, original_ip=None, user_agent=None, redirect=None, authenticated=None, endpoint_filter=None, auth=None, requests_auth=None, raise_exc=True, **kwargs): """Send an HTTP request with the specified characteristics. Wrapper around `requests.Session.request` to handle tasks such as setting headers, JSON encoding/decoding, and error handling. Arguments that are not handled are passed through to the requests library. :param string url: Path or fully qualified URL of HTTP request. If only a path is provided then endpoint_filter must also be provided such that the base URL can be determined. If a fully qualified URL is provided then endpoint_filter will be ignored. :param string method: The http method to use. (e.g. 'GET', 'POST') :param string original_ip: Mark this request as forwarded for this ip. (optional) :param dict headers: Headers to be included in the request. (optional) :param json: Some data to be represented as JSON. (optional) :param string user_agent: A user_agent to use for the request. If present will override one present in headers. (optional) :param int/bool redirect: the maximum number of redirections that can be followed by a request. Either an integer for a specific count or True/False for forever/never. (optional) :param bool authenticated: True if a token should be attached to this request, False if not or None for attach if an auth_plugin is available. (optional, defaults to None) :param dict endpoint_filter: Data to be provided to an auth plugin with which it should be able to determine an endpoint to use for this request. If not provided then URL is expected to be a fully qualified URL. (optional) :param auth: The auth plugin to use when authenticating this request. This will override the plugin that is attached to the session (if any). (optional) :type auth: :class:`keystoneclient.auth.base.BaseAuthPlugin` :param requests_auth: A requests library auth plugin that cannot be passed via kwarg because the `auth` kwarg collides with our own auth plugins. (optional) :type requests_auth: :class:`requests.auth.AuthBase` :param bool raise_exc: If True then raise an appropriate exception for failed HTTP requests. If False then return the request object. (optional, default True) :param kwargs: any other parameter that can be passed to requests.Session.request (such as `headers`). Except: 'data' will be overwritten by the data in 'json' param. 'allow_redirects' is ignored as redirects are handled by the session. :raises exceptions.ClientException: For connection failure, or to indicate an error response code. :returns: The response to the request. """ headers = kwargs.setdefault('headers', dict()) if authenticated is None: authenticated = bool(auth or self.auth) if authenticated: token = self.get_token(auth) if not token: raise exceptions.AuthorizationFailure("No token Available") headers['X-Auth-Token'] = token # if we are passed a fully qualified URL and an endpoint_filter we # should ignore the filter. This will make it easier for clients who # want to overrule the default endpoint_filter data added to all client # requests. We check fully qualified here by the presence of a host. url_data = urllib.parse.urlparse(url) if endpoint_filter and not url_data.netloc: base_url = self.get_endpoint(auth, **endpoint_filter) if not base_url: raise exceptions.EndpointNotFound() url = '%s/%s' % (base_url.rstrip('/'), url.lstrip('/')) if self.cert: kwargs.setdefault('cert', self.cert) if self.timeout is not None: kwargs.setdefault('timeout', self.timeout) if user_agent: headers['User-Agent'] = user_agent elif self.user_agent: user_agent = headers.setdefault('User-Agent', self.user_agent) else: user_agent = headers.setdefault('User-Agent', USER_AGENT) if self.original_ip: headers.setdefault('Forwarded', 'for=%s;by=%s' % (self.original_ip, user_agent)) if json is not None: headers['Content-Type'] = 'application/json' kwargs['data'] = jsonutils.dumps(json) kwargs.setdefault('verify', self.verify) if requests_auth: kwargs['auth'] = requests_auth string_parts = ['curl -i'] # NOTE(jamielennox): None means let requests do its default validation # so we need to actually check that this is False. if self.verify is False: string_parts.append('--insecure') if method: string_parts.extend(['-X', method]) string_parts.append(url) if headers: for header in six.iteritems(headers): string_parts.append('-H "%s: %s"' % header) try: string_parts.append("-d '%s'" % kwargs['data']) except KeyError: pass _logger.debug('REQ: %s', ' '.join(string_parts)) # Force disable requests redirect handling. We will manage this below. kwargs['allow_redirects'] = False if redirect is None: redirect = self.redirect resp = self._send_request(url, method, redirect, **kwargs) if raise_exc and resp.status_code >= 400: _logger.debug('Request returned failure status: %s', resp.status_code) raise exceptions.from_response(resp, method, url) return resp
def _url_for(service_type=None): if service_type == 'metric': return 'http://gnocchi/' elif service_type == 'alarming': return 'http://alarm-endpoint:8008/' raise exceptions.EndpointNotFound()
def fake_ks_service_catalog_url_for(*args, **kwargs): raise exceptions.EndpointNotFound("Fake keystone exception")
def request(self, url, method, json=None, original_ip=None, user_agent=None, redirect=None, authenticated=None, endpoint_filter=None, auth=None, requests_auth=None, raise_exc=True, allow_reauth=True, log=True, endpoint_override=None, connect_retries=0, logger=_logger, **kwargs): """Send an HTTP request with the specified characteristics. Wrapper around `requests.Session.request` to handle tasks such as setting headers, JSON encoding/decoding, and error handling. Arguments that are not handled are passed through to the requests library. :param string url: Path or fully qualified URL of HTTP request. If only a path is provided then endpoint_filter must also be provided such that the base URL can be determined. If a fully qualified URL is provided then endpoint_filter will be ignored. :param string method: The http method to use. (e.g. 'GET', 'POST') :param string original_ip: Mark this request as forwarded for this ip. (optional) :param dict headers: Headers to be included in the request. (optional) :param json: Some data to be represented as JSON. (optional) :param string user_agent: A user_agent to use for the request. If present will override one present in headers. (optional) :param int/bool redirect: the maximum number of redirections that can be followed by a request. Either an integer for a specific count or True/False for forever/never. (optional) :param int connect_retries: the maximum number of retries that should be attempted for connection errors. (optional, defaults to 0 - never retry). :param bool authenticated: True if a token should be attached to this request, False if not or None for attach if an auth_plugin is available. (optional, defaults to None) :param dict endpoint_filter: Data to be provided to an auth plugin with which it should be able to determine an endpoint to use for this request. If not provided then URL is expected to be a fully qualified URL. (optional) :param str endpoint_override: The URL to use instead of looking up the endpoint in the auth plugin. This will be ignored if a fully qualified URL is provided but take priority over an endpoint_filter. (optional) :param auth: The auth plugin to use when authenticating this request. This will override the plugin that is attached to the session (if any). (optional) :type auth: :py:class:`keystoneclient.auth.base.BaseAuthPlugin` :param requests_auth: A requests library auth plugin that cannot be passed via kwarg because the `auth` kwarg collides with our own auth plugins. (optional) :type requests_auth: :py:class:`requests.auth.AuthBase` :param bool raise_exc: If True then raise an appropriate exception for failed HTTP requests. If False then return the request object. (optional, default True) :param bool allow_reauth: Allow fetching a new token and retrying the request on receiving a 401 Unauthorized response. (optional, default True) :param bool log: If True then log the request and response data to the debug log. (optional, default True) :param logger: The logger object to use to log request and responses. If not provided the keystoneclient.session default logger will be used. :type logger: logging.Logger :param kwargs: any other parameter that can be passed to requests.Session.request (such as `headers`). Except: 'data' will be overwritten by the data in 'json' param. 'allow_redirects' is ignored as redirects are handled by the session. :raises keystoneclient.exceptions.ClientException: For connection failure, or to indicate an error response code. :returns: The response to the request. """ headers = kwargs.setdefault('headers', dict()) if authenticated is None: authenticated = bool(auth or self.auth) if authenticated: auth_headers = self.get_auth_headers(auth) if auth_headers is None: msg = _('No valid authentication is available') raise exceptions.AuthorizationFailure(msg) headers.update(auth_headers) if osprofiler_web: headers.update(osprofiler_web.get_trace_id_headers()) # if we are passed a fully qualified URL and an endpoint_filter we # should ignore the filter. This will make it easier for clients who # want to overrule the default endpoint_filter data added to all client # requests. We check fully qualified here by the presence of a host. if not urllib.parse.urlparse(url).netloc: base_url = None if endpoint_override: base_url = endpoint_override elif endpoint_filter: base_url = self.get_endpoint(auth, **endpoint_filter) if not base_url: service_type = (endpoint_filter or {}).get('service_type', 'unknown') msg = _('Endpoint for %s service') % service_type raise exceptions.EndpointNotFound(msg) url = '%s/%s' % (base_url.rstrip('/'), url.lstrip('/')) if self.cert: kwargs.setdefault('cert', self.cert) if self.timeout is not None: kwargs.setdefault('timeout', self.timeout) if user_agent: headers['User-Agent'] = user_agent elif self.user_agent: user_agent = headers.setdefault('User-Agent', self.user_agent) else: user_agent = headers.setdefault('User-Agent', USER_AGENT) if self.original_ip: headers.setdefault('Forwarded', 'for=%s;by=%s' % (self.original_ip, user_agent)) if json is not None: headers['Content-Type'] = 'application/json' kwargs['data'] = jsonutils.dumps(json) kwargs.setdefault('verify', self.verify) if requests_auth: kwargs['auth'] = requests_auth if log: self._http_log_request(url, method=method, data=kwargs.get('data'), headers=headers, logger=logger) # Force disable requests redirect handling. We will manage this below. kwargs['allow_redirects'] = False if redirect is None: redirect = self.redirect send = functools.partial(self._send_request, url, method, redirect, log, logger, connect_retries) try: connection_params = self.get_auth_connection_params(auth=auth) except exceptions.MissingAuthPlugin: # nosec(cjschaef) # NOTE(jamielennox): If we've gotten this far without an auth # plugin then we should be happy with allowing no additional # connection params. This will be the typical case for plugins # anyway. pass else: if connection_params: kwargs.update(connection_params) resp = send(**kwargs) # handle getting a 401 Unauthorized response by invalidating the plugin # and then retrying the request. This is only tried once. if resp.status_code == 401 and authenticated and allow_reauth: if self.invalidate(auth): auth_headers = self.get_auth_headers(auth) if auth_headers is not None: headers.update(auth_headers) resp = send(**kwargs) if raise_exc and resp.status_code >= 400: logger.debug('Request returned failure status: %s', resp.status_code) raise exceptions.from_response(resp, method, url) return resp
def fake_get_kwapi_client(ksclient, endpoint): raise exceptions.EndpointNotFound("fake keystone exception")
def url_for(self, attr=None, filter_value=None, service_type='identity', endpoint_type='publicURL', region_name=None, service_name=None): """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` :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. :param string region_name: Region of the endpoint. :param string service_name: The assigned name of the service. """ if not self.get_data(): raise exceptions.EmptyCatalog(_('The service catalog is empty.')) urls = self.get_urls(attr=attr, filter_value=filter_value, service_type=service_type, endpoint_type=endpoint_type, region_name=region_name, service_name=service_name) try: return urls[0] except Exception: if service_name and region_name: msg = (_('%(endpoint_type)s endpoint for %(service_type)s ' 'service named %(service_name)s in %(region_name)s ' 'region not found') % { 'endpoint_type': endpoint_type, 'service_type': service_type, 'service_name': service_name, 'region_name': region_name }) elif service_name: msg = (_('%(endpoint_type)s endpoint for %(service_type)s ' 'service named %(service_name)s not found') % { 'endpoint_type': endpoint_type, 'service_type': service_type, 'service_name': service_name }) elif region_name: msg = (_('%(endpoint_type)s endpoint for %(service_type)s ' 'service in %(region_name)s region not found') % { 'endpoint_type': endpoint_type, 'service_type': service_type, 'region_name': region_name }) else: msg = (_('%(endpoint_type)s endpoint for %(service_type)s ' 'service not found') % { 'endpoint_type': endpoint_type, 'service_type': service_type }) raise exceptions.EndpointNotFound(msg)