Beispiel #1
0
def pick_microversion(session, required):
    """Get a new microversion if it is higher than session's default.

    :param session: The session to use for making this request.
    :type session: :class:`~keystoneauth1.adapter.Adapter`
    :param required: Version that is required for an action.
    :type required: String or tuple or None.
    :return: ``required`` as a string if the ``session``'s default is too low,
        the ``session``'s default otherwise. Returns ``None`` of both
        are ``None``.
    :raises: TypeError if ``required`` is invalid.
    """
    if required is not None:
        required = discover.normalize_version_number(required)

    if session.default_microversion is not None:
        default = discover.normalize_version_number(
            session.default_microversion)

        if required is None:
            required = default
        else:
            required = (default if discover.version_match(required, default)
                        else required)

    if required is not None:
        return discover.version_to_string(required)
def pick_microversion(session, required):
    """Get a new microversion if it is higher than session's default.

    :param session: The session to use for making this request.
    :type session: :class:`~keystoneauth1.adapter.Adapter`
    :param required: Version that is required for an action.
    :type required: String or tuple or None.
    :return: ``required`` as a string if the ``session``'s default is too low,
        the ``session``'s default otherwise. Returns ``None`` of both
        are ``None``.
    :raises: TypeError if ``required`` is invalid.
    """
    if required is not None:
        required = discover.normalize_version_number(required)

    if session.default_microversion is not None:
        default = discover.normalize_version_number(
            session.default_microversion)

        if required is None:
            required = default
        else:
            required = (default if discover.version_match(required, default)
                        else required)

    if required is not None:
        return discover.version_to_string(required)
Beispiel #3
0
def maximum_supported_microversion(adapter, client_maximum):
    """Determinte the maximum microversion supported by both client and server.

    :param adapter: :class:`~keystoneauth1.adapter.Adapter` instance.
    :param client_maximum: Maximum microversion supported by the client.
        If ``None``, ``None`` is returned.

    :returns: the maximum supported microversion as string or ``None``.
    """
    if client_maximum is None:
        return None

    endpoint_data = adapter.get_endpoint_data()
    if not endpoint_data.max_microversion:
        return None

    client_max = discover.normalize_version_number(client_maximum)
    server_max = discover.normalize_version_number(
        endpoint_data.max_microversion)

    if endpoint_data.min_microversion:
        server_min = discover.normalize_version_number(
            endpoint_data.min_microversion)
        if client_max < server_min:
            # NOTE(dtantsur): we may want to raise in this case, but this keeps
            # the current behavior intact.
            return None

    result = min(client_max, server_max)
    return discover.version_to_string(result)
Beispiel #4
0
def _format_endpoint(endpoint, **kwargs):
    # can't format AUTH_INTERFACE object so replace with string
    if kwargs.get('service_type') is plugin.AUTH_INTERFACE:
        kwargs['service_type'] = 'identity'

    version = kwargs.get('version')
    if version:
        discover.normalize_version_number(version)
        kwargs['version'] = ".".join(str(v) for v in version)

    return endpoint % kwargs  # pass kwargs ok?
Beispiel #5
0
    def _create_identity_server(self):
        # NOTE(jamielennox): Loading Session here should be exactly the
        # same as calling Session.load_from_conf_options(CONF, GROUP)
        # however we can't do that because we have to use _conf_get to
        # support the paste.ini options.
        sess = session_loading.Session().load_from_options(
            cert=self._conf_get('certfile'),
            key=self._conf_get('keyfile'),
            cacert=self._conf_get('cafile'),
            insecure=self._conf_get('insecure'),
            timeout=self._conf_get('http_connect_timeout'),
            user_agent=self._build_useragent_string())

        auth_plugin = self._get_auth_plugin()

        adap = adapter.Adapter(
            sess,
            auth=auth_plugin,
            service_type='identity',
            interface='admin',
            region_name=self._conf_get('region_name'),
            connect_retries=self._conf_get('http_request_max_retries'))

        auth_version = self._conf_get('auth_version')
        if auth_version is not None:
            auth_version = discover.normalize_version_number(auth_version)
        return _identity.IdentityServer(
            self.log,
            adap,
            include_service_catalog=self._include_service_catalog,
            requested_auth_version=auth_version)
    def _create_identity_server(self):
        # NOTE(jamielennox): Loading Session here should be exactly the
        # same as calling Session.load_from_conf_options(CONF, GROUP)
        # however we can't do that because we have to use _conf_get to
        # support the paste.ini options.
        sess = session_loading.Session().load_from_options(
            cert=self._conf_get('certfile'),
            key=self._conf_get('keyfile'),
            cacert=self._conf_get('cafile'),
            insecure=self._conf_get('insecure'),
            timeout=self._conf_get('http_connect_timeout'),
            user_agent=self._build_useragent_string()
        )

        auth_plugin = self._get_auth_plugin()

        adap = adapter.Adapter(
            sess,
            auth=auth_plugin,
            service_type='identity',
            interface='admin',
            region_name=self._conf_get('region_name'),
            connect_retries=self._conf_get('http_request_max_retries'))

        auth_version = self._conf_get('auth_version')
        if auth_version is not None:
            auth_version = discover.normalize_version_number(auth_version)
        return _identity.IdentityServer(
            self.log,
            adap,
            include_service_catalog=self._include_service_catalog,
            requested_auth_version=auth_version)
Beispiel #7
0
    def version_data(self):
        """Get an endpoint with its versions"""
        all_version_data = []

        if not self.endpoint_with_versions:
            return None
        else:
            for endpoint in self.endpoint_with_versions:

                if not endpoint:
                    continue

                for version in endpoint:
                    if not self.desired_version:
                        if 'version' in version and version['version']:
                            all_version_data.append(version)
                        elif 'id' in version:
                            all_version_data.append(version)
                    else:
                        if 'version' in version and version['version']:
                            if self.exact_match:
                                if version['version'] == str(
                                        self.desired_version):
                                    all_version_data.append(version)
                            else:
                                current_micro_version = normalize_version_number(
                                    version['version'])
                                required_micro_version = normalize_version_number(
                                    str(self.desired_version))
                                if version_match(required_micro_version,
                                                 current_micro_version):
                                    all_version_data.append(version)
                        elif 'id' in version and version["id"]:
                            if self.exact_match:
                                if version['id'] == 'v' + str(
                                        self.desired_version):
                                    all_version_data.append(version)
                            else:
                                current_version = normalize_version_number(
                                    version['id'])
                                required_version = normalize_version_number(
                                    str(self.desired_version))
                                if version_match(required_version,
                                                 current_version):
                                    all_version_data.append(version)
            return all_version_data
Beispiel #8
0
def supports_microversion(adapter, microversion, raise_exception=False):
    """Determine if the given adapter supports the given microversion.

    Checks the min and max microversion asserted by the service and checks to
    make sure that ``min <= microversion <= max``. Current default microversion
    is taken into consideration if set and verifies that ``microversion <=
    default``.

    :param adapter: :class:`~keystoneauth1.adapter.Adapter` instance.
    :param str microversion: String containing the desired microversion.
    :param bool raise_exception: Raise exception when requested microversion
        is not supported be the server side or is higher than the current
        default microversion.
    :returns: True if the service supports the microversion.
    :rtype: bool
    :raises: :class:`~openstack.exceptions.SDKException` when requested
        microversion is not supported.
    """

    endpoint_data = adapter.get_endpoint_data()
    if (endpoint_data.min_microversion
            and endpoint_data.max_microversion and discover.version_between(
                endpoint_data.min_microversion, endpoint_data.max_microversion,
                microversion)):
        if adapter.default_microversion is not None:
            # If default_microversion is set - evaluate
            # whether it match the expectation
            candidate = discover.normalize_version_number(
                adapter.default_microversion)
            required = discover.normalize_version_number(microversion)
            supports = discover.version_match(required, candidate)
            if raise_exception and not supports:
                raise exceptions.SDKException(
                    'Required microversion {ver} is higher than currently '
                    'selected {curr}'.format(
                        ver=microversion, curr=adapter.default_microversion))
            return supports
        return True
    if raise_exception:
        raise exceptions.SDKException(
            'Required microversion {ver} is not supported '
            'by the server side'.format(ver=microversion))
    return False
def maximum_supported_microversion(adapter, client_maximum):
    """Determinte the maximum microversion supported by both client and server.

    :param adapter: :class:`~keystoneauth1.adapter.Adapter` instance.
    :param client_maximum: Maximum microversion supported by the client.
        If ``None``, ``None`` is returned.

    :returns: the maximum supported microversion as string or ``None``.
    """
    if client_maximum is None:
        return None

    # NOTE(dtantsur): if we cannot determine supported microversions, fall back
    # to the default one.
    try:
        endpoint_data = adapter.get_endpoint_data()
    except keystoneauth1.exceptions.discovery.DiscoveryFailure:
        endpoint_data = None

    if endpoint_data is None:
        log = _log.setup_logging('openstack')
        log.warning('Cannot determine endpoint data for service %s',
                    adapter.service_type or adapter.service_name)
        return None

    if not endpoint_data.max_microversion:
        return None

    client_max = discover.normalize_version_number(client_maximum)
    server_max = discover.normalize_version_number(
        endpoint_data.max_microversion)

    if endpoint_data.min_microversion:
        server_min = discover.normalize_version_number(
            endpoint_data.min_microversion)
        if client_max < server_min:
            # NOTE(dtantsur): we may want to raise in this case, but this keeps
            # the current behavior intact.
            return None

    result = min(client_max, server_max)
    return discover.version_to_string(result)
Beispiel #10
0
def maximum_supported_microversion(adapter, client_maximum):
    """Determinte the maximum microversion supported by both client and server.

    :param adapter: :class:`~keystoneauth1.adapter.Adapter` instance.
    :param client_maximum: Maximum microversion supported by the client.
        If ``None``, ``None`` is returned.

    :returns: the maximum supported microversion as string or ``None``.
    """
    if client_maximum is None:
        return None

    # NOTE(dtantsur): if we cannot determine supported microversions, fall back
    # to the default one.
    try:
        endpoint_data = adapter.get_endpoint_data()
    except keystoneauth1.exceptions.discovery.DiscoveryFailure:
        endpoint_data = None

    if endpoint_data is None:
        log = _log.setup_logging('openstack')
        log.warning('Cannot determine endpoint data for service %s',
                    adapter.service_type or adapter.service_name)
        return None

    if not endpoint_data.max_microversion:
        return None

    client_max = discover.normalize_version_number(client_maximum)
    server_max = discover.normalize_version_number(
        endpoint_data.max_microversion)

    if endpoint_data.min_microversion:
        server_min = discover.normalize_version_number(
            endpoint_data.min_microversion)
        if client_max < server_min:
            # NOTE(dtantsur): we may want to raise in this case, but this keeps
            # the current behavior intact.
            return None

    result = min(client_max, server_max)
    return discover.version_to_string(result)
Beispiel #11
0
    def get_endpoint(self, session, interface=None, version=None, **kwargs):
        """Return an endpoint for the client.

        There are no required keyword arguments to ``get_endpoint`` as a plugin
        implementation should use best effort with the information available to
        determine the endpoint.

        :param session: The session object that the auth_plugin belongs to.
        :type session: keystoneauth1.session.Session
        :param version: The version number required for this endpoint.
        :type version: tuple or str
        :param str interface: what visibility the endpoint should have.

        :returns: The base URL that will be used to talk to the required
                  service or None if not available.
        :rtype: string
        """
        if interface == plugin.AUTH_INTERFACE:
            return self._identity_uri

        if not version:
            # NOTE(jamielennox): This plugin can only be used within auth_token
            # and auth_token will always provide version= with requests.
            return None

        if not self._discover:
            self._discover = discover.Discover(session,
                                               url=self._identity_uri,
                                               authenticated=False)

        if not self._discover.url_for(version):
            # NOTE(jamielennox): The requested version is not supported by the
            # identity server.
            return None

        # NOTE(jamielennox): for backwards compatibility here we don't
        # actually use the URL from discovery we hack it up instead. :(
        # NOTE(blk-u): Normalizing the version is a workaround for bug 1450272.
        # This can be removed once that's fixed. Also fix the docstring for the
        # version parameter to be just "tuple".
        version = discover.normalize_version_number(version)
        if discover.version_match((2, 0), version):
            return '%s/v2.0' % self._identity_uri
        elif discover.version_match((3, 0), version):
            return '%s/v3' % self._identity_uri

        # NOTE(jamielennox): This plugin will only get called from auth_token
        # middleware. The middleware should never request a version that the
        # plugin doesn't know how to handle.
        msg = _('Invalid version asked for in auth_token plugin')
        raise NotImplementedError(msg)
Beispiel #12
0
    def get_endpoint(self, session, interface=None, version=None, **kwargs):
        """Return an endpoint for the client.

        There are no required keyword arguments to ``get_endpoint`` as a plugin
        implementation should use best effort with the information available to
        determine the endpoint.

        :param session: The session object that the auth_plugin belongs to.
        :type session: keystoneauth1.session.Session
        :param version: The version number required for this endpoint.
        :type version: tuple or str
        :param str interface: what visibility the endpoint should have.

        :returns: The base URL that will be used to talk to the required
                  service or None if not available.
        :rtype: string
        """
        if interface == plugin.AUTH_INTERFACE:
            return self._identity_uri

        if not version:
            # NOTE(jamielennox): This plugin can only be used within auth_token
            # and auth_token will always provide version= with requests.
            return None

        if not self._discover:
            self._discover = discover.Discover(session,
                                               url=self._identity_uri,
                                               authenticated=False)

        if not self._discover.url_for(version):
            # NOTE(jamielennox): The requested version is not supported by the
            # identity server.
            return None

        # NOTE(jamielennox): for backwards compatibility here we don't
        # actually use the URL from discovery we hack it up instead. :(
        # NOTE(blk-u): Normalizing the version is a workaround for bug 1450272.
        # This can be removed once that's fixed. Also fix the docstring for the
        # version parameter to be just "tuple".
        version = discover.normalize_version_number(version)
        if discover.version_match((2, 0), version):
            return '%s/v2.0' % self._identity_uri
        elif discover.version_match((3, 0), version):
            return '%s/v3' % self._identity_uri

        # NOTE(jamielennox): This plugin will only get called from auth_token
        # middleware. The middleware should never request a version that the
        # plugin doesn't know how to handle.
        msg = _('Invalid version asked for in auth_token plugin')
        raise NotImplementedError(msg)
    def _create_identity_server(self):
        adap = adapter.Adapter(
            self._session,
            auth=self._auth,
            service_type='identity',
            interface='admin',
            region_name=self._conf.get('region_name'),
            connect_retries=self._conf.get('http_request_max_retries'))

        auth_version = self._conf.get('auth_version')
        if auth_version is not None:
            auth_version = discover.normalize_version_number(auth_version)
        return _identity.IdentityServer(
            self.log,
            adap,
            include_service_catalog=self._include_service_catalog,
            requested_auth_version=auth_version)
    def _create_identity_server(self):
        adap = adapter.Adapter(
            self._session,
            auth=self._auth,
            service_type='identity',
            interface='admin',
            region_name=self._conf.get('region_name'),
            connect_retries=self._conf.get('http_request_max_retries'))

        auth_version = self._conf.get('auth_version')
        if auth_version is not None:
            auth_version = discover.normalize_version_number(auth_version)
        return _identity.IdentityServer(
            self.log,
            adap,
            include_service_catalog=self._include_service_catalog,
            requested_auth_version=auth_version)
Beispiel #15
0
    def _set_microversion_headers(headers, microversion, service_type,
                                  endpoint_filter):
        # We're converting it to normalized version number for two reasons.
        # First, to validate it's a real version number. Second, so that in
        # the future we can pre-validate that it is within the range of
        # available microversions before we send the request.
        # TODO(mordred) Validate when we get the response back that
        # the server executed in the microversion we expected.
        # TODO(mordred) Validate that the requested microversion works
        # with the microversion range we found in discovery.
        microversion = discover.normalize_version_number(microversion)
        # Can't specify a M.latest microversion
        if (microversion[0] != discover.LATEST
                and discover.LATEST in microversion[1:]):
            raise TypeError(
                "Specifying a '{major}.latest' microversion is not allowed.")
        microversion = discover.version_to_string(microversion)
        if not service_type:
            if endpoint_filter and 'service_type' in endpoint_filter:
                service_type = endpoint_filter['service_type']
            else:
                raise TypeError(
                    "microversion {microversion} was requested but no"
                    " service_type information is available. Either provide a"
                    " service_type in endpoint_filter or pass"
                    " microversion_service_type as an argument.".format(
                        microversion=microversion))

        # TODO(mordred) cinder uses volume in its microversion header. This
        # logic should be handled in the future by os-service-types but for
        # now hard-code for cinder.
        if (service_type.startswith('volume')
                or service_type == 'block-storage'):
            service_type = 'volume'
        headers.setdefault(
            'OpenStack-API-Version',
            '{service_type} {microversion}'.format(service_type=service_type,
                                                   microversion=microversion))
        header_names = _mv_legacy_headers_for_service(service_type)
        for h in header_names:
            headers.setdefault(h, microversion)
Beispiel #16
0
 def assertVersion(out, inp):
     self.assertEqual(out, discover.normalize_version_number(inp))
Beispiel #17
0
 def assertVersion(inp, out):
     self.assertEqual(out, discover.normalize_version_number(inp))