diff options
author | Zuul <zuul@review.opendev.org> | 2022-09-25 08:44:37 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2022-09-25 08:44:37 +0000 |
commit | 853872152da038397d80db4d5a87a95a76142f14 (patch) | |
tree | dd07d397ed88d325e5d3f6b4b4677d9ae0676c1b | |
parent | e812b6f580d84402f085a1171a230d88609dc228 (diff) | |
parent | d322f8e8b5a95fd60dab9c6c543b4c77ea893836 (diff) | |
download | nova-853872152da038397d80db4d5a87a95a76142f14.tar.gz |
Merge "neutron: Unbind remaining ports after PortNotFound" into stable/xena
-rw-r--r-- | nova/network/neutron.py | 3 | ||||
-rw-r--r-- | nova/tests/unit/network/test_neutron.py | 84 |
2 files changed, 64 insertions, 23 deletions
diff --git a/nova/network/neutron.py b/nova/network/neutron.py index d8c58c6e13..3ec9d03c26 100644 --- a/nova/network/neutron.py +++ b/nova/network/neutron.py @@ -621,6 +621,7 @@ class API: # in case the caller forgot to filter the list. if port_id is None: continue + port_req_body: ty.Dict[str, ty.Any] = { 'port': { 'device_id': '', @@ -635,7 +636,7 @@ class API: except exception.PortNotFound: LOG.debug('Unable to show port %s as it no longer ' 'exists.', port_id) - return + continue except Exception: # NOTE: In case we can't retrieve the binding:profile or # network info assume that they are empty diff --git a/nova/tests/unit/network/test_neutron.py b/nova/tests/unit/network/test_neutron.py index 5056b70c4e..0d6e84c505 100644 --- a/nova/tests/unit/network/test_neutron.py +++ b/nova/tests/unit/network/test_neutron.py @@ -5212,7 +5212,8 @@ class TestAPI(TestAPIBase): self.assertEqual(['2', '3'], result, "Invalid preexisting ports") @mock.patch('nova.network.neutron.API._show_port') - def _test_unbind_ports_get_client(self, mock_neutron, mock_show): + @mock.patch('nova.network.neutron.get_client') + def test_unbind_ports_get_client(self, mock_neutron, mock_show): mock_ctx = mock.Mock(is_admin=False) ports = ["1", "2", "3"] @@ -5228,23 +5229,16 @@ class TestAPI(TestAPIBase): self.assertEqual(1, mock_neutron.call_count) mock_neutron.assert_has_calls(get_client_calls, True) - @mock.patch('nova.network.neutron.get_client') - def test_unbind_ports_get_client_binding_extension(self, - mock_neutron): - self._test_unbind_ports_get_client(mock_neutron) - - @mock.patch('nova.network.neutron.get_client') - def test_unbind_ports_get_client(self, mock_neutron): - self._test_unbind_ports_get_client(mock_neutron) - @mock.patch('nova.network.neutron.API._show_port') - def _test_unbind_ports(self, mock_neutron, mock_show): + @mock.patch('nova.network.neutron.get_client') + def test_unbind_ports(self, mock_neutron, mock_show): mock_client = mock.Mock() mock_update_port = mock.Mock() mock_client.update_port = mock_update_port mock_ctx = mock.Mock(is_admin=False) ports = ["1", "2", "3"] mock_show.side_effect = [{"id": "1"}, {"id": "2"}, {"id": "3"}] + api = neutronapi.API() api._unbind_ports(mock_ctx, ports, mock_neutron, mock_client) @@ -5258,14 +5252,6 @@ class TestAPI(TestAPIBase): self.assertEqual(3, mock_update_port.call_count) mock_update_port.assert_has_calls(update_port_calls) - @mock.patch('nova.network.neutron.get_client') - def test_unbind_ports_binding_ext(self, mock_neutron): - self._test_unbind_ports(mock_neutron) - - @mock.patch('nova.network.neutron.get_client') - def test_unbind_ports(self, mock_neutron): - self._test_unbind_ports(mock_neutron) - def test_unbind_ports_no_port_ids(self): # Tests that None entries in the ports list are filtered out. mock_client = mock.Mock() @@ -6014,7 +6000,6 @@ class TestAPI(TestAPIBase): def test_unbind_ports_port_show_portnotfound(self, mock_log, mock_show): api = neutronapi.API() neutron_client = mock.Mock() - mock_show.return_value = {'id': uuids.port} api._unbind_ports(self.context, [uuids.port_id], neutron_client, neutron_client) mock_show.assert_called_once_with( @@ -6023,6 +6008,59 @@ class TestAPI(TestAPIBase): neutron_client=mock.ANY) mock_log.assert_not_called() + @mock.patch('nova.network.neutron.API._show_port') + @mock.patch.object(neutronapi, 'LOG') + def test_unbind_ports_port_show_portnotfound_multiple_ports( + self, mock_log, mock_show, + ): + """Ensure we continue unbinding ports even when one isn't found.""" + mock_show.side_effect = [ + exception.PortNotFound(port_id=uuids.port_a), + {'id': uuids.port_b}, + ] + api = neutronapi.API() + neutron_client = mock.Mock() + + api._unbind_ports( + self.context, + [uuids.port_a, uuids.port_b], + neutron_client, + neutron_client, + ) + + mock_show.assert_has_calls( + [ + mock.call( + self.context, + uuids.port_a, + fields=['binding:profile', 'network_id'], + neutron_client=neutron_client, + ), + mock.call( + self.context, + uuids.port_b, + fields=['binding:profile', 'network_id'], + neutron_client=neutron_client, + ), + ] + ) + # Only the port that exists should be updated + neutron_client.update_port.assert_called_once_with( + uuids.port_b, + { + 'port': { + 'device_id': '', + 'device_owner': '', + 'binding:profile': {}, + 'binding:host_id': None, + } + } + ) + mock_log.exception.assert_not_called() + mock_log.debug.assert_called_with( + 'Unable to show port %s as it no longer exists.', uuids.port_a, + ) + @mock.patch('nova.network.neutron.API._show_port', side_effect=Exception) @mock.patch.object(neutronapi.LOG, 'exception') @@ -6042,7 +6080,7 @@ class TestAPI(TestAPIBase): @mock.patch('nova.network.neutron.API._show_port') @mock.patch.object(neutronapi.LOG, 'exception') - def test_unbind_ports_portnotfound(self, mock_log, mock_show): + def test_unbind_ports_port_update_portnotfound(self, mock_log, mock_show): api = neutronapi.API() neutron_client = mock.Mock() neutron_client.update_port = mock.Mock( @@ -6058,7 +6096,9 @@ class TestAPI(TestAPIBase): @mock.patch('nova.network.neutron.API._show_port') @mock.patch.object(neutronapi.LOG, 'exception') - def test_unbind_ports_unexpected_error(self, mock_log, mock_show): + def test_unbind_ports_port_update_unexpected_error( + self, mock_log, mock_show, + ): api = neutronapi.API() neutron_client = mock.Mock() neutron_client.update_port = mock.Mock( |