2525import org .apache .commons .collections .CollectionUtils ;
2626import org .apache .commons .collections .ListUtils ;
2727import org .apache .commons .lang3 .ObjectUtils ;
28- import org .apache .commons .lang3 .StringUtils ;
2928import org .springframework .stereotype .Component ;
3029
3130import com .cloud .agent .manager .allocator .HostAllocator ;
3231import com .cloud .capacity .CapacityManager ;
33- import com .cloud .dc .ClusterDetailsDao ;
34- import com .cloud .dc .dao .ClusterDao ;
3532import com .cloud .deploy .DeploymentPlan ;
3633import com .cloud .deploy .DeploymentPlanner .ExcludeList ;
3734import com .cloud .host .Host ;
4340import com .cloud .storage .VMTemplateVO ;
4441import com .cloud .utils .Pair ;
4542import com .cloud .utils .component .AdapterBase ;
46- import com .cloud .vm .VirtualMachine ;
4743import com .cloud .vm .VirtualMachineProfile ;
4844
4945@ Component
@@ -53,142 +49,133 @@ public class RandomAllocator extends AdapterBase implements HostAllocator {
5349 @ Inject
5450 private ResourceManager _resourceMgr ;
5551 @ Inject
56- private ClusterDao clusterDao ;
57- @ Inject
58- private ClusterDetailsDao clusterDetailsDao ;
59- @ Inject
6052 private CapacityManager capacityManager ;
6153
62- protected List <HostVO > listHostsByTags (Host .Type type , long dcId , Long podId , Long clusterId , String offeringHostTag , String templateTag ) {
63- List <HostVO > taggedHosts = new ArrayList <>();
64- if (offeringHostTag != null ) {
65- taggedHosts .addAll (_hostDao .listByHostTag (type , clusterId , podId , dcId , offeringHostTag ));
66- }
67- if (templateTag != null ) {
68- List <HostVO > templateTaggedHosts = _hostDao .listByHostTag (type , clusterId , podId , dcId , templateTag );
69- if (taggedHosts .isEmpty ()) {
70- taggedHosts = templateTaggedHosts ;
71- } else {
72- taggedHosts .retainAll (templateTaggedHosts );
73- }
74- }
75- if (logger .isDebugEnabled ()) {
76- logger .debug (String .format ("Found %d hosts %s with type: %s, zone ID: %d, pod ID: %d, cluster ID: %s, offering host tag(s): %s, template tag: %s" ,
77- taggedHosts .size (),
78- (taggedHosts .isEmpty () ? "" : String .format ("(%s)" , StringUtils .join (taggedHosts .stream ().map (HostVO ::getId ).toArray (), "," ))),
79- type .name (), dcId , podId , clusterId , offeringHostTag , templateTag ));
80- }
81- return taggedHosts ;
82- }
83- private List <Host > findSuitableHosts (VirtualMachineProfile vmProfile , DeploymentPlan plan , Type type ,
84- ExcludeList avoid , List <? extends Host > hosts , int returnUpTo ,
54+ protected List <Host > findSuitableHosts (VirtualMachineProfile vmProfile , DeploymentPlan plan , Type type , ExcludeList avoid , List <? extends Host > hosts , int returnUpTo ,
8555 boolean considerReservedCapacity ) {
56+ if (type == Host .Type .Storage ) {
57+ return null ;
58+ }
59+
8660 long dcId = plan .getDataCenterId ();
8761 Long podId = plan .getPodId ();
8862 Long clusterId = plan .getClusterId ();
8963 ServiceOffering offering = vmProfile .getServiceOffering ();
90- List <? extends Host > hostsCopy = null ;
91- List <Host > suitableHosts = new ArrayList <>();
9264
93- if (type == Host .Type .Storage ) {
94- return suitableHosts ;
95- }
9665 String offeringHostTag = offering .getHostTag ();
97- VMTemplateVO template = (VMTemplateVO )vmProfile .getTemplate ();
98- String templateTag = template .getTemplateTag ();
99- String hostTag = null ;
100- if (ObjectUtils .anyNull (offeringHostTag , templateTag )) {
101- hostTag = offeringHostTag ;
102- hostTag = hostTag == null ? templateTag : String .format ("%s, %s" , hostTag , templateTag );
103- logger .debug (String .format ("Looking for hosts in dc [%s], pod [%s], cluster [%s] and complying with host tag(s): [%s]" , dcId , podId , clusterId , hostTag ));
104- } else {
105- logger .debug ("Looking for hosts in dc: " + dcId + " pod:" + podId + " cluster:" + clusterId );
106- }
107- if (hosts != null ) {
108- // retain all computing hosts, regardless of whether they support routing...it's random after all
109- hostsCopy = new ArrayList <>(hosts );
110- if (ObjectUtils .anyNotNull (offeringHostTag , templateTag )) {
111- hostsCopy .retainAll (listHostsByTags (type , dcId , podId , clusterId , offeringHostTag , templateTag ));
112- } else {
113- hostsCopy .retainAll (_hostDao .listAllHostsThatHaveNoRuleTag (type , clusterId , podId , dcId ));
114- }
115- } else {
116- // list all computing hosts, regardless of whether they support routing...it's random after all
117- if (offeringHostTag != null ) {
118- hostsCopy = listHostsByTags (type , dcId , podId , clusterId , offeringHostTag , templateTag );
119- } else {
120- hostsCopy = _hostDao .listAllHostsThatHaveNoRuleTag (type , clusterId , podId , dcId );
121- }
122- }
123- hostsCopy = ListUtils .union (hostsCopy , _hostDao .findHostsWithTagRuleThatMatchComputeOfferingTags (hostTag ));
66+ VMTemplateVO template = (VMTemplateVO ) vmProfile .getTemplate ();
67+ logger .debug ("Looking for hosts in zone [{}], pod [{}], cluster [{}]." , dcId , podId , clusterId );
68+
69+ List <? extends Host > availableHosts = retrieveHosts (type , (List <HostVO >) hosts , template , offeringHostTag , clusterId , podId , dcId );
12470
125- if (hostsCopy .isEmpty ()) {
126- logger .info ("No suitable host found for VM [{}] in {} ." , vmProfile , hostTag );
71+ if (availableHosts .isEmpty ()) {
72+ logger .info ("No suitable host found for VM [{}] in zone [{}], pod [{}], cluster [{}] ." , vmProfile , dcId , podId , clusterId );
12773 return null ;
12874 }
12975
130- logger .debug ("Random Allocator found {} hosts" , hostsCopy .size ());
131- if (hostsCopy .isEmpty ()) {
132- return suitableHosts ;
133- }
76+ return filterAvailableHosts (avoid , returnUpTo , considerReservedCapacity , availableHosts , offering );
77+ }
13478
135- Collections .shuffle (hostsCopy );
136- for (Host host : hostsCopy ) {
79+ protected List <Host > filterAvailableHosts (ExcludeList avoid , int returnUpTo , boolean considerReservedCapacity , List <? extends Host > availableHosts , ServiceOffering offering ) {
80+ logger .debug ("Random Allocator found [{}] available hosts. They will be checked if they are in the avoid set and for CPU capability and capacity." , availableHosts ::size );
81+ List <Host > suitableHosts = new ArrayList <>();
82+
83+ Collections .shuffle (availableHosts );
84+ for (Host host : availableHosts ) {
13785 if (suitableHosts .size () == returnUpTo ) {
13886 break ;
13987 }
88+
14089 if (avoid .shouldAvoid (host )) {
141- if (logger .isDebugEnabled ()) {
142- logger .debug ("Host name: " + host .getName () + ", hostId: " + host .getId () + " is in avoid set, skipping this and trying other available hosts" );
143- }
90+ logger .debug ("Host [{}] is in the avoid set, skipping it and trying other available hosts." , () -> host );
14491 continue ;
14592 }
146- Pair <Boolean , Boolean > cpuCapabilityAndCapacity = capacityManager .checkIfHostHasCpuCapabilityAndCapacity (host , offering , considerReservedCapacity );
147- if (!cpuCapabilityAndCapacity .first () || !cpuCapabilityAndCapacity .second ()) {
148- if (logger .isDebugEnabled ()) {
149- logger .debug ("Not using host " + host .getId () + "; host has cpu capability? " + cpuCapabilityAndCapacity .first () + ", host has capacity?" + cpuCapabilityAndCapacity .second ());
150- }
93+
94+ if (!hostHasCpuCapabilityAndCapacity (considerReservedCapacity , offering , host )) {
15195 continue ;
15296 }
153- if (logger .isDebugEnabled ()) {
154- logger .debug ("Found a suitable host, adding to list: " + host .getId ());
155- }
97+
98+ logger .debug ("Found the suitable host [{}], adding to list." , () -> host );
15699 suitableHosts .add (host );
157100 }
158- if (logger .isDebugEnabled ()) {
159- logger .debug ("Random Host Allocator returning " + suitableHosts .size () + " suitable hosts" );
160- }
101+
102+ logger .debug ("Random Host Allocator returning {} suitable hosts." , suitableHosts ::size );
161103 return suitableHosts ;
162104 }
163105
106+
107+ protected boolean hostHasCpuCapabilityAndCapacity (boolean considerReservedCapacity , ServiceOffering offering , Host host ) {
108+ Pair <Boolean , Boolean > cpuCapabilityAndCapacity = capacityManager .checkIfHostHasCpuCapabilityAndCapacity (host , offering , considerReservedCapacity );
109+ Boolean hasCpuCapability = cpuCapabilityAndCapacity .first ();
110+ Boolean hasCpuCapacity = cpuCapabilityAndCapacity .second ();
111+
112+ if (hasCpuCapability && hasCpuCapacity ) {
113+ logger .debug ("Host {} has enough CPU capability and CPU capacity." , host );
114+ return true ;
115+ }
116+
117+ logger .debug ("Not using host [{}]. Does the host have cpu capability? {}. Does the host have capacity? {}." , () -> host , () -> hasCpuCapability , () -> hasCpuCapacity );
118+ return false ;
119+ }
120+
121+ /**
122+ * @return all computing hosts, regardless of whether they support routing.
123+ */
124+ protected List <HostVO > retrieveHosts (Type type , List <HostVO > hosts , VMTemplateVO template , String offeringHostTag , Long clusterId , Long podId , long dcId ) {
125+ List <HostVO > availableHosts ;
126+ String templateTag = template .getTemplateTag ();
127+
128+ if (CollectionUtils .isNotEmpty (hosts )) {
129+ availableHosts = new ArrayList <>(hosts );
130+ } else {
131+ availableHosts = _resourceMgr .listAllUpAndEnabledHosts (type , clusterId , podId , dcId );
132+ }
133+
134+ if (ObjectUtils .anyNotNull (offeringHostTag , templateTag )) {
135+ retainHostsWithMatchingTags (availableHosts , type , clusterId , podId , dcId , offeringHostTag , templateTag );
136+ } else {
137+ List <HostVO > hostsWithNoRuleTag = _hostDao .listAllHostsThatHaveNoRuleTag (type , clusterId , podId , dcId );
138+ logger .debug ("Retaining hosts {} because they do not have rule tags." , hostsWithNoRuleTag );
139+ availableHosts .retainAll (hostsWithNoRuleTag );
140+ }
141+
142+ List <HostVO > hostsWithTagRuleThatMatchComputeOfferingTags = _hostDao .findHostsWithTagRuleThatMatchComputeOfferingTags (offeringHostTag );
143+ logger .debug ("Adding hosts {} to the available pool hosts because they match the compute offering's tag." , hostsWithTagRuleThatMatchComputeOfferingTags , offeringHostTag );
144+ availableHosts = ListUtils .union (availableHosts , hostsWithTagRuleThatMatchComputeOfferingTags );
145+
146+ return availableHosts ;
147+ }
148+
149+ protected void retainHostsWithMatchingTags (List <HostVO > availableHosts , Type type , long dcId , Long podId , Long clusterId , String offeringHostTag , String templateTag ) {
150+ logger .debug ("Hosts {} will be checked for template and host tags compatibility." , availableHosts );
151+
152+ if (offeringHostTag != null ) {
153+ List <HostVO > hostsWithHostTag = _hostDao .listByHostTag (type , clusterId , podId , dcId , offeringHostTag );
154+ logger .debug ("Retaining hosts {} because they match the offering host tag {}." , hostsWithHostTag , offeringHostTag );
155+ availableHosts .retainAll (hostsWithHostTag );
156+ }
157+
158+ if (templateTag != null ) {
159+ List <HostVO > hostsWithTemplateTag = _hostDao .listByHostTag (type , clusterId , podId , dcId , templateTag );
160+ logger .debug ("Retaining hosts {} because they match the template tag {}." , hostsWithTemplateTag , offeringHostTag );
161+ availableHosts .retainAll (hostsWithTemplateTag );
162+ }
163+
164+ logger .debug ("Remaining hosts after template tag and host tags validations are {}." , availableHosts );
165+ }
166+
164167 @ Override
165168 public List <Host > allocateTo (VirtualMachineProfile vmProfile , DeploymentPlan plan , Type type , ExcludeList avoid , int returnUpTo ) {
166- return allocateTo (vmProfile , plan , type , avoid , returnUpTo , true );
169+ return allocateTo (vmProfile , plan , type , avoid , null , returnUpTo , true );
167170 }
168171
169172 @ Override
170- public List <Host > allocateTo (VirtualMachineProfile vmProfile , DeploymentPlan plan , Type type ,
171- ExcludeList avoid , List <? extends Host > hosts , int returnUpTo ,
173+ public List <Host > allocateTo (VirtualMachineProfile vmProfile , DeploymentPlan plan , Type type , ExcludeList avoid , List <? extends Host > hosts , int returnUpTo ,
172174 boolean considerReservedCapacity ) {
173175 if (CollectionUtils .isEmpty (hosts )) {
174- if (logger .isDebugEnabled ()) {
175- logger .debug ("Random Allocator found 0 hosts as given host list is empty" );
176- }
176+ logger .debug ("Random Allocator found 0 hosts as given host list is empty" );
177177 return new ArrayList <>();
178178 }
179179 return findSuitableHosts (vmProfile , plan , type , avoid , hosts , returnUpTo , considerReservedCapacity );
180180 }
181-
182- @ Override
183- public List <Host > allocateTo (VirtualMachineProfile vmProfile , DeploymentPlan plan ,
184- Type type , ExcludeList avoid , int returnUpTo , boolean considerReservedCapacity ) {
185- return findSuitableHosts (vmProfile , plan , type , avoid , null , returnUpTo , considerReservedCapacity );
186- }
187-
188- @ Override
189- public boolean isVirtualMachineUpgradable (VirtualMachine vm , ServiceOffering offering ) {
190- // currently we do no special checks to rule out a VM being upgradable to an offering, so
191- // return true
192- return true ;
193- }
194181}
0 commit comments