summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2019-10-22 18:33:36 +0000
committerGerrit Code Review <review@openstack.org>2019-10-22 18:33:36 +0000
commitc08da08e08570ab80ea827138a276abe5e89c033 (patch)
tree06e0d91f6fcdbaf08ecd12d99c599db3c80c0473
parent9d6514ac1a941bd3f710f36a5a9250c4ff003055 (diff)
parent9bcce90be0c0d8a9cf0d2bb03cc02fb5ceb62970 (diff)
downloadswift-c08da08e08570ab80ea827138a276abe5e89c033.tar.gz
Merge "s3api: Delete multipart uploads via multi-delete" into stable/rocky
-rw-r--r--swift/common/middleware/s3api/controllers/multi_delete.py26
-rw-r--r--test/functional/s3api/test_multi_upload.py24
-rw-r--r--test/unit/common/middleware/s3api/test_multi_delete.py10
3 files changed, 57 insertions, 3 deletions
diff --git a/swift/common/middleware/s3api/controllers/multi_delete.py b/swift/common/middleware/s3api/controllers/multi_delete.py
index a7e95a7bd..682b7bb36 100644
--- a/swift/common/middleware/s3api/controllers/multi_delete.py
+++ b/swift/common/middleware/s3api/controllers/multi_delete.py
@@ -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:
diff --git a/test/functional/s3api/test_multi_upload.py b/test/functional/s3api/test_multi_upload.py
index 33b6cadfe..0aaa7b8fd 100644
--- a/test/functional/s3api/test_multi_upload.py
+++ b/test/functional/s3api/test_multi_upload.py
@@ -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()
diff --git a/test/unit/common/middleware/s3api/test_multi_delete.py b/test/unit/common/middleware/s3api/test_multi_delete.py
index 91f8e8d22..155227ce5 100644
--- a/test/unit/common/middleware/s3api/test_multi_delete.py
+++ b/test/unit/common/middleware/s3api/test_multi_delete.py
@@ -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']: