cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From prachida...@apache.org
Subject [2/4] git commit: updated refs/heads/4.3 to d3520a5
Date Fri, 06 Dec 2013 21:20:18 GMT
CLOUDSTACK-5399: Add option to createVolume API to specify a VM, to place the volume appropriately
and attach immediately

Changes:

    - Added 'virtualmachineid' parameter to the createVolume API to specify a VM for the volume.
The Vm should be in 'Running' or 'Stopped' state.
    - This parameter is used only when createVolume API is called using snapshotid parameter
    - When this parameter is set, the volume is created from the snapshot in the pod/cluster
of the VM. Also the volume is then attached to the VM in the same request
    - If attach Volume fails but create has succeeded, the API errors out but the Volume created
remains available. User may attach the same volume later
    - When Vm is provided, but if no storage pool is available in the VM's pod/cluster then
the volume is not created and API fails.


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

Branch: refs/heads/4.3
Commit: 3a6adb3c581c0b34f9b675de41fcf6a54a7c1452
Parents: 5c984ea
Author: Prachi Damle <prachi@cloud.com>
Authored: Fri Dec 6 01:04:26 2013 -0800
Committer: Prachi Damle <prachi@cloud.com>
Committed: Fri Dec 6 13:18:37 2013 -0800

----------------------------------------------------------------------
 .../command/user/volume/CreateVolumeCmd.java    |  9 ++-
 .../service/VolumeOrchestrationService.java     |  3 +-
 .../orchestration/VolumeOrchestrator.java       | 58 ++++++++++++++++++--
 .../com/cloud/storage/VolumeApiServiceImpl.java | 57 +++++++++++++++++--
 4 files changed, 115 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3a6adb3c/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java b/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java
index e5c7a51..97db648 100644
--- a/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/user/volume/CreateVolumeCmd.java
@@ -20,13 +20,13 @@ import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiCommandJobType;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.ApiErrorCode;
-import org.apache.cloudstack.api.BaseAsyncCreateCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.api.response.DiskOfferingResponse;
 import org.apache.cloudstack.api.response.DomainResponse;
 import org.apache.cloudstack.api.response.ProjectResponse;
 import org.apache.cloudstack.api.response.SnapshotResponse;
+import org.apache.cloudstack.api.response.UserVmResponse;
 import org.apache.cloudstack.api.response.VolumeResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
 import org.apache.cloudstack.context.CallContext;
@@ -86,6 +86,9 @@ public class CreateVolumeCmd extends BaseAsyncCreateCmd {
     @Parameter(name=ApiConstants.DISPLAY_VOLUME, type=CommandType.BOOLEAN, description="an
optional field, whether to display the volume to the end user or not.")
     private Boolean displayVolume;
 
+    @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.UUID, entityType
= UserVmResponse.class, description = "the ID of the virtual machine; to be used with snapshot
Id, VM to which the volume gets attached after creation")
+    private Long virtualMachineId;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -135,6 +138,10 @@ public class CreateVolumeCmd extends BaseAsyncCreateCmd {
         return displayVolume;
     }
 
+    public Long getVirtualMachineId() {
+        return virtualMachineId;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3a6adb3c/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
----------------------------------------------------------------------
diff --git a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
index a773ac4..1bba479 100644
--- a/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
+++ b/engine/api/src/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java
@@ -39,6 +39,7 @@ import com.cloud.storage.Volume;
 import com.cloud.storage.Volume.Type;
 import com.cloud.template.VirtualMachineTemplate;
 import com.cloud.user.Account;
+import com.cloud.uservm.UserVm;
 import com.cloud.utils.fsm.NoTransitionException;
 import com.cloud.vm.DiskProfile;
 import com.cloud.vm.VirtualMachine;
@@ -62,7 +63,7 @@ public interface VolumeOrchestrationService {
 
     String getVmNameOnVolume(Volume volume);
 
-    VolumeInfo createVolumeFromSnapshot(Volume volume, Snapshot snapshot) throws StorageUnavailableException;
+    VolumeInfo createVolumeFromSnapshot(Volume volume, Snapshot snapshot, UserVm vm) throws
StorageUnavailableException;
 
     Volume migrateVolume(Volume volume, StoragePool destPool) throws StorageUnavailableException;
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3a6adb3c/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
----------------------------------------------------------------------
diff --git a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
index 0f9e1e4..41a3f29 100644
--- a/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
+++ b/engine/orchestration/src/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java
@@ -265,7 +265,8 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
 
     @DB
     @Override
-    public VolumeInfo createVolumeFromSnapshot(Volume volume, Snapshot snapshot) throws StorageUnavailableException
{
+    public VolumeInfo createVolumeFromSnapshot(Volume volume, Snapshot snapshot, UserVm vm)
+            throws StorageUnavailableException {
         Account account = _entityMgr.findById(Account.class, volume.getAccountId());
 
         final HashSet<StoragePool> poolsToAvoid = new HashSet<StoragePool>();
@@ -278,17 +279,62 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati
         DataCenter dc = _entityMgr.findById(DataCenter.class, volume.getDataCenterId());
         DiskProfile dskCh = new DiskProfile(volume, diskOffering, snapshot.getHypervisorType());
 
-        // Determine what pod to store the volume in
-        while ((pod = findPod(null, null, dc, account.getId(), podsToAvoid)) != null) {
-            podsToAvoid.add(pod.first().getId());
+        String msg = "There are no available storage pools to store the volume in";
+
+        if(vm != null){
+            Pod podofVM = _entityMgr.findById(Pod.class, vm.getPodIdToDeployIn());
+            if(podofVM != null){
+                pod = new Pair<Pod, Long>(podofVM, podofVM.getId());
+            }
+        }
+
+        if(vm != null && pod != null){
+            //if VM is running use the hostId to find the clusterID. If it is stopped, refer
the cluster where the ROOT volume of the VM exists.
+            Long hostId = null;
+            Long clusterId = null;
+            if(vm.getState() == State.Running){
+                hostId = vm.getHostId();
+                if(hostId != null){
+                    Host vmHost = _entityMgr.findById(Host.class, hostId);
+                    clusterId = vmHost.getClusterId();
+                }
+            }else{
+                List<VolumeVO> rootVolumesOfVm = _volsDao.findByInstanceAndType(vm.getId(),
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. Please contact Cloud Support.");
+                } else {
+                    VolumeVO rootVolumeOfVm = rootVolumesOfVm.get(0);
+                    StoragePoolVO rootDiskPool = _storagePoolDao.findById(rootVolumeOfVm.getPoolId());
+                    clusterId = (rootDiskPool == null ? null : rootDiskPool.getClusterId());
+                }
+            }
             // Determine what storage pool to store the volume in
-            while ((pool = findStoragePool(dskCh, dc, pod.first(), null, null, null, poolsToAvoid))
!= null) {
+            while ((pool = findStoragePool(dskCh, dc, pod.first(), clusterId, hostId, vm,
poolsToAvoid)) != null) {
                 break;
             }
+
+            if (pool == null) {
+                //pool could not be found in the VM's pod/cluster.
+                if(s_logger.isDebugEnabled()){
+                    s_logger.debug("Could not find any storage pool to create Volume in the
pod/cluster of the provided VM "+vm.getUuid());
+                }
+                StringBuilder addDetails = new StringBuilder(msg);
+                addDetails.append(", Could not find any storage pool to create Volume in
the pod/cluster of the VM ");
+                addDetails.append(vm.getUuid());
+                msg = addDetails.toString();
+            }
+        }else{
+            // Determine what pod to store the volume in
+            while ((pod = findPod(null, null, dc, account.getId(), podsToAvoid)) != null)
{
+                podsToAvoid.add(pod.first().getId());
+                // Determine what storage pool to store the volume in
+                while ((pool = findStoragePool(dskCh, dc, pod.first(), null, null, null,
poolsToAvoid)) != null) {
+                    break;
+                }
+            }
         }
 
         if (pool == null) {
-            String msg = "There are no available storage pools to store the volume in";
             s_logger.info(msg);
             throw new StorageUnavailableException(msg, -1);
         }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/3a6adb3c/server/src/com/cloud/storage/VolumeApiServiceImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/com/cloud/storage/VolumeApiServiceImpl.java
index 91131fe..6e01893 100644
--- a/server/src/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/com/cloud/storage/VolumeApiServiceImpl.java
@@ -572,6 +572,26 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
 
             // check snapshot permissions
             _accountMgr.checkAccess(caller, null, true, snapshotCheck);
+
+            // one step operation - create volume in VM's cluster and attach it
+            // to the VM
+            Long vmId = cmd.getVirtualMachineId();
+            if (vmId != null) {
+                // Check that the virtual machine ID is valid and it's a user vm
+                UserVmVO vm = _userVmDao.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.");
+                }
+
+                // permission check
+                _accountMgr.checkAccess(caller, null, false, vm);
+            }
+
         }
 
         if (displayVolumeEnabled == null) {
@@ -677,10 +697,28 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
 
         try {
             if (cmd.getSnapshotId() != null) {
-                volume = createVolumeFromSnapshot(volume, cmd.getSnapshotId());
+                volume = createVolumeFromSnapshot(volume, cmd.getSnapshotId(), cmd.getVirtualMachineId());
                 if (volume.getState() != Volume.State.Ready) {
                     created = false;
                 }
+
+                // if VM Id is provided, attach the volume to the VM
+                if (cmd.getVirtualMachineId() != null) {
+                    try {
+                        attachVolumeToVM(cmd.getVirtualMachineId(), volume.getId(), volume.getDeviceId());
+                    } catch (Exception ex) {
+                        StringBuilder message = new StringBuilder("Volume: ");
+                        message.append(volume.getUuid());
+                        message.append(" created successfully, but failed to attach the newly
created volume to VM: ");
+                        message.append(cmd.getVirtualMachineId());
+                        message.append(" due to error: ");
+                        message.append(ex.getMessage());
+                        if (s_logger.isDebugEnabled()) {
+                            s_logger.debug(message, ex);
+                        }
+                        throw new CloudRuntimeException(message.toString());
+                    }
+                }
             }
             return volume;
         } catch (Exception e) {
@@ -696,10 +734,16 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
         }
     }
 
-    protected VolumeVO createVolumeFromSnapshot(VolumeVO volume, long snapshotId) throws
StorageUnavailableException {
+    protected VolumeVO createVolumeFromSnapshot(VolumeVO volume, long snapshotId, Long vmId)
+            throws StorageUnavailableException {
         VolumeInfo createdVolume = null;
         SnapshotVO snapshot = _snapshotDao.findById(snapshotId);
-        createdVolume = _volumeMgr.createVolumeFromSnapshot(volume, snapshot);
+
+        UserVmVO vm = null;
+        if (vmId != null) {
+            vm = _userVmDao.findById(vmId);
+        }
+        createdVolume = _volumeMgr.createVolumeFromSnapshot(volume, snapshot, vm);
 
         UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, createdVolume.getAccountId(),
createdVolume.getDataCenterId(), createdVolume.getId(),
                 createdVolume.getName(), createdVolume.getDiskOfferingId(), null, createdVolume.getSize(),
Volume.class.getName(), createdVolume.getUuid());
@@ -981,11 +1025,16 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
     }
 
     @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();
+        return attachVolumeToVM(vmId, volumeId, deviceId);
+    }
+
+
+    @ActionEvent(eventType = EventTypes.EVENT_VOLUME_ATTACH, eventDescription = "attaching
volume", async = true)
+    public Volume attachVolumeToVM(Long vmId, Long volumeId, Long deviceId) {
         Account caller = CallContext.current().getCallingAccount();
 
         // Check that the volume ID is valid


Mime
View raw message