Add network_id column to apic_ml2_ha_ipaddress_to_port_owner table

Add network_id column to apic_ml2_ha_ipaddress_to_port_owner table
to guard against multiple rows of same VIP address.

Change-Id: I2d5a2cfdb4242450140689adc50df2197d4a04b3
This commit is contained in:
Sayali Naval
2021-09-24 11:45:19 -07:00
parent 5e455f8ba1
commit 6ddc59aedc
6 changed files with 214 additions and 115 deletions

View File

@@ -5129,9 +5129,12 @@ class TestMigrations(ApicAimTestCase, db.DbMixin):
for sg_rule in [sg_rule1, sg_rule2]:
self._check_sg_rule(sg['id'], sg_rule)
def test_ha_ip_vrf_name_insertion(self):
net = self._make_network(self.fmt, 'net1', True)
sub = self._make_subnet(self.fmt, net, '10.0.0.1', '10.0.0.0/24')[
def test_ha_ip_duplicate_entries_removal(self):
net1 = self._make_network(self.fmt, 'net1', True)
sub1 = self._make_subnet(self.fmt, net1, '10.0.0.1', '10.0.0.0/24')[
'subnet']
net2 = self._make_network(self.fmt, 'net1', True)
sub2 = self._make_subnet(self.fmt, net2, '10.0.0.2', '10.0.0.0/24')[
'subnet']
allow_addr = [{'ip_address': '1.2.3.250',
'mac_address': '00:00:00:AA:AA:AA'},
@@ -5139,39 +5142,95 @@ class TestMigrations(ApicAimTestCase, db.DbMixin):
'mac_address': '00:00:00:BB:BB:BB'}]
owned_addr = ['1.2.3.250', '1.2.3.251']
# create 2 ports configured with the same allowed-addresses
p1 = self._make_port(self.fmt, net['network']['id'],
p1 = self._make_port(self.fmt, net1['network']['id'],
arg_list=('allowed_address_pairs',),
device_owner='compute:',
fixed_ips=[{'subnet_id': sub['id']}],
fixed_ips=[{'subnet_id': sub1['id']}],
allowed_address_pairs=allow_addr)['port']
self._bind_port_to_host(p1['id'], 'h1')
net_mapping = self._get_network_mapping(
self.db_session, p1['network_id'])
vrf1 = net_mapping.vrf_name
ip_owner_info = {'port': p1['id'],
'ip_address_v4': owned_addr[0],
'network_id': p1['network_id']}
self.update_ip_owner(ip_owner_info)
p1_2 = self._make_port(self.fmt, net1['network']['id'],
arg_list=('allowed_address_pairs',),
device_owner='compute:',
fixed_ips=[{'subnet_id': sub1['id']}],
allowed_address_pairs=allow_addr)['port']
self._bind_port_to_host(p1['id'], 'h1')
ip_owner_info = {'port': p1_2['id'],
'ip_address_v4': owned_addr[0],
'network_id': p1_2['network_id']}
self.update_ip_owner(ip_owner_info)
p2 = self._make_port(self.fmt, net2['network']['id'],
arg_list=('allowed_address_pairs',),
device_owner='compute:',
fixed_ips=[{'subnet_id': sub2['id']}],
allowed_address_pairs=allow_addr)['port']
self._bind_port_to_host(p2['id'], 'h2')
ip_owner_info = {'port': p2['id'],
'ip_address_v4': owned_addr[0],
'network_id': p2['network_id']}
self.update_ip_owner(ip_owner_info)
data_migrations.do_ha_ip_duplicate_entries_removal(self.db_session)
dump = self.get_ha_port_associations()
self.assertEqual(2, len(dump))
def test_ha_ip_network_id_insertion(self):
net1 = self._make_network(self.fmt, 'net1', True)
sub1 = self._make_subnet(self.fmt, net1, '10.0.0.1', '10.0.0.0/24')[
'subnet']
net2 = self._make_network(self.fmt, 'net1', True)
sub2 = self._make_subnet(self.fmt, net2, '10.0.0.2', '10.0.0.0/24')[
'subnet']
allow_addr = [{'ip_address': '1.2.3.250',
'mac_address': '00:00:00:AA:AA:AA'},
{'ip_address': '1.2.3.251',
'mac_address': '00:00:00:BB:BB:BB'}]
owned_addr = ['1.2.3.250', '1.2.3.251']
# create 2 ports configured with the same allowed-addresses
p1 = self._make_port(self.fmt, net1['network']['id'],
arg_list=('allowed_address_pairs',),
device_owner='compute:',
fixed_ips=[{'subnet_id': sub1['id']}],
allowed_address_pairs=allow_addr)['port']
self._bind_port_to_host(p1['id'], 'h1')
ip_owner_info = {'port': p1['id'],
'ip_address_v4': owned_addr[0],
'network_id': p1['network_id']}
self.update_ip_owner(ip_owner_info)
p2 = self._make_port(self.fmt, net2['network']['id'],
arg_list=('allowed_address_pairs',),
device_owner='compute:',
fixed_ips=[{'subnet_id': sub2['id']}],
allowed_address_pairs=allow_addr)['port']
self._bind_port_to_host(p2['id'], 'h2')
ip_owner_info = {'port': p2['id'],
'ip_address_v4': owned_addr[0],
'network_id': p2['network_id']}
self.update_ip_owner(ip_owner_info)
with self.db_session.begin(subtransactions=True):
obj = self.get_port_for_ha_ipaddress_and_vrf(
owned_addr[0], vrf1, p1['network_id'], session=self.db_session)
dump = self.get_ha_port_associations()
self.assertEqual(2, len(dump))
obj = self.get_port_for_ha_ipaddress(
owned_addr[0], p1['network_id'], session=self.db_session)
# check HAIP object details
self.assertEqual(obj['port_id'], p1['id'])
self.assertEqual(obj['ha_ip_address'], owned_addr[0])
self.assertEqual(obj['vrf'], vrf1)
# Wipe out vrf from HAIP object
self.assertEqual(obj['network_id'], p1['network_id'])
# Wipe out network_id from HAIP object
haip_ip = db.HAIPAddressToPortAssociation.ha_ip_address
haip_port_id = db.HAIPAddressToPortAssociation.port_id
self.db_session.query(db.HAIPAddressToPortAssociation).filter(
haip_ip == owned_addr[0]).filter(
haip_port_id == p1['id']).update(
{'vrf': ''})
# check that vrf value is wiped from the object
self.assertEqual(obj['vrf'], '')
{'network_id': ''})
# check that network id value is wiped from the object
self.assertEqual(obj['network_id'], '')
# perform data migration
data_migrations.do_ha_ip_vrf_name_insertion(self.db_session)
# check that vrf value is again added correctly to the obj
self.assertEqual(obj['vrf'], vrf1)
data_migrations.do_ha_ip_network_id_insertion(self.db_session)
# check that network id value is again added correctly to the obj
self.assertEqual(obj['network_id'], p1['network_id'])
class TestPortBinding(ApicAimTestCase):
@@ -6396,77 +6455,73 @@ class TestPortToHAIPAddressBinding(ApicAimTestCase):
self.port1 = self.plugin.create_port(self.context, self.port1_data)
self.port1_2 = self.plugin.create_port(self.context, self.port1_2_data)
self.port2 = self.plugin.create_port(self.context, self.port2_data)
self.net1_id = self.port1['network_id']
self.net2_id = self.port2['network_id']
self.port_haip = db.DbMixin()
self.net1_mapping = self.port_haip._get_network_mapping(
self.db_session, self.port1['network_id'])
self.net2_mapping = self.port_haip._get_network_mapping(
self.db_session, self.port2['network_id'])
self.vrf1 = self.net1_mapping.vrf_name
self.vrf2 = self.net2_mapping.vrf_name
self.port_haip.plugin = self.plugin
def test_update_and_get_port_to_ha_ip_binding(self):
# Test new HA IP address to port binding can be created
obj = self.port_haip.update_port_id_for_ha_ipaddress(
self.port1['id'], self.ha_ip1, 'vrf1')
self.port1['id'], self.ha_ip1, self.net1_id)
self.assertEqual(self.port1['id'], obj['port_id'])
self.assertEqual(self.ha_ip1, obj['ha_ip_address'])
# In this test case we also test that same HA IP address can be set/get
# for two different ports in different networks
obj = self.port_haip.update_port_id_for_ha_ipaddress(
self.port2['id'], self.ha_ip1, 'vrf2')
self.port2['id'], self.ha_ip1, self.net2_id)
self.assertEqual(self.port2['id'], obj['port_id'])
self.assertEqual(self.ha_ip1, obj['ha_ip_address'])
# Test get
obj = self.port_haip.get_port_for_ha_ipaddress_and_vrf(
self.ha_ip1, 'vrf1', self.port1['network_id'])
obj = self.port_haip.get_port_for_ha_ipaddress(
self.ha_ip1, self.net1_id)
self.assertEqual(self.port1['id'], obj['port_id'])
obj = self.port_haip.get_port_for_ha_ipaddress_and_vrf(
self.ha_ip1, 'vrf2', self.port2['network_id'])
obj = self.port_haip.get_port_for_ha_ipaddress(
self.ha_ip1, self.net2_id)
self.assertEqual(self.port2['id'], obj['port_id'])
def test_port_to_multiple_ha_ip_binding(self):
self.port_haip.update_port_id_for_ha_ipaddress(self.port1['id'],
self.ha_ip1,
self.vrf1)
self.net1_id)
self.port_haip.update_port_id_for_ha_ipaddress(self.port1['id'],
self.ha_ip2,
self.vrf1)
obj = self.port_haip.get_port_for_ha_ipaddress_and_vrf(
self.ha_ip1, self.vrf1, self.port1['network_id'])
self.net1_id)
obj = self.port_haip.get_port_for_ha_ipaddress(
self.ha_ip1, self.net1_id)
self.assertEqual(self.port1['id'], obj['port_id'])
obj = self.port_haip.get_port_for_ha_ipaddress_and_vrf(
self.ha_ip2, self.vrf1, self.port1['network_id'])
obj = self.port_haip.get_port_for_ha_ipaddress(
self.ha_ip2, self.net1_id)
self.assertEqual(self.port1['id'], obj['port_id'])
def test_delete_port_for_ha_ip_binding(self):
self.port_haip.update_port_id_for_ha_ipaddress(self.port1['id'],
self.ha_ip1,
self.vrf1)
self.net1_id)
result = self.port_haip.delete_port_id_for_ha_ipaddress(
self.port1['id'], self.ha_ip1)
self.assertEqual(1, result)
obj = self.port_haip.get_port_for_ha_ipaddress_and_vrf(
self.ha_ip1, self.vrf2, self.port2['network_id'])
obj = self.port_haip.get_port_for_ha_ipaddress(
self.ha_ip1, self.net2_id)
self.assertIsNone(obj)
def test_get_ha_ip_addresses_for_port(self):
self.port_haip.update_port_id_for_ha_ipaddress(self.port1['id'],
self.ha_ip1,
self.vrf1)
self.net1_id)
self.port_haip.update_port_id_for_ha_ipaddress(self.port1['id'],
self.ha_ip2,
self.vrf1)
self.net1_id)
ha_ips = self.port_haip.get_ha_ipaddresses_for_port(self.port1['id'])
self.assertEqual(sorted([self.ha_ip1, self.ha_ip2]), ha_ips)
def test_idempotent(self):
self.port_haip.update_port_id_for_ha_ipaddress(self.port1['id'],
self.ha_ip1,
self.vrf1)
self.net1_id)
obj = self.port_haip.update_port_id_for_ha_ipaddress(self.port1['id'],
self.ha_ip1,
self.vrf1)
self.net1_id)
self.assertEqual(self.port1['id'], obj['port_id'])
self.assertEqual(self.ha_ip1, obj['ha_ip_address'])
@@ -6478,7 +6533,7 @@ class TestPortToHAIPAddressBinding(ApicAimTestCase):
def test_delete_non_existing_entry(self):
self.port_haip.update_port_id_for_ha_ipaddress(self.port1['id'],
self.ha_ip1,
self.vrf1)
self.net1_id)
result = self.port_haip.delete_port_id_for_ha_ipaddress(
self.port1['id'], "fake")
self.assertEqual(0, result)
@@ -6492,21 +6547,21 @@ class TestPortToHAIPAddressBinding(ApicAimTestCase):
# set new owner
ports = self.port_haip.update_ip_owner(ip_owner_info)
obj = self.port_haip.get_port_for_ha_ipaddress_and_vrf(
self.ha_ip1, self.vrf1, self.port1['network_id'])
obj = self.port_haip.get_port_for_ha_ipaddress(
self.ha_ip1, self.net1_id)
self.assertEqual(self.port1['id'], obj['port_id'])
self.assertTrue(self.port1['id'] in ports)
# update owner
self.port2_data['port']['id'] = _uuid()
self.port2_data['port']['network_id'] = self.port1['network_id']
self.port2_data['port']['network_id'] = self.net1_id
self.port2_data['port']['mac_address'] = 'fake-mac-3'
port3 = self.plugin.create_port(self.context, self.port2_data)
ip_owner_info['port'] = port3['id']
ports = self.port_haip.update_ip_owner(ip_owner_info)
obj = self.port_haip.get_port_for_ha_ipaddress_and_vrf(
self.ha_ip1, self.vrf2, port3['network_id'])
obj = self.port_haip.get_port_for_ha_ipaddress(
self.ha_ip1, port3['network_id'])
self.assertEqual(port3['id'], obj['port_id'])
def test_ip_replaced(self):
@@ -6538,16 +6593,16 @@ class TestPortToHAIPAddressBinding(ApicAimTestCase):
def test_duplicate_entry_handled_gracefully(self):
self.port_haip.update_port_id_for_ha_ipaddress(
self.port1['id'], self.ha_ip1, self.vrf1)
self.port1['id'], self.ha_ip1, self.net1_id)
# Set this twice, without hijacking the query
obj = self.port_haip.update_port_id_for_ha_ipaddress(
self.port1['id'], self.ha_ip1, self.vrf1)
self.port1['id'], self.ha_ip1, self.net1_id)
self.assertEqual(obj.port_id, self.port1['id'])
self.assertEqual(obj.ha_ip_address, self.ha_ip1)
# Now simulate null return from query
self.port_haip._get_ha_ipaddress = mock.Mock(return_value=None)
obj = self.port_haip.update_port_id_for_ha_ipaddress(
self.port1['id'], self.ha_ip1, self.vrf1)
self.port1['id'], self.ha_ip1, self.net1_id)
self.assertIsNone(obj)
@@ -12147,10 +12202,8 @@ class TestOpflexRpc(ApicAimTestCase):
self.driver.ip_address_owner_update(
n_context.get_admin_context(), ip_owner_info=ip_owner_info,
host='h1')
mapping = self.driver._get_network_mapping(self.db_session, net_id)
vrf_name = mapping.vrf_name
obj = self.driver.get_port_for_ha_ipaddress_and_vrf(
'1.2.3.4', vrf_name, net_id)
obj = self.driver.get_port_for_ha_ipaddress(
'1.2.3.4', net_id)
self.assertEqual(port1_id, obj['port_id'])
self.driver._notify_port_update.assert_called_with(
mock.ANY, port1_id)
@@ -12161,8 +12214,8 @@ class TestOpflexRpc(ApicAimTestCase):
self.driver.ip_address_owner_update(
n_context.get_admin_context(), ip_owner_info=ip_owner_info,
host='h2')
obj = self.driver.get_port_for_ha_ipaddress_and_vrf(
'1.2.3.4', vrf_name, net_id)
obj = self.driver.get_port_for_ha_ipaddress(
'1.2.3.4', net_id)
self.assertEqual(port2_id, obj['port_id'])
exp_calls = [
mock.call(mock.ANY, port1_id),

View File

@@ -3747,11 +3747,8 @@ class TestPolicyTarget(AIMBaseTestCase,
# set new owner
self.mech_driver.ip_address_owner_update(self._context,
ip_owner_info=ip_owner_info, host='h1')
mapping = self.mech_driver._get_network_mapping(
self.db_session, net_id)
vrf_name = mapping.vrf_name
obj = self.mech_driver.get_port_for_ha_ipaddress_and_vrf(
'1.2.3.4', vrf_name, net_id)
obj = self.mech_driver.get_port_for_ha_ipaddress(
'1.2.3.4', net_id)
self.assertEqual(pt1['port_id'], obj['port_id'])
self.mech_driver._notify_port_update.assert_called_with(
@@ -3762,8 +3759,8 @@ class TestPolicyTarget(AIMBaseTestCase,
ip_owner_info['port'] = pt2['port_id']
self.mech_driver.ip_address_owner_update(self._context,
ip_owner_info=ip_owner_info, host='h2')
obj = self.mech_driver.get_port_for_ha_ipaddress_and_vrf(
'1.2.3.4', vrf_name, net_id)
obj = self.mech_driver.get_port_for_ha_ipaddress(
'1.2.3.4', net_id)
self.assertEqual(pt2['port_id'], obj['port_id'])
exp_calls = [
mock.call(mock.ANY, pt1['port_id']),