Merge "VMware: expand support for Opaque networks"

This commit is contained in:
Jenkins
2015-11-16 11:52:25 +00:00
committed by Gerrit Code Review
5 changed files with 199 additions and 188 deletions
+97 -126
View File
@@ -16,7 +16,7 @@
import mock
from oslo_config import cfg
from oslo_vmware import exceptions as vexc
from oslo_vmware import vim_util as vutil
from oslo_vmware import vim_util
from nova import exception
from nova.network import model as network_model
@@ -24,6 +24,7 @@ from nova import test
from nova.tests.unit import matchers
from nova.tests.unit import utils
from nova.tests.unit.virt.vmwareapi import fake
from nova.virt.vmwareapi import constants
from nova.virt.vmwareapi import network_util
from nova.virt.vmwareapi import vif
from nova.virt.vmwareapi import vm_util
@@ -41,7 +42,7 @@ class VMwareVifTestCase(test.NoDBTestCase):
vlan=3,
bridge_interface='eth0',
injected=True)
self._network = network
self.vif = network_model.NetworkInfo([
network_model.VIF(id=None,
address='DE:AD:BE:EF:00:00',
@@ -132,12 +133,6 @@ class VMwareVifTestCase(test.NoDBTestCase):
create_vlan=False)
self.assertThat(ref, matchers.DictMatches(network_ref))
def test_get_network_ref_neutron(self):
self.mox.StubOutWithMock(vif, 'get_neutron_network')
vif.get_neutron_network(self.session, 'fa0', self.cluster, self.vif)
self.mox.ReplayAll()
vif.get_network_ref(self.session, self.cluster, self.vif, True)
def test_get_network_ref_flat_dhcp(self):
self.mox.StubOutWithMock(vif, 'ensure_vlan_bridge')
vif.ensure_vlan_bridge(self.session, self.vif, cluster=self.cluster,
@@ -168,110 +163,6 @@ class VMwareVifTestCase(test.NoDBTestCase):
])[0]
vif.get_network_ref(self.session, self.cluster, self.vif, False)
def test_get_network_ref_bridge_from_opaque(self):
opaque_networks = [{'opaqueNetworkId': 'bridge_id',
'opaqueNetworkName': 'name',
'opaqueNetworkType': 'OpaqueNetwork'}]
network_ref = vif._get_network_ref_from_opaque(opaque_networks,
'integration_bridge', 'bridge_id')
self.assertEqual('bridge_id', network_ref['network-id'])
def test_get_network_ref_multiple_bridges_from_opaque(self):
opaque_networks = [{'opaqueNetworkId': 'bridge_id1',
'opaqueNetworkName': 'name1',
'opaqueNetworkType': 'OpaqueNetwork'},
{'opaqueNetworkId': 'bridge_id2',
'opaqueNetworkName': 'name2',
'opaqueNetworkType': 'OpaqueNetwork'}]
network_ref = vif._get_network_ref_from_opaque(opaque_networks,
'integration_bridge', 'bridge_id2')
self.assertEqual('bridge_id2', network_ref['network-id'])
def test_get_network_ref_integration(self):
opaque_networks = [{'opaqueNetworkId': 'integration_bridge',
'opaqueNetworkName': 'name',
'opaqueNetworkType': 'OpaqueNetwork'}]
network_ref = vif._get_network_ref_from_opaque(opaque_networks,
'integration_bridge', 'bridge_id')
self.assertEqual('integration_bridge', network_ref['network-id'])
def test_get_network_ref_bridge_none(self):
opaque_networks = [{'opaqueNetworkId': 'bridge_id1',
'opaqueNetworkName': 'name1',
'opaqueNetworkType': 'OpaqueNetwork'},
{'opaqueNetworkId': 'bridge_id2',
'opaqueNetworkName': 'name2',
'opaqueNetworkType': 'OpaqueNetwork'}]
network_ref = vif._get_network_ref_from_opaque(opaque_networks,
'integration_bridge', 'bridge_id')
self.assertIsNone(network_ref)
def test_get_network_ref_integration_multiple(self):
opaque_networks = [{'opaqueNetworkId': 'bridge_id1',
'opaqueNetworkName': 'name1',
'opaqueNetworkType': 'OpaqueNetwork'},
{'opaqueNetworkId': 'integration_bridge',
'opaqueNetworkName': 'name2',
'opaqueNetworkType': 'OpaqueNetwork'}]
network_ref = vif._get_network_ref_from_opaque(opaque_networks,
'integration_bridge', 'bridge_id')
self.assertIsNone(network_ref)
def test_get_neutron_network(self):
self.mox.StubOutWithMock(vm_util, 'get_host_ref')
self.mox.StubOutWithMock(self.session, '_call_method')
self.mox.StubOutWithMock(vif, '_get_network_ref_from_opaque')
vm_util.get_host_ref(self.session,
self.cluster).AndReturn('fake-host')
opaque = fake.DataObject()
opaque.HostOpaqueNetworkInfo = ['fake-network-info']
self.session._call_method(vutil, "get_object_property",
'fake-host', 'config.network.opaqueNetwork').AndReturn(opaque)
vif._get_network_ref_from_opaque(opaque.HostOpaqueNetworkInfo,
CONF.vmware.integration_bridge,
self.vif['network']['id']).AndReturn('fake-network-ref')
self.mox.ReplayAll()
network_ref = vif.get_neutron_network(self.session,
self.vif['network']['id'],
self.cluster,
self.vif)
self.assertEqual(network_ref, 'fake-network-ref')
def test_get_neutron_network_opaque_network_not_found(self):
self.mox.StubOutWithMock(vm_util, 'get_host_ref')
self.mox.StubOutWithMock(self.session, '_call_method')
self.mox.StubOutWithMock(vif, '_get_network_ref_from_opaque')
vm_util.get_host_ref(self.session,
self.cluster).AndReturn('fake-host')
opaque = fake.DataObject()
opaque.HostOpaqueNetworkInfo = ['fake-network-info']
self.session._call_method(vutil, "get_object_property",
'fake-host', 'config.network.opaqueNetwork').AndReturn(opaque)
vif._get_network_ref_from_opaque(opaque.HostOpaqueNetworkInfo,
CONF.vmware.integration_bridge,
self.vif['network']['id']).AndReturn(None)
self.mox.ReplayAll()
self.assertRaises(exception.NetworkNotFoundForBridge,
vif.get_neutron_network, self.session,
self.vif['network']['id'], self.cluster, self.vif)
def test_get_neutron_network_bridge_network_not_found(self):
self.mox.StubOutWithMock(vm_util, 'get_host_ref')
self.mox.StubOutWithMock(self.session, '_call_method')
self.mox.StubOutWithMock(network_util, 'get_network_with_the_name')
vm_util.get_host_ref(self.session,
self.cluster).AndReturn('fake-host')
opaque = fake.DataObject()
opaque.HostOpaqueNetworkInfo = ['fake-network-info']
self.session._call_method(vutil, "get_object_property",
'fake-host', 'config.network.opaqueNetwork').AndReturn(None)
network_util.get_network_with_the_name(self.session, 0,
self.cluster).AndReturn(None)
self.mox.ReplayAll()
self.assertRaises(exception.NetworkNotFoundForBridge,
vif.get_neutron_network, self.session,
self.vif['network']['id'], self.cluster, self.vif)
def test_create_port_group_already_exists(self):
def fake_call_method(module, method, *args, **kwargs):
if method == 'AddPortGroup':
@@ -304,20 +195,6 @@ class VMwareVifTestCase(test.NoDBTestCase):
'vswitch_name', vlan_id=0,
cluster=None)
def test_get_neutron_network_invalid_property(self):
def fake_call_method(module, method, *args, **kwargs):
if method == 'get_object_property':
raise vexc.InvalidPropertyException()
with test.nested(
mock.patch.object(vm_util, 'get_host_ref'),
mock.patch.object(self.session, '_call_method',
fake_call_method),
mock.patch.object(network_util, 'get_network_with_the_name')
) as (_get_host, _call_method, _get_name):
vif.get_neutron_network(self.session, 'network_name',
'cluster', self.vif)
def test_get_vif_info_none(self):
vif_info = vif.get_vif_info('fake_session', 'fake_cluster',
'is_neutron', 'fake_model', None)
@@ -339,3 +216,97 @@ class VMwareVifTestCase(test.NoDBTestCase):
'network_ref': 'fake_ref',
'vif_model': 'fake_model'}]
self.assertEqual(expected, vif_info)
@mock.patch.object(vif, '_check_ovs_supported_version')
def test_get_neutron_network_ovs_integration_bridge(self,
mock_check):
self.flags(integration_bridge='fake-bridge-id', group='vmware')
vif_info = network_model.NetworkInfo([
network_model.VIF(type=network_model.VIF_TYPE_OVS,
address='DE:AD:BE:EF:00:00',
network=self._network)]
)[0]
network_ref = vif._get_neutron_network('fake-session',
'fake-cluster',
vif_info)
expected_ref = {'type': 'OpaqueNetwork',
'network-id': 'fake-bridge-id',
'network-type': 'opaque',
'use-external-id': False}
self.assertEqual(expected_ref, network_ref)
mock_check.assert_called_once_with('fake-session')
@mock.patch.object(vif, '_check_ovs_supported_version')
def test_get_neutron_network_ovs(self, mock_check):
vif_info = network_model.NetworkInfo([
network_model.VIF(type=network_model.VIF_TYPE_OVS,
address='DE:AD:BE:EF:00:00',
network=self._network)]
)[0]
network_ref = vif._get_neutron_network('fake-session',
'fake-cluster',
vif_info)
expected_ref = {'type': 'OpaqueNetwork',
'network-id': 0,
'network-type': 'nsx.LogicalSwitch',
'use-external-id': True}
self.assertEqual(expected_ref, network_ref)
mock_check.assert_called_once_with('fake-session')
@mock.patch.object(network_util, 'get_network_with_the_name')
def test_get_neutron_network_dvs(self, mock_network_name):
fake_network_obj = {'type': 'DistributedVirtualPortgroup',
'dvpg': 'fake-key',
'dvsw': 'fake-props'}
mock_network_name.return_value = 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)
mock_network_name.assert_called_once_with('fake-session',
'fa0',
'fake-cluster')
self.assertEqual(fake_network_obj, network_ref)
@mock.patch.object(network_util, 'get_network_with_the_name',
return_value=None)
def test_get_neutron_network_dvs_no_match(self, mock_network_name):
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]
self.assertRaises(exception.NetworkNotFoundForBridge,
vif._get_neutron_network,
'fake-session',
'fake-cluster',
vif_info)
def test_get_neutron_network_invalid_type(self):
vif_info = network_model.NetworkInfo([
network_model.VIF(address='DE:AD:BE:EF:00:00',
network=self._network)]
)[0]
self.assertRaises(exception.InvalidInput,
vif._get_neutron_network,
'fake-session',
'fake-cluster',
vif_info)
@mock.patch.object(vif.LOG, 'warning')
@mock.patch.object(vim_util, 'get_vc_version',
return_value='5.0.0')
def test_check_invalid_ovs_version(self, mock_version, mock_warning):
vif._check_ovs_supported_version('fake_session')
# assert that the min version is in a warning message
expected_arg = {'version': constants.MIN_VC_OVS_VERSION}
version_arg_found = False
for call in mock_warning.call_args_list:
if call[0][1] == expected_arg:
version_arg_found = True
break
self.assertTrue(version_arg_found)
+46 -8
View File
@@ -1012,14 +1012,13 @@ class VMwareVMUtilTestCase(test.NoDBTestCase):
_wait_for_task.assert_called_once_with(
'fake_reconfigure_task')
def test_get_network_attach_config_spec_opaque(self):
vif_info = {'network_name': 'br-int',
'mac_address': '00:00:00:ca:fe:01',
'network_ref': {'type': 'OpaqueNetwork',
'network-id': 'fake-network-id',
'network-type': 'opaque'},
'iface_id': 7,
'vif_model': 'VirtualE1000'}
def _get_network_attach_config_spec_opaque(self, network_ref,
vc6_onwards=False):
vif_info = {'network_name': 'fake-name',
'mac_address': '00:00:00:ca:fe:01',
'network_ref': network_ref,
'iface_id': 7,
'vif_model': 'VirtualE1000'}
fake_factory = fake.FakeFactory()
result = vm_util.get_network_attach_config_spec(
fake_factory, vif_info, 1)
@@ -1038,6 +1037,14 @@ class VMwareVMUtilTestCase(test.NoDBTestCase):
device = fake_factory.create('ns0:VirtualE1000')
device.macAddress = vif_info['mac_address']
if network_ref['use-external-id']:
if vc6_onwards:
device.externalId = vif_info['iface_id']
else:
dp = fake_factory.create('ns0:DynamicProperty')
dp.name = '__externalId__'
dp.val = vif_info['iface_id']
device.dynamicProperty = [dp]
device.addressType = 'manual'
connectable = fake_factory.create('ns0:VirtualDeviceConnectInfo')
connectable.allowGuestControl = True
@@ -1055,6 +1062,37 @@ class VMwareVMUtilTestCase(test.NoDBTestCase):
self.assertEqual(expected, result)
def test_get_network_attach_config_spec_opaque_integration_bridge(self):
network_ref = {'type': 'OpaqueNetwork',
'network-id': 'fake-network-id',
'network-type': 'opaque',
'use-external-id': False}
self._get_network_attach_config_spec_opaque(network_ref)
def test_get_network_attach_config_spec_opaque(self):
network_ref = {'type': 'OpaqueNetwork',
'network-id': 'fake-network-id',
'network-type': 'nsx.LogicalSwitch',
'use-external-id': True}
self._get_network_attach_config_spec_opaque(network_ref)
@mock.patch.object(fake, 'DataObject')
def test_get_network_attach_config_spec_opaque_vc6_onwards(self,
mock_object):
# Add new attribute externalId supported from VC6
class FakeVirtualE1000(fake.DataObject):
def __init__(self):
super(FakeVirtualE1000, self).__init__()
self.externalId = None
mock_object.return_value = FakeVirtualE1000
network_ref = {'type': 'OpaqueNetwork',
'network-id': 'fake-network-id',
'network-type': 'nsx.LogicalSwitch',
'use-external-id': True}
self._get_network_attach_config_spec_opaque(network_ref,
vc6_onwards=True)
def test_get_network_attach_config_spec_dvs(self):
vif_info = {'network_name': 'br100',
'mac_address': '00:00:00:ca:fe:01',
+2
View File
@@ -19,6 +19,8 @@ Shared constants across the VMware driver
from nova.network import model as network_model
MIN_VC_VERSION = '5.1.0'
# The minimum VC version for Neutron 'ovs' port type support
MIN_VC_OVS_VERSION = '5.5.0'
DISK_FORMAT_ISO = 'iso'
DISK_FORMAT_VMDK = 'vmdk'
+44 -54
View File
@@ -17,12 +17,13 @@
from oslo_config import cfg
from oslo_log import log as logging
from oslo_vmware import exceptions as vexc
from oslo_vmware import vim_util as vutil
from oslo_vmware import vim_util
from nova import exception
from nova.i18n import _LW
from nova.i18n import _, _LW
from nova.network import model
from nova import utils
from nova.virt.vmwareapi import constants
from nova.virt.vmwareapi import network_util
from nova.virt.vmwareapi import vm_util
@@ -34,8 +35,11 @@ vmwareapi_vif_opts = [
default='vmnic0',
help='Physical ethernet adapter name for vlan networking'),
cfg.StrOpt('integration_bridge',
default='br-int',
help='Name of Integration Bridge'),
help='This option should be configured only when using the '
'NSX-MH Neutron plugin. This is the name of the '
'integration bridge on the ESXi. This should not be set '
'for any other Neutron plugin. Hence the default value '
'is not set.'),
]
CONF.register_opts(vmwareapi_vif_opts, 'vmware')
@@ -99,63 +103,49 @@ def ensure_vlan_bridge(session, vif, cluster=None, create_vlan=True):
return network_ref
def _is_valid_opaque_network_id(opaque_id, bridge_id, integration_bridge,
num_networks):
return (opaque_id == bridge_id or
(num_networks == 1 and
opaque_id == integration_bridge))
def _check_ovs_supported_version(session):
# The port type 'ovs' is only support by the VC version 5.5 onwards
min_version = utils.convert_version_to_int(
constants.MIN_VC_OVS_VERSION)
vc_version = utils.convert_version_to_int(
vim_util.get_vc_version(session))
if vc_version < min_version:
LOG.warning(_LW('VMware vCenter version less than %(version)s '
'does not support the \'ovs\' port type.'),
{'version': constants.MIN_VC_OVS_VERSION})
def _get_network_ref_from_opaque(opaque_networks, integration_bridge, bridge):
num_networks = len(opaque_networks)
for network in opaque_networks:
if _is_valid_opaque_network_id(network['opaqueNetworkId'], bridge,
integration_bridge, num_networks):
return {'type': 'OpaqueNetwork',
'network-id': network['opaqueNetworkId'],
'network-name': network['opaqueNetworkName'],
'network-type': network['opaqueNetworkType']}
LOG.warning(_LW("No valid network found in %(opaque)s, from %(bridge)s "
"or %(integration_bridge)s"),
{'opaque': opaque_networks, 'bridge': bridge,
'integration_bridge': integration_bridge})
def _get_opaque_network(session, cluster):
host = vm_util.get_host_ref(session, cluster)
try:
opaque = session._call_method(vutil,
"get_object_property",
host,
"config.network.opaqueNetwork")
except vexc.InvalidPropertyException:
opaque = None
return opaque
def get_neutron_network(session, network_name, cluster, vif):
opaque = None
if vif['type'] != model.VIF_TYPE_DVS:
opaque = _get_opaque_network(session, cluster)
if opaque:
bridge = vif['network']['id']
opaque_networks = opaque.HostOpaqueNetworkInfo
network_ref = _get_network_ref_from_opaque(opaque_networks,
CONF.vmware.integration_bridge, bridge)
else:
bridge = network_name
def _get_neutron_network(session, cluster, vif):
if vif['type'] == model.VIF_TYPE_OVS:
_check_ovs_supported_version(session)
# Check if this is the NSX-MH plugin is used
if CONF.vmware.integration_bridge:
net_id = CONF.vmware.integration_bridge
use_external_id = False
network_type = 'opaque'
else:
net_id = vif['network']['id']
use_external_id = True
network_type = 'nsx.LogicalSwitch'
network_ref = {'type': 'OpaqueNetwork',
'network-id': net_id,
'network-type': network_type,
'use-external-id': use_external_id}
elif vif['type'] == model.VIF_TYPE_DVS:
network_id = vif['network']['bridge']
network_ref = network_util.get_network_with_the_name(
session, network_name, cluster)
if not network_ref:
raise exception.NetworkNotFoundForBridge(bridge=bridge)
session, network_id, cluster)
if not network_ref:
raise exception.NetworkNotFoundForBridge(bridge=network_id)
else:
reason = _('vif type %s not supported') % vif['type']
raise exception.InvalidInput(reason=reason)
return network_ref
def get_network_ref(session, cluster, vif, is_neutron):
if is_neutron:
network_name = (vif['network']['bridge'] or
CONF.vmware.integration_bridge)
network_ref = get_neutron_network(session, network_name, cluster, vif)
network_ref = _get_neutron_network(session, cluster, vif)
else:
create_vlan = vif['network'].get_meta('should_create_vlan', False)
network_ref = ensure_vlan_bridge(session, vif, cluster=cluster,
+10
View File
@@ -428,6 +428,16 @@ def _create_vif_spec(client_factory, vif_info):
'ns0:VirtualEthernetCardOpaqueNetworkBackingInfo')
backing.opaqueNetworkId = network_ref['network-id']
backing.opaqueNetworkType = network_ref['network-type']
# Configure externalId
if network_ref['use-external-id']:
# externalId is only supported from vCenter 6.0 onwards
if hasattr(net_device, 'externalId'):
net_device.externalId = vif_info['iface_id']
else:
dp = client_factory.create('ns0:DynamicProperty')
dp.name = "__externalId__"
dp.val = vif_info['iface_id']
net_device.dynamicProperty = [dp]
elif (network_ref and
network_ref['type'] == "DistributedVirtualPortgroup"):
backing = client_factory.create(