diff --git a/neutron/plugins/ml2/common/constants.py b/neutron/plugins/ml2/common/constants.py index f9e627ff59e..a6b015a7a68 100644 --- a/neutron/plugins/ml2/common/constants.py +++ b/neutron/plugins/ml2/common/constants.py @@ -14,6 +14,9 @@ from neutron_lib import constants DEFAULT_DEVICE_OWNER = '' +# TODO(carthaca): use from neutron-lib once +# change id I9be781d99a08a6a015c3747eb15f20bc356cf08e has been released +DEVICE_OWNER_MANILA_PREFIX = "manila:" # TODO(liuyulong): move to neutron-lib or common constants NO_PBLOCKS_TYPES = [ diff --git a/neutron/plugins/ml2/plugin.py b/neutron/plugins/ml2/plugin.py index 7b40a447e2b..d540da76ee7 100644 --- a/neutron/plugins/ml2/plugin.py +++ b/neutron/plugins/ml2/plugin.py @@ -2611,11 +2611,12 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, self.mechanism_manager.update_network_postcommit(mech_context) @staticmethod - def _validate_compute_port(port): - if not port['device_owner'].startswith( - const.DEVICE_OWNER_COMPUTE_PREFIX): + def _validate_port_supports_multiple_bindings(port): + if not port['device_owner'].startswith(( + const.DEVICE_OWNER_COMPUTE_PREFIX, + ml2_consts.DEVICE_OWNER_MANILA_PREFIX)): msg = _('Invalid port %s. Operation only valid on compute ' - 'ports') % port['id'] + 'and shared filesystem ports') % port['id'] raise exc.BadRequest(resource='port', msg=msg) def _make_port_binding_dict(self, binding, fields=None): @@ -2655,7 +2656,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, attrs = binding[pbe_ext.RESOURCE_NAME] with db_api.CONTEXT_WRITER.using(context): port_db = self._get_port(context, port_id) - self._validate_compute_port(port_db) + self._validate_port_supports_multiple_bindings(port_db) if self._get_binding_for_host(port_db.port_bindings, attrs[pbe_ext.HOST]): raise exc.PortBindingAlreadyExists( @@ -2703,7 +2704,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, port = ports_obj.Port.get_object(context, id=port_id) if not port: raise exc.PortNotFound(port_id=port_id) - self._validate_compute_port(port) + self._validate_port_supports_multiple_bindings(port) filters = filters or {} pager = base_obj.Pager(sorts, limit, page_reverse, marker) bindings = ports_obj.PortBinding.get_objects( @@ -2718,7 +2719,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, port = ports_obj.Port.get_object(context, id=port_id) if not port: raise exc.PortNotFound(port_id=port_id) - self._validate_compute_port(port) + self._validate_port_supports_multiple_bindings(port) binding = ports_obj.PortBinding.get_object(context, host=host, port_id=port_id) if not binding: @@ -2736,7 +2737,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, attrs = binding[pbe_ext.RESOURCE_NAME] with db_api.CONTEXT_WRITER.using(context): port_db = self._get_port(context, port_id) - self._validate_compute_port(port_db) + self._validate_port_supports_multiple_bindings(port_db) original_binding = self._get_binding_for_host( port_db.port_bindings, host) if not original_binding: @@ -2773,7 +2774,7 @@ class Ml2Plugin(db_base_plugin_v2.NeutronDbPluginV2, if isinstance(port_id, dict): port_id = port_id['port_id'] port_db = self._get_port(context, port_id) - self._validate_compute_port(port_db) + self._validate_port_supports_multiple_bindings(port_db) active_binding = p_utils.get_port_binding_by_status_and_host( port_db.port_bindings, const.ACTIVE) if host == (active_binding and active_binding.host): diff --git a/neutron/tests/unit/plugins/ml2/test_plugin.py b/neutron/tests/unit/plugins/ml2/test_plugin.py index 6f49c0465db..5045f365d6b 100644 --- a/neutron/tests/unit/plugins/ml2/test_plugin.py +++ b/neutron/tests/unit/plugins/ml2/test_plugin.py @@ -2197,6 +2197,25 @@ class TestMl2PluginOnly(Ml2PluginV2TestCase): host=host, port_id=port_id) + def test__validate_port_supports_multiple_bindings(self): + plugin = directory.get_plugin() + device_owner_raises = { + 'manila:share': False, + 'compute:host': False, + 'network:router': True, + 'fake:device': True, + } + + for device_owner, raises in device_owner_raises.items(): + port = {'id': 'fake_port_id', 'device_owner': device_owner} + if raises: + self.assertRaises( + exc.BadRequest, + plugin._validate_port_supports_multiple_bindings, + port) + else: + plugin._validate_port_supports_multiple_bindings(port) + class Test_GetNetworkMtu(Ml2PluginV2TestCase): diff --git a/releasenotes/notes/multiple-portbinding-for-manila-5f5232d506fe414e.yaml b/releasenotes/notes/multiple-portbinding-for-manila-5f5232d506fe414e.yaml new file mode 100644 index 00000000000..e947f8549d3 --- /dev/null +++ b/releasenotes/notes/multiple-portbinding-for-manila-5f5232d506fe414e.yaml @@ -0,0 +1,6 @@ +--- +features: + - | + Manila owned ports can now have multiple port bindings associated in order + to support nondisruptive Manila share server migration across physical + networks.