diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py index 8f3c43c6aed..8a68b80084b 100644 --- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py +++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/ovn_db_sync.py @@ -1390,7 +1390,8 @@ class OvnSbSynchronizer(OvnDbSynchronizer): str(datetime.now())) host_phynets_map = self.ovn_api.get_chassis_hostname_and_physnets() current_hosts = set(host_phynets_map) - previous_hosts = segments_db.get_hosts_mapped_with_segments(ctx) + previous_hosts = segments_db.get_hosts_mapped_with_segments( + ctx, include_agent_types={ovn_const.OVN_CONTROLLER_AGENT}) stale_hosts = previous_hosts - current_hosts for host in stale_hosts: diff --git a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_db_sync.py b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_db_sync.py index ea486c52893..82e429b4b4b 100644 --- a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_db_sync.py +++ b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_db_sync.py @@ -1820,6 +1820,22 @@ class TestOvnSbSync(base.TestOVNFunctionalBase): def _sync_resources(self): self.sb_synchronizer.sync_hostname_and_physical_networks(self.ctx) + def create_agent(self, host, bridge_mappings=None, agent_type=None): + if agent_type is None: + agent_type = ovn_const.OVN_CONTROLLER_AGENT + if bridge_mappings is None: + bridge_mappings = {} + agent = { + 'host': host, + 'agent_type': agent_type, + 'binary': '/bin/test', + 'topic': 'test_topic', + 'configurations': {'bridge_mappings': bridge_mappings} + } + _, status = self.plugin.create_or_update_agent(self.context, agent) + + return status['id'] + def create_segment(self, network_id, physical_network, segmentation_id): segment_data = {'network_id': network_id, 'physical_network': physical_network, @@ -1860,6 +1876,7 @@ class TestOvnSbSync(base.TestOVNFunctionalBase): segment = self.create_segment(network_id, 'physnet1', 50) segments_db.update_segment_host_mapping( self.ctx, 'host1', {segment['id']}) + _ = self.create_agent('host1', bridge_mappings={'physnet1': 'eth0'}) segment_hosts = segments_db.get_hosts_mapped_with_segments(self.ctx) self.assertEqual({'host1'}, segment_hosts) # Since there is no chassis in the sb DB, host1 is the stale host @@ -1868,6 +1885,36 @@ class TestOvnSbSync(base.TestOVNFunctionalBase): segment_hosts = segments_db.get_hosts_mapped_with_segments(self.ctx) self.assertFalse(segment_hosts) + def test_ovn_sb_sync_host_with_no_agent_not_deleted(self): + with self.network() as network: + network_id = network['network']['id'] + segment = self.create_segment(network_id, 'physnet1', 50) + segments_db.update_segment_host_mapping( + self.ctx, 'host1', {segment['id']}) + _ = self.create_agent('host1', bridge_mappings={'physnet1': 'eth0'}, + agent_type="Not OVN Agent") + segment_hosts = segments_db.get_hosts_mapped_with_segments(self.ctx) + self.assertEqual({'host1'}, segment_hosts) + # There is no chassis in the sb DB, host1 does not have an agent + # so it is not deleted. + self._sync_resources() + segment_hosts = segments_db.get_hosts_mapped_with_segments(self.ctx) + self.assertEqual({'host1'}, segment_hosts) + + def test_ovn_sb_sync_host_with_other_agent_type_not_deleted(self): + with self.network() as network: + network_id = network['network']['id'] + segment = self.create_segment(network_id, 'physnet1', 50) + segments_db.update_segment_host_mapping( + self.ctx, 'host1', {segment['id']}) + segment_hosts = segments_db.get_hosts_mapped_with_segments(self.ctx) + self.assertEqual({'host1'}, segment_hosts) + # There is no chassis in the sb DB, host1 does not have an agent + # so it is not deleted. + self._sync_resources() + segment_hosts = segments_db.get_hosts_mapped_with_segments(self.ctx) + self.assertEqual({'host1'}, segment_hosts) + def test_ovn_sb_sync(self): with self.network() as network: network_id = network['network']['id'] @@ -1880,6 +1927,9 @@ class TestOvnSbSync(base.TestOVNFunctionalBase): segments_db.update_segment_host_mapping( self.ctx, 'host3', {seg1['id']}) segment_hosts = segments_db.get_hosts_mapped_with_segments(self.ctx) + _ = self.create_agent('host1') + _ = self.create_agent('host2', bridge_mappings={'physnet2': 'eth0'}) + _ = self.create_agent('host3', bridge_mappings={'physnet3': 'eth0'}) self.assertEqual({'host1', 'host2', 'host3'}, segment_hosts) self.add_fake_chassis('host2', ['physnet2']) self.add_fake_chassis('host3', ['physnet3']) diff --git a/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_db_sync.py b/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_db_sync.py index 9527763ccfe..cd54dde0241 100644 --- a/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_db_sync.py +++ b/neutron/tests/unit/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_ovn_db_sync.py @@ -1169,8 +1169,10 @@ class TestOvnSbSyncML2(test_mech_driver.OVNMechanismDriverTestCase): with mock.patch.object(ovn_db_sync.segments_db, 'get_hosts_mapped_with_segments', - return_value=hosts_in_neutron): + return_value=hosts_in_neutron) as mock_ghmws: ovn_sb_synchronizer.sync_hostname_and_physical_networks(mock.ANY) + mock_ghmws.assert_called_once_with( + mock.ANY, include_agent_types={ovn_const.OVN_CONTROLLER_AGENT}) all_hosts = set(hostname_with_physnets.keys()) | hosts_in_neutron self.assertEqual( len(all_hosts), diff --git a/releasenotes/notes/ovn-db-sync-host-physnet-filter-agent-type-9e22942bed304807.yaml b/releasenotes/notes/ovn-db-sync-host-physnet-filter-agent-type-9e22942bed304807.yaml new file mode 100644 index 00000000000..79a2593174a --- /dev/null +++ b/releasenotes/notes/ovn-db-sync-host-physnet-filter-agent-type-9e22942bed304807.yaml @@ -0,0 +1,10 @@ +--- +fixes: + - | + When synchronizing the OVN databases, either when running the migration + command or during startup, the code responsible for synchronization will + only clean up segment-to-host mappings for hosts with agent_type + ``OVN Controller agent``. Before, the synchronization would clean up + (delete) segment-to-host mappings for non-OVN hosts. Fixes bug: + `2040172 `_. +