s3api: Fix (async) multi-delete of MPUs

Change-Id: I2347a73ff23c5c7d415f23d864fc29147e4a1754
This commit is contained in:
Tim Burke
2021-07-29 15:04:34 -07:00
parent 5759072d25
commit 61dd2ee44a
3 changed files with 24 additions and 9 deletions

View File

@@ -17,6 +17,7 @@ import copy
import json import json
from swift.common.constraints import MAX_OBJECT_NAME_LENGTH from swift.common.constraints import MAX_OBJECT_NAME_LENGTH
from swift.common.http import HTTP_NO_CONTENT
from swift.common.utils import public, StreamingPile, get_swift_info from swift.common.utils import public, StreamingPile, get_swift_info
from swift.common.middleware.s3api.controllers.base import Controller, \ from swift.common.middleware.s3api.controllers.base import Controller, \
@@ -127,8 +128,11 @@ class MultiObjectDeleteController(Controller):
resp = req.get_response(self.app, method='DELETE', query=query, resp = req.get_response(self.app, method='DELETE', query=query,
headers={'Accept': 'application/json'}) headers={'Accept': 'application/json'})
# Have to read the response to actually do the SLO delete # If async segment cleanup is available, we expect to get
if query.get('multipart-manifest'): # back a 204; otherwise, the delete is synchronous and we
# have to read the response to actually do the SLO delete
if query.get('multipart-manifest') and \
resp.status_int != HTTP_NO_CONTENT:
try: try:
delete_result = json.loads(resp.body) delete_result = json.loads(resp.body)
if delete_result['Errors']: if delete_result['Errors']:

View File

@@ -62,14 +62,14 @@ class TestS3ApiMultiDelete(S3ApiTestCase):
@s3acl @s3acl
def test_object_multi_DELETE(self): def test_object_multi_DELETE(self):
self.swift.register('HEAD', '/v1/AUTH_test/bucket/Key3',
swob.HTTPOk,
{'x-static-large-object': 'True'},
None)
self.swift.register('DELETE', '/v1/AUTH_test/bucket/Key1', self.swift.register('DELETE', '/v1/AUTH_test/bucket/Key1',
swob.HTTPNoContent, {}, None) swob.HTTPNoContent, {}, None)
self.swift.register('DELETE', '/v1/AUTH_test/bucket/Key2', self.swift.register('DELETE', '/v1/AUTH_test/bucket/Key2',
swob.HTTPNotFound, {}, None) swob.HTTPNotFound, {}, None)
self.swift.register('HEAD', '/v1/AUTH_test/bucket/Key3',
swob.HTTPOk,
{'x-static-large-object': 'True'},
None)
slo_delete_resp = { slo_delete_resp = {
'Number Not Found': 0, 'Number Not Found': 0,
'Response Status': '200 OK', 'Response Status': '200 OK',
@@ -79,9 +79,16 @@ class TestS3ApiMultiDelete(S3ApiTestCase):
} }
self.swift.register('DELETE', '/v1/AUTH_test/bucket/Key3', self.swift.register('DELETE', '/v1/AUTH_test/bucket/Key3',
swob.HTTPOk, {}, json.dumps(slo_delete_resp)) swob.HTTPOk, {}, json.dumps(slo_delete_resp))
self.swift.register('HEAD', '/v1/AUTH_test/bucket/Key4',
swob.HTTPOk,
{'x-static-large-object': 'True',
'x-object-sysmeta-s3api-etag': 'some-etag'},
None)
self.swift.register('DELETE', '/v1/AUTH_test/bucket/Key4',
swob.HTTPNoContent, {}, None)
elem = Element('Delete') elem = Element('Delete')
for key in ['Key1', 'Key2', 'Key3']: for key in ['Key1', 'Key2', 'Key3', 'Key4']:
obj = SubElement(elem, 'Object') obj = SubElement(elem, 'Object')
SubElement(obj, 'Key').text = key SubElement(obj, 'Key').text = key
body = tostring(elem, use_s3ns=False) body = tostring(elem, use_s3ns=False)
@@ -99,7 +106,8 @@ class TestS3ApiMultiDelete(S3ApiTestCase):
self.assertEqual(status.split()[0], '200') self.assertEqual(status.split()[0], '200')
elem = fromstring(body) elem = fromstring(body)
self.assertEqual(len(elem.findall('Deleted')), 3) self.assertEqual(len(elem.findall('Deleted')), 4)
self.assertEqual(len(elem.findall('Error')), 0)
self.assertEqual(self.swift.calls, [ self.assertEqual(self.swift.calls, [
('HEAD', '/v1/AUTH_test/bucket'), ('HEAD', '/v1/AUTH_test/bucket'),
('HEAD', '/v1/AUTH_test/bucket/Key1?symlink=get'), ('HEAD', '/v1/AUTH_test/bucket/Key1?symlink=get'),
@@ -108,6 +116,9 @@ class TestS3ApiMultiDelete(S3ApiTestCase):
('DELETE', '/v1/AUTH_test/bucket/Key2'), ('DELETE', '/v1/AUTH_test/bucket/Key2'),
('HEAD', '/v1/AUTH_test/bucket/Key3?symlink=get'), ('HEAD', '/v1/AUTH_test/bucket/Key3?symlink=get'),
('DELETE', '/v1/AUTH_test/bucket/Key3?multipart-manifest=delete'), ('DELETE', '/v1/AUTH_test/bucket/Key3?multipart-manifest=delete'),
('HEAD', '/v1/AUTH_test/bucket/Key4?symlink=get'),
('DELETE',
'/v1/AUTH_test/bucket/Key4?async=on&multipart-manifest=delete'),
]) ])
@s3acl @s3acl

View File

@@ -1572,7 +1572,7 @@ class TestS3ApiObj(S3ApiTestCase):
'x-object-sysmeta-s3api-etag': 's3-style-etag'}, 'x-object-sysmeta-s3api-etag': 's3-style-etag'},
None) None)
self.swift.register('DELETE', '/v1/AUTH_test/bucket/object', self.swift.register('DELETE', '/v1/AUTH_test/bucket/object',
swob.HTTPOk, {}, '<SLO delete results>') swob.HTTPNoContent, {}, '')
req = Request.blank('/bucket/object', req = Request.blank('/bucket/object',
environ={'REQUEST_METHOD': 'DELETE'}, environ={'REQUEST_METHOD': 'DELETE'},
headers={'Authorization': 'AWS test:tester:hmac', headers={'Authorization': 'AWS test:tester:hmac',