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 2012/08/21 03:16:43 UTC

[2/3] refactor attach/detach iso

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/7d6938ba/server/src/com/cloud/storage/volume/VolumeManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/volume/VolumeManagerImpl.java b/server/src/com/cloud/storage/volume/VolumeManagerImpl.java
index c14a10b..b702590 100644
--- a/server/src/com/cloud/storage/volume/VolumeManagerImpl.java
+++ b/server/src/com/cloud/storage/volume/VolumeManagerImpl.java
@@ -18,6 +18,7 @@ import org.apache.log4j.Logger;
 
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.AttachIsoCommand;
 import com.cloud.agent.api.AttachVolumeAnswer;
 import com.cloud.agent.api.AttachVolumeCommand;
 import com.cloud.agent.api.storage.CopyVolumeAnswer;
@@ -35,7 +36,10 @@ import com.cloud.api.commands.ListVolumesCmd;
 import com.cloud.async.AsyncJobExecutor;
 import com.cloud.async.AsyncJobVO;
 import com.cloud.async.BaseAsyncJobExecutor;
+import com.cloud.cluster.CheckPointManager;
 import com.cloud.configuration.Config;
+import com.cloud.configuration.Resource.ResourceType;
+import com.cloud.configuration.dao.ConfigurationDao;
 import com.cloud.dc.DataCenterVO;
 import com.cloud.dc.HostPodVO;
 import com.cloud.dc.dao.DataCenterDao;
@@ -48,17 +52,23 @@ import com.cloud.exception.AgentUnavailableException;
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.InsufficientStorageCapacityException;
 import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.OperationTimedoutException;
+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;
 import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.hypervisor.dao.HypervisorCapabilitiesDao;
+import com.cloud.org.Grouping;
+import com.cloud.projects.Project.ListProjectResourcesCriteria;
 import com.cloud.server.ResourceTag.TaggedResourceType;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.storage.DiskOfferingVO;
 import com.cloud.storage.StoragePoolVO;
 import com.cloud.storage.VMTemplateHostVO;
+import com.cloud.storage.VMTemplateSwiftVO;
 import com.cloud.storage.VMTemplateVO;
 import com.cloud.storage.VolumeHostVO;
 import com.cloud.storage.VolumeVO;
@@ -67,21 +77,28 @@ import com.cloud.storage.dao.DiskOfferingDao;
 import com.cloud.storage.dao.StoragePoolDao;
 import com.cloud.storage.dao.VMTemplateDao;
 import com.cloud.storage.dao.VMTemplateHostDao;
+import com.cloud.storage.dao.VMTemplateSwiftDao;
 import com.cloud.storage.dao.VolumeDao;
 import com.cloud.storage.dao.VolumeHostDao;
 import com.cloud.storage.image.ImageManager;
-import com.cloud.storage.orchestra.StorageMigrationCleanupMaid;
+import com.cloud.storage.StorageMigrationCleanupMaid;
 import com.cloud.storage.pool.Storage;
 import com.cloud.storage.pool.Storage.ImageFormat;
+import com.cloud.storage.pool.Storage.TemplateType;
 import com.cloud.storage.pool.StoragePool;
 import com.cloud.storage.pool.StoragePoolManager;
 import com.cloud.storage.snapshot.SnapshotManager;
 import com.cloud.storage.volume.Volume.Event;
 import com.cloud.storage.volume.Volume.Type;
 import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.ResourceLimitService;
 import com.cloud.user.UserContext;
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.EnumUtils;
 import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.Pair;
+import com.cloud.utils.Ternary;
 import com.cloud.utils.component.Inject;
 import com.cloud.utils.component.Manager;
 import com.cloud.utils.db.DB;
@@ -110,1267 +127,1152 @@ import com.cloud.template.TemplateManager;
 import com.cloud.template.VirtualMachineTemplate;
 
 public class VolumeManagerImpl implements VolumeManager, Manager {
-    private static final Logger s_logger = Logger.getLogger(VolumeManagerImpl.class);
-    protected int _retry = 2;
-    protected int _copyvolumewait;
-    private StateMachine2<Volume.State, Volume.Event, Volume> _volStateMachine;
-    protected SearchBuilder<VMTemplateHostVO> HostTemplateStatesSearch;
-    
-    @Inject
-    protected VolumeDao _volumeDao;
-    @Inject
-    protected VMTemplateHostDao _vmTemplateHostDao = null;
-    @Inject
-    protected HostDao _hostDao;
-    @Inject
+	private static final Logger s_logger = Logger.getLogger(VolumeManagerImpl.class);
+	protected int _retry = 2;
+	protected int _copyvolumewait;
+	private StateMachine2<Volume.State, Volume.Event, Volume> _volStateMachine;
+	protected SearchBuilder<VMTemplateHostVO> HostTemplateStatesSearch;
+
+	@Inject
+	protected VolumeDao _volumeDao;
+	@Inject
+	protected VMTemplateHostDao _vmTemplateHostDao = null;
+	@Inject
+	protected HostDao _hostDao;
+	@Inject
 	protected DiskOfferingDao _diskOfferingDao;
-    @Inject
-    protected StoragePoolManager _storagePoolMgr;
-    @Inject
-    protected SnapshotManager _snapshotMgr;
-    @Inject
-    protected ImageManager _imageMgr;
-    @Inject
-    protected VolumeHostDao _volHostDao;
-    @Inject 
-    protected AgentManager _agentMgr;
-    @Inject
-    protected VMInstanceDao _vmInstanceDao;
-    @Inject
-    protected ResourceTagDao _resourceTagDao;
-    @Inject
-    protected TemplateManager _templateMgr;
-    @Inject
-    protected VMInstanceDao _vmDao;
-    @Inject
-    protected VMTemplateDao _templateDao;
-    @Inject
-    protected UserVmDao _userVmDao;
-    @Inject
-    protected StoragePoolDao _storagePoolDao;
-    @Inject
-    protected VolumeHostDao _volumeHostDao;
-    @Inject
-    protected DataCenterDao _dcDao;
-    @Inject
-    protected HostPodDao _podDao;
-    @Inject
-    protected UsageEventDao _usageEventDao;
-    
-    @Inject
-    protected HypervisorCapabilitiesDao _hypervisorCapabilitiesDao;
-	
-   
+	@Inject
+	protected StoragePoolManager _storagePoolMgr;
+	@Inject
+	protected SnapshotManager _snapshotMgr;
+	@Inject
+	protected ImageManager _imageMgr;
+	@Inject
+	protected AccountManager _accountMgr;
+	@Inject
+	protected VolumeHostDao _volHostDao;
+	@Inject
+	protected AgentManager _agentMgr;
+	@Inject
+	protected VMInstanceDao _vmInstanceDao;
+	@Inject
+	protected ResourceTagDao _resourceTagDao;
+	@Inject
+	protected TemplateManager _templateMgr;
+	@Inject
+	protected VMInstanceDao _vmDao;
+	@Inject
+	protected VMTemplateDao _templateDao;
+	@Inject
+	protected UserVmDao _userVmDao;
+	@Inject
+	protected StoragePoolDao _storagePoolDao;
+	@Inject
+	protected VolumeHostDao _volumeHostDao;
+	@Inject
+	protected DataCenterDao _dcDao;
+	@Inject
+	protected HostPodDao _podDao;
+	@Inject
+	protected UsageEventDao _usageEventDao;
+	@Inject
+	protected ConfigurationDao _configDao;
+	@Inject
+	protected ResourceLimitService _resourceLimitMgr;
+	@Inject
+	protected CheckPointManager _checkPointMgr;
+	@Inject
+	protected VMTemplateSwiftDao _vmTemplateSwiftDao = null;
+	@Inject
+	protected HypervisorCapabilitiesDao _hypervisorCapabilitiesDao;
 
 	@Override
 	@DB
 	public boolean destroyVolume(VolumeVO volume) throws ConcurrentOperationException {
 		try {
-			if (!processEvent(volume, Volume.Event.DestroyRequested)) {
-				throw new ConcurrentOperationException("Failed to transit to destroyed state");
-			}
+			processEvent(volume, Volume.Event.DestroyRequested);
 		} catch (NoTransitionException e) {
-			s_logger.debug("Unable to destoy the volume: " + e.toString());
-			return false;
+			throw new ConcurrentOperationException(e.toString());
 		}
 
 		long volumeId = volume.getId();
+		boolean success = false;
 
-		// Delete the recurring snapshot policies for this volume.
-		_snapshotMgr.deletePoliciesForVolume(volumeId);
+		try {
+			_snapshotMgr.deletePoliciesForVolume(volumeId);
+			Long instanceId = volume.getInstanceId();
+			VMInstanceVO vmInstance = null;
+			if (instanceId != null) {
+				vmInstance = _vmInstanceDao.findById(instanceId);
+			}
+
+			processEvent(volume, Volume.Event.OperationSucceeded);
+			success = true;
 
-		Long instanceId = volume.getInstanceId();
-		VMInstanceVO vmInstance = null;
-		if (instanceId != null) {
-			vmInstance = _vmInstanceDao.findById(instanceId);
+			if (instanceId == null || (vmInstance.getType().equals(VirtualMachine.Type.User))) {
+				// Decrement the resource count for volumes belonging user VM's
+				// only
+				_resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.volume);
+				// Log usage event for volumes belonging user VM's only
+				UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName());
+				_usageEventDao.persist(usageEvent);
+			}
+			return success;
+		} catch (NoTransitionException e) {
+			throw new ConcurrentOperationException(e.toString());
+		} finally {
+			if (!success) {
+				try {
+					processEvent(volume, Volume.Event.OperationFailed);
+				} catch (NoTransitionException e) {
+					s_logger.debug("Failed to transit volume state: " + e.toString());
+				}
+			}
 		}
+	}
 
-		if (instanceId == null || (vmInstance.getType().equals(VirtualMachine.Type.User))) {
-			// Decrement the resource count for volumes belonging user VM's only
-			_resourceLimitMgr.decrementResourceCount(volume.getAccountId(), ResourceType.volume);
-			// Log usage event for volumes belonging user VM's only
-			UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_DELETE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName());
-			_usageEventDao.persist(usageEvent);
+	@Override
+	public VolumeVO allocateDuplicateVolume(VolumeVO oldVol, Long templateId) {
+		VolumeVO newVol = new VolumeVO(oldVol.getVolumeType(), oldVol.getName(), oldVol.getDataCenterId(), oldVol.getDomainId(), oldVol.getAccountId(), oldVol.getDiskOfferingId(), oldVol.getSize());
+		if (templateId != null) {
+			newVol.setTemplateId(templateId);
+		} else {
+			newVol.setTemplateId(oldVol.getTemplateId());
 		}
+		newVol.setDeviceId(oldVol.getDeviceId());
+		newVol.setInstanceId(oldVol.getInstanceId());
+		newVol.setRecreatable(oldVol.isRecreatable());
+		return _volumeDao.persist(newVol);
+	}
 
+	@DB
+	protected void copyVolumeFromSec(VolumeVO volume, StoragePool pool) throws ConcurrentOperationException, StorageUnavailableException {
 		try {
-			if (!processEvent(volume, Volume.Event.OperationSucceeded)) {
-				throw new ConcurrentOperationException("Failed to transit state");
+			processEvent(volume, Volume.Event.CopyRequested);
+		} catch (NoTransitionException e) {
+			throw new ConcurrentOperationException("Unable to request a copy operation on volume " + volume);
+		}
 
+		boolean success = false;
+		try {
+			VolumeHostVO volumeHostVO = _volumeHostDao.findByVolumeId(volume.getId());
+			HostVO secStorage = _hostDao.findById(volumeHostVO.getHostId());
+			String secondaryStorageURL = secStorage.getStorageUrl();
+			String[] volumePath = volumeHostVO.getInstallPath().split("/");
+			String volumeUUID = volumePath[volumePath.length - 1].split("\\.")[0];
+
+			CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(), volumeUUID, pool, secondaryStorageURL, false, _copyvolumewait);
+			CopyVolumeAnswer cvAnswer;
+
+			cvAnswer = (CopyVolumeAnswer) _storagePoolMgr.sendToPool(pool, cvCmd);
+			boolean result = (cvAnswer != null && cvAnswer.getResult()) ? true : false;
+			if (result) {
+				Transaction txn = Transaction.currentTxn();
+				txn.start();
+				volume.setPath(cvAnswer.getVolumePath());
+				volume.setFolder(pool.getPath());
+				volume.setPodId(pool.getPodId());
+				volume.setPoolId(pool.getId());
+				volume.setPodId(pool.getPodId());
+
+				processEvent(volume, Event.CopySucceeded);
+
+				UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(),
+						volume.getDiskOfferingId(), null, volume.getSize());
+				_usageEventDao.persist(usageEvent);
+				_volumeHostDao.remove(volumeHostVO.getId());
+				txn.commit();
 			}
+			success = result;
+		} catch (StorageUnavailableException e) {
+			throw e;
 		} catch (NoTransitionException e) {
-			s_logger.debug("Unable to change volume state: " + e.toString());
-			return false;
+			throw new ConcurrentOperationException("Failed to copy volume: " + volume);
+		} finally {
+			if (!success) {
+				try {
+					processEvent(volume, Event.CopyFailed);
+				} catch (NoTransitionException e) {
+					s_logger.debug("Failed to change volume: " + volume + " state: " + e.toString());
+				}
+			}
+		}
+	}
+
+	@Override
+	@DB
+	public VolumeVO createVolume(VolumeVO volume, long VMTemplateId, DiskOfferingVO diskOffering, HypervisorType hyperType, StoragePool assignedPool) throws StorageUnavailableException,
+			ConcurrentOperationException {
+		Long existingPoolId = null;
+		existingPoolId = volume.getPoolId();
+
+		if (existingPoolId == null && assignedPool == null) {
+			throw new CloudRuntimeException("Volume has no pool associate and also no storage pool assigned in DeployDestination, Unable to create.");
+		}
+
+		if (assignedPool == null) {
+			if (s_logger.isDebugEnabled()) {
+				s_logger.debug("No need to recreate the volume: " + volume + ", since it already has a pool assigned: " + volume.getPoolId() + ", adding disk to VM");
+			}
+			return volume;
+		}
+
+		boolean needToCreateVolume = false;
+		boolean needToRecreateVolume = false;
+		boolean needToMigrateVolume = false;
+		boolean needToCopyFromSec = false;
+		Volume.State state = volume.getState();
+		if (state == Volume.State.Allocated || state == Volume.State.Creating) {
+			needToCreateVolume = true;
+		} else if (state == Volume.State.UploadOp) {
+			needToCopyFromSec = true;
+		}
+
+		if (volume.isRecreatable()) {
+			if (s_logger.isDebugEnabled()) {
+				s_logger.debug("Volume " + volume + " will be recreated on storage pool " + assignedPool + " assigned by deploymentPlanner");
+			}
+			if (volume.getPoolId() == null) {
+				needToCreateVolume = true;
+			} else {
+				needToRecreateVolume = true;
+			}
+		} else {
+			if (assignedPool.getId() != volume.getPoolId()) {
+				if (s_logger.isDebugEnabled()) {
+					s_logger.debug("Mismatch in storage pool " + assignedPool + " assigned by deploymentPlanner and the one associated with volume " + volume);
+				}
+				if (diskOffering.getUseLocalStorage()) {
+					throw new CloudRuntimeException("Can't recreate volume: " + volume + " on local storage");
+				} else {
+					if (s_logger.isDebugEnabled()) {
+						s_logger.debug("Shared volume " + volume + " will be migrated on storage pool " + assignedPool + " assigned by deploymentPlanner");
+					}
+					needToMigrateVolume = true;
+				}
+			} else {
+				return volume;
+			}
+		}
+
+		VolumeVO newVol = volume;
+		if (needToCreateVolume || needToRecreateVolume) {
+			if (needToRecreateVolume) {
+				newVol = switchVolume(volume, VMTemplateId);
+			}
+			newVol = createVolume(newVol, diskOffering, hyperType, assignedPool);
+		} else if (needToMigrateVolume) {
+			List<Volume> volumesToMigrate = new ArrayList<Volume>();
+			volumesToMigrate.add(volume);
+			migrateVolumes(volumesToMigrate, assignedPool);
+
+		} else if (needToCopyFromSec) {
+			copyVolumeFromSec(volume, assignedPool);
+		}
+
+		newVol = _volumeDao.findById(volume.getId());
+		return newVol;
+	}
+
+	/**
+	 * Give a volume in allocated state, created on specified storage
+	 * 
+	 * @param toBeCreated
+	 * @param offering
+	 * @param hypervisorType
+	 * @param sPool
+	 * @return
+	 * @throws StorageUnavailableException
+	 */
+	private VolumeVO createVolume(VolumeVO toBeCreated, DiskOfferingVO offering, HypervisorType hypervisorType, StoragePool sPool) throws StorageUnavailableException, ConcurrentOperationException {
+		if (sPool == null) {
+			throw new CloudRuntimeException("can't create volume: " + toBeCreated + " on a empty storage");
+		}
+
+		if (toBeCreated == null) {
+			throw new CloudRuntimeException("volume can't be null");
+		}
+
+		if (s_logger.isDebugEnabled()) {
+			s_logger.debug("Creating volume: " + toBeCreated + " on pool: " + sPool);
+		}
+
+		DiskProfile diskProfile = new DiskProfile(toBeCreated, offering, hypervisorType);
+
+		toBeCreated.setPoolId(sPool.getId());
+		try {
+			processEvent(toBeCreated, Volume.Event.CreateRequested);
+		} catch (NoTransitionException e) {
+			throw new ConcurrentOperationException("Unable to request a create operation on volume " + toBeCreated);
+		}
+
+		boolean createdSuccessed = false;
+		try {
+			VMTemplateVO template = null;
+			String templateOnStoragePath = null;
+			if (toBeCreated.getTemplateId() != null) {
+				template = _templateDao.findById(toBeCreated.getTemplateId());
+				templateOnStoragePath = _templateMgr.prepareTemplateOnPool(template, sPool);
+			}
+
+			CreateCommand cmd = null;
+			cmd = new CreateCommand(diskProfile, templateOnStoragePath, new StorageFilerTO(sPool));
+
+			Answer answer = _storagePoolMgr.sendToPool(sPool, null, cmd);
+			if (answer.getResult()) {
+				CreateAnswer createAnswer = (CreateAnswer) answer;
+				VolumeTO created = createAnswer.getVolume();
+
+				toBeCreated.setFolder(sPool.getPath());
+				toBeCreated.setPath(created.getPath());
+				toBeCreated.setSize(created.getSize());
+				toBeCreated.setPoolType(sPool.getPoolType());
+				toBeCreated.setPoolId(sPool.getId());
+				toBeCreated.setPodId(sPool.getPodId());
+
+				processEvent(toBeCreated, Volume.Event.OperationSucceeded);
+				createdSuccessed = true;
+			}
+			return toBeCreated;
+		} catch (NoTransitionException e) {
+			throw new ConcurrentOperationException("Unable to update volume state: " + e.toString());
+		} finally {
+			if (createdSuccessed == false) {
+				try {
+					processEvent(toBeCreated, Volume.Event.OperationFailed);
+				} catch (NoTransitionException e1) {
+					s_logger.debug("Unable to update volume state: " + e1.toString());
+				}
+			}
+		}
+	}
+
+	@DB
+	public boolean migrateVolumes(List<Volume> volumes, StoragePool destPool) throws ConcurrentOperationException {
+		Transaction txn = Transaction.currentTxn();
+		txn.start();
+
+		boolean transitResult = false;
+		long checkPointTaskId = -1;
+		try {
+			List<Long> volIds = new ArrayList<Long>();
+			for (Volume volume : volumes) {
+				if (!_snapshotMgr.canOperateOnVolume((VolumeVO) volume)) {
+					throw new CloudRuntimeException("There are snapshots creating on this volume, can not move this volume");
+				}
+
+				try {
+					if (!processEvent(volume, Volume.Event.MigrationRequested)) {
+						throw new ConcurrentOperationException("Failed to transit volume state");
+					}
+				} catch (NoTransitionException e) {
+					s_logger.debug("Failed to set state into migrate: " + e.toString());
+					throw new CloudRuntimeException("Failed to set state into migrate: " + e.toString());
+				}
+				volIds.add(volume.getId());
+			}
+
+			checkPointTaskId = _checkPointMgr.pushCheckPoint(new StorageMigrationCleanupMaid(StorageMigrationCleanupMaid.StorageMigrationState.MIGRATING, volIds));
+			transitResult = true;
+		} finally {
+			if (!transitResult) {
+				txn.rollback();
+			} else {
+				txn.commit();
+			}
 		}
 
+		// At this stage, nobody can modify volumes. Send the copyvolume command
+		List<Pair<StoragePoolVO, DestroyCommand>> destroyCmds = new ArrayList<Pair<StoragePoolVO, DestroyCommand>>();
+		List<CopyVolumeAnswer> answers = new ArrayList<CopyVolumeAnswer>();
+		try {
+			for (Volume volume : volumes) {
+				String secondaryStorageURL = _storagePoolMgr.getSecondaryStorageURL(volume.getDataCenterId());
+				StoragePoolVO srcPool = _storagePoolDao.findById(volume.getPoolId());
+				CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(), volume.getPath(), srcPool, secondaryStorageURL, true, _copyvolumewait);
+				CopyVolumeAnswer cvAnswer;
+				try {
+					cvAnswer = (CopyVolumeAnswer) _storagePoolMgr.sendToPool(srcPool, cvCmd);
+				} catch (StorageUnavailableException e1) {
+					throw new CloudRuntimeException("Failed to copy the volume from the source primary storage pool to secondary storage.", e1);
+				}
+
+				if (cvAnswer == null || !cvAnswer.getResult()) {
+					throw new CloudRuntimeException("Failed to copy the volume from the source primary storage pool to secondary storage.");
+				}
+
+				String secondaryStorageVolumePath = cvAnswer.getVolumePath();
+
+				// Copy the volume from secondary storage to the destination
+				// storage
+				// pool
+				cvCmd = new CopyVolumeCommand(volume.getId(), secondaryStorageVolumePath, destPool, secondaryStorageURL, false, _copyvolumewait);
+				try {
+					cvAnswer = (CopyVolumeAnswer) _storagePoolMgr.sendToPool(destPool, cvCmd);
+				} catch (StorageUnavailableException e1) {
+					throw new CloudRuntimeException("Failed to copy the volume from secondary storage to the destination primary storage pool.");
+				}
+
+				if (cvAnswer == null || !cvAnswer.getResult()) {
+					throw new CloudRuntimeException("Failed to copy the volume from secondary storage to the destination primary storage pool.");
+				}
+
+				answers.add(cvAnswer);
+				destroyCmds.add(new Pair<StoragePoolVO, DestroyCommand>(srcPool, new DestroyCommand(srcPool, volume, null)));
+			}
+		} finally {
+			if (answers.size() != volumes.size()) {
+				// this means one of copying volume failed
+				for (Volume volume : volumes) {
+					try {
+						processEvent(volume, Volume.Event.OperationFailed);
+					} catch (NoTransitionException e) {
+						s_logger.debug("Failed to change volume state: " + e.toString());
+					}
+				}
+				_checkPointMgr.popCheckPoint(checkPointTaskId);
+			} else {
+				// Need a transaction, make sure all the volumes get migrated to
+				// new storage pool
+				txn = Transaction.currentTxn();
+				txn.start();
+
+				transitResult = false;
+				try {
+					for (int i = 0; i < volumes.size(); i++) {
+						CopyVolumeAnswer answer = answers.get(i);
+						VolumeVO volume = (VolumeVO) volumes.get(i);
+						Long oldPoolId = volume.getPoolId();
+						volume.setPath(answer.getVolumePath());
+						volume.setFolder(destPool.getPath());
+						volume.setPodId(destPool.getPodId());
+						volume.setPoolId(destPool.getId());
+						volume.setLastPoolId(oldPoolId);
+						volume.setPodId(destPool.getPodId());
+						try {
+							processEvent(volume, Volume.Event.OperationSucceeded);
+						} catch (NoTransitionException e) {
+							s_logger.debug("Failed to change volume state: " + e.toString());
+							throw new CloudRuntimeException("Failed to change volume state: " + e.toString());
+						}
+					}
+					transitResult = true;
+					try {
+						_checkPointMgr.popCheckPoint(checkPointTaskId);
+					} catch (Exception e) {
+
+					}
+				} finally {
+					if (!transitResult) {
+						txn.rollback();
+					} else {
+						txn.commit();
+					}
+				}
+
+			}
+		}
+
+		// all the volumes get migrated to new storage pool, need to delete the
+		// copy on old storage pool
+		for (Pair<StoragePoolVO, DestroyCommand> cmd : destroyCmds) {
+			try {
+				Answer cvAnswer = _storagePoolMgr.sendToPool(cmd.first(), cmd.second());
+			} catch (StorageUnavailableException e) {
+				s_logger.debug("Unable to delete the old copy on storage pool: " + e.toString());
+			}
+		}
 		return true;
+	}
 
+	@Override
+	public boolean volumeInactive(VolumeVO volume) {
+		Long vmId = volume.getInstanceId();
+		if (vmId != null) {
+			UserVm vm = _userVmDao.findById(vmId);
+			if (vm == null) {
+				return true;
+			}
+			State state = vm.getState();
+			if (state.equals(State.Stopped) || state.equals(State.Destroyed)) {
+				return true;
+			}
+		}
+		return false;
 	}
-	
-    @Override
-    public VolumeVO allocateDuplicateVolume(VolumeVO oldVol, Long templateId) {
-        VolumeVO newVol = new VolumeVO(oldVol.getVolumeType(), oldVol.getName(), oldVol.getDataCenterId(), oldVol.getDomainId(), oldVol.getAccountId(), oldVol.getDiskOfferingId(), oldVol.getSize());
-        if (templateId != null) {
-            newVol.setTemplateId(templateId);
-        } else {
-            newVol.setTemplateId(oldVol.getTemplateId());
-        }
-        newVol.setDeviceId(oldVol.getDeviceId());
-        newVol.setInstanceId(oldVol.getInstanceId());
-        newVol.setRecreatable(oldVol.isRecreatable());
-        return _volumeDao.persist(newVol);
-    }
-    
-    @DB
-    protected void copyVolumeFromSec(VolumeVO volume, StoragePool pool) throws ConcurrentOperationException, StorageUnavailableException {
-    	try {
-        	processEvent(volume, Volume.Event.CopyRequested);
-        } catch (NoTransitionException e) {
-        	throw new ConcurrentOperationException("Unable to request a copy operation on volume " + volume);
-        }
-        
-        boolean success = false;
-        try {
-        	VolumeHostVO volumeHostVO = _volumeHostDao.findByVolumeId(volume.getId());
-        	HostVO secStorage = _hostDao.findById(volumeHostVO.getHostId());
-        	String secondaryStorageURL = secStorage.getStorageUrl();
-        	String[] volumePath = volumeHostVO.getInstallPath().split("/");
-        	String volumeUUID = volumePath[volumePath.length - 1].split("\\.")[0];
-
-        	CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(), volumeUUID, pool, secondaryStorageURL, false, _copyvolumewait);
-        	CopyVolumeAnswer cvAnswer;
-
-        	cvAnswer = (CopyVolumeAnswer) _storagePoolMgr.sendToPool(pool, cvCmd);
-        	boolean result = (cvAnswer != null && cvAnswer.getResult()) ? true : false;
-        	if (result) {
-        		Transaction txn = Transaction.currentTxn();
-        		txn.start();        
-        		volume.setPath(cvAnswer.getVolumePath());
-        		volume.setFolder(pool.getPath());
-        		volume.setPodId(pool.getPodId());
-        		volume.setPoolId(pool.getId());        
-        		volume.setPodId(pool.getPodId());
-        		processEvent(volume, Event.CopySucceeded); 
-        		UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), volume.getDiskOfferingId(), null, volume.getSize());
-        		_usageEventDao.persist(usageEvent);
-        		_volumeHostDao.remove(volumeHostVO.getId());
-        		txn.commit();
-        	}
-        	
-        	success = result;
-        } catch (StorageUnavailableException e) {
-        	processEvent(volume, Event.CopyFailed);
-        	throw e;
-        } finally {
-        	if (!success) {
-        		processEvent(volume, Event.CopyFailed);
-        		throw new ConcurrentOperationException("Failed to copy volume: " + volume);
-        	}
-        }
-    }
-    
-    @Override
-    @DB
-    public VolumeVO createVolume(VolumeVO volume, long VMTemplateId, DiskOfferingVO diskOffering,
-             HypervisorType hyperType, StoragePool assignedPool) throws StorageUnavailableException, ConcurrentOperationException {
-         Long existingPoolId = null;
-    	 existingPoolId = volume.getPoolId();
-         
-    	 if (existingPoolId == null && assignedPool == null) {
-    		 throw new StorageUnavailableException("Volume has no pool associate and also no storage pool assigned in DeployDestination, Unable to create.", 
-    				 								Volume.class, volume.getId());
-    	 }
-    	 
-    	 if (assignedPool == null) {
-    		 if (s_logger.isDebugEnabled()) {
-                 s_logger.debug("No need to recreate the volume: " + volume + ", since it already has a pool assigned: " + volume.getPoolId() + ", adding disk to VM");
-             }
-             StoragePoolVO pool = (StoragePoolVO)_storagePoolMgr.getStoragePoolById(volume.getPoolId());
-             return volume;
-    	 }
-    	 
-    	 boolean needToCreateVolume = false;
-    	 boolean needToRecreateVolume = false;
-    	 boolean needToMigrateVolume = false;
-    	 boolean needToCopyFromSec = false;
-    	 Volume.State state = volume.getState();
-    	 if (state == Volume.State.Allocated || state == Volume.State.Creating) {
-        	 needToCreateVolume = true;
-         } else if (state == Volume.State.UploadOp) {
-        	 needToCopyFromSec = true;
-         }
-
-    	 if (volume.isRecreatable()) {
-    		 if (s_logger.isDebugEnabled()) {
-    			 s_logger.debug("Volume " + volume + " will be recreated on storage pool " + assignedPool + " assigned by deploymentPlanner");
-    		 }
-    		 if (volume.getPoolId() == null) {
-    			 needToCreateVolume = true;
-    		 } else {
-    			 needToRecreateVolume = true;
-    		 }
-    	 } else {
-    		 if (assignedPool.getId() != volume.getPoolId()) {
-    			 if (s_logger.isDebugEnabled()) {
-    				 s_logger.debug("Mismatch in storage pool " + assignedPool + " assigned by deploymentPlanner and the one associated with volume " + volume);
-    			 }
-    			 if (diskOffering.getUseLocalStorage()) {
-    				 throw new StorageUnavailableException("Can't recreate volume: " + volume + " on local storage", Volume.class, volume.getId());
-    			 } else {
-    				 if (s_logger.isDebugEnabled()) {
-    	        		 s_logger.debug("Shared volume " + volume + " will be migrated on storage pool " + assignedPool + " assigned by deploymentPlanner");
-    	        	 }
-    				needToMigrateVolume = true;
-    			 }
-    		 } else {
-    			 return volume;
-    		 }
-    	 }
-    	 
-    	 VolumeVO newVol = volume;
-    	 if (needToCreateVolume || needToRecreateVolume) {
-    		 if (needToRecreateVolume) {
-    			 newVol = switchVolume(volume, VMTemplateId);
-    		 }
-    		 newVol = createVolume(newVol, diskOffering, hyperType, assignedPool);
-    	 } else if (needToMigrateVolume) {
-    		 List<Volume> volumesToMigrate = new ArrayList<Volume>();
-    		 volumesToMigrate.add(volume);
-    		 migrateVolumes(volumesToMigrate, assignedPool);
-    		 
-         } else if (needToCopyFromSec) {
-        	 copyVolumeFromSec(volume, assignedPool);
-         }
-    	 
-    	 newVol = _volumeDao.findById(volume.getId());
-    	 return newVol;
-    }
-    
-    /**
-     * Give a volume in allocated state, created on specified storage
-     * @param toBeCreated
-     * @param offering
-     * @param hypervisorType
-     * @param sPool
-     * @return
-     * @throws StorageUnavailableException
-     */
-    private VolumeVO createVolume(VolumeVO toBeCreated, DiskOfferingVO offering, HypervisorType hypervisorType,
-            StoragePool sPool) throws StorageUnavailableException, ConcurrentOperationException {
-        if (sPool == null) {
-        	throw new StorageUnavailableException("can't create volume: " + toBeCreated + " on a empty storage", Volume.class, toBeCreated.getId());
-        }
-        
-        if (toBeCreated == null) {
-        	throw new StorageUnavailableException("volume can't be null", Volume.class, toBeCreated.getId());
-        }
-        
-        if (s_logger.isDebugEnabled()) {
-            s_logger.debug("Creating volume: " + toBeCreated + " on pool: " + sPool);
-        }
-         
-        DiskProfile diskProfile = new DiskProfile(toBeCreated, offering, hypervisorType);
-        
-        toBeCreated.setPoolId(sPool.getId());
-        try {
-        	processEvent(toBeCreated, Volume.Event.CreateRequested);
-        } catch (NoTransitionException e) {
-        	throw new ConcurrentOperationException("Unable to request a create operation on volume " + toBeCreated);
-        }
-
-        boolean createdSuccessed = false;
-        try {
-        	VMTemplateVO template = null;
-        	String templateOnStoragePath = null;
-        	if (toBeCreated.getTemplateId() != null) {
-        		template = _templateDao.findById(toBeCreated.getTemplateId());
-        		templateOnStoragePath = _templateMgr.prepareTemplateOnPool(template, sPool);
-        	}
-        	
-        	CreateCommand cmd = null;
-        	cmd = new CreateCommand(diskProfile, templateOnStoragePath, new StorageFilerTO(sPool));
-
-        	Answer answer = _storagePoolMgr.sendToPool(sPool, null, cmd);
-        	if (answer.getResult()) {
-        		CreateAnswer createAnswer = (CreateAnswer) answer;
-        		VolumeTO created = createAnswer.getVolume();
-        		
-        		toBeCreated.setFolder(sPool.getPath());
-        		toBeCreated.setPath(created.getPath());
-        		toBeCreated.setSize(created.getSize());
-        		toBeCreated.setPoolType(sPool.getPoolType());
-        		toBeCreated.setPoolId(sPool.getId());
-        		toBeCreated.setPodId(sPool.getPodId());
-        		
-        		try {
-        			processEvent(toBeCreated, Volume.Event.OperationSucceeded);
-        			createdSuccessed = true;
-        		} catch (NoTransitionException e) {
-        			throw new ConcurrentOperationException("Unable to update volume state: " + e.toString());
-        		}
-        	}
-        	return toBeCreated;
-        } finally {
-        	if (createdSuccessed == false) {
-        		try {
-        			processEvent(toBeCreated, Volume.Event.OperationFailed);
-        		} catch (NoTransitionException e1) {
-        			throw new ConcurrentOperationException("Unable to update volume state: " + e1.toString());
-        		}
-        	}
-        }
-    }
-    
-    @DB
-    private VolumeVO createVolume1(VolumeVO volume, VirtualMachineProfile<? extends VirtualMachine> vm, VMTemplateVO template, DataCenterVO dc, HostPodVO pod, Long clusterId, ServiceOfferingVO offering, DiskOfferingVO diskOffering,
-            List<StoragePoolVO> avoids, long size, HypervisorType hyperType) {
-        StoragePoolVO pool = null;
-        final HashSet<StoragePool> avoidPools = new HashSet<StoragePool>(avoids);
-
-        try {
-            processEvent(volume, Volume.Event.CreateRequested);
-        } catch (NoTransitionException e) {
-            s_logger.debug("Unable to update volume state: " + e.toString());
-            return null;
-        }
-
-        if (diskOffering != null && diskOffering.isCustomized()) {
-            diskOffering.setDiskSize(size);
-        }
-        DiskProfile dskCh = null;
-        if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO != template.getFormat()) {
-            dskCh = createDiskCharacteristics(volume, template, dc, offering);
-        } else {
-            dskCh = createDiskCharacteristics(volume, template, dc, diskOffering);
-        }
-
-        dskCh.setHyperType(hyperType);
-
-        VolumeTO created = null;
-        int retry = _retry;
-        while (--retry >= 0) {
-            created = null;
-
-            long podId = pod.getId();
-            pod = _podDao.findById(podId);
-            if (pod == null) {
-                s_logger.warn("Unable to find pod " + podId + " when create volume " + volume.getName());
-                break;
-            }
-
-            pool = findStoragePool(dskCh, dc, pod, clusterId, vm, avoidPools);
-            if (pool == null) {
-                s_logger.warn("Unable to find storage poll when create volume " + volume.getName());
-                break;
-            }
-
-            avoidPools.add(pool);
-            if (s_logger.isDebugEnabled()) {
-                s_logger.debug("Trying to create " + volume + " on " + pool);
-            }
-
-            CreateCommand cmd = null;
-            VMTemplateStoragePoolVO tmpltStoredOn = null;
-
-            for (int i = 0; i < 2; i++) {
-                if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO != template.getFormat()) {
-                    tmpltStoredOn = _tmpltMgr.prepareTemplateForCreate(template, pool);
-                    if (tmpltStoredOn == null) {
-                        continue;
-                    }
-                    cmd = new CreateCommand(dskCh, tmpltStoredOn.getLocalDownloadPath(), new StorageFilerTO(pool));
-                } else {
-                    if (volume.getVolumeType() == Type.ROOT && Storage.ImageFormat.ISO == template.getFormat()) {
-                        VMTemplateHostVO tmpltHostOn = _tmpltMgr.prepareISOForCreate(template, pool);
-                        if (tmpltHostOn == null) {
-                            throw new CloudRuntimeException("Did not find ISO in secondry storage in zone " + pool.getDataCenterId());
-                        }
-                    }
-                    cmd = new CreateCommand(dskCh, new StorageFilerTO(pool));
-                }
-
-                try {
-                    Answer answer = sendToPool(pool, cmd);
-                    if (answer != null && answer.getResult()) {
-                        created = ((CreateAnswer) answer).getVolume();
-                        break;
-                    }
-
-                    if (tmpltStoredOn != null && answer != null && (answer instanceof CreateAnswer) && ((CreateAnswer) answer).templateReloadRequested()) {
-                        if (!_tmpltMgr.resetTemplateDownloadStateOnPool(tmpltStoredOn.getId())) {
-                            break; // break out of template-redeploy retry loop
-                        }
-                    } else {
-                        break;
-                    }
-                } catch (StorageUnavailableException e) {
-                    s_logger.debug("Storage unavailable for " + pool.getId());
-                    break; // break out of template-redeploy retry loop
-                }
-            }
-
-            if (created != null) {
-                break;
-            }
-
-            s_logger.debug("Retrying the create because it failed on pool " + pool);
-        }
-
-        if (created == null) {
-            return null;
-        } else {
-            volume.setFolder(pool.getPath());
-            volume.setPath(created.getPath());
-            volume.setSize(created.getSize());
-            volume.setPoolType(pool.getPoolType());
-            volume.setPoolId(pool.getId());
-            volume.setPodId(pod.getId());
-            try {
-                processEvent(volume, Volume.Event.OperationSucceeded);
-            } catch (NoTransitionException e) {
-                s_logger.debug("Unable to update volume state: " + e.toString());
-                return null;
-            }
-            return volume;
-        }
-    }
-    
-    @DB
-    public boolean migrateVolumes(List<Volume> volumes, StoragePool destPool) throws ConcurrentOperationException {
-        Transaction txn = Transaction.currentTxn();
-        txn.start();
-
-        boolean transitResult = false;
-        long checkPointTaskId = -1;
-        try {
-            List<Long> volIds = new ArrayList<Long>();
-            for (Volume volume : volumes) {
-                if (!_snapshotMgr.canOperateOnVolume((VolumeVO) volume)) {
-                    throw new CloudRuntimeException("There are snapshots creating on this volume, can not move this volume");
-                }
-
-                try {
-                    if (!processEvent(volume, Volume.Event.MigrationRequested)) {
-                        throw new ConcurrentOperationException("Failed to transit volume state");
-                    }
-                } catch (NoTransitionException e) {
-                    s_logger.debug("Failed to set state into migrate: " + e.toString());
-                    throw new CloudRuntimeException("Failed to set state into migrate: " + e.toString());
-                }
-                volIds.add(volume.getId());
-            }
-
-            checkPointTaskId = _checkPointMgr.pushCheckPoint(new StorageMigrationCleanupMaid(StorageMigrationCleanupMaid.StorageMigrationState.MIGRATING, volIds));
-            transitResult = true;
-        } finally {
-            if (!transitResult) {
-                txn.rollback();
-            } else {
-                txn.commit();
-            }
-        }
-
-        // At this stage, nobody can modify volumes. Send the copyvolume command
-        List<Pair<StoragePoolVO, DestroyCommand>> destroyCmds = new ArrayList<Pair<StoragePoolVO, DestroyCommand>>();
-        List<CopyVolumeAnswer> answers = new ArrayList<CopyVolumeAnswer>();
-        try {
-            for (Volume volume : volumes) {
-                String secondaryStorageURL = getSecondaryStorageURL(volume.getDataCenterId());
-                StoragePoolVO srcPool = _storagePoolDao.findById(volume.getPoolId());
-                CopyVolumeCommand cvCmd = new CopyVolumeCommand(volume.getId(), volume.getPath(), srcPool, secondaryStorageURL, true, _copyvolumewait);
-                CopyVolumeAnswer cvAnswer;
-                try {
-                    cvAnswer = (CopyVolumeAnswer) sendToPool(srcPool, cvCmd);
-                } catch (StorageUnavailableException e1) {
-                    throw new CloudRuntimeException("Failed to copy the volume from the source primary storage pool to secondary storage.", e1);
-                }
-
-                if (cvAnswer == null || !cvAnswer.getResult()) {
-                    throw new CloudRuntimeException("Failed to copy the volume from the source primary storage pool to secondary storage.");
-                }
-
-                String secondaryStorageVolumePath = cvAnswer.getVolumePath();
-
-                // Copy the volume from secondary storage to the destination storage
-                // pool
-                cvCmd = new CopyVolumeCommand(volume.getId(), secondaryStorageVolumePath, destPool, secondaryStorageURL, false, _copyvolumewait);
-                try {
-                    cvAnswer = (CopyVolumeAnswer) sendToPool(destPool, cvCmd);
-                } catch (StorageUnavailableException e1) {
-                    throw new CloudRuntimeException("Failed to copy the volume from secondary storage to the destination primary storage pool.");
-                }
-
-                if (cvAnswer == null || !cvAnswer.getResult()) {
-                    throw new CloudRuntimeException("Failed to copy the volume from secondary storage to the destination primary storage pool.");
-                }
-
-                answers.add(cvAnswer);
-                destroyCmds.add(new Pair<StoragePoolVO, DestroyCommand>(srcPool, new DestroyCommand(srcPool, volume, null)));
-            }
-        } finally {
-            if (answers.size() != volumes.size()) {
-                // this means one of copying volume failed
-                for (Volume volume : volumes) {
-                    try {
-                        processEvent(volume, Volume.Event.OperationFailed);
-                    } catch (NoTransitionException e) {
-                        s_logger.debug("Failed to change volume state: " + e.toString());
-                    }
-                }
-                _checkPointMgr.popCheckPoint(checkPointTaskId);
-            } else {
-                // Need a transaction, make sure all the volumes get migrated to new storage pool
-                txn = Transaction.currentTxn();
-                txn.start();
-
-                transitResult = false;
-                try {
-                    for (int i = 0; i < volumes.size(); i++) {
-                        CopyVolumeAnswer answer = answers.get(i);
-                        VolumeVO volume = (VolumeVO) volumes.get(i);
-                        Long oldPoolId = volume.getPoolId();
-                        volume.setPath(answer.getVolumePath());
-                        volume.setFolder(destPool.getPath());
-                        volume.setPodId(destPool.getPodId());
-                        volume.setPoolId(destPool.getId());
-                        volume.setLastPoolId(oldPoolId);
-                        volume.setPodId(destPool.getPodId());
-                        try {
-                            processEvent(volume, Volume.Event.OperationSucceeded);
-                        } catch (NoTransitionException e) {
-                            s_logger.debug("Failed to change volume state: " + e.toString());
-                            throw new CloudRuntimeException("Failed to change volume state: " + e.toString());
-                        }
-                    }
-                    transitResult = true;
-                    try {
-                        _checkPointMgr.popCheckPoint(checkPointTaskId);
-                    } catch (Exception e) {
-
-                    }
-                } finally {
-                    if (!transitResult) {
-                        txn.rollback();
-                    } else {
-                        txn.commit();
-                    }
-                }
-
-            }
-        }
-
-        // all the volumes get migrated to new storage pool, need to delete the copy on old storage pool
-        for (Pair<StoragePoolVO, DestroyCommand> cmd : destroyCmds) {
-            try {
-                Answer cvAnswer = _storagePoolMgr.sendToPool(cmd.first(), cmd.second());
-            } catch (StorageUnavailableException e) {
-                s_logger.debug("Unable to delete the old copy on storage pool: " + e.toString());
-            }
-        }
-        return true;
-    }
-    
-    @Override
-    public boolean volumeInactive(VolumeVO volume) {
-        Long vmId = volume.getInstanceId();
-        if (vmId != null) {
-            UserVm vm = _userVmDao.findById(vmId);
-            if (vm == null) {
-                return true;
-            }
-            State state = vm.getState();
-            if (state.equals(State.Stopped) || state.equals(State.Destroyed)) {
-                return true;
-            }
-        }
-        return false;
-    }
-    
-    @Override
-    public String getVmNameOnVolume(VolumeVO volume) {
-        Long vmId = volume.getInstanceId();
-        if (vmId != null) {
-            VMInstanceVO vm = _vmInstanceDao.findById(vmId);
-
-            if (vm == null) {
-                return null;
-            }
-            return vm.getInstanceName();
-        }
-        return null;
-    }
-    
-    @Override
-    public boolean volumeOnSharedStoragePool(VolumeVO volume) {
-    	boolean result = false;
-    	if (volume.getState() != Volume.State.Ready) {
-    		//if it's not ready, we don't care
-    		result = true;
-    	}
-    	
-        Long poolId = volume.getPoolId();
-        if (poolId == null) {
-            result = false;
-        } else {
-            StoragePoolVO pool = _storagePoolDao.findById(poolId);
-
-            if (pool == null) {
-                result = false;
-            } else {
-                result = pool.isShared();
-            }
-        }
-        
-        if (!result) {
-        	throw new InvalidParameterValueException("Please specify a volume that has been created on a shared storage pool.");
-        }
-        
-        return result;
-    }
-    
-    public String getRandomVolumeName() {
-        return UUID.randomUUID().toString();
-    }
-    
-    @Override
-    public VolumeVO moveVolume(VolumeVO volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId, HypervisorType dataDiskHyperType) throws ConcurrentOperationException {
-
-        // Find a destination storage pool with the specified criteria
-        DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
-        DiskProfile dskCh = new DiskProfile(volume.getId(), volume.getVolumeType(), volume.getName(), diskOffering.getId(), diskOffering.getDiskSize(), diskOffering.getTagsArray(),
-                diskOffering.getUseLocalStorage(), diskOffering.isRecreatable(), null);
-        dskCh.setHyperType(dataDiskHyperType);
-        DataCenterVO destPoolDataCenter = _dcDao.findById(destPoolDcId);
-        HostPodVO destPoolPod = _podDao.findById(destPoolPodId);
-        StoragePoolVO destPool = findStoragePool(dskCh, destPoolDataCenter, destPoolPod, destPoolClusterId, null, new HashSet<StoragePool>());
-        String secondaryStorageURL = getSecondaryStorageURL(volume.getDataCenterId());
-
-        if (destPool == null) {
-            throw new CloudRuntimeException("Failed to find a storage pool with enough capacity to move the volume to.");
-        }
-        if (secondaryStorageURL == null) {
-            throw new CloudRuntimeException("Failed to find secondary storage.");
-        }
-
-        List<Volume> vols = new ArrayList<Volume>();
-        vols.add(volume);
-        migrateVolumes(vols, destPool);
-        return _volumeDao.findById(volume.getId());
-    }
-    
-    
-    public boolean validateVolume(Account caller, long ownerId, Long zoneId, String volumeName, String url, String format) throws ResourceAllocationException{
-
-        // permission check
-        _accountMgr.checkAccess(caller, null, true, _accountMgr.getActiveAccountById(ownerId));
-
-        // Check that the resource limit for volumes won't be exceeded
-        _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(ownerId), ResourceType.volume);
-        
-
-        // Verify that zone exists
-        DataCenterVO zone = _dcDao.findById(zoneId);
-        if (zone == null) {
-            throw new InvalidParameterValueException("Unable to find zone by id " + zoneId);
-        }
-
-        // Check if zone is disabled
-        if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) {
-            throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zoneId);
-        }
-        
+
+	@Override
+	public String getVmNameOnVolume(VolumeVO volume) {
+		Long vmId = volume.getInstanceId();
+		if (vmId != null) {
+			VMInstanceVO vm = _vmInstanceDao.findById(vmId);
+
+			if (vm == null) {
+				return null;
+			}
+			return vm.getInstanceName();
+		}
+		return null;
+	}
+
+	@Override
+	public boolean volumeOnSharedStoragePool(VolumeVO volume) {
+		boolean result = false;
+		if (volume.getState() != Volume.State.Ready) {
+			// if it's not ready, we don't care
+			result = true;
+		}
+
+		Long poolId = volume.getPoolId();
+		if (poolId == null) {
+			result = false;
+		} else {
+			StoragePoolVO pool = _storagePoolDao.findById(poolId);
+
+			if (pool == null) {
+				result = false;
+			} else {
+				result = pool.isShared();
+			}
+		}
+
+		if (!result) {
+			throw new InvalidParameterValueException("Please specify a volume that has been created on a shared storage pool.");
+		}
+
+		return result;
+	}
+
+	public String getRandomVolumeName() {
+		return UUID.randomUUID().toString();
+	}
+
+	@Override
+	public VolumeVO moveVolume(VolumeVO volume, long destPoolDcId, Long destPoolPodId, Long destPoolClusterId, HypervisorType dataDiskHyperType) throws ConcurrentOperationException {
+
+		// Find a destination storage pool with the specified criteria
+		DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId());
+		DiskProfile dskCh = new DiskProfile(volume.getId(), volume.getVolumeType(), volume.getName(), diskOffering.getId(), diskOffering.getDiskSize(), diskOffering.getTagsArray(),
+				diskOffering.getUseLocalStorage(), diskOffering.isRecreatable(), null);
+		dskCh.setHyperType(dataDiskHyperType);
+		DataCenterVO destPoolDataCenter = _dcDao.findById(destPoolDcId);
+		HostPodVO destPoolPod = _podDao.findById(destPoolPodId);
+		StoragePoolVO destPool = _storagePoolMgr.findStoragePool(dskCh, destPoolDataCenter, destPoolPod, destPoolClusterId, null, new HashSet<StoragePool>());
+		String secondaryStorageURL = _storagePoolMgr.getSecondaryStorageURL(volume.getDataCenterId());
+
+		if (destPool == null) {
+			throw new CloudRuntimeException("Failed to find a storage pool with enough capacity to move the volume to.");
+		}
+		if (secondaryStorageURL == null) {
+			throw new CloudRuntimeException("Failed to find secondary storage.");
+		}
+
+		List<Volume> vols = new ArrayList<Volume>();
+		vols.add(volume);
+		migrateVolumes(vols, destPool);
+		return _volumeDao.findById(volume.getId());
+	}
+
+	public boolean validateVolume(Account caller, long ownerId, Long zoneId, String volumeName, String url, String format) throws ResourceAllocationException {
+
+		// permission check
+		_accountMgr.checkAccess(caller, null, true, _accountMgr.getActiveAccountById(ownerId));
+
+		// Check that the resource limit for volumes won't be exceeded
+		_resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(ownerId), ResourceType.volume);
+
+		// Verify that zone exists
+		DataCenterVO zone = _dcDao.findById(zoneId);
+		if (zone == null) {
+			throw new InvalidParameterValueException("Unable to find zone by id " + zoneId);
+		}
+
+		// Check if zone is disabled
+		if (Grouping.AllocationState.Disabled == zone.getAllocationState() && !_accountMgr.isRootAdmin(caller.getType())) {
+			throw new PermissionDeniedException("Cannot perform this operation, Zone is currently disabled: " + zoneId);
+		}
+
 		if (url.toLowerCase().contains("file://")) {
 			throw new InvalidParameterValueException("File:// type urls are currently unsupported");
 		}
-		
+
 		ImageFormat imgfmt = ImageFormat.valueOf(format.toUpperCase());
 		if (imgfmt == null) {
 			throw new IllegalArgumentException("Image format is incorrect " + format + ". Supported formats are " + EnumUtils.listValues(ImageFormat.values()));
 		}
-		
-        String userSpecifiedName = volumeName;
-        if (userSpecifiedName == null) {
-            userSpecifiedName = getRandomVolumeName();
-        }
-		if((!url.toLowerCase().endsWith("vhd"))&&(!url.toLowerCase().endsWith("vhd.zip"))
-		        &&(!url.toLowerCase().endsWith("vhd.bz2"))&&(!url.toLowerCase().endsWith("vhd.gz")) 
-		        &&(!url.toLowerCase().endsWith("qcow2"))&&(!url.toLowerCase().endsWith("qcow2.zip"))
-		        &&(!url.toLowerCase().endsWith("qcow2.bz2"))&&(!url.toLowerCase().endsWith("qcow2.gz"))
-		        &&(!url.toLowerCase().endsWith("ova"))&&(!url.toLowerCase().endsWith("ova.zip"))
-		        &&(!url.toLowerCase().endsWith("ova.bz2"))&&(!url.toLowerCase().endsWith("ova.gz"))
-		        &&(!url.toLowerCase().endsWith("img"))&&(!url.toLowerCase().endsWith("raw"))){
-		        throw new InvalidParameterValueException("Please specify a valid " + format.toLowerCase());
-		    }
-			
-			if ((format.equalsIgnoreCase("vhd") && (!url.toLowerCase().endsWith(".vhd") && !url.toLowerCase().endsWith("vhd.zip") && !url.toLowerCase().endsWith("vhd.bz2") && !url.toLowerCase().endsWith("vhd.gz") ))
-				|| (format.equalsIgnoreCase("qcow2") && (!url.toLowerCase().endsWith(".qcow2") && !url.toLowerCase().endsWith("qcow2.zip") && !url.toLowerCase().endsWith("qcow2.bz2") && !url.toLowerCase().endsWith("qcow2.gz") ))
-				|| (format.equalsIgnoreCase("ova") && (!url.toLowerCase().endsWith(".ova") && !url.toLowerCase().endsWith("ova.zip") && !url.toLowerCase().endsWith("ova.bz2") && !url.toLowerCase().endsWith("ova.gz")))
-				|| (format.equalsIgnoreCase("raw") && (!url.toLowerCase().endsWith(".img") && !url.toLowerCase().endsWith("raw")))) {
-		        throw new InvalidParameterValueException("Please specify a valid URL. URL:" + url + " is an invalid for the format " + format.toLowerCase());
+
+		String userSpecifiedName = volumeName;
+		if (userSpecifiedName == null) {
+			userSpecifiedName = getRandomVolumeName();
+		}
+		if ((!url.toLowerCase().endsWith("vhd")) && (!url.toLowerCase().endsWith("vhd.zip")) && (!url.toLowerCase().endsWith("vhd.bz2")) && (!url.toLowerCase().endsWith("vhd.gz"))
+				&& (!url.toLowerCase().endsWith("qcow2")) && (!url.toLowerCase().endsWith("qcow2.zip")) && (!url.toLowerCase().endsWith("qcow2.bz2")) && (!url.toLowerCase().endsWith("qcow2.gz"))
+				&& (!url.toLowerCase().endsWith("ova")) && (!url.toLowerCase().endsWith("ova.zip")) && (!url.toLowerCase().endsWith("ova.bz2")) && (!url.toLowerCase().endsWith("ova.gz"))
+				&& (!url.toLowerCase().endsWith("img")) && (!url.toLowerCase().endsWith("raw"))) {
+			throw new InvalidParameterValueException("Please specify a valid " + format.toLowerCase());
+		}
+
+		if ((format.equalsIgnoreCase("vhd") && (!url.toLowerCase().endsWith(".vhd") && !url.toLowerCase().endsWith("vhd.zip") && !url.toLowerCase().endsWith("vhd.bz2") && !url.toLowerCase().endsWith(
+				"vhd.gz")))
+				|| (format.equalsIgnoreCase("qcow2") && (!url.toLowerCase().endsWith(".qcow2") && !url.toLowerCase().endsWith("qcow2.zip") && !url.toLowerCase().endsWith("qcow2.bz2") && !url
+						.toLowerCase().endsWith("qcow2.gz")))
+				|| (format.equalsIgnoreCase("ova") && (!url.toLowerCase().endsWith(".ova") && !url.toLowerCase().endsWith("ova.zip") && !url.toLowerCase().endsWith("ova.bz2") && !url.toLowerCase()
+						.endsWith("ova.gz"))) || (format.equalsIgnoreCase("raw") && (!url.toLowerCase().endsWith(".img") && !url.toLowerCase().endsWith("raw")))) {
+			throw new InvalidParameterValueException("Please specify a valid URL. URL:" + url + " is an invalid for the format " + format.toLowerCase());
+		}
+		validateUrl(url);
+
+		return false;
+	}
+
+	private String validateUrl(String url) {
+		try {
+			URI uri = new URI(url);
+			if ((uri.getScheme() == null) || (!uri.getScheme().equalsIgnoreCase("http") && !uri.getScheme().equalsIgnoreCase("https") && !uri.getScheme().equalsIgnoreCase("file"))) {
+				throw new IllegalArgumentException("Unsupported scheme for url: " + url);
 			}
-        validateUrl(url);
-               
-    	return false;
-    }
-    
-    private String validateUrl(String url){
- 		try {
- 			URI uri = new URI(url);
- 			if ((uri.getScheme() == null) || (!uri.getScheme().equalsIgnoreCase("http") 
- 				&& !uri.getScheme().equalsIgnoreCase("https") && !uri.getScheme().equalsIgnoreCase("file"))) {
- 				throw new IllegalArgumentException("Unsupported scheme for url: " + url);
- 			}
-
- 			int port = uri.getPort();
- 			if (!(port == 80 || port == 443 || port == -1)) {
- 				throw new IllegalArgumentException("Only ports 80 and 443 are allowed");
- 			}
- 			String host = uri.getHost();
- 			try {
- 				InetAddress hostAddr = InetAddress.getByName(host);
- 				if (hostAddr.isAnyLocalAddress() || hostAddr.isLinkLocalAddress() || hostAddr.isLoopbackAddress() || hostAddr.isMulticastAddress()) {
- 					throw new IllegalArgumentException("Illegal host specified in url");
- 				}
- 				if (hostAddr instanceof Inet6Address) {
- 					throw new IllegalArgumentException("IPV6 addresses not supported (" + hostAddr.getHostAddress() + ")");
- 				}
- 			} catch (UnknownHostException uhe) {
- 				throw new IllegalArgumentException("Unable to resolve " + host);
- 			}
- 			
- 			return uri.toString();
- 		} catch (URISyntaxException e) {
- 			throw new IllegalArgumentException("Invalid URL " + url);
- 		}
-     	
-     }
-    
-    
-    public VolumeVO persistVolume(Account caller, long ownerId, Long zoneId, String volumeName, String url, String format) {
-     	
-        Transaction txn = Transaction.currentTxn();
-        txn.start();
-
-        VolumeVO volume = new VolumeVO(volumeName, zoneId, -1, -1, -1, new Long(-1), null, null, 0, Volume.Type.DATADISK);
-        volume.setPoolId(null);
-        volume.setDataCenterId(zoneId);
-        volume.setPodId(null);
-        volume.setAccountId(ownerId);
-        volume.setDomainId(((caller == null) ? Domain.ROOT_DOMAIN : caller.getDomainId()));
-        long diskOfferingId = _diskOfferingDao.findByUniqueName("Cloud.com-Custom").getId();
-        volume.setDiskOfferingId(diskOfferingId);        
-        //volume.setSize(size);
-        volume.setInstanceId(null);
-        volume.setUpdated(new Date());
-        volume.setDomainId((caller == null) ? Domain.ROOT_DOMAIN : caller.getDomainId());
-
-        volume = _volumeDao.persist(volume);
-        try {
+
+			int port = uri.getPort();
+			if (!(port == 80 || port == 443 || port == -1)) {
+				throw new IllegalArgumentException("Only ports 80 and 443 are allowed");
+			}
+			String host = uri.getHost();
+			try {
+				InetAddress hostAddr = InetAddress.getByName(host);
+				if (hostAddr.isAnyLocalAddress() || hostAddr.isLinkLocalAddress() || hostAddr.isLoopbackAddress() || hostAddr.isMulticastAddress()) {
+					throw new IllegalArgumentException("Illegal host specified in url");
+				}
+				if (hostAddr instanceof Inet6Address) {
+					throw new IllegalArgumentException("IPV6 addresses not supported (" + hostAddr.getHostAddress() + ")");
+				}
+			} catch (UnknownHostException uhe) {
+				throw new IllegalArgumentException("Unable to resolve " + host);
+			}
+
+			return uri.toString();
+		} catch (URISyntaxException e) {
+			throw new IllegalArgumentException("Invalid URL " + url);
+		}
+
+	}
+
+	public VolumeVO persistVolume(Account caller, long ownerId, Long zoneId, String volumeName, String url, String format) {
+
+		Transaction txn = Transaction.currentTxn();
+		txn.start();
+
+		VolumeVO volume = new VolumeVO(volumeName, zoneId, -1, -1, -1, new Long(-1), null, null, 0, Volume.Type.DATADISK);
+		volume.setPoolId(null);
+		volume.setDataCenterId(zoneId);
+		volume.setPodId(null);
+		volume.setAccountId(ownerId);
+		volume.setDomainId(((caller == null) ? Domain.ROOT_DOMAIN : caller.getDomainId()));
+		long diskOfferingId = _diskOfferingDao.findByUniqueName("Cloud.com-Custom").getId();
+		volume.setDiskOfferingId(diskOfferingId);
+		// volume.setSize(size);
+		volume.setInstanceId(null);
+		volume.setUpdated(new Date());
+		volume.setDomainId((caller == null) ? Domain.ROOT_DOMAIN : caller.getDomainId());
+
+		volume = _volumeDao.persist(volume);
+		try {
 			processEvent(volume, Event.UploadRequested);
 		} catch (NoTransitionException e) {
 			s_logger.debug("Can't create persist volume, due to " + e.toString());
 		}
-        UserContext.current().setEventDetails("Volume Id: " + volume.getId());
+		UserContext.current().setEventDetails("Volume Id: " + volume.getId());
 
-        // Increment resource count during allocation; if actual creation fails, decrement it
-        _resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.volume);
+		// Increment resource count during allocation; if actual creation fails,
+		// decrement it
+		_resourceLimitMgr.incrementResourceCount(volume.getAccountId(), ResourceType.volume);
 
-        txn.commit();
+		txn.commit();
 		return volume;
 	}
-   
-   
-    
-    @Override
-    @DB
-    @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DELETE, eventDescription = "deleting volume")
-    public boolean deleteVolume(long volumeId) throws ConcurrentOperationException {
-        Account caller = UserContext.current().getCaller();
-
-        // Check that the volume ID is valid
-        VolumeVO volume = _volumeDao.findById(volumeId);
-        if (volume == null) {
-            throw new InvalidParameterValueException("Unable to aquire volume with ID: " + volumeId);
-        }
-
-        if (!_snapshotMgr.canOperateOnVolume(volume)) {
-            throw new InvalidParameterValueException("There are snapshot creating on it, Unable to delete the volume");
-        }
-
-        // permission check
-        _accountMgr.checkAccess(caller, null, true, volume);
-
-        // Check that the volume is not currently attached to any VM
-        if (volume.getInstanceId() != null) {
-            throw new InvalidParameterValueException("Please specify a volume that is not attached to any VM.");
-        }
-
-        // Check that volume is completely Uploaded 
-        if (volume.getState() == Volume.State.UploadOp){
-        	VolumeHostVO volumeHost = _volumeHostDao.findByVolumeId(volume.getId());
-            if (volumeHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS){
-            	throw new InvalidParameterValueException("Please specify a volume that is not uploading");
-            }            
-        }
-        
-        // Check that the volume is not already destroyed
-        if (volume.getState() != Volume.State.Destroy) {
-            if (!destroyVolume(volume)) {
-                return false;
-            }
-        }
-
-        try {
-            expungeVolume(volume, false);
-        } catch (Exception e) {
-            s_logger.warn("Failed to expunge volume:", e);
-            return false;
-        }
-
-        return true;
-    }
-
-    @Override
-    public VolumeVO allocateDiskVolume(String volumeName, long zoneId, long ownerId, long domainId, long diskOfferingId, long size) {
-    	if (volumeName == null) {
-    		volumeName = getRandomVolumeName();
-    	}
-
-    	VolumeVO volume = new VolumeVO(volumeName, -1, -1, -1, -1, new Long(-1), null, null, 0, Volume.Type.DATADISK);
-    	volume.setPoolId(null);
-    	volume.setDataCenterId(zoneId);
-    	volume.setPodId(null);
-    	volume.setAccountId(ownerId);
-    	volume.setDomainId(domainId);
-    	volume.setDiskOfferingId(diskOfferingId);
-    	volume.setSize(size);
-    	volume.setInstanceId(null);
-    	volume.setUpdated(new Date());
-    	volume.setDomainId(domainId);
-
-    	volume = _volumeDao.persist(volume);
-    	return volume;
-    }
-    
-    @Override
-    public DiskProfile allocateVolume(Long vmId,
-    		Pair<? extends DiskOfferingVO, Long> rootDiskOffering,
-    		List<Pair<DiskOfferingVO, Long>> dataDiskOfferings, Long templateId, Account owner) {
-    	VirtualMachineTemplate template = _templateMgr.getTemplate(templateId);
-    	VirtualMachine vm = _vmDao.findById(vmId);
-    	DiskProfile diskProfile = null;
-    	if (template.getFormat() == ImageFormat.ISO) {
-    		diskProfile = allocateRawVolume(Type.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), rootDiskOffering.second(), vm, owner);
-    	} else if (template.getFormat() == ImageFormat.BAREMETAL) {
-    		// Do nothing
-    	} else {
-    		diskProfile = allocateTemplatedVolume(Type.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), template, vm, owner);
-    	}
-
-    	for (Pair<DiskOfferingVO, Long> offering : dataDiskOfferings) {
-    		diskProfile = allocateRawVolume(Type.DATADISK, "DATA-" + vm.getId(), offering.first(), offering.second(), vm, owner);
-    	}
-    	return diskProfile;
-    }
-    
-    public DiskProfile allocateRawVolume(Type type, String name, DiskOfferingVO offering, Long size, VirtualMachine vm, Account owner) {
-        if (size == null) {
-            size = offering.getDiskSize();
-        } else {
-            size = (size * 1024 * 1024 * 1024);
-        }
-        VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterIdToDeployIn(), owner.getDomainId(), owner.getId(), offering.getId(), size);
-        if (vm != null) {
-            vol.setInstanceId(vm.getId());
-        }
-
-        if (type.equals(Type.ROOT)) {
-            vol.setDeviceId(0l);
-        } else {
-            vol.setDeviceId(1l);
-        }
-
-        vol = _volumeDao.persist(vol);
-
-        // Save usage event and update resource count for user vm volumes
-        if (vm instanceof UserVm) {
-
-            UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), vol.getDataCenterId(), vol.getId(), vol.getName(), offering.getId(), null, size);
-            _usageEventDao.persist(usageEvent);
-
-            _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.volume);
-        }
-        return toDiskProfile(vol, offering);
-    }
-
-    public DiskProfile allocateTemplatedVolume(Type type, String name, DiskOfferingVO offering, VirtualMachineTemplate template, VirtualMachine vm, Account owner) {
-        assert (template.getFormat() != ImageFormat.ISO) : "ISO is not a template really....";
-
-        SearchCriteria<VMTemplateHostVO> sc = HostTemplateStatesSearch.create();
-        sc.setParameters("id", template.getId());
-        sc.setParameters("state", com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOADED);
-        sc.setJoinParameters("host", "dcId", vm.getDataCenterIdToDeployIn());
-        List<VMTemplateSwiftVO> tsvs = _vmTemplateSwiftDao.listByTemplateId(template.getId());
-        Long size = null;
-        if (tsvs != null && tsvs.size() > 0) {
-            size = tsvs.get(0).getSize();
-        }
-        if (size == null) {
-            List<VMTemplateHostVO> sss = _vmTemplateHostDao.search(sc, null);
-            if (sss == null || sss.size() == 0) {
-                throw new CloudRuntimeException("Template " + template.getName() + " has not been completely downloaded to zone " + vm.getDataCenterIdToDeployIn());
-            }
-            size = sss.get(0).getSize();
-        }
-
-        VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterIdToDeployIn(), owner.getDomainId(), owner.getId(), offering.getId(), size);
-        if (vm != null) {
-            vol.setInstanceId(vm.getId());
-        }
-        vol.setTemplateId(template.getId());
-
-        if (type.equals(Type.ROOT)) {
-            vol.setDeviceId(0l);
-            if (!vm.getType().equals(VirtualMachine.Type.User)) {
-                vol.setRecreatable(true);
-            }
-        } else {
-            vol.setDeviceId(1l);
-        }
-
-        vol = _volumeDao.persist(vol);
-
-        // Create event and update resource count for volumes if vm is a user vm
-        if (vm instanceof UserVm) {
-
-            Long offeringId = null;
-
-            if (offering.getType() == DiskOfferingVO.Type.Disk) {
-                offeringId = offering.getId();
-            }
-
-            UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), vol.getDataCenterId(), vol.getId(), vol.getName(), offeringId, template.getId(),
-                    vol.getSize());
-            _usageEventDao.persist(usageEvent);
-
-            _resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.volume);
-        }
-        return toDiskProfile(vol, offering);
-    }
-
-    @DB
-    protected VolumeVO switchVolume(VolumeVO existingVolume, long vmTemplateId) throws StorageUnavailableException {
-        Transaction txn = Transaction.currentTxn();
-        txn.start();
-        try {
-            processEvent(existingVolume, Volume.Event.DestroyRequested);
-        } catch (NoTransitionException e) {
-            s_logger.debug("Unable to destroy existing volume: " + e.toString());
-        }
-
-        Long templateIdToUse = null;
-        Long volTemplateId = existingVolume.getTemplateId();
-        if (volTemplateId != null && volTemplateId.longValue() != vmTemplateId) {
-            if (s_logger.isDebugEnabled()) {
-                s_logger.debug("switchVolume: Old Volume's templateId: " + volTemplateId + " does not match the VM's templateId: " + vmTemplateId + ", updating templateId in the new Volume");
-            }
-            templateIdToUse = vmTemplateId;
-        }
-        VolumeVO newVolume = allocateDuplicateVolume(existingVolume, templateIdToUse);
-        txn.commit();
-        return newVolume;
-
-    }
-    
-    public void expungeVolume(VolumeVO vol, boolean force) {
-        if (s_logger.isDebugEnabled()) {
-            s_logger.debug("Expunging " + vol);
-        }
-        
-        //Find out if the volume is present on secondary storage
-        VolumeHostVO volumeHost = _volHostDao.findByVolumeId(vol.getId());
-        if(volumeHost != null){
-        	if (volumeHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOADED){
-        		HostVO ssHost = _hostDao.findById(volumeHost.getHostId());
-        		DeleteVolumeCommand dtCommand = new DeleteVolumeCommand(ssHost.getStorageUrl(), volumeHost.getInstallPath());            
-        		Answer answer = _agentMgr.sendToSecStorage(ssHost, dtCommand);
-        		if (answer == null || !answer.getResult()) {
-        			s_logger.debug("Failed to delete " + volumeHost + " due to " + ((answer == null) ? "answer is null" : answer.getDetails()));
-        			return;
-        		}
-        	}else if(volumeHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS){									
-					s_logger.debug("Volume: " + vol.getName() + " is currently being uploaded; cant' delete it.");
-					throw new CloudRuntimeException("Please specify a volume that is not currently being uploaded.");
-        	}
-            _volHostDao.remove(volumeHost.getId());
-            _volumeDao.remove(vol.getId());
-            return;             
-        }
-        
-        String vmName = null;
-        if (vol.getVolumeType() == Type.ROOT && vol.getInstanceId() != null) {
-            VirtualMachine vm = _vmInstanceDao.findByIdIncludingRemoved(vol.getInstanceId());
-            if (vm != null) {
-                vmName = vm.getInstanceName();
-            }
-        }
-
-        String volumePath = vol.getPath();
-        Long poolId = vol.getPoolId();
-        if (poolId == null || volumePath == null || volumePath.trim().isEmpty()) {
-            if (s_logger.isDebugEnabled()) {
-                s_logger.debug("Marking volume that was never created as destroyed: " + vol);
-            }
-            _volumeDao.remove(vol.getId());
-            return;
-        }
-
-        StoragePoolVO pool = (StoragePoolVO)_storagePoolMgr.getStoragePool(poolId);
-        if (pool == null) {
-            s_logger.debug("Removing volume as storage pool is gone: " + poolId);
-            _volumeDao.remove(vol.getId());
-            return;
-        }
-
-        DestroyCommand cmd = new DestroyCommand(pool, vol, vmName);
-        boolean removeVolume = false;
-        try {
-            Answer answer = _storagePoolMgr.sendToPool(pool, cmd);
-            if (answer != null && answer.getResult()) {
-                removeVolume = true;
-            } else {
-                s_logger.info("Will retry delete of " + vol + " from " + poolId);
-            }
-        } catch (StorageUnavailableException e) {
-            if (force) {
-                s_logger.info("Storage is unavailable currently, but marking volume id=" + vol.getId() + " as expunged anyway due to force=true");
-                removeVolume = true;
-            } else {
-                s_logger.info("Storage is unavailable currently.  Will retry delete of " + vol + " from " + poolId);
-            }
-        } catch (RuntimeException ex) {
-            if (force) {
-                s_logger.info("Failed to expunge volume, but marking volume id=" + vol.getId() + " as expunged anyway " +
-                		"due to force=true. Volume failed to expunge due to ", ex);
-                removeVolume = true;
-            } else {
-                throw ex;
-            }
-        } finally {
-            if (removeVolume) {
-                _volumeDao.remove(vol.getId());
-                if (s_logger.isDebugEnabled()) {
-                    s_logger.debug("Volume successfully expunged from " + poolId);
-                }
-            }
-        }
-
-    }
-    
-    @Override
-    @DB
-    public void cleanupVolumes(long vmId) throws ConcurrentOperationException {
-        if (s_logger.isDebugEnabled()) {
-            s_logger.debug("Cleaning storage for vm: " + vmId);
-        }
-        List<VolumeVO> volumesForVm = _volumeDao.findByInstance(vmId);
-        List<VolumeVO> toBeExpunged = new ArrayList<VolumeVO>();
-        Transaction txn = Transaction.currentTxn();
-        txn.start();
-        for (VolumeVO vol : volumesForVm) {
-            if (vol.getVolumeType().equals(Type.ROOT)) {
-                // This check is for VM in Error state (volume is already destroyed)
-                if (!vol.getState().equals(Volume.State.Destroy)) {
-                    destroyVolume(vol);
-                }
-                toBeExpunged.add(vol);
-            } else {
-                if (s_logger.isDebugEnabled()) {
-                    s_logger.debug("Detaching " + vol);
-                }
-                _volumeDao.detachVolume(vol.getId());
-            }
-        }
-        txn.commit();
-
-        for (VolumeVO expunge : toBeExpunged) {
-            expungeVolume(expunge, false);
-        }
-    }
-    
-    @Override
-    public List<VolumeVO> searchForVolumes(ListVolumesCmd cmd) {
-    	//TODO: ACL code is removed
-        //Account caller = UserContext.current().getCaller();
-        List<Long> permittedAccounts = new ArrayList<Long>();
-
-        Long id = cmd.getId();
-        Long vmInstanceId = cmd.getVirtualMachineId();
-        String name = cmd.getVolumeName();
-        String keyword = cmd.getKeyword();
-        String type = cmd.getType();
-        Map<String, String> tags = cmd.getTags();
-
-        Long zoneId = cmd.getZoneId();
-        Long podId = null;
-
-        /*
-        if (_accountMgr.isAdmin(caller.getType())) {
-            podId = cmd.getPodId();
-        }
-        */
-
-        /*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();
-        */
-        Filter searchFilter = new Filter(VolumeVO.class, "created", false, cmd.getStartIndex(), cmd.getPageSizeVal());
-
-        // hack for now, this should be done better but due to needing a join I opted to
-        // do this quickly and worry about making it pretty later
-        SearchBuilder<VolumeVO> sb = _volumeDao.createSearchBuilder();
-       // _accountMgr.buildACLSearchBuilder(sb, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
-
-        sb.and("name", sb.entity().getName(), SearchCriteria.Op.LIKE);
-        sb.and("id", sb.entity().getId(), SearchCriteria.Op.EQ);
-        sb.and("volumeType", sb.entity().getVolumeType(), SearchCriteria.Op.LIKE);
-        sb.and("instanceId", sb.entity().getInstanceId(), SearchCriteria.Op.EQ);
-        sb.and("dataCenterId", sb.entity().getDataCenterId(), SearchCriteria.Op.EQ);
-        sb.and("podId", sb.entity().getPodId(), SearchCriteria.Op.EQ);
-        // Only return volumes that are not destroyed
-        sb.and("state", sb.entity().getState(), SearchCriteria.Op.NEQ);
-
-        SearchBuilder<DiskOfferingVO> diskOfferingSearch = _diskOfferingDao.createSearchBuilder();
-        diskOfferingSearch.and("systemUse", diskOfferingSearch.entity().getSystemUse(), SearchCriteria.Op.NEQ);
-        sb.join("diskOfferingSearch", diskOfferingSearch, sb.entity().getDiskOfferingId(), diskOfferingSearch.entity().getId(), JoinBuilder.JoinType.LEFTOUTER);
-
-        // display UserVM volumes only
-        SearchBuilder<VMInstanceVO> vmSearch = _vmInstanceDao.createSearchBuilder();
-        vmSearch.and("type", vmSearch.entity().getType(), SearchCriteria.Op.NIN);
-        vmSearch.or("nulltype", vmSearch.entity().getType(), SearchCriteria.Op.NULL);
-        sb.join("vmSearch", vmSearch, sb.entity().getInstanceId(), vmSearch.entity().getId(), JoinBuilder.JoinType.LEFTOUTER);
-        
-        if (tags != null && !tags.isEmpty()) {
-            SearchBuilder<ResourceTagVO> tagSearch = _resourceTagDao.createSearchBuilder();
-            for (int count=0; count < tags.size(); count++) {
-                tagSearch.or().op("key" + String.valueOf(count), tagSearch.entity().getKey(), SearchCriteria.Op.EQ);
-                tagSearch.and("value" + String.valueOf(count), tagSearch.entity().getValue(), SearchCriteria.Op.EQ);
-                tagSearch.cp();
-            }
-            tagSearch.and("resourceType", tagSearch.entity().getResourceType(), SearchCriteria.Op.EQ);
-            sb.groupBy(sb.entity().getId());
-            sb.join("tagSearch", tagSearch, sb.entity().getId(), tagSearch.entity().getResourceId(), JoinBuilder.JoinType.INNER);
-        }
-
-        // now set the SC criteria...
-        SearchCriteria<VolumeVO> sc = sb.create();
-        //_accountMgr.buildACLSearchCriteria(sc, domainId, isRecursive, permittedAccounts, listProjectResourcesCriteria);
-
-        if (keyword != null) {
-            SearchCriteria<VolumeVO> ssc = _volumeDao.createSearchCriteria();
-            ssc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%");
-            ssc.addOr("volumeType", SearchCriteria.Op.LIKE, "%" + keyword + "%");
-
-            sc.addAnd("name", SearchCriteria.Op.SC, ssc);
-        }
-
-        if (name != null) {
-            sc.setParameters("name", "%" + name + "%");
-        }
-
-        sc.setJoinParameters("diskOfferingSearch", "systemUse", 1);
-        
-        if (tags != null && !tags.isEmpty()) {
-            int count = 0;
-            sc.setJoinParameters("tagSearch", "resourceType", TaggedResourceType.Volume.toString());
-            for (String key : tags.keySet()) {
-                sc.setJoinParameters("tagSearch", "key" + String.valueOf(count), key);
-                sc.setJoinParameters("tagSearch", "value" + String.valueOf(count), tags.get(key));
-                count++;
-            }
-        }
-
-        if (id != null) {
-            sc.setParameters("id", id);
-        }
-
-        if (type != null) {
-            sc.setParameters("volumeType", "%" + type + "%");
-        }
-        if (vmInstanceId != null) {
-            sc.setParameters("instanceId", vmInstanceId);
-        }
-        if (zoneId != null) {
-            sc.setParameters("dataCenterId", zoneId);
-        }
-        if (podId != null) {
-            sc.setParameters("podId", podId);
-        }
-
-        // Don't return DomR and ConsoleProxy volumes
-        sc.setJoinParameters("vmSearch", "type", VirtualMachine.Type.ConsoleProxy, VirtualMachine.Type.SecondaryStorageVm, VirtualMachine.Type.DomainRouter);
-
-        // Only return volumes that are not destroyed
-        sc.setParameters("state", Volume.State.Destroy);
-
-        return _volumeDao.search(sc, searchFilter);
-    }
+
+	@Override
+	@DB
+	@ActionEvent(eventType = EventTypes.EVENT_VOLUME_DELETE, eventDescription = "deleting volume")
+	public boolean deleteVolume(long volumeId) throws ConcurrentOperationException {
+		Account caller = UserContext.current().getCaller();
+		VolumeVO volume = _volumeDao.findById(volumeId);
+		if (volume == null) {
+			throw new InvalidParameterValueException("Unable to aquire volume with ID: " + volumeId);
+		}
+
+		if (!_snapshotMgr.canOperateOnVolume(volume)) {
+			throw new InvalidParameterValueException("There are snapshot creating on it, Unable to delete the volume");
+		}
+
+		_accountMgr.checkAccess(caller, null, true, volume);
+
+		if (volume.getInstanceId() != null) {
+			throw new InvalidParameterValueException("Please specify a volume that is not attached to any VM.");
+		}
+
+		if (volume.getState() == Volume.State.UploadOp) {
+			VolumeHostVO volumeHost = _volumeHostDao.findByVolumeId(volume.getId());
+			if (volumeHost.getDownloadState() == VMTemplateStorageResourceAssoc.Status.DOWNLOAD_IN_PROGRESS) {
+				throw new InvalidParameterValueException("Please specify a volume that is not uploading");
+			}
+		}
+
+		if (volume.getState() != Volume.State.Destroy) {
+			destroyVolume(volume);
+		}
+
+		try {
+			expungeVolume(volume, false);
+		} catch (Exception e) {
+			s_logger.warn("Failed to expunge volume:", e);
+			return false;
+		}
+
+		return true;
+	}
+
+	@Override
+	public VolumeVO allocateDiskVolume(String volumeName, long zoneId, long ownerId, long domainId, long diskOfferingId, long size) {
+		if (volumeName == null) {
+			volumeName = getRandomVolumeName();
+		}
+
+		VolumeVO volume = new VolumeVO(volumeName, -1, -1, -1, -1, new Long(-1), null, null, 0, Volume.Type.DATADISK);
+		volume.setPoolId(null);
+		volume.setDataCenterId(zoneId);
+		volume.setPodId(null);
+		volume.setAccountId(ownerId);
+		volume.setDomainId(domainId);
+		volume.setDiskOfferingId(diskOfferingId);
+		volume.setSize(size);
+		volume.setInstanceId(null);
+		volume.setUpdated(new Date());
+		volume.setDomainId(domainId);
+
+		volume = _volumeDao.persist(volume);
+		return volume;
+	}
+
+	private DiskProfile toDiskProfile(VolumeVO vol, DiskOfferingVO offering) {
+		return new DiskProfile(vol.getId(), vol.getVolumeType(), vol.getName(), offering.getId(), vol.getSize(), offering.getTagsArray(), offering.getUseLocalStorage(), offering.isRecreatable(),
+				vol.getTemplateId());
+	}
+
+	@Override
+	public DiskProfile allocateVolume(Long vmId, Pair<? extends DiskOfferingVO, Long> rootDiskOffering, List<Pair<DiskOfferingVO, Long>> dataDiskOfferings, Long templateId, Account owner) {
+		VirtualMachineTemplate template = _templateMgr.getTemplate(templateId);
+		VirtualMachine vm = _vmDao.findById(vmId);
+		DiskProfile diskProfile = null;
+		if (template.getFormat() == ImageFormat.ISO) {
+			diskProfile = allocateRawVolume(Type.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), rootDiskOffering.second(), vm, owner);
+		} else if (template.getFormat() == ImageFormat.BAREMETAL) {
+			// Do nothing
+		} else {
+			diskProfile = allocateTemplatedVolume(Type.ROOT, "ROOT-" + vm.getId(), rootDiskOffering.first(), template, vm, owner);
+		}
+
+		for (Pair<DiskOfferingVO, Long> offering : dataDiskOfferings) {
+			diskProfile = allocateRawVolume(Type.DATADISK, "DATA-" + vm.getId(), offering.first(), offering.second(), vm, owner);
+		}
+		return diskProfile;
+	}
+
+	public DiskProfile allocateRawVolume(Type type, String name, DiskOfferingVO offering, Long size, VirtualMachine vm, Account owner) {
+		if (size == null) {
+			size = offering.getDiskSize();
+		} else {
+			size = (size * 1024 * 1024 * 1024);
+		}
+		VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterIdToDeployIn(), owner.getDomainId(), owner.getId(), offering.getId(), size);
+		if (vm != null) {
+			vol.setInstanceId(vm.getId());
+		}
+
+		if (type.equals(Type.ROOT)) {
+			vol.setDeviceId(0l);
+		} else {
+			vol.setDeviceId(1l);
+		}
+
+		vol = _volumeDao.persist(vol);
+
+		// Save usage event and update resource count for user vm volumes
+		if (vm instanceof UserVm) {
+
+			UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), vol.getDataCenterId(), vol.getId(), vol.getName(), offering.getId(), null, size);
+			_usageEventDao.persist(usageEvent);
+
+			_resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.volume);
+		}
+		return toDiskProfile(vol, offering);
+	}
+
+	public DiskProfile allocateTemplatedVolume(Type type, String name, DiskOfferingVO offering, VirtualMachineTemplate template, VirtualMachine vm, Account owner) {
+		assert (template.getFormat() != ImageFormat.ISO) : "ISO is not a template really....";
+
+		SearchCriteria<VMTemplateHostVO> sc = HostTemplateStatesSearch.create();
+		sc.setParameters("id", template.getId());
+		sc.setParameters("state", com.cloud.storage.VMTemplateStorageResourceAssoc.Status.DOWNLOADED);
+		sc.setJoinParameters("host", "dcId", vm.getDataCenterIdToDeployIn());
+		List<VMTemplateSwiftVO> tsvs = _vmTemplateSwiftDao.listByTemplateId(template.getId());
+		Long size = null;
+		if (tsvs != null && tsvs.size() > 0) {
+			size = tsvs.get(0).getSize();
+		}
+		if (size == null) {
+			List<VMTemplateHostVO> sss = _vmTemplateHostDao.search(sc, null);
+			if (sss == null || sss.size() == 0) {
+				throw new CloudRuntimeException("Template " + template.getName() + " has not been completely downloaded to zone " + vm.getDataCenterIdToDeployIn());
+			}
+			size = sss.get(0).getSize();
+		}
+
+		VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterIdToDeployIn(), owner.getDomainId(), owner.getId(), offering.getId(), size);
+		if (vm != null) {
+			vol.setInstanceId(vm.getId());
+		}
+		vol.setTemplateId(template.getId());
+
+		if (type.equals(Type.ROOT)) {
+			vol.setDeviceId(0l);
+			if (!vm.getType().equals(VirtualMachine.Type.User)) {
+				vol.setRecreatable(true);
+			}
+		} else {
+			vol.setDeviceId(1l);
+		}
+
+		vol = _volumeDao.persist(vol);
+
+		// Create event and update resource count for volumes if vm is a user vm
+		if (vm instanceof UserVm) {
+
+			Long offeringId = null;
+
+			if (offering.getType() == DiskOfferingVO.Type.Disk) {
+				offeringId = offering.getId();
+			}
+
+			UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_VOLUME_CREATE, vol.getAccountId(), vol.getDataCenterId(), vol.getId(), vol.getName(), offeringId, template.getId(),
+					vol.getSize());
+			_usageEventDao.persist(usageEvent);
+
+			_resourceLimitMgr.incrementResourceCount(vm.getAccountId(), ResourceType.volume);
+		}
+		return toDiskProfile(vol, offering);
+	}
+
+	@DB
+	protected VolumeVO switchVolume(VolumeVO existingVolume, long vmTemplateId) throws StorageUnavailableException {
+		Transaction txn = Transaction.currentTxn();
+		txn.start();
+		try {
+			processEvent(existingVolume, Volume.Event.DestroyRequested);
+		} catch (NoTransitionException e) {
+			s_logger.debug("Unable to destroy existing volume: " + e.toString());
+		}
+
+		Long templateIdToUse = null;
+		Long volTemplateId = existingVolume.getTemplateId();
+		if (volTemplateId != null && volTemplateId.longValue() != vmTemplateId) {
+			if (s_logger.isDebugEnabled()) {
+				s_logger.debug("switchVolume: Old Volume's templateId: " + volTemplateId + " does not match the VM's templateId: " + vmTemplateId + ", updating templateId in the new Volume");
+			}
+			templateIdToUse = vmTemplateId;
+		}
+		VolumeVO newVolume = allocateDuplicateVolume(existingVolume, templateIdToUse);
+		txn.commit();
+		return newVolume;
+
+	}
+
+	private void deleteVolumeFromSec(VolumeVO vol) {
+		VolumeHostV

<TRUNCATED>