Skip to content

Commit d322f8e

Browse files
committed
neutron: Unbind remaining ports after PortNotFound
Just because we encountered a PortNotFound error when unbinding a port doesn't mean we should stop unbinding the remaining ports. If this error is encountered, simply continue with the other ports. While we're here, we clean up some other tests related to '_unbind_port' since they're clearly duplicates. Conflicts: nova/tests/unit/network/test_neutron.py NOTE(stephenfin): Conflicts are due to the absence of change I8058902df167239fa455396d3595a56bcf472b2b ("neutron: Rework how we check for extensions") which we don't want to backport. Change-Id: Id04e0df12829df4d8929e03a8b76b5cbe0549059 Signed-off-by: Stephen Finucane <[email protected]> Closes-Bug: #1974173 (cherry picked from commit 9e0dcb5) (cherry picked from commit 6f32b11)
1 parent 568769e commit d322f8e

File tree

2 files changed

+64
-23
lines changed

2 files changed

+64
-23
lines changed

nova/network/neutron.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,7 @@ def _unbind_ports(self, context, ports,
621621
# in case the caller forgot to filter the list.
622622
if port_id is None:
623623
continue
624+
624625
port_req_body: ty.Dict[str, ty.Any] = {
625626
'port': {
626627
'device_id': '',
@@ -635,7 +636,7 @@ def _unbind_ports(self, context, ports,
635636
except exception.PortNotFound:
636637
LOG.debug('Unable to show port %s as it no longer '
637638
'exists.', port_id)
638-
return
639+
continue
639640
except Exception:
640641
# NOTE: In case we can't retrieve the binding:profile or
641642
# network info assume that they are empty

nova/tests/unit/network/test_neutron.py

Lines changed: 62 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5212,7 +5212,8 @@ def test_get_preexisting_port_ids(self, mock_get_nw_info):
52125212
self.assertEqual(['2', '3'], result, "Invalid preexisting ports")
52135213

52145214
@mock.patch('nova.network.neutron.API._show_port')
5215-
def _test_unbind_ports_get_client(self, mock_neutron, mock_show):
5215+
@mock.patch('nova.network.neutron.get_client')
5216+
def test_unbind_ports_get_client(self, mock_neutron, mock_show):
52165217
mock_ctx = mock.Mock(is_admin=False)
52175218
ports = ["1", "2", "3"]
52185219

@@ -5228,23 +5229,16 @@ def _test_unbind_ports_get_client(self, mock_neutron, mock_show):
52285229
self.assertEqual(1, mock_neutron.call_count)
52295230
mock_neutron.assert_has_calls(get_client_calls, True)
52305231

5231-
@mock.patch('nova.network.neutron.get_client')
5232-
def test_unbind_ports_get_client_binding_extension(self,
5233-
mock_neutron):
5234-
self._test_unbind_ports_get_client(mock_neutron)
5235-
5236-
@mock.patch('nova.network.neutron.get_client')
5237-
def test_unbind_ports_get_client(self, mock_neutron):
5238-
self._test_unbind_ports_get_client(mock_neutron)
5239-
52405232
@mock.patch('nova.network.neutron.API._show_port')
5241-
def _test_unbind_ports(self, mock_neutron, mock_show):
5233+
@mock.patch('nova.network.neutron.get_client')
5234+
def test_unbind_ports(self, mock_neutron, mock_show):
52425235
mock_client = mock.Mock()
52435236
mock_update_port = mock.Mock()
52445237
mock_client.update_port = mock_update_port
52455238
mock_ctx = mock.Mock(is_admin=False)
52465239
ports = ["1", "2", "3"]
52475240
mock_show.side_effect = [{"id": "1"}, {"id": "2"}, {"id": "3"}]
5241+
52485242
api = neutronapi.API()
52495243
api._unbind_ports(mock_ctx, ports, mock_neutron, mock_client)
52505244

@@ -5258,14 +5252,6 @@ def _test_unbind_ports(self, mock_neutron, mock_show):
52585252
self.assertEqual(3, mock_update_port.call_count)
52595253
mock_update_port.assert_has_calls(update_port_calls)
52605254

5261-
@mock.patch('nova.network.neutron.get_client')
5262-
def test_unbind_ports_binding_ext(self, mock_neutron):
5263-
self._test_unbind_ports(mock_neutron)
5264-
5265-
@mock.patch('nova.network.neutron.get_client')
5266-
def test_unbind_ports(self, mock_neutron):
5267-
self._test_unbind_ports(mock_neutron)
5268-
52695255
def test_unbind_ports_no_port_ids(self):
52705256
# Tests that None entries in the ports list are filtered out.
52715257
mock_client = mock.Mock()
@@ -6014,7 +6000,6 @@ def test_get_instance_id_by_floating_address_port_not_found(self,
60146000
def test_unbind_ports_port_show_portnotfound(self, mock_log, mock_show):
60156001
api = neutronapi.API()
60166002
neutron_client = mock.Mock()
6017-
mock_show.return_value = {'id': uuids.port}
60186003
api._unbind_ports(self.context, [uuids.port_id],
60196004
neutron_client, neutron_client)
60206005
mock_show.assert_called_once_with(
@@ -6023,6 +6008,59 @@ def test_unbind_ports_port_show_portnotfound(self, mock_log, mock_show):
60236008
neutron_client=mock.ANY)
60246009
mock_log.assert_not_called()
60256010

6011+
@mock.patch('nova.network.neutron.API._show_port')
6012+
@mock.patch.object(neutronapi, 'LOG')
6013+
def test_unbind_ports_port_show_portnotfound_multiple_ports(
6014+
self, mock_log, mock_show,
6015+
):
6016+
"""Ensure we continue unbinding ports even when one isn't found."""
6017+
mock_show.side_effect = [
6018+
exception.PortNotFound(port_id=uuids.port_a),
6019+
{'id': uuids.port_b},
6020+
]
6021+
api = neutronapi.API()
6022+
neutron_client = mock.Mock()
6023+
6024+
api._unbind_ports(
6025+
self.context,
6026+
[uuids.port_a, uuids.port_b],
6027+
neutron_client,
6028+
neutron_client,
6029+
)
6030+
6031+
mock_show.assert_has_calls(
6032+
[
6033+
mock.call(
6034+
self.context,
6035+
uuids.port_a,
6036+
fields=['binding:profile', 'network_id'],
6037+
neutron_client=neutron_client,
6038+
),
6039+
mock.call(
6040+
self.context,
6041+
uuids.port_b,
6042+
fields=['binding:profile', 'network_id'],
6043+
neutron_client=neutron_client,
6044+
),
6045+
]
6046+
)
6047+
# Only the port that exists should be updated
6048+
neutron_client.update_port.assert_called_once_with(
6049+
uuids.port_b,
6050+
{
6051+
'port': {
6052+
'device_id': '',
6053+
'device_owner': '',
6054+
'binding:profile': {},
6055+
'binding:host_id': None,
6056+
}
6057+
}
6058+
)
6059+
mock_log.exception.assert_not_called()
6060+
mock_log.debug.assert_called_with(
6061+
'Unable to show port %s as it no longer exists.', uuids.port_a,
6062+
)
6063+
60266064
@mock.patch('nova.network.neutron.API._show_port',
60276065
side_effect=Exception)
60286066
@mock.patch.object(neutronapi.LOG, 'exception')
@@ -6042,7 +6080,7 @@ def test_unbind_ports_port_show_unexpected_error(self,
60426080

60436081
@mock.patch('nova.network.neutron.API._show_port')
60446082
@mock.patch.object(neutronapi.LOG, 'exception')
6045-
def test_unbind_ports_portnotfound(self, mock_log, mock_show):
6083+
def test_unbind_ports_port_update_portnotfound(self, mock_log, mock_show):
60466084
api = neutronapi.API()
60476085
neutron_client = mock.Mock()
60486086
neutron_client.update_port = mock.Mock(
@@ -6058,7 +6096,9 @@ def test_unbind_ports_portnotfound(self, mock_log, mock_show):
60586096

60596097
@mock.patch('nova.network.neutron.API._show_port')
60606098
@mock.patch.object(neutronapi.LOG, 'exception')
6061-
def test_unbind_ports_unexpected_error(self, mock_log, mock_show):
6099+
def test_unbind_ports_port_update_unexpected_error(
6100+
self, mock_log, mock_show,
6101+
):
60626102
api = neutronapi.API()
60636103
neutron_client = mock.Mock()
60646104
neutron_client.update_port = mock.Mock(

0 commit comments

Comments
 (0)