Merge "Add ability to pass data to create_object"

This commit is contained in:
Zuul
2018-07-20 06:33:56 +00:00
committed by Gerrit Code Review
4 changed files with 95 additions and 7 deletions

View File

@@ -7429,7 +7429,7 @@ class OpenStackCloud(_normalize.Normalizer):
self, container, name, filename=None, self, container, name, filename=None,
md5=None, sha256=None, segment_size=None, md5=None, sha256=None, segment_size=None,
use_slo=True, metadata=None, use_slo=True, metadata=None,
generate_checksums=True, generate_checksums=None, data=None,
**headers): **headers):
"""Create a file object. """Create a file object.
@@ -7439,7 +7439,9 @@ class OpenStackCloud(_normalize.Normalizer):
This container will be created if it does not exist already. This container will be created if it does not exist already.
:param name: Name for the object within the container. :param name: Name for the object within the container.
:param filename: The path to the local file whose contents will be :param filename: The path to the local file whose contents will be
uploaded. uploaded. Mutually exclusive with data.
:param data: The content to upload to the object. Mutually exclusive
with filename.
:param md5: A hexadecimal md5 of the file. (Optional), if it is known :param md5: A hexadecimal md5 of the file. (Optional), if it is known
and can be passed here, it will save repeating the expensive md5 and can be passed here, it will save repeating the expensive md5
process. It is assumed to be accurate. process. It is assumed to be accurate.
@@ -7462,10 +7464,25 @@ class OpenStackCloud(_normalize.Normalizer):
:raises: ``OpenStackCloudException`` on operation error. :raises: ``OpenStackCloudException`` on operation error.
""" """
if data is not None and filename:
raise ValueError(
"Both filename and data given. Please choose one.")
if data is not None and not name:
raise ValueError(
"name is a required parameter when data is given")
if data is not None and generate_checksums:
raise ValueError(
"checksums cannot be generated with data parameter")
if generate_checksums is None:
if data is not None:
generate_checksums = False
else:
generate_checksums = True
if not metadata: if not metadata:
metadata = {} metadata = {}
if not filename: if not filename and data is None:
filename = name filename = name
# segment_size gets used as a step value in a range call, so needs # segment_size gets used as a step value in a range call, so needs
@@ -7473,7 +7490,10 @@ class OpenStackCloud(_normalize.Normalizer):
if segment_size: if segment_size:
segment_size = int(segment_size) segment_size = int(segment_size)
segment_size = self.get_object_segment_size(segment_size) segment_size = self.get_object_segment_size(segment_size)
if filename:
file_size = os.path.getsize(filename) file_size = os.path.getsize(filename)
else:
file_size = len(data)
if generate_checksums and (md5 is None or sha256 is None): if generate_checksums and (md5 is None or sha256 is None):
(md5, sha256) = self._get_file_hashes(filename) (md5, sha256) = self._get_file_hashes(filename)
@@ -7487,10 +7507,17 @@ class OpenStackCloud(_normalize.Normalizer):
# On some clouds this is not necessary. On others it is. I'm confused. # On some clouds this is not necessary. On others it is. I'm confused.
self.create_container(container) self.create_container(container)
endpoint = '{container}/{name}'.format(container=container, name=name)
if data is not None:
self.log.debug(
"swift uploading data to %(endpoint)s",
{'endpoint': endpoint})
return self._upload_object_data(endpoint, data, headers)
if self.is_object_stale(container, name, filename, md5, sha256): if self.is_object_stale(container, name, filename, md5, sha256):
endpoint = '{container}/{name}'.format(
container=container, name=name)
self.log.debug( self.log.debug(
"swift uploading %(filename)s to %(endpoint)s", "swift uploading %(filename)s to %(endpoint)s",
{'filename': filename, 'endpoint': endpoint}) {'filename': filename, 'endpoint': endpoint})
@@ -7502,6 +7529,10 @@ class OpenStackCloud(_normalize.Normalizer):
endpoint, filename, headers, endpoint, filename, headers,
file_size, segment_size, use_slo) file_size, segment_size, use_slo)
def _upload_object_data(self, endpoint, data, headers):
return self._object_store_client.put(
endpoint, headers=headers, data=data)
def _upload_object(self, endpoint, filename, headers): def _upload_object(self, endpoint, filename, headers):
return self._object_store_client.put( return self._object_store_client.put(
endpoint, headers=headers, data=open(filename, 'r')) endpoint, headers=headers, data=open(filename, 'r'))

View File

@@ -594,7 +594,7 @@ class TestCase(base.TestCase):
key = '{method}|{uri}|{params}'.format( key = '{method}|{uri}|{params}'.format(
method=method, uri=uri, params=kw_params) method=method, uri=uri, params=kw_params)
validate = to_mock.pop('validate', {}) validate = to_mock.pop('validate', {})
valid_keys = set(['json', 'headers', 'params']) valid_keys = set(['json', 'headers', 'params', 'data'])
invalid_keys = set(validate.keys()) - valid_keys invalid_keys = set(validate.keys()) - valid_keys
if invalid_keys: if invalid_keys:
raise TypeError( raise TypeError(

View File

@@ -950,3 +950,55 @@ class TestObjectUploads(BaseTestObject):
generate_checksums=False) generate_checksums=False)
self.assert_calls() self.assert_calls()
def test_create_object_data(self):
self.register_uris([
dict(method='GET',
uri='https://object-store.example.com/info',
json=dict(
swift={'max_file_size': 1000},
slo={'min_segment_size': 500})),
dict(method='HEAD',
uri='{endpoint}/{container}'.format(
endpoint=self.endpoint,
container=self.container),
status_code=404),
dict(method='PUT',
uri='{endpoint}/{container}'.format(
endpoint=self.endpoint, container=self.container),
status_code=201,
headers={
'Date': 'Fri, 16 Dec 2016 18:21:20 GMT',
'Content-Length': '0',
'Content-Type': 'text/html; charset=UTF-8',
}),
dict(method='HEAD',
uri='{endpoint}/{container}'.format(
endpoint=self.endpoint, container=self.container),
headers={
'Content-Length': '0',
'X-Container-Object-Count': '0',
'Accept-Ranges': 'bytes',
'X-Storage-Policy': 'Policy-0',
'Date': 'Fri, 16 Dec 2016 18:29:05 GMT',
'X-Timestamp': '1481912480.41664',
'X-Trans-Id': 'tx60ec128d9dbf44b9add68-0058543271dfw1',
'X-Container-Bytes-Used': '0',
'Content-Type': 'text/plain; charset=utf-8'}),
dict(method='PUT',
uri='{endpoint}/{container}/{object}'.format(
endpoint=self.endpoint,
container=self.container, object=self.object),
status_code=201,
validate=dict(
headers={},
data=self.content,
)),
])
self.cloud.create_object(
container=self.container, name=self.object,
data=self.content)
self.assert_calls()

View File

@@ -0,0 +1,5 @@
---
features:
- |
Add a data parameter to ``openstack.connection.Connection.create_object``
so that data can be passed in directly instead of through a file.