# Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import argparse import typing as ty from keystoneauth1 import adapter from keystoneauth1.loading import _utils from keystoneauth1.loading import base if ty.TYPE_CHECKING: from oslo_config import cfg from keystoneauth1.loading import opts __all__ = ( 'register_argparse_arguments', 'register_service_argparse_arguments', 'register_conf_options', 'load_from_conf_options', 'get_conf_options', ) class Adapter(base._BaseLoader[adapter.Adapter]): @property def plugin_class(self) -> ty.Type[adapter.Adapter]: return adapter.Adapter def get_options(self) -> list['opts.Opt']: return [] @staticmethod def get_conf_options( include_deprecated: bool = True, deprecated_opts: ty.Optional[ dict[str, list['cfg.DeprecatedOpt']] ] = None, ) -> list['cfg.Opt']: """Get oslo_config options that are needed for a :py:class:`.Adapter`. These may be useful without being registered for config file generation or to manipulate the options before registering them yourself. The options that are set are: :service_type: The default service_type for URL discovery. :service_name: The default service_name for URL discovery. :interface: The default interface for URL discovery. (deprecated) :valid_interfaces: List of acceptable interfaces for URL discovery. Can be a list of any of 'public', 'internal' or 'admin'. :region_name: The default region_name for URL discovery. :endpoint_override: Always use this endpoint URL for requests for this client. :version: The minimum version restricted to a given Major API. Mutually exclusive with min_version and max_version. :min_version: The minimum major version of a given API, intended to be used as the lower bound of a range with max_version. Mutually exclusive with version. If min_version is given with no max_version it is as if max version is 'latest'. :max_version: The maximum major version of a given API, intended to be used as the upper bound of a range with min_version. Mutually exclusive with version. :param include_deprecated: If True (the default, for backward compatibility), deprecated options are included in the result. If False, they are excluded. :param dict deprecated_opts: Deprecated options that should be included in the definition of new options. This should be a dict from the name of the new option to a list of oslo.DeprecatedOpts that correspond to the new option. (optional) For example, to support the ``api_endpoint`` option pointing to the new ``endpoint_override`` option name:: old_opt = oslo_cfg.DeprecatedOpt('api_endpoint', 'old_group') deprecated_opts = {'endpoint_override': [old_opt]} :returns: A list of oslo_config options. """ cfg = _utils.get_oslo_config() if deprecated_opts is None: deprecated_opts = {} # This is goofy, but need to support hyphens *or* underscores deprecated_opts = { name.replace('_', '-'): opt for name, opt in deprecated_opts.items() } opts = [ cfg.StrOpt( 'service-type', deprecated_opts=deprecated_opts.get('service-type'), help='The default service_type for endpoint URL discovery.', ), cfg.StrOpt( 'service-name', deprecated_opts=deprecated_opts.get('service-name'), help='The default service_name for endpoint URL discovery.', ), cfg.ListOpt( 'valid-interfaces', deprecated_opts=deprecated_opts.get('valid-interfaces'), help='List of interfaces, in order of preference, ' 'for endpoint URL.', ), cfg.StrOpt( 'region-name', deprecated_opts=deprecated_opts.get('region-name'), help='The default region_name for endpoint URL discovery.', ), cfg.StrOpt( 'endpoint-override', deprecated_opts=deprecated_opts.get('endpoint-override'), help='Always use this endpoint URL for requests ' 'for this client. NOTE: The unversioned ' 'endpoint should be specified here; to ' 'request a particular API version, use the ' '`version`, `min-version`, and/or ' '`max-version` options.', ), cfg.StrOpt( 'version', deprecated_opts=deprecated_opts.get('version'), help='Minimum Major API version within a given ' 'Major API version for endpoint URL ' 'discovery. Mutually exclusive with ' 'min_version and max_version', ), cfg.StrOpt( 'min-version', deprecated_opts=deprecated_opts.get('min-version'), help='The minimum major version of a given API, ' 'intended to be used as the lower bound of a ' 'range with max_version. Mutually exclusive ' 'with version. If min_version is given with ' 'no max_version it is as if max version is ' '"latest".', ), cfg.StrOpt( 'max-version', deprecated_opts=deprecated_opts.get('max-version'), help='The maximum major version of a given API, ' 'intended to be used as the upper bound of a ' 'range with min_version. Mutually exclusive ' 'with version.', ), cfg.IntOpt( 'connect-retries', deprecated_opts=deprecated_opts.get('connect-retries'), help='The maximum number of retries that should be ' 'attempted for connection errors.', ), cfg.FloatOpt( 'connect-retry-delay', deprecated_opts=deprecated_opts.get('connect-retry-delay'), help='Delay (in seconds) between two retries ' 'for connection errors. If not set, ' 'exponential retry starting with 0.5 ' 'seconds up to a maximum of 60 seconds ' 'is used.', ), cfg.IntOpt( 'status-code-retries', deprecated_opts=deprecated_opts.get('status-code-retries'), help='The maximum number of retries that should be ' 'attempted for retriable HTTP status codes.', ), cfg.FloatOpt( 'status-code-retry-delay', deprecated_opts=deprecated_opts.get('status-code-retry-delay'), help='Delay (in seconds) between two retries ' 'for retriable status codes. If not set, ' 'exponential retry starting with 0.5 ' 'seconds up to a maximum of 60 seconds ' 'is used.', ), cfg.ListOpt( 'retriable-status-codes', deprecated_opts=deprecated_opts.get('retriable-status-codes'), item_type=cfg.types.Integer(), help='List of retriable HTTP status codes that ' 'should be retried. If not set default to ' ' [503]', ), ] if include_deprecated: opts += [ cfg.StrOpt( 'interface', help='The default interface for endpoint URL discovery.', deprecated_for_removal=True, deprecated_reason='Using valid-interfaces is' ' preferrable because it is' ' capable of accepting a list of' ' possible interfaces.', ) ] return opts def register_conf_options( self, conf: 'cfg.ConfigOpts', group: str, include_deprecated: bool = True, deprecated_opts: ty.Optional[ dict[str, list['cfg.DeprecatedOpt']] ] = None, ) -> list['cfg.Opt']: """Register the oslo_config options that are needed for an Adapter. The options that are set are: :service_type: The default service_type for URL discovery. :service_name: The default service_name for URL discovery. :interface: The default interface for URL discovery. (deprecated) :valid_interfaces: List of acceptable interfaces for URL discovery. Can be a list of any of 'public', 'internal' or 'admin'. :region_name: The default region_name for URL discovery. :endpoint_override: Always use this endpoint URL for requests for this client. :version: The minimum version restricted to a given Major API. Mutually exclusive with min_version and max_version. :min_version: The minimum major version of a given API, intended to be used as the lower bound of a range with max_version. Mutually exclusive with version. If min_version is given with no max_version it is as if max version is 'latest'. :max_version: The maximum major version of a given API, intended to be used as the upper bound of a range with min_version. Mutually exclusive with version. :connect_retries: The maximum number of retries that should be attempted for connection errors. :status_code_retries: The maximum number of retries that should be attempted for retriable HTTP status codes. :param oslo_config.Cfg conf: config object to register with. :param string group: The ini group to register options in. :param include_deprecated: If True (the default, for backward compatibility), deprecated options are registered. If False, they are excluded. :param dict deprecated_opts: Deprecated options that should be included in the definition of new options. This should be a dict from the name of the new option to a list of oslo.DeprecatedOpts that correspond to the new option. (optional) For example, to support the ``api_endpoint`` option pointing to the new ``endpoint_override`` option name:: old_opt = oslo_cfg.DeprecatedOpt('api_endpoint', 'old_group') deprecated_opts = {'endpoint_override': [old_opt]} :returns: The list of options that was registered. """ opts = self.get_conf_options( include_deprecated=include_deprecated, deprecated_opts=deprecated_opts, ) conf.register_group(_utils.get_oslo_config().OptGroup(group)) conf.register_opts(opts, group=group) return opts def load_from_conf_options( self, conf: 'cfg.ConfigOpts', group: str, **kwargs: ty.Any ) -> adapter.Adapter: """Create an Adapter object from an oslo_config object. The options must have been previously registered with register_conf_options. :param oslo_config.Cfg conf: config object to register with. :param string group: The ini group to register options in. :param dict kwargs: Additional parameters to pass to Adapter construction. :returns: A new Adapter object. :rtype: :py:class:`.Adapter` """ c = conf[group] process_conf_options(c, kwargs) return self.load_from_options(**kwargs) def process_conf_options( confgrp: 'cfg.OptGroup', kwargs: dict[str, ty.Any] ) -> None: """Set Adapter constructor kwargs based on conf options. :param oslo_config.cfg.OptGroup confgrp: Config object group containing options to inspect. :param dict kwargs: Keyword arguments suitable for the constructor of keystoneauth1.adapter.Adapter. Will be modified by this method. Values already set remain unaffected. :raise TypeError: If invalid conf option values or combinations are found. """ if confgrp.valid_interfaces and getattr(confgrp, 'interface', None): raise TypeError( "interface and valid_interfaces are mutually " "exclusive. Please use valid_interfaces." ) if confgrp.valid_interfaces: for iface in confgrp.valid_interfaces: if iface not in ('public', 'internal', 'admin'): raise TypeError( f"'{iface}' is not a valid value for" " valid_interfaces. Valid values are" " public, internal or admin" ) kwargs.setdefault('interface', confgrp.valid_interfaces) elif hasattr(confgrp, 'interface'): kwargs.setdefault('interface', confgrp.interface) kwargs.setdefault('service_type', confgrp.service_type) kwargs.setdefault('service_name', confgrp.service_name) kwargs.setdefault('region_name', confgrp.region_name) kwargs.setdefault('endpoint_override', confgrp.endpoint_override) kwargs.setdefault('version', confgrp.version) kwargs.setdefault('min_version', confgrp.min_version) kwargs.setdefault('max_version', confgrp.max_version) if kwargs['version'] and (kwargs['max_version'] or kwargs['min_version']): raise TypeError( "version is mutually exclusive with min_version and max_version" ) kwargs.setdefault('connect_retries', confgrp.connect_retries) kwargs.setdefault('connect_retry_delay', confgrp.connect_retry_delay) kwargs.setdefault('status_code_retries', confgrp.status_code_retries) kwargs.setdefault( 'status_code_retry_delay', confgrp.status_code_retry_delay ) kwargs.setdefault('retriable_status_codes', confgrp.retriable_status_codes) def register_argparse_arguments( parser: argparse.ArgumentParser, service_type: ty.Optional[str] = None ) -> None: return adapter.register_adapter_argparse_arguments(parser, service_type) def register_service_argparse_arguments( parser: argparse.ArgumentParser, service_type: str ) -> None: return adapter.register_service_adapter_argparse_arguments( parser, service_type ) def register_conf_options( conf: 'cfg.ConfigOpts', group: str, include_deprecated: bool = True, deprecated_opts: ty.Optional[dict[str, list['cfg.DeprecatedOpt']]] = None, ) -> list['cfg.Opt']: return Adapter().register_conf_options( conf, group, include_deprecated=include_deprecated, deprecated_opts=deprecated_opts, ) def load_from_conf_options( conf: 'cfg.ConfigOpts', group: str, **kwargs: ty.Any ) -> adapter.Adapter: return Adapter().load_from_conf_options(conf, group, **kwargs) def get_conf_options( include_deprecated: bool = True, deprecated_opts: ty.Optional[dict[str, list['cfg.DeprecatedOpt']]] = None, ) -> list['cfg.Opt']: return Adapter.get_conf_options(include_deprecated, deprecated_opts)