Example #1
0
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)
Example #2
0
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)
Example #3
0
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)
Example #4
0
    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
Example #5
0
    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
Example #6
0
    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()
Example #7
0
    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()
Example #8
0
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
Example #9
0
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
Example #10
0
 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)
Example #11
0
 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)
Example #12
0
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)
Example #13
0
 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)
Example #14
0
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)
Example #15
0
    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
Example #16
0
    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
Example #17
0
 def __init__(self, context):
     auth = service_auth.get_auth_plugin(context)
     self._client = utils.get_ksa_adapter('accelerator', ksa_auth=auth)