Merge "s3api: Delete multipart uploads via multi-delete" into stable/rocky
This commit is contained in:
commit
c08da08e08
|
@ -14,6 +14,7 @@
|
|||
# limitations under the License.
|
||||
|
||||
from swift.common.utils import public
|
||||
import json
|
||||
|
||||
from swift.common.middleware.s3api.controllers.base import Controller, \
|
||||
bucket_operation
|
||||
|
@ -104,7 +105,30 @@ class MultiObjectDeleteController(Controller):
|
|||
|
||||
try:
|
||||
query = req.gen_multipart_manifest_delete_query(self.app)
|
||||
req.get_response(self.app, method='DELETE', query=query)
|
||||
resp = req.get_response(self.app, method='DELETE', query=query,
|
||||
headers={'Accept': 'application/json'})
|
||||
# Have to read the response to actually do the SLO delete
|
||||
if query:
|
||||
try:
|
||||
delete_result = json.loads(resp.body)
|
||||
if delete_result['Errors']:
|
||||
# NB: bulk includes 404s in "Number Not Found",
|
||||
# not "Errors"
|
||||
msg_parts = [delete_result['Response Status']]
|
||||
msg_parts.extend(
|
||||
'%s: %s' % (obj, status)
|
||||
for obj, status in delete_result['Errors'])
|
||||
return key, {'code': 'SLODeleteError',
|
||||
'message': '\n'.join(msg_parts)}
|
||||
# else, all good
|
||||
except (ValueError, TypeError, KeyError):
|
||||
# Logs get all the gory details
|
||||
self.logger.exception(
|
||||
'Could not parse SLO delete response: %r',
|
||||
resp.body)
|
||||
# Client gets something more generic
|
||||
return key, {'code': 'SLODeleteError',
|
||||
'message': 'Unexpected swift response'}
|
||||
except NoSuchKey:
|
||||
pass
|
||||
except ErrorResponse as e:
|
||||
|
|
|
@ -32,7 +32,8 @@ from swift.common.middleware.s3api.utils import mktime
|
|||
|
||||
from test.functional.s3api import S3ApiBase
|
||||
from test.functional.s3api.s3_test_client import Connection
|
||||
from test.functional.s3api.utils import get_error_code, get_error_msg
|
||||
from test.functional.s3api.utils import get_error_code, get_error_msg, \
|
||||
calculate_md5
|
||||
|
||||
|
||||
def setUpModule():
|
||||
|
@ -844,6 +845,27 @@ class TestS3ApiMultiUploadSigV4(TestS3ApiMultiUpload):
|
|||
self.assertEqual(status, 200) # sanity
|
||||
self.assertEqual(content, body) # sanity
|
||||
|
||||
# Can delete it with DeleteMultipleObjects request
|
||||
elem = Element('Delete')
|
||||
SubElement(elem, 'Quiet').text = 'true'
|
||||
obj_elem = SubElement(elem, 'Object')
|
||||
SubElement(obj_elem, 'Key').text = key
|
||||
body = tostring(elem, use_s3ns=False)
|
||||
|
||||
status, headers, body = self.conn.make_request(
|
||||
'POST', bucket, body=body, query='delete',
|
||||
headers={'Content-MD5': calculate_md5(body)})
|
||||
self.assertEqual(status, 200)
|
||||
self.assertCommonResponseHeaders(headers)
|
||||
|
||||
status, headers, body = \
|
||||
self.conn.make_request('GET', bucket, key)
|
||||
self.assertEqual(status, 404) # sanity
|
||||
|
||||
# Now we can delete
|
||||
status, headers, body = \
|
||||
self.conn.make_request('DELETE', bucket)
|
||||
self.assertEqual(status, 204) # sanity
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest2.main()
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import json
|
||||
import unittest
|
||||
from datetime import datetime
|
||||
from hashlib import md5
|
||||
|
@ -64,8 +65,15 @@ class TestS3ApiMultiDelete(S3ApiTestCase):
|
|||
swob.HTTPNoContent, {}, None)
|
||||
self.swift.register('DELETE', '/v1/AUTH_test/bucket/Key2',
|
||||
swob.HTTPNotFound, {}, None)
|
||||
slo_delete_resp = {
|
||||
'Number Not Found': 0,
|
||||
'Response Status': '200 OK',
|
||||
'Errors': [],
|
||||
'Response Body': '',
|
||||
'Number Deleted': 8
|
||||
}
|
||||
self.swift.register('DELETE', '/v1/AUTH_test/bucket/Key3',
|
||||
swob.HTTPOk, {}, None)
|
||||
swob.HTTPOk, {}, json.dumps(slo_delete_resp))
|
||||
|
||||
elem = Element('Delete')
|
||||
for key in ['Key1', 'Key2', 'Key3']:
|
||||
|
|
Loading…
Reference in New Issue