CLOUDSTACK-10107: For VMware VMs add devices without unit number (#2288)

When VMs are deployed or nics are plugged, using a static unit number
may cause device configuration errors. This fixes a previous limitation
that more than 7 nics/networks could not be added to a VM.

Per the API docs, `unitNumber` need not be set:
https://www.vmware.com/support/developer/converter-sdk/conv55_apireference/vim.vm.device.VirtualDevice.html

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
Rohit Yadav 2017-10-25 09:56:44 +05:30 committed by GitHub
parent 285fd77674
commit bd953d811f
3 changed files with 153 additions and 25 deletions

View File

@ -1085,18 +1085,15 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
ManagedObjectReference dvsMor = dataCenterMo.getDvSwitchMor(networkInfo.first()); ManagedObjectReference dvsMor = dataCenterMo.getDvSwitchMor(networkInfo.first());
dvSwitchUuid = dataCenterMo.getDvSwitchUuid(dvsMor); dvSwitchUuid = dataCenterMo.getDvSwitchUuid(dvsMor);
s_logger.info("Preparing NIC device on dvSwitch : " + dvSwitchUuid); s_logger.info("Preparing NIC device on dvSwitch : " + dvSwitchUuid);
nic = nic = VmwareHelper.prepareDvNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(), dvSwitchUuid,
VmwareHelper.prepareDvNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(), dvSwitchUuid, nicTo.getMac(), deviceNumber, nicTo.getMac(), deviceNumber + 1, true, true);
deviceNumber + 1, true, true);
} else { } else {
s_logger.info("Preparing NIC device on network " + networkInfo.second()); s_logger.info("Preparing NIC device on network " + networkInfo.second());
nic = nic = VmwareHelper.prepareNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(),
VmwareHelper.prepareNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(), nicTo.getMac(), deviceNumber, deviceNumber + 1, true, nicTo.getMac(), deviceNumber + 1, true, true);
true);
} }
VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec(); VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();
//VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1];
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec(); VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
deviceConfigSpec.setDevice(nic); deviceConfigSpec.setDevice(nic);
deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD); deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD);
@ -1754,7 +1751,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
int i = 0; int i = 0;
int ideUnitNumber = 0; int ideUnitNumber = 0;
int scsiUnitNumber = 0; int scsiUnitNumber = 0;
int nicUnitNumber = 0;
int ideControllerKey = vmMo.getIDEDeviceControllerKey(); int ideControllerKey = vmMo.getIDEDeviceControllerKey();
int scsiControllerKey = vmMo.getGenericScsiDeviceControllerKeyNoException(); int scsiControllerKey = vmMo.getGenericScsiDeviceControllerKeyNoException();
int controllerKey; int controllerKey;
@ -2016,21 +2012,21 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
ManagedObjectReference dvsMor = dataCenterMo.getDvSwitchMor(networkInfo.first()); ManagedObjectReference dvsMor = dataCenterMo.getDvSwitchMor(networkInfo.first());
dvSwitchUuid = dataCenterMo.getDvSwitchUuid(dvsMor); dvSwitchUuid = dataCenterMo.getDvSwitchUuid(dvsMor);
s_logger.info("Preparing NIC device on dvSwitch : " + dvSwitchUuid); s_logger.info("Preparing NIC device on dvSwitch : " + dvSwitchUuid);
nic = nic = VmwareHelper.prepareDvNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(), dvSwitchUuid,
VmwareHelper.prepareDvNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(), dvSwitchUuid, nicTo.getMac(), nicUnitNumber++, nicTo.getMac(), i + 1, true, true);
i + 1, true, true);
if (nicTo.getUuid() != null) { if (nicTo.getUuid() != null) {
nicUuidToDvSwitchUuid.put(nicTo.getUuid(), dvSwitchUuid); nicUuidToDvSwitchUuid.put(nicTo.getUuid(), dvSwitchUuid);
} }
} else { } else {
s_logger.info("Preparing NIC device on network " + networkInfo.second()); s_logger.info("Preparing NIC device on network " + networkInfo.second());
nic = nic = VmwareHelper.prepareNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(),
VmwareHelper.prepareNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(), nicTo.getMac(), nicUnitNumber++, i + 1, true, true); nicTo.getMac(), i + 1, true, true);
} }
} }
else{ else{
//if NSX API VERSION >= 4.2, connect to br-int (nsx.network), do not create portgroup else previous behaviour //if NSX API VERSION >= 4.2, connect to br-int (nsx.network), do not create portgroup else previous behaviour
nic = VmwareHelper.prepareNicOpaque(vmMo, nicDeviceType, networkInfo.second(), nicTo.getMac(), nicUnitNumber++, i + 1, true, true); nic = VmwareHelper.prepareNicOpaque(vmMo, nicDeviceType, networkInfo.second(),
nicTo.getMac(), i + 1, true, true);
} }
deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();

View File

@ -32,6 +32,8 @@ import signal
import sys import sys
import logging import logging
import time import time
import threading
import Queue
class TestNic(cloudstackTestCase): class TestNic(cloudstackTestCase):
@ -316,6 +318,141 @@ class TestNic(cloudstackTestCase):
self.assertTrue(found, "Nic not successfully added with specified mac address") self.assertTrue(found, "Nic not successfully added with specified mac address")
@attr(tags = ["devcloud", "advanced", "advancedns", "smoke"], required_hardware="true")
def test_03_nic_multiple_vmware(self):
"""Test to adding multiple nics to a VMware VM and restarting VM
Refer to CLOUDSTACK-10107 for details, in this test we add 8 nics to
a VM and stop, start it to show that VMware VMs are not limited to
having up to 7 nics.
"""
if self.hypervisor.lower() != "vmware":
self.skipTest("Skipping test applicable for VMware")
network_offering = NetworkOffering.create(
self.apiclient,
self.services["nw_off_isolated_persistent"]
)
self.cleanup.insert(0, network_offering)
network_offering.update(self.apiclient, state='Enabled')
offering = dict(self.services["network"])
offering["networkoffering"] = network_offering.id
networks = []
def createNetwork(idx):
offering["name"] = "Test Network%s" % idx
network = Network.create(
self.apiclient,
offering,
self.account.name,
self.account.domainid,
zoneid=self.services["network"]["zoneid"]
)
networks.append(network)
self.cleanup.insert(0, network)
class NetworkMaker(threading.Thread):
def __init__(self, queue=None, createNetwork=None):
threading.Thread.__init__(self)
self.queue = queue
self.createNetwork = createNetwork
def run(self):
while True:
idx = self.queue.get()
if idx is not None:
self.createNetwork(idx)
self.queue.task_done()
# Start multiple networks
tsize = 8
queue = Queue.Queue()
for _ in range(tsize):
worker = NetworkMaker(queue, createNetwork)
worker.setDaemon(True)
worker.start()
for idx in range(tsize):
queue.put(idx)
queue.join()
# Deploy a VM
vm = VirtualMachine.create(
self.apiclient,
self.services["small"],
accountid=self.account.name,
domainid=self.account.domainid,
serviceofferingid=self.service_offering.id,
networkids=[networks[0].id],
mode=self.zone.networktype
)
self.cleanup.insert(0, vm)
# Add nics to networks
for network in networks[1:]:
response = vm.add_nic(self.apiclient, network.id)
found = False
for nic in response.nic:
if nic.networkid == network.id:
found = True
break
self.assertTrue(found, "Nic not successfully added for the specific network")
# Stop VM
vm.stop(self.apiclient, forced=True)
vms = VirtualMachine.list(
self.apiclient,
id=vm.id
)
self.assertEqual(
validateList(vms)[0],
PASS,
"vms list validation failed")
vm_response = vms[0]
self.assertEqual(
vm_response.state,
"Stopped",
"Verify the VM is stopped"
)
# Start VM
vm.start(self.apiclient)
vms = VirtualMachine.list(
self.apiclient,
id=vm.id
)
self.assertEqual(
validateList(vms)[0],
PASS,
"vms list validation failed")
vm_response = vms[0]
self.assertEqual(
vm_response.state,
"Running",
"Verify the VM is running"
)
self.assertTrue(len(vm_response.nic) == len(networks), "Number of nics on VM not 8")
# Validate nics exist on each of the network
for network in networks:
found = False
for nic in vm_response.nic:
if nic.networkid == network.id:
found = True
break
self.assertTrue(found, "Nic not found for the specific network")
def tearDown(self): def tearDown(self):
try: try:
for obj in self.cleanup: for obj in self.cleanup:

View File

@ -89,7 +89,7 @@ public class VmwareHelper {
} }
public static VirtualDevice prepareNicOpaque(VirtualMachineMO vmMo, VirtualEthernetCardType deviceType, String portGroupName, public static VirtualDevice prepareNicOpaque(VirtualMachineMO vmMo, VirtualEthernetCardType deviceType, String portGroupName,
String macAddress, int deviceNumber, int contextNumber, boolean conntected, boolean connectOnStart) throws Exception { String macAddress, int contextNumber, boolean connected, boolean connectOnStart) throws Exception {
assert(vmMo.getRunningHost().hasOpaqueNSXNetwork()); assert(vmMo.getRunningHost().hasOpaqueNSXNetwork());
@ -123,18 +123,17 @@ public class VmwareHelper {
VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo(); VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo();
connectInfo.setAllowGuestControl(true); connectInfo.setAllowGuestControl(true);
connectInfo.setConnected(conntected); connectInfo.setConnected(connected);
connectInfo.setStartConnected(connectOnStart); connectInfo.setStartConnected(connectOnStart);
nic.setAddressType("Manual"); nic.setAddressType("Manual");
nic.setConnectable(connectInfo); nic.setConnectable(connectInfo);
nic.setMacAddress(macAddress); nic.setMacAddress(macAddress);
nic.setUnitNumber(deviceNumber);
nic.setKey(-contextNumber); nic.setKey(-contextNumber);
return nic; return nic;
} }
public static VirtualDevice prepareNicDevice(VirtualMachineMO vmMo, ManagedObjectReference morNetwork, VirtualEthernetCardType deviceType, String portGroupName, public static VirtualDevice prepareNicDevice(VirtualMachineMO vmMo, ManagedObjectReference morNetwork, VirtualEthernetCardType deviceType, String portGroupName,
String macAddress, int deviceNumber, int contextNumber, boolean conntected, boolean connectOnStart) throws Exception { String macAddress, int contextNumber, boolean connected, boolean connectOnStart) throws Exception {
VirtualEthernetCard nic; VirtualEthernetCard nic;
switch (deviceType) { switch (deviceType) {
@ -166,18 +165,17 @@ public class VmwareHelper {
VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo(); VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo();
connectInfo.setAllowGuestControl(true); connectInfo.setAllowGuestControl(true);
connectInfo.setConnected(conntected); connectInfo.setConnected(connected);
connectInfo.setStartConnected(connectOnStart); connectInfo.setStartConnected(connectOnStart);
nic.setAddressType("Manual"); nic.setAddressType("Manual");
nic.setConnectable(connectInfo); nic.setConnectable(connectInfo);
nic.setMacAddress(macAddress); nic.setMacAddress(macAddress);
nic.setUnitNumber(deviceNumber);
nic.setKey(-contextNumber); nic.setKey(-contextNumber);
return nic; return nic;
} }
public static VirtualDevice prepareDvNicDevice(VirtualMachineMO vmMo, ManagedObjectReference morNetwork, VirtualEthernetCardType deviceType, String dvPortGroupName, public static VirtualDevice prepareDvNicDevice(VirtualMachineMO vmMo, ManagedObjectReference morNetwork, VirtualEthernetCardType deviceType, String dvPortGroupName,
String dvSwitchUuid, String macAddress, int deviceNumber, int contextNumber, boolean conntected, boolean connectOnStart) throws Exception { String dvSwitchUuid, String macAddress, int contextNumber, boolean connected, boolean connectOnStart) throws Exception {
VirtualEthernetCard nic; VirtualEthernetCard nic;
switch (deviceType) { switch (deviceType) {
@ -210,16 +208,13 @@ public class VmwareHelper {
dvPortConnection.setPortgroupKey(morNetwork.getValue()); dvPortConnection.setPortgroupKey(morNetwork.getValue());
dvPortBacking.setPort(dvPortConnection); dvPortBacking.setPort(dvPortConnection);
nic.setBacking(dvPortBacking); nic.setBacking(dvPortBacking);
nic.setKey(30);
connectInfo.setAllowGuestControl(true); connectInfo.setAllowGuestControl(true);
connectInfo.setConnected(conntected); connectInfo.setConnected(connected);
connectInfo.setStartConnected(connectOnStart); connectInfo.setStartConnected(connectOnStart);
nic.setAddressType("Manual"); nic.setAddressType("Manual");
nic.setConnectable(connectInfo); nic.setConnectable(connectInfo);
nic.setMacAddress(macAddress); nic.setMacAddress(macAddress);
nic.setUnitNumber(deviceNumber);
nic.setKey(-contextNumber); nic.setKey(-contextNumber);
return nic; return nic;
} }