s3api: Improve error message when bucket is not empty
When the versioning is enabled (or suspended), AWS specifies in the error message that all versions should be deleted. Change-Id: I3da9469a5cfed031a2cee85e1dfcd78bbe54695a
This commit is contained in:
parent
6142ce88cc
commit
179fc43eb5
@ -32,7 +32,8 @@ from swift.common.middleware.s3api.etree import Element, SubElement, \
|
|||||||
from swift.common.middleware.s3api.s3response import \
|
from swift.common.middleware.s3api.s3response import \
|
||||||
HTTPOk, S3NotImplemented, InvalidArgument, \
|
HTTPOk, S3NotImplemented, InvalidArgument, \
|
||||||
MalformedXML, InvalidLocationConstraint, NoSuchBucket, \
|
MalformedXML, InvalidLocationConstraint, NoSuchBucket, \
|
||||||
BucketNotEmpty, InternalError, ServiceUnavailable, NoSuchKey
|
BucketNotEmpty, VersionedBucketNotEmpty, InternalError, \
|
||||||
|
ServiceUnavailable, NoSuchKey
|
||||||
from swift.common.middleware.s3api.utils import MULTIUPLOAD_SUFFIX
|
from swift.common.middleware.s3api.utils import MULTIUPLOAD_SUFFIX
|
||||||
|
|
||||||
MAX_PUT_BUCKET_BODY_SIZE = 10240
|
MAX_PUT_BUCKET_BODY_SIZE = 10240
|
||||||
@ -53,6 +54,9 @@ class BucketController(Controller):
|
|||||||
try:
|
try:
|
||||||
resp = req.get_response(self.app, 'HEAD')
|
resp = req.get_response(self.app, 'HEAD')
|
||||||
if int(resp.sw_headers['X-Container-Object-Count']) > 0:
|
if int(resp.sw_headers['X-Container-Object-Count']) > 0:
|
||||||
|
if resp.sw_headers.get('X-Container-Sysmeta-Versions-Enabled'):
|
||||||
|
raise VersionedBucketNotEmpty()
|
||||||
|
else:
|
||||||
raise BucketNotEmpty()
|
raise BucketNotEmpty()
|
||||||
# FIXME: This extra HEAD saves unexpected segment deletion
|
# FIXME: This extra HEAD saves unexpected segment deletion
|
||||||
# but if a complete multipart upload happen while cleanup
|
# but if a complete multipart upload happen while cleanup
|
||||||
|
@ -334,6 +334,12 @@ class BucketNotEmpty(ErrorResponse):
|
|||||||
_msg = 'The bucket you tried to delete is not empty'
|
_msg = 'The bucket you tried to delete is not empty'
|
||||||
|
|
||||||
|
|
||||||
|
class VersionedBucketNotEmpty(BucketNotEmpty):
|
||||||
|
_msg = 'The bucket you tried to delete is not empty. ' \
|
||||||
|
'You must delete all versions in the bucket.'
|
||||||
|
_code = 'BucketNotEmpty'
|
||||||
|
|
||||||
|
|
||||||
class CredentialsNotSupported(ErrorResponse):
|
class CredentialsNotSupported(ErrorResponse):
|
||||||
_status = '400 Bad Request'
|
_status = '400 Bad Request'
|
||||||
_msg = 'This request does not support credentials.'
|
_msg = 'This request does not support credentials.'
|
||||||
|
@ -1369,10 +1369,50 @@ class TestS3ApiBucket(S3ApiTestCase):
|
|||||||
self.assertEqual(code, 'InternalError')
|
self.assertEqual(code, 'InternalError')
|
||||||
|
|
||||||
# bucket not empty is now validated at s3api
|
# bucket not empty is now validated at s3api
|
||||||
|
self.swift._responses.get(('HEAD', '/v1/AUTH_test/bucket'))
|
||||||
self.swift.register('HEAD', '/v1/AUTH_test/bucket', swob.HTTPNoContent,
|
self.swift.register('HEAD', '/v1/AUTH_test/bucket', swob.HTTPNoContent,
|
||||||
{'X-Container-Object-Count': '1'}, None)
|
{'X-Container-Object-Count': '1'}, None)
|
||||||
code = self._test_method_error('DELETE', '/bucket', swob.HTTPConflict)
|
req = Request.blank('/bucket',
|
||||||
self.assertEqual(code, 'BucketNotEmpty')
|
environ={'REQUEST_METHOD': 'DELETE'},
|
||||||
|
headers={'Authorization': 'AWS test:tester:hmac',
|
||||||
|
'Date': self.get_date_header()})
|
||||||
|
status, _headers, body = self.call_s3api(req)
|
||||||
|
self.assertEqual('409 Conflict', status)
|
||||||
|
self.assertEqual('BucketNotEmpty', self._get_error_code(body))
|
||||||
|
self.assertNotIn('You must delete all versions in the bucket',
|
||||||
|
self._get_error_message(body))
|
||||||
|
|
||||||
|
@s3acl
|
||||||
|
def test_bucket_DELETE_error_with_enabled_versioning(self):
|
||||||
|
self.swift.register('HEAD', '/v1/AUTH_test/bucket', swob.HTTPNoContent,
|
||||||
|
{'X-Container-Object-Count': '1',
|
||||||
|
'X-Container-Sysmeta-Versions-Enabled': 'True'},
|
||||||
|
None)
|
||||||
|
req = Request.blank('/bucket',
|
||||||
|
environ={'REQUEST_METHOD': 'DELETE'},
|
||||||
|
headers={'Authorization': 'AWS test:tester:hmac',
|
||||||
|
'Date': self.get_date_header()})
|
||||||
|
status, _headers, body = self.call_s3api(req)
|
||||||
|
self.assertEqual('409 Conflict', status)
|
||||||
|
self.assertEqual('BucketNotEmpty', self._get_error_code(body))
|
||||||
|
self.assertIn('You must delete all versions in the bucket',
|
||||||
|
self._get_error_message(body))
|
||||||
|
|
||||||
|
@s3acl
|
||||||
|
def test_bucket_DELETE_error_with_suspended_versioning(self):
|
||||||
|
self.swift.register('HEAD', '/v1/AUTH_test/bucket', swob.HTTPNoContent,
|
||||||
|
{'X-Container-Object-Count': '1',
|
||||||
|
'X-Container-Sysmeta-Versions-Enabled': 'False'},
|
||||||
|
None)
|
||||||
|
req = Request.blank('/bucket',
|
||||||
|
environ={'REQUEST_METHOD': 'DELETE'},
|
||||||
|
headers={'Authorization': 'AWS test:tester:hmac',
|
||||||
|
'Date': self.get_date_header()})
|
||||||
|
status, _headers, body = self.call_s3api(req)
|
||||||
|
self.assertEqual('409 Conflict', status)
|
||||||
|
self.assertEqual('BucketNotEmpty', self._get_error_code(body))
|
||||||
|
self.assertIn('You must delete all versions in the bucket',
|
||||||
|
self._get_error_message(body))
|
||||||
|
|
||||||
@s3acl
|
@s3acl
|
||||||
def test_bucket_DELETE(self):
|
def test_bucket_DELETE(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user