From 51ea345a076a72cfeefecbf12ef7bc7b84569a0f Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Thu, 18 Feb 2021 22:09:25 +0000 Subject: [PATCH 01/14] server: Optional destination host when migrate a vm --- .../api/command/admin/vm/MigrateVMCmd.java | 10 ++-- .../java/com/cloud/vm/UserVmManagerImpl.java | 53 +++++++++++++++---- ui/src/views/compute/MigrateWizard.vue | 2 +- 3 files changed, 48 insertions(+), 17 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/MigrateVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/MigrateVMCmd.java index 9f73ae586a08..1ffbc993cc64 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/MigrateVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/MigrateVMCmd.java @@ -60,7 +60,7 @@ public class MigrateVMCmd extends BaseAsyncCmd { type = CommandType.UUID, entityType = HostResponse.class, required = false, - description = "Destination Host ID to migrate VM to. Required for live migrating a VM from host to host") + description = "Destination Host ID to migrate VM to.") private Long hostId; @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, @@ -132,10 +132,6 @@ public String getEventDescription() { @Override public void execute() { - if (getHostId() == null && getStoragePoolId() == null) { - throw new InvalidParameterValueException("Either hostId or storageId must be specified"); - } - if (getHostId() != null && getStoragePoolId() != null) { throw new InvalidParameterValueException("Only one of hostId and storageId can be specified"); } @@ -169,9 +165,9 @@ public void execute() { try { VirtualMachine migratedVm = null; - if (getHostId() != null) { + if (getStoragePoolId() == null) { migratedVm = _userVmService.migrateVirtualMachine(getVirtualMachineId(), destinationHost); - } else if (getStoragePoolId() != null) { + } else { migratedVm = _userVmService.vmStorageMigration(getVirtualMachineId(), destStoragePool); } if (migratedVm != null) { diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 1eafefa4c4c6..dccae7fad991 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -183,11 +183,13 @@ import com.cloud.event.UsageEventUtils; import com.cloud.event.UsageEventVO; import com.cloud.event.dao.UsageEventDao; +import com.cloud.exception.AffinityConflictException; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.CloudException; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.exception.InvalidParameterValueException; import com.cloud.exception.ManagementServerException; import com.cloud.exception.OperationTimedoutException; @@ -5895,8 +5897,46 @@ public VirtualMachine migrateVirtualMachine(Long vmId, Host destinationHost) thr throw new InvalidParameterValueException("Cannot migrate VM, host with id: " + srcHostId + " for VM not found"); } + DeployDestination dest = null; + if (destinationHost == null) { + vm.setLastHostId(null); // Last host does not have higher priority in vm migration + final ServiceOfferingVO offering = _offeringDao.findById(vm.getId(), vm.getServiceOfferingId()); + final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm, null, offering, null, null); + final Host host = _hostDao.findById(srcHostId); + final DataCenterDeployment plan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), host.getClusterId(), null, null, null); + ExcludeList excludes = new ExcludeList(); + excludes.addHost(srcHostId); + try { + dest = _planningMgr.planDeployment(profile, plan, excludes, null); + } catch (final AffinityConflictException e2) { + s_logger.warn("Unable to create deployment, affinity rules associted to the VM conflict", e2); + throw new CloudRuntimeException("Unable to create deployment, affinity rules associted to the VM conflict"); + } catch (final InsufficientServerCapacityException e3) { + throw new CloudRuntimeException("Unable to find a server to migrate the vm to"); + } + } else { + dest = checkVmMigrationDestination(vm, srcHost, destinationHost); + } - if (destinationHost.getId() == srcHostId) { + // If no suitable destination found then throw exception + if (dest == null) { + throw new CloudRuntimeException("Unable to find suitable destination to migrate VM " + vm.getInstanceName()); + } + + UserVmVO uservm = _vmDao.findById(vmId); + if (uservm != null) { + collectVmDiskStatistics(uservm); + collectVmNetworkStatistics(uservm); + } + _itMgr.migrate(vm.getUuid(), srcHostId, dest); + return findMigratedVm(vm.getId(), vm.getType()); + } + + private DeployDestination checkVmMigrationDestination(VMInstanceVO vm, Host srcHost, Host destinationHost) throws VirtualMachineMigrationException { + if (destinationHost == null) { + return null; + } + if (destinationHost.getId() == srcHost.getId()) { throw new InvalidParameterValueException("Cannot migrate VM, VM is already present on this host, please specify valid destination host to migrate the VM"); } @@ -5917,7 +5957,7 @@ public VirtualMachine migrateVirtualMachine(Long vmId, Host destinationHost) thr throw new CloudRuntimeException("Cannot migrate VM, VM is DPDK enabled VM but destination host is not DPDK enabled"); } - checkHostsDedication(vm, srcHostId, destinationHost.getId()); + checkHostsDedication(vm, srcHost.getId(), destinationHost.getId()); // call to core process DataCenterVO dcVO = _dcDao.findById(destinationHost.getDataCenterId()); @@ -5936,19 +5976,14 @@ public VirtualMachine migrateVirtualMachine(Long vmId, Host destinationHost) thr + " already has max Running VMs(count includes system VMs), cannot migrate to this host"); } //check if there are any ongoing volume snapshots on the volumes associated with the VM. + Long vmId = vm.getId(); s_logger.debug("Checking if there are any ongoing snapshots volumes associated with VM with ID " + vmId); if (checkStatusOfVolumeSnapshots(vmId, null)) { throw new CloudRuntimeException("There is/are unbacked up snapshot(s) on volume(s) attached to this VM, VM Migration is not permitted, please try again later."); } s_logger.debug("Found no ongoing snapshots on volumes associated with the vm with id " + vmId); - UserVmVO uservm = _vmDao.findById(vmId); - if (uservm != null) { - collectVmDiskStatistics(uservm); - collectVmNetworkStatistics(uservm); - } - _itMgr.migrate(vm.getUuid(), srcHostId, dest); - return findMigratedVm(vm.getId(), vm.getType()); + return dest; } private boolean isOnSupportedHypevisorForMigration(VMInstanceVO vm) { diff --git a/ui/src/views/compute/MigrateWizard.vue b/ui/src/views/compute/MigrateWizard.vue index f34a778fe1cd..04034983faa7 100644 --- a/ui/src/views/compute/MigrateWizard.vue +++ b/ui/src/views/compute/MigrateWizard.vue @@ -84,7 +84,7 @@
- + {{ $t('label.ok') }}
From 9bdc324d860acfc074fa94707467f9131bdbc88a Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 15 Mar 2021 13:44:25 +0000 Subject: [PATCH 02/14] #4378: migrate systemvms/routers with optional host --- .../admin/systemvm/MigrateSystemVMCmd.java | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/systemvm/MigrateSystemVMCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/systemvm/MigrateSystemVMCmd.java index 50129a580b31..1b8d9e0df759 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/systemvm/MigrateSystemVMCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/systemvm/MigrateSystemVMCmd.java @@ -126,23 +126,10 @@ public void execute() { throw new InvalidParameterValueException("Either hostId or storageId must be specified"); } - if (getHostId() != null && getStorageId() != null) { - throw new InvalidParameterValueException("Only one of hostId and storageId can be specified"); - } try { //FIXME : Should not be calling UserVmService to migrate all types of VMs - need a generic VM layer VirtualMachine migratedVm = null; - if (getHostId() != null) { - Host destinationHost = _resourceService.getHost(getHostId()); - if (destinationHost == null) { - throw new InvalidParameterValueException("Unable to find the host to migrate the VM, host id=" + getHostId()); - } - if (destinationHost.getType() != Host.Type.Routing) { - throw new InvalidParameterValueException("The specified host(" + destinationHost.getName() + ") is not suitable to migrate the VM, please specify another one"); - } - CallContext.current().setEventDetails("VM Id: " + getVirtualMachineId() + " to host Id: " + getHostId()); - migratedVm = _userVmService.migrateVirtualMachineWithVolume(getVirtualMachineId(), destinationHost, new HashMap()); - } else if (getStorageId() != null) { + if (getStorageId() != null) { // OfflineMigration performed when this parameter is specified StoragePool destStoragePool = _storageService.getStoragePool(getStorageId()); if (destStoragePool == null) { @@ -150,6 +137,19 @@ public void execute() { } CallContext.current().setEventDetails("VM Id: " + getVirtualMachineId() + " to storage pool Id: " + getStorageId()); migratedVm = _userVmService.vmStorageMigration(getVirtualMachineId(), destStoragePool); + } else { + Host destinationHost = null; + if (getHostId() != null) { + destinationHost =_resourceService.getHost(getHostId()); + if (destinationHost == null) { + throw new InvalidParameterValueException("Unable to find the host to migrate the VM, host id=" + getHostId()); + } + if (destinationHost.getType() != Host.Type.Routing) { + throw new InvalidParameterValueException("The specified host(" + destinationHost.getName() + ") is not suitable to migrate the VM, please specify another one"); + } + } + CallContext.current().setEventDetails("VM Id: " + getVirtualMachineId() + " to host Id: " + getHostId()); + migratedVm = _userVmService.migrateVirtualMachineWithVolume(getVirtualMachineId(), destinationHost, new HashMap()); } if (migratedVm != null) { // return the generic system VM instance response From b6c444969d999bb3c21dceab52fc61fc26fefd9f Mon Sep 17 00:00:00 2001 From: Rakesh Venkatesh Date: Thu, 17 Sep 2020 13:39:56 +0000 Subject: [PATCH 03/14] Migrate vms across clusters After enabling maintenance mode on host, if no suitable hosts are found in the same cluster then search for hosts in different clusters having the same hypervisor type set global setting migrate.vm.across.clusters to true --- .../com/cloud/vm/VirtualMachineManager.java | 2 + .../cloud/vm/VirtualMachineManagerImpl.java | 69 +++++++++++++++++-- .../ConfigurationManagerImpl.java | 6 +- .../cloud/resource/ResourceManagerImpl.java | 25 ++++++- 4 files changed, 93 insertions(+), 9 deletions(-) diff --git a/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java b/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java index 3ca300804f79..6502ea8d1215 100644 --- a/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java +++ b/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java @@ -260,4 +260,6 @@ static String getHypervisorHostname(String name) { boolean unmanage(String vmUuid); UserVm restoreVirtualMachine(long vmId, Long newTemplateId) throws ResourceUnavailableException, InsufficientCapacityException; + + boolean checkIfVmHasClusterWideVolumes(Long vmId); } diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 2bbb8cbe7c58..30b09e82d96d 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -33,6 +33,7 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Optional; import java.util.Set; import java.util.TimeZone; import java.util.UUID; @@ -130,6 +131,7 @@ import com.cloud.configuration.Resource.ResourceType; import com.cloud.dc.ClusterDetailsDao; import com.cloud.dc.ClusterDetailsVO; +import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; @@ -241,6 +243,8 @@ import com.cloud.vm.snapshot.dao.VMSnapshotDao; import com.google.common.base.Strings; +import static com.cloud.configuration.ConfigurationManagerImpl.MIGRATE_VM_ACROSS_CLUSTERS; + public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMachineManager, VmWorkJobHandler, Listener, Configurable { private static final Logger s_logger = Logger.getLogger(VirtualMachineManagerImpl.class); @@ -3311,15 +3315,20 @@ private void orchestrateMigrateAway(final String vmUuid, final long srcHostId, f throw new CloudRuntimeException("Unable to create deployment, affinity rules associted to the VM conflict"); } - if (dest != null) { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Found destination " + dest + " for migrating to."); + if (dest == null) { + Optional deployDestination = Optional.empty(); + if (MIGRATE_VM_ACROSS_CLUSTERS.value() && !checkIfVmHasClusterWideVolumes(vm.getId())) { + s_logger.info("Searching for hosts in different clusters for vm migration"); + deployDestination = getSuitableDeploymentDestination(profile, excludes, planner, host, poolId); } - } else { - if (s_logger.isDebugEnabled()) { - s_logger.debug("Unable to find destination for migrating the vm " + profile); + if (deployDestination.isEmpty()) { + s_logger.warn("Unable to find destination for migrating the vm " + profile); + throw new InsufficientServerCapacityException("Unable to find a server to migrate to.", host.getClusterId()); } - throw new InsufficientServerCapacityException("Unable to find a server to migrate to.", host.getClusterId()); + dest = deployDestination.get(); + } + if (s_logger.isDebugEnabled()) { + s_logger.debug("Found destination " + dest + " for migrating to."); } excludes.addHost(dest.getHost().getId()); @@ -3348,6 +3357,52 @@ private void orchestrateMigrateAway(final String vmUuid, final long srcHostId, f } } + /** + * Find a destination host across all clusters in the same zone which has the same hypervisor type as the + * virtual machine running on the host + * @param profile + * @param excludes + * @param planner + * @param host + * @param poolId + * @return Optional + * @throws InsufficientServerCapacityException + */ + private Optional getSuitableDeploymentDestination(final VirtualMachineProfile profile, + final ExcludeList excludes, + final DeploymentPlanner planner, + final Host host, + Long poolId) throws InsufficientServerCapacityException { + DataCenterDeployment plan; + DeployDestination dest; + + List clusterList = _clusterDao.listByDcHyType(host.getDataCenterId(), host.getHypervisorType().toString()); + // find a suitable target cluster which can used for vm migration + for (ClusterVO cluster : clusterList) { + plan = new DataCenterDeployment(cluster.getDataCenterId(), cluster.getPodId(), cluster.getId(), null, poolId, null); + dest = _dpMgr.planDeployment(profile, plan, excludes, planner); + if (dest != null) { + return Optional.of(dest); + } + } + + return Optional.empty(); + } + + /** + * Check if the virtual machine has any volume in cluster-wide pool + * @param vmId id of the virtual machine + * @return true if volume exists on cluster-wide pool else false + */ + @Override + public boolean checkIfVmHasClusterWideVolumes(Long vmId) { + final List volumesList = _volsDao.findCreatedByInstance(vmId); + + return volumesList.parallelStream() + .anyMatch(vol -> _storagePoolDao.findById(vol.getPoolId()).getScope().equals(ScopeType.CLUSTER)); + + } + protected class CleanupTask extends ManagedContextRunnable { @Override protected void runInContext() { diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index f5de35af3ed2..6e6fffca71ca 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -423,6 +423,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati "Indicates whether the host in down state can be put into maintenance state so thats its not enabled after it comes back.", true, ConfigKey.Scope.Zone, null); + public static final ConfigKey MIGRATE_VM_ACROSS_CLUSTERS = new ConfigKey(Boolean.class, "migrate.vm.across.clusters", "Advanced", "false", + "Indicates whether the VM can be migrated to different cluster if no host is found in same cluster",true, ConfigKey.Scope.Zone, null); + private static final String IOPS_READ_RATE = "IOPS Read"; private static final String IOPS_WRITE_RATE = "IOPS Write"; private static final String BYTES_READ_RATE = "Bytes Read"; @@ -6485,6 +6488,7 @@ public String getConfigComponentName() { @Override public ConfigKey[] getConfigKeys() { return new ConfigKey[] {SystemVMUseLocalStorage, IOPS_MAX_READ_LENGTH, IOPS_MAX_WRITE_LENGTH, - BYTES_MAX_READ_LENGTH, BYTES_MAX_WRITE_LENGTH, ADD_HOST_ON_SERVICE_RESTART_KVM, SET_HOST_DOWN_TO_MAINTENANCE}; + BYTES_MAX_READ_LENGTH, BYTES_MAX_WRITE_LENGTH, ADD_HOST_ON_SERVICE_RESTART_KVM, SET_HOST_DOWN_TO_MAINTENANCE, + MIGRATE_VM_ACROSS_CLUSTERS}; } } diff --git a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java index f2455020c5a2..e18d9eab39fc 100755 --- a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java @@ -181,6 +181,7 @@ import com.google.gson.Gson; +import static com.cloud.configuration.ConfigurationManagerImpl.MIGRATE_VM_ACROSS_CLUSTERS; import static com.cloud.configuration.ConfigurationManagerImpl.SET_HOST_DOWN_TO_MAINTENANCE; @Component @@ -1262,7 +1263,29 @@ private boolean doMaintain(final long hostId) { return true; } - final List hosts = listAllUpAndEnabledHosts(Host.Type.Routing, host.getClusterId(), host.getPodId(), host.getDataCenterId()); + List hosts = listAllUpAndEnabledHosts(Host.Type.Routing, host.getClusterId(), host.getPodId(), host.getDataCenterId()); + if (hosts == null || hosts.isEmpty()) { + s_logger.warn("Unable to find a host for vm migration in cluster: " + host.getClusterId()); + if (MIGRATE_VM_ACROSS_CLUSTERS.value()) { + s_logger.info("Looking for hosts across different clusters in zone: " + host.getDataCenterId()); + hosts = listAllUpAndEnabledHosts(Host.Type.Routing, null, null, host.getDataCenterId()); + if (hosts == null || hosts.isEmpty()) { + s_logger.warn("Unable to find a host for vm migration in zone: " + host.getDataCenterId()); + return false; + } + // Dont migrate vm if it has volumes on cluster-wide pool + for (final VMInstanceVO vm : vms) { + if (_vmMgr.checkIfVmHasClusterWideVolumes(vm.getId())) { + s_logger.warn("Unable to migrate vm " + vm.getInstanceName() + " as it has volumes on cluster-wide pool"); + return false; + } + } + } else { + s_logger.warn("Not migrating VM across cluster since " + MIGRATE_VM_ACROSS_CLUSTERS.key() + " is false"); + return false; + } + } + for (final VMInstanceVO vm : vms) { if (hosts == null || hosts.isEmpty() || !answer.getMigrate() || _serviceOfferingDetailsDao.findDetail(vm.getServiceOfferingId(), GPU.Keys.vgpuType.toString()) != null) { From 8e85f028982e004deeb54b4ece1a0ff8425138f3 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 12 Oct 2020 07:53:11 +0000 Subject: [PATCH 04/14] search all clusters in zone when migrate vm across clusters if applicable --- .../cloud/vm/VirtualMachineManagerImpl.java | 64 ++++++------------- 1 file changed, 19 insertions(+), 45 deletions(-) diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 30b09e82d96d..152c084b2acd 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -33,7 +33,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; -import java.util.Optional; import java.util.Set; import java.util.TimeZone; import java.util.UUID; @@ -3300,9 +3299,9 @@ private void orchestrateMigrateAway(final String vmUuid, final long srcHostId, f } } - final DataCenterDeployment plan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), host.getClusterId(), null, poolId, null); final ExcludeList excludes = new ExcludeList(); excludes.addHost(hostId); + DataCenterDeployment plan = getMigrationDeployment(vm.getId(), host, poolId, excludes); DeployDestination dest = null; while (true) { @@ -3314,18 +3313,9 @@ private void orchestrateMigrateAway(final String vmUuid, final long srcHostId, f s_logger.warn("Unable to create deployment, affinity rules associted to the VM conflict", e2); throw new CloudRuntimeException("Unable to create deployment, affinity rules associted to the VM conflict"); } - if (dest == null) { - Optional deployDestination = Optional.empty(); - if (MIGRATE_VM_ACROSS_CLUSTERS.value() && !checkIfVmHasClusterWideVolumes(vm.getId())) { - s_logger.info("Searching for hosts in different clusters for vm migration"); - deployDestination = getSuitableDeploymentDestination(profile, excludes, planner, host, poolId); - } - if (deployDestination.isEmpty()) { - s_logger.warn("Unable to find destination for migrating the vm " + profile); - throw new InsufficientServerCapacityException("Unable to find a server to migrate to.", host.getClusterId()); - } - dest = deployDestination.get(); + s_logger.warn("Unable to find destination for migrating the vm " + profile); + throw new InsufficientServerCapacityException("Unable to find a server to migrate to.", DataCenter.class, host.getDataCenterId()); } if (s_logger.isDebugEnabled()) { s_logger.debug("Found destination " + dest + " for migrating to."); @@ -3357,38 +3347,6 @@ private void orchestrateMigrateAway(final String vmUuid, final long srcHostId, f } } - /** - * Find a destination host across all clusters in the same zone which has the same hypervisor type as the - * virtual machine running on the host - * @param profile - * @param excludes - * @param planner - * @param host - * @param poolId - * @return Optional - * @throws InsufficientServerCapacityException - */ - private Optional getSuitableDeploymentDestination(final VirtualMachineProfile profile, - final ExcludeList excludes, - final DeploymentPlanner planner, - final Host host, - Long poolId) throws InsufficientServerCapacityException { - DataCenterDeployment plan; - DeployDestination dest; - - List clusterList = _clusterDao.listByDcHyType(host.getDataCenterId(), host.getHypervisorType().toString()); - // find a suitable target cluster which can used for vm migration - for (ClusterVO cluster : clusterList) { - plan = new DataCenterDeployment(cluster.getDataCenterId(), cluster.getPodId(), cluster.getId(), null, poolId, null); - dest = _dpMgr.planDeployment(profile, plan, excludes, planner); - if (dest != null) { - return Optional.of(dest); - } - } - - return Optional.empty(); - } - /** * Check if the virtual machine has any volume in cluster-wide pool * @param vmId id of the virtual machine @@ -3403,6 +3361,22 @@ public boolean checkIfVmHasClusterWideVolumes(Long vmId) { } + private DataCenterDeployment getMigrationDeployment(final Long vmId, final Host host, final Long poolId, final ExcludeList excludes) { + if (MIGRATE_VM_ACROSS_CLUSTERS.value() && !checkIfVmHasClusterWideVolumes(vmId)) { + s_logger.info("Searching for hosts in the zone for vm migration"); + List clustersToExcluded = _clusterDao.listAllClusters(host.getDataCenterId()); + List clusterList = _clusterDao.listByDcHyType(host.getDataCenterId(), host.getHypervisorType().toString()); + for (ClusterVO cluster : clusterList) { + clustersToExcluded.remove(cluster.getId()); + } + for (Long clusterId : clustersToExcluded) { + excludes.addCluster(clusterId); + } + return new DataCenterDeployment(host.getDataCenterId(), null, null, null, poolId, null); + } + return new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), host.getClusterId(), null, poolId, null); + } + protected class CleanupTask extends ManagedContextRunnable { @Override protected void runInContext() { From 8e36c02d6d92789d1255506d04552235828abfd3 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 16 Nov 2020 19:34:48 +0000 Subject: [PATCH 05/14] Honor migrate.vm.across.clusters when migrate vm without destination --- .../src/main/java/com/cloud/vm/VirtualMachineManager.java | 5 +++++ .../main/java/com/cloud/vm/VirtualMachineManagerImpl.java | 3 ++- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java b/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java index 6502ea8d1215..57e7be6eca39 100644 --- a/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java +++ b/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java @@ -26,15 +26,18 @@ import com.cloud.agent.api.to.NicTO; import com.cloud.agent.api.to.VirtualMachineTO; +import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; import com.cloud.deploy.DeploymentPlanner; +import com.cloud.deploy.DeploymentPlanner.ExcludeList; import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InsufficientServerCapacityException; import com.cloud.exception.OperationTimedoutException; import com.cloud.exception.ResourceUnavailableException; +import com.cloud.host.Host; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.Network; import com.cloud.offering.DiskOffering; @@ -262,4 +265,6 @@ static String getHypervisorHostname(String name) { UserVm restoreVirtualMachine(long vmId, Long newTemplateId) throws ResourceUnavailableException, InsufficientCapacityException; boolean checkIfVmHasClusterWideVolumes(Long vmId); + + DataCenterDeployment getMigrationDeployment(Long vmId, Host host, Long poolId, ExcludeList excludes); } diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 152c084b2acd..235163119c9d 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -3361,7 +3361,8 @@ public boolean checkIfVmHasClusterWideVolumes(Long vmId) { } - private DataCenterDeployment getMigrationDeployment(final Long vmId, final Host host, final Long poolId, final ExcludeList excludes) { + @Override + public DataCenterDeployment getMigrationDeployment(final Long vmId, final Host host, final Long poolId, final ExcludeList excludes) { if (MIGRATE_VM_ACROSS_CLUSTERS.value() && !checkIfVmHasClusterWideVolumes(vmId)) { s_logger.info("Searching for hosts in the zone for vm migration"); List clustersToExcluded = _clusterDao.listAllClusters(host.getDataCenterId()); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index dccae7fad991..bd033c67bad8 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -5903,9 +5903,9 @@ public VirtualMachine migrateVirtualMachine(Long vmId, Host destinationHost) thr final ServiceOfferingVO offering = _offeringDao.findById(vm.getId(), vm.getServiceOfferingId()); final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm, null, offering, null, null); final Host host = _hostDao.findById(srcHostId); - final DataCenterDeployment plan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), host.getClusterId(), null, null, null); ExcludeList excludes = new ExcludeList(); excludes.addHost(srcHostId); + final DataCenterDeployment plan = _itMgr.getMigrationDeployment(vm.getId(), host, null, excludes); try { dest = _planningMgr.planDeployment(profile, plan, excludes, null); } catch (final AffinityConflictException e2) { From f6f8cfc6f7a58a636512c7334c5b5b4dfa081174 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 11 Dec 2020 12:43:34 +0000 Subject: [PATCH 06/14] Check MIGRATE_VM_ACROSS_CLUSTERS in zone setting --- .../src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java | 2 +- .../src/main/java/com/cloud/resource/ResourceManagerImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 235163119c9d..dc7be3d22223 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -3363,7 +3363,7 @@ public boolean checkIfVmHasClusterWideVolumes(Long vmId) { @Override public DataCenterDeployment getMigrationDeployment(final Long vmId, final Host host, final Long poolId, final ExcludeList excludes) { - if (MIGRATE_VM_ACROSS_CLUSTERS.value() && !checkIfVmHasClusterWideVolumes(vmId)) { + if (MIGRATE_VM_ACROSS_CLUSTERS.valueIn(host.getDataCenterId()) && !checkIfVmHasClusterWideVolumes(vmId)) { s_logger.info("Searching for hosts in the zone for vm migration"); List clustersToExcluded = _clusterDao.listAllClusters(host.getDataCenterId()); List clusterList = _clusterDao.listByDcHyType(host.getDataCenterId(), host.getHypervisorType().toString()); diff --git a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java index e18d9eab39fc..dbf10c5b17b9 100755 --- a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java @@ -1266,7 +1266,7 @@ private boolean doMaintain(final long hostId) { List hosts = listAllUpAndEnabledHosts(Host.Type.Routing, host.getClusterId(), host.getPodId(), host.getDataCenterId()); if (hosts == null || hosts.isEmpty()) { s_logger.warn("Unable to find a host for vm migration in cluster: " + host.getClusterId()); - if (MIGRATE_VM_ACROSS_CLUSTERS.value()) { + if (MIGRATE_VM_ACROSS_CLUSTERS.valueIn(host.getDataCenterId())) { s_logger.info("Looking for hosts across different clusters in zone: " + host.getDataCenterId()); hosts = listAllUpAndEnabledHosts(Host.Type.Routing, null, null, host.getDataCenterId()); if (hosts == null || hosts.isEmpty()) { From d4d80807681993c9090e8b024deb973bdcc7f1ee Mon Sep 17 00:00:00 2001 From: Sina Kashipazha Date: Thu, 27 Aug 2020 14:54:02 +0200 Subject: [PATCH 07/14] #4534 Fix Vms are migrated to same clusters in CloudStack caused by dedicated resources. --- .../com/cloud/capacity/dao/CapacityDao.java | 4 +- .../cloud/capacity/dao/CapacityDaoImpl.java | 37 +++++++++++++------ .../implicitplanner/ImplicitPlannerTest.java | 4 +- .../com/cloud/deploy/FirstFitPlanner.java | 8 ++-- .../com/cloud/vm/FirstFitPlannerTest.java | 4 +- 5 files changed, 36 insertions(+), 21 deletions(-) diff --git a/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDao.java b/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDao.java index f2735b819a92..dc04f76f2f2f 100644 --- a/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDao.java +++ b/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDao.java @@ -27,7 +27,7 @@ public interface CapacityDao extends GenericDao { CapacityVO findByHostIdType(Long hostId, short capacityType); - List listClustersInZoneOrPodByHostCapacities(long id, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone); + List listClustersInZoneOrPodByHostCapacities(long id, long vmId, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone); List listHostsWithEnoughCapacity(int requiredCpu, long requiredRam, Long clusterId, String hostType); @@ -37,7 +37,7 @@ public interface CapacityDao extends GenericDao { List findNonSharedStorageForClusterPodZone(Long zoneId, Long podId, Long clusterId); - Pair, Map> orderClustersByAggregateCapacity(long id, short capacityType, boolean isZone); + Pair, Map> orderClustersByAggregateCapacity(long id, long vmId, short capacityType, boolean isZone); List findCapacityBy(Integer capacityType, Long zoneId, Long podId, Long clusterId); diff --git a/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java b/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java index 72d5b0707613..fe6f2f4ce7be 100644 --- a/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/capacity/dao/CapacityDaoImpl.java @@ -75,13 +75,24 @@ public class CapacityDaoImpl extends GenericDaoBase implements + " AND host_capacity.host_id IN (SELECT capacity.host_id FROM `cloud`.`op_host_capacity` capacity JOIN `cloud`.`cluster_details` cluster_details ON (capacity.cluster_id= cluster_details.cluster_id) where capacity_type='0' AND cluster_details.name='memoryOvercommitRatio' AND ((total_capacity* cluster_details.value) - used_capacity ) >= ?)) "; private static final String ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART1 = - "SELECT capacity.cluster_id, SUM(used_capacity+reserved_capacity)/SUM(total_capacity ) FROM `cloud`.`op_host_capacity` capacity WHERE "; + "SELECT capacity.cluster_id, SUM(used_capacity+reserved_capacity)/SUM(total_capacity ) FROM `cloud`.`op_host_capacity` capacity "; private static final String ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART2 = - " AND capacity_type = ? AND cluster_details.name =? GROUP BY capacity.cluster_id ORDER BY SUM(used_capacity+reserved_capacity)/SUM(total_capacity * cluster_details.value) ASC"; + " AND capacity_type = ? GROUP BY capacity.cluster_id ORDER BY SUM(used_capacity+reserved_capacity)/SUM(total_capacity) ASC"; + + private static final String ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_JOIN_1 = + "JOIN host ON capacity.host_id = host.id " + + "LEFT JOIN (SELECT affinity_group.id, agvm.instance_id FROM affinity_group_vm_map agvm JOIN affinity_group ON agvm.affinity_group_id = affinity_group.id AND affinity_group.type='ExplicitDedication') AS ag ON ag.instance_id = ? " + + "LEFT JOIN dedicated_resources dr_pod ON dr_pod.pod_id IS NOT NULL AND dr_pod.pod_id = host.pod_id " + + "LEFT JOIN dedicated_resources dr_cluster ON dr_cluster.cluster_id IS NOT NULL AND dr_cluster.cluster_id = host.cluster_id " + + "LEFT JOIN dedicated_resources dr_host ON dr_host.host_id IS NOT NULL AND dr_host.host_id = host.id "; + + private static final String ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_JOIN_2 = + " AND ((ag.id IS NULL AND dr_pod.pod_id IS NULL AND dr_cluster.cluster_id IS NULL AND dr_host.host_id IS NULL) OR " + + "(dr_pod.affinity_group_id = ag.id OR dr_cluster.affinity_group_id = ag.id OR dr_host.affinity_group_id = ag.id))"; private static final String ORDER_CLUSTERS_BY_AGGREGATE_OVERCOMMIT_CAPACITY_PART1 = - "SELECT capacity.cluster_id, SUM(used_capacity+reserved_capacity)/SUM(total_capacity * cluster_details.value) FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`cluster_details` cluster_details ON (capacity.cluster_id = cluster_details.cluster_id) WHERE "; + "SELECT capacity.cluster_id, SUM(used_capacity+reserved_capacity)/SUM(total_capacity * cluster_details.value) FROM `cloud`.`op_host_capacity` capacity INNER JOIN `cloud`.`cluster_details` cluster_details ON (capacity.cluster_id = cluster_details.cluster_id) "; private static final String ORDER_CLUSTERS_BY_AGGREGATE_OVERCOMMIT_CAPACITY_PART2 = " AND capacity_type = ? AND cluster_details.name =? GROUP BY capacity.cluster_id ORDER BY SUM(used_capacity+reserved_capacity)/SUM(total_capacity * cluster_details.value) ASC"; @@ -572,7 +583,7 @@ public CapacityVO findByHostIdType(Long hostId, short capacityType) { } @Override - public List listClustersInZoneOrPodByHostCapacities(long id, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone) { + public List listClustersInZoneOrPodByHostCapacities(long id, long vmId, int requiredCpu, long requiredRam, short capacityTypeForOrdering, boolean isZone) { TransactionLegacy txn = TransactionLegacy.currentTxn(); PreparedStatement pstmt = null; List result = new ArrayList(); @@ -854,7 +865,7 @@ public boolean removeBy(Short capacityType, Long zoneId, Long podId, Long cluste } @Override - public Pair, Map> orderClustersByAggregateCapacity(long id, short capacityTypeForOrdering, boolean isZone) { + public Pair, Map> orderClustersByAggregateCapacity(long id, long vmId, short capacityTypeForOrdering, boolean isZone) { TransactionLegacy txn = TransactionLegacy.currentTxn(); PreparedStatement pstmt = null; List result = new ArrayList(); @@ -866,11 +877,14 @@ public Pair, Map> orderClustersByAggregateCapacity(long sql.append(ORDER_CLUSTERS_BY_AGGREGATE_OVERCOMMIT_CAPACITY_PART1); } + sql.append(ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_JOIN_1); if (isZone) { - sql.append(" data_center_id = ?"); + sql.append("WHERE capacity.capacity_state = 'Enabled' AND capacity.data_center_id = ?"); } else { - sql.append(" pod_id = ?"); + sql.append("WHERE capacity.capacity_state = 'Enabled' AND capacity.pod_id = ?"); } + sql.append(ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_JOIN_2); + if (capacityTypeForOrdering != Capacity.CAPACITY_TYPE_CPU && capacityTypeForOrdering != Capacity.CAPACITY_TYPE_MEMORY) { sql.append(ORDER_CLUSTERS_BY_AGGREGATE_CAPACITY_PART2); } else { @@ -879,13 +893,14 @@ public Pair, Map> orderClustersByAggregateCapacity(long try { pstmt = txn.prepareAutoCloseStatement(sql.toString()); - pstmt.setLong(1, id); - pstmt.setShort(2, capacityTypeForOrdering); + pstmt.setLong(1, vmId); + pstmt.setLong(2, id); + pstmt.setShort(3, capacityTypeForOrdering); if (capacityTypeForOrdering == Capacity.CAPACITY_TYPE_CPU) { - pstmt.setString(3, "cpuOvercommitRatio"); + pstmt.setString(4, "cpuOvercommitRatio"); } else if (capacityTypeForOrdering == Capacity.CAPACITY_TYPE_MEMORY) { - pstmt.setString(3, "memoryOvercommitRatio"); + pstmt.setString(4, "memoryOvercommitRatio"); } ResultSet rs = pstmt.executeQuery(); diff --git a/plugins/deployment-planners/implicit-dedication/src/test/java/org/apache/cloudstack/implicitplanner/ImplicitPlannerTest.java b/plugins/deployment-planners/implicit-dedication/src/test/java/org/apache/cloudstack/implicitplanner/ImplicitPlannerTest.java index 1a3aed0ab611..a25ad9fd308f 100644 --- a/plugins/deployment-planners/implicit-dedication/src/test/java/org/apache/cloudstack/implicitplanner/ImplicitPlannerTest.java +++ b/plugins/deployment-planners/implicit-dedication/src/test/java/org/apache/cloudstack/implicitplanner/ImplicitPlannerTest.java @@ -382,7 +382,7 @@ private void initializeForTest(VirtualMachineProfileImpl vmProfile, DataCenterDe clustersWithEnoughCapacity.add(2L); clustersWithEnoughCapacity.add(3L); when( - capacityDao.listClustersInZoneOrPodByHostCapacities(dataCenterId, noOfCpusInOffering * cpuSpeedInOffering, ramInOffering * 1024L * 1024L, + capacityDao.listClustersInZoneOrPodByHostCapacities(dataCenterId, 12L, noOfCpusInOffering * cpuSpeedInOffering, ramInOffering * 1024L * 1024L, Capacity.CAPACITY_TYPE_CPU, true)).thenReturn(clustersWithEnoughCapacity); Map clusterCapacityMap = new HashMap(); @@ -390,7 +390,7 @@ private void initializeForTest(VirtualMachineProfileImpl vmProfile, DataCenterDe clusterCapacityMap.put(2L, 2048D); clusterCapacityMap.put(3L, 2048D); Pair, Map> clustersOrderedByCapacity = new Pair, Map>(clustersWithEnoughCapacity, clusterCapacityMap); - when(capacityDao.orderClustersByAggregateCapacity(dataCenterId, Capacity.CAPACITY_TYPE_CPU, true)).thenReturn(clustersOrderedByCapacity); + when(capacityDao.orderClustersByAggregateCapacity(dataCenterId, 12L, Capacity.CAPACITY_TYPE_CPU, true)).thenReturn(clustersOrderedByCapacity); List disabledClusters = new ArrayList(); List clustersWithDisabledPods = new ArrayList(); diff --git a/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java b/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java index a93da7102b40..02657aa2953d 100644 --- a/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java @@ -392,7 +392,7 @@ private List scanClustersForDestinationInZoneOrPod(long id, boolean isZone long requiredRam = offering.getRamSize() * 1024L * 1024L; //list clusters under this zone by cpu and ram capacity - Pair, Map> clusterCapacityInfo = listClustersByCapacity(id, requiredCpu, requiredRam, avoid, isZone); + Pair, Map> clusterCapacityInfo = listClustersByCapacity(id, vmProfile.getId(), requiredCpu, requiredRam, avoid, isZone); List prioritizedClusterIds = clusterCapacityInfo.first(); if (!prioritizedClusterIds.isEmpty()) { if (avoid.getClustersToAvoid() != null) { @@ -480,7 +480,7 @@ private List listDisabledPods(long zoneId) { return disabledPods; } - protected Pair, Map> listClustersByCapacity(long id, int requiredCpu, long requiredRam, ExcludeList avoid, boolean isZone) { + protected Pair, Map> listClustersByCapacity(long id, long vmId, int requiredCpu, long requiredRam, ExcludeList avoid, boolean isZone) { //look at the aggregate available cpu and ram per cluster //although an aggregate value may be false indicator that a cluster can host a vm, it will at the least eliminate those clusters which definitely cannot @@ -495,11 +495,11 @@ protected Pair, Map> listClustersByCapacity(long id, in capacityType = Capacity.CAPACITY_TYPE_MEMORY; } - List clusterIdswithEnoughCapacity = capacityDao.listClustersInZoneOrPodByHostCapacities(id, requiredCpu, requiredRam, capacityType, isZone); + List clusterIdswithEnoughCapacity = capacityDao.listClustersInZoneOrPodByHostCapacities(id, vmId, requiredCpu, requiredRam, capacityType, isZone); if (s_logger.isTraceEnabled()) { s_logger.trace("ClusterId List having enough CPU and RAM capacity: " + clusterIdswithEnoughCapacity); } - Pair, Map> result = capacityDao.orderClustersByAggregateCapacity(id, capacityType, isZone); + Pair, Map> result = capacityDao.orderClustersByAggregateCapacity(id, vmId, capacityType, isZone); List clusterIdsOrderedByAggregateCapacity = result.first(); //only keep the clusters that have enough capacity to host this VM if (s_logger.isTraceEnabled()) { diff --git a/server/src/test/java/com/cloud/vm/FirstFitPlannerTest.java b/server/src/test/java/com/cloud/vm/FirstFitPlannerTest.java index 41deea2823f4..bfca1fe5d985 100644 --- a/server/src/test/java/com/cloud/vm/FirstFitPlannerTest.java +++ b/server/src/test/java/com/cloud/vm/FirstFitPlannerTest.java @@ -291,7 +291,7 @@ private void initializeForTest(VirtualMachineProfileImpl vmProfile, DataCenterDe clustersWithEnoughCapacity.add(6L); when( - capacityDao.listClustersInZoneOrPodByHostCapacities(dataCenterId, noOfCpusInOffering * cpuSpeedInOffering, ramInOffering * 1024L * 1024L, + capacityDao.listClustersInZoneOrPodByHostCapacities(dataCenterId, 12L, noOfCpusInOffering * cpuSpeedInOffering, ramInOffering * 1024L * 1024L, Capacity.CAPACITY_TYPE_CPU, true)).thenReturn(clustersWithEnoughCapacity); Map clusterCapacityMap = new HashMap(); @@ -303,7 +303,7 @@ private void initializeForTest(VirtualMachineProfileImpl vmProfile, DataCenterDe clusterCapacityMap.put(6L, 2048D); Pair, Map> clustersOrderedByCapacity = new Pair, Map>(clustersWithEnoughCapacity, clusterCapacityMap); - when(capacityDao.orderClustersByAggregateCapacity(dataCenterId, Capacity.CAPACITY_TYPE_CPU, true)).thenReturn(clustersOrderedByCapacity); + when(capacityDao.orderClustersByAggregateCapacity(dataCenterId, 12L, Capacity.CAPACITY_TYPE_CPU, true)).thenReturn(clustersOrderedByCapacity); List disabledClusters = new ArrayList(); List clustersWithDisabledPods = new ArrayList(); From 3250cf9da7853de0689ed8c298e78e6608c0af3a Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 26 Jan 2021 14:10:08 +0000 Subject: [PATCH 08/14] #4534 extract some codes to methods --- .../cloud/vm/VirtualMachineManagerImpl.java | 6 +-- .../cloud/resource/ResourceManagerImpl.java | 39 +++++++++++-------- .../java/com/cloud/vm/UserVmManagerImpl.java | 36 ++++++++++------- 3 files changed, 47 insertions(+), 34 deletions(-) diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index dc7be3d22223..7457cf7df7b2 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -3365,12 +3365,12 @@ public boolean checkIfVmHasClusterWideVolumes(Long vmId) { public DataCenterDeployment getMigrationDeployment(final Long vmId, final Host host, final Long poolId, final ExcludeList excludes) { if (MIGRATE_VM_ACROSS_CLUSTERS.valueIn(host.getDataCenterId()) && !checkIfVmHasClusterWideVolumes(vmId)) { s_logger.info("Searching for hosts in the zone for vm migration"); - List clustersToExcluded = _clusterDao.listAllClusters(host.getDataCenterId()); + List clustersToExclude = _clusterDao.listAllClusters(host.getDataCenterId()); List clusterList = _clusterDao.listByDcHyType(host.getDataCenterId(), host.getHypervisorType().toString()); for (ClusterVO cluster : clusterList) { - clustersToExcluded.remove(cluster.getId()); + clustersToExclude.remove(cluster.getId()); } - for (Long clusterId : clustersToExcluded) { + for (Long clusterId : clustersToExclude) { excludes.addCluster(clusterId); } return new DataCenterDeployment(host.getDataCenterId(), null, null, null, poolId, null); diff --git a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java index dbf10c5b17b9..96e965355b56 100755 --- a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java @@ -1266,22 +1266,7 @@ private boolean doMaintain(final long hostId) { List hosts = listAllUpAndEnabledHosts(Host.Type.Routing, host.getClusterId(), host.getPodId(), host.getDataCenterId()); if (hosts == null || hosts.isEmpty()) { s_logger.warn("Unable to find a host for vm migration in cluster: " + host.getClusterId()); - if (MIGRATE_VM_ACROSS_CLUSTERS.valueIn(host.getDataCenterId())) { - s_logger.info("Looking for hosts across different clusters in zone: " + host.getDataCenterId()); - hosts = listAllUpAndEnabledHosts(Host.Type.Routing, null, null, host.getDataCenterId()); - if (hosts == null || hosts.isEmpty()) { - s_logger.warn("Unable to find a host for vm migration in zone: " + host.getDataCenterId()); - return false; - } - // Dont migrate vm if it has volumes on cluster-wide pool - for (final VMInstanceVO vm : vms) { - if (_vmMgr.checkIfVmHasClusterWideVolumes(vm.getId())) { - s_logger.warn("Unable to migrate vm " + vm.getInstanceName() + " as it has volumes on cluster-wide pool"); - return false; - } - } - } else { - s_logger.warn("Not migrating VM across cluster since " + MIGRATE_VM_ACROSS_CLUSTERS.key() + " is false"); + if (! isClusterWideMigrationSupported(host, vms, hosts)) { return false; } } @@ -1305,6 +1290,28 @@ private boolean doMaintain(final long hostId) { return true; } + private boolean isClusterWideMigrationSupported(Host host, List vms, List hosts) { + if (MIGRATE_VM_ACROSS_CLUSTERS.valueIn(host.getDataCenterId())) { + s_logger.info("Looking for hosts across different clusters in zone: " + host.getDataCenterId()); + hosts = listAllUpAndEnabledHosts(Host.Type.Routing, null, null, host.getDataCenterId()); + if (hosts == null || hosts.isEmpty()) { + s_logger.warn("Unable to find a host for vm migration in zone: " + host.getDataCenterId()); + return false; + } + // Dont migrate vm if it has volumes on cluster-wide pool + for (final VMInstanceVO vm : vms) { + if (_vmMgr.checkIfVmHasClusterWideVolumes(vm.getId())) { + s_logger.warn("Unable to migrate vm " + vm.getInstanceName() + " as it has volumes on cluster-wide pool"); + return false; + } + } + } else { + s_logger.warn("Not migrating VM across cluster since " + MIGRATE_VM_ACROSS_CLUSTERS.key() + " is false"); + return false; + } + return true; + } + @Override public boolean maintain(final long hostId) throws AgentUnavailableException { final Boolean result = propagateResourceEvent(hostId, ResourceState.Event.AdminAskMaintenance); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index bd033c67bad8..e21f164e5037 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -5899,21 +5899,7 @@ public VirtualMachine migrateVirtualMachine(Long vmId, Host destinationHost) thr DeployDestination dest = null; if (destinationHost == null) { - vm.setLastHostId(null); // Last host does not have higher priority in vm migration - final ServiceOfferingVO offering = _offeringDao.findById(vm.getId(), vm.getServiceOfferingId()); - final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm, null, offering, null, null); - final Host host = _hostDao.findById(srcHostId); - ExcludeList excludes = new ExcludeList(); - excludes.addHost(srcHostId); - final DataCenterDeployment plan = _itMgr.getMigrationDeployment(vm.getId(), host, null, excludes); - try { - dest = _planningMgr.planDeployment(profile, plan, excludes, null); - } catch (final AffinityConflictException e2) { - s_logger.warn("Unable to create deployment, affinity rules associted to the VM conflict", e2); - throw new CloudRuntimeException("Unable to create deployment, affinity rules associted to the VM conflict"); - } catch (final InsufficientServerCapacityException e3) { - throw new CloudRuntimeException("Unable to find a server to migrate the vm to"); - } + dest = findVmMigrationDestination(vm, srcHostId); } else { dest = checkVmMigrationDestination(vm, srcHost, destinationHost); } @@ -5932,6 +5918,26 @@ public VirtualMachine migrateVirtualMachine(Long vmId, Host destinationHost) thr return findMigratedVm(vm.getId(), vm.getType()); } + private DeployDestination findVmMigrationDestination(VMInstanceVO vm, Long srcHostId) { + DeployDestination dest = null; + vm.setLastHostId(null); // Last host does not have higher priority in vm migration + final ServiceOfferingVO offering = _offeringDao.findById(vm.getId(), vm.getServiceOfferingId()); + final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm, null, offering, null, null); + final Host host = _hostDao.findById(srcHostId); + ExcludeList excludes = new ExcludeList(); + excludes.addHost(srcHostId); + final DataCenterDeployment plan = _itMgr.getMigrationDeployment(vm.getId(), host, null, excludes); + try { + dest = _planningMgr.planDeployment(profile, plan, excludes, null); + } catch (final AffinityConflictException e2) { + s_logger.warn("Unable to create deployment, affinity rules associted to the VM conflict", e2); + throw new CloudRuntimeException("Unable to create deployment, affinity rules associted to the VM conflict"); + } catch (final InsufficientServerCapacityException e3) { + throw new CloudRuntimeException("Unable to find a server to migrate the vm to"); + } + return dest; + } + private DeployDestination checkVmMigrationDestination(VMInstanceVO vm, Host srcHost, Host destinationHost) throws VirtualMachineMigrationException { if (destinationHost == null) { return null; From 404cd34c15644c600ff3f55e39bfec82bc302b6a Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 6 Sep 2021 08:32:38 +0200 Subject: [PATCH 09/14] fix #4534: an error in 'git merge' --- server/src/main/java/com/cloud/vm/UserVmManagerImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 44912a08f38c..957980bf9f75 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -6013,9 +6013,9 @@ private DeployDestination chooseVmMigrationDestination(VMInstanceVO vm, Host src final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm, null, offering, null, null); final Long srcHostId = srcHost.getId(); final Host host = _hostDao.findById(srcHostId); - final DataCenterDeployment plan = new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), host.getClusterId(), null, null, null); ExcludeList excludes = new ExcludeList(); excludes.addHost(srcHostId); + final DataCenterDeployment plan = _itMgr.getMigrationDeployment(vm.getId(), host, null, excludes); try { return _planningMgr.planDeployment(profile, plan, excludes, null); } catch (final AffinityConflictException e2) { From ca3d0cc510683ede46aa9956ea030839a8961201 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 6 Sep 2021 08:32:58 +0200 Subject: [PATCH 10/14] fix #4534: remove useless methods in FirstFitPlanner.java --- .../java/com/cloud/deploy/FirstFitPlanner.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java b/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java index 8aba02e11cb3..f5263e210459 100644 --- a/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java +++ b/server/src/main/java/com/cloud/deploy/FirstFitPlanner.java @@ -441,21 +441,6 @@ protected List reorderPods(Pair, Map> podCapacity return podIdsByCapacity; } - private List listDisabledClusters(long zoneId, Long podId) { - List disabledClusters = clusterDao.listDisabledClusters(zoneId, podId); - if (podId == null) { - //list all disabled clusters under this zone + clusters under any disabled pod of this zone - List clustersWithDisabledPods = clusterDao.listClustersWithDisabledPods(zoneId); - disabledClusters.addAll(clustersWithDisabledPods); - } - return disabledClusters; - } - - private List listDisabledPods(long zoneId) { - List disabledPods = podDao.listDisabledPods(zoneId); - return disabledPods; - } - protected Pair, Map> listClustersByCapacity(long id, long vmId, int requiredCpu, long requiredRam, ExcludeList avoid, boolean isZone) { //look at the aggregate available cpu and ram per cluster //although an aggregate value may be false indicator that a cluster can host a vm, it will at the least eliminate those clusters which definitely cannot From a31e24e68a9f212d1d26e7982f72dba3e8f14ed8 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 6 Sep 2021 08:33:07 +0200 Subject: [PATCH 11/14] fix #4534: vms are stopped in host maintenance --- .../cloud/resource/ResourceManagerImpl.java | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java index 6a4509cefb32..06a38a4c7946 100755 --- a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java @@ -1308,9 +1308,9 @@ private boolean doMaintain(final long hostId) { } List hosts = listAllUpAndEnabledHosts(Host.Type.Routing, host.getClusterId(), host.getPodId(), host.getDataCenterId()); - if (hosts == null || hosts.isEmpty()) { + if (CollectionUtils.isEmpty(hosts)) { s_logger.warn("Unable to find a host for vm migration in cluster: " + host.getClusterId()); - if (! isClusterWideMigrationSupported(host, vms, hosts)) { + if (! isClusterWideMigrationPossible(host.getDataCenterId(), vms, hosts)) { return false; } } @@ -1344,23 +1344,24 @@ private boolean doMaintain(final long hostId) { return true; } - private boolean isClusterWideMigrationSupported(Host host, List vms, List hosts) { - if (MIGRATE_VM_ACROSS_CLUSTERS.valueIn(host.getDataCenterId())) { - s_logger.info("Looking for hosts across different clusters in zone: " + host.getDataCenterId()); - hosts = listAllUpAndEnabledHosts(Host.Type.Routing, null, null, host.getDataCenterId()); - if (hosts == null || hosts.isEmpty()) { - s_logger.warn("Unable to find a host for vm migration in zone: " + host.getDataCenterId()); + private boolean isClusterWideMigrationPossible(long zoneId, List vms, List hosts) { + if (MIGRATE_VM_ACROSS_CLUSTERS.valueIn(zoneId)) { + s_logger.info("Looking for hosts across different clusters in zone: " + zoneId); + hosts.addAll(listAllUpAndEnabledHosts(Host.Type.Routing, null, null, zoneId)); + if (CollectionUtils.isEmpty(hosts)) { + s_logger.warn("Unable to find a host for vm migration in zone: " + zoneId); return false; } - // Dont migrate vm if it has volumes on cluster-wide pool + s_logger.info("Found hosts in the zone for vm migration: " + hosts); + // Don't migrate vm if it has volumes on cluster-wide pool for (final VMInstanceVO vm : vms) { if (_vmMgr.checkIfVmHasClusterWideVolumes(vm.getId())) { - s_logger.warn("Unable to migrate vm " + vm.getInstanceName() + " as it has volumes on cluster-wide pool"); + s_logger.warn(String.format("VM %s cannot be migrated across cluster as it has volumes on cluster-wide pool", vm)); return false; } } } else { - s_logger.warn("Not migrating VM across cluster since " + MIGRATE_VM_ACROSS_CLUSTERS.key() + " is false"); + s_logger.warn(String.format("VMs cannot be migrated across cluster since %s is false for zone ID: %d", MIGRATE_VM_ACROSS_CLUSTERS.key(), zoneId)); return false; } return true; From beeee5e2931fc20ae904e73e23776324e9aa5cc9 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 6 Sep 2021 08:38:00 +0200 Subject: [PATCH 12/14] fix #4534: across-cluster migration of vms with cluster-scoped pools is supported by vmware vmotion --- .../com/cloud/vm/VirtualMachineManagerImpl.java | 3 ++- .../com/cloud/resource/ResourceManagerImpl.java | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index ddf6aa10b09d..204c9688f5ef 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -3435,7 +3435,8 @@ public boolean checkIfVmHasClusterWideVolumes(Long vmId) { @Override public DataCenterDeployment getMigrationDeployment(final Long vmId, final Host host, final Long poolId, final ExcludeList excludes) { - if (MIGRATE_VM_ACROSS_CLUSTERS.valueIn(host.getDataCenterId()) && !checkIfVmHasClusterWideVolumes(vmId)) { + if (MIGRATE_VM_ACROSS_CLUSTERS.valueIn(host.getDataCenterId()) && + (HypervisorType.VMware.equals(host.getHypervisorType()) || !checkIfVmHasClusterWideVolumes(vmId))) { s_logger.info("Searching for hosts in the zone for vm migration"); List clustersToExclude = _clusterDao.listAllClusters(host.getDataCenterId()); List clusterList = _clusterDao.listByDcHyType(host.getDataCenterId(), host.getHypervisorType().toString()); diff --git a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java index 06a38a4c7946..9d17267deefd 100755 --- a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java @@ -1310,7 +1310,7 @@ private boolean doMaintain(final long hostId) { List hosts = listAllUpAndEnabledHosts(Host.Type.Routing, host.getClusterId(), host.getPodId(), host.getDataCenterId()); if (CollectionUtils.isEmpty(hosts)) { s_logger.warn("Unable to find a host for vm migration in cluster: " + host.getClusterId()); - if (! isClusterWideMigrationPossible(host.getDataCenterId(), vms, hosts)) { + if (! isClusterWideMigrationPossible(host, vms, hosts)) { return false; } } @@ -1344,24 +1344,24 @@ private boolean doMaintain(final long hostId) { return true; } - private boolean isClusterWideMigrationPossible(long zoneId, List vms, List hosts) { - if (MIGRATE_VM_ACROSS_CLUSTERS.valueIn(zoneId)) { - s_logger.info("Looking for hosts across different clusters in zone: " + zoneId); - hosts.addAll(listAllUpAndEnabledHosts(Host.Type.Routing, null, null, zoneId)); + private boolean isClusterWideMigrationPossible(Host host, List vms, List hosts) { + if (MIGRATE_VM_ACROSS_CLUSTERS.valueIn(host.getDataCenterId())) { + s_logger.info("Looking for hosts across different clusters in zone: " + host.getDataCenterId()); + hosts.addAll(listAllUpAndEnabledHosts(Host.Type.Routing, null, null, host.getDataCenterId())); if (CollectionUtils.isEmpty(hosts)) { - s_logger.warn("Unable to find a host for vm migration in zone: " + zoneId); + s_logger.warn("Unable to find a host for vm migration in zone: " + host.getDataCenterId()); return false; } s_logger.info("Found hosts in the zone for vm migration: " + hosts); // Don't migrate vm if it has volumes on cluster-wide pool for (final VMInstanceVO vm : vms) { - if (_vmMgr.checkIfVmHasClusterWideVolumes(vm.getId())) { + if (! HypervisorType.VMware.equals(host.getHypervisorType()) && _vmMgr.checkIfVmHasClusterWideVolumes(vm.getId())) { s_logger.warn(String.format("VM %s cannot be migrated across cluster as it has volumes on cluster-wide pool", vm)); return false; } } } else { - s_logger.warn(String.format("VMs cannot be migrated across cluster since %s is false for zone ID: %d", MIGRATE_VM_ACROSS_CLUSTERS.key(), zoneId)); + s_logger.warn(String.format("VMs cannot be migrated across cluster since %s is false for zone ID: %d", MIGRATE_VM_ACROSS_CLUSTERS.key(), host.getDataCenterId())); return false; } return true; From 75a8b0dcc9028b56b633065f36e62e2274ff13a7 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 6 Sep 2021 08:40:12 +0200 Subject: [PATCH 13/14] fix #4534: migrate systemvms is only possible across clusters in same pod to avoid potential network errors. --- .../main/java/com/cloud/vm/VirtualMachineManager.java | 2 +- .../java/com/cloud/vm/VirtualMachineManagerImpl.java | 9 ++++++--- .../java/com/cloud/resource/ResourceManagerImpl.java | 10 +++++++++- .../src/main/java/com/cloud/vm/UserVmManagerImpl.java | 2 +- 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java b/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java index 5c0cf77f2883..c192f876aac5 100644 --- a/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java +++ b/engine/api/src/main/java/com/cloud/vm/VirtualMachineManager.java @@ -251,7 +251,7 @@ static String getHypervisorHostname(String name) { boolean checkIfVmHasClusterWideVolumes(Long vmId); - DataCenterDeployment getMigrationDeployment(Long vmId, Host host, Long poolId, ExcludeList excludes); + DataCenterDeployment getMigrationDeployment(VirtualMachine vm, Host host, Long poolId, ExcludeList excludes); /** * Returns true if the VM's Root volume is allocated at a local storage pool diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 204c9688f5ef..4c498d114f93 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -3373,7 +3373,7 @@ private void orchestrateMigrateAway(final String vmUuid, final long srcHostId, f final ExcludeList excludes = new ExcludeList(); excludes.addHost(hostId); - DataCenterDeployment plan = getMigrationDeployment(vm.getId(), host, poolId, excludes); + DataCenterDeployment plan = getMigrationDeployment(vm, host, poolId, excludes); DeployDestination dest = null; while (true) { @@ -3434,9 +3434,9 @@ public boolean checkIfVmHasClusterWideVolumes(Long vmId) { } @Override - public DataCenterDeployment getMigrationDeployment(final Long vmId, final Host host, final Long poolId, final ExcludeList excludes) { + public DataCenterDeployment getMigrationDeployment(final VirtualMachine vm, final Host host, final Long poolId, final ExcludeList excludes) { if (MIGRATE_VM_ACROSS_CLUSTERS.valueIn(host.getDataCenterId()) && - (HypervisorType.VMware.equals(host.getHypervisorType()) || !checkIfVmHasClusterWideVolumes(vmId))) { + (HypervisorType.VMware.equals(host.getHypervisorType()) || !checkIfVmHasClusterWideVolumes(vm.getId()))) { s_logger.info("Searching for hosts in the zone for vm migration"); List clustersToExclude = _clusterDao.listAllClusters(host.getDataCenterId()); List clusterList = _clusterDao.listByDcHyType(host.getDataCenterId(), host.getHypervisorType().toString()); @@ -3446,6 +3446,9 @@ public DataCenterDeployment getMigrationDeployment(final Long vmId, final Host h for (Long clusterId : clustersToExclude) { excludes.addCluster(clusterId); } + if (VirtualMachine.systemVMs.contains(vm.getType())) { + return new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), null, null, poolId, null); + } return new DataCenterDeployment(host.getDataCenterId(), null, null, null, poolId, null); } return new DataCenterDeployment(host.getDataCenterId(), host.getPodId(), host.getClusterId(), null, poolId, null); diff --git a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java index 9d17267deefd..febac35a5f9d 100755 --- a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java @@ -1347,7 +1347,15 @@ private boolean doMaintain(final long hostId) { private boolean isClusterWideMigrationPossible(Host host, List vms, List hosts) { if (MIGRATE_VM_ACROSS_CLUSTERS.valueIn(host.getDataCenterId())) { s_logger.info("Looking for hosts across different clusters in zone: " + host.getDataCenterId()); - hosts.addAll(listAllUpAndEnabledHosts(Host.Type.Routing, null, null, host.getDataCenterId())); + Long podId = null; + for (final VMInstanceVO vm : vms) { + if (VirtualMachine.systemVMs.contains(vm.getType())) { + // SystemVMs can only be migrated to same pod + podId = host.getPodId(); + break; + } + } + hosts.addAll(listAllUpAndEnabledHosts(Host.Type.Routing, null, podId, host.getDataCenterId())); if (CollectionUtils.isEmpty(hosts)) { s_logger.warn("Unable to find a host for vm migration in zone: " + host.getDataCenterId()); return false; diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 957980bf9f75..b8a38349207c 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -6015,7 +6015,7 @@ private DeployDestination chooseVmMigrationDestination(VMInstanceVO vm, Host src final Host host = _hostDao.findById(srcHostId); ExcludeList excludes = new ExcludeList(); excludes.addHost(srcHostId); - final DataCenterDeployment plan = _itMgr.getMigrationDeployment(vm.getId(), host, null, excludes); + final DataCenterDeployment plan = _itMgr.getMigrationDeployment(vm, host, null, excludes); try { return _planningMgr.planDeployment(profile, plan, excludes, null); } catch (final AffinityConflictException e2) { From 13086b1b9f16224aae1a7da003837f2b0b8eeecf Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 6 Sep 2021 15:00:58 +0200 Subject: [PATCH 14/14] fix #4534: code optimization --- .../main/java/com/cloud/resource/ResourceManagerImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java index 5ecd132cbe89..2b4e2334871f 100755 --- a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java @@ -1370,9 +1370,13 @@ private boolean isClusterWideMigrationPossible(Host host, List vms return false; } s_logger.info("Found hosts in the zone for vm migration: " + hosts); + if (HypervisorType.VMware.equals(host.getHypervisorType())) { + s_logger.debug("Skipping pool check of volumes on VMware environment because across-cluster vm migration is supported by vMotion"); + return true; + } // Don't migrate vm if it has volumes on cluster-wide pool for (final VMInstanceVO vm : vms) { - if (! HypervisorType.VMware.equals(host.getHypervisorType()) && _vmMgr.checkIfVmHasClusterWideVolumes(vm.getId())) { + if (_vmMgr.checkIfVmHasClusterWideVolumes(vm.getId())) { s_logger.warn(String.format("VM %s cannot be migrated across cluster as it has volumes on cluster-wide pool", vm)); return false; }