Allow to create vip in lb-mgmt-net

Change-Id: Ie2c916bd557190e5dfead12c2635955da92c52ff
Closes-Bug: #1659488
This commit is contained in:
Adam Harwell 2017-02-08 13:07:21 -08:00 committed by Lubosz Kosnik (diltram)
parent 0d275928b3
commit e1ec15c9a8
5 changed files with 180 additions and 32 deletions

View File

@ -74,10 +74,14 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
ret.append(interface)
return ret
def _get_plugged_interface(self, compute_id, network_id):
def _get_plugged_interface(self, compute_id, network_id, lb_network_ip):
interfaces = self.get_plugged_networks(compute_id)
for interface in interfaces:
if interface.network_id == network_id:
is_correct_interface = interface.network_id == network_id
for ip in interface.fixed_ips:
if ip.ip_address == lb_network_ip:
is_correct_interface = False
if is_correct_interface:
return interface
def _plug_amphora_vip(self, amphora, subnet):
@ -299,8 +303,8 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
lambda amp: amp.status == constants.AMPHORA_ALLOCATED,
load_balancer.amphorae):
interface = self._get_plugged_interface(amphora.compute_id,
subnet.network_id)
interface = self._get_plugged_interface(
amphora.compute_id, subnet.network_id, amphora.lb_network_ip)
if not interface:
interface = self._plug_amphora_vip(amphora, subnet)
@ -310,7 +314,9 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
interface.port_id)
vrrp_ip = None
for fixed_ip in interface.fixed_ips:
if fixed_ip.subnet_id == subnet.id:
is_correct_subnet = fixed_ip.subnet_id == subnet.id
is_management_ip = fixed_ip.ip_address == amphora.lb_network_ip
if is_correct_subnet and not is_management_ip:
vrrp_ip = fixed_ip.ip_address
break
plugged_amphorae.append(data_models.Amphora(
@ -358,8 +364,8 @@ class AllowedAddressPairsDriver(neutron_base.BaseNeutronDriver):
lambda amp: amp.status == constants.AMPHORA_ALLOCATED,
load_balancer.amphorae):
interface = self._get_plugged_interface(amphora.compute_id,
subnet.network_id)
interface = self._get_plugged_interface(
amphora.compute_id, subnet.network_id, amphora.lb_network_ip)
if not interface:
# Thought about raising PluggedVIPNotFound exception but
# then that wouldn't evaluate all amphorae, so just continue

View File

@ -18,14 +18,18 @@ class MockNovaInterface(object):
port_id = None
fixed_ips = []
MOCK_NETWORK_ID = '1'
MOCK_NETWORK_ID = 'mock-network-1'
MOCK_NETWORK_ID2 = 'mock-network-2'
MOCK_NETWORK_NAME = 'TestNet1'
MOCK_SUBNET_ID = '2'
MOCK_SUBNET_ID = 'mock-subnet-1'
MOCK_SUBNET_ID2 = 'mock-subnet-2'
MOCK_SUBNET_NAME = 'TestSubnet1'
MOCK_PORT_ID = '3'
MOCK_PORT_ID = 'mock-port-1'
MOCK_PORT_ID2 = 'mock-port-2'
MOCK_PORT_NAME = 'TestPort1'
MOCK_COMPUTE_ID = '4'
MOCK_COMPUTE_ID = 'mock-compute-1'
MOCK_IP_ADDRESS = '10.0.0.1'
MOCK_IP_ADDRESS2 = '10.0.0.2'
MOCK_CIDR = '10.0.0.0/24'
MOCK_MAC_ADDR = 'fe:16:3e:00:95:5c'
MOCK_NOVA_INTERFACE = MockNovaInterface()
@ -33,6 +37,12 @@ MOCK_SUBNET = {'subnet': {'id': MOCK_SUBNET_ID, 'network_id': MOCK_NETWORK_ID}}
MOCK_NOVA_INTERFACE.net_id = MOCK_NETWORK_ID
MOCK_NOVA_INTERFACE.port_id = MOCK_PORT_ID
MOCK_NOVA_INTERFACE.fixed_ips = [{'ip_address': MOCK_IP_ADDRESS}]
MOCK_NOVA_INTERFACE2 = MockNovaInterface()
MOCK_SUBNET2 = {'subnet': {'id': MOCK_SUBNET_ID2,
'network_id': MOCK_NETWORK_ID2}}
MOCK_NOVA_INTERFACE2.net_id = MOCK_NETWORK_ID2
MOCK_NOVA_INTERFACE2.port_id = MOCK_PORT_ID2
MOCK_NOVA_INTERFACE2.fixed_ips = [{'ip_address': MOCK_IP_ADDRESS2}]
MOCK_DEVICE_OWNER = 'Moctavia'
MOCK_DEVICE_ID = 'Moctavia123'
@ -42,3 +52,76 @@ MOCK_NEUTRON_PORT = {'port': {'network_id': MOCK_NETWORK_ID,
'id': MOCK_PORT_ID,
'fixed_ips': [{'ip_address': MOCK_IP_ADDRESS,
'subnet_id': MOCK_SUBNET_ID}]}}
MOCK_AMP_ID1 = 'amp1-id'
MOCK_AMP_ID2 = 'amp2-id'
MOCK_AMP_COMPUTE_ID1 = 'amp1-compute-id'
MOCK_AMP_COMPUTE_ID2 = 'amp2-compute-id'
MOCK_MANAGEMENT_SUBNET_ID = 'mgmt-subnet-1'
MOCK_MANAGEMENT_NET_ID = 'mgmt-net-1'
MOCK_MANAGEMENT_PORT_ID1 = 'mgmt-port-1'
MOCK_MANAGEMENT_PORT_ID2 = 'mgmt-port-2'
# These IPs become lb_network_ip
MOCK_MANAGEMENT_IP1 = '99.99.99.1'
MOCK_MANAGEMENT_IP2 = '99.99.99.2'
MOCK_MANAGEMENT_FIXED_IPS1 = [{'ip_address': MOCK_MANAGEMENT_IP1,
'subnet_id': MOCK_MANAGEMENT_SUBNET_ID}]
MOCK_MANAGEMENT_FIXED_IPS2 = [{'ip_address': MOCK_MANAGEMENT_IP2,
'subnet_id': MOCK_MANAGEMENT_SUBNET_ID}]
MOCK_MANAGEMENT_INTERFACE1 = MockNovaInterface()
MOCK_MANAGEMENT_INTERFACE1.net_id = MOCK_MANAGEMENT_NET_ID
MOCK_MANAGEMENT_INTERFACE1.port_id = MOCK_MANAGEMENT_PORT_ID1
MOCK_MANAGEMENT_INTERFACE1.fixed_ips = MOCK_MANAGEMENT_FIXED_IPS1
MOCK_MANAGEMENT_INTERFACE2 = MockNovaInterface()
MOCK_MANAGEMENT_INTERFACE2.net_id = MOCK_MANAGEMENT_NET_ID
MOCK_MANAGEMENT_INTERFACE2.port_id = MOCK_MANAGEMENT_PORT_ID2
MOCK_MANAGEMENT_INTERFACE2.fixed_ips = MOCK_MANAGEMENT_FIXED_IPS2
MOCK_MANAGEMENT_PORT1 = {'port': {'network_id': MOCK_MANAGEMENT_NET_ID,
'device_id': MOCK_AMP_COMPUTE_ID1,
'device_owner': MOCK_DEVICE_OWNER,
'id': MOCK_MANAGEMENT_PORT_ID1,
'fixed_ips': MOCK_MANAGEMENT_FIXED_IPS1}}
MOCK_MANAGEMENT_PORT2 = {'port': {'network_id': MOCK_MANAGEMENT_NET_ID,
'device_id': MOCK_AMP_COMPUTE_ID2,
'device_owner': MOCK_DEVICE_OWNER,
'id': MOCK_MANAGEMENT_PORT_ID2,
'fixed_ips': MOCK_MANAGEMENT_FIXED_IPS2}}
MOCK_VIP_SUBNET_ID = 'vip-subnet-1'
MOCK_VIP_NET_ID = 'vip-net-1'
MOCK_VRRP_PORT_ID1 = 'vrrp-port-1'
MOCK_VRRP_PORT_ID2 = 'vrrp-port-2'
# These IPs become vrrp_ip
MOCK_VRRP_IP1 = '55.55.55.1'
MOCK_VRRP_IP2 = '55.55.55.2'
MOCK_VRRP_FIXED_IPS1 = [{'ip_address': MOCK_VRRP_IP1,
'subnet_id': MOCK_VIP_SUBNET_ID}]
MOCK_VRRP_FIXED_IPS2 = [{'ip_address': MOCK_VRRP_IP2,
'subnet_id': MOCK_VIP_SUBNET_ID}]
MOCK_VRRP_INTERFACE1 = MockNovaInterface()
MOCK_VRRP_INTERFACE1.net_id = MOCK_VIP_NET_ID
MOCK_VRRP_INTERFACE1.port_id = MOCK_VRRP_PORT_ID1
MOCK_VRRP_INTERFACE1.fixed_ips = MOCK_VRRP_FIXED_IPS1
MOCK_VRRP_INTERFACE2 = MockNovaInterface()
MOCK_VRRP_INTERFACE2.net_id = MOCK_VIP_NET_ID
MOCK_VRRP_INTERFACE2.port_id = MOCK_VRRP_PORT_ID2
MOCK_VRRP_INTERFACE2.fixed_ips = MOCK_VRRP_FIXED_IPS2
MOCK_VRRP_PORT1 = {'port': {'network_id': MOCK_VIP_NET_ID,
'device_id': MOCK_AMP_COMPUTE_ID1,
'device_owner': MOCK_DEVICE_OWNER,
'id': MOCK_VRRP_PORT_ID1,
'fixed_ips': MOCK_VRRP_FIXED_IPS1}}
MOCK_VRRP_PORT2 = {'port': {'network_id': MOCK_VIP_NET_ID,
'device_id': MOCK_AMP_COMPUTE_ID2,
'device_owner': MOCK_DEVICE_OWNER,
'id': MOCK_VRRP_PORT_ID2,
'fixed_ips': MOCK_VRRP_FIXED_IPS2}}

View File

@ -14,6 +14,7 @@
from octavia.common import constants
from octavia.common import data_models
from octavia.tests.common import constants as ut_constants
def generate_load_balancer_tree():
@ -54,8 +55,8 @@ def generate_vip(load_balancer=None):
global VIP_SEED
VIP_SEED += 1
vip = data_models.Vip(ip_address='10.0.0.{0}'.format(VIP_SEED),
subnet_id='subnet{0}-id'.format(VIP_SEED),
port_id='port{0}-id'.format(VIP_SEED),
subnet_id=ut_constants.MOCK_VIP_SUBNET_ID,
port_id='vrrp-port-{0}'.format(VIP_SEED),
load_balancer=load_balancer)
if load_balancer:
vip.load_balancer_id = load_balancer.id
@ -69,10 +70,10 @@ def generate_amphora(load_balancer=None):
global AMP_SEED
AMP_SEED += 1
amp = data_models.Amphora(id='amp{0}-id'.format(AMP_SEED),
compute_id='compute{0}-id'.format(AMP_SEED),
compute_id='amp{0}-compute-id'.format(AMP_SEED),
status='ACTIVE',
lb_network_ip='11.0.0.{0}'.format(AMP_SEED),
vrrp_ip='12.0.0.{0}'.format(AMP_SEED),
lb_network_ip='99.99.99.{0}'.format(AMP_SEED),
vrrp_ip='55.55.55.{0}'.format(AMP_SEED),
load_balancer=load_balancer)
if load_balancer:
amp.load_balancer_id = load_balancer.id

View File

@ -252,11 +252,17 @@ class TestAllowedAddressPairsDriver(base.TestCase):
show_subnet = self.driver.neutron_client.show_subnet
show_subnet.return_value = {
'subnet': {
'id': lb.vip.subnet_id
'id': t_constants.MOCK_VIP_SUBNET_ID,
'network_id': t_constants.MOCK_VIP_NET_ID
}
}
list_ports = self.driver.neutron_client.list_ports
port1 = t_constants.MOCK_MANAGEMENT_PORT1['port']
port2 = t_constants.MOCK_MANAGEMENT_PORT2['port']
list_ports.side_effect = [{'ports': [port1]}, {'ports': [port2]}]
interface_attach = self.driver.nova_client.servers.interface_attach
interface_attach.return_value = t_constants.MOCK_NOVA_INTERFACE
interface_attach.side_effect = [t_constants.MOCK_VRRP_INTERFACE1,
t_constants.MOCK_VRRP_INTERFACE2]
list_security_groups = self.driver.neutron_client.list_security_groups
list_security_groups.return_value = {
'security_groups': [
@ -266,22 +272,69 @@ class TestAllowedAddressPairsDriver(base.TestCase):
update_port = self.driver.neutron_client.update_port
expected_aap = {'port': {'allowed_address_pairs':
[{'ip_address': lb.vip.ip_address}]}}
interface_list = self.driver.nova_client.servers.interface_list
if1 = t_constants.MOCK_NOVA_INTERFACE
if2 = t_constants.MockNovaInterface()
if2.net_id = '3'
if2.port_id = '4'
if2.fixed_ips = [{'ip_address': '10.0.0.2'}]
if1.fixed_ips = [{'ip_address': t_constants.MOCK_IP_ADDRESS,
'subnet_id': lb.vip.subnet_id}]
interface_list.return_value = [if1, if2]
amps = self.driver.plug_vip(lb, lb.vip)
self.assertEqual(5, update_port.call_count)
update_port.assert_any_call(if1.port_id, expected_aap)
for amp in amps:
self.assertEqual(t_constants.MOCK_IP_ADDRESS, amp.vrrp_ip)
update_port.assert_any_call(amp.vrrp_port_id, expected_aap)
self.assertIn(amp.vrrp_ip, [t_constants.MOCK_VRRP_IP1,
t_constants.MOCK_VRRP_IP2])
self.assertEqual(lb.vip.ip_address, amp.ha_ip)
def _set_safely(self, obj, name, value):
if isinstance(obj, dict):
current = obj.get(name)
self.addCleanup(obj.update, {name: current})
obj.update({name: value})
else:
current = getattr(obj, name)
self.addCleanup(setattr, obj, name, current)
setattr(obj, name, value)
def test_plug_vip_on_mgmt_net(self):
lb = dmh.generate_load_balancer_tree()
lb.vip.subnet_id = t_constants.MOCK_MANAGEMENT_SUBNET_ID
show_subnet = self.driver.neutron_client.show_subnet
show_subnet.return_value = {
'subnet': {
'id': t_constants.MOCK_MANAGEMENT_SUBNET_ID,
'network_id': t_constants.MOCK_MANAGEMENT_NET_ID
}
}
list_ports = self.driver.neutron_client.list_ports
port1 = t_constants.MOCK_MANAGEMENT_PORT1['port']
port2 = t_constants.MOCK_MANAGEMENT_PORT2['port']
self._set_safely(t_constants.MOCK_MANAGEMENT_FIXED_IPS1[0],
'ip_address', lb.amphorae[0].lb_network_ip)
self._set_safely(t_constants.MOCK_MANAGEMENT_FIXED_IPS2[0],
'ip_address', lb.amphorae[1].lb_network_ip)
list_ports.side_effect = [{'ports': [port1]}, {'ports': [port2]}]
interface_attach = self.driver.nova_client.servers.interface_attach
self._set_safely(t_constants.MOCK_VRRP_INTERFACE1,
'net_id', t_constants.MOCK_MANAGEMENT_NET_ID)
self._set_safely(t_constants.MOCK_VRRP_FIXED_IPS1[0],
'subnet_id', t_constants.MOCK_MANAGEMENT_SUBNET_ID)
self._set_safely(t_constants.MOCK_VRRP_INTERFACE2,
'net_id', t_constants.MOCK_MANAGEMENT_NET_ID)
self._set_safely(t_constants.MOCK_VRRP_FIXED_IPS2[0],
'subnet_id', t_constants.MOCK_MANAGEMENT_SUBNET_ID)
interface_attach.side_effect = [t_constants.MOCK_VRRP_INTERFACE1,
t_constants.MOCK_VRRP_INTERFACE2]
list_security_groups = self.driver.neutron_client.list_security_groups
list_security_groups.return_value = {
'security_groups': [
{'id': 'lb-sec-grp1'}
]
}
update_port = self.driver.neutron_client.update_port
expected_aap = {'port': {'allowed_address_pairs':
[{'ip_address': lb.vip.ip_address}]}}
amps = self.driver.plug_vip(lb, lb.vip)
self.assertEqual(5, update_port.call_count)
for amp in amps:
update_port.assert_any_call(amp.vrrp_port_id, expected_aap)
self.assertIn(amp.vrrp_ip, [t_constants.MOCK_VRRP_IP1,
t_constants.MOCK_VRRP_IP2])
self.assertEqual(lb.vip.ip_address, amp.ha_ip)
self.assertIn(amp.id, [lb.amphorae[0].id, lb.amphorae[1].id])
def test_allocate_vip_when_port_already_provided(self):
show_port = self.driver.neutron_client.show_port
@ -306,7 +359,7 @@ class TestAllowedAddressPairsDriver(base.TestCase):
self.assertRaises(network_base.AllocateVIPException,
self.driver.allocate_vip, fake_lb)
def test_allocate_vip_when_only_subnet_provided(self):
def test_allocate_vip_when_no_port_provided(self):
port_create_dict = copy.copy(t_constants.MOCK_NEUTRON_PORT)
port_create_dict['port']['device_owner'] = (
allowed_address_pairs.OCTAVIA_OWNER)
@ -433,7 +486,8 @@ class TestAllowedAddressPairsDriver(base.TestCase):
actual_ips = [fixed_ip.ip_address
for fixed_ip in oct_interface.fixed_ips]
self.assertEqual(exp_ips, actual_ips)
self.assertEqual(t_constants.MOCK_COMPUTE_ID, oct_interface.compute_id)
self.assertEqual(t_constants.MOCK_COMPUTE_ID,
oct_interface.compute_id)
self.assertEqual(net_id, oct_interface.network_id)
def test_unplug_network_when_compute_port_cant_be_found(self):

View File

@ -0,0 +1,4 @@
---
fixes:
- Allow the loadbalancer's VIP to be created on the same
network as the management interface.