diff --git a/neutron/services/trunk/rpc/server.py b/neutron/services/trunk/rpc/server.py index 5515fe7f241..3e3dce45553 100644 --- a/neutron/services/trunk/rpc/server.py +++ b/neutron/services/trunk/rpc/server.py @@ -128,6 +128,12 @@ class TrunkSkeleton(object): trunk_port_id = trunk.port_id trunk_port = self.core_plugin.get_port(context, trunk_port_id) trunk_host = trunk_port.get(portbindings.HOST_ID) + migrating_to_host = trunk_port.get( + portbindings.PROFILE, {}).get('migrating_to') + if migrating_to_host and trunk_host != migrating_to_host: + # Trunk is migrating now, so lets update host of the subports + # to the new host already + trunk_host = migrating_to_host # NOTE(status_police) Set the trunk in BUILD state before # processing subport bindings. The trunk will stay in BUILD diff --git a/neutron/tests/unit/services/trunk/rpc/test_server.py b/neutron/tests/unit/services/trunk/rpc/test_server.py index 6357635d0cf..c0cd066c0e9 100644 --- a/neutron/tests/unit/services/trunk/rpc/test_server.py +++ b/neutron/tests/unit/services/trunk/rpc/test_server.py @@ -103,6 +103,43 @@ class TrunkSkeletonTest(test_plugin.Ml2PluginV2TestCase): for port in updated_subports[trunk['id']]: self.assertEqual('trunk_host_id', port[portbindings.HOST_ID]) + def test_update_subport_bindings_during_migration(self): + with self.port() as _parent_port: + parent_port = _parent_port + trunk = self._create_test_trunk(parent_port) + subports = [] + for vid in range(0, 3): + with self.port() as new_port: + obj = trunk_obj.SubPort( + context=self.context, + trunk_id=trunk['id'], + port_id=new_port['port']['id'], + segmentation_type='vlan', + segmentation_id=vid) + subports.append(obj) + + expected_calls = [ + mock.call( + mock.ANY, subport['port_id'], + {'port': {portbindings.HOST_ID: 'new_trunk_host_id', + 'device_owner': constants.TRUNK_SUBPORT_OWNER}}) + for subport in subports] + + test_obj = server.TrunkSkeleton() + test_obj._trunk_plugin = self.trunk_plugin + test_obj._core_plugin = self.core_plugin + port_data = { + portbindings.HOST_ID: 'trunk_host_id', + portbindings.PROFILE: {'migrating_to': 'new_trunk_host_id'}} + with mock.patch.object( + self.core_plugin, "get_port", + return_value=port_data), \ + mock.patch.object( + test_obj, "_safe_update_trunk"): + test_obj.update_subport_bindings(self.context, subports=subports) + for expected_call in expected_calls: + self.assertIn(expected_call, self.mock_update_port.mock_calls) + def test__handle_port_binding_binding_error(self): with self.port() as _trunk_port: trunk = self._create_test_trunk(_trunk_port)