From 61dd85876b259be856568177cb7edb54f22a41fb Mon Sep 17 00:00:00 2001 From: Harikrishna Patnala Date: Thu, 30 Jul 2020 10:06:37 +0530 Subject: [PATCH] Fix migrate vm and volume APIs in case if datastore cluster --- .../java/com/cloud/storage/StoragePool.java | 2 ++ .../main/java/com/cloud/vm/DiskProfile.java | 4 +++ .../service/VolumeOrchestrationService.java | 2 ++ .../api/storage/PrimaryDataStoreInfo.java | 2 ++ .../api/storage/StoragePoolAllocator.java | 2 ++ .../orchestration/VolumeOrchestrator.java | 28 +++++++++++++++++++ .../AbstractStoragePoolAllocator.java | 5 ++-- .../datastore/PrimaryDataStoreImpl.java | 5 ++++ .../cloud/server/ManagementServerImpl.java | 21 +++++++++++++- .../cloud/storage/VolumeApiServiceImpl.java | 8 ++++++ .../java/com/cloud/vm/UserVmManagerImpl.java | 8 ++++++ 11 files changed, 84 insertions(+), 3 deletions(-) diff --git a/api/src/main/java/com/cloud/storage/StoragePool.java b/api/src/main/java/com/cloud/storage/StoragePool.java index 3a2d3bd8fee..6c65ca17ac9 100644 --- a/api/src/main/java/com/cloud/storage/StoragePool.java +++ b/api/src/main/java/com/cloud/storage/StoragePool.java @@ -106,4 +106,6 @@ public interface StoragePool extends Identity, InternalIdentity { Hypervisor.HypervisorType getHypervisor(); boolean isManaged(); + + Long getParent(); } diff --git a/api/src/main/java/com/cloud/vm/DiskProfile.java b/api/src/main/java/com/cloud/vm/DiskProfile.java index 2b76c682ba3..175a92afaf9 100644 --- a/api/src/main/java/com/cloud/vm/DiskProfile.java +++ b/api/src/main/java/com/cloud/vm/DiskProfile.java @@ -100,6 +100,10 @@ public class DiskProfile { return name; } + public void setTags(String[] tags) { + this.tags = tags; + } + /** * @return tags for the disk. This can be used to match it to different storage pools. */ diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java index 9458de76353..db13c1f48a8 100644 --- a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java +++ b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java @@ -84,6 +84,8 @@ public interface VolumeOrchestrationService { String getVmNameOnVolume(Volume volume); + StoragePool findChildDataStoreInDataStoreCluster(DataCenter dc, Pod pod, Long clusterId, Long hostId, VirtualMachine vm, Long datastoreClusterId); + VolumeInfo createVolumeFromSnapshot(Volume volume, Snapshot snapshot, UserVm vm) throws StorageUnavailableException; Volume migrateVolume(Volume volume, StoragePool destPool) throws StorageUnavailableException; diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java index 7f2f4dc6b85..3e072e8f1bb 100644 --- a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java +++ b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreInfo.java @@ -58,4 +58,6 @@ public interface PrimaryDataStoreInfo extends StoragePool { Map getDetails(); PrimaryDataStoreLifeCycle getLifeCycle(); + + Long getParent(); } diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/StoragePoolAllocator.java b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/StoragePoolAllocator.java index dfdbd8ab92c..46f8f5e0429 100644 --- a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/StoragePoolAllocator.java +++ b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/StoragePoolAllocator.java @@ -51,4 +51,6 @@ public interface StoragePoolAllocator extends Adapter { List allocateToPool(DiskProfile dskCh, VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo); static int RETURN_UPTO_ALL = -1; + + List reorderPools(List pools, VirtualMachineProfile vmProfile, DeploymentPlan plan); } diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java index 3e68d3a4ab0..958771c561d 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java @@ -296,6 +296,34 @@ public class VolumeOrchestrator extends ManagerBase implements VolumeOrchestrati return null; } + @Override + public StoragePool findChildDataStoreInDataStoreCluster(DataCenter dc, Pod pod, Long clusterId, Long hostId, VirtualMachine vm, Long datastoreClusterId) { + Long podId = null; + if (pod != null) { + podId = pod.getId(); + } else if (clusterId != null) { + Cluster cluster = _entityMgr.findById(Cluster.class, clusterId); + if (cluster != null) { + podId = cluster.getPodId(); + } + } + List childDatastores = _storagePoolDao.listChildStoragePoolsInDatastoreCluster(datastoreClusterId); + List suitablePools = new ArrayList(); + + for (StoragePoolVO childDatastore: childDatastores) + suitablePools.add((StoragePool)dataStoreMgr.getDataStore(childDatastore.getId(), DataStoreRole.Primary)); + + VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm); + for (StoragePoolAllocator allocator : _storagePoolAllocators) { + DataCenterDeployment plan = new DataCenterDeployment(dc.getId(), podId, clusterId, hostId, null, null); + final List poolList = allocator.reorderPools(suitablePools, profile, plan); + + if (poolList != null && !poolList.isEmpty()) { + return (StoragePool)dataStoreMgr.getDataStore(poolList.get(0).getId(), DataStoreRole.Primary); + } + } + return null; + } public Pair findPod(VirtualMachineTemplate template, ServiceOffering offering, DataCenter dc, long accountId, Set avoids) { for (PodAllocator allocator : _podAllocators) { final Pair pod = allocator.allocateTo(template, offering, dc, accountId, avoids); diff --git a/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java b/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java index 68efe16fd7a..114385bb3c2 100644 --- a/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java +++ b/engine/storage/src/main/java/org/apache/cloudstack/storage/allocator/AbstractStoragePoolAllocator.java @@ -90,7 +90,7 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement @Override public List allocateToPool(DiskProfile dskCh, VirtualMachineProfile vmProfile, DeploymentPlan plan, ExcludeList avoid, int returnUpTo) { List pools = select(dskCh, vmProfile, plan, avoid, returnUpTo); - return reOrder(pools, vmProfile, plan); + return reorderPools(pools, vmProfile, plan); } protected List reorderPoolsByCapacity(DeploymentPlan plan, @@ -156,7 +156,8 @@ public abstract class AbstractStoragePoolAllocator extends AdapterBase implement return reorderedPools; } - protected List reOrder(List pools, VirtualMachineProfile vmProfile, DeploymentPlan plan) { + @Override + public List reorderPools(List pools, VirtualMachineProfile vmProfile, DeploymentPlan plan) { if (pools == null) { return null; } diff --git a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java index 81966784be0..16c3396884e 100644 --- a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java +++ b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/PrimaryDataStoreImpl.java @@ -241,6 +241,11 @@ public class PrimaryDataStoreImpl implements PrimaryDataStore { return pdsv.isManaged(); } + @Override + public Long getParent() { + return pdsv.getParent(); + } + private boolean canCloneVolume() { return Boolean.valueOf(getDriver().getCapabilities().get(DataStoreCapabilities.CAN_CREATE_VOLUME_FROM_VOLUME.toString())); } diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index 80b54c09dfa..bed1ec00030 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -27,10 +27,13 @@ import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.TimeZone; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; +import java.util.stream.Collectors; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; @@ -1482,10 +1485,26 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe } else { suitablePools = allPools; } - + abstractDataStoreClustersList((List) allPools); + abstractDataStoreClustersList((List) suitablePools); return new Pair, List>(allPools, suitablePools); } + private void abstractDataStoreClustersList(List storagePools) { + Predicate childDatastorePredicate = pool -> (pool.getParent() != 0); + List childDatastores = storagePools.stream().filter(childDatastorePredicate).collect(Collectors.toList()); + + if (!childDatastores.isEmpty()) { + storagePools.removeAll(childDatastores); + Set parentStoragePoolIds = childDatastores.stream().map(mo -> mo.getParent()).collect(Collectors.toSet()); + for (Long parentStoragePoolId : parentStoragePoolIds) { + StoragePool parentPool = _poolDao.findById(parentStoragePoolId); + if (!storagePools.contains(parentPool)) + storagePools.add(parentPool); + } + } + } + /** * This method looks for all storage pools that are compatible with the given volume. *
    diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java index b5c33eb5fa1..e18c3553b01 100644 --- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java @@ -30,6 +30,7 @@ import java.util.concurrent.ExecutionException; import javax.inject.Inject; +import com.cloud.dc.Pod; import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd; import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd; import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd; @@ -2192,6 +2193,13 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic throw new InvalidParameterValueException("Cannot migrate volume " + vol + "to the destination storage pool " + destPool.getName() + " as the storage pool is in maintenance mode."); } + if (destPool.getPoolType() == Storage.StoragePoolType.DatastoreCluster) { + DataCenter dc = _entityMgr.findById(DataCenter.class, vol.getDataCenterId()); + Pod destPoolPod = _entityMgr.findById(Pod.class, destPool.getPodId()); + + destPool = _volumeMgr.findChildDataStoreInDataStoreCluster(dc, destPoolPod, destPool.getClusterId(), null, null, destPool.getId()); + } + if (!storageMgr.storagePoolHasEnoughSpace(Collections.singletonList(vol), destPool)) { throw new CloudRuntimeException("Storage pool " + destPool.getName() + " does not have enough space to migrate volume " + vol.getName()); } diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index ef7617699ce..09dc4e7e3b7 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -504,6 +504,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir private ResourceTagDao resourceTagDao; @Inject private TemplateOVFPropertiesDao templateOVFPropertiesDao; + @Inject + private VolumeOrchestrationService _volumeMgr; private ScheduledExecutorService _executor = null; private ScheduledExecutorService _vmIpFetchExecutor = null; @@ -5556,6 +5558,12 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir } checkDestinationHypervisorType(destPool, vm); + if (destPool.getPoolType() == Storage.StoragePoolType.DatastoreCluster) { + DataCenter dc = _entityMgr.findById(DataCenter.class, vm.getDataCenterId()); + Pod destPoolPod = _entityMgr.findById(Pod.class, destPool.getPodId()); + + destPool = _volumeMgr.findChildDataStoreInDataStoreCluster(dc, destPoolPod, destPool.getClusterId(), null, null, destPool.getId()); + } _itMgr.storageMigration(vm.getUuid(), destPool); return _vmDao.findById(vm.getId());