mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
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:
parent
e81e75c6b0
commit
ae231444bc
@ -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
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user