copy X-Delete-At unless X-Fresh-Metadata: true is supplied on an object copy
Current codes will copy metadata headers when x-fresh-metadata:false, we still need copy "x-delete-at" header and ensure expiring work at the same time. Change-Id: Ie31326b5f7b565e51e5aa249279bc1786f7bc847 Fixes: bug #1067528
This commit is contained in:
parent
5d52d2d1cc
commit
fef0f491ff
1
.mailmap
1
.mailmap
@ -42,3 +42,4 @@ David Hadas <davidh@il.ibm.com> <david.hadas@gmail.com>
|
||||
Yaguang Wang <yaguang.wang@intel.com> ywang19 <yaguang.wang@intel.com>
|
||||
Liu Siqi <meizu647@gmail.com> dk647 <meizu647@gmail.com>
|
||||
James E. Blair <jeblair@openstack.org> <james.blair@rackspace.com>
|
||||
Kun Huang <gareth@unitedstack.com> <academicgareth@gmail.com>
|
||||
|
@ -71,8 +71,9 @@ def copy_headers_into(from_r, to_r):
|
||||
:params from_r: a swob Request or Response
|
||||
:params to_r: a swob Request or Response
|
||||
"""
|
||||
pass_headers = ['x-delete-at']
|
||||
for k, v in from_r.headers.items():
|
||||
if k.lower().startswith('x-object-meta-'):
|
||||
if k.lower().startswith('x-object-meta-') or k.lower() in pass_headers:
|
||||
to_r.headers[k] = v
|
||||
|
||||
|
||||
@ -712,25 +713,6 @@ class ObjectController(Controller):
|
||||
content_type='text/plain',
|
||||
body='Non-integer X-Delete-After')
|
||||
req.headers['x-delete-at'] = '%d' % (time.time() + x_delete_after)
|
||||
if 'x-delete-at' in req.headers:
|
||||
try:
|
||||
x_delete_at = int(req.headers['x-delete-at'])
|
||||
if x_delete_at < time.time():
|
||||
return HTTPBadRequest(
|
||||
body='X-Delete-At in past', request=req,
|
||||
content_type='text/plain')
|
||||
except ValueError:
|
||||
return HTTPBadRequest(request=req, content_type='text/plain',
|
||||
body='Non-integer X-Delete-At')
|
||||
delete_at_container = str(
|
||||
x_delete_at /
|
||||
self.app.expiring_objects_container_divisor *
|
||||
self.app.expiring_objects_container_divisor)
|
||||
delete_at_part, delete_at_nodes = \
|
||||
self.app.container_ring.get_nodes(
|
||||
self.app.expiring_objects_account, delete_at_container)
|
||||
else:
|
||||
delete_at_part = delete_at_nodes = None
|
||||
partition, nodes = self.app.object_ring.get_nodes(
|
||||
self.account_name, self.container_name, self.object_name)
|
||||
# do a HEAD request for container sync and checking object versions
|
||||
@ -863,6 +845,27 @@ class ObjectController(Controller):
|
||||
source_resp.headers['X-Static-Large-Object']
|
||||
|
||||
req = new_req
|
||||
|
||||
if 'x-delete-at' in req.headers:
|
||||
try:
|
||||
x_delete_at = int(req.headers['x-delete-at'])
|
||||
if x_delete_at < time.time():
|
||||
return HTTPBadRequest(
|
||||
body='X-Delete-At in past', request=req,
|
||||
content_type='text/plain')
|
||||
except ValueError:
|
||||
return HTTPBadRequest(request=req, content_type='text/plain',
|
||||
body='Non-integer X-Delete-At')
|
||||
delete_at_container = str(
|
||||
x_delete_at /
|
||||
self.app.expiring_objects_container_divisor *
|
||||
self.app.expiring_objects_container_divisor)
|
||||
delete_at_part, delete_at_nodes = \
|
||||
self.app.container_ring.get_nodes(
|
||||
self.app.expiring_objects_account, delete_at_container)
|
||||
else:
|
||||
delete_at_part = delete_at_nodes = None
|
||||
|
||||
node_iter = self.iter_nodes(self.app.object_ring, partition)
|
||||
pile = GreenPile(len(nodes))
|
||||
chunked = req.headers.get('transfer-encoding')
|
||||
|
@ -318,6 +318,7 @@ def fake_http_connect(*code_iter, **kwargs):
|
||||
'x-timestamp': self.timestamp,
|
||||
'last-modified': self.timestamp,
|
||||
'x-object-meta-test': 'testing',
|
||||
'x-delete-at': '9876543210',
|
||||
'etag': etag,
|
||||
'x-works': 'yes',
|
||||
'x-account-container-count': kwargs.get('count', 12345)}
|
||||
|
@ -2510,6 +2510,7 @@ class TestObjectController(unittest.TestCase):
|
||||
self.assertEquals(resp.headers.get('x-object-meta-test'),
|
||||
'testing')
|
||||
self.assertEquals(resp.headers.get('x-object-meta-ours'), 'okay')
|
||||
self.assertEquals(resp.headers.get('x-delete-at'), '9876543210')
|
||||
|
||||
# copy-from object is too large to fit in target object
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||
@ -2641,6 +2642,7 @@ class TestObjectController(unittest.TestCase):
|
||||
self.assertEquals(resp.headers.get('x-object-meta-test'),
|
||||
'testing')
|
||||
self.assertEquals(resp.headers.get('x-object-meta-ours'), 'okay')
|
||||
self.assertEquals(resp.headers.get('x-delete-at'), '9876543210')
|
||||
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'COPY'},
|
||||
headers={'Destination': '/c/o'})
|
||||
@ -2678,6 +2680,29 @@ class TestObjectController(unittest.TestCase):
|
||||
self.assertEquals(resp.headers['x-copied-from-last-modified'],
|
||||
'3')
|
||||
|
||||
def test_COPY_delete_at(self):
|
||||
with save_globals():
|
||||
given_headers = {}
|
||||
|
||||
def fake_connect_put_node(nodes, part, path, headers,
|
||||
logger_thread_locals):
|
||||
given_headers.update(headers)
|
||||
|
||||
controller = proxy_server.ObjectController(self.app, 'a',
|
||||
'c', 'o')
|
||||
controller._connect_put_node = fake_connect_put_node
|
||||
set_http_connect(200, 200, 200, 200, 200, 201, 201, 201)
|
||||
self.app.memcache.store = {}
|
||||
req = Request.blank('/a/c/o', environ={'REQUEST_METHOD': 'COPY'},
|
||||
headers={'Destination': '/c/o'})
|
||||
|
||||
self.app.update_request(req)
|
||||
controller.COPY(req)
|
||||
self.assertEquals(given_headers.get('X-Delete-At'), '9876543210')
|
||||
self.assertTrue('X-Delete-At-Host' in given_headers)
|
||||
self.assertTrue('X-Delete-At-Device' in given_headers)
|
||||
self.assertTrue('X-Delete-At-Partition' in given_headers)
|
||||
|
||||
def test_chunked_put(self):
|
||||
|
||||
class ChunkedFile():
|
||||
|
Loading…
Reference in New Issue
Block a user