Merge "Preserve expiring object behaviour with old proxy-server"
This commit is contained in:
commit
9ddd833dfc
@ -389,14 +389,26 @@ class ObjectController(BaseStorageServer):
|
||||
'x-trans-id': headers_in.get('x-trans-id', '-'),
|
||||
'referer': request.as_referer()})
|
||||
if op != 'DELETE':
|
||||
delete_at_container = headers_in.get('X-Delete-At-Container', None)
|
||||
if not delete_at_container:
|
||||
hosts = headers_in.get('X-Delete-At-Host', None)
|
||||
if hosts is None:
|
||||
# If header is missing, no update needed as sufficient other
|
||||
# object servers should perform the required update.
|
||||
return
|
||||
|
||||
delete_at_container = headers_in.get('X-Delete-At-Container', None)
|
||||
if not delete_at_container:
|
||||
# older proxy servers did not send X-Delete-At-Container so for
|
||||
# backwards compatibility calculate the value here, but also
|
||||
# log a warning because this is prone to inconsistent
|
||||
# expiring_objects_container_divisor configurations.
|
||||
# See https://bugs.launchpad.net/swift/+bug/1187200
|
||||
self.logger.warning(
|
||||
'X-Delete-At-Container header must be specified for '
|
||||
'expiring objects background %s to work properly. Making '
|
||||
'best guess as to the container name for now.' % op)
|
||||
delete_at_container = get_expirer_container(
|
||||
delete_at, self.expiring_objects_container_divisor,
|
||||
account, container, obj)
|
||||
partition = headers_in.get('X-Delete-At-Partition', None)
|
||||
hosts = headers_in.get('X-Delete-At-Host', '')
|
||||
contdevices = headers_in.get('X-Delete-At-Device', '')
|
||||
updates = [upd for upd in
|
||||
zip((h.strip() for h in hosts.split(',')),
|
||||
|
@ -5597,8 +5597,116 @@ class TestObjectController(unittest.TestCase):
|
||||
'X-Backend-Storage-Policy-Index': int(policy)})
|
||||
self.object_controller.delete_at_update('PUT', 2, 'a', 'c', 'o',
|
||||
req, 'sda1', policy)
|
||||
self.assertEqual(
|
||||
self.logger.get_lines_for_level('warning'),
|
||||
['X-Delete-At-Container header must be specified for expiring '
|
||||
'objects background PUT to work properly. Making best guess as '
|
||||
'to the container name for now.'])
|
||||
self.assertEqual(
|
||||
given_args, [
|
||||
'PUT', '.expiring_objects', '0000000000', '0000000002-a/c/o',
|
||||
'127.0.0.1:1234',
|
||||
'3', 'sdc1', HeaderKeyDict({
|
||||
# the .expiring_objects account is always policy-0
|
||||
'X-Backend-Storage-Policy-Index': 0,
|
||||
'x-size': '0',
|
||||
'x-etag': 'd41d8cd98f00b204e9800998ecf8427e',
|
||||
'x-content-type': 'text/plain',
|
||||
'x-timestamp': utils.Timestamp('1').internal,
|
||||
'x-trans-id': '1234',
|
||||
'referer': 'PUT http://localhost/v1/a/c/o'}),
|
||||
'sda1', policy])
|
||||
|
||||
def test_delete_at_update_put_with_info_but_missing_host(self):
|
||||
# Same as test_delete_at_update_put_with_info, but just
|
||||
# missing the X-Delete-At-Host header.
|
||||
policy = random.choice(list(POLICIES))
|
||||
given_args = []
|
||||
|
||||
def fake_async_update(*args):
|
||||
given_args.extend(args)
|
||||
|
||||
self.object_controller.async_update = fake_async_update
|
||||
self.object_controller.logger = self.logger
|
||||
req = Request.blank(
|
||||
'/v1/a/c/o',
|
||||
environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'X-Timestamp': 1,
|
||||
'X-Trans-Id': '1234',
|
||||
'X-Delete-At-Container': '0',
|
||||
'X-Delete-At-Partition': '3',
|
||||
'X-Delete-At-Device': 'sdc1',
|
||||
'X-Backend-Storage-Policy-Index': int(policy)})
|
||||
self.object_controller.delete_at_update('PUT', 2, 'a', 'c', 'o',
|
||||
req, 'sda1', policy)
|
||||
self.assertFalse(self.logger.get_lines_for_level('warning'))
|
||||
self.assertEqual(given_args, [])
|
||||
|
||||
def test_delete_at_update_put_with_info_but_empty_host(self):
|
||||
# Same as test_delete_at_update_put_with_info, but empty
|
||||
# X-Delete-At-Host header and no X-Delete-At-Partition nor
|
||||
# X-Delete-At-Device.
|
||||
policy = random.choice(list(POLICIES))
|
||||
given_args = []
|
||||
|
||||
def fake_async_update(*args):
|
||||
given_args.extend(args)
|
||||
|
||||
self.object_controller.async_update = fake_async_update
|
||||
self.object_controller.logger = self.logger
|
||||
req = Request.blank(
|
||||
'/v1/a/c/o',
|
||||
environ={'REQUEST_METHOD': 'PUT'},
|
||||
headers={'X-Timestamp': 1,
|
||||
'X-Trans-Id': '1234',
|
||||
'X-Delete-At-Container': '0',
|
||||
'X-Delete-At-Host': '',
|
||||
'X-Backend-Storage-Policy-Index': int(policy)})
|
||||
self.object_controller.delete_at_update('PUT', 2, 'a', 'c', 'o',
|
||||
req, 'sda1', policy)
|
||||
self.assertFalse(self.logger.get_lines_for_level('warning'))
|
||||
self.assertEqual(
|
||||
given_args, [
|
||||
'PUT', '.expiring_objects', '0000000000', '0000000002-a/c/o',
|
||||
None,
|
||||
None, None, HeaderKeyDict({
|
||||
# the .expiring_objects account is always policy-0
|
||||
'X-Backend-Storage-Policy-Index': 0,
|
||||
'x-size': '0',
|
||||
'x-etag': 'd41d8cd98f00b204e9800998ecf8427e',
|
||||
'x-content-type': 'text/plain',
|
||||
'x-timestamp': utils.Timestamp('1').internal,
|
||||
'x-trans-id': '1234',
|
||||
'referer': 'PUT http://localhost/v1/a/c/o'}),
|
||||
'sda1', policy])
|
||||
|
||||
def test_delete_at_update_delete(self):
|
||||
policy = random.choice(list(POLICIES))
|
||||
given_args = []
|
||||
|
||||
def fake_async_update(*args):
|
||||
given_args.extend(args)
|
||||
|
||||
self.object_controller.async_update = fake_async_update
|
||||
req = Request.blank(
|
||||
'/v1/a/c/o',
|
||||
environ={'REQUEST_METHOD': 'DELETE'},
|
||||
headers={'X-Timestamp': 1,
|
||||
'X-Trans-Id': '1234',
|
||||
'X-Backend-Storage-Policy-Index': int(policy)})
|
||||
self.object_controller.delete_at_update('DELETE', 2, 'a', 'c', 'o',
|
||||
req, 'sda1', policy)
|
||||
self.assertEqual(
|
||||
given_args, [
|
||||
'DELETE', '.expiring_objects', '0000000000',
|
||||
'0000000002-a/c/o', None, None,
|
||||
None, HeaderKeyDict({
|
||||
'X-Backend-Storage-Policy-Index': 0,
|
||||
'x-timestamp': utils.Timestamp('1').internal,
|
||||
'x-trans-id': '1234',
|
||||
'referer': 'DELETE http://localhost/v1/a/c/o'}),
|
||||
'sda1', policy])
|
||||
|
||||
def test_delete_backend_replication(self):
|
||||
# If X-Backend-Replication: True delete_at_update should completely
|
||||
# short-circuit.
|
||||
@ -6249,6 +6357,7 @@ class TestObjectController(unittest.TestCase):
|
||||
headers={'X-Timestamp': normalize_timestamp(put_time),
|
||||
'X-Delete-At': str(delete_at_timestamp_1),
|
||||
'X-Delete-At-Container': delete_at_container_1,
|
||||
'X-Delete-At-Host': '1.2.3.4',
|
||||
'Content-Length': '4',
|
||||
'Content-Type': 'application/octet-stream'})
|
||||
req.body = 'TEST'
|
||||
@ -6266,6 +6375,7 @@ class TestObjectController(unittest.TestCase):
|
||||
'X-Backend-Clean-Expiring-Object-Queue': 'false',
|
||||
'X-Delete-At': str(delete_at_timestamp_2),
|
||||
'X-Delete-At-Container': delete_at_container_2,
|
||||
'X-Delete-At-Host': '1.2.3.4',
|
||||
'Content-Length': '9',
|
||||
'Content-Type': 'application/octet-stream'})
|
||||
req.body = 'new stuff'
|
||||
|
Loading…
Reference in New Issue
Block a user