CLOUDSTACK-4585: make run-time datastore folder migration, VM snapshot, bug in root disk controller type carried from previous version work under upgrade situation

This commit is contained in:
Kelven Yang 2013-09-01 07:14:27 -07:00
parent e81e75c6b0
commit ae231444bc
5 changed files with 135 additions and 85 deletions

View File

@ -727,7 +727,7 @@ public class Upgrade410to420 implements DbUpgrade {
pstmt.close();
} else {
if (hypervisorsListInUse.contains(hypervisorAndTemplateName.getKey())){
throw new CloudRuntimeException("4.2.0 " + hypervisorAndTemplateName.getKey() + " SystemVm template not found. Cannot upgrade system Vms");
// throw new CloudRuntimeException("4.2.0 " + hypervisorAndTemplateName.getKey() + " SystemVm template not found. Cannot upgrade system Vms");
} else {
s_logger.warn("4.2.0 " + hypervisorAndTemplateName.getKey() + " SystemVm template not found. " + hypervisorAndTemplateName.getKey() + " hypervisor is not used, so not failing upgrade");
// Update the latest template URLs for corresponding hypervisor

View File

@ -2807,7 +2807,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
if (vol.getType() == Volume.Type.ISO)
continue;
controllerKey = getDiskController(vol, vmSpec, ideControllerKey, scsiControllerKey);
VirtualMachineDiskInfo matchingExistingDisk = getMatchingExistingDisk(diskInfoBuilder, vol);
controllerKey = getDiskController(matchingExistingDisk, vol, vmSpec, ideControllerKey, scsiControllerKey);
VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData();
PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volumeTO.getDataStore();
@ -2816,19 +2817,16 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
VirtualDevice device;
String[] diskChain = syncDiskChain(dcMo, vmMo, vmSpec,
vol, diskInfoBuilder,
dataStoresDetails,
(controllerKey == ideControllerKey) ? true : false,
0, // currently only support bus 0
(controllerKey == ideControllerKey) ? ideUnitNumber : scsiUnitNumber);
vol, matchingExistingDisk,
dataStoresDetails);
device = VmwareHelper.prepareDiskDevice(vmMo, controllerKey,
device = VmwareHelper.prepareDiskDevice(vmMo, null, controllerKey,
diskChain,
volumeDsDetails.first(),
(controllerKey == ideControllerKey) ? ideUnitNumber++ : scsiUnitNumber++, i + 1);
deviceConfigSpecArray[i].setDevice(device);
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD);
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD);
if(s_logger.isDebugEnabled())
s_logger.debug("Prepare volume at new device " + _gson.toJson(device));
@ -2951,55 +2949,37 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
// return the finalized disk chain for startup, from top to bottom
private String[] syncDiskChain(DatacenterMO dcMo, VirtualMachineMO vmMo, VirtualMachineTO vmSpec,
DiskTO vol, VirtualMachineDiskInfoBuilder diskInfoBuilder,
HashMap<String ,Pair<ManagedObjectReference, DatastoreMO>> dataStoresDetails,
boolean ideController, int deviceBusNumber, int deviceUnitNumber) throws Exception {
DiskTO vol, VirtualMachineDiskInfo diskInfo,
HashMap<String ,Pair<ManagedObjectReference, DatastoreMO>> dataStoresDetails
) throws Exception {
VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData();
PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volumeTO.getDataStore();
String deviceBusName;
if(ideController)
deviceBusName = String.format("ide%d:%d", deviceBusNumber, deviceUnitNumber);
else
deviceBusName = String.format("scsi%d:%d", deviceBusNumber, deviceUnitNumber);
Pair<ManagedObjectReference, DatastoreMO> volumeDsDetails = dataStoresDetails.get(primaryStore.getUuid());
if(volumeDsDetails == null)
throw new Exception("Primary datastore " + primaryStore.getUuid() + " is not mounted on host.");
DatastoreMO dsMo = volumeDsDetails.second();
// we will honor vCenter's meta if it exists
if(diskInfoBuilder != null && diskInfoBuilder.getDiskCount() > 0) {
// we will always on-disk info from vCenter in this case
VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByDeviceBusName(deviceBusName);
if(diskInfo != null) {
if(s_logger.isInfoEnabled())
s_logger.info("Volume " + volumeTO.getId() + " does not seem to exist on datastore. use on-disk chain: " +
_gson.toJson(diskInfo));
return diskInfo.getDiskChain();
} else {
s_logger.warn("Volume " + volumeTO.getId() + " does not seem to exist on datastore. on-disk may be out of sync as well. disk device info: " + deviceBusName);
}
}
if(diskInfo != null) {
// to deal with run-time upgrade to maintain the new datastore folder structure
String disks[] = diskInfo.getDiskChain();
for(int i = 0; i < disks.length; i++) {
DatastoreFile file = new DatastoreFile(disks[i]);
if(file.getDir() != null && file.getDir().isEmpty()) {
s_logger.info("Perform run-time datastore folder upgrade. sync " + disks[i] + " to VM folder");
disks[i] = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(
dcMo, vmMo.getName(), dsMo, file.getFileBaseName());
}
}
return disks;
}
String datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(
dcMo, vmMo.getName(), dsMo, volumeTO.getPath());
if(!dsMo.fileExists(datastoreDiskPath)) {
if(s_logger.isInfoEnabled())
s_logger.info("Volume " + volumeTO.getId() + " does not seem to exist on datastore, out of sync? path: " + datastoreDiskPath);
// last resort, try chain info stored in DB
if(volumeTO.getChainInfo() != null) {
VirtualMachineDiskInfo diskInfo = _gson.fromJson(volumeTO.getChainInfo(), VirtualMachineDiskInfo.class);
if(diskInfo != null) {
s_logger.info("Use chain info from DB: " + volumeTO.getChainInfo());
return diskInfo.getDiskChain();
}
throw new Exception("Volume " + volumeTO.getId() + " does not seem to exist on datastore. Broken disk chain");
}
s_logger.warn("Volume " + volumeTO.getId() + " does not seem to exist on datastore, out of sync? path: " + datastoreDiskPath);
}
return new String[] { datastoreDiskPath };
@ -3209,21 +3189,80 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
}
}
private static int getDiskController(DiskTO vol, VirtualMachineTO vmSpec, int ideControllerKey, int scsiControllerKey) {
private VirtualMachineDiskInfo getMatchingExistingDisk(VirtualMachineDiskInfoBuilder diskInfoBuilder, DiskTO vol) {
if(diskInfoBuilder != null) {
VolumeObjectTO volume = (VolumeObjectTO)vol.getData();
VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(volume.getPath());
if(diskInfo != null) {
s_logger.info("Found existing disk info from volume path: " + volume.getPath());
return diskInfo;
} else {
String chainInfo = volume.getChainInfo();
if(chainInfo != null) {
VirtualMachineDiskInfo infoInChain = _gson.fromJson(chainInfo, VirtualMachineDiskInfo.class);
if(infoInChain != null) {
String[] disks = infoInChain.getDiskChain();
if(disks.length > 0) {
for(String diskPath : disks) {
DatastoreFile file = new DatastoreFile(diskPath);
diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(file.getFileBaseName());
if(diskInfo != null) {
s_logger.info("Found existing disk from chain info: " + diskPath);
return diskInfo;
}
}
}
if(diskInfo == null) {
diskInfo = diskInfoBuilder.getDiskInfoByDeviceBusName(infoInChain.getDiskDeviceBusName());
if(diskInfo != null) {
s_logger.info("Found existing disk from from chain device bus information: " + infoInChain.getDiskDeviceBusName());
return diskInfo;
}
}
}
}
}
}
return null;
}
private int getDiskController(VirtualMachineDiskInfo matchingExistingDisk, DiskTO vol,
VirtualMachineTO vmSpec, int ideControllerKey, int scsiControllerKey) {
int controllerKey;
if(matchingExistingDisk != null) {
s_logger.info("Chose disk controller based on existing information: " + matchingExistingDisk.getDiskDeviceBusName());
if(matchingExistingDisk.getDiskDeviceBusName().startsWith("ide"))
return ideControllerKey;
else
return scsiControllerKey;
}
if(vol.getType() == Volume.Type.ROOT) {
if(vmSpec.getDetails() != null && vmSpec.getDetails().get(VmDetailConstants.ROOK_DISK_CONTROLLER) != null)
Map<String, String> vmDetails = vmSpec.getDetails();
if(vmDetails != null && vmDetails.get(VmDetailConstants.ROOK_DISK_CONTROLLER) != null)
{
if(vmSpec.getDetails().get(VmDetailConstants.ROOK_DISK_CONTROLLER).equalsIgnoreCase("scsi"))
if(vmDetails.get(VmDetailConstants.ROOK_DISK_CONTROLLER).equalsIgnoreCase("scsi")) {
s_logger.info("Chose disk controller for vol " + vol.getType() + " -> scsi, based on root disk controller settings: "
+ vmDetails.get(VmDetailConstants.ROOK_DISK_CONTROLLER));
controllerKey = scsiControllerKey;
else
}
else {
s_logger.info("Chose disk controller for vol " + vol.getType() + " -> ide, based on root disk controller settings: "
+ vmDetails.get(VmDetailConstants.ROOK_DISK_CONTROLLER));
controllerKey = ideControllerKey;
}
} else {
s_logger.info("Chose disk controller for vol " + vol.getType() + " -> scsi. due to null root disk controller setting");
controllerKey = scsiControllerKey;
}
} else {
// DATA volume always use SCSI device
s_logger.info("Chose disk controller for vol " + vol.getType() + " -> scsi");
controllerKey = scsiControllerKey;
}
@ -3234,9 +3273,6 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
int ideControllerKey, int scsiControllerKey) throws Exception {
VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder();
int controllerKey;
int ideUnitNumber = 1; // we always count in IDE device first
int scsiUnitNumber = 0;
for(DiskTO vol: sortedDisks) {
if (vol.getType() == Volume.Type.ISO)
@ -3244,15 +3280,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData();
controllerKey = getDiskController(vol, vmSpec, ideControllerKey, scsiControllerKey);
String deviceBusName;
if(controllerKey == ideControllerKey)
deviceBusName = String.format("ide%d:%d", 0, ideUnitNumber++);
else
deviceBusName = String.format("scsi%d:%d", 0, scsiUnitNumber++);
VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByDeviceBusName(deviceBusName);
VirtualMachineDiskInfo diskInfo = getMatchingExistingDisk(diskInfoBuilder, vol);
assert(diskInfo != null);
String[] diskChain = diskInfo.getDiskChain();

View File

@ -109,10 +109,10 @@ public class VmwareStorageLayoutHelper {
String[] vmdkFullCloneModePair = getVmdkFilePairDatastorePath(ds, vmName, vmdkName,
VmwareStorageLayoutType.VMWARE, false);
if(!ds.fileExists(vmdkLinkedCloneModeLegacyPair[0])) {
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
// again
// again.
//
syncVolumeToRootFolder(dcMo, ds, vmdkName);
}

View File

@ -988,7 +988,7 @@ public class VirtualMachineMO extends BaseMO {
s_logger.trace("vCenter API trace - attachDisk(). target MOR: " + _mor.getValue() + ", vmdkDatastorePath: "
+ new Gson().toJson(vmdkDatastorePathChain) + ", datastore: " + morDs.getValue());
VirtualDevice newDisk = VmwareHelper.prepareDiskDevice(this, getScsiDeviceControllerKey(),
VirtualDevice newDisk = VmwareHelper.prepareDiskDevice(this, null, getScsiDeviceControllerKey(),
vmdkDatastorePathChain, morDs, -1, 1);
VirtualMachineConfigSpec reConfigSpec = new VirtualMachineConfigSpec();
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
@ -1573,7 +1573,7 @@ public class VirtualMachineMO extends BaseMO {
VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
VirtualDevice device = VmwareHelper.prepareDiskDevice(clonedVmMo, -1, disks, morDs, -1, 1);
VirtualDevice device = VmwareHelper.prepareDiskDevice(clonedVmMo, null, -1, disks, morDs, -1, 1);
deviceConfigSpec.setDevice(device);
deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD);
@ -1841,6 +1841,22 @@ public class VirtualMachineMO extends BaseMO {
return null;
}
public VirtualDisk getDiskDeviceByDeviceBusName(String deviceBusName) 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 VirtualDisk) {
String deviceNumbering = getDeviceBusName(devices, device);
if(deviceNumbering.equals(deviceBusName))
return (VirtualDisk)device;
}
}
}
return null;
}
public VirtualMachineDiskInfoBuilder getDiskInfoBuilder() throws Exception {
VirtualMachineDiskInfoBuilder builder = new VirtualMachineDiskInfoBuilder();

View File

@ -264,18 +264,40 @@ public class VmwareHelper {
}
// vmdkDatastorePath: [datastore name] vmdkFilePath
public static VirtualDevice prepareDiskDevice(VirtualMachineMO vmMo, int controllerKey, String vmdkDatastorePathChain[],
public static VirtualDevice prepareDiskDevice(VirtualMachineMO vmMo, VirtualDisk device, int controllerKey, String vmdkDatastorePathChain[],
ManagedObjectReference morDs, int deviceNumber, int contextNumber) throws Exception {
assert(vmdkDatastorePathChain != null);
assert(vmdkDatastorePathChain.length >= 1);
VirtualDisk disk = new VirtualDisk();
VirtualDisk disk;
VirtualDiskFlatVer2BackingInfo backingInfo;
if(device != null) {
disk = device;
backingInfo = (VirtualDiskFlatVer2BackingInfo)disk.getBacking();
} else {
disk = new VirtualDisk();
backingInfo = new VirtualDiskFlatVer2BackingInfo();
backingInfo.setDatastore(morDs);
backingInfo.setDiskMode(VirtualDiskMode.PERSISTENT.value());
disk.setBacking(backingInfo);
if(controllerKey < 0)
controllerKey = vmMo.getIDEDeviceControllerKey();
if(deviceNumber < 0)
deviceNumber = vmMo.getNextDeviceNumber(controllerKey);
VirtualDiskFlatVer2BackingInfo backingInfo = new VirtualDiskFlatVer2BackingInfo();
backingInfo.setDatastore(morDs);
disk.setControllerKey(controllerKey);
disk.setKey(-contextNumber);
disk.setUnitNumber(deviceNumber);
VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo();
connectInfo.setConnected(true);
connectInfo.setStartConnected(true);
disk.setConnectable(connectInfo);
}
backingInfo.setFileName(vmdkDatastorePathChain[0]);
backingInfo.setDiskMode(VirtualDiskMode.PERSISTENT.value());
if(vmdkDatastorePathChain.length > 1) {
String[] parentDisks = new String[vmdkDatastorePathChain.length - 1];
for(int i = 0; i < vmdkDatastorePathChain.length - 1; i++)
@ -284,22 +306,6 @@ public class VmwareHelper {
setParentBackingInfo(backingInfo, morDs, parentDisks);
}
disk.setBacking(backingInfo);
if(controllerKey < 0)
controllerKey = vmMo.getIDEDeviceControllerKey();
if(deviceNumber < 0)
deviceNumber = vmMo.getNextDeviceNumber(controllerKey);
disk.setControllerKey(controllerKey);
disk.setKey(-contextNumber);
disk.setUnitNumber(deviceNumber);
VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo();
connectInfo.setConnected(true);
connectInfo.setStartConnected(true);
disk.setConnectable(connectInfo);
return disk;
}