Skip to content

Commit fe077c5

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "ovn: first tear down old metadata namespaces, then deploy new" into stable/yoga
2 parents ab12ee0 + e62c81a commit fe077c5

File tree

2 files changed

+51
-64
lines changed

2 files changed

+51
-64
lines changed

neutron/agent/ovn/metadata/agent.py

Lines changed: 23 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,12 @@ def _get_ovn_bridge(self):
315315
"br-int instead.")
316316
return 'br-int'
317317

318+
def get_networks(self):
319+
ports = self.sb_idl.get_ports_on_chassis(self.chassis)
320+
return {(str(p.datapath.uuid),
321+
ovn_utils.get_network_name_from_datapath(p.datapath))
322+
for p in self._vif_ports(ports)}
323+
318324
@_sync_lock
319325
def sync(self):
320326
"""Agent sync.
@@ -323,16 +329,26 @@ def sync(self):
323329
chassis are serving metadata. Also, it will tear down those namespaces
324330
which were serving metadata but are no longer needed.
325331
"""
326-
metadata_namespaces = self.ensure_all_networks_provisioned()
332+
333+
# first, clean up namespaces that should no longer deploy
327334
system_namespaces = tuple(
328335
ns.decode('utf-8') if isinstance(ns, bytes) else ns
329336
for ns in ip_lib.list_network_namespaces())
337+
nets = self.get_networks()
338+
metadata_namespaces = [
339+
self._get_namespace_name(net[1])
340+
for net in nets
341+
]
330342
unused_namespaces = [ns for ns in system_namespaces if
331343
ns.startswith(NS_PREFIX) and
332344
ns not in metadata_namespaces]
333345
for ns in unused_namespaces:
334346
self.teardown_datapath(self._get_datapath_name(ns))
335347

348+
# now that all obsolete namespaces are cleaned up, deploy required
349+
# networks
350+
self.ensure_all_networks_provisioned(nets)
351+
336352
@staticmethod
337353
def _get_veth_name(datapath):
338354
return ['{}{}{}'.format(n_const.TAP_DEVICE_PREFIX,
@@ -424,8 +440,6 @@ def provision_datapath(self, datapath, net_name):
424440
and assign the IP addresses to the interface corresponding to the
425441
metadata port of the network. It will also remove existing IP
426442
addresses that are no longer needed.
427-
428-
:return: The metadata namespace name of this datapath
429443
"""
430444
LOG.debug("Provisioning metadata for network %s", net_name)
431445
port = self.sb_idl.get_metadata_port_network(datapath)
@@ -533,28 +547,13 @@ def provision_datapath(self, datapath, net_name):
533547
self.conf, bind_address=n_const.METADATA_V4_IP,
534548
network_id=net_name)
535549

536-
return namespace
550+
def ensure_all_networks_provisioned(self, nets):
551+
"""Ensure that all requested datapaths are provisioned.
537552
538-
def ensure_all_networks_provisioned(self):
539-
"""Ensure that all datapaths are provisioned.
540-
541-
This function will make sure that all datapaths with ports bound to
542-
our chassis have its namespace, VETH pair and OVS port created and
543-
metadata proxy is up and running.
544-
545-
:return: A list with the namespaces that are currently serving
546-
metadata
553+
This function will make sure that requested datapaths have their
554+
namespaces, VETH pair and OVS ports created and metadata proxies are up
555+
and running.
547556
"""
548-
# Retrieve all VIF ports in our Chassis
549-
ports = self.sb_idl.get_ports_on_chassis(self.chassis)
550-
nets = {(str(p.datapath.uuid),
551-
ovn_utils.get_network_name_from_datapath(p.datapath))
552-
for p in self._vif_ports(ports)}
553-
namespaces = []
554557
# Make sure that all those datapaths are serving metadata
555558
for datapath, net_name in nets:
556-
netns = self.provision_datapath(datapath, net_name)
557-
if netns:
558-
namespaces.append(netns)
559-
560-
return namespaces
559+
self.provision_datapath(datapath, net_name)

neutron/tests/unit/agent/ovn/metadata/test_agent.py

Lines changed: 28 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -73,19 +73,29 @@ def setUp(self):
7373
self.agent.chassis = 'chassis'
7474
self.agent.ovn_bridge = 'br-int'
7575

76+
self.ports = []
77+
for i in range(0, 3):
78+
self.ports.append(makePort(datapath=DatapathInfo(uuid=str(i),
79+
external_ids={'name': 'neutron-%d' % i})))
80+
self.agent.sb_idl.get_ports_on_chassis.return_value = self.ports
81+
7682
def test_sync(self):
83+
7784
with mock.patch.object(
7885
self.agent, 'ensure_all_networks_provisioned') as enp,\
7986
mock.patch.object(
8087
ip_lib, 'list_network_namespaces') as lnn,\
8188
mock.patch.object(
8289
self.agent, 'teardown_datapath') as tdp:
83-
enp.return_value = ['ovnmeta-1', 'ovnmeta-2']
8490
lnn.return_value = ['ovnmeta-1', 'ovnmeta-2']
8591

8692
self.agent.sync()
8793

88-
enp.assert_called_once_with()
94+
enp.assert_called_once_with({
95+
(p.datapath.uuid, p.datapath.uuid)
96+
for p in self.ports
97+
})
98+
8999
lnn.assert_called_once_with()
90100
tdp.assert_not_called()
91101

@@ -97,18 +107,20 @@ def test_sync_teardown_namespace(self):
97107
ip_lib, 'list_network_namespaces') as lnn,\
98108
mock.patch.object(
99109
self.agent, 'teardown_datapath') as tdp:
100-
enp.return_value = ['ovnmeta-1', 'ovnmeta-2']
101110
lnn.return_value = ['ovnmeta-1', 'ovnmeta-2', 'ovnmeta-3',
102111
'ns1', 'ns2']
103112

104113
self.agent.sync()
105114

106-
enp.assert_called_once_with()
115+
enp.assert_called_once_with({
116+
(p.datapath.uuid, p.datapath.uuid)
117+
for p in self.ports
118+
})
107119
lnn.assert_called_once_with()
108120
tdp.assert_called_once_with('3')
109121

110-
def test_ensure_all_networks_provisioned(self):
111-
"""Test networks are provisioned.
122+
def test_get_networks(self):
123+
"""Test which networks are provisioned.
112124
113125
This test simulates that this chassis has the following ports:
114126
* datapath '0': 1 port
@@ -117,61 +129,37 @@ def test_ensure_all_networks_provisioned(self):
117129
* datapath '3': 1 port with type 'external'
118130
* datapath '5': 1 port with type 'unknown'
119131
120-
It is expected that only datapaths '0', '1' and '2' are provisioned
121-
once.
132+
It is expected that only datapaths '0', '1' and '2' are scheduled for
133+
provisioning.
122134
"""
123135

124-
ports = []
125-
for i in range(0, 3):
126-
ports.append(makePort(datapath=DatapathInfo(uuid=str(i),
127-
external_ids={'name': 'neutron-%d' % i})))
128-
ports.append(makePort(datapath=DatapathInfo(uuid='1',
136+
self.ports.append(makePort(datapath=DatapathInfo(uuid='1',
129137
external_ids={'name': 'neutron-1'})))
130-
ports.append(makePort(datapath=DatapathInfo(uuid='3',
138+
self.ports.append(makePort(datapath=DatapathInfo(uuid='3',
131139
external_ids={'name': 'neutron-3'}), type='external'))
132-
ports.append(makePort(datapath=DatapathInfo(uuid='5',
140+
self.ports.append(makePort(datapath=DatapathInfo(uuid='5',
133141
external_ids={'name': 'neutron-5'}), type='unknown'))
134142

135-
with mock.patch.object(self.agent, 'provision_datapath',
136-
return_value=None) as pdp,\
137-
mock.patch.object(self.agent.sb_idl, 'get_ports_on_chassis',
138-
return_value=ports):
139-
self.agent.ensure_all_networks_provisioned()
140-
141-
expected_calls = [mock.call(str(i), str(i)) for i in range(0, 4)]
142-
self.assertEqual(sorted(expected_calls),
143-
sorted(pdp.call_args_list))
143+
expected_networks = {(str(i), str(i)) for i in range(0, 4)}
144+
self.assertEqual(expected_networks, self.agent.get_networks())
144145

145146
def test_update_datapath_provision(self):
146-
ports = []
147-
for i in range(0, 3):
148-
ports.append(makePort(datapath=DatapathInfo(uuid=str(i),
149-
external_ids={'name': 'neutron-%d' % i})))
150-
ports.append(makePort(datapath=DatapathInfo(uuid='3',
147+
self.ports.append(makePort(datapath=DatapathInfo(uuid='3',
151148
external_ids={'name': 'neutron-3'}), type='external'))
152149

153150
with mock.patch.object(self.agent, 'provision_datapath',
154151
return_value=None) as pdp,\
155-
mock.patch.object(self.agent, 'teardown_datapath') as tdp,\
156-
mock.patch.object(self.agent.sb_idl, 'get_ports_on_chassis',
157-
return_value=ports):
152+
mock.patch.object(self.agent, 'teardown_datapath') as tdp:
158153
self.agent.update_datapath('1', 'a')
159154
self.agent.update_datapath('3', 'b')
160155
expected_calls = [mock.call('1', 'a'), mock.call('3', 'b')]
161156
pdp.assert_has_calls(expected_calls)
162157
tdp.assert_not_called()
163158

164159
def test_update_datapath_teardown(self):
165-
ports = []
166-
for i in range(0, 3):
167-
ports.append(makePort(datapath=DatapathInfo(uuid=str(i),
168-
external_ids={'name': 'neutron-%d' % i})))
169-
170160
with mock.patch.object(self.agent, 'provision_datapath',
171161
return_value=None) as pdp,\
172-
mock.patch.object(self.agent, 'teardown_datapath') as tdp,\
173-
mock.patch.object(self.agent.sb_idl, 'get_ports_on_chassis',
174-
return_value=ports):
162+
mock.patch.object(self.agent, 'teardown_datapath') as tdp:
175163
self.agent.update_datapath('5', 'a')
176164
tdp.assert_called_once_with('5', 'a')
177165
pdp.assert_not_called()

0 commit comments

Comments
 (0)