From 9ce4e29a3e09f8a2c3485579a45804db0c213fba Mon Sep 17 00:00:00 2001 From: Michal Kelner Mishali Date: Mon, 26 Mar 2018 15:55:46 +0300 Subject: [PATCH] Handle network and port create/update, ENS + QOS Bug fix 2082554: handle the exception in neutron side for Qos since its not supported from NSXT for ENS TZ Change-Id: I8ca4c7d04286830ce785a60d7a24439b9a39d801 Signed-off-by: Michal Kelner Mishali --- vmware_nsx/plugins/nsx_v3/plugin.py | 32 ++++- vmware_nsx/tests/unit/nsx_v3/test_plugin.py | 128 ++++++++++++++++++++ 2 files changed, 157 insertions(+), 3 deletions(-) diff --git a/vmware_nsx/plugins/nsx_v3/plugin.py b/vmware_nsx/plugins/nsx_v3/plugin.py index b02745608b..bf7811d3de 100644 --- a/vmware_nsx/plugins/nsx_v3/plugin.py +++ b/vmware_nsx/plugins/nsx_v3/plugin.py @@ -965,6 +965,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, provider_data = self._validate_provider_create(context, net_data, az, transparent_vlan) + physical_net = provider_data['physical_net'] + self._assert_on_ens_with_qos(physical_net, net_data) if (provider_data['switch_mode'] == self.nsxlib.transport_zone.HOST_SWITCH_MODE_ENS): if not cfg.CONF.nsx_v3.ens_support: @@ -1256,6 +1258,12 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, return created_net + def _assert_on_ens_with_qos(self, tz_id, net_data): + qos_id = net_data.get(qos_consts.QOS_POLICY_ID) + if validators.is_attr_set(qos_id) and tz_id and self._is_ens_tz(tz_id): + err_msg = _("Cannot configure QOS on ENS networks") + raise n_exc.InvalidInput(error_message=err_msg) + def _has_active_port(self, context, network_id): ports_in_use = context.session.query(models_v2.Port).filter_by( network_id=network_id).all() @@ -1357,6 +1365,9 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, is_nsx_net = self._network_is_nsx_net(context, id) if extern_net: self._assert_on_external_net_with_qos(net_data) + else: + self._assert_on_ens_with_qos(self._get_net_tz(context, id), + net_data) updated_net = super(NsxV3Plugin, self).update_network(context, id, network) self._extension_manager.process_update_network(context, net_data, @@ -2232,11 +2243,13 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, tz_id = self._get_net_tz(context, net_id) if tz_id: # Check the mode of this TZ - mode = self.nsxlib.transport_zone.get_host_switch_mode(tz_id) - return (mode == - self.nsxlib.transport_zone.HOST_SWITCH_MODE_ENS) + return self._is_ens_tz(tz_id) return False + def _is_ens_tz(self, tz_id): + mode = self.nsxlib.transport_zone.get_host_switch_mode(tz_id) + return mode == self.nsxlib.transport_zone.HOST_SWITCH_MODE_ENS + def _is_ens_tz_port(self, context, port_data): # Check the host-switch-mode of the TZ connected to the ports network return self._is_ens_tz_net(context, port_data['network_id']) @@ -2726,6 +2739,12 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, port_data.get('device_owner')) self._assert_on_dhcp_relay_without_router(context, port_data) is_ens_tz_port = self._is_ens_tz_port(context, port_data) + qos_selected = validators.is_attr_set(port_data.get( + qos_consts.QOS_POLICY_ID)) + + if is_ens_tz_port and qos_selected: + err_msg = _("Cannot configure QOS on ENS networks") + raise n_exc.InvalidInput(error_message=err_msg) # TODO(salv-orlando): Undo logical switch creation on failure with db_api.context_manager.writer.using(context): @@ -3202,6 +3221,13 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, self._assert_on_dhcp_relay_without_router(context, port_data, original_port) + is_ens_tz_port = self._is_ens_tz_port(context, original_port) + qos_selected = validators.is_attr_set(port_data.get + (qos_consts.QOS_POLICY_ID)) + if is_ens_tz_port and qos_selected: + err_msg = _("Cannot configure QOS on ENS networks") + raise n_exc.InvalidInput(error_message=err_msg) + dhcp_opts = port_data.get(ext_edo.EXTRADHCPOPTS) self._validate_extra_dhcp_options(dhcp_opts) diff --git a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py index 2c72d65433..77405b6f22 100644 --- a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py +++ b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py @@ -509,6 +509,65 @@ class TestNetworksV2(test_plugin.TestNetworksV2, NsxV3PluginTestCaseMixin): self.assertEqual('NsxENSPortSecurity', res['NeutronError']['type']) + def test_create_ens_network_with_qos(self): + cfg.CONF.set_override('ens_support', True, 'nsx_v3') + mock_ens = mock.patch('vmware_nsxlib.v3' + '.core_resources.NsxLibTransportZone' + '.get_host_switch_mode', return_value='ENS') + mock_tz = mock.patch('vmware_nsxlib.v3' + '.core_resources.NsxLibLogicalSwitch.get', + return_value={'transport_zone_id': 'xxx'}) + mock_tt = mock.patch('vmware_nsxlib.v3' + '.core_resources.NsxLibTransportZone' + '.get_transport_type', return_value='VLAN') + policy_id = uuidutils.generate_uuid() + data = {'network': { + 'name': 'qos_net', + 'tenant_id': 'some_tenant', + 'provider:network_type': 'flat', + 'provider:physical_network': 'xxx', + 'qos_policy_id': policy_id, + 'port_security_enabled': False}} + with mock_ens, mock_tz, mock_tt: + self.assertRaises(n_exc.InvalidInput, + self.plugin.create_network, + context.get_admin_context(), data) + + def test_update_ens_network_with_qos(self): + cfg.CONF.set_override('ens_support', True, 'nsx_v3') + mock_ens = mock.patch('vmware_nsxlib.v3' + '.core_resources.NsxLibTransportZone' + '.get_host_switch_mode', return_value='ENS') + mock_tz = mock.patch('vmware_nsxlib.v3' + '.core_resources.NsxLibLogicalSwitch.get', + return_value={'transport_zone_id': 'xxx'}) + mock_tt = mock.patch('vmware_nsxlib.v3' + '.core_resources.NsxLibTransportZone' + '.get_transport_type', return_value='VLAN') + data = {'network': { + 'name': 'qos_net', + 'tenant_id': 'some_tenant', + 'provider:network_type': 'flat', + 'provider:physical_network': 'xxx', + 'admin_state_up': True, + 'shared': False, + 'port_security_enabled': False}} + with mock_ens, mock_tz, mock_tt: + network = self.plugin.create_network(context.get_admin_context(), + data) + policy_id = uuidutils.generate_uuid() + data = {'network': { + 'id': network['id'], + 'admin_state_up': True, + 'shared': False, + 'port_security_enabled': False, + 'tenant_id': 'some_tenant', + 'qos_policy_id': policy_id}} + self.assertRaises(n_exc.InvalidInput, + self.plugin.update_network, + context.get_admin_context(), + network['id'], data) + def test_update_ens_network(self): cfg.CONF.set_override('ens_support', True, 'nsx_v3') providernet_args = {psec.PORTSECURITY: False} @@ -819,6 +878,75 @@ class TestPortsV2(test_plugin.TestPortsV2, NsxV3PluginTestCaseMixin, self.assertRaises(n_exc.InvalidInput, self.plugin.create_port, self.ctx, data) + def test_create_port_ens_with_qos_fail(self): + with self.network() as network: + with self.subnet(network=network, cidr='10.0.0.0/24'): + policy_id = uuidutils.generate_uuid() + mock_ens = mock.patch('vmware_nsxlib.v3' + '.core_resources.NsxLibTransportZone' + '.get_host_switch_mode', + return_value='ENS') + mock_tz = mock.patch('vmware_nsxlib.v3' + '.core_resources' + '.NsxLibLogicalSwitch.get', + return_value={ + 'transport_zone_id': 'xxx'}) + mock_tt = mock.patch('vmware_nsxlib.v3' + '.core_resources.NsxLibTransportZone' + '.get_transport_type', + return_value='VLAN') + data = {'port': { + 'network_id': network['network']['id'], + 'tenant_id': self._tenant_id, + 'name': 'qos_port', + 'admin_state_up': True, + 'device_id': 'fake_device', + 'device_owner': 'fake_owner', + 'fixed_ips': [], + 'port_security_enabled': False, + 'mac_address': '00:00:00:00:00:01', + 'qos_policy_id': policy_id} + } + # Cannot add qos policy to this type of port + with mock_ens, mock_tz, mock_tt: + self.assertRaises(n_exc.InvalidInput, + self.plugin.create_port, self.ctx, data) + + def test_update_port_ens_with_qos_fail(self): + with self.network() as network: + with self.subnet(network=network, cidr='10.0.0.0/24'): + policy_id = uuidutils.generate_uuid() + mock_ens = mock.patch('vmware_nsxlib.v3' + '.core_resources.NsxLibTransportZone' + '.get_host_switch_mode', + return_value='ENS') + mock_tz = mock.patch('vmware_nsxlib.v3' + '.core_resources' + '.NsxLibLogicalSwitch.get', + return_value={ + 'transport_zone_id': 'xxx'}) + mock_tt = mock.patch('vmware_nsxlib.v3' + '.core_resources.NsxLibTransportZone' + '.get_transport_type', + return_value='VLAN') + data = {'port': { + 'network_id': network['network']['id'], + 'tenant_id': self._tenant_id, + 'name': 'qos_port', + 'admin_state_up': True, + 'device_id': 'fake_device', + 'device_owner': 'fake_owner', + 'fixed_ips': [], + 'port_security_enabled': False, + 'mac_address': '00:00:00:00:00:01'} + } + with mock_ens, mock_tz, mock_tt: + port = self.plugin.create_port(self.ctx, data) + data['port'] = {'qos_policy_id': policy_id} + self.assertRaises(n_exc.InvalidInput, + self.plugin.update_port, + self.ctx, port['id'], data) + def test_create_router_port_with_qos_fail(self): self._test_create_illegal_port_with_qos_fail( 'network:router_interface')