You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ed...@apache.org on 2013/05/10 18:49:19 UTC

[1/7] refactor kvm/vmware resource code

Updated Branches:
  refs/heads/object_store a83b87b7e -> e444867e6


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/server/src/com/cloud/template/TemplateManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/template/TemplateManagerImpl.java b/server/src/com/cloud/template/TemplateManagerImpl.java
index 20cdce1..0bdd8c1 100755
--- a/server/src/com/cloud/template/TemplateManagerImpl.java
+++ b/server/src/com/cloud/template/TemplateManagerImpl.java
@@ -65,7 +65,9 @@ import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
 import org.apache.cloudstack.framework.async.AsyncCallFuture;
+import org.apache.cloudstack.storage.command.AttachCommand;
 import org.apache.cloudstack.storage.command.CommandResult;
+import org.apache.cloudstack.storage.command.DettachCommand;
 import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
 import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
@@ -79,8 +81,11 @@ import org.springframework.stereotype.Component;
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.AttachIsoCommand;
+import com.cloud.agent.api.Command;
 import com.cloud.agent.api.ComputeChecksumCommand;
 import com.cloud.agent.api.storage.DestroyCommand;
+import com.cloud.agent.api.to.DataTO;
+import com.cloud.agent.api.to.DiskTO;
 import com.cloud.api.ApiDBUtils;
 import com.cloud.async.AsyncJobManager;
 import com.cloud.async.AsyncJobVO;
@@ -1024,27 +1029,13 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
         } else if (vm.getState() != State.Running) {
             return true;
         }
-        String isoPath;
-        VMTemplateVO tmplt = this._tmpltDao.findById(isoId);
+        //FIXME: if it's s3, need to download into cache store
+        TemplateInfo tmplt = this._tmplFactory.getTemplate(isoId, DataStoreRole.Image, vm.getDataCenterId());
         if (tmplt == null) {
             s_logger.warn("ISO: " + isoId + " does not exist");
             return false;
         }
-        // Get the path of the ISO
-        Pair<String, String> isoPathPair = null;
-        if (tmplt.getTemplateType() == TemplateType.PERHOST) {
-            isoPath = tmplt.getName();
-        } else {
-            isoPathPair = getAbsoluteIsoPath(isoId,
-                    vm.getDataCenterId());
-            if (isoPathPair == null) {
-                s_logger.warn("Couldn't get absolute iso path");
-                return false;
-            } else {
-                isoPath = isoPathPair.first();
-            }
-        }
-
+      
         String vmName = vm.getInstanceName();
 
         HostVO host = _hostDao.findById(vm.getHostId());
@@ -1052,12 +1043,16 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
             s_logger.warn("Host: " + vm.getHostId() + " does not exist");
             return false;
         }
-        AttachIsoCommand cmd = new AttachIsoCommand(vmName, isoPath, attach);
-        if (isoPathPair != null) {
-            cmd.setStoreUrl(isoPathPair.second());
+        
+        DataTO isoTO = tmplt.getTO();
+        DiskTO disk = new DiskTO(isoTO, null, Volume.Type.ISO);
+        Command cmd = null;
+        if (attach) {
+            cmd = new AttachCommand(disk, vmName);
+        } else {
+            cmd = new DettachCommand(disk, vmName);
         }
         Answer a = _agentMgr.easySend(vm.getHostId(), cmd);
-
         return (a != null && a.getResult());
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/server/src/com/cloud/vm/UserVmManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java
index 000430f..98aeaf2 100755
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -42,7 +42,10 @@ import org.apache.cloudstack.api.command.user.vmgroup.CreateVMGroupCmd;
 import org.apache.cloudstack.api.command.user.vmgroup.DeleteVMGroupCmd;
 import org.apache.cloudstack.engine.cloud.entity.api.VirtualMachineEntity;
 import org.apache.cloudstack.engine.service.api.OrchestrationService;
+import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory;
+import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.storage.to.TemplateObjectTO;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.log4j.Logger;
 
@@ -58,6 +61,7 @@ import com.cloud.agent.api.StopAnswer;
 import com.cloud.agent.api.UnPlugNicAnswer;
 import com.cloud.agent.api.UnPlugNicCommand;
 import com.cloud.agent.api.VmStatsEntry;
+import com.cloud.agent.api.to.DiskTO;
 import com.cloud.agent.api.to.NicTO;
 import com.cloud.agent.api.to.VirtualMachineTO;
 import com.cloud.agent.api.to.VolumeTO;
@@ -159,6 +163,7 @@ import com.cloud.storage.Storage;
 import com.cloud.storage.Storage.ImageFormat;
 import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.storage.Storage.TemplateType;
+import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.StorageManager;
 import com.cloud.storage.StoragePool;
 import com.cloud.storage.StoragePoolStatus;
@@ -373,6 +378,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
 
     @Inject
     List<DeployPlannerSelector> plannerSelectors;
+    @Inject
+    TemplateDataFactory templateFactory;
 
     protected ScheduledExecutorService _executor = null;
     protected int _expungeInterval;
@@ -2625,52 +2632,33 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
         vm.setDetails(details);
 
         if (vm.getIsoId() != null) {
-            String isoPath = null;
-
-            VirtualMachineTemplate template = _templateDao.findById(vm
-                    .getIsoId());
+            TemplateInfo template = templateFactory.getTemplate(vm.getIsoId(), DataStoreRole.Image, vm.getDataCenterId());
+           
             if (template == null || template.getFormat() != ImageFormat.ISO) {
                 throw new CloudRuntimeException(
                         "Can not find ISO in vm_template table for id "
                                 + vm.getIsoId());
             }
-
-            Pair<String, String> isoPathPair = this.templateMgr.getAbsoluteIsoPath(
-                    template.getId(), vm.getDataCenterId());
-
-            if (template.getTemplateType() == TemplateType.PERHOST) {
-                isoPath = template.getName();
-            } else {
-                if (isoPathPair == null) {
-                    s_logger.warn("Couldn't get absolute iso path");
-                    return false;
-                } else {
-                    isoPath = isoPathPair.first();
-                }
-            }
-
+       
             if (template.isBootable()) {
                 profile.setBootLoaderType(BootloaderType.CD);
             }
+            
             GuestOSVO guestOS = _guestOSDao.findById(template.getGuestOSId());
             String displayName = null;
             if (guestOS != null) {
                 displayName = guestOS.getDisplayName();
             }
-            VolumeTO iso = new VolumeTO(profile.getId(), Volume.Type.ISO,
-                    StoragePoolType.ISO, null, template.getName(), null,
-                    isoPath, 0, null, displayName);
-
-            iso.setDeviceId(3);
-            profile.addDisk(iso);
+            
+            TemplateObjectTO iso = (TemplateObjectTO)template.getTO();
+            iso.setGuestOsType(displayName);
+            DiskTO disk = new DiskTO(iso, 3L, Volume.Type.ISO);
+            profile.addDisk(disk);
         } else {
-            VirtualMachineTemplate template = profile.getTemplate();
-            /* create a iso placeholder */
-            VolumeTO iso = new VolumeTO(profile.getId(), Volume.Type.ISO,
-                    StoragePoolType.ISO, null, template.getName(), null, null,
-                    0, null);
-            iso.setDeviceId(3);
-            profile.addDisk(iso);
+            TemplateObjectTO iso = new TemplateObjectTO();
+            iso.setFormat(ImageFormat.ISO);
+            DiskTO disk = new DiskTO(iso, 3L, Volume.Type.ISO);
+            profile.addDisk(disk);
         }
 
         return true;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/server/src/com/cloud/vm/VirtualMachineProfileImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/VirtualMachineProfileImpl.java b/server/src/com/cloud/vm/VirtualMachineProfileImpl.java
index 24f44cb..c4e8822 100644
--- a/server/src/com/cloud/vm/VirtualMachineProfileImpl.java
+++ b/server/src/com/cloud/vm/VirtualMachineProfileImpl.java
@@ -22,6 +22,7 @@ import java.util.List;
 import java.util.Map;
 
 
+import com.cloud.agent.api.to.DiskTO;
 import com.cloud.agent.api.to.VolumeTO;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.offering.ServiceOffering;
@@ -46,7 +47,7 @@ public class VirtualMachineProfileImpl<T extends VMInstanceVO> implements Virtua
     UserVmDetailVO _userVmDetails;
     Map<Param, Object> _params;
     List<NicProfile> _nics = new ArrayList<NicProfile>();
-    List<VolumeTO> _disks = new ArrayList<VolumeTO>();
+    List<DiskTO> _disks = new ArrayList<DiskTO>();
     StringBuilder _bootArgs = new StringBuilder();
     Account _owner;
     BootloaderType _bootloader;
@@ -141,7 +142,7 @@ public class VirtualMachineProfileImpl<T extends VMInstanceVO> implements Virtua
         _nics = nics;
     }
     
-    public void setDisks(List<VolumeTO> disks) {
+    public void setDisks(List<DiskTO> disks) {
         _disks = disks;
     }
     
@@ -151,7 +152,7 @@ public class VirtualMachineProfileImpl<T extends VMInstanceVO> implements Virtua
     }
     
     @Override
-    public List<VolumeTO> getDisks() {
+    public List<DiskTO> getDisks() {
         return _disks;
     }
     
@@ -161,7 +162,7 @@ public class VirtualMachineProfileImpl<T extends VMInstanceVO> implements Virtua
     }
     
     @Override
-    public void addDisk(int index, VolumeTO disk) {
+    public void addDisk(int index, DiskTO disk) {
         _disks.add(index, disk);
     }
     
@@ -210,7 +211,7 @@ public class VirtualMachineProfileImpl<T extends VMInstanceVO> implements Virtua
     }
 
     @Override
-    public void addDisk(VolumeTO disk) {
+    public void addDisk(DiskTO disk) {
         _disks.add(disk);
     }
 


[4/7] refactor kvm/vmware resource code

Posted by ed...@apache.org.
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);
+                    		}
+                    	}
                     }
                 }
             }


[2/7] refactor kvm/vmware resource code

Posted by ed...@apache.org.
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java
deleted file mode 100644
index 8b27efe..0000000
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageResource.java
+++ /dev/null
@@ -1,1327 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with 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.
- */
-package com.cloud.hypervisor.xen.resource;
-
-import java.beans.BeanInfo;
-import java.beans.IntrospectionException;
-import java.beans.Introspector;
-import java.beans.PropertyDescriptor;
-import java.io.BufferedOutputStream;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
-import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreAnswer;
-import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreCmd;
-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.CreatePrimaryDataStoreCmd;
-import org.apache.cloudstack.storage.command.DeleteCommand;
-import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
-import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol;
-import org.apache.cloudstack.storage.to.ImageStoreTO;
-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.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.client.ClientProtocolException;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.DefaultHttpClient;
-import org.apache.log4j.Logger;
-import org.apache.xmlrpc.XmlRpcException;
-
-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.CopyVolumeAnswer;
-import com.cloud.agent.api.storage.CreateAnswer;
-import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
-import com.cloud.agent.api.storage.DeleteVolumeCommand;
-import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
-import com.cloud.agent.api.to.DataStoreTO;
-import com.cloud.agent.api.to.NfsTO;
-import com.cloud.agent.api.to.S3TO;
-import com.cloud.agent.api.to.StorageFilerTO;
-import com.cloud.agent.api.to.SwiftTO;
-import com.cloud.agent.api.to.VolumeTO;
-import com.cloud.exception.InternalErrorException;
-import com.cloud.hypervisor.xen.resource.CitrixResourceBase.SRType;
-import com.cloud.storage.DataStoreRole;
-import com.cloud.storage.Storage.ImageFormat;
-import com.cloud.utils.S3Utils;
-import com.cloud.utils.StringUtils;
-import com.cloud.utils.exception.CloudRuntimeException;
-import com.cloud.utils.storage.encoding.DecodedDataObject;
-import com.cloud.utils.storage.encoding.DecodedDataStore;
-import com.cloud.utils.storage.encoding.Decoder;
-import com.cloud.vm.DiskProfile;
-import com.xensource.xenapi.Connection;
-import com.xensource.xenapi.Host;
-import com.xensource.xenapi.PBD;
-import com.xensource.xenapi.SR;
-import com.xensource.xenapi.Types;
-import com.xensource.xenapi.Types.BadServerResponse;
-import com.xensource.xenapi.Types.XenAPIException;
-import com.xensource.xenapi.VDI;
-
-public class XenServerStorageResource {
-    private static final Logger s_logger = Logger.getLogger(XenServerStorageResource.class);
-    protected CitrixResourceBase hypervisorResource;
-
-    public XenServerStorageResource(CitrixResourceBase resource) {
-        this.hypervisorResource = resource;
-    }
-
-    public Answer handleStorageCommands(StorageSubSystemCommand command) {
-        if (command instanceof CopyCommand) {
-            return this.execute((CopyCommand)command);
-        } else if (command instanceof AttachPrimaryDataStoreCmd) {
-            return this.execute((AttachPrimaryDataStoreCmd)command);
-        } else if (command instanceof CreatePrimaryDataStoreCmd) {
-            return execute((CreatePrimaryDataStoreCmd) command);
-        } else if (command instanceof CreateObjectCommand) {
-            return execute((CreateObjectCommand) command);
-        } else if (command instanceof DeleteCommand) {
-            return execute((DeleteCommand)command);
-        }
-        return new Answer((Command)command, false, "not implemented yet");
-    }
-
-    protected SR getSRByNameLabel(Connection conn, String nameLabel) throws BadServerResponse, XenAPIException, XmlRpcException {
-        Set<SR> srs = SR.getByNameLabel(conn, nameLabel);
-        if (srs.size() != 1) {
-            throw new CloudRuntimeException("storage uuid: " + nameLabel + " is not unique");
-        }
-        SR poolsr = srs.iterator().next();
-        return poolsr;
-    }
-
-    protected VDI createVdi(Connection conn, String vdiName, SR sr, long size) throws BadServerResponse, XenAPIException, XmlRpcException {
-        VDI.Record vdir = new VDI.Record();
-        vdir.nameLabel = vdiName;
-        vdir.SR = sr;
-        vdir.type = Types.VdiType.USER;
-
-        vdir.virtualSize = size;
-        VDI vdi = VDI.create(conn, vdir);
-        return vdi;
-    }
-
-    protected void deleteVDI(Connection conn, VDI vdi) throws BadServerResponse, XenAPIException, XmlRpcException {
-        vdi.destroy(conn);
-    }
-
-    private Map<String, String> getParameters(URI uri) {
-        String parameters = uri.getQuery();
-        Map<String, String> params = new HashMap<String, String>();
-        List<String> paraLists = Arrays.asList(parameters.split("&"));
-        for (String para : paraLists) {
-            String[] pair = para.split("=");
-            params.put(pair[0], pair[1]);
-        }
-        return params;
-    }
-
-    protected CreateObjectAnswer getTemplateSize(CreateObjectCommand cmd, String templateUrl) {
-        /*Connection conn = hypervisorResource.getConnection();
-        long size = this.getTemplateSize(conn, templateUrl);
-        return new CreateObjectAnswer(cmd, templateUrl, size);*/
-        return null;
-    }
-
-    protected CreateObjectAnswer createSnapshot(SnapshotObjectTO snapshotTO) {
-        Connection conn = hypervisorResource.getConnection();
-        long snapshotId = snapshotTO.getId();
-        String snapshotName = snapshotTO.getName();
-        String details = "create snapshot operation Failed for snapshotId: " + snapshotId;
-        String snapshotUUID = null;
-
-        try {
-            String volumeUUID = snapshotTO.getVolume().getPath();
-            VDI volume = VDI.getByUuid(conn, volumeUUID);
-
-            VDI snapshot = volume.snapshot(conn, new HashMap<String, String>());
-
-            if (snapshotName != null) {
-                snapshot.setNameLabel(conn, snapshotName);
-            }
-
-            snapshotUUID = snapshot.getUuid(conn);
-            String preSnapshotUUID = snapshotTO.getParentSnapshotPath();
-            //check if it is a empty snapshot
-            if( preSnapshotUUID != null) {
-                SR sr = volume.getSR(conn);
-                String srUUID = sr.getUuid(conn);
-                String type = sr.getType(conn);
-                Boolean isISCSI = IsISCSI(type);
-                String snapshotParentUUID = getVhdParent(conn, srUUID, snapshotUUID, isISCSI);
-
-                String preSnapshotParentUUID = getVhdParent(conn, srUUID, preSnapshotUUID, isISCSI);
-                if( snapshotParentUUID != null && snapshotParentUUID.equals(preSnapshotParentUUID)) {
-                    // this is empty snapshot, remove it
-                    snapshot.destroy(conn);
-                    snapshotUUID = preSnapshotUUID;
-                }
-            }
-            SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
-            newSnapshot.setPath(snapshotUUID);
-            return new CreateObjectAnswer(newSnapshot);
-        } catch (XenAPIException e) {
-            details += ", reason: " + e.toString();
-            s_logger.warn(details, e);
-        } catch (Exception e) {
-            details += ", reason: " + e.toString();
-            s_logger.warn(details, e);
-        }
-
-        return new CreateObjectAnswer(details);
-    }
-    protected CreateObjectAnswer execute(CreateObjectCommand cmd) {
-       DataTO data = cmd.getData();
-       try {
-           if (data.getObjectType() == DataObjectType.VOLUME) {
-               return createVolume(data);
-           } else if (data.getObjectType() == DataObjectType.SNAPSHOT) {
-               return createSnapshot((SnapshotObjectTO)data);
-           }
-           return new CreateObjectAnswer("not supported type");
-       } catch (Exception e) {
-           s_logger.debug("Failed to create object: " + data.getObjectType() + ": " + e.toString());
-           return new CreateObjectAnswer(e.toString());
-       }
-    }
-    
-    protected Answer deleteVolume(VolumeObjectTO volume) {
-        Connection conn = hypervisorResource.getConnection();
-        String errorMsg = null;
-        try {
-            VDI vdi = VDI.getByUuid(conn, volume.getPath());
-            deleteVDI(conn, vdi);
-            return new Answer(null);
-        } catch (BadServerResponse e) {
-            s_logger.debug("Failed to delete volume", e);
-            errorMsg = e.toString();
-        } catch (XenAPIException e) {
-            s_logger.debug("Failed to delete volume", e);
-            errorMsg = e.toString();
-        } catch (XmlRpcException e) {
-            s_logger.debug("Failed to delete volume", e);
-            errorMsg = e.toString();
-        }
-        return new Answer(null, false, errorMsg);
-    }
-
-    protected Answer execute(DeleteCommand cmd) {
-        DataTO data = cmd.getData();
-        Answer answer = null;
-        if (data.getObjectType() == DataObjectType.VOLUME) {
-            answer = deleteVolume((VolumeObjectTO)data);
-        } else {
-            answer = new Answer(cmd, false, "unsupported type");
-        }
-
-        return answer;
-    }
-
-   /* protected Answer execute(CreateVolumeFromBaseImageCommand cmd) {
-        VolumeObjectTO volume = cmd.getVolume();
-        ImageOnPrimayDataStoreTO baseImage = cmd.getImage();
-        Connection conn = hypervisorResource.getConnection();
-
-        try {
-            VDI baseVdi = VDI.getByUuid(conn, baseImage.getPathOnPrimaryDataStore());
-            VDI newVol = baseVdi.createClone(conn, new HashMap<String, String>());
-            newVol.setNameLabel(conn, volume.getName());
-            return new CreateObjectAnswer(cmd, newVol.getUuid(conn), newVol.getVirtualSize(conn));
-        } catch (BadServerResponse e) {
-            return new Answer(cmd, false, e.toString());
-        } catch (XenAPIException e) {
-            return new Answer(cmd, false, e.toString());
-        } catch (XmlRpcException e) {
-            return new Answer(cmd, false, e.toString());
-        }
-    }*/
-
-    protected SR getNfsSR(Connection conn, DecodedDataStore store) {
-
-        Map<String, String> deviceConfig = new HashMap<String, String>();
-
-        String uuid = store.getUuid();
-        try {
-            String server = store.getServer();
-            String serverpath = store.getPath();
-
-            serverpath = serverpath.replace("//", "/");
-            Set<SR> srs = SR.getAll(conn);
-            for (SR sr : srs) {
-                if (!SRType.NFS.equals(sr.getType(conn))) {
-                    continue;
-                }
-
-                Set<PBD> pbds = sr.getPBDs(conn);
-                if (pbds.isEmpty()) {
-                    continue;
-                }
-
-                PBD pbd = pbds.iterator().next();
-
-                Map<String, String> dc = pbd.getDeviceConfig(conn);
-
-                if (dc == null) {
-                    continue;
-                }
-
-                if (dc.get("server") == null) {
-                    continue;
-                }
-
-                if (dc.get("serverpath") == null) {
-                    continue;
-                }
-
-                if (server.equals(dc.get("server")) && serverpath.equals(dc.get("serverpath"))) {
-                    throw new CloudRuntimeException("There is a SR using the same configuration server:" + dc.get("server") + ", serverpath:"
-                            + dc.get("serverpath") + " for pool " + uuid + "on host:" + hypervisorResource.getHost().uuid);
-                }
-
-            }
-            deviceConfig.put("server", server);
-            deviceConfig.put("serverpath", serverpath);
-            Host host = Host.getByUuid(conn, hypervisorResource.getHost().uuid);
-            SR sr = SR.create(conn, host, deviceConfig, new Long(0), uuid, uuid, SRType.NFS.toString(), "user", true,
-                    new HashMap<String, String>());
-            sr.scan(conn);
-            return sr;
-        } catch (XenAPIException e) {
-            throw new CloudRuntimeException("Unable to create NFS SR " + uuid, e);
-        } catch (XmlRpcException e) {
-            throw new CloudRuntimeException("Unable to create NFS SR " + uuid, e);
-        }
-    }
-    /*
-    protected SR getIscsiSR(Connection conn, PrimaryDataStoreTO pool) {
-        synchronized (pool.getUuid().intern()) {
-            Map<String, String> deviceConfig = new HashMap<String, String>();
-            try {
-                String target = pool.getHost();
-                String path = pool.getPath();
-                if (path.endsWith("/")) {
-                    path = path.substring(0, path.length() - 1);
-                }
-
-                String tmp[] = path.split("/");
-                if (tmp.length != 3) {
-                    String msg = "Wrong iscsi path " + pool.getPath() + " it should be /targetIQN/LUN";
-                    s_logger.warn(msg);
-                    throw new CloudRuntimeException(msg);
-                }
-                String targetiqn = tmp[1].trim();
-                String lunid = tmp[2].trim();
-                String scsiid = "";
-
-                Set<SR> srs = SR.getByNameLabel(conn, pool.getUuid());
-                for (SR sr : srs) {
-                    if (!SRType.LVMOISCSI.equals(sr.getType(conn))) {
-                        continue;
-                    }
-                    Set<PBD> pbds = sr.getPBDs(conn);
-                    if (pbds.isEmpty()) {
-                        continue;
-                    }
-                    PBD pbd = pbds.iterator().next();
-                    Map<String, String> dc = pbd.getDeviceConfig(conn);
-                    if (dc == null) {
-                        continue;
-                    }
-                    if (dc.get("target") == null) {
-                        continue;
-                    }
-                    if (dc.get("targetIQN") == null) {
-                        continue;
-                    }
-                    if (dc.get("lunid") == null) {
-                        continue;
-                    }
-                    if (target.equals(dc.get("target")) && targetiqn.equals(dc.get("targetIQN")) && lunid.equals(dc.get("lunid"))) {
-                        throw new CloudRuntimeException("There is a SR using the same configuration target:" + dc.get("target") +  ",  targetIQN:"
-                                + dc.get("targetIQN")  + ", lunid:" + dc.get("lunid") + " for pool " + pool.getUuid() + "on host:" + _host.uuid);
-                    }
-                }
-                deviceConfig.put("target", target);
-                deviceConfig.put("targetIQN", targetiqn);
-
-                Host host = Host.getByUuid(conn, _host.uuid);
-                Map<String, String> smConfig = new HashMap<String, String>();
-                String type = SRType.LVMOISCSI.toString();
-                String poolId = Long.toString(pool.getId());
-                SR sr = null;
-                try {
-                    sr = SR.create(conn, host, deviceConfig, new Long(0), pool.getUuid(), poolId, type, "user", true,
-                            smConfig);
-                } catch (XenAPIException e) {
-                    String errmsg = e.toString();
-                    if (errmsg.contains("SR_BACKEND_FAILURE_107")) {
-                        String lun[] = errmsg.split("<LUN>");
-                        boolean found = false;
-                        for (int i = 1; i < lun.length; i++) {
-                            int blunindex = lun[i].indexOf("<LUNid>") + 7;
-                            int elunindex = lun[i].indexOf("</LUNid>");
-                            String ilun = lun[i].substring(blunindex, elunindex);
-                            ilun = ilun.trim();
-                            if (ilun.equals(lunid)) {
-                                int bscsiindex = lun[i].indexOf("<SCSIid>") + 8;
-                                int escsiindex = lun[i].indexOf("</SCSIid>");
-                                scsiid = lun[i].substring(bscsiindex, escsiindex);
-                                scsiid = scsiid.trim();
-                                found = true;
-                                break;
-                            }
-                        }
-                        if (!found) {
-                            String msg = "can not find LUN " + lunid + " in " + errmsg;
-                            s_logger.warn(msg);
-                            throw new CloudRuntimeException(msg);
-                        }
-                    } else {
-                        String msg = "Unable to create Iscsi SR  " + deviceConfig + " due to  " + e.toString();
-                        s_logger.warn(msg, e);
-                        throw new CloudRuntimeException(msg, e);
-                    }
-                }
-                deviceConfig.put("SCSIid", scsiid);
-
-                String result = SR.probe(conn, host, deviceConfig, type , smConfig);
-                String pooluuid = null;
-                if( result.indexOf("<UUID>") != -1) {
-                    pooluuid = result.substring(result.indexOf("<UUID>") + 6, result.indexOf("</UUID>")).trim();
-                }
-                if( pooluuid == null || pooluuid.length() != 36) {
-                    sr = SR.create(conn, host, deviceConfig, new Long(0), pool.getUuid(), poolId, type, "user", true,
-                            smConfig);
-                } else {
-                    sr = SR.introduce(conn, pooluuid, pool.getUuid(), poolId,
-                            type, "user", true, smConfig);
-                    Pool.Record pRec = XenServerConnectionPool.getPoolRecord(conn);
-                    PBD.Record rec = new PBD.Record();
-                    rec.deviceConfig = deviceConfig;
-                    rec.host = pRec.master;
-                    rec.SR = sr;
-                    PBD pbd = PBD.create(conn, rec);
-                    pbd.plug(conn);
-                }
-                sr.scan(conn);
-                return sr;
-            } catch (XenAPIException e) {
-                String msg = "Unable to create Iscsi SR  " + deviceConfig + " due to  " + e.toString();
-                s_logger.warn(msg, e);
-                throw new CloudRuntimeException(msg, e);
-            } catch (Exception e) {
-                String msg = "Unable to create Iscsi SR  " + deviceConfig + " due to  " + e.getMessage();
-                s_logger.warn(msg, e);
-                throw new CloudRuntimeException(msg, e);
-            }
-        }
-    }*/
-
-    protected Answer execute(CreatePrimaryDataStoreCmd cmd) {
-        Connection conn = hypervisorResource.getConnection();
-        String storeUrl = cmd.getDataStore();
-
-        try {
-            DecodedDataObject obj = Decoder.decode(storeUrl);
-            DecodedDataStore store = obj.getStore();
-
-            if (store.getScheme().equalsIgnoreCase("nfs")) {
-                SR sr = getNfsSR(conn, store);
-            } else if (store.getScheme().equalsIgnoreCase("iscsi")) {
-                //getIscsiSR(conn, dataStore);
-            } else if (store.getScheme().equalsIgnoreCase("presetup")) {
-            } else {
-                return new Answer(cmd, false, "The pool type: " + store.getScheme() + " is not supported.");
-            }
-            return new Answer(cmd, true, "success");
-        } catch (Exception e) {
-           // String msg = "Catch Exception " + e.getClass().getName() + ", create StoragePool failed due to " + e.toString() + " on host:" + _host.uuid + " pool: " + pool.getHost() + pool.getPath();
-            //s_logger.warn(msg, e);
-            return new Answer(cmd, false, null);
-        }
-    }
-
-    private long getTemplateSize(Connection conn, String url) {
-        String size = hypervisorResource.callHostPlugin(conn, "storagePlugin", "getTemplateSize", "srcUrl", url);
-        if (size.equalsIgnoreCase("") || size == null) {
-            throw new CloudRuntimeException("Can't get template size");
-        }
-
-        try {
-            return Long.parseLong(size);
-        } catch (NumberFormatException e) {
-            throw new CloudRuntimeException("Failed to get template lenght", e);
-        }
-
-        /*
-        HttpHead method = new HttpHead(url);
-        DefaultHttpClient client = new DefaultHttpClient();
-        try {
-            HttpResponse response = client.execute(method);
-            Header header = response.getFirstHeader("Content-Length");
-            if (header == null) {
-                throw new CloudRuntimeException("Can't get content-lenght header from :" + url);
-            }
-            Long length = Long.parseLong(header.getValue());
-            return length;
-        } catch (HttpException e) {
-            throw new CloudRuntimeException("Failed to get template lenght", e);
-        } catch (IOException e) {
-            throw new CloudRuntimeException("Failed to get template lenght", e);
-        } catch (NumberFormatException e) {
-            throw new CloudRuntimeException("Failed to get template lenght", e);
-        }*/
-    }
-
-    private void downloadHttpToLocalFile(String destFilePath, String url) {
-        File destFile = new File(destFilePath);
-        if (!destFile.exists()) {
-            throw new CloudRuntimeException("dest file doesn't exist: " + destFilePath);
-        }
-
-        DefaultHttpClient client = new DefaultHttpClient();
-        HttpGet getMethod = new HttpGet(url);
-        HttpResponse response;
-        BufferedOutputStream output = null;
-        long length = 0;
-        try {
-            response = client.execute(getMethod);
-            HttpEntity entity = response.getEntity();
-            length = entity.getContentLength();
-            output = new BufferedOutputStream(new FileOutputStream(destFile));
-            entity.writeTo(output);
-        } catch (ClientProtocolException e) {
-           throw new CloudRuntimeException("Failed to download template", e);
-        } catch (IOException e) {
-            throw new CloudRuntimeException("Failed to download template", e);
-        } finally {
-            if (output != null) {
-                try {
-                    output.close();
-                } catch (IOException e) {
-                    throw new CloudRuntimeException("Failed to download template", e);
-                }
-            }
-        }
-
-        //double check the length
-        destFile = new File(destFilePath);
-        if (destFile.length() != length) {
-            throw new CloudRuntimeException("Download file length doesn't match: expected: " + length + ", actual: " + destFile.length());
-        }
-
-    }
-
-    protected Answer directDownloadHttpTemplate(CopyCommand cmd, DecodedDataObject srcObj, DecodedDataObject destObj) {
-        Connection conn = hypervisorResource.getConnection();
-        SR poolsr = null;
-        VDI vdi = null;
-        boolean result = false;
-        try {
-            if (destObj.getPath() == null) {
-                //need to create volume at first
-
-            }
-            vdi = VDI.getByUuid(conn, destObj.getPath());
-            if (vdi == null) {
-                throw new CloudRuntimeException("can't find volume: " + destObj.getPath());
-            }
-            String destStoreUuid = destObj.getStore().getUuid();
-            Set<SR> srs = SR.getByNameLabel(conn, destStoreUuid);
-            if (srs.size() != 1) {
-                throw new CloudRuntimeException("storage uuid: " + destStoreUuid + " is not unique");
-            }
-            poolsr = srs.iterator().next();
-            VDI.Record vdir = vdi.getRecord(conn);
-            String vdiLocation = vdir.location;
-            String pbdLocation = null;
-            if (destObj.getStore().getScheme().equalsIgnoreCase(DataStoreProtocol.NFS.toString())) {
-                pbdLocation = "/run/sr-mount/" + poolsr.getUuid(conn);
-            } else {
-                Set<PBD> pbds = poolsr.getPBDs(conn);
-                if (pbds.size() != 1) {
-                    throw new CloudRuntimeException("Don't how to handle multiple pbds:" + pbds.size() + " for sr: " + poolsr.getUuid(conn));
-                }
-                PBD pbd = pbds.iterator().next();
-                Map<String, String> deviceCfg = pbd.getDeviceConfig(conn);
-                pbdLocation = deviceCfg.get("location");
-            }
-            if (pbdLocation == null) {
-                throw new CloudRuntimeException("Can't get pbd location");
-            }
-
-            String vdiPath = pbdLocation + "/" + vdiLocation + ".vhd";
-            //download a url into vdipath
-            //downloadHttpToLocalFile(vdiPath, template.getPath());
-            hypervisorResource.callHostPlugin(conn, "storagePlugin", "downloadTemplateFromUrl", "destPath", vdiPath, "srcUrl", srcObj.getPath());
-            result = true;
-            //return new CopyCmdAnswer(cmd, vdi.getUuid(conn));
-        } catch (BadServerResponse e) {
-            s_logger.debug("Failed to download template", e);
-        } catch (XenAPIException e) {
-            s_logger.debug("Failed to download template", e);
-        } catch (XmlRpcException e) {
-            s_logger.debug("Failed to download template", e);
-        } catch (Exception e) {
-            s_logger.debug("Failed to download template", e);
-        } finally {
-            if (!result && vdi != null) {
-                try {
-                    vdi.destroy(conn);
-                } catch (BadServerResponse e) {
-                   s_logger.debug("Failed to cleanup newly created vdi");
-                } catch (XenAPIException e) {
-                    s_logger.debug("Failed to cleanup newly created vdi");
-                } catch (XmlRpcException e) {
-                    s_logger.debug("Failed to cleanup newly created vdi");
-                }
-            }
-        }
-        return new Answer(cmd, false, "Failed to download template");
-    }
-
-    protected Answer execute(AttachPrimaryDataStoreCmd cmd) {
-        String dataStoreUri = cmd.getDataStore();
-        Connection conn = hypervisorResource.getConnection();
-        try {
-            DecodedDataObject obj = Decoder.decode(dataStoreUri);
-
-            DecodedDataStore store = obj.getStore();
-
-            SR sr = hypervisorResource.getStorageRepository(conn, store.getUuid());
-            hypervisorResource.setupHeartbeatSr(conn, sr, false);
-            long capacity = sr.getPhysicalSize(conn);
-            long available = capacity - sr.getPhysicalUtilisation(conn);
-            if (capacity == -1) {
-                String msg = "Pool capacity is -1! pool: ";
-                s_logger.warn(msg);
-                return new Answer(cmd, false, msg);
-            }
-            AttachPrimaryDataStoreAnswer answer = new AttachPrimaryDataStoreAnswer(cmd);
-            answer.setCapacity(capacity);
-            answer.setUuid(sr.getUuid(conn));
-            answer.setAvailable(available);
-            return answer;
-        } catch (XenAPIException e) {
-            String msg = "AttachPrimaryDataStoreCmd add XenAPIException:" + e.toString();
-            s_logger.warn(msg, e);
-            return new Answer(cmd, false, msg);
-        } catch (Exception e) {
-            String msg = "AttachPrimaryDataStoreCmd failed:" + e.getMessage();
-            s_logger.warn(msg, e);
-            return new Answer(cmd, false, msg);
-        }
-    }
-
-    private boolean IsISCSI(String type) {
-        return SRType.LVMOHBA.equals(type) || SRType.LVMOISCSI.equals(type) || SRType.LVM.equals(type) ;
-    }
-
-    private String copy_vhd_from_secondarystorage(Connection conn, String mountpoint, String sruuid, int wait) {
-        String nameLabel = "cloud-" + UUID.randomUUID().toString();
-        String results = hypervisorResource.callHostPluginAsync(conn, "vmopspremium", "copy_vhd_from_secondarystorage",
-                wait, "mountpoint", mountpoint, "sruuid", sruuid, "namelabel", nameLabel);
-        String errMsg = null;
-        if (results == null || results.isEmpty()) {
-            errMsg = "copy_vhd_from_secondarystorage return null";
-        } else {
-            String[] tmp = results.split("#");
-            String status = tmp[0];
-            if (status.equals("0")) {
-                return tmp[1];
-            } else {
-                errMsg = tmp[1];
-            }
-        }
-        String source = mountpoint.substring(mountpoint.lastIndexOf('/') + 1);
-        if( hypervisorResource.killCopyProcess(conn, source) ) {
-            destroyVDIbyNameLabel(conn, nameLabel);
-        }
-        s_logger.warn(errMsg);
-        throw new CloudRuntimeException(errMsg);
-    }
-
-    private void destroyVDIbyNameLabel(Connection conn, String nameLabel) {
-        try {
-            Set<VDI> vdis = VDI.getByNameLabel(conn, nameLabel);
-            if ( vdis.size() != 1 ) {
-                s_logger.warn("destoryVDIbyNameLabel failed due to there are " + vdis.size() + " VDIs with name " + nameLabel);
-                return;
-            }
-            for (VDI vdi : vdis) {
-                try {
-                    vdi.destroy(conn);
-                } catch (Exception e) {
-                }
-            }
-        } catch (Exception e){
-        }
-    }
-
-    protected VDI getVDIbyUuid(Connection conn, String uuid) {
-        try {
-            return VDI.getByUuid(conn, uuid);
-        } catch (Exception e) {
-            String msg = "Catch Exception " + e.getClass().getName() + " :VDI getByUuid for uuid: " + uuid + " failed due to " + e.toString();
-            s_logger.debug(msg);
-            throw new CloudRuntimeException(msg, e);
-        }
-    }
-
-    protected String getVhdParent(Connection conn, String primaryStorageSRUuid, String snapshotUuid, Boolean isISCSI) {
-        String parentUuid = hypervisorResource.callHostPlugin(conn, "vmopsSnapshot", "getVhdParent", "primaryStorageSRUuid", primaryStorageSRUuid,
-                "snapshotUuid", snapshotUuid, "isISCSI", isISCSI.toString());
-
-        if (parentUuid == null || parentUuid.isEmpty() || parentUuid.equalsIgnoreCase("None")) {
-            s_logger.debug("Unable to get parent of VHD " + snapshotUuid + " in SR " + primaryStorageSRUuid);
-            // errString is already logged.
-            return null;
-        }
-        return parentUuid;
-    }
-
-    protected CopyCmdAnswer copyTemplateToPrimaryStorage(DataTO srcData, DataTO destData, int wait) {
-        DataStoreTO srcStore = srcData.getDataStore();
-        try {
-            if ((srcStore instanceof NfsTO) && (srcData.getObjectType() == DataObjectType.TEMPLATE)) {
-                NfsTO srcImageStore = (NfsTO)srcStore;
-                TemplateObjectTO srcTemplate = (TemplateObjectTO)srcData;
-                String storeUrl = srcImageStore.getUrl();
-            
-                URI uri = new URI(storeUrl);
-                String tmplpath = uri.getHost() + ":" + uri.getPath() + "/" + srcData.getPath();
-                PrimaryDataStoreTO destStore = (PrimaryDataStoreTO)destData.getDataStore();
-                String poolName = destStore.getUuid();
-                Connection conn = hypervisorResource.getConnection();
-
-                SR poolsr = null;
-                Set<SR> srs = SR.getByNameLabel(conn, poolName);
-                if (srs.size() != 1) {
-                    String msg = "There are " + srs.size() + " SRs with same name: " + poolName;
-                    s_logger.warn(msg);
-                    return new CopyCmdAnswer(msg);
-                } else {
-                    poolsr = srs.iterator().next();
-                }
-                String pUuid = poolsr.getUuid(conn);
-                boolean isISCSI = IsISCSI(poolsr.getType(conn));
-                String uuid = copy_vhd_from_secondarystorage(conn, tmplpath, pUuid, wait);
-                VDI tmpl = getVDIbyUuid(conn, uuid);
-                VDI snapshotvdi = tmpl.snapshot(conn, new HashMap<String, String>());
-                String snapshotUuid = snapshotvdi.getUuid(conn);
-                snapshotvdi.setNameLabel(conn, "Template " + srcTemplate.getName());
-                String parentuuid = getVhdParent(conn, pUuid, snapshotUuid, isISCSI);
-                VDI parent = getVDIbyUuid(conn, parentuuid);
-                Long phySize = parent.getPhysicalUtilisation(conn);
-                tmpl.destroy(conn);
-                poolsr.scan(conn);
-                try{
-                    Thread.sleep(5000);
-                } catch (Exception e) {
-                }
-
-                TemplateObjectTO newVol = new TemplateObjectTO();
-                newVol.setUuid(snapshotvdi.getUuid(conn));
-                newVol.setPath(newVol.getUuid());
-                return new CopyCmdAnswer(newVol);
-            }
-        }catch (Exception e) {
-            String msg = "Catch Exception " + e.getClass().getName() + " for template + " + " due to " + e.toString();
-            s_logger.warn(msg, e);
-            return new CopyCmdAnswer(msg);
-        }
-        return new CopyCmdAnswer("not implemented yet");
-    }
-
-    protected CreateObjectAnswer createVolume(DataTO data) throws BadServerResponse, XenAPIException, XmlRpcException {
-        VolumeObjectTO volume = (VolumeObjectTO)data;
-
-        Connection conn = hypervisorResource.getConnection();
-        PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)data.getDataStore();
-        SR poolSr = hypervisorResource.getStorageRepository(conn, primaryStore.getUuid());
-        VDI.Record vdir = new VDI.Record();
-        vdir.nameLabel = volume.getName();
-        vdir.SR = poolSr;
-        vdir.type = Types.VdiType.USER;
-
-        vdir.virtualSize = volume.getSize();
-        VDI vdi;
-
-        vdi = VDI.create(conn, vdir);
-        vdir = vdi.getRecord(conn);
-        VolumeObjectTO newVol = new VolumeObjectTO();
-        newVol.setName(vdir.nameLabel);
-        newVol.setSize(vdir.virtualSize);
-        newVol.setPath(vdir.uuid);
-
-        return new CreateObjectAnswer(newVol);
-    }
-
-    protected CopyCmdAnswer cloneVolumeFromBaseTemplate(DataTO srcData, DataTO destData) {
-        Connection conn = hypervisorResource.getConnection();
-        PrimaryDataStoreTO pool = (PrimaryDataStoreTO)destData.getDataStore();
-        VolumeObjectTO volume = (VolumeObjectTO)destData;
-        VDI vdi = null;
-        try {
-            VDI tmpltvdi = null;
-
-            tmpltvdi = getVDIbyUuid(conn, srcData.getPath());
-            vdi = tmpltvdi.createClone(conn, new HashMap<String, String>());
-            vdi.setNameLabel(conn, volume.getName());
-
-
-            VDI.Record vdir;
-            vdir = vdi.getRecord(conn);
-            s_logger.debug("Succesfully created VDI: Uuid = " + vdir.uuid);
-
-            VolumeObjectTO newVol = new VolumeObjectTO();
-            newVol.setName(vdir.nameLabel);
-            newVol.setSize(vdir.virtualSize);
-            newVol.setPath(vdir.uuid);
-
-            return new CopyCmdAnswer(newVol);
-        } catch (Exception e) {
-            s_logger.warn("Unable to create volume; Pool=" + pool + "; Disk: ", e);
-            return new CopyCmdAnswer(e.toString());
-        }
-    }
-
-
-    protected Answer copyVolumeFromImageCacheToPrimary(DataTO srcData, DataTO destData, int wait) {
-        Connection conn = hypervisorResource.getConnection();
-        VolumeObjectTO srcVolume = (VolumeObjectTO)srcData;
-        VolumeObjectTO destVolume = (VolumeObjectTO)destData;
-        PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)destVolume.getDataStore();
-        DataStoreTO srcStore = srcVolume.getDataStore();
-
-        if (srcStore instanceof NfsTO) {
-            NfsTO nfsStore = (NfsTO)srcStore;
-            try {
-                SR primaryStoragePool = hypervisorResource.getStorageRepository(conn, primaryStore.getUuid());
-                String srUuid = primaryStoragePool.getUuid(conn);
-                String volumePath = nfsStore.getUrl() + ":" + srcVolume.getPath();
-                String uuid = copy_vhd_from_secondarystorage(conn, volumePath, srUuid, wait );
-                VolumeObjectTO newVol = new VolumeObjectTO();
-                newVol.setPath(uuid);
-                newVol.setSize(srcVolume.getSize());
-
-                return new CopyCmdAnswer(newVol);
-            } catch (Exception e) {
-                String msg = "Catch Exception " + e.getClass().getName() + " due to " + e.toString();
-                s_logger.warn(msg, e);
-                return new CopyCmdAnswer(e.toString());
-            }
-        }
-
-        s_logger.debug("unsupported protocol");
-        return new CopyCmdAnswer("unsupported protocol");
-    }
-
-    protected Answer copyVolumeFromPrimaryToSecondary(DataTO srcData, DataTO destData, int wait) {
-        Connection conn = hypervisorResource.getConnection();
-        VolumeObjectTO srcVolume = (VolumeObjectTO)srcData;
-        VolumeObjectTO destVolume = (VolumeObjectTO)destData;
-        DataStoreTO destStore = destVolume.getDataStore();
-
-        if (destStore instanceof NfsTO) {
-            SR secondaryStorage = null;
-            try {
-                NfsTO nfsStore = (NfsTO)destStore;
-                URI uri = new URI(nfsStore.getUrl());
-                // Create the volume folder
-                if (!hypervisorResource.createSecondaryStorageFolder(conn, uri.getHost() + ":" + uri.getPath(), destVolume.getPath())) {
-                    throw new InternalErrorException("Failed to create the volume folder.");
-                }
-
-                // Create a SR for the volume UUID folder
-                secondaryStorage = hypervisorResource.createNfsSRbyURI(conn, new URI(nfsStore.getUrl() + destVolume.getPath()), false);
-                // Look up the volume on the source primary storage pool
-                VDI srcVdi = getVDIbyUuid(conn, srcVolume.getPath());
-                // Copy the volume to secondary storage
-                VDI destVdi = hypervisorResource.cloudVDIcopy(conn, srcVdi, secondaryStorage, wait);
-                String destVolumeUUID = destVdi.getUuid(conn);
-
-                VolumeObjectTO newVol = new VolumeObjectTO();
-                newVol.setPath(destVolumeUUID);
-                newVol.setSize(srcVolume.getSize());
-                return new CopyCmdAnswer(newVol);
-            } catch (Exception e) {
-                s_logger.debug("Failed to copy volume to secondary: " + e.toString());
-                return new CopyCmdAnswer("Failed to copy volume to secondary: " + e.toString());
-            } finally {
-                hypervisorResource.removeSR(conn, secondaryStorage);
-            }
-        }
-        return new CopyCmdAnswer("unsupported protocol");
-    }
-
-    boolean swiftUpload(Connection conn, SwiftTO swift, String container, String ldir, String lfilename, Boolean isISCSI, int wait) {
-        String result = null;
-        try {
-            result = hypervisorResource.callHostPluginAsync(conn, "swiftxen", "swift", wait,
-                    "op", "upload", "url", swift.getUrl(), "account", swift.getAccount(),
-                    "username", swift.getUserName(), "key", swift.getKey(), "container", container,
-                    "ldir", ldir, "lfilename", lfilename, "isISCSI", isISCSI.toString());
-            if( result != null && result.equals("true")) {
-                return true;
-            }
-        } catch (Exception e) {
-            s_logger.warn("swift upload failed due to " + e.toString(), e);
-        }
-        return false;
-    }
-
-    protected String deleteSnapshotBackup(Connection conn, String path, String secondaryStorageMountPath, String backupUUID) {
-
-        // If anybody modifies the formatting below again, I'll skin them
-        String result = hypervisorResource.callHostPlugin(conn, "vmopsSnapshot", "deleteSnapshotBackup", "backupUUID", backupUUID, "path", path, "secondaryStorageMountPath", secondaryStorageMountPath);
-
-        return result;
-    }
-
-    public void swiftBackupSnapshot(Connection conn, SwiftTO swift, String srUuid, String snapshotUuid, String container, Boolean isISCSI, int wait)  {
-        String lfilename;
-        String ldir;
-        if ( isISCSI ) {
-            ldir = "/dev/VG_XenStorage-" + srUuid;
-            lfilename = "VHD-" + snapshotUuid;
-        } else {
-            ldir = "/var/run/sr-mount/" + srUuid;
-            lfilename = snapshotUuid + ".vhd";
-        }
-        swiftUpload(conn, swift, container, ldir, lfilename, isISCSI, wait);
-    }
-
-    private static List<String> serializeProperties(final Object object,
-            final Class<?> propertySet) {
-
-        assert object != null;
-        assert propertySet != null;
-        assert propertySet.isAssignableFrom(object.getClass());
-
-        try {
-
-            final BeanInfo beanInfo = Introspector.getBeanInfo(propertySet);
-            final PropertyDescriptor[] descriptors = beanInfo
-                    .getPropertyDescriptors();
-
-            final List<String> serializedProperties = new ArrayList<String>();
-            for (final PropertyDescriptor descriptor : descriptors) {
-
-                serializedProperties.add(descriptor.getName());
-                final Object value = descriptor.getReadMethod().invoke(object);
-                serializedProperties.add(value != null ? value.toString()
-                        : "null");
-
-            }
-
-            return Collections.unmodifiableList(serializedProperties);
-
-        } catch (IntrospectionException e) {
-            s_logger.warn(
-                    "Ignored IntrospectionException when serializing class "
-                            + object.getClass().getCanonicalName(), e);
-        } catch (IllegalArgumentException e) {
-            s_logger.warn(
-                    "Ignored IllegalArgumentException when serializing class "
-                            + object.getClass().getCanonicalName(), e);
-        } catch (IllegalAccessException e) {
-            s_logger.warn(
-                    "Ignored IllegalAccessException when serializing class "
-                            + object.getClass().getCanonicalName(), e);
-        } catch (InvocationTargetException e) {
-            s_logger.warn(
-                    "Ignored InvocationTargetException when serializing class "
-                            + object.getClass().getCanonicalName(), e);
-        }
-
-        return Collections.emptyList();
-
-    }
-
-    private boolean backupSnapshotToS3(final Connection connection,
-            final S3TO s3, final String srUuid, final String snapshotUuid,
-            final Boolean iSCSIFlag, final int wait) {
-
-        final String filename = iSCSIFlag ? "VHD-" + snapshotUuid
-                : snapshotUuid + ".vhd";
-        final String dir = (iSCSIFlag ? "/dev/VG_XenStorage-"
-                : "/var/run/sr-mount/") + srUuid;
-        final String key = StringUtils.join("/", "snapshots", snapshotUuid);
-
-        try {
-
-            final List<String> parameters = new ArrayList<String>(
-                    serializeProperties(s3, S3Utils.ClientOptions.class));
-            parameters.addAll(Arrays.asList("operation", "put", "directory",
-                    dir, "filename", filename, "iSCSIFlag",
-                    iSCSIFlag.toString(), "key", key));
-            final String result = hypervisorResource.callHostPluginAsync(connection, "s3xen",
-                    "s3", wait,
-                    parameters.toArray(new String[parameters.size()]));
-
-            if (result != null && result.equals("true")) {
-                return true;
-            }
-
-        } catch (Exception e) {
-            s_logger.error(String.format(
-                    "S3 upload failed of snapshot %1$s due to %2$s.",
-                    snapshotUuid, e.toString()), e);
-        }
-
-        return false;
-
-    }
-
-    protected String backupSnapshot(Connection conn, String primaryStorageSRUuid, String path, String secondaryStorageMountPath, String snapshotUuid, String prevBackupUuid, Boolean isISCSI, int wait) {
-        String backupSnapshotUuid = null;
-
-        if (prevBackupUuid == null) {
-            prevBackupUuid = "";
-        }
-
-        // Each argument is put in a separate line for readability.
-        // Using more lines does not harm the environment.
-        String backupUuid = UUID.randomUUID().toString();
-        String results = hypervisorResource.callHostPluginAsync(conn, "vmopsSnapshot", "backupSnapshot", wait,
-                "primaryStorageSRUuid", primaryStorageSRUuid, "path", path, "secondaryStorageMountPath", secondaryStorageMountPath,
-                "snapshotUuid", snapshotUuid, "prevBackupUuid", prevBackupUuid, "backupUuid", backupUuid, "isISCSI", isISCSI.toString());
-        String errMsg = null;
-        if (results == null || results.isEmpty()) {
-            errMsg = "Could not copy backupUuid: " + backupSnapshotUuid
-                    + " from primary storage " + primaryStorageSRUuid + " to secondary storage "
-                    + secondaryStorageMountPath + " due to null";
-        } else {
-
-            String[] tmp = results.split("#");
-            String status = tmp[0];
-            backupSnapshotUuid = tmp[1];
-            // status == "1" if and only if backupSnapshotUuid != null
-            // So we don't rely on status value but return backupSnapshotUuid as an
-            // indicator of success.
-            if (status != null && status.equalsIgnoreCase("1") && backupSnapshotUuid != null) {
-                s_logger.debug("Successfully copied backupUuid: " + backupSnapshotUuid
-                        + " to secondary storage");
-                return backupSnapshotUuid;
-            } else {
-                errMsg = "Could not copy backupUuid: " + backupSnapshotUuid
-                        + " from primary storage " + primaryStorageSRUuid + " to secondary storage "
-                        + secondaryStorageMountPath + " due to " + tmp[1];
-            }
-        }
-        String source = backupUuid + ".vhd";
-        hypervisorResource.killCopyProcess(conn, source);
-        s_logger.warn(errMsg);
-        return null;
-
-    }
-
-    private boolean destroySnapshotOnPrimaryStorageExceptThis(Connection conn, String volumeUuid, String avoidSnapshotUuid){
-        try {
-            VDI volume = getVDIbyUuid(conn, volumeUuid);
-            if (volume == null) {
-                throw new InternalErrorException("Could not destroy snapshot on volume " + volumeUuid + " due to can not find it");
-            }
-            Set<VDI> snapshots = volume.getSnapshots(conn);
-            for( VDI snapshot : snapshots ) {
-                try {
-                    if(! snapshot.getUuid(conn).equals(avoidSnapshotUuid)) {
-                        snapshot.destroy(conn);
-                    }
-                } catch (Exception e) {
-                    String msg = "Destroying snapshot: " + snapshot+ " on primary storage failed due to " + e.toString();
-                    s_logger.warn(msg, e);
-                }
-            }
-            s_logger.debug("Successfully destroyed snapshot on volume: " + volumeUuid + " execept this current snapshot "+ avoidSnapshotUuid );
-            return true;
-        } catch (XenAPIException e) {
-            String msg = "Destroying snapshot on volume: " + volumeUuid + " execept this current snapshot "+ avoidSnapshotUuid + " failed due to " + e.toString();
-            s_logger.error(msg, e);
-        } catch (Exception e) {
-            String msg = "Destroying snapshot on volume: " + volumeUuid + " execept this current snapshot "+ avoidSnapshotUuid + " failed due to " + e.toString();
-            s_logger.warn(msg, e);
-        }
-
-        return false;
-    }
-
-    protected Answer backupSnasphot(DataTO srcData, DataTO destData, DataTO cacheData, int wait) {
-        Connection conn = hypervisorResource.getConnection();
-        PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)srcData.getDataStore();
-        String primaryStorageNameLabel = primaryStore.getUuid();
-        String secondaryStorageUrl = null;
-        NfsTO cacheStore = null;
-        String destPath = null;
-        if (cacheData != null) {
-            cacheStore = (NfsTO)cacheData.getDataStore();
-            secondaryStorageUrl = cacheStore.getUrl();
-            destPath = cacheData.getPath();
-        } else {
-            cacheStore = (NfsTO)destData.getDataStore();
-            secondaryStorageUrl = cacheStore.getUrl();
-            destPath = destData.getPath();
-        }
-
-        SnapshotObjectTO snapshotTO = (SnapshotObjectTO)srcData;
-        SnapshotObjectTO snapshotOnImage = (SnapshotObjectTO)destData;
-        String snapshotUuid = snapshotTO.getPath();
-
-        String prevBackupUuid = snapshotOnImage.getParentSnapshotPath();
-        String prevSnapshotUuid = snapshotTO.getParentSnapshotPath();
-
-        // By default assume failure
-        String details = null;
-        String snapshotBackupUuid = null;
-        boolean fullbackup = true;
-        try {
-            SR primaryStorageSR = hypervisorResource.getSRByNameLabelandHost(conn, primaryStorageNameLabel);
-            if (primaryStorageSR == null) {
-                throw new InternalErrorException("Could not backup snapshot because the primary Storage SR could not be created from the name label: " + primaryStorageNameLabel);
-            }
-            String psUuid = primaryStorageSR.getUuid(conn);
-            Boolean isISCSI = IsISCSI(primaryStorageSR.getType(conn));
-
-            VDI snapshotVdi = getVDIbyUuid(conn, snapshotUuid);
-            String snapshotPaUuid = null;
-            if ( prevBackupUuid != null ) {
-                try {
-                    snapshotPaUuid = getVhdParent(conn, psUuid, snapshotUuid, isISCSI);
-                    if( snapshotPaUuid != null ) {
-                        String snashotPaPaPaUuid = getVhdParent(conn, psUuid, snapshotPaUuid, isISCSI);
-                        String prevSnashotPaUuid = getVhdParent(conn, psUuid, prevSnapshotUuid, isISCSI);
-                        if (snashotPaPaPaUuid != null && prevSnashotPaUuid!= null && prevSnashotPaUuid.equals(snashotPaPaPaUuid)) {
-                            fullbackup = false;
-                        }
-                    }
-                } catch (Exception e) {
-                }
-            }
-
-            URI uri = new URI(secondaryStorageUrl);
-            String secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
-            DataStoreTO destStore = destData.getDataStore();
-            String folder = destPath;
-            if (fullbackup) {
-                // the first snapshot is always a full snapshot
-
-                if( !hypervisorResource.createSecondaryStorageFolder(conn, secondaryStorageMountPath, folder)) {
-                    details = " Filed to create folder " + folder + " in secondary storage";
-                    s_logger.warn(details);
-                    return new CopyCmdAnswer(details);
-                }
-                String snapshotMountpoint = secondaryStorageUrl + "/" + folder;
-                SR snapshotSr = null;
-                try {
-                    snapshotSr = hypervisorResource.createNfsSRbyURI(conn, new URI(snapshotMountpoint), false);
-                    VDI backedVdi = hypervisorResource.cloudVDIcopy(conn, snapshotVdi, snapshotSr, wait);
-                    snapshotBackupUuid = backedVdi.getUuid(conn);
-
-                    if( destStore instanceof SwiftTO) {
-                        try {
-                            hypervisorResource.swiftBackupSnapshot(conn, (SwiftTO)destStore, snapshotSr.getUuid(conn), snapshotBackupUuid, "S-" + snapshotTO.getVolume().getVolumeId().toString(), false, wait);
-                            snapshotBackupUuid = snapshotBackupUuid + ".vhd";
-                        } finally {
-                            deleteSnapshotBackup(conn, folder, secondaryStorageMountPath, snapshotBackupUuid);
-                        }
-                    } else if (destStore instanceof S3TO) {
-                        try {
-                            backupSnapshotToS3(conn, (S3TO)destStore, snapshotSr.getUuid(conn), snapshotBackupUuid, isISCSI, wait);
-                            snapshotBackupUuid = snapshotBackupUuid + ".vhd";
-                        } finally {
-                            deleteSnapshotBackup(conn, folder, secondaryStorageMountPath, snapshotBackupUuid);
-                        }
-                    }
-
-                } finally {
-                    if( snapshotSr != null) {
-                        hypervisorResource.removeSR(conn, snapshotSr);
-                    }
-                }
-            } else {
-                String primaryStorageSRUuid = primaryStorageSR.getUuid(conn);
-                if( destStore instanceof SwiftTO ) {
-                    swiftBackupSnapshot(conn, (SwiftTO)destStore, primaryStorageSRUuid, snapshotPaUuid, "S-" + snapshotTO.getVolume().getVolumeId().toString(), isISCSI, wait);
-                    if ( isISCSI ) {
-                        snapshotBackupUuid = "VHD-" + snapshotPaUuid;
-                    } else {
-                        snapshotBackupUuid = snapshotPaUuid + ".vhd";
-                    }
-
-                } else if (destStore instanceof S3TO ) {
-                    backupSnapshotToS3(conn, (S3TO)destStore, primaryStorageSRUuid, snapshotPaUuid, isISCSI, wait);
-                } else {
-                    snapshotBackupUuid = backupSnapshot(conn, primaryStorageSRUuid, folder + File.separator + UUID.nameUUIDFromBytes(secondaryStorageMountPath.getBytes())
-                             , secondaryStorageMountPath, snapshotUuid, prevBackupUuid, isISCSI, wait);
-
-                }
-            }
-            String volumeUuid = snapshotTO.getVolume().getPath();
-            destroySnapshotOnPrimaryStorageExceptThis(conn, volumeUuid, snapshotUuid);
-
-            SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
-            newSnapshot.setPath(folder + File.separator + snapshotBackupUuid);
-            if (fullbackup) {
-                newSnapshot.setParentSnapshotPath(null);
-            } else {
-                newSnapshot.setParentSnapshotPath(prevBackupUuid);
-            }
-            return new CopyCmdAnswer(newSnapshot);
-        } catch (XenAPIException e) {
-            details = "BackupSnapshot Failed due to " + e.toString();
-            s_logger.warn(details, e);
-        } catch (Exception e) {
-            details = "BackupSnapshot Failed due to " + e.getMessage();
-            s_logger.warn(details, e);
-        }
-
-        return new CopyCmdAnswer(details);
-    }
-    
-    protected CopyCmdAnswer createTemplateFromVolume(DataTO srcData, DataTO destData, int wait) {
-        Connection conn = this.hypervisorResource.getConnection();
-        VolumeObjectTO volume = (VolumeObjectTO)srcData;
-        TemplateObjectTO template = (TemplateObjectTO)destData;
-        NfsTO destStore = (NfsTO)destData.getDataStore();
-        
-        String secondaryStoragePoolURL = destStore.getUrl();
-        String volumeUUID = volume.getPath();
-       
-        String userSpecifiedName = template.getName();
-      
-     
-        String details = null;
-        SR tmpltSR = null;
-        boolean result = false;
-        String secondaryStorageMountPath = null;
-        String installPath = null;
-        try {
-            URI uri = new URI(secondaryStoragePoolURL);
-            secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
-            installPath = template.getPath();
-            if( !this.hypervisorResource.createSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath)) {
-                details = " Filed to create folder " + installPath + " in secondary storage";
-                s_logger.warn(details);
-                return new CopyCmdAnswer(details);
-            }
-
-            VDI vol = getVDIbyUuid(conn, volumeUUID);
-            // create template SR
-            URI tmpltURI = new URI(secondaryStoragePoolURL + "/" + installPath);
-            tmpltSR = this.hypervisorResource.createNfsSRbyURI(conn, tmpltURI, false);
-
-            // copy volume to template SR
-            VDI tmpltVDI = this.hypervisorResource.cloudVDIcopy(conn, vol, tmpltSR, wait);
-            // scan makes XenServer pick up VDI physicalSize
-            tmpltSR.scan(conn);
-            if (userSpecifiedName != null) {
-                tmpltVDI.setNameLabel(conn, userSpecifiedName);
-            }
-
-            String tmpltUUID = tmpltVDI.getUuid(conn);
-            String tmpltFilename = tmpltUUID + ".vhd";
-            long virtualSize = tmpltVDI.getVirtualSize(conn);
-            long physicalSize = tmpltVDI.getPhysicalUtilisation(conn);
-            // create the template.properties file
-            String templatePath = secondaryStorageMountPath + "/" + installPath;
-            result = this.hypervisorResource.postCreatePrivateTemplate(conn, templatePath, tmpltFilename, tmpltUUID, userSpecifiedName, null, physicalSize, virtualSize, template.getId());
-            if (!result) {
-                throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir: " + tmpltURI);
-            }
-            installPath = installPath + "/" + tmpltFilename;
-            this.hypervisorResource.removeSR(conn, tmpltSR);
-            tmpltSR = null;
-            TemplateObjectTO newTemplate = new TemplateObjectTO();
-            newTemplate.setPath(installPath);
-            newTemplate.setFormat(ImageFormat.VHD);
-            CopyCmdAnswer answer = new CopyCmdAnswer(newTemplate);
-            return answer;
-        } catch (Exception e) {
-            if (tmpltSR != null) {
-                this.hypervisorResource.removeSR(conn, tmpltSR);
-            }
-            if ( secondaryStorageMountPath != null) {
-                this.hypervisorResource.deleteSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath);
-            }
-            details = "Creating template from volume " + volumeUUID + " failed due to " + e.toString();
-            s_logger.error(details, e);
-        }
-        return new CopyCmdAnswer(details);
-    }
-
-    protected Answer execute(CopyCommand cmd) {
-        DataTO srcData = cmd.getSrcTO();
-        DataTO destData = cmd.getDestTO();
-        DataStoreTO srcDataStore = srcData.getDataStore();
-        DataStoreTO destDataStore = destData.getDataStore();
-        DataObjectType srcType = srcData.getObjectType();
-        DataObjectType destType = destData.getObjectType();
-        DataStoreRole destRole = destDataStore.getRole();
-        
-        boolean nfs = (srcDataStore instanceof NfsTO) ? true : false;
-
-        if ((srcData.getObjectType() == DataObjectType.TEMPLATE) && (srcDataStore instanceof NfsTO)  && (destData.getDataStore().getRole() == DataStoreRole.Primary)) {
-            //copy template to primary storage
-            return copyTemplateToPrimaryStorage(srcData, destData, cmd.getWait());
-        } else if (srcData.getObjectType() == DataObjectType.TEMPLATE && srcDataStore.getRole() == DataStoreRole.Primary && destDataStore.getRole() == DataStoreRole.Primary) {
-            //clone template to a volume
-            return cloneVolumeFromBaseTemplate(srcData, destData);
-        } else if (srcData.getObjectType() == DataObjectType.VOLUME && (srcData.getDataStore().getRole() == DataStoreRole.ImageCache || srcDataStore.getRole() == DataStoreRole.Image)) {
-            //copy volume from image cache to primary
-            return copyVolumeFromImageCacheToPrimary(srcData, destData, cmd.getWait());
-        } else if (srcData.getObjectType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
-            if (destData.getObjectType() == DataObjectType.VOLUME) {
-                return copyVolumeFromPrimaryToSecondary(srcData, destData, cmd.getWait());
-            } else if (destData.getObjectType() == DataObjectType.TEMPLATE) {
-                return createTemplateFromVolume(srcData, destData, cmd.getWait());
-            }
-        } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
-            DataTO cacheData = cmd.getCacheTO();
-            return backupSnasphot(srcData, destData, cacheData, cmd.getWait());
-        }
-
-        return new Answer(cmd, false, "not implemented yet");
-    }
-}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java
----------------------------------------------------------------------
diff --git a/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java b/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java
index 1865068..52f8d9c 100644
--- a/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java
+++ b/plugins/storage/image/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackImageStoreDriverImpl.java
@@ -27,10 +27,8 @@ import javax.inject.Inject;
 import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
@@ -53,7 +51,9 @@ import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.storage.DeleteTemplateCommand;
 import com.cloud.agent.api.storage.DeleteVolumeCommand;
 import com.cloud.agent.api.storage.DownloadAnswer;
+import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
 import com.cloud.agent.api.to.NfsTO;
 import com.cloud.event.EventTypes;
 import com.cloud.event.UsageEventUtils;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/storage/image/s3/src/org/apache/cloudstack/storage/datastore/driver/S3ImageStoreDriverImpl.java
----------------------------------------------------------------------
diff --git a/plugins/storage/image/s3/src/org/apache/cloudstack/storage/datastore/driver/S3ImageStoreDriverImpl.java b/plugins/storage/image/s3/src/org/apache/cloudstack/storage/datastore/driver/S3ImageStoreDriverImpl.java
index 354151e..1992c5e 100644
--- a/plugins/storage/image/s3/src/org/apache/cloudstack/storage/datastore/driver/S3ImageStoreDriverImpl.java
+++ b/plugins/storage/image/s3/src/org/apache/cloudstack/storage/datastore/driver/S3ImageStoreDriverImpl.java
@@ -29,10 +29,8 @@ import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
@@ -57,7 +55,9 @@ import com.cloud.agent.api.DeleteSnapshotBackupCommand;
 import com.cloud.agent.api.storage.DeleteTemplateCommand;
 import com.cloud.agent.api.storage.DeleteVolumeCommand;
 import com.cloud.agent.api.storage.DownloadAnswer;
+import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
 import com.cloud.agent.api.to.S3TO;
 import com.cloud.event.EventTypes;
 import com.cloud.event.UsageEventUtils;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java
----------------------------------------------------------------------
diff --git a/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java b/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java
index 72864c3..2c7ba11 100644
--- a/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java
+++ b/plugins/storage/image/sample/src/org/apache/cloudstack/storage/datastore/driver/SampleImageStoreDriverImpl.java
@@ -25,9 +25,7 @@ import javax.inject.Inject;
 import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
 import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
@@ -36,7 +34,9 @@ import org.apache.cloudstack.storage.command.CreateObjectAnswer;
 import org.apache.cloudstack.storage.command.CreateObjectCommand;
 import org.apache.cloudstack.storage.image.ImageStoreDriver;
 
+import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
 import com.cloud.storage.dao.VMTemplateDao;
 
 //http-read-only based image store

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/storage/image/swift/src/org/apache/cloudstack/storage/datastore/driver/SwiftImageStoreDriverImpl.java
----------------------------------------------------------------------
diff --git a/plugins/storage/image/swift/src/org/apache/cloudstack/storage/datastore/driver/SwiftImageStoreDriverImpl.java b/plugins/storage/image/swift/src/org/apache/cloudstack/storage/datastore/driver/SwiftImageStoreDriverImpl.java
index 0eb3acf..82df043 100644
--- a/plugins/storage/image/swift/src/org/apache/cloudstack/storage/datastore/driver/SwiftImageStoreDriverImpl.java
+++ b/plugins/storage/image/swift/src/org/apache/cloudstack/storage/datastore/driver/SwiftImageStoreDriverImpl.java
@@ -29,10 +29,8 @@ import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
 import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher;
@@ -56,7 +54,9 @@ import com.cloud.agent.api.DeleteSnapshotBackupCommand;
 import com.cloud.agent.api.storage.DeleteTemplateCommand;
 import com.cloud.agent.api.storage.DeleteVolumeCommand;
 import com.cloud.agent.api.storage.DownloadAnswer;
+import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
 import com.cloud.agent.api.to.SwiftTO;
 import com.cloud.event.EventTypes;
 import com.cloud.event.UsageEventUtils;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
index 912a11e..aad1769 100644
--- a/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
+++ b/plugins/storage/volume/default/src/org/apache/cloudstack/storage/datastore/driver/CloudStackPrimaryDataStoreDriverImpl.java
@@ -25,9 +25,7 @@ import javax.inject.Inject;
 import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
 import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
@@ -50,7 +48,9 @@ import com.cloud.agent.api.storage.CreateCommand;
 import com.cloud.agent.api.storage.DestroyCommand;
 import com.cloud.agent.api.storage.ResizeVolumeAnswer;
 import com.cloud.agent.api.storage.ResizeVolumeCommand;
+import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
 import com.cloud.agent.api.to.StorageFilerTO;
 import com.cloud.exception.StorageUnavailableException;
 import com.cloud.host.dao.HostDao;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
index f530362..b3a83f7 100644
--- a/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
+++ b/plugins/storage/volume/sample/src/org/apache/cloudstack/storage/datastore/driver/SamplePrimaryDataStoreDriverImpl.java
@@ -25,7 +25,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
 import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
@@ -42,6 +41,7 @@ import org.apache.log4j.Logger;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
 import com.cloud.storage.dao.StoragePoolHostDao;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.storage.encoding.DecodedDataObject;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java
----------------------------------------------------------------------
diff --git a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java
index 9b2334b..eee9ba5 100644
--- a/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java
+++ b/plugins/storage/volume/solidfire/src/org/apache/cloudstack/storage/datastore/driver/SolidfirePrimaryDataStoreDriver.java
@@ -22,7 +22,6 @@ import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.CreateCmdResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
 import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
@@ -30,6 +29,7 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
 import org.apache.cloudstack.storage.command.CommandResult;
 
 import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
 
 public class SolidfirePrimaryDataStoreDriver implements PrimaryDataStoreDriver {
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/server/src/com/cloud/hypervisor/HypervisorGuruBase.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java
index d77796d..2300953 100644
--- a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java
+++ b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java
@@ -22,6 +22,7 @@ import java.util.Map;
 import javax.inject.Inject;
 
 import com.cloud.agent.api.Command;
+import com.cloud.agent.api.to.DataTO;
 import com.cloud.agent.api.to.NicTO;
 import com.cloud.agent.api.to.VirtualMachineTO;
 import com.cloud.agent.api.to.VolumeTO;
@@ -101,7 +102,7 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
         }
 
         to.setNics(nics);
-        to.setDisks(vmProfile.getDisks().toArray(new VolumeTO[vmProfile.getDisks().size()]));
+        to.setDisks(vmProfile.getDisks().toArray(new DataTO[vmProfile.getDisks().size()]));
 
         if(vmProfile.getTemplate().getBits() == 32) {
             to.setArch("i686");

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/server/src/com/cloud/storage/VolumeManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/VolumeManagerImpl.java b/server/src/com/cloud/storage/VolumeManagerImpl.java
index 90b2366..17e0e09 100644
--- a/server/src/com/cloud/storage/VolumeManagerImpl.java
+++ b/server/src/com/cloud/storage/VolumeManagerImpl.java
@@ -45,18 +45,22 @@ import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProviderManager;
-import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
+import org.apache.cloudstack.engine.subsystem.api.storage.TemplateDataFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeService.VolumeApiResult;
 import org.apache.cloudstack.framework.async.AsyncCallFuture;
+import org.apache.cloudstack.storage.command.AttachAnswer;
+import org.apache.cloudstack.storage.command.AttachCommand;
+import org.apache.cloudstack.storage.command.DettachAnswer;
+import org.apache.cloudstack.storage.command.DettachCommand;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
@@ -69,8 +73,8 @@ import org.springframework.stereotype.Component;
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.AttachVolumeAnswer;
-import com.cloud.agent.api.AttachVolumeCommand;
-import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.agent.api.to.DataTO;
+import com.cloud.agent.api.to.DiskTO;
 import com.cloud.alert.AlertManager;
 import com.cloud.api.ApiDBUtils;
 import com.cloud.async.AsyncJobExecutor;
@@ -117,7 +121,6 @@ import com.cloud.server.ManagementServer;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.service.dao.ServiceOfferingDao;
 import com.cloud.storage.Storage.ImageFormat;
-import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.storage.Volume.Event;
 import com.cloud.storage.Volume.Type;
 import com.cloud.storage.dao.DiskOfferingDao;
@@ -168,7 +171,6 @@ import com.cloud.vm.dao.DomainRouterDao;
 import com.cloud.vm.dao.SecondaryStorageVmDao;
 import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VMInstanceDao;
-import com.cloud.vm.snapshot.VMSnapshot;
 import com.cloud.vm.snapshot.VMSnapshotVO;
 import com.cloud.vm.snapshot.dao.VMSnapshotDao;
 
@@ -1514,7 +1516,7 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
         String errorMsg = "Failed to attach volume: " + volume.getName()
                 + " to VM: " + vm.getHostName();
         boolean sendCommand = (vm.getState() == State.Running);
-        AttachVolumeAnswer answer = null;
+        AttachAnswer answer = null;
         Long hostId = vm.getHostId();
         if (hostId == null) {
             hostId = vm.getLastHostId();
@@ -1526,16 +1528,11 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
         }
 
         if (sendCommand) {
-            StoragePoolVO volumePool = _storagePoolDao.findById(volume
-                    .getPoolId());
-            AttachVolumeCommand cmd = new AttachVolumeCommand(true,
-                    vm.getInstanceName(), volume.getPoolType(),
-                    volume.getFolder(), volume.getPath(), volume.getName(),
-                    deviceId, volume.getChainInfo());
-            cmd.setPoolUuid(volumePool.getUuid());
-
+            DataTO volTO = this.volFactory.getVolume(volume.getId()).getTO();
+            DiskTO disk = new DiskTO(volTO, deviceId, volume.getVolumeType());
+            AttachCommand cmd = new AttachCommand(disk, vm.getInstanceName());
             try {
-                answer = (AttachVolumeAnswer) _agentMgr.send(hostId, cmd);
+                answer = (AttachAnswer) _agentMgr.send(hostId, cmd);
             } catch (Exception e) {
                 throw new CloudRuntimeException(errorMsg + " due to: "
                         + e.getMessage());
@@ -1545,8 +1542,9 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
         if (!sendCommand || (answer != null && answer.getResult())) {
             // Mark the volume as attached
             if (sendCommand) {
+                DiskTO disk = answer.getDisk();
                 _volsDao.attachVolume(volume.getId(), vm.getId(),
-                        answer.getDeviceId());
+                        disk.getDiskSeq());
             } else {
                 _volsDao.attachVolume(volume.getId(), vm.getId(), deviceId);
             }
@@ -1858,16 +1856,9 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
         Answer answer = null;
 
         if (sendCommand) {
-            AttachVolumeCommand cmd = new AttachVolumeCommand(false,
-                    vm.getInstanceName(), volume.getPoolType(),
-                    volume.getFolder(), volume.getPath(), volume.getName(),
-                    cmmd.getDeviceId() != null ? cmmd.getDeviceId() : volume
-                            .getDeviceId(), volume.getChainInfo());
-
-            StoragePoolVO volumePool = _storagePoolDao.findById(volume
-                    .getPoolId());
-            cmd.setPoolUuid(volumePool.getUuid());
-
+            DataTO volTO = this.volFactory.getVolume(volume.getId()).getTO();
+            DiskTO disk = new DiskTO(volTO, volume.getDeviceId(), volume.getVolumeType());
+            DettachCommand cmd = new DettachCommand(disk, vm.getInstanceName());
             try {
                 answer = _agentMgr.send(vm.getHostId(), cmd);
             } catch (Exception e) {
@@ -1879,12 +1870,6 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
         if (!sendCommand || (answer != null && answer.getResult())) {
             // Mark the volume as detached
             _volsDao.detachVolume(volume.getId());
-            if (answer != null && answer instanceof AttachVolumeAnswer) {
-                volume.setChainInfo(((AttachVolumeAnswer) answer)
-                        .getChainInfo());
-                _volsDao.update(volume.getId(), volume);
-            }
-
             return _volsDao.findById(volumeId);
         } else {
 
@@ -2097,22 +2082,17 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
         }
 
         for (VolumeVO vol : vols) {
-            PrimaryDataStoreInfo pool = (PrimaryDataStoreInfo)this.dataStoreMgr.getDataStore(vol.getPoolId(), DataStoreRole.Primary);
-            vm.addDisk(new VolumeTO(vol, pool));
+            DataTO volTO = this.volFactory.getVolume(vol.getId()).getTO();
+            DiskTO disk = new DiskTO(volTO, vol.getDeviceId(), vol.getVolumeType());
+            vm.addDisk(disk);
         }
 
         if (vm.getType() == VirtualMachine.Type.User) {
             UserVmVO userVM = (UserVmVO) vm.getVirtualMachine();
             if (userVM.getIsoId() != null) {
-                Pair<String, String> isoPathPair = this._tmpltMgr.getAbsoluteIsoPath(
-                        userVM.getIsoId(), userVM.getDataCenterId());
-                if (isoPathPair != null) {
-                    String isoPath = isoPathPair.first();
-                    VolumeTO iso = new VolumeTO(vm.getId(), Volume.Type.ISO,
-                            StoragePoolType.ISO, null, null, null, isoPath, 0,
-                            null, null);
-                    vm.addDisk(iso);
-                }
+                DataTO dataTO = this.tmplFactory.getTemplate(userVM.getIsoId(), DataStoreRole.Image, userVM.getDataCenterId()).getTO();
+                DiskTO iso = new DiskTO(dataTO, 3L, Volume.Type.ISO);
+                vm.addDisk(iso);
             }
         }
     }
@@ -2328,7 +2308,9 @@ public class VolumeManagerImpl extends ManagerBase implements VolumeManager {
                 pool = (StoragePool)dataStoreMgr.getDataStore(result.second().getId(), DataStoreRole.Primary);
                 vol = result.first();
             }
-            vm.addDisk(new VolumeTO(vol, pool));
+            DataTO volumeTO = this.volFactory.getVolume(vol.getId()).getTO();
+            DiskTO disk = new DiskTO(volumeTO, vol.getDeviceId(), vol.getVolumeType());
+            vm.addDisk(disk);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/server/src/com/cloud/storage/download/DownloadListener.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/download/DownloadListener.java b/server/src/com/cloud/storage/download/DownloadListener.java
index 001b45d..691d655 100755
--- a/server/src/com/cloud/storage/download/DownloadListener.java
+++ b/server/src/com/cloud/storage/download/DownloadListener.java
@@ -26,7 +26,6 @@ import java.util.TimerTask;
 import javax.inject.Inject;
 
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
@@ -50,6 +49,7 @@ import com.cloud.agent.api.StartupCommand;
 import com.cloud.agent.api.StartupRoutingCommand;
 import com.cloud.agent.api.StartupSecondaryStorageCommand;
 import com.cloud.agent.api.storage.DownloadAnswer;
+import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.exception.AgentUnavailableException;
 import com.cloud.exception.ConnectionException;
 import com.cloud.host.Host;


[3/7] refactor kvm/vmware resource code

Posted by ed...@apache.org.
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
new file mode 100644
index 0000000..727c3f4
--- /dev/null
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
@@ -0,0 +1,1404 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with 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.
+ */
+package com.cloud.hypervisor.xen.resource;
+
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.io.File;
+import java.lang.reflect.InvocationTargetException;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+
+import org.apache.cloudstack.storage.command.AttachAnswer;
+import org.apache.cloudstack.storage.command.AttachCommand;
+import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreAnswer;
+import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreCmd;
+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.DettachAnswer;
+import org.apache.cloudstack.storage.command.DettachCommand;
+import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol;
+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 org.apache.xmlrpc.XmlRpcException;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.CreateStoragePoolCommand;
+import com.cloud.agent.api.to.DataObjectType;
+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.S3TO;
+import com.cloud.agent.api.to.StorageFilerTO;
+import com.cloud.agent.api.to.SwiftTO;
+import com.cloud.exception.InternalErrorException;
+import com.cloud.hypervisor.xen.resource.CitrixResourceBase.SRType;
+import com.cloud.storage.Storage.ImageFormat;
+import com.cloud.storage.Storage.StoragePoolType;
+import com.cloud.storage.resource.StorageProcessor;
+import com.cloud.utils.S3Utils;
+import com.cloud.utils.StringUtils;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.storage.encoding.DecodedDataObject;
+import com.cloud.utils.storage.encoding.DecodedDataStore;
+import com.cloud.utils.storage.encoding.Decoder;
+import com.xensource.xenapi.Connection;
+import com.xensource.xenapi.Host;
+import com.xensource.xenapi.PBD;
+import com.xensource.xenapi.Pool;
+import com.xensource.xenapi.SR;
+import com.xensource.xenapi.Types;
+import com.xensource.xenapi.Types.BadServerResponse;
+import com.xensource.xenapi.Types.XenAPIException;
+import com.xensource.xenapi.VBD;
+import com.xensource.xenapi.VDI;
+import com.xensource.xenapi.VM;
+import com.xensource.xenapi.VMGuestMetrics;
+
+public class XenServerStorageProcessor implements StorageProcessor {
+    private static final Logger s_logger = Logger.getLogger(XenServerStorageProcessor.class);
+    protected CitrixResourceBase hypervisorResource;
+
+    public XenServerStorageProcessor(CitrixResourceBase resource) {
+        this.hypervisorResource = resource;
+    }
+    
+    @Override
+    public AttachAnswer attachIso(AttachCommand cmd) {
+        DiskTO disk = cmd.getDisk();
+        DataTO data = disk.getData();
+        DataStoreTO store = data.getDataStore();
+
+        if (!(store instanceof NfsTO)) {
+            s_logger.debug("Can't attach a iso which is not created on nfs: ");
+            return new AttachAnswer("Can't attach a iso which is not created on nfs: ");
+        }
+        NfsTO nfsStore = (NfsTO)store;
+        String isoURL = nfsStore.getUrl() + File.separator + data.getPath();
+
+        String vmName = cmd.getVmName();
+        try {
+            Connection conn = this.hypervisorResource.getConnection();
+
+            VBD isoVBD = null;
+
+            // Find the VM
+            VM vm = this.hypervisorResource.getVM(conn, vmName);
+            // Find the ISO VDI
+            VDI isoVDI = this.hypervisorResource.getIsoVDIByURL(conn, vmName, isoURL);
+
+            // Find the VM's CD-ROM VBD
+            Set<VBD> vbds = vm.getVBDs(conn);
+            for (VBD vbd : vbds) {
+                String userDevice = vbd.getUserdevice(conn);
+                Types.VbdType type = vbd.getType(conn);
+
+                if (userDevice.equals("3") && type == Types.VbdType.CD) {
+                    isoVBD = vbd;
+                    break;
+                }
+            }
+
+            if (isoVBD == null) {
+                throw new CloudRuntimeException("Unable to find CD-ROM VBD for VM: " + vmName);
+            } else {
+                // If an ISO is already inserted, eject it
+                if (isoVBD.getEmpty(conn) == false) {
+                    isoVBD.eject(conn);
+                }
+
+                // Insert the new ISO
+                isoVBD.insert(conn, isoVDI);
+            }
+
+            return new AttachAnswer(disk);
+
+        } catch (XenAPIException e) {
+            s_logger.warn("Failed to attach iso" + ": " + e.toString(), e);
+            return new AttachAnswer(e.toString());
+        } catch (Exception e) {
+            s_logger.warn("Failed to attach iso" + ": " + e.toString(), e);
+            return new AttachAnswer(e.toString());
+        }
+    }
+    
+    @Override
+    public AttachAnswer attachVolume(AttachCommand cmd) {
+        String vmName = cmd.getVmName();
+        DiskTO disk = cmd.getDisk();
+        DataTO data = disk.getData();
+
+        try {
+            Connection conn = this.hypervisorResource.getConnection();
+            // Look up the VDI
+            VDI vdi = this.hypervisorResource.mount(conn, null, null, data.getPath());
+            // Look up the VM
+            VM vm = this.hypervisorResource.getVM(conn, vmName);
+            /* For HVM guest, if no pv driver installed, no attach/detach */
+            boolean isHVM;
+            if (vm.getPVBootloader(conn).equalsIgnoreCase("")) {
+                isHVM = true;
+            } else {
+                isHVM = false;
+            }
+            VMGuestMetrics vgm = vm.getGuestMetrics(conn);
+            boolean pvDrvInstalled = false;
+            if (!this.hypervisorResource.isRefNull(vgm) && vgm.getPVDriversUpToDate(conn)) {
+                pvDrvInstalled = true;
+            }
+            if (isHVM && !pvDrvInstalled) {
+                s_logger.warn(": You attempted an operation on a VM which requires PV drivers to be installed but the drivers were not detected");
+                return new AttachAnswer("You attempted an operation that requires PV drivers to be installed on the VM. Please install them by inserting xen-pv-drv.iso.");
+            }
+
+            // Figure out the disk number to attach the VM to
+            String diskNumber = null;
+            Long deviceId = disk.getDiskSeq();
+            if( deviceId != null ) {
+                if( deviceId.longValue() == 3 ) {
+                    String msg = "Device 3 is reserved for CD-ROM, choose other device";
+                    return new AttachAnswer(msg);
+                }
+                if(this.hypervisorResource.isDeviceUsed(conn, vm, deviceId)) {
+                    String msg = "Device " + deviceId + " is used in VM " + vmName;
+                    return new AttachAnswer(msg);
+                }
+                diskNumber = deviceId.toString();
+            } else {
+                diskNumber = this.hypervisorResource.getUnusedDeviceNum(conn, vm);
+            }
+            // Create a new VBD
+            VBD.Record vbdr = new VBD.Record();
+            vbdr.VM = vm;
+            vbdr.VDI = vdi;
+            vbdr.bootable = false;
+            vbdr.userdevice = diskNumber;
+            vbdr.mode = Types.VbdMode.RW;
+            vbdr.type = Types.VbdType.DISK;
+            vbdr.unpluggable = true;
+            VBD vbd = VBD.create(conn, vbdr);
+
+            // Attach the VBD to the VM
+            vbd.plug(conn);
+
+            // Update the VDI's label to include the VM name
+            vdi.setNameLabel(conn, vmName + "-DATA");
+            DiskTO newDisk = new DiskTO(disk.getData(), Long.parseLong(diskNumber), disk.getType());
+            return new AttachAnswer(newDisk);
+
+        } catch (XenAPIException e) {
+            String msg = "Failed to attach volume" + " for uuid: " + data.getPath() + "  due to " + e.toString();
+            s_logger.warn(msg, e);
+            return new AttachAnswer(msg);
+        } catch (Exception e) {
+            String msg = "Failed to attach volume" + " for uuid: " + data.getPath() + "  due to "  + e.getMessage();
+            s_logger.warn(msg, e);
+            return new AttachAnswer(msg);
+        }
+    }
+    
+    @Override
+    public Answer dettachIso(DettachCommand cmd) {
+        DiskTO disk = cmd.getDisk();
+        DataTO data = disk.getData();
+        DataStoreTO store = data.getDataStore();
+
+        if (!(store instanceof NfsTO)) {
+            s_logger.debug("Can't attach a iso which is not created on nfs: ");
+            return new DettachAnswer("Can't attach a iso which is not created on nfs: ");
+        }
+        NfsTO nfsStore = (NfsTO)store;
+        String isoURL = nfsStore.getUrl() + File.separator + data.getPath();
+
+        try {
+            Connection conn = this.hypervisorResource.getConnection();
+            // Find the VM
+            VM vm = this.hypervisorResource.getVM(conn, cmd.getVmName());
+            String vmUUID = vm.getUuid(conn);
+
+            // Find the ISO VDI
+            VDI isoVDI = this.hypervisorResource.getIsoVDIByURL(conn, cmd.getVmName(), isoURL);
+
+            SR sr = isoVDI.getSR(conn);
+
+            // Look up all VBDs for this VDI
+            Set<VBD> vbds = isoVDI.getVBDs(conn);
+
+            // Iterate through VBDs, and if the VBD belongs the VM, eject
+            // the ISO from it
+            for (VBD vbd : vbds) {
+                VM vbdVM = vbd.getVM(conn);
+                String vbdVmUUID = vbdVM.getUuid(conn);
+
+                if (vbdVmUUID.equals(vmUUID)) {
+                    // If an ISO is already inserted, eject it
+                    if (!vbd.getEmpty(conn)) {
+                        vbd.eject(conn);
+                    }
+                    break;
+                }
+            }
+
+            if (!sr.getNameLabel(conn).startsWith("XenServer Tools")) {
+                this.hypervisorResource.removeSR(conn, sr);
+            }
+
+            return new DettachAnswer(disk);
+        } catch (XenAPIException e) {
+            String msg = "Failed to dettach volume" + " for uuid: " + data.getPath() + "  due to " + e.toString();
+            s_logger.warn(msg, e);
+            return new DettachAnswer(msg);
+        } catch (Exception e) {
+            String msg = "Failed to dettach volume" + " for uuid: " + data.getPath() + "  due to "  + e.getMessage();
+            s_logger.warn(msg, e);
+            return new DettachAnswer(msg);
+        } 
+    }
+
+
+    @Override
+    public Answer dettachVolume(DettachCommand cmd) {
+        String vmName = cmd.getVmName();
+        DiskTO disk = cmd.getDisk();
+        DataTO data = disk.getData();
+        try {
+            Connection conn = this.hypervisorResource.getConnection();
+            // Look up the VDI
+            VDI vdi = this.hypervisorResource.mount(conn, null, null, data.getPath());
+            // Look up the VM
+            VM vm = this.hypervisorResource.getVM(conn, vmName);
+            /* For HVM guest, if no pv driver installed, no attach/detach */
+            boolean isHVM;
+            if (vm.getPVBootloader(conn).equalsIgnoreCase("")) {
+                isHVM = true;
+            } else {
+                isHVM = false;
+            }
+            VMGuestMetrics vgm = vm.getGuestMetrics(conn);
+            boolean pvDrvInstalled = false;
+            if (!this.hypervisorResource.isRefNull(vgm) && vgm.getPVDriversUpToDate(conn)) {
+                pvDrvInstalled = true;
+            }
+            if (isHVM && !pvDrvInstalled) {
+                s_logger.warn(": You attempted an operation on a VM which requires PV drivers to be installed but the drivers were not detected");
+                return new DettachAnswer("You attempted an operation that requires PV drivers to be installed on the VM. Please install them by inserting xen-pv-drv.iso.");
+            }
+
+            
+            // Look up all VBDs for this VDI
+            Set<VBD> vbds = vdi.getVBDs(conn);
+
+            // Detach each VBD from its VM, and then destroy it
+            for (VBD vbd : vbds) {
+                VBD.Record vbdr = vbd.getRecord(conn);
+
+                if (vbdr.currentlyAttached) {
+                    vbd.unplug(conn);
+                }
+
+                vbd.destroy(conn);
+            }
+
+            // Update the VDI's label to be "detached"
+            vdi.setNameLabel(conn, "detached");
+
+            this.hypervisorResource.umount(conn, vdi);
+
+            return new DettachAnswer(disk);
+        } catch(Exception e) {
+            s_logger.warn("Failed dettach volume: " + data.getPath());
+            return new DettachAnswer("Failed dettach volume: " + data.getPath() + ", due to " + e.toString());
+        }
+    }
+    
+
+    protected SR getSRByNameLabel(Connection conn, String nameLabel) throws BadServerResponse, XenAPIException, XmlRpcException {
+        Set<SR> srs = SR.getByNameLabel(conn, nameLabel);
+        if (srs.size() != 1) {
+            throw new CloudRuntimeException("storage uuid: " + nameLabel + " is not unique");
+        }
+        SR poolsr = srs.iterator().next();
+        return poolsr;
+    }
+
+    protected VDI createVdi(Connection conn, String vdiName, SR sr, long size) throws BadServerResponse, XenAPIException, XmlRpcException {
+        VDI.Record vdir = new VDI.Record();
+        vdir.nameLabel = vdiName;
+        vdir.SR = sr;
+        vdir.type = Types.VdiType.USER;
+
+        vdir.virtualSize = size;
+        VDI vdi = VDI.create(conn, vdir);
+        return vdi;
+    }
+
+    protected void deleteVDI(Connection conn, VDI vdi) throws BadServerResponse, XenAPIException, XmlRpcException {
+        vdi.destroy(conn);
+    }
+
+    @Override
+    public Answer createSnapshot(CreateObjectCommand cmd) {
+        Connection conn = hypervisorResource.getConnection();
+        SnapshotObjectTO snapshotTO = (SnapshotObjectTO)cmd.getData();
+        long snapshotId = snapshotTO.getId();
+        String snapshotName = snapshotTO.getName();
+        String details = "create snapshot operation Failed for snapshotId: " + snapshotId;
+        String snapshotUUID = null;
+
+        try {
+            String volumeUUID = snapshotTO.getVolume().getPath();
+            VDI volume = VDI.getByUuid(conn, volumeUUID);
+
+            VDI snapshot = volume.snapshot(conn, new HashMap<String, String>());
+
+            if (snapshotName != null) {
+                snapshot.setNameLabel(conn, snapshotName);
+            }
+
+            snapshotUUID = snapshot.getUuid(conn);
+            String preSnapshotUUID = snapshotTO.getParentSnapshotPath();
+            //check if it is a empty snapshot
+            if( preSnapshotUUID != null) {
+                SR sr = volume.getSR(conn);
+                String srUUID = sr.getUuid(conn);
+                String type = sr.getType(conn);
+                Boolean isISCSI = IsISCSI(type);
+                String snapshotParentUUID = getVhdParent(conn, srUUID, snapshotUUID, isISCSI);
+
+                String preSnapshotParentUUID = getVhdParent(conn, srUUID, preSnapshotUUID, isISCSI);
+                if( snapshotParentUUID != null && snapshotParentUUID.equals(preSnapshotParentUUID)) {
+                    // this is empty snapshot, remove it
+                    snapshot.destroy(conn);
+                    snapshotUUID = preSnapshotUUID;
+                }
+            }
+            SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
+            newSnapshot.setPath(snapshotUUID);
+            return new CreateObjectAnswer(newSnapshot);
+        } catch (XenAPIException e) {
+            details += ", reason: " + e.toString();
+            s_logger.warn(details, e);
+        } catch (Exception e) {
+            details += ", reason: " + e.toString();
+            s_logger.warn(details, e);
+        }
+
+        return new CreateObjectAnswer(details);
+    }
+    
+    @Override
+    public Answer deleteVolume(DeleteCommand cmd) {
+    	DataTO volume = cmd.getData();
+        Connection conn = hypervisorResource.getConnection();
+        String errorMsg = null;
+        try {
+            VDI vdi = VDI.getByUuid(conn, volume.getPath());
+            deleteVDI(conn, vdi);
+            return new Answer(null);
+        } catch (BadServerResponse e) {
+            s_logger.debug("Failed to delete volume", e);
+            errorMsg = e.toString();
+        } catch (XenAPIException e) {
+            s_logger.debug("Failed to delete volume", e);
+            errorMsg = e.toString();
+        } catch (XmlRpcException e) {
+            s_logger.debug("Failed to delete volume", e);
+            errorMsg = e.toString();
+        }
+        return new Answer(null, false, errorMsg);
+    }
+
+
+    protected SR getNfsSR(Connection conn, StorageFilerTO pool) {
+        Map<String, String> deviceConfig = new HashMap<String, String>();
+        try {
+            String server = pool.getHost();
+            String serverpath = pool.getPath();
+            serverpath = serverpath.replace("//", "/");
+            Set<SR> srs = SR.getAll(conn);
+            for (SR sr : srs) {
+                if (!SRType.NFS.equals(sr.getType(conn))) {
+                    continue;
+                }
+
+                Set<PBD> pbds = sr.getPBDs(conn);
+                if (pbds.isEmpty()) {
+                    continue;
+                }
+
+                PBD pbd = pbds.iterator().next();
+
+                Map<String, String> dc = pbd.getDeviceConfig(conn);
+
+                if (dc == null) {
+                    continue;
+                }
+
+                if (dc.get("server") == null) {
+                    continue;
+                }
+
+                if (dc.get("serverpath") == null) {
+                    continue;
+                }
+
+                if (server.equals(dc.get("server")) && serverpath.equals(dc.get("serverpath"))) {
+                    throw new CloudRuntimeException("There is a SR using the same configuration server:" + dc.get("server") + ", serverpath:"
+                            + dc.get("serverpath") + " for pool " + pool.getUuid() + "on host:" + hypervisorResource.getHost().uuid);
+                }
+
+            }
+            deviceConfig.put("server", server);
+            deviceConfig.put("serverpath", serverpath);
+            Host host = Host.getByUuid(conn, hypervisorResource.getHost().uuid);
+            SR sr = SR.create(conn, host, deviceConfig, new Long(0), pool.getUuid(), Long.toString(pool.getId()), SRType.NFS.toString(), "user", true,
+                    new HashMap<String, String>());
+            sr.scan(conn);
+            return sr;
+        } catch (XenAPIException e) {
+            throw new CloudRuntimeException("Unable to create NFS SR " + pool.toString(), e);
+        } catch (XmlRpcException e) {
+            throw new CloudRuntimeException("Unable to create NFS SR " + pool.toString(), e);
+        }
+    }
+    
+    protected SR getIscsiSR(Connection conn, StorageFilerTO pool) {
+        synchronized (pool.getUuid().intern()) {
+            Map<String, String> deviceConfig = new HashMap<String, String>();
+            try {
+                String target = pool.getHost();
+                String path = pool.getPath();
+                if (path.endsWith("/")) {
+                    path = path.substring(0, path.length() - 1);
+                }
+
+                String tmp[] = path.split("/");
+                if (tmp.length != 3) {
+                    String msg = "Wrong iscsi path " + pool.getPath() + " it should be /targetIQN/LUN";
+                    s_logger.warn(msg);
+                    throw new CloudRuntimeException(msg);
+                }
+                String targetiqn = tmp[1].trim();
+                String lunid = tmp[2].trim();
+                String scsiid = "";
+
+                Set<SR> srs = SR.getByNameLabel(conn, pool.getUuid());
+                for (SR sr : srs) {
+                    if (!SRType.LVMOISCSI.equals(sr.getType(conn))) {
+                        continue;
+                    }
+                    Set<PBD> pbds = sr.getPBDs(conn);
+                    if (pbds.isEmpty()) {
+                        continue;
+                    }
+                    PBD pbd = pbds.iterator().next();
+                    Map<String, String> dc = pbd.getDeviceConfig(conn);
+                    if (dc == null) {
+                        continue;
+                    }
+                    if (dc.get("target") == null) {
+                        continue;
+                    }
+                    if (dc.get("targetIQN") == null) {
+                        continue;
+                    }
+                    if (dc.get("lunid") == null) {
+                        continue;
+                    }
+                    if (target.equals(dc.get("target")) && targetiqn.equals(dc.get("targetIQN")) && lunid.equals(dc.get("lunid"))) {
+                        throw new CloudRuntimeException("There is a SR using the same configuration target:" + dc.get("target") +  ",  targetIQN:"
+                                + dc.get("targetIQN")  + ", lunid:" + dc.get("lunid") + " for pool " + pool.getUuid() + "on host:" + this.hypervisorResource.getHost().uuid);
+                    }
+                }
+                deviceConfig.put("target", target);
+                deviceConfig.put("targetIQN", targetiqn);
+
+                Host host = Host.getByUuid(conn, this.hypervisorResource.getHost().uuid);
+                Map<String, String> smConfig = new HashMap<String, String>();
+                String type = SRType.LVMOISCSI.toString();
+                String poolId = Long.toString(pool.getId());
+                SR sr = null;
+                try {
+                    sr = SR.create(conn, host, deviceConfig, new Long(0), pool.getUuid(), poolId, type, "user", true,
+                            smConfig);
+                } catch (XenAPIException e) {
+                    String errmsg = e.toString();
+                    if (errmsg.contains("SR_BACKEND_FAILURE_107")) {
+                        String lun[] = errmsg.split("<LUN>");
+                        boolean found = false;
+                        for (int i = 1; i < lun.length; i++) {
+                            int blunindex = lun[i].indexOf("<LUNid>") + 7;
+                            int elunindex = lun[i].indexOf("</LUNid>");
+                            String ilun = lun[i].substring(blunindex, elunindex);
+                            ilun = ilun.trim();
+                            if (ilun.equals(lunid)) {
+                                int bscsiindex = lun[i].indexOf("<SCSIid>") + 8;
+                                int escsiindex = lun[i].indexOf("</SCSIid>");
+                                scsiid = lun[i].substring(bscsiindex, escsiindex);
+                                scsiid = scsiid.trim();
+                                found = true;
+                                break;
+                            }
+                        }
+                        if (!found) {
+                            String msg = "can not find LUN " + lunid + " in " + errmsg;
+                            s_logger.warn(msg);
+                            throw new CloudRuntimeException(msg);
+                        }
+                    } else {
+                        String msg = "Unable to create Iscsi SR  " + deviceConfig + " due to  " + e.toString();
+                        s_logger.warn(msg, e);
+                        throw new CloudRuntimeException(msg, e);
+                    }
+                }
+                deviceConfig.put("SCSIid", scsiid);
+
+                String result = SR.probe(conn, host, deviceConfig, type , smConfig);
+                String pooluuid = null;
+                if( result.indexOf("<UUID>") != -1) {
+                    pooluuid = result.substring(result.indexOf("<UUID>") + 6, result.indexOf("</UUID>")).trim();
+                }
+                if( pooluuid == null || pooluuid.length() != 36) {
+                    sr = SR.create(conn, host, deviceConfig, new Long(0), pool.getUuid(), poolId, type, "user", true,
+                            smConfig);
+                } else {
+                    sr = SR.introduce(conn, pooluuid, pool.getUuid(), poolId,
+                            type, "user", true, smConfig);
+                    Pool.Record pRec = XenServerConnectionPool.getPoolRecord(conn);
+                    PBD.Record rec = new PBD.Record();
+                    rec.deviceConfig = deviceConfig;
+                    rec.host = pRec.master;
+                    rec.SR = sr;
+                    PBD pbd = PBD.create(conn, rec);
+                    pbd.plug(conn);
+                }
+                sr.scan(conn);
+                return sr;
+            } catch (XenAPIException e) {
+                String msg = "Unable to create Iscsi SR  " + deviceConfig + " due to  " + e.toString();
+                s_logger.warn(msg, e);
+                throw new CloudRuntimeException(msg, e);
+            } catch (Exception e) {
+                String msg = "Unable to create Iscsi SR  " + deviceConfig + " due to  " + e.getMessage();
+                s_logger.warn(msg, e);
+                throw new CloudRuntimeException(msg, e);
+            }
+        }
+    }
+    protected Answer execute(CreateStoragePoolCommand cmd) {
+        Connection conn = this.hypervisorResource.getConnection();
+        StorageFilerTO pool = cmd.getPool();
+        try {
+            if (pool.getType() == StoragePoolType.NetworkFilesystem) {
+                getNfsSR(conn, pool);
+            } else if (pool.getType() == StoragePoolType.IscsiLUN) {
+                getIscsiSR(conn, pool);
+            } else if (pool.getType() == StoragePoolType.PreSetup) {
+            } else {
+                return new Answer(cmd, false, "The pool type: " + pool.getType().name() + " is not supported.");
+            }
+            return new Answer(cmd, true, "success");
+        } catch (Exception e) {
+            String msg = "Catch Exception " + e.getClass().getName() + ", create StoragePool failed due to " + e.toString() + " on host:" + this.hypervisorResource.getHost().uuid + " pool: " + pool.getHost() + pool.getPath();
+            s_logger.warn(msg, e);
+            return new Answer(cmd, false, msg);
+        }
+
+    }
+
+    protected Answer directDownloadHttpTemplate(CopyCommand cmd, DecodedDataObject srcObj, DecodedDataObject destObj) {
+        Connection conn = hypervisorResource.getConnection();
+        SR poolsr = null;
+        VDI vdi = null;
+        boolean result = false;
+        try {
+            if (destObj.getPath() == null) {
+                //need to create volume at first
+
+            }
+            vdi = VDI.getByUuid(conn, destObj.getPath());
+            if (vdi == null) {
+                throw new CloudRuntimeException("can't find volume: " + destObj.getPath());
+            }
+            String destStoreUuid = destObj.getStore().getUuid();
+            Set<SR> srs = SR.getByNameLabel(conn, destStoreUuid);
+            if (srs.size() != 1) {
+                throw new CloudRuntimeException("storage uuid: " + destStoreUuid + " is not unique");
+            }
+            poolsr = srs.iterator().next();
+            VDI.Record vdir = vdi.getRecord(conn);
+            String vdiLocation = vdir.location;
+            String pbdLocation = null;
+            if (destObj.getStore().getScheme().equalsIgnoreCase(DataStoreProtocol.NFS.toString())) {
+                pbdLocation = "/run/sr-mount/" + poolsr.getUuid(conn);
+            } else {
+                Set<PBD> pbds = poolsr.getPBDs(conn);
+                if (pbds.size() != 1) {
+                    throw new CloudRuntimeException("Don't how to handle multiple pbds:" + pbds.size() + " for sr: " + poolsr.getUuid(conn));
+                }
+                PBD pbd = pbds.iterator().next();
+                Map<String, String> deviceCfg = pbd.getDeviceConfig(conn);
+                pbdLocation = deviceCfg.get("location");
+            }
+            if (pbdLocation == null) {
+                throw new CloudRuntimeException("Can't get pbd location");
+            }
+
+            String vdiPath = pbdLocation + "/" + vdiLocation + ".vhd";
+            //download a url into vdipath
+            //downloadHttpToLocalFile(vdiPath, template.getPath());
+            hypervisorResource.callHostPlugin(conn, "storagePlugin", "downloadTemplateFromUrl", "destPath", vdiPath, "srcUrl", srcObj.getPath());
+            result = true;
+            //return new CopyCmdAnswer(cmd, vdi.getUuid(conn));
+        } catch (BadServerResponse e) {
+            s_logger.debug("Failed to download template", e);
+        } catch (XenAPIException e) {
+            s_logger.debug("Failed to download template", e);
+        } catch (XmlRpcException e) {
+            s_logger.debug("Failed to download template", e);
+        } catch (Exception e) {
+            s_logger.debug("Failed to download template", e);
+        } finally {
+            if (!result && vdi != null) {
+                try {
+                    vdi.destroy(conn);
+                } catch (BadServerResponse e) {
+                   s_logger.debug("Failed to cleanup newly created vdi");
+                } catch (XenAPIException e) {
+                    s_logger.debug("Failed to cleanup newly created vdi");
+                } catch (XmlRpcException e) {
+                    s_logger.debug("Failed to cleanup newly created vdi");
+                }
+            }
+        }
+        return new Answer(cmd, false, "Failed to download template");
+    }
+
+    protected Answer execute(AttachPrimaryDataStoreCmd cmd) {
+        String dataStoreUri = cmd.getDataStore();
+        Connection conn = hypervisorResource.getConnection();
+        try {
+            DecodedDataObject obj = Decoder.decode(dataStoreUri);
+
+            DecodedDataStore store = obj.getStore();
+
+            SR sr = hypervisorResource.getStorageRepository(conn, store.getUuid());
+            hypervisorResource.setupHeartbeatSr(conn, sr, false);
+            long capacity = sr.getPhysicalSize(conn);
+            long available = capacity - sr.getPhysicalUtilisation(conn);
+            if (capacity == -1) {
+                String msg = "Pool capacity is -1! pool: ";
+                s_logger.warn(msg);
+                return new Answer(cmd, false, msg);
+            }
+            AttachPrimaryDataStoreAnswer answer = new AttachPrimaryDataStoreAnswer(cmd);
+            answer.setCapacity(capacity);
+            answer.setUuid(sr.getUuid(conn));
+            answer.setAvailable(available);
+            return answer;
+        } catch (XenAPIException e) {
+            String msg = "AttachPrimaryDataStoreCmd add XenAPIException:" + e.toString();
+            s_logger.warn(msg, e);
+            return new Answer(cmd, false, msg);
+        } catch (Exception e) {
+            String msg = "AttachPrimaryDataStoreCmd failed:" + e.getMessage();
+            s_logger.warn(msg, e);
+            return new Answer(cmd, false, msg);
+        }
+    }
+
+    private boolean IsISCSI(String type) {
+        return SRType.LVMOHBA.equals(type) || SRType.LVMOISCSI.equals(type) || SRType.LVM.equals(type) ;
+    }
+
+    private String copy_vhd_from_secondarystorage(Connection conn, String mountpoint, String sruuid, int wait) {
+        String nameLabel = "cloud-" + UUID.randomUUID().toString();
+        String results = hypervisorResource.callHostPluginAsync(conn, "vmopspremium", "copy_vhd_from_secondarystorage",
+                wait, "mountpoint", mountpoint, "sruuid", sruuid, "namelabel", nameLabel);
+        String errMsg = null;
+        if (results == null || results.isEmpty()) {
+            errMsg = "copy_vhd_from_secondarystorage return null";
+        } else {
+            String[] tmp = results.split("#");
+            String status = tmp[0];
+            if (status.equals("0")) {
+                return tmp[1];
+            } else {
+                errMsg = tmp[1];
+            }
+        }
+        String source = mountpoint.substring(mountpoint.lastIndexOf('/') + 1);
+        if( hypervisorResource.killCopyProcess(conn, source) ) {
+            destroyVDIbyNameLabel(conn, nameLabel);
+        }
+        s_logger.warn(errMsg);
+        throw new CloudRuntimeException(errMsg);
+    }
+
+    private void destroyVDIbyNameLabel(Connection conn, String nameLabel) {
+        try {
+            Set<VDI> vdis = VDI.getByNameLabel(conn, nameLabel);
+            if ( vdis.size() != 1 ) {
+                s_logger.warn("destoryVDIbyNameLabel failed due to there are " + vdis.size() + " VDIs with name " + nameLabel);
+                return;
+            }
+            for (VDI vdi : vdis) {
+                try {
+                    vdi.destroy(conn);
+                } catch (Exception e) {
+                }
+            }
+        } catch (Exception e){
+        }
+    }
+
+    protected VDI getVDIbyUuid(Connection conn, String uuid) {
+        try {
+            return VDI.getByUuid(conn, uuid);
+        } catch (Exception e) {
+            String msg = "Catch Exception " + e.getClass().getName() + " :VDI getByUuid for uuid: " + uuid + " failed due to " + e.toString();
+            s_logger.debug(msg);
+            throw new CloudRuntimeException(msg, e);
+        }
+    }
+
+    protected String getVhdParent(Connection conn, String primaryStorageSRUuid, String snapshotUuid, Boolean isISCSI) {
+        String parentUuid = hypervisorResource.callHostPlugin(conn, "vmopsSnapshot", "getVhdParent", "primaryStorageSRUuid", primaryStorageSRUuid,
+                "snapshotUuid", snapshotUuid, "isISCSI", isISCSI.toString());
+
+        if (parentUuid == null || parentUuid.isEmpty() || parentUuid.equalsIgnoreCase("None")) {
+            s_logger.debug("Unable to get parent of VHD " + snapshotUuid + " in SR " + primaryStorageSRUuid);
+            // errString is already logged.
+            return null;
+        }
+        return parentUuid;
+    }
+
+    @Override
+    public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) {
+    	DataTO srcData = cmd.getSrcTO();
+    	DataTO destData = cmd.getDestTO();
+    	int wait = cmd.getWait();
+        DataStoreTO srcStore = srcData.getDataStore();
+        try {
+            if ((srcStore instanceof NfsTO) && (srcData.getObjectType() == DataObjectType.TEMPLATE)) {
+                NfsTO srcImageStore = (NfsTO)srcStore;
+                TemplateObjectTO srcTemplate = (TemplateObjectTO)srcData;
+                String storeUrl = srcImageStore.getUrl();
+            
+                URI uri = new URI(storeUrl);
+                String tmplpath = uri.getHost() + ":" + uri.getPath() + "/" + srcData.getPath();
+                PrimaryDataStoreTO destStore = (PrimaryDataStoreTO)destData.getDataStore();
+                String poolName = destStore.getUuid();
+                Connection conn = hypervisorResource.getConnection();
+
+                SR poolsr = null;
+                Set<SR> srs = SR.getByNameLabel(conn, poolName);
+                if (srs.size() != 1) {
+                    String msg = "There are " + srs.size() + " SRs with same name: " + poolName;
+                    s_logger.warn(msg);
+                    return new CopyCmdAnswer(msg);
+                } else {
+                    poolsr = srs.iterator().next();
+                }
+                String pUuid = poolsr.getUuid(conn);
+                boolean isISCSI = IsISCSI(poolsr.getType(conn));
+                String uuid = copy_vhd_from_secondarystorage(conn, tmplpath, pUuid, wait);
+                VDI tmpl = getVDIbyUuid(conn, uuid);
+                VDI snapshotvdi = tmpl.snapshot(conn, new HashMap<String, String>());
+                String snapshotUuid = snapshotvdi.getUuid(conn);
+                snapshotvdi.setNameLabel(conn, "Template " + srcTemplate.getName());
+                String parentuuid = getVhdParent(conn, pUuid, snapshotUuid, isISCSI);
+                VDI parent = getVDIbyUuid(conn, parentuuid);
+                Long phySize = parent.getPhysicalUtilisation(conn);
+                tmpl.destroy(conn);
+                poolsr.scan(conn);
+                try{
+                    Thread.sleep(5000);
+                } catch (Exception e) {
+                }
+
+                TemplateObjectTO newVol = new TemplateObjectTO();
+                newVol.setUuid(snapshotvdi.getUuid(conn));
+                newVol.setPath(newVol.getUuid());
+                return new CopyCmdAnswer(newVol);
+            }
+        }catch (Exception e) {
+            String msg = "Catch Exception " + e.getClass().getName() + " for template + " + " due to " + e.toString();
+            s_logger.warn(msg, e);
+            return new CopyCmdAnswer(msg);
+        }
+        return new CopyCmdAnswer("not implemented yet");
+    }
+
+    @Override
+    public Answer createVolume(CreateObjectCommand cmd) {
+    	DataTO data = cmd.getData();
+    	VolumeObjectTO volume = (VolumeObjectTO)data;
+
+    	try {
+    		Connection conn = hypervisorResource.getConnection();
+    		PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)data.getDataStore();
+    		SR poolSr = hypervisorResource.getStorageRepository(conn, primaryStore.getUuid());
+    		VDI.Record vdir = new VDI.Record();
+    		vdir.nameLabel = volume.getName();
+    		vdir.SR = poolSr;
+    		vdir.type = Types.VdiType.USER;
+
+    		vdir.virtualSize = volume.getSize();
+    		VDI vdi;
+
+    		vdi = VDI.create(conn, vdir);
+    		vdir = vdi.getRecord(conn);
+    		VolumeObjectTO newVol = new VolumeObjectTO();
+    		newVol.setName(vdir.nameLabel);
+    		newVol.setSize(vdir.virtualSize);
+    		newVol.setPath(vdir.uuid);
+
+    		return new CreateObjectAnswer(newVol);
+    	} catch (Exception e) {
+    		s_logger.debug("create volume failed: " + e.toString());
+    		return new CreateObjectAnswer(e.toString());
+    	}
+    }
+
+    @Override
+    public Answer cloneVolumeFromBaseTemplate(CopyCommand cmd) {
+        Connection conn = hypervisorResource.getConnection();
+        DataTO srcData = cmd.getSrcTO();
+        DataTO destData = cmd.getDestTO();
+        PrimaryDataStoreTO pool = (PrimaryDataStoreTO)destData.getDataStore();
+        VolumeObjectTO volume = (VolumeObjectTO)destData;
+        VDI vdi = null;
+        try {
+            VDI tmpltvdi = null;
+
+            tmpltvdi = getVDIbyUuid(conn, srcData.getPath());
+            vdi = tmpltvdi.createClone(conn, new HashMap<String, String>());
+            vdi.setNameLabel(conn, volume.getName());
+
+
+            VDI.Record vdir;
+            vdir = vdi.getRecord(conn);
+            s_logger.debug("Succesfully created VDI: Uuid = " + vdir.uuid);
+
+            VolumeObjectTO newVol = new VolumeObjectTO();
+            newVol.setName(vdir.nameLabel);
+            newVol.setSize(vdir.virtualSize);
+            newVol.setPath(vdir.uuid);
+
+            return new CopyCmdAnswer(newVol);
+        } catch (Exception e) {
+            s_logger.warn("Unable to create volume; Pool=" + pool + "; Disk: ", e);
+            return new CopyCmdAnswer(e.toString());
+        }
+    }
+
+    @Override
+    public Answer copyVolumeFromImageCacheToPrimary(CopyCommand cmd) {
+        Connection conn = hypervisorResource.getConnection();
+        DataTO srcData = cmd.getSrcTO();
+        DataTO destData = cmd.getDestTO();
+        int wait = cmd.getWait();
+        VolumeObjectTO srcVolume = (VolumeObjectTO)srcData;
+        VolumeObjectTO destVolume = (VolumeObjectTO)destData;
+        PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)destVolume.getDataStore();
+        DataStoreTO srcStore = srcVolume.getDataStore();
+
+        if (srcStore instanceof NfsTO) {
+            NfsTO nfsStore = (NfsTO)srcStore;
+            try {
+                SR primaryStoragePool = hypervisorResource.getStorageRepository(conn, primaryStore.getUuid());
+                String srUuid = primaryStoragePool.getUuid(conn);
+                String volumePath = nfsStore.getUrl() + ":" + srcVolume.getPath();
+                String uuid = copy_vhd_from_secondarystorage(conn, volumePath, srUuid, wait );
+                VolumeObjectTO newVol = new VolumeObjectTO();
+                newVol.setPath(uuid);
+                newVol.setSize(srcVolume.getSize());
+
+                return new CopyCmdAnswer(newVol);
+            } catch (Exception e) {
+                String msg = "Catch Exception " + e.getClass().getName() + " due to " + e.toString();
+                s_logger.warn(msg, e);
+                return new CopyCmdAnswer(e.toString());
+            }
+        }
+
+        s_logger.debug("unsupported protocol");
+        return new CopyCmdAnswer("unsupported protocol");
+    }
+
+    @Override
+    public Answer copyVolumeFromPrimaryToSecondary(CopyCommand cmd) {
+        Connection conn = hypervisorResource.getConnection();
+        VolumeObjectTO srcVolume = (VolumeObjectTO)cmd.getSrcTO();
+        VolumeObjectTO destVolume = (VolumeObjectTO)cmd.getDestTO();
+        int wait = cmd.getWait();
+        DataStoreTO destStore = destVolume.getDataStore();
+
+        if (destStore instanceof NfsTO) {
+            SR secondaryStorage = null;
+            try {
+                NfsTO nfsStore = (NfsTO)destStore;
+                URI uri = new URI(nfsStore.getUrl());
+                // Create the volume folder
+                if (!hypervisorResource.createSecondaryStorageFolder(conn, uri.getHost() + ":" + uri.getPath(), destVolume.getPath())) {
+                    throw new InternalErrorException("Failed to create the volume folder.");
+                }
+
+                // Create a SR for the volume UUID folder
+                secondaryStorage = hypervisorResource.createNfsSRbyURI(conn, new URI(nfsStore.getUrl() + destVolume.getPath()), false);
+                // Look up the volume on the source primary storage pool
+                VDI srcVdi = getVDIbyUuid(conn, srcVolume.getPath());
+                // Copy the volume to secondary storage
+                VDI destVdi = hypervisorResource.cloudVDIcopy(conn, srcVdi, secondaryStorage, wait);
+                String destVolumeUUID = destVdi.getUuid(conn);
+
+                VolumeObjectTO newVol = new VolumeObjectTO();
+                newVol.setPath(destVolumeUUID);
+                newVol.setSize(srcVolume.getSize());
+                return new CopyCmdAnswer(newVol);
+            } catch (Exception e) {
+                s_logger.debug("Failed to copy volume to secondary: " + e.toString());
+                return new CopyCmdAnswer("Failed to copy volume to secondary: " + e.toString());
+            } finally {
+                hypervisorResource.removeSR(conn, secondaryStorage);
+            }
+        }
+        return new CopyCmdAnswer("unsupported protocol");
+    }
+
+    boolean swiftUpload(Connection conn, SwiftTO swift, String container, String ldir, String lfilename, Boolean isISCSI, int wait) {
+        String result = null;
+        try {
+            result = hypervisorResource.callHostPluginAsync(conn, "swiftxen", "swift", wait,
+                    "op", "upload", "url", swift.getUrl(), "account", swift.getAccount(),
+                    "username", swift.getUserName(), "key", swift.getKey(), "container", container,
+                    "ldir", ldir, "lfilename", lfilename, "isISCSI", isISCSI.toString());
+            if( result != null && result.equals("true")) {
+                return true;
+            }
+        } catch (Exception e) {
+            s_logger.warn("swift upload failed due to " + e.toString(), e);
+        }
+        return false;
+    }
+
+    protected String deleteSnapshotBackup(Connection conn, String path, String secondaryStorageMountPath, String backupUUID) {
+
+        // If anybody modifies the formatting below again, I'll skin them
+        String result = hypervisorResource.callHostPlugin(conn, "vmopsSnapshot", "deleteSnapshotBackup", "backupUUID", backupUUID, "path", path, "secondaryStorageMountPath", secondaryStorageMountPath);
+
+        return result;
+    }
+
+    public void swiftBackupSnapshot(Connection conn, SwiftTO swift, String srUuid, String snapshotUuid, String container, Boolean isISCSI, int wait)  {
+        String lfilename;
+        String ldir;
+        if ( isISCSI ) {
+            ldir = "/dev/VG_XenStorage-" + srUuid;
+            lfilename = "VHD-" + snapshotUuid;
+        } else {
+            ldir = "/var/run/sr-mount/" + srUuid;
+            lfilename = snapshotUuid + ".vhd";
+        }
+        swiftUpload(conn, swift, container, ldir, lfilename, isISCSI, wait);
+    }
+
+    private static List<String> serializeProperties(final Object object,
+            final Class<?> propertySet) {
+
+        assert object != null;
+        assert propertySet != null;
+        assert propertySet.isAssignableFrom(object.getClass());
+
+        try {
+
+            final BeanInfo beanInfo = Introspector.getBeanInfo(propertySet);
+            final PropertyDescriptor[] descriptors = beanInfo
+                    .getPropertyDescriptors();
+
+            final List<String> serializedProperties = new ArrayList<String>();
+            for (final PropertyDescriptor descriptor : descriptors) {
+
+                serializedProperties.add(descriptor.getName());
+                final Object value = descriptor.getReadMethod().invoke(object);
+                serializedProperties.add(value != null ? value.toString()
+                        : "null");
+
+            }
+
+            return Collections.unmodifiableList(serializedProperties);
+
+        } catch (IntrospectionException e) {
+            s_logger.warn(
+                    "Ignored IntrospectionException when serializing class "
+                            + object.getClass().getCanonicalName(), e);
+        } catch (IllegalArgumentException e) {
+            s_logger.warn(
+                    "Ignored IllegalArgumentException when serializing class "
+                            + object.getClass().getCanonicalName(), e);
+        } catch (IllegalAccessException e) {
+            s_logger.warn(
+                    "Ignored IllegalAccessException when serializing class "
+                            + object.getClass().getCanonicalName(), e);
+        } catch (InvocationTargetException e) {
+            s_logger.warn(
+                    "Ignored InvocationTargetException when serializing class "
+                            + object.getClass().getCanonicalName(), e);
+        }
+
+        return Collections.emptyList();
+
+    }
+
+    private boolean backupSnapshotToS3(final Connection connection,
+            final S3TO s3, final String srUuid, final String snapshotUuid,
+            final Boolean iSCSIFlag, final int wait) {
+
+        final String filename = iSCSIFlag ? "VHD-" + snapshotUuid
+                : snapshotUuid + ".vhd";
+        final String dir = (iSCSIFlag ? "/dev/VG_XenStorage-"
+                : "/var/run/sr-mount/") + srUuid;
+        final String key = StringUtils.join("/", "snapshots", snapshotUuid);
+
+        try {
+
+            final List<String> parameters = new ArrayList<String>(
+                    serializeProperties(s3, S3Utils.ClientOptions.class));
+            parameters.addAll(Arrays.asList("operation", "put", "directory",
+                    dir, "filename", filename, "iSCSIFlag",
+                    iSCSIFlag.toString(), "key", key));
+            final String result = hypervisorResource.callHostPluginAsync(connection, "s3xen",
+                    "s3", wait,
+                    parameters.toArray(new String[parameters.size()]));
+
+            if (result != null && result.equals("true")) {
+                return true;
+            }
+
+        } catch (Exception e) {
+            s_logger.error(String.format(
+                    "S3 upload failed of snapshot %1$s due to %2$s.",
+                    snapshotUuid, e.toString()), e);
+        }
+
+        return false;
+
+    }
+
+    protected String backupSnapshot(Connection conn, String primaryStorageSRUuid, String path, String secondaryStorageMountPath, String snapshotUuid, String prevBackupUuid, Boolean isISCSI, int wait) {
+        String backupSnapshotUuid = null;
+
+        if (prevBackupUuid == null) {
+            prevBackupUuid = "";
+        }
+
+        // Each argument is put in a separate line for readability.
+        // Using more lines does not harm the environment.
+        String backupUuid = UUID.randomUUID().toString();
+        String results = hypervisorResource.callHostPluginAsync(conn, "vmopsSnapshot", "backupSnapshot", wait,
+                "primaryStorageSRUuid", primaryStorageSRUuid, "path", path, "secondaryStorageMountPath", secondaryStorageMountPath,
+                "snapshotUuid", snapshotUuid, "prevBackupUuid", prevBackupUuid, "backupUuid", backupUuid, "isISCSI", isISCSI.toString());
+        String errMsg = null;
+        if (results == null || results.isEmpty()) {
+            errMsg = "Could not copy backupUuid: " + backupSnapshotUuid
+                    + " from primary storage " + primaryStorageSRUuid + " to secondary storage "
+                    + secondaryStorageMountPath + " due to null";
+        } else {
+
+            String[] tmp = results.split("#");
+            String status = tmp[0];
+            backupSnapshotUuid = tmp[1];
+            // status == "1" if and only if backupSnapshotUuid != null
+            // So we don't rely on status value but return backupSnapshotUuid as an
+            // indicator of success.
+            if (status != null && status.equalsIgnoreCase("1") && backupSnapshotUuid != null) {
+                s_logger.debug("Successfully copied backupUuid: " + backupSnapshotUuid
+                        + " to secondary storage");
+                return backupSnapshotUuid;
+            } else {
+                errMsg = "Could not copy backupUuid: " + backupSnapshotUuid
+                        + " from primary storage " + primaryStorageSRUuid + " to secondary storage "
+                        + secondaryStorageMountPath + " due to " + tmp[1];
+            }
+        }
+        String source = backupUuid + ".vhd";
+        hypervisorResource.killCopyProcess(conn, source);
+        s_logger.warn(errMsg);
+        return null;
+
+    }
+
+    private boolean destroySnapshotOnPrimaryStorageExceptThis(Connection conn, String volumeUuid, String avoidSnapshotUuid){
+        try {
+            VDI volume = getVDIbyUuid(conn, volumeUuid);
+            if (volume == null) {
+                throw new InternalErrorException("Could not destroy snapshot on volume " + volumeUuid + " due to can not find it");
+            }
+            Set<VDI> snapshots = volume.getSnapshots(conn);
+            for( VDI snapshot : snapshots ) {
+                try {
+                    if(! snapshot.getUuid(conn).equals(avoidSnapshotUuid)) {
+                        snapshot.destroy(conn);
+                    }
+                } catch (Exception e) {
+                    String msg = "Destroying snapshot: " + snapshot+ " on primary storage failed due to " + e.toString();
+                    s_logger.warn(msg, e);
+                }
+            }
+            s_logger.debug("Successfully destroyed snapshot on volume: " + volumeUuid + " execept this current snapshot "+ avoidSnapshotUuid );
+            return true;
+        } catch (XenAPIException e) {
+            String msg = "Destroying snapshot on volume: " + volumeUuid + " execept this current snapshot "+ avoidSnapshotUuid + " failed due to " + e.toString();
+            s_logger.error(msg, e);
+        } catch (Exception e) {
+            String msg = "Destroying snapshot on volume: " + volumeUuid + " execept this current snapshot "+ avoidSnapshotUuid + " failed due to " + e.toString();
+            s_logger.warn(msg, e);
+        }
+
+        return false;
+    }
+
+    @Override
+    public Answer backupSnasphot(CopyCommand cmd) {
+        Connection conn = hypervisorResource.getConnection();
+        DataTO srcData = cmd.getSrcTO();
+        DataTO cacheData = cmd.getCacheTO();
+        DataTO destData = cmd.getDestTO();
+        int wait = cmd.getWait();
+        PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)srcData.getDataStore();
+        String primaryStorageNameLabel = primaryStore.getUuid();
+        String secondaryStorageUrl = null;
+        NfsTO cacheStore = null;
+        String destPath = null;
+        if (cacheData != null) {
+            cacheStore = (NfsTO)cacheData.getDataStore();
+            secondaryStorageUrl = cacheStore.getUrl();
+            destPath = cacheData.getPath();
+        } else {
+            cacheStore = (NfsTO)destData.getDataStore();
+            secondaryStorageUrl = cacheStore.getUrl();
+            destPath = destData.getPath();
+        }
+
+        SnapshotObjectTO snapshotTO = (SnapshotObjectTO)srcData;
+        SnapshotObjectTO snapshotOnImage = (SnapshotObjectTO)destData;
+        String snapshotUuid = snapshotTO.getPath();
+
+        String prevBackupUuid = snapshotOnImage.getParentSnapshotPath();
+        String prevSnapshotUuid = snapshotTO.getParentSnapshotPath();
+
+        // By default assume failure
+        String details = null;
+        String snapshotBackupUuid = null;
+        boolean fullbackup = true;
+        try {
+            SR primaryStorageSR = hypervisorResource.getSRByNameLabelandHost(conn, primaryStorageNameLabel);
+            if (primaryStorageSR == null) {
+                throw new InternalErrorException("Could not backup snapshot because the primary Storage SR could not be created from the name label: " + primaryStorageNameLabel);
+            }
+            String psUuid = primaryStorageSR.getUuid(conn);
+            Boolean isISCSI = IsISCSI(primaryStorageSR.getType(conn));
+
+            VDI snapshotVdi = getVDIbyUuid(conn, snapshotUuid);
+            String snapshotPaUuid = null;
+            if ( prevBackupUuid != null ) {
+                try {
+                    snapshotPaUuid = getVhdParent(conn, psUuid, snapshotUuid, isISCSI);
+                    if( snapshotPaUuid != null ) {
+                        String snashotPaPaPaUuid = getVhdParent(conn, psUuid, snapshotPaUuid, isISCSI);
+                        String prevSnashotPaUuid = getVhdParent(conn, psUuid, prevSnapshotUuid, isISCSI);
+                        if (snashotPaPaPaUuid != null && prevSnashotPaUuid!= null && prevSnashotPaUuid.equals(snashotPaPaPaUuid)) {
+                            fullbackup = false;
+                        }
+                    }
+                } catch (Exception e) {
+                }
+            }
+
+            URI uri = new URI(secondaryStorageUrl);
+            String secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
+            DataStoreTO destStore = destData.getDataStore();
+            String folder = destPath;
+            if (fullbackup) {
+                // the first snapshot is always a full snapshot
+
+                if( !hypervisorResource.createSecondaryStorageFolder(conn, secondaryStorageMountPath, folder)) {
+                    details = " Filed to create folder " + folder + " in secondary storage";
+                    s_logger.warn(details);
+                    return new CopyCmdAnswer(details);
+                }
+                String snapshotMountpoint = secondaryStorageUrl + "/" + folder;
+                SR snapshotSr = null;
+                try {
+                    snapshotSr = hypervisorResource.createNfsSRbyURI(conn, new URI(snapshotMountpoint), false);
+                    VDI backedVdi = hypervisorResource.cloudVDIcopy(conn, snapshotVdi, snapshotSr, wait);
+                    snapshotBackupUuid = backedVdi.getUuid(conn);
+
+                    if( destStore instanceof SwiftTO) {
+                        try {
+                            hypervisorResource.swiftBackupSnapshot(conn, (SwiftTO)destStore, snapshotSr.getUuid(conn), snapshotBackupUuid, "S-" + snapshotTO.getVolume().getVolumeId().toString(), false, wait);
+                            snapshotBackupUuid = snapshotBackupUuid + ".vhd";
+                        } finally {
+                            deleteSnapshotBackup(conn, folder, secondaryStorageMountPath, snapshotBackupUuid);
+                        }
+                    } else if (destStore instanceof S3TO) {
+                        try {
+                            backupSnapshotToS3(conn, (S3TO)destStore, snapshotSr.getUuid(conn), snapshotBackupUuid, isISCSI, wait);
+                            snapshotBackupUuid = snapshotBackupUuid + ".vhd";
+                        } finally {
+                            deleteSnapshotBackup(conn, folder, secondaryStorageMountPath, snapshotBackupUuid);
+                        }
+                    }
+
+                } finally {
+                    if( snapshotSr != null) {
+                        hypervisorResource.removeSR(conn, snapshotSr);
+                    }
+                }
+            } else {
+                String primaryStorageSRUuid = primaryStorageSR.getUuid(conn);
+                if( destStore instanceof SwiftTO ) {
+                    swiftBackupSnapshot(conn, (SwiftTO)destStore, primaryStorageSRUuid, snapshotPaUuid, "S-" + snapshotTO.getVolume().getVolumeId().toString(), isISCSI, wait);
+                    if ( isISCSI ) {
+                        snapshotBackupUuid = "VHD-" + snapshotPaUuid;
+                    } else {
+                        snapshotBackupUuid = snapshotPaUuid + ".vhd";
+                    }
+
+                } else if (destStore instanceof S3TO ) {
+                    backupSnapshotToS3(conn, (S3TO)destStore, primaryStorageSRUuid, snapshotPaUuid, isISCSI, wait);
+                } else {
+                    snapshotBackupUuid = backupSnapshot(conn, primaryStorageSRUuid, folder + File.separator + UUID.nameUUIDFromBytes(secondaryStorageMountPath.getBytes())
+                             , secondaryStorageMountPath, snapshotUuid, prevBackupUuid, isISCSI, wait);
+
+                }
+            }
+            String volumeUuid = snapshotTO.getVolume().getPath();
+            destroySnapshotOnPrimaryStorageExceptThis(conn, volumeUuid, snapshotUuid);
+
+            SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
+            newSnapshot.setPath(folder + File.separator + snapshotBackupUuid);
+            if (fullbackup) {
+                newSnapshot.setParentSnapshotPath(null);
+            } else {
+                newSnapshot.setParentSnapshotPath(prevBackupUuid);
+            }
+            return new CopyCmdAnswer(newSnapshot);
+        } catch (XenAPIException e) {
+            details = "BackupSnapshot Failed due to " + e.toString();
+            s_logger.warn(details, e);
+        } catch (Exception e) {
+            details = "BackupSnapshot Failed due to " + e.getMessage();
+            s_logger.warn(details, e);
+        }
+
+        return new CopyCmdAnswer(details);
+    }
+    
+    @Override
+    public Answer createTemplateFromVolume(CopyCommand cmd) {
+        Connection conn = this.hypervisorResource.getConnection();
+        VolumeObjectTO volume = (VolumeObjectTO)cmd.getSrcTO();
+        TemplateObjectTO template = (TemplateObjectTO)cmd.getDestTO();
+        NfsTO destStore = (NfsTO)cmd.getDestTO().getDataStore();
+        int wait = cmd.getWait();
+        
+        String secondaryStoragePoolURL = destStore.getUrl();
+        String volumeUUID = volume.getPath();
+       
+        String userSpecifiedName = template.getName();
+      
+     
+        String details = null;
+        SR tmpltSR = null;
+        boolean result = false;
+        String secondaryStorageMountPath = null;
+        String installPath = null;
+        try {
+            URI uri = new URI(secondaryStoragePoolURL);
+            secondaryStorageMountPath = uri.getHost() + ":" + uri.getPath();
+            installPath = template.getPath();
+            if( !this.hypervisorResource.createSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath)) {
+                details = " Filed to create folder " + installPath + " in secondary storage";
+                s_logger.warn(details);
+                return new CopyCmdAnswer(details);
+            }
+
+            VDI vol = getVDIbyUuid(conn, volumeUUID);
+            // create template SR
+            URI tmpltURI = new URI(secondaryStoragePoolURL + "/" + installPath);
+            tmpltSR = this.hypervisorResource.createNfsSRbyURI(conn, tmpltURI, false);
+
+            // copy volume to template SR
+            VDI tmpltVDI = this.hypervisorResource.cloudVDIcopy(conn, vol, tmpltSR, wait);
+            // scan makes XenServer pick up VDI physicalSize
+            tmpltSR.scan(conn);
+            if (userSpecifiedName != null) {
+                tmpltVDI.setNameLabel(conn, userSpecifiedName);
+            }
+
+            String tmpltUUID = tmpltVDI.getUuid(conn);
+            String tmpltFilename = tmpltUUID + ".vhd";
+            long virtualSize = tmpltVDI.getVirtualSize(conn);
+            long physicalSize = tmpltVDI.getPhysicalUtilisation(conn);
+            // create the template.properties file
+            String templatePath = secondaryStorageMountPath + "/" + installPath;
+            result = this.hypervisorResource.postCreatePrivateTemplate(conn, templatePath, tmpltFilename, tmpltUUID, userSpecifiedName, null, physicalSize, virtualSize, template.getId());
+            if (!result) {
+                throw new CloudRuntimeException("Could not create the template.properties file on secondary storage dir: " + tmpltURI);
+            }
+            installPath = installPath + "/" + tmpltFilename;
+            this.hypervisorResource.removeSR(conn, tmpltSR);
+            tmpltSR = null;
+            TemplateObjectTO newTemplate = new TemplateObjectTO();
+            newTemplate.setPath(installPath);
+            newTemplate.setFormat(ImageFormat.VHD);
+            CopyCmdAnswer answer = new CopyCmdAnswer(newTemplate);
+            return answer;
+        } catch (Exception e) {
+            if (tmpltSR != null) {
+                this.hypervisorResource.removeSR(conn, tmpltSR);
+            }
+            if ( secondaryStorageMountPath != null) {
+                this.hypervisorResource.deleteSecondaryStorageFolder(conn, secondaryStorageMountPath, installPath);
+            }
+            details = "Creating template from volume " + volumeUUID + " failed due to " + e.toString();
+            s_logger.error(details, e);
+        }
+        return new CopyCmdAnswer(details);
+    }
+}


[6/7] git commit: updated refs/heads/object_store to e444867

Posted by ed...@apache.org.
refactor kvm/vmware resource code


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/42e25a22
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/42e25a22
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/42e25a22

Branch: refs/heads/object_store
Commit: 42e25a22fc7140c68cda589e95d98dda3ba6cdf3
Parents: a83b87b
Author: Edison Su <ed...@citrix.com>
Authored: Thu May 9 23:09:42 2013 -0700
Committer: Edison Su <ed...@citrix.com>
Committed: Thu May 9 23:10:05 2013 -0700

----------------------------------------------------------------------
 api/src/com/cloud/agent/api/to/DataObjectType.java |   25 +
 api/src/com/cloud/agent/api/to/DataTO.java         |   28 +
 api/src/com/cloud/agent/api/to/DiskTO.java         |   60 +
 .../com/cloud/agent/api/to/VirtualMachineTO.java   |    6 +-
 api/src/com/cloud/vm/VirtualMachineProfile.java    |    8 +-
 core/src/com/cloud/serializer/GsonHelper.java      |    2 +-
 .../resource/NfsSecondaryStorageResource.java      |    4 +-
 .../cloud/storage/resource/StorageProcessor.java   |   45 +
 .../resource/StorageSubsystemCommandHandler.java   |   27 +
 .../StorageSubsystemCommandHandlerBase.java        |  135 ++
 .../engine/subsystem/api/storage/DataObject.java   |    2 +
 .../subsystem/api/storage/DataObjectType.java      |   25 -
 .../subsystem/api/storage/DataStoreDriver.java     |    1 +
 .../engine/subsystem/api/storage/DataTO.java       |   30 -
 .../cloudstack/storage/command/AttachAnswer.java   |   44 +
 .../cloudstack/storage/command/AttachCommand.java  |   52 +
 .../cloudstack/storage/command/CopyCmdAnswer.java  |    2 +-
 .../cloudstack/storage/command/CopyCommand.java    |    2 +-
 .../storage/command/CreateObjectAnswer.java        |    2 +-
 .../storage/command/CreateObjectCommand.java       |    2 +-
 .../cloudstack/storage/command/DeleteCommand.java  |    2 +-
 .../cloudstack/storage/command/DettachAnswer.java  |   44 +
 .../cloudstack/storage/command/DettachCommand.java |   52 +
 .../cloudstack/storage/to/PrimaryDataStoreTO.java  |   41 +
 .../cloudstack/storage/to/SnapshotObjectTO.java    |    4 +-
 .../cloudstack/storage/to/TemplateObjectTO.java    |   11 +-
 .../cloudstack/storage/to/VolumeObjectTO.java      |   30 +-
 .../storage/motion/AncientDataMotionStrategy.java  |    4 +-
 .../storage/image/TemplateDataFactoryImpl.java     |   11 +
 .../storage/image/store/TemplateObject.java        |    4 +-
 .../storage/snapshot/SnapshotObject.java           |    4 +-
 .../datastore/ObjectInDataStoreManager.java        |    2 +-
 .../datastore/ObjectInDataStoreManagerImpl.java    |    2 +-
 .../cloudstack/storage/db/ObjectInDataStoreVO.java |    2 +-
 .../storage/datastore/PrimaryDataStoreImpl.java    |    2 +-
 .../cloudstack/storage/volume/VolumeObject.java    |    4 +-
 .../kvm/resource/LibvirtComputingResource.java     |  190 +--
 .../hypervisor/kvm/resource/LibvirtVMDef.java      |    6 +-
 .../kvm/storage/KVMStorageProcessor.java           |  879 +++++++++
 .../hypervisor/kvm/storage/KVMStorageResource.java |   87 +
 .../hypervisor/vmware/resource/VmwareResource.java |  209 ++-
 .../VmwareSecondaryStorageResourceHandler.java     |   10 +
 .../storage/resource/VmwareStorageProcessor.java   | 1144 ++++++++++++
 .../xen/resource/CitrixResourceBase.java           |   84 +-
 .../xen/resource/XenServer56FP1Resource.java       |   21 +-
 .../xen/resource/XenServerStorageProcessor.java    | 1404 +++++++++++++++
 .../xen/resource/XenServerStorageResource.java     | 1327 --------------
 .../driver/CloudStackImageStoreDriverImpl.java     |    4 +-
 .../datastore/driver/S3ImageStoreDriverImpl.java   |    4 +-
 .../driver/SampleImageStoreDriverImpl.java         |    4 +-
 .../driver/SwiftImageStoreDriverImpl.java          |    4 +-
 .../CloudStackPrimaryDataStoreDriverImpl.java      |    4 +-
 .../driver/SamplePrimaryDataStoreDriverImpl.java   |    2 +-
 .../driver/SolidfirePrimaryDataStoreDriver.java    |    2 +-
 .../com/cloud/hypervisor/HypervisorGuruBase.java   |    3 +-
 .../src/com/cloud/storage/VolumeManagerImpl.java   |   70 +-
 .../cloud/storage/download/DownloadListener.java   |    2 +-
 .../com/cloud/template/TemplateManagerImpl.java    |   37 +-
 server/src/com/cloud/vm/UserVmManagerImpl.java     |   52 +-
 .../com/cloud/vm/VirtualMachineProfileImpl.java    |   11 +-
 60 files changed, 4504 insertions(+), 1777 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/api/src/com/cloud/agent/api/to/DataObjectType.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/to/DataObjectType.java b/api/src/com/cloud/agent/api/to/DataObjectType.java
new file mode 100644
index 0000000..6f7a007
--- /dev/null
+++ b/api/src/com/cloud/agent/api/to/DataObjectType.java
@@ -0,0 +1,25 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with 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.
+ */
+package com.cloud.agent.api.to;
+
+public enum DataObjectType {
+    VOLUME,
+    SNAPSHOT,
+    TEMPLATE
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/api/src/com/cloud/agent/api/to/DataTO.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/to/DataTO.java b/api/src/com/cloud/agent/api/to/DataTO.java
new file mode 100644
index 0000000..bd9a16b
--- /dev/null
+++ b/api/src/com/cloud/agent/api/to/DataTO.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with 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.
+ */
+package com.cloud.agent.api.to;
+
+public interface DataTO {
+    public DataObjectType getObjectType();
+    public DataStoreTO getDataStore();
+    /**
+     * @return
+     */
+    String getPath();
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/api/src/com/cloud/agent/api/to/DiskTO.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/to/DiskTO.java b/api/src/com/cloud/agent/api/to/DiskTO.java
new file mode 100644
index 0000000..7b32f00
--- /dev/null
+++ b/api/src/com/cloud/agent/api/to/DiskTO.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with 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.
+ */
+package com.cloud.agent.api.to;
+
+import com.cloud.storage.Volume;
+
+public class DiskTO {
+    private DataTO data;
+    private Long diskSeq;
+    private Volume.Type type;
+    public DiskTO() {
+        
+    }
+    
+    public DiskTO(DataTO data, Long diskSeq, Volume.Type type) {
+        this.data = data;
+        this.diskSeq = diskSeq;
+        this.type = type;
+    }
+
+    public DataTO getData() {
+        return data;
+    }
+
+    public void setData(DataTO data) {
+        this.data = data;
+    }
+
+    public Long getDiskSeq() {
+        return diskSeq;
+    }
+
+    public void setDiskSeq(Long diskSeq) {
+        this.diskSeq = diskSeq;
+    }
+
+    public Volume.Type getType() {
+        return type;
+    }
+
+    public void setType(Volume.Type type) {
+        this.type = type;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/api/src/com/cloud/agent/api/to/VirtualMachineTO.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/to/VirtualMachineTO.java b/api/src/com/cloud/agent/api/to/VirtualMachineTO.java
index b84d20a..2644c04 100644
--- a/api/src/com/cloud/agent/api/to/VirtualMachineTO.java
+++ b/api/src/com/cloud/agent/api/to/VirtualMachineTO.java
@@ -57,7 +57,7 @@ public class VirtualMachineTO {
     Map<String, String> params;
     String uuid;
 
-    VolumeTO[] disks;
+    DiskTO[] disks;
     NicTO[] nics;
 
     public VirtualMachineTO(long id, String instanceName, VirtualMachine.Type type, int cpus, Integer speed, long minRam, long maxRam, BootloaderType bootloader, String os, boolean enableHA, boolean limitCpuUse, String vncPassword) {
@@ -206,11 +206,11 @@ public class VirtualMachineTO {
         this.bootupScripts = bootupScripts;
     }
 
-    public VolumeTO[] getDisks() {
+    public DiskTO[] getDisks() {
         return disks;
     }
 
-    public void setDisks(VolumeTO[] disks) {
+    public void setDisks(DiskTO[] disks) {
         this.disks = disks;
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/api/src/com/cloud/vm/VirtualMachineProfile.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/vm/VirtualMachineProfile.java b/api/src/com/cloud/vm/VirtualMachineProfile.java
index 33a9171..6861372 100644
--- a/api/src/com/cloud/vm/VirtualMachineProfile.java
+++ b/api/src/com/cloud/vm/VirtualMachineProfile.java
@@ -19,6 +19,8 @@ package com.cloud.vm;
 import java.util.List;
 import java.util.Map;
 
+import com.cloud.agent.api.to.DataTO;
+import com.cloud.agent.api.to.DiskTO;
 import com.cloud.agent.api.to.VolumeTO;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.offering.ServiceOffering;
@@ -111,11 +113,11 @@ public interface VirtualMachineProfile<T extends VirtualMachine> {
 
     List<NicProfile> getNics();
 
-    List<VolumeTO> getDisks();
+    List<DiskTO> getDisks();
 
     void addNic(int index, NicProfile nic);
 
-    void addDisk(int index, VolumeTO disk);
+    void addDisk(int index, DiskTO disk);
 
     StringBuilder getBootArgsBuilder();
 
@@ -125,7 +127,7 @@ public interface VirtualMachineProfile<T extends VirtualMachine> {
 
     void addNic(NicProfile nic);
 
-    void addDisk(VolumeTO disk);
+    void addDisk(DiskTO disk);
 
     VirtualMachine.Type getType();
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/core/src/com/cloud/serializer/GsonHelper.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/serializer/GsonHelper.java b/core/src/com/cloud/serializer/GsonHelper.java
index 5656d91..54b6b17 100644
--- a/core/src/com/cloud/serializer/GsonHelper.java
+++ b/core/src/com/cloud/serializer/GsonHelper.java
@@ -20,13 +20,13 @@ package com.cloud.serializer;
 
 import java.util.List;
 
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 import org.apache.log4j.Logger;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
 import com.cloud.agent.api.SecStorageFirewallCfgCommand.PortConfig;
 import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
 import com.cloud.agent.transport.ArrayTypeAdaptor;
 import com.cloud.agent.transport.InterfaceTypeAdaptor;
 import com.cloud.agent.transport.LoggingExclusionStrategy;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java b/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java
index 03e822e..36b6bbc 100755
--- a/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java
+++ b/core/src/com/cloud/storage/resource/NfsSecondaryStorageResource.java
@@ -46,8 +46,6 @@ import java.util.concurrent.Callable;
 
 import javax.naming.ConfigurationException;
 
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 import org.apache.cloudstack.storage.command.CopyCmdAnswer;
 import org.apache.cloudstack.storage.command.CopyCommand;
 import org.apache.cloudstack.storage.command.DownloadCommand;
@@ -97,7 +95,9 @@ import com.cloud.agent.api.storage.ListVolumeAnswer;
 import com.cloud.agent.api.storage.ListVolumeCommand;
 import com.cloud.agent.api.storage.UploadCommand;
 import com.cloud.agent.api.storage.ssCommand;
+import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
 import com.cloud.agent.api.to.NfsTO;
 import com.cloud.agent.api.to.S3TO;
 import com.cloud.agent.api.to.SwiftTO;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/core/src/com/cloud/storage/resource/StorageProcessor.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/storage/resource/StorageProcessor.java b/core/src/com/cloud/storage/resource/StorageProcessor.java
new file mode 100644
index 0000000..ec965ed
--- /dev/null
+++ b/core/src/com/cloud/storage/resource/StorageProcessor.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with 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.
+ */
+package com.cloud.storage.resource;
+
+import org.apache.cloudstack.storage.command.AttachCommand;
+import org.apache.cloudstack.storage.command.CopyCommand;
+import org.apache.cloudstack.storage.command.CreateObjectCommand;
+import org.apache.cloudstack.storage.command.DeleteCommand;
+import org.apache.cloudstack.storage.command.DettachCommand;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.to.DataTO;
+import com.cloud.agent.api.to.DiskTO;
+
+public interface StorageProcessor {
+    public Answer copyTemplateToPrimaryStorage(CopyCommand cmd);
+    public Answer cloneVolumeFromBaseTemplate(CopyCommand cmd);
+    public Answer copyVolumeFromImageCacheToPrimary(CopyCommand cmd);
+    public Answer copyVolumeFromPrimaryToSecondary(CopyCommand cmd);
+    public Answer createTemplateFromVolume(CopyCommand cmd);
+    public Answer backupSnasphot(CopyCommand cmd);
+    public Answer attachIso(AttachCommand cmd);
+    public Answer attachVolume(AttachCommand cmd);
+    public Answer dettachIso(DettachCommand cmd);
+    public Answer dettachVolume(DettachCommand cmd);
+    public Answer createVolume(CreateObjectCommand cmd);
+    public Answer createSnapshot(CreateObjectCommand cmd);
+    public Answer deleteVolume(DeleteCommand cmd);
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandler.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandler.java b/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandler.java
new file mode 100644
index 0000000..5ac601e
--- /dev/null
+++ b/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandler.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with 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.
+ */
+package com.cloud.storage.resource;
+
+import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
+
+import com.cloud.agent.api.Answer;
+
+public interface StorageSubsystemCommandHandler {
+    public Answer handleStorageCommands(StorageSubSystemCommand command);
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java b/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java
new file mode 100644
index 0000000..8f76e93
--- /dev/null
+++ b/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with 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.
+ */
+package com.cloud.storage.resource;
+
+import org.apache.cloudstack.storage.command.AttachCommand;
+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.command.StorageSubSystemCommand;
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.to.DataObjectType;
+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.storage.DataStoreRole;
+import com.cloud.storage.Volume;
+
+public class StorageSubsystemCommandHandlerBase implements StorageSubsystemCommandHandler {
+    private static final Logger s_logger = Logger.getLogger(StorageSubsystemCommandHandlerBase.class);
+    private StorageProcessor processor;
+    public StorageSubsystemCommandHandlerBase(StorageProcessor processor) {
+        this.processor = processor;
+    }
+    @Override
+    public Answer handleStorageCommands(StorageSubSystemCommand command) {
+        if (command instanceof CopyCommand) {
+            return this.execute((CopyCommand)command);
+        } else if (command instanceof CreateObjectCommand) {
+            return execute((CreateObjectCommand) command);
+        } else if (command instanceof DeleteCommand) {
+            return execute((DeleteCommand)command);
+        } else if (command instanceof AttachCommand) {
+            return execute((AttachCommand)command);
+        } else if (command instanceof DettachCommand) {
+            return execute((DettachCommand)command);
+        }
+        return new Answer((Command)command, false, "not implemented yet");
+    }
+
+    protected Answer execute(CopyCommand cmd) {
+        DataTO srcData = cmd.getSrcTO();
+        DataTO destData = cmd.getDestTO();
+        DataStoreTO srcDataStore = srcData.getDataStore();
+        DataStoreTO destDataStore = destData.getDataStore();
+
+        if ((srcData.getObjectType() == DataObjectType.TEMPLATE) && (srcDataStore instanceof NfsTO)  && (destData.getDataStore().getRole() == DataStoreRole.Primary)) {
+            //copy template to primary storage
+            return processor.copyTemplateToPrimaryStorage(cmd);
+        } else if (srcData.getObjectType() == DataObjectType.TEMPLATE && srcDataStore.getRole() == DataStoreRole.Primary && destDataStore.getRole() == DataStoreRole.Primary) {
+            //clone template to a volume
+            return processor.cloneVolumeFromBaseTemplate(cmd);
+        } else if (srcData.getObjectType() == DataObjectType.VOLUME && (srcData.getDataStore().getRole() == DataStoreRole.ImageCache || srcDataStore.getRole() == DataStoreRole.Image)) {
+            //copy volume from image cache to primary
+            return processor.copyVolumeFromImageCacheToPrimary(cmd);
+        } else if (srcData.getObjectType() == DataObjectType.VOLUME && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
+            if (destData.getObjectType() == DataObjectType.VOLUME) {
+                return processor.copyVolumeFromPrimaryToSecondary(cmd);
+            } else if (destData.getObjectType() == DataObjectType.TEMPLATE) {
+                return processor.createTemplateFromVolume(cmd);
+            }
+        } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
+            return processor.backupSnasphot(cmd);
+        }
+
+        return new Answer(cmd, false, "not implemented yet");
+    }
+    
+    
+    protected Answer execute(CreateObjectCommand cmd) {
+        DataTO data = cmd.getData();
+        try {
+            if (data.getObjectType() == DataObjectType.VOLUME) {
+                return processor.createVolume(cmd);
+            } else if (data.getObjectType() == DataObjectType.SNAPSHOT) {
+                return processor.createSnapshot(cmd);
+            }
+            return new CreateObjectAnswer("not supported type");
+        } catch (Exception e) {
+            s_logger.debug("Failed to create object: " + data.getObjectType() + ": " + e.toString());
+            return new CreateObjectAnswer(e.toString());
+        }
+    }
+    
+    protected Answer execute(DeleteCommand cmd) {
+        DataTO data = cmd.getData();
+        Answer answer = null;
+        if (data.getObjectType() == DataObjectType.VOLUME) {
+            answer = processor.deleteVolume(cmd);
+        } else {
+            answer = new Answer(cmd, false, "unsupported type");
+        }
+
+        return answer;
+    }
+    
+    protected Answer execute(AttachCommand cmd) {
+        DiskTO disk = cmd.getDisk();
+        if (disk.getType() == Volume.Type.ISO) {
+            return processor.attachIso(cmd);
+        } else {
+            return processor.attachVolume(cmd);
+        }
+    }
+    
+    protected Answer execute(DettachCommand cmd) {
+        DiskTO disk = cmd.getDisk();
+        if (disk.getType() == Volume.Type.ISO) {
+            return processor.dettachIso(cmd);
+        } else {
+            return processor.dettachVolume(cmd);
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObject.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObject.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObject.java
index 8ffed6a..7610bca 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObject.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObject.java
@@ -19,6 +19,8 @@
 package org.apache.cloudstack.engine.subsystem.api.storage;
 
 import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.to.DataObjectType;
+import com.cloud.agent.api.to.DataTO;
 
 public interface DataObject {
     public long getId();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObjectType.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObjectType.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObjectType.java
deleted file mode 100644
index b4d1a57..0000000
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataObjectType.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with 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.
- */
-package org.apache.cloudstack.engine.subsystem.api.storage;
-
-public enum DataObjectType {
-    VOLUME,
-    SNAPSHOT,
-    TEMPLATE
-}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreDriver.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreDriver.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreDriver.java
index cd2dc86..5ed9ab8 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreDriver.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataStoreDriver.java
@@ -24,6 +24,7 @@ import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
 import org.apache.cloudstack.storage.command.CommandResult;
 
 import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
 
 public interface DataStoreDriver {
     public String grantAccess(DataObject data, EndPoint ep);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataTO.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataTO.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataTO.java
deleted file mode 100644
index 9e26894..0000000
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/DataTO.java
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with 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.
- */
-package org.apache.cloudstack.engine.subsystem.api.storage;
-
-import com.cloud.agent.api.to.DataStoreTO;
-
-public interface DataTO {
-    public DataObjectType getObjectType();
-    public DataStoreTO getDataStore();
-    /**
-     * @return
-     */
-    String getPath();
-}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/api/src/org/apache/cloudstack/storage/command/AttachAnswer.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/command/AttachAnswer.java b/engine/api/src/org/apache/cloudstack/storage/command/AttachAnswer.java
new file mode 100644
index 0000000..1ddcd7d
--- /dev/null
+++ b/engine/api/src/org/apache/cloudstack/storage/command/AttachAnswer.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with 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.
+ */
+package org.apache.cloudstack.storage.command;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.to.DiskTO;
+
+public class AttachAnswer extends Answer {
+    private DiskTO disk;
+    public AttachAnswer() {
+        super(null);
+    }
+    
+    public AttachAnswer(DiskTO disk) {
+        this.setDisk(disk);
+    }
+    public AttachAnswer(String errMsg) {
+        super(null, false, errMsg);
+    }
+
+    public DiskTO getDisk() {
+        return disk;
+    }
+
+    public void setDisk(DiskTO disk) {
+        this.disk = disk;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/api/src/org/apache/cloudstack/storage/command/AttachCommand.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/command/AttachCommand.java b/engine/api/src/org/apache/cloudstack/storage/command/AttachCommand.java
new file mode 100644
index 0000000..fa205a5
--- /dev/null
+++ b/engine/api/src/org/apache/cloudstack/storage/command/AttachCommand.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with 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.
+ */
+package org.apache.cloudstack.storage.command;
+
+
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.to.DiskTO;
+
+public class AttachCommand extends Command implements StorageSubSystemCommand {
+    private DiskTO disk;
+    private String vmName;
+    
+    public AttachCommand(DiskTO disk, String vmName) {
+        this.disk = disk;
+        this.vmName = vmName;
+    }
+    
+    @Override
+    public boolean executeInSequence() {
+        // TODO Auto-generated method stub
+        return false;
+    }
+    public DiskTO getDisk() {
+        return disk;
+    }
+    public void setDisk(DiskTO disk) {
+        this.disk = disk;
+    }
+    public String getVmName() {
+        return vmName;
+    }
+    public void setVmName(String vmName) {
+        this.vmName = vmName;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/api/src/org/apache/cloudstack/storage/command/CopyCmdAnswer.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/command/CopyCmdAnswer.java b/engine/api/src/org/apache/cloudstack/storage/command/CopyCmdAnswer.java
index 3612cf9..132832a 100644
--- a/engine/api/src/org/apache/cloudstack/storage/command/CopyCmdAnswer.java
+++ b/engine/api/src/org/apache/cloudstack/storage/command/CopyCmdAnswer.java
@@ -17,9 +17,9 @@
 package org.apache.cloudstack.storage.command;
 
 
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 
 import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.to.DataTO;
 
 public class CopyCmdAnswer extends Answer {
     private DataTO newData;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/api/src/org/apache/cloudstack/storage/command/CopyCommand.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/command/CopyCommand.java b/engine/api/src/org/apache/cloudstack/storage/command/CopyCommand.java
index 5bceb03..d512e60 100644
--- a/engine/api/src/org/apache/cloudstack/storage/command/CopyCommand.java
+++ b/engine/api/src/org/apache/cloudstack/storage/command/CopyCommand.java
@@ -16,9 +16,9 @@
 // under the License.
 package org.apache.cloudstack.storage.command;
 
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 
 import com.cloud.agent.api.Command;
+import com.cloud.agent.api.to.DataTO;
 
 public class CopyCommand extends Command implements StorageSubSystemCommand {
     private DataTO srcTO;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/api/src/org/apache/cloudstack/storage/command/CreateObjectAnswer.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/command/CreateObjectAnswer.java b/engine/api/src/org/apache/cloudstack/storage/command/CreateObjectAnswer.java
index ddd678a..2c174e4 100644
--- a/engine/api/src/org/apache/cloudstack/storage/command/CreateObjectAnswer.java
+++ b/engine/api/src/org/apache/cloudstack/storage/command/CreateObjectAnswer.java
@@ -18,9 +18,9 @@
  */
 package org.apache.cloudstack.storage.command;
 
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 
 import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.to.DataTO;
 
 public class CreateObjectAnswer extends Answer {
     private DataTO data;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/api/src/org/apache/cloudstack/storage/command/CreateObjectCommand.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/command/CreateObjectCommand.java b/engine/api/src/org/apache/cloudstack/storage/command/CreateObjectCommand.java
index 6a72277..dfadc2d 100644
--- a/engine/api/src/org/apache/cloudstack/storage/command/CreateObjectCommand.java
+++ b/engine/api/src/org/apache/cloudstack/storage/command/CreateObjectCommand.java
@@ -18,9 +18,9 @@
  */
 package org.apache.cloudstack.storage.command;
 
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 
 import com.cloud.agent.api.Command;
+import com.cloud.agent.api.to.DataTO;
 
 public class CreateObjectCommand extends Command implements StorageSubSystemCommand {
     private DataTO data;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/api/src/org/apache/cloudstack/storage/command/DeleteCommand.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/command/DeleteCommand.java b/engine/api/src/org/apache/cloudstack/storage/command/DeleteCommand.java
index 3335848..41af42c 100644
--- a/engine/api/src/org/apache/cloudstack/storage/command/DeleteCommand.java
+++ b/engine/api/src/org/apache/cloudstack/storage/command/DeleteCommand.java
@@ -18,9 +18,9 @@
  */
 package org.apache.cloudstack.storage.command;
 
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 
 import com.cloud.agent.api.Command;
+import com.cloud.agent.api.to.DataTO;
 
 public class DeleteCommand extends Command implements StorageSubSystemCommand {
     private  DataTO data;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/api/src/org/apache/cloudstack/storage/command/DettachAnswer.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/command/DettachAnswer.java b/engine/api/src/org/apache/cloudstack/storage/command/DettachAnswer.java
new file mode 100644
index 0000000..9019e0c
--- /dev/null
+++ b/engine/api/src/org/apache/cloudstack/storage/command/DettachAnswer.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with 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.
+ */
+package org.apache.cloudstack.storage.command;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.to.DiskTO;
+
+public class DettachAnswer extends Answer {
+    private DiskTO disk;
+    public DettachAnswer() {
+        super(null);
+    }
+    
+    public DettachAnswer(DiskTO disk) {
+        this.setDisk(disk);
+    }
+    public DettachAnswer(String errMsg) {
+        super(null, false, errMsg);
+    }
+
+    public DiskTO getDisk() {
+        return disk;
+    }
+
+    public void setDisk(DiskTO disk) {
+        this.disk = disk;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/api/src/org/apache/cloudstack/storage/command/DettachCommand.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/command/DettachCommand.java b/engine/api/src/org/apache/cloudstack/storage/command/DettachCommand.java
new file mode 100644
index 0000000..c435e10
--- /dev/null
+++ b/engine/api/src/org/apache/cloudstack/storage/command/DettachCommand.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with 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.
+ */
+package org.apache.cloudstack.storage.command;
+
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.to.DiskTO;
+
+public class DettachCommand extends Command implements StorageSubSystemCommand {
+    private DiskTO disk;
+    private String vmName;
+    
+    public DettachCommand(DiskTO disk, String vmName) {
+        this.disk = disk;
+        this.vmName = vmName;
+    }
+    
+    @Override
+    public boolean executeInSequence() {
+        // TODO Auto-generated method stub
+        return false;
+    }
+    public DiskTO getDisk() {
+        return disk;
+    }
+    public void setDisk(DiskTO disk) {
+        this.disk = disk;
+    }
+    public String getVmName() {
+        return vmName;
+    }
+    public void setVmName(String vmName) {
+        this.vmName = vmName;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/api/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java b/engine/api/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java
index cf9448b..c3ce0e0 100644
--- a/engine/api/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java
+++ b/engine/api/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java
@@ -20,17 +20,26 @@ import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo;
 
 import com.cloud.agent.api.to.DataStoreTO;
 import com.cloud.storage.DataStoreRole;
+import com.cloud.storage.Storage.StoragePoolType;
 
 public class PrimaryDataStoreTO implements DataStoreTO {
     private final String uuid;
     private final String name;
     private  String type;
     private final long id;
+    private StoragePoolType poolType;
+    private String host;
+    private String path;
+    private int port;
     public PrimaryDataStoreTO(PrimaryDataStoreInfo dataStore) {
         this.uuid = dataStore.getUuid();
         this.name = dataStore.getName();
       //  this.type = dataStore.getType();
         this.id = dataStore.getId();
+        this.setPoolType(dataStore.getPoolType());
+        this.setHost(dataStore.getHostAddress());
+        this.setPath(dataStore.getPath());
+        this.setPort(dataStore.getPort());
     }
     
     public long getId() {
@@ -53,4 +62,36 @@ public class PrimaryDataStoreTO implements DataStoreTO {
     public DataStoreRole getRole() {
         return DataStoreRole.Primary;
     }
+
+    public StoragePoolType getPoolType() {
+        return poolType;
+    }
+
+    public void setPoolType(StoragePoolType poolType) {
+        this.poolType = poolType;
+    }
+
+    public String getHost() {
+        return host;
+    }
+
+    public void setHost(String host) {
+        this.host = host;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    public int getPort() {
+        return port;
+    }
+
+    public void setPort(int port) {
+        this.port = port;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java b/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
index ed4cbe1..a2e336b 100644
--- a/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
+++ b/engine/api/src/org/apache/cloudstack/storage/to/SnapshotObjectTO.java
@@ -1,10 +1,10 @@
 package org.apache.cloudstack.storage.to;
 
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
 
+import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 
 public class SnapshotObjectTO implements DataTO {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java b/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java
index aad5d71..14577ef 100644
--- a/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java
+++ b/engine/api/src/org/apache/cloudstack/storage/to/TemplateObjectTO.java
@@ -16,13 +16,13 @@
 // under the License.
 package org.apache.cloudstack.storage.to;
 
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 import org.apache.cloudstack.engine.subsystem.api.storage.TemplateInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat;
 import org.apache.cloudstack.storage.image.datastore.ImageStoreInfo;
 
+import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
 import com.cloud.storage.Storage.ImageFormat;
 import com.cloud.template.VirtualMachineTemplate;
 
@@ -38,6 +38,7 @@ public class TemplateObjectTO implements DataTO {
     private String displayText;
     private  DataStoreTO imageDataStore;
     private  String name;
+    private String guestOsType;
 
     public TemplateObjectTO() {
 
@@ -151,5 +152,11 @@ public class TemplateObjectTO implements DataTO {
         this.imageDataStore = imageDataStore;
     }
 
+    public String getGuestOsType() {
+        return guestOsType;
+    }
 
+    public void setGuestOsType(String guestOsType) {
+        this.guestOsType = guestOsType;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java b/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
index 3f7a8f1..0ae2bc7 100644
--- a/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
+++ b/engine/api/src/org/apache/cloudstack/storage/to/VolumeObjectTO.java
@@ -16,17 +16,18 @@
 // under the License.
 package org.apache.cloudstack.storage.to;
 
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.engine.subsystem.api.storage.disktype.DiskFormat;
 import org.apache.cloudstack.engine.subsystem.api.storage.type.VolumeType;
 
+import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
+import com.cloud.storage.Volume;
 
 public class VolumeObjectTO implements DataTO {
     private String uuid;
-    private VolumeType volumeType;
+    private Volume.Type volumeType;
     private DiskFormat diskType;
     private DataStoreTO dataStore;
     private String name;
@@ -35,6 +36,8 @@ public class VolumeObjectTO implements DataTO {
     private Long volumeId;
     private String vmName;
     private long accountId;
+    private String chainInfo;
+    private long id;
 
     public VolumeObjectTO() {
 
@@ -52,6 +55,9 @@ public class VolumeObjectTO implements DataTO {
         this.vmName = volume.getAttachedVmName();
         this.size = volume.getSize();
         this.setVolumeId(volume.getId());
+        this.chainInfo = volume.getChainInfo();
+        this.volumeType = volume.getVolumeType();
+        this.setId(volume.getId());
     }
 
     public String getUuid() {
@@ -62,7 +68,7 @@ public class VolumeObjectTO implements DataTO {
         return this.path;
     }
 
-    public VolumeType getVolumeType() {
+    public Volume.Type getVolumeType() {
         return this.volumeType;
     }
 
@@ -130,5 +136,21 @@ public class VolumeObjectTO implements DataTO {
         this.vmName = vmName;
     }
 
+	public String getChainInfo() {
+		return chainInfo;
+	}
+
+	public void setChainInfo(String chainInfo) {
+		this.chainInfo = chainInfo;
+	}
+
+	public long getId() {
+		return id;
+	}
+
+	public void setId(long id) {
+		this.id = id;
+	}
+
 
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
index 560c34f..4e9b02b 100644
--- a/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
+++ b/engine/storage/datamotion/src/org/apache/cloudstack/storage/motion/AncientDataMotionStrategy.java
@@ -26,10 +26,8 @@ import javax.inject.Inject;
 import org.apache.cloudstack.engine.subsystem.api.storage.CopyCommandResult;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataMotionStrategy;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPoint;
 import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
@@ -61,7 +59,9 @@ import com.cloud.agent.api.UpgradeSnapshotCommand;
 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.to.DataObjectType;
 import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DataTO;
 import com.cloud.agent.api.to.NfsTO;
 import com.cloud.agent.api.to.S3TO;
 import com.cloud.agent.api.to.SwiftTO;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateDataFactoryImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateDataFactoryImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateDataFactoryImpl.java
index 6f20426..09c79b2 100644
--- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateDataFactoryImpl.java
+++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateDataFactoryImpl.java
@@ -33,6 +33,7 @@ import org.springframework.stereotype.Component;
 
 import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.VMTemplateStoragePoolVO;
+import com.cloud.storage.VMTemplateStorageResourceAssoc;
 import com.cloud.storage.VMTemplateVO;
 import com.cloud.storage.dao.VMTemplateDao;
 import com.cloud.storage.dao.VMTemplatePoolDao;
@@ -89,6 +90,16 @@ public class TemplateDataFactoryImpl implements TemplateDataFactory {
         }
         return this.getTemplate(templateId, store);
     }
+    
+    @Override
+    public TemplateInfo getTemplate(long templateId, long zoneId) {
+        TemplateDataStoreVO tmplStore = templateStoreDao.findByTemplateZoneDownloadStatus(templateId, zoneId, VMTemplateStorageResourceAssoc.Status.DOWNLOADED);
+        if (tmplStore != null) {
+            DataStore store = this.storeMgr.getDataStore(tmplStore.getDataStoreId(), DataStoreRole.Image);
+            return this.getTemplate(templateId, store);
+        }
+        return null;
+    }
 
 
     @Override

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java
----------------------------------------------------------------------
diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java
index daf8568..12e29e7 100644
--- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java
+++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/TemplateObject.java
@@ -24,9 +24,7 @@ import java.util.Map;
 import javax.inject.Inject;
 
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
 import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
 import org.apache.cloudstack.engine.subsystem.api.storage.TemplateEvent;
@@ -40,6 +38,8 @@ import org.apache.cloudstack.storage.to.TemplateObjectTO;
 import org.apache.log4j.Logger;
 
 import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.to.DataObjectType;
+import com.cloud.agent.api.to.DataTO;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.Storage.ImageFormat;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
index f5800c1..423d8c9 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotObject.java
@@ -22,9 +22,7 @@ import java.util.Date;
 
 import javax.inject.Inject;
 
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotDataFactory;
 import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotInfo;
@@ -39,6 +37,8 @@ import org.apache.cloudstack.storage.to.SnapshotObjectTO;
 import org.apache.log4j.Logger;
 
 import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.to.DataObjectType;
+import com.cloud.agent.api.to.DataTO;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.storage.Snapshot;
 import com.cloud.storage.SnapshotVO;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManager.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManager.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManager.java
index ca9f22c..f49929f 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManager.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManager.java
@@ -18,10 +18,10 @@ package org.apache.cloudstack.storage.datastore;
 
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
 
+import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.storage.DataStoreRole;
 import com.cloud.utils.fsm.NoTransitionException;
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java
index f0b54e1..4816e51 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/datastore/ObjectInDataStoreManagerImpl.java
@@ -20,7 +20,6 @@ import javax.inject.Inject;
 
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
@@ -42,6 +41,7 @@ import org.apache.cloudstack.storage.db.ObjectInDataStoreVO;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
+import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.VMTemplateStoragePoolVO;
 import com.cloud.storage.dao.SnapshotDao;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreVO.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreVO.java b/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreVO.java
index 5b69251..ecf0391 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreVO.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/db/ObjectInDataStoreVO.java
@@ -30,10 +30,10 @@ import javax.persistence.Temporal;
 import javax.persistence.TemporalType;
 
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
 import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
 import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State;
 
+import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.Storage;
 import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java
index 49bfa65..55c5b91 100644
--- a/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java
+++ b/engine/storage/volume/src/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java
@@ -25,7 +25,6 @@ import javax.inject.Inject;
 
 import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreProvider;
 import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
@@ -46,6 +45,7 @@ import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
 import org.apache.cloudstack.storage.volume.VolumeObject;
 import org.apache.log4j.Logger;
 
+import com.cloud.agent.api.to.DataObjectType;
 import com.cloud.agent.api.to.DataStoreTO;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.storage.Storage.StoragePoolType;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
----------------------------------------------------------------------
diff --git a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
index be7bd12..6754a1d 100644
--- a/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
+++ b/engine/storage/volume/src/org/apache/cloudstack/storage/volume/VolumeObject.java
@@ -21,9 +21,7 @@ import java.util.Date;
 import javax.inject.Inject;
 
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectInStore;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataObjectType;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
-import org.apache.cloudstack.engine.subsystem.api.storage.DataTO;
 import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
 import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.storage.command.CopyCmdAnswer;
@@ -36,6 +34,8 @@ import org.apache.log4j.Logger;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.storage.DownloadAnswer;
+import com.cloud.agent.api.to.DataObjectType;
+import com.cloud.agent.api.to.DataTO;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.Volume;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
index 706c9ef..dd92a31 100755
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java
@@ -39,11 +39,11 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
-import java.util.HashSet;
 import java.util.Properties;
+import java.util.Set;
 import java.util.UUID;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ExecutionException;
@@ -56,11 +56,13 @@ import java.util.regex.Pattern;
 import javax.ejb.Local;
 import javax.naming.ConfigurationException;
 
-import org.apache.log4j.Logger;
-import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
+import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
+import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
 import org.apache.cloudstack.utils.qemu.QemuImg;
-import org.apache.cloudstack.utils.qemu.QemuImgFile;
+import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
 import org.apache.cloudstack.utils.qemu.QemuImgException;
+import org.apache.cloudstack.utils.qemu.QemuImgFile;
+import org.apache.log4j.Logger;
 import org.libvirt.Connect;
 import org.libvirt.Domain;
 import org.libvirt.DomainInfo;
@@ -166,9 +168,13 @@ import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
 import com.cloud.agent.api.storage.DestroyCommand;
 import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
 import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
-import com.cloud.agent.api.storage.ResizeVolumeCommand;
 import com.cloud.agent.api.storage.ResizeVolumeAnswer;
+import com.cloud.agent.api.storage.ResizeVolumeCommand;
+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.IpAddressTO;
+import com.cloud.agent.api.to.NfsTO;
 import com.cloud.agent.api.to.NicTO;
 import com.cloud.agent.api.to.StorageFilerTO;
 import com.cloud.agent.api.to.VirtualMachineTO;
@@ -194,11 +200,12 @@ import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InputDef;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.InterfaceDef.hostNicType;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.SerialDef;
-import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.VirtioSerialDef;
 import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.TermPolicy;
+import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.VirtioSerialDef;
 import com.cloud.hypervisor.kvm.storage.KVMPhysicalDisk;
 import com.cloud.hypervisor.kvm.storage.KVMStoragePool;
 import com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager;
+import com.cloud.hypervisor.kvm.storage.KVMStorageProcessor;
 import com.cloud.network.Networks.BroadcastDomainType;
 import com.cloud.network.Networks.IsolationType;
 import com.cloud.network.Networks.RouterPrivateIpStrategy;
@@ -212,14 +219,16 @@ import com.cloud.storage.Storage.ImageFormat;
 import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.storage.StorageLayer;
 import com.cloud.storage.Volume;
+import com.cloud.storage.resource.StorageSubsystemCommandHandler;
+import com.cloud.storage.resource.StorageSubsystemCommandHandlerBase;
 import com.cloud.storage.template.Processor;
 import com.cloud.storage.template.Processor.FormatInfo;
 import com.cloud.storage.template.QCOW2Processor;
-import com.cloud.storage.template.TemplateProp;
 import com.cloud.storage.template.TemplateLocation;
+import com.cloud.storage.template.TemplateProp;
+import com.cloud.utils.FileUtil;
 import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.Pair;
-import com.cloud.utils.FileUtil;
 import com.cloud.utils.PropertiesUtil;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.net.NetUtils;
@@ -345,7 +354,6 @@ ServerResource {
     protected String _localStoragePath;
     protected String _localStorageUUID;
     private final Map <String, String> _pifs = new HashMap<String, String>();
-    private final Map<String, Map<String, String>> hostNetInfo = new HashMap<String, Map<String, String>>();
     private final Map<String, vmStats> _vmStats = new ConcurrentHashMap<String, vmStats>();
 
     protected boolean _disconnected = true;
@@ -383,6 +391,8 @@ ServerResource {
     }
 
     protected BridgeType _bridgeType;
+    
+    protected StorageSubsystemCommandHandler storageHandler;
 
     private String getEndIpFromStartIp(String startIp, int numIps) {
         String[] tokens = startIp.split("[.]");
@@ -810,6 +820,10 @@ ServerResource {
         params.put("libvirt.computing.resource", this);
 
         configureVifDrivers(params);
+        
+        KVMStorageProcessor storageProcessor = new KVMStorageProcessor(this._storagePoolMgr, this);
+        storageProcessor.configure(name, params);
+        storageHandler = new StorageSubsystemCommandHandlerBase(storageProcessor);
 
         return true;
     }
@@ -958,11 +972,6 @@ ServerResource {
 
         return pif;
     }
-
-    private String getOvsPif(String bridge) {
-        String pif = Script.runSimpleBashScript("ovs-vsctl list-ports " + bridge);
-        return pif;
-    }
     
     private String matchPifFileInDirectory(String bridgeName){
         File f = new File("/sys/devices/virtual/net/" + bridgeName + "/brif");
@@ -1203,6 +1212,8 @@ ServerResource {
                 return execute((CheckNetworkCommand) cmd);
             } else if (cmd instanceof NetworkRulesVmSecondaryIpCommand) {
                 return execute((NetworkRulesVmSecondaryIpCommand) cmd);
+            } else if (cmd instanceof StorageSubSystemCommand) {
+                return this.storageHandler.handleStorageCommands((StorageSubSystemCommand)cmd);
             } else {
                 s_logger.warn("Unsupported command ");
                 return Answer.createUnsupportedCommandAnswer(cmd);
@@ -1496,8 +1507,6 @@ ServerResource {
                     vol.getPoolType(),
                     vol.getPoolUuid());
             pool.deletePhysicalDisk(vol.getPath());
-            String vmName = cmd.getVmName();
-            String poolPath = pool.getLocalPath();
             return new Answer(cmd, true, "Success");
         } catch (CloudRuntimeException e) {
             s_logger.debug("Failed to delete volume: " + e.toString());
@@ -1606,7 +1615,6 @@ ServerResource {
 
         try {
             conn = LibvirtConnection.getConnectionByVmName(routerName);
-            Domain vm = getDomain(conn, routerName);
             List<InterfaceDef> pluggedNics = getInterfaces(conn, routerName);
             InterfaceDef routerNic = null;
 
@@ -1621,7 +1629,6 @@ ServerResource {
                 return new SetupGuestNetworkAnswer(cmd, false, "Can not find nic with mac " + nic.getMac() + " for VM " + routerName);
             }
 
-            String args = "vpc_guestnw.sh " + routerIP + " -C";
             String dev = "eth" + nic.getDeviceId();
             String netmask = NetUtils.getSubNet(routerGIP, nic.getNetmask());
             String result = _virtRouterResource.assignGuestNetwork(dev, routerIP,
@@ -1640,14 +1647,10 @@ ServerResource {
 
     private SetNetworkACLAnswer execute(SetNetworkACLCommand cmd) {
         String[] results = new String[cmd.getRules().length];
-        String callResult;
-        Connect conn;
-        String routerName = cmd.getAccessDetail(NetworkElementCommand.ROUTER_NAME);
+       
         String routerIp = cmd.getAccessDetail(NetworkElementCommand.ROUTER_IP);
 
         try {
-            conn = LibvirtConnection.getConnectionByVmName(routerName);
-            Domain vm = getDomain(conn, routerName);
             String [][] rules = cmd.generateFwRules();
             String[] aclRules = rules[0];
             NicTO nic = cmd.getNic();
@@ -1671,7 +1674,7 @@ ServerResource {
             }
 
             return new SetNetworkACLAnswer(cmd, true, results);
-        } catch (LibvirtException e) {
+        } catch (Exception e) {
             String msg = "SetNetworkACL failed due to " + e.toString();
             s_logger.error(msg, e);
             return new SetNetworkACLAnswer(cmd, false, results);
@@ -1686,7 +1689,6 @@ ServerResource {
 
         try {
             conn = LibvirtConnection.getConnectionByVmName(routerName);
-            Domain vm = getDomain(conn, routerName);
             Integer devNum = 0;
             String pubVlan = pubIP.getVlanId();
             List<InterfaceDef> pluggedNics = getInterfaces(conn, routerName);
@@ -1733,7 +1735,6 @@ ServerResource {
         try {
             conn = LibvirtConnection.getConnectionByVmName(routerName);
             IpAddressTO[] ips = cmd.getIpAddresses();
-            Domain vm = getDomain(conn, routerName);
             Integer devNum = 0;
             Map<String, Integer> vlanToNicNum = new HashMap<String, Integer>();
             List<InterfaceDef> pluggedNics = getInterfaces(conn, routerName);
@@ -1919,7 +1920,6 @@ ServerResource {
         Long volumeId = cmd.getVolumeId();
         String secondaryStoragePoolUrl = cmd.getSecondaryStorageUrl();
         String snapshotName = cmd.getSnapshotName();
-        String snapshotPath = cmd.getVolumePath();
         String snapshotDestPath = null;
         String snapshotRelPath = null;
         String vmName = cmd.getVmName();
@@ -2194,7 +2194,6 @@ ServerResource {
         KVMStoragePool secondaryStorage = null;
         KVMStoragePool primary = null;
         try {
-            Connect conn = LibvirtConnection.getConnectionByVmName(cmd.getVmName());
             String templateFolder = cmd.getAccountId() + File.separator
                     + cmd.getTemplateId() + File.separator;
             String templateInstallFolder = "/template/tmpl/" + templateFolder;
@@ -2290,10 +2289,6 @@ ServerResource {
                     templateInstallFolder + cmd.getUniqueName() + ".qcow2",
                     info.virtualSize, info.size, cmd.getUniqueName(),
                     ImageFormat.QCOW2);
-        } catch (LibvirtException e) {
-            s_logger.debug("Failed to get secondary storage pool: "
-                    + e.toString());
-            return new CreatePrivateTemplateAnswer(cmd, false, e.toString());
         } catch (InternalErrorException e) {
             return new CreatePrivateTemplateAnswer(cmd, false, e.toString());
         } catch (IOException e) {
@@ -2372,7 +2367,6 @@ ServerResource {
     }
 
     protected Answer execute(ModifyStoragePoolCommand cmd) {
-        String poolType = cmd.getPool().getType().toString();
         KVMStoragePool storagepool = _storagePoolMgr.createStoragePool(cmd
                 .getPool().getUuid(), cmd.getPool().getHost(),
                 cmd.getPool().getPort(), cmd.getPool().getPath(),
@@ -2700,8 +2694,8 @@ ServerResource {
             }
 
             /* setup disks, e.g for iso */
-            VolumeTO[] volumes = vm.getDisks();
-            for (VolumeTO volume : volumes) {
+            DiskTO[] volumes = vm.getDisks();
+            for (DiskTO volume : volumes) {
                 if (volume.getType() == Volume.Type.ISO) {
                     getVolumePath(conn, volume);
                 }
@@ -3279,10 +3273,14 @@ ServerResource {
         }
     }
 
-    private String getVolumePath(Connect conn, VolumeTO volume)
+    private String getVolumePath(Connect conn, DiskTO volume)
             throws LibvirtException, URISyntaxException {
-        if (volume.getType() == Volume.Type.ISO && volume.getPath() != null) {
-            String isoPath = volume.getPath();
+        DataTO data = volume.getData();
+        DataStoreTO store = data.getDataStore();
+        
+        if (volume.getType() == Volume.Type.ISO && data.getPath() != null) {
+            NfsTO nfsStore = (NfsTO)store;
+            String isoPath = nfsStore.getUrl() + File.separator + data.getPath();
             int index = isoPath.lastIndexOf("/");
             String path = isoPath.substring(0, index);
             String name = isoPath.substring(index + 1);
@@ -3291,26 +3289,28 @@ ServerResource {
             KVMPhysicalDisk isoVol = secondaryPool.getPhysicalDisk(name);
             return isoVol.getPath();
         } else {
-            return volume.getPath();
+            return data.getPath();
         }
     }
 
     protected void createVbd(Connect conn, VirtualMachineTO vmSpec,
             String vmName, LibvirtVMDef vm) throws InternalErrorException,
             LibvirtException, URISyntaxException {
-        List<VolumeTO> disks = Arrays.asList(vmSpec.getDisks());
-        Collections.sort(disks, new Comparator<VolumeTO>() {
+        List<DiskTO> disks = Arrays.asList(vmSpec.getDisks());
+        Collections.sort(disks, new Comparator<DiskTO>() {
             @Override
-            public int compare(VolumeTO arg0, VolumeTO arg1) {
-                return arg0.getDeviceId() > arg1.getDeviceId() ? 1 : -1;
+            public int compare(DiskTO arg0, DiskTO arg1) {
+                return arg0.getDiskSeq() > arg1.getDiskSeq() ? 1 : -1;
             }
         });
 
-        for (VolumeTO volume : disks) {
+        for (DiskTO volume : disks) {
             KVMPhysicalDisk physicalDisk = null;
             KVMStoragePool pool = null;
-            if (volume.getType() == Volume.Type.ISO && volume.getPath() != null) {
-                String volPath = volume.getPath();
+            DataTO data = volume.getData();
+            if (volume.getType() == Volume.Type.ISO && data.getPath() != null) {
+                NfsTO nfsStore = (NfsTO)data.getDataStore();
+                String volPath = nfsStore.getUrl() + File.separator + data.getPath();
                 int index = volPath.lastIndexOf("/");
                 String volDir = volPath.substring(0, index);
                 String volName = volPath.substring(index + 1);
@@ -3318,10 +3318,11 @@ ServerResource {
                         getStoragePoolByURI(volDir);
                 physicalDisk = secondaryStorage.getPhysicalDisk(volName);
             } else if (volume.getType() != Volume.Type.ISO) {
+                PrimaryDataStoreTO store = (PrimaryDataStoreTO)data.getDataStore();
                 pool = _storagePoolMgr.getStoragePool(
-                        volume.getPoolType(),
-                        volume.getPoolUuid());
-                physicalDisk = pool.getPhysicalDisk(volume.getPath());
+                        store.getPoolType(),
+                        store.getUuid());
+                physicalDisk = pool.getPhysicalDisk(data.getPath());
             }
 
             String volPath = null;
@@ -3339,7 +3340,7 @@ ServerResource {
                     disk.defISODisk(volPath);
                 }
             } else {
-                int devId = (int) volume.getDeviceId();
+                int devId = volume.getDiskSeq().intValue();
 
                 if (pool.getType() == StoragePoolType.RBD) {
                     /*
@@ -3379,12 +3380,14 @@ ServerResource {
 
         // For LXC, find and add the root filesystem
         if (HypervisorType.LXC.toString().toLowerCase().equals(vm.getHvsType())) {
-            for (VolumeTO volume : disks) {
+            for (DiskTO volume : disks) {
                 if (volume.getType() == Volume.Type.ROOT) {
+                    DataTO data = volume.getData();
+                    PrimaryDataStoreTO store = (PrimaryDataStoreTO)data.getDataStore();
                     KVMStoragePool pool = _storagePoolMgr.getStoragePool(
-                            volume.getPoolType(),
-                            volume.getPoolUuid());
-                    KVMPhysicalDisk physicalDisk = pool.getPhysicalDisk(volume.getPath());
+                            store.getPoolType(),
+                            store.getUuid());
+                    KVMPhysicalDisk physicalDisk = pool.getPhysicalDisk(data.getPath());
                     FilesystemDef rootFs = new FilesystemDef(physicalDisk.getPath(), "/");
                     vm.getDevices().addDevice(rootFs);
                     break;
@@ -3394,16 +3397,6 @@ ServerResource {
 
     }
 
-    private VolumeTO getVolume(VirtualMachineTO vmSpec, Volume.Type type) {
-        VolumeTO volumes[] = vmSpec.getDisks();
-        for (VolumeTO volume : volumes) {
-            if (volume.getType() == type) {
-                return volume;
-            }
-        }
-        return null;
-    }
-
     private void createVif(LibvirtVMDef vm, NicTO nic)
             throws InternalErrorException, LibvirtException {
         vm.getDevices().addDevice(
@@ -3432,7 +3425,7 @@ ServerResource {
         return new CheckSshAnswer(cmd);
     }
 
-    private boolean cleanupDisk(Connect conn, DiskDef disk) {
+    public boolean cleanupDisk(Connect conn, DiskDef disk) {
         // need to umount secondary storage
         String path = disk.getDiskPath();
         String poolUuid = null;
@@ -4237,28 +4230,6 @@ ServerResource {
         return parser.getEmulator();
     }
 
-    private String getGuestType(Connect conn, String vmName) {
-        LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
-        Domain dm = null;
-        try {
-            dm = conn.domainLookupByUUID(UUID.nameUUIDFromBytes(vmName
-                    .getBytes()));
-            String xmlDesc = dm.getXMLDesc(0);
-            parser.parseDomainXML(xmlDesc);
-            return parser.getDescription();
-        } catch (LibvirtException e) {
-            s_logger.trace("Ignoring libvirt error.", e);
-            return null;
-        } finally {
-            try {
-                if (dm != null) {
-                    dm.free();
-                }
-            } catch (LibvirtException l) {
-                s_logger.trace("Ignoring libvirt error.", l);
-            }
-        }
-    }
 
     boolean isGuestPVEnabled(String guestOS) {
         if (guestOS == null) {
@@ -4296,14 +4267,6 @@ ServerResource {
         }
     }
 
-    private InterfaceDef.nicModel getGuestNicModel(String guestOSType) {
-        if (isGuestPVEnabled(guestOSType)) {
-            return InterfaceDef.nicModel.VIRTIO;
-        } else {
-            return InterfaceDef.nicModel.E1000;
-        }
-    }
-
     private DiskDef.diskBus getGuestDiskModel(String guestOSType) {
         if (isGuestPVEnabled(guestOSType)) {
             return DiskDef.diskBus.VIRTIO;
@@ -4337,7 +4300,7 @@ ServerResource {
         }
     }
 
-    private Domain getDomain(Connect conn, String vmName)
+    public Domain getDomain(Connect conn, String vmName)
             throws LibvirtException {
         return conn
                 .domainLookupByUUID(UUID.nameUUIDFromBytes(vmName.getBytes()));
@@ -4366,7 +4329,7 @@ ServerResource {
         }
     }
 
-    protected List<DiskDef> getDisks(Connect conn, String vmName) {
+    public List<DiskDef> getDisks(Connect conn, String vmName) {
         LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
         Domain dm = null;
         try {
@@ -4396,38 +4359,7 @@ ServerResource {
         return command.execute();
     }
 
-    private String executeBashScript(String script, OutputInterpreter parser) {
-        Script command = new Script("/bin/bash", _timeout, s_logger);
-        command.add("-c");
-        command.add(script);
-        return command.execute(parser);
-    }
 
-    private void deletExitingLinkLocalRoutTable(String linkLocalBr) {
-        Script command = new Script("/bin/bash", _timeout);
-        command.add("-c");
-        command.add("ip route | grep " + NetUtils.getLinkLocalCIDR());
-        OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser();
-        String result = command.execute(parser);
-        boolean foundLinkLocalBr = false;
-        if (result == null && parser.getLines() != null) {
-            String[] lines = parser.getLines().split("\\n");
-            for (String line : lines) {
-                String[] tokens = line.split(" ");
-                if (!tokens[2].equalsIgnoreCase(linkLocalBr)) {
-                    Script.runSimpleBashScript("ip route del "
-                            + NetUtils.getLinkLocalCIDR());
-                } else {
-                    foundLinkLocalBr = true;
-                }
-            }
-        }
-        if (!foundLinkLocalBr) {
-            Script.runSimpleBashScript("ip route add "
-                    + NetUtils.getLinkLocalCIDR() + " dev " + linkLocalBr
-                    + " src " + NetUtils.getLinkLocalGateway());
-        }
-    }
 
     private class vmStats {
         long _usedTime;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
index 9cddb2e..345b4e8 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java
@@ -354,7 +354,7 @@ public class LibvirtVMDef {
     }
 
     public static class DiskDef {
-        enum deviceType {
+        public enum deviceType {
             FLOPPY("floppy"), DISK("disk"), CDROM("cdrom");
             String _type;
 
@@ -396,7 +396,7 @@ public class LibvirtVMDef {
             }
         }
 
-        enum diskBus {
+        public enum diskBus {
             IDE("ide"), SCSI("scsi"), VIRTIO("virtio"), XEN("xen"), USB("usb"), UML(
                     "uml"), FDC("fdc");
             String _bus;
@@ -411,7 +411,7 @@ public class LibvirtVMDef {
             }
         }
 
-        enum diskFmtType {
+        public enum diskFmtType {
             RAW("raw"), QCOW2("qcow2");
             String _fmtType;
 


[5/7] refactor kvm/vmware resource code

Posted by ed...@apache.org.
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
new file mode 100644
index 0000000..c3fc0ec
--- /dev/null
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
@@ -0,0 +1,879 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with 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.
+ */
+package com.cloud.hypervisor.kvm.storage;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.text.DateFormat;
+import java.text.MessageFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.naming.ConfigurationException;
+
+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.DettachAnswer;
+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.cloudstack.utils.qemu.QemuImg;
+import org.apache.cloudstack.utils.qemu.QemuImgException;
+import org.apache.cloudstack.utils.qemu.QemuImgFile;
+import org.apache.cloudstack.utils.qemu.QemuImg.PhysicalDiskFormat;
+import org.apache.log4j.Logger;
+import org.libvirt.Connect;
+import org.libvirt.Domain;
+import org.libvirt.DomainInfo;
+import org.libvirt.DomainSnapshot;
+import org.libvirt.LibvirtException;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.AttachVolumeAnswer;
+import com.cloud.agent.api.BackupSnapshotAnswer;
+import com.cloud.agent.api.ManageSnapshotAnswer;
+import com.cloud.agent.api.ManageSnapshotCommand;
+import com.cloud.agent.api.storage.CreateAnswer;
+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.StorageFilerTO;
+import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.exception.InternalErrorException;
+import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
+import com.cloud.hypervisor.kvm.resource.LibvirtConnection;
+import com.cloud.hypervisor.kvm.resource.LibvirtDomainXMLParser;
+import com.cloud.hypervisor.kvm.resource.LibvirtVMDef.DiskDef;
+import com.cloud.storage.JavaStorageLayer;
+import com.cloud.storage.StorageLayer;
+import com.cloud.storage.Storage.ImageFormat;
+import com.cloud.storage.Storage.StoragePoolType;
+import com.cloud.storage.resource.StorageProcessor;
+import com.cloud.storage.template.Processor;
+import com.cloud.storage.template.QCOW2Processor;
+import com.cloud.storage.template.TemplateLocation;
+import com.cloud.storage.template.Processor.FormatInfo;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.script.Script;
+import com.cloud.vm.DiskProfile;
+
+public class KVMStorageProcessor implements StorageProcessor {
+    private static final Logger s_logger = Logger.getLogger(KVMStorageProcessor.class);
+    private KVMStoragePoolManager storagePoolMgr;
+    private LibvirtComputingResource resource;
+    private StorageLayer storageLayer;
+    private String _createTmplPath;
+    private String _manageSnapshotPath;
+    private int _cmdsTimeout;
+    public KVMStorageProcessor(KVMStoragePoolManager storagePoolMgr, LibvirtComputingResource resource) {
+        this.storagePoolMgr = storagePoolMgr;
+        this.resource = resource;
+    }
+    
+    protected String getDefaultStorageScriptsDir() {
+        return "scripts/storage/qcow2";
+    }
+    
+    public boolean configure(String name, Map<String, Object> params)
+            throws ConfigurationException {
+        storageLayer = new JavaStorageLayer();
+        storageLayer.configure("StorageLayer", params);
+        
+        String storageScriptsDir = (String) params.get("storage.scripts.dir");
+        if (storageScriptsDir == null) {
+            storageScriptsDir = getDefaultStorageScriptsDir();
+        }
+        
+        _createTmplPath = Script
+                .findScript(storageScriptsDir, "createtmplt.sh");
+        if (_createTmplPath == null) {
+            throw new ConfigurationException(
+                    "Unable to find the createtmplt.sh");
+        }
+        
+        _manageSnapshotPath = Script.findScript(storageScriptsDir,
+                "managesnapshot.sh");
+        if (_manageSnapshotPath == null) {
+            throw new ConfigurationException(
+                    "Unable to find the managesnapshot.sh");
+        }
+        
+        String value = (String) params.get("cmds.timeout");
+        _cmdsTimeout = NumbersUtil.parseInt(value, 7200) * 1000;
+        return true;
+    }
+
+    @Override
+    public Answer copyTemplateToPrimaryStorage(CopyCommand cmd) {
+    	DataTO srcData = cmd.getSrcTO();
+    	DataTO destData = cmd.getDestTO();
+        TemplateObjectTO template = (TemplateObjectTO)srcData;
+        DataStoreTO imageStore = template.getDataStore();
+        VolumeObjectTO volume = (VolumeObjectTO)destData;
+        PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volume.getDataStore();
+        
+        if (!(imageStore instanceof NfsTO)) {
+            return new CopyCmdAnswer("unsupported protocol");
+        }
+        
+        NfsTO nfsImageStore = (NfsTO)imageStore;
+        String tmplturl = nfsImageStore.getUrl() + File.separator + template.getPath();
+        int index = tmplturl.lastIndexOf("/");
+        String mountpoint = tmplturl.substring(0, index);
+        String tmpltname = null;
+        if (index < tmplturl.length() - 1) {
+            tmpltname = tmplturl.substring(index + 1);
+        }
+
+        KVMPhysicalDisk tmplVol = null;
+        KVMStoragePool secondaryPool = null;
+        try {
+            secondaryPool = storagePoolMgr.getStoragePoolByURI(mountpoint);
+
+            /* Get template vol */
+            if (tmpltname == null) {
+                secondaryPool.refresh();
+                List<KVMPhysicalDisk> disks = secondaryPool.listPhysicalDisks();
+                if (disks == null || disks.isEmpty()) {
+                    return new PrimaryStorageDownloadAnswer(
+                            "Failed to get volumes from pool: "
+                                    + secondaryPool.getUuid());
+                }
+                for (KVMPhysicalDisk disk : disks) {
+                    if (disk.getName().endsWith("qcow2")) {
+                        tmplVol = disk;
+                        break;
+                    }
+                }
+                if (tmplVol == null) {
+                    return new PrimaryStorageDownloadAnswer(
+                            "Failed to get template from pool: "
+                                    + secondaryPool.getUuid());
+                }
+            } else {
+                tmplVol = secondaryPool.getPhysicalDisk(tmpltname);
+            }
+
+            /* Copy volume to primary storage */
+            KVMStoragePool primaryPool = storagePoolMgr.getStoragePool(
+                    primaryStore.getPoolType(),
+                    primaryStore.getUuid());
+
+            KVMPhysicalDisk primaryVol = storagePoolMgr.copyPhysicalDisk(
+                    tmplVol, UUID.randomUUID().toString(), primaryPool);
+
+            VolumeObjectTO newVol = new VolumeObjectTO();
+            newVol.setPath(primaryVol.getName());
+            newVol.setSize(primaryVol.getSize());
+            return new CopyCmdAnswer(newVol);
+        } catch (CloudRuntimeException e) {
+            return new CopyCmdAnswer(e.toString());
+        } finally {
+            if (secondaryPool != null) {
+                secondaryPool.delete();
+            }
+        }
+    }
+    
+    // this is much like PrimaryStorageDownloadCommand, but keeping it separate
+    private KVMPhysicalDisk templateToPrimaryDownload(String templateUrl, KVMStoragePool primaryPool) {
+        int index = templateUrl.lastIndexOf("/");
+        String mountpoint = templateUrl.substring(0, index);
+        String templateName = null;
+        if (index < templateUrl.length() - 1) {
+            templateName = templateUrl.substring(index + 1);
+        }
+
+        KVMPhysicalDisk templateVol = null;
+        KVMStoragePool secondaryPool = null;
+        try {
+            secondaryPool = storagePoolMgr.getStoragePoolByURI(mountpoint);
+            /* Get template vol */
+            if (templateName == null) {
+                secondaryPool.refresh();
+                List<KVMPhysicalDisk> disks = secondaryPool.listPhysicalDisks();
+                if (disks == null || disks.isEmpty()) {
+                    s_logger.error("Failed to get volumes from pool: " + secondaryPool.getUuid());
+                    return null;
+                }
+                for (KVMPhysicalDisk disk : disks) {
+                    if (disk.getName().endsWith("qcow2")) {
+                        templateVol = disk;
+                        break;
+                    }
+                }
+                if (templateVol == null) {
+                    s_logger.error("Failed to get template from pool: " + secondaryPool.getUuid());
+                    return null;
+                }
+            } else {
+                templateVol = secondaryPool.getPhysicalDisk(templateName);
+            }
+
+            /* Copy volume to primary storage */
+
+            KVMPhysicalDisk primaryVol = storagePoolMgr.copyPhysicalDisk(templateVol, UUID.randomUUID().toString(), primaryPool);
+            return primaryVol;
+        } catch (CloudRuntimeException e) {
+            s_logger.error("Failed to download template to primary storage",e);
+            return null;
+        } finally {
+            if (secondaryPool != null) {
+                secondaryPool.delete();
+            }
+        }
+    }
+
+    @Override
+    public Answer cloneVolumeFromBaseTemplate(CopyCommand cmd) {
+    	DataTO srcData = cmd.getSrcTO();
+    	DataTO destData = cmd.getDestTO();
+        TemplateObjectTO template = (TemplateObjectTO)srcData;
+        DataStoreTO imageStore = template.getDataStore();
+        VolumeObjectTO volume = (VolumeObjectTO)destData;
+        PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volume.getDataStore();
+        KVMPhysicalDisk BaseVol = null;
+        KVMStoragePool primaryPool = null;
+        KVMPhysicalDisk vol = null;
+      
+        try {
+            primaryPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(),
+                    primaryStore.getUuid());
+
+            String templatePath = null;
+            if (imageStore instanceof NfsTO) {
+                NfsTO nfsImageStore = (NfsTO)imageStore;
+                templatePath = nfsImageStore.getUrl();
+            } else {
+                s_logger.debug("Failed to create volume: ");
+                return new CopyCmdAnswer("Unsupported protocol");
+            }
+             
+            if(primaryPool.getType() == StoragePoolType.CLVM) { 
+                vol = templateToPrimaryDownload(templatePath, primaryPool);
+            } else {
+                BaseVol = primaryPool.getPhysicalDisk(templatePath);
+                vol = storagePoolMgr.createDiskFromTemplate(BaseVol, UUID
+                        .randomUUID().toString(), primaryPool);
+            }
+            if (vol == null) {
+                return new CopyCmdAnswer(
+                        " Can't create storage volume on storage pool");
+            }
+
+            VolumeObjectTO newVol = new VolumeObjectTO();
+            newVol.setPath(vol.getName());
+            newVol.setSize(vol.getSize());
+            
+            return new CopyCmdAnswer(newVol);
+        } catch (CloudRuntimeException e) {
+            s_logger.debug("Failed to create volume: " + e.toString());
+            return new CopyCmdAnswer(e.toString());
+        }
+    }
+
+    @Override
+    public Answer copyVolumeFromImageCacheToPrimary(CopyCommand cmd) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Answer copyVolumeFromPrimaryToSecondary(CopyCommand cmd) {
+        return null;
+    }
+
+    @Override
+    public Answer createTemplateFromVolume(CopyCommand cmd) {
+    	DataTO srcData = cmd.getSrcTO();
+    	DataTO destData = cmd.getDestTO();
+    	int wait = cmd.getWait();
+        TemplateObjectTO template = (TemplateObjectTO)srcData;
+        DataStoreTO imageStore = template.getDataStore();
+        VolumeObjectTO volume = (VolumeObjectTO)destData;
+        PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volume.getDataStore();
+        
+        if (!(imageStore instanceof NfsTO)) {
+            return new CopyCmdAnswer("unsupported protocol");
+        }
+        NfsTO nfsImageStore = (NfsTO)imageStore;
+
+        KVMStoragePool secondaryStorage = null;
+        KVMStoragePool primary = null;
+        try {
+            String templateFolder = template.getPath();
+
+            secondaryStorage = storagePoolMgr.getStoragePoolByURI(
+                    nfsImageStore.getUrl());
+
+            try {
+                primary = storagePoolMgr.getStoragePool(
+                    primaryStore.getPoolType(),
+                    primaryStore.getUuid());
+            } catch (CloudRuntimeException e) {
+                if (e.getMessage().contains("not found")) {
+                    primary = storagePoolMgr.createStoragePool(primaryStore.getUuid(),
+                            primaryStore.getHost(), primaryStore.getPort(),
+                            primaryStore.getPath(), null,
+                            primaryStore.getPoolType());
+                } else {
+                    return new CopyCmdAnswer(e.getMessage());
+                }
+            }
+
+            KVMPhysicalDisk disk = primary.getPhysicalDisk(volume.getPath());
+            String tmpltPath = secondaryStorage.getLocalPath() + File.separator
+                    + templateFolder;
+            this.storageLayer.mkdirs(tmpltPath);
+            String templateName = UUID.randomUUID().toString();
+
+            if (primary.getType() != StoragePoolType.RBD) {
+                Script command = new Script(_createTmplPath, wait, s_logger);
+                command.add("-f", disk.getPath());
+                command.add("-t", tmpltPath);
+                command.add("-n", templateName + ".qcow2");
+
+                String result = command.execute();
+
+                if (result != null) {
+                    s_logger.debug("failed to create template: " + result);
+                    return new CopyCmdAnswer(result);
+                }
+            } else {
+                s_logger.debug("Converting RBD disk " + disk.getPath() + " into template " + templateName);
+
+                QemuImgFile srcFile = new QemuImgFile(KVMPhysicalDisk.RBDStringBuilder(primary.getSourceHost(),
+                                primary.getSourcePort(),
+                                primary.getAuthUserName(),
+                                primary.getAuthSecret(),
+                                disk.getPath()));
+                srcFile.setFormat(PhysicalDiskFormat.RAW);
+
+                QemuImgFile destFile = new QemuImgFile(tmpltPath + "/" + templateName + ".qcow2");
+                destFile.setFormat(PhysicalDiskFormat.QCOW2);
+
+                QemuImg q = new QemuImg();
+                try {
+                    q.convert(srcFile, destFile);
+                } catch (QemuImgException e) {
+                    s_logger.error("Failed to create new template while converting "
+                                    + srcFile.getFileName() + " to " + destFile.getFileName() + " the error was: " + e.getMessage());
+                }
+
+                File templateProp = new File(tmpltPath + "/template.properties");
+                if (!templateProp.exists()) {
+                    templateProp.createNewFile();
+                }
+
+                String templateContent = "filename=" + templateName + ".qcow2" + System.getProperty("line.separator");
+
+                DateFormat dateFormat = new SimpleDateFormat("MM_dd_yyyy");
+                Date date = new Date();
+                templateContent += "snapshot.name=" + dateFormat.format(date) + System.getProperty("line.separator");
+
+                FileOutputStream templFo = new FileOutputStream(templateProp);
+                templFo.write(templateContent.getBytes());
+                templFo.flush();
+                templFo.close();
+            }
+
+            Map<String, Object> params = new HashMap<String, Object>();
+            params.put(StorageLayer.InstanceConfigKey, this.storageLayer);
+            Processor qcow2Processor = new QCOW2Processor();
+
+            qcow2Processor.configure("QCOW2 Processor", params);
+
+            FormatInfo info = qcow2Processor.process(tmpltPath, null,
+                    templateName);
+
+            TemplateLocation loc = new TemplateLocation(this.storageLayer, tmpltPath);
+            loc.create(1, true, templateName);
+            loc.addFormat(info);
+            loc.save();
+
+            TemplateObjectTO newTemplate = new TemplateObjectTO();
+            newTemplate.setPath(templateFolder + templateName + ".qcow2");
+            return new CopyCmdAnswer(newTemplate);
+        } catch (Exception e) {
+           s_logger.debug("Failed to create template from volume: " + e.toString());
+           return new CopyCmdAnswer(e.toString());
+        } finally {
+            if (secondaryStorage != null) {
+                secondaryStorage.delete();
+            }
+        }
+    }
+
+    @Override
+    public Answer backupSnasphot(CopyCommand cmd) {
+    	DataTO srcData = cmd.getSrcTO();
+    	DataTO destData = cmd.getDestTO();
+    	int wait = cmd.getWait();
+        SnapshotObjectTO snapshot = (SnapshotObjectTO)srcData;
+        PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)snapshot.getDataStore();
+        SnapshotObjectTO destSnapshot = (SnapshotObjectTO)destData;
+        DataStoreTO imageStore = destData.getDataStore();
+        
+        if (!(imageStore instanceof NfsTO)) {
+            return new CopyCmdAnswer("unsupported protocol");
+        }
+        NfsTO nfsImageStore = (NfsTO)imageStore;
+ 
+        String secondaryStoragePoolUrl = nfsImageStore.getUrl();
+        //NOTE: snapshot name is encoded in snapshot path
+        int index = snapshot.getPath().lastIndexOf("/");
+        
+        String snapshotName = snapshot.getPath().substring(index + 1);
+        String volumePath = snapshot.getVolume().getPath();
+        String snapshotDestPath = null;
+        String snapshotRelPath = null;
+        String vmName = snapshot.getVmName();
+        KVMStoragePool secondaryStoragePool = null;
+        try {
+            Connect conn = LibvirtConnection.getConnectionByVmName(vmName);
+
+            secondaryStoragePool = storagePoolMgr.getStoragePoolByURI(
+                    secondaryStoragePoolUrl);
+
+            String ssPmountPath = secondaryStoragePool.getLocalPath();
+            snapshotRelPath = destSnapshot.getPath();
+
+            snapshotDestPath = ssPmountPath + File.separator + snapshotRelPath;
+            KVMStoragePool primaryPool = storagePoolMgr.getStoragePool(
+                   primaryStore.getPoolType(),
+                    primaryStore.getUuid());
+            KVMPhysicalDisk snapshotDisk = primaryPool.getPhysicalDisk(volumePath);
+            Script command = new Script(_manageSnapshotPath, _cmdsTimeout,
+                    s_logger);
+            command.add("-b", snapshotDisk.getPath());
+            command.add("-n", snapshotName);
+            command.add("-p", snapshotDestPath);
+            command.add("-t", snapshotName);
+            String result = command.execute();
+            if (result != null) {
+                s_logger.debug("Failed to backup snaptshot: " + result);
+                return new CopyCmdAnswer(result);
+            }
+            /* Delete the snapshot on primary */
+
+            DomainInfo.DomainState state = null;
+            Domain vm = null;
+            if (vmName != null) {
+                try {
+                    vm = this.resource.getDomain(conn, vmName);
+                    state = vm.getInfo().state;
+                } catch (LibvirtException e) {
+                    s_logger.trace("Ignoring libvirt error.", e);
+                }
+            }
+
+            KVMStoragePool primaryStorage = storagePoolMgr.getStoragePool(
+                    primaryStore.getPoolType(),
+                    primaryStore.getUuid());
+            if (state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING
+                    && !primaryStorage.isExternalSnapshot()) {
+                DomainSnapshot snap = vm.snapshotLookupByName(snapshotName);
+                snap.delete(0);
+
+                /*
+                 * libvirt on RHEL6 doesn't handle resume event emitted from
+                 * qemu
+                 */
+                vm = this.resource.getDomain(conn, vmName);
+                state = vm.getInfo().state;
+                if (state == DomainInfo.DomainState.VIR_DOMAIN_PAUSED) {
+                    vm.resume();
+                }
+            } else {
+                command = new Script(_manageSnapshotPath, _cmdsTimeout,
+                        s_logger);
+                command.add("-d", snapshotDisk.getPath());
+                command.add("-n", snapshotName);
+                result = command.execute();
+                if (result != null) {
+                    s_logger.debug("Failed to backup snapshot: " + result);
+                    return new CopyCmdAnswer(
+                            "Failed to backup snapshot: " + result);
+                }
+            }
+            
+            SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
+            newSnapshot.setPath(snapshotRelPath
+                    + File.separator + snapshotName);
+            return new CopyCmdAnswer(newSnapshot);
+        } catch (LibvirtException e) {
+            s_logger.debug("Failed to backup snapshot: " + e.toString());
+            return new CopyCmdAnswer(e.toString());
+        } catch (CloudRuntimeException e) {
+            s_logger.debug("Failed to backup snapshot: " + e.toString());
+            return new CopyCmdAnswer(e.toString());
+        } finally {
+            if (secondaryStoragePool != null) {
+                secondaryStoragePool.delete();
+            }
+        }
+    }
+
+    protected synchronized String attachOrDetachISO(Connect conn,
+            String vmName, String isoPath, boolean isAttach)
+                    throws LibvirtException, URISyntaxException, InternalErrorException {
+        String isoXml = null;
+        if (isoPath != null && isAttach) {
+            int index = isoPath.lastIndexOf("/");
+            String path = isoPath.substring(0, index);
+            String name = isoPath.substring(index + 1);
+            KVMStoragePool secondaryPool = storagePoolMgr.getStoragePoolByURI(
+                    path);
+            KVMPhysicalDisk isoVol = secondaryPool.getPhysicalDisk(name);
+            isoPath = isoVol.getPath();
+
+            DiskDef iso = new DiskDef();
+            iso.defISODisk(isoPath);
+            isoXml = iso.toString();
+        } else {
+            DiskDef iso = new DiskDef();
+            iso.defISODisk(null);
+            isoXml = iso.toString();
+        }
+
+        List<DiskDef> disks = this.resource.getDisks(conn, vmName);
+        String result = attachOrDetachDevice(conn, true, vmName, isoXml);
+        if (result == null && !isAttach) {
+            for (DiskDef disk : disks) {
+                if (disk.getDeviceType() == DiskDef.deviceType.CDROM) {
+                    this.resource.cleanupDisk(conn, disk);
+                }
+            }
+
+        }
+        return result;
+    }
+    @Override
+    public Answer attachIso(AttachCommand cmd) {
+        DiskTO disk = cmd.getDisk();
+        TemplateObjectTO isoTO = (TemplateObjectTO)disk.getData();
+        DataStoreTO store = isoTO.getDataStore();
+        if (!(store instanceof NfsTO)) {
+        	return new AttachAnswer("unsupported protocol");
+        }
+        NfsTO nfsStore = (NfsTO)store;
+        try {
+            Connect conn = LibvirtConnection.getConnectionByVmName(cmd.getVmName());
+            attachOrDetachISO(conn, cmd.getVmName(), nfsStore.getUrl() + File.separator + isoTO.getPath(),
+                    true);
+        } catch (LibvirtException e) {
+            return new Answer(cmd, false, e.toString());
+        } catch (URISyntaxException e) {
+            return new Answer(cmd, false, e.toString());
+        } catch (InternalErrorException e) {
+            return new Answer(cmd, false, e.toString());
+        }
+
+        return new Answer(cmd);
+    }
+    
+    protected synchronized String attachOrDetachDevice(Connect conn,
+            boolean attach, String vmName, String xml) throws LibvirtException,
+            InternalErrorException {
+        Domain dm = null;
+        try {
+            dm = conn.domainLookupByUUID(UUID.nameUUIDFromBytes((vmName
+                    .getBytes())));
+
+            if (attach) {
+                s_logger.debug("Attaching device: " + xml);
+                dm.attachDevice(xml);
+            } else {
+                s_logger.debug("Detaching device: " + xml);
+                dm.detachDevice(xml);
+            }
+        } catch (LibvirtException e) {
+            if (attach) {
+                s_logger.warn("Failed to attach device to " + vmName + ": "
+                        + e.getMessage());
+            } else {
+                s_logger.warn("Failed to detach device from " + vmName + ": "
+                        + e.getMessage());
+            }
+            throw e;
+        } finally {
+            if (dm != null) {
+                try {
+                    dm.free();
+                } catch (LibvirtException l) {
+                    s_logger.trace("Ignoring libvirt error.", l);
+                }
+            }
+        }
+
+        return null;
+    }
+    
+    protected synchronized String attachOrDetachDisk(Connect conn,
+            boolean attach, String vmName, KVMPhysicalDisk attachingDisk,
+            int devId) throws LibvirtException, InternalErrorException {
+        List<DiskDef> disks = null;
+        Domain dm = null;
+        DiskDef diskdef = null;
+        try {
+            if (!attach) {
+                dm = conn.domainLookupByUUID(UUID.nameUUIDFromBytes(vmName
+                        .getBytes()));
+                LibvirtDomainXMLParser parser = new LibvirtDomainXMLParser();
+                String xml = dm.getXMLDesc(0);
+                parser.parseDomainXML(xml);
+                disks = parser.getDisks();
+
+                for (DiskDef disk : disks) {
+                    String file = disk.getDiskPath();
+                    if (file != null
+                            && file.equalsIgnoreCase(attachingDisk.getPath())) {
+                        diskdef = disk;
+                        break;
+                    }
+                }
+                if (diskdef == null) {
+                    throw new InternalErrorException("disk: "
+                            + attachingDisk.getPath()
+                            + " is not attached before");
+                }
+            } else {
+                diskdef = new DiskDef();
+                if (attachingDisk.getFormat() == PhysicalDiskFormat.QCOW2) {
+                    diskdef.defFileBasedDisk(attachingDisk.getPath(), devId,
+                            DiskDef.diskBus.VIRTIO, DiskDef.diskFmtType.QCOW2);
+                } else if (attachingDisk.getFormat() == PhysicalDiskFormat.RAW) {
+                    diskdef.defBlockBasedDisk(attachingDisk.getPath(), devId,
+                            DiskDef.diskBus.VIRTIO);
+                }
+            }
+
+            String xml = diskdef.toString();
+            return attachOrDetachDevice(conn, attach, vmName, xml);
+        } finally {
+            if (dm != null) {
+                dm.free();
+            }
+        }
+    }
+
+    @Override
+    public Answer attachVolume(AttachCommand cmd) {
+    	DiskTO disk = cmd.getDisk();
+        VolumeObjectTO vol = (VolumeObjectTO)disk.getData();
+        PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)vol.getDataStore();
+        String vmName = vol.getVmName();
+        try {
+            Connect conn = LibvirtConnection.getConnectionByVmName(vmName);
+            KVMStoragePool primary = storagePoolMgr.getStoragePool(
+                    primaryStore.getPoolType(),
+                    primaryStore.getUuid());
+            
+            KVMPhysicalDisk phyDisk = primary.getPhysicalDisk(vol.getPath());
+            attachOrDetachDisk(conn, true, vmName, phyDisk,
+                    disk.getDiskSeq().intValue());
+            
+            return new AttachAnswer(disk);
+        } catch (LibvirtException e) {
+            s_logger.debug("Failed to attach volume: " + vol.getPath() + ", due to " + e.toString());
+            return new AttachAnswer(e.toString());
+        } catch (InternalErrorException e) {
+            s_logger.debug("Failed to attach volume: " + vol.getPath() + ", due to " + e.toString());
+            return new AttachAnswer(e.toString());
+        }
+
+        
+    }
+
+    @Override
+    public Answer dettachIso(DettachCommand cmd) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Answer dettachVolume(DettachCommand cmd) {
+    	DiskTO disk = cmd.getDisk();
+        VolumeObjectTO vol = (VolumeObjectTO)disk.getData();
+        PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)vol.getDataStore();
+        String vmName = vol.getVmName();
+        try {
+            Connect conn = LibvirtConnection.getConnectionByVmName(vmName);
+            KVMStoragePool primary = storagePoolMgr.getStoragePool(
+                    primaryStore.getPoolType(),
+                    primaryStore.getUuid());
+            
+            KVMPhysicalDisk phyDisk = primary.getPhysicalDisk(vol.getPath());
+            attachOrDetachDisk(conn, false, vmName, phyDisk,
+                    disk.getDiskSeq().intValue());
+            
+            return new DettachAnswer(disk);
+        } catch (LibvirtException e) {
+            s_logger.debug("Failed to attach volume: " + vol.getPath() + ", due to " + e.toString());
+            return new DettachAnswer(e.toString());
+        } catch (InternalErrorException e) {
+            s_logger.debug("Failed to attach volume: " + vol.getPath() + ", due to " + e.toString());
+            return new DettachAnswer(e.toString());
+        }
+    }
+
+    @Override
+    public Answer createVolume(CreateObjectCommand cmd) {
+        VolumeObjectTO volume = (VolumeObjectTO)cmd.getData();
+        PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volume.getDataStore();
+   
+        KVMStoragePool primaryPool = null;
+        KVMPhysicalDisk vol = null;
+        long disksize;
+        try {
+            primaryPool = storagePoolMgr.getStoragePool(primaryStore.getPoolType(),
+                    primaryStore.getUuid());
+            disksize = volume.getSize();
+
+            vol = primaryPool.createPhysicalDisk(UUID.randomUUID()
+                    .toString(), disksize);
+
+            VolumeObjectTO newVol = new VolumeObjectTO();
+            newVol.setPath(vol.getName());
+            
+            return new CreateObjectAnswer(newVol);
+        } catch (Exception e) {
+            s_logger.debug("Failed to create volume: " + e.toString());
+            return new CreateObjectAnswer(e.toString());
+        }
+    }
+    
+    protected static MessageFormat SnapshotXML = new MessageFormat(
+            "   <domainsnapshot>" + "       <name>{0}</name>" + "          <domain>"
+                    + "            <uuid>{1}</uuid>" + "        </domain>"
+                    + "    </domainsnapshot>");
+
+    @Override
+    public Answer createSnapshot(CreateObjectCommand cmd) {
+        VolumeObjectTO volume = (VolumeObjectTO)cmd.getData();
+        PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volume.getDataStore();
+        String snapshotName = UUID.randomUUID().toString();
+        String vmName = volume.getVmName();
+        try {
+            Connect conn = LibvirtConnection.getConnectionByVmName(vmName);
+            DomainInfo.DomainState state = null;
+            Domain vm = null;
+            if (vmName != null) {
+                try {
+                    vm = this.resource.getDomain(conn, vmName);
+                    state = vm.getInfo().state;
+                } catch (LibvirtException e) {
+                    s_logger.trace("Ignoring libvirt error.", e);
+                }
+            }
+
+            KVMStoragePool primaryPool = storagePoolMgr.getStoragePool(
+                    primaryStore.getPoolType(),
+                    primaryStore.getUuid());
+
+            if (primaryPool.getType() == StoragePoolType.RBD) {
+                s_logger.debug("Snapshots are not supported on RBD volumes");
+                return new CreateObjectAnswer(
+                        "Snapshots are not supported on RBD volumes");
+            }
+
+            KVMPhysicalDisk disk = primaryPool.getPhysicalDisk(volume.getPath());
+            if (state == DomainInfo.DomainState.VIR_DOMAIN_RUNNING
+                    && !primaryPool.isExternalSnapshot()) {
+                String vmUuid = vm.getUUIDString();
+                Object[] args = new Object[] { snapshotName, vmUuid };
+                String snapshot = SnapshotXML.format(args);
+                s_logger.debug(snapshot);
+             
+                vm.snapshotCreateXML(snapshot);
+                /*
+                 * libvirt on RHEL6 doesn't handle resume event emitted from
+                 * qemu
+                 */
+                vm = this.resource.getDomain(conn, vmName);
+                state = vm.getInfo().state;
+                if (state == DomainInfo.DomainState.VIR_DOMAIN_PAUSED) {
+                    vm.resume();
+                }
+            } else {
+
+                /* VM is not running, create a snapshot by ourself */
+                final Script command = new Script(_manageSnapshotPath,
+                        this._cmdsTimeout, s_logger);
+                command.add("-c", disk.getPath());
+                command.add("-n", snapshotName);
+                String result = command.execute();
+                if (result != null) {
+                    s_logger.debug("Failed to manage snapshot: " + result);
+                    return new CreateObjectAnswer(
+                            "Failed to manage snapshot: " + result);
+                }
+            }
+            
+            SnapshotObjectTO newSnapshot = new SnapshotObjectTO();
+            //NOTE: sort of hack, we'd better just put snapshtoName 
+            newSnapshot.setPath(disk.getPath() + File.separator + snapshotName);
+            return new CreateObjectAnswer(newSnapshot);
+        } catch (LibvirtException e) {
+            s_logger.debug("Failed to manage snapshot: " + e.toString());
+            return new CreateObjectAnswer(
+                    "Failed to manage snapshot: " + e.toString());
+        }
+    }
+
+    @Override
+    public Answer deleteVolume(DeleteCommand cmd) {
+        VolumeObjectTO vol = (VolumeObjectTO)cmd.getData();
+        PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)vol.getDataStore();
+        try {
+            KVMStoragePool pool = storagePoolMgr.getStoragePool(
+                    primaryStore.getPoolType(),
+                    primaryStore.getUuid());
+            try {
+                pool.getPhysicalDisk(vol.getPath());
+            } catch(Exception e) {
+                s_logger.debug("can't find volume: " + vol.getPath() + ", return true");
+                return new Answer(null);
+            }
+            pool.deletePhysicalDisk(vol.getPath());
+            return new Answer(null);
+        } catch (CloudRuntimeException e) {
+            s_logger.debug("Failed to delete volume: " + e.toString());
+            return new Answer(null, false, e.toString());
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageResource.java b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageResource.java
new file mode 100644
index 0000000..52e142e
--- /dev/null
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageResource.java
@@ -0,0 +1,87 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with 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.
+ */
+package com.cloud.hypervisor.kvm.storage;
+
+import org.apache.cloudstack.storage.command.AttachCommand;
+import org.apache.cloudstack.storage.command.AttachPrimaryDataStoreCmd;
+import org.apache.cloudstack.storage.command.CopyCommand;
+import org.apache.cloudstack.storage.command.CreateObjectCommand;
+import org.apache.cloudstack.storage.command.CreatePrimaryDataStoreCmd;
+import org.apache.cloudstack.storage.command.DeleteCommand;
+import org.apache.cloudstack.storage.command.DettachCommand;
+import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
+
+public class KVMStorageResource {
+    private LibvirtComputingResource resource;
+    public KVMStorageResource(LibvirtComputingResource resource) {
+        this.resource = resource;
+    }
+    
+    public Answer handleStorageCommands(StorageSubSystemCommand command) {
+        if (command instanceof CopyCommand) {
+            return this.execute((CopyCommand)command);
+        } else if (command instanceof AttachPrimaryDataStoreCmd) {
+            return this.execute((AttachPrimaryDataStoreCmd)command);
+        } else if (command instanceof CreatePrimaryDataStoreCmd) {
+            return execute((CreatePrimaryDataStoreCmd) command);
+        } else if (command instanceof CreateObjectCommand) {
+            return execute((CreateObjectCommand) command);
+        } else if (command instanceof DeleteCommand) {
+            return execute((DeleteCommand)command);
+        } else if (command instanceof AttachCommand) {
+            return execute((AttachCommand)command);
+        } else if (command instanceof DettachCommand) {
+            return execute((DettachCommand)command);
+        }
+        return new Answer((Command)command, false, "not implemented yet");
+    }
+    
+    protected Answer execute(CopyCommand cmd) {
+        return new Answer((Command)cmd, false, "not implemented yet");
+    }
+    
+    protected Answer execute(AttachPrimaryDataStoreCmd cmd) {
+        return new Answer((Command)cmd, false, "not implemented yet");
+    }
+    
+    protected Answer execute(CreatePrimaryDataStoreCmd cmd) {
+        return new Answer((Command)cmd, false, "not implemented yet");
+    }
+    
+    protected Answer execute(CreateObjectCommand cmd) {
+        return new Answer((Command)cmd, false, "not implemented yet");
+    }
+    
+    protected Answer execute(DeleteCommand cmd) {
+        return new Answer((Command)cmd, false, "not implemented yet");
+    }
+    
+    protected Answer execute(AttachCommand cmd) {
+        return new Answer((Command)cmd, false, "not implemented yet");
+    }
+    
+    protected Answer execute(DettachCommand cmd) {
+        return new Answer((Command)cmd, false, "not implemented yet");
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index 0f85f4e..f91786f 100755
--- a/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/hypervisor/vmware/resource/VmwareResource.java
@@ -39,6 +39,11 @@ import java.util.UUID;
 
 import javax.naming.ConfigurationException;
 
+import org.apache.cloudstack.storage.command.DeleteCommand;
+import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
+import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
+import org.apache.cloudstack.storage.to.TemplateObjectTO;
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
 import org.apache.log4j.Logger;
 import org.apache.log4j.NDC;
 
@@ -162,8 +167,11 @@ import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
 import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
 import com.cloud.agent.api.storage.ResizeVolumeAnswer;
 import com.cloud.agent.api.storage.ResizeVolumeCommand;
+import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.agent.api.to.DiskTO;
 import com.cloud.agent.api.to.FirewallRuleTO;
 import com.cloud.agent.api.to.IpAddressTO;
+import com.cloud.agent.api.to.NfsTO;
 import com.cloud.agent.api.to.NicTO;
 import com.cloud.agent.api.to.PortForwardingRuleTO;
 import com.cloud.agent.api.to.StaticNatRuleTO;
@@ -177,6 +185,7 @@ import com.cloud.host.Host.Type;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.hypervisor.vmware.manager.VmwareHostService;
 import com.cloud.hypervisor.vmware.manager.VmwareManager;
+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.CustomFieldsManagerMO;
@@ -210,8 +219,12 @@ import com.cloud.storage.Storage;
 import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.storage.Volume;
 import com.cloud.storage.resource.StoragePoolResource;
+import com.cloud.storage.resource.StorageSubsystemCommandHandler;
+import com.cloud.storage.resource.StorageSubsystemCommandHandlerBase;
+import com.cloud.storage.resource.VmwareStorageProcessor;
 import com.cloud.storage.template.TemplateProp;
 import com.cloud.utils.DateUtil;
+import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.Pair;
 import com.cloud.utils.StringUtils;
 import com.cloud.utils.db.DB;
@@ -313,6 +326,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
     protected Gson _gson;
 
     protected volatile long _cmdSequence = 1;
+    
+    protected StorageSubsystemCommandHandler storageHandler;
 
     protected static HashMap<VirtualMachinePowerState, State> s_statesTable;
     static {
@@ -321,6 +336,10 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         s_statesTable.put(VirtualMachinePowerState.POWERED_OFF, State.Stopped);
         s_statesTable.put(VirtualMachinePowerState.SUSPENDED, State.Stopped);
     }
+    
+    public Gson getGson() {
+    	return this._gson;
+    }
 
     public VmwareResource() {
         _gson = GsonHelper.getGsonLogger();
@@ -472,6 +491,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
                 answer = execute((CheckS2SVpnConnectionsCommand) cmd);
             } else if (clz == ResizeVolumeCommand.class) {
                 return execute((ResizeVolumeCommand) cmd);
+            } else if (clz == StorageSubSystemCommand.class) {
+            	return this.storageHandler.handleStorageCommands((StorageSubSystemCommand)cmd);
             } else {
                 answer = Answer.createUnsupportedCommandAnswer(cmd);
             }
@@ -2026,14 +2047,21 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         return new CheckSshAnswer(cmd);
     }
 
-    private VolumeTO[] validateDisks(VolumeTO[] disks) {
-        List<VolumeTO> validatedDisks = new ArrayList<VolumeTO>();
+    private DiskTO[] validateDisks(DiskTO[] disks) {
+        List<DiskTO> validatedDisks = new ArrayList<DiskTO>();
 
-        for (VolumeTO vol : disks) {
-            if (vol.getPoolUuid() != null && !vol.getPoolUuid().isEmpty()) {
-                validatedDisks.add(vol);
-            } else if (vol.getPoolType() == StoragePoolType.ISO && (vol.getPath() != null && !vol.getPath().isEmpty())) {
-                validatedDisks.add(vol);
+        for (DiskTO vol : disks) {
+            if (vol.getType() != Volume.Type.ISO) {
+            	VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData();
+            	PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volumeTO.getDataStore();
+            	if (primaryStore.getUuid() != null && !primaryStore.getUuid().isEmpty()) {
+            		validatedDisks.add(vol);
+            	}
+            } else if (vol.getType() == Volume.Type.ISO) {
+            	TemplateObjectTO templateTO = (TemplateObjectTO)vol.getData();
+            	if (templateTO.getPath() != null && !templateTO.getPath().isEmpty()) {
+            		validatedDisks.add(vol);
+            	}
             } else {
                 if (s_logger.isDebugEnabled()) {
                     s_logger.debug("Drop invalid disk option, volumeTO: " + _gson.toJson(vol));
@@ -2041,7 +2069,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
             }
         }
 
-        return validatedDisks.toArray(new VolumeTO[0]);
+        return validatedDisks.toArray(new DiskTO[0]);
     }
 
     protected StartAnswer execute(StartCommand cmd) {
@@ -2068,7 +2096,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
                 s_logger.debug("VM " + vmName + " will be started with NIC device type: " + nicDeviceType);
 
             VmwareHypervisorHost hyperHost = getHyperHost(context);
-            VolumeTO[] disks = validateDisks(vmSpec.getDisks());
+            DiskTO[] disks = validateDisks(vmSpec.getDisks());
             assert (disks.length > 0);
             NicTO[] nics = vmSpec.getNics();
 
@@ -2105,9 +2133,10 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
                 } else {
                     int ramMb = (int) (vmSpec.getMinRam() / (1024 * 1024));
                     Pair<ManagedObjectReference, DatastoreMO> rootDiskDataStoreDetails = null;
-                    for (VolumeTO vol : disks) {
+                    for (DiskTO vol : disks) {
                         if (vol.getType() == Volume.Type.ROOT) {
-                            rootDiskDataStoreDetails = dataStoresDetails.get(vol.getPoolUuid());
+                        	PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)vol.getData().getDataStore();
+                            rootDiskDataStoreDetails = dataStoresDetails.get(primaryStore.getUuid());
                         }
                     }
 
@@ -2126,12 +2155,12 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
             }
 
             int totalChangeDevices = disks.length + nics.length;
-            VolumeTO volIso = null;
+            DiskTO volIso = null;
             if (vmSpec.getType() != VirtualMachine.Type.User) {
                 // system VM needs a patch ISO
                 totalChangeDevices++;
             } else {
-                for (VolumeTO vol : disks) {
+                for (DiskTO vol : disks) {
                     if (vol.getType() == Volume.Type.ISO) {
                         volIso = vol;
                         break;
@@ -2188,23 +2217,35 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
                 i++;
             } else {
                 // we will always plugin a CDROM device
-                if (volIso != null && volIso.getPath() != null && !volIso.getPath().isEmpty()) {
-                    Pair<String, ManagedObjectReference> isoDatastoreInfo = getIsoDatastoreInfo(hyperHost, volIso.getPath());
-                    assert (isoDatastoreInfo != null);
-                    assert (isoDatastoreInfo.second() != null);
-
-                    deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
-                    Pair<VirtualDevice, Boolean> isoInfo = VmwareHelper.prepareIsoDevice(vmMo, isoDatastoreInfo.first(), isoDatastoreInfo.second(), true, true, i, i + 1);
-                    deviceConfigSpecArray[i].setDevice(isoInfo.first());
-                    if (isoInfo.second()) {
-                        if(s_logger.isDebugEnabled())
-                            s_logger.debug("Prepare ISO volume at new device " + _gson.toJson(isoInfo.first()));
-                        deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD);
-                    } else {
-                        if(s_logger.isDebugEnabled())
-                            s_logger.debug("Prepare ISO volume at existing device " + _gson.toJson(isoInfo.first()));
-                        deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT);
-                    }
+            	
+                if (volIso != null) {
+                	TemplateObjectTO iso = (TemplateObjectTO)volIso.getData();
+
+                	if (iso.getPath() != null && !iso.getPath().isEmpty()) {
+                		DataStoreTO imageStore = iso.getDataStore();
+                		if (!(imageStore instanceof NfsTO)) {
+                			s_logger.debug("unsupported protocol");
+                			throw new Exception("unsupported protocol");
+                		}
+                		NfsTO nfsImageStore = (NfsTO)imageStore;
+                		String isoPath = nfsImageStore.getUrl() + File.separator + iso.getPath();
+                		Pair<String, ManagedObjectReference> isoDatastoreInfo = getIsoDatastoreInfo(hyperHost, isoPath);
+                		assert (isoDatastoreInfo != null);
+                		assert (isoDatastoreInfo.second() != null);
+
+                		deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
+                		Pair<VirtualDevice, Boolean> isoInfo = VmwareHelper.prepareIsoDevice(vmMo, isoDatastoreInfo.first(), isoDatastoreInfo.second(), true, true, i, i + 1);
+                		deviceConfigSpecArray[i].setDevice(isoInfo.first());
+                		if (isoInfo.second()) {
+                			if(s_logger.isDebugEnabled())
+                				s_logger.debug("Prepare ISO volume at new device " + _gson.toJson(isoInfo.first()));
+                			deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.ADD);
+                		} else {
+                			if(s_logger.isDebugEnabled())
+                				s_logger.debug("Prepare ISO volume at existing device " + _gson.toJson(isoInfo.first()));
+                			deviceConfigSpecArray[i].setOperation(VirtualDeviceConfigSpecOperation.EDIT);
+                		}
+                	}
                 } else {
                     deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
                     Pair<VirtualDevice, Boolean> isoInfo = VmwareHelper.prepareIsoDevice(vmMo, null, null, true, true, i, i + 1);
@@ -2224,7 +2265,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
                 i++;
             }
 
-            for (VolumeTO vol : sortVolumesByDeviceId(disks)) {
+            for (DiskTO vol : sortVolumesByDeviceId(disks)) {
                 deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec();
 
                 if (vol.getType() == Volume.Type.ISO) {
@@ -2247,11 +2288,13 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
                 }
 
                 if (vol.getType() != Volume.Type.ISO) {
-                    Pair<ManagedObjectReference, DatastoreMO> volumeDsDetails = dataStoresDetails.get(vol.getPoolUuid());
+                	VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData();
+                	PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volumeTO.getDataStore();
+                    Pair<ManagedObjectReference, DatastoreMO> volumeDsDetails = dataStoresDetails.get(primaryStore.getUuid());
                     assert (volumeDsDetails != null);
                     VirtualDevice device;
-                    datastoreDiskPath = String.format("[%s] %s.vmdk", volumeDsDetails.second().getName(), vol.getPath());
-                    String chainInfo = vol.getChainInfo();
+                    datastoreDiskPath = String.format("[%s] %s.vmdk", volumeDsDetails.second().getName(), volumeTO.getPath());
+                    String chainInfo = volumeTO.getChainInfo();
 
                     if (chainInfo != null && !chainInfo.isEmpty()) {
                         String[] diskChain = _gson.fromJson(chainInfo, String[].class);
@@ -2424,19 +2467,19 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         return listForSort.toArray(new NicTO[0]);
     }
 
-    private VolumeTO[] sortVolumesByDeviceId(VolumeTO[] volumes) {
+    private DiskTO[] sortVolumesByDeviceId(DiskTO[] volumes) {
 
-        List<VolumeTO> listForSort = new ArrayList<VolumeTO>();
-        for (VolumeTO vol : volumes) {
+        List<DiskTO> listForSort = new ArrayList<DiskTO>();
+        for (DiskTO vol : volumes) {
             listForSort.add(vol);
         }
-        Collections.sort(listForSort, new Comparator<VolumeTO>() {
+        Collections.sort(listForSort, new Comparator<DiskTO>() {
 
             @Override
-            public int compare(VolumeTO arg0, VolumeTO arg1) {
-                if (arg0.getDeviceId() < arg1.getDeviceId()) {
+            public int compare(DiskTO arg0, DiskTO arg1) {
+                if (arg0.getDiskSeq() < arg1.getDiskSeq()) {
                     return -1;
-                } else if (arg0.getDeviceId() == arg1.getDeviceId()) {
+                } else if (arg0.getDiskSeq() == arg1.getDiskSeq()) {
                     return 0;
                 }
 
@@ -2444,16 +2487,18 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
             }
         });
 
-        return listForSort.toArray(new VolumeTO[0]);
+        return listForSort.toArray(new DiskTO[0]);
     }
 
-    private HashMap<String, Pair<ManagedObjectReference, DatastoreMO>> inferDatastoreDetailsFromDiskInfo(VmwareHypervisorHost hyperHost, VmwareContext context, VolumeTO[] disks) throws Exception {
+    private HashMap<String, Pair<ManagedObjectReference, DatastoreMO>> inferDatastoreDetailsFromDiskInfo(VmwareHypervisorHost hyperHost, VmwareContext context, DiskTO[] disks) throws Exception {
         HashMap<String ,Pair<ManagedObjectReference, DatastoreMO>> poolMors = new HashMap<String, Pair<ManagedObjectReference, DatastoreMO>>();
 
         assert (hyperHost != null) && (context != null);
-        for (VolumeTO vol : disks) {
+        for (DiskTO vol : disks) {
             if (vol.getType() != Volume.Type.ISO) {
-                String poolUuid = vol.getPoolUuid();
+            	VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData();
+            	PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)volumeTO.getDataStore();
+                String poolUuid = primaryStore.getUuid();
                 if(poolMors.get(poolUuid) == null) {
                     ManagedObjectReference morDataStore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, poolUuid);
                     if (morDataStore == null) {
@@ -2461,7 +2506,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
                         s_logger.error(msg);
                         throw new Exception(msg);
                     }
-                    poolMors.put(vol.getPoolUuid(), new Pair<ManagedObjectReference, DatastoreMO> (morDataStore, new DatastoreMO(context, morDataStore)));
+                    poolMors.put(poolUuid, new Pair<ManagedObjectReference, DatastoreMO> (morDataStore, new DatastoreMO(context, morDataStore)));
                 }
             }
         }
@@ -3306,7 +3351,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         }
     }
 
-    private synchronized ManagedObjectReference prepareSecondaryDatastoreOnHost(String storeUrl) throws Exception {
+    public synchronized ManagedObjectReference prepareSecondaryDatastoreOnHost(String storeUrl) throws Exception {
         String storeName = getSecondaryDatastoreUUID(storeUrl);
         URI uri = new URI(storeUrl);
 
@@ -3670,8 +3715,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         }
     }
 
-    @Override
-    public Answer execute(DestroyCommand cmd) {
+    
+    public Answer execute(DeleteCommand cmd) {
         if (s_logger.isInfoEnabled()) {
             s_logger.info("Executing resource DestroyCommand: " + _gson.toJson(cmd));
         }
@@ -3691,11 +3736,12 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         try {
             VmwareContext context = getServiceContext();
             VmwareHypervisorHost hyperHost = getHyperHost(context);
-            VolumeTO vol = cmd.getVolume();
+            VolumeObjectTO vol = (VolumeObjectTO)cmd.getData();
+            PrimaryDataStoreTO store = (PrimaryDataStoreTO)vol.getDataStore();
 
-            ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, vol.getPoolUuid());
+            ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, store.getUuid());
             if (morDs == null) {
-                String msg = "Unable to find datastore based on volume mount point " + cmd.getVolume().getMountPoint();
+                String msg = "Unable to find datastore based on volume mount point " + store.getPath();
                 s_logger.error(msg);
                 throw new Exception(msg);
             }
@@ -3706,8 +3752,8 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
             ManagedObjectReference morCluster = hyperHost.getHyperHostCluster();
             ClusterMO clusterMo = new ClusterMO(context, morCluster);
 
-            if (cmd.getVolume().getType() == Volume.Type.ROOT) {
-                String vmName = cmd.getVmName();
+            if (vol.getVolumeType() == Volume.Type.ROOT) {
+                String vmName = vol.getVmName();
                 if (vmName != null) {
                     VirtualMachineMO vmMo = clusterMo.findVmOnHyperHost(vmName);
                     if (vmMo != null) {
@@ -3734,20 +3780,20 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
                     }
 
                     if (s_logger.isInfoEnabled())
-                        s_logger.info("Destroy volume by original name: " + cmd.getVolume().getPath() + ".vmdk");
-                    dsMo.deleteFile(cmd.getVolume().getPath() + ".vmdk", morDc, true);
+                        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: " + cmd.getVolume().getPath() + "-flat.vmdk");
+                            s_logger.info("Destroy volume by derived name: " + vol.getPath() + "-flat.vmdk");
                         }
-                        dsMo.deleteFile(cmd.getVolume().getPath() + "-flat.vmdk", morDc, true);
+                        dsMo.deleteFile(vol.getPath() + "-flat.vmdk", morDc, true);
                     } else {
                         if (s_logger.isInfoEnabled()) {
-                        s_logger.info("Destroy volume by derived name: " + cmd.getVolume().getPath() + "-delta.vmdk");
+                        s_logger.info("Destroy volume by derived name: " + vol.getPath() + "-delta.vmdk");
                         }
-                    dsMo.deleteFile(cmd.getVolume().getPath() + "-delta.vmdk", morDc, true);
+                    dsMo.deleteFile(vol.getPath() + "-delta.vmdk", morDc, true);
                     }
                     return new Answer(cmd, true, "Success");
                 }
@@ -3757,17 +3803,17 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
                 }
             } else {
                 // evitTemplate will be converted into DestroyCommand, test if we are running in this case
-                VirtualMachineMO vmMo = clusterMo.findVmOnHyperHost(cmd.getVolume().getPath());
+                VirtualMachineMO vmMo = clusterMo.findVmOnHyperHost(vol.getPath());
                 if (vmMo != null) {
                     if (s_logger.isInfoEnabled())
-                        s_logger.info("Destroy template volume " + cmd.getVolume().getPath());
+                        s_logger.info("Destroy template volume " + vol.getPath());
 
                     vmMo.destroy();
                     return new Answer(cmd, true, "Success");
                 }
             }
 
-            String chainInfo = cmd.getVolume().getChainInfo();
+            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);
@@ -3783,23 +3829,23 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
                     if (s_logger.isInfoEnabled()) {
                         s_logger.info("Empty disk chain info, fall back to try to delete by original backing file name");
                     }
-                    dsMo.deleteFile(cmd.getVolume().getPath() + ".vmdk", morDc, true);
+                    dsMo.deleteFile(vol.getPath() + ".vmdk", morDc, true);
 
                     if (s_logger.isInfoEnabled()) {
-                        s_logger.info("Destroy volume by derived name: " + cmd.getVolume().getPath() + "-flat.vmdk");
+                        s_logger.info("Destroy volume by derived name: " + vol.getPath() + "-flat.vmdk");
                     }
-                    dsMo.deleteFile(cmd.getVolume().getPath() + "-flat.vmdk", morDc, true);
+                    dsMo.deleteFile(vol.getPath() + "-flat.vmdk", morDc, true);
                 }
             } else {
                 if (s_logger.isInfoEnabled()) {
-                    s_logger.info("Destroy volume by original name: " + cmd.getVolume().getPath() + ".vmdk");
+                    s_logger.info("Destroy volume by original name: " + vol.getPath() + ".vmdk");
                 }
-                dsMo.deleteFile(cmd.getVolume().getPath() + ".vmdk", morDc, true);
+                dsMo.deleteFile(vol.getPath() + ".vmdk", morDc, true);
 
                 if (s_logger.isInfoEnabled()) {
-                    s_logger.info("Destroy volume by derived name: " + cmd.getVolume().getPath() + "-flat.vmdk");
+                    s_logger.info("Destroy volume by derived name: " + vol.getPath() + "-flat.vmdk");
                 }
-                dsMo.deleteFile(cmd.getVolume().getPath() + "-flat.vmdk", morDc, true);
+                dsMo.deleteFile(vol.getPath() + "-flat.vmdk", morDc, true);
             }
 
             return new Answer(cmd, true, "Success");
@@ -3815,7 +3861,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         }
     }
 
-    private void cleanupNetwork(HostMO hostMo, NetworkDetails netDetails) {
+    public void cleanupNetwork(HostMO hostMo, NetworkDetails netDetails) {
         // we will no longer cleanup VLAN networks in order to support native VMware HA
         /*
          * assert(netDetails.getName() != null); try { synchronized(this) { NetworkMO networkMo = new
@@ -4857,7 +4903,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         return s_statesTable.get(powerState);
     }
 
-    private static State getVmState(VirtualMachineMO vmMo) throws Exception {
+    public static State getVmState(VirtualMachineMO vmMo) throws Exception {
         VirtualMachineRuntimeInfo runtimeInfo = vmMo.getRuntimeInfo();
         return convertState(runtimeInfo.getPowerState());
     }
@@ -4991,6 +5037,13 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         } else {
             _fullCloneFlag = false;
         }
+        value = (String)params.get("scripts.timeout");
+        int timeout = NumbersUtil.parseInt(value, 1440) * 1000;
+        VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME);
+        VmwareStorageProcessor storageProcessor = new VmwareStorageProcessor((VmwareHostService)this, this._fullCloneFlag, (VmwareStorageMount)mgr,
+        		timeout, this, this._shutdown_waitMs
+        		);
+        storageHandler = new StorageSubsystemCommandHandlerBase(storageProcessor);
 
         return true;
     }
@@ -5010,15 +5063,15 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
         return true;
     }
 
-    private VmwareContext getServiceContext() {
+    public VmwareContext getServiceContext() {
         return getServiceContext(null);
     }
 
-    private void invalidateServiceContext() {
+    public void invalidateServiceContext() {
         invalidateServiceContext(null);
     }
 
-    private VmwareHypervisorHost getHyperHost(VmwareContext context) {
+    public VmwareHypervisorHost getHyperHost(VmwareContext context) {
         return getHyperHost(context, null);
     }
 
@@ -5115,4 +5168,10 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
 		// TODO Auto-generated method stub
 
 	}
+
+	@Override
+	public Answer execute(DestroyCommand cmd) {
+		// TODO Auto-generated method stub
+		return null;
+	}
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/42e25a22/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java
index 566e750..645b6d3 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareSecondaryStorageResourceHandler.java
@@ -18,6 +18,7 @@ package com.cloud.storage.resource;
 
 import java.util.List;
 
+import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
 import org.apache.log4j.Logger;
 
 import com.cloud.agent.api.Answer;
@@ -29,6 +30,7 @@ import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
 import com.cloud.agent.api.storage.CopyVolumeCommand;
 import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
 import com.cloud.hypervisor.vmware.manager.VmwareHostService;
+import com.cloud.hypervisor.vmware.manager.VmwareManager;
 import com.cloud.hypervisor.vmware.manager.VmwareStorageManager;
 import com.cloud.hypervisor.vmware.manager.VmwareStorageManagerImpl;
 import com.cloud.hypervisor.vmware.manager.VmwareStorageMount;
@@ -51,6 +53,7 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe
     private final VmwareStorageManager _storageMgr;
 
     private final Gson _gson;
+    private StorageSubsystemCommandHandler storageSubsystemHandler;
 
     /*
 	private Map<String, HostMO> _activeHosts = new HashMap<String, HostMO>();
@@ -60,6 +63,11 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe
         _resource = resource;
         _storageMgr = new VmwareStorageManagerImpl(this);
         _gson = GsonHelper.getGsonLogger();
+      
+        VmwareStorageProcessor storageProcessor = new VmwareStorageProcessor((VmwareHostService)this, true, (VmwareStorageMount)this,
+        		null, null, null
+        		);
+        storageSubsystemHandler = new StorageSubsystemCommandHandlerBase(storageProcessor);
     }
 
     @Override
@@ -77,6 +85,8 @@ public class VmwareSecondaryStorageResourceHandler implements SecondaryStorageRe
             answer = execute((CopyVolumeCommand)cmd);
         } else if(cmd instanceof CreateVolumeFromSnapshotCommand) {
             answer = execute((CreateVolumeFromSnapshotCommand)cmd);
+        } else if (cmd instanceof StorageSubSystemCommand) {
+        	answer = storageSubsystemHandler.handleStorageCommands((StorageSubSystemCommand)cmd);
         } else {
             answer =  _resource.defaultAction(cmd);
         }


[7/7] git commit: updated refs/heads/object_store to e444867

Posted by ed...@apache.org.
fix compile


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/e444867e
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/e444867e
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/e444867e

Branch: refs/heads/object_store
Commit: e444867e619e88a68af0a06974f63ed892e8d39d
Parents: 42e25a2
Author: Edison Su <ed...@citrix.com>
Authored: Fri May 10 09:47:09 2013 -0700
Committer: Edison Su <ed...@citrix.com>
Committed: Fri May 10 09:47:09 2013 -0700

----------------------------------------------------------------------
 .../storage/image/TemplateDataFactoryImpl.java     |   11 ------
 .../com/cloud/ovm/hypervisor/OvmResourceBase.java  |   26 ++++++++++++---
 .../com/cloud/hypervisor/HypervisorGuruBase.java   |    3 +-
 tools/marvin/marvin/deployDataCenter.py            |    5 ++-
 4 files changed, 26 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e444867e/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateDataFactoryImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateDataFactoryImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateDataFactoryImpl.java
index 09c79b2..52c79e6 100644
--- a/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateDataFactoryImpl.java
+++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/TemplateDataFactoryImpl.java
@@ -90,17 +90,6 @@ public class TemplateDataFactoryImpl implements TemplateDataFactory {
         }
         return this.getTemplate(templateId, store);
     }
-    
-    @Override
-    public TemplateInfo getTemplate(long templateId, long zoneId) {
-        TemplateDataStoreVO tmplStore = templateStoreDao.findByTemplateZoneDownloadStatus(templateId, zoneId, VMTemplateStorageResourceAssoc.Status.DOWNLOADED);
-        if (tmplStore != null) {
-            DataStore store = this.storeMgr.getDataStore(tmplStore.getDataStoreId(), DataStoreRole.Image);
-            return this.getTemplate(templateId, store);
-        }
-        return null;
-    }
-
 
     @Override
     public TemplateInfo getTemplate(long templateId, DataStoreRole storeRole, Long zoneId) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e444867e/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java b/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java
index 7d8d90c..61ac54e 100755
--- a/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java
+++ b/plugins/hypervisors/ovm/src/com/cloud/ovm/hypervisor/OvmResourceBase.java
@@ -29,6 +29,8 @@ import java.util.concurrent.ConcurrentHashMap;
 
 import javax.naming.ConfigurationException;
 
+import org.apache.cloudstack.storage.to.TemplateObjectTO;
+import org.apache.cloudstack.storage.to.VolumeObjectTO;
 import org.apache.log4j.Logger;
 import org.apache.xmlrpc.XmlRpcException;
 
@@ -90,6 +92,10 @@ import com.cloud.agent.api.storage.CreatePrivateTemplateAnswer;
 import com.cloud.agent.api.storage.DestroyCommand;
 import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
 import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand;
+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.NicTO;
 import com.cloud.agent.api.to.StorageFilerTO;
 import com.cloud.agent.api.to.VirtualMachineTO;
@@ -527,25 +533,35 @@ public class OvmResourceBase implements ServerResource, HypervisorResource {
 	}
 	
 	protected void createVbds(OvmVm.Details vm, VirtualMachineTO spec) throws URISyntaxException {
-		for (VolumeTO volume : spec.getDisks()) {
+		for (DiskTO volume : spec.getDisks()) {
 			if (volume.getType() == Volume.Type.ROOT) {
+				VolumeObjectTO vol = (VolumeObjectTO)volume.getData();
 				OvmDisk.Details root = new OvmDisk.Details();
-				root.path = volume.getPath();
+				root.path = vol.getPath();
 				root.type = OvmDisk.WRITE;
 				root.isIso = false;
 				vm.rootDisk = root;
 			} else if (volume.getType() == Volume.Type.ISO) {
-				if (volume.getPath() != null) {
+				DataTO isoTO = volume.getData();
+				if (isoTO.getPath() != null) {
+					TemplateObjectTO template = (TemplateObjectTO)isoTO;
+					DataStoreTO store = template.getDataStore();
+					if (!(store instanceof NfsTO)) {
+						throw new CloudRuntimeException("unsupported protocol");
+					}
+					NfsTO nfsStore = (NfsTO)store;
+					String isoPath = nfsStore.getUrl() + File.separator + template.getPath();
 					OvmDisk.Details iso = new OvmDisk.Details();
-					URI path = new URI(volume.getPath());
+					URI path = new URI(isoPath);
 					iso.path = path.getHost() + ":" + path.getPath();
 					iso.type = OvmDisk.READ;
 					iso.isIso = true;
 					vm.disks.add(iso);
 				}
 			} else if (volume.getType() == Volume.Type.DATADISK){
+				
 				OvmDisk.Details data = new OvmDisk.Details();
-				data.path = volume.getPath();
+				data.path = volume.getData().getPath();
 				data.type = OvmDisk.SHAREDWRITE;
 				data.isIso = false;
 				vm.disks.add(data);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e444867e/server/src/com/cloud/hypervisor/HypervisorGuruBase.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java
index 2300953..e11aa50 100644
--- a/server/src/com/cloud/hypervisor/HypervisorGuruBase.java
+++ b/server/src/com/cloud/hypervisor/HypervisorGuruBase.java
@@ -23,6 +23,7 @@ import javax.inject.Inject;
 
 import com.cloud.agent.api.Command;
 import com.cloud.agent.api.to.DataTO;
+import com.cloud.agent.api.to.DiskTO;
 import com.cloud.agent.api.to.NicTO;
 import com.cloud.agent.api.to.VirtualMachineTO;
 import com.cloud.agent.api.to.VolumeTO;
@@ -102,7 +103,7 @@ public abstract class HypervisorGuruBase extends AdapterBase implements Hypervis
         }
 
         to.setNics(nics);
-        to.setDisks(vmProfile.getDisks().toArray(new DataTO[vmProfile.getDisks().size()]));
+        to.setDisks(vmProfile.getDisks().toArray(new DiskTO[vmProfile.getDisks().size()]));
 
         if(vmProfile.getTemplate().getBits() == 32) {
             to.setArch("i686");

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/e444867e/tools/marvin/marvin/deployDataCenter.py
----------------------------------------------------------------------
diff --git a/tools/marvin/marvin/deployDataCenter.py b/tools/marvin/marvin/deployDataCenter.py
index 164af74..956d2bc 100644
--- a/tools/marvin/marvin/deployDataCenter.py
+++ b/tools/marvin/marvin/deployDataCenter.py
@@ -142,8 +142,9 @@ class deployDataCenters():
             secondarycmd.url = secondary.url
             secondarycmd.provider = secondary.providerName
             secondarycmd.details = []
-            for item in secondary.details:
-                secondarycmd.details.append(item.__dict__)
+            if secondary.providerName != "NFS":
+                for item in secondary.details:
+                    secondarycmd.details.append(item.__dict__)
             if secondarycmd.provider == "NFS":
                 secondarycmd.zoneid = zoneId
             self.apiClient.addImageStore(secondarycmd)