Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ go 1.25.0
// These are needed for the OTE tests. Due to how we get the kubeconfig from the command line, there doesn't seem to be
// an API yet we can leverage so that I do not have to copy what openshift/kubernetes/openshift-hack/cmd/k8s-tests-ext did to initialize.
replace (

github.com/onsi/ginkgo/v2 => github.com/openshift/onsi-ginkgo/v2 v2.6.1-0.20260303184444-1cc650aa0565
github.com/openshift/api => /home/rmanak/workspaces/OCPBUGS-82584/api

k8s.io/apiserver => github.com/openshift/kubernetes/staging/src/k8s.io/apiserver v0.0.0-20260305123649-d18f3f005eaa // openshift kubernetes has very old copy of k8s.io/kubernetes/pkg/kubelet/server/server.go
k8s.io/kubelet => github.com/openshift/kubernetes/staging/src/k8s.io/kubelet v0.0.0-20260305123649-d18f3f005eaa // openshift kubernetes has very old copy of k8s.io/kubernetes/cmd/kubelet/app/options/options.go
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -463,8 +463,6 @@ github.com/opencontainers/selinux v1.13.0 h1:Zza88GWezyT7RLql12URvoxsbLfjFx988+L
github.com/opencontainers/selinux v1.13.0/go.mod h1:XxWTed+A/s5NNq4GmYScVy+9jzXhGBVEOAyucdRUY8s=
github.com/openshift-eng/openshift-tests-extension v0.0.0-20260127124016-0fed2b824818 h1:jJLE/aCAqDf8U4wc3bE1IEKgIxbb0ICjCNVFA49x/8s=
github.com/openshift-eng/openshift-tests-extension v0.0.0-20260127124016-0fed2b824818/go.mod h1:6gkP5f2HL0meusT0Aim8icAspcD1cG055xxBZ9yC68M=
github.com/openshift/api v0.0.0-20260317165824-54a3998d81eb h1:iwBR3mzmyE3EMFx7R3CQ9lOccTS0dNht8TW82aGITg0=
github.com/openshift/api v0.0.0-20260317165824-54a3998d81eb/go.mod h1:pyVjK0nZ4sRs4fuQVQ4rubsJdahI1PB94LnQ8sGdvxo=
github.com/openshift/client-go v0.0.0-20260317180604-743f664b82d1 h1:Hr/R38eg5ZJXfbiaHumjJIN1buDZwhsm4ys4npVCXH0=
github.com/openshift/client-go v0.0.0-20260317180604-743f664b82d1/go.mod h1:Za51LlH76ALiQ/aKGBYJXmyJNkA//IDJ+I///30CA2M=
github.com/openshift/cluster-api-actuator-pkg/testutils v0.0.0-20250910145856-21d03d30056d h1:+sqUThLi/lmgT5/scmmjnS6+RZFtbdxRAscNfCPyLPI=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,15 @@ spec:
labels of the machine template of the MachineSet.
format: int32
type: integer
labelSelector:
description: |-
labelSelector is a label selector, in string format, for Machines corresponding to the MachineSet.
It is exposed via the scale subresource as status.selector.
When omitted, the MachineSet controller has not yet reconciled spec.selector into status.labelSelector.
When present, it must not be empty and must not exceed 4096 characters.
maxLength: 4096
minLength: 1
type: string
observedGeneration:
description: observedGeneration reflects the generation of the most
recently observed MachineSet.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,15 @@ spec:
labels of the machine template of the MachineSet.
format: int32
type: integer
labelSelector:
description: |-
labelSelector is a label selector, in string format, for Machines corresponding to the MachineSet.
It is exposed via the scale subresource as status.selector.
When omitted, the MachineSet controller has not yet reconciled spec.selector into status.labelSelector.
When present, it must not be empty and must not exceed 4096 characters.
maxLength: 4096
minLength: 1
type: string
observedGeneration:
description: observedGeneration reflects the generation of the most
recently observed MachineSet.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,15 @@ spec:
labels of the machine template of the MachineSet.
format: int32
type: integer
labelSelector:
description: |-
labelSelector is a label selector, in string format, for Machines corresponding to the MachineSet.
It is exposed via the scale subresource as status.selector.
When omitted, the MachineSet controller has not yet reconciled spec.selector into status.labelSelector.
When present, it must not be empty and must not exceed 4096 characters.
maxLength: 4096
minLength: 1
type: string
observedGeneration:
description: observedGeneration reflects the generation of the most
recently observed MachineSet.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,15 @@ spec:
labels of the machine template of the MachineSet.
format: int32
type: integer
labelSelector:
description: |-
labelSelector is a label selector, in string format, for Machines corresponding to the MachineSet.
It is exposed via the scale subresource as status.selector.
When omitted, the MachineSet controller has not yet reconciled spec.selector into status.labelSelector.
When present, it must not be empty and must not exceed 4096 characters.
maxLength: 4096
minLength: 1
type: string
observedGeneration:
description: observedGeneration reflects the generation of the most
recently observed MachineSet.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -660,6 +660,15 @@ spec:
labels of the machine template of the MachineSet.
format: int32
type: integer
labelSelector:
description: |-
labelSelector is a label selector, in string format, for Machines corresponding to the MachineSet.
It is exposed via the scale subresource as status.selector.
When omitted, the MachineSet controller has not yet reconciled spec.selector into status.labelSelector.
When present, it must not be empty and must not exceed 4096 characters.
maxLength: 4096
minLength: 1
type: string
observedGeneration:
description: observedGeneration reflects the generation of the most
recently observed MachineSet.
Expand Down
21 changes: 13 additions & 8 deletions pkg/controller/machineset/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package machineset
import (
"context"
"errors"
"fmt"
"reflect"

machinev1 "github.com/openshift/api/machine/v1beta1"
Expand Down Expand Up @@ -67,6 +66,7 @@ func (c *ReconcileMachineSet) calculateStatus(ms *machinev1.MachineSet, filtered
newStatus.FullyLabeledReplicas = int32(fullyLabeledReplicasCount)
newStatus.ReadyReplicas = int32(readyReplicasCount)
newStatus.AvailableReplicas = int32(availableReplicasCount)
newStatus.LabelSelector = metav1.FormatLabelSelector(&ms.Spec.Selector)
return newStatus
}

Expand All @@ -80,6 +80,7 @@ func updateMachineSetStatus(c client.Client, ms *machinev1.MachineSet, newStatus
ms.Status.FullyLabeledReplicas == newStatus.FullyLabeledReplicas &&
ms.Status.ReadyReplicas == newStatus.ReadyReplicas &&
ms.Status.AvailableReplicas == newStatus.AvailableReplicas &&
ms.Status.LabelSelector == newStatus.LabelSelector &&
reflect.DeepEqual(ms.Status.Conditions, newStatus.Conditions) &&
ms.Generation == ms.Status.ObservedGeneration {
return ms, nil
Expand All @@ -97,13 +98,17 @@ func updateMachineSetStatus(c client.Client, ms *machinev1.MachineSet, newStatus
if ms.Spec.Replicas != nil {
replicas = *ms.Spec.Replicas
}
klog.V(4).Infof("%s", fmt.Sprintf("Updating status for %v: %s/%s, ", ms.Kind, ms.Namespace, ms.Name)+
fmt.Sprintf("replicas %d->%d (need %d), ", ms.Status.Replicas, newStatus.Replicas, replicas)+
fmt.Sprintf("fullyLabeledReplicas %d->%d, ", ms.Status.FullyLabeledReplicas, newStatus.FullyLabeledReplicas)+
fmt.Sprintf("readyReplicas %d->%d, ", ms.Status.ReadyReplicas, newStatus.ReadyReplicas)+
fmt.Sprintf("availableReplicas %d->%d, ", ms.Status.AvailableReplicas, newStatus.AvailableReplicas)+
fmt.Sprintf("sequence No: %v->%v", ms.Status.ObservedGeneration, newStatus.ObservedGeneration)+
fmt.Sprintf("conditions: %v->%v", ms.Status.Conditions, newStatus.Conditions))
klog.V(4).Infof(
"Updating status for %v: %s/%s, replicas %d->%d (need %d), fullyLabeledReplicas %d->%d, readyReplicas %d->%d, availableReplicas %d->%d, labelSelector %q->%q, sequence No: %v->%v, conditions: %v->%v",
ms.Kind, ms.Namespace, ms.Name,
ms.Status.Replicas, newStatus.Replicas, replicas,
ms.Status.FullyLabeledReplicas, newStatus.FullyLabeledReplicas,
ms.Status.ReadyReplicas, newStatus.ReadyReplicas,
ms.Status.AvailableReplicas, newStatus.AvailableReplicas,
ms.Status.LabelSelector, newStatus.LabelSelector,
ms.Status.ObservedGeneration, newStatus.ObservedGeneration,
ms.Status.Conditions, newStatus.Conditions,
)

ms.Status = newStatus
patchErr = c.Status().Patch(context.Background(), ms, client.MergeFrom(machineSetCopy))
Expand Down
114 changes: 114 additions & 0 deletions pkg/controller/machineset/status_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
Copyright 2026 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package machineset

import (
"context"
"testing"

. "github.com/onsi/gomega"
machinev1 "github.com/openshift/api/machine/v1beta1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/scheme"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
)

// TestMachineSetStatusLabelSelectorMatchesScaleSubresource verifies that status.labelSelector is the
// serialized label selector string expected by the CRD scale subresource (labelSelectorPath
// -> .status.labelSelector), which the apiserver maps to autoscaling/v1 Scale status.selector.
func TestMachineSetStatusLabelSelectorMatchesScaleSubresource(t *testing.T) {
tests := []struct {
name string
spec metav1.LabelSelector
}{
{
name: "matchLabels",
spec: metav1.LabelSelector{
MatchLabels: map[string]string{
"machine.openshift.io/cluster-api-cluster": "cluster-id",
"machine.openshift.io/cluster-api-machineset": "workers",
},
},
},
{
name: "matchExpressions",
spec: metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{
{Key: "role", Operator: metav1.LabelSelectorOpIn, Values: []string{"worker", "infra"}},
},
},
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
g := NewWithT(t)

ms := &machinev1.MachineSet{
Spec: machinev1.MachineSetSpec{
Selector: tc.spec,
},
}

got := (&ReconcileMachineSet{}).calculateStatus(ms, nil).LabelSelector
want := metav1.FormatLabelSelector(&ms.Spec.Selector)
g.Expect(got).To(Equal(want), "status.labelSelector must match Scale status.selector for HPA")
})
}
}

func TestUpdateMachineSetStatusUpdatesLabelSelectorWithoutReplicaChanges(t *testing.T) {
t.Helper()

g := NewWithT(t)

ms := &machinev1.MachineSet{
ObjectMeta: metav1.ObjectMeta{
Name: "machineset-test",
Namespace: "openshift-machine-api",
Generation: 1,
},
Status: machinev1.MachineSetStatus{
Replicas: 0,
FullyLabeledReplicas: 0,
ReadyReplicas: 0,
AvailableReplicas: 0,
ObservedGeneration: 1,
},
}

cl := fake.NewClientBuilder().
WithScheme(scheme.Scheme).
WithRuntimeObjects(ms.DeepCopy()).
WithStatusSubresource(&machinev1.MachineSet{}).
Build()

current := &machinev1.MachineSet{}
key := client.ObjectKeyFromObject(ms)
g.Expect(cl.Get(context.Background(), key, current)).To(Succeed(), "failed to fetch machineset")

newStatus := current.Status
newStatus.LabelSelector = "machine.openshift.io/cluster-api-cluster=test-cluster"

updated, err := updateMachineSetStatus(cl, current, newStatus)
g.Expect(err).NotTo(HaveOccurred(), "failed to update machineset status")
g.Expect(updated.Status.LabelSelector).To(Equal(newStatus.LabelSelector))

stored := &machinev1.MachineSet{}
g.Expect(cl.Get(context.Background(), key, stored)).To(Succeed(), "failed to refetch machineset")
g.Expect(stored.Status.LabelSelector).To(Equal(newStatus.LabelSelector))
}
6 changes: 6 additions & 0 deletions vendor/github.com/openshift/api/.golangci.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions vendor/github.com/openshift/api/config/v1/types.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 8 additions & 1 deletion vendor/github.com/openshift/api/config/v1/types_dns.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading