From de981a324a8cd967c946812895ccdc0a7e4d6145 Mon Sep 17 00:00:00 2001 From: Monty Taylor Date: Thu, 26 Jul 2018 10:48:22 -0400 Subject: [PATCH] Add method for returning a raw response for an object Some use cases are complex and need access to the raw response object. Add a method, get_object_raw, which just returns the requests response object. python-requests needs at least 2.18 for Response to be a contextmanager. Change-Id: I03f31f33cbef93c30acf56de5e06acf0d721bc03 --- lower-constraints.txt | 2 +- openstack/cloud/openstackcloud.py | 95 ++++++++++++------- .../get-object-raw-e58284e59c81c8ef.yaml | 5 + 3 files changed, 67 insertions(+), 35 deletions(-) create mode 100644 releasenotes/notes/get-object-raw-e58284e59c81c8ef.yaml diff --git a/lower-constraints.txt b/lower-constraints.txt index d3253c46f..2842cdfd0 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -27,7 +27,7 @@ pbr==2.0.0 python-mimeparse==1.6.0 python-subunit==1.0.0 PyYAML==3.12 -requests==2.14.2 +requests==2.18.0 requests-mock==1.2.0 requestsexceptions==1.2.0 six==1.10.0 diff --git a/openstack/cloud/openstackcloud.py b/openstack/cloud/openstackcloud.py index 7a8e2c234..e655dae74 100755 --- a/openstack/cloud/openstackcloud.py +++ b/openstack/cloud/openstackcloud.py @@ -7779,53 +7779,80 @@ class OpenStackCloud(_normalize.Normalizer): return None raise + def get_object_raw(self, container, obj, query_string=None, stream=False): + """Get a raw response object for an object. + + :param string container: name of the container. + :param string obj: name of the object. + :param string query_string: + query args for uri. (delimiter, prefix, etc.) + :param bool stream: + Whether to stream the response or not. + + :returns: A `requests.Response` + :raises: OpenStackCloudException on operation error. + """ + endpoint = self._get_object_endpoint(container, obj, query_string) + try: + return self._object_store_client.get(endpoint, stream=stream) + except exc.OpenStackCloudHTTPError as e: + if e.response.status_code == 404: + return None + raise + + def _get_object_endpoint(self, container, obj, query_string): + endpoint = '{container}/{object}'.format( + container=container, object=obj) + if query_string: + endpoint = '{endpoint}?{query_string}'.format( + endpoint=endpoint, query_string=query_string) + return endpoint + def get_object(self, container, obj, query_string=None, resp_chunk_size=1024, outfile=None): """Get the headers and body of an object :param string container: name of the container. :param string obj: name of the object. - :param string query_string: query args for uri. - (delimiter, prefix, etc.) - :param int resp_chunk_size: chunk size of data to read. Only used - if the results are being written to a - file. (optional, defaults to 1k) - :param outfile: Write the object to a file instead of - returning the contents. If this option is - given, body in the return tuple will be None. outfile - can either be a file path given as a string, or a - File like object. + :param string query_string: + query args for uri. (delimiter, prefix, etc.) + :param int resp_chunk_size: + chunk size of data to read. Only used if the results are + being written to a file or stream is True. + (optional, defaults to 1k) + :param outfile: + Write the object to a file instead of returning the contents. + If this option is given, body in the return tuple will be None. + outfile can either be a file path given as a string, or a + File like object. :returns: Tuple (headers, body) of the object, or None if the object - is not found (404) + is not found (404). :raises: OpenStackCloudException on operation error. """ # TODO(mordred) implement resp_chunk_size + endpoint = self._get_object_endpoint(container, obj, query_string) try: - endpoint = '{container}/{object}'.format( - container=container, object=obj) - if query_string: - endpoint = '{endpoint}?{query_string}'.format( - endpoint=endpoint, query_string=query_string) - response = self._object_store_client.get( - endpoint, stream=True) - response_headers = { - k.lower(): v for k, v in response.headers.items()} - if outfile: - if isinstance(outfile, six.string_types): - outfile_handle = open(outfile, 'wb') + get_stream = (outfile is not None) + with self._object_store_client.get( + endpoint, stream=get_stream) as response: + response_headers = { + k.lower(): v for k, v in response.headers.items()} + if outfile: + if isinstance(outfile, six.string_types): + outfile_handle = open(outfile, 'wb') + else: + outfile_handle = outfile + for chunk in response.iter_content( + resp_chunk_size, decode_unicode=False): + outfile_handle.write(chunk) + if isinstance(outfile, six.string_types): + outfile_handle.close() + else: + outfile_handle.flush() + return (response_headers, None) else: - outfile_handle = outfile - for chunk in response.iter_content( - resp_chunk_size, decode_unicode=False): - outfile_handle.write(chunk) - if isinstance(outfile, six.string_types): - outfile_handle.close() - else: - outfile_handle.flush() - return (response_headers, None) - else: - return (response_headers, response.text) + return (response_headers, response.text) except exc.OpenStackCloudHTTPError as e: if e.response.status_code == 404: return None diff --git a/releasenotes/notes/get-object-raw-e58284e59c81c8ef.yaml b/releasenotes/notes/get-object-raw-e58284e59c81c8ef.yaml new file mode 100644 index 000000000..d854d8ea4 --- /dev/null +++ b/releasenotes/notes/get-object-raw-e58284e59c81c8ef.yaml @@ -0,0 +1,5 @@ +--- +features: + - | + Added ``get_object_raw`` method for downloading an object from swift + and returning a raw requests Response object.