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 <[email protected]>
Authored: Fri Aug 23 17:38:17 2013 -0700
Committer: Kelven Yang <[email protected]>
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 {

Reply via email to