From 8161ed81d6f9b89fc53ea260cfaa16003909271a Mon Sep 17 00:00:00 2001 From: Monty Taylor <mordred@inaugust.com> Date: Tue, 11 Jul 2017 17:20:45 -0500 Subject: [PATCH] Add min_version and max_version to adapter constructors They should be here as an Adapter is essentially a codified endpoint_filter. Add them to the conf options for Adapter, since that is how Adapters get defined in services which is one of the reasons for doing all of this work. Change-Id: I8c6613bac09f28169e903b303c7330b1e90fe72d --- keystoneauth1/adapter.py | 28 +++++++++- keystoneauth1/loading/adapter.py | 51 +++++++++++++++++++ .../tests/unit/loading/test_adapter.py | 38 +++++++++++++- 3 files changed, 113 insertions(+), 4 deletions(-) diff --git a/keystoneauth1/adapter.py b/keystoneauth1/adapter.py index c9981d8d..91ff5a82 100644 --- a/keystoneauth1/adapter.py +++ b/keystoneauth1/adapter.py @@ -27,6 +27,9 @@ class Adapter(object): particular client that is using the session. An adapter provides a wrapper of client local data around the global session object. + version, min_version and max_version can all be given either as a + string or a tuple. + :param session: The session object to wrap. :type session: keystoneauth1.session.Session :param str service_type: The default service_type for URL discovery. @@ -35,7 +38,9 @@ class Adapter(object): :param str region_name: The default region_name for URL discovery. :param str endpoint_override: Always use this endpoint URL for requests for this client. - :param tuple version: The version that this API targets. + :param version: The minimum version restricted to a given Major API. + Mutually exclusive with min_version and max_version. + (optional) :param auth: An auth plugin to use instead of the session one. :type auth: keystoneauth1.plugin.BaseAuthPlugin :param str user_agent: The User-Agent string to set. @@ -64,6 +69,14 @@ class Adapter(object): ``req-$uuid``) that will be passed on all requests. Enables cross project request id tracking. + :param 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'. (optional) + :param 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. (optional) """ client_name = None @@ -76,7 +89,12 @@ class Adapter(object): connect_retries=None, logger=None, allow={}, additional_headers=None, client_name=None, client_version=None, allow_version_hack=None, - global_request_id=None): + global_request_id=None, + min_version=None, max_version=None): + if version and (min_version or max_version): + raise TypeError( + "version is mutually exclusive with min_version and" + " max_version") # NOTE(jamielennox): when adding new parameters to adapter please also # add them to the adapter call in httpclient.HTTPClient.__init__ as # well as to load_adapter_from_argparse below if the argument is @@ -96,6 +114,8 @@ class Adapter(object): self.allow = allow self.additional_headers = additional_headers or {} self.allow_version_hack = allow_version_hack + self.min_version = min_version + self.max_version = max_version self.global_request_id = global_request_id @@ -115,6 +135,10 @@ class Adapter(object): kwargs.setdefault('region_name', self.region_name) if self.version: kwargs.setdefault('version', self.version) + if self.min_version: + kwargs.setdefault('min_version', self.min_version) + if self.max_version: + kwargs.setdefault('max_version', self.max_version) if self.allow_version_hack is not None: kwargs.setdefault('allow_version_hack', self.allow_version_hack) diff --git a/keystoneauth1/loading/adapter.py b/keystoneauth1/loading/adapter.py index 5b3638db..256c4282 100644 --- a/keystoneauth1/loading/adapter.py +++ b/keystoneauth1/loading/adapter.py @@ -45,6 +45,19 @@ class Adapter(base.BaseLoader): :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. :returns: A list of oslo_config options. """ @@ -65,6 +78,23 @@ class Adapter(base.BaseLoader): cfg.StrOpt('endpoint-override', help='Always use this endpoint URL for requests ' 'for this client.'), + cfg.StrOpt('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', + 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', + 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.'), ] def register_conf_options(self, conf, group): @@ -77,6 +107,19 @@ class Adapter(base.BaseLoader): :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 oslo_config.Cfg conf: config object to register with. :param string group: The ini group to register options in. @@ -107,6 +150,14 @@ class Adapter(base.BaseLoader): kwargs.setdefault('interface', c.interface) kwargs.setdefault('region_name', c.region_name) kwargs.setdefault('endpoint_override', c.endpoint_override) + kwargs.setdefault('version', c.version) + kwargs.setdefault('min_version', c.min_version) + kwargs.setdefault('max_version', c.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") return self.load_from_options(**kwargs) diff --git a/keystoneauth1/tests/unit/loading/test_adapter.py b/keystoneauth1/tests/unit/loading/test_adapter.py index f50bca72..aa4bf929 100644 --- a/keystoneauth1/tests/unit/loading/test_adapter.py +++ b/keystoneauth1/tests/unit/loading/test_adapter.py @@ -31,7 +31,7 @@ class ConfLoadingTests(utils.TestCase): self.conf_fx.config( service_type='type', service_name='name', interface='iface', region_name='region', endpoint_override='endpoint', - group=self.GROUP) + version='2.0', group=self.GROUP) adap = loading.load_adapter_from_conf_options( self.conf_fx.conf, self.GROUP, session='session', auth='auth') self.assertEqual('type', adap.service_type) @@ -41,11 +41,45 @@ class ConfLoadingTests(utils.TestCase): self.assertEqual('endpoint', adap.endpoint_override) self.assertEqual('session', adap.session) self.assertEqual('auth', adap.auth) + self.assertEqual('2.0', adap.version) + self.assertIsNone(adap.min_version) + self.assertIsNone(adap.max_version) + + def test_load_version_range(self): + self.conf_fx.config( + service_type='type', service_name='name', interface='iface', + region_name='region', endpoint_override='endpoint', + min_version='2.0', max_version='3.0', group=self.GROUP) + adap = loading.load_adapter_from_conf_options( + self.conf_fx.conf, self.GROUP, session='session', auth='auth') + self.assertEqual('type', adap.service_type) + self.assertEqual('name', adap.service_name) + self.assertEqual('iface', adap.interface) + self.assertEqual('region', adap.region_name) + self.assertEqual('endpoint', adap.endpoint_override) + self.assertEqual('session', adap.session) + self.assertEqual('auth', adap.auth) + self.assertIsNone(adap.version) + self.assertEqual('2.0', adap.min_version) + self.assertEqual('3.0', adap.max_version) + + def test_load_bad_version(self): + self.conf_fx.config( + service_type='type', service_name='name', interface='iface', + region_name='region', endpoint_override='endpoint', + version='2.0', min_version='2.0', max_version='3.0', + group=self.GROUP) + + self.assertRaises( + TypeError, + loading.load_adapter_from_conf_options, + self.conf_fx.conf, self.GROUP, session='session', auth='auth') def test_get_conf_options(self): opts = loading.get_adapter_conf_options() for opt in opts: self.assertIsInstance(opt, cfg.StrOpt) self.assertEqual({'service-type', 'service-name', 'interface', - 'region-name', 'endpoint-override'}, + 'region-name', 'endpoint-override', 'version', + 'min-version', 'max-version'}, {opt.name for opt in opts})