Repository: cloudstack Updated Branches: refs/heads/vmware-disk-controllers 06d4458d0 -> a4cc987a6
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a4cc987a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java ---------------------------------------------------------------------- diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java index 5f180e1..35878d6 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java @@ -55,12 +55,15 @@ import com.vmware.vim25.OptionValue; import com.vmware.vim25.OvfCreateDescriptorParams; import com.vmware.vim25.OvfCreateDescriptorResult; import com.vmware.vim25.OvfFile; +import com.vmware.vim25.ParaVirtualSCSIController; import com.vmware.vim25.PropertyFilterSpec; import com.vmware.vim25.PropertySpec; import com.vmware.vim25.TraversalSpec; +import com.vmware.vim25.VirtualBusLogicController; import com.vmware.vim25.VirtualCdrom; import com.vmware.vim25.VirtualCdromIsoBackingInfo; import com.vmware.vim25.VirtualCdromRemotePassthroughBackingInfo; +import com.vmware.vim25.VirtualController; import com.vmware.vim25.VirtualDevice; import com.vmware.vim25.VirtualDeviceBackingInfo; import com.vmware.vim25.VirtualDeviceConfigSpec; @@ -80,6 +83,7 @@ import com.vmware.vim25.VirtualEthernetCardDistributedVirtualPortBackingInfo; import com.vmware.vim25.VirtualHardwareOption; import com.vmware.vim25.VirtualIDEController; import com.vmware.vim25.VirtualLsiLogicController; +import com.vmware.vim25.VirtualLsiLogicSASController; import com.vmware.vim25.VirtualMachineCloneSpec; import com.vmware.vim25.VirtualMachineConfigInfo; import com.vmware.vim25.VirtualMachineConfigOption; @@ -97,7 +101,6 @@ import com.vmware.vim25.VirtualMachineRelocateSpecDiskLocator; import com.vmware.vim25.VirtualMachineRuntimeInfo; import com.vmware.vim25.VirtualMachineSnapshotInfo; import com.vmware.vim25.VirtualMachineSnapshotTree; -import com.vmware.vim25.VirtualPCIController; import com.vmware.vim25.VirtualSCSIController; import com.vmware.vim25.VirtualSCSISharing; @@ -1083,6 +1086,130 @@ public class VirtualMachineMO extends BaseMO { s_logger.trace("vCenter API trace - createDisk() done(successfully)"); } + public void updateVmdkAdapter(String vmdkFileName, String newAdapterType) throws Exception { + Pair<VmdkFileDescriptor, byte[]> vmdkInfo = getVmdkFileInfo(vmdkFileName); + VmdkFileDescriptor vmdkFileDescriptor = vmdkInfo.first(); + boolean isVmfsSparseFile = vmdkFileDescriptor.isVmfsSparseFile(); + if (!isVmfsSparseFile) { + String currentAdapterType = vmdkFileDescriptor.getAdapterType(); + if (!currentAdapterType.equalsIgnoreCase(newAdapterType)) { + s_logger.info("Updating adapter type to " + newAdapterType + " for VMDK file " + vmdkFileName); + Pair<DatacenterMO, String> dcInfo = getOwnerDatacenter(); + byte[] newVmdkContent = vmdkFileDescriptor.changeVmdkAdapterType(vmdkInfo.second(), newAdapterType); + String vmdkUploadUrl = getContext().composeDatastoreBrowseUrl(dcInfo.first().getName(), vmdkFileName); + getContext().uploadResourceContent(vmdkUploadUrl, newVmdkContent); + s_logger.info("Updated VMDK file " + vmdkFileName); + } + } + } + + public void updateAdapterTypeIfRequired(String vmdkFileName) throws Exception { + // Validate existing adapter type of VMDK file. Update it with a supported adapter type if validation fails. + Pair<VmdkFileDescriptor, byte[]> vmdkInfo = getVmdkFileInfo(vmdkFileName); + VmdkFileDescriptor vmdkFileDescriptor = vmdkInfo.first(); + + boolean isVmfsSparseFile = vmdkFileDescriptor.isVmfsSparseFile(); + if (!isVmfsSparseFile) { + String currentAdapterTypeStr = vmdkFileDescriptor.getAdapterType(); + if (s_logger.isTraceEnabled()) { + s_logger.trace("Detected adapter type " + currentAdapterTypeStr + " for VMDK file " + vmdkFileName); + } + VmdkAdapterType currentAdapterType = VmdkAdapterType.getType(currentAdapterTypeStr); + if (currentAdapterType == VmdkAdapterType.none) { + // Value of currentAdapterType can be VmdkAdapterType.none only if adapter type of vmdk is set to either + // lsisas1068 (SAS controller) or pvscsi (Vmware Paravirtual) only. Valid adapter type for those controllers is lsilogic. + // Hence use adapter type lsilogic. Other adapter types ide, lsilogic, buslogic are valid and does not need to be modified. + VmdkAdapterType newAdapterType = VmdkAdapterType.lsilogic; + s_logger.debug("Updating adapter type to " + newAdapterType + " from " + currentAdapterTypeStr + " for VMDK file " + vmdkFileName); + Pair<DatacenterMO, String> dcInfo = getOwnerDatacenter(); + byte[] newVmdkContent = vmdkFileDescriptor.changeVmdkAdapterType(vmdkInfo.second(), newAdapterType.toString()); + String vmdkUploadUrl = getContext().composeDatastoreBrowseUrl(dcInfo.first().getName(), vmdkFileName); + + getContext().uploadResourceContent(vmdkUploadUrl, newVmdkContent); + s_logger.debug("Updated VMDK file " + vmdkFileName); + } + } + } + + public void attachDisk(String[] vmdkDatastorePathChain, ManagedObjectReference morDs, String diskController) throws Exception { + + if(s_logger.isTraceEnabled()) + s_logger.trace("vCenter API trace - attachDisk(). target MOR: " + _mor.getValue() + ", vmdkDatastorePath: " + + new Gson().toJson(vmdkDatastorePathChain) + ", datastore: " + morDs.getValue()); + int controllerKey = 0; + int unitNumber = 0; + + if (DiskControllerType.getType(diskController) == DiskControllerType.ide) { + // IDE virtual disk cannot be added if VM is running + if (getPowerState() == VirtualMachinePowerState.POWERED_ON) { + throw new Exception("Adding a virtual disk over IDE controller is not supported while VM is running in VMware hypervisor. Please re-try when VM is not running."); + } + // Get next available unit number and controller key + int ideDeviceCount = getNumberOfIDEDevices(); + if (ideDeviceCount >= VmwareHelper.MAX_IDE_CONTROLLER_COUNT * VmwareHelper.MAX_ALLOWED_DEVICES_IDE_CONTROLLER) { + throw new Exception("Maximum limit of devices supported on IDE controllers [" + VmwareHelper.MAX_IDE_CONTROLLER_COUNT + * VmwareHelper.MAX_ALLOWED_DEVICES_IDE_CONTROLLER + "] is reached."); + } + controllerKey = getIDEControllerKey(ideDeviceCount); + unitNumber = getFreeUnitNumberOnIDEController(controllerKey); + } else { + controllerKey = getScsiDiskControllerKey(diskController); + unitNumber = -1; + } + synchronized (_mor.getValue().intern()) { + VirtualDevice newDisk = VmwareHelper.prepareDiskDevice(this, null, controllerKey, vmdkDatastorePathChain, morDs, unitNumber, 1); + controllerKey = newDisk.getControllerKey(); + unitNumber = newDisk.getUnitNumber(); + VirtualDiskFlatVer2BackingInfo backingInfo = (VirtualDiskFlatVer2BackingInfo)newDisk.getBacking(); + String vmdkFileName = backingInfo.getFileName(); + DiskControllerType diskControllerType = DiskControllerType.getType(diskController); + VmdkAdapterType vmdkAdapterType = VmdkAdapterType.getAdapterType(diskControllerType); + if (vmdkAdapterType == VmdkAdapterType.none) { + String message = "Failed to attach disk due to invalid vmdk adapter type for vmdk file [" + + vmdkFileName + "] with controller : " + diskControllerType; + s_logger.debug(message); + throw new Exception(message); + } + updateVmdkAdapter(vmdkFileName, vmdkAdapterType.toString()); + VirtualMachineConfigSpec reConfigSpec = new VirtualMachineConfigSpec(); + VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec(); + + deviceConfigSpec.setDevice(newDisk); + deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD); + + reConfigSpec.getDeviceChange().add(deviceConfigSpec); + + ManagedObjectReference morTask = _context.getService().reconfigVMTask(_mor, reConfigSpec); + boolean result = _context.getVimClient().waitForTask(morTask); + + if (!result) { + if (s_logger.isTraceEnabled()) + s_logger.trace("vCenter API trace - attachDisk() done(failed)"); + throw new Exception("Failed to attach disk due to " + TaskMO.getTaskFailureInfo(_context, morTask)); + } + + _context.waitForTaskProgressDone(morTask); + } + + if(s_logger.isTraceEnabled()) + s_logger.trace("vCenter API trace - attachDisk() done(successfully)"); + } + + private int getControllerBusNumber(int controllerKey) throws Exception { + List<VirtualDevice> devices = (List<VirtualDevice>)_context.getVimClient(). + getDynamicProperty(_mor, "config.hardware.device"); + + if (devices != null && devices.size() > 0) { + for (VirtualDevice device : devices) { + if (device instanceof VirtualController && device.getKey() == controllerKey) { + return ((VirtualController)device).getBusNumber(); + } + } + } + throw new Exception("SCSI Controller with key " + controllerKey + " is Not Found"); + + } + public void attachDisk(String[] vmdkDatastorePathChain, ManagedObjectReference morDs) throws Exception { if (s_logger.isTraceEnabled()) @@ -1753,11 +1880,16 @@ public class VirtualMachineMO extends BaseMO { public GuestOsDescriptor getGuestOsDescriptor(String guestOsId) throws Exception { GuestOsDescriptor guestOsDescriptor = null; - ManagedObjectReference vmEnvironmentBrowser = _context.getVimClient().getMoRefProp(_mor, "environmentBrowser"); + String guestId = guestOsId; + if (guestId == null) { + guestId = getGuestId(); + } + ManagedObjectReference vmEnvironmentBrowser = + _context.getVimClient().getMoRefProp(_mor, "environmentBrowser"); VirtualMachineConfigOption vmConfigOption = _context.getService().queryConfigOption(vmEnvironmentBrowser, null, null); List<GuestOsDescriptor> guestDescriptors = vmConfigOption.getGuestOSDescriptor(); for (GuestOsDescriptor descriptor : guestDescriptors) { - if (guestOsId != null && guestOsId.equalsIgnoreCase(descriptor.getId())) { + if (guestId != null && guestId.equalsIgnoreCase(descriptor.getId())) { guestOsDescriptor = descriptor; break; } @@ -1896,6 +2028,134 @@ public class VirtualMachineMO extends BaseMO { } } + public int getPvScsiDeviceControllerKeyNoException() throws Exception { + List<VirtualDevice> devices = (List<VirtualDevice>)_context.getVimClient(). + getDynamicProperty(_mor, "config.hardware.device"); + + if (devices != null && devices.size() > 0) { + for (VirtualDevice device : devices) { + if (device instanceof ParaVirtualSCSIController) { + return device.getKey(); + } + } + } + + return -1; + } + + public int getPvScsiDeviceControllerKey() throws Exception { + List<VirtualDevice> devices = (List<VirtualDevice>)_context.getVimClient(). + getDynamicProperty(_mor, "config.hardware.device"); + + if (devices != null && devices.size() > 0) { + for (VirtualDevice device : devices) { + if (device instanceof ParaVirtualSCSIController) { + return device.getKey(); + } + } + } + + assert (false); + throw new Exception("VMware Paravirtual SCSI Controller Not Found"); + } + + public void ensurePvScsiDeviceController(int requiredNumScsiControllers, int availableBusNum) throws Exception { + VirtualMachineConfigSpec vmConfig = new VirtualMachineConfigSpec(); + + int busNum = availableBusNum; + while (busNum < requiredNumScsiControllers) { + ParaVirtualSCSIController scsiController = new ParaVirtualSCSIController(); + + scsiController.setSharedBus(VirtualSCSISharing.NO_SHARING); + scsiController.setBusNumber(busNum); + scsiController.setKey(busNum - VmwareHelper.MAX_SCSI_CONTROLLER_COUNT); + VirtualDeviceConfigSpec scsiControllerSpec = new VirtualDeviceConfigSpec(); + scsiControllerSpec.setDevice(scsiController); + scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD); + + vmConfig.getDeviceChange().add(scsiControllerSpec); + busNum++; + } + + if (configureVm(vmConfig)) { + throw new Exception("Unable to add Scsi controllers to the VM " + getName()); + } else { + s_logger.info("Successfully added " + requiredNumScsiControllers + " SCSI controllers."); + } + } + + public String getRecommendedDiskController(String guestOsId) throws Exception { + String recommendedController; + GuestOsDescriptor guestOsDescriptor = getGuestOsDescriptor(guestOsId); + recommendedController = VmwareHelper.getRecommendedDiskControllerFromDescriptor(guestOsDescriptor); + return recommendedController; + } + + public boolean isPvScsiSupported() throws Exception { + int virtualHardwareVersion; + + virtualHardwareVersion = getVirtualHardwareVersion(); + + // Check if virtual machine is using hardware version 7 or later. + if (virtualHardwareVersion < 7) { + s_logger.error("The virtual hardware version of the VM is " + virtualHardwareVersion + + ", which doesn't support PV SCSI controller type for virtual harddisks. Please upgrade this VM's virtual hardware version to 7 or later."); + return false; + } + return true; + } + + // Would be useful if there exists multiple sub types of SCSI controllers per VM are supported in CloudStack f + public int getScsiDiskControllerKey(String diskController) throws Exception { + List<VirtualDevice> devices = (List<VirtualDevice>)_context.getVimClient(). + getDynamicProperty(_mor, "config.hardware.device"); + + if (devices != null && devices.size() > 0) { + for (VirtualDevice device : devices) { + if ((DiskControllerType.getType(diskController) == DiskControllerType.lsilogic || DiskControllerType.getType(diskController) == DiskControllerType.scsi) + && device instanceof VirtualLsiLogicController) { + return ((VirtualLsiLogicController)device).getKey(); + } else if ((DiskControllerType.getType(diskController) == DiskControllerType.lsisas1068 || DiskControllerType.getType(diskController) == DiskControllerType.scsi) + && device instanceof VirtualLsiLogicSASController) { + return ((VirtualLsiLogicSASController)device).getKey(); + } else if ((DiskControllerType.getType(diskController) == DiskControllerType.pvscsi || DiskControllerType.getType(diskController) == DiskControllerType.scsi) + && device instanceof ParaVirtualSCSIController) { + return ((ParaVirtualSCSIController)device).getKey(); + } else if ((DiskControllerType.getType(diskController) == DiskControllerType.buslogic || DiskControllerType.getType(diskController) == DiskControllerType.scsi) + && device instanceof VirtualBusLogicController) { + return ((VirtualBusLogicController)device).getKey(); + } + } + } + + assert (false); + throw new Exception(diskController + " Controller Not Found"); + } + + public int getScsiDiskControllerKeyNoException(String diskController) throws Exception { + List<VirtualDevice> devices = (List<VirtualDevice>)_context.getVimClient(). + getDynamicProperty(_mor, "config.hardware.device"); + + if (devices != null && devices.size() > 0) { + for (VirtualDevice device : devices) { + if ((DiskControllerType.getType(diskController) == DiskControllerType.lsilogic || DiskControllerType.getType(diskController) == DiskControllerType.scsi) + && device instanceof VirtualLsiLogicController) { + return ((VirtualLsiLogicController)device).getKey(); + } else if ((DiskControllerType.getType(diskController) == DiskControllerType.lsisas1068 || DiskControllerType.getType(diskController) == DiskControllerType.scsi) + && device instanceof VirtualLsiLogicSASController) { + return ((VirtualLsiLogicSASController)device).getKey(); + } else if ((DiskControllerType.getType(diskController) == DiskControllerType.pvscsi || DiskControllerType.getType(diskController) == DiskControllerType.scsi) + && device instanceof ParaVirtualSCSIController) { + return ((ParaVirtualSCSIController)device).getKey(); + } else if ((DiskControllerType.getType(diskController) == DiskControllerType.buslogic || DiskControllerType.getType(diskController) == DiskControllerType.scsi) + && device instanceof VirtualBusLogicController) { + return ((VirtualBusLogicController)device).getKey(); + } + } + } + return -1; + } + public int getNextScsiDiskDeviceNumber() throws Exception { int scsiControllerKey = getScsiDeviceControllerKey(); int deviceNumber = getNextDeviceNumber(scsiControllerKey); @@ -1908,7 +2168,7 @@ public class VirtualMachineMO extends BaseMO { if (devices != null && devices.size() > 0) { for (VirtualDevice device : devices) { - if (device instanceof VirtualLsiLogicController) { + if (device instanceof VirtualSCSIController) { return device.getKey(); } } @@ -1918,12 +2178,27 @@ public class VirtualMachineMO extends BaseMO { throw new Exception("SCSI Controller Not Found"); } - public int getScsiDeviceControllerKeyNoException() throws Exception { + public int getGenericScsiDeviceControllerKeyNoException() throws Exception { List<VirtualDevice> devices = _context.getVimClient().getDynamicProperty(_mor, "config.hardware.device"); if (devices != null && devices.size() > 0) { for (VirtualDevice device : devices) { - if (device instanceof VirtualLsiLogicController) { + if (device instanceof VirtualSCSIController) { + return device.getKey(); + } + } + } + + return -1; + } + + public int getScsiDeviceControllerKeyNoException() throws Exception { + List<VirtualDevice> devices = (List<VirtualDevice>)_context.getVimClient(). + getDynamicProperty(_mor, "config.hardware.device"); + + if(devices != null && devices.size() > 0) { + for(VirtualDevice device : devices) { + if(device instanceof VirtualLsiLogicController) { return device.getKey(); } } @@ -1953,6 +2228,32 @@ public class VirtualMachineMO extends BaseMO { } } + public void ensureScsiDeviceControllers(int count, int availableBusNum) throws Exception { + int scsiControllerKey = getScsiDeviceControllerKeyNoException(); + if (scsiControllerKey < 0) { + VirtualMachineConfigSpec vmConfig = new VirtualMachineConfigSpec(); + + int busNum = availableBusNum; + while (busNum < count) { + VirtualLsiLogicController scsiController = new VirtualLsiLogicController(); + scsiController.setSharedBus(VirtualSCSISharing.NO_SHARING); + scsiController.setBusNumber(busNum); + scsiController.setKey(busNum - VmwareHelper.MAX_SCSI_CONTROLLER_COUNT); + VirtualDeviceConfigSpec scsiControllerSpec = new VirtualDeviceConfigSpec(); + scsiControllerSpec.setDevice(scsiController); + scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD); + + vmConfig.getDeviceChange().add(scsiControllerSpec); + busNum++; + } + if (configureVm(vmConfig)) { + throw new Exception("Unable to add Scsi controllers to the VM " + getName()); + } else { + s_logger.info("Successfully added " + count + " SCSI controllers."); + } + } + } + // return pair of VirtualDisk and disk device bus name(ide0:0, etc) public Pair<VirtualDisk, String> getDiskDevice(String vmdkDatastorePath, boolean matchExactly) throws Exception { List<VirtualDevice> devices = _context.getVimClient().getDynamicProperty(_mor, "config.hardware.device"); @@ -2305,43 +2606,84 @@ public class VirtualMachineMO extends BaseMO { throw new Exception("IDE Controller Not Found"); } - public int getNextIDEDeviceNumber() throws Exception { - int controllerKey = getIDEDeviceControllerKey(); - return getNextDeviceNumber(controllerKey); + public int getIDEControllerKey(int ideUnitNumber) throws Exception { + List<VirtualDevice> devices = (List<VirtualDevice>)_context.getVimClient(). + getDynamicProperty(_mor, "config.hardware.device"); + + int requiredIdeController = ideUnitNumber / VmwareHelper.MAX_IDE_CONTROLLER_COUNT; + + int ideControllerCount = 0; + if(devices != null && devices.size() > 0) { + for(VirtualDevice device : devices) { + if(device instanceof VirtualIDEController) { + if (ideControllerCount == requiredIdeController) { + return ((VirtualIDEController)device).getKey(); + } + ideControllerCount++; + } + } + } + + assert(false); + throw new Exception("IDE Controller Not Found"); } - public VirtualDevice getIsoDevice() throws Exception { - List<VirtualDevice> devices = _context.getVimClient().getDynamicProperty(_mor, "config.hardware.device"); + public int getNumberOfIDEDevices() throws Exception { + int ideDeviceCount = 0; + List<VirtualDevice> devices = (List<VirtualDevice>)_context.getVimClient(). + getDynamicProperty(_mor, "config.hardware.device"); + if (devices != null && devices.size() > 0) { for (VirtualDevice device : devices) { - if (device instanceof VirtualCdrom) { - return device; + if (device instanceof VirtualIDEController) { + ideDeviceCount += ((VirtualIDEController)device).getDevice().size(); } } } - return null; + return ideDeviceCount; } - public int getPCIDeviceControllerKey() throws Exception { - List<VirtualDevice> devices = _context.getVimClient().getDynamicProperty(_mor, "config.hardware.device"); + public int getFreeUnitNumberOnIDEController(int controllerKey) throws Exception { + int freeUnitNumber = 0; + List<VirtualDevice> devices = (List<VirtualDevice>)_context.getVimClient(). + getDynamicProperty(_mor, "config.hardware.device"); + int deviceCount = 0; + int ideDeviceUnitNumber = -1; if (devices != null && devices.size() > 0) { for (VirtualDevice device : devices) { - if (device instanceof VirtualPCIController) { - return ((VirtualPCIController)device).getKey(); + if (device instanceof VirtualDisk && (controllerKey == device.getControllerKey())) { + deviceCount++; + ideDeviceUnitNumber = device.getUnitNumber(); } } } - - assert (false); - throw new Exception("PCI Controller Not Found"); + if (deviceCount == 1) { + if (ideDeviceUnitNumber == 0) { + freeUnitNumber = 1; + } // else freeUnitNumber is already initialized to 0 + } else if (deviceCount == 2) { + throw new Exception("IDE controller with key [" + controllerKey + "] already has 2 device attached. Cannot attach more than the limit of 2."); + } + return freeUnitNumber; } - - public int getNextPCIDeviceNumber() throws Exception { - int controllerKey = getPCIDeviceControllerKey(); + public int getNextIDEDeviceNumber() throws Exception { + int controllerKey = getIDEDeviceControllerKey(); return getNextDeviceNumber(controllerKey); } + public VirtualDevice getIsoDevice() throws Exception { + List<VirtualDevice> devices = _context.getVimClient().getDynamicProperty(_mor, "config.hardware.device"); + if (devices != null && devices.size() > 0) { + for (VirtualDevice device : devices) { + if (device instanceof VirtualCdrom) { + return device; + } + } + } + return null; + } + public int getNextDeviceNumber(int controllerKey) throws Exception { List<VirtualDevice> devices = _context.getVimClient().getDynamicProperty(_mor, "config.hardware.device"); @@ -2596,6 +2938,9 @@ public class VirtualMachineMO extends BaseMO { public long getHotAddMemoryLimitInMb() throws Exception { return (Long)_context.getVimClient().getDynamicProperty(_mor, "config.hotPlugMemoryLimit"); } + public String getGuestId() throws Exception { + return (String)_context.getVimClient().getDynamicProperty(_mor, "config.guestId"); + } public int getCoresPerSocket() throws Exception { // number of cores per socket is 1 in case of ESXi. It's not defined explicitly and the property is support since vSphere API 5.0. @@ -2672,6 +3017,135 @@ public class VirtualMachineMO extends BaseMO { } return guestOsSupportsMemoryHotAdd && virtualHardwareSupportsMemoryHotAdd; } + public void ensureLsiLogicSasDeviceControllers(int count, int availableBusNum) throws Exception { + int scsiControllerKey = getLsiLogicSasDeviceControllerKeyNoException(); + if (scsiControllerKey < 0) { + VirtualMachineConfigSpec vmConfig = new VirtualMachineConfigSpec(); + + int busNum = availableBusNum; + while (busNum < count) { + VirtualLsiLogicSASController scsiController = new VirtualLsiLogicSASController(); + scsiController.setSharedBus(VirtualSCSISharing.NO_SHARING); + scsiController.setBusNumber(busNum); + scsiController.setKey(busNum - VmwareHelper.MAX_SCSI_CONTROLLER_COUNT); + VirtualDeviceConfigSpec scsiControllerSpec = new VirtualDeviceConfigSpec(); + scsiControllerSpec.setDevice(scsiController); + scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD); + + vmConfig.getDeviceChange().add(scsiControllerSpec); + busNum++; + } + if (configureVm(vmConfig)) { + throw new Exception("Unable to add Scsi controller of type LsiLogic SAS."); + } + } + + } + + private int getLsiLogicSasDeviceControllerKeyNoException() throws Exception { + List<VirtualDevice> devices = (List<VirtualDevice>)_context.getVimClient(). + getDynamicProperty(_mor, "config.hardware.device"); + + if (devices != null && devices.size() > 0) { + for (VirtualDevice device : devices) { + if (device instanceof VirtualLsiLogicSASController) { + return device.getKey(); + } + } + } + + return -1; + } + + public void ensureBusLogicDeviceControllers(int count, int availableBusNum) throws Exception { + int scsiControllerKey = getBusLogicDeviceControllerKeyNoException(); + if (scsiControllerKey < 0) { + VirtualMachineConfigSpec vmConfig = new VirtualMachineConfigSpec(); + + int busNum = availableBusNum; + while (busNum < count) { + VirtualBusLogicController scsiController = new VirtualBusLogicController(); + + scsiController.setSharedBus(VirtualSCSISharing.NO_SHARING); + scsiController.setBusNumber(busNum); + scsiController.setKey(busNum - VmwareHelper.MAX_SCSI_CONTROLLER_COUNT); + VirtualDeviceConfigSpec scsiControllerSpec = new VirtualDeviceConfigSpec(); + scsiControllerSpec.setDevice(scsiController); + scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD); + + vmConfig.getDeviceChange().add(scsiControllerSpec); + busNum++; + } + + if (configureVm(vmConfig)) { + throw new Exception("Unable to add Scsi BusLogic controllers to the VM " + getName()); + } else { + s_logger.info("Successfully added " + count + " SCSI BusLogic controllers."); + } + } + } + + private int getBusLogicDeviceControllerKeyNoException() throws Exception { + List<VirtualDevice> devices = (List<VirtualDevice>)_context.getVimClient(). + getDynamicProperty(_mor, "config.hardware.device"); + + if (devices != null && devices.size() > 0) { + for (VirtualDevice device : devices) { + if (device instanceof VirtualBusLogicController) { + return device.getKey(); + } + } + } + + return -1; + } + + public Ternary<Integer, Integer, DiskControllerType> getScsiControllerInfo() throws Exception { + List<VirtualDevice> devices = (List<VirtualDevice>)_context.getVimClient(). + getDynamicProperty(_mor, "config.hardware.device"); + + int scsiControllerCount = 0; + int busNum = -1; + DiskControllerType controllerType = DiskControllerType.lsilogic; + if (devices != null && devices.size() > 0) { + for (VirtualDevice device : devices) { + if (device instanceof VirtualSCSIController) { + scsiControllerCount++; + int deviceBus = ((VirtualSCSIController)device).getBusNumber(); + if (busNum < deviceBus) { + busNum = deviceBus; + } + if (device instanceof VirtualLsiLogicController) { + controllerType = DiskControllerType.lsilogic; + } else if (device instanceof VirtualLsiLogicSASController) { + controllerType = DiskControllerType.lsisas1068; + } else if (device instanceof VirtualBusLogicController) { + controllerType = DiskControllerType.buslogic; + } else if (device instanceof ParaVirtualSCSIController) { + controllerType = DiskControllerType.pvscsi; + } + } + } + } + + return new Ternary<Integer, Integer, DiskControllerType>(scsiControllerCount, busNum, controllerType); + } + + public int getNumberOfVirtualDisks() throws Exception { + List<VirtualDevice> devices = (List<VirtualDevice>)_context.getVimClient().getDynamicProperty(_mor, "config.hardware.device"); + + s_logger.info("Counting disk devices attached to VM " + getVmName()); + int count = 0; + + if (devices != null && devices.size() > 0) { + for (VirtualDevice device : devices) { + if (device instanceof VirtualDisk) { + count++; + } + } + } + return count; + } public boolean consolidateVmDisks() throws Exception { ManagedObjectReference morTask = _context.getService().consolidateVMDisksTask(_mor); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a4cc987a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VmdkAdapterType.java ---------------------------------------------------------------------- diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VmdkAdapterType.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VmdkAdapterType.java new file mode 100644 index 0000000..f602c46 --- /dev/null +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VmdkAdapterType.java @@ -0,0 +1,48 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package com.cloud.hypervisor.vmware.mo; + +public enum VmdkAdapterType { + ide, + lsilogic, + buslogic, + none; + + public static VmdkAdapterType getAdapterType(DiskControllerType diskControllerType) { + if (diskControllerType == DiskControllerType.ide) { + return VmdkAdapterType.ide; + } else if (diskControllerType == DiskControllerType.buslogic) { + return VmdkAdapterType.buslogic; + } else if (diskControllerType == DiskControllerType.lsilogic || diskControllerType == DiskControllerType.pvscsi || diskControllerType == DiskControllerType.lsisas1068) { + return VmdkAdapterType.lsilogic; + } else { + return VmdkAdapterType.none; + } + } + + public static VmdkAdapterType getType(String vmdkAdapterType) { + if (vmdkAdapterType.equalsIgnoreCase("ide")) { + return VmdkAdapterType.ide; + } else if (vmdkAdapterType.equalsIgnoreCase("lsilogic")) { + return VmdkAdapterType.lsilogic; + } else if (vmdkAdapterType.equalsIgnoreCase("buslogic")) { + return VmdkAdapterType.buslogic; + } else { + return VmdkAdapterType.none; + } + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a4cc987a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VmdkFileDescriptor.java ---------------------------------------------------------------------- diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VmdkFileDescriptor.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VmdkFileDescriptor.java index 8aecfdd..932c251 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VmdkFileDescriptor.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VmdkFileDescriptor.java @@ -29,6 +29,9 @@ import org.apache.log4j.Logger; public class VmdkFileDescriptor { private static final Logger s_logger = Logger.getLogger(VmdkFileDescriptor.class); + private static final String VMDK_PROPERTY_CREATE_TYPE = "createType"; + private static final String VMDK_CREATE_TYPE_VMFSSPARSE = "vmfsSparse"; + private static final String VMDK_PROPERTY_ADAPTER_TYPE = "ddb.adapterType"; private Properties _properties = new Properties(); private String _baseFileName; @@ -84,6 +87,73 @@ public class VmdkFileDescriptor { return _properties.getProperty("parentFileNameHint"); } + public boolean isVmfsSparseFile() { + String vmdkCreateType = _properties.getProperty(VMDK_PROPERTY_CREATE_TYPE); + if (vmdkCreateType.equalsIgnoreCase(VMDK_CREATE_TYPE_VMFSSPARSE)) { + return true; + } + return false; + } + + public String getAdapterType() { + return _properties.getProperty(VMDK_PROPERTY_ADAPTER_TYPE); + } + + + public static byte[] changeVmdkAdapterType(byte[] vmdkContent, String newAdapterType) throws IOException { + assert (vmdkContent != null); + + BufferedReader in = null; + BufferedWriter out = null; + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + try { + in = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(vmdkContent))); + out = new BufferedWriter(new OutputStreamWriter(bos)); + String line; + while ((line = in.readLine()) != null) { + // ignore empty and comment lines + line = line.trim(); + if (line.isEmpty()) { + out.newLine(); + continue; + } + if (line.charAt(0) == '#') { + out.write(line); + out.newLine(); + continue; + } + + String[] tokens = line.split("="); + if (tokens.length == 2) { + String name = tokens[0].trim(); + String value = tokens[1].trim(); + if (value.charAt(0) == '\"') + value = value.substring(1, value.length() - 1); + + if (newAdapterType != null && name.equals(VMDK_PROPERTY_ADAPTER_TYPE)) { + out.write(name + "=\"" + newAdapterType + "\""); + out.newLine(); + } else { + out.write(line); + out.newLine(); + } + } else { + out.write(line); + out.newLine(); + } + } + } finally { + if (in != null) + in.close(); + if (out != null) + out.close(); + } + + return bos.toByteArray(); + + } + public static byte[] changeVmdkContentBaseInfo(byte[] vmdkContent, String baseFileName, String parentFileName) throws IOException { assert (vmdkContent != null); http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a4cc987a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java ---------------------------------------------------------------------- diff --git a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java index 9727e17..fdfc254 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java @@ -23,6 +23,7 @@ import com.vmware.vim25.ObjectContent; import com.vmware.vim25.VirtualMachineConfigSpec; import com.cloud.hypervisor.vmware.util.VmwareContext; +import com.cloud.utils.Pair; /** * Interface to consolidate ESX(i) hosts and HA/FT clusters into a common interface used by CloudStack Hypervisor resources @@ -53,7 +54,8 @@ public interface VmwareHypervisorHost { boolean createVm(VirtualMachineConfigSpec vmSpec) throws Exception; boolean createBlankVm(String vmName, String vmInternalCSName, int cpuCount, int cpuSpeedMHz, int cpuReservedMHz, boolean limitCpuUse, int memoryMB, - int memoryReserveMB, String guestOsIdentifier, ManagedObjectReference morDs, boolean snapshotDirToParent) throws Exception; + int memoryReserveMB, String guestOsIdentifier, ManagedObjectReference morDs, boolean snapshotDirToParent, + Pair<String, String> controllerInfo, Boolean systemVm) throws Exception; void importVmFromOVF(String ovfFilePath, String vmName, DatastoreMO dsMo, String diskOption) throws Exception; @@ -81,4 +83,5 @@ public interface VmwareHypervisorHost { ComputeResourceSummary getHyperHostHardwareSummary() throws Exception; LicenseAssignmentManagerMO getLicenseAssignmentManager() throws Exception; + String getRecommendedDiskController(String guestOsId) throws Exception; } http://git-wip-us.apache.org/repos/asf/cloudstack/blob/a4cc987a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java ---------------------------------------------------------------------- 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 b2b1090..8379813 100644 --- a/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java +++ b/vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java @@ -34,6 +34,7 @@ import org.apache.log4j.Logger; import com.vmware.vim25.DistributedVirtualSwitchPortConnection; import com.vmware.vim25.DynamicProperty; +import com.vmware.vim25.GuestOsDescriptor; import com.vmware.vim25.ManagedObjectReference; import com.vmware.vim25.MethodFault; import com.vmware.vim25.ObjectContent; @@ -62,6 +63,7 @@ import com.vmware.vim25.VirtualPCNet32; import com.vmware.vim25.VirtualVmxnet2; import com.vmware.vim25.VirtualVmxnet3; +import com.cloud.hypervisor.vmware.mo.DiskControllerType; import com.cloud.hypervisor.vmware.mo.HostMO; import com.cloud.hypervisor.vmware.mo.LicenseAssignmentManagerMO; import com.cloud.hypervisor.vmware.mo.VirtualEthernetCardType; @@ -75,6 +77,11 @@ public class VmwareHelper { @SuppressWarnings("unused") private static final Logger s_logger = Logger.getLogger(VmwareHelper.class); + public static final int MAX_SCSI_CONTROLLER_COUNT = 4; + public static final int MAX_IDE_CONTROLLER_COUNT = 2; + public static final int MAX_ALLOWED_DEVICES_IDE_CONTROLLER = 2; + public static final int MAX_ALLOWED_DEVICES_SCSI_CONTROLLER = 15; + public static boolean isReservedScsiDeviceNumber(int deviceNumber) { return deviceNumber == 7; } @@ -705,6 +712,19 @@ public class VmwareHelper { return UUID.randomUUID().toString().replaceAll("-", ""); } + public static String getRecommendedDiskControllerFromDescriptor(GuestOsDescriptor guestOsDescriptor) throws Exception { + String recommendedController; + + recommendedController = guestOsDescriptor.getRecommendedDiskController(); + + // By-pass auto detected PVSCSI controller to use LsiLogic Parallel instead + if (DiskControllerType.getType(recommendedController) == DiskControllerType.pvscsi) { + recommendedController = DiskControllerType.lsilogic.toString(); + } + + return recommendedController; + } + public static String trimSnapshotDeltaPostfix(String name) { String[] tokens = name.split("-"); if (tokens.length > 1 && tokens[tokens.length - 1].matches("[0-9]{6,}")) { @@ -716,4 +736,8 @@ public class VmwareHelper { return name; } + public static boolean isControllerOsRecommended(String dataDiskController) { + return DiskControllerType.getType(dataDiskController) == DiskControllerType.osdefault; + } + }