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/10/04 22:07:10 UTC

[1/2] Refactor Storage Related Resource Code These changes are a joint effort between Edison and I to refactor some of the code around snapshotting VM volumes and creating templates/volumes from VM volume snapshots. In general, we were working towards al

Updated Branches:
  refs/heads/master c9f41d404 -> 180cfa19e


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/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
index 739b974..5da0571 100644
--- a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
+++ b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
@@ -18,6 +18,36 @@
  */
 package com.cloud.hypervisor.xen.resource;
 
+import java.io.File;
+import java.net.URI;
+import java.util.Arrays;
+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.command.ForgetObjectCmd;
+import org.apache.cloudstack.storage.command.IntroduceObjectAnswer;
+import org.apache.cloudstack.storage.command.IntroduceObjectCmd;
+import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol;
+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;
@@ -51,33 +81,6 @@ import com.xensource.xenapi.VBD;
 import com.xensource.xenapi.VDI;
 import com.xensource.xenapi.VM;
 import com.xensource.xenapi.VMGuestMetrics;
-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 java.io.File;
-import java.net.URI;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
 
 import static com.cloud.utils.ReflectUtil.flattenProperties;
 import static com.google.common.collect.Lists.newArrayList;
@@ -841,8 +844,7 @@ public class XenServerStorageProcessor implements StorageProcessor {
 
                 URI uri = new URI(storeUrl);
                 String tmplpath = uri.getHost() + ":" + uri.getPath() + "/" + srcData.getPath();
-                PrimaryDataStoreTO destStore = (PrimaryDataStoreTO)destData.getDataStore();
-                String poolName = destStore.getUuid();
+                String poolName = destData.getDataStore().getUuid();
                 Connection conn = hypervisorResource.getConnection();
 
                 SR poolsr = null;
@@ -892,8 +894,7 @@ public class XenServerStorageProcessor implements StorageProcessor {
 
         try {
             Connection conn = hypervisorResource.getConnection();
-            PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)data.getDataStore();
-            SR poolSr = hypervisorResource.getStorageRepository(conn, primaryStore.getUuid());
+            SR poolSr = hypervisorResource.getStorageRepository(conn, data.getDataStore().getUuid());
             VDI.Record vdir = new VDI.Record();
             vdir.nameLabel = volume.getName();
             vdir.SR = poolSr;
@@ -921,7 +922,6 @@ public class XenServerStorageProcessor implements StorageProcessor {
         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 {
@@ -943,7 +943,7 @@ public class XenServerStorageProcessor implements StorageProcessor {
 
             return new CopyCmdAnswer(newVol);
         } catch (Exception e) {
-            s_logger.warn("Unable to create volume; Pool=" + pool + "; Disk: ", e);
+            s_logger.warn("Unable to create volume; Pool=" + destData + "; Disk: ", e);
             return new CopyCmdAnswer(e.toString());
         }
     }
@@ -956,13 +956,12 @@ public class XenServerStorageProcessor implements StorageProcessor {
         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());
+                SR primaryStoragePool = hypervisorResource.getStorageRepository(conn, destVolume.getDataStore().getUuid());
                 String srUuid = primaryStoragePool.getUuid(conn);
                 URI uri = new URI(nfsStore.getUrl());
                 String volumePath = uri.getHost() + ":" + uri.getPath() + File.separator + srcVolume.getPath();
@@ -1179,8 +1178,7 @@ public class XenServerStorageProcessor implements StorageProcessor {
         DataTO cacheData = cmd.getCacheTO();
         DataTO destData = cmd.getDestTO();
         int wait = cmd.getWait();
-        PrimaryDataStoreTO primaryStore = (PrimaryDataStoreTO)srcData.getDataStore();
-        String primaryStorageNameLabel = primaryStore.getUuid();
+        String primaryStorageNameLabel = srcData.getDataStore().getUuid();
         String secondaryStorageUrl = null;
         NfsTO cacheStore = null;
         String destPath = null;
@@ -1415,7 +1413,6 @@ public class XenServerStorageProcessor implements StorageProcessor {
         DataTO srcData = cmd.getSrcTO();
         SnapshotObjectTO snapshot = (SnapshotObjectTO)srcData;
         DataTO destData = cmd.getDestTO();
-        PrimaryDataStoreTO pool = (PrimaryDataStoreTO)destData.getDataStore();
         DataStoreTO imageStore = srcData.getDataStore();
 
         if (!(imageStore instanceof NfsTO)) {
@@ -1423,7 +1420,7 @@ public class XenServerStorageProcessor implements StorageProcessor {
         }
 
         NfsTO nfsImageStore = (NfsTO)imageStore;
-        String primaryStorageNameLabel = pool.getUuid();
+        String primaryStorageNameLabel = destData.getDataStore().getUuid();
         String secondaryStorageUrl = nfsImageStore.getUrl();
         int wait = cmd.getWait();
         boolean result = false;
@@ -1503,4 +1500,32 @@ public class XenServerStorageProcessor implements StorageProcessor {
         }
         return new Answer(cmd, false, "unsupported storage type");
     }
+
+    @Override
+    public Answer introduceObject(IntroduceObjectCmd cmd) {
+        try {
+            Connection conn = hypervisorResource.getConnection();
+            DataStoreTO store = cmd.getDataTO().getDataStore();
+            SR poolSr = hypervisorResource.getStorageRepository(conn, store.getUuid());
+            poolSr.scan(conn);
+            return new IntroduceObjectAnswer(cmd.getDataTO());
+        } catch (Exception e) {
+            s_logger.debug("Failed to introduce object", e);
+            return new Answer(cmd, false, e.toString());
+        }
+    }
+
+    @Override
+    public Answer forgetObject(ForgetObjectCmd cmd) {
+        try {
+            Connection conn = hypervisorResource.getConnection();
+            DataTO data = cmd.getDataTO();
+            VDI vdi = VDI.getByUuid(conn, data.getPath());
+            vdi.forget(conn);
+            return new IntroduceObjectAnswer(cmd.getDataTO());
+        } catch (Exception e) {
+            s_logger.debug("Failed to introduce object", e);
+            return new Answer(cmd, false, e.toString());
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
index 2297e6a..0b53cfd 100755
--- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
+++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
@@ -48,7 +48,6 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
-
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
@@ -69,13 +68,11 @@ import com.cloud.event.ActionEventUtils;
 import com.cloud.event.EventTypes;
 import com.cloud.event.EventVO;
 import com.cloud.event.UsageEventUtils;
-import com.cloud.event.dao.EventDao;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.PermissionDeniedException;
 import com.cloud.exception.ResourceAllocationException;
 import com.cloud.exception.StorageUnavailableException;
 import com.cloud.host.HostVO;
-import com.cloud.host.dao.HostDao;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.projects.Project.ListProjectResourcesCriteria;
 import com.cloud.resource.ResourceManager;
@@ -193,10 +190,10 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
     @Inject VolumeDataFactory volFactory;
     @Inject SnapshotDataFactory snapshotFactory;
     @Inject EndPointSelector _epSelector;
-	@Inject
-	private ResourceManager _resourceMgr;
-	@Inject
-	protected List<SnapshotStrategy> snapshotStrategies;
+    @Inject
+    private ResourceManager _resourceMgr;
+    @Inject
+    protected List<SnapshotStrategy> snapshotStrategies;
 
 
     private int _totalRetries;
@@ -261,16 +258,38 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
     }
 
     @Override
+    public boolean revertSnapshot(Long snapshotId) {
+        Snapshot snapshot = _snapshotDao.findById(snapshotId);
+        if (snapshot == null) {
+            throw new InvalidParameterValueException("No such snapshot");
+        }
+
+        SnapshotStrategy snapshotStrategy = null;
+        for (SnapshotStrategy strategy : snapshotStrategies) {
+            if (strategy.canHandle(snapshot)) {
+                snapshotStrategy = strategy;
+                break;
+            }
+        }
+
+        if (snapshotStrategy == null) {
+            return false;
+        }
+
+        return snapshotStrategy.revertSnapshot(snapshotId);
+    }
+
+    @Override
     @DB
     @ActionEvent(eventType = EventTypes.EVENT_SNAPSHOT_CREATE, eventDescription = "creating snapshot", async = true)
     public Snapshot createSnapshot(Long volumeId, Long policyId, Long snapshotId, Account snapshotOwner) {
         VolumeInfo volume = volFactory.getVolume(volumeId);
         if (volume == null) {
-        	throw new InvalidParameterValueException("No such volume exist");
+            throw new InvalidParameterValueException("No such volume exist");
         }
 
         if (volume.getState() != Volume.State.Ready) {
-        	throw new InvalidParameterValueException("Volume is not in ready state");
+            throw new InvalidParameterValueException("Volume is not in ready state");
         }
 
 
@@ -281,16 +300,16 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
         SnapshotInfo snapshot = snapshotFactory.getSnapshot(snapshotId, DataStoreRole.Primary);
 
         try {
-        	postCreateSnapshot(volumeId, snapshot.getId(), policyId);
-        	//Check if the snapshot was removed while backingUp. If yes, do not log snapshot create usage event
-        	SnapshotVO freshSnapshot = _snapshotDao.findById(snapshot.getId());
-        	if ((freshSnapshot != null) && backedUp) {
-        		UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(),
-        				snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null,
-        				volume.getSize(), snapshot.getClass().getName(), snapshot.getUuid());
-        	}
+            postCreateSnapshot(volumeId, snapshot.getId(), policyId);
+            //Check if the snapshot was removed while backingUp. If yes, do not log snapshot create usage event
+            SnapshotVO freshSnapshot = _snapshotDao.findById(snapshot.getId());
+            if ((freshSnapshot != null) && backedUp) {
+                UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_CREATE, snapshot.getAccountId(),
+                        snapshot.getDataCenterId(), snapshotId, snapshot.getName(), null, null,
+                        volume.getSize(), snapshot.getClass().getName(), snapshot.getUuid());
+            }
 
-        	_resourceLimitMgr.incrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot);
+            _resourceLimitMgr.incrementResourceCount(snapshotOwner.getId(), ResourceType.snapshot);
 
         } catch(Exception e) {
             s_logger.debug("Failed to create snapshot", e);
@@ -311,12 +330,12 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
 
     @Override
     public Snapshot backupSnapshot(Long snapshotId) {
-    	 SnapshotInfo snapshot = snapshotFactory.getSnapshot(snapshotId, DataStoreRole.Image);
-    	 if (snapshot != null) {
-    		 throw new CloudRuntimeException("Already in the backup snapshot:" + snapshotId);
-    	 }
+        SnapshotInfo snapshot = snapshotFactory.getSnapshot(snapshotId, DataStoreRole.Image);
+        if (snapshot != null) {
+            throw new CloudRuntimeException("Already in the backup snapshot:" + snapshotId);
+        }
 
-         return snapshotSrv.backupSnapshot(snapshot);
+        return snapshotSrv.backupSnapshot(snapshot);
     }
 
     /*
@@ -412,14 +431,14 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
 
     @Override
     public SnapshotVO getParentSnapshot(VolumeInfo volume) {
-    	 long preId = _snapshotDao.getLastSnapshot(volume.getId(), DataStoreRole.Primary);
+        long preId = _snapshotDao.getLastSnapshot(volume.getId(), DataStoreRole.Primary);
 
-         SnapshotVO preSnapshotVO = null;
-         if (preId != 0 && !(volume.getLastPoolId() != null && !volume.getLastPoolId().equals(volume.getPoolId()))) {
-             preSnapshotVO = _snapshotDao.findByIdIncludingRemoved(preId);
-         }
+        SnapshotVO preSnapshotVO = null;
+        if (preId != 0 && !(volume.getLastPoolId() != null && !volume.getLastPoolId().equals(volume.getPoolId()))) {
+            preSnapshotVO = _snapshotDao.findByIdIncludingRemoved(preId);
+        }
 
-         return preSnapshotVO;
+        return preSnapshotVO;
     }
 
     private Long getSnapshotUserId() {
@@ -463,7 +482,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
                 s_logger.debug("Max snaps: " + policy.getMaxSnaps() + " exceeded for snapshot policy with Id: " + policyId + ". Deleting oldest snapshot: " + oldSnapId);
             }
             if(deleteSnapshot(oldSnapId)){
-            	//log Snapshot delete event
+                //log Snapshot delete event
                 ActionEventUtils.onCompletedActionEvent(User.UID_SYSTEM, oldestSnapshot.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_SNAPSHOT_DELETE, "Successfully deleted oldest snapshot: " + oldSnapId, 0);
             }
             snaps.remove(oldestSnapshot);
@@ -485,27 +504,27 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
         _accountMgr.checkAccess(caller, null, true, snapshotCheck);
         SnapshotStrategy snapshotStrategy = null;
         for (SnapshotStrategy strategy : snapshotStrategies) {
-        	if (strategy.canHandle(snapshotCheck)) {
-        		snapshotStrategy = strategy;
-        		break;
-        	}
+            if (strategy.canHandle(snapshotCheck)) {
+                snapshotStrategy = strategy;
+                break;
+            }
         }
         try {
-        	boolean result = snapshotStrategy.deleteSnapshot(snapshotId);
-        	if (result) {
+            boolean result = snapshotStrategy.deleteSnapshot(snapshotId);
+            if (result) {
                 if (snapshotCheck.getState() == Snapshot.State.BackedUp) {
-        			UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshotCheck.getAccountId(),
-        					snapshotCheck.getDataCenterId(), snapshotId, snapshotCheck.getName(), null, null, 0L,
-        					snapshotCheck.getClass().getName(), snapshotCheck.getUuid());
-        		}
+                    UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE, snapshotCheck.getAccountId(),
+                            snapshotCheck.getDataCenterId(), snapshotId, snapshotCheck.getName(), null, null, 0L,
+                            snapshotCheck.getClass().getName(), snapshotCheck.getUuid());
+                }
                 _resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(), ResourceType.snapshot);
                 _resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(), ResourceType.secondary_storage,
                         new Long(snapshotCheck.getSize()));
-        	}
-        	return result;
+            }
+            return result;
         } catch (Exception e) {
-        	s_logger.debug("Failed to delete snapshot: " + snapshotCheck.getId() + ":" + e.toString());
-        	throw new CloudRuntimeException("Failed to delete snapshot:" + e.toString());
+            s_logger.debug("Failed to delete snapshot: " + snapshotCheck.getId() + ":" + e.toString());
+            throw new CloudRuntimeException("Failed to delete snapshot:" + e.toString());
         }
     }
 
@@ -544,10 +563,10 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
         }
 
         Ternary<Long, Boolean, ListProjectResourcesCriteria> domainIdRecursiveListProject = new Ternary<Long, Boolean, ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null);
-       _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
-       Long domainId = domainIdRecursiveListProject.first();
-       Boolean isRecursive = domainIdRecursiveListProject.second();
-       ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
+        _accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false);
+        Long domainId = domainIdRecursiveListProject.first();
+        Boolean isRecursive = domainIdRecursiveListProject.second();
+        ListProjectResourcesCriteria listProjectResourcesCriteria = domainIdRecursiveListProject.third();
 
         Filter searchFilter = new Filter(SnapshotVO.class, "created", false, cmd.getStartIndex(), cmd.getPageSizeVal());
         SearchBuilder<SnapshotVO> sb = _snapshotDao.createSearchBuilder();
@@ -560,7 +579,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
         sb.and("snapshotTypeEQ", sb.entity().getsnapshotType(), SearchCriteria.Op.IN);
         sb.and("snapshotTypeNEQ", sb.entity().getsnapshotType(), SearchCriteria.Op.NEQ);
         sb.and("dataCenterId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ);
-        
+
         if (tags != null && !tags.isEmpty()) {
             SearchBuilder<ResourceTagVO> tagSearch = _resourceTagDao.createSearchBuilder();
             for (int count=0; count < tags.size(); count++) {
@@ -595,7 +614,7 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
         if (zoneId != null) {
             sc.setParameters("dataCenterId", zoneId);
         }
-        
+
         if (name != null) {
             sc.setParameters("name", "%" + name + "%");
         }
@@ -763,10 +782,10 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
         long domainLimit = _resourceLimitMgr.findCorrectResourceLimitForDomain(_domainMgr.getDomain(owner.getDomainId()), ResourceType.snapshot);
         int max = cmd.getMaxSnaps().intValue();
         if (owner.getType() != Account.ACCOUNT_TYPE_ADMIN && ((accountLimit != -1 && max > accountLimit) || (domainLimit != -1 && max > domainLimit))) {
-        	String message = "domain/account";
-        	if (owner.getType() == Account.ACCOUNT_TYPE_PROJECT) {
-        		message = "domain/project";
-        	}
+            String message = "domain/account";
+            if (owner.getType() == Account.ACCOUNT_TYPE_PROJECT) {
+                message = "domain/project";
+            }
 
             throw new InvalidParameterValueException("Max number of snapshots shouldn't exceed the " + message + " level snapshot limit");
         }
@@ -905,37 +924,37 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
 
 
     private boolean hostSupportSnapsthotForVolume(HostVO host, VolumeInfo volume) {
-		if (host.getHypervisorType() != HypervisorType.KVM) {
-			return true;
-		}
+        if (host.getHypervisorType() != HypervisorType.KVM) {
+            return true;
+        }
 
         //Turn off snapshot by default for KVM if the volume attached to vm that is not in the Stopped/Destroyed state,
-		//unless it is set in the global flag
-		Long vmId = volume.getInstanceId();
-		if (vmId != null) {
-		    VMInstanceVO vm = _vmDao.findById(vmId);
-		    if (vm.getState() != VirtualMachine.State.Stopped && vm.getState() != VirtualMachine.State.Destroyed) {
-		        boolean snapshotEnabled = Boolean.parseBoolean(_configDao.getValue("kvm.snapshot.enabled"));
-	            if (!snapshotEnabled) {
-	                 s_logger.debug("Snapshot is not supported on host " + host + " for the volume " + volume + " attached to the vm " + vm);
-	                 return false;
-	            }
-		    }
-		}
-        
-		// Determine host capabilities
-		String caps = host.getCapabilities();
-
-		if (caps != null) {
-			String[] tokens = caps.split(",");
-			for (String token : tokens) {
-				if (token.contains("snapshot")) {
-					return true;
-				}
-			}
-		}
-		return false;
-	}
+        //unless it is set in the global flag
+        Long vmId = volume.getInstanceId();
+        if (vmId != null) {
+            VMInstanceVO vm = _vmDao.findById(vmId);
+            if (vm.getState() != VirtualMachine.State.Stopped && vm.getState() != VirtualMachine.State.Destroyed) {
+                boolean snapshotEnabled = Boolean.parseBoolean(_configDao.getValue("kvm.snapshot.enabled"));
+                if (!snapshotEnabled) {
+                    s_logger.debug("Snapshot is not supported on host " + host + " for the volume " + volume + " attached to the vm " + vm);
+                    return false;
+                }
+            }
+        }
+
+        // Determine host capabilities
+        String caps = host.getCapabilities();
+
+        if (caps != null) {
+            String[] tokens = caps.split(",");
+            for (String token : tokens) {
+                if (token.contains("snapshot")) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
 
     private boolean supportedByHypervisor(VolumeInfo volume) {
         HypervisorType hypervisorType;
@@ -967,10 +986,10 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
             }
         }
 
-		// if volume is attached to a vm in destroyed or expunging state; disallow
-		if (volume.getInstanceId() != null) {
-			UserVmVO userVm = _vmDao.findById(volume.getInstanceId());
-			if (userVm != null) {
+        // if volume is attached to a vm in destroyed or expunging state; disallow
+        if (volume.getInstanceId() != null) {
+            UserVmVO userVm = _vmDao.findById(volume.getInstanceId());
+            if (userVm != null) {
                 if (userVm.getState().equals(State.Destroyed) || userVm.getState().equals(State.Expunging)) {
                     throw new CloudRuntimeException("Creating snapshot failed due to volume:" + volume.getId()
                             + " is associated with vm:" + userVm.getInstanceName() + " is in "
@@ -993,11 +1012,11 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
                     throw new CloudRuntimeException(
                             "There is other active vm snapshot tasks on the instance to which the volume is attached, please try again later");
                 }
-			}
-		}
+            }
+        }
 
-		return true;
-	}
+        return true;
+    }
     @Override
     @DB
     public SnapshotInfo takeSnapshot(VolumeInfo volume) throws ResourceAllocationException {
@@ -1124,10 +1143,10 @@ public class SnapshotManagerImpl extends ManagerBase implements SnapshotManager,
     public boolean canOperateOnVolume(Volume volume) {
         List<SnapshotVO> snapshots = _snapshotDao.listByStatus(volume.getId(), Snapshot.State.Creating,
                 Snapshot.State.CreatedOnPrimary, Snapshot.State.BackingUp);
-    	if (snapshots.size() > 0) {
-    		return false;
-    	}
-    	return true;
+        if (snapshots.size() > 0) {
+            return false;
+        }
+        return true;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java
----------------------------------------------------------------------
diff --git a/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java b/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java
index 3ef950b..e26f02d 100755
--- a/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java
+++ b/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java
@@ -16,14 +16,15 @@
 // under the License.
 package org.apache.cloudstack.storage.resource;
 
-import static com.cloud.utils.S3Utils.putFile;
-import static com.cloud.utils.StringUtils.join;
-import static com.cloud.utils.db.GlobalLock.executeWithNoWaitLock;
-import static java.lang.String.format;
-import static java.util.Arrays.asList;
-import static org.apache.commons.lang.StringUtils.substringAfterLast;
-
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
 import java.math.BigInteger;
 import java.net.InetAddress;
 import java.net.URI;
@@ -39,10 +40,6 @@ import java.util.concurrent.Callable;
 
 import javax.naming.ConfigurationException;
 
-import com.cloud.agent.api.storage.*;
-import com.cloud.storage.VMTemplateStorageResourceAssoc;
-import com.cloud.storage.template.*;
-import com.cloud.utils.SwiftUtil;
 import org.apache.cloudstack.storage.command.CopyCmdAnswer;
 import org.apache.cloudstack.storage.command.CopyCommand;
 import org.apache.cloudstack.storage.command.DeleteCommand;
@@ -53,6 +50,8 @@ import org.apache.cloudstack.storage.template.DownloadManagerImpl;
 import org.apache.cloudstack.storage.template.DownloadManagerImpl.ZfsPathParser;
 import org.apache.cloudstack.storage.template.UploadManager;
 import org.apache.cloudstack.storage.template.UploadManagerImpl;
+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;
@@ -88,6 +87,14 @@ import com.cloud.agent.api.SecStorageSetupCommand.Certificates;
 import com.cloud.agent.api.SecStorageVMSetupCommand;
 import com.cloud.agent.api.StartupCommand;
 import com.cloud.agent.api.StartupSecondaryStorageCommand;
+import com.cloud.agent.api.storage.CreateEntityDownloadURLCommand;
+import com.cloud.agent.api.storage.DeleteEntityDownloadURLCommand;
+import com.cloud.agent.api.storage.DownloadAnswer;
+import com.cloud.agent.api.storage.ListTemplateAnswer;
+import com.cloud.agent.api.storage.ListTemplateCommand;
+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.to.DataObjectType;
 import com.cloud.agent.api.to.DataStoreTO;
 import com.cloud.agent.api.to.DataTO;
@@ -101,16 +108,34 @@ import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.resource.ServerResourceBase;
 import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.Storage.ImageFormat;
+import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.storage.StorageLayer;
+import com.cloud.storage.VMTemplateStorageResourceAssoc;
+import com.cloud.storage.template.Processor;
 import com.cloud.storage.template.Processor.FormatInfo;
+import com.cloud.storage.template.QCOW2Processor;
+import com.cloud.storage.template.RawImageProcessor;
+import com.cloud.storage.template.TemplateLocation;
+import com.cloud.storage.template.TemplateProp;
+import com.cloud.storage.template.VhdProcessor;
+import com.cloud.storage.template.VmdkProcessor;
 import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.S3Utils;
 import com.cloud.utils.S3Utils.FileNamingStrategy;
+import com.cloud.utils.SwiftUtil;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.net.NetUtils;
 import com.cloud.utils.script.OutputInterpreter;
 import com.cloud.utils.script.Script;
 import com.cloud.vm.SecondaryStorageVm;
+import com.google.common.io.Files;
+
+import static com.cloud.utils.S3Utils.putFile;
+import static com.cloud.utils.StringUtils.join;
+import static com.cloud.utils.db.GlobalLock.executeWithNoWaitLock;
+import static java.lang.String.format;
+import static java.util.Arrays.asList;
+import static org.apache.commons.lang.StringUtils.substringAfterLast;
 
 public class NfsSecondaryStorageResource extends ServerResourceBase implements SecondaryStorageResource {
 
@@ -357,6 +382,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
             snapshotName = snapshotName + ".vhd";
         }
         snapshotPath = snapshotPath.substring(0, index);
+
         snapshotPath = srcMountPoint + File.separator + snapshotPath;
         String destMountPoint = this.getRootDir(destDataStore.getUrl());
         String destPath = destMountPoint + File.separator + destData.getPath();
@@ -424,7 +450,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
 
             // get snapshot file name
             String templateName = srcFile.getName();
-            // add kvm file extension for copied template name    
+            // add kvm file extension for copied template name
             String fileName = templateName + "." + srcFormat.getFileExtension();
             String destFileFullPath = destFile.getAbsolutePath() + File.separator + fileName;
             s_logger.debug("copy snapshot " + srcFile.getAbsolutePath() + " to template " + destFileFullPath);
@@ -509,15 +535,16 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
         DataTO destData = cmd.getDestTO();
         DataStoreTO srcDataStore = srcData.getDataStore();
         DataStoreTO destDataStore = destData.getDataStore();
-        if (srcDataStore.getRole() == DataStoreRole.Image || srcDataStore.getRole() == DataStoreRole.ImageCache) {
+        if (srcDataStore.getRole() == DataStoreRole.Image || srcDataStore.getRole() == DataStoreRole.ImageCache ||
+                srcDataStore.getRole() == DataStoreRole.Primary) {
             if (!(srcDataStore instanceof NfsTO)) {
                 s_logger.debug("only support nfs storage as src, when create template from snapshot");
                 return Answer.createUnsupportedCommandAnswer(cmd);
             }
 
             if (destDataStore instanceof NfsTO) {
-                return copySnapshotToTemplateFromNfsToNfs(cmd, (SnapshotObjectTO) srcData, (NfsTO) srcDataStore,
-                        (TemplateObjectTO) destData, (NfsTO) destDataStore);
+                return copySnapshotToTemplateFromNfsToNfs(cmd, (SnapshotObjectTO) srcData, (NfsTO)srcDataStore,
+                        (TemplateObjectTO) destData, (NfsTO)destDataStore);
             } else if (destDataStore instanceof SwiftTO) {
                 //create template on the same data store
                 CopyCmdAnswer answer = (CopyCmdAnswer)copySnapshotToTemplateFromNfsToNfs(cmd, (SnapshotObjectTO) srcData, (NfsTO) srcDataStore,
@@ -543,8 +570,8 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
                     execute(deleteCommand);
                 } catch (Exception e) {
                     s_logger.debug("Failed to clean up staging area:", e);
-                }  
-                
+                }
+
                 TemplateObjectTO template = new TemplateObjectTO();
                 template.setPath(swiftPath);
                 template.setSize(templateFile.length());
@@ -569,7 +596,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
                     execute(deleteCommand);
                 } catch (Exception e) {
                     s_logger.debug("Failed to clean up staging area:", e);
-                }  
+                }
                 return result;
             }
         }
@@ -792,7 +819,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
             processor.configure("template processor", new HashMap<String, Object>());
             return processor.getVirtualSize(file);
         } catch (Exception e) {
-           s_logger.debug("Failed to get virtual size:" ,e);
+            s_logger.debug("Failed to get virtual size:" ,e);
         }
         return file.length();
     }
@@ -2226,8 +2253,8 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
      * 
      * CIFS parameters are documented with mount.cifs at
      * http://linux.die.net/man/8/mount.cifs
-	 * For simplicity, when a URI is used to specify a CIFS share,
-	 * options such as domain,user,password are passed as query parameters.
+     * For simplicity, when a URI is used to specify a CIFS share,
+     * options such as domain,user,password are passed as query parameters.
      * 
      * @param uri
      *            crresponding to the remote device. Will throw for unsupported
@@ -2262,7 +2289,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
         return dir;
     }
 
-    
+
     protected void umount(String localRootPath, URI uri) {
         ensureLocalRootPathExists(localRootPath, uri);
 
@@ -2286,7 +2313,7 @@ public class NfsSecondaryStorageResource extends ServerResourceBase implements S
         }
         s_logger.debug("Successfully umounted " + localRootPath);
     }
-    
+
     protected void mount(String localRootPath, String remoteDevice, URI uri) {
         s_logger.debug("mount " + uri.toString() + " on " + localRootPath);
         ensureLocalRootPathExists(localRootPath, uri);


[2/2] git commit: updated refs/heads/master to 180cfa1

Posted by ed...@apache.org.
Refactor Storage Related Resource Code
These changes are a joint effort between Edison and I to refactor some
of the code around snapshotting VM volumes and creating
templates/volumes from VM volume snapshots. In general, we were working
towards allowing PrimaryDataStoreDrivers to create snapshots on primary
storage and not requiring the snapshots to be transferred to secondary
storage.

High level changes:
-Added uuid to NfsTO, SwiftTO & S3TO to cut down on the requirement of
PrimaryDataStoreTO and ImageStoreTO which don't really serve much of a
purpose
-Initial work towards enable reverting VM volume from snapshots
-Added hypervisor commands for introducing and forgetting new hypervisor
objects (snapshots, templates & volumes)

Signed-off-by: Edison Su <su...@gmail.com>


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

Branch: refs/heads/master
Commit: 180cfa19e87b909cb1c8a738359e31a6111b11c5
Parents: c9f41d4
Author: Chris Suich <ch...@netapp.com>
Authored: Fri Oct 4 10:45:47 2013 -0700
Committer: Edison Su <su...@gmail.com>
Committed: Fri Oct 4 13:06:42 2013 -0700

----------------------------------------------------------------------
 api/src/com/cloud/agent/api/to/DataStoreTO.java |   2 +-
 api/src/com/cloud/agent/api/to/NfsTO.java       |   9 +-
 api/src/com/cloud/agent/api/to/SwiftTO.java     |  11 +-
 api/src/com/cloud/event/EventTypes.java         |   5 +-
 .../storage/snapshot/SnapshotApiService.java    |   2 +
 .../admin/storage/ListStoragePoolsCmd.java      |   3 +-
 .../storage/resource/StorageProcessor.java      |   6 +
 .../StorageSubsystemCommandHandlerBase.java     |  22 +-
 .../cloudstack/storage/to/ImageStoreTO.java     |  10 +
 .../storage/to/PrimaryDataStoreTO.java          |   1 +
 .../subsystem/api/storage/EndPointSelector.java |   2 +
 .../subsystem/api/storage/SnapshotService.java  |   2 +-
 .../subsystem/api/storage/SnapshotStrategy.java |   4 +-
 .../motion/AncientDataMotionStrategy.java       |  29 ++-
 .../storage/image/store/ImageStoreImpl.java     |  14 +-
 .../storage/test/SnapshotTestWithFakeData.java  |  96 ++++---
 .../storage/snapshot/SnapshotServiceImpl.java   |  42 +--
 .../storage/snapshot/SnapshotStrategyBase.java  |   7 +-
 .../snapshot/XenserverSnapshotStrategy.java     |  20 +-
 .../endpoint/DefaultEndPointSelector.java       |  10 +-
 .../kvm/storage/KVMStorageProcessor.java        |  43 ++--
 .../resource/SimulatorStorageProcessor.java     |  35 ++-
 .../resource/VmwareStorageProcessor.java        | 257 ++++++++++---------
 .../xen/resource/XenServerStorageProcessor.java | 103 +++++---
 .../storage/snapshot/SnapshotManagerImpl.java   | 209 ++++++++-------
 .../resource/NfsSecondaryStorageResource.java   |  75 ++++--
 26 files changed, 604 insertions(+), 415 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/api/src/com/cloud/agent/api/to/DataStoreTO.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/to/DataStoreTO.java b/api/src/com/cloud/agent/api/to/DataStoreTO.java
index 9014f8e..b79ba7d 100644
--- a/api/src/com/cloud/agent/api/to/DataStoreTO.java
+++ b/api/src/com/cloud/agent/api/to/DataStoreTO.java
@@ -20,7 +20,7 @@ package com.cloud.agent.api.to;
 
 import com.cloud.storage.DataStoreRole;
 
-
 public interface DataStoreTO {
     public DataStoreRole getRole();
+    public String getUuid();
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/api/src/com/cloud/agent/api/to/NfsTO.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/to/NfsTO.java b/api/src/com/cloud/agent/api/to/NfsTO.java
index 415c95c..54683c7 100644
--- a/api/src/com/cloud/agent/api/to/NfsTO.java
+++ b/api/src/com/cloud/agent/api/to/NfsTO.java
@@ -22,6 +22,7 @@ public class NfsTO implements DataStoreTO {
 
     private String _url;
     private DataStoreRole _role;
+    private String uuid;
 
     public NfsTO() {
 
@@ -55,6 +56,12 @@ public class NfsTO implements DataStoreTO {
         this._role = _role;
     }
 
+    @Override
+    public String getUuid() {
+        return uuid;
+    }
 
-
+    public void setUuid(String uuid) {
+        this.uuid = uuid;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/api/src/com/cloud/agent/api/to/SwiftTO.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/agent/api/to/SwiftTO.java b/api/src/com/cloud/agent/api/to/SwiftTO.java
index 7349d77..3ad131a 100644
--- a/api/src/com/cloud/agent/api/to/SwiftTO.java
+++ b/api/src/com/cloud/agent/api/to/SwiftTO.java
@@ -29,8 +29,7 @@ public class SwiftTO implements DataStoreTO, SwiftUtil.SwiftClientCfg {
 
     public SwiftTO() { }
 
-    public SwiftTO(Long id, String url, String account, String userName, String key
-                  ) {
+    public SwiftTO(Long id, String url, String account, String userName, String key) {
         this.id = id;
         this.url = url;
         this.account = account;
@@ -46,14 +45,17 @@ public class SwiftTO implements DataStoreTO, SwiftUtil.SwiftClientCfg {
         return url;
     }
 
+    @Override
     public String getAccount() {
         return account;
     }
 
+    @Override
     public String getUserName() {
         return userName;
     }
 
+    @Override
     public String getKey() {
         return key;
     }
@@ -67,4 +69,9 @@ public class SwiftTO implements DataStoreTO, SwiftUtil.SwiftClientCfg {
     public String getEndPoint() {
         return this.url;
     }
+
+    @Override
+    public String getUuid() {
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/api/src/com/cloud/event/EventTypes.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java
index ec9604e..a762606 100755
--- a/api/src/com/cloud/event/EventTypes.java
+++ b/api/src/com/cloud/event/EventTypes.java
@@ -199,6 +199,7 @@ public class EventTypes {
     // Snapshots
     public static final String EVENT_SNAPSHOT_CREATE = "SNAPSHOT.CREATE";
     public static final String EVENT_SNAPSHOT_DELETE = "SNAPSHOT.DELETE";
+    public static final String EVENT_SNAPSHOT_REVERT = "SNAPSHOT.REVERT";
     public static final String EVENT_SNAPSHOT_POLICY_CREATE = "SNAPSHOTPOLICY.CREATE";
     public static final String EVENT_SNAPSHOT_POLICY_UPDATE = "SNAPSHOTPOLICY.UPDATE";
     public static final String EVENT_SNAPSHOT_POLICY_DELETE = "SNAPSHOTPOLICY.DELETE";
@@ -387,7 +388,7 @@ public class EventTypes {
     public static final String EVENT_RESOURCE_DETAILS_CREATE = "CREATE_RESOURCE_DETAILS";
     public static final String EVENT_RESOURCE_DETAILS_DELETE = "DELETE_RESOURCE_DETAILS";
 
-	// vm snapshot events
+    // vm snapshot events
     public static final String EVENT_VM_SNAPSHOT_CREATE = "VMSNAPSHOT.CREATE";
     public static final String EVENT_VM_SNAPSHOT_DELETE = "VMSNAPSHOT.DELETE";
     public static final String EVENT_VM_SNAPSHOT_REVERT = "VMSNAPSHOT.REVERTTO";
@@ -444,7 +445,7 @@ public class EventTypes {
     public static final String EVENT_DEDICATE_RESOURCE_RELEASE = "DEDICATE.RESOURCE.RELEASE";
 
     public static final String EVENT_CLEANUP_VM_RESERVATION = "VM.RESERVATION.CLEANUP";
-    
+
     public static final String EVENT_UCS_ASSOCIATED_PROFILE = "UCS.ASSOCIATEPROFILE";
 
     static {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/api/src/com/cloud/storage/snapshot/SnapshotApiService.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/storage/snapshot/SnapshotApiService.java b/api/src/com/cloud/storage/snapshot/SnapshotApiService.java
index 23e6522..4f13510 100644
--- a/api/src/com/cloud/storage/snapshot/SnapshotApiService.java
+++ b/api/src/com/cloud/storage/snapshot/SnapshotApiService.java
@@ -106,4 +106,6 @@ public interface SnapshotApiService {
      * @return
      */
     Long getHostIdForSnapshotOperation(Volume vol);
+
+    boolean revertSnapshot(Long snapshotId);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/api/src/org/apache/cloudstack/api/command/admin/storage/ListStoragePoolsCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/storage/ListStoragePoolsCmd.java b/api/src/org/apache/cloudstack/api/command/admin/storage/ListStoragePoolsCmd.java
index 26351bb..ddf0391 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/storage/ListStoragePoolsCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/storage/ListStoragePoolsCmd.java
@@ -59,7 +59,7 @@ public class ListStoragePoolsCmd extends BaseListCmd {
     @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType = ZoneResponse.class,
             description="the Zone ID for the storage pool")
     private Long zoneId;
-    
+
     @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = StoragePoolResponse.class,
             description="the ID of the storage pool")
     private Long id;
@@ -109,6 +109,7 @@ public class ListStoragePoolsCmd extends BaseListCmd {
         return s_name;
     }
 
+    @Override
     public ApiCommandJobType getInstanceType() {
         return ApiCommandJobType.StoragePool;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/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
index 5fa9f8a..29f4a67 100644
--- a/core/src/com/cloud/storage/resource/StorageProcessor.java
+++ b/core/src/com/cloud/storage/resource/StorageProcessor.java
@@ -23,8 +23,12 @@ 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 org.apache.cloudstack.storage.command.ForgetObjectCmd;
+import org.apache.cloudstack.storage.command.IntroduceObjectCmd;
 
 import com.cloud.agent.api.Answer;
+import org.apache.cloudstack.storage.command.ForgetObjectCmd;
+import org.apache.cloudstack.storage.command.IntroduceObjectCmd;
 
 public interface StorageProcessor {
     public Answer copyTemplateToPrimaryStorage(CopyCommand cmd);
@@ -43,4 +47,6 @@ public interface StorageProcessor {
     public Answer deleteVolume(DeleteCommand cmd);
     public Answer createVolumeFromSnapshot(CopyCommand cmd);
     public Answer deleteSnapshot(DeleteCommand cmd);
+    Answer introduceObject(IntroduceObjectCmd cmd);
+    Answer forgetObject(ForgetObjectCmd cmd);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/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
index ab9aa2a..002143f 100644
--- a/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java
+++ b/core/src/com/cloud/storage/resource/StorageSubsystemCommandHandlerBase.java
@@ -24,6 +24,7 @@ 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.IntroduceObjectCmd;
 import org.apache.cloudstack.storage.command.StorageSubSystemCommand;
 import org.apache.log4j.Logger;
 
@@ -55,6 +56,8 @@ public class StorageSubsystemCommandHandlerBase implements StorageSubsystemComma
             return execute((AttachCommand)command);
         } else if (command instanceof DettachCommand) {
             return execute((DettachCommand)command);
+        } else if (command instanceof IntroduceObjectCmd) {
+            return processor.introduceObject((IntroduceObjectCmd)command);
         }
         return new Answer((Command)command, false, "not implemented yet");
     }
@@ -65,7 +68,7 @@ public class StorageSubsystemCommandHandlerBase implements StorageSubsystemComma
         DataStoreTO srcDataStore = srcData.getDataStore();
         DataStoreTO destDataStore = destData.getDataStore();
 
-        if ((srcData.getObjectType() == DataObjectType.TEMPLATE) && (srcDataStore instanceof NfsTO)  && (destData.getDataStore().getRole() == DataStoreRole.Primary)) {
+        if ((srcData.getObjectType() == DataObjectType.TEMPLATE) && (destData.getObjectType() == DataObjectType.TEMPLATE && 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) {
@@ -80,18 +83,19 @@ public class StorageSubsystemCommandHandlerBase implements StorageSubsystemComma
             } else if (destData.getObjectType() == DataObjectType.TEMPLATE) {
                 return processor.createTemplateFromVolume(cmd);
             }
-        } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT && srcData.getDataStore().getRole() == DataStoreRole.Primary) {
+        } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT && destData.getObjectType() == DataObjectType.SNAPSHOT &&
+                destData.getDataStore().getRole() == DataStoreRole.Primary) {
             return processor.backupSnapshot(cmd);
         } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT && destData.getObjectType() == DataObjectType.VOLUME) {
-        	return processor.createVolumeFromSnapshot(cmd);
+            return processor.createVolumeFromSnapshot(cmd);
         } else if (srcData.getObjectType() == DataObjectType.SNAPSHOT && destData.getObjectType() == DataObjectType.TEMPLATE) {
             return processor.createTemplateFromSnapshot(cmd);
         }
 
         return new Answer(cmd, false, "not implemented yet");
     }
-    
-    
+
+
     protected Answer execute(CreateObjectCommand cmd) {
         DataTO data = cmd.getData();
         try {
@@ -106,21 +110,21 @@ public class StorageSubsystemCommandHandlerBase implements StorageSubsystemComma
             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 if (data.getObjectType() == DataObjectType.SNAPSHOT) {
-        	answer = processor.deleteSnapshot(cmd);
+            answer = processor.deleteSnapshot(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) {
@@ -129,7 +133,7 @@ public class StorageSubsystemCommandHandlerBase implements StorageSubsystemComma
             return processor.attachVolume(cmd);
         }
     }
-    
+
     protected Answer execute(DettachCommand cmd) {
         DiskTO disk = cmd.getDisk();
         if (disk.getType() == Volume.Type.ISO) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/core/src/org/apache/cloudstack/storage/to/ImageStoreTO.java
----------------------------------------------------------------------
diff --git a/core/src/org/apache/cloudstack/storage/to/ImageStoreTO.java b/core/src/org/apache/cloudstack/storage/to/ImageStoreTO.java
index 0037ea5..ec6c240 100644
--- a/core/src/org/apache/cloudstack/storage/to/ImageStoreTO.java
+++ b/core/src/org/apache/cloudstack/storage/to/ImageStoreTO.java
@@ -26,6 +26,7 @@ public class ImageStoreTO implements DataStoreTO {
     private String uri;
     private String providerName;
     private DataStoreRole role;
+    private String uuid;
 
     public ImageStoreTO() {
 
@@ -76,4 +77,13 @@ public class ImageStoreTO implements DataStoreTO {
         return new StringBuilder("ImageStoreTO[type=").append(type).append("|provider=").append(providerName)
                 .append("|role=").append(role).append("|uri=").append(uri).append("]").toString();
     }
+
+    @Override
+    public String getUuid() {
+        return uuid;
+    }
+
+    public void setUuid(String uuid) {
+        this.uuid = uuid;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java
----------------------------------------------------------------------
diff --git a/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java b/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java
index 5e870df..91d78a4 100644
--- a/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java
+++ b/core/src/org/apache/cloudstack/storage/to/PrimaryDataStoreTO.java
@@ -46,6 +46,7 @@ public class PrimaryDataStoreTO implements DataStoreTO {
         return this.id;
     }
 
+    @Override
     public String getUuid() {
         return this.uuid;
     }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java
index ca0cc2c..b812f6e 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/EndPointSelector.java
@@ -28,4 +28,6 @@ public interface EndPointSelector {
     EndPoint select(DataStore store);
 
     List<EndPoint> selectAll(DataStore store);
+
+    EndPoint select(Scope scope, Long storeId);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java
index d594a07..e953eb6 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotService.java
@@ -24,5 +24,5 @@ public interface SnapshotService {
 
     boolean deleteSnapshot(SnapshotInfo snapshot);
 
-    boolean revertSnapshot(SnapshotInfo snapshot);
+    boolean revertSnapshot(Long snapshotId);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java
index 86ae532..47e595b 100644
--- a/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java
+++ b/engine/api/src/org/apache/cloudstack/engine/subsystem/api/storage/SnapshotStrategy.java
@@ -11,7 +11,7 @@
 // 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 
+// 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;
@@ -25,5 +25,7 @@ public interface SnapshotStrategy {
 
     boolean deleteSnapshot(Long snapshotId);
 
+    boolean revertSnapshot(Long snapshotId);
+
     boolean canHandle(Snapshot snapshot);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/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 96d1f5a..fb6962a 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
@@ -47,7 +47,7 @@ import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.TemplateDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.VolumeDataStoreDao;
 import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
-
+import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
@@ -62,9 +62,9 @@ import com.cloud.agent.api.to.VirtualMachineTO;
 import com.cloud.configuration.Config;
 import com.cloud.host.Host;
 import com.cloud.host.dao.HostDao;
-import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.server.ManagementService;
 import com.cloud.storage.DataStoreRole;
+import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.storage.StorageManager;
 import com.cloud.storage.StoragePool;
 import com.cloud.storage.VolumeVO;
@@ -81,7 +81,7 @@ import com.cloud.utils.exception.CloudRuntimeException;
 
 @Component
 public class
-        AncientDataMotionStrategy implements DataMotionStrategy {
+AncientDataMotionStrategy implements DataMotionStrategy {
     private static final Logger s_logger = Logger.getLogger(AncientDataMotionStrategy.class);
     @Inject
     EndPointSelector selector;
@@ -138,7 +138,8 @@ public class
         DataTO destTO = destData.getTO();
         DataStoreTO srcStoreTO = srcTO.getDataStore();
         DataStoreTO destStoreTO = destTO.getDataStore();
-        if (srcStoreTO instanceof NfsTO || srcStoreTO.getRole() == DataStoreRole.ImageCache) {
+        if (srcStoreTO instanceof NfsTO || srcStoreTO.getRole() == DataStoreRole.ImageCache ||
+                (srcStoreTO instanceof PrimaryDataStoreTO && ((PrimaryDataStoreTO)srcStoreTO).getPoolType() == StoragePoolType.NetworkFilesystem)) {
             return false;
         }
 
@@ -264,8 +265,14 @@ public class
             int _createVolumeFromSnapshotWait = NumbersUtil.parseInt(value,
                     Integer.parseInt(Config.CreateVolumeFromSnapshotWait.getDefaultValue()));
 
+            EndPoint ep = null;
+            if (srcData.getDataStore().getRole() == DataStoreRole.Primary) {
+                ep = selector.select(volObj);
+            } else {
+                ep = selector.select(snapObj, volObj);
+            }
+
             CopyCommand cmd = new CopyCommand(srcData.getTO(), volObj.getTO(), _createVolumeFromSnapshotWait, _mgmtServer.getExecuteInSequence());
-            EndPoint ep = selector.select(snapObj, volObj);
             Answer answer = ep.sendMessage(cmd);
 
             return answer;
@@ -433,11 +440,17 @@ public class
             srcData = cacheSnapshotChain(snapshot);
         }
 
+        EndPoint ep = null;
+        if (srcData.getDataStore().getRole() == DataStoreRole.Primary) {
+            ep = selector.select(destData);
+        } else {
+            ep = selector.select(srcData, destData);
+        }
+
         CopyCommand cmd = new CopyCommand(srcData.getTO(), destData.getTO(), _createprivatetemplatefromsnapshotwait, _mgmtServer.getExecuteInSequence());
-        EndPoint ep = selector.select(srcData, destData);
         Answer answer = ep.sendMessage(cmd);
-        
-        // clean up snapshot copied to staging 
+
+        // clean up snapshot copied to staging
         if (needCache && srcData != null) {
             cacheMgr.deleteCacheObject(srcData);
         }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java
index 855d8cb..d77658b 100644
--- a/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java
+++ b/engine/storage/image/src/org/apache/cloudstack/storage/image/store/ImageStoreImpl.java
@@ -24,7 +24,6 @@ import java.util.concurrent.ExecutionException;
 
 import javax.inject.Inject;
 
-import com.cloud.capacity.dao.CapacityDao;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataObject;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreDriver;
 import org.apache.cloudstack.engine.subsystem.api.storage.ImageStoreProvider;
@@ -39,9 +38,11 @@ import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
 import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
 import org.apache.cloudstack.storage.image.ImageStoreDriver;
 import org.apache.cloudstack.storage.image.datastore.ImageStoreEntity;
+import org.apache.cloudstack.storage.to.ImageStoreTO;
 import org.apache.log4j.Logger;
 
 import com.cloud.agent.api.to.DataStoreTO;
+import com.cloud.capacity.dao.CapacityDao;
 import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.Storage.ImageFormat;
 import com.cloud.storage.dao.VMTemplateDao;
@@ -181,7 +182,16 @@ public class ImageStoreImpl implements ImageStoreEntity {
 
     @Override
     public DataStoreTO getTO() {
-        return getDriver().getStoreTO(this);
+        DataStoreTO to = getDriver().getStoreTO(this);
+        if (to == null) {
+            ImageStoreTO primaryTO = new ImageStoreTO();
+            primaryTO.setProviderName(getProviderName());
+            primaryTO.setRole(getRole());
+            primaryTO.setType(getProtocol());
+            primaryTO.setUri(getUri());
+            return primaryTO;
+        }
+        return to;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTestWithFakeData.java
----------------------------------------------------------------------
diff --git a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTestWithFakeData.java b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTestWithFakeData.java
index 2aaabda..c73d167 100644
--- a/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTestWithFakeData.java
+++ b/engine/storage/integration-test/test/org/apache/cloudstack/storage/test/SnapshotTestWithFakeData.java
@@ -18,7 +18,50 @@
  */
 package org.apache.cloudstack.storage.test;
 
-import com.cloud.cluster.LockMasterListener;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+import javax.inject.Inject;
+
+import junit.framework.Assert;
+
+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.DataStoreProvider;
+import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
+import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreProvider;
+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.SnapshotResult;
+import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService;
+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.storage.datastore.db.ImageStoreDao;
+import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
+import org.apache.cloudstack.storage.volume.VolumeObject;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+
 import com.cloud.dc.ClusterVO;
 import com.cloud.dc.DataCenter;
 import com.cloud.dc.DataCenterVO;
@@ -29,6 +72,7 @@ import com.cloud.dc.dao.HostPodDao;
 import com.cloud.hypervisor.Hypervisor;
 import com.cloud.org.Cluster;
 import com.cloud.org.Managed;
+import com.cloud.server.LockMasterListener;
 import com.cloud.storage.CreateSnapshotPayload;
 import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.ScopeType;
@@ -47,53 +91,7 @@ import com.cloud.user.AccountManager;
 import com.cloud.user.User;
 import com.cloud.utils.DateUtil;
 import com.cloud.utils.component.ComponentContext;
-import com.cloud.utils.db.DB;
 import com.cloud.utils.db.Merovingian2;
-import junit.framework.Assert;
-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.DataStoreProvider;
-import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine;
-import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
-import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreProvider;
-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.SnapshotResult;
-import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService;
-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.storage.datastore.PrimaryDataStore;
-import org.apache.cloudstack.storage.datastore.db.ImageStoreDao;
-import org.apache.cloudstack.storage.datastore.db.ImageStoreVO;
-import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
-import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
-import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
-import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
-import org.apache.cloudstack.storage.volume.VolumeObject;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mockito;
-import org.springframework.test.context.ContextConfiguration;
-import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
-
-import javax.inject.Inject;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.UUID;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Executor;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
 
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -317,7 +315,7 @@ public class SnapshotTestWithFakeData  {
         final VolumeInfo volumeInfo = createVolume(1L, store);
         Assert.assertTrue(volumeInfo.getState() == Volume.State.Ready);
         vol = volumeInfo;
-       // final SnapshotPolicyVO policyVO = createSnapshotPolicy(vol.getId());
+        // final SnapshotPolicyVO policyVO = createSnapshotPolicy(vol.getId());
 
 
         ExecutorService pool = Executors.newFixedThreadPool(2);
@@ -325,7 +323,7 @@ public class SnapshotTestWithFakeData  {
         List<Future<Boolean>> future = new ArrayList<Future<Boolean>>();
         for(int i = 0; i < 12; i++) {
             final int cnt = i;
-           Future<Boolean> task =  pool.submit(new Callable<Boolean>() {
+            Future<Boolean> task =  pool.submit(new Callable<Boolean>() {
                 @Override
                 public Boolean call() throws Exception {
                     boolean r = true;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
index 3ead93f..c09adca 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotServiceImpl.java
@@ -17,20 +17,24 @@
 
 package org.apache.cloudstack.storage.snapshot;
 
-import com.cloud.dc.dao.ClusterDao;
-import com.cloud.storage.DataStoreRole;
-import com.cloud.storage.Snapshot;
-import com.cloud.storage.dao.SnapshotDao;
-import com.cloud.storage.dao.VolumeDao;
-import com.cloud.storage.snapshot.SnapshotManager;
-import com.cloud.utils.exception.CloudRuntimeException;
-import com.cloud.utils.fsm.NoTransitionException;
-import com.cloud.vm.dao.UserVmDao;
-import com.cloud.vm.snapshot.dao.VMSnapshotDao;
+import java.util.concurrent.ExecutionException;
+
+import javax.inject.Inject;
 
 import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
-import org.apache.cloudstack.engine.subsystem.api.storage.*;
+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.DataMotionService;
+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;
 import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.Event;
+import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
+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.SnapshotResult;
+import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.framework.async.AsyncCallFuture;
 import org.apache.cloudstack.framework.async.AsyncCallbackDispatcher;
 import org.apache.cloudstack.framework.async.AsyncCompletionCallback;
@@ -41,13 +45,19 @@ import org.apache.cloudstack.storage.datastore.ObjectInDataStoreManager;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
-
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
-import javax.inject.Inject;
-
-import java.util.concurrent.ExecutionException;
+import com.cloud.dc.dao.ClusterDao;
+import com.cloud.storage.DataStoreRole;
+import com.cloud.storage.Snapshot;
+import com.cloud.storage.dao.SnapshotDao;
+import com.cloud.storage.dao.VolumeDao;
+import com.cloud.storage.snapshot.SnapshotManager;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.fsm.NoTransitionException;
+import com.cloud.vm.dao.UserVmDao;
+import com.cloud.vm.snapshot.dao.VMSnapshotDao;
 
 @Component
 public class SnapshotServiceImpl implements SnapshotService {
@@ -383,7 +393,7 @@ public class SnapshotServiceImpl implements SnapshotService {
     }
 
     @Override
-    public boolean revertSnapshot(SnapshotInfo snapshot) {
+    public boolean revertSnapshot(Long snapshotId) {
         return false;
     }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java
index 1b57922..6db8343 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/SnapshotStrategyBase.java
@@ -11,7 +11,7 @@
 // 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 
+// KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
 package org.apache.cloudstack.storage.snapshot;
@@ -35,4 +35,9 @@ public abstract class SnapshotStrategyBase implements SnapshotStrategy {
     public SnapshotInfo backupSnapshot(SnapshotInfo snapshot) {
         return snapshotSvr.backupSnapshot(snapshot);
     }
+
+    @Override
+    public boolean revertSnapshot(Long snapshotId) {
+        return snapshotSvr.revertSnapshot(snapshotId);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
----------------------------------------------------------------------
diff --git a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
index 60d9407..aae4cde 100644
--- a/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
+++ b/engine/storage/snapshot/src/org/apache/cloudstack/storage/snapshot/XenserverSnapshotStrategy.java
@@ -11,24 +11,27 @@
 // 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 
+// KIND, either express or implied.  See the License for the
 // specific language governing permissions and limitations
 // under the License.
 package org.apache.cloudstack.storage.snapshot;
 
 import javax.inject.Inject;
 
-import com.cloud.storage.Volume;
-import com.cloud.utils.db.DB;
-import org.apache.cloudstack.engine.subsystem.api.storage.*;
+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.Event;
 import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine.State;
+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.SnapshotResult;
+import org.apache.cloudstack.engine.subsystem.api.storage.SnapshotService;
+import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
 import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
 import org.apache.cloudstack.storage.command.CreateObjectAnswer;
 import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
 import org.apache.cloudstack.storage.to.SnapshotObjectTO;
-
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
@@ -36,9 +39,11 @@ import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.Snapshot;
 import com.cloud.storage.SnapshotVO;
+import com.cloud.storage.Volume;
 import com.cloud.storage.dao.SnapshotDao;
 import com.cloud.storage.snapshot.SnapshotManager;
 import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.db.DB;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.fsm.NoTransitionException;
 
@@ -237,6 +242,11 @@ public class XenserverSnapshotStrategy extends SnapshotStrategyBase {
     }
 
     @Override
+    public boolean revertSnapshot(Long snapshotId) {
+        throw new CloudRuntimeException("revert Snapshot is not supported");
+    }
+
+    @Override
     @DB
     public SnapshotInfo takeSnapshot(SnapshotInfo snapshot) {
         SnapshotVO snapshotVO = snapshotDao.acquireInLockTable(snapshot.getId());

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java
----------------------------------------------------------------------
diff --git a/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java b/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java
index fdc12bf..e7c6627 100644
--- a/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java
+++ b/engine/storage/src/org/apache/cloudstack/storage/endpoint/DefaultEndPointSelector.java
@@ -27,9 +27,6 @@ import java.util.List;
 
 import javax.inject.Inject;
 
-import org.apache.log4j.Logger;
-import org.springframework.stereotype.Component;
-
 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.EndPoint;
@@ -37,6 +34,8 @@ import org.apache.cloudstack.engine.subsystem.api.storage.EndPointSelector;
 import org.apache.cloudstack.engine.subsystem.api.storage.Scope;
 import org.apache.cloudstack.storage.LocalHostEndpoint;
 import org.apache.cloudstack.storage.RemoteHostEndPoint;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
 
 import com.cloud.host.Host;
 import com.cloud.host.HostVO;
@@ -251,6 +250,11 @@ public class DefaultEndPointSelector implements EndPointSelector {
     }
 
     @Override
+    public EndPoint select(Scope scope, Long storeId) {
+        return findEndPointInScope(scope, findOneHostOnPrimaryStorage, storeId);
+    }
+
+    @Override
     public List<EndPoint> selectAll(DataStore store) {
         List<EndPoint> endPoints = new ArrayList<EndPoint>();
         if (store.getScope().getScopeType() == ScopeType.HOST) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/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
index 82fd2ce..b1c8ec7 100644
--- a/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
+++ b/plugins/hypervisors/kvm/src/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java
@@ -18,10 +18,10 @@
  */
 package com.cloud.hypervisor.kvm.storage;
 
+import java.io.BufferedOutputStream;
 import java.io.File;
-import java.io.FileOutputStream;
 import java.io.FileNotFoundException;
-import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
 import java.io.IOException;
 import java.net.URISyntaxException;
 import java.text.DateFormat;
@@ -35,11 +35,6 @@ import java.util.UUID;
 
 import javax.naming.ConfigurationException;
 
-import com.cloud.agent.api.storage.CopyVolumeAnswer;
-import com.cloud.agent.api.to.DataObjectType;
-import com.cloud.agent.api.to.S3TO;
-import com.cloud.agent.api.to.StorageFilerTO;
-import com.cloud.utils.S3Utils;
 import org.apache.cloudstack.storage.command.AttachAnswer;
 import org.apache.cloudstack.storage.command.AttachCommand;
 import org.apache.cloudstack.storage.command.CopyCmdAnswer;
@@ -49,6 +44,8 @@ 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.command.ForgetObjectCmd;
+import org.apache.cloudstack.storage.command.IntroduceObjectCmd;
 import org.apache.cloudstack.storage.to.PrimaryDataStoreTO;
 import org.apache.cloudstack.storage.to.SnapshotObjectTO;
 import org.apache.cloudstack.storage.to.TemplateObjectTO;
@@ -57,20 +54,28 @@ import org.apache.cloudstack.utils.qemu.QemuImg;
 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.apache.commons.io.FileUtils;
+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.ceph.rados.IoCTX;
+import com.ceph.rados.Rados;
+import com.ceph.rados.RadosException;
+import com.ceph.rbd.Rbd;
+import com.ceph.rbd.RbdException;
+import com.ceph.rbd.RbdImage;
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer;
+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.exception.InternalErrorException;
 import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
 import com.cloud.hypervisor.kvm.resource.LibvirtConnection;
@@ -87,16 +92,10 @@ import com.cloud.storage.template.Processor.FormatInfo;
 import com.cloud.storage.template.QCOW2Processor;
 import com.cloud.storage.template.TemplateLocation;
 import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.S3Utils;
 import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.script.Script;
 
-import com.ceph.rados.Rados;
-import com.ceph.rados.RadosException;
-import com.ceph.rados.IoCTX;
-import com.ceph.rbd.Rbd;
-import com.ceph.rbd.RbdImage;
-import com.ceph.rbd.RbdException;
-
 import static com.cloud.utils.S3Utils.putFile;
 
 public class KVMStorageProcessor implements StorageProcessor {
@@ -197,7 +196,7 @@ public class KVMStorageProcessor implements StorageProcessor {
                     primaryPool, cmd.getWaitInMillSeconds());
 
 
-             DataTO data = null;
+            DataTO data = null;
             /**
              * Force the ImageFormat for RBD templates to RAW
              *
@@ -370,7 +369,7 @@ public class KVMStorageProcessor implements StorageProcessor {
             String srcVolumeName = srcVolumePath.substring(index + 1);
             secondaryStoragePool = storagePoolMgr.getStoragePoolByURI(
                     secondaryStorageUrl + File.separator + volumeDir
-                           );
+                    );
             if (!srcVolumeName.endsWith(".qcow2") && srcFormat == ImageFormat.QCOW2) {
                 srcVolumeName = srcVolumeName + ".qcow2";
             }
@@ -1207,4 +1206,14 @@ public class KVMStorageProcessor implements StorageProcessor {
     public Answer deleteSnapshot(DeleteCommand cmd) {
         return new Answer(cmd);
     }
+
+    @Override
+    public Answer introduceObject(IntroduceObjectCmd cmd) {
+        return new Answer(cmd, false, "not implememented yet");
+    }
+
+    @Override
+    public Answer forgetObject(ForgetObjectCmd cmd) {
+        return new Answer(cmd, false, "not implememented yet");
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java
index c7768aa..1c99272 100644
--- a/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java
+++ b/plugins/hypervisors/simulator/src/com/cloud/resource/SimulatorStorageProcessor.java
@@ -19,14 +19,9 @@
 
 package com.cloud.resource;
 
-import com.cloud.agent.api.Answer;
-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.manager.SimulatorManager;
-import com.cloud.storage.Storage;
-import com.cloud.storage.resource.StorageProcessor;
+import java.io.File;
+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;
@@ -36,13 +31,21 @@ 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.command.ForgetObjectCmd;
+import org.apache.cloudstack.storage.command.IntroduceObjectCmd;
 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 java.io.File;
-import java.util.UUID;
+import com.cloud.agent.api.Answer;
+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.manager.SimulatorManager;
+import com.cloud.storage.Storage;
+import com.cloud.storage.resource.StorageProcessor;
 
 public class SimulatorStorageProcessor implements StorageProcessor {
 
@@ -214,4 +217,16 @@ public class SimulatorStorageProcessor implements StorageProcessor {
     public Answer deleteSnapshot(DeleteCommand cmd) {
         return new Answer(cmd);
     }
+
+    @Override
+    public Answer introduceObject(IntroduceObjectCmd cmd) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public Answer forgetObject(ForgetObjectCmd cmd) {
+        // TODO Auto-generated method stub
+        return null;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
index 4982d87..a14c403 100644
--- a/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
+++ b/plugins/hypervisors/vmware/src/com/cloud/storage/resource/VmwareStorageProcessor.java
@@ -26,22 +26,6 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.UUID;
-
-import org.apache.commons.lang.StringUtils;
-import org.apache.log4j.Logger;
-
-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;
-
 import org.apache.cloudstack.storage.command.AttachAnswer;
 import org.apache.cloudstack.storage.command.AttachCommand;
 import org.apache.cloudstack.storage.command.CopyCmdAnswer;
@@ -50,10 +34,14 @@ 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.ForgetObjectCmd;
+import org.apache.cloudstack.storage.command.IntroduceObjectCmd;
 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.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
@@ -88,10 +76,13 @@ import com.cloud.utils.Pair;
 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.VirtualDisk;
 
 public class VmwareStorageProcessor implements StorageProcessor {
     private static final Logger s_logger = Logger.getLogger(VmwareStorageProcessor.class);
-    
+
     private VmwareHostService hostService;
     private boolean _fullCloneFlag;
     private VmwareStorageMount mountService;
@@ -128,9 +119,9 @@ public class VmwareStorageProcessor implements StorageProcessor {
         }
         return null;
     }
-    
+
     private void copyTemplateFromSecondaryToPrimary(VmwareHypervisorHost hyperHost, DatastoreMO datastoreMo, String secondaryStorageUrl,
-        String templatePathAtSecondaryStorage, String templateName, String templateUuid) throws Exception {
+            String templatePathAtSecondaryStorage, String templateName, String templateUuid) throws Exception {
 
         s_logger.info("Executing copyTemplateFromSecondaryToPrimary. secondaryStorage: "
                 + secondaryStorageUrl + ", templatePathAtSecondaryStorage: " + templatePathAtSecondaryStorage
@@ -140,9 +131,9 @@ public class VmwareStorageProcessor implements StorageProcessor {
         s_logger.info("Secondary storage mount point: " + secondaryMountPoint);
 
         String srcOVAFileName = VmwareStorageLayoutHelper.getTemplateOnSecStorageFilePath(
-        	secondaryMountPoint, templatePathAtSecondaryStorage,
-        	templateName, ImageFormat.OVA.getFileExtension());
-        		
+                secondaryMountPoint, templatePathAtSecondaryStorage,
+                templateName, ImageFormat.OVA.getFileExtension());
+
         String srcFileName = getOVFFilePath(srcOVAFileName);
         if(srcFileName == null) {
             Script command = new Script("tar", 0, s_logger);
@@ -178,8 +169,8 @@ public class VmwareStorageProcessor implements StorageProcessor {
         }
 
         if(vmMo.createSnapshot("cloud.template.base", "Base snapshot", false, false)) {
-        	// the same template may be deployed with multiple copies at per-datastore per-host basis,
-        	// save the original template name from CloudStack DB as the UUID to associate them.
+            // the same template may be deployed with multiple copies at per-datastore per-host basis,
+            // save the original template name from CloudStack DB as the UUID to associate them.
             vmMo.setCustomFieldValue(CustomFieldConstants.CLOUD_UUID, templateName);
             vmMo.markAsTemplate();
         } else {
@@ -197,7 +188,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
         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();
@@ -206,9 +197,9 @@ public class VmwareStorageProcessor implements StorageProcessor {
         assert (secondaryStorageUrl != null);
 
         String templateUrl = secondaryStorageUrl + "/" + srcData.getPath();
-        
+
         Pair<String, String> templateInfo = VmwareStorageLayoutHelper.decodeTemplateRelativePathAndNameFromUrl(
-        	secondaryStorageUrl, templateUrl, template.getName());
+                secondaryStorageUrl, templateUrl, template.getName());
 
         VmwareContext context = hostService.getServiceContext(cmd);
         try {
@@ -246,7 +237,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
             return new CopyCmdAnswer(msg);
         }
     }
-    
+
     private boolean createVMLinkedClone(VirtualMachineMO vmTemplate, DatacenterMO dcMo, DatastoreMO dsMo,
             String vmdkName, ManagedObjectReference morDatastore, ManagedObjectReference morPool) throws Exception {
 
@@ -265,16 +256,16 @@ public class VmwareStorageProcessor implements StorageProcessor {
         }
 
         s_logger.info("Move volume out of volume-wrapper VM ");
-        String[] vmwareLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, 
-        		vmdkName, vmdkName, VmwareStorageLayoutType.VMWARE, true);
-        String[] legacyCloudStackLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, 
-        		vmdkName, vmdkName, VmwareStorageLayoutType.CLOUDSTACK_LEGACY, true);
-        
+        String[] vmwareLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo,
+                vmdkName, vmdkName, VmwareStorageLayoutType.VMWARE, true);
+        String[] legacyCloudStackLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo,
+                vmdkName, vmdkName, VmwareStorageLayoutType.CLOUDSTACK_LEGACY, true);
+
         dsMo.moveDatastoreFile(vmwareLayoutFilePair[0],
                 dcMo.getMor(), dsMo.getMor(),
                 legacyCloudStackLayoutFilePair[0],
                 dcMo.getMor(), true);
-        
+
         dsMo.moveDatastoreFile(vmwareLayoutFilePair[1],
                 dcMo.getMor(), dsMo.getMor(),
                 legacyCloudStackLayoutFilePair[1],
@@ -292,18 +283,18 @@ public class VmwareStorageProcessor implements StorageProcessor {
             s_logger.error(msg);
             throw new Exception(msg);
         }
-        
+
         s_logger.info("Move volume out of volume-wrapper VM ");
-        String[] vmwareLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, 
-        		vmdkName, vmdkName, VmwareStorageLayoutType.VMWARE, false);
-        String[] legacyCloudStackLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, 
-        		vmdkName, vmdkName, VmwareStorageLayoutType.CLOUDSTACK_LEGACY, false);
-        
+        String[] vmwareLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo,
+                vmdkName, vmdkName, VmwareStorageLayoutType.VMWARE, false);
+        String[] legacyCloudStackLayoutFilePair = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo,
+                vmdkName, vmdkName, VmwareStorageLayoutType.CLOUDSTACK_LEGACY, false);
+
         dsMo.moveDatastoreFile(vmwareLayoutFilePair[0],
                 dcMo.getMor(), dsMo.getMor(),
                 legacyCloudStackLayoutFilePair[0],
                 dcMo.getMor(), true);
-        
+
         dsMo.moveDatastoreFile(vmwareLayoutFilePair[1],
                 dcMo.getMor(), dsMo.getMor(),
                 legacyCloudStackLayoutFilePair[1],
@@ -343,17 +334,17 @@ public class VmwareStorageProcessor implements StorageProcessor {
                         throw new Exception("Unable to create a dummy VM for volume creation");
                     }
 
-                    String vmdkFilePair[] = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, null, vmdkName, 
-                    	VmwareStorageLayoutType.CLOUDSTACK_LEGACY, 
-                    	true	// we only use the first file in the pair, linked or not will not matter
-                    	);
+                    String vmdkFilePair[] = VmwareStorageLayoutHelper.getVmdkFilePairDatastorePath(dsMo, null, vmdkName,
+                            VmwareStorageLayoutType.CLOUDSTACK_LEGACY,
+                            true	// we only use the first file in the pair, linked or not will not matter
+                            );
                     String volumeDatastorePath = vmdkFilePair[0];
                     synchronized (this) {
                         s_logger.info("Delete file if exists in datastore to clear the way for creating the volume. file: " + volumeDatastorePath);
                         VmwareStorageLayoutHelper.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);
@@ -506,7 +497,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
 
         try {
             ManagedObjectReference morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, poolId);
-            
+
             if (morDs == null) {
                 String msg = "Unable to find volumes's storage pool for copy volume operation";
                 s_logger.error(msg);
@@ -518,7 +509,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
                 // create a dummy worker vm for attaching the volume
                 DatastoreMO dsMo = new DatastoreMO(hyperHost.getContext(), morDs);
                 workerVm = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, workerVmName);
-                
+
                 if (workerVm == null) {
                     String msg = "Unable to create worker VM to execute CopyVolumeCommand";
                     s_logger.error(msg);
@@ -657,7 +648,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
             Pair<VirtualMachineMO, String[]> cloneResult = vmMo.cloneFromCurrentSnapshot(workerVmName, 0, 4, volumeDeviceInfo.second(),
                     VmwareHelper.getDiskDeviceDatastore(volumeDeviceInfo.first()));
             clonedVm = cloneResult.first();
-            
+
             clonedVm.exportVm(secondaryMountPoint + "/" + installPath, templateUniqueName, true, false);
 
             long physicalSize = new File(installFullPath + "/" + templateUniqueName + ".ova").length();
@@ -960,7 +951,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
                     throw new Exception("unable to prepare snapshot backup directory");
                 }
             }
-        }	
+        }
 
         VirtualMachineMO clonedVm = null;
         try {
@@ -974,7 +965,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
 
             // 4 MB is the minimum requirement for VM memory in VMware
             Pair<VirtualMachineMO, String[]> cloneResult = vmMo.cloneFromCurrentSnapshot(workerVmName, 0, 4, volumeDeviceInfo.second(),
-                VmwareHelper.getDiskDeviceDatastore(volumeDeviceInfo.first()));
+                    VmwareHelper.getDiskDeviceDatastore(volumeDeviceInfo.first()));
             clonedVm = cloneResult.first();
             String disks[] = cloneResult.second();
 
@@ -998,7 +989,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
                 installPath, backupUuid, workerVmName);
         return new Ternary<String, String, String[]>(backupUuid + "/" + backupUuid, snapshotInfo.first(), snapshotInfo.second());
     }
-    
+
     @Override
     public Answer backupSnapshot(CopyCommand cmd) {
         SnapshotObjectTO srcSnapshot = (SnapshotObjectTO)cmd.getSrcTO();
@@ -1025,7 +1016,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
         String details = null;
         boolean success = false;
         String snapshotBackupUuid = null;
-        
+
         boolean hasOwnerVm = false;
         Ternary<String, String, String[]> backupResult = null;
 
@@ -1037,7 +1028,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
             morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, primaryStore.getUuid());
 
             CopyCmdAnswer answer = null;
-            
+
             try {
                 vmMo = hyperHost.findVmOnHyperHost(vmName);
                 if (vmMo == null) {
@@ -1050,7 +1041,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
                         dsMo = new DatastoreMO(hyperHost.getContext(), morDs);
 
                         workerVMName = hostService.getWorkerName(context, cmd, 0);
-                        
+
                         vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, workerVMName);
 
                         if (vmMo == null) {
@@ -1062,12 +1053,12 @@ public class VmwareStorageProcessor implements StorageProcessor {
                         String datastoreVolumePath = dsMo.getDatastorePath(volumePath + ".vmdk");
                         vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs);
                     } else {
-                    	s_logger.info("Using owner VM " + vmName + " for snapshot operation");
-                    	hasOwnerVm = true;
+                        s_logger.info("Using owner VM " + vmName + " for snapshot operation");
+                        hasOwnerVm = true;
                     }
                 } else {
-                	s_logger.info("Using owner VM " + vmName + " for snapshot operation");
-                	hasOwnerVm = true;
+                    s_logger.info("Using owner VM " + vmName + " for snapshot operation");
+                    hasOwnerVm = true;
                 }
 
                 if (!vmMo.createSnapshot(snapshotUuid, "Snapshot taken for " + srcSnapshot.getName(), false, false)) {
@@ -1093,52 +1084,52 @@ public class VmwareStorageProcessor implements StorageProcessor {
                     ManagedObjectReference snapshotMor = vmMo.getSnapshotMor(snapshotUuid);
                     if (snapshotMor != null) {
                         vmMo.removeSnapshot(snapshotUuid, false);
-                        
+
                         // Snapshot operation may cause disk consolidation in VMware, when this happens
                         // we need to update CloudStack DB
                         //
                         // TODO: this post operation fixup is not atomic and not safe when management server stops
                         // in the middle
                         if(backupResult != null && hasOwnerVm) {
-                        	s_logger.info("Check if we have disk consolidation after snapshot operation");
-                        	
-                        	boolean chainConsolidated = false;
-                        	for(String vmdkDsFilePath : backupResult.third()) {
-                        		s_logger.info("Validate disk chain file:" + vmdkDsFilePath);
-                        		
-                        		if(vmMo.getDiskDevice(vmdkDsFilePath, false) == null) {
-                        			s_logger.info("" + vmdkDsFilePath + " no longer exists, consolidation detected");
-                        			chainConsolidated = true;
-                        			break;
-                        		} else {
-                        			s_logger.info("" + vmdkDsFilePath + " is found still in chain");
-                        		}
-                        	}
-                        	
-                        	if(chainConsolidated) {
-                        		String topVmdkFilePath = null;
-                        		try {
-                        			topVmdkFilePath = vmMo.getDiskCurrentTopBackingFileInChain(backupResult.second());
-                        		} catch(Exception e) {
-                        			s_logger.error("Unexpected exception", e);
-                        		}
-                        		
-                        		s_logger.info("Disk has been consolidated, top VMDK is now: " + topVmdkFilePath);
-                        		if(topVmdkFilePath != null) {
-	                        		DatastoreFile file = new DatastoreFile(topVmdkFilePath);
-	                        		
-	                        		SnapshotObjectTO snapshotInfo = (SnapshotObjectTO)answer.getNewData();
-	                        		VolumeObjectTO vol = new VolumeObjectTO();
-	                        		vol.setUuid(srcSnapshot.getVolume().getUuid());
-	                        		vol.setPath(file.getFileBaseName());
-	                        		snapshotInfo.setVolume(vol);
-                        		} else {
-                        			s_logger.error("Disk has been consolidated, but top VMDK is not found ?!");
-                        		}
-                        	}
+                            s_logger.info("Check if we have disk consolidation after snapshot operation");
+
+                            boolean chainConsolidated = false;
+                            for(String vmdkDsFilePath : backupResult.third()) {
+                                s_logger.info("Validate disk chain file:" + vmdkDsFilePath);
+
+                                if(vmMo.getDiskDevice(vmdkDsFilePath, false) == null) {
+                                    s_logger.info("" + vmdkDsFilePath + " no longer exists, consolidation detected");
+                                    chainConsolidated = true;
+                                    break;
+                                } else {
+                                    s_logger.info("" + vmdkDsFilePath + " is found still in chain");
+                                }
+                            }
+
+                            if(chainConsolidated) {
+                                String topVmdkFilePath = null;
+                                try {
+                                    topVmdkFilePath = vmMo.getDiskCurrentTopBackingFileInChain(backupResult.second());
+                                } catch(Exception e) {
+                                    s_logger.error("Unexpected exception", e);
+                                }
+
+                                s_logger.info("Disk has been consolidated, top VMDK is now: " + topVmdkFilePath);
+                                if(topVmdkFilePath != null) {
+                                    DatastoreFile file = new DatastoreFile(topVmdkFilePath);
+
+                                    SnapshotObjectTO snapshotInfo = (SnapshotObjectTO)answer.getNewData();
+                                    VolumeObjectTO vol = new VolumeObjectTO();
+                                    vol.setUuid(srcSnapshot.getVolume().getUuid());
+                                    vol.setPath(file.getFileBaseName());
+                                    snapshotInfo.setVolume(vol);
+                                } else {
+                                    s_logger.error("Disk has been consolidated, but top VMDK is not found ?!");
+                                }
+                            }
                         }
                     } else {
-                    	s_logger.error("Can not find the snapshot we just used ?!");
+                        s_logger.error("Can not find the snapshot we just used ?!");
                     }
                 }
 
@@ -1152,7 +1143,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
                     s_logger.warn("Failed to destroy worker VM: " + workerVMName);
                 }
             }
-            
+
             return answer;
         } catch (Throwable e) {
             if (e instanceof RemoteException) {
@@ -1205,7 +1196,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
             }
             else {
                 morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, isManaged ? VmwareResource.getDatastoreName(iScsiName) : primaryStore.getUuid());
-           }
+            }
 
             if (morDs == null) {
                 String msg = "Unable to find the mounted datastore to execute AttachVolumeCommand, vmName: " + vmName;
@@ -1217,30 +1208,30 @@ public class VmwareStorageProcessor implements StorageProcessor {
             String datastoreVolumePath;
 
             if(isAttach) {
-            	if(!isManaged)
-	            	datastoreVolumePath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), vmName, 
-		                dsMo, volumeTO.getPath());
-            	else 
-            		datastoreVolumePath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk");
+                if(!isManaged)
+                    datastoreVolumePath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dsMo.getOwnerDatacenter().first(), vmName,
+                            dsMo, volumeTO.getPath());
+                else
+                    datastoreVolumePath = dsMo.getDatastorePath(dsMo.getName() + ".vmdk");
             } else {
-            	datastoreVolumePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo, volumeTO.getPath() + ".vmdk");
-            	if(!dsMo.fileExists(datastoreVolumePath))
-            		datastoreVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, volumeTO.getPath() + ".vmdk");
+                datastoreVolumePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo, volumeTO.getPath() + ".vmdk");
+                if(!dsMo.fileExists(datastoreVolumePath))
+                    datastoreVolumePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, volumeTO.getPath() + ".vmdk");
             }
-            
+
             disk.setVdiUuid(datastoreVolumePath);
 
             AttachAnswer answer = new AttachAnswer(disk);
             if (isAttach) {
                 vmMo.attachDisk(new String[] { datastoreVolumePath }, morDs);
-            } else {	
+            } else {
                 vmMo.removeAllSnapshots();
                 vmMo.detachDisk(datastoreVolumePath, false);
 
                 if (isManaged) {
                     this.hostService.handleDatastoreAndVmdkDetach(iScsiName, storageHost, storagePort);
                 } else {
-                	VmwareStorageLayoutHelper.syncVolumeToRootFolder(dsMo.getOwnerDatacenter().first(), dsMo, volumeTO.getPath());
+                    VmwareStorageLayoutHelper.syncVolumeToRootFolder(dsMo.getOwnerDatacenter().first(), dsMo, volumeTO.getPath());
                 }
             }
 
@@ -1274,7 +1265,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
 
         return morDatastore;
     }
-    
+
     private Answer attachIso(DiskTO disk, boolean isAttach, String vmName) {
         try {
             VmwareHypervisorHost hyperHost = hostService.getHyperHost(hostService.getServiceContext(null), null);
@@ -1387,7 +1378,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
             String volumeDatastorePath = dsMo.getDatastorePath(volumeUuid + ".vmdk");
             String dummyVmName = this.hostService.getWorkerName(context, cmd, 0);
             try {
-            	s_logger.info("Create worker VM " + dummyVmName);
+                s_logger.info("Create worker VM " + dummyVmName);
                 vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, dummyVmName);
                 if (vmMo == null) {
                     throw new Exception("Unable to create a dummy VM for volume creation");
@@ -1408,8 +1399,8 @@ public class VmwareStorageProcessor implements StorageProcessor {
             } finally {
                 s_logger.info("Destroy dummy VM after volume creation");
                 if(vmMo != null) {
-	                vmMo.detachAllDisks();
-	                vmMo.destroy();
+                    vmMo.detachAllDisks();
+                    vmMo.destroy();
                 }
             }
         } catch (Throwable e) {
@@ -1460,7 +1451,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
             ClusterMO clusterMo = new ClusterMO(context, morCluster);
 
             if (vol.getVolumeType() == Volume.Type.ROOT) {
-            	
+
                 String vmName = vol.getVmName();
                 if (vmName != null) {
                     VirtualMachineMO vmMo = clusterMo.findVmOnHyperHost(vmName);
@@ -1471,12 +1462,12 @@ public class VmwareStorageProcessor implements StorageProcessor {
 
                         // Remove all snapshots to consolidate disks for removal
                         vmMo.removeAllSnapshots();
-                        
+
                         VirtualMachineDiskInfo diskInfo = null;
                         if(vol.getChainInfo() != null)
-                        	diskInfo = _gson.fromJson(vol.getChainInfo(), VirtualMachineDiskInfo.class);
-                        
-                        
+                            diskInfo = _gson.fromJson(vol.getChainInfo(), VirtualMachineDiskInfo.class);
+
+
                         HostMO hostMo = vmMo.getRunningHost();
                         List<NetworkDetails> networks = vmMo.getNetworksWithDetails();
 
@@ -1484,7 +1475,7 @@ public class VmwareStorageProcessor implements StorageProcessor {
                         if (this.resource.getVmState(vmMo) != State.Stopped) {
                             vmMo.safePowerOff(_shutdown_waitMs);
                         }
-                        
+
                         List<String> detachedDisks = vmMo.detachAllDisksExcept(vol.getPath(), diskInfo != null ? diskInfo.getDiskDeviceBusName() : null);
                         VmwareStorageLayoutHelper.moveVolumeToRootFolder(new DatacenterMO(context, morDc), detachedDisks);
 
@@ -1501,13 +1492,13 @@ public class VmwareStorageProcessor implements StorageProcessor {
                         }
                     }
 
-/*                    
+                    /*
                     if (s_logger.isInfoEnabled()) {
                         s_logger.info("Destroy volume by original name: " + vol.getPath() + ".vmdk");
                     }
 
                     VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vol.getPath(), new DatacenterMO(context, morDc));
-*/
+                     */
                     return new Answer(cmd, true, "Success");
                 }
 
@@ -1527,8 +1518,8 @@ public class VmwareStorageProcessor implements StorageProcessor {
                 }
             }
 
-            VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vol.getPath(), new DatacenterMO(context, morDc));                   
-            
+            VmwareStorageLayoutHelper.deleteVolumeVmdkFiles(dsMo, vol.getPath(), new DatacenterMO(context, morDc));
+
             return new Answer(cmd, true, "Success");
         } catch (Throwable e) {
             if (e instanceof RemoteException) {
@@ -1672,10 +1663,20 @@ public class VmwareStorageProcessor implements StorageProcessor {
             return new Answer(cmd, false, "unsupported command");
         }
     }
-    
+
+    @Override
+    public Answer introduceObject(IntroduceObjectCmd cmd) {
+        return new Answer(cmd, false, "not implememented yet");
+    }
+
+    @Override
+    public Answer forgetObject(ForgetObjectCmd cmd) {
+        return new Answer(cmd, false, "not implememented yet");
+    }
+
     private static String deriveTemplateUuidOnHost(VmwareHypervisorHost hyperHost, String storeIdentifier, String templateName) {
-    	String templateUuid = UUID.nameUUIDFromBytes((templateName + "@" + storeIdentifier + "-" + hyperHost.getMor().getValue()).getBytes()).toString();
-    	templateUuid = templateUuid.replaceAll("-", "");
-    	return templateUuid;
+        String templateUuid = UUID.nameUUIDFromBytes((templateName + "@" + storeIdentifier + "-" + hyperHost.getMor().getValue()).getBytes()).toString();
+        templateUuid = templateUuid.replaceAll("-", "");
+        return templateUuid;
     }
 }


Re: [1/2] Refactor Storage Related Resource Code These changes are a joint effort between Edison and I to refactor some of the code around snapshotting VM volumes and creating templates/volumes from VM volume snapshots. In general, we were working towards al

Posted by Chip Childers <ch...@sungard.com>.
I some outstanding questions I just posted to the review.

Any thoughts on those questions?

https://reviews.apache.org/r/14477/


On Fri, Oct 4, 2013 at 4:07 PM, <ed...@apache.org> wrote:

> Updated Branches:
>   refs/heads/master c9f41d404 -> 180cfa19e
>
>
>
> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/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
> index 739b974..5da0571 100644
> ---
> a/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
> +++
> b/plugins/hypervisors/xen/src/com/cloud/hypervisor/xen/resource/XenServerStorageProcessor.java
> @@ -18,6 +18,36 @@
>   */
>  package com.cloud.hypervisor.xen.resource;
>
> +import java.io.File;
> +import java.net.URI;
> +import java.util.Arrays;
> +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.command.ForgetObjectCmd;
> +import org.apache.cloudstack.storage.command.IntroduceObjectAnswer;
> +import org.apache.cloudstack.storage.command.IntroduceObjectCmd;
> +import org.apache.cloudstack.storage.datastore.protocol.DataStoreProtocol;
> +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;
> @@ -51,33 +81,6 @@ import com.xensource.xenapi.VBD;
>  import com.xensource.xenapi.VDI;
>  import com.xensource.xenapi.VM;
>  import com.xensource.xenapi.VMGuestMetrics;
> -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 java.io.File;
> -import java.net.URI;
> -import java.util.Arrays;
> -import java.util.HashMap;
> -import java.util.List;
> -import java.util.Map;
> -import java.util.Set;
> -import java.util.UUID;
>
>  import static com.cloud.utils.ReflectUtil.flattenProperties;
>  import static com.google.common.collect.Lists.newArrayList;
> @@ -841,8 +844,7 @@ public class XenServerStorageProcessor implements
> StorageProcessor {
>
>                  URI uri = new URI(storeUrl);
>                  String tmplpath = uri.getHost() + ":" + uri.getPath() +
> "/" + srcData.getPath();
> -                PrimaryDataStoreTO destStore =
> (PrimaryDataStoreTO)destData.getDataStore();
> -                String poolName = destStore.getUuid();
> +                String poolName = destData.getDataStore().getUuid();
>                  Connection conn = hypervisorResource.getConnection();
>
>                  SR poolsr = null;
> @@ -892,8 +894,7 @@ public class XenServerStorageProcessor implements
> StorageProcessor {
>
>          try {
>              Connection conn = hypervisorResource.getConnection();
> -            PrimaryDataStoreTO primaryStore =
> (PrimaryDataStoreTO)data.getDataStore();
> -            SR poolSr = hypervisorResource.getStorageRepository(conn,
> primaryStore.getUuid());
> +            SR poolSr = hypervisorResource.getStorageRepository(conn,
> data.getDataStore().getUuid());
>              VDI.Record vdir = new VDI.Record();
>              vdir.nameLabel = volume.getName();
>              vdir.SR = poolSr;
> @@ -921,7 +922,6 @@ public class XenServerStorageProcessor implements
> StorageProcessor {
>          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 {
> @@ -943,7 +943,7 @@ public class XenServerStorageProcessor implements
> StorageProcessor {
>
>              return new CopyCmdAnswer(newVol);
>          } catch (Exception e) {
> -            s_logger.warn("Unable to create volume; Pool=" + pool + ";
> Disk: ", e);
> +            s_logger.warn("Unable to create volume; Pool=" + destData +
> "; Disk: ", e);
>              return new CopyCmdAnswer(e.toString());
>          }
>      }
> @@ -956,13 +956,12 @@ public class XenServerStorageProcessor implements
> StorageProcessor {
>          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());
> +                SR primaryStoragePool =
> hypervisorResource.getStorageRepository(conn,
> destVolume.getDataStore().getUuid());
>                  String srUuid = primaryStoragePool.getUuid(conn);
>                  URI uri = new URI(nfsStore.getUrl());
>                  String volumePath = uri.getHost() + ":" + uri.getPath() +
> File.separator + srcVolume.getPath();
> @@ -1179,8 +1178,7 @@ public class XenServerStorageProcessor implements
> StorageProcessor {
>          DataTO cacheData = cmd.getCacheTO();
>          DataTO destData = cmd.getDestTO();
>          int wait = cmd.getWait();
> -        PrimaryDataStoreTO primaryStore =
> (PrimaryDataStoreTO)srcData.getDataStore();
> -        String primaryStorageNameLabel = primaryStore.getUuid();
> +        String primaryStorageNameLabel = srcData.getDataStore().getUuid();
>          String secondaryStorageUrl = null;
>          NfsTO cacheStore = null;
>          String destPath = null;
> @@ -1415,7 +1413,6 @@ public class XenServerStorageProcessor implements
> StorageProcessor {
>          DataTO srcData = cmd.getSrcTO();
>          SnapshotObjectTO snapshot = (SnapshotObjectTO)srcData;
>          DataTO destData = cmd.getDestTO();
> -        PrimaryDataStoreTO pool =
> (PrimaryDataStoreTO)destData.getDataStore();
>          DataStoreTO imageStore = srcData.getDataStore();
>
>          if (!(imageStore instanceof NfsTO)) {
> @@ -1423,7 +1420,7 @@ public class XenServerStorageProcessor implements
> StorageProcessor {
>          }
>
>          NfsTO nfsImageStore = (NfsTO)imageStore;
> -        String primaryStorageNameLabel = pool.getUuid();
> +        String primaryStorageNameLabel =
> destData.getDataStore().getUuid();
>          String secondaryStorageUrl = nfsImageStore.getUrl();
>          int wait = cmd.getWait();
>          boolean result = false;
> @@ -1503,4 +1500,32 @@ public class XenServerStorageProcessor implements
> StorageProcessor {
>          }
>          return new Answer(cmd, false, "unsupported storage type");
>      }
> +
> +    @Override
> +    public Answer introduceObject(IntroduceObjectCmd cmd) {
> +        try {
> +            Connection conn = hypervisorResource.getConnection();
> +            DataStoreTO store = cmd.getDataTO().getDataStore();
> +            SR poolSr = hypervisorResource.getStorageRepository(conn,
> store.getUuid());
> +            poolSr.scan(conn);
> +            return new IntroduceObjectAnswer(cmd.getDataTO());
> +        } catch (Exception e) {
> +            s_logger.debug("Failed to introduce object", e);
> +            return new Answer(cmd, false, e.toString());
> +        }
> +    }
> +
> +    @Override
> +    public Answer forgetObject(ForgetObjectCmd cmd) {
> +        try {
> +            Connection conn = hypervisorResource.getConnection();
> +            DataTO data = cmd.getDataTO();
> +            VDI vdi = VDI.getByUuid(conn, data.getPath());
> +            vdi.forget(conn);
> +            return new IntroduceObjectAnswer(cmd.getDataTO());
> +        } catch (Exception e) {
> +            s_logger.debug("Failed to introduce object", e);
> +            return new Answer(cmd, false, e.toString());
> +        }
> +    }
>  }
>
>
> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
> ----------------------------------------------------------------------
> diff --git
> a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
> b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
> index 2297e6a..0b53cfd 100755
> --- a/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
> +++ b/server/src/com/cloud/storage/snapshot/SnapshotManagerImpl.java
> @@ -48,7 +48,6 @@ import
> org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
>  import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreDao;
>  import org.apache.cloudstack.storage.datastore.db.SnapshotDataStoreVO;
>  import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
> -
>  import org.apache.log4j.Logger;
>  import org.springframework.stereotype.Component;
>
> @@ -69,13 +68,11 @@ import com.cloud.event.ActionEventUtils;
>  import com.cloud.event.EventTypes;
>  import com.cloud.event.EventVO;
>  import com.cloud.event.UsageEventUtils;
> -import com.cloud.event.dao.EventDao;
>  import com.cloud.exception.InvalidParameterValueException;
>  import com.cloud.exception.PermissionDeniedException;
>  import com.cloud.exception.ResourceAllocationException;
>  import com.cloud.exception.StorageUnavailableException;
>  import com.cloud.host.HostVO;
> -import com.cloud.host.dao.HostDao;
>  import com.cloud.hypervisor.Hypervisor.HypervisorType;
>  import com.cloud.projects.Project.ListProjectResourcesCriteria;
>  import com.cloud.resource.ResourceManager;
> @@ -193,10 +190,10 @@ public class SnapshotManagerImpl extends ManagerBase
> implements SnapshotManager,
>      @Inject VolumeDataFactory volFactory;
>      @Inject SnapshotDataFactory snapshotFactory;
>      @Inject EndPointSelector _epSelector;
> -       @Inject
> -       private ResourceManager _resourceMgr;
> -       @Inject
> -       protected List<SnapshotStrategy> snapshotStrategies;
> +    @Inject
> +    private ResourceManager _resourceMgr;
> +    @Inject
> +    protected List<SnapshotStrategy> snapshotStrategies;
>
>
>      private int _totalRetries;
> @@ -261,16 +258,38 @@ public class SnapshotManagerImpl extends ManagerBase
> implements SnapshotManager,
>      }
>
>      @Override
> +    public boolean revertSnapshot(Long snapshotId) {
> +        Snapshot snapshot = _snapshotDao.findById(snapshotId);
> +        if (snapshot == null) {
> +            throw new InvalidParameterValueException("No such snapshot");
> +        }
> +
> +        SnapshotStrategy snapshotStrategy = null;
> +        for (SnapshotStrategy strategy : snapshotStrategies) {
> +            if (strategy.canHandle(snapshot)) {
> +                snapshotStrategy = strategy;
> +                break;
> +            }
> +        }
> +
> +        if (snapshotStrategy == null) {
> +            return false;
> +        }
> +
> +        return snapshotStrategy.revertSnapshot(snapshotId);
> +    }
> +
> +    @Override
>      @DB
>      @ActionEvent(eventType = EventTypes.EVENT_SNAPSHOT_CREATE,
> eventDescription = "creating snapshot", async = true)
>      public Snapshot createSnapshot(Long volumeId, Long policyId, Long
> snapshotId, Account snapshotOwner) {
>          VolumeInfo volume = volFactory.getVolume(volumeId);
>          if (volume == null) {
> -               throw new InvalidParameterValueException("No such volume
> exist");
> +            throw new InvalidParameterValueException("No such volume
> exist");
>          }
>
>          if (volume.getState() != Volume.State.Ready) {
> -               throw new InvalidParameterValueException("Volume is not in
> ready state");
> +            throw new InvalidParameterValueException("Volume is not in
> ready state");
>          }
>
>
> @@ -281,16 +300,16 @@ public class SnapshotManagerImpl extends ManagerBase
> implements SnapshotManager,
>          SnapshotInfo snapshot = snapshotFactory.getSnapshot(snapshotId,
> DataStoreRole.Primary);
>
>          try {
> -               postCreateSnapshot(volumeId, snapshot.getId(), policyId);
> -               //Check if the snapshot was removed while backingUp. If
> yes, do not log snapshot create usage event
> -               SnapshotVO freshSnapshot =
> _snapshotDao.findById(snapshot.getId());
> -               if ((freshSnapshot != null) && backedUp) {
> -
> UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_CREATE,
> snapshot.getAccountId(),
> -                                       snapshot.getDataCenterId(),
> snapshotId, snapshot.getName(), null, null,
> -                                       volume.getSize(),
> snapshot.getClass().getName(), snapshot.getUuid());
> -               }
> +            postCreateSnapshot(volumeId, snapshot.getId(), policyId);
> +            //Check if the snapshot was removed while backingUp. If yes,
> do not log snapshot create usage event
> +            SnapshotVO freshSnapshot =
> _snapshotDao.findById(snapshot.getId());
> +            if ((freshSnapshot != null) && backedUp) {
> +
>  UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_CREATE,
> snapshot.getAccountId(),
> +                        snapshot.getDataCenterId(), snapshotId,
> snapshot.getName(), null, null,
> +                        volume.getSize(), snapshot.getClass().getName(),
> snapshot.getUuid());
> +            }
>
> -
> _resourceLimitMgr.incrementResourceCount(snapshotOwner.getId(),
> ResourceType.snapshot);
> +
>  _resourceLimitMgr.incrementResourceCount(snapshotOwner.getId(),
> ResourceType.snapshot);
>
>          } catch(Exception e) {
>              s_logger.debug("Failed to create snapshot", e);
> @@ -311,12 +330,12 @@ public class SnapshotManagerImpl extends ManagerBase
> implements SnapshotManager,
>
>      @Override
>      public Snapshot backupSnapshot(Long snapshotId) {
> -        SnapshotInfo snapshot = snapshotFactory.getSnapshot(snapshotId,
> DataStoreRole.Image);
> -        if (snapshot != null) {
> -                throw new CloudRuntimeException("Already in the backup
> snapshot:" + snapshotId);
> -        }
> +        SnapshotInfo snapshot = snapshotFactory.getSnapshot(snapshotId,
> DataStoreRole.Image);
> +        if (snapshot != null) {
> +            throw new CloudRuntimeException("Already in the backup
> snapshot:" + snapshotId);
> +        }
>
> -         return snapshotSrv.backupSnapshot(snapshot);
> +        return snapshotSrv.backupSnapshot(snapshot);
>      }
>
>      /*
> @@ -412,14 +431,14 @@ public class SnapshotManagerImpl extends ManagerBase
> implements SnapshotManager,
>
>      @Override
>      public SnapshotVO getParentSnapshot(VolumeInfo volume) {
> -        long preId = _snapshotDao.getLastSnapshot(volume.getId(),
> DataStoreRole.Primary);
> +        long preId = _snapshotDao.getLastSnapshot(volume.getId(),
> DataStoreRole.Primary);
>
> -         SnapshotVO preSnapshotVO = null;
> -         if (preId != 0 && !(volume.getLastPoolId() != null &&
> !volume.getLastPoolId().equals(volume.getPoolId()))) {
> -             preSnapshotVO = _snapshotDao.findByIdIncludingRemoved(preId);
> -         }
> +        SnapshotVO preSnapshotVO = null;
> +        if (preId != 0 && !(volume.getLastPoolId() != null &&
> !volume.getLastPoolId().equals(volume.getPoolId()))) {
> +            preSnapshotVO = _snapshotDao.findByIdIncludingRemoved(preId);
> +        }
>
> -         return preSnapshotVO;
> +        return preSnapshotVO;
>      }
>
>      private Long getSnapshotUserId() {
> @@ -463,7 +482,7 @@ public class SnapshotManagerImpl extends ManagerBase
> implements SnapshotManager,
>                  s_logger.debug("Max snaps: " + policy.getMaxSnaps() + "
> exceeded for snapshot policy with Id: " + policyId + ". Deleting oldest
> snapshot: " + oldSnapId);
>              }
>              if(deleteSnapshot(oldSnapId)){
> -               //log Snapshot delete event
> +                //log Snapshot delete event
>                  ActionEventUtils.onCompletedActionEvent(User.UID_SYSTEM,
> oldestSnapshot.getAccountId(), EventVO.LEVEL_INFO,
> EventTypes.EVENT_SNAPSHOT_DELETE, "Successfully deleted oldest snapshot: "
> + oldSnapId, 0);
>              }
>              snaps.remove(oldestSnapshot);
> @@ -485,27 +504,27 @@ public class SnapshotManagerImpl extends ManagerBase
> implements SnapshotManager,
>          _accountMgr.checkAccess(caller, null, true, snapshotCheck);
>          SnapshotStrategy snapshotStrategy = null;
>          for (SnapshotStrategy strategy : snapshotStrategies) {
> -               if (strategy.canHandle(snapshotCheck)) {
> -                       snapshotStrategy = strategy;
> -                       break;
> -               }
> +            if (strategy.canHandle(snapshotCheck)) {
> +                snapshotStrategy = strategy;
> +                break;
> +            }
>          }
>          try {
> -               boolean result =
> snapshotStrategy.deleteSnapshot(snapshotId);
> -               if (result) {
> +            boolean result = snapshotStrategy.deleteSnapshot(snapshotId);
> +            if (result) {
>                  if (snapshotCheck.getState() == Snapshot.State.BackedUp) {
> -
> UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE,
> snapshotCheck.getAccountId(),
> -
> snapshotCheck.getDataCenterId(), snapshotId, snapshotCheck.getName(), null,
> null, 0L,
> -
> snapshotCheck.getClass().getName(), snapshotCheck.getUuid());
> -                       }
> +
>  UsageEventUtils.publishUsageEvent(EventTypes.EVENT_SNAPSHOT_DELETE,
> snapshotCheck.getAccountId(),
> +                            snapshotCheck.getDataCenterId(), snapshotId,
> snapshotCheck.getName(), null, null, 0L,
> +                            snapshotCheck.getClass().getName(),
> snapshotCheck.getUuid());
> +                }
>
>  _resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(),
> ResourceType.snapshot);
>
>  _resourceLimitMgr.decrementResourceCount(snapshotCheck.getAccountId(),
> ResourceType.secondary_storage,
>                          new Long(snapshotCheck.getSize()));
> -               }
> -               return result;
> +            }
> +            return result;
>          } catch (Exception e) {
> -               s_logger.debug("Failed to delete snapshot: " +
> snapshotCheck.getId() + ":" + e.toString());
> -               throw new CloudRuntimeException("Failed to delete
> snapshot:" + e.toString());
> +            s_logger.debug("Failed to delete snapshot: " +
> snapshotCheck.getId() + ":" + e.toString());
> +            throw new CloudRuntimeException("Failed to delete snapshot:"
> + e.toString());
>          }
>      }
>
> @@ -544,10 +563,10 @@ public class SnapshotManagerImpl extends ManagerBase
> implements SnapshotManager,
>          }
>
>          Ternary<Long, Boolean, ListProjectResourcesCriteria>
> domainIdRecursiveListProject = new Ternary<Long, Boolean,
> ListProjectResourcesCriteria>(cmd.getDomainId(), cmd.isRecursive(), null);
> -       _accountMgr.buildACLSearchParameters(caller, id,
> cmd.getAccountName(), cmd.getProjectId(), permittedAccounts,
> domainIdRecursiveListProject, cmd.listAll(), false);
> -       Long domainId = domainIdRecursiveListProject.first();
> -       Boolean isRecursive = domainIdRecursiveListProject.second();
> -       ListProjectResourcesCriteria listProjectResourcesCriteria =
> domainIdRecursiveListProject.third();
> +        _accountMgr.buildACLSearchParameters(caller, id,
> cmd.getAccountName(), cmd.getProjectId(), permittedAccounts,
> domainIdRecursiveListProject, cmd.listAll(), false);
> +        Long domainId = domainIdRecursiveListProject.first();
> +        Boolean isRecursive = domainIdRecursiveListProject.second();
> +        ListProjectResourcesCriteria listProjectResourcesCriteria =
> domainIdRecursiveListProject.third();
>
>          Filter searchFilter = new Filter(SnapshotVO.class, "created",
> false, cmd.getStartIndex(), cmd.getPageSizeVal());
>          SearchBuilder<SnapshotVO> sb = _snapshotDao.createSearchBuilder();
> @@ -560,7 +579,7 @@ public class SnapshotManagerImpl extends ManagerBase
> implements SnapshotManager,
>          sb.and("snapshotTypeEQ", sb.entity().getsnapshotType(),
> SearchCriteria.Op.IN);
>          sb.and("snapshotTypeNEQ", sb.entity().getsnapshotType(),
> SearchCriteria.Op.NEQ);
>          sb.and("dataCenterId", sb.entity().getDataCenterId(),
> SearchCriteria.Op.EQ);
> -
> +
>          if (tags != null && !tags.isEmpty()) {
>              SearchBuilder<ResourceTagVO> tagSearch =
> _resourceTagDao.createSearchBuilder();
>              for (int count=0; count < tags.size(); count++) {
> @@ -595,7 +614,7 @@ public class SnapshotManagerImpl extends ManagerBase
> implements SnapshotManager,
>          if (zoneId != null) {
>              sc.setParameters("dataCenterId", zoneId);
>          }
> -
> +
>          if (name != null) {
>              sc.setParameters("name", "%" + name + "%");
>          }
> @@ -763,10 +782,10 @@ public class SnapshotManagerImpl extends ManagerBase
> implements SnapshotManager,
>          long domainLimit =
> _resourceLimitMgr.findCorrectResourceLimitForDomain(_domainMgr.getDomain(owner.getDomainId()),
> ResourceType.snapshot);
>          int max = cmd.getMaxSnaps().intValue();
>          if (owner.getType() != Account.ACCOUNT_TYPE_ADMIN &&
> ((accountLimit != -1 && max > accountLimit) || (domainLimit != -1 && max >
> domainLimit))) {
> -               String message = "domain/account";
> -               if (owner.getType() == Account.ACCOUNT_TYPE_PROJECT) {
> -                       message = "domain/project";
> -               }
> +            String message = "domain/account";
> +            if (owner.getType() == Account.ACCOUNT_TYPE_PROJECT) {
> +                message = "domain/project";
> +            }
>
>              throw new InvalidParameterValueException("Max number of
> snapshots shouldn't exceed the " + message + " level snapshot limit");
>          }
> @@ -905,37 +924,37 @@ public class SnapshotManagerImpl extends ManagerBase
> implements SnapshotManager,
>
>
>      private boolean hostSupportSnapsthotForVolume(HostVO host, VolumeInfo
> volume) {
> -               if (host.getHypervisorType() != HypervisorType.KVM) {
> -                       return true;
> -               }
> +        if (host.getHypervisorType() != HypervisorType.KVM) {
> +            return true;
> +        }
>
>          //Turn off snapshot by default for KVM if the volume attached to
> vm that is not in the Stopped/Destroyed state,
> -               //unless it is set in the global flag
> -               Long vmId = volume.getInstanceId();
> -               if (vmId != null) {
> -                   VMInstanceVO vm = _vmDao.findById(vmId);
> -                   if (vm.getState() != VirtualMachine.State.Stopped &&
> vm.getState() != VirtualMachine.State.Destroyed) {
> -                       boolean snapshotEnabled =
> Boolean.parseBoolean(_configDao.getValue("kvm.snapshot.enabled"));
> -                   if (!snapshotEnabled) {
> -                        s_logger.debug("Snapshot is not supported on host
> " + host + " for the volume " + volume + " attached to the vm " + vm);
> -                        return false;
> -                   }
> -                   }
> -               }
> -
> -               // Determine host capabilities
> -               String caps = host.getCapabilities();
> -
> -               if (caps != null) {
> -                       String[] tokens = caps.split(",");
> -                       for (String token : tokens) {
> -                               if (token.contains("snapshot")) {
> -                                       return true;
> -                               }
> -                       }
> -               }
> -               return false;
> -       }
> +        //unless it is set in the global flag
> +        Long vmId = volume.getInstanceId();
> +        if (vmId != null) {
> +            VMInstanceVO vm = _vmDao.findById(vmId);
> +            if (vm.getState() != VirtualMachine.State.Stopped &&
> vm.getState() != VirtualMachine.State.Destroyed) {
> +                boolean snapshotEnabled =
> Boolean.parseBoolean(_configDao.getValue("kvm.snapshot.enabled"));
> +                if (!snapshotEnabled) {
> +                    s_logger.debug("Snapshot is not supported on host " +
> host + " for the volume " + volume + " attached to the vm " + vm);
> +                    return false;
> +                }
> +            }
> +        }
> +
> +        // Determine host capabilities
> +        String caps = host.getCapabilities();
> +
> +        if (caps != null) {
> +            String[] tokens = caps.split(",");
> +            for (String token : tokens) {
> +                if (token.contains("snapshot")) {
> +                    return true;
> +                }
> +            }
> +        }
> +        return false;
> +    }
>
>      private boolean supportedByHypervisor(VolumeInfo volume) {
>          HypervisorType hypervisorType;
> @@ -967,10 +986,10 @@ public class SnapshotManagerImpl extends ManagerBase
> implements SnapshotManager,
>              }
>          }
>
> -               // if volume is attached to a vm in destroyed or expunging
> state; disallow
> -               if (volume.getInstanceId() != null) {
> -                       UserVmVO userVm =
> _vmDao.findById(volume.getInstanceId());
> -                       if (userVm != null) {
> +        // if volume is attached to a vm in destroyed or expunging state;
> disallow
> +        if (volume.getInstanceId() != null) {
> +            UserVmVO userVm = _vmDao.findById(volume.getInstanceId());
> +            if (userVm != null) {
>                  if (userVm.getState().equals(State.Destroyed) ||
> userVm.getState().equals(State.Expunging)) {
>                      throw new CloudRuntimeException("Creating snapshot
> failed due to volume:" + volume.getId()
>                              + " is associated with vm:" +
> userVm.getInstanceName() + " is in "
> @@ -993,11 +1012,11 @@ public class SnapshotManagerImpl extends
> ManagerBase implements SnapshotManager,
>                      throw new CloudRuntimeException(
>                              "There is other active vm snapshot tasks on
> the instance to which the volume is attached, please try again later");
>                  }
> -                       }
> -               }
> +            }
> +        }
>
> -               return true;
> -       }
> +        return true;
> +    }
>      @Override
>      @DB
>      public SnapshotInfo takeSnapshot(VolumeInfo volume) throws
> ResourceAllocationException {
> @@ -1124,10 +1143,10 @@ public class SnapshotManagerImpl extends
> ManagerBase implements SnapshotManager,
>      public boolean canOperateOnVolume(Volume volume) {
>          List<SnapshotVO> snapshots =
> _snapshotDao.listByStatus(volume.getId(), Snapshot.State.Creating,
>                  Snapshot.State.CreatedOnPrimary,
> Snapshot.State.BackingUp);
> -       if (snapshots.size() > 0) {
> -               return false;
> -       }
> -       return true;
> +        if (snapshots.size() > 0) {
> +            return false;
> +        }
> +        return true;
>      }
>
>      @Override
>
>
> http://git-wip-us.apache.org/repos/asf/cloudstack/blob/180cfa19/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java
> ----------------------------------------------------------------------
> diff --git
> a/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java
> b/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java
> index 3ef950b..e26f02d 100755
> ---
> a/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java
> +++
> b/services/secondary-storage/src/org/apache/cloudstack/storage/resource/NfsSecondaryStorageResource.java
> @@ -16,14 +16,15 @@
>  // under the License.
>  package org.apache.cloudstack.storage.resource;
>
> -import static com.cloud.utils.S3Utils.putFile;
> -import static com.cloud.utils.StringUtils.join;
> -import static com.cloud.utils.db.GlobalLock.executeWithNoWaitLock;
> -import static java.lang.String.format;
> -import static java.util.Arrays.asList;
> -import static org.apache.commons.lang.StringUtils.substringAfterLast;
> -
> -import java.io.*;
> +import java.io.BufferedReader;
> +import java.io.BufferedWriter;
> +import java.io.File;
> +import java.io.FileInputStream;
> +import java.io.FileOutputStream;
> +import java.io.FileReader;
> +import java.io.FileWriter;
> +import java.io.IOException;
> +import java.io.InputStream;
>  import java.math.BigInteger;
>  import java.net.InetAddress;
>  import java.net.URI;
> @@ -39,10 +40,6 @@ import java.util.concurrent.Callable;
>
>  import javax.naming.ConfigurationException;
>
> -import com.cloud.agent.api.storage.*;
> -import com.cloud.storage.VMTemplateStorageResourceAssoc;
> -import com.cloud.storage.template.*;
> -import com.cloud.utils.SwiftUtil;
>  import org.apache.cloudstack.storage.command.CopyCmdAnswer;
>  import org.apache.cloudstack.storage.command.CopyCommand;
>  import org.apache.cloudstack.storage.command.DeleteCommand;
> @@ -53,6 +50,8 @@ import
> org.apache.cloudstack.storage.template.DownloadManagerImpl;
>  import
> org.apache.cloudstack.storage.template.DownloadManagerImpl.ZfsPathParser;
>  import org.apache.cloudstack.storage.template.UploadManager;
>  import org.apache.cloudstack.storage.template.UploadManagerImpl;
> +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;
> @@ -88,6 +87,14 @@ import
> com.cloud.agent.api.SecStorageSetupCommand.Certificates;
>  import com.cloud.agent.api.SecStorageVMSetupCommand;
>  import com.cloud.agent.api.StartupCommand;
>  import com.cloud.agent.api.StartupSecondaryStorageCommand;
> +import com.cloud.agent.api.storage.CreateEntityDownloadURLCommand;
> +import com.cloud.agent.api.storage.DeleteEntityDownloadURLCommand;
> +import com.cloud.agent.api.storage.DownloadAnswer;
> +import com.cloud.agent.api.storage.ListTemplateAnswer;
> +import com.cloud.agent.api.storage.ListTemplateCommand;
> +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.to.DataObjectType;
>  import com.cloud.agent.api.to.DataStoreTO;
>  import com.cloud.agent.api.to.DataTO;
> @@ -101,16 +108,34 @@ import
> com.cloud.hypervisor.Hypervisor.HypervisorType;
>  import com.cloud.resource.ServerResourceBase;
>  import com.cloud.storage.DataStoreRole;
>  import com.cloud.storage.Storage.ImageFormat;
> +import com.cloud.storage.Storage.StoragePoolType;
>  import com.cloud.storage.StorageLayer;
> +import com.cloud.storage.VMTemplateStorageResourceAssoc;
> +import com.cloud.storage.template.Processor;
>  import com.cloud.storage.template.Processor.FormatInfo;
> +import com.cloud.storage.template.QCOW2Processor;
> +import com.cloud.storage.template.RawImageProcessor;
> +import com.cloud.storage.template.TemplateLocation;
> +import com.cloud.storage.template.TemplateProp;
> +import com.cloud.storage.template.VhdProcessor;
> +import com.cloud.storage.template.VmdkProcessor;
>  import com.cloud.utils.NumbersUtil;
>  import com.cloud.utils.S3Utils;
>  import com.cloud.utils.S3Utils.FileNamingStrategy;
> +import com.cloud.utils.SwiftUtil;
>  import com.cloud.utils.exception.CloudRuntimeException;
>  import com.cloud.utils.net.NetUtils;
>  import com.cloud.utils.script.OutputInterpreter;
>  import com.cloud.utils.script.Script;
>  import com.cloud.vm.SecondaryStorageVm;
> +import com.google.common.io.Files;
> +
> +import static com.cloud.utils.S3Utils.putFile;
> +import static com.cloud.utils.StringUtils.join;
> +import static com.cloud.utils.db.GlobalLock.executeWithNoWaitLock;
> +import static java.lang.String.format;
> +import static java.util.Arrays.asList;
> +import static org.apache.commons.lang.StringUtils.substringAfterLast;
>
>  public class NfsSecondaryStorageResource extends ServerResourceBase
> implements SecondaryStorageResource {
>
> @@ -357,6 +382,7 @@ public class NfsSecondaryStorageResource extends
> ServerResourceBase implements S
>              snapshotName = snapshotName + ".vhd";
>          }
>          snapshotPath = snapshotPath.substring(0, index);
> +
>          snapshotPath = srcMountPoint + File.separator + snapshotPath;
>          String destMountPoint = this.getRootDir(destDataStore.getUrl());
>          String destPath = destMountPoint + File.separator +
> destData.getPath();
> @@ -424,7 +450,7 @@ public class NfsSecondaryStorageResource extends
> ServerResourceBase implements S
>
>              // get snapshot file name
>              String templateName = srcFile.getName();
> -            // add kvm file extension for copied template name
> +            // add kvm file extension for copied template name
>              String fileName = templateName + "." +
> srcFormat.getFileExtension();
>              String destFileFullPath = destFile.getAbsolutePath() +
> File.separator + fileName;
>              s_logger.debug("copy snapshot " + srcFile.getAbsolutePath() +
> " to template " + destFileFullPath);
> @@ -509,15 +535,16 @@ public class NfsSecondaryStorageResource extends
> ServerResourceBase implements S
>          DataTO destData = cmd.getDestTO();
>          DataStoreTO srcDataStore = srcData.getDataStore();
>          DataStoreTO destDataStore = destData.getDataStore();
> -        if (srcDataStore.getRole() == DataStoreRole.Image ||
> srcDataStore.getRole() == DataStoreRole.ImageCache) {
> +        if (srcDataStore.getRole() == DataStoreRole.Image ||
> srcDataStore.getRole() == DataStoreRole.ImageCache ||
> +                srcDataStore.getRole() == DataStoreRole.Primary) {
>              if (!(srcDataStore instanceof NfsTO)) {
>                  s_logger.debug("only support nfs storage as src, when
> create template from snapshot");
>                  return Answer.createUnsupportedCommandAnswer(cmd);
>              }
>
>              if (destDataStore instanceof NfsTO) {
> -                return copySnapshotToTemplateFromNfsToNfs(cmd,
> (SnapshotObjectTO) srcData, (NfsTO) srcDataStore,
> -                        (TemplateObjectTO) destData, (NfsTO)
> destDataStore);
> +                return copySnapshotToTemplateFromNfsToNfs(cmd,
> (SnapshotObjectTO) srcData, (NfsTO)srcDataStore,
> +                        (TemplateObjectTO) destData,
> (NfsTO)destDataStore);
>              } else if (destDataStore instanceof SwiftTO) {
>                  //create template on the same data store
>                  CopyCmdAnswer answer =
> (CopyCmdAnswer)copySnapshotToTemplateFromNfsToNfs(cmd, (SnapshotObjectTO)
> srcData, (NfsTO) srcDataStore,
> @@ -543,8 +570,8 @@ public class NfsSecondaryStorageResource extends
> ServerResourceBase implements S
>                      execute(deleteCommand);
>                  } catch (Exception e) {
>                      s_logger.debug("Failed to clean up staging area:", e);
> -                }
> -
> +                }
> +
>                  TemplateObjectTO template = new TemplateObjectTO();
>                  template.setPath(swiftPath);
>                  template.setSize(templateFile.length());
> @@ -569,7 +596,7 @@ public class NfsSecondaryStorageResource extends
> ServerResourceBase implements S
>                      execute(deleteCommand);
>                  } catch (Exception e) {
>                      s_logger.debug("Failed to clean up staging area:", e);
> -                }
> +                }
>                  return result;
>              }
>          }
> @@ -792,7 +819,7 @@ public class NfsSecondaryStorageResource extends
> ServerResourceBase implements S
>              processor.configure("template processor", new HashMap<String,
> Object>());
>              return processor.getVirtualSize(file);
>          } catch (Exception e) {
> -           s_logger.debug("Failed to get virtual size:" ,e);
> +            s_logger.debug("Failed to get virtual size:" ,e);
>          }
>          return file.length();
>      }
> @@ -2226,8 +2253,8 @@ public class NfsSecondaryStorageResource extends
> ServerResourceBase implements S
>       *
>       * CIFS parameters are documented with mount.cifs at
>       * http://linux.die.net/man/8/mount.cifs
> -        * For simplicity, when a URI is used to specify a CIFS share,
> -        * options such as domain,user,password are passed as query
> parameters.
> +     * For simplicity, when a URI is used to specify a CIFS share,
> +     * options such as domain,user,password are passed as query
> parameters.
>       *
>       * @param uri
>       *            crresponding to the remote device. Will throw for
> unsupported
> @@ -2262,7 +2289,7 @@ public class NfsSecondaryStorageResource extends
> ServerResourceBase implements S
>          return dir;
>      }
>
> -
> +
>      protected void umount(String localRootPath, URI uri) {
>          ensureLocalRootPathExists(localRootPath, uri);
>
> @@ -2286,7 +2313,7 @@ public class NfsSecondaryStorageResource extends
> ServerResourceBase implements S
>          }
>          s_logger.debug("Successfully umounted " + localRootPath);
>      }
> -
> +
>      protected void mount(String localRootPath, String remoteDevice, URI
> uri) {
>          s_logger.debug("mount " + uri.toString() + " on " +
> localRootPath);
>          ensureLocalRootPathExists(localRootPath, uri);
>
>
>