Merge "Add microversioning support for httpclient"
This commit is contained in:
		@@ -34,6 +34,7 @@ USER_AGENT = 'python-magnumclient'
 | 
			
		||||
CHUNKSIZE = 1024 * 64  # 64kB
 | 
			
		||||
 | 
			
		||||
API_VERSION = '/v1'
 | 
			
		||||
DEFAULT_API_VERSION = 'latest'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def _extract_error_json(body):
 | 
			
		||||
@@ -51,8 +52,11 @@ def _extract_error_json(body):
 | 
			
		||||
        else:
 | 
			
		||||
            error_body = body_json['errors'][0]
 | 
			
		||||
            raw_msg = error_body['title']
 | 
			
		||||
            error_json = {'faultstring': error_body['title'],
 | 
			
		||||
                          'debuginfo': error_body['detail']}
 | 
			
		||||
            error_json = {'faultstring': error_body['title']}
 | 
			
		||||
            if 'detail' in error_body:
 | 
			
		||||
                error_json['debuginfo'] = error_body['detail']
 | 
			
		||||
            elif 'description' in error_body:
 | 
			
		||||
                error_json['debuginfo'] = error_body['description']
 | 
			
		||||
 | 
			
		||||
    except ValueError:
 | 
			
		||||
        return {}
 | 
			
		||||
@@ -62,10 +66,11 @@ def _extract_error_json(body):
 | 
			
		||||
 | 
			
		||||
class HTTPClient(object):
 | 
			
		||||
 | 
			
		||||
    def __init__(self, endpoint, **kwargs):
 | 
			
		||||
    def __init__(self, endpoint, api_version=DEFAULT_API_VERSION, **kwargs):
 | 
			
		||||
        self.endpoint = endpoint
 | 
			
		||||
        self.auth_token = kwargs.get('token')
 | 
			
		||||
        self.auth_ref = kwargs.get('auth_ref')
 | 
			
		||||
        self.api_version = kwargs.get('api_version')
 | 
			
		||||
        self.connection_params = self.get_connection_params(endpoint, **kwargs)
 | 
			
		||||
 | 
			
		||||
    @staticmethod
 | 
			
		||||
@@ -152,6 +157,10 @@ class HTTPClient(object):
 | 
			
		||||
        # Copy the kwargs so we can reuse the original in case of redirects
 | 
			
		||||
        kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {}))
 | 
			
		||||
        kwargs['headers'].setdefault('User-Agent', USER_AGENT)
 | 
			
		||||
        if self.api_version:
 | 
			
		||||
            version_string = 'container-infra %s' % self.api_version
 | 
			
		||||
            kwargs['headers'].setdefault(
 | 
			
		||||
                'OpenStack-API-Version', version_string)
 | 
			
		||||
        if self.auth_token:
 | 
			
		||||
            kwargs['headers'].setdefault('X-Auth-Token', self.auth_token)
 | 
			
		||||
 | 
			
		||||
@@ -304,7 +313,10 @@ class VerifiedHTTPSConnection(six.moves.http_client.HTTPSConnection):
 | 
			
		||||
class SessionClient(adapter.LegacyJsonAdapter):
 | 
			
		||||
    """HTTP client based on Keystone client session."""
 | 
			
		||||
 | 
			
		||||
    def __init__(self, user_agent=USER_AGENT, logger=LOG, *args, **kwargs):
 | 
			
		||||
    def __init__(self, user_agent=USER_AGENT, logger=LOG,
 | 
			
		||||
                 api_version=DEFAULT_API_VERSION, *args, **kwargs):
 | 
			
		||||
        self.user_agent = USER_AGENT
 | 
			
		||||
        self.api_version = api_version
 | 
			
		||||
        super(SessionClient, self).__init__(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def _http_request(self, url, method, **kwargs):
 | 
			
		||||
@@ -315,6 +327,14 @@ class SessionClient(adapter.LegacyJsonAdapter):
 | 
			
		||||
        kwargs.setdefault('auth', self.auth)
 | 
			
		||||
        kwargs.setdefault('endpoint_override', self.endpoint_override)
 | 
			
		||||
 | 
			
		||||
        # Copy the kwargs so we can reuse the original in case of redirects
 | 
			
		||||
        kwargs['headers'] = copy.deepcopy(kwargs.get('headers', {}))
 | 
			
		||||
        kwargs['headers'].setdefault('User-Agent', self.user_agent)
 | 
			
		||||
        if self.api_version:
 | 
			
		||||
            version_string = 'container-infra %s' % self.api_version
 | 
			
		||||
            kwargs['headers'].setdefault(
 | 
			
		||||
                'OpenStack-API-Version', version_string)
 | 
			
		||||
 | 
			
		||||
        endpoint_filter = kwargs.setdefault('endpoint_filter', {})
 | 
			
		||||
        endpoint_filter.setdefault('interface', self.interface)
 | 
			
		||||
        endpoint_filter.setdefault('service_type', self.service_type)
 | 
			
		||||
@@ -340,8 +360,6 @@ class SessionClient(adapter.LegacyJsonAdapter):
 | 
			
		||||
        kwargs.setdefault('headers', {})
 | 
			
		||||
        kwargs['headers'].setdefault('Content-Type', 'application/json')
 | 
			
		||||
        kwargs['headers'].setdefault('Accept', 'application/json')
 | 
			
		||||
        kwargs['headers'].setdefault(
 | 
			
		||||
            'OpenStack-API-Version', 'container-infra latest')
 | 
			
		||||
        if 'body' in kwargs:
 | 
			
		||||
            kwargs['data'] = json.dumps(kwargs.pop('body'))
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -55,7 +55,7 @@ from magnumclient.v1 import client as client_v1
 | 
			
		||||
from magnumclient.v1 import shell as shell_v1
 | 
			
		||||
from magnumclient import version
 | 
			
		||||
 | 
			
		||||
DEFAULT_API_VERSION = '1'
 | 
			
		||||
LATEST_API_VERSION = ('1', 'latest')
 | 
			
		||||
DEFAULT_INTERFACE = 'public'
 | 
			
		||||
DEFAULT_SERVICE_TYPE = 'container-infra'
 | 
			
		||||
 | 
			
		||||
@@ -386,7 +386,7 @@ class OpenStackMagnumShell(object):
 | 
			
		||||
                            metavar='<magnum-api-ver>',
 | 
			
		||||
                            default=cliutils.env(
 | 
			
		||||
                                'MAGNUM_API_VERSION',
 | 
			
		||||
                                default=DEFAULT_API_VERSION),
 | 
			
		||||
                                default='latest'),
 | 
			
		||||
                            help='Accepts "api", '
 | 
			
		||||
                                 'defaults to env[MAGNUM_API_VERSION].')
 | 
			
		||||
        parser.add_argument('--magnum_api_version',
 | 
			
		||||
@@ -429,7 +429,7 @@ class OpenStackMagnumShell(object):
 | 
			
		||||
 | 
			
		||||
        try:
 | 
			
		||||
            actions_modules = {
 | 
			
		||||
                '1': shell_v1.COMMAND_MODULES,
 | 
			
		||||
                '1': shell_v1.COMMAND_MODULES
 | 
			
		||||
            }[version]
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            actions_modules = shell_v1.COMMAND_MODULES
 | 
			
		||||
@@ -487,6 +487,34 @@ class OpenStackMagnumShell(object):
 | 
			
		||||
            logging.basicConfig(level=logging.CRITICAL,
 | 
			
		||||
                                format=streamformat)
 | 
			
		||||
 | 
			
		||||
    def _check_version(self, api_version):
 | 
			
		||||
        if api_version == 'latest':
 | 
			
		||||
            return LATEST_API_VERSION
 | 
			
		||||
        else:
 | 
			
		||||
            try:
 | 
			
		||||
                versions = tuple(int(i) for i in api_version.split('.'))
 | 
			
		||||
            except ValueError:
 | 
			
		||||
                versions = ()
 | 
			
		||||
            if len(versions) == 1:
 | 
			
		||||
                # Default value of magnum_api_version is '1'.
 | 
			
		||||
                # If user not specify the value of api version, not passing
 | 
			
		||||
                # headers at all.
 | 
			
		||||
                magnum_api_version = None
 | 
			
		||||
            elif len(versions) == 2:
 | 
			
		||||
                magnum_api_version = api_version
 | 
			
		||||
                # In the case of '1.0'
 | 
			
		||||
                if versions[1] == 0:
 | 
			
		||||
                    magnum_api_version = None
 | 
			
		||||
            else:
 | 
			
		||||
                msg = _("The requested API version %(ver)s is an unexpected "
 | 
			
		||||
                        "format. Acceptable formats are 'X', 'X.Y', or the "
 | 
			
		||||
                        "literal string '%(latest)s'."
 | 
			
		||||
                        ) % {'ver': api_version, 'latest': 'latest'}
 | 
			
		||||
                raise exc.CommandError(msg)
 | 
			
		||||
 | 
			
		||||
            api_major_version = versions[0]
 | 
			
		||||
            return (api_major_version, magnum_api_version)
 | 
			
		||||
 | 
			
		||||
    def main(self, argv):
 | 
			
		||||
 | 
			
		||||
        # NOTE(Christoph Jansen): With Python 3.4 argv somehow becomes a Map.
 | 
			
		||||
@@ -506,8 +534,12 @@ class OpenStackMagnumShell(object):
 | 
			
		||||
            spot = argv.index('--endpoint_type')
 | 
			
		||||
            argv[spot] = '--endpoint-type'
 | 
			
		||||
 | 
			
		||||
        # build available subcommands based on version
 | 
			
		||||
        (api_major_version, magnum_api_version) = (
 | 
			
		||||
            self._check_version(options.magnum_api_version))
 | 
			
		||||
 | 
			
		||||
        subcommand_parser = (
 | 
			
		||||
            self.get_subcommand_parser(options.magnum_api_version)
 | 
			
		||||
            self.get_subcommand_parser(api_major_version)
 | 
			
		||||
        )
 | 
			
		||||
        self.parser = subcommand_parser
 | 
			
		||||
 | 
			
		||||
@@ -566,7 +598,7 @@ class OpenStackMagnumShell(object):
 | 
			
		||||
        try:
 | 
			
		||||
            client = {
 | 
			
		||||
                '1': client_v1,
 | 
			
		||||
            }[options.magnum_api_version]
 | 
			
		||||
            }[api_major_version]
 | 
			
		||||
        except KeyError:
 | 
			
		||||
            client = client_v1
 | 
			
		||||
 | 
			
		||||
@@ -595,6 +627,7 @@ class OpenStackMagnumShell(object):
 | 
			
		||||
            magnum_url=args.os_endpoint_override,
 | 
			
		||||
            interface=args.os_interface,
 | 
			
		||||
            insecure=args.insecure,
 | 
			
		||||
            api_version=args.magnum_api_version,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        args.func(self.cs, args)
 | 
			
		||||
 
 | 
			
		||||
@@ -222,7 +222,8 @@ class ShellTest(utils.TestCase):
 | 
			
		||||
            'project_domain_id': None, 'project_domain_name': None,
 | 
			
		||||
            'region_name': None, 'service_type': 'container-infra',
 | 
			
		||||
            'user_id': None, 'username': 'username',
 | 
			
		||||
            'user_domain_id': None, 'user_domain_name': None
 | 
			
		||||
            'user_domain_id': None, 'user_domain_name': None,
 | 
			
		||||
            'api_version': 'latest'
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    @mock.patch('magnumclient.v1.client.Client')
 | 
			
		||||
 
 | 
			
		||||
@@ -51,6 +51,7 @@ class ClientInitializeTest(testtools.TestCase):
 | 
			
		||||
        kwargs = self._load_service_type_kwargs()
 | 
			
		||||
        kwargs['endpoint_override'] = None
 | 
			
		||||
        kwargs['session'] = session
 | 
			
		||||
        kwargs['api_version'] = None
 | 
			
		||||
 | 
			
		||||
        return kwargs
 | 
			
		||||
 | 
			
		||||
@@ -130,14 +131,17 @@ class ClientInitializeTest(testtools.TestCase):
 | 
			
		||||
                                  mock_http_client,):
 | 
			
		||||
        expected_token = 'expected_password'
 | 
			
		||||
        expected_magnum_url = 'expected_magnum_url'
 | 
			
		||||
        expected_api_version = 'expected_api_version'
 | 
			
		||||
        expected_kwargs = {'expected_key': 'expected_value'}
 | 
			
		||||
        client.Client(auth_token=expected_token,
 | 
			
		||||
                      magnum_url=expected_magnum_url,
 | 
			
		||||
                      api_version=expected_api_version,
 | 
			
		||||
                      **expected_kwargs)
 | 
			
		||||
 | 
			
		||||
        mock_http_client.assert_called_once_with(
 | 
			
		||||
            expected_magnum_url,
 | 
			
		||||
            token=expected_token,
 | 
			
		||||
            api_version=expected_api_version,
 | 
			
		||||
            **expected_kwargs)
 | 
			
		||||
 | 
			
		||||
    def _test_init_with_interface(self,
 | 
			
		||||
 
 | 
			
		||||
@@ -80,7 +80,8 @@ def _load_session_client(session=None, endpoint_override=None, username=None,
 | 
			
		||||
                         user_domain_name=None, project_domain_id=None,
 | 
			
		||||
                         project_domain_name=None, auth_token=None,
 | 
			
		||||
                         timeout=None, service_type=None, service_name=None,
 | 
			
		||||
                         interface=None, region_name=None, **kwargs):
 | 
			
		||||
                         interface=None, region_name=None, api_version=None,
 | 
			
		||||
                         **kwargs):
 | 
			
		||||
    if not session:
 | 
			
		||||
        session = _load_session(
 | 
			
		||||
            username=username,
 | 
			
		||||
@@ -115,6 +116,7 @@ def _load_session_client(session=None, endpoint_override=None, username=None,
 | 
			
		||||
        region_name=region_name,
 | 
			
		||||
        session=session,
 | 
			
		||||
        endpoint_override=endpoint_override,
 | 
			
		||||
        api_version=api_version,
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -128,7 +130,8 @@ class Client(object):
 | 
			
		||||
                 interface=None, service_name=None, insecure=False,
 | 
			
		||||
                 user_domain_id=None, user_domain_name=None,
 | 
			
		||||
                 project_domain_id=None, project_domain_name=None,
 | 
			
		||||
                 auth_token=None, timeout=600, **kwargs):
 | 
			
		||||
                 auth_token=None, timeout=600, api_version=None,
 | 
			
		||||
                 **kwargs):
 | 
			
		||||
 | 
			
		||||
        # We have to keep the api_key are for backwards compat, but let's
 | 
			
		||||
        # remove it from the rest of our code since it's not a keystone
 | 
			
		||||
@@ -158,6 +161,7 @@ class Client(object):
 | 
			
		||||
            self.http_client = httpclient.HTTPClient(
 | 
			
		||||
                endpoint_override,
 | 
			
		||||
                token=auth_token,
 | 
			
		||||
                api_version=api_version,
 | 
			
		||||
                **kwargs
 | 
			
		||||
            )
 | 
			
		||||
        else:
 | 
			
		||||
@@ -181,6 +185,7 @@ class Client(object):
 | 
			
		||||
                service_name=service_name,
 | 
			
		||||
                interface=interface,
 | 
			
		||||
                region_name=region_name,
 | 
			
		||||
                api_version=api_version,
 | 
			
		||||
                **kwargs
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user