From 8d4eeee135a4c6597aa7e6c976a5e13ca3ac237c Mon Sep 17 00:00:00 2001 From: Fernando Royo Date: Tue, 11 Jun 2024 14:22:18 +0200 Subject: [PATCH] [OVN] Bump revision number after update_virtual_port_host This patch adds bump revision after updating the hostname of a virtual port (more specifically its associated port). This way there is no misalignment between the revision number of Neutron DB and OVN DB. It also avoids the unnecessary execution of the maintenance task to simply match the revision_number. Closes-Bug: #2069046 Change-Id: I2734984f10341ab97ebbdee11389d214bb1150f3 (cherry picked from commit f210a904793b585dafea8085ed62e06f3fed2e6e) --- .../drivers/ovn/mech_driver/mech_driver.py | 12 ++++++-- .../mech_driver/ovsdb/test_ovsdb_monitor.py | 29 +++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/mech_driver.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/mech_driver.py index af6e5cb0d5f..6d86d69a24f 100644 --- a/neutron/plugins/ml2/drivers/ovn/mech_driver/mech_driver.py +++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/mech_driver.py @@ -1077,9 +1077,11 @@ class OVNMechanismDriver(api.MechanismDriver): hostname = '' # Updates neutron database with hostname for virtual port - self._plugin.update_virtual_port_host(n_context.get_admin_context(), - port_id, hostname) - + context = n_context.get_admin_context() + self._plugin.update_virtual_port_host(context, port_id, hostname) + db_port = self._plugin.get_port(context, port_id) + check_rev_cmd = self.nb_ovn.check_revision_number( + port_id, db_port, ovn_const.TYPE_PORTS) # Updates OVN NB database with hostname for lsp virtual port with self.nb_ovn.transaction(check_error=True) as txn: ext_ids = ('external_ids', @@ -1087,6 +1089,10 @@ class OVNMechanismDriver(api.MechanismDriver): txn.add( self.nb_ovn.db_set( 'Logical_Switch_Port', port_id, ext_ids)) + txn.add(check_rev_cmd) + if check_rev_cmd.result == ovn_const.TXN_COMMITTED: + ovn_revision_numbers_db.bump_revision(context, db_port, + ovn_const.TYPE_PORTS) def get_workers(self): """Get any worker instances that should have their own process diff --git a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovsdb_monitor.py b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovsdb_monitor.py index fbba7d3633b..f26dd558313 100644 --- a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovsdb_monitor.py +++ b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovsdb_monitor.py @@ -447,6 +447,30 @@ class TestNBDbMonitor(base.TestOVNFunctionalBase): # Check that both neutron and ovn are the same as given host_id return port[portbindings.HOST_ID] == host_id == ovn_host_id + def _check_port_and_port_binding_revision_number(self, port_id): + + def is_port_and_port_binding_same_revision_number(port_id): + # This function checks if given port matches the revision_number + # in the neutron DB as well as in the OVN DB for the port_binding + core_plugin = directory.get_plugin() + + # Get port from neutron DB + port = core_plugin.get_ports( + self.context, filters={'id': [port_id]})[0] + + # Get port binding from OVN DB + bp = self._find_port_binding(port_id) + ovn_port_binding_revision_number = bp.external_ids.get( + ovn_const.OVN_REV_NUM_EXT_ID_KEY, ovn_const.INITIAL_REV_NUM) + + # Check that both neutron and ovn are the same as given host_id + return port['revision_number'] == int( + ovn_port_binding_revision_number) + + check = functools.partial( + is_port_and_port_binding_same_revision_number, port_id) + n_utils.wait_until_true(check, timeout=10) + def test_virtual_port_host_update_upon_failover(self): # NOTE: we can't simulate traffic, but we can simulate the event that # would've been triggered by OVN, which is what we do. @@ -466,6 +490,7 @@ class TestNBDbMonitor(base.TestOVNFunctionalBase): vip_address = vip['fixed_ips'][0]['ip_address'] allowed_address_pairs = [{'ip_address': vip_address}] self._check_port_binding_type(vip['id'], '') + self._check_port_and_port_binding_revision_number(vip['id']) # 3) Create two ports with the allowed address pairs set. hosts = ('ovs-host1', second_chassis_name) @@ -482,6 +507,7 @@ class TestNBDbMonitor(base.TestOVNFunctionalBase): # have been assigned to the port binding self._check_port_binding_type(vip['id'], ovn_const.LSP_TYPE_VIRTUAL) self._check_port_virtual_parents(vip['id'], ','.join(port_ids)) + self._check_port_and_port_binding_revision_number(vip['id']) # 5) Bind the ports to a host, so a chassis is bound, which is # required for the update_virtual_port_host method. Without this @@ -489,11 +515,13 @@ class TestNBDbMonitor(base.TestOVNFunctionalBase): self._test_port_binding_and_status(ports[0]['id'], 'bind', 'ACTIVE') self.chassis = second_chassis self._test_port_binding_and_status(ports[1]['id'], 'bind', 'ACTIVE') + self._check_port_and_port_binding_revision_number(vip['id']) # 6) For both ports, bind vip on parent and check hostname in DBs for idx in range(len(ports)): # Set port binding to the first port, and update the chassis self._set_port_binding_virtual_parent(vip['id'], ports[idx]['id']) + self._check_port_and_port_binding_revision_number(vip['id']) # Check if the host_id has been updated in OVN and DB # by the event that eventually calls for method @@ -501,6 +529,7 @@ class TestNBDbMonitor(base.TestOVNFunctionalBase): n_utils.wait_until_true( lambda: self._check_port_host_set(vip['id'], hosts[idx]), timeout=10) + self._check_port_and_port_binding_revision_number(vip['id']) class TestNBDbMonitorOverTcp(TestNBDbMonitor):