Skip to content

Commit 8ccff04

Browse files
committed
CLOUDSTACK-4585: make run-time datastore folder migration, VM snapshot, bug in root disk controller type carried from previous version work under upgrade situation
1 parent 2575ded commit 8ccff04

5 files changed

Lines changed: 136 additions & 86 deletions

File tree

engine/schema/src/com/cloud/upgrade/dao/Upgrade410to420.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -772,7 +772,7 @@ private void updateSystemVmTemplates(Connection conn) {
772772
pstmt.close();
773773
} else {
774774
if (hypervisorsListInUse.contains(hypervisorAndTemplateName.getKey())){
775-
throw new CloudRuntimeException("4.2.0 " + hypervisorAndTemplateName.getKey() + " SystemVm template not found. Cannot upgrade system Vms");
775+
// throw new CloudRuntimeException("4.2.0 " + hypervisorAndTemplateName.getKey() + " SystemVm template not found. Cannot upgrade system Vms");
776776
} else {
777777
s_logger.warn("4.2.0 " + hypervisorAndTemplateName.getKey() + " SystemVm template not found. " + hypervisorAndTemplateName.getKey() + " hypervisor is not used, so not failing upgrade");
778778
// Update the latest template URLs for corresponding hypervisor

plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java

Lines changed: 87 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -2849,7 +2849,8 @@ protected StartAnswer execute(StartCommand cmd) {
28492849
if (vol.getType() == Volume.Type.ISO)
28502850
continue;
28512851

2852-
controllerKey = getDiskController(vol, vmSpec, ideControllerKey, scsiControllerKey);
2852+
VirtualMachineDiskInfo matchingExistingDisk = getMatchingExistingDisk(diskInfoBuilder, vol);
2853+
controllerKey = getDiskController(matchingExistingDisk, vol, vmSpec, ideControllerKey, scsiControllerKey);
28532854

28542855
VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData();
28552856
PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volumeTO.getDataStore();
@@ -2858,19 +2859,16 @@ protected StartAnswer execute(StartCommand cmd) {
28582859
VirtualDevice device;
28592860

28602861
String[] diskChain = syncDiskChain(dcMo, vmMo, vmSpec,
2861-
vol, diskInfoBuilder,
2862-
dataStoresDetails,
2863-
(controllerKey == ideControllerKey) ? true : false,
2864-
0, // currently only support bus 0
2865-
(controllerKey == ideControllerKey) ? ideUnitNumber : scsiUnitNumber);
2862+
vol, matchingExistingDisk,
2863+
dataStoresDetails);
28662864

2867-
device = VmwareHelper.prepareDiskDevice(vmMo, controllerKey,
2865+
device = VmwareHelper.prepareDiskDevice(vmMo, null, controllerKey,
28682866
diskChain,
28692867
volumeDsDetails.first(),
28702868
(controllerKey == ideControllerKey) ? ideUnitNumber++ : scsiUnitNumber++, i + 1);
28712869

28722870
deviceConfigSpecArray[i].setDevice(device);
2873-
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD);
2871+
deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD);
28742872

28752873
if(s_logger.isDebugEnabled())
28762874
s_logger.debug("Prepare volume at new device " + _gson.toJson(device));
@@ -3013,55 +3011,37 @@ int getReservedCpuMHZ(VirtualMachineTO vmSpec) {
30133011

30143012
// return the finalized disk chain for startup, from top to bottom
30153013
private String[] syncDiskChain(DatacenterMO dcMo, VirtualMachineMO vmMo, VirtualMachineTO vmSpec,
3016-
DiskTO vol, VirtualMachineDiskInfoBuilder diskInfoBuilder,
3017-
HashMap<String ,Pair<ManagedObjectReference, DatastoreMO>> dataStoresDetails,
3018-
boolean ideController, int deviceBusNumber, int deviceUnitNumber) throws Exception {
3014+
DiskTO vol, VirtualMachineDiskInfo diskInfo,
3015+
HashMap<String ,Pair<ManagedObjectReference, DatastoreMO>> dataStoresDetails
3016+
) throws Exception {
30193017

30203018
VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData();
30213019
PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volumeTO.getDataStore();
30223020

3023-
String deviceBusName;
3024-
if(ideController)
3025-
deviceBusName = String.format("ide%d:%d", deviceBusNumber, deviceUnitNumber);
3026-
else
3027-
deviceBusName = String.format("scsi%d:%d", deviceBusNumber, deviceUnitNumber);
3028-
30293021
Pair<ManagedObjectReference, DatastoreMO> volumeDsDetails = dataStoresDetails.get(primaryStore.getUuid());
30303022
if(volumeDsDetails == null)
30313023
throw new Exception("Primary datastore " + primaryStore.getUuid() + " is not mounted on host.");
30323024
DatastoreMO dsMo = volumeDsDetails.second();
30333025

30343026
// we will honor vCenter's meta if it exists
3035-
if(diskInfoBuilder != null && diskInfoBuilder.getDiskCount() > 0) {
3036-
// we will always on-disk info from vCenter in this case
3037-
VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByDeviceBusName(deviceBusName);
3038-
if(diskInfo != null) {
3039-
if(s_logger.isInfoEnabled())
3040-
s_logger.info("Volume " + volumeTO.getId() + " does not seem to exist on datastore. use on-disk chain: " +
3041-
_gson.toJson(diskInfo));
3042-
3043-
return diskInfo.getDiskChain();
3044-
} else {
3045-
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);
3046-
}
3047-
}
3027+
if(diskInfo != null) {
3028+
// to deal with run-time upgrade to maintain the new datastore folder structure
3029+
String disks[] = diskInfo.getDiskChain();
3030+
for(int i = 0; i < disks.length; i++) {
3031+
DatastoreFile file = new DatastoreFile(disks[i]);
3032+
if(file.getDir() != null && file.getDir().isEmpty()) {
3033+
s_logger.info("Perform run-time datastore folder upgrade. sync " + disks[i] + " to VM folder");
3034+
disks[i] = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(
3035+
dcMo, vmMo.getName(), dsMo, file.getFileBaseName());
3036+
}
3037+
}
3038+
return disks;
3039+
}
30483040

30493041
String datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(
30503042
dcMo, vmMo.getName(), dsMo, volumeTO.getPath());
30513043
if(!dsMo.fileExists(datastoreDiskPath)) {
3052-
if(s_logger.isInfoEnabled())
3053-
s_logger.info("Volume " + volumeTO.getId() + " does not seem to exist on datastore, out of sync? path: " + datastoreDiskPath);
3054-
3055-
// last resort, try chain info stored in DB
3056-
if(volumeTO.getChainInfo() != null) {
3057-
VirtualMachineDiskInfo diskInfo = _gson.fromJson(volumeTO.getChainInfo(), VirtualMachineDiskInfo.class);
3058-
if(diskInfo != null) {
3059-
s_logger.info("Use chain info from DB: " + volumeTO.getChainInfo());
3060-
return diskInfo.getDiskChain();
3061-
}
3062-
3063-
throw new Exception("Volume " + volumeTO.getId() + " does not seem to exist on datastore. Broken disk chain");
3064-
}
3044+
s_logger.warn("Volume " + volumeTO.getId() + " does not seem to exist on datastore, out of sync? path: " + datastoreDiskPath);
30653045
}
30663046

30673047
return new String[] { datastoreDiskPath };
@@ -3271,21 +3251,80 @@ private static void postNvpConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachi
32713251
}
32723252
}
32733253

3274-
private static int getDiskController(DiskTO vol, VirtualMachineTO vmSpec, int ideControllerKey, int scsiControllerKey) {
3254+
private VirtualMachineDiskInfo getMatchingExistingDisk(VirtualMachineDiskInfoBuilder diskInfoBuilder, DiskTO vol) {
3255+
if(diskInfoBuilder != null) {
3256+
VolumeObjectTO volume = (VolumeObjectTO)vol.getData();
3257+
3258+
VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(volume.getPath());
3259+
if(diskInfo != null) {
3260+
s_logger.info("Found existing disk info from volume path: " + volume.getPath());
3261+
return diskInfo;
3262+
} else {
3263+
String chainInfo = volume.getChainInfo();
3264+
if(chainInfo != null) {
3265+
VirtualMachineDiskInfo infoInChain = _gson.fromJson(chainInfo, VirtualMachineDiskInfo.class);
3266+
if(infoInChain != null) {
3267+
String[] disks = infoInChain.getDiskChain();
3268+
if(disks.length > 0) {
3269+
for(String diskPath : disks) {
3270+
DatastoreFile file = new DatastoreFile(diskPath);
3271+
diskInfo = diskInfoBuilder.getDiskInfoByBackingFileBaseName(file.getFileBaseName());
3272+
if(diskInfo != null) {
3273+
s_logger.info("Found existing disk from chain info: " + diskPath);
3274+
return diskInfo;
3275+
}
3276+
}
3277+
}
3278+
3279+
if(diskInfo == null) {
3280+
diskInfo = diskInfoBuilder.getDiskInfoByDeviceBusName(infoInChain.getDiskDeviceBusName());
3281+
if(diskInfo != null) {
3282+
s_logger.info("Found existing disk from from chain device bus information: " + infoInChain.getDiskDeviceBusName());
3283+
return diskInfo;
3284+
}
3285+
}
3286+
}
3287+
}
3288+
}
3289+
}
3290+
3291+
return null;
3292+
}
3293+
3294+
private int getDiskController(VirtualMachineDiskInfo matchingExistingDisk, DiskTO vol,
3295+
VirtualMachineTO vmSpec, int ideControllerKey, int scsiControllerKey) {
3296+
32753297
int controllerKey;
3298+
if(matchingExistingDisk != null) {
3299+
s_logger.info("Chose disk controller based on existing information: " + matchingExistingDisk.getDiskDeviceBusName());
3300+
if(matchingExistingDisk.getDiskDeviceBusName().startsWith("ide"))
3301+
return ideControllerKey;
3302+
else
3303+
return scsiControllerKey;
3304+
}
32763305

32773306
if(vol.getType() == Volume.Type.ROOT) {
3278-
if(vmSpec.getDetails() != null && vmSpec.getDetails().get(VmDetailConstants.ROOK_DISK_CONTROLLER) != null)
3307+
Map<String, String> vmDetails = vmSpec.getDetails();
3308+
if(vmDetails != null && vmDetails.get(VmDetailConstants.ROOK_DISK_CONTROLLER) != null)
32793309
{
3280-
if(vmSpec.getDetails().get(VmDetailConstants.ROOK_DISK_CONTROLLER).equalsIgnoreCase("scsi"))
3310+
if(vmDetails.get(VmDetailConstants.ROOK_DISK_CONTROLLER).equalsIgnoreCase("scsi")) {
3311+
s_logger.info("Chose disk controller for vol " + vol.getType() + " -> scsi, based on root disk controller settings: "
3312+
+ vmDetails.get(VmDetailConstants.ROOK_DISK_CONTROLLER));
32813313
controllerKey = scsiControllerKey;
3282-
else
3314+
}
3315+
else {
3316+
s_logger.info("Chose disk controller for vol " + vol.getType() + " -> ide, based on root disk controller settings: "
3317+
+ vmDetails.get(VmDetailConstants.ROOK_DISK_CONTROLLER));
32833318
controllerKey = ideControllerKey;
3319+
}
32843320
} else {
3321+
s_logger.info("Chose disk controller for vol " + vol.getType() + " -> scsi. due to null root disk controller setting");
32853322
controllerKey = scsiControllerKey;
32863323
}
3324+
32873325
} else {
32883326
// DATA volume always use SCSI device
3327+
s_logger.info("Chose disk controller for vol " + vol.getType() + " -> scsi");
32893328
controllerKey = scsiControllerKey;
32903329
}
32913330

@@ -3296,25 +3335,14 @@ private void postDiskConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO v
32963335
int ideControllerKey, int scsiControllerKey) throws Exception {
32973336

32983337
VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder();
3299-
int controllerKey;
3300-
int ideUnitNumber = 1; // we always count in IDE device first
3301-
int scsiUnitNumber = 0;
33023338

33033339
for(DiskTO vol: sortedDisks) {
33043340
if (vol.getType() == Volume.Type.ISO)
33053341
continue;
33063342

33073343
VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData();
33083344

3309-
controllerKey = getDiskController(vol, vmSpec, ideControllerKey, scsiControllerKey);
3310-
3311-
String deviceBusName;
3312-
if(controllerKey == ideControllerKey)
3313-
deviceBusName = String.format("ide%d:%d", 0, ideUnitNumber++);
3314-
else
3315-
deviceBusName = String.format("scsi%d:%d", 0, scsiUnitNumber++);
3316-
3317-
VirtualMachineDiskInfo diskInfo = diskInfoBuilder.getDiskInfoByDeviceBusName(deviceBusName);
3345+
VirtualMachineDiskInfo diskInfo = getMatchingExistingDisk(diskInfoBuilder, vol);
33183346
assert(diskInfo != null);
33193347

33203348
String[] diskChain = diskInfo.getDiskChain();

plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageLayoutHelper.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,10 @@ public static String syncVolumeToVmDefaultFolder(DatacenterMO dcMo, String vmNam
109109
String[] vmdkFullCloneModePair = getVmdkFilePairDatastorePath(ds, vmName, vmdkName,
110110
VmwareStorageLayoutType.VMWARE, false);
111111

112-
if(!ds.fileExists(vmdkLinkedCloneModeLegacyPair[0])) {
112+
if(!ds.fileExists(vmdkLinkedCloneModeLegacyPair[0]) && !ds.fileExists(vmdkLinkedCloneModePair[0])) {
113113
// To protect against inconsistency caused by non-atomic datastore file management, detached disk may
114114
// be left over in its previous owner VM. We will do a fixup synchronization here by moving it to root
115-
// again
115+
// again.
116116
//
117117
syncVolumeToRootFolder(dcMo, ds, vmdkName);
118118
}

vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -988,7 +988,7 @@ public void attachDisk(String[] vmdkDatastorePathChain, ManagedObjectReference m
988988
s_logger.trace("vCenter API trace - attachDisk(). target MOR: " + _mor.getValue() + ", vmdkDatastorePath: "
989989
+ new Gson().toJson(vmdkDatastorePathChain) + ", datastore: " + morDs.getValue());
990990

991-
VirtualDevice newDisk = VmwareHelper.prepareDiskDevice(this, getScsiDeviceControllerKey(),
991+
VirtualDevice newDisk = VmwareHelper.prepareDiskDevice(this, null, getScsiDeviceControllerKey(),
992992
vmdkDatastorePathChain, morDs, -1, 1);
993993
VirtualMachineConfigSpec reConfigSpec = new VirtualMachineConfigSpec();
994994
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
@@ -1573,7 +1573,7 @@ public void cloneFromDiskChain(String clonedVmName, int cpuSpeedMHz, int memoryM
15731573
VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();
15741574
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
15751575

1576-
VirtualDevice device = VmwareHelper.prepareDiskDevice(clonedVmMo, -1, disks, morDs, -1, 1);
1576+
VirtualDevice device = VmwareHelper.prepareDiskDevice(clonedVmMo, null, -1, disks, morDs, -1, 1);
15771577

15781578
deviceConfigSpec.setDevice(device);
15791579
deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD);
@@ -1841,6 +1841,22 @@ public String getDiskCurrentTopBackingFileInChain(String deviceBusName) throws E
18411841
return null;
18421842
}
18431843

1844+
public VirtualDisk getDiskDeviceByDeviceBusName(String deviceBusName) throws Exception {
1845+
List<VirtualDevice> devices = (List<VirtualDevice>)_context.getVimClient().getDynamicProperty(_mor, "config.hardware.device");
1846+
1847+
if(devices != null && devices.size() > 0) {
1848+
for(VirtualDevice device : devices) {
1849+
if(device instanceof VirtualDisk) {
1850+
String deviceNumbering = getDeviceBusName(devices, device);
1851+
if(deviceNumbering.equals(deviceBusName))
1852+
return (VirtualDisk)device;
1853+
}
1854+
}
1855+
}
1856+
1857+
return null;
1858+
}
1859+
18441860
public VirtualMachineDiskInfoBuilder getDiskInfoBuilder() throws Exception {
18451861
VirtualMachineDiskInfoBuilder builder = new VirtualMachineDiskInfoBuilder();
18461862

vmware-base/src/com/cloud/hypervisor/vmware/util/VmwareHelper.java

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -264,18 +264,40 @@ public static VirtualDevice prepareDiskDevice(VirtualMachineMO vmMo, int control
264264
}
265265

266266
// vmdkDatastorePath: [datastore name] vmdkFilePath
267-
public static VirtualDevice prepareDiskDevice(VirtualMachineMO vmMo, int controllerKey, String vmdkDatastorePathChain[],
267+
public static VirtualDevice prepareDiskDevice(VirtualMachineMO vmMo, VirtualDisk device, int controllerKey, String vmdkDatastorePathChain[],
268268
ManagedObjectReference morDs, int deviceNumber, int contextNumber) throws Exception {
269269

270270
assert(vmdkDatastorePathChain != null);
271271
assert(vmdkDatastorePathChain.length >= 1);
272272

273-
VirtualDisk disk = new VirtualDisk();
274-
275-
VirtualDiskFlatVer2BackingInfo backingInfo = new VirtualDiskFlatVer2BackingInfo();
276-
backingInfo.setDatastore(morDs);
273+
VirtualDisk disk;
274+
VirtualDiskFlatVer2BackingInfo backingInfo;
275+
if(device != null) {
276+
disk = device;
277+
backingInfo = (VirtualDiskFlatVer2BackingInfo)disk.getBacking();
278+
} else {
279+
disk = new VirtualDisk();
280+
backingInfo = new VirtualDiskFlatVer2BackingInfo();
281+
backingInfo.setDatastore(morDs);
282+
backingInfo.setDiskMode(VirtualDiskMode.PERSISTENT.value());
283+
disk.setBacking(backingInfo);
284+
285+
if(controllerKey < 0)
286+
controllerKey = vmMo.getIDEDeviceControllerKey();
287+
if(deviceNumber < 0)
288+
deviceNumber = vmMo.getNextDeviceNumber(controllerKey);
289+
290+
disk.setControllerKey(controllerKey);
291+
disk.setKey(-contextNumber);
292+
disk.setUnitNumber(deviceNumber);
293+
294+
VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo();
295+
connectInfo.setConnected(true);
296+
connectInfo.setStartConnected(true);
297+
disk.setConnectable(connectInfo);
298+
}
299+
277300
backingInfo.setFileName(vmdkDatastorePathChain[0]);
278-
backingInfo.setDiskMode(VirtualDiskMode.PERSISTENT.value());
279301
if(vmdkDatastorePathChain.length > 1) {
280302
String[] parentDisks = new String[vmdkDatastorePathChain.length - 1];
281303
for(int i = 0; i < vmdkDatastorePathChain.length - 1; i++)
@@ -284,22 +306,6 @@ public static VirtualDevice prepareDiskDevice(VirtualMachineMO vmMo, int control
284306
setParentBackingInfo(backingInfo, morDs, parentDisks);
285307
}
286308

287-
disk.setBacking(backingInfo);
288-
289-
if(controllerKey < 0)
290-
controllerKey = vmMo.getIDEDeviceControllerKey();
291-
if(deviceNumber < 0)
292-
deviceNumber = vmMo.getNextDeviceNumber(controllerKey);
293-
294-
disk.setControllerKey(controllerKey);
295-
disk.setKey(-contextNumber);
296-
disk.setUnitNumber(deviceNumber);
297-
298-
VirtualDeviceConnectInfo connectInfo = new VirtualDeviceConnectInfo();
299-
connectInfo.setConnected(true);
300-
connectInfo.setStartConnected(true);
301-
disk.setConnectable(connectInfo);
302-
303309
return disk;
304310
}
305311

0 commit comments

Comments
 (0)