summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2022-11-23 01:04:38 +0000
committerGerrit Code Review <review@openstack.org>2022-11-23 01:04:38 +0000
commit7145ccf47b11357f083c390d1a350ce60de79b09 (patch)
tree65b081aaa9ee723bc7e5c75a7d6590d5890a48ae
parent1e6ff935d8130d7d1336c58713ce2258602cdd1e (diff)
parente6878c12c3064a5a13589dd4df05a053e3f96bee (diff)
downloadneutron-7145ccf47b11357f083c390d1a350ce60de79b09.tar.gz
Merge "ovn: first tear down old metadata namespaces, then deploy new" into stable/victoria
-rw-r--r--neutron/agent/ovn/metadata/agent.py46
-rw-r--r--neutron/tests/unit/agent/ovn/metadata/test_agent.py68
2 files changed, 51 insertions, 63 deletions
diff --git a/neutron/agent/ovn/metadata/agent.py b/neutron/agent/ovn/metadata/agent.py
index 22d8ee78ab..182f137962 100644
--- a/neutron/agent/ovn/metadata/agent.py
+++ b/neutron/agent/ovn/metadata/agent.py
@@ -320,6 +320,12 @@ class MetadataAgent(object):
"br-int instead.")
return 'br-int'
+ def get_networks(self):
+ ports = self.sb_idl.get_ports_on_chassis(self.chassis)
+ return {(str(p.datapath.uuid),
+ ovn_utils.get_network_name_from_datapath(p.datapath))
+ for p in self._vif_ports(ports)}
+
@_sync_lock
def sync(self):
"""Agent sync.
@@ -328,16 +334,26 @@ class MetadataAgent(object):
chassis are serving metadata. Also, it will tear down those namespaces
which were serving metadata but are no longer needed.
"""
- metadata_namespaces = self.ensure_all_networks_provisioned()
+
+ # first, clean up namespaces that should no longer deploy
system_namespaces = tuple(
ns.decode('utf-8') if isinstance(ns, bytes) else ns
for ns in ip_lib.list_network_namespaces())
+ nets = self.get_networks()
+ metadata_namespaces = [
+ self._get_namespace_name(net[1])
+ for net in nets
+ ]
unused_namespaces = [ns for ns in system_namespaces if
ns.startswith(NS_PREFIX) and
ns not in metadata_namespaces]
for ns in unused_namespaces:
self.teardown_datapath(self._get_datapath_name(ns))
+ # now that all obsolete namespaces are cleaned up, deploy required
+ # networks
+ self.ensure_all_networks_provisioned(nets)
+
@staticmethod
def _get_veth_name(datapath):
return ['{}{}{}'.format(n_const.TAP_DEVICE_PREFIX,
@@ -431,8 +447,6 @@ class MetadataAgent(object):
and assign the IP addresses to the interface corresponding to the
metadata port of the network. It will also remove existing IP
addresses that are no longer needed.
-
- :return: The metadata namespace name of this datapath
"""
LOG.debug("Provisioning metadata for network %s", net_name)
port = self.sb_idl.get_metadata_port_network(datapath)
@@ -541,31 +555,17 @@ class MetadataAgent(object):
network_id=net_name)
self.update_chassis_metadata_networks(net_name)
- return namespace
- def ensure_all_networks_provisioned(self):
- """Ensure that all datapaths are provisioned.
+ def ensure_all_networks_provisioned(self, nets):
+ """Ensure that all requested datapaths are provisioned.
- This function will make sure that all datapaths with ports bound to
- our chassis have its namespace, VETH pair and OVS port created and
- metadata proxy is up and running.
-
- :return: A list with the namespaces that are currently serving
- metadata
+ This function will make sure that requested datapaths have their
+ namespaces, VETH pair and OVS ports created and metadata proxies are up
+ and running.
"""
- # Retrieve all VIF ports in our Chassis
- ports = self.sb_idl.get_ports_on_chassis(self.chassis)
- nets = {(str(p.datapath.uuid),
- ovn_utils.get_network_name_from_datapath(p.datapath))
- for p in self._vif_ports(ports)}
- namespaces = []
# Make sure that all those datapaths are serving metadata
for datapath, net_name in nets:
- netns = self.provision_datapath(datapath, net_name)
- if netns:
- namespaces.append(netns)
-
- return namespaces
+ self.provision_datapath(datapath, net_name)
# NOTE(lucasagomes): Even tho the metadata agent is a multi-process
# application, there's only one Southbound database IDL instance in
diff --git a/neutron/tests/unit/agent/ovn/metadata/test_agent.py b/neutron/tests/unit/agent/ovn/metadata/test_agent.py
index 9c61d2881b..ee6fb18f3d 100644
--- a/neutron/tests/unit/agent/ovn/metadata/test_agent.py
+++ b/neutron/tests/unit/agent/ovn/metadata/test_agent.py
@@ -71,19 +71,29 @@ class TestMetadataAgent(base.BaseTestCase):
self.agent.chassis = 'chassis'
self.agent.ovn_bridge = 'br-int'
+ self.ports = []
+ for i in range(0, 3):
+ self.ports.append(makePort(datapath=DatapathInfo(uuid=str(i),
+ external_ids={'name': 'neutron-%d' % i})))
+ self.agent.sb_idl.get_ports_on_chassis.return_value = self.ports
+
def test_sync(self):
+
with mock.patch.object(
self.agent, 'ensure_all_networks_provisioned') as enp,\
mock.patch.object(
ip_lib, 'list_network_namespaces') as lnn,\
mock.patch.object(
self.agent, 'teardown_datapath') as tdp:
- enp.return_value = ['ovnmeta-1', 'ovnmeta-2']
lnn.return_value = ['ovnmeta-1', 'ovnmeta-2']
self.agent.sync()
- enp.assert_called_once_with()
+ enp.assert_called_once_with({
+ (p.datapath.uuid, p.datapath.uuid)
+ for p in self.ports
+ })
+
lnn.assert_called_once_with()
tdp.assert_not_called()
@@ -95,18 +105,20 @@ class TestMetadataAgent(base.BaseTestCase):
ip_lib, 'list_network_namespaces') as lnn,\
mock.patch.object(
self.agent, 'teardown_datapath') as tdp:
- enp.return_value = ['ovnmeta-1', 'ovnmeta-2']
lnn.return_value = ['ovnmeta-1', 'ovnmeta-2', 'ovnmeta-3',
'ns1', 'ns2']
self.agent.sync()
- enp.assert_called_once_with()
+ enp.assert_called_once_with({
+ (p.datapath.uuid, p.datapath.uuid)
+ for p in self.ports
+ })
lnn.assert_called_once_with()
tdp.assert_called_once_with('3')
- def test_ensure_all_networks_provisioned(self):
- """Test networks are provisioned.
+ def test_get_networks(self):
+ """Test which networks are provisioned.
This test simulates that this chassis has the following ports:
* datapath '0': 1 port
@@ -115,44 +127,27 @@ class TestMetadataAgent(base.BaseTestCase):
* datapath '3': 1 port with type 'external'
* datapath '5': 1 port with type 'unknown'
- It is expected that only datapaths '0', '1' and '2' are provisioned
- once.
+ It is expected that only datapaths '0', '1' and '2' are scheduled for
+ provisioning.
"""
- ports = []
- for i in range(0, 3):
- ports.append(makePort(datapath=DatapathInfo(uuid=str(i),
- external_ids={'name': 'neutron-%d' % i})))
- ports.append(makePort(datapath=DatapathInfo(uuid='1',
+ self.ports.append(makePort(datapath=DatapathInfo(uuid='1',
external_ids={'name': 'neutron-1'})))
- ports.append(makePort(datapath=DatapathInfo(uuid='3',
+ self.ports.append(makePort(datapath=DatapathInfo(uuid='3',
external_ids={'name': 'neutron-3'}), type='external'))
- ports.append(makePort(datapath=DatapathInfo(uuid='5',
+ self.ports.append(makePort(datapath=DatapathInfo(uuid='5',
external_ids={'name': 'neutron-5'}), type='unknown'))
- with mock.patch.object(self.agent, 'provision_datapath',
- return_value=None) as pdp,\
- mock.patch.object(self.agent.sb_idl, 'get_ports_on_chassis',
- return_value=ports):
- self.agent.ensure_all_networks_provisioned()
-
- expected_calls = [mock.call(str(i), str(i)) for i in range(0, 4)]
- self.assertEqual(sorted(expected_calls),
- sorted(pdp.call_args_list))
+ expected_networks = {(str(i), str(i)) for i in range(0, 4)}
+ self.assertEqual(expected_networks, self.agent.get_networks())
def test_update_datapath_provision(self):
- ports = []
- for i in range(0, 3):
- ports.append(makePort(datapath=DatapathInfo(uuid=str(i),
- external_ids={'name': 'neutron-%d' % i})))
- ports.append(makePort(datapath=DatapathInfo(uuid='3',
+ self.ports.append(makePort(datapath=DatapathInfo(uuid='3',
external_ids={'name': 'neutron-3'}), type='external'))
with mock.patch.object(self.agent, 'provision_datapath',
return_value=None) as pdp,\
- mock.patch.object(self.agent, 'teardown_datapath') as tdp,\
- mock.patch.object(self.agent.sb_idl, 'get_ports_on_chassis',
- return_value=ports):
+ mock.patch.object(self.agent, 'teardown_datapath') as tdp:
self.agent.update_datapath('1', 'a')
self.agent.update_datapath('3', 'b')
expected_calls = [mock.call('1', 'a'), mock.call('3', 'b')]
@@ -160,16 +155,9 @@ class TestMetadataAgent(base.BaseTestCase):
tdp.assert_not_called()
def test_update_datapath_teardown(self):
- ports = []
- for i in range(0, 3):
- ports.append(makePort(datapath=DatapathInfo(uuid=str(i),
- external_ids={'name': 'neutron-%d' % i})))
-
with mock.patch.object(self.agent, 'provision_datapath',
return_value=None) as pdp,\
- mock.patch.object(self.agent, 'teardown_datapath') as tdp,\
- mock.patch.object(self.agent.sb_idl, 'get_ports_on_chassis',
- return_value=ports):
+ mock.patch.object(self.agent, 'teardown_datapath') as tdp:
self.agent.update_datapath('5', 'a')
tdp.assert_called_once_with('5', 'a')
pdp.assert_not_called()