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());
dvSwitchUuid = dataCenterMo.getDvSwitchUuid(dvsMor);
s_logger.info("Preparing NIC device on dvSwitch : " + dvSwitchUuid);
nic =
VmwareHelper.prepareDvNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(), dvSwitchUuid, nicTo.getMac(), deviceNumber,
deviceNumber + 1, true, true);
nic = VmwareHelper.prepareDvNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(), dvSwitchUuid,
nicTo.getMac(), deviceNumber + 1, true, true);
} else {
s_logger.info("Preparing NIC device on network " + networkInfo.second());
nic =
VmwareHelper.prepareNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(), nicTo.getMac(), deviceNumber, deviceNumber + 1, true,
true);
nic = VmwareHelper.prepareNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(),
nicTo.getMac(), deviceNumber + 1, true, true);
}
VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();
//VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1];
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
deviceConfigSpec.setDevice(nic);
deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD);
@ -1754,7 +1751,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
int i = 0;
int ideUnitNumber = 0;
int scsiUnitNumber = 0;
int nicUnitNumber = 0;
int ideControllerKey = vmMo.getIDEDeviceControllerKey();
int scsiControllerKey = vmMo.getGenericScsiDeviceControllerKeyNoException();
int controllerKey;
@ -2016,21 +2012,21 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
ManagedObjectReference dvsMor = dataCenterMo.getDvSwitchMor(networkInfo.first());
dvSwitchUuid = dataCenterMo.getDvSwitchUuid(dvsMor);
s_logger.info("Preparing NIC device on dvSwitch : " + dvSwitchUuid);
nic =
VmwareHelper.prepareDvNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(), dvSwitchUuid, nicTo.getMac(), nicUnitNumber++,
i + 1, true, true);
nic = VmwareHelper.prepareDvNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(), dvSwitchUuid,
nicTo.getMac(), i + 1, true, true);
if (nicTo.getUuid() != null) {
nicUuidToDvSwitchUuid.put(nicTo.getUuid(), dvSwitchUuid);
}
} else {
s_logger.info("Preparing NIC device on network " + networkInfo.second());
nic =
VmwareHelper.prepareNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(), nicTo.getMac(), nicUnitNumber++, i + 1, true, true);
nic = VmwareHelper.prepareNicDevice(vmMo, networkInfo.first(), nicDeviceType, networkInfo.second(),
nicTo.getMac(), i + 1, true, true);
}
}
else{
//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();

View File

@ -32,6 +32,8 @@ import signal
import sys
import logging
import time
import threading
import Queue
class TestNic(cloudstackTestCase):
@ -316,6 +318,141 @@ class TestNic(cloudstackTestCase):
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):
try:
for obj in self.cleanup:

View File

@ -89,7 +89,7 @@ public class VmwareHelper {
}
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());
@ -123,18 +123,17 @@ public class VmwareHelper {
VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo();
connectInfo.setAllowGuestControl(true);
connectInfo.setConnected(conntected);
connectInfo.setConnected(connected);
connectInfo.setStartConnected(connectOnStart);
nic.setAddressType("Manual");
nic.setConnectable(connectInfo);
nic.setMacAddress(macAddress);
nic.setUnitNumber(deviceNumber);
nic.setKey(-contextNumber);
return nic;
}
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;
switch (deviceType) {
@ -166,18 +165,17 @@ public class VmwareHelper {
VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo();
connectInfo.setAllowGuestControl(true);
connectInfo.setConnected(conntected);
connectInfo.setConnected(connected);
connectInfo.setStartConnected(connectOnStart);
nic.setAddressType("Manual");
nic.setConnectable(connectInfo);
nic.setMacAddress(macAddress);
nic.setUnitNumber(deviceNumber);
nic.setKey(-contextNumber);
return nic;
}
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;
switch (deviceType) {
@ -210,16 +208,13 @@ public class VmwareHelper {
dvPortConnection.setPortgroupKey(morNetwork.getValue());
dvPortBacking.setPort(dvPortConnection);
nic.setBacking(dvPortBacking);
nic.setKey(30);
connectInfo.setAllowGuestControl(true);
connectInfo.setConnected(conntected);
connectInfo.setConnected(connected);
connectInfo.setStartConnected(connectOnStart);
nic.setAddressType("Manual");
nic.setConnectable(connectInfo);
nic.setMacAddress(macAddress);
nic.setUnitNumber(deviceNumber);
nic.setKey(-contextNumber);
return nic;
}