From 51ea345a076a72cfeefecbf12ef7bc7b84569a0f Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Thu, 18 Feb 2021 22:09:25 +0000 Subject: [PATCH 01/12] 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/12] #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 f5aed32ebddef19b9b2f1bed724bf0b16c69f0b6 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 16 Mar 2021 14:04:00 +0000 Subject: [PATCH 03/12] #4378: fix mistake --- .../api/command/admin/systemvm/MigrateSystemVMCmd.java | 4 ++-- 1 file changed, 2 insertions(+), 2 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 1b8d9e0df759..0526a12742d6 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 @@ -122,8 +122,8 @@ public String getEventDescription() { @Override public void execute() { - if (getHostId() == null && getStorageId() == null) { - 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 { From 92b8f7370c599a2260a2055ca8fb13166bea6b52 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 17 Mar 2021 13:33:39 +0000 Subject: [PATCH 04/12] #4378: fix issue when migrate systemvm --- .../api/command/admin/systemvm/MigrateSystemVMCmd.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) 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 0526a12742d6..afaa8e9f81c4 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 @@ -149,7 +149,11 @@ public void execute() { } } CallContext.current().setEventDetails("VM Id: " + getVirtualMachineId() + " to host Id: " + getHostId()); - migratedVm = _userVmService.migrateVirtualMachineWithVolume(getVirtualMachineId(), destinationHost, new HashMap()); + if (destinationHost == null) { + migratedVm = _userVmService.migrateVirtualMachine(getVirtualMachineId(), null); + } else { + migratedVm = _userVmService.migrateVirtualMachineWithVolume(getVirtualMachineId(), destinationHost, new HashMap()); + } } if (migratedVm != null) { // return the generic system VM instance response From c1a1e2a08c9405e64f30a333f83e39795f4a7f21 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 22 Mar 2021 15:17:42 +0000 Subject: [PATCH 05/12] #4378 add autoselect to migrate api commands --- .../java/org/apache/cloudstack/api/ApiConstants.java | 1 + .../command/admin/systemvm/MigrateSystemVMCmd.java | 12 ++++++++++++ .../api/command/admin/vm/MigrateVMCmd.java | 12 ++++++++++++ ui/src/views/compute/MigrateWizard.vue | 10 +++++----- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 93f6e5ebd494..16869689568f 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -29,6 +29,7 @@ public class ApiConstants { public static final String ANNOTATION = "annotation"; public static final String API_KEY = "apikey"; public static final String ASYNC_BACKUP = "asyncbackup"; + public static final String AUTO_SELECT = "autoselect"; public static final String USER_API_KEY = "userapikey"; public static final String APPLIED = "applied"; public static final String LIST_LB_VMIPS = "lbvmips"; 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 afaa8e9f81c4..ea046d577fe3 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 @@ -75,6 +75,12 @@ public class MigrateSystemVMCmd extends BaseAsyncCmd { description = "Destination storage pool ID to migrate VM volumes to. Required for migrating the root disk volume") private Long storageId; + @Parameter(name = ApiConstants.AUTO_SELECT, + since = "4.16.0", + type = CommandType.BOOLEAN, + description = "Automatically select a destination host which do not require storage migration, if hostId and storageId are not specified. false by default") + private Boolean autoSelect; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -91,6 +97,10 @@ public Long getStorageId() { return storageId; } + public Boolean isAutoSelect() { + return autoSelect != null ? autoSelect : false; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -147,6 +157,8 @@ public void execute() { 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"); } + } else if (! isAutoSelect()) { + throw new InvalidParameterValueException("Please specify a host or storage as destination, or pass 'autoselect=true' to automatically select a destination host which do not require storage migration"); } CallContext.current().setEventDetails("VM Id: " + getVirtualMachineId() + " to host Id: " + getHostId()); if (destinationHost == null) { 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 1ffbc993cc64..616d652391d4 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 @@ -77,6 +77,12 @@ public class MigrateVMCmd extends BaseAsyncCmd { description = "Destination storage pool ID to migrate VM volumes to. Required for migrating the root disk volume") private Long storageId; + @Parameter(name = ApiConstants.AUTO_SELECT, + since = "4.16.0", + type = CommandType.BOOLEAN, + description = "Automatically select a destination host which do not require storage migration, if hostId and storageId are not specified. false by default") + private Boolean autoSelect; + ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -93,6 +99,10 @@ public Long getStoragePoolId() { return storageId; } + public Boolean isAutoSelect() { + return autoSelect != null ? autoSelect : false; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -151,6 +161,8 @@ public void execute() { 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()); + } else if (! isAutoSelect()) { + throw new InvalidParameterValueException("Please specify a host or storage as destination, or pass 'autoselect=true' to automatically select a destination host which do not require storage migration"); } // OfflineMigration performed when this parameter is specified diff --git a/ui/src/views/compute/MigrateWizard.vue b/ui/src/views/compute/MigrateWizard.vue index 04034983faa7..8c0a4d32fc43 100644 --- a/ui/src/views/compute/MigrateWizard.vue +++ b/ui/src/views/compute/MigrateWizard.vue @@ -84,7 +84,7 @@
- + {{ $t('label.ok') }}
@@ -168,6 +168,7 @@ export default { this.hosts.sort((a, b) => { return b.suitableformigration - a.suitableformigration }) + this.hosts.unshift({ id: -1, name: 'autoselect', suitableformigration: true, requiresstoragemigration: false }) this.totalCount = response.findhostsformigrationresponse.count }).catch(error => { this.$message.error(`${this.$t('message.load.host.failed')}: ${error}`) @@ -184,10 +185,9 @@ export default { var migrateApi = isUserVm ? this.selectedHost.requiresStorageMotion ? 'migrateVirtualMachineWithVolume' : 'migrateVirtualMachine' : 'migrateSystemVm' - api(migrateApi, { - hostid: this.selectedHost.id, - virtualmachineid: this.resource.id - }).then(response => { + var migrateParams = this.selectedHost.id === -1 ? { autoselect: true, virtualmachineid: this.resource.id } + : { hostid: this.selectedHost.id, virtualmachineid: this.resource.id } + api(migrateApi, migrateParams).then(response => { var migrateResponse = isUserVm ? this.selectedHost.requiresStorageMotion ? response.migratevirtualmachinewithvolumeresponse : response.migratevirtualmachineresponse : response.migratesystemvmresponse From 62a4886ea622773c8d7ef7d68b1cd6ab53152121 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 21 Jun 2021 11:00:23 +0000 Subject: [PATCH 06/12] #4378: more ui change --- ui/src/views/compute/MigrateWizard.vue | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ui/src/views/compute/MigrateWizard.vue b/ui/src/views/compute/MigrateWizard.vue index 8c0a4d32fc43..415f74a12346 100644 --- a/ui/src/views/compute/MigrateWizard.vue +++ b/ui/src/views/compute/MigrateWizard.vue @@ -45,7 +45,9 @@ v-else />
- {{ record.memoryused | byteToGigabyte }} GB + + {{ record.memoryused | byteToGigabyte }} GB +
{{ record.memoryallocatedpercentage }} @@ -168,7 +170,12 @@ export default { this.hosts.sort((a, b) => { return b.suitableformigration - a.suitableformigration }) - this.hosts.unshift({ id: -1, name: 'autoselect', suitableformigration: true, requiresstoragemigration: false }) + for (const key in this.hosts) { + if (this.hosts[key].suitableformigration && !this.hosts[key].requiresstoragemigration) { + this.hosts.unshift({ id: -1, name: 'autoselect', suitableformigration: true, requiresstoragemigration: false }) + break + } + } this.totalCount = response.findhostsformigrationresponse.count }).catch(error => { this.$message.error(`${this.$t('message.load.host.failed')}: ${error}`) From a258544ca957d77077e0d3eb5caf54bb34d713d7 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Mon, 21 Jun 2021 12:06:04 +0000 Subject: [PATCH 07/12] #4378: add label label.migrate.auto.select --- ui/public/locales/en.json | 1 + ui/src/views/compute/MigrateWizard.vue | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 39d213667656..af2b75840825 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -1355,6 +1355,7 @@ "label.metrics.network.usage": "Network Usage", "label.metrics.network.write": "Write", "label.metrics.num.cpu.cores": "Cores", +"label.migrate.auto.select": "AutoSelect", "label.migrate.data.from.image.store": "Migrate Data from Image store", "label.migrate.instance.to": "Migrate instance to", "label.migrate.instance.to.host": "Migrate instance to another host", diff --git a/ui/src/views/compute/MigrateWizard.vue b/ui/src/views/compute/MigrateWizard.vue index 415f74a12346..f8740826f0a9 100644 --- a/ui/src/views/compute/MigrateWizard.vue +++ b/ui/src/views/compute/MigrateWizard.vue @@ -172,7 +172,7 @@ export default { }) for (const key in this.hosts) { if (this.hosts[key].suitableformigration && !this.hosts[key].requiresstoragemigration) { - this.hosts.unshift({ id: -1, name: 'autoselect', suitableformigration: true, requiresstoragemigration: false }) + this.hosts.unshift({ id: -1, name: this.$t('label.migrate.auto.select'), suitableformigration: true, requiresstoragemigration: false }) break } } From 90b1ff5e01275bd8976f179075516aa6483c465e Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 25 Jun 2021 13:16:01 +0000 Subject: [PATCH 08/12] #4378: add method chooseVmMigrationDestination --- .../java/com/cloud/vm/UserVmManagerImpl.java | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index dccae7fad991..78ff79acaf74 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); - 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"); - } + dest = chooseVmMigrationDestination(vm, srcHost); } else { dest = checkVmMigrationDestination(vm, srcHost, destinationHost); } @@ -5932,6 +5918,25 @@ public VirtualMachine migrateVirtualMachine(Long vmId, Host destinationHost) thr return findMigratedVm(vm.getId(), vm.getType()); } + private DeployDestination chooseVmMigrationDestination(VMInstanceVO vm, Host srcHost) { + 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 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); + try { + return _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"); + } + } + private DeployDestination checkVmMigrationDestination(VMInstanceVO vm, Host srcHost, Host destinationHost) throws VirtualMachineMigrationException { if (destinationHost == null) { return null; From e7216e18a89dc0d81c8a0feedd503bc707c9b31e Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Tue, 29 Jun 2021 15:14:49 +0000 Subject: [PATCH 09/12] #4378: fix vm migration wih storageid on vmware --- .../api/command/admin/vm/MigrateVMCmd.java | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 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 616d652391d4..5c916a53fdf3 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 @@ -152,7 +152,15 @@ public void execute() { } Host destinationHost = null; - if (getHostId() != null) { + // OfflineMigration performed when this parameter is specified + StoragePool destStoragePool = null; + if (getStoragePoolId() != null) { + destStoragePool = _storageService.getStoragePool(getStoragePoolId()); + if (destStoragePool == null) { + throw new InvalidParameterValueException("Unable to find the storage pool to migrate the VM"); + } + CallContext.current().setEventDetails("VM Id: " + getVirtualMachineId() + " to storage pool Id: " + getStoragePoolId()); + } else 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()); @@ -165,16 +173,6 @@ public void execute() { throw new InvalidParameterValueException("Please specify a host or storage as destination, or pass 'autoselect=true' to automatically select a destination host which do not require storage migration"); } - // OfflineMigration performed when this parameter is specified - StoragePool destStoragePool = null; - if (getStoragePoolId() != null) { - destStoragePool = _storageService.getStoragePool(getStoragePoolId()); - if (destStoragePool == null) { - throw new InvalidParameterValueException("Unable to find the storage pool to migrate the VM"); - } - CallContext.current().setEventDetails("VM Id: " + getVirtualMachineId() + " to storage pool Id: " + getStoragePoolId()); - } - try { VirtualMachine migratedVm = null; if (getStoragePoolId() == null) { From 6e54dc33d10595e083f0ae6fa7588e05281ddd5c Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 2 Jul 2021 10:46:52 +0000 Subject: [PATCH 10/12] #4378: add method to collect vm disk/network statistics --- .../java/com/cloud/vm/UserVmManagerImpl.java | 33 ++++++++++++------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 78ff79acaf74..979981b13a7d 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -963,8 +963,7 @@ private UserVm rebootVirtualMachine(long userId, long vmId, boolean enterSetup, } if (vm.getState() == State.Running && vm.getHostId() != null) { - collectVmDiskStatistics(vm); - collectVmNetworkStatistics(vm); + collectVmDiskAndNetworkStatistics(vm, State.Running); if (forced) { Host vmOnHost = _hostDao.findById(vm.getHostId()); @@ -5909,11 +5908,7 @@ public VirtualMachine migrateVirtualMachine(Long vmId, Host destinationHost) thr 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); - } + collectVmDiskAndNetworkStatistics(vmId, State.Running); _itMgr.migrate(vm.getUuid(), srcHostId, dest); return findMigratedVm(vm.getId(), vm.getType()); } @@ -7324,11 +7319,7 @@ else if (!answer.getResult()) { @Override public void prepareStop(VirtualMachineProfile profile) { - UserVmVO vm = _vmDao.findById(profile.getId()); - if (vm != null && vm.getState() == State.Stopping) { - collectVmDiskStatistics(vm); - collectVmNetworkStatistics(vm); - } + collectVmDiskAndNetworkStatistics(profile.getId(), State.Stopping); } @Override @@ -7670,4 +7661,22 @@ private Network getNetworkForOvfNetworkMapping(DataCenter zone, Account owner) t } return network; } + + private void collectVmDiskAndNetworkStatistics(Long vmId, State expectedState) { + UserVmVO uservm = _vmDao.findById(vmId); + if (uservm != null) { + collectVmDiskAndNetworkStatistics(uservm, expectedState); + } else { + s_logger.info(String.format("Skip collecting vm %s disk and network statistics as it is not user vm", uservm)); + } + } + + private void collectVmDiskAndNetworkStatistics(UserVm vm, State expectedState) { + if (expectedState == null || expectedState == vm.getState()) { + collectVmDiskStatistics(vm); + collectVmNetworkStatistics(vm); + } else { + s_logger.warn(String.format("Skip collecting vm %s disk and network statistics as the expected vm state is %s but actual state is %s", vm, expectedState, vm.getState())); + } + } } From 0d8175c7ea3f8a661482dee48829f7469d771b6a Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Fri, 23 Jul 2021 07:04:34 +0000 Subject: [PATCH 11/12] #4378: set autoSelect to default 'true' --- .../api/command/admin/systemvm/MigrateSystemVMCmd.java | 2 +- .../apache/cloudstack/api/command/admin/vm/MigrateVMCmd.java | 2 +- 2 files changed, 2 insertions(+), 2 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 ea046d577fe3..c7be8cc637ad 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 @@ -98,7 +98,7 @@ public Long getStorageId() { } public Boolean isAutoSelect() { - return autoSelect != null ? autoSelect : false; + return autoSelect != null ? autoSelect : true; } ///////////////////////////////////////////////////// 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 5c916a53fdf3..c0df6f17805d 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 @@ -100,7 +100,7 @@ public Long getStoragePoolId() { } public Boolean isAutoSelect() { - return autoSelect != null ? autoSelect : false; + return autoSelect != null ? autoSelect : true; } ///////////////////////////////////////////////////// From 6530abeafdc9b0dc18268a488f24591d539f3c62 Mon Sep 17 00:00:00 2001 From: Wei Zhou Date: Wed, 28 Jul 2021 10:36:24 +0000 Subject: [PATCH 12/12] #4378: use BooleanUtils.isNotFalse --- .../api/command/admin/systemvm/MigrateSystemVMCmd.java | 3 ++- .../apache/cloudstack/api/command/admin/vm/MigrateVMCmd.java | 3 ++- 2 files changed, 4 insertions(+), 2 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 c7be8cc637ad..decc722e86f1 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 @@ -30,6 +30,7 @@ import org.apache.cloudstack.api.response.StoragePoolResponse; import org.apache.cloudstack.api.response.SystemVmResponse; import org.apache.cloudstack.context.CallContext; +import org.apache.commons.lang.BooleanUtils; import org.apache.log4j.Logger; import com.cloud.event.EventTypes; @@ -98,7 +99,7 @@ public Long getStorageId() { } public Boolean isAutoSelect() { - return autoSelect != null ? autoSelect : true; + return BooleanUtils.isNotFalse(autoSelect); } ///////////////////////////////////////////////////// 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 c0df6f17805d..2c68d86f4450 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 @@ -29,6 +29,7 @@ import org.apache.cloudstack.api.response.StoragePoolResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.context.CallContext; +import org.apache.commons.lang.BooleanUtils; import com.cloud.event.EventTypes; import com.cloud.exception.ConcurrentOperationException; @@ -100,7 +101,7 @@ public Long getStoragePoolId() { } public Boolean isAutoSelect() { - return autoSelect != null ? autoSelect : true; + return BooleanUtils.isNotFalse(autoSelect); } /////////////////////////////////////////////////////