@@ -1454,17 +1454,27 @@ protected boolean zoneWideVolumeRequiresStorageMotion(PrimaryDataStore volumeDat
14541454 return false ;
14551455 }
14561456
1457- @ Override
1458- public Ternary <Pair <List <? extends Host >, Integer >, List <? extends Host >, Map <Host , Boolean >> listHostsForMigrationOfVM (final VirtualMachine vm , final Long startIndex , final Long pageSize ,
1459- final String keyword , List <VirtualMachine > vmList ) {
1460-
1461- validateVmForHostMigration (vm );
1457+ /**
1458+ * Get technically compatible hosts for VM migration (storage, hypervisor, UEFI filtering).
1459+ * This determines which hosts are technically capable of hosting the VM based on
1460+ * storage requirements, hypervisor capabilities, and UEFI requirements.
1461+ *
1462+ * @param vm The virtual machine to migrate
1463+ * @param startIndex Starting index for pagination
1464+ * @param pageSize Page size for pagination
1465+ * @param keyword Keyword filter for host search
1466+ * @return Ternary containing: (all hosts with count, filtered compatible hosts, storage motion requirements map)
1467+ */
1468+ protected Ternary <Pair <List <HostVO >, Integer >, List <HostVO >, Map <Host , Boolean >> getTechnicallyCompatibleHosts (
1469+ final VirtualMachine vm ,
1470+ final Long startIndex ,
1471+ final Long pageSize ,
1472+ final String keyword ) {
14621473
1474+ // GPU check
14631475 if (_serviceOfferingDetailsDao .findDetail (vm .getServiceOfferingId (), GPU .Keys .pciDevice .toString ()) != null ) {
14641476 logger .info (" Live Migration of GPU enabled VM : " + vm .getInstanceName () + " is not supported" );
1465- // Return empty list.
1466- return new Ternary <>(new Pair <>(new ArrayList <>(), 0 ),
1467- new ArrayList <>(), new HashMap <>());
1477+ return new Ternary <>(new Pair <>(new ArrayList <>(), 0 ), new ArrayList <>(), new HashMap <>());
14681478 }
14691479
14701480 final long srcHostId = vm .getHostId ();
@@ -1478,6 +1488,7 @@ public Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Ho
14781488 ex .addProxyObject (vm .getUuid (), "vmId" );
14791489 throw ex ;
14801490 }
1491+
14811492 String srcHostVersion = srcHost .getHypervisorVersion ();
14821493 if (HypervisorType .KVM .equals (srcHost .getHypervisorType ()) && srcHostVersion == null ) {
14831494 srcHostVersion = "" ;
@@ -1513,7 +1524,7 @@ public Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Ho
15131524 List <HostVO > allHosts = null ;
15141525 List <HostVO > filteredHosts = null ;
15151526 final Map <Host , Boolean > requiresStorageMotion = new HashMap <>();
1516- DataCenterDeployment plan = null ;
1527+
15171528 if (canMigrateWithStorage ) {
15181529 Long podId = !VirtualMachine .Type .User .equals (vm .getType ()) ? srcHost .getPodId () : null ;
15191530 allHostsPair = searchForServers (startIndex , pageSize , null , hostType , null , srcHost .getDataCenterId (), podId , null , null , keyword ,
@@ -1562,7 +1573,6 @@ public Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Ho
15621573 if (CollectionUtils .isEmpty (filteredHosts )) {
15631574 return new Ternary <>(new Pair <>(allHosts , allHostsPair .second ()), new ArrayList <>(), new HashMap <>());
15641575 }
1565- plan = new DataCenterDeployment (srcHost .getDataCenterId (), podId , null , null , null , null );
15661576 } else {
15671577 final Long cluster = srcHost .getClusterId ();
15681578 if (logger .isDebugEnabled ()) {
@@ -1571,19 +1581,37 @@ public Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Ho
15711581 allHostsPair = searchForServers (startIndex , pageSize , null , hostType , null , null , null , cluster , null , keyword , null , null , null ,
15721582 null , srcHost .getId ());
15731583 allHosts = allHostsPair .first ();
1574- plan = new DataCenterDeployment ( srcHost . getDataCenterId (), srcHost . getPodId (), srcHost . getClusterId (), null , null , null ) ;
1584+ filteredHosts = allHosts ;
15751585 }
15761586
1577- final Pair <List <? extends Host >, Integer > otherHosts = new Pair <>(allHosts , allHostsPair .second ());
1587+ final Pair <List <HostVO >, Integer > allHostsPairResult = new Pair <>(allHosts , allHostsPair .second ());
15781588 Pair <Boolean , List <HostVO >> uefiFilteredResult = filterUefiHostsForMigration (allHosts , filteredHosts , vm );
15791589 if (!uefiFilteredResult .first ()) {
1580- return new Ternary <>(otherHosts , new ArrayList <>(), new HashMap <>());
1590+ return new Ternary <>(allHostsPairResult , new ArrayList <>(), new HashMap <>());
15811591 }
15821592 filteredHosts = uefiFilteredResult .second ();
15831593
1584- List <Host > suitableHosts = new ArrayList <>();
1594+ return new Ternary <>(allHostsPairResult , filteredHosts , requiresStorageMotion );
1595+ }
1596+
1597+ /**
1598+ * Apply affinity group constraints and other exclusion rules for VM migration.
1599+ * This builds an ExcludeList based on affinity groups, DPDK requirements, and dedicated resources.
1600+ *
1601+ * @param vm The virtual machine to migrate
1602+ * @param vmProfile The VM profile
1603+ * @param plan The deployment plan
1604+ * @param vmList List of VMs with current/simulated placements for affinity processing
1605+ * @return ExcludeList containing hosts to avoid
1606+ */
1607+ protected ExcludeList applyAffinityConstraints (
1608+ final VirtualMachine vm ,
1609+ final VirtualMachineProfile vmProfile ,
1610+ final DataCenterDeployment plan ,
1611+ final List <VirtualMachine > vmList ) {
1612+
15851613 final ExcludeList excludes = new ExcludeList ();
1586- excludes .addHost (srcHostId );
1614+ excludes .addHost (vm . getHostId () );
15871615
15881616 if (dpdkHelper .isVMDpdkEnabled (vm .getId ())) {
15891617 excludeNonDPDKEnabledHosts (plan , excludes );
@@ -1599,13 +1627,37 @@ public Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Ho
15991627 }
16001628
16011629 if (vm .getType () == VirtualMachine .Type .User || vm .getType () == VirtualMachine .Type .DomainRouter ) {
1602- final DataCenterVO dc = _dcDao .findById (srcHost .getDataCenterId ());
1630+ final DataCenterVO dc = _dcDao .findById (plan .getDataCenterId ());
16031631 _dpMgr .checkForNonDedicatedResources (vmProfile , dc , excludes );
16041632 }
16051633
1634+ return excludes ;
1635+ }
1636+
1637+ /**
1638+ * Get hosts with available capacity using host allocators, and apply architecture filtering.
1639+ *
1640+ * @param vm The virtual machine (for architecture filtering)
1641+ * @param vmProfile The VM profile
1642+ * @param plan The deployment plan
1643+ * @param compatibleHosts List of technically compatible hosts
1644+ * @param excludes ExcludeList with hosts to avoid
1645+ * @param srcHost Source host (for architecture filtering)
1646+ * @return List of suitable hosts with capacity
1647+ */
1648+ protected List <Host > getCapableSuitableHosts (
1649+ final VirtualMachine vm ,
1650+ final VirtualMachineProfile vmProfile ,
1651+ final DataCenterDeployment plan ,
1652+ final List <HostVO > compatibleHosts ,
1653+ final ExcludeList excludes ,
1654+ final Host srcHost ) {
1655+
1656+ List <Host > suitableHosts = new ArrayList <>();
1657+
16061658 for (final HostAllocator allocator : hostAllocators ) {
1607- if (CollectionUtils .isNotEmpty (filteredHosts )) {
1608- suitableHosts = allocator .allocateTo (vmProfile , plan , Host .Type .Routing , excludes , filteredHosts , HostAllocator .RETURN_UPTO_ALL , false );
1659+ if (CollectionUtils .isNotEmpty (compatibleHosts )) {
1660+ suitableHosts = allocator .allocateTo (vmProfile , plan , Host .Type .Routing , excludes , compatibleHosts , HostAllocator .RETURN_UPTO_ALL , false );
16091661 } else {
16101662 suitableHosts = allocator .allocateTo (vmProfile , plan , Host .Type .Routing , excludes , HostAllocator .RETURN_UPTO_ALL , false );
16111663 }
@@ -1631,6 +1683,43 @@ public Ternary<Pair<List<? extends Host>, Integer>, List<? extends Host>, Map<Ho
16311683 }
16321684 }
16331685
1686+ return suitableHosts ;
1687+ }
1688+
1689+ @ Override
1690+ public Ternary <Pair <List <? extends Host >, Integer >, List <? extends Host >, Map <Host , Boolean >> listHostsForMigrationOfVM (final VirtualMachine vm , final Long startIndex , final Long pageSize ,
1691+ final String keyword , List <VirtualMachine > vmList ) {
1692+
1693+ validateVmForHostMigration (vm );
1694+
1695+ // Get technically compatible hosts (storage, hypervisor, UEFI)
1696+ Ternary <Pair <List <HostVO >, Integer >, List <HostVO >, Map <Host , Boolean >> compatibilityResult =
1697+ getTechnicallyCompatibleHosts (vm , startIndex , pageSize , keyword );
1698+
1699+ Pair <List <HostVO >, Integer > allHostsPair = compatibilityResult .first ();
1700+ List <HostVO > filteredHosts = compatibilityResult .second ();
1701+ Map <Host , Boolean > requiresStorageMotion = compatibilityResult .third ();
1702+
1703+ // If no compatible hosts, return early
1704+ if (CollectionUtils .isEmpty (filteredHosts )) {
1705+ final Pair <List <? extends Host >, Integer > otherHosts = new Pair <>(allHostsPair .first (), allHostsPair .second ());
1706+ return new Ternary <>(otherHosts , new ArrayList <>(), requiresStorageMotion );
1707+ }
1708+
1709+ // Create deployment plan and VM profile
1710+ final Host srcHost = _hostDao .findById (vm .getHostId ());
1711+ final DataCenterDeployment plan = new DataCenterDeployment (
1712+ srcHost .getDataCenterId (), srcHost .getPodId (), srcHost .getClusterId (), null , null , null );
1713+ final VirtualMachineProfile vmProfile = new VirtualMachineProfileImpl (
1714+ vm , null , _offeringDao .findById (vm .getId (), vm .getServiceOfferingId ()), null , null );
1715+
1716+ // Apply affinity constraints
1717+ final ExcludeList excludes = applyAffinityConstraints (vm , vmProfile , plan , vmList );
1718+
1719+ // Get hosts with capacity
1720+ List <Host > suitableHosts = getCapableSuitableHosts (vm , vmProfile , plan , filteredHosts , excludes , srcHost );
1721+
1722+ final Pair <List <? extends Host >, Integer > otherHosts = new Pair <>(allHostsPair .first (), allHostsPair .second ());
16341723 return new Ternary <>(otherHosts , suitableHosts , requiresStorageMotion );
16351724 }
16361725
0 commit comments