diff --git a/neutron/services/trunk/plugin.py b/neutron/services/trunk/plugin.py index ad150f3db53..56c870cc45f 100644 --- a/neutron/services/trunk/plugin.py +++ b/neutron/services/trunk/plugin.py @@ -21,6 +21,7 @@ from neutron_lib.api.definitions import trunk_details from neutron_lib.callbacks import events from neutron_lib.callbacks import registry from neutron_lib.callbacks import resources +from neutron_lib import constants as const from neutron_lib import context from neutron_lib.db import api as db_api from neutron_lib.db import resource_extend @@ -451,12 +452,19 @@ class TrunkPlugin(service_base.ServicePluginBase): original_port = kwargs['original_port'] orig_vif_type = original_port.get(portbindings.VIF_TYPE) new_vif_type = updated_port.get(portbindings.VIF_TYPE) + orig_status = original_port.get('status') + new_status = updated_port.get('status') vif_type_changed = orig_vif_type != new_vif_type + trunk_id = trunk_details['trunk_id'] if vif_type_changed and new_vif_type == portbindings.VIF_TYPE_UNBOUND: - trunk_id = trunk_details['trunk_id'] # NOTE(status_police) Trunk status goes to DOWN when the parent # port is unbound. This means there are no more physical resources # associated with the logical resource. self.update_trunk( context, trunk_id, {'trunk': {'status': constants.TRUNK_DOWN_STATUS}}) + elif new_status == const.PORT_STATUS_ACTIVE and \ + new_status != orig_status: + self.update_trunk( + context, trunk_id, + {'trunk': {'status': constants.TRUNK_ACTIVE_STATUS}}) diff --git a/neutron/tests/unit/services/trunk/test_plugin.py b/neutron/tests/unit/services/trunk/test_plugin.py index d4954ddcbf7..505b7dff650 100644 --- a/neutron/tests/unit/services/trunk/test_plugin.py +++ b/neutron/tests/unit/services/trunk/test_plugin.py @@ -18,6 +18,7 @@ from neutron_lib.api.definitions import portbindings from neutron_lib.callbacks import events from neutron_lib.callbacks import registry from neutron_lib.callbacks import resources +from neutron_lib import constants as neutron_const from neutron_lib.plugins import directory from neutron_lib.services.trunk import constants import testtools @@ -293,6 +294,32 @@ class TrunkPluginTestCase(test_plugin.Ml2PluginV2TestCase): {'sub_ports': [{'port_id': subport['port']['id']}]}) self.assertEqual(constants.TRUNK_DOWN_STATUS, trunk['status']) + def test__trigger_trunk_status_change_parent_port_status_down(self): + callback = register_mock_callback(resources.TRUNK, events.AFTER_UPDATE) + with self.port() as parent: + parent['status'] = neutron_const.PORT_STATUS_DOWN + original_port = {'status': neutron_const.PORT_STATUS_DOWN} + _, _ = ( + self._test__trigger_trunk_status_change( + parent, original_port, + constants.TRUNK_DOWN_STATUS, + constants.TRUNK_DOWN_STATUS)) + callback.assert_not_called() + + def test__trigger_trunk_status_change_parent_port_status_up(self): + callback = register_mock_callback(resources.TRUNK, events.AFTER_UPDATE) + with self.port() as parent: + parent['status'] = neutron_const.PORT_STATUS_ACTIVE + original_port = {'status': neutron_const.PORT_STATUS_DOWN} + _, _ = ( + self._test__trigger_trunk_status_change( + parent, original_port, + constants.TRUNK_DOWN_STATUS, + constants.TRUNK_ACTIVE_STATUS)) + callback.assert_called_once_with( + resources.TRUNK, events.AFTER_UPDATE, + self.trunk_plugin, payload=mock.ANY) + def test__trigger_trunk_status_change_vif_type_changed_unbound(self): callback = register_mock_callback(resources.TRUNK, events.AFTER_UPDATE) with self.port() as parent: