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

View File

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

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