def get_api_servers(context): """Shuffle a list of service endpoints and return an iterator that will cycle through the list, looping around to the beginning if necessary. """ # NOTE(efried): utils.get_ksa_adapter().get_endpoint() is the preferred # mechanism for endpoint discovery. Only use `api_servers` if you really # need to shuffle multiple endpoints. if CONF.glance.api_servers: api_servers = CONF.glance.api_servers random.shuffle(api_servers) else: sess, auth = _session_and_auth(context) ksa_adap = utils.get_ksa_adapter(nova.conf.glance.DEFAULT_SERVICE_TYPE, ksa_auth=auth, ksa_session=sess, min_version='2.0', max_version='2.latest') endpoint = utils.get_endpoint(ksa_adap) if endpoint: # NOTE(mriedem): Due to python-glanceclient bug 1707995 we have # to massage the endpoint URL otherwise it won't work properly. # We can't use glanceclient.common.utils.strip_version because # of bug 1748009. endpoint = re.sub(r'/v\d+(\.\d+)?/?$', '/', endpoint) api_servers = [endpoint] return itertools.cycle(api_servers)
def get_api_servers(context): """Shuffle a list of service endpoints and return an iterator that will cycle through the list, looping around to the beginning if necessary. """ # NOTE(efried): utils.get_ksa_adapter().get_endpoint() is the preferred # mechanism for endpoint discovery. Only use `api_servers` if you really # need to shuffle multiple endpoints. if CONF.glance.api_servers: api_servers = CONF.glance.api_servers random.shuffle(api_servers) else: sess, auth = _session_and_auth(context) ksa_adap = utils.get_ksa_adapter( nova.conf.glance.DEFAULT_SERVICE_TYPE, ksa_auth=auth, ksa_session=sess, min_version='2.0', max_version='2.latest') endpoint = utils.get_endpoint(ksa_adap) if endpoint: # NOTE(mriedem): Due to python-glanceclient bug 1707995 we have # to massage the endpoint URL otherwise it won't work properly. # We can't use glanceclient.common.utils.strip_version because # of bug 1748009. endpoint = re.sub(r'/v\d+(\.\d+)?/?$', '/', endpoint) api_servers = [endpoint] return itertools.cycle(api_servers)
def get_api_servers(): """Shuffle a list of service endpoints and return an iterator that will cycle through the list, looping around to the beginning if necessary. """ # NOTE(efried): utils.get_ksa_adapter().get_endpoint() is the preferred # mechanism for endpoint discovery. Only use `api_servers` if you really # need to shuffle multiple endpoints. api_servers = [] if CONF.glance.api_servers: for api_server in CONF.glance.api_servers: if '//' not in api_server: api_server = 'http://' + api_server # NOTE(sdague): remove in O. LOG.warning("No protocol specified in for api_server '%s', " "please update [glance] api_servers with fully " "qualified url including scheme (http / https)", api_server) api_servers.append(api_server) random.shuffle(api_servers) else: # TODO(efried): Plumb in a reasonable auth from callers' contexts ksa_adap = utils.get_ksa_adapter( nova.conf.glance.DEFAULT_SERVICE_TYPE, min_version='2.0', max_version='2.latest') # TODO(efried): Use ksa_adap.get_endpoint() when bug #1707995 is fixed. api_servers.append(ksa_adap.endpoint_override or ksa_adap.get_endpoint_data().catalog_url) return itertools.cycle(api_servers)
def _get_client(self, retry_on_conflict=True): max_retries = CONF.ironic.api_max_retries if retry_on_conflict else 1 retry_interval = (CONF.ironic.api_retry_interval if retry_on_conflict else 0) # If we've already constructed a valid, authed client, just return # that. if retry_on_conflict and self._cached_client is not None: return self._cached_client auth_plugin = self._get_auth_plugin() sess = ks_loading.load_session_from_conf_options(CONF, IRONIC_GROUP.name, auth=auth_plugin) # Retries for Conflict exception kwargs = {} kwargs['max_retries'] = max_retries kwargs['retry_interval'] = retry_interval kwargs['os_ironic_api_version'] = '%d.%d' % IRONIC_API_VERSION # NOTE(clenimar/efried): by default, the endpoint is taken from the # service catalog. Use `endpoint_override` if you want to override it. if CONF.ironic.api_endpoint: # NOTE(efried): `api_endpoint` still overrides service catalog and # `endpoint_override` conf options. This will be removed in a # future release. ironic_url = CONF.ironic.api_endpoint else: try: ksa_adap = utils.get_ksa_adapter( nova.conf.ironic.DEFAULT_SERVICE_TYPE, ksa_auth=auth_plugin, ksa_session=sess, min_version=IRONIC_API_VERSION, max_version=(IRONIC_API_VERSION[0], ks_disc.LATEST)) ironic_url = ksa_adap.get_endpoint() except exception.ServiceNotFound: # NOTE(efried): No reason to believe service catalog lookup # won't also fail in ironic client init, but this way will # yield the expected exception/behavior. ironic_url = None try: cli = ironic.client.get_client(IRONIC_API_VERSION[0], ironic_url=ironic_url, session=sess, **kwargs) # Cache the client so we don't have to reconstruct and # reauthenticate it every time we need it. if retry_on_conflict: self._cached_client = cli except ironic.exc.Unauthorized: msg = _("Unable to authenticate Ironic client.") LOG.error(msg) raise exception.NovaException(msg) return cli
def _placement_get(path): """Do an HTTP get call against placement engine. This is in a dedicated method to make it easier for unit testing purposes. """ client = utils.get_ksa_adapter('placement') return client.get(path, raise_exc=True).json()
def verify_project_id(context, project_id): """verify that a project_id exists. This attempts to verify that a project id exists. If it does not, an HTTPBadRequest is emitted. """ adap = utils.get_ksa_adapter('identity', ksa_auth=context.get_auth_plugin(), min_version=(3, 0), max_version=(3, 'latest')) failure = webob.exc.HTTPBadRequest( explanation=_("Project ID %s is not a valid project.") % project_id) try: resp = adap.get('/projects/%s' % project_id, raise_exc=False) except kse.EndpointNotFound: LOG.error( "Keystone identity service version 3.0 was not found. This might " "be because your endpoint points to the v2.0 versioned endpoint " "which is not supported. Please fix this.") raise failure except kse.ClientException: # something is wrong, like there isn't a keystone v3 endpoint, # or nova isn't configured for the interface to talk to it; # we'll take the pass and default to everything being ok. LOG.info("Unable to contact keystone to verify project_id") return True if resp: # All is good with this 20x status return True elif resp.status_code == 404: # we got access, and we know this project is not there raise failure elif resp.status_code == 403: # we don't have enough permission to verify this, so default # to "it's ok". LOG.info( "Insufficient permissions for user %(user)s to verify " "existence of project_id %(pid)s", { "user": context.user_id, "pid": project_id }) return True else: LOG.warning( "Unexpected response from keystone trying to " "verify project_id %(pid)s - resp: %(code)s %(content)s", { "pid": project_id, "code": resp.status_code, "content": resp.content }) # realize we did something wrong, but move on with a warning return True
def verify_project_id(context, project_id): """verify that a project_id exists. This attempts to verify that a project id exists. If it does not, an HTTPBadRequest is emitted. """ adap = utils.get_ksa_adapter( 'identity', ksa_auth=context.get_auth_plugin(), min_version=(3, 0), max_version=(3, 'latest')) failure = webob.exc.HTTPBadRequest( explanation=_("Project ID %s is not a valid project.") % project_id) try: resp = adap.get('/projects/%s' % project_id) except kse.EndpointNotFound: LOG.error( "Keystone identity service version 3.0 was not found. This might " "be because your endpoint points to the v2.0 versioned endpoint " "which is not supported. Please fix this.") raise failure except kse.ClientException: # something is wrong, like there isn't a keystone v3 endpoint, # or nova isn't configured for the interface to talk to it; # we'll take the pass and default to everything being ok. LOG.info("Unable to contact keystone to verify project_id") return True if resp: # All is good with this 20x status return True elif resp.status_code == 404: # we got access, and we know this project is not there raise failure elif resp.status_code == 403: # we don't have enough permission to verify this, so default # to "it's ok". LOG.info( "Insufficient permissions for user %(user)s to verify " "existence of project_id %(pid)s", {"user": context.user_id, "pid": project_id}) return True else: LOG.warning( "Unexpected response from keystone trying to " "verify project_id %(pid)s - resp: %(code)s %(content)s", {"pid": project_id, "code": resp.status_code, "content": resp.content}) # realize we did something wrong, but move on with a warning return True
def test_auth_from_session(self): self.sess.auth = 'auth' ret = utils.get_ksa_adapter('baremetal', ksa_session=self.sess) # Returned the result of load_adapter_from_conf_options self.assertEqual(self.load_adap.return_value, ret) # Because ksa_auth found in ksa_session, load_auth* not called self.mock_ksa_load_auth.assert_not_called() # Because we supplied ksa_session, load_session* not called self.mock_ksa_load_sess.assert_not_called() # load_adapter* called with the auth from the session self.load_adap.assert_called_once_with(utils.CONF, 'ironic', session=self.sess, auth='auth', min_version=None, max_version=None, raise_exc=False)
def test_load_auth_and_session(self): ret = utils.get_ksa_adapter('volumev3') # Returned the result of load_adapter_from_conf_options self.assertEqual(self.load_adap.return_value, ret) # Had to load the auth self.mock_ksa_load_auth.assert_called_once_with(utils.CONF, 'cinder') # Had to load the session, passed in the loaded auth self.mock_ksa_load_sess.assert_called_once_with(utils.CONF, 'cinder', auth=self.auth) # load_adapter* called with the loaded auth & session self.load_adap.assert_called_once_with(utils.CONF, 'cinder', session=self.sess, auth=self.auth, min_version=None, max_version=None, raise_exc=False)
def get_api_servers(context): """Shuffle a list of service endpoints and return an iterator that will cycle through the list, looping around to the beginning if necessary. """ # NOTE(efried): utils.get_ksa_adapter().get_endpoint() is the preferred # mechanism for endpoint discovery. Only use `api_servers` if you really # need to shuffle multiple endpoints. if CONF.glance.api_servers: api_servers = CONF.glance.api_servers random.shuffle(api_servers) else: sess, auth = _session_and_auth(context) ksa_adap = utils.get_ksa_adapter( nova.conf.glance.DEFAULT_SERVICE_TYPE, ksa_auth=auth, ksa_session=sess, min_version='2.0', max_version='2.latest') api_servers = [utils.get_endpoint(ksa_adap)] return itertools.cycle(api_servers)
def test_all_params(self): ret = utils.get_ksa_adapter('image', ksa_auth='auth', ksa_session='sess', min_version='min', max_version='max') # Returned the result of load_adapter_from_conf_options self.assertEqual(self.load_adap.return_value, ret) # Because we supplied ksa_auth, load_auth* not called self.mock_ksa_load_auth.assert_not_called() # Ditto ksa_session/load_session* self.mock_ksa_load_sess.assert_not_called() # load_adapter* called with what we passed in (and the right group) self.load_adap.assert_called_once_with(utils.CONF, 'glance', session='sess', auth='auth', min_version='min', max_version='max', raise_exc=False)
def get_api_servers(): """Shuffle a list of service endpoints and return an iterator that will cycle through the list, looping around to the beginning if necessary. """ # NOTE(efried): utils.get_ksa_adapter().get_endpoint() is the preferred # mechanism for endpoint discovery. Only use `api_servers` if you really # need to shuffle multiple endpoints. if CONF.glance.api_servers: api_servers = CONF.glance.api_servers random.shuffle(api_servers) else: # TODO(efried): Plumb in a reasonable auth from callers' contexts ksa_adap = utils.get_ksa_adapter(nova.conf.glance.DEFAULT_SERVICE_TYPE, min_version='2.0', max_version='2.latest') # TODO(efried): Use ksa_adap.get_endpoint() when bug #1707995 is fixed. api_servers = [ ksa_adap.endpoint_override or ksa_adap.get_endpoint_data().catalog_url ] return itertools.cycle(api_servers)
def _get_client(self, retry_on_conflict=True): max_retries = CONF.ironic.api_max_retries if retry_on_conflict else 1 retry_interval = (CONF.ironic.api_retry_interval if retry_on_conflict else 0) # If we've already constructed a valid, authed client, just return # that. if retry_on_conflict and self._cached_client is not None: return self._cached_client auth_plugin = self._get_auth_plugin() sess = ks_loading.load_session_from_conf_options(CONF, IRONIC_GROUP.name, auth=auth_plugin) # Retries for Conflict exception kwargs = {} kwargs['max_retries'] = max_retries kwargs['retry_interval'] = retry_interval # NOTE(TheJulia): The ability for a list of available versions to be # accepted was added in python-ironicclient 2.2.0. The highest # available version will be utilized by the client for the lifetime # of the client. kwargs['os_ironic_api_version'] = [ '%d.%d' % IRONIC_API_VERSION, '%d.%d' % PRIOR_IRONIC_API_VERSION] ironic_conf = CONF[IRONIC_GROUP.name] # valid_interfaces is a list. ironicclient passes this kwarg through to # ksa, which is set up to handle 'interface' as either a list or a # single value. kwargs['interface'] = ironic_conf.valid_interfaces # NOTE(clenimar/efried): by default, the endpoint is taken from the # service catalog. Use `endpoint_override` if you want to override it. if CONF.ironic.api_endpoint: # NOTE(efried): `api_endpoint` still overrides service catalog and # `endpoint_override` conf options. This will be removed in a # future release. ironic_url = CONF.ironic.api_endpoint else: try: ksa_adap = utils.get_ksa_adapter( nova.conf.ironic.DEFAULT_SERVICE_TYPE, ksa_auth=auth_plugin, ksa_session=sess, min_version=(IRONIC_API_VERSION[0], 0), max_version=(IRONIC_API_VERSION[0], ks_disc.LATEST)) ironic_url = ksa_adap.get_endpoint() ironic_url_none_reason = 'returned None' except exception.ServiceNotFound: # NOTE(efried): No reason to believe service catalog lookup # won't also fail in ironic client init, but this way will # yield the expected exception/behavior. ironic_url = None ironic_url_none_reason = 'raised ServiceNotFound' if ironic_url is None: LOG.warning("Could not discover ironic_url via keystoneauth1: " "Adapter.get_endpoint %s", ironic_url_none_reason) # NOTE(eandersson): We pass in region here to make sure # that the Ironic client can make an educated decision when # we don't have a valid endpoint to pass on. kwargs['region_name'] = ironic_conf.region_name try: cli = ironic.client.get_client(IRONIC_API_VERSION[0], endpoint=ironic_url, session=sess, **kwargs) # Cache the client so we don't have to reconstruct and # reauthenticate it every time we need it. if retry_on_conflict: self._cached_client = cli except ironic.exc.Unauthorized: msg = _("Unable to authenticate Ironic client.") LOG.error(msg) raise exception.NovaException(msg) return cli
def _get_client(self, retry_on_conflict=True): max_retries = CONF.ironic.api_max_retries if retry_on_conflict else 1 retry_interval = (CONF.ironic.api_retry_interval if retry_on_conflict else 0) # If we've already constructed a valid, authed client, just return # that. if retry_on_conflict and self._cached_client is not None: return self._cached_client auth_plugin = self._get_auth_plugin() sess = ks_loading.load_session_from_conf_options(CONF, IRONIC_GROUP.name, auth=auth_plugin) # Retries for Conflict exception kwargs = {} kwargs['max_retries'] = max_retries kwargs['retry_interval'] = retry_interval # NOTE(TheJulia): The ability for a list of available versions to be # accepted was added in python-ironicclient 2.2.0. The highest # available version will be utilized by the client for the lifetime # of the client. kwargs['os_ironic_api_version'] = [ '%d.%d' % IRONIC_API_VERSION, '%d.%d' % PRIOR_IRONIC_API_VERSION] ironic_conf = CONF[IRONIC_GROUP.name] # valid_interfaces is a list. ironicclient passes this kwarg through to # ksa, which is set up to handle 'interface' as either a list or a # single value. kwargs['interface'] = ironic_conf.valid_interfaces # NOTE(clenimar/efried): by default, the endpoint is taken from the # service catalog. Use `endpoint_override` if you want to override it. try: ksa_adap = utils.get_ksa_adapter( nova.conf.ironic.DEFAULT_SERVICE_TYPE, ksa_auth=auth_plugin, ksa_session=sess, min_version=(IRONIC_API_VERSION[0], 0), max_version=(IRONIC_API_VERSION[0], ks_disc.LATEST)) ironic_url = ksa_adap.get_endpoint() ironic_url_none_reason = 'returned None' except exception.ServiceNotFound: # NOTE(efried): No reason to believe service catalog lookup # won't also fail in ironic client init, but this way will # yield the expected exception/behavior. ironic_url = None ironic_url_none_reason = 'raised ServiceNotFound' if ironic_url is None: LOG.warning("Could not discover ironic_url via keystoneauth1: " "Adapter.get_endpoint %s", ironic_url_none_reason) # NOTE(eandersson): We pass in region here to make sure # that the Ironic client can make an educated decision when # we don't have a valid endpoint to pass on. kwargs['region_name'] = ironic_conf.region_name try: cli = ironic.client.get_client(IRONIC_API_VERSION[0], endpoint=ironic_url, session=sess, **kwargs) # Cache the client so we don't have to reconstruct and # reauthenticate it every time we need it. if retry_on_conflict: self._cached_client = cli except ironic.exc.Unauthorized: msg = _("Unable to authenticate Ironic client.") LOG.error(msg) raise exception.NovaException(msg) return cli
def __init__(self, context): auth = service_auth.get_auth_plugin(context) self._client = utils.get_ksa_adapter('accelerator', ksa_auth=auth)