cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From edi...@apache.org
Subject [4/7] refactor kvm/vmware resource code
Date Fri, 10 May 2013 16:49:22 GMT
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/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
new file mode 100644
index 0000000..988658d
--- /dev/null
+++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
@@ -0,0 +1,1144 @@
+package com.cloud.storage.resource;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.net.URI;
+import java.rmi.RemoteException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import org.apache.cloudstack.storage.command.AttachAnswer;
+import org.apache.cloudstack.storage.command.AttachCommand;
+import org.apache.cloudstack.storage.command.CopyCmdAnswer;
+import org.apache.cloudstack.storage.command.CopyCommand;
+import org.apache.cloudstack.storage.command.CreateObjectAnswer;
+import org.apache.cloudstack.storage.command.CreateObjectCommand;
+import org.apache.cloudstack.storage.command.DeleteCommand;
+import org.apache.cloudstack.storage.command.DettachCommand;
+import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
+import org.apache.cloudstack.storage.to.SnapshotObjectTO;
+import org.apache.cloudstack.storage.to.TemplateObjectTO;
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.BackupSnapshotAnswer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.ManageSnapshotAnswer;
+import com.cloud.agent.api.ManageSnapshotCommand;
+import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
+import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
+import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
+import com.cloud.agent.api.to.DiskTO;
+import com.cloud.agent.api.to.NfsTO;
+import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.hypervisor.vmware.manager.VmwareHostService;
+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.DatastoreMO;
+import com.cloud.hypervisor.vmware.mo.HostMO;
+import com.cloud.hypervisor.vmware.mo.HypervisorHostHelper;
+import com.cloud.hypervisor.vmware.mo.NetworkDetails;
+import com.cloud.hypervisor.vmware.mo.VirtualMachineMO;
+import com.cloud.hypervisor.vmware.mo.VmwareHypervisorHost;
+import com.cloud.hypervisor.vmware.resource.VmwareResource;
+import com.cloud.hypervisor.vmware.util.VmwareContext;
+import com.cloud.hypervisor.vmware.util.VmwareHelper;
+import com.cloud.serializer.GsonHelper;
+import com.cloud.storage.JavaStorageLayer;
+import com.cloud.storage.StorageLayer;
+import com.cloud.storage.Volume;
+import com.cloud.storage.Storage.ImageFormat;
+import com.cloud.storage.template.VmdkProcessor;
+import com.cloud.utils.Pair;
+import com.cloud.utils.StringUtils;
+import com.cloud.utils.Ternary;
+import com.cloud.utils.script.Script;
+import com.cloud.vm.VirtualMachine.State;
+import com.google.gson.Gson;
+import com.vmware.vim25.ManagedObjectReference;
+import com.vmware.vim25.VirtualDeviceConfigSpec;
+import com.vmware.vim25.VirtualDeviceConfigSpecOperation;
+import com.vmware.vim25.VirtualDisk;
+import com.vmware.vim25.VirtualEthernetCard;
+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 VmwareStorageProcessor implements StorageProcessor {
+	private static final Logger s_logger = Logger.getLogger(VmwareStorageProcessor.class);
+	private VmwareHostService hostService;
+	private boolean _fullCloneFlag;
+	private VmwareStorageMount mountService;
+	private VmwareResource resource;
+	private Integer _timeout;
+	protected Integer _shutdown_waitMs;
+	private final Gson _gson;
+	private final StorageLayer _storage = new JavaStorageLayer();
+	public VmwareStorageProcessor(VmwareHostService hostService, boolean fullCloneFlag, VmwareStorageMount mountService,
+			Integer timeout,
+			VmwareResource resource,
+			Integer shutdownWaitMs) {
+		this.hostService = hostService;
+		this._fullCloneFlag = fullCloneFlag;
+		this.mountService = mountService;
+		this._timeout = timeout;
+		this.resource = resource;
+		this._shutdown_waitMs = shutdownWaitMs;
+		_gson = GsonHelper.getGsonLogger();
+	}
+	
+	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 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);
+		        }
+		    }
+	
+	@Override
+	public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) {
+		DataTO srcData = cmd.getSrcTO();
+		TemplateObjectTO template = (TemplateObjectTO)srcData;
+		DataStoreTO srcStore = srcData.getDataStore();
+		if (!(srcStore instanceof NfsTO)) {
+			return new CopyCmdAnswer("unsupported protocol");
+		}
+		NfsTO nfsImageStore = (NfsTO)srcStore;
+		DataTO destData = cmd.getDestTO();
+		DataStoreTO destStore = destData.getDataStore();
+		PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)destStore;
+		String secondaryStorageUrl = nfsImageStore.getUrl();
+		assert (secondaryStorageUrl != null);
+
+		String templateUrl = secondaryStorageUrl + File.separator + srcData.getPath();
+
+		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 = template.getName();
+			}
+		} else {
+			mountPoint = templateUrl.substring(secondaryStorageUrl.length() + 1);
+			if (!mountPoint.endsWith("/")) {
+				mountPoint = mountPoint + "/";
+			}
+			templateName = template.getName();
+		}
+
+		VmwareContext context = hostService.getServiceContext(cmd);
+		try {
+			VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+
+			String templateUuidName = UUID.nameUUIDFromBytes((templateName + "@" + primaryStore.getUuid() + "-" + hyperHost.getMor().getValue()).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, primaryStore.getUuid());
+				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");
+			}
+
+			TemplateObjectTO newTemplate = new TemplateObjectTO();
+			newTemplate.setPath(templateUuidName);
+			return new CopyCmdAnswer(newTemplate);
+		} 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 CopyCmdAnswer(msg);
+		}
+	}
+	private boolean createVMLinkedClone(VirtualMachineMO vmTemplate, DatacenterMO dcMo, DatastoreMO dsMo,
+            String vmdkName, ManagedObjectReference morDatastore, ManagedObjectReference morPool) throws Exception {
+
+        ManagedObjectReference morBaseSnapshot = vmTemplate.getSnapshotMor("cloud.template.base");
+        if (morBaseSnapshot == null) {
+            String msg = "Unable to find template base snapshot, invalid template";
+            s_logger.error(msg);
+            throw new Exception(msg);
+        }
+
+        if(dsMo.folderExists(String.format("[%s]", dsMo.getName()), vmdkName))
+            dsMo.deleteFile(String.format("[%s] %s/", dsMo.getName(), vmdkName), dcMo.getMor(), false);
+
+        s_logger.info("creating linked clone from template");
+        if (!vmTemplate.createLinkedClone(vmdkName, morBaseSnapshot, dcMo.getVmFolder(), morPool, morDatastore)) {
+            String msg = "Unable to clone from the template";
+            s_logger.error(msg);
+            throw new Exception(msg);
+        }
+
+        // we can't rely on un-offical API (VirtualMachineMO.moveAllVmDiskFiles() any more, use hard-coded disk names that we know
+        // to move files
+        s_logger.info("Move volume out of volume-wrapper VM ");
+        dsMo.moveDatastoreFile(String.format("[%s] %s/%s.vmdk", dsMo.getName(), vmdkName, vmdkName),
+                dcMo.getMor(), dsMo.getMor(),
+                String.format("[%s] %s.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true);
+
+        dsMo.moveDatastoreFile(String.format("[%s] %s/%s-delta.vmdk", dsMo.getName(), vmdkName, vmdkName),
+                dcMo.getMor(), dsMo.getMor(),
+                String.format("[%s] %s-delta.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true);
+
+        return true;
+    }
+
+	private boolean createVMFullClone(VirtualMachineMO vmTemplate, DatacenterMO dcMo, DatastoreMO dsMo,
+            String vmdkName, ManagedObjectReference morDatastore, ManagedObjectReference morPool) throws Exception {
+
+        if(dsMo.folderExists(String.format("[%s]", dsMo.getName()), vmdkName))
+            dsMo.deleteFile(String.format("[%s] %s/", dsMo.getName(), vmdkName), dcMo.getMor(), false);
+
+        s_logger.info("creating full clone from template");
+        if (!vmTemplate.createFullClone(vmdkName, dcMo.getVmFolder(), morPool, morDatastore)) {
+            String msg = "Unable to create full clone from the template";
+            s_logger.error(msg);
+            throw new Exception(msg);
+        }
+
+        // we can't rely on un-offical API (VirtualMachineMO.moveAllVmDiskFiles() any more, use hard-coded disk names that we know
+        // to move files
+        s_logger.info("Move volume out of volume-wrapper VM ");
+        dsMo.moveDatastoreFile(String.format("[%s] %s/%s.vmdk", dsMo.getName(), vmdkName, vmdkName),
+                dcMo.getMor(), dsMo.getMor(),
+                String.format("[%s] %s.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true);
+
+        dsMo.moveDatastoreFile(String.format("[%s] %s/%s-flat.vmdk", dsMo.getName(), vmdkName, vmdkName),
+                dcMo.getMor(), dsMo.getMor(),
+                String.format("[%s] %s-flat.vmdk", dsMo.getName(), vmdkName), dcMo.getMor(), true);
+
+        return true;
+    }
+
+	@Override
+	public Answer cloneVolumeFromBaseTemplate(CopyCommand cmd) {
+		DataTO srcData = cmd.getSrcTO();
+		TemplateObjectTO template = (TemplateObjectTO)srcData;
+		DataStoreTO imageStore = template.getDataStore();
+		DataTO destData = cmd.getDestTO();
+		VolumeObjectTO volume = (VolumeObjectTO)destData;
+		PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volume.getDataStore();
+		if (imageStore != null && !(imageStore instanceof NfsTO)) {
+			return new CopyCmdAnswer("unsupported protocol");
+		}
+		NfsTO nfsImageStore = (NfsTO)imageStore;
+		
+		try {
+			VmwareContext context = this.hostService.getServiceContext(null);
+			VmwareHypervisorHost hyperHost = this.hostService.getHyperHost(context, null);
+			DatacenterMO dcMo = new DatacenterMO(context, hyperHost.getHyperHostDatacenter());
+			VirtualMachineMO vmMo = null;
+			ManagedObjectReference morDatastore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, primaryStore.getUuid());
+			if (morDatastore == null)
+				throw new Exception("Unable to find datastore in vSphere");
+
+			DatastoreMO dsMo = new DatastoreMO(context, morDatastore);
+
+
+			// attach volume id to make the name unique
+			String vmdkName = volume.getName() + "-" + volume.getId();
+			if (nfsImageStore == null) {
+				// create a root volume for blank VM
+				String dummyVmName = this.hostService.getWorkerName(context, cmd, 0);
+
+				try {
+					vmMo = prepareVolumeHostDummyVm(hyperHost, dsMo, dummyVmName);
+					if (vmMo == null) {
+						throw new Exception("Unable to create a dummy VM for volume creation");
+					}
+
+					String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), vmdkName);
+					synchronized (this) {
+						s_logger.info("Delete file if exists in datastore to clear the way for creating the volume. file: " + volumeDatastorePath);
+						VmwareHelper.deleteVolumeVmdkFiles(dsMo, vmdkName, dcMo);
+						vmMo.createDisk(volumeDatastorePath, (int) (volume.getSize() / (1024L * 1024L)), morDatastore, -1);
+						vmMo.detachDisk(volumeDatastorePath, false);
+					}
+
+					VolumeObjectTO newVol = new VolumeObjectTO();
+					newVol.setPath(vmdkName);
+					return new CopyCmdAnswer(newVol);
+				} finally {
+					vmMo.detachAllDisks();
+
+					s_logger.info("Destroy dummy VM after volume creation");
+					vmMo.destroy();
+				}
+			} else {
+				String templateUrl = nfsImageStore.getUrl() + File.separator + template.getPath();
+				VirtualMachineMO vmTemplate = VmwareHelper.pickOneVmOnRunningHost(dcMo.findVmByNameAndLabel(templateUrl), true);
+				if (vmTemplate == null) {
+					s_logger.warn("Template host in vSphere is not in connected state, request template reload");
+					return new CopyCmdAnswer("Template host in vSphere is not in connected state, request template reload");
+				}
+
+				ManagedObjectReference morPool = hyperHost.getHyperHostOwnerResourcePool();
+				ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
+				//createVMLinkedClone(vmTemplate, dcMo, dsMo, vmdkName, morDatastore, morPool);
+				if (!_fullCloneFlag) {
+					createVMLinkedClone(vmTemplate, dcMo, dsMo, vmdkName, morDatastore, morPool);
+				} else {
+					createVMFullClone(vmTemplate, dcMo, dsMo, vmdkName, morDatastore, morPool);
+				}
+
+				vmMo = new ClusterMO(context, morCluster).findVmOnHyperHost(vmdkName);
+				assert (vmMo != null);
+
+				s_logger.info("detach disks from volume-wrapper VM " + vmdkName);
+				vmMo.detachAllDisks();
+
+				s_logger.info("destroy volume-wrapper VM " + vmdkName);
+				vmMo.destroy();
+
+				String srcFile = String.format("[%s] %s/", dsMo.getName(), vmdkName);
+				dsMo.deleteFile(srcFile, dcMo.getMor(), true);
+				VolumeObjectTO newVol = new VolumeObjectTO();
+				newVol.setPath(vmdkName);
+				return new CopyCmdAnswer(newVol);
+			}
+		} catch (Throwable e) {
+			if (e instanceof RemoteException) {
+				s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context");
+				this.hostService.invalidateServiceContext(null);
+			}
+
+			String msg = "CreateCommand failed due to " + VmwareHelper.getExceptionMessage(e);
+			s_logger.error(msg, e);
+			return new CopyCmdAnswer(e.toString());
+		}
+	}
+	
+
+	@Override
+	public Answer copyVolumeFromImageCacheToPrimary(CopyCommand cmd) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public Answer copyVolumeFromPrimaryToSecondary(CopyCommand cmd) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+	
+	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 Ternary<String, Long, Long> createTemplateFromVolume(VirtualMachineMO vmMo, String installPath, long templateId, String templateUniqueName,
+	        String secStorageUrl, String volumePath, String workerVmName) throws Exception {
+
+	        String secondaryMountPoint = mountService.getMountPoint(secStorageUrl);
+	        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);
+	        }
+	    }
+
+	@Override
+	public Answer createTemplateFromVolume(CopyCommand cmd) {
+		VolumeObjectTO volume = (VolumeObjectTO)cmd.getSrcTO();
+		PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volume.getDataStore();
+		TemplateObjectTO template = (TemplateObjectTO)cmd.getDestTO();
+		DataStoreTO imageStore = template.getDataStore();
+		
+		if (!(imageStore instanceof NfsTO)) {
+			return new CopyCmdAnswer("unsupported protocol");
+		}
+		NfsTO nfsImageStore = (NfsTO)imageStore;
+		String secondaryStoragePoolURL = nfsImageStore.getUrl();
+		String volumePath = volume.getPath();
+
+		String details = null;
+
+		VmwareContext context = hostService.getServiceContext(cmd);
+		try {
+			VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+
+			VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(volume.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(volume.getVmName());
+
+				if(vmMo == null) {
+					String msg = "Unable to find the owner VM for volume operation. vm: " + volume.getVmName();
+					s_logger.error(msg);
+					throw new Exception(msg);
+				}
+			}
+
+			Ternary<String, Long, Long> result = createTemplateFromVolume(vmMo,
+					template.getPath(), template.getId(), template.getName(),
+					secondaryStoragePoolURL, volumePath,
+					hostService.getWorkerName(context, cmd, 0));
+
+			TemplateObjectTO newTemplate = new TemplateObjectTO();
+			newTemplate.setPath(template.getName());
+			newTemplate.setFormat(ImageFormat.OVA);
+			return new CopyCmdAnswer(newTemplate);
+
+		} catch (Throwable e) {
+			if (e instanceof RemoteException) {
+				hostService.invalidateServiceContext(context);
+			}
+
+			s_logger.error("Unexpecpted exception ", e);
+
+			details = "CreatePrivateTemplateFromVolumeCommand exception: " + StringUtils.getExceptionStackInfo(e);
+			return new CopyCmdAnswer(details);
+		}
+	}
+	
+	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 + "/" + exportName;
+	        
+	        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 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,
+	        		installPath, backupUuid, workerVmName);
+	        return backupUuid + "/" + backupUuid;
+	    }
+	@Override
+	public Answer backupSnasphot(CopyCommand cmd) {
+		SnapshotObjectTO srcSnapshot = (SnapshotObjectTO)cmd.getSrcTO();
+		PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)srcSnapshot.getDataStore();
+		SnapshotObjectTO destSnapshot = (SnapshotObjectTO)cmd.getDestTO();
+		DataStoreTO destStore = destSnapshot.getDataStore();
+		if (!(destStore instanceof NfsTO)) {
+			return new CopyCmdAnswer("unsupported protocol");
+		}
+
+		NfsTO destNfsStore = (NfsTO)destStore;
+
+
+		String secondaryStorageUrl = destNfsStore.getUrl();
+		String snapshotUuid = srcSnapshot.getPath();
+		String prevSnapshotUuid = srcSnapshot.getParentSnapshotPath();
+		String prevBackupUuid = destSnapshot.getParentSnapshotPath();
+		VirtualMachineMO workerVm=null;
+		String workerVMName = null;
+		String volumePath = srcSnapshot.getVolume().getPath();
+		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;
+		String vmName = srcSnapshot.getVmName();
+		try {
+			VmwareHypervisorHost hyperHost = hostService.getHyperHost(context, cmd);
+			morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, primaryStore.getUuid());
+
+			try {
+				vmMo = hyperHost.findVmOnHyperHost(vmName);
+				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(vmName);
+					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.OTHER_GUEST.value(), 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 " + 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,
+						hostService.getWorkerName(context, cmd, 1));
+
+				success = (snapshotBackupUuid != null);
+				if (success) {
+					details = "Successfully backedUp the snapshotUuid: " + snapshotUuid + " to secondary storage.";
+					return new CopyCmdAnswer(details);
+				} else {
+					SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
+					newSnapshot.setPath(snapshotBackupUuid);
+					return new CopyCmdAnswer(newSnapshot);
+				}
+			} finally {
+				if(vmMo != null){
+					ManagedObjectReference snapshotMor = vmMo.getSnapshotMor(snapshotUuid);
+					if (snapshotMor != null){
+						vmMo.removeSnapshot(snapshotUuid, false);
+					}
+				}
+
+				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 CopyCmdAnswer(details);
+		}
+	}
+
+	@Override
+	public Answer attachIso(AttachCommand cmd) {
+		return this.attachIso(cmd.getDisk(), true, cmd.getVmName());
+	}
+
+	@Override
+	public Answer attachVolume(AttachCommand cmd) {
+		return this.attachVolume(cmd, cmd.getDisk(), true, cmd.getVmName());
+	}
+	
+	private Answer attachVolume(Command cmd, DiskTO disk, boolean isAttach, String vmName) {
+
+		VolumeObjectTO volumeTO = (VolumeObjectTO)disk.getData();
+		PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volumeTO.getDataStore();
+		try {
+			VmwareHypervisorHost hyperHost = this.hostService.getHyperHost(this.hostService.getServiceContext(null), null);
+			VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmName);
+			if (vmMo == null) {
+				String msg = "Unable to find the VM to execute AttachVolumeCommand, vmName: " + vmName;
+				s_logger.error(msg);
+				throw new Exception(msg);
+			}
+
+			ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, primaryStore.getUuid());
+			if (morDs == null) {
+				String msg = "Unable to find the mounted datastore to execute AttachVolumeCommand, vmName: " + vmName;
+				s_logger.error(msg);
+				throw new Exception(msg);
+			}
+
+			DatastoreMO dsMo = new DatastoreMO(this.hostService.getServiceContext(null), morDs);
+			String datastoreVolumePath = String.format("[%s] %s.vmdk", dsMo.getName(), volumeTO.getPath());
+
+			AttachAnswer answer = new AttachAnswer(disk);
+			if (isAttach) {
+				vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs);
+			} else {
+				vmMo.removeAllSnapshots();
+				vmMo.detachDisk(datastoreVolumePath, false);
+			}
+
+			return answer;
+		} catch (Throwable e) {
+			if (e instanceof RemoteException) {
+				s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context");
+				this.hostService.invalidateServiceContext(null);
+			}
+
+			String msg = "AttachVolumeCommand failed due to " + VmwareHelper.getExceptionMessage(e);
+			s_logger.error(msg, e);
+			return new AttachAnswer(msg);
+		}
+	}
+	
+	  private static String getSecondaryDatastoreUUID(String storeUrl) {
+	        return UUID.nameUUIDFromBytes(storeUrl.getBytes()).toString();
+	    }
+
+	public synchronized ManagedObjectReference prepareSecondaryDatastoreOnHost(String storeUrl) throws Exception {
+        String storeName = getSecondaryDatastoreUUID(storeUrl);
+        URI uri = new URI(storeUrl);
+
+        VmwareHypervisorHost hyperHost = this.hostService.getHyperHost(this.hostService.getServiceContext(null), null);
+        ManagedObjectReference morDatastore = hyperHost.mountDatastore(false, uri.getHost(), 0, uri.getPath(), storeName.replace("-", ""));
+
+        if (morDatastore == null)
+            throw new Exception("Unable to mount secondary storage on host. storeUrl: " + storeUrl);
+
+        return morDatastore;
+    }
+	private Answer attachIso(DiskTO disk, boolean isAttach, String vmName) {
+		
+
+	        try {
+	            VmwareHypervisorHost hyperHost = this.hostService.getHyperHost(this.hostService.getServiceContext(null), null);
+	            VirtualMachineMO vmMo = hyperHost.findVmOnHyperHost(vmName);
+	            if (vmMo == null) {
+	                String msg = "Unable to find VM in vSphere to execute AttachIsoCommand, vmName: " + vmName;
+	                s_logger.error(msg);
+	                throw new Exception(msg);
+	            }
+	            TemplateObjectTO iso = (TemplateObjectTO)disk.getData();
+	            NfsTO nfsImageStore = (NfsTO)iso.getDataStore();
+	            String storeUrl = nfsImageStore.getUrl();
+	            if (storeUrl == null) {
+	                if (!iso.getName().equalsIgnoreCase("vmware-tools.iso")) {
+	                    String msg = "ISO store root url is not found in AttachIsoCommand";
+	                    s_logger.error(msg);
+	                    throw new Exception(msg);
+	                } else {
+	                    if (isAttach) {
+	                        vmMo.mountToolsInstaller();
+	                    } else {
+	                        try{
+	                            vmMo.unmountToolsInstaller();
+	                        }catch(Throwable e){
+	                            vmMo.detachIso(null);
+	                        }
+	                    }
+
+	                    return new AttachAnswer(disk);
+	                }
+	            }
+
+	            ManagedObjectReference morSecondaryDs = prepareSecondaryDatastoreOnHost(storeUrl);
+	            String isoPath = nfsImageStore.getUrl() + File.separator + iso.getPath();
+	            if (!isoPath.startsWith(storeUrl)) {
+	                assert (false);
+	                String msg = "ISO path does not start with the secondary storage root";
+	                s_logger.error(msg);
+	                throw new Exception(msg);
+	            }
+
+	            int isoNameStartPos = isoPath.lastIndexOf('/');
+	            String isoFileName = isoPath.substring(isoNameStartPos + 1);
+	            String isoStorePathFromRoot = isoPath.substring(storeUrl.length(), isoNameStartPos);
+
+	            // TODO, check if iso is already attached, or if there is a previous
+	            // attachment
+	            DatastoreMO secondaryDsMo = new DatastoreMO(this.hostService.getServiceContext(null), morSecondaryDs);
+	            String storeName = secondaryDsMo.getName();
+	            String isoDatastorePath = String.format("[%s] %s%s", storeName, isoStorePathFromRoot, isoFileName);
+
+	            if (isAttach) {
+	                vmMo.attachIso(isoDatastorePath, morSecondaryDs, true, false);
+	            } else {
+	                vmMo.detachIso(isoDatastorePath);
+	            }
+
+	            return new AttachAnswer(disk);
+	        } catch (Throwable e) {
+	            if (e instanceof RemoteException) {
+	                s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context");
+	                this.hostService.invalidateServiceContext(null);
+	            }
+
+	            if(isAttach) {
+	                String msg = "AttachIsoCommand(attach) failed due to " + VmwareHelper.getExceptionMessage(e);
+	                s_logger.error(msg, e);
+	                return new AttachAnswer(msg);
+	            } else {
+	                String msg = "AttachIsoCommand(detach) failed due to " + VmwareHelper.getExceptionMessage(e);
+	                s_logger.warn(msg, e);
+	                return new AttachAnswer(msg);
+	            }
+	        }
+	}
+	@Override
+	public Answer dettachIso(DettachCommand cmd) {
+		return this.attachIso(cmd.getDisk(), false, cmd.getVmName());
+	}
+
+	@Override
+	public Answer dettachVolume(DettachCommand cmd) {
+		return this.attachVolume(cmd, cmd.getDisk(), false, cmd.getVmName());
+	}
+
+	protected VirtualMachineMO prepareVolumeHostDummyVm(VmwareHypervisorHost hyperHost, DatastoreMO dsMo, String vmName) throws Exception {
+        assert (hyperHost != null);
+
+        VirtualMachineMO vmMo = null;
+        VirtualMachineConfigSpec vmConfig = new VirtualMachineConfigSpec();
+        vmConfig.setName(vmName);
+        vmConfig.setMemoryMB((long) 4); // vmware request minimum of 4 MB
+        vmConfig.setNumCPUs(1);
+        vmConfig.setGuestId(VirtualMachineGuestOsIdentifier.OTHER_GUEST.value());
+        VirtualMachineFileInfo fileInfo = new VirtualMachineFileInfo();
+        fileInfo.setVmPathName(String.format("[%s]", dsMo.getName()));
+        vmConfig.setFiles(fileInfo);
+
+        // Scsi controller
+        VirtualLsiLogicController scsiController = new VirtualLsiLogicController();
+        scsiController.setSharedBus(VirtualSCSISharing.NO_SHARING);
+        scsiController.setBusNumber(0);
+        scsiController.setKey(1);
+        VirtualDeviceConfigSpec scsiControllerSpec = new VirtualDeviceConfigSpec();
+        scsiControllerSpec.setDevice(scsiController);
+        scsiControllerSpec.setOperation(VirtualDeviceConfigSpecOperation.ADD);
+
+        vmConfig.getDeviceChange().add(scsiControllerSpec );
+        hyperHost.createVm(vmConfig);
+        vmMo = hyperHost.findVmOnHyperHost(vmName);
+        return vmMo;
+    }
+	@Override
+	public Answer createVolume(CreateObjectCommand cmd) {
+
+		VolumeObjectTO volume = (VolumeObjectTO)cmd.getData();
+		PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volume.getDataStore();
+       
+		try {
+			VmwareContext context = this.hostService.getServiceContext(null);
+			VmwareHypervisorHost hyperHost = this.hostService.getHyperHost(context, null);
+			DatacenterMO dcMo = new DatacenterMO(context, hyperHost.getHyperHostDatacenter());
+
+			ManagedObjectReference morDatastore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, primaryStore.getUuid());
+			if (morDatastore == null)
+				throw new Exception("Unable to find datastore in vSphere");
+
+			DatastoreMO dsMo = new DatastoreMO(context, morDatastore);
+			// create data volume
+			VirtualMachineMO vmMo = null;
+			String volumeUuid = UUID.randomUUID().toString().replace("-", "");
+			String volumeDatastorePath = String.format("[%s] %s.vmdk", dsMo.getName(), volumeUuid);
+			String dummyVmName = this.hostService.getWorkerName(context, cmd, 0);
+			try {
+				vmMo = prepareVolumeHostDummyVm(hyperHost, dsMo, dummyVmName);
+				if (vmMo == null) {
+					throw new Exception("Unable to create a dummy VM for volume creation");
+				}
+
+				synchronized (this) {
+					// s_logger.info("Delete file if exists in datastore to clear the way for creating the volume. file: " + volumeDatastorePath);
+					VmwareHelper.deleteVolumeVmdkFiles(dsMo, volumeUuid.toString(), dcMo);
+
+					vmMo.createDisk(volumeDatastorePath, (int) (volume.getSize() / (1024L * 1024L)), morDatastore, vmMo.getScsiDeviceControllerKey());
+					vmMo.detachDisk(volumeDatastorePath, false);
+				}
+
+				VolumeObjectTO newVol = new VolumeObjectTO();
+				newVol.setPath(volumeUuid);
+				return new CreateObjectAnswer(newVol);
+			} finally {
+				s_logger.info("Destroy dummy VM after volume creation");
+				vmMo.detachAllDisks();
+				vmMo.destroy();
+			}
+
+		} catch (Throwable e) {
+			if (e instanceof RemoteException) {
+				s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context");
+				this.hostService.invalidateServiceContext(null);
+			}
+
+			String msg = "CreateCommand failed due to " + VmwareHelper.getExceptionMessage(e);
+			s_logger.error(msg, e);
+			return new CreateObjectAnswer(e.toString());
+		}
+	}
+
+	@Override
+	public Answer createSnapshot(CreateObjectCommand cmd) {
+		// snapshot operation (create or destroy) is handled inside BackupSnapshotCommand(), we just fake
+		// a success return here
+		String snapshotUUID = UUID.randomUUID().toString();
+		SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
+		newSnapshot.setPath(snapshotUUID);
+		return new CreateObjectAnswer(newSnapshot);
+	}
+
+	@Override
+	public Answer deleteVolume(DeleteCommand cmd) {
+		if (s_logger.isInfoEnabled()) {
+			s_logger.info("Executing resource DestroyCommand: " + _gson.toJson(cmd));
+		}
+
+		/*
+		 * DestroyCommand content example
+		 *
+		 * {"volume": {"id":5,"name":"Volume1", "mountPoint":"/export/home/kelven/vmware-test/primary",
+		 * "path":"6bb8762f-c34c-453c-8e03-26cc246ceec4", "size":0,"type":"DATADISK","resourceType":
+		 * "STORAGE_POOL","storagePoolType":"NetworkFilesystem", "poolId":0,"deviceId":0 } }
+		 *
+		 * {"volume": {"id":1, "name":"i-2-1-KY-ROOT", "mountPoint":"/export/home/kelven/vmware-test/primary",
+		 * "path":"i-2-1-KY-ROOT","size":0,"type":"ROOT", "resourceType":"STORAGE_POOL", "storagePoolType":"NetworkFilesystem",
+		 * "poolId":0,"deviceId":0 } }
+		 */
+
+		try {
+			VmwareContext context = this.hostService.getServiceContext(null);
+			VmwareHypervisorHost hyperHost = this.hostService.getHyperHost(context, null);
+			VolumeObjectTO vol = (VolumeObjectTO)cmd.getData();
+			PrimaryDataStoreTO store = (PrimaryDataStoreTO)vol.getDataStore();
+
+			ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, store.getUuid());
+			if (morDs == null) {
+				String msg = "Unable to find datastore based on volume mount point " + store.getPath();
+				s_logger.error(msg);
+				throw new Exception(msg);
+			}
+
+			DatastoreMO dsMo = new DatastoreMO(context, morDs);
+
+			ManagedObjectReference morDc = hyperHost.getHyperHostDatacenter();
+			ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
+			ClusterMO clusterMo = new ClusterMO(context, morCluster);
+
+			if (vol.getVolumeType() == Volume.Type.ROOT) {
+				String vmName = vol.getVmName();
+				if (vmName != null) {
+					VirtualMachineMO vmMo = clusterMo.findVmOnHyperHost(vmName);
+					if (vmMo != null) {
+						if (s_logger.isInfoEnabled()) {
+							s_logger.info("Destroy root volume and VM itself. vmName " + vmName);
+						}
+
+						HostMO hostMo = vmMo.getRunningHost();
+						List<NetworkDetails> networks = vmMo.getNetworksWithDetails();
+
+						// tear down all devices first before we destroy the VM to avoid accidently delete disk backing files
+						if (this.resource.getVmState(vmMo) != State.Stopped)
+							vmMo.safePowerOff(_shutdown_waitMs);
+						vmMo.tearDownDevices(new Class<?>[] { VirtualDisk.class, VirtualEthernetCard.class });
+						vmMo.destroy();
+
+						for (NetworkDetails netDetails : networks) {
+							if (netDetails.getGCTag() != null && netDetails.getGCTag().equalsIgnoreCase("true")) {
+								if (netDetails.getVMMorsOnNetwork() == null || netDetails.getVMMorsOnNetwork().length == 1) {
+									this.resource.cleanupNetwork(hostMo, netDetails);
+								}
+							}
+						}
+					}
+
+					if (s_logger.isInfoEnabled())
+						s_logger.info("Destroy volume by original name: " + vol.getPath() + ".vmdk");
+					dsMo.deleteFile(vol.getPath() + ".vmdk", morDc, true);
+
+					// root volume may be created via linked-clone, delete the delta disk as well
+					if (_fullCloneFlag) {
+						if (s_logger.isInfoEnabled()) {
+							s_logger.info("Destroy volume by derived name: " + vol.getPath() + "-flat.vmdk");
+						}
+						dsMo.deleteFile(vol.getPath() + "-flat.vmdk", morDc, true);
+					} else {
+						if (s_logger.isInfoEnabled()) {
+							s_logger.info("Destroy volume by derived name: " + vol.getPath() + "-delta.vmdk");
+						}
+						dsMo.deleteFile(vol.getPath() + "-delta.vmdk", morDc, true);
+					}
+					return new Answer(cmd, true, "Success");
+				}
+
+				if (s_logger.isInfoEnabled()) {
+					s_logger.info("Destroy root volume directly from datastore");
+				}
+			} else {
+				// evitTemplate will be converted into DestroyCommand, test if we are running in this case
+				VirtualMachineMO vmMo = clusterMo.findVmOnHyperHost(vol.getPath());
+				if (vmMo != null) {
+					if (s_logger.isInfoEnabled())
+						s_logger.info("Destroy template volume " + vol.getPath());
+
+					vmMo.destroy();
+					return new Answer(cmd, true, "Success");
+				}
+			}
+
+			String chainInfo = vol.getChainInfo();
+			if (chainInfo != null && !chainInfo.isEmpty()) {
+				s_logger.info("Destroy volume by chain info: " + chainInfo);
+				String[] diskChain = _gson.fromJson(chainInfo, String[].class);
+
+				if (diskChain != null && diskChain.length > 0) {
+					for (String backingName : diskChain) {
+						if (s_logger.isInfoEnabled()) {
+							s_logger.info("Delete volume backing file: " + backingName);
+						}
+						dsMo.deleteFile(backingName, morDc, true);
+					}
+				} else {
+					if (s_logger.isInfoEnabled()) {
+						s_logger.info("Empty disk chain info, fall back to try to delete by original backing file name");
+					}
+					dsMo.deleteFile(vol.getPath() + ".vmdk", morDc, true);
+
+					if (s_logger.isInfoEnabled()) {
+						s_logger.info("Destroy volume by derived name: " + vol.getPath() + "-flat.vmdk");
+					}
+					dsMo.deleteFile(vol.getPath() + "-flat.vmdk", morDc, true);
+				}
+			} else {
+				if (s_logger.isInfoEnabled()) {
+					s_logger.info("Destroy volume by original name: " + vol.getPath() + ".vmdk");
+				}
+				dsMo.deleteFile(vol.getPath() + ".vmdk", morDc, true);
+
+				if (s_logger.isInfoEnabled()) {
+					s_logger.info("Destroy volume by derived name: " + vol.getPath() + "-flat.vmdk");
+				}
+				dsMo.deleteFile(vol.getPath() + "-flat.vmdk", morDc, true);
+			}
+
+			return new Answer(cmd, true, "Success");
+		} catch (Throwable e) {
+			if (e instanceof RemoteException) {
+				s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context");
+				this.hostService.invalidateServiceContext(null);
+			}
+
+			String msg = "DestroyCommand failed due to " + VmwareHelper.getExceptionMessage(e);
+			s_logger.error(msg, e);
+			return new Answer(cmd, false, msg);
+		}
+	}
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
index c88a746..701adbe 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/CitrixResourceBase.java
@@ -58,6 +58,8 @@ import com.cloud.agent.api.to.*;
 import com.cloud.network.rules.FirewallRule;
 
 import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
+import org.apache.cloudstack.storage.to.TemplateObjectTO;
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
 import org.apache.log4j.Logger;
 import org.apache.xmlrpc.XmlRpcException;
 import org.w3c.dom.Document;
@@ -234,6 +236,8 @@ import com.cloud.storage.Storage.ImageFormat;
 import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.storage.Volume;
 import com.cloud.storage.VolumeVO;
+import com.cloud.storage.resource.StorageSubsystemCommandHandler;
+import com.cloud.storage.resource.StorageSubsystemCommandHandlerBase;
 import com.cloud.storage.template.TemplateProp;
 import com.cloud.template.VirtualMachineTemplate.BootloaderType;
 import com.cloud.utils.NumbersUtil;
@@ -334,7 +338,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
     protected boolean _canBridgeFirewall = false;
     protected boolean _isOvs = false;
     protected List<VIF> _tmpDom0Vif = new ArrayList<VIF>();
-    protected XenServerStorageResource storageResource;
+    protected StorageSubsystemCommandHandler storageHandler;
     protected int _maxNics = 7;
 
     public enum SRType {
@@ -594,7 +598,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         } else if (clazz == CheckS2SVpnConnectionsCommand.class) {
             return execute((CheckS2SVpnConnectionsCommand) cmd);
         } else if (cmd instanceof StorageSubSystemCommand) {
-            return this.storageResource.handleStorageCommands((StorageSubSystemCommand)cmd);
+            return this.storageHandler.handleStorageCommands((StorageSubSystemCommand)cmd);
         } else if (clazz == CreateVMSnapshotCommand.class) {
             return execute((CreateVMSnapshotCommand)cmd);
         } else if (clazz == DeleteVMSnapshotCommand.class) {
@@ -1089,31 +1093,42 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
         }
     }
 
-    protected VDI mount(Connection conn, String vmName, VolumeTO volume) throws XmlRpcException, XenAPIException {
-        if (volume.getType() == Volume.Type.ISO) {
-            String isopath = volume.getPath();
-            if (isopath == null) {
+    protected VDI mount(Connection conn, String vmName, DiskTO volume) throws XmlRpcException, XenAPIException {
+        DataTO data = volume.getData();
+        Volume.Type type = volume.getType();
+        if (type == Volume.Type.ISO) {
+            TemplateObjectTO iso = (TemplateObjectTO)data;
+            DataStoreTO store = iso.getDataStore();
+            
+            if (store == null) {
+                //It's a fake iso
                 return null;
             }
-            if (isopath.startsWith("xs-tools")) {
+            
+            //corer case, xenserver pv driver iso
+            String templateName = iso.getName();
+            if (templateName.startsWith("xs-tools")) {
                 try {
-                    Set<VDI> vdis = VDI.getByNameLabel(conn, isopath);
+                    Set<VDI> vdis = VDI.getByNameLabel(conn, templateName);
                     if (vdis.isEmpty()) {
-                        throw new CloudRuntimeException("Could not find ISO with URL: " + isopath);
+                        throw new CloudRuntimeException("Could not find ISO with URL: " + templateName);
                     }
                     return vdis.iterator().next();
-
                 } catch (XenAPIException e) {
-                    throw new CloudRuntimeException("Unable to get pv iso: " + isopath + " due to " + e.toString());
+                    throw new CloudRuntimeException("Unable to get pv iso: " + templateName + " due to " + e.toString());
                 } catch (Exception e) {
-                    throw new CloudRuntimeException("Unable to get pv iso: " + isopath + " due to " + e.toString());
+                    throw new CloudRuntimeException("Unable to get pv iso: " + templateName + " due to " + e.toString());
                 }
             }
+            
+            if (!(store instanceof NfsTO)) {
+                throw new CloudRuntimeException("only support mount iso on nfs");
+            }
+            NfsTO nfsStore = (NfsTO)store;
+            String isoPath = nfsStore.getUrl() + File.separator + iso.getPath();
+            int index = isoPath.lastIndexOf("/");
 
-
-            int index = isopath.lastIndexOf("/");
-
-            String mountpoint = isopath.substring(0, index);
+            String mountpoint = isoPath.substring(0, index);
             URI uri;
             try {
                 uri = new URI(mountpoint);
@@ -1122,20 +1137,21 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
             }
             SR isoSr = createIsoSRbyURI(conn, uri, vmName, false);
 
-            String isoname = isopath.substring(index + 1);
+            String isoname = isoPath.substring(index + 1);
 
             VDI isoVdi = getVDIbyLocationandSR(conn, isoname, isoSr);
 
             if (isoVdi == null) {
-                throw new CloudRuntimeException("Unable to find ISO " + volume.getPath());
+                throw new CloudRuntimeException("Unable to find ISO " + isoPath);
             }
             return isoVdi;
         } else {
-            return VDI.getByUuid(conn, volume.getPath());
+            VolumeObjectTO vol = (VolumeObjectTO)data;
+            return VDI.getByUuid(conn,vol.getPath());
         }
     }
 
-    protected VBD createVbd(Connection conn, VolumeTO volume, String vmName, VM vm, BootloaderType bootLoaderType) throws XmlRpcException, XenAPIException {
+    protected VBD createVbd(Connection conn, DiskTO volume, String vmName, VM vm, BootloaderType bootLoaderType) throws XmlRpcException, XenAPIException {
         Volume.Type type = volume.getType();
 
         VDI vdi = mount(conn, vmName, volume);
@@ -1153,7 +1169,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
             vbdr.bootable = true;
         }
 
-        vbdr.userdevice = Long.toString(volume.getDeviceId());
+        vbdr.userdevice = Long.toString(volume.getDiskSeq());
         if (volume.getType() == Volume.Type.ISO) {
             vbdr.mode = Types.VbdMode.RO;
             vbdr.type = Types.VbdType.CD;
@@ -1246,12 +1262,17 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
 
         if (!(guestOsTypeName.startsWith("Windows") || guestOsTypeName.startsWith("Citrix") || guestOsTypeName.startsWith("Other"))) {
             if (vmSpec.getBootloader() == BootloaderType.CD) {
-                VolumeTO [] disks = vmSpec.getDisks();
-                for (VolumeTO disk : disks) {
-                    if (disk.getType() == Volume.Type.ISO && disk.getOsType() != null) {
-                        String isoGuestOsName = getGuestOsType(disk.getOsType(), vmSpec.getBootloader() == BootloaderType.CD);
-                        if (!isoGuestOsName.equals(guestOsTypeName)) {
-                            vmSpec.setBootloader(BootloaderType.PyGrub);
+                DiskTO [] disks = vmSpec.getDisks();
+                for (DiskTO disk : disks) {
+                    Volume.Type type = disk.getType();
+                    if (type == Volume.Type.ISO) {
+                        TemplateObjectTO tmpl = (TemplateObjectTO)disk.getData();
+                        String osType = tmpl.getGuestOsType();
+                        if (tmpl.getFormat() == ImageFormat.ISO && osType != null ) {
+                            String isoGuestOsName = getGuestOsType(osType, vmSpec.getBootloader() == BootloaderType.CD);
+                            if (!isoGuestOsName.equals(guestOsTypeName)) {
+                                vmSpec.setBootloader(BootloaderType.PyGrub);
+                            }
                         }
                     }
                 }
@@ -1496,7 +1517,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
             Host host = Host.getByUuid(conn, _host.uuid);
             vm = createVmFromTemplate(conn, vmSpec, host);
 
-            for (VolumeTO disk : vmSpec.getDisks()) {
+            for (DiskTO disk : vmSpec.getDisks()) {
                 createVbd(conn, disk, vmName, vm, vmSpec.getBootloader());
             }
 
@@ -5774,13 +5795,14 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
 
         CheckXenHostInfo();
 
-        this.storageResource = getStorageResource();
+        this.storageHandler = getStorageHandler();
         return true;
 
     }
 
-    protected XenServerStorageResource getStorageResource() {
-        return new XenServerStorageResource(this);
+    protected StorageSubsystemCommandHandler getStorageHandler() {
+    	XenServerStorageProcessor processor = new XenServerStorageProcessor(this);
+        return new StorageSubsystemCommandHandlerBase(processor);
     }
 
     private void CheckXenHostInfo() throws ConfigurationException {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java
index d64e173..6ce3837 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServer56FP1Resource.java
@@ -26,11 +26,14 @@ import java.util.Map;
 import java.util.Set;
 
 import javax.ejb.Local;
+
+import org.apache.cloudstack.storage.to.TemplateObjectTO;
 import org.apache.log4j.Logger;
 import org.apache.xmlrpc.XmlRpcException;
 
 import com.cloud.agent.api.FenceAnswer;
 import com.cloud.agent.api.FenceCommand;
+import com.cloud.agent.api.to.DiskTO;
 import com.cloud.agent.api.to.VirtualMachineTO;
 import com.cloud.agent.api.to.VolumeTO;
 import com.cloud.resource.ServerResource;
@@ -194,13 +197,17 @@ public class XenServer56FP1Resource extends XenServer56Resource {
 
         if (!(guestOsTypeName.startsWith("Windows") || guestOsTypeName.startsWith("Citrix") || guestOsTypeName.startsWith("Other"))) {
             if (vmSpec.getBootloader() == BootloaderType.CD) {
-                VolumeTO[] disks = vmSpec.getDisks();
-                for (VolumeTO disk : disks) {
-                    if (disk.getType() == Volume.Type.ISO && disk.getOsType() != null) {
-                        String isoGuestOsName = getGuestOsType(disk.getOsType(), vmSpec.getBootloader() == BootloaderType.CD);
-                        if (!isoGuestOsName.equals(guestOsTypeName)) {
-                            vmSpec.setBootloader(BootloaderType.PyGrub);
-                        }
+                DiskTO[] disks = vmSpec.getDisks();
+                for (DiskTO disk : disks) {
+                    if (disk.getType() == Volume.Type.ISO ) {
+                    	TemplateObjectTO iso = (TemplateObjectTO)disk.getData();
+                    	String osType = iso.getGuestOsType();
+                    	if (osType != null) {
+                    		String isoGuestOsName = getGuestOsType(osType, vmSpec.getBootloader() == BootloaderType.CD);
+                    		if (!isoGuestOsName.equals(guestOsTypeName)) {
+                    			vmSpec.setBootloader(BootloaderType.PyGrub);
+                    		}
+                    	}
                     }
                 }
             }


Mime
View raw message