Updated Branches:
  refs/heads/storagerefactor 87678b852 -> 63c3634b7

refactor attachvolumetoVM


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

Branch: refs/heads/storagerefactor
Commit: 63c3634b79b74e9fcade2eddc2d0cbb31edf923d
Parents: 87678b8
Author: Edison Su <[email protected]>
Authored: Sun Aug 19 22:43:59 2012 -0700
Committer: Edison Su <[email protected]>
Committed: Sun Aug 19 22:43:59 2012 -0700

----------------------------------------------------------------------
 .../com/cloud/storage/pool/StoragePoolService.java |    6 +
 api/src/com/cloud/storage/volume/Volume.java       |    2 +
 core/src/com/cloud/storage/VolumeVO.java           |    5 +
 .../storage/orchestra/StorageOrchestraEngine.java  |    2 +
 .../orchestra/StorageOrchestraEngineImpl.java      |   87 ++---
 .../com/cloud/storage/pool/StoragePoolManager.java |    5 +
 .../cloud/storage/pool/StoragePoolManagerImpl.java |    6 +-
 .../com/cloud/storage/volume/VolumeManager.java    |    8 +-
 .../cloud/storage/volume/VolumeManagerImpl.java    |  316 ++++++++++++++-
 server/src/com/cloud/vm/UserVmManagerImpl.java     |  281 +-------------
 10 files changed, 365 insertions(+), 353 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/63c3634b/api/src/com/cloud/storage/pool/StoragePoolService.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/storage/pool/StoragePoolService.java 
b/api/src/com/cloud/storage/pool/StoragePoolService.java
index c7bfc5b..d0a24f5 100644
--- a/api/src/com/cloud/storage/pool/StoragePoolService.java
+++ b/api/src/com/cloud/storage/pool/StoragePoolService.java
@@ -18,6 +18,7 @@ package com.cloud.storage.pool;
 
 import java.net.UnknownHostException;
 import java.util.List;
+import java.util.Set;
 
 import com.cloud.api.commands.CancelPrimaryStorageMaintenanceCmd;
 import com.cloud.api.commands.CreateStoragePoolCmd;
@@ -26,13 +27,18 @@ import com.cloud.api.commands.DeletePoolCmd;
 import com.cloud.api.commands.ListVolumesCmd;
 import com.cloud.api.commands.UpdateStoragePoolCmd;
 import com.cloud.api.commands.UploadVolumeCmd;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.HostPodVO;
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.InsufficientCapacityException;
 import com.cloud.exception.PermissionDeniedException;
 import com.cloud.exception.ResourceAllocationException;
 import com.cloud.exception.ResourceInUseException;
 import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.storage.StoragePoolVO;
 import com.cloud.storage.volume.Volume;
+import com.cloud.vm.DiskProfile;
+import com.cloud.vm.VMInstanceVO;
 
 public interface StoragePoolService {
     /**

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/63c3634b/api/src/com/cloud/storage/volume/Volume.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/storage/volume/Volume.java 
b/api/src/com/cloud/storage/volume/Volume.java
index 87415a5..bb29414 100755
--- a/api/src/com/cloud/storage/volume/Volume.java
+++ b/api/src/com/cloud/storage/volume/Volume.java
@@ -147,4 +147,6 @@ public interface Volume extends ControlledEntity, BasedOn, 
StateObject<Volume.St
     public void incrUpdatedCount();
 
     public Date getUpdated();
+
+       boolean isAttachedToVm();
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/63c3634b/core/src/com/cloud/storage/VolumeVO.java
----------------------------------------------------------------------
diff --git a/core/src/com/cloud/storage/VolumeVO.java 
b/core/src/com/cloud/storage/VolumeVO.java
index 55c508a..52fa1d5 100755
--- a/core/src/com/cloud/storage/VolumeVO.java
+++ b/core/src/com/cloud/storage/VolumeVO.java
@@ -438,4 +438,9 @@ public class VolumeVO implements Volume, Identity {
     public void setUuid(String uuid) {
        this.uuid = uuid;
     }
+    
+    @Override
+    public boolean isAttachedToVm() {
+       return this.getInstanceId() != null ? true : false; 
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/63c3634b/server/src/com/cloud/storage/orchestra/StorageOrchestraEngine.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/orchestra/StorageOrchestraEngine.java 
b/server/src/com/cloud/storage/orchestra/StorageOrchestraEngine.java
index 5bad709..001d1d1 100644
--- a/server/src/com/cloud/storage/orchestra/StorageOrchestraEngine.java
+++ b/server/src/com/cloud/storage/orchestra/StorageOrchestraEngine.java
@@ -4,6 +4,7 @@ import java.util.List;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
+import com.cloud.api.commands.AttachVolumeCmd;
 import com.cloud.api.commands.CreateVolumeCmd;
 import com.cloud.capacity.CapacityVO;
 import com.cloud.deploy.DeployDestination;
@@ -33,4 +34,5 @@ public interface StorageOrchestraEngine {
        VolumeVO createVolume(CreateVolumeCmd cmd);
        VolumeVO allocVolume(CreateVolumeCmd cmd)
                        throws ResourceAllocationException;
+       Volume attachVolumeToVM(AttachVolumeCmd command);
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/63c3634b/server/src/com/cloud/storage/orchestra/StorageOrchestraEngineImpl.java
----------------------------------------------------------------------
diff --git 
a/server/src/com/cloud/storage/orchestra/StorageOrchestraEngineImpl.java 
b/server/src/com/cloud/storage/orchestra/StorageOrchestraEngineImpl.java
index 50f7ea9..78b2fcf 100644
--- a/server/src/com/cloud/storage/orchestra/StorageOrchestraEngineImpl.java
+++ b/server/src/com/cloud/storage/orchestra/StorageOrchestraEngineImpl.java
@@ -1,4 +1,4 @@
-package com.cloud.storage.orchestra;
+hpackage com.cloud.storage.orchestra;
 
 import java.util.ArrayList;
 import java.util.Date;
@@ -12,6 +12,8 @@ import javax.naming.ConfigurationException;
 import org.apache.log4j.Logger;
 
 import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.AttachVolumeAnswer;
+import com.cloud.agent.api.AttachVolumeCommand;
 import com.cloud.agent.api.CreateVolumeFromSnapshotAnswer;
 import com.cloud.agent.api.CreateVolumeFromSnapshotCommand;
 import com.cloud.agent.api.UpgradeSnapshotCommand;
@@ -21,7 +23,12 @@ import com.cloud.agent.api.storage.CreateAnswer;
 import com.cloud.agent.api.storage.CreateCommand;
 import com.cloud.agent.api.storage.DestroyCommand;
 import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.api.BaseCmd;
+import com.cloud.api.commands.AttachVolumeCmd;
 import com.cloud.api.commands.CreateVolumeCmd;
+import com.cloud.async.AsyncJobExecutor;
+import com.cloud.async.AsyncJobVO;
+import com.cloud.async.BaseAsyncJobExecutor;
 import com.cloud.configuration.Config;
 import com.cloud.configuration.ConfigurationManager;
 import com.cloud.configuration.Resource.ResourceType;
@@ -52,6 +59,7 @@ import com.cloud.storage.VMTemplateHostVO;
 import com.cloud.storage.VMTemplateVO;
 import com.cloud.storage.VolumeHostVO;
 import com.cloud.storage.VolumeVO;
+import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
 import com.cloud.storage.dao.DiskOfferingDao;
 import com.cloud.storage.dao.SnapshotDao;
 import com.cloud.storage.dao.StoragePoolDao;
@@ -91,6 +99,8 @@ import com.cloud.vm.UserVmVO;
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.VirtualMachine.State;
+import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VMInstanceDao;
 
 public class StorageOrchestraEngineImpl implements StorageOrchestraEngine, 
Manager {
@@ -115,6 +125,8 @@ public class StorageOrchestraEngineImpl implements 
StorageOrchestraEngine, Manag
        protected StoragePoolDao _storagePoolDao;
        @Inject
        protected UsageEventDao _usageEventDao;
+       @Inject
+       protected UserVmDao _userVmDao;
        
        
        
@@ -360,7 +372,8 @@ public class StorageOrchestraEngineImpl implements 
StorageOrchestraEngine, Manag
     }
     
     @Override
-    public void prepare(VirtualMachineProfile<? extends VirtualMachine> vm, 
DeployDestination dest, boolean recreate) throws StorageUnavailableException, 
InsufficientStorageCapacityException {
+    public void prepare(VirtualMachineProfile<? extends VirtualMachine> vm, 
DeployDestination dest, boolean recreate) throws StorageUnavailableException, 
InsufficientStorageCapacityException,
+                                       ConcurrentOperationException {
         if (dest == null) {
             throw new CloudRuntimeException("Unable to prepare Volume for vm 
because DeployDestination is null, vm:" + vm);
         }
@@ -377,55 +390,6 @@ public class StorageOrchestraEngineImpl implements 
StorageOrchestraEngine, Manag
             vm.addDisk(new VolumeTO(created, destPool));
         }
     }
-        
-       @Override
-    @DB
-    public VolumeVO copyVolumeFromSecToPrimary(VolumeVO volume, VMInstanceVO 
vm, VMTemplateVO template, DataCenterVO dc, HostPodVO pod, Long clusterId, 
ServiceOfferingVO offering, DiskOfferingVO diskOffering,
-            List<StoragePoolVO> avoids, long size, HypervisorType hyperType) 
throws NoTransitionException {
-       
-       final HashSet<StoragePool> avoidPools = new 
HashSet<StoragePool>(avoids);
-       DiskProfile dskCh = createDiskCharacteristics(volume, template, dc, 
diskOffering);
-       dskCh.setHyperType(vm.getHypervisorType());
-       // Find a suitable storage to create volume on 
-       StoragePoolVO destPool = findStoragePool(dskCh, dc, pod, clusterId, vm, 
avoidPools);
-       
-       // Copy the volume from secondary storage to the destination storage 
pool               
-       processEvent(volume, Event.CopyRequested);
-       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, destPool, secondaryStorageURL, false, _copyvolumewait);
-        CopyVolumeAnswer cvAnswer;
-               try {
-            cvAnswer = (CopyVolumeAnswer) sendToPool(destPool, cvCmd);
-        } catch (StorageUnavailableException e1) {
-               processEvent(volume, Event.CopyFailed);
-            throw new CloudRuntimeException("Failed to copy the volume from 
secondary storage to the destination primary storage pool.");
-        }
-
-        if (cvAnswer == null || !cvAnswer.getResult()) {
-               processEvent(volume, Event.CopyFailed);
-            throw new CloudRuntimeException("Failed to copy the volume from 
secondary storage to the destination primary storage pool.");
-        }        
-        Transaction txn = Transaction.currentTxn();
-        txn.start();        
-        volume.setPath(cvAnswer.getVolumePath());
-        volume.setFolder(destPool.getPath());
-        volume.setPodId(destPool.getPodId());
-        volume.setPoolId(destPool.getId());        
-        volume.setPodId(destPool.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();
-               return volume;
-       
-    }
-        
        
         
         @Override
@@ -544,6 +508,27 @@ public class StorageOrchestraEngineImpl implements 
StorageOrchestraEngine, Manag
         migrateVolumes(vols, destPool);
         return vol;
     }
+    
+    @Override
+    @ActionEvent(eventType = EventTypes.EVENT_VOLUME_ATTACH, eventDescription 
= "attaching volume", async = true)
+    public Volume attachVolumeToVM(AttachVolumeCmd command) {
+        Account caller = UserContext.current().getCaller();
+               Long vmId = command.getVirtualMachineId();
+        Long volumeId = command.getId();
+        Long deviceId = command.getDeviceId();
+        VolumeVO volume = _volumeDao.findById(volumeId);
+
+        if (volume == null || volume.getVolumeType() != Volume.Type.DATADISK) {
+            throw new InvalidParameterValueException("Please specify a valid 
data volume.");
+        }
+        
+        UserVmVO vm = _userVmDao.findById(vmId);
+        if (vm == null || vm.getType() != VirtualMachine.Type.User) {
+            throw new InvalidParameterValueException("Please specify a valid 
User VM.");
+        }
+        _accountMgr.checkAccess(caller, null, true, volume, vm);
+        return _volumeMgr.attachVolumeToVM(volume, vm, deviceId);
+    }
 
    
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/63c3634b/server/src/com/cloud/storage/pool/StoragePoolManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/pool/StoragePoolManager.java 
b/server/src/com/cloud/storage/pool/StoragePoolManager.java
index 0ad0bf6..35cbeae 100755
--- a/server/src/com/cloud/storage/pool/StoragePoolManager.java
+++ b/server/src/com/cloud/storage/pool/StoragePoolManager.java
@@ -18,6 +18,7 @@ package com.cloud.storage.pool;
 
 import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import com.cloud.agent.api.Answer;
 import com.cloud.agent.api.Command;
@@ -154,4 +155,8 @@ public interface StoragePoolManager extends 
StoragePoolService, Manager {
                        Account account, HashSet<StoragePool> poolsToAvoid);
 
        boolean PrepareTemplateOnPool(VMTemplateVO template, StoragePool pool);
+
+       StoragePoolVO findStoragePool(DiskProfile dskCh, DataCenterVO dc,
+                       HostPodVO pod, Long clusterId, VMInstanceVO vm,
+                       Set<StoragePool> avoid);
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/63c3634b/server/src/com/cloud/storage/pool/StoragePoolManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/pool/StoragePoolManagerImpl.java 
b/server/src/com/cloud/storage/pool/StoragePoolManagerImpl.java
index d499c29..40e68e4 100755
--- a/server/src/com/cloud/storage/pool/StoragePoolManagerImpl.java
+++ b/server/src/com/cloud/storage/pool/StoragePoolManagerImpl.java
@@ -438,7 +438,8 @@ public class StoragePoolManagerImpl implements 
StoragePoolManager, Manager, Clus
                return null;
     }
 
-    protected StoragePoolVO findStoragePool(DiskProfile dskCh, final 
DataCenterVO dc, HostPodVO pod, Long clusterId, VMInstanceVO vm, final 
Set<StoragePool> avoid) {
+    @Override
+    public StoragePoolVO findStoragePool(DiskProfile dskCh, final DataCenterVO 
dc, HostPodVO pod, Long clusterId, VMInstanceVO vm, final Set<StoragePool> 
avoid) {
 
         VirtualMachineProfile<VMInstanceVO> profile = new 
VirtualMachineProfileImpl<VMInstanceVO>(vm);
         Enumeration<StoragePoolAllocator> en = 
_storagePoolAllocators.enumeration();
@@ -2292,4 +2293,7 @@ public class StoragePoolManagerImpl implements 
StoragePoolManager, Manager, Clus
     public boolean PrepareTemplateOnPool(VMTemplateVO template, StoragePool 
pool) {
        
     }
+    
+    @O
+    
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/63c3634b/server/src/com/cloud/storage/volume/VolumeManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/volume/VolumeManager.java 
b/server/src/com/cloud/storage/volume/VolumeManager.java
index e98d78a..64ced09 100644
--- a/server/src/com/cloud/storage/volume/VolumeManager.java
+++ b/server/src/com/cloud/storage/volume/VolumeManager.java
@@ -3,6 +3,7 @@ package com.cloud.storage.volume;
 import java.util.List;
 
 import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.api.commands.AttachVolumeCmd;
 import com.cloud.api.commands.ListVolumesCmd;
 import com.cloud.dc.DataCenterVO;
 import com.cloud.dc.HostPodVO;
@@ -24,6 +25,7 @@ import com.cloud.user.Account;
 import com.cloud.utils.Pair;
 import com.cloud.utils.fsm.NoTransitionException;
 import com.cloud.vm.DiskProfile;
+import com.cloud.vm.UserVmVO;
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachineProfile;
@@ -61,9 +63,11 @@ public interface VolumeManager {
         * @param size
         * @param hyperType
         * @return volume VO if success, null otherwise
+        * @throws StorageUnavailableException 
+        * @throws ConcurrentOperationException 
         */
        VolumeVO createVolume(VolumeVO volume, long VMTemplateId, 
DiskOfferingVO diskOffering,
-            HypervisorType hyperType, StoragePool assignedPool);
+            HypervisorType hyperType, StoragePool assignedPool) throws 
StorageUnavailableException, ConcurrentOperationException;
        
        /**
         * Marks the specified volume as destroyed in the management server 
database. The expunge thread will delete the volume from its storage pool.
@@ -133,4 +137,6 @@ public interface VolumeManager {
 
        VolumeVO allocateDiskVolume(String volumeName, long zoneId, long 
ownerId,
                        long domainId, long diskOfferingId, long size);
+
+       Volume attachVolumeToVM(VolumeVO volume, UserVmVO vm, Long deviceId);
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/63c3634b/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 facb52e..c14a10b 100644
--- a/server/src/com/cloud/storage/volume/VolumeManagerImpl.java
+++ b/server/src/com/cloud/storage/volume/VolumeManagerImpl.java
@@ -10,6 +10,7 @@ import java.util.Date;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.UUID;
 
 import javax.naming.ConfigurationException;
 
@@ -17,6 +18,8 @@ import org.apache.log4j.Logger;
 
 import com.cloud.agent.AgentManager;
 import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.AttachVolumeAnswer;
+import com.cloud.agent.api.AttachVolumeCommand;
 import com.cloud.agent.api.storage.CopyVolumeAnswer;
 import com.cloud.agent.api.storage.CopyVolumeCommand;
 import com.cloud.agent.api.storage.CreateAnswer;
@@ -25,14 +28,23 @@ import com.cloud.agent.api.storage.DeleteVolumeCommand;
 import com.cloud.agent.api.storage.DestroyCommand;
 import com.cloud.agent.api.to.StorageFilerTO;
 import com.cloud.agent.api.to.VolumeTO;
+import com.cloud.api.BaseCmd;
+import com.cloud.api.commands.AttachVolumeCmd;
 import com.cloud.api.commands.CreateVolumeCmd;
 import com.cloud.api.commands.ListVolumesCmd;
+import com.cloud.async.AsyncJobExecutor;
+import com.cloud.async.AsyncJobVO;
+import com.cloud.async.BaseAsyncJobExecutor;
+import com.cloud.configuration.Config;
 import com.cloud.dc.DataCenterVO;
 import com.cloud.dc.HostPodVO;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.HostPodDao;
 import com.cloud.deploy.DeployDestination;
 import com.cloud.domain.Domain;
 import com.cloud.event.EventTypes;
 import com.cloud.event.UsageEventVO;
+import com.cloud.exception.AgentUnavailableException;
 import com.cloud.exception.ConcurrentOperationException;
 import com.cloud.exception.InsufficientStorageCapacityException;
 import com.cloud.exception.InvalidParameterValueException;
@@ -41,6 +53,7 @@ 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.hypervisor.dao.HypervisorCapabilitiesDao;
 import com.cloud.server.ResourceTag.TaggedResourceType;
 import com.cloud.service.ServiceOfferingVO;
 import com.cloud.storage.DiskOfferingVO;
@@ -49,7 +62,9 @@ import com.cloud.storage.VMTemplateHostVO;
 import com.cloud.storage.VMTemplateVO;
 import com.cloud.storage.VolumeHostVO;
 import com.cloud.storage.VolumeVO;
+import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
 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.VolumeDao;
@@ -64,6 +79,8 @@ 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.UserContext;
+import com.cloud.utils.NumbersUtil;
 import com.cloud.utils.Pair;
 import com.cloud.utils.component.Inject;
 import com.cloud.utils.component.Manager;
@@ -77,11 +94,15 @@ import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.utils.fsm.NoTransitionException;
 import com.cloud.utils.fsm.StateMachine2;
 import com.cloud.vm.DiskProfile;
+import com.cloud.vm.UserVmVO;
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.VirtualMachine.State;
+import com.cloud.vm.dao.UserVmDao;
 import com.cloud.vm.dao.VMInstanceDao;
 import com.cloud.event.ActionEvent;
+import com.cloud.event.dao.UsageEventDao;
 import com.cloud.storage.VMTemplateStorageResourceAssoc;
 import com.cloud.tags.ResourceTagVO;
 import com.cloud.tags.dao.ResourceTagDao;
@@ -91,8 +112,10 @@ 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
@@ -121,6 +144,21 @@ public class VolumeManagerImpl implements VolumeManager, 
Manager {
     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;
        
    
 
@@ -183,15 +221,64 @@ public class VolumeManagerImpl implements VolumeManager, 
Manager {
         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) {
+             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, Volume.class, volume.getId());
+                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) {
@@ -205,9 +292,12 @@ public class VolumeManagerImpl implements VolumeManager, 
Manager {
         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()) {
@@ -244,16 +334,15 @@ public class VolumeManagerImpl implements VolumeManager, 
Manager {
                 }
                 newVol = createVolume(newVol, diskOffering, hyperType, 
assignedPool);
         } else if (needToMigrateVolume) {
-                try {
-                        List<Volume> volumesToMigrate = new 
ArrayList<Volume>();
-                        volumesToMigrate.add(volume);
-                        migrateVolumes(volumesToMigrate, assignedPool);
-                        newVol = _volumeDao.findById(volume.getId());
-                } catch (ConcurrentOperationException e) {
-                        throw new CloudRuntimeException("Migration of volume " 
+ volume + " to storage pool " + assignedPool + " failed", e);
-                }
+                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;
     }
     
@@ -267,13 +356,13 @@ public class VolumeManagerImpl implements VolumeManager, 
Manager {
      * @throws StorageUnavailableException
      */
     private VolumeVO createVolume(VolumeVO toBeCreated, DiskOfferingVO 
offering, HypervisorType hypervisorType,
-            StoragePool sPool) throws StorageUnavailableException {
+            StoragePool sPool) throws StorageUnavailableException, 
ConcurrentOperationException {
         if (sPool == null) {
-               throw new CloudRuntimeException("can't create volume: " + 
toBeCreated + " on a empty storage");
+               throw new StorageUnavailableException("can't create volume: " + 
toBeCreated + " on a empty storage", Volume.class, toBeCreated.getId());
         }
         
         if (toBeCreated == null) {
-               throw new CloudRuntimeException("volume can't be null");
+               throw new StorageUnavailableException("volume can't be null", 
Volume.class, toBeCreated.getId());
         }
         
         if (s_logger.isDebugEnabled()) {
@@ -286,7 +375,7 @@ public class VolumeManagerImpl implements VolumeManager, 
Manager {
         try {
                processEvent(toBeCreated, Volume.Event.CreateRequested);
         } catch (NoTransitionException e) {
-               throw new CloudRuntimeException("Unable to request a create 
operation on volume " + toBeCreated);
+               throw new ConcurrentOperationException("Unable to request a 
create operation on volume " + toBeCreated);
         }
 
         boolean createdSuccessed = false;
@@ -317,8 +406,7 @@ public class VolumeManagerImpl implements VolumeManager, 
Manager {
                                processEvent(toBeCreated, 
Volume.Event.OperationSucceeded);
                                createdSuccessed = true;
                        } catch (NoTransitionException e) {
-                               s_logger.debug("Unable to update volume state: 
" + e.toString());
-                               return null;
+                               throw new ConcurrentOperationException("Unable 
to update volume state: " + e.toString());
                        }
                }
                return toBeCreated;
@@ -327,7 +415,7 @@ public class VolumeManagerImpl implements VolumeManager, 
Manager {
                        try {
                                processEvent(toBeCreated, 
Volume.Event.OperationFailed);
                        } catch (NoTransitionException e1) {
-                               s_logger.debug("Unable to update volume state: 
" + e1.toString());
+                               throw new ConcurrentOperationException("Unable 
to update volume state: " + e1.toString());
                        }
                }
         }
@@ -614,18 +702,30 @@ public class VolumeManagerImpl implements VolumeManager, 
Manager {
     
     @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) {
-            return false;
+            result = false;
         } else {
             StoragePoolVO pool = _storagePoolDao.findById(poolId);
 
             if (pool == null) {
-                return false;
+                result = false;
             } else {
-                return pool.isShared();
+                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() {
@@ -1263,6 +1363,9 @@ public class VolumeManagerImpl implements VolumeManager, 
Manager {
         HostTemplateStatesSearch.join("host", HostSearch, 
HostSearch.entity().getId(), HostTemplateStatesSearch.entity().getHostId(), 
JoinBuilder.JoinType.INNER);
         HostSearch.done();
         HostTemplateStatesSearch.done();
+        
+        String value = configDao.getValue(Config.CopyVolumeWait.toString());
+        _copyvolumewait = NumbersUtil.parseInt(value, 
Integer.parseInt(Config.CopyVolumeWait.getDefaultValue()));
                return false;
        }
        
@@ -1287,4 +1390,177 @@ public class VolumeManagerImpl implements 
VolumeManager, Manager {
                // TODO Auto-generated method stub
                return null;
        }
+
+       
+       private int getMaxDataVolumesSupported(UserVmVO vm) {
+               Long hostId = vm.getHostId();
+               if (hostId == null) {
+                       hostId = vm.getLastHostId();
+               }
+               HostVO host = _hostDao.findById(hostId);
+               Integer maxDataVolumesSupported = null;
+               if (host != null) {
+                       _hostDao.loadDetails(host);
+                       maxDataVolumesSupported = 
_hypervisorCapabilitiesDao.getMaxDataVolumesLimit(host.getHypervisorType(), 
host.getDetail("product_version"));
+               }
+               if (maxDataVolumesSupported == null) {
+                       maxDataVolumesSupported = 6;  // 6 data disks by 
default if nothing is specified in 'hypervisor_capabilities' table
+               }
+
+               return maxDataVolumesSupported.intValue();
+       }
+
+       private boolean reachMaxDataDisks(VolumeVO volume, UserVmVO vm) {
+               List<VolumeVO> existingDataVolumes = 
_volumeDao.findByInstanceAndType(vm.getId(), Volume.Type.DATADISK);
+               int maxDataVolumesSupported = getMaxDataVolumesSupported(vm);
+               if (existingDataVolumes.size() >= maxDataVolumesSupported) {
+                       throw new InvalidParameterValueException("The specified 
VM already has the maximum number of data disks (" + maxDataVolumesSupported + 
"). Please specify another VM.");
+               }
+               return true;
+       }
+
+       private boolean isVolumeHypevisorMatchVm(VolumeVO volume, UserVmVO vm) {
+               HypervisorType dataDiskHyperType = 
_volumeDao.getHypervisorType(volume.getId());
+               if (dataDiskHyperType != HypervisorType.None && 
vm.getHypervisorType() != dataDiskHyperType) {
+                       throw new InvalidParameterValueException("Can't attach 
a volume created by: " + dataDiskHyperType + " to a " + vm.getHypervisorType() 
+ " vm");
+               }
+       }
+       
+       private boolean isVolumeReadyToAttach(VolumeVO volume) {
+               if (!volume.isAttachedToVm()) {
+                       throw new InvalidParameterValueException("Please 
specify a volume that is not attached to any VM.");
+               }
+
+               if ( !(Volume.State.Allocated.equals(volume.getState()) || 
Volume.State.Ready.equals(volume.getState()) || 
Volume.State.UploadOp.equals(volume.getState())) ) {
+                       throw new InvalidParameterValueException("Volume state 
must be in Allocated, Ready or in Uploaded state");
+               }
+               
+               if (Volume.State.UploadOp.equals(volume.getState())) {
+                       VolumeHostVO  volHostVO = 
_volumeHostDao.findByVolumeId(volume.getId());
+                       if (volHostVO != null) {
+                               if( 
!(Status.DOWNLOADED.equals(volHostVO.getDownloadState())) ) {
+                                       throw new 
InvalidParameterValueException("Volume is not uploaded yet. Please try this 
operation once the volume is uploaded");
+                               }
+               }
+               }
+       }
+       
+       private VolumeVO prepareDataDisk(VolumeVO volume, UserVmVO vm, Long 
clusterId) throws ConcurrentOperationException, StorageUnavailableException {
+               DataCenterVO dc = 
_dcDao.findById(vm.getDataCenterIdToDeployIn());
+               HostPodVO pod = _podDao.findById(vm.getPodIdToDeployIn());
+               DiskOfferingVO diskVO = 
_diskOfferingDao.findById(volume.getDiskOfferingId());
+        DiskProfile diskProfile = new DiskProfile(volume, diskVO, 
vm.getHypervisorType());
+        
+        StoragePoolVO destStoragePool = 
_storagePoolMgr.findStoragePool(diskProfile, dc, pod, clusterId, 
(VMInstanceVO)vm, new HashSet<StoragePool>());
+        if (destStoragePool == null) {
+               throw new StorageUnavailableException("No available storage in 
dc: " + dc.getId() + ", pod: " + pod.getId() + 
+                               ", cluster " + clusterId, Volume.class, 
volume.getId());
+        }
+        
+        return createVolume(volume, vm.getTemplateId(), diskVO, 
vm.getHypervisorType(), destStoragePool);
+       }
+       
+       private long getDeviceId(VolumeVO volume, UserVmVO vm, Long assignedId) 
{
+               //allocate deviceId
+        List<VolumeVO> vols = _volumeDao.findByInstance(vm.getId());
+        if (assignedId != null) {
+            if (assignedId.longValue() > 15 || assignedId.longValue() == 0 || 
assignedId.longValue() == 3) {
+                throw new InvalidParameterValueException("deviceId should be 
1,2,4-15");
+            }
+            for (VolumeVO vol : vols) {
+                if (vol.getDeviceId().equals(assignedId)) {
+                    throw new InvalidParameterValueException("deviceId " + 
assignedId + " is used by VM " + vm.getHostName());
+                }
+            }
+        } else {
+            // allocate deviceId here
+            List<String> devIds = new ArrayList<String>();
+            for (int i = 1; i < 15; i++) {
+                devIds.add(String.valueOf(i));
+            }
+            devIds.remove("3");
+            for (VolumeVO vol : vols) {
+                devIds.remove(vol.getDeviceId().toString().trim());
+            }
+            assignedId = Long.parseLong(devIds.iterator().next());
+        }
+        return assignedId.longValue();
+       }
+       
+       private VolumeVO sendAttachCmd(UserVmVO vm, VolumeVO volume, Long 
devId) {
+               String errorMsg = "Failed to attach volume: " + 
volume.getName() + " to VM: " + vm.getHostName();
+        boolean sendCommand = (vm.getState() == State.Running);
+        AttachVolumeAnswer answer = null;
+        Long hostId = vm.getHostId();
+        if (hostId == null) {
+            hostId = vm.getLastHostId();
+            HostVO host = _hostDao.findById(hostId);
+            if (host != null && host.getHypervisorType() == 
HypervisorType.VMware) {
+                sendCommand = true;
+            }
+        }
+        
+        if (!sendCommand) {
+               _volumeDao.attachVolume(volume.getId(), vm.getId(), devId);
+               return _volumeDao.findById(volume.getId());
+        }
+
+        StoragePoolVO volumePool = 
_storagePoolDao.findById(volume.getPoolId());
+        AttachVolumeCommand cmd = new AttachVolumeCommand(true, 
vm.getInstanceName(), volume.getPoolType(), 
+                                                                       
volume.getFolder(), volume.getPath(), volume.getName(), devId, 
volume.getChainInfo());
+        cmd.setPoolUuid(volumePool.getUuid());
+
+        answer = (AttachVolumeAnswer) _agentMgr.send(hostId, cmd);
+
+        if (answer != null && answer.getResult()) {
+               _volumeDao.attachVolume(volume.getId(), vm.getId(), 
answer.getDeviceId());
+               return _volumeDao.findById(volume.getId());
+        } else {
+               if (answer != null) {
+                       String details = answer.getDetails();
+                       if (details != null && !details.isEmpty()) {
+                               errorMsg += "; " + details;
+                       }
+               }
+               throw new CloudRuntimeException(errorMsg);
+        }
+       }
+       
+       @Override
+       public Volume attachVolumeToVM(VolumeVO volume, UserVmVO vm, Long 
deviceId) {
+               if (vm.getDataCenterIdToDeployIn() != volume.getDataCenterId()) 
{
+                       throw new InvalidParameterValueException("Please 
specify a VM that is in the same zone as the volume.");
+               }
+
+        if (vm.getState() != State.Running && vm.getState() != State.Stopped) {
+            throw new InvalidParameterValueException("Please specify a VM that 
is either running or stopped.");
+        }
+        
+        long devId = getDeviceId(volume, vm, deviceId);
+        
+        isVolumeReadyToAttach(volume);
+
+        reachMaxDataDisks(volume, vm);
+        
+        isVolumeHypevisorMatchVm(volume, vm);
+        
+        volumeOnSharedStoragePool(volume);
+        
+               VolumeVO rootVolumeOfVm = null;
+               List<VolumeVO> rootVolumesOfVm = 
_volumeDao.findByInstanceAndType(vm.getId(), Volume.Type.ROOT);
+
+               rootVolumeOfVm = rootVolumesOfVm.get(0);
+
+               if (rootVolumeOfVm.getState() == Volume.State.Allocated) {
+                       return volume;
+               }
+               StoragePoolVO rootDiskPool = 
_storagePoolDao.findById(rootVolumeOfVm.getPoolId());
+        Long clusterId = rootDiskPool.getClusterId();
+               
+               
+        volume = prepareDataDisk(volume, vm, clusterId);
+
+        volume = sendAttachCmd(vm, volume, devId);
+        return volume;
+       }
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/63c3634b/server/src/com/cloud/vm/UserVmManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java 
b/server/src/com/cloud/vm/UserVmManagerImpl.java
index e0be886..501eb9b 100755
--- a/server/src/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/com/cloud/vm/UserVmManagerImpl.java
@@ -508,286 +508,7 @@ public class UserVmManagerImpl implements UserVmManager, 
UserVmService, Manager
             return status;
         }
     }
-
-    private int getMaxDataVolumesSupported(UserVmVO vm) {
-        Long hostId = vm.getHostId();
-        if (hostId == null) {
-            hostId = vm.getLastHostId();
-        }
-        HostVO host = _hostDao.findById(hostId);
-        Integer maxDataVolumesSupported = null;
-        if (host != null) {
-            _hostDao.loadDetails(host);
-            maxDataVolumesSupported = 
_hypervisorCapabilitiesDao.getMaxDataVolumesLimit(host.getHypervisorType(), 
host.getDetail("product_version"));
-        }
-        if (maxDataVolumesSupported == null) {
-            maxDataVolumesSupported = 6;  // 6 data disks by default if 
nothing is specified in 'hypervisor_capabilities' table
-        }
-
-        return maxDataVolumesSupported.intValue();
-    }
-
-    @Override
-    @ActionEvent(eventType = EventTypes.EVENT_VOLUME_ATTACH, eventDescription 
= "attaching volume", async = true)
-    public Volume attachVolumeToVM(AttachVolumeCmd command) {
-        Long vmId = command.getVirtualMachineId();
-        Long volumeId = command.getId();
-        Long deviceId = command.getDeviceId();
-        Account caller = UserContext.current().getCaller();
-
-        // Check that the volume ID is valid
-        VolumeVO volume = _volsDao.findById(volumeId);
-        // Check that the volume is a data volume
-        if (volume == null || volume.getVolumeType() != Volume.Type.DATADISK) {
-            throw new InvalidParameterValueException("Please specify a valid 
data 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 the volume is not destroyed
-        if (volume.getState() == Volume.State.Destroy) {
-            throw new InvalidParameterValueException("Please specify a volume 
that is not destroyed.");
-        }
-
-        // Check that the virtual machine ID is valid and it's a user vm
-        UserVmVO vm = _vmDao.findById(vmId);
-        if (vm == null || vm.getType() != VirtualMachine.Type.User) {
-            throw new InvalidParameterValueException("Please specify a valid 
User VM.");
-        }
-
-        // Check that the VM is in the correct state
-        if (vm.getState() != State.Running && vm.getState() != State.Stopped) {
-            throw new InvalidParameterValueException("Please specify a VM that 
is either running or stopped.");
-        }
-
-        // Check that the device ID is valid
-        if (deviceId != null) {
-            if (deviceId.longValue() == 0) {
-                throw new InvalidParameterValueException("deviceId can't be 0, 
which is used by Root device");
-            }
-        }
-
-        // Check that the number of data volumes attached to VM is less than 
that supported by hypervisor
-        List<VolumeVO> existingDataVolumes = 
_volsDao.findByInstanceAndType(vmId, Volume.Type.DATADISK);
-        int maxDataVolumesSupported = getMaxDataVolumesSupported(vm);
-        if (existingDataVolumes.size() >= maxDataVolumesSupported) {
-            throw new InvalidParameterValueException("The specified VM already 
has the maximum number of data disks (" + maxDataVolumesSupported + "). Please 
specify another VM.");
-        }
-
-        // Check that the VM and the volume are in the same zone
-        if (vm.getDataCenterIdToDeployIn() != volume.getDataCenterId()) {
-            throw new InvalidParameterValueException("Please specify a VM that 
is in the same zone as the volume.");
-        }
-
-        //permission check
-        _accountMgr.checkAccess(caller, null, true, volume, vm);
-
-        //Check if volume is stored on secondary Storage.
-        boolean isVolumeOnSec = false;
-        VolumeHostVO  volHostVO = 
_volumeHostDao.findByVolumeId(volume.getId());
-        if (volHostVO != null){
-            isVolumeOnSec = true;
-            if( !(volHostVO.getDownloadState() == Status.DOWNLOADED) ){
-                throw new InvalidParameterValueException("Volume is not 
uploaded yet. Please try this operation once the volume is uploaded");
-            }
-        }
-
-        //If the volume is Ready, check that the volume is stored on shared 
storage
-        if (!(Volume.State.Allocated.equals(volume.getState()) || 
Volume.State.UploadOp.equals(volume.getState())) && 
!_storageMgr.volumeOnSharedStoragePool(volume)) {
-            throw new InvalidParameterValueException("Please specify a volume 
that has been created on a shared storage pool.");
-        }
-
-        if ( !(Volume.State.Allocated.equals(volume.getState()) || 
Volume.State.Ready.equals(volume.getState()) || 
Volume.State.UploadOp.equals(volume.getState())) ) {
-            throw new InvalidParameterValueException("Volume state must be in 
Allocated, Ready or in Uploaded state");
-        }
-
-        VolumeVO rootVolumeOfVm = null;
-        List<VolumeVO> rootVolumesOfVm = _volsDao.findByInstanceAndType(vmId, 
Volume.Type.ROOT);
-        if (rootVolumesOfVm.size() != 1) {
-            throw new CloudRuntimeException("The VM " + vm.getHostName() + " 
has more than one ROOT volume and is in an invalid state.");
-        } else {
-            rootVolumeOfVm = rootVolumesOfVm.get(0);
-        }
-
-        HypervisorType rootDiskHyperType = vm.getHypervisorType();
-
-        HypervisorType dataDiskHyperType = 
_volsDao.getHypervisorType(volume.getId());
-        if (dataDiskHyperType != HypervisorType.None && rootDiskHyperType != 
dataDiskHyperType) {
-            throw new InvalidParameterValueException("Can't attach a volume 
created by: " + dataDiskHyperType + " to a " + rootDiskHyperType + " vm");
-        }
-
-        //allocate deviceId
-        List<VolumeVO> vols = _volsDao.findByInstance(vmId);
-        if (deviceId != null) {
-            if (deviceId.longValue() > 15 || deviceId.longValue() == 0 || 
deviceId.longValue() == 3) {
-                throw new RuntimeException("deviceId should be 1,2,4-15");
-            }
-            for (VolumeVO vol : vols) {
-                if (vol.getDeviceId().equals(deviceId)) {
-                    throw new RuntimeException("deviceId " + deviceId + " is 
used by VM " + vm.getHostName());
-                }
-            }
-        } else {
-            // allocate deviceId here
-            List<String> devIds = new ArrayList<String>();
-            for (int i = 1; i < 15; i++) {
-                devIds.add(String.valueOf(i));
-            }
-            devIds.remove("3");
-            for (VolumeVO vol : vols) {
-                devIds.remove(vol.getDeviceId().toString().trim());
-            }
-            deviceId = Long.parseLong(devIds.iterator().next());
-        }
-
-        boolean createVolumeOnBackend = true;
-        if (rootVolumeOfVm.getState() == Volume.State.Allocated) {
-            createVolumeOnBackend = false;
-            if(isVolumeOnSec){
-                throw new CloudRuntimeException("Cant attach uploaded volume 
to the vm which is not created. Please start it and then retry");
-            }
-        }
-
-        //create volume on the backend only when vm's root volume is allocated
-        if (createVolumeOnBackend) {
-            if (volume.getState().equals(Volume.State.Allocated) || 
isVolumeOnSec) {
-                /* Need to create the volume */
-                VMTemplateVO rootDiskTmplt = 
_templateDao.findById(vm.getTemplateId());
-                DataCenterVO dcVO = 
_dcDao.findById(vm.getDataCenterIdToDeployIn());
-                HostPodVO pod = _podDao.findById(vm.getPodIdToDeployIn());
-                StoragePoolVO rootDiskPool = 
_storagePoolDao.findById(rootVolumeOfVm.getPoolId());
-                ServiceOfferingVO svo = 
_serviceOfferingDao.findById(vm.getServiceOfferingId());
-                DiskOfferingVO diskVO = 
_diskOfferingDao.findById(volume.getDiskOfferingId());
-                Long clusterId = (rootDiskPool == null ? null : 
rootDiskPool.getClusterId());
-
-                if (!isVolumeOnSec){
-                    volume = _storageMgr.createVolume(volume, vm, 
rootDiskTmplt, dcVO, pod, clusterId, svo, diskVO, new 
ArrayList<StoragePoolVO>(), volume.getSize(), rootDiskHyperType);
-                }else {
-                    try {
-                        // Format of data disk should be the same as root disk
-                        if( ! 
volHostVO.getFormat().getFileExtension().equals(_storageMgr.getSupportedImageFormatForCluster(rootDiskPool.getClusterId()))
 ){
-                            throw new InvalidParameterValueException("Failed 
to attach volume to VM since volumes format " 
+volHostVO.getFormat().getFileExtension() + " is not compatible with the vm 
hypervisor type" );
-                        }
-
-                        // Check that there is some shared storage.
-                        StoragePoolVO vmRootVolumePool = 
_storagePoolDao.findById(rootVolumeOfVm.getPoolId());                           
                
-                        List<StoragePoolVO> sharedVMPools = 
_storagePoolDao.findPoolsByTags(vmRootVolumePool.getDataCenterId(), 
vmRootVolumePool.getPodId(), vmRootVolumePool.getClusterId(), null, true);
-                        if (sharedVMPools.size() == 0) {
-                            throw new CloudRuntimeException("Cannot attach 
volume since there are no shared storage pools in the VM's cluster to copy the 
uploaded volume to.");
-                        }
-
-                        volume = 
_storageMgr.copyVolumeFromSecToPrimary(volume, vm, rootDiskTmplt, dcVO, pod, 
rootDiskPool.getClusterId(), svo, diskVO, new ArrayList<StoragePoolVO>(), 
volume.getSize(), rootDiskHyperType);
-                    } catch (NoTransitionException e) {
-                        throw new CloudRuntimeException("Unable to transition 
the volume ",e);
-                    }
-                }
-
-                if (volume == null) {
-                    throw new CloudRuntimeException("Failed to create volume 
when attaching it to VM: " + vm.getHostName());
-                }
-            }
-
-            StoragePoolVO vmRootVolumePool = 
_storagePoolDao.findById(rootVolumeOfVm.getPoolId());
-            DiskOfferingVO volumeDiskOffering = 
_diskOfferingDao.findById(volume.getDiskOfferingId());
-            String[] volumeTags = volumeDiskOffering.getTagsArray();
-
-            StoragePoolVO sourcePool = 
_storagePoolDao.findById(volume.getPoolId());
-            List<StoragePoolVO> sharedVMPools = 
_storagePoolDao.findPoolsByTags(vmRootVolumePool.getDataCenterId(), 
vmRootVolumePool.getPodId(), vmRootVolumePool.getClusterId(), volumeTags, true);
-            boolean moveVolumeNeeded = true;
-            if (sharedVMPools.size() == 0) {
-                String poolType;
-                if (vmRootVolumePool.getClusterId() != null) {
-                    poolType = "cluster";
-                } else if (vmRootVolumePool.getPodId() != null) {
-                    poolType = "pod";
-                } else {
-                    poolType = "zone";
-                }
-                throw new CloudRuntimeException("There are no storage pools in 
the VM's " + poolType + " with all of the volume's tags (" + 
volumeDiskOffering.getTags() + ").");
-            } else {
-                Long sourcePoolDcId = sourcePool.getDataCenterId();
-                Long sourcePoolPodId = sourcePool.getPodId();
-                Long sourcePoolClusterId = sourcePool.getClusterId();
-                for (StoragePoolVO vmPool : sharedVMPools) {
-                    Long vmPoolDcId = vmPool.getDataCenterId();
-                    Long vmPoolPodId = vmPool.getPodId();
-                    Long vmPoolClusterId = vmPool.getClusterId();
-
-                    if (sourcePoolDcId == vmPoolDcId && sourcePoolPodId == 
vmPoolPodId && sourcePoolClusterId == vmPoolClusterId) {
-                        moveVolumeNeeded = false;
-                        break;
-                    }
-                }
-            }
-
-            if (moveVolumeNeeded) {
-                // Move the volume to a storage pool in the VM's zone, pod, or 
cluster
-                try {
-                    volume = _storageMgr.moveVolume(volume, 
vmRootVolumePool.getDataCenterId(), vmRootVolumePool.getPodId(), 
vmRootVolumePool.getClusterId(), dataDiskHyperType);
-                } catch (ConcurrentOperationException e) {
-                    throw new CloudRuntimeException(e.toString());
-                }
-            }
-        }
-
-        AsyncJobExecutor asyncExecutor = 
BaseAsyncJobExecutor.getCurrentExecutor();
-        if (asyncExecutor != null) {
-            AsyncJobVO job = asyncExecutor.getJob();
-
-            if (s_logger.isInfoEnabled()) {
-                s_logger.info("Trying to attaching volume " + volumeId + " to 
vm instance:" + vm.getId() + ", update async job-" + job.getId() + " progress 
status");
-            }
-
-            _asyncMgr.updateAsyncJobAttachment(job.getId(), "volume", 
volumeId);
-            _asyncMgr.updateAsyncJobStatus(job.getId(), 
BaseCmd.PROGRESS_INSTANCE_CREATED, volumeId);
-        }
-
-        String errorMsg = "Failed to attach volume: " + volume.getName() + " 
to VM: " + vm.getHostName();
-        boolean sendCommand = (vm.getState() == State.Running);
-        AttachVolumeAnswer answer = null;
-        Long hostId = vm.getHostId();
-        if (hostId == null) {
-            hostId = vm.getLastHostId();
-            HostVO host = _hostDao.findById(hostId);
-            if (host != null && host.getHypervisorType() == 
HypervisorType.VMware) {
-                sendCommand = true;
-            }
-        }
-
-        if (sendCommand) {
-            StoragePoolVO volumePool = 
_storagePoolDao.findById(volume.getPoolId());
-            AttachVolumeCommand cmd = new AttachVolumeCommand(true, 
vm.getInstanceName(), volume.getPoolType(), volume.getFolder(), 
volume.getPath(), volume.getName(), deviceId, volume.getChainInfo());
-            cmd.setPoolUuid(volumePool.getUuid());
-
-            try {
-                answer = (AttachVolumeAnswer) _agentMgr.send(hostId, cmd);
-            } catch (Exception e) {
-                throw new CloudRuntimeException(errorMsg + " due to: " + 
e.getMessage());
-            }
-        }
-
-        if (!sendCommand || (answer != null && answer.getResult())) {
-            // Mark the volume as attached
-            if (sendCommand) {
-                _volsDao.attachVolume(volume.getId(), vmId, 
answer.getDeviceId());
-            } else {
-                _volsDao.attachVolume(volume.getId(), vmId, deviceId);
-            }
-            return _volsDao.findById(volumeId);
-        } else {
-            if (answer != null) {
-                String details = answer.getDetails();
-                if (details != null && !details.isEmpty()) {
-                    errorMsg += "; " + details;
-                }
-            }
-            throw new CloudRuntimeException(errorMsg);
-        }
-    }
-
+    
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_VOLUME_DETACH, eventDescription 
= "detaching volume", async = true)
     public Volume detachVolumeFromVM(DetachVolumeCmd cmmd) {

Reply via email to