Merge "Improve the ``PortBindingUpdateVirtualPortsEvent`` match filter"
commit
7431d2f86e
|
@ -538,43 +538,42 @@ class PortBindingUpdateVirtualPortsEvent(row_event.RowEvent):
|
|||
def __init__(self, driver):
|
||||
self.driver = driver
|
||||
table = 'Port_Binding'
|
||||
events = (self.ROW_UPDATE, )
|
||||
events = (self.ROW_UPDATE, self.ROW_DELETE)
|
||||
super().__init__(events, table, None)
|
||||
self.event_name = 'PortBindingUpdateVirtualPortsEvent'
|
||||
|
||||
def match_fn(self, event, row, old):
|
||||
# This event should catch only those events from ports that are
|
||||
# "virtual" or have been "virtual". The second happens when all virtual
|
||||
# parent are disassociated; in the same transaction the
|
||||
# "virtual-parents" list is removed from "options" and the type is set
|
||||
# to "".
|
||||
if (row.type != ovn_const.PB_TYPE_VIRTUAL and
|
||||
getattr(old, 'type', None) != ovn_const.PB_TYPE_VIRTUAL):
|
||||
return False
|
||||
# This event should catch the events related to virtual parents (that
|
||||
# are associated to virtual ports).
|
||||
if event == self.ROW_DELETE:
|
||||
# The port binding has been deleted, delete the host ID (if the
|
||||
# port was not deleted before).
|
||||
return True
|
||||
|
||||
virtual_parents = (row.options or {}).get(
|
||||
ovn_const.LSP_OPTIONS_VIRTUAL_PARENTS_KEY)
|
||||
old_virtual_parents = getattr(old, 'options', {}).get(
|
||||
ovn_const.LSP_OPTIONS_VIRTUAL_PARENTS_KEY)
|
||||
chassis = row.chassis
|
||||
old_chassis = getattr(old, 'chassis', [])
|
||||
|
||||
if virtual_parents and chassis != old_chassis:
|
||||
# That happens when the chassis is assigned (VIP is first detected
|
||||
# in a port) or changed (the VIP changes of assigned port and
|
||||
# host).
|
||||
return True
|
||||
|
||||
if not virtual_parents and old_virtual_parents:
|
||||
if virtual_parents != old_virtual_parents:
|
||||
# 1) if virtual_parents and not old_virtual_parents:
|
||||
# The port has received a virtual parent and now is bound.
|
||||
# 2) elif (virtual_parents and old_virtual_parents and
|
||||
# old_virtual_parents != virtual_parents):
|
||||
# If the port virtual parents have changed (the VIP is bound
|
||||
# to another host because it's owned by another port).
|
||||
# 3) if not virtual_parents and old_virtual_parents:
|
||||
# All virtual parent ports are removed, the VIP is unbound.
|
||||
return True
|
||||
return False
|
||||
|
||||
def run(self, event, row, old):
|
||||
virtual_parents = (row.options or {}).get(
|
||||
ovn_const.LSP_OPTIONS_VIRTUAL_PARENTS_KEY)
|
||||
chassis_uuid = (row.chassis[0].uuid if
|
||||
row.chassis and virtual_parents else None)
|
||||
if event == self.ROW_DELETE:
|
||||
chassis_uuid = None
|
||||
else:
|
||||
virtual_parents = (row.options or {}).get(
|
||||
ovn_const.LSP_OPTIONS_VIRTUAL_PARENTS_KEY)
|
||||
chassis_uuid = (row.chassis[0].uuid if
|
||||
row.chassis and virtual_parents else None)
|
||||
self.driver.update_virtual_port_host(row.logical_port, chassis_uuid)
|
||||
|
||||
|
||||
|
|
|
@ -2068,8 +2068,14 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2,
|
|||
"""
|
||||
hostname = hostname or ''
|
||||
with db_api.CONTEXT_WRITER.using(context):
|
||||
for pb in ports_obj.PortBinding.get_objects(context,
|
||||
port_id=port_id):
|
||||
pbindings = ports_obj.PortBinding.get_objects(context,
|
||||
port_id=port_id)
|
||||
if not pbindings:
|
||||
# The port has been deleted and there is no need to delete and
|
||||
# create any port binding.
|
||||
return
|
||||
|
||||
for pb in pbindings:
|
||||
pb.delete()
|
||||
|
||||
attrs = {'port_id': port_id,
|
||||
|
|
|
@ -312,6 +312,17 @@ class TestNBDbMonitor(base.TestOVNFunctionalBase):
|
|||
rows = cmd.execute(check_error=True)
|
||||
return rows[0] if rows else None
|
||||
|
||||
def _set_port_binding_virtual_parent(self, port_id, parent_port_id):
|
||||
pb_port_parent = self.sb_api.db_find_rows(
|
||||
'Port_Binding', ('logical_port', '=', parent_port_id)).execute(
|
||||
check_error=True)[0]
|
||||
pb_port_vip = self.sb_api.db_find_rows(
|
||||
'Port_Binding', ('logical_port', '=', port_id)).execute(
|
||||
check_error=True)[0]
|
||||
self.sb_api.db_set(
|
||||
'Port_Binding', pb_port_vip.uuid,
|
||||
('virtual_parent', pb_port_parent.uuid)).execute(check_error=True)
|
||||
|
||||
def _check_port_binding_type(self, port_id, port_type):
|
||||
def is_port_binding_type(port_id, port_type):
|
||||
bp = self._find_port_binding(port_id)
|
||||
|
@ -341,6 +352,7 @@ class TestNBDbMonitor(base.TestOVNFunctionalBase):
|
|||
port = self.create_port()
|
||||
self._check_port_binding_type(vip['id'], '')
|
||||
|
||||
# 1) Set the allowed address pairs.
|
||||
data = {'port': {'allowed_address_pairs': allowed_address_pairs}}
|
||||
req = self.new_update_request('ports', data, port['id'])
|
||||
req.get_response(self.api)
|
||||
|
@ -348,8 +360,21 @@ class TestNBDbMonitor(base.TestOVNFunctionalBase):
|
|||
# and the corresponding "virtual-parents".
|
||||
self._check_port_binding_type(vip['id'], ovn_const.LSP_TYPE_VIRTUAL)
|
||||
self._check_port_virtual_parents(vip['id'], port['id'])
|
||||
mock_update_vip_host.assert_not_called()
|
||||
n_utils.wait_until_true(lambda: mock_update_vip_host.called,
|
||||
timeout=10)
|
||||
# The "Port_Binding" has been deleted. Then the "Port_Binding" register
|
||||
# is created again without virtual_parents, but this event doesn't
|
||||
# call "update_virtual_port_host".
|
||||
mock_update_vip_host.assert_called_once_with(vip['id'], None)
|
||||
|
||||
# 2) Unset the allowed address pairs.
|
||||
# Assign the VIP again and delete the virtual port.
|
||||
# Before unsetting the allowed address pairs, we first manually add
|
||||
# the Port_Binding.virtual_parent of the virtual port. That happens
|
||||
# when an ovn-controller detects traffic with the VIP and assign the
|
||||
# port hosting the VIP as virtual parent.
|
||||
self._set_port_binding_virtual_parent(vip['id'], port['id'])
|
||||
mock_update_vip_host.reset_mock()
|
||||
data = {'port': {'allowed_address_pairs': []}}
|
||||
req = self.new_update_request('ports', data, port['id'])
|
||||
req.get_response(self.api)
|
||||
|
@ -357,6 +382,24 @@ class TestNBDbMonitor(base.TestOVNFunctionalBase):
|
|||
self._check_port_virtual_parents(vip['id'], None)
|
||||
n_utils.wait_until_true(lambda: mock_update_vip_host.called,
|
||||
timeout=10)
|
||||
# The virtual port is no longer considered as virtual. The
|
||||
# "Port_Binding" register is deleted.
|
||||
mock_update_vip_host.assert_called_once_with(vip['id'], None)
|
||||
|
||||
# 3) Set again the allowed address pairs.
|
||||
mock_update_vip_host.reset_mock()
|
||||
data = {'port': {'allowed_address_pairs': allowed_address_pairs}}
|
||||
req = self.new_update_request('ports', data, port['id'])
|
||||
req.get_response(self.api)
|
||||
# This test checks that the VIP "Port_Binding" register gets the type
|
||||
# and the corresponding "virtual-parents".
|
||||
self._check_port_binding_type(vip['id'], ovn_const.LSP_TYPE_VIRTUAL)
|
||||
self._check_port_virtual_parents(vip['id'], port['id'])
|
||||
mock_update_vip_host.reset_mock()
|
||||
self._delete('ports', vip['id'])
|
||||
n_utils.wait_until_true(lambda: mock_update_vip_host.called,
|
||||
timeout=10)
|
||||
# The virtual port is deleted and so the associated "Port_Binding".
|
||||
mock_update_vip_host.assert_called_once_with(vip['id'], None)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue