From f43891bf866b65ceef0e51633afbbf57ee2a6be8 Mon Sep 17 00:00:00 2001 From: Rodolfo Alonso Hernandez Date: Wed, 5 Oct 2022 13:22:29 +0200 Subject: [PATCH] [OVN] Allow to execute ``MetadataProxyHandler`` in a local thread If configuration option "metadata_workers=0", the OVN metadata agent will try to spawn the ``MetadataProxyHandler`` instance inside a local thread, instead of creating a new process. In this case, the method ``MetadataProxyHandler.post_fork_initialize`` is never called and the SB IDL is never created. This patch passes the OVN metadata agent SB IDL instance to the proxy handler instance. This also reduces the number of OVN database active connections. Closes-Bug: #1993181 Change-Id: If9d827228002de7e3a55be660da266b60b0dfb79 --- neutron/agent/ovn/metadata/agent.py | 12 ++++++------ neutron/agent/ovn/metadata/server.py | 11 +++++++---- .../agent/ovn/metadata/test_metadata_agent.py | 17 +++++++++++------ .../unit/agent/ovn/metadata/test_server.py | 4 ++-- 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/neutron/agent/ovn/metadata/agent.py b/neutron/agent/ovn/metadata/agent.py index a60ad26d964..d5679e7d565 100644 --- a/neutron/agent/ovn/metadata/agent.py +++ b/neutron/agent/ovn/metadata/agent.py @@ -241,11 +241,6 @@ class MetadataAgent(object): self.ovs_idl = ovsdb.MetadataAgentOvsIdl().start() self._load_config() - # Launch the server that will act as a proxy between the VM's and Nova. - proxy = metadata_server.UnixDomainMetadataProxy(self.conf, - self.chassis) - proxy.run() - tables = ('Encap', 'Port_Binding', 'Datapath_Binding', 'SB_Global', 'Chassis') events = (PortBindingChassisCreatedEvent(self), @@ -271,13 +266,18 @@ class MetadataAgent(object): # Now IDL connections can be safely used. self._post_fork_event.set() + # Launch the server that will act as a proxy between the VM's and Nova. + self._proxy = metadata_server.UnixDomainMetadataProxy( + self.conf, self.chassis, sb_idl=self.sb_idl) + self._proxy.run() + # Do the initial sync. self.sync() # Register the agent with its corresponding Chassis self.register_metadata_agent() - proxy.wait() + self._proxy.wait() @ovn_utils.retry() def register_metadata_agent(self): diff --git a/neutron/agent/ovn/metadata/server.py b/neutron/agent/ovn/metadata/server.py index 21818f483f6..abd0c92fb5f 100644 --- a/neutron/agent/ovn/metadata/server.py +++ b/neutron/agent/ovn/metadata/server.py @@ -44,10 +44,10 @@ MODE_MAP = { class MetadataProxyHandler(object): - def __init__(self, conf, chassis): + def __init__(self, conf, chassis, sb_idl): self.conf = conf self.chassis = chassis - self._sb_idl = None + self._sb_idl = sb_idl self._post_fork_event = threading.Event() self.subscribe() @@ -193,9 +193,10 @@ class MetadataProxyHandler(object): class UnixDomainMetadataProxy(object): - def __init__(self, conf, chassis): + def __init__(self, conf, chassis, sb_idl=None): self.conf = conf self.chassis = chassis + self.sb_idl = sb_idl agent_utils.ensure_directory_exists_without_file( cfg.CONF.metadata_proxy_socket) @@ -224,7 +225,9 @@ class UnixDomainMetadataProxy(object): md_workers = self.conf.metadata_workers if md_workers is None: md_workers = 2 - self.server.start(MetadataProxyHandler(self.conf, self.chassis), + sb_idl = self.sb_idl if md_workers == 0 else None + self.server.start(MetadataProxyHandler(self.conf, self.chassis, + sb_idl), self.conf.metadata_proxy_socket, workers=md_workers, backlog=self.conf.metadata_backlog, diff --git a/neutron/tests/functional/agent/ovn/metadata/test_metadata_agent.py b/neutron/tests/functional/agent/ovn/metadata/test_metadata_agent.py index bb6e67f1549..80ecaa7b040 100644 --- a/neutron/tests/functional/agent/ovn/metadata/test_metadata_agent.py +++ b/neutron/tests/functional/agent/ovn/metadata/test_metadata_agent.py @@ -87,18 +87,17 @@ class TestMetadataAgent(base.TestOVNFunctionalBase): ovn_sb_db = self.ovsdb_server_mgr.get_ovsdb_connection_path('sb') conf.set_override('ovn_sb_connection', ovn_sb_db, group='ovn') - - # We don't need the HA proxy server running for now - p = mock.patch.object(metadata_server, 'UnixDomainMetadataProxy') - p.start() - self.addCleanup(p.stop) + conf.set_override('metadata_workers', '0') self.chassis_name = self.add_fake_chassis(self.FAKE_CHASSIS_HOST) mock.patch.object(agent.MetadataAgent, '_get_own_chassis_name', return_value=self.chassis_name).start() agt = agent.MetadataAgent(conf) - agt.start() + with mock.patch.object(metadata_server.UnixDomainMetadataProxy, + 'wait'): + agt.start() + # Metadata agent will open connections to OVS and SB databases. # Close connections to them when the test ends, self.addCleanup(agt.ovs_idl.ovsdb_connection.stop) @@ -338,3 +337,9 @@ class TestMetadataAgent(base.TestOVNFunctionalBase): else: self.fail('Rule not found in "mangle" table, in namespace %s' % namespace) + + def test_metadata_proxy_handler_idl(self): + # This test relies on the configuration option metadata_workers=0 + proxy_sb_idl = self.agent._proxy.server._server._application.sb_idl + agent_sb_idl = self.agent.sb_idl + self.assertEqual(agent_sb_idl, proxy_sb_idl) diff --git a/neutron/tests/unit/agent/ovn/metadata/test_server.py b/neutron/tests/unit/agent/ovn/metadata/test_server.py index 43dce60769e..88fbe89eef9 100644 --- a/neutron/tests/unit/agent/ovn/metadata/test_server.py +++ b/neutron/tests/unit/agent/ovn/metadata/test_server.py @@ -55,8 +55,8 @@ class TestMetadataProxyHandler(base.BaseTestCase): self.useFixture(self.fake_conf_fixture) self.log_p = mock.patch.object(agent, 'LOG') self.log = self.log_p.start() - self.handler = agent.MetadataProxyHandler(self.fake_conf, 'chassis1') - self.handler.sb_idl = mock.Mock() + self.handler = agent.MetadataProxyHandler(self.fake_conf, 'chassis1', + mock.Mock()) self.handler._post_fork_event.set() def test_call(self):