Merge "[OVN] Update metadata port ony for requested subnet" into stable/victoria

This commit is contained in:
Zuul 2021-02-08 13:28:12 +00:00 committed by Gerrit Code Review
commit a97046e981
2 changed files with 91 additions and 24 deletions

View File

@ -1951,7 +1951,8 @@ class OVNClient(object):
def create_subnet(self, context, subnet, network):
if subnet['enable_dhcp']:
if subnet['ip_version'] == 4:
self.update_metadata_port(context, network['id'])
self.update_metadata_port(context, network['id'],
subnet_id=subnet['id'])
self._add_subnet_dhcp_options(subnet, network)
db_rev.bump_revision(context, subnet, ovn_const.TYPE_SUBNETS)
@ -1968,7 +1969,8 @@ class OVNClient(object):
subnet['id'])['subnet']
if subnet['enable_dhcp'] or ovn_subnet:
self.update_metadata_port(context, network['id'])
self.update_metadata_port(context, network['id'],
subnet_id=subnet['id'])
check_rev_cmd = self._nb_idl.check_revision_number(
subnet['id'], subnet, ovn_const.TYPE_SUBNETS)
@ -2076,12 +2078,24 @@ class OVNClient(object):
# TODO(boden): rehome create_port into neutron-lib
p_utils.create_port(self._plugin, context, port)
def update_metadata_port(self, context, network_id):
def update_metadata_port(self, context, network_id, subnet_id=None):
"""Update metadata port.
This function will allocate an IP address for the metadata port of
the given network in all its IPv4 subnets.
the given network in all its IPv4 subnets or the given subnet.
"""
def update_metadata_port_fixed_ips(metadata_port, subnet_ids):
wanted_fixed_ips = [
{'subnet_id': fixed_ip['subnet_id'],
'ip_address': fixed_ip['ip_address']} for fixed_ip in
metadata_port['fixed_ips']]
wanted_fixed_ips.extend({'subnet_id': s_id} for s_id in subnet_ids)
port = {'id': metadata_port['id'],
'port': {'network_id': network_id,
'fixed_ips': wanted_fixed_ips}}
self._plugin.update_port(n_context.get_admin_context(),
metadata_port['id'], port)
if not ovn_conf.is_ovn_metadata_enabled():
return
@ -2092,31 +2106,28 @@ class OVNClient(object):
network_id)
return
port_subnet_ids = set(ip['subnet_id'] for ip in
metadata_port['fixed_ips'])
# If this method is called from "create_subnet" or "update_subnet",
# only the fixed IP address from this subnet should be updated in the
# metadata port.
if subnet_id:
if subnet_id not in port_subnet_ids:
update_metadata_port_fixed_ips(metadata_port, [subnet_id])
return
# Retrieve all subnets in this network
subnets = self._plugin.get_subnets(context, filters=dict(
network_id=[network_id], ip_version=[4]))
subnet_ids = set(s['id'] for s in subnets)
port_subnet_ids = set(ip['subnet_id'] for ip in
metadata_port['fixed_ips'])
# Find all subnets where metadata port doesn't have an IP in and
# allocate one.
if subnet_ids != port_subnet_ids:
wanted_fixed_ips = []
for fixed_ip in metadata_port['fixed_ips']:
wanted_fixed_ips.append(
{'subnet_id': fixed_ip['subnet_id'],
'ip_address': fixed_ip['ip_address']})
wanted_fixed_ips.extend(
dict(subnet_id=s)
for s in subnet_ids - port_subnet_ids)
port = {'id': metadata_port['id'],
'port': {'network_id': network_id,
'fixed_ips': wanted_fixed_ips}}
self._plugin.update_port(n_context.get_admin_context(),
metadata_port['id'], port)
update_metadata_port_fixed_ips(metadata_port,
subnet_ids - port_subnet_ids)
def get_parent_port(self, port_id):
return self._nb_idl.get_parent_port(port_id)

View File

@ -1504,13 +1504,13 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
self.mech_driver.update_subnet_postcommit(context)
esd.assert_called_once_with(
context.current, context.network.current, mock.ANY)
umd.assert_called_once_with(mock.ANY, 'id')
umd.assert_called_once_with(mock.ANY, 'id', subnet_id='subnet_id')
def test_update_subnet_postcommit_disable_dhcp(self):
self.mech_driver._nb_ovn.get_subnet_dhcp_options.return_value = {
'subnet': mock.sentinel.subnet, 'ports': []}
context = fakes.FakeSubnetContext(
subnet={'enable_dhcp': False, 'id': 'fake_id', 'ip_version': 4,
subnet={'enable_dhcp': False, 'id': 'subnet_id', 'ip_version': 4,
'network_id': 'id'},
network={'id': 'id'})
with mock.patch.object(
@ -1521,7 +1521,7 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
'update_metadata_port') as umd:
self.mech_driver.update_subnet_postcommit(context)
dsd.assert_called_once_with(context.current['id'], mock.ANY)
umd.assert_called_once_with(mock.ANY, 'id')
umd.assert_called_once_with(mock.ANY, 'id', subnet_id='subnet_id')
def test_update_subnet_postcommit_update_dhcp(self):
self.mech_driver._nb_ovn.get_subnet_dhcp_options.return_value = {
@ -1539,7 +1539,63 @@ class TestOVNMechanismDriver(test_plugin.Ml2PluginV2TestCase):
self.mech_driver.update_subnet_postcommit(context)
usd.assert_called_once_with(
context.current, context.network.current, mock.ANY)
umd.assert_called_once_with(mock.ANY, 'id')
umd.assert_called_once_with(mock.ANY, 'id', subnet_id='subnet_id')
def test_update_metadata_port_with_subnet_present_in_port(self):
ovn_conf.cfg.CONF.set_override('ovn_metadata_enabled', True,
group='ovn')
fixed_ips = [{'subnet_id': 'subnet1', 'ip_address': 'ip_add1'}]
with mock.patch.object(
self.mech_driver._ovn_client, '_find_metadata_port',
return_value={'fixed_ips': fixed_ips, 'id': 'metadata_id'}), \
mock.patch.object(self.mech_driver._plugin, 'get_subnets',
return_value=[{'id': 'subnet1'},
{'id': 'subnet2'}]), \
mock.patch.object(self.mech_driver._plugin, 'update_port') as \
mock_update_port:
self.mech_driver._ovn_client.update_metadata_port(
self.context, 'net_id', subnet_id='subnet1')
mock_update_port.assert_not_called()
def test_update_metadata_port_with_subnet_not_present_in_port(self):
ovn_conf.cfg.CONF.set_override('ovn_metadata_enabled', True,
group='ovn')
fixed_ips = [{'subnet_id': 'subnet1', 'ip_address': 'ip_add1'}]
with mock.patch.object(
self.mech_driver._ovn_client, '_find_metadata_port',
return_value={'fixed_ips': fixed_ips, 'id': 'metadata_id'}), \
mock.patch.object(self.mech_driver._plugin, 'get_subnets',
return_value=[{'id': 'subnet1'},
{'id': 'subnet2'}]), \
mock.patch.object(self.mech_driver._plugin, 'update_port') as \
mock_update_port:
self.mech_driver._ovn_client.update_metadata_port(
self.context, 'net_id', subnet_id='subnet3')
fixed_ips.append({'subnet_id': 'subnet3'})
port = {'id': 'metadata_id', 'port': {
'network_id': 'net_id', 'fixed_ips': fixed_ips}}
mock_update_port.assert_called_once_with(
mock.ANY, 'metadata_id', port)
def test_update_metadata_port_no_subnet(self):
ovn_conf.cfg.CONF.set_override('ovn_metadata_enabled', True,
group='ovn')
fixed_ips = [{'subnet_id': 'subnet1', 'ip_address': 'ip_add1'}]
with mock.patch.object(
self.mech_driver._ovn_client, '_find_metadata_port',
return_value={'fixed_ips': fixed_ips, 'id': 'metadata_id'}), \
mock.patch.object(self.mech_driver._plugin, 'get_subnets',
return_value=[{'id': 'subnet1'},
{'id': 'subnet2'}]), \
mock.patch.object(self.mech_driver._plugin, 'update_port') as \
mock_update_port:
self.mech_driver._ovn_client.update_metadata_port(self.context,
'net_id')
fixed_ips.append({'subnet_id': 'subnet2'})
port = {'id': 'metadata_id', 'port': {
'network_id': 'net_id', 'fixed_ips': fixed_ips}}
mock_update_port.assert_called_once_with(
mock.ANY, 'metadata_id', port)
@mock.patch.object(provisioning_blocks, 'is_object_blocked')
@mock.patch.object(provisioning_blocks, 'provisioning_complete')