[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. Closes-Bug: #1948457 Change-Id: I206c31201470f178efdde8839622be7900c6ae3e
This commit is contained in:
parent
90b5456b8c
commit
fa2179278f
@ -28,6 +28,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
|
||||
@ -462,7 +463,10 @@ 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, payload):
|
||||
l3plugin = directory.get_plugin(plugin_constants.L3)
|
||||
if not l3plugin:
|
||||
@ -470,8 +474,23 @@ class OVNL3RouterPlugin(service_base.ServicePluginBase,
|
||||
|
||||
context = payload.context
|
||||
current = payload.latest_state
|
||||
original = payload.states[0]
|
||||
|
||||
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
|
||||
|
@ -1414,6 +1414,22 @@ class TestOVNL3RouterPlugin(test_mech_driver.Ml2PluginV2TestCase):
|
||||
port,
|
||||
if_exists=True)
|
||||
|
||||
def test_port_update_before_update_router_port_without_ip(self):
|
||||
context = 'fake_context'
|
||||
port = {'device_owner': constants.DEVICE_OWNER_ROUTER_INTF,
|
||||
'fixed_ips': [],
|
||||
'id': 'port-id'}
|
||||
self.assertRaises(
|
||||
n_exc.ServicePortInUse,
|
||||
self.l3_inst._port_update,
|
||||
resources.PORT,
|
||||
events.BEFORE_UPDATE,
|
||||
None,
|
||||
payload=events.DBEventPayload(
|
||||
context,
|
||||
states=(port,))
|
||||
)
|
||||
|
||||
@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')
|
||||
|
6
releasenotes/notes/bug-817525-eef68687dafa97fd.yaml
Normal file
6
releasenotes/notes/bug-817525-eef68687dafa97fd.yaml
Normal 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>`_
|
Loading…
Reference in New Issue
Block a user