Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
import java.util.Arrays;
import java.util.List;

import com.vmware.vim25.FileBackedVirtualDiskSpec;
import com.vmware.vim25.ManagedObjectReference;
import com.vmware.vim25.VirtualDiskAdapterType;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.logging.log4j.Logger;
Expand All @@ -30,6 +32,10 @@
import com.cloud.hypervisor.vmware.mo.DatastoreFile;
import com.cloud.hypervisor.vmware.mo.DatastoreMO;
import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
import com.cloud.hypervisor.vmware.mo.VirtualDiskManagerMO;
import com.cloud.hypervisor.vmware.mo.VmdkAdapterType;
import com.cloud.hypervisor.vmware.util.VmwareHelper;
import com.cloud.storage.Storage;

import com.cloud.utils.Pair;

Expand Down Expand Up @@ -168,6 +174,17 @@ public static String syncVolumeToVmDefaultFolder(DatacenterMO dcMo, String vmNam
}

public static String syncVolumeToVmDefaultFolder(DatacenterMO dcMo, String vmName, DatastoreMO ds, String vmdkName, String excludeFolders) throws Exception {
return syncVolumeToVmDefaultFolder(dcMo, vmName, ds, vmdkName, excludeFolders, null);
}

public static String syncVolumeToVmDefaultFolder(DatacenterMO dcMo, String vmName, DatastoreMO ds, String vmdkName, String excludeFolders,
VmdkAdapterType targetAdapterType) throws Exception {
return syncVolumeToVmDefaultFolder(dcMo, vmName, ds, vmdkName, excludeFolders, targetAdapterType, null).first();
}

public static Pair<String, Boolean> syncVolumeToVmDefaultFolder(DatacenterMO dcMo, String vmName, DatastoreMO ds, String vmdkName,
String excludeFolders, VmdkAdapterType targetAdapterType,
Storage.ProvisioningType provisioningType) throws Exception {

assert (ds != null);
if (!ds.folderExists(String.format("[%s]", ds.getName()), vmName)) {
Expand All @@ -182,6 +199,21 @@ public static String syncVolumeToVmDefaultFolder(DatacenterMO dcMo, String vmNam
String[] vmdkLinkedCloneModePair = getVmdkFilePairDatastorePath(ds, vmName, vmdkName, VmwareStorageLayoutType.VMWARE, true);
String[] vmdkFullCloneModePair = getVmdkFilePairDatastorePath(ds, vmName, vmdkName, VmwareStorageLayoutType.VMWARE, false);

String deprecatedLegacyPath = getDeprecatedLegacyDatastorePathFromVmdkFileName(ds, vmdkName + ".vmdk");
if (ds.fileExists(deprecatedLegacyPath)) {
String vmwarePath = vmdkLinkedCloneModePair[0];
LOGGER.info("sync " + deprecatedLegacyPath + "->" + vmwarePath);
VirtualDiskManagerMO diskManager = new VirtualDiskManagerMO(ds.getContext());
if (targetAdapterType == null) {
diskManager.moveVirtualDisk(deprecatedLegacyPath, dcMo.getMor(), vmwarePath, dcMo.getMor(), true);
} else {
FileBackedVirtualDiskSpec diskSpec = createDiskSpec(targetAdapterType, provisioningType);
diskManager.copyVirtualDisk(deprecatedLegacyPath, dcMo.getMor(), vmwarePath, dcMo.getMor(), diskSpec, true);
diskManager.deleteVirtualDisk(deprecatedLegacyPath, dcMo.getMor());
}
return new Pair<>(vmwarePath, targetAdapterType != null);
}

if (!ds.fileExists(vmdkLinkedCloneModeLegacyPair[0]) && !ds.fileExists(vmdkLinkedCloneModePair[0])) {
// To protect against inconsistency caused by non-atomic datastore file management, detached disk may
// be left over in its previous owner VM. We will do a fixup synchronization here by moving it to root
Expand All @@ -190,6 +222,16 @@ public static String syncVolumeToVmDefaultFolder(DatacenterMO dcMo, String vmNam
syncVolumeToRootFolder(dcMo, ds, vmdkName, vmName, excludeFolders);
}

if (targetAdapterType != null && ds.fileExists(vmdkLinkedCloneModeLegacyPair[0])) {
String vmwarePath = vmdkLinkedCloneModePair[0];
LOGGER.info("sync " + vmdkLinkedCloneModeLegacyPair[0] + "->" + vmwarePath);
VirtualDiskManagerMO diskManager = new VirtualDiskManagerMO(ds.getContext());
FileBackedVirtualDiskSpec diskSpec = createDiskSpec(targetAdapterType, provisioningType);
diskManager.copyVirtualDisk(vmdkLinkedCloneModeLegacyPair[0], dcMo.getMor(), vmwarePath, dcMo.getMor(), diskSpec, true);
diskManager.deleteVirtualDisk(vmdkLinkedCloneModeLegacyPair[0], dcMo.getMor());
return new Pair<>(vmwarePath, true);
}

for (int i=1; i<vmdkFullCloneModeLegacyPair.length; i++) {
if (ds.fileExists(vmdkFullCloneModeLegacyPair[i])) {
LOGGER.info("sync " + vmdkFullCloneModeLegacyPair[i] + "->" + vmdkFullCloneModePair[i]);
Expand All @@ -212,7 +254,20 @@ public static String syncVolumeToVmDefaultFolder(DatacenterMO dcMo, String vmNam
}

// Note: we will always return a path
return vmdkLinkedCloneModePair[0];
return new Pair<>(vmdkLinkedCloneModePair[0], false);
}

private static FileBackedVirtualDiskSpec createDiskSpec(VmdkAdapterType targetAdapterType, Storage.ProvisioningType provisioningType) {
FileBackedVirtualDiskSpec diskSpec = new FileBackedVirtualDiskSpec();
if (targetAdapterType == VmdkAdapterType.buslogic) {
diskSpec.setAdapterType(VirtualDiskAdapterType.BUS_LOGIC.value());
} else if (targetAdapterType == VmdkAdapterType.lsilogic) {
diskSpec.setAdapterType(VirtualDiskAdapterType.LSI_LOGIC.value());
} else {
diskSpec.setAdapterType(targetAdapterType.toString());
}
diskSpec.setDiskType(VmwareHelper.getVirtualDiskType(provisioningType).value());
return diskSpec;
}

public static void syncVolumeToRootFolder(DatacenterMO dcMo, DatastoreMO ds, String vmdkName, String vmName) throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@
import com.cloud.hypervisor.vmware.mo.NetworkDetails;
import com.cloud.hypervisor.vmware.mo.VirtualMachineDiskInfoBuilder;
import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
import com.cloud.hypervisor.vmware.mo.VirtualStorageObjectManagerMO;
import com.cloud.hypervisor.vmware.mo.VmdkAdapterType;
import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
import com.cloud.hypervisor.vmware.resource.VmwareResource;
import com.cloud.hypervisor.vmware.util.VmwareContext;
Expand All @@ -107,7 +107,6 @@
import com.cloud.vm.VirtualMachine.PowerState;
import com.cloud.vm.VmDetailConstants;
import com.google.gson.Gson;
import com.vmware.vim25.BaseConfigInfoDiskFileBackingInfo;
import com.vmware.vim25.DatastoreHostMount;
import com.vmware.vim25.HostHostBusAdapter;
import com.vmware.vim25.HostInternetScsiHba;
Expand All @@ -126,7 +125,6 @@
import com.vmware.vim25.HostUnresolvedVmfsVolume;
import com.vmware.vim25.InvalidStateFaultMsg;
import com.vmware.vim25.ManagedObjectReference;
import com.vmware.vim25.VStorageObject;
import com.vmware.vim25.VirtualDeviceBackingInfo;
import com.vmware.vim25.VirtualDeviceConfigSpec;
import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
Expand Down Expand Up @@ -2057,7 +2055,24 @@ private Answer attachVolume(Command cmd, DiskTO disk, boolean isAttach, boolean
String datastoreVolumePath;
boolean datastoreChangeObserved = false;
boolean volumePathChangeObserved = false;
boolean updateVmdkAdapter = true;
String chainInfo = null;
String diskController = null;

if (isAttach) {
String rootDiskControllerDetail = DiskControllerType.ide.toString();
if (controllerInfo != null && StringUtils.isNotEmpty(controllerInfo.get(VmDetailConstants.ROOT_DISK_CONTROLLER))) {
rootDiskControllerDetail = controllerInfo.get(VmDetailConstants.ROOT_DISK_CONTROLLER);
}
String dataDiskControllerDetail = getLegacyVmDataDiskController();
if (controllerInfo != null && StringUtils.isNotEmpty(controllerInfo.get(VmDetailConstants.DATA_DISK_CONTROLLER))) {
dataDiskControllerDetail = controllerInfo.get(VmDetailConstants.DATA_DISK_CONTROLLER);
}

VmwareHelper.validateDiskControllerDetails(rootDiskControllerDetail, dataDiskControllerDetail);
Pair<String, String> chosenDiskControllers = VmwareHelper.chooseRequiredDiskControllers(new Pair<>(rootDiskControllerDetail, dataDiskControllerDetail), vmMo, null, null);
diskController = VmwareHelper.getControllerBasedOnDiskType(chosenDiskControllers, disk);
}

if (isAttach) {
if (isManaged) {
Expand All @@ -2066,7 +2081,11 @@ private Answer attachVolume(Command cmd, DiskTO disk, boolean isAttach, boolean
if (dsMo.getDatastoreType().equalsIgnoreCase("VVOL")) {
datastoreVolumePath = VmwareStorageLayoutHelper.getDatastoreVolumePath(dsMo, vmName, volumePath);
} else {
datastoreVolumePath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), vmName, dsMo, volumePath, VmwareManager.s_vmwareSearchExcludeFolder.value());
VmdkAdapterType targetAdapterType = VmdkAdapterType.getAdapterType(DiskControllerType.getType(diskController));
Pair<String, Boolean> syncResult = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), vmName, dsMo,
volumePath, VmwareManager.s_vmwareSearchExcludeFolder.value(), targetAdapterType, volumeTO.getProvisioningType());
datastoreVolumePath = syncResult.first();
updateVmdkAdapter = !syncResult.second();
Comment on lines +2084 to +2088
}
}
} else {
Expand Down Expand Up @@ -2102,20 +2121,8 @@ private Answer attachVolume(Command cmd, DiskTO disk, boolean isAttach, boolean
AttachAnswer answer = new AttachAnswer(disk);

if (isAttach) {
String rootDiskControllerDetail = DiskControllerType.ide.toString();
if (controllerInfo != null && StringUtils.isNotEmpty(controllerInfo.get(VmDetailConstants.ROOT_DISK_CONTROLLER))) {
rootDiskControllerDetail = controllerInfo.get(VmDetailConstants.ROOT_DISK_CONTROLLER);
}
String dataDiskControllerDetail = getLegacyVmDataDiskController();
if (controllerInfo != null && StringUtils.isNotEmpty(controllerInfo.get(VmDetailConstants.DATA_DISK_CONTROLLER))) {
dataDiskControllerDetail = controllerInfo.get(VmDetailConstants.DATA_DISK_CONTROLLER);
}

VmwareHelper.validateDiskControllerDetails(rootDiskControllerDetail, dataDiskControllerDetail);
Pair<String, String> chosenDiskControllers = VmwareHelper.chooseRequiredDiskControllers(new Pair<>(rootDiskControllerDetail, dataDiskControllerDetail), vmMo, null, null);
String diskController = VmwareHelper.getControllerBasedOnDiskType(chosenDiskControllers, disk);

vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs, diskController, storagePolicyId, volumeTO.getIopsReadRate() + volumeTO.getIopsWriteRate());
vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs, diskController, storagePolicyId,
volumeTO.getIopsReadRate() + volumeTO.getIopsWriteRate(), updateVmdkAdapter);
VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder();
VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(volumePath, dsMo.getName());
chainInfo = _gson.toJson(diskInfo);
Expand Down Expand Up @@ -2416,49 +2423,42 @@ public Answer createVolume(CreateObjectCommand cmd) {
VirtualMachineMO vmMo = null;
String volumeUuid = UUID.randomUUID().toString().replace("-", "");

String volumeDatastorePath = VmwareStorageLayoutHelper.getDatastorePathBaseFolderFromVmdkFileName(dsMo, volumeUuid + ".vmdk");
VolumeObjectTO newVol = new VolumeObjectTO();

String volumeDatastorePath = VmwareStorageLayoutHelper.getDeprecatedLegacyDatastorePathFromVmdkFileName(dsMo, volumeUuid + ".vmdk");
String dummyVmName = hostService.getWorkerName(context, cmd, 0, dsMo);
try {
VirtualStorageObjectManagerMO vStorageObjectManagerMO = new VirtualStorageObjectManagerMO(context);
VStorageObject virtualDisk = vStorageObjectManagerMO.createDisk(morDatastore, volume.getProvisioningType(), volume.getSize(), volumeDatastorePath, volumeUuid);
DatastoreFile file = new DatastoreFile(((BaseConfigInfoDiskFileBackingInfo)virtualDisk.getConfig().getBacking()).getFilePath());
newVol.setPath(file.getFileBaseName());
newVol.setSize(volume.getSize());
} catch (Exception e) {
logger.error(String.format("Create disk using vStorageObject manager failed due to [%s], retrying using worker VM.", e.getMessage()), e);
String dummyVmName = hostService.getWorkerName(context, cmd, 0, dsMo);
try {
logger.info(String.format("Creating worker VM [%s].", dummyVmName));
vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, dummyVmName, null);
if (vmMo == null) {
throw new CloudRuntimeException("Unable to create a dummy VM for volume creation.");
}
logger.info(String.format("Creating worker VM [%s].", dummyVmName));
vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, dummyVmName, null);
if (vmMo == null) {
throw new CloudRuntimeException("Unable to create a dummy VM for volume creation.");
}

synchronized (this) {
try {
vmMo.createDisk(volumeDatastorePath, (int)(volume.getSize() / (1024L * 1024L)), morDatastore, vmMo.getScsiDeviceControllerKey(), vSphereStoragePolicyId);
vmMo.detachDisk(volumeDatastorePath, false);
}
catch (Exception e1) {
logger.error(String.format("Deleting file [%s] due to [%s].", volumeDatastorePath, e1.getMessage()), e1);
VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, volumeUuid, dcMo, VmwareManager.s_vmwareSearchExcludeFolder.value());
throw new CloudRuntimeException(String.format("Unable to create volume due to [%s].", e1.getMessage()));
}
synchronized (this) {
try {
vmMo.createDisk(volumeDatastorePath, volume.getProvisioningType(), (int)(volume.getSize() / (1024L * 1024L)), morDatastore,
vmMo.getScsiDeviceControllerKey(), vSphereStoragePolicyId);
vmMo.detachDisk(volumeDatastorePath, false);
}
catch (Exception e) {
logger.error(String.format("Deleting file [%s] due to [%s].", volumeDatastorePath, e.getMessage()), e);
VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, volumeUuid, dcMo, VmwareManager.s_vmwareSearchExcludeFolder.value());
throw new CloudRuntimeException(String.format("Unable to create volume due to [%s].", e.getMessage()));
}
}

newVol = new VolumeObjectTO();
newVol.setPath(volumeUuid);
newVol.setSize(volume.getSize());
return new CreateObjectAnswer(newVol);
} finally {
logger.info("Destroying dummy VM after volume creation.");
if (vmMo != null) {
VolumeObjectTO newVol = new VolumeObjectTO();
newVol.setPath(volumeUuid);
newVol.setSize(volume.getSize());
return new CreateObjectAnswer(newVol);
} finally {
logger.info("Destroying dummy VM after volume creation.");
if (vmMo != null) {
try {
vmMo.detachAllDisksAndDestroy();
} catch (Exception e) {
logger.warn(String.format("Failed to destroy worker VM [%s] after volume creation due to: [%s].", dummyVmName, e.getMessage()), e);
}
}
}
return new CreateObjectAnswer(newVol);
} catch (Throwable e) {
return new CreateObjectAnswer(hostService.createLogMessageException(e, cmd));
}
Expand Down
Loading
Loading