Merge "[OVN] Prevent deleting the only IP of a router port" into stable/ussuri

This commit is contained in:
Zuul 2022-01-11 14:06:31 +00:00 committed by Gerrit Code Review
commit 3cdb5c81bd
3 changed files with 49 additions and 2 deletions

View File

@ -30,6 +30,7 @@ from neutron_lib.services import base as service_base
from oslo_log import log
from oslo_utils import excutils
from neutron._i18n import _
from neutron.common.ovn import constants as ovn_const
from neutron.common.ovn import extensions
from neutron.common.ovn import utils
@ -457,15 +458,33 @@ class OVNL3RouterPlugin(service_base.ServicePluginBase,
context, router_id, add, remove, txn=txn)
@staticmethod
@registry.receives(resources.PORT, [events.AFTER_UPDATE])
@registry.receives(
resources.PORT,
[events.BEFORE_UPDATE, events.AFTER_UPDATE]
)
def _port_update(resource, event, trigger, **kwargs):
l3plugin = directory.get_plugin(plugin_constants.L3)
if not l3plugin:
return
current = kwargs['port']
original = kwargs['original_port']
if utils.is_lsp_router_port(current):
# The OVN NB DB has a constraint where network has to be
# greater than 0. Updating it with an empty network would
# cause a constraint violation error. This problem happens
# when the last IP of a LRP is deleted, in order to avoid it
# an exception needs to be thrown before any write is performed
# to the DB, since if not it would leave the Neutron DB and the
# OVN DB unsync.
# https://bugs.launchpad.net/neutron/+bug/1948457
if (event == events.BEFORE_UPDATE and
'fixed_ips' in current and not current['fixed_ips'] and
utils.is_lsp_router_port(original)):
reason = _("Router port must have at least one IP.")
raise n_exc.ServicePortInUse(port_id=original['id'], reason=reason)
if event == events.AFTER_UPDATE and utils.is_lsp_router_port(current):
# We call the update_router port with if_exists, because neutron,
# internally creates the port, and then calls update, which will
# trigger this callback even before we had the chance to create

View File

@ -1345,12 +1345,14 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase):
'ovn_client.OVNClient.update_router_port')
def test_port_update_postcommit(self, update_rp_mock):
kwargs = {'port': {'device_owner': 'foo'},
'original_port': '',
'context': 'fake_context'}
self.l3_inst._port_update(resources.PORT, events.AFTER_UPDATE, None,
**kwargs)
update_rp_mock.assert_not_called()
kwargs = {'port': {'device_owner': constants.DEVICE_OWNER_ROUTER_INTF},
'original_port': '',
'context': 'fake_context'}
self.l3_inst._port_update(resources.PORT, events.AFTER_UPDATE, None,
**kwargs)
@ -1359,6 +1361,26 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase):
kwargs['port'],
if_exists=True)
def test_port_update_before_update_router_port_without_ip(self):
context = 'fake_context'
og_port = {'device_owner': constants.DEVICE_OWNER_ROUTER_INTF,
'fixed_ips': ['10.0.0.10'],
'id': 'port-id'}
port = {'device_owner': constants.DEVICE_OWNER_ROUTER_INTF,
'fixed_ips': [],
'id': 'port-id'}
kwargs = {'original_port': og_port,
'port': port,
'context': context}
self.assertRaises(
n_exc.ServicePortInUse,
self.l3_inst._port_update,
resources.PORT,
events.BEFORE_UPDATE,
None,
**kwargs,
)
@mock.patch('neutron.plugins.ml2.plugin.Ml2Plugin.update_port_status')
@mock.patch('neutron.plugins.ml2.plugin.Ml2Plugin.update_port')
@mock.patch('neutron.db.db_base_plugin_v2.NeutronDbPluginV2.get_ports')

View File

@ -0,0 +1,6 @@
---
fixes:
- |
Changes the API behaviour while using OVN driver to enforce that it's not possible to delete
all the IPs from a router port.
For more info see `bug LP#1948457 <https://bugs.launchpad.net/neutron/+bug/1948457>`_