[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
(cherry picked from commit f43891bf86)
This commit is contained in:
Rodolfo Alonso Hernandez 2022-10-05 13:22:29 +02:00
parent dd7fc47684
commit c8409a33d9
4 changed files with 26 additions and 18 deletions

View File

@ -242,11 +242,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),
@ -272,13 +267,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()
@tenacity.retry(
wait=tenacity.wait_exponential(

View File

@ -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,

View File

@ -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)

View File

@ -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):