Fix member address selection in lbaas driver
Currently when Senlin adds a member to load balancer's pool, it just uses the first address of the node. In a dual stack network, if the first address does not match with the subnet ip version, the member will become unaccessible from the load balancer. This patch ensures the right address will be picked according to the subnet ip version. Change-Id: I0322184dfdb46a7560c20e85452d84d2ffb83a1c Closes-Bug: #1813089
This commit is contained in:
parent
20e40cb4fe
commit
ec3c42a2ad
|
@ -291,8 +291,17 @@ class LoadBalancerDriver(base.DriverBase):
|
|||
LOG.error('Node is not in subnet %(subnet)s', {'subnet': subnet})
|
||||
return None
|
||||
|
||||
# Use the first IP address if more than one are found in target network
|
||||
address = addresses[net_name][0]['addr']
|
||||
# Use the first IP address that match with the subnet ip_version
|
||||
# if more than one are found in target network
|
||||
address = None
|
||||
for ip in addresses[net_name]:
|
||||
if ip['version'] == subnet_obj.ip_version:
|
||||
address = ip['addr']
|
||||
break
|
||||
if not address:
|
||||
LOG.error("Node does not match with subnet's (%s) ip version (%s)"
|
||||
% (subnet, subnet_obj.ip_version))
|
||||
return None
|
||||
try:
|
||||
# FIXME(Yanyan Hu): Currently, Neutron lbaasv2 service can not
|
||||
# handle concurrent lb member operations well: new member creation
|
||||
|
|
|
@ -445,6 +445,7 @@ class TestOctaviaLBaaSDriver(base.SenlinTestCase):
|
|||
port = '80'
|
||||
subnet = 'subnet'
|
||||
subnet_obj = mock.Mock(id='SUBNET_ID', network_id='NETWORK_ID')
|
||||
subnet_obj.ip_version = '4'
|
||||
subnet_obj.name = 'subnet'
|
||||
network_obj = mock.Mock(id='NETWORK_ID')
|
||||
network_obj.name = 'network1'
|
||||
|
@ -452,8 +453,9 @@ class TestOctaviaLBaaSDriver(base.SenlinTestCase):
|
|||
node_detail = {
|
||||
'name': 'node-01',
|
||||
'addresses': {
|
||||
'network1': [{'addr': 'ipaddr_net1'}],
|
||||
'network2': [{'addr': 'ipaddr_net2'}]
|
||||
'network1': [{'addr': 'ipaddr1_net1', 'version': '6'},
|
||||
{'addr': 'ipaddr2_net1', 'version': '4'}],
|
||||
'network2': [{'addr': 'ipaddr_net2', 'version': '4'}]
|
||||
}
|
||||
}
|
||||
mock_load.return_value = node
|
||||
|
@ -469,8 +471,9 @@ class TestOctaviaLBaaSDriver(base.SenlinTestCase):
|
|||
self.assertEqual('MEMBER_ID', res)
|
||||
self.nc.subnet_get.assert_called_once_with(subnet)
|
||||
self.nc.network_get.assert_called_once_with('NETWORK_ID')
|
||||
# Make sure the ip matches with subnet ip_version
|
||||
self.oc.pool_member_create.assert_called_once_with(
|
||||
pool_id, 'ipaddr_net1', port, 'SUBNET_ID')
|
||||
pool_id, 'ipaddr2_net1', port, 'SUBNET_ID')
|
||||
self.lb_driver._wait_for_lb_ready.assert_has_calls(
|
||||
[mock.call('LB_ID'), mock.call('LB_ID')])
|
||||
mock_load.assert_called_once_with(fake_context, db_node=node)
|
||||
|
@ -505,13 +508,14 @@ class TestOctaviaLBaaSDriver(base.SenlinTestCase):
|
|||
node = mock.Mock()
|
||||
subnet_obj = mock.Mock(id='SUBNET_ID', network_id='NETWORK_ID')
|
||||
subnet_obj.name = 'subnet'
|
||||
subnet_obj.ip_version = '4'
|
||||
network_obj = mock.Mock(id='NETWORK_ID')
|
||||
network_obj.name = 'network1'
|
||||
node_detail = {
|
||||
'name': 'node-01',
|
||||
'addresses': {
|
||||
'network1': [{'addr': 'ipaddr_net1'}],
|
||||
'network2': [{'addr': 'ipaddr_net2'}]
|
||||
'network1': [{'addr': 'ipaddr_net1', 'version': '4'}],
|
||||
'network2': [{'addr': 'ipaddr_net2', 'version': '4'}]
|
||||
}
|
||||
}
|
||||
mock_load.return_value = node
|
||||
|
@ -536,13 +540,14 @@ class TestOctaviaLBaaSDriver(base.SenlinTestCase):
|
|||
node = mock.Mock()
|
||||
subnet_obj = mock.Mock(id='SUBNET_ID', network_id='NETWORK_ID')
|
||||
subnet_obj.name = 'subnet'
|
||||
subnet_obj.ip_version = '4'
|
||||
network_obj = mock.Mock(id='NETWORK_ID')
|
||||
network_obj.name = 'network1'
|
||||
node_detail = {
|
||||
'name': 'node-01',
|
||||
'addresses': {
|
||||
'network1': [{'addr': 'ipaddr_net1'}],
|
||||
'network2': [{'addr': 'ipaddr_net2'}]
|
||||
'network1': [{'addr': 'ipaddr_net1', 'version': '4'}],
|
||||
'network2': [{'addr': 'ipaddr_net2', 'version': '4'}]
|
||||
}
|
||||
}
|
||||
mock_load.return_value = node
|
||||
|
@ -561,17 +566,48 @@ class TestOctaviaLBaaSDriver(base.SenlinTestCase):
|
|||
|
||||
@mock.patch.object(nodem.Node, 'load')
|
||||
@mock.patch.object(oslo_context, 'get_current')
|
||||
def test_member_add_wait_for_lb_timeout(self, mock_get_current, mock_load):
|
||||
def test_member_add_ip_version_match_failed(self, mock_get_current,
|
||||
mock_load):
|
||||
node = mock.Mock()
|
||||
subnet_obj = mock.Mock(id='SUBNET_ID', network_id='NETWORK_ID')
|
||||
subnet_obj.name = 'subnet'
|
||||
subnet_obj.ip_version = '4'
|
||||
network_obj = mock.Mock(id='NETWORK_ID')
|
||||
network_obj.name = 'network1'
|
||||
node_detail = {
|
||||
'name': 'node-01',
|
||||
'addresses': {
|
||||
'network1': [{'addr': 'ipaddr_net1'}],
|
||||
'network2': [{'addr': 'ipaddr_net2'}]
|
||||
'network1': [{'addr': 'ipaddr_net1', 'version': '6'}],
|
||||
'network2': [{'addr': 'ipaddr_net2', 'version': '6'}]
|
||||
}
|
||||
}
|
||||
mock_load.return_value = node
|
||||
node.get_details.return_value = node_detail
|
||||
|
||||
# Node does not match with subnet ip_version
|
||||
self.lb_driver._wait_for_lb_ready = mock.Mock()
|
||||
self.lb_driver._wait_for_lb_ready.return_value = True
|
||||
self.nc.subnet_get.return_value = subnet_obj
|
||||
self.nc.network_get.return_value = network_obj
|
||||
self.oc.pool_member_create = mock.Mock(id='MEMBER_ID')
|
||||
res = self.lb_driver.member_add(node, 'LB_ID', 'POOL_ID', 80,
|
||||
'subnet')
|
||||
self.assertIsNone(res)
|
||||
|
||||
@mock.patch.object(nodem.Node, 'load')
|
||||
@mock.patch.object(oslo_context, 'get_current')
|
||||
def test_member_add_wait_for_lb_timeout(self, mock_get_current, mock_load):
|
||||
node = mock.Mock()
|
||||
subnet_obj = mock.Mock(id='SUBNET_ID', network_id='NETWORK_ID')
|
||||
subnet_obj.name = 'subnet'
|
||||
subnet_obj.ip_version = '4'
|
||||
network_obj = mock.Mock(id='NETWORK_ID')
|
||||
network_obj.name = 'network1'
|
||||
node_detail = {
|
||||
'name': 'node-01',
|
||||
'addresses': {
|
||||
'network1': [{'addr': 'ipaddr_net1', 'version': '4'}],
|
||||
'network2': [{'addr': 'ipaddr_net2', 'version': '4'}]
|
||||
}
|
||||
}
|
||||
mock_load.return_value = node
|
||||
|
|
Loading…
Reference in New Issue