Skip to content

Commit 5a64edc

Browse files
Merge pull request #2923 from metal3-io-bot/cherry-pick-2918-to-release-1.11
🐛 Fix host selection being unreliable with more than 200 hosts in one namespace
2 parents 49c0bbb + 0b17af6 commit 5a64edc

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
@@ -797,50 +797,19 @@ func getHost(ctx context.Context, m3Machine *infrav1.Metal3Machine, cl client.Cl
797797
// associated with the metal3 machine. It searches all hosts in case one already has an
798798
// association with this metal3 machine.
799799
func (m *MachineManager) chooseHost(ctx context.Context) (*bmov1alpha1.BareMetalHost, *v1beta1patch.Helper, error) {
800-
// get list of BMH.
801-
hosts := bmov1alpha1.BareMetalHostList{}
802-
// without this ListOption, all namespaces would be including in the listing.
803-
opts := &client.ListOptions{
804-
Namespace: m.Metal3Machine.Namespace,
805-
Limit: DefaultListLimit,
806-
}
807-
808-
err := m.client.List(ctx, &hosts, opts)
800+
labelSelector, err := hostLabelSelectorForMachine(m.Metal3Machine, m.Log)
809801
if err != nil {
810802
return nil, nil, err
811803
}
812804

813-
// Using the label selector on ListOptions above doesn't seem to work.
814-
// I think it's because we have a local cache of all BareMetalHosts.
815-
labelSelector := labels.NewSelector()
816-
var reqs labels.Requirements
817-
var r *labels.Requirement
818-
819-
for labelKey, labelVal := range m.Metal3Machine.Spec.HostSelector.MatchLabels {
820-
m.Log.Info("Adding requirement to match label",
821-
"label key", labelKey,
822-
"label value", labelVal)
823-
r, err = labels.NewRequirement(labelKey, selection.Equals, []string{labelVal})
824-
if err != nil {
825-
m.Log.Error(err, "Failed to create MatchLabel requirement, not choosing host")
826-
return nil, nil, err
827-
}
828-
reqs = append(reqs, *r)
829-
}
830-
for _, req := range m.Metal3Machine.Spec.HostSelector.MatchExpressions {
831-
m.Log.Info("Adding requirement to match label",
832-
"label key", req.Key,
833-
"label operator", req.Operator,
834-
"label value", req.Values)
835-
lowercaseOperator := selection.Operator(strings.ToLower(string(req.Operator)))
836-
r, err = labels.NewRequirement(req.Key, lowercaseOperator, req.Values)
837-
if err != nil {
838-
m.Log.Error(err, "Failed to create MatchExpression requirement, not choosing host")
839-
return nil, nil, err
840-
}
841-
reqs = append(reqs, *r)
805+
hosts := bmov1alpha1.BareMetalHostList{}
806+
err = m.client.List(ctx, &hosts,
807+
client.InNamespace(m.Metal3Machine.Namespace),
808+
client.MatchingLabelsSelector{Selector: labelSelector},
809+
)
810+
if err != nil {
811+
return nil, nil, err
842812
}
843-
labelSelector = labelSelector.Add(reqs...)
844813

845814
availableHosts := []*bmov1alpha1.BareMetalHost{}
846815
availableHostsWithNodeReuse := []*bmov1alpha1.BareMetalHost{}
@@ -875,26 +844,22 @@ func (m *MachineManager) chooseHost(ctx context.Context) (*bmov1alpha1.BareMetal
875844
}
876845
}
877846

878-
if labelSelector.Matches(labels.Set(host.ObjectMeta.Labels)) {
879-
if m.nodeReuseLabelExists(ctx, &host) && m.nodeReuseLabelMatches(ctx, &host) {
880-
m.Log.Info("Found host with nodeReuseLabelName and it matches, adding it to availableHostsWithNodeReuse list", "host", host.Name)
881-
availableHostsWithNodeReuse = append(availableHostsWithNodeReuse, &hosts.Items[i])
882-
} else if !m.nodeReuseLabelExists(ctx, &host) {
883-
switch host.Status.Provisioning.State {
884-
case bmov1alpha1.StateReady, bmov1alpha1.StateAvailable:
885-
// Break out of the switch
886-
case bmov1alpha1.StateNone, bmov1alpha1.StateUnmanaged, bmov1alpha1.StateRegistering, bmov1alpha1.StateMatchProfile,
887-
bmov1alpha1.StatePreparing, bmov1alpha1.StateProvisioning, bmov1alpha1.StateProvisioned, bmov1alpha1.StateExternallyProvisioned,
888-
bmov1alpha1.StateDeprovisioning, bmov1alpha1.StateInspecting, bmov1alpha1.StatePoweringOffBeforeDelete, bmov1alpha1.StateDeleting:
889-
continue
890-
default:
891-
continue
892-
}
893-
m.Log.Info("Host matched hostSelector for Metal3Machine, adding it to availableHosts list", "host", host.Name)
894-
availableHosts = append(availableHosts, &hosts.Items[i])
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
895860
}
896-
} else {
897-
m.Log.Info("Host did not match hostSelector for Metal3Machine", "host", host.Name)
861+
m.Log.Info("Host matched hostSelector for Metal3Machine, adding it to availableHosts list", "host", host.Name)
862+
availableHosts = append(availableHosts, &hosts.Items[i])
898863
}
899864
}
900865

@@ -945,6 +910,38 @@ func (m *MachineManager) chooseHost(ctx context.Context) (*bmov1alpha1.BareMetal
945910
return chosenHost, helper, err
946911
}
947912

913+
// hostLabelSelectorForMachine builds a label selector from the Metal3Machine's host selector.
914+
func hostLabelSelectorForMachine(machine *infrav1.Metal3Machine, log logr.Logger) (labels.Selector, error) {
915+
labelSelector := labels.NewSelector()
916+
917+
for labelKey, labelVal := range machine.Spec.HostSelector.MatchLabels {
918+
log.Info("Adding requirement to match label",
919+
"label key", labelKey,
920+
"label value", labelVal)
921+
r, err := labels.NewRequirement(labelKey, selection.Equals, []string{labelVal})
922+
if err != nil {
923+
log.Error(err, "Failed to create MatchLabel requirement, not choosing host")
924+
return nil, err
925+
}
926+
labelSelector = labelSelector.Add(*r)
927+
}
928+
929+
for _, req := range machine.Spec.HostSelector.MatchExpressions {
930+
log.Info("Adding requirement to match label",
931+
"label key", req.Key,
932+
"label operator", req.Operator,
933+
"label value", req.Values)
934+
lowercaseOperator := selection.Operator(strings.ToLower(string(req.Operator)))
935+
r, err := labels.NewRequirement(req.Key, lowercaseOperator, req.Values)
936+
if err != nil {
937+
log.Error(err, "Failed to create MatchExpression requirement, not choosing host")
938+
return nil, err
939+
}
940+
labelSelector = labelSelector.Add(*r)
941+
}
942+
return labelSelector, nil
943+
}
944+
948945
// consumerRefMatches returns a boolean based on whether the consumer
949946
// reference and bare metal machine metadata match.
950947
func consumerRefMatches(consumer *corev1.ObjectReference, m3machine *infrav1.Metal3Machine) bool {

0 commit comments

Comments
 (0)