You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ed...@apache.org on 2013/08/27 01:32:53 UTC
[17/50] [abbrv] git commit: updated refs/heads/4.2 to a23322b
CLOUDSTACK-3237: acknowledge the behind-back VMDK disk consolidation happend in vCenter after storage live migration
Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/834fdc88
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/834fdc88
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/834fdc88
Branch: refs/heads/4.2
Commit: 834fdc8859a92989a818fac2f24af97c87d5ed55
Parents: d9016635
Author: Kelven Yang <ke...@gmail.com>
Authored: Fri Aug 23 17:38:17 2013 -0700
Committer: Kelven Yang <ke...@gmail.com>
Committed: Fri Aug 23 17:38:34 2013 -0700
----------------------------------------------------------------------
.../storage/snapshot/SnapshotObject.java | 14 ++++
.../manager/VmwareStorageManagerImpl.java | 3 +-
.../resource/VmwareStorageProcessor.java | 84 +++++++++++++++++---
.../hypervisor/vmware/mo/VirtualMachineMO.java | 29 ++++++-
4 files changed, 115 insertions(+), 15 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/834fdc88/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
index 3d67d38..e69881c 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
@@ -38,6 +38,7 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.storage.DataStoreRole;
import com.cloud.storage.Snapshot;
import com.cloud.storage.SnapshotVO;
+import com.cloud.storage.VolumeVO;
import com.cloud.storage.dao.SnapshotDao;
import com.cloud.storage.dao.VolumeDao;
import com.cloud.utils.component.ComponentContext;
@@ -262,6 +263,19 @@ public class SnapshotObject implements SnapshotInfo {
snapshotStore.setParentSnapshotId(0L);
}
this.snapshotStoreDao.update(snapshotStore.getId(), snapshotStore);
+
+ // update side-effect of snapshot operation
+ if(snapshotTO.getVolume().getPath() != null) {
+ VolumeVO vol = this.volumeDao.findByUuid(snapshotTO.getVolume().getUuid());
+ if(vol != null) {
+ s_logger.info("Update volume path change due to snapshot operation, volume " + vol.getId() + " path: "
+ + vol.getPath() + "->" + snapshotTO.getVolume().getPath());
+ vol.setPath(snapshotTO.getVolume().getPath());
+ this.volumeDao.update(vol.getId(), vol);
+ } else {
+ s_logger.error("Cound't find the original volume with uuid: " + snapshotTO.getVolume().getUuid());
+ }
+ }
} else {
throw new CloudRuntimeException("Unknown answer: " + answer.getClass());
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/834fdc88/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
index e7fbb04..955b111 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
@@ -292,6 +292,7 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
}
@Override
+ @Deprecated
public Answer execute(VmwareHostService hostService, BackupSnapshotCommand cmd) {
Long accountId = cmd.getAccountId();
Long volumeId = cmd.getVolumeId();
@@ -362,7 +363,7 @@ public class VmwareStorageManagerImpl implements VmwareStorageManager {
} finally {
if(vmMo != null){
ManagedObjectReference snapshotMor = vmMo.getSnapshotMor(snapshotUuid);
- if (snapshotMor != null){
+ if (snapshotMor != null) {
vmMo.removeSnapshot(snapshotUuid, false);
}
}
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/834fdc88/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
index 138f725..c2e55fb 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
@@ -58,6 +58,7 @@ import com.cloud.hypervisor.vmware.manager.VmwareStorageMount;
import com.cloud.hypervisor.vmware.mo.ClusterMO;
import com.cloud.hypervisor.vmware.mo.CustomFieldConstants;
import com.cloud.hypervisor.vmware.mo.DatacenterMO;
+import com.cloud.hypervisor.vmware.mo.DatastoreFile;
import com.cloud.hypervisor.vmware.mo.DatastoreMO;
import com.cloud.hypervisor.vmware.mo.HostMO;
import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
@@ -949,7 +950,8 @@ public class VmwareStorageProcessor implements StorageProcessor {
}
}
- private void exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volumePath,
+ // return Pair<String(divice bus name), String[](disk chain)>
+ private Pair<String, String[]> exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volumePath,
String secStorageUrl, String secStorageDir, String exportName,
String workerVmName) throws Exception {
@@ -978,7 +980,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
}
// 4 MB is the minimum requirement for VM memory in VMware
- vmMo.cloneFromCurrentSnapshot(workerVmName, 0, 4, volumeDeviceInfo.second(),
+ String disks[] = vmMo.cloneFromCurrentSnapshot(workerVmName, 0, 4, volumeDeviceInfo.second(),
VmwareHelper.getDiskDeviceDatastore(volumeDeviceInfo.first()));
clonedVm = vmMo.getRunningHost().findVmOnHyperHost(workerVmName);
if(clonedVm == null) {
@@ -988,6 +990,8 @@ public class VmwareStorageProcessor implements StorageProcessor {
}
clonedVm.exportVm(exportPath, exportName, false, false);
+
+ return new Pair<String, String[]>(volumeDeviceInfo.second(), disks);
} finally {
if(clonedVm != null) {
clonedVm.detachAllDisks();
@@ -996,15 +1000,15 @@ public class VmwareStorageProcessor implements StorageProcessor {
}
}
-
- private String backupSnapshotToSecondaryStorage(VirtualMachineMO vmMo, String installPath,
+ // Ternary<String(backup uuid in secondary storage), String(device bus name), String[](original disk chain in the snapshot)>
+ private Ternary<String, String, String[]> backupSnapshotToSecondaryStorage(VirtualMachineMO vmMo, String installPath,
String volumePath, String snapshotUuid, String secStorageUrl,
String prevSnapshotUuid, String prevBackupUuid, String workerVmName) throws Exception {
String backupUuid = UUID.randomUUID().toString();
- exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl,
+ Pair<String, String[]> snapshotInfo = exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl,
installPath, backupUuid, workerVmName);
- return backupUuid + "/" + backupUuid;
+ return new Ternary<String, String, String[]>(backupUuid + "/" + backupUuid, snapshotInfo.first(), snapshotInfo.second());
}
@Override
@@ -1033,6 +1037,9 @@ public class VmwareStorageProcessor implements StorageProcessor {
String details = null;
boolean success = false;
String snapshotBackupUuid = null;
+
+ boolean hasOwnerVm = false;
+ Ternary<String, String, String[]> backupResult = null;
VmwareContext context = hostService.getServiceContext(cmd);
VirtualMachineMO vmMo = null;
@@ -1041,6 +1048,8 @@ public class VmwareStorageProcessor implements StorageProcessor {
VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, primaryStore.getUuid());
+ CopyCmdAnswer answer = null;
+
try {
if (vmName != null) {
vmMo = hyperHost.findVmOnHyperHost(vmName);
@@ -1067,31 +1076,84 @@ public class VmwareStorageProcessor implements StorageProcessor {
// attach volume to worker VM
String datastoreVolumePath = dsMo.getDatastorePath(volumePath + ".vmdk");
vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs);
+ } else {
+ s_logger.info("Using owner VM " + vmName + " for snapshot operation");
+ hasOwnerVm = true;
}
+ } else {
+ s_logger.info("Using owner VM " + vmName + " for snapshot operation");
+ hasOwnerVm = true;
}
if (!vmMo.createSnapshot(snapshotUuid, "Snapshot taken for " + srcSnapshot.getName(), false, false)) {
throw new Exception("Failed to take snapshot " + srcSnapshot.getName() + " on vm: " + vmName);
}
- snapshotBackupUuid = backupSnapshotToSecondaryStorage(vmMo, destSnapshot.getPath(), srcSnapshot.getVolume().getPath(), snapshotUuid, secondaryStorageUrl, prevSnapshotUuid, prevBackupUuid,
+ backupResult = backupSnapshotToSecondaryStorage(vmMo, destSnapshot.getPath(), srcSnapshot.getVolume().getPath(), snapshotUuid, secondaryStorageUrl, prevSnapshotUuid, prevBackupUuid,
hostService.getWorkerName(context, cmd, 1));
+ snapshotBackupUuid = backupResult.first();
success = (snapshotBackupUuid != null);
if (!success) {
details = "Failed to backUp the snapshot with uuid: " + snapshotUuid + " to secondary storage.";
- return new CopyCmdAnswer(details);
+ answer = new CopyCmdAnswer(details);
} else {
details = "Successfully backedUp the snapshot with Uuid: " + snapshotUuid + " to secondary storage.";
SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
newSnapshot.setPath(destSnapshot.getPath() + "/" + snapshotBackupUuid);
- return new CopyCmdAnswer(newSnapshot);
+ answer = new CopyCmdAnswer(newSnapshot);
}
} finally {
if(vmMo != null){
ManagedObjectReference snapshotMor = vmMo.getSnapshotMor(snapshotUuid);
- if (snapshotMor != null){
+ if (snapshotMor != null) {
vmMo.removeSnapshot(snapshotUuid, false);
+
+ // Snapshot operation may cause disk consolidation in VMware, when this happens
+ // we need to update CloudStack DB
+ //
+ // TODO: this post operation fixup is not atomic and not safe when management server stops
+ // in the middle
+ if(backupResult != null && hasOwnerVm) {
+ s_logger.info("Check if we have disk consolidation after snapshot operation");
+
+ boolean chainConsolidated = false;
+ for(String vmdkDsFilePath : backupResult.third()) {
+ s_logger.info("Validate disk chain file:" + vmdkDsFilePath);
+
+ if(vmMo.getDiskDevice(vmdkDsFilePath, false) == null) {
+ s_logger.info("" + vmdkDsFilePath + " no longer exists, consolidation detected");
+ chainConsolidated = true;
+ break;
+ } else {
+ s_logger.info("" + vmdkDsFilePath + " is found still in chain");
+ }
+ }
+
+ if(chainConsolidated) {
+ String topVmdkFilePath = null;
+ try {
+ topVmdkFilePath = vmMo.getDiskCurrentTopBackingFileInChain(backupResult.second());
+ } catch(Exception e) {
+ s_logger.error("Unexpected exception", e);
+ }
+
+ s_logger.info("Disk has been consolidated, top VMDK is now: " + topVmdkFilePath);
+ if(topVmdkFilePath != null) {
+ DatastoreFile file = new DatastoreFile(topVmdkFilePath);
+
+ SnapshotObjectTO snapshotInfo = (SnapshotObjectTO)answer.getNewData();
+ VolumeObjectTO vol = new VolumeObjectTO();
+ vol.setUuid(srcSnapshot.getVolume().getUuid());
+ vol.setPath(file.getFileBaseName());
+ snapshotInfo.setVolume(vol);
+ } else {
+ s_logger.error("Disk has been consolidated, but top VMDK is not found ?!");
+ }
+ }
+ }
+ } else {
+ s_logger.error("Can not find the snapshot we just used ?!");
}
}
@@ -1105,6 +1167,8 @@ public class VmwareStorageProcessor implements StorageProcessor {
s_logger.warn("Failed to destroy worker VM: " + workerVMName);
}
}
+
+ return answer;
} catch (Throwable e) {
if (e instanceof RemoteException) {
hostService.invalidateServiceContext(context);
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/834fdc88/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 8e3df50..6a16ffa 100644
--- a/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
+++ b/vmware-base/src/com/cloud/hypervisor/vmware/mo/VirtualMachineMO.java
@@ -1551,11 +1551,13 @@ public class VirtualMachineMO extends BaseMO {
return diskDsFullPaths.toArray(new String[0]);
}
- public void cloneFromCurrentSnapshot(String clonedVmName, int cpuSpeedMHz, int memoryMb, String diskDevice,
+ // return the disk chain (VMDK datastore paths) for cloned snapshot
+ public String[] cloneFromCurrentSnapshot(String clonedVmName, int cpuSpeedMHz, int memoryMb, String diskDevice,
ManagedObjectReference morDs) throws Exception {
assert(morDs != null);
String[] disks = getCurrentSnapshotDiskChainDatastorePaths(diskDevice);
cloneFromDiskChain(clonedVmName, cpuSpeedMHz, memoryMb, disks, morDs);
+ return disks;
}
public void cloneFromDiskChain(String clonedVmName, int cpuSpeedMHz, int memoryMb,
@@ -1576,7 +1578,6 @@ public class VirtualMachineMO extends BaseMO {
boolean bSuccess = false;
try {
VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();
- //VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1];
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
VirtualDevice device = VmwareHelper.prepareDiskDevice(clonedVmMo, -1, disks, morDs, -1, 1);
@@ -1611,7 +1612,6 @@ public class VirtualMachineMO extends BaseMO {
public void plugDevice(VirtualDevice device) throws Exception {
VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();
- //VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1];
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
deviceConfigSpec.setDevice(device);
deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD);
@@ -1624,7 +1624,6 @@ public class VirtualMachineMO extends BaseMO {
public void tearDownDevice(VirtualDevice device) throws Exception {
VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec();
- //VirtualDeviceConfigSpec[] deviceConfigSpecArray = new VirtualDeviceConfigSpec[1];
VirtualDeviceConfigSpec deviceConfigSpec = new VirtualDeviceConfigSpec();
deviceConfigSpec.setDevice(device);
deviceConfigSpec.setOperation(VirtualDeviceConfigSpecOperation.REMOVE);
@@ -1826,6 +1825,28 @@ public class VirtualMachineMO extends BaseMO {
return null;
}
+
+ public String getDiskCurrentTopBackingFileInChain(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) {
+ s_logger.info("Test against disk device, controller key: " + device.getControllerKey() + ", unit number: " + device.getUnitNumber());
+
+ VirtualDeviceBackingInfo backingInfo = ((VirtualDisk)device).getBacking();
+ if(backingInfo instanceof VirtualDiskFlatVer2BackingInfo) {
+ VirtualDiskFlatVer2BackingInfo diskBackingInfo = (VirtualDiskFlatVer2BackingInfo)backingInfo;
+
+ String deviceNumbering = getDeviceBusName(devices, device);
+ if(deviceNumbering.equals(deviceBusName))
+ return diskBackingInfo.getFileName();
+ }
+ }
+ }
+ }
+
+ return null;
+ }
@Deprecated
public List<Pair<String, ManagedObjectReference>> getDiskDatastorePathChain(VirtualDisk disk, boolean followChain) throws Exception {