From 1300110ccb9963e48a7c19e70599194d5c7da92c Mon Sep 17 00:00:00 2001
From: Jakub Libosvar <libosvar@redhat.com>
Date: Tue, 1 Oct 2024 16:54:18 -0400
Subject: [PATCH] Set distributed flag to NB_Global

The patch introduces a new maintenance routine that always sets
NB_Global.external_ids:fip-distributed value in Northbound OVN DB to the
same value that enable_distributed_floating_ip config option has.

This is useful for projects that do not use RPC and rely on data only in
the OVN database.

Closes-Bug: #2083456
Change-Id: I7f30e6e030292b762dc9fc785c494c0dc215c749
Signed-off-by: Jakub Libosvar <libosvar@redhat.com>
---
 neutron/common/ovn/constants.py               |  1 +
 .../ovn/mech_driver/ovsdb/maintenance.py      | 15 ++++++
 .../ovn/mech_driver/ovsdb/test_maintenance.py | 48 +++++++++++++++++++
 3 files changed, 64 insertions(+)

diff --git a/neutron/common/ovn/constants.py b/neutron/common/ovn/constants.py
index 50fa43c271d..efbb8bcd603 100644
--- a/neutron/common/ovn/constants.py
+++ b/neutron/common/ovn/constants.py
@@ -57,6 +57,7 @@ METADATA_LIVENESS_CHECK_EXT_ID_KEY = 'neutron:metadata_liveness_check_at'
 OVN_PORT_BINDING_PROFILE = portbindings.PROFILE
 OVN_HOST_ID_EXT_ID_KEY = 'neutron:host_id'
 OVN_LRSR_EXT_ID_KEY = 'neutron:is_static_route'
+OVN_FIP_DISTRIBUTED_KEY = 'neutron:fip-distributed'
 
 MIGRATING_ATTR = 'migrating_to'
 OVN_ROUTER_PORT_OPTION_KEYS = ['router-port', 'nat-addresses',
diff --git a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/maintenance.py b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/maintenance.py
index 2941cfbaef4..5d705560824 100644
--- a/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/maintenance.py
+++ b/neutron/plugins/ml2/drivers/ovn/mech_driver/ovsdb/maintenance.py
@@ -1326,6 +1326,21 @@ class DBInconsistenciesPeriodics(SchemaAwarePeriodicsBase):
                     txn.add(cmd)
         raise periodics.NeverAgain()
 
+    @has_lock_periodic(
+        periodic_run_limit=ovn_const.MAINTENANCE_TASK_RETRY_LIMIT,
+        spacing=ovn_const.MAINTENANCE_ONE_RUN_TASK_SPACING,
+        run_immediately=True)
+    def set_fip_distributed_flag(self):
+        """Set the NB_Global.external_ids:fip-distributed flag."""
+        distributed = ovn_conf.is_ovn_distributed_floating_ip()
+        LOG.debug(
+            "Setting fip-distributed flag in NB_Global to %s", distributed)
+        self._nb_idl.db_set(
+            'NB_Global', '.', external_ids={
+                ovn_const.OVN_FIP_DISTRIBUTED_KEY: str(distributed)}).execute(
+                    check_error=True)
+        raise periodics.NeverAgain()
+
 
 class HashRingHealthCheckPeriodics(object):
 
diff --git a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_maintenance.py b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_maintenance.py
index 60c592e7de8..6660efa694f 100644
--- a/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_maintenance.py
+++ b/neutron/tests/functional/plugins/ml2/drivers/ovn/mech_driver/ovsdb/test_maintenance.py
@@ -1395,6 +1395,54 @@ class TestMaintenance(_TestMaintenanceHelper):
             if route.ip_prefix == '30.0.0.0/24':
                 self.assertEqual({}, route.external_ids)
 
+    def _get_nb_global_external_ids(self):
+        return self.nb_api.db_get(
+            'NB_Global', '.', 'external_ids').execute(check_error=True)
+
+    def test_set_fip_distributed_flag(self):
+        ovn_config.cfg.CONF.set_override(
+            'enable_distributed_floating_ip', True, 'ovn')
+        nb_global_ext_id = self._get_nb_global_external_ids()
+        self.assertNotIn(ovn_const.OVN_FIP_DISTRIBUTED_KEY, nb_global_ext_id)
+
+        self.assertRaises(
+            periodics.NeverAgain, self.maint.set_fip_distributed_flag)
+
+        nb_global_ext_id = self._get_nb_global_external_ids()
+        self.assertEqual(
+            "True", nb_global_ext_id[ovn_const.OVN_FIP_DISTRIBUTED_KEY])
+
+    def _test_set_fip_distributed_flag_change(
+            self, original_value, config_value):
+        ovn_config.cfg.CONF.set_override(
+            'enable_distributed_floating_ip', config_value, 'ovn')
+        self.nb_api.db_set(
+            'NB_Global', '.', external_ids={
+                ovn_const.OVN_FIP_DISTRIBUTED_KEY: str(original_value)}
+        ).execute(check_error=True)
+        nb_global_ext_id = self._get_nb_global_external_ids()
+        self.assertEqual(
+            str(original_value),
+            nb_global_ext_id[ovn_const.OVN_FIP_DISTRIBUTED_KEY])
+
+        self.assertRaises(
+            periodics.NeverAgain, self.maint.set_fip_distributed_flag)
+
+        nb_global_ext_id = self._get_nb_global_external_ids()
+        self.assertEqual(
+            str(config_value),
+            nb_global_ext_id[ovn_const.OVN_FIP_DISTRIBUTED_KEY])
+
+    def test_set_fip_distributed_flag_changed(self):
+        self._test_set_fip_distributed_flag_change(
+            original_value=False,
+            config_value=True)
+
+    def test_set_fip_distributed_flag_unchanged(self):
+        self._test_set_fip_distributed_flag_change(
+            original_value=True,
+            config_value=True)
+
 
 class TestLogMaintenance(_TestMaintenanceHelper,
                          test_log_driver.LogApiTestCaseBase):