Skip to content

Commit b78b40a

Browse files
Merge pull request #2918 from schrej/fix/host-selection
🐛 fix host selection being unreliable with more than 200 hosts in one namespace
2 parents 6ef80e3 + 08e380b commit b78b40a

File tree

1 file changed

+55
-58
lines changed

1 file changed

+55
-58
lines changed

baremetal/metal3machine_manager.go

Lines changed: 55 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -765,50 +765,19 @@ func getHost(ctx context.Context, m3Machine *infrav1.Metal3Machine, cl client.Cl
765765
// associated with the metal3 machine. It searches all hosts in case one already has an
766766
// association with this metal3 machine.
767767
func (m *MachineManager) chooseHost(ctx context.Context) (*bmov1alpha1.BareMetalHost, *v1beta1patch.Helper, error) {
768-
// get list of BMH.
769-
hosts := bmov1alpha1.BareMetalHostList{}
770-
// without this ListOption, all namespaces would be including in the listing.
771-
opts := &client.ListOptions{
772-
Namespace: m.Metal3Machine.Namespace,
773-
Limit: DefaultListLimit,
774-
}
775-
776-
err := m.client.List(ctx, &hosts, opts)
768+
labelSelector, err := hostLabelSelectorForMachine(m.Metal3Machine, m.Log)
777769
if err != nil {
778770
return nil, nil, err
779771
}
780772

781-
// Using the label selector on ListOptions above doesn't seem to work.
782-
// I think it's because we have a local cache of all BareMetalHosts.
783-
labelSelector := labels.NewSelector()
784-
var reqs labels.Requirements
785-
var r *labels.Requirement
786-
787-
for labelKey, labelVal := range m.Metal3Machine.Spec.HostSelector.MatchLabels {
788-
m.Log.Info("Adding requirement to match label",
789-
"label key", labelKey,
790-
"label value", labelVal)
791-
r, err = labels.NewRequirement(labelKey, selection.Equals, []string{labelVal})
792-
if err != nil {
793-
m.Log.Error(err, "Failed to create MatchLabel requirement, not choosing host")
794-
return nil, nil, err
795-
}
796-
reqs = append(reqs, *r)
797-
}
798-
for _, req := range m.Metal3Machine.Spec.HostSelector.MatchExpressions {
799-
m.Log.Info("Adding requirement to match label",
800-
"label key", req.Key,
801-
"label operator", req.Operator,
802-
"label value", req.Values)
803-
lowercaseOperator := selection.Operator(strings.ToLower(string(req.Operator)))
804-
r, err = labels.NewRequirement(req.Key, lowercaseOperator, req.Values)
805-
if err != nil {
806-
m.Log.Error(err, "Failed to create MatchExpression requirement, not choosing host")
807-
return nil, nil, err
808-
}
809-
reqs = append(reqs, *r)
773+
hosts := bmov1alpha1.BareMetalHostList{}
774+
err = m.client.List(ctx, &hosts,
775+
client.InNamespace(m.Metal3Machine.Namespace),
776+
client.MatchingLabelsSelector{Selector: labelSelector},
777+
)
778+
if err != nil {
779+
return nil, nil, err
810780
}
811-
labelSelector = labelSelector.Add(reqs...)
812781

813782
availableHosts := []*bmov1alpha1.BareMetalHost{}
814783
availableHostsWithNodeReuse := []*bmov1alpha1.BareMetalHost{}
@@ -843,26 +812,22 @@ func (m *MachineManager) chooseHost(ctx context.Context) (*bmov1alpha1.BareMetal
843812
}
844813
}
845814

846-
if labelSelector.Matches(labels.Set(host.ObjectMeta.Labels)) {
847-
if m.nodeReuseLabelExists(ctx, &host) && m.nodeReuseLabelMatches(ctx, &host) {
848-
m.Log.Info("Found host with nodeReuseLabelName and it matches, adding it to availableHostsWithNodeReuse list", "host", host.Name)
849-
availableHostsWithNodeReuse = append(availableHostsWithNodeReuse, &hosts.Items[i])
850-
} else if !m.nodeReuseLabelExists(ctx, &host) {
851-
switch host.Status.Provisioning.State {
852-
case bmov1alpha1.StateReady, bmov1alpha1.StateAvailable:
853-
// Break out of the switch
854-
case bmov1alpha1.StateNone, bmov1alpha1.StateUnmanaged, bmov1alpha1.StateRegistering, bmov1alpha1.StateMatchProfile,
855-
bmov1alpha1.StatePreparing, bmov1alpha1.StateProvisioning, bmov1alpha1.StateProvisioned, bmov1alpha1.StateExternallyProvisioned,
856-
bmov1alpha1.StateDeprovisioning, bmov1alpha1.StateInspecting, bmov1alpha1.StatePoweringOffBeforeDelete, bmov1alpha1.StateDeleting:
857-
continue
858-
default:
859-
continue
860-
}
861-
m.Log.Info("Host matched hostSelector for Metal3Machine, adding it to availableHosts list", "host", host.Name)
862-
availableHosts = append(availableHosts, &hosts.Items[i])
815+
if m.nodeReuseLabelExists(ctx, &host) && m.nodeReuseLabelMatches(ctx, &host) {
816+
m.Log.Info("Found host with nodeReuseLabelName and it matches, adding it to availableHostsWithNodeReuse list", "host", host.Name)
817+
availableHostsWithNodeReuse = append(availableHostsWithNodeReuse, &hosts.Items[i])
818+
} else if !m.nodeReuseLabelExists(ctx, &host) {
819+
switch host.Status.Provisioning.State {
820+
case bmov1alpha1.StateReady, bmov1alpha1.StateAvailable:
821+
// Break out of the switch
822+
case bmov1alpha1.StateNone, bmov1alpha1.StateUnmanaged, bmov1alpha1.StateRegistering, bmov1alpha1.StateMatchProfile,
823+
bmov1alpha1.StatePreparing, bmov1alpha1.StateProvisioning, bmov1alpha1.StateProvisioned, bmov1alpha1.StateExternallyProvisioned,
824+
bmov1alpha1.StateDeprovisioning, bmov1alpha1.StateInspecting, bmov1alpha1.StatePoweringOffBeforeDelete, bmov1alpha1.StateDeleting:
825+
continue
826+
default:
827+
continue
863828
}
864-
} else {
865-
m.Log.Info("Host did not match hostSelector for Metal3Machine", "host", host.Name)
829+
m.Log.Info("Host matched hostSelector for Metal3Machine, adding it to availableHosts list", "host", host.Name)
830+
availableHosts = append(availableHosts, &hosts.Items[i])
866831
}
867832
}
868833

@@ -917,6 +882,38 @@ func (m *MachineManager) chooseHost(ctx context.Context) (*bmov1alpha1.BareMetal
917882
return chosenHost, helper, err
918883
}
919884

885+
// hostLabelSelectorForMachine builds a label selector from the Metal3Machine's host selector.
886+
func hostLabelSelectorForMachine(machine *infrav1.Metal3Machine, log logr.Logger) (labels.Selector, error) {
887+
labelSelector := labels.NewSelector()
888+
889+
for labelKey, labelVal := range machine.Spec.HostSelector.MatchLabels {
890+
log.Info("Adding requirement to match label",
891+
"label key", labelKey,
892+
"label value", labelVal)
893+
r, err := labels.NewRequirement(labelKey, selection.Equals, []string{labelVal})
894+
if err != nil {
895+
log.Error(err, "Failed to create MatchLabel requirement, not choosing host")
896+
return nil, err
897+
}
898+
labelSelector = labelSelector.Add(*r)
899+
}
900+
901+
for _, req := range machine.Spec.HostSelector.MatchExpressions {
902+
log.Info("Adding requirement to match label",
903+
"label key", req.Key,
904+
"label operator", req.Operator,
905+
"label value", req.Values)
906+
lowercaseOperator := selection.Operator(strings.ToLower(string(req.Operator)))
907+
r, err := labels.NewRequirement(req.Key, lowercaseOperator, req.Values)
908+
if err != nil {
909+
log.Error(err, "Failed to create MatchExpression requirement, not choosing host")
910+
return nil, err
911+
}
912+
labelSelector = labelSelector.Add(*r)
913+
}
914+
return labelSelector, nil
915+
}
916+
920917
// consumerRefMatches returns a boolean based on whether the consumer
921918
// reference and bare metal machine metadata match.
922919
func consumerRefMatches(consumer *corev1.ObjectReference, m3machine *infrav1.Metal3Machine) bool {

0 commit comments

Comments
 (0)