From 77e51f14a50dafb46176e50ff3788e7918ff29df Mon Sep 17 00:00:00 2001 From: Gary Kotton Date: Sun, 21 Aug 2016 23:37:27 -0700 Subject: [PATCH] VMware: ensure that provider networks work for type 'portgroup' When an existing portgroup is used as a provider network the vmware_nsx NSX|V and DVS plugins will validate that the name of the network is the same name as the actual portgroup. This name is used when searching for the portgroup. Using the network UUID will not match here as that is the network UUID. A provider network can be a regular port group or a NSX virtual wire. Change-Id: Icc72b9c4ddd11964f0e4a774588684eb016fae0f Closes-bug: #1615498 --- .../unit/virt/vmwareapi/test_network_util.py | 13 +++++++++++ nova/tests/unit/virt/vmwareapi/test_vif.py | 19 ++++++++++++++++ nova/virt/vmwareapi/network_util.py | 22 +++++++++++++++---- nova/virt/vmwareapi/vif.py | 7 ++++++ 4 files changed, 57 insertions(+), 4 deletions(-) diff --git a/nova/tests/unit/virt/vmwareapi/test_network_util.py b/nova/tests/unit/virt/vmwareapi/test_network_util.py index 35616cb99d..66b43789b0 100644 --- a/nova/tests/unit/virt/vmwareapi/test_network_util.py +++ b/nova/tests/unit/virt/vmwareapi/test_network_util.py @@ -233,3 +233,16 @@ class GetVlanIdAndVswitchForPortgroupTestCase(test.NoDBTestCase): response = fake.DataObject() response.HostPortGroup = [port_group] return response + + +class GetDVSNetworkNameTestCase(test.NoDBTestCase): + + def test__get_name_from_dvs_name(self): + vxw = 'vxw-dvs-22-virtualwire-89-sid-5008-' + uuid = '2425c130-fd39-45a6-91d8-bf7ebe66b77c' + cases = [('name', 'name'), + ('%sname' % vxw, 'name'), + ('%s%s' % (vxw, uuid), uuid)] + for (dvsname, expected) in cases: + self.assertEqual(expected, + network_util._get_name_from_dvs_name(dvsname)) diff --git a/nova/tests/unit/virt/vmwareapi/test_vif.py b/nova/tests/unit/virt/vmwareapi/test_vif.py index aecd9abe64..c6ee403d4a 100644 --- a/nova/tests/unit/virt/vmwareapi/test_vif.py +++ b/nova/tests/unit/virt/vmwareapi/test_vif.py @@ -343,3 +343,22 @@ class VMwareVifTestCase(test.NoDBTestCase): version_arg_found = True break self.assertTrue(version_arg_found) + + @mock.patch.object(network_util, 'get_network_with_the_name') + def test_get_neutron_network_dvs_provider(self, mock_network_name): + fake_network_obj = {'type': 'DistributedVirtualPortgroup', + 'dvpg': 'fake-key', + 'dvsw': 'fake-props'} + mock_network_name.side_effect = [None, fake_network_obj] + vif_info = network_model.NetworkInfo([ + network_model.VIF(type=network_model.VIF_TYPE_DVS, + address='DE:AD:BE:EF:00:00', + network=self._network)] + )[0] + network_ref = vif._get_neutron_network('fake-session', + 'fake-cluster', + vif_info) + calls = [mock.call('fake-session', 'fa0', 'fake-cluster'), + mock.call('fake-session', 'fake', 'fake-cluster')] + mock_network_name.assert_has_calls(calls) + self.assertEqual(fake_network_obj, network_ref) diff --git a/nova/virt/vmwareapi/network_util.py b/nova/virt/vmwareapi/network_util.py index d835d008e8..367fbf8521 100644 --- a/nova/virt/vmwareapi/network_util.py +++ b/nova/virt/vmwareapi/network_util.py @@ -17,6 +17,8 @@ """ Utility functions for ESX Networking. """ +import re + from oslo_log import log as logging from oslo_vmware import exceptions as vexc from oslo_vmware import vim_util as vutil @@ -28,6 +30,20 @@ from nova.virt.vmwareapi import vm_util LOG = logging.getLogger(__name__) +# a virtual wire will have the following format: +# vxw---- +# Examples: +# - vxw-dvs-22-virtualwire-89-sid-5008-NAME +# - vxw-dvs-22-virtualwire-89-sid-5008-UUID +VWIRE_REGEX = re.compile('vxw-dvs-(\d+)-virtualwire-(\d+)-sid-(\d+)-(.*)') + + +def _get_name_from_dvs_name(dvs_name): + vwire = VWIRE_REGEX.match(dvs_name) + if not vwire: + return dvs_name + return vwire.group(4) + def _get_network_obj(session, network_objects, network_name): """Gets the network object for the requested network. @@ -64,10 +80,8 @@ def _get_network_obj(session, network_objects, network_name): "config") # NOTE(asomya): This only works on ESXi if the port binding # is set to ephemeral - # For a VLAN the network name will be the UUID. For a VXLAN - # network this will have a VXLAN prefix and then the - # network name. - if network_name in props.name: + net_name = _get_name_from_dvs_name(props.name) + if network_name in net_name: network_obj['type'] = 'DistributedVirtualPortgroup' network_obj['dvpg'] = props.key dvs_props = session._call_method(vutil, diff --git a/nova/virt/vmwareapi/vif.py b/nova/virt/vmwareapi/vif.py index c937cf454b..93f1aaa4fa 100644 --- a/nova/virt/vmwareapi/vif.py +++ b/nova/virt/vmwareapi/vif.py @@ -138,6 +138,13 @@ def _get_neutron_network(session, cluster, vif): network_id = vif['network']['bridge'] network_ref = network_util.get_network_with_the_name( session, network_id, cluster) + if not network_ref: + # We may have a provider network for a portgroup. The portgroup + # will have the same name as the network 'label'. This is enforced + # when the provider network is created + network_id = vif['network']['label'] + network_ref = network_util.get_network_with_the_name( + session, network_id, cluster) if not network_ref: raise exception.NetworkNotFoundForBridge(bridge=network_id) if vif.get('details') and vif['details'].get('dvs_port_key'):