Fix create, update or delete container metadata method

Swift provides a single API to Create, Update or Delete
container metadata.
With different headers or values those operation can be
achieved. For example:
- delete metadata by passing metadata without value
- update metadata by passing updated value with same key

Details- https://developer.openstack.org/api-ref/object-store/?expanded=create-update-or-delete-container-metadata-detail

But current service client for account has 2 different
method for these operation. update_, delete_

To make it consistent with other service client and to have
single service client method per API, this patch merge those
methods.

Partially implements blueprint consistent-service-method-names

Change-Id: I75e40fc5c19d5b56d2be5f68e6cdb41bda4f9595
This commit is contained in:
ghanshyam 2017-09-14 20:19:15 +03:00
parent 871b1a837e
commit 7351cbdc09
9 changed files with 109 additions and 94 deletions

View File

@ -41,10 +41,11 @@ class ObjectTestACLs(base.BaseObjectTest):
tenant_name = self.os_roles_operator_alt.credentials.tenant_name
username = self.os_roles_operator_alt.credentials.username
cont_headers = {'X-Container-Read': tenant_name + ':' + username}
container_client = self.os_roles_operator.container_client
resp_meta, _ = (
self.os_roles_operator.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix=''))
container_client.create_update_or_delete_container_metadata(
self.container_name, create_update_metadata=cont_headers,
create_update_metadata_prefix=''))
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
object_name = data_utils.rand_name(name='Object')
@ -68,10 +69,11 @@ class ObjectTestACLs(base.BaseObjectTest):
tenant_name = self.os_roles_operator_alt.credentials.tenant_name
username = self.os_roles_operator_alt.credentials.username
cont_headers = {'X-Container-Write': tenant_name + ':' + username}
container_client = self.os_roles_operator.container_client
resp_meta, _ = (
self.os_roles_operator.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix=''))
container_client.create_update_or_delete_container_metadata(
self.container_name, create_update_metadata=cont_headers,
create_update_metadata_prefix=''))
self.assertHeaders(resp_meta, 'Container', 'POST')
# set alternative authentication data; cannot simply use the
# other object client.

View File

@ -133,9 +133,10 @@ class ObjectACLsNegativeTest(base.BaseObjectTest):
# attempt to read object using non-authorized user
# update X-Container-Read metadata ACL
cont_headers = {'X-Container-Read': 'badtenant:baduser'}
resp_meta, _ = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
resp_meta, _ = (
self.container_client.create_update_or_delete_container_metadata(
self.container_name, create_update_metadata=cont_headers,
create_update_metadata_prefix=''))
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
object_name = data_utils.rand_name(name='Object')
@ -157,9 +158,10 @@ class ObjectACLsNegativeTest(base.BaseObjectTest):
# attempt to write object using non-authorized user
# update X-Container-Write metadata ACL
cont_headers = {'X-Container-Write': 'badtenant:baduser'}
resp_meta, _ = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
resp_meta, _ = (
self.container_client.create_update_or_delete_container_metadata(
self.container_name, create_update_metadata=cont_headers,
create_update_metadata_prefix=''))
self.assertHeaders(resp_meta, 'Container', 'POST')
# Trying to write the object without rights
self.object_client.auth_provider.set_alt_auth_data(
@ -182,9 +184,10 @@ class ObjectACLsNegativeTest(base.BaseObjectTest):
cont_headers = {'X-Container-Read':
tenant_name + ':' + username,
'X-Container-Write': ''}
resp_meta, _ = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
resp_meta, _ = (
self.container_client.create_update_or_delete_container_metadata(
self.container_name, create_update_metadata=cont_headers,
create_update_metadata_prefix=''))
self.assertHeaders(resp_meta, 'Container', 'POST')
# Trying to write the object without write rights
self.object_client.auth_provider.set_alt_auth_data(
@ -207,9 +210,10 @@ class ObjectACLsNegativeTest(base.BaseObjectTest):
cont_headers = {'X-Container-Read':
tenant_name + ':' + username,
'X-Container-Write': ''}
resp_meta, _ = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
resp_meta, _ = (
self.container_client.create_update_or_delete_container_metadata(
self.container_name, create_update_metadata=cont_headers,
create_update_metadata_prefix=''))
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
object_name = data_utils.rand_name(name='Object')

View File

@ -40,8 +40,8 @@ class ContainerQuotasTest(base.BaseObjectTest):
self.container_name = self.create_container()
metadata = {"quota-bytes": str(QUOTA_BYTES),
"quota-count": str(QUOTA_COUNT), }
self.container_client.update_container_metadata(
self.container_name, metadata)
self.container_client.create_update_or_delete_container_metadata(
self.container_name, create_update_metadata=metadata)
def tearDown(self):
"""Cleans the container of any object after each test."""

View File

@ -277,9 +277,9 @@ class ContainerTest(base.BaseObjectTest):
container_name = self.create_container()
metadata = {'name': 'Pictures'}
self.container_client.update_container_metadata(
self.container_client.create_update_or_delete_container_metadata(
container_name,
metadata=metadata)
create_update_metadata=metadata)
resp, _ = self.container_client.list_container_metadata(
container_name)
@ -307,10 +307,11 @@ class ContainerTest(base.BaseObjectTest):
self.containers.append(container_name)
metadata_2 = {'test-container-meta2': 'Meta2'}
resp, _ = self.container_client.update_container_metadata(
resp, _ = (
self.container_client.create_update_or_delete_container_metadata(
container_name,
metadata=metadata_2,
remove_metadata=metadata_1)
create_update_metadata=metadata_2,
delete_metadata=metadata_1))
self.assertHeaders(resp, 'Container', 'POST')
resp, _ = self.container_client.list_container_metadata(
@ -326,9 +327,10 @@ class ContainerTest(base.BaseObjectTest):
container_name = self.create_container()
metadata = {'test-container-meta1': 'Meta1'}
resp, _ = self.container_client.update_container_metadata(
resp, _ = (
self.container_client.create_update_or_delete_container_metadata(
container_name,
metadata=metadata)
create_update_metadata=metadata))
self.assertHeaders(resp, 'Container', 'POST')
resp, _ = self.container_client.list_container_metadata(
@ -346,9 +348,10 @@ class ContainerTest(base.BaseObjectTest):
metadata=metadata)
self.containers.append(container_name)
resp, _ = self.container_client.delete_container_metadata(
resp, _ = (
self.container_client.create_update_or_delete_container_metadata(
container_name,
metadata=metadata)
delete_metadata=metadata))
self.assertHeaders(resp, 'Container', 'POST')
resp, _ = self.container_client.list_container_metadata(
@ -361,9 +364,10 @@ class ContainerTest(base.BaseObjectTest):
container_name = self.create_container()
metadata = {'test-container-meta1': ''}
resp, _ = self.container_client.update_container_metadata(
resp, _ = (
self.container_client.create_update_or_delete_container_metadata(
container_name,
metadata=metadata)
create_update_metadata=metadata))
self.assertHeaders(resp, 'Container', 'POST')
resp, _ = self.container_client.list_container_metadata(
@ -380,9 +384,10 @@ class ContainerTest(base.BaseObjectTest):
self.containers.append(container_name)
metadata = {'test-container-meta1': ''}
resp, _ = self.container_client.delete_container_metadata(
resp, _ = (
self.container_client.create_update_or_delete_container_metadata(
container_name,
metadata=metadata)
delete_metadata=metadata))
self.assertHeaders(resp, 'Container', 'POST')
resp, _ = self.container_client.list_container_metadata(container_name)

View File

@ -120,9 +120,10 @@ class ContainerNegativeTest(base.BaseObjectTest):
# Attempts to update metadata using a nonexistent container name.
metadata = {'animal': 'penguin'}
self.assertRaises(exceptions.NotFound,
self.container_client.update_container_metadata,
'nonexistent_container_name', metadata)
self.assertRaises(
exceptions.NotFound,
self.container_client.create_update_or_delete_container_metadata,
'nonexistent_container_name', create_update_metadata=metadata)
@decorators.attr(type=["negative"])
@decorators.idempotent_id('65387dbf-a0e2-4aac-9ddc-16eb3f1f69ba')
@ -130,9 +131,10 @@ class ContainerNegativeTest(base.BaseObjectTest):
# Attempts to delete metadata using a nonexistent container name.
metadata = {'animal': 'penguin'}
self.assertRaises(exceptions.NotFound,
self.container_client.delete_container_metadata,
'nonexistent_container_name', metadata)
self.assertRaises(
exceptions.NotFound,
self.container_client.create_update_or_delete_container_metadata,
'nonexistent_container_name', delete_metadata=metadata)
@decorators.attr(type=["negative"])
@decorators.idempotent_id('14331d21-1e81-420a-beea-19cb5e5207f5')

View File

@ -34,10 +34,10 @@ class StaticWebTest(base.BaseObjectTest):
cls.object_name, cls.object_data = cls.create_object(
cls.container_name)
cls.container_client.update_container_metadata(
cls.container_client.create_update_or_delete_container_metadata(
cls.container_name,
metadata=headers_public_read_acl,
metadata_prefix="X-Container-")
create_update_metadata=headers_public_read_acl,
create_update_metadata_prefix="X-Container-")
@classmethod
def resource_cleanup(cls):
@ -49,8 +49,8 @@ class StaticWebTest(base.BaseObjectTest):
def test_web_index(self):
headers = {'web-index': self.object_name}
self.container_client.update_container_metadata(
self.container_name, metadata=headers)
self.container_client.create_update_or_delete_container_metadata(
self.container_name, create_update_metadata=headers)
# Maintain original headers, no auth added
self.account_client.auth_provider.set_alt_auth_data(
@ -68,8 +68,9 @@ class StaticWebTest(base.BaseObjectTest):
self.assertEqual(body, self.object_data)
# clean up before exiting
self.container_client.update_container_metadata(self.container_name,
{'web-index': ""})
self.container_client.create_update_or_delete_container_metadata(
self.container_name,
create_update_metadata={'web-index': ""})
_, body = self.container_client.list_container_metadata(
self.container_name)
@ -80,8 +81,8 @@ class StaticWebTest(base.BaseObjectTest):
def test_web_listing(self):
headers = {'web-listings': 'true'}
self.container_client.update_container_metadata(
self.container_name, metadata=headers)
self.container_client.create_update_or_delete_container_metadata(
self.container_name, create_update_metadata=headers)
# test GET on http://account_url/container_name
# we should retrieve a listing of objects
@ -100,9 +101,9 @@ class StaticWebTest(base.BaseObjectTest):
self.assertIn(self.object_name, body.decode())
# clean up before exiting
self.container_client.update_container_metadata(self.container_name,
{'web-listings': ""})
self.container_client.create_update_or_delete_container_metadata(
self.container_name,
create_update_metadata={'web-listings': ""})
_, body = self.container_client.list_container_metadata(
self.container_name)
self.assertNotIn('x-container-meta-web-listings', body)
@ -113,8 +114,8 @@ class StaticWebTest(base.BaseObjectTest):
headers = {'web-listings': 'true',
'web-listings-css': 'listings.css'}
self.container_client.update_container_metadata(
self.container_name, metadata=headers)
self.container_client.create_update_or_delete_container_metadata(
self.container_name, create_update_metadata=headers)
# Maintain original headers, no auth added
self.account_client.auth_provider.set_alt_auth_data(
@ -136,8 +137,8 @@ class StaticWebTest(base.BaseObjectTest):
headers = {'web-listings': 'true',
'web-error': self.object_name}
self.container_client.update_container_metadata(
self.container_name, metadata=headers)
self.container_client.create_update_or_delete_container_metadata(
self.container_name, create_update_metadata=headers)
# Create object to return when requested object not found
object_name_404 = "404" + self.object_name

View File

@ -990,8 +990,11 @@ class PublicObjectTest(base.BaseObjectTest):
# update container metadata to make it publicly readable
cont_headers = {'X-Container-Read': '.r:*,.rlistings'}
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers, metadata_prefix='')
resp_meta, body = (
self.container_client.create_update_or_delete_container_metadata(
self.container_name,
create_update_metadata=cont_headers,
create_update_metadata_prefix=''))
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object
@ -1025,9 +1028,10 @@ class PublicObjectTest(base.BaseObjectTest):
# make container public-readable and access an object in it using
# another user's credentials
cont_headers = {'X-Container-Read': '.r:*,.rlistings'}
resp_meta, body = self.container_client.update_container_metadata(
self.container_name, metadata=cont_headers,
metadata_prefix='')
resp_meta, body = (
self.container_client.create_update_or_delete_container_metadata(
self.container_name, create_update_metadata=cont_headers,
create_update_metadata_prefix=''))
self.assertHeaders(resp_meta, 'Container', 'POST')
# create object

View File

@ -1367,8 +1367,8 @@ class ObjectStorageScenarioTest(ScenarioTest):
def change_container_acl(self, container_name, acl):
metadata_param = {'metadata_prefix': 'x-container-',
'metadata': {'read': acl}}
self.container_client.update_container_metadata(container_name,
**metadata_param)
self.container_client.create_update_or_delete_container_metadata(
container_name, create_update_metadata=metadata_param)
resp, _ = self.container_client.list_container_metadata(container_name)
self.assertEqual(resp['x-container-read'], acl)

View File

@ -55,40 +55,37 @@ class ContainerClient(rest_client.RestClient):
self.expected_success(204, resp.status)
return resp, body
def update_container_metadata(
def create_update_or_delete_container_metadata(
self, container_name,
metadata=None,
remove_metadata=None,
metadata_prefix='X-Container-Meta-',
remove_metadata_prefix='X-Remove-Container-Meta-'):
"""Updates arbitrary metadata on container."""
create_update_metadata=None,
delete_metadata=None,
create_update_metadata_prefix='X-Container-Meta-',
delete_metadata_prefix='X-Remove-Container-Meta-'):
"""Creates, Updates or deletes an containter metadata entry.
Container Metadata can be created, updated or deleted based on
metadata header or value. For detailed info, please refer to the
official API reference:
https://developer.openstack.org/api-ref/object-store/#create-update-or-delete-container-metadata
"""
url = str(container_name)
headers = {}
if create_update_metadata:
for key in create_update_metadata:
metadata_header_name = create_update_metadata_prefix + key
headers[metadata_header_name] = create_update_metadata[key]
if delete_metadata:
for key in delete_metadata:
headers[delete_metadata_prefix + key] = delete_metadata[key]
if metadata is not None:
for key in metadata:
headers[metadata_prefix + key] = metadata[key]
if remove_metadata is not None:
for key in remove_metadata:
headers[remove_metadata_prefix + key] = remove_metadata[key]
resp, body = self.post(url, body=None, headers=headers)
resp, body = self.post(url, headers=headers, body=None)
self.expected_success(204, resp.status)
return resp, body
def delete_container_metadata(self, container_name, metadata,
metadata_prefix='X-Remove-Container-Meta-'):
"""Deletes arbitrary metadata on container."""
url = str(container_name)
headers = {}
if metadata is not None:
for item in metadata:
headers[metadata_prefix + item] = metadata[item]
resp, body = self.post(url, body=None, headers=headers)
self.expected_success(204, resp.status)
return resp, body
update_container_metadata = debtcollector.moves.moved_function(
create_update_or_delete_container_metadata,
'update_container_metadata', __name__,
version='Queens', removal_version='Rocky')
def list_container_metadata(self, container_name):
"""List all container metadata."""