Allow object-expirer to delete the last version of an object
Fix bug 1067677 When we delete a versioned object, the last version will be poped out from the versiones container. When a versioned object is expired and deleted by object- expirer, the last version is restored but remains in the versions container instead of getting deleted. The reason is object-expirer will set 'X-If-Delete- At' header when deleteing an object. However this is for the current version - not for the last version. When the object-server is trying to delete the last version, the transaction will fail with error: X-If-Delete-At and X-Delete-At do not match. Delete the 'X-If-Delete-At' field in the later built delete request would help to solve this issue. This patch, without the test, was first proposed by Zhou Yuan <yuan.zhou@intel.com>. Change-Id: I62c97e6a0f140888497e189129825865fb6f7966
This commit is contained in:
parent
7af535cb2c
commit
ba3babadde
@ -873,6 +873,9 @@ class ObjectController(Controller):
|
||||
new_del_req.acl = container_info['write_acl']
|
||||
new_del_req.path_info = copy_path
|
||||
req = new_del_req
|
||||
# remove 'X-If-Delete-At', since it is not for the older copy
|
||||
if 'X-If-Delete-At' in req.headers:
|
||||
del req.headers['X-If-Delete-At']
|
||||
if 'swift.authorize' in req.environ:
|
||||
aresp = req.environ['swift.authorize'](req)
|
||||
if aresp:
|
||||
|
@ -266,6 +266,8 @@ def fake_http_connect(*code_iter, **kwargs):
|
||||
x = [x] * len(code_iter)
|
||||
container_ts_iter = iter(x)
|
||||
code_iter = iter(code_iter)
|
||||
static_body = kwargs.get('body', None)
|
||||
body_iter = kwargs.get('body_iter', None)
|
||||
|
||||
def connect(*args, **ckwargs):
|
||||
if 'give_content_type' in kwargs:
|
||||
@ -285,8 +287,12 @@ def fake_http_connect(*code_iter, **kwargs):
|
||||
|
||||
if status <= 0:
|
||||
raise HTTPException()
|
||||
return FakeConn(status, etag, body=kwargs.get('body', ''),
|
||||
timestamp=timestamp, expect_status=expect_status)
|
||||
if body_iter is None:
|
||||
body = static_body or ''
|
||||
else:
|
||||
body = body_iter.next()
|
||||
return FakeConn(status, etag, body=body, timestamp=timestamp,
|
||||
expect_status=expect_status)
|
||||
|
||||
return connect
|
||||
|
||||
@ -844,6 +850,39 @@ class TestObjectController(unittest.TestCase):
|
||||
res = controller.PUT(req)
|
||||
self.assertTrue(res.status.startswith('201 '))
|
||||
|
||||
def test_expirer_DELETE_on_versioned_object(self):
|
||||
test_errors = []
|
||||
|
||||
def test_connect(ipaddr, port, device, partition, method, path,
|
||||
headers=None, query_string=None):
|
||||
if method == 'DELETE':
|
||||
if 'x-if-delete-at' in headers or 'X-If-Delete-At' in headers:
|
||||
test_errors.append('X-If-Delete-At in headers')
|
||||
|
||||
body = simplejson.dumps(
|
||||
[{"name": "001o/1",
|
||||
"hash": "x",
|
||||
"bytes": 0,
|
||||
"content_type": "text/plain",
|
||||
"last_modified": "1970-01-01T00:00:01.000000"}])
|
||||
body_iter = ('', '', body, '', '', '', '', '', '', '', '', '', '', '')
|
||||
with save_globals():
|
||||
controller = proxy_server.ObjectController(self.app, 'a', 'c', 'o')
|
||||
# HEAD HEAD GET GET HEAD GET GET GET PUT PUT
|
||||
# PUT DEL DEL DEL
|
||||
set_http_connect(200, 200, 200, 200, 200, 200, 200, 200, 201, 201,
|
||||
201, 200, 200, 200,
|
||||
give_connect=test_connect,
|
||||
body_iter=iter(body_iter),
|
||||
headers={'x-versions-location': 'foo'})
|
||||
self.app.memcache.store = {}
|
||||
req = Request.blank('/a/c/o',
|
||||
headers={'X-If-Delete-At': 1},
|
||||
environ={'REQUEST_METHOD': 'DELETE'})
|
||||
self.app.update_request(req)
|
||||
res = controller.DELETE(req)
|
||||
self.assertEquals(test_errors, [])
|
||||
|
||||
def test_PUT_auto_content_type(self):
|
||||
with save_globals():
|
||||
controller = proxy_server.ObjectController(self.app, 'account',
|
||||
|
Loading…
x
Reference in New Issue
Block a user