You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by mu...@apache.org on 2012/06/27 04:45:55 UTC

[5/9] moving out VMWAre and Nexus VSM support code into plugins/hypervisors/vmware

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8197f1f0/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
new file mode 100644
index 0000000..b525e13
--- /dev/null
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageManagerImpl.java
@@ -0,0 +1,880 @@
+// Copyright 2012 Citrix Systems, Inc. Licensed under the
+// Apache License, Version 2.0 (the "License"); you may not use this
+// file except in compliance with the License.  Citrix Systems, Inc.
+// reserves all rights not expressly granted by the License.
+// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
+// Automatically generated by addcopyright.py at 04/03/2012
+package com.cloud.hypervisor.vmware.manager;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.rmi.RemoteException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.BackupSnapshotAnswer;
+import com.cloud.agent.api.BackupSnapshotCommand;
+import com.cloud.agent.api.CreatePrivateTemplateFromSnapshotCommand;
+import com.cloud.agent.api.CreatePrivateTemplateFromVolumeCommand;
+import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
+import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
+import com.cloud.agent.api.storage.CopyVolumeAnswer;
+import com.cloud.agent.api.storage.CopyVolumeCommand;
+import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
+import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
+import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
+import com.cloud.agent.api.to.StorageFilerTO;
+import com.cloud.hypervisor.vmware.mo.CustomFieldConstants;
+import com.cloud.hypervisor.vmware.mo.DatacenterMO;
+import com.cloud.hypervisor.vmware.mo.DatastoreMO;
+import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
+import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
+import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
+import com.cloud.hypervisor.vmware.util.VmwareContext;
+import com.cloud.hypervisor.vmware.util.VmwareHelper;
+import com.cloud.storage.JavaStorageLayer;
+import com.cloud.storage.Storage.ImageFormat;
+import com.cloud.storage.StorageLayer;
+import com.cloud.storage.template.VmdkProcessor;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.Pair;
+import com.cloud.utils.StringUtils;
+import com.cloud.utils.Ternary;
+import com.cloud.utils.script.Script;
+import com.vmware.vim25.ManagedObjectReference;
+import com.vmware.vim25.VirtualDeviceConfigSpec;
+import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
+import com.vmware.vim25.VirtualDisk;
+import com.vmware.vim25.VirtualLsiLogicController;
+import com.vmware.vim25.VirtualMachineConfigSpec;
+import com.vmware.vim25.VirtualMachineFileInfo;
+import com.vmware.vim25.VirtualMachineGuestOsIdentifier;
+import com.vmware.vim25.VirtualSCSISharing;
+
+public class VmwareStorageManagerImpl implements VmwareStorageManager {
+    private static final Logger s_logger = Logger.getLogger(VmwareStorageManagerImpl.class);
+    
+    private final VmwareStorageMount _mountService;
+    private final StorageLayer _storage = new JavaStorageLayer();
+    
+    private int _timeout;
+    
+    public VmwareStorageManagerImpl(VmwareStorageMount mountService) {
+        assert(mountService != null);
+        _mountService = mountService;
+    }
+    
+    public void configure(Map<String, Object> params) {
+        s_logger.info("Configure VmwareStorageManagerImpl");
+        
+        String value = (String)params.get("scripts.timeout");
+        _timeout = NumbersUtil.parseInt(value, 1440) * 1000;
+    }
+    
+    @Override
+    public Answer execute(VmwareHostService hostService, PrimaryStorageDownloadCommand cmd) {
+		String secondaryStorageUrl = cmd.getSecondaryStorageUrl();
+		assert (secondaryStorageUrl != null);
+
+		String templateUrl = cmd.getUrl();
+
+		String templateName = null;
+		String mountPoint = null;
+		if (templateUrl.endsWith(".ova")) {
+			int index = templateUrl.lastIndexOf("/");
+			mountPoint = templateUrl.substring(0, index);
+			mountPoint = mountPoint.substring(secondaryStorageUrl.length() + 1);
+			if (!mountPoint.endsWith("/")) {
+				mountPoint = mountPoint + "/";
+			}
+
+			templateName = templateUrl.substring(index + 1).replace("." + ImageFormat.OVA.getFileExtension(), "");
+
+			if (templateName == null || templateName.isEmpty()) {
+				templateName = cmd.getName();
+			}
+		} else {
+			mountPoint = templateUrl.substring(secondaryStorageUrl.length() + 1);
+			if (!mountPoint.endsWith("/")) {
+				mountPoint = mountPoint + "/";
+			}
+			templateName = cmd.getName();
+		}
+		
+		VmwareContext context = hostService.getServiceContext(cmd);
+		try {
+			VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+			
+			String templateUuidName = UUID.nameUUIDFromBytes((templateName + "@" + cmd.getPoolUuid() + "-" + hyperHost.getMor().get_value()).getBytes()).toString();
+			// truncate template name to 32 chars to ensure they work well with vSphere API's.
+			templateUuidName = templateUuidName.replace("-", ""); 
+			
+			DatacenterMO dcMo = new DatacenterMO(context, hyperHost.getHyperHostDatacenter());
+			VirtualMachineMO templateMo = VmwareHelper.pickOneVmOnRunningHost(dcMo.findVmByNameAndLabel(templateUuidName), true);
+			
+			if (templateMo == null) {
+			    if(s_logger.isInfoEnabled())
+			        s_logger.info("Template " + templateName + " is not setup yet, setup template from secondary storage with uuid name: " + templateUuidName);
+				ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getPoolUuid());
+				assert (morDs != null);
+				DatastoreMO primaryStorageDatastoreMo = new DatastoreMO(context, morDs);
+
+				copyTemplateFromSecondaryToPrimary(hyperHost,
+					primaryStorageDatastoreMo, secondaryStorageUrl,
+					mountPoint, templateName, templateUuidName);
+			} else {
+				s_logger.info("Template " + templateName + " has already been setup, skip the template setup process in primary storage");
+			}
+
+			return new PrimaryStorageDownloadAnswer(templateUuidName, 0);
+		} catch (Throwable e) {
+			if (e instanceof RemoteException) {
+				hostService.invalidateServiceContext(context);
+			}
+
+			String msg = "Unable to execute PrimaryStorageDownloadCommand due to exception";
+			s_logger.error(msg, e);
+			return new PrimaryStorageDownloadAnswer(msg);
+		}
+    }
+    
+    @Override
+	public Answer execute(VmwareHostService hostService, BackupSnapshotCommand cmd) {
+		Long accountId = cmd.getAccountId();
+		Long volumeId = cmd.getVolumeId();
+        String secondaryStorageUrl = cmd.getSecondaryStorageUrl();
+        String snapshotUuid = cmd.getSnapshotUuid(); // not null: Precondition.
+		String prevSnapshotUuid = cmd.getPrevSnapshotUuid();
+		String prevBackupUuid = cmd.getPrevBackupUuid();
+        VirtualMachineMO workerVm=null;
+        String workerVMName = null;
+		String volumePath = cmd.getVolumePath();
+		ManagedObjectReference morDs = null;
+		DatastoreMO dsMo=null;
+
+		// By default assume failure
+		String details = null;
+		boolean success = false;
+		String snapshotBackupUuid = null;
+
+		VmwareContext context = hostService.getServiceContext(cmd);
+		VirtualMachineMO vmMo = null;
+		try {
+			VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+			morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getPool().getUuid());
+
+			try {
+				vmMo = hyperHost.findVmOnHyperHost(cmd.getVmName());
+				if (vmMo == null) {
+					if(s_logger.isDebugEnabled())
+						s_logger.debug("Unable to find owner VM for BackupSnapshotCommand on host " + hyperHost.getHyperHostName() + ", will try within datacenter");
+	
+					vmMo = hyperHost.findVmOnPeerHyperHost(cmd.getVmName());
+					if(vmMo == null) {
+						dsMo = new DatastoreMO(hyperHost.getContext(), morDs);
+						
+						workerVMName = hostService.getWorkerName(context, cmd, 0);
+	
+						// attach a volume to dummay wrapper VM for taking snapshot and exporting the VM for backup
+						if (!hyperHost.createBlankVm(workerVMName, 1, 512, 0, false, 4, 0, VirtualMachineGuestOsIdentifier._otherGuest.toString(), morDs, false)) {
+							String msg = "Unable to create worker VM to execute BackupSnapshotCommand";
+							s_logger.error(msg);
+							throw new Exception(msg);
+						}
+						vmMo = hyperHost.findVmOnHyperHost(workerVMName);
+						if (vmMo == null) {
+							throw new Exception("Failed to find the newly create or relocated VM. vmName: " + workerVMName);
+						}
+						workerVm = vmMo;
+	
+						// attach volume to worker VM
+						String datastoreVolumePath = String.format("[%s] %s.vmdk", dsMo.getName(), volumePath);
+						vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs);
+					} 
+				} 
+				
+                if (!vmMo.createSnapshot(snapshotUuid, "Snapshot taken for " + cmd.getSnapshotName(), false, false)) {
+                    throw new Exception("Failed to take snapshot " + cmd.getSnapshotName() + " on vm: " + cmd.getVmName());
+                }
+				
+	            snapshotBackupUuid = backupSnapshotToSecondaryStorage(vmMo, accountId, volumeId, cmd.getVolumePath(), snapshotUuid, secondaryStorageUrl, prevSnapshotUuid, prevBackupUuid,
+	                    hostService.getWorkerName(context, cmd, 1));
+
+                success = (snapshotBackupUuid != null);
+                if (success) {
+                    details = "Successfully backedUp the snapshotUuid: " + snapshotUuid + " to secondary storage.";
+                }
+				
+			} finally {
+                if(vmMo != null)
+                    vmMo.removeAllSnapshots();
+			    
+				try {
+		            if (workerVm != null) {
+		                // detach volume and destroy worker vm
+		                workerVm.detachAllDisks();
+		                workerVm.destroy();
+		            }
+		        } catch (Throwable e) {
+		        	s_logger.warn("Failed to destroy worker VM: " + workerVMName);
+		        }			
+			}
+		} catch (Throwable e) {
+			if (e instanceof RemoteException) {
+				hostService.invalidateServiceContext(context);
+			}
+
+			s_logger.error("Unexpecpted exception ", e);
+
+			details = "BackupSnapshotCommand exception: " + StringUtils.getExceptionStackInfo(e);
+			return new BackupSnapshotAnswer(cmd, false, details, snapshotBackupUuid, true);
+		}
+
+		return new BackupSnapshotAnswer(cmd, success, details, snapshotBackupUuid, true);
+	}
+
+    @Override
+	public Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromVolumeCommand cmd) {
+        String secondaryStoragePoolURL = cmd.getSecondaryStorageUrl();
+		String volumePath = cmd.getVolumePath();
+		Long accountId = cmd.getAccountId();
+		Long templateId = cmd.getTemplateId();
+		String details = null;
+
+		VmwareContext context = hostService.getServiceContext(cmd);
+		try {
+			VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+			
+			VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(cmd.getVmName());
+			if (vmMo == null) {
+				if(s_logger.isDebugEnabled())
+					s_logger.debug("Unable to find the owner VM for CreatePrivateTemplateFromVolumeCommand on host " + hyperHost.getHyperHostName() + ", try within datacenter");
+				vmMo = hyperHost.findVmOnPeerHyperHost(cmd.getVmName());
+
+				if(vmMo == null) {
+					String msg = "Unable to find the owner VM for volume operation. vm: " + cmd.getVmName();
+					s_logger.error(msg);
+					throw new Exception(msg);
+				}
+			}
+
+			Ternary<String, Long, Long> result = createTemplateFromVolume(vmMo,
+					accountId, templateId, cmd.getUniqueName(),
+					secondaryStoragePoolURL, volumePath, 
+					hostService.getWorkerName(context, cmd, 0));
+
+			return new CreatePrivateTemplateAnswer(cmd, true, null,
+					result.first(), result.third(), result.second(),
+					cmd.getUniqueName(), ImageFormat.OVA);
+
+		} catch (Throwable e) {
+			if (e instanceof RemoteException) {
+				hostService.invalidateServiceContext(context);
+			}
+
+			s_logger.error("Unexpecpted exception ", e);
+
+			details = "CreatePrivateTemplateFromVolumeCommand exception: " + StringUtils.getExceptionStackInfo(e);
+			return new CreatePrivateTemplateAnswer(cmd, false, details);
+		}
+	}
+
+    @Override
+	public Answer execute(VmwareHostService hostService, CreatePrivateTemplateFromSnapshotCommand cmd) {
+		Long accountId = cmd.getAccountId();
+		Long volumeId = cmd.getVolumeId();
+        String secondaryStorageUrl = cmd.getSecondaryStorageUrl();
+		String backedUpSnapshotUuid = cmd.getSnapshotUuid();
+		Long newTemplateId = cmd.getNewTemplateId();
+		String details;
+		String uniqeName = UUID.randomUUID().toString();
+
+		VmwareContext context = hostService.getServiceContext(cmd);
+		try {
+			Ternary<String, Long, Long> result = createTemplateFromSnapshot(accountId,
+				newTemplateId, uniqeName,
+				secondaryStorageUrl, volumeId,
+				backedUpSnapshotUuid);
+
+			return new CreatePrivateTemplateAnswer(cmd, true, null,
+					result.first(), result.third(), result.second(),
+					uniqeName, ImageFormat.OVA);
+		} catch (Throwable e) {
+			if (e instanceof RemoteException) {
+				hostService.invalidateServiceContext(context);
+			}
+
+			s_logger.error("Unexpecpted exception ", e);
+
+			details = "CreatePrivateTemplateFromSnapshotCommand exception: " + StringUtils.getExceptionStackInfo(e);
+			return new CreatePrivateTemplateAnswer(cmd, false, details);
+		}
+	}
+	
+    @Override
+	public Answer execute(VmwareHostService hostService, CopyVolumeCommand cmd) {
+		Long volumeId = cmd.getVolumeId();
+		String volumePath = cmd.getVolumePath();
+		String secondaryStorageURL = cmd.getSecondaryStorageURL();
+		String vmName = cmd.getVmName();
+
+		VmwareContext context = hostService.getServiceContext(cmd);
+		try {
+			VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+
+			Pair<String, String> result;
+			if (cmd.toSecondaryStorage()) {
+				result = copyVolumeToSecStorage(hostService,
+						hyperHost, cmd, vmName, volumeId, cmd.getPool().getUuid(), volumePath,
+						secondaryStorageURL,
+						hostService.getWorkerName(context, cmd, 0));
+			} else {
+				StorageFilerTO poolTO = cmd.getPool();
+
+				ManagedObjectReference morDatastore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, poolTO.getUuid());
+				if (morDatastore == null) {
+					morDatastore = hyperHost.mountDatastore(
+							false,
+							poolTO.getHost(), 0, poolTO.getPath(),
+							poolTO.getUuid().replace("-", ""));
+
+					if (morDatastore == null) {
+						throw new Exception("Unable to mount storage pool on host. storeUrl: " + poolTO.getHost() + ":/" + poolTO.getPath());
+					}
+				}
+
+				result = copyVolumeFromSecStorage(
+						hyperHost, volumeId,
+						new DatastoreMO(context, morDatastore),
+						secondaryStorageURL, volumePath);
+			}
+			return new CopyVolumeAnswer(cmd, true, null, result.first(), result.second());
+		} catch (Throwable e) {
+			if (e instanceof RemoteException) {
+				hostService.invalidateServiceContext(context);
+			}
+
+			String msg = "Unable to execute CopyVolumeCommand due to exception";
+			s_logger.error(msg, e);
+			return new CopyVolumeAnswer(cmd, false, "CopyVolumeCommand failed due to exception: " + StringUtils.getExceptionStackInfo(e), null, null);
+		}
+	}
+    
+    @Override
+	public Answer execute(VmwareHostService hostService, CreateVolumeFromSnapshotCommand cmd) {
+
+		String primaryStorageNameLabel = cmd.getPrimaryStoragePoolNameLabel();
+		Long accountId = cmd.getAccountId();
+		Long volumeId = cmd.getVolumeId();
+        String secondaryStorageUrl = cmd.getSecondaryStorageUrl();
+		String backedUpSnapshotUuid = cmd.getSnapshotUuid();
+
+		String details = null;
+		boolean success = false;
+		String newVolumeName = UUID.randomUUID().toString().replaceAll("-", "");
+
+		VmwareContext context = hostService.getServiceContext(cmd);
+		try {
+			VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+			
+			ManagedObjectReference morPrimaryDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, primaryStorageNameLabel);
+			if (morPrimaryDs == null) {
+				String msg = "Unable to find datastore: " + primaryStorageNameLabel;
+				s_logger.error(msg);
+				throw new Exception(msg);
+			}
+
+			DatastoreMO primaryDsMo = new DatastoreMO(hyperHost.getContext(), morPrimaryDs);
+			details = createVolumeFromSnapshot(hyperHost, primaryDsMo,
+					newVolumeName, accountId, volumeId, secondaryStorageUrl, backedUpSnapshotUuid);
+			if (details == null) {
+				success = true;
+			}
+		} catch (Throwable e) {
+			if (e instanceof RemoteException) {
+				hostService.invalidateServiceContext(context);
+			}
+
+			s_logger.error("Unexpecpted exception ", e);
+			details = "CreateVolumeFromSnapshotCommand exception: " + StringUtils.getExceptionStackInfo(e);
+		}
+
+		return new CreateVolumeFromSnapshotAnswer(cmd, success, details, newVolumeName);
+	}
+	
+    // templateName: name in secondary storage
+    // templateUuid: will be used at hypervisor layer
+    private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, DatastoreMO datastoreMo, String secondaryStorageUrl,
+        String templatePathAtSecondaryStorage, String templateName, String templateUuid) throws Exception {
+        
+        s_logger.info("Executing copyTemplateFromSecondaryToPrimary. secondaryStorage: " 
+            + secondaryStorageUrl + ", templatePathAtSecondaryStorage: " + templatePathAtSecondaryStorage
+            + ", templateName: " + templateName);
+        
+        String secondaryMountPoint = _mountService.getMountPoint(secondaryStorageUrl);
+        s_logger.info("Secondary storage mount point: " + secondaryMountPoint);
+        
+        String srcOVAFileName = secondaryMountPoint + "/" +  templatePathAtSecondaryStorage + 
+            templateName + "." + ImageFormat.OVA.getFileExtension();
+        
+        String srcFileName = getOVFFilePath(srcOVAFileName);
+        if(srcFileName == null) {
+            Script command = new Script("tar", 0, s_logger);
+            command.add("--no-same-owner");
+            command.add("-xf", srcOVAFileName);
+            command.setWorkDir(secondaryMountPoint + "/" +  templatePathAtSecondaryStorage);
+            s_logger.info("Executing command: " + command.toString());
+            String result = command.execute();
+            if(result != null) {
+                String msg = "Unable to unpack snapshot OVA file at: " + srcOVAFileName;
+                s_logger.error(msg);
+                throw new Exception(msg);
+            }
+        }
+        
+        srcFileName = getOVFFilePath(srcOVAFileName);
+        if(srcFileName == null) {    
+            String msg = "Unable to locate OVF file in template package directory: " + srcOVAFileName; 
+            s_logger.error(msg);
+            throw new Exception(msg);
+        }
+        
+        String vmName = templateUuid;
+        hyperHost.importVmFromOVF(srcFileName, vmName, datastoreMo, "thin");
+        
+        VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmName);
+        if(vmMo == null) {
+            String msg = "Failed to import OVA template. secondaryStorage: " 
+                + secondaryStorageUrl + ", templatePathAtSecondaryStorage: " + templatePathAtSecondaryStorage
+                + ", templateName: " + templateName + ", templateUuid: " + templateUuid;
+            s_logger.error(msg);
+            throw new Exception(msg);
+        }
+        
+        if(vmMo.createSnapshot("cloud.template.base", "Base snapshot", false, false)) {
+            vmMo.setCustomFieldValue(CustomFieldConstants.CLOUD_UUID, templateUuid);
+            vmMo.markAsTemplate();
+        } else {
+            vmMo.destroy();
+            String msg = "Unable to create base snapshot for template, templateName: " + templateName + ", templateUuid: " + templateUuid; 
+            s_logger.error(msg);
+            throw new Exception(msg);
+        }
+    }
+    
+    private Ternary<String, Long, Long> createTemplateFromVolume(VirtualMachineMO vmMo, long accountId, long templateId, String templateUniqueName, 
+        String secStorageUrl, String volumePath, String workerVmName) throws Exception {
+        
+        String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl);
+        String installPath = getTemplateRelativeDirInSecStorage(accountId, templateId);
+        String installFullPath = secondaryMountPoint + "/" + installPath;
+        synchronized(installPath.intern()) {
+            Script command = new Script(false, "mkdir", _timeout, s_logger);
+            command.add("-p");
+            command.add(installFullPath);
+            
+            String result = command.execute();
+            if(result != null) {
+                String msg = "unable to prepare template directory: " 
+                    + installPath + ", storage: " + secStorageUrl + ", error msg: " + result;
+                s_logger.error(msg);
+                throw new Exception(msg);
+            }
+        }
+        
+        VirtualMachineMO clonedVm = null;
+        try {
+            Pair<VirtualDisk, String> volumeDeviceInfo = vmMo.getDiskDevice(volumePath, false);
+            if(volumeDeviceInfo == null) {
+                String msg = "Unable to find related disk device for volume. volume path: " + volumePath;
+                s_logger.error(msg);
+                throw new Exception(msg);
+            }
+            
+            if(!vmMo.createSnapshot(templateUniqueName, "Temporary snapshot for template creation", false, false)) {
+                String msg = "Unable to take snapshot for creating template from volume. volume path: " + volumePath;
+                s_logger.error(msg);
+                throw new Exception(msg);
+            }
+        
+            // 4 MB is the minimum requirement for VM memory in VMware
+            vmMo.cloneFromCurrentSnapshot(workerVmName, 0, 4, volumeDeviceInfo.second(), 
+                VmwareHelper.getDiskDeviceDatastore(volumeDeviceInfo.first()));
+            clonedVm = vmMo.getRunningHost().findVmOnHyperHost(workerVmName);
+            if(clonedVm == null) {
+                String msg = "Unable to create dummy VM to export volume. volume path: " + volumePath;
+                s_logger.error(msg);
+                throw new Exception(msg);
+            }
+        
+            clonedVm.exportVm(secondaryMountPoint + "/" + installPath, templateUniqueName, true, false);
+            
+            long physicalSize = new File(installFullPath + "/" + templateUniqueName + ".ova").length();
+            VmdkProcessor processor = new VmdkProcessor();
+            Map<String, Object> params = new HashMap<String, Object>();
+            params.put(StorageLayer.InstanceConfigKey, _storage);
+            processor.configure("VMDK Processor", params);
+            long virtualSize = processor.getTemplateVirtualSize(installFullPath, templateUniqueName);
+
+            postCreatePrivateTemplate(installFullPath, templateId, templateUniqueName, physicalSize, virtualSize);
+            return new Ternary<String, Long, Long>(installPath + "/" + templateUniqueName + ".ova", physicalSize, virtualSize);
+            
+        } finally {
+            if(clonedVm != null) {
+                clonedVm.detachAllDisks();
+                clonedVm.destroy();
+            }
+        
+            vmMo.removeSnapshot(templateUniqueName, false);
+        }
+    }
+    
+    private Ternary<String, Long, Long> createTemplateFromSnapshot(long accountId, long templateId, String templateUniqueName, 
+        String secStorageUrl, long volumeId, String backedUpSnapshotUuid) throws Exception {
+        
+        String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl);
+        String installPath = getTemplateRelativeDirInSecStorage(accountId, templateId);
+        String installFullPath = secondaryMountPoint + "/" + installPath;
+        String installFullName = installFullPath + "/" + templateUniqueName + ".ova";
+        String snapshotFullName = secondaryMountPoint + "/" + getSnapshotRelativeDirInSecStorage(accountId, volumeId) 
+            + "/" + backedUpSnapshotUuid + ".ova";
+        String result;
+        Script command;
+        
+        synchronized(installPath.intern()) {
+            command = new Script(false, "mkdir", _timeout, s_logger);
+            command.add("-p");
+            command.add(installFullPath);
+            
+            result = command.execute();
+            if(result != null) {
+                String msg = "unable to prepare template directory: " 
+                    + installPath + ", storage: " + secStorageUrl + ", error msg: " + result;
+                s_logger.error(msg);
+                throw new Exception(msg);
+            }
+        }
+        
+        try {
+            command = new Script(false, "cp", _timeout, s_logger);
+            command.add(snapshotFullName);
+            command.add(installFullName);
+            result = command.execute();
+            if(result != null) {
+                String msg = "unable to copy snapshot " + snapshotFullName + " to " + installFullPath; 
+                s_logger.error(msg);
+                throw new Exception(msg);
+            }
+            
+            // untar OVA file at template directory
+            command = new Script("tar", 0, s_logger);
+            command.add("--no-same-owner");
+            command.add("-xf", installFullName);
+            command.setWorkDir(installFullPath);
+            s_logger.info("Executing command: " + command.toString());
+            result = command.execute();
+            if(result != null) {
+                String msg = "unable to untar snapshot " + snapshotFullName + " to " 
+                    + installFullPath; 
+                s_logger.error(msg);
+                throw new Exception(msg);
+            }
+            
+            long physicalSize = new File(installFullPath + "/" + templateUniqueName + ".ova").length();
+            VmdkProcessor processor = new VmdkProcessor();
+            Map<String, Object> params = new HashMap<String, Object>();
+            params.put(StorageLayer.InstanceConfigKey, _storage);
+            processor.configure("VMDK Processor", params);
+            long virtualSize = processor.getTemplateVirtualSize(installFullPath, templateUniqueName);
+
+            postCreatePrivateTemplate(installFullPath, templateId, templateUniqueName, physicalSize, virtualSize);
+            return new Ternary<String, Long, Long>(installPath + "/" + templateUniqueName + ".ova", physicalSize, virtualSize);
+        
+        } catch(Exception e) {
+            // TODO, clean up left over files
+            throw e;
+        }
+    }
+    
+    private void postCreatePrivateTemplate(String installFullPath, long templateId, 
+        String templateName, long size, long virtualSize) throws Exception {
+
+        // TODO a bit ugly here
+        BufferedWriter out = null;
+        try {
+            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(installFullPath + "/template.properties")));
+            out.write("filename=" + templateName + ".ova"); 
+            out.newLine();
+            out.write("description="); 
+            out.newLine();
+            out.write("checksum="); 
+            out.newLine();
+            out.write("hvm=false"); 
+            out.newLine();
+            out.write("size=" + size); 
+            out.newLine();
+            out.write("ova=true"); 
+            out.newLine();
+            out.write("id=" + templateId); 
+            out.newLine();
+            out.write("public=false"); 
+            out.newLine();
+            out.write("ova.filename=" + templateName + ".ova"); 
+            out.newLine();
+            out.write("uniquename=" + templateName);
+            out.newLine();
+            out.write("ova.virtualsize=" + virtualSize); 
+            out.newLine();
+            out.write("virtualsize=" + virtualSize); 
+            out.newLine();
+            out.write("ova.size=" + size); 
+            out.newLine();
+        } finally {
+            if(out != null)
+                out.close();
+        }
+    }
+
+    private String createVolumeFromSnapshot(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName, 
+        long accountId, long volumeId, String secStorageUrl, String snapshotBackupUuid) throws Exception {
+        
+        restoreVolumeFromSecStorage(hyperHost, primaryDsMo, newVolumeName, 
+            secStorageUrl, getSnapshotRelativeDirInSecStorage(accountId, volumeId), snapshotBackupUuid);
+        return null;
+    }
+    
+    private void restoreVolumeFromSecStorage(VmwareHypervisorHost hyperHost, DatastoreMO primaryDsMo, String newVolumeName, 
+        String secStorageUrl, String secStorageDir, String backupName) throws Exception {
+        
+        String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl);
+        String srcOVAFileName = secondaryMountPoint + "/" +  secStorageDir + "/"  
+            + backupName + "." + ImageFormat.OVA.getFileExtension();
+        
+        String srcFileName = getOVFFilePath(srcOVAFileName);
+        if(srcFileName == null) {
+            Script command = new Script("tar", 0, s_logger);
+            command.add("--no-same-owner");
+            command.add("-xf", srcOVAFileName);
+            command.setWorkDir(secondaryMountPoint + "/" +  secStorageDir);
+            s_logger.info("Executing command: " + command.toString());
+            String result = command.execute();
+            if(result != null) {
+                String msg = "Unable to unpack snapshot OVA file at: " + srcOVAFileName;
+                s_logger.error(msg);
+                throw new Exception(msg);
+            }
+        }
+        
+        srcFileName = getOVFFilePath(srcOVAFileName);
+        if(srcFileName == null) {
+            String msg = "Unable to locate OVF file in template package directory: " + srcOVAFileName; 
+            s_logger.error(msg);
+            throw new Exception(msg);
+        }
+        
+        VirtualMachineMO clonedVm = null;
+        try {
+            hyperHost.importVmFromOVF(srcFileName, newVolumeName, primaryDsMo, "thin");
+            clonedVm = hyperHost.findVmOnHyperHost(newVolumeName);
+            if(clonedVm == null)
+                throw new Exception("Unable to create container VM for volume creation");
+            
+            clonedVm.moveAllVmDiskFiles(primaryDsMo, "", false);
+            clonedVm.detachAllDisks();
+        } finally {
+            if(clonedVm != null) {
+                clonedVm.detachAllDisks();
+                clonedVm.destroy();
+            }
+        }
+    }
+    
+    private String backupSnapshotToSecondaryStorage(VirtualMachineMO vmMo, long accountId, long volumeId, 
+        String volumePath, String snapshotUuid, String secStorageUrl, 
+        String prevSnapshotUuid, String prevBackupUuid, String workerVmName) throws Exception {
+        
+        String backupUuid = UUID.randomUUID().toString();
+        exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, 
+            getSnapshotRelativeDirInSecStorage(accountId, volumeId), backupUuid, workerVmName);
+        return backupUuid;
+    }
+    
+    private void exportVolumeToSecondaryStroage(VirtualMachineMO vmMo, String volumePath,  
+        String secStorageUrl, String secStorageDir, String exportName,
+        String workerVmName) throws Exception {
+        
+        String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl);
+        String exportPath =  secondaryMountPoint + "/" + secStorageDir;
+        
+        synchronized(exportPath.intern()) {
+            if(!new File(exportPath).exists()) {
+                Script command = new Script(false, "mkdir", _timeout, s_logger);
+                command.add("-p");
+                command.add(exportPath);
+                if(command.execute() != null)
+                    throw new Exception("unable to prepare snapshot backup directory");
+            }
+        }
+
+        VirtualMachineMO clonedVm = null;
+        try {
+        
+            Pair<VirtualDisk, String> volumeDeviceInfo = vmMo.getDiskDevice(volumePath, false);
+            if(volumeDeviceInfo == null) {
+                String msg = "Unable to find related disk device for volume. volume path: " + volumePath;
+                s_logger.error(msg);
+                throw new Exception(msg);
+            }
+        
+            // 4 MB is the minimum requirement for VM memory in VMware
+            vmMo.cloneFromCurrentSnapshot(workerVmName, 0, 4, volumeDeviceInfo.second(), 
+                VmwareHelper.getDiskDeviceDatastore(volumeDeviceInfo.first()));
+            clonedVm = vmMo.getRunningHost().findVmOnHyperHost(workerVmName);
+            if(clonedVm == null) {
+                String msg = "Unable to create dummy VM to export volume. volume path: " + volumePath;
+                s_logger.error(msg);
+                throw new Exception(msg);
+            }
+        
+            clonedVm.exportVm(exportPath, exportName, true, true);
+        } finally {
+            if(clonedVm != null) {
+                clonedVm.detachAllDisks();
+                clonedVm.destroy();
+            }
+        }
+    }
+    
+    private String deleteSnapshotOnSecondaryStorge(long accountId, long volumeId, String secStorageUrl, String backupUuid) throws Exception {
+
+        String secondaryMountPoint = _mountService.getMountPoint(secStorageUrl);
+        String snapshotMountRoot = secondaryMountPoint + "/" + getSnapshotRelativeDirInSecStorage(accountId, volumeId);
+        File file = new File(snapshotMountRoot + "/" + backupUuid + ".ova");
+        if(file.exists()) {
+            if(file.delete())
+                return null;
+            
+        } else {
+            return "Backup file does not exist. backupUuid: " + backupUuid;
+        }
+        
+        return "Failed to delete snapshot backup file, backupUuid: " + backupUuid;
+    }
+    
+    private Pair<String, String> copyVolumeToSecStorage(VmwareHostService hostService, VmwareHypervisorHost hyperHost, CopyVolumeCommand cmd, 
+        String vmName, long volumeId, String poolId, String volumePath, 
+        String secStorageUrl, String workerVmName) throws Exception {
+        
+        String volumeFolder = String.valueOf(volumeId) + "/";
+        VirtualMachineMO workerVm=null;
+        VirtualMachineMO vmMo=null;
+        String exportName = UUID.randomUUID().toString();
+
+        try {
+            ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, poolId);
+
+            if (morDs == null) {
+                String msg = "Unable to find volumes's storage pool for copy volume operation";
+                s_logger.error(msg);
+                throw new Exception(msg);
+            }
+
+            vmMo = hyperHost.findVmOnHyperHost(vmName);
+            if (vmMo == null) {
+                // create a dummy worker vm for attaching the volume
+                DatastoreMO dsMo = new DatastoreMO(hyperHost.getContext(), morDs);
+                //restrict VM name to 32 chars, (else snapshot descriptor file name will be truncated to 32 chars of vm name)
+                VirtualMachineConfigSpec vmConfig = new VirtualMachineConfigSpec();
+                vmConfig.setName(workerVmName);
+                vmConfig.setMemoryMB((long) 4);
+                vmConfig.setNumCPUs(1);
+                vmConfig.setGuestId(VirtualMachineGuestOsIdentifier._otherGuest.toString());
+                VirtualMachineFileInfo fileInfo = new VirtualMachineFileInfo();
+                fileInfo.setVmPathName(String.format("[%s]", dsMo.getName()));
+                vmConfig.setFiles(fileInfo);
+
+                // Scsi controller
+                VirtualLsiLogicController scsiController = new VirtualLsiLogicController();
+                scsiController.setSharedBus(VirtualSCSISharing.noSharing);
+                scsiController.setBusNumber(0);
+                scsiController.setKey(1);
+                VirtualDeviceConfigSpec scsiControllerSpec = new VirtualDeviceConfigSpec();
+                scsiControllerSpec.setDevice(scsiController);
+                scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.add);
+                vmConfig.setDeviceChange(new VirtualDeviceConfigSpec[] { scsiControllerSpec });
+	
+                hyperHost.createVm(vmConfig);
+                workerVm = hyperHost.findVmOnHyperHost(workerVmName);
+                if (workerVm == null) {
+                    String msg = "Unable to create worker VM to execute CopyVolumeCommand";
+                    s_logger.error(msg);
+                    throw new Exception(msg);
+                }
+	
+                //attach volume to worker VM
+                String datastoreVolumePath = String.format("[%s] %s.vmdk", dsMo.getName(), volumePath);
+                workerVm.attachDisk(new String[] { datastoreVolumePath }, morDs);
+                vmMo = workerVm;
+            }
+
+            vmMo.createSnapshot(exportName, "Temporary snapshot for copy-volume command", false, false);
+
+            exportVolumeToSecondaryStroage(vmMo, volumePath, secStorageUrl, "volumes/" + volumeFolder, exportName, 
+                hostService.getWorkerName(hyperHost.getContext(), cmd, 1));
+            return new Pair<String, String>(volumeFolder, exportName);
+
+        } finally {
+            vmMo.removeSnapshot(exportName, false);
+            if (workerVm != null) {
+                //detach volume and destroy worker vm
+                workerVm.detachAllDisks();
+                workerVm.destroy();
+            }
+        }
+    }
+
+    private Pair<String, String> copyVolumeFromSecStorage(VmwareHypervisorHost hyperHost, long volumeId, 
+        DatastoreMO dsMo, String secStorageUrl, String exportName) throws Exception {
+
+        String volumeFolder = String.valueOf(volumeId) + "/";
+        String newVolume    = UUID.randomUUID().toString().replaceAll("-", "");
+        restoreVolumeFromSecStorage(hyperHost, dsMo, newVolume, secStorageUrl, "volumes/" + volumeFolder, exportName);
+        
+        return new Pair<String, String>(volumeFolder, newVolume);
+    }
+    
+    private String getOVFFilePath(String srcOVAFileName) {
+        File file = new File(srcOVAFileName);
+        assert(_storage != null);
+        String[] files = _storage.listFiles(file.getParent());
+        if(files != null) {
+            for(String fileName : files) {
+                if(fileName.toLowerCase().endsWith(".ovf")) {
+                    File ovfFile = new File(fileName);
+                    return file.getParent() + File.separator + ovfFile.getName();
+                }
+            }
+        }
+        return null;
+    }
+    
+    private static String getTemplateRelativeDirInSecStorage(long accountId, long templateId) {
+        return "template/tmpl/" + accountId + "/" + templateId;
+    }
+    
+    private static String getSnapshotRelativeDirInSecStorage(long accountId, long volumeId) {
+        return "snapshots/" + accountId + "/" + volumeId;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8197f1f0/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java
new file mode 100644
index 0000000..9f4de50
--- /dev/null
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/manager/VmwareStorageMount.java
@@ -0,0 +1,17 @@
+// Copyright 2012 Citrix Systems, Inc. Licensed under the
+// Apache License, Version 2.0 (the "License"); you may not use this
+// file except in compliance with the License.  Citrix Systems, Inc.
+// reserves all rights not expressly granted by the License.
+// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
+// Automatically generated by addcopyright.py at 04/03/2012
+package com.cloud.hypervisor.vmware.manager;
+
+public interface VmwareStorageMount {
+    String getMountPoint(String storageUrl);
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/8197f1f0/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java
new file mode 100755
index 0000000..f82afb8
--- /dev/null
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareContextFactory.java
@@ -0,0 +1,60 @@
+// Copyright 2012 Citrix Systems, Inc. Licensed under the
+// Apache License, Version 2.0 (the "License"); you may not use this
+// file except in compliance with the License.  Citrix Systems, Inc.
+// reserves all rights not expressly granted by the License.
+// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// 
+// Automatically generated by addcopyright.py at 04/03/2012
+package com.cloud.hypervisor.vmware.resource;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.hypervisor.vmware.manager.VmwareManager;
+import com.cloud.hypervisor.vmware.util.VmwareContext;
+import com.cloud.utils.StringUtils;
+import com.cloud.utils.component.ComponentLocator;
+import com.vmware.apputils.version.ExtendedAppUtil;
+
+public class VmwareContextFactory {
+	
+    private static final Logger s_logger = Logger.getLogger(VmwareContextFactory.class);
+	
+	private static volatile int s_seq = 1;
+	private static VmwareManager s_vmwareMgr;
+	
+	static {
+		// skip certificate check
+		System.setProperty("axis.socketSecureFactory", "org.apache.axis.components.net.SunFakeTrustSocketFactory");
+		
+		ComponentLocator locator = ComponentLocator.getLocator("management-server");
+		s_vmwareMgr = locator.getManager(VmwareManager.class);
+	}
+
+	public static VmwareContext create(String vCenterAddress, String vCenterUserName, String vCenterPassword) throws Exception {
+		assert(vCenterAddress != null);
+		assert(vCenterUserName != null);
+		assert(vCenterPassword != null);
+
+		String serviceUrl = "https://" + vCenterAddress + "/sdk/vimService";
+		String[] params = new String[] {"--url", serviceUrl, "--username", vCenterUserName, "--password", vCenterPassword };
+
+		if(s_logger.isDebugEnabled())
+			s_logger.debug("initialize VmwareContext. url: " + serviceUrl + ", username: " + vCenterUserName + ", password: " + StringUtils.getMaskedPasswordForDisplay(vCenterPassword));
+			
+		ExtendedAppUtil appUtil = ExtendedAppUtil.initialize(vCenterAddress + "-" + s_seq++, params);
+		
+		appUtil.connect();
+		VmwareContext context = new VmwareContext(appUtil, vCenterAddress);
+		context.registerStockObject(VmwareManager.CONTEXT_STOCK_NAME, s_vmwareMgr);
+		
+		context.registerStockObject("serviceconsole", s_vmwareMgr.getServiceConsolePortGroupName());
+		context.registerStockObject("manageportgroup", s_vmwareMgr.getManagementPortGroupName());
+
+		return context;
+	}
+}