Merge "[OVN] Only account for bound ports in metadata agent"

This commit is contained in:
Zuul 2021-04-26 12:13:21 +00:00 committed by Gerrit Code Review
commit 26117123d2
4 changed files with 37 additions and 22 deletions

View File

@ -222,7 +222,8 @@ class MetadataAgent(object):
self._load_config()
# Launch the server that will act as a proxy between the VM's and Nova.
proxy = metadata_server.UnixDomainMetadataProxy(self.conf)
proxy = metadata_server.UnixDomainMetadataProxy(self.conf,
self.chassis)
proxy.run()
tables = ('Encap', 'Port_Binding', 'Datapath_Binding', 'SB_Global',

View File

@ -43,8 +43,9 @@ MODE_MAP = {
class MetadataProxyHandler(object):
def __init__(self, conf):
def __init__(self, conf, chassis):
self.conf = conf
self.chassis = chassis
self.subscribe()
def subscribe(self):
@ -56,7 +57,8 @@ class MetadataProxyHandler(object):
# We need to open a connection to OVN SouthBound database for
# each worker so that we can process the metadata requests.
self.sb_idl = ovsdb.MetadataAgentOvnSbIdl(
tables=('Port_Binding', 'Datapath_Binding')).start()
tables=('Port_Binding', 'Datapath_Binding', 'Chassis'),
chassis=self.chassis).start()
@webob.dec.wsgify(RequestClass=webob.Request)
def __call__(self, req):
@ -173,8 +175,9 @@ class MetadataProxyHandler(object):
class UnixDomainMetadataProxy(object):
def __init__(self, conf):
def __init__(self, conf, chassis):
self.conf = conf
self.chassis = chassis
agent_utils.ensure_directory_exists_without_file(
cfg.CONF.metadata_proxy_socket)
@ -203,7 +206,7 @@ class UnixDomainMetadataProxy(object):
md_workers = self.conf.metadata_workers
if md_workers is None:
md_workers = 2
self.server.start(MetadataProxyHandler(self.conf),
self.server.start(MetadataProxyHandler(self.conf, self.chassis),
self.conf.metadata_proxy_socket,
workers=md_workers,
backlog=self.conf.metadata_backlog,

View File

@ -851,15 +851,24 @@ class OvsdbSbOvnIdl(sb_impl_idl.OvnSbApiIdlImpl, Backend):
rows = self.db_list_rows('Port_Binding').execute(check_error=True)
# TODO(twilson) It would be useful to have a db_find that takes a
# comparison function
# TODO(dalvarez): Remove the comparison to r.datapath.uuid in Y cycle
# when we are sure that all namespaces will be created with the
# Neutron network UUID and not anymore with the OVN datapath UUID.
return [r for r in rows
if (r.mac and (
str(r.datapath.uuid) == network or
utils.get_network_name_from_datapath(
r.datapath) == network)) and
ip_address in r.mac[0].split(' ')]
def check_net_and_ip(port):
# If the port is not bound to any chassis it is not relevant
if not port.chassis:
return False
# TODO(dalvarez): Remove the comparison to port.datapath.uuid in Y
# cycle when we are sure that all namespaces will be created with
# the Neutron network UUID and not anymore with the OVN datapath
# UUID.
is_in_network = lambda port: (
str(port.datapath.uuid) == network or
utils.get_network_name_from_datapath(port.datapath) == network)
return port.mac and is_in_network(port) and (
ip_address in port.mac[0].split(' '))
return [r for r in rows if check_net_and_ip(r)]
def set_port_cidrs(self, name, cidrs):
# TODO(twilson) add if_exists to db commands

View File

@ -27,7 +27,8 @@ from neutron.conf.agent.metadata import config as meta_conf
from neutron.conf.agent.ovn.metadata import config as ovn_meta_conf
from neutron.tests import base
OvnPortInfo = collections.namedtuple('OvnPortInfo', 'external_ids')
OvnPortInfo = collections.namedtuple(
'OvnPortInfo', ['external_ids', 'chassis'])
class ConfFixture(config_fixture.Config):
@ -54,7 +55,7 @@ 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)
self.handler = agent.MetadataProxyHandler(self.fake_conf, 'chassis1')
self.handler.sb_idl = mock.Mock()
def test_call(self):
@ -113,7 +114,8 @@ class TestMetadataProxyHandler(base.BaseTestCase):
ovn_port = OvnPortInfo(
external_ids={'neutron:device_id': 'device_id',
'neutron:project_id': 'project_id'})
'neutron:project_id': 'project_id'},
chassis=['chassis1'])
ports = [[ovn_port]]
self.assertEqual(
@ -220,14 +222,14 @@ class TestUnixDomainMetadataProxy(base.BaseTestCase):
@mock.patch.object(fileutils, 'ensure_tree')
def test_init_doesnot_exists(self, ensure_dir):
agent.UnixDomainMetadataProxy(mock.Mock())
agent.UnixDomainMetadataProxy(mock.Mock(), 'chassis1')
ensure_dir.assert_called_once_with('/the', mode=0o755)
def test_init_exists(self):
with mock.patch('os.path.isdir') as isdir:
with mock.patch('os.unlink') as unlink:
isdir.return_value = True
agent.UnixDomainMetadataProxy(mock.Mock())
agent.UnixDomainMetadataProxy(mock.Mock(), 'chassis1')
unlink.assert_called_once_with('/the/path')
def test_init_exists_unlink_no_file(self):
@ -238,7 +240,7 @@ class TestUnixDomainMetadataProxy(base.BaseTestCase):
exists.return_value = False
unlink.side_effect = OSError
agent.UnixDomainMetadataProxy(mock.Mock())
agent.UnixDomainMetadataProxy(mock.Mock(), 'chassis1')
unlink.assert_called_once_with('/the/path')
def test_init_exists_unlink_fails_file_still_exists(self):
@ -250,14 +252,14 @@ class TestUnixDomainMetadataProxy(base.BaseTestCase):
unlink.side_effect = OSError
with testtools.ExpectedException(OSError):
agent.UnixDomainMetadataProxy(mock.Mock())
agent.UnixDomainMetadataProxy(mock.Mock(), 'chassis1')
unlink.assert_called_once_with('/the/path')
@mock.patch.object(agent, 'MetadataProxyHandler')
@mock.patch.object(agent_utils, 'UnixDomainWSGIServer')
@mock.patch.object(fileutils, 'ensure_tree')
def test_run(self, ensure_dir, server, handler):
p = agent.UnixDomainMetadataProxy(self.cfg.CONF)
p = agent.UnixDomainMetadataProxy(self.cfg.CONF, 'chassis1')
p.run()
ensure_dir.assert_called_once_with('/the', mode=0o755)