[OVN] Update metadata port ony for requested subnet
When a subnet is updated or created, the metadata port is updated too,
to add the fixed IP address of the new subnet. In this case, the port
should update only the IP address of this specific subnet.
Change-Id: I05394e49077a72199bbc80c8cb622ec2b17f2fa7
Closes-Bug: #1890432
(cherry picked from commit 93225e016b
)
This commit is contained in:
parent
04e1a63979
commit
9c43b4e7a0
|
@ -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)
|
||||
|
|
|
@ -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')
|
||||
|
|
Loading…
Reference in New Issue