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
(cherry picked from commit ec3c42a2ad
)
This commit is contained in:
parent
831c47f0c9
commit
60a7db5f52
|
@ -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