Skip to content

Commit d5e5b48

Browse files
author
Ranier Amorim
committed
fix: skip VMs with host passthrough during DRS plan generation
When iterating over VMs in getBestMigration, the call to listHostsForMigrationOfVM throws InvalidParameterValueException for VMs using a vGPU passthrough profile. This exception was not caught inside the loop, causing it to propagate up and abort the entire DRS plan generation for the cluster, leaving all other eligible VMs without a migration plan. Fix wraps the listHostsForMigrationOfVM call in a try-catch block. When the exception is caught, the VM is skipped with a debug log message and the loop continues evaluating the remaining VMs. Also adds unit test testGetBestMigrationSkipsPassthroughVm to verify that a VM throwing InvalidParameterValueException is skipped while other eligible VMs are still considered for migration. Fixes: #13098
1 parent f9513b4 commit d5e5b48

2 files changed

Lines changed: 52 additions & 3 deletions

File tree

server/src/main/java/org/apache/cloudstack/cluster/ClusterDrsServiceImpl.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -449,9 +449,15 @@ Pair<VirtualMachine, Host> getBestMigration(Cluster cluster, ClusterDrsAlgorithm
449449
) {
450450
continue;
451451
}
452-
Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>> hostsForMigrationOfVM = managementServer
453-
.listHostsForMigrationOfVM(
454-
vm, 0L, 500L, null, vmList);
452+
Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Host, Boolean>> hostsForMigrationOfVM;
453+
try {
454+
hostsForMigrationOfVM = managementServer
455+
.listHostsForMigrationOfVM(
456+
vm, 0L, 500L, null, vmList);
457+
} catch (InvalidParameterValueException e) {
458+
logger.debug("Skipping VM {} for DRS, unsupported operation: {}", vm, e.getMessage());
459+
continue;
460+
}
455461
List<? extends Host> compatibleDestinationHosts = hostsForMigrationOfVM.first().first();
456462
List<? extends Host> suitableDestinationHosts = hostsForMigrationOfVM.second();
457463

server/src/test/java/org/apache/cloudstack/cluster/ClusterDrsServiceImplTest.java

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,49 @@ public void testGetBestMigration() throws ConfigurationException {
404404
assertEquals(vm1, bestMigration.first());
405405
}
406406

407+
@Test
408+
public void testGetBestMigrationSkipsPassthroughVm() throws ConfigurationException {
409+
ClusterVO cluster = Mockito.mock(ClusterVO.class);
410+
Mockito.when(cluster.getId()).thenReturn(1L);
411+
412+
HostVO destHost = Mockito.mock(HostVO.class);
413+
Mockito.when(destHost.getClusterId()).thenReturn(1L);
414+
415+
VMInstanceVO vmPassthrough = Mockito.mock(VMInstanceVO.class);
416+
Mockito.when(vmPassthrough.getId()).thenReturn(1L);
417+
Mockito.when(vmPassthrough.getType()).thenReturn(VirtualMachine.Type.User);
418+
Mockito.when(vmPassthrough.getState()).thenReturn(VirtualMachine.State.Running);
419+
Mockito.when(vmPassthrough.getDetails()).thenReturn(Collections.emptyMap());
420+
421+
VMInstanceVO vmNormal = Mockito.mock(VMInstanceVO.class);
422+
Mockito.when(vmNormal.getId()).thenReturn(2L);
423+
Mockito.when(vmNormal.getType()).thenReturn(VirtualMachine.Type.User);
424+
Mockito.when(vmNormal.getState()).thenReturn(VirtualMachine.State.Running);
425+
Mockito.when(vmNormal.getDetails()).thenReturn(Collections.emptyMap());
426+
427+
List<VirtualMachine> vmList = new ArrayList<>();
428+
vmList.add(vmPassthrough);
429+
vmList.add(vmNormal);
430+
431+
ServiceOffering serviceOffering = Mockito.mock(ServiceOffering.class);
432+
Map<Long, ServiceOffering> vmIdServiceOfferingMap = new HashMap<>();
433+
vmIdServiceOfferingMap.put(vmPassthrough.getId(), serviceOffering);
434+
vmIdServiceOfferingMap.put(vmNormal.getId(), serviceOffering);
435+
436+
Mockito.when(managementServer.listHostsForMigrationOfVM(vmPassthrough, 0L, 500L, null, vmList))
437+
.thenThrow(new InvalidParameterValueException("Unsupported operation, VM uses host passthrough, cannot migrate"));
438+
Mockito.when(managementServer.listHostsForMigrationOfVM(vmNormal, 0L, 500L, null, vmList)).thenReturn(
439+
new Ternary<>(new Pair<>(List.of(destHost), 1), List.of(destHost), Map.of(destHost, false)));
440+
Mockito.when(balancedAlgorithm.getMetrics(cluster, vmNormal, serviceOffering, destHost, new HashMap<>(),
441+
new HashMap<>(), false)).thenReturn(new Ternary<>(1.0, 0.5, 1.5));
442+
443+
Pair<VirtualMachine, Host> bestMigration = clusterDrsService.getBestMigration(cluster, balancedAlgorithm,
444+
vmList, vmIdServiceOfferingMap, new HashMap<>(), new HashMap<>());
445+
446+
assertEquals(vmNormal, bestMigration.first());
447+
assertEquals(destHost, bestMigration.second());
448+
}
449+
407450
@Test
408451
public void testGetBestMigrationDifferentCluster() throws ConfigurationException {
409452
ClusterVO cluster = Mockito.mock(ClusterVO.class);

0 commit comments

Comments
 (0)