[OVN] Prevent deleting the only IP of a router port
Neutron allows deleting the only IP of a router port but
the OVN NB DB doesn't, since it expects that the
network value of a port is greater than 0. This should
not be possible since it causes that the DB are not
perfectly sync.
It is needed to check BEFORE_UPDATE if the port
that will be updated is of type router owned and
if it will have an IP after the update. If not
an error needs to be raised.
Compared to master patch, this has changed payload to kwargs
Conflicts:
neutron/services/ovn_l3/plugin.py
Closes-Bug: #1948457
Change-Id: I206c31201470f178efdde8839622be7900c6ae3e
(cherry picked from commit 935c88032b
)
This commit is contained in:
parent
124215ccd6
commit
f7f083c9da
|
@ -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
|
||||
|
@ -460,15 +461,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
|
||||
|
|
|
@ -1339,12 +1339,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)
|
||||
|
@ -1353,6 +1355,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')
|
||||
|
|
|
@ -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>`_
|
Loading…
Reference in New Issue