From bd953d811f35e26d91455c7531756037ce8bd494 Mon Sep 17 00:00:00 2001 From: Rohit Yadav Date: Wed, 25 Oct 2017 09:56:44 +0530 Subject: [PATCH] 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 --- .../vmware/resource/VmwareResource.java | 24 ++- test/integration/smoke/test_nic.py | 137 ++++++++++++++++++ .../hypervisor/vmware/util/VmwareHelper.java | 17 +-- 3 files changed, 153 insertions(+), 25 deletions(-) diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java index ccb5d0f7abbd..17064ff0d1e7 100644 --- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -1085,18 +1085,15 @@ private PlugNicAnswer execute(PlugNicCommand cmd) { 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 @@ protected StartAnswer execute(StartCommand cmd) { 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 @@ protected StartAnswer execute(StartCommand cmd) { 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(); diff --git a/test/integration/smoke/test_nic.py b/test/integration/smoke/test_nic.py index 9dc385c5432e..c7f8468d7f20 100644 --- a/test/integration/smoke/test_nic.py +++ b/test/integration/smoke/test_nic.py @@ -32,6 +32,8 @@ import sys import logging import time +import threading +import Queue class TestNic(cloudstackTestCase): @@ -316,6 +318,141 @@ def test_02_nic_with_mac(self): 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: diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java index 65dfe7bd7137..dddab4de5ad4 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java @@ -89,7 +89,7 @@ public static boolean isReservedScsiDeviceNumber(int deviceNumber) { } 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 static VirtualDevice prepareNicOpaque(VirtualMachineMO vmMo, VirtualEther 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 static VirtualDevice prepareNicDevice(VirtualMachineMO vmMo, ManagedObjec 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 static VirtualDevice prepareDvNicDevice(VirtualMachineMO vmMo, ManagedObj 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; }