replication network aware helper for container-updater in proxy

Change-Id: I303a1ff97325654478c2a47af056deda37696b7b
This commit is contained in:
indianwhocodes 2023-10-24 06:44:55 -07:00 committed by ASHWIN A NAIR
parent 6f890d2ba9
commit e375ce5bf0
3 changed files with 86 additions and 7 deletions

View File

@ -448,14 +448,15 @@ class BaseObjectController(Controller):
headers = [self.generate_request_headers(req, additional=req.headers)
for _junk in range(n_outgoing)]
def set_container_update(index, container):
def set_container_update(index, container_node):
ip, port = get_ip_port(container_node, headers[index])
headers[index]['X-Container-Partition'] = container_partition
headers[index]['X-Container-Host'] = csv_append(
headers[index].get('X-Container-Host'),
'%(ip)s:%(port)s' % container)
'%(ip)s:%(port)s' % {'ip': ip, 'port': port})
headers[index]['X-Container-Device'] = csv_append(
headers[index].get('X-Container-Device'),
container['device'])
container_node['device'])
if container_path:
headers[index]['X-Backend-Quoted-Container-Path'] = quote(
container_path)
@ -468,11 +469,12 @@ class BaseObjectController(Controller):
# will eat the update and move it as a misplaced object.
def set_delete_at_headers(index, delete_at_node):
ip, port = get_ip_port(delete_at_node, headers[index])
headers[index]['X-Delete-At-Container'] = delete_at_container
headers[index]['X-Delete-At-Partition'] = delete_at_partition
headers[index]['X-Delete-At-Host'] = csv_append(
headers[index].get('X-Delete-At-Host'),
'%(ip)s:%(port)s' % delete_at_node)
'%(ip)s:%(port)s' % {'ip': ip, 'port': port})
headers[index]['X-Delete-At-Device'] = csv_append(
headers[index].get('X-Delete-At-Device'),
delete_at_node['device'])

View File

@ -434,6 +434,67 @@ class CommonObjectControllerMixin(BaseObjectControllerMixin):
resp = req.get_response(self.app)
self.assertEqual(resp.status_int, 204)
def test_object_DELETE_backend_update_container_ip_default(self):
self.policy.object_ring = FakeRing(separate_replication=True)
self.app.container_ring = FakeRing(separate_replication=True)
# sanity, devs have different ip & replication_ip
for ring in (self.policy.object_ring, self.app.container_ring):
for dev in ring.devs:
self.assertNotEqual(dev['ip'], dev['replication_ip'])
req = swift.common.swob.Request.blank('/v1/a/c/o', method='DELETE')
codes = [204] * self.replicas()
with mocked_http_conn(*codes) as log:
resp = req.get_response(self.app)
self.assertEqual(resp.status_int, 204)
# sanity, object hosts use node ip/port
object_hosts = {'%(ip)s:%(port)s' % req for req in log.requests}
object_ring = self.app.get_object_ring(int(self.policy))
part, object_nodes = object_ring.get_nodes('a', 'c', 'o')
expected_object_hosts = {'%(ip)s:%(port)s' % n for n in object_nodes}
self.assertEqual(object_hosts, expected_object_hosts)
# container hosts use node ip/port
container_hosts = {req['headers']['x-container-host']
for req in log.requests}
part, container_nodes = self.app.container_ring.get_nodes('a', 'c')
expected_container_hosts = {'%(ip)s:%(port)s' % n
for n in container_nodes}
self.assertEqual(container_hosts, expected_container_hosts)
def test_repl_object_DELETE_backend_update_container_repl_ip(self):
self.policy.object_ring = FakeRing(separate_replication=True)
self.app.container_ring = FakeRing(separate_replication=True)
# sanity, devs have different ip & replication_ip
for ring in (self.policy.object_ring, self.app.container_ring):
for dev in ring.devs:
self.assertNotEqual(dev['ip'], dev['replication_ip'])
req = swift.common.swob.Request.blank(
'/v1/a/c/o', method='DELETE', headers={
'x-backend-use-replication-network': 'true'})
codes = [204] * self.replicas()
with mocked_http_conn(*codes) as log:
resp = req.get_response(self.app)
self.assertEqual(resp.status_int, 204)
# sanity, object hosts use node replication ip/port
object_hosts = {'%(ip)s:%(port)s' % req for req in log.requests}
object_ring = self.app.get_object_ring(int(self.policy))
part, object_nodes = object_ring.get_nodes('a', 'c', 'o')
expected_object_hosts = {
'%(replication_ip)s:%(replication_port)s' % n
for n in object_nodes}
self.assertEqual(object_hosts, expected_object_hosts)
# container hosts use node replication ip/port
container_hosts = {req['headers']['x-container-host']
for req in log.requests}
part, container_nodes = self.app.container_ring.get_nodes('a', 'c')
expected_container_hosts = {
'%(replication_ip)s:%(replication_port)s' % n
for n in container_nodes}
self.assertEqual(container_hosts, expected_container_hosts)
def test_DELETE_missing_one(self):
# Obviously this test doesn't work if we're testing 1 replica.
# In that case, we don't have any failovers to check.

View File

@ -4176,20 +4176,32 @@ class TestReplicatedObjectController(
StoragePolicy(1, 'one', object_ring=FakeRing()),
])
def test_POST_backend_headers(self):
self.app = proxy_server.Application(
{},
account_ring=FakeRing(separate_replication=True),
container_ring=FakeRing(separate_replication=True))
part = self.app.container_ring.get_part('a', 'c')
nodes = self.app.container_ring.get_part_nodes(part)
self.assertNotEqual(nodes[0]['ip'], nodes[0]['replication_ip'])
# reset the router post patch_policies
self.app.obj_controller_router = proxy_server.ObjectControllerRouter()
self.app.sort_nodes = lambda nodes, *args, **kwargs: nodes
def do_test(resp_headers):
def do_test(resp_headers, use_replication=False):
backend_requests = []
def capture_requests(ip, port, method, path, headers, *args,
**kwargs):
backend_requests.append((method, path, headers))
replication_aware = 'true' if use_replication else 'false'
req = Request.blank('/v1/a/c/o', {}, method='POST',
headers={'X-Object-Meta-Color': 'Blue',
'Content-Type': 'text/plain'})
'Content-Type': 'text/plain',
'x-backend-use-replication-network':
replication_aware})
# we want the container_info response to says a policy index of 1
with mocked_http_conn(
@ -4244,7 +4256,10 @@ class TestReplicatedObjectController(
expected = {}
for i, device in enumerate(['sda', 'sdb', 'sdc']):
expected[device] = '10.0.0.%d:100%d' % (i, i)
if use_replication:
expected[device] = '10.0.1.%d:110%d' % (i, i)
else:
expected[device] = '10.0.0.%d:100%d' % (i, i)
self.assertEqual(container_headers, expected)
# and again with policy override
@ -4277,6 +4292,7 @@ class TestReplicatedObjectController(
do_test(resp_headers)
resp_headers['X-Backend-Sharding-State'] = 'unsharded'
do_test(resp_headers)
do_test(resp_headers, use_replication=True)
def _check_request(self, req, method, path, headers=None, params=None):
self.assertEqual(method, req['method'])