From 450d89094285f2363302dccc7e805466b61af9e9 Mon Sep 17 00:00:00 2001 From: Anshul Gangwar Date: Fri, 20 Jun 2014 14:32:05 +0530 Subject: [PATCH] CLOUDSTACK-6830: Fixed during VM migration, volumes on zone wide primary store requires storage migration resulting in failure of VM migration. This also improves the hostsformigration api. Firstly we were trying to list all hosts and then finding suitable storage pools for all volumes and then we were checking whether vm migration requires storage migration to that host. Now the process is updated. We are checking for only those volumes which are not in zone wide primary store. We are verifying by comparing volumes->poolid->clusterid to host clusterid. If it uses local or clusterids are different then verifying whether host has suitable storage pools for the volume of the vm to be migrated too. --- .../cloud/vm/VirtualMachineManagerImpl.java | 16 +++- .../cloud/server/ManagementServerImpl.java | 89 ++++++------------- 2 files changed, 42 insertions(+), 63 deletions(-) diff --git a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java index d0fcd4a7c52..728f04c5531 100755 --- a/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/com/cloud/vm/VirtualMachineManagerImpl.java @@ -41,6 +41,8 @@ import javax.ejb.Local; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.log4j.Logger; + import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; @@ -69,7 +71,6 @@ import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.cloudstack.utils.identity.ManagementServerNode; -import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; @@ -160,6 +161,7 @@ import com.cloud.resource.ResourceManager; import com.cloud.service.ServiceOfferingVO; import com.cloud.service.dao.ServiceOfferingDao; import com.cloud.storage.DiskOfferingVO; +import com.cloud.storage.ScopeType; import com.cloud.storage.Storage.ImageFormat; import com.cloud.storage.StoragePool; import com.cloud.storage.Volume; @@ -1827,8 +1829,16 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac } if (fromHost.getClusterId().longValue() != dest.getCluster().getId()) { - s_logger.info("Source and destination host are not in same cluster, unable to migrate to host: " + dest.getHost().getId()); - throw new CloudRuntimeException("Source and destination host are not in same cluster, unable to migrate to host: " + dest.getHost().getId()); + List volumes = _volsDao.findCreatedByInstance(vm.getId()); + for (VolumeVO volume : volumes) { + if (!(_storagePoolDao.findById(volume.getPoolId())).getScope().equals(ScopeType.ZONE)) { + s_logger.info("Source and destination host are not in same cluster and all volumes are not on zone wide primary store, unable to migrate to host: " + + dest.getHost().getId()); + throw new CloudRuntimeException( + "Source and destination host are not in same cluster and all volumes are not on zone wide primary store, unable to migrate to host: " + + dest.getHost().getId()); + } + } } VirtualMachineGuru vmGuru = getVmGuru(vm); diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index 790441bdb91..fb214b72840 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -20,7 +20,6 @@ import java.lang.reflect.Field; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; -import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; @@ -38,6 +37,9 @@ import javax.crypto.spec.SecretKeySpec; import javax.inject.Inject; import javax.naming.ConfigurationException; +import org.apache.commons.codec.binary.Base64; +import org.apache.log4j.Logger; + import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.affinity.AffinityGroupProcessor; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; @@ -507,8 +509,6 @@ import org.apache.cloudstack.storage.datastore.db.ImageStoreVO; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; import org.apache.cloudstack.utils.identity.ManagementServerNode; -import org.apache.commons.codec.binary.Base64; -import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.api.GetVncPortAnswer; @@ -1171,29 +1171,28 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe List allHosts = null; Map requiresStorageMotion = new HashMap(); DataCenterDeployment plan = null; - boolean zoneWideStoragePool = false; + if (canMigrateWithStorage) { - allHostsPair = searchForServers(startIndex, pageSize, null, hostType, null, srcHost.getDataCenterId(), null, null, null, null, null, null, srcHost.getHypervisorType(), - srcHost.getHypervisorVersion()); + allHostsPair = searchForServers(startIndex, pageSize, null, hostType, null, srcHost.getDataCenterId(), null, null, null, null, null, null, + srcHost.getHypervisorType(), srcHost.getHypervisorVersion()); allHosts = allHostsPair.first(); allHosts.remove(srcHost); - - // Check if the host has storage pools for all the volumes of the vm to be migrated. - for (Iterator iterator = allHosts.iterator(); iterator.hasNext();) { - Host host = iterator.next(); - Map> volumePools = findSuitablePoolsForVolumes(vmProfile, host); - if (volumePools.isEmpty()) { - iterator.remove(); - } else { - if (srcHost.getHypervisorType() == HypervisorType.VMware || srcHost.getHypervisorType() == HypervisorType.KVM) { - zoneWideStoragePool = checkForZoneWideStoragePool(volumePools); - } - if ((!host.getClusterId().equals(srcHost.getClusterId()) || usesLocal) && !zoneWideStoragePool) { - requiresStorageMotion.put(host, true); + for (VolumeVO volume : volumes) { + Long volClusterId = _poolDao.findById(volume.getPoolId()).getClusterId(); + // only check for volume which are not in zone wide primary store, as only those may require storage motion + if (volClusterId != null) { + for (Iterator iterator = allHosts.iterator(); iterator.hasNext();) { + Host host = iterator.next(); + if (!host.getClusterId().equals(volClusterId) || usesLocal) { + if (hasSuitablePoolsForVolume(volume, host, vmProfile)) { + requiresStorageMotion.put(host, true); + } else { + iterator.remove(); + } + } } } } - plan = new DataCenterDeployment(srcHost.getDataCenterId(), null, null, null, null, null); } else { Long cluster = srcHost.getClusterId(); @@ -1244,50 +1243,20 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe return new Ternary, Integer>, List, Map>(otherHosts, suitableHosts, requiresStorageMotion); } - private boolean checkForZoneWideStoragePool(Map> volumePools) { - boolean zoneWideStoragePool = false; - Collection> pools = volumePools.values(); - List aggregatePoolList = new ArrayList(); - for (Iterator> volumePoolsIter = pools.iterator(); volumePoolsIter.hasNext();) { - aggregatePoolList.addAll(volumePoolsIter.next()); - } - for (StoragePool pool : aggregatePoolList) { - if (null == pool.getClusterId()) { - zoneWideStoragePool = true; - break; - } - } - return zoneWideStoragePool; - } + private boolean hasSuitablePoolsForVolume(VolumeVO volume, Host host, VirtualMachineProfile vmProfile) { + DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId()); + DiskProfile diskProfile = new DiskProfile(volume, diskOffering, vmProfile.getHypervisorType()); + DataCenterDeployment plan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), host.getClusterId(), host.getId(), null, null); + ExcludeList avoid = new ExcludeList(); - private Map> findSuitablePoolsForVolumes(VirtualMachineProfile vmProfile, Host host) { - List volumes = _volumeDao.findCreatedByInstance(vmProfile.getId()); - Map> suitableVolumeStoragePools = new HashMap>(); - - // For each volume find list of suitable storage pools by calling the allocators - for (VolumeVO volume : volumes) { - DiskOfferingVO diskOffering = _diskOfferingDao.findById(volume.getDiskOfferingId()); - DiskProfile diskProfile = new DiskProfile(volume, diskOffering, vmProfile.getHypervisorType()); - DataCenterDeployment plan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), host.getClusterId(), host.getId(), null, null); - ExcludeList avoid = new ExcludeList(); - - boolean foundPools = false; - for (StoragePoolAllocator allocator : _storagePoolAllocators) { - List poolList = allocator.allocateToPool(diskProfile, vmProfile, plan, avoid, StoragePoolAllocator.RETURN_UPTO_ALL); - if (poolList != null && !poolList.isEmpty()) { - suitableVolumeStoragePools.put(volume, poolList); - foundPools = true; - break; - } - } - - if (!foundPools) { - suitableVolumeStoragePools.clear(); - break; + for (StoragePoolAllocator allocator : _storagePoolAllocators) { + List poolList = allocator.allocateToPool(diskProfile, vmProfile, plan, avoid, 1); + if (poolList != null && !poolList.isEmpty()) { + return true; } } - return suitableVolumeStoragePools; + return false; } @Override