diff --git a/openstack/cloud/openstackcloud.py b/openstack/cloud/openstackcloud.py index cf8c9fdcb..f075e862a 100755 --- a/openstack/cloud/openstackcloud.py +++ b/openstack/cloud/openstackcloud.py @@ -7417,6 +7417,35 @@ class OpenStackCloud(_normalize.Normalizer): {'container': container, 'name': name}) return False + def create_directory_marker_object(self, container, name, **headers): + """Create a zero-byte directory marker object + + .. note:: + + This method is not needed in most cases. Modern swift does not + require directory marker objects. However, some swift installs may + need these. + + When using swift Static Web and Web Listings to serve static content + one may need to create a zero-byte object to represent each + "directory". Doing so allows Web Listings to generate an index of the + objects inside of it, and allows Static Web to render index.html + "files" that are "inside" the directory. + + :param container: The name of the container. + :param name: Name for the directory marker object within the container. + :param headers: These will be passed through to the object creation + API as HTTP Headers. + """ + headers['content-type'] = 'application/directory' + + return self.create_object( + container, + name, + data='', + generate_checksums=False, + **headers) + def create_object( self, container, name, filename=None, md5=None, sha256=None, segment_size=None, diff --git a/openstack/tests/unit/cloud/test_object.py b/openstack/tests/unit/cloud/test_object.py index 6e08d52b6..448a30f77 100644 --- a/openstack/tests/unit/cloud/test_object.py +++ b/openstack/tests/unit/cloud/test_object.py @@ -470,6 +470,57 @@ class TestObjectUploads(BaseTestObject): self.assert_calls() + def test_create_directory_marker_object(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={ + 'content-type': 'application/directory', + })) + ]) + + self.cloud.create_directory_marker_object( + container=self.container, name=self.object) + + self.assert_calls() + def test_create_dynamic_large_object(self): max_file_size = 2 diff --git a/releasenotes/notes/create-object-directory-98e2cae175cc5082.yaml b/releasenotes/notes/create-object-directory-98e2cae175cc5082.yaml new file mode 100644 index 000000000..08cce1665 --- /dev/null +++ b/releasenotes/notes/create-object-directory-98e2cae175cc5082.yaml @@ -0,0 +1,7 @@ +--- +features: + - | + Added a ``create_directory_marker_object``' method to allow for easy + creation of zero-byte 'directory' marker objects. These are not needed + in most cases, but on some clouds they are used by Static + Web and Web Listings in swift to facilitate directory traversal.