diff --git a/releasenotes/notes/nsxv3-switching-profiles-250aa43f5070dc37.yaml b/releasenotes/notes/nsxv3-switching-profiles-250aa43f5070dc37.yaml new file mode 100644 index 0000000000..c5bb1812b3 --- /dev/null +++ b/releasenotes/notes/nsxv3-switching-profiles-250aa43f5070dc37.yaml @@ -0,0 +1,8 @@ +--- +prelude: > + The nsx-v3 plugin can add pre-configured switching profiles to new nsx + ports. The configuration can also be done per availability zone. +features: + - | + The nsx-v3 plugin can add pre-configured switching profiles to new nsx + ports. The configuration can also be done per availability zone. diff --git a/vmware_nsx/common/config.py b/vmware_nsx/common/config.py index 7bc5a6d98f..c19806f328 100644 --- a/vmware_nsx/common/config.py +++ b/vmware_nsx/common/config.py @@ -434,6 +434,11 @@ nsx_v3_opts = [ help=_("This is the scope of the tag that will be used for " "finding the objects uuids on the NSX during plugin " "init.")), + cfg.ListOpt('switching_profiles', + default=[], + help=_("Optional parameter defining a list switching profiles " + "uuids that will be attached to all neutron created " + "nsx ports.")), ] @@ -792,6 +797,9 @@ nsxv3_az_opts = [ "transport zone that will be used for bridging between " "Neutron networks, if no physical network has been " "specified")), + cfg.ListOpt('switching_profiles', + help=_("(Optional) list switching profiles uuids that will be " + "attached to all neutron created nsx ports.")), ] # Register the configuration options diff --git a/vmware_nsx/plugins/nsx_v3/availability_zones.py b/vmware_nsx/plugins/nsx_v3/availability_zones.py index 971d4a90e0..a50f7f8bb3 100644 --- a/vmware_nsx/plugins/nsx_v3/availability_zones.py +++ b/vmware_nsx/plugins/nsx_v3/availability_zones.py @@ -19,7 +19,7 @@ from vmware_nsx._i18n import _ from vmware_nsx.common import availability_zones as common_az from vmware_nsx.common import config from vmware_nsx.common import exceptions as nsx_exc - +from vmware_nsxlib.v3 import core_resources DEFAULT_NAME = common_az.DEFAULT_NAME @@ -74,6 +74,10 @@ class NsxV3AvailabilityZone(common_az.ConfiguredAvailabilityZone): if self.default_vlan_tz is None: self.default_vlan_tz = cfg.CONF.nsx_v3.default_vlan_tz + self.switching_profiles = az_info.get('switching_profiles') + if self.switching_profiles is None: + self.switching_profiles = cfg.CONF.nsx_v3.switching_profiles + def init_default_az(self): # use the default configuration self.metadata_proxy = cfg.CONF.nsx_v3.metadata_proxy @@ -83,6 +87,7 @@ class NsxV3AvailabilityZone(common_az.ConfiguredAvailabilityZone): self.nameservers = cfg.CONF.nsx_v3.nameservers self.default_overlay_tz = cfg.CONF.nsx_v3.default_overlay_tz self.default_vlan_tz = cfg.CONF.nsx_v3.default_vlan_tz + self.switching_profiles = cfg.CONF.nsx_v3.switching_profiles def translate_configured_names_to_uuids(self, nsxlib): # Mandatory configurations (in AZ or inherited from global values) @@ -154,6 +159,18 @@ class NsxV3AvailabilityZone(common_az.ConfiguredAvailabilityZone): else: self._default_vlan_tz_uuid = None + # switching profiles are already uuids, but we need to translate + # those to objects + profiles = [] + if self.switching_profiles: + for profile in self.switching_profiles: + nsx_profile = nsxlib.switching_profile.get(profile) + # TODO(asarfaty): skip or alert on unsupported types + profiles.append(core_resources.SwitchingProfileTypeId( + nsx_profile.get('resource_type'), + nsx_profile.get('id'))) + self.switching_profiles_objs = profiles + class NsxV3AvailabilityZones(common_az.ConfiguredAvailabilityZones): diff --git a/vmware_nsx/plugins/nsx_v3/plugin.py b/vmware_nsx/plugins/nsx_v3/plugin.py index 73aec3a1cf..5b556f24b5 100644 --- a/vmware_nsx/plugins/nsx_v3/plugin.py +++ b/vmware_nsx/plugins/nsx_v3/plugin.py @@ -1626,6 +1626,14 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, vif_uuid = port_data['id'] profiles = [] + + # Add availability zone profiles first (so that specific profiles will + # override them) + port_az = self.get_network_az_by_net_id(context, + port_data['network_id']) + if port_az.switching_profiles_objs: + profiles.extend(port_az.switching_profiles_objs) + mac_learning_profile_set = False if psec_is_on: address_pairs = port_data.get(addr_pair.ADDRESS_PAIRS) @@ -2420,6 +2428,14 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin, updated_port.get(ext_sg.SECURITYGROUPS, []) + updated_port.get(provider_sg.PROVIDER_SECURITYGROUPS, [])) + # Add availability zone profiles first (so that specific profiles will + # override them) + port_az = self.get_network_az_by_net_id(context, + updated_port['network_id']) + if port_az.switching_profiles_objs: + switch_profile_ids = (port_az.switching_profiles_objs + + switch_profile_ids) + # Update the DHCP profile if updated_device_owner == const.DEVICE_OWNER_DHCP: switch_profile_ids.append(self._dhcp_profile) diff --git a/vmware_nsx/tests/unit/nsx_v3/test_availability_zones.py b/vmware_nsx/tests/unit/nsx_v3/test_availability_zones.py index 57c767a46c..0ce6afca67 100644 --- a/vmware_nsx/tests/unit/nsx_v3/test_availability_zones.py +++ b/vmware_nsx/tests/unit/nsx_v3/test_availability_zones.py @@ -40,6 +40,7 @@ class Nsxv3AvailabilityZonesTestCase(base.BaseTestCase): "native_metadata_route", "1.1.1.1", group="nsx_v3") cfg.CONF.set_override("dns_domain", "xxx.com", group="nsx_v3") cfg.CONF.set_override("nameservers", ["10.1.1.1"], group="nsx_v3") + cfg.CONF.set_override("switching_profiles", ["uuid1"], group="nsx_v3") def _config_az(self, metadata_proxy="metadata_proxy1", @@ -48,7 +49,8 @@ class Nsxv3AvailabilityZonesTestCase(base.BaseTestCase): dns_domain="aaa.com", nameservers=["20.1.1.1"], default_overlay_tz='otz', - default_vlan_tz='vtz'): + default_vlan_tz='vtz', + switching_profiles=["uuid2"]): if metadata_proxy is not None: cfg.CONF.set_override("metadata_proxy", metadata_proxy, group=self.group_name) @@ -71,6 +73,9 @@ class Nsxv3AvailabilityZonesTestCase(base.BaseTestCase): if default_vlan_tz is not None: cfg.CONF.set_override("default_vlan_tz", default_vlan_tz, group=self.group_name) + if switching_profiles is not None: + cfg.CONF.set_override("switching_profiles", switching_profiles, + group=self.group_name) def test_simple_availability_zone(self): self._config_az() @@ -83,6 +88,7 @@ class Nsxv3AvailabilityZonesTestCase(base.BaseTestCase): self.assertEqual(["20.1.1.1"], az.nameservers) self.assertEqual("otz", az.default_overlay_tz) self.assertEqual("vtz", az.default_vlan_tz) + self.assertEqual(["uuid2"], az.switching_profiles) def test_missing_group_section(self): self.assertRaises( @@ -120,3 +126,8 @@ class Nsxv3AvailabilityZonesTestCase(base.BaseTestCase): self._config_az(nameservers=None) az = nsx_az.NsxV3AvailabilityZone(self.az_name) self.assertEqual(["10.1.1.1"], az.nameservers) + + def test_availability_zone_missing_profiles(self): + self._config_az(switching_profiles=None) + az = nsx_az.NsxV3AvailabilityZone(self.az_name) + self.assertEqual(["uuid1"], az.switching_profiles) diff --git a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py index c0938dcb6e..2a568edae5 100644 --- a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py +++ b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py @@ -61,6 +61,7 @@ PLUGIN_NAME = 'vmware_nsx.plugin.NsxV3Plugin' NSX_TZ_NAME = 'default transport zone' NSX_DHCP_PROFILE_ID = 'default dhcp profile' NSX_METADATA_PROXY_ID = 'default metadata proxy' +NSX_SWITCH_PROFILE = 'dummy switch profile' def _mock_create_firewall_rules(*args): @@ -298,6 +299,8 @@ class TestPortsV2(test_plugin.TestPortsV2, NsxV3PluginTestCaseMixin, HAS_PORT_FILTER = True def setUp(self): + cfg.CONF.set_override('switching_profiles', [NSX_SWITCH_PROFILE], + 'nsx_v3') super(TestPortsV2, self).setUp() self.plugin = directory.get_plugin() self.ctx = context.get_admin_context() @@ -537,6 +540,30 @@ class TestPortsV2(test_plugin.TestPortsV2, NsxV3PluginTestCaseMixin, self.assertEqual(exc.HTTPBadRequest.code, res.status_int) + def test_create_port_with_switching_profiles(self): + """Tests that nsx ports get the configures switching profiles""" + self.plugin = directory.get_plugin() + with self.network() as network: + data = {'port': { + 'network_id': network['network']['id'], + 'tenant_id': self._tenant_id, + 'name': 'p1', + 'admin_state_up': True, + 'device_id': 'fake_device', + 'device_owner': 'fake_owner', + 'fixed_ips': [], + 'mac_address': '00:00:00:00:00:01'} + } + with mock.patch.object(self.plugin.nsxlib.logical_port, 'create', + return_value={'id': 'fake'}) as nsx_create: + self.plugin.create_port(self.ctx, data) + expected_prof = self.plugin.get_default_az().\ + switching_profiles_objs[0] + actual_profs = nsx_create.call_args[1]['switch_profile_ids'] + # the ports switching profiles should start with the + # configured one + self.assertEqual(expected_prof, actual_profs[0]) + def test_update_port_update_ip_address_only(self): self.skipTest('Multiple fixed ips on a port are not supported')