diff --git a/api/v1beta1/conversion_test.go b/api/v1beta1/conversion_test.go index 9f3dc392cbbd..9c83da3fecef 100644 --- a/api/v1beta1/conversion_test.go +++ b/api/v1beta1/conversion_test.go @@ -275,6 +275,11 @@ func hubMachineSetStatus(in *clusterv1.MachineSetStatus, c fuzz.Continue) { if in.Deprecated.V1Beta1 == nil { in.Deprecated.V1Beta1 = &clusterv1.MachineSetV1Beta1DeprecatedStatus{} } + // nil becomes &0 after hub => spoke => hub conversion + // This is acceptable as usually Replicas is set and controllers using older apiVersions are not writing MachineSet status. + if in.Replicas == nil { + in.Replicas = ptr.To(int32(0)) + } } func spokeMachineSetStatus(in *MachineSetStatus, c fuzz.Continue) { @@ -304,6 +309,11 @@ func hubMachineDeploymentStatus(in *clusterv1.MachineDeploymentStatus, c fuzz.Co if in.Deprecated.V1Beta1 == nil { in.Deprecated.V1Beta1 = &clusterv1.MachineDeploymentV1Beta1DeprecatedStatus{} } + // nil becomes &0 after hub => spoke => hub conversion + // This is acceptable as usually Replicas is set and controllers using older apiVersions are not writing MachineSet status. + if in.Replicas == nil { + in.Replicas = ptr.To(int32(0)) + } } func spokeMachineDeploymentSpec(in *MachineDeploymentSpec, c fuzz.Continue) { diff --git a/api/v1beta1/zz_generated.conversion.go b/api/v1beta1/zz_generated.conversion.go index dcc8501d0e63..edc536cc3c0b 100644 --- a/api/v1beta1/zz_generated.conversion.go +++ b/api/v1beta1/zz_generated.conversion.go @@ -2238,7 +2238,9 @@ func Convert_v1beta2_MachineDeploymentSpec_To_v1beta1_MachineDeploymentSpec(in * func autoConvert_v1beta1_MachineDeploymentStatus_To_v1beta2_MachineDeploymentStatus(in *MachineDeploymentStatus, out *v1beta2.MachineDeploymentStatus, s conversion.Scope) error { out.ObservedGeneration = in.ObservedGeneration out.Selector = in.Selector - out.Replicas = in.Replicas + if err := v1.Convert_int32_To_Pointer_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } // WARNING: in.UpdatedReplicas requires manual conversion: does not exist in peer-type if err := v1.Convert_int32_To_Pointer_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err @@ -2277,7 +2279,9 @@ func autoConvert_v1beta2_MachineDeploymentStatus_To_v1beta1_MachineDeploymentSta } out.ObservedGeneration = in.ObservedGeneration out.Selector = in.Selector - out.Replicas = in.Replicas + if err := v1.Convert_Pointer_int32_To_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } if err := v1.Convert_Pointer_int32_To_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err } @@ -3170,7 +3174,9 @@ func Convert_v1beta2_MachineSetSpec_To_v1beta1_MachineSetSpec(in *v1beta2.Machin func autoConvert_v1beta1_MachineSetStatus_To_v1beta2_MachineSetStatus(in *MachineSetStatus, out *v1beta2.MachineSetStatus, s conversion.Scope) error { out.Selector = in.Selector - out.Replicas = in.Replicas + if err := v1.Convert_int32_To_Pointer_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } // WARNING: in.FullyLabeledReplicas requires manual conversion: does not exist in peer-type if err := v1.Convert_int32_To_Pointer_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err @@ -3209,7 +3215,9 @@ func autoConvert_v1beta2_MachineSetStatus_To_v1beta1_MachineSetStatus(in *v1beta out.Conditions = nil } out.Selector = in.Selector - out.Replicas = in.Replicas + if err := v1.Convert_Pointer_int32_To_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } if err := v1.Convert_Pointer_int32_To_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err } diff --git a/api/v1beta2/machinedeployment_types.go b/api/v1beta2/machinedeployment_types.go index 778f30d04d53..e56074d614ea 100644 --- a/api/v1beta2/machinedeployment_types.go +++ b/api/v1beta2/machinedeployment_types.go @@ -463,7 +463,7 @@ type MachineDeploymentStatus struct { // replicas is the total number of non-terminated machines targeted by this deployment // (their labels match the selector). // +optional - Replicas int32 `json:"replicas"` + Replicas *int32 `json:"replicas,omitempty"` // readyReplicas is the number of ready replicas for this MachineDeployment. A machine is considered ready when Machine's Ready condition is true. // +optional diff --git a/api/v1beta2/machineset_types.go b/api/v1beta2/machineset_types.go index 2d15a1d062e6..63fc6473d160 100644 --- a/api/v1beta2/machineset_types.go +++ b/api/v1beta2/machineset_types.go @@ -301,7 +301,7 @@ type MachineSetStatus struct { // replicas is the most recently observed number of replicas. // +optional - Replicas int32 `json:"replicas"` + Replicas *int32 `json:"replicas,omitempty"` // readyReplicas is the number of ready replicas for this MachineSet. A machine is considered ready when Machine's Ready condition is true. // +optional diff --git a/api/v1beta2/zz_generated.deepcopy.go b/api/v1beta2/zz_generated.deepcopy.go index 1d3c1568e0ee..9c669c6fdc19 100644 --- a/api/v1beta2/zz_generated.deepcopy.go +++ b/api/v1beta2/zz_generated.deepcopy.go @@ -1511,6 +1511,11 @@ func (in *MachineDeploymentStatus) DeepCopyInto(out *MachineDeploymentStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.Replicas != nil { + in, out := &in.Replicas, &out.Replicas + *out = new(int32) + **out = **in + } if in.ReadyReplicas != nil { in, out := &in.ReadyReplicas, &out.ReadyReplicas *out = new(int32) @@ -2471,6 +2476,11 @@ func (in *MachineSetStatus) DeepCopyInto(out *MachineSetStatus) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.Replicas != nil { + in, out := &in.Replicas, &out.Replicas + *out = new(int32) + **out = **in + } if in.ReadyReplicas != nil { in, out := &in.ReadyReplicas, &out.ReadyReplicas *out = new(int32) diff --git a/api/v1beta2/zz_generated.openapi.go b/api/v1beta2/zz_generated.openapi.go index 1546f37088e3..c2ed1efd1aff 100644 --- a/api/v1beta2/zz_generated.openapi.go +++ b/api/v1beta2/zz_generated.openapi.go @@ -2578,7 +2578,6 @@ func schema_sigsk8sio_cluster_api_api_v1beta2_MachineDeploymentStatus(ref common "replicas": { SchemaProps: spec.SchemaProps{ Description: "replicas is the total number of non-terminated machines targeted by this deployment (their labels match the selector).", - Default: 0, Type: []string{"integer"}, Format: "int32", }, @@ -4212,7 +4211,6 @@ func schema_sigsk8sio_cluster_api_api_v1beta2_MachineSetStatus(ref common.Refere "replicas": { SchemaProps: spec.SchemaProps{ Description: "replicas is the most recently observed number of replicas.", - Default: 0, Type: []string{"integer"}, Format: "int32", }, diff --git a/controlplane/kubeadm/api/v1beta1/conversion_test.go b/controlplane/kubeadm/api/v1beta1/conversion_test.go index 728f79b86951..97e8ce6e9e38 100644 --- a/controlplane/kubeadm/api/v1beta1/conversion_test.go +++ b/controlplane/kubeadm/api/v1beta1/conversion_test.go @@ -25,6 +25,7 @@ import ( fuzz "github.com/google/gofuzz" "k8s.io/apimachinery/pkg/api/apitesting/fuzzer" runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/utils/ptr" bootstrapv1beta1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1" controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta2" @@ -70,6 +71,12 @@ func hubKubeadmControlPlaneStatus(in *controlplanev1.KubeadmControlPlaneStatus, in.Initialization = nil } } + + // nil becomes &0 after hub => spoke => hub conversion + // This is acceptable as usually Replicas is set and controllers using older apiVersions are not writing MachineSet status. + if in.Replicas == nil { + in.Replicas = ptr.To(int32(0)) + } } func spokeKubeadmControlPlaneStatus(in *KubeadmControlPlaneStatus, c fuzz.Continue) { diff --git a/controlplane/kubeadm/api/v1beta1/zz_generated.conversion.go b/controlplane/kubeadm/api/v1beta1/zz_generated.conversion.go index 2bf565883cce..19478599f3eb 100644 --- a/controlplane/kubeadm/api/v1beta1/zz_generated.conversion.go +++ b/controlplane/kubeadm/api/v1beta1/zz_generated.conversion.go @@ -399,7 +399,9 @@ func Convert_v1beta2_KubeadmControlPlaneSpec_To_v1beta1_KubeadmControlPlaneSpec( func autoConvert_v1beta1_KubeadmControlPlaneStatus_To_v1beta2_KubeadmControlPlaneStatus(in *KubeadmControlPlaneStatus, out *v1beta2.KubeadmControlPlaneStatus, s conversion.Scope) error { out.Selector = in.Selector - out.Replicas = in.Replicas + if err := v1.Convert_int32_To_Pointer_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } out.Version = (*string)(unsafe.Pointer(in.Version)) // WARNING: in.UpdatedReplicas requires manual conversion: does not exist in peer-type if err := v1.Convert_int32_To_Pointer_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { @@ -441,7 +443,9 @@ func autoConvert_v1beta2_KubeadmControlPlaneStatus_To_v1beta1_KubeadmControlPlan } // WARNING: in.Initialization requires manual conversion: does not exist in peer-type out.Selector = in.Selector - out.Replicas = in.Replicas + if err := v1.Convert_Pointer_int32_To_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } if err := v1.Convert_Pointer_int32_To_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err } diff --git a/controlplane/kubeadm/api/v1beta2/kubeadm_control_plane_types.go b/controlplane/kubeadm/api/v1beta2/kubeadm_control_plane_types.go index 675caf609221..e171442b26ac 100644 --- a/controlplane/kubeadm/api/v1beta2/kubeadm_control_plane_types.go +++ b/controlplane/kubeadm/api/v1beta2/kubeadm_control_plane_types.go @@ -650,7 +650,7 @@ type KubeadmControlPlaneStatus struct { // replicas is the total number of non-terminated machines targeted by this control plane // (their labels match the selector). // +optional - Replicas int32 `json:"replicas"` + Replicas *int32 `json:"replicas,omitempty"` // readyReplicas is the number of ready replicas for this KubeadmControlPlane. A machine is considered ready when Machine's Ready condition is true. // +optional diff --git a/controlplane/kubeadm/api/v1beta2/zz_generated.deepcopy.go b/controlplane/kubeadm/api/v1beta2/zz_generated.deepcopy.go index dbd61573b6c4..6f0f3c452ef7 100644 --- a/controlplane/kubeadm/api/v1beta2/zz_generated.deepcopy.go +++ b/controlplane/kubeadm/api/v1beta2/zz_generated.deepcopy.go @@ -219,6 +219,11 @@ func (in *KubeadmControlPlaneStatus) DeepCopyInto(out *KubeadmControlPlaneStatus *out = new(KubeadmControlPlaneInitializationStatus) **out = **in } + if in.Replicas != nil { + in, out := &in.Replicas, &out.Replicas + *out = new(int32) + **out = **in + } if in.ReadyReplicas != nil { in, out := &in.ReadyReplicas, &out.ReadyReplicas *out = new(int32) diff --git a/controlplane/kubeadm/internal/controllers/controller_test.go b/controlplane/kubeadm/internal/controllers/controller_test.go index a1e8d74f96b5..c34405431ee4 100644 --- a/controlplane/kubeadm/internal/controllers/controller_test.go +++ b/controlplane/kubeadm/internal/controllers/controller_test.go @@ -1385,7 +1385,7 @@ kubernetesVersion: metav1.16.1 g.Expect(kcp.Finalizers).To(ContainElement(controlplanev1.KubeadmControlPlaneFinalizer)) g.Expect(kcp.Status.Selector).NotTo(BeEmpty()) - g.Expect(kcp.Status.Replicas).To(BeEquivalentTo(1)) + g.Expect(kcp.Status.Replicas).To(HaveValue(BeEquivalentTo(1))) g.Expect(v1beta1conditions.IsFalse(kcp, controlplanev1.AvailableV1Beta1Condition)).To(BeTrue()) g.Expect(conditions.IsFalse(kcp, controlplanev1.KubeadmControlPlaneInitializedCondition)).To(BeTrue()) @@ -1626,7 +1626,7 @@ kubernetesVersion: metav1.16.1`, g.Expect(kcp.Finalizers).To(ContainElement(controlplanev1.KubeadmControlPlaneFinalizer)) g.Expect(kcp.Status.Selector).NotTo(BeEmpty()) - g.Expect(kcp.Status.Replicas).To(BeEquivalentTo(1)) + g.Expect(kcp.Status.Replicas).To(HaveValue(BeEquivalentTo(1))) g.Expect(v1beta1conditions.IsFalse(kcp, controlplanev1.AvailableV1Beta1Condition)).To(BeTrue()) // Verify that the kubeconfig is using the custom CA diff --git a/controlplane/kubeadm/internal/controllers/status.go b/controlplane/kubeadm/internal/controllers/status.go index 2b63bc2f5513..b397c3fa1463 100644 --- a/controlplane/kubeadm/internal/controllers/status.go +++ b/controlplane/kubeadm/internal/controllers/status.go @@ -188,7 +188,7 @@ func setReplicas(_ context.Context, kcp *controlplanev1.KubeadmControlPlane, mac } } - kcp.Status.Replicas = int32(len(machines)) + kcp.Status.Replicas = ptr.To(int32(len(machines))) kcp.Status.ReadyReplicas = ptr.To(readyReplicas) kcp.Status.AvailableReplicas = ptr.To(availableReplicas) kcp.Status.UpToDateReplicas = ptr.To(upToDateReplicas) diff --git a/controlplane/kubeadm/internal/controllers/status_test.go b/controlplane/kubeadm/internal/controllers/status_test.go index d71d74442976..a8d8a9843c9e 100644 --- a/controlplane/kubeadm/internal/controllers/status_test.go +++ b/controlplane/kubeadm/internal/controllers/status_test.go @@ -130,7 +130,8 @@ func TestSetReplicas(t *testing.T) { setReplicas(ctx, c.KCP, c.Machines) g.Expect(kcp.Status).ToNot(BeNil()) - g.Expect(kcp.Status.Replicas).To(Equal(int32(6))) + g.Expect(kcp.Status.Replicas).ToNot(BeNil()) + g.Expect(*kcp.Status.Replicas).To(Equal(int32(6))) g.Expect(kcp.Status.ReadyReplicas).ToNot(BeNil()) g.Expect(*kcp.Status.ReadyReplicas).To(Equal(int32(3))) g.Expect(kcp.Status.AvailableReplicas).ToNot(BeNil()) @@ -304,7 +305,7 @@ func Test_setScalingUpCondition(t *testing.T) { controlPlane: &internal.ControlPlane{ KCP: &controlplanev1.KubeadmControlPlane{ Spec: controlplanev1.KubeadmControlPlaneSpec{Replicas: ptr.To(int32(3))}, - Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: 3}, + Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: ptr.To(int32(3))}, }, Machines: collections.FromMachines( &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "m1"}}, @@ -323,7 +324,7 @@ func Test_setScalingUpCondition(t *testing.T) { controlPlane: &internal.ControlPlane{ KCP: &controlplanev1.KubeadmControlPlane{ Spec: controlplanev1.KubeadmControlPlaneSpec{Replicas: ptr.To(int32(3)), MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{InfrastructureRef: corev1.ObjectReference{Kind: "AWSTemplate"}}}, - Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: 3}, + Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: ptr.To(int32(3))}, }, Machines: collections.FromMachines( &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "m1"}}, @@ -344,7 +345,7 @@ func Test_setScalingUpCondition(t *testing.T) { controlPlane: &internal.ControlPlane{ KCP: &controlplanev1.KubeadmControlPlane{ Spec: controlplanev1.KubeadmControlPlaneSpec{Replicas: ptr.To(int32(5))}, - Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: 3}, + Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: ptr.To(int32(3))}, }, Machines: collections.FromMachines( &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "m1"}}, @@ -365,7 +366,7 @@ func Test_setScalingUpCondition(t *testing.T) { KCP: &controlplanev1.KubeadmControlPlane{ ObjectMeta: metav1.ObjectMeta{DeletionTimestamp: ptr.To(metav1.Time{Time: time.Now()})}, Spec: controlplanev1.KubeadmControlPlaneSpec{Replicas: ptr.To(int32(5))}, - Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: 3}, + Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: ptr.To(int32(3))}, }, Machines: collections.FromMachines( &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "m1"}}, @@ -384,7 +385,7 @@ func Test_setScalingUpCondition(t *testing.T) { controlPlane: &internal.ControlPlane{ KCP: &controlplanev1.KubeadmControlPlane{ Spec: controlplanev1.KubeadmControlPlaneSpec{Replicas: ptr.To(int32(5)), MachineTemplate: controlplanev1.KubeadmControlPlaneMachineTemplate{InfrastructureRef: corev1.ObjectReference{Kind: "AWSTemplate"}}}, - Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: 3}, + Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: ptr.To(int32(3))}, }, Machines: collections.FromMachines( &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "m1"}}, @@ -413,7 +414,7 @@ func Test_setScalingUpCondition(t *testing.T) { }, KCP: &controlplanev1.KubeadmControlPlane{ Spec: controlplanev1.KubeadmControlPlaneSpec{Replicas: ptr.To(int32(5))}, - Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: 3}, + Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: ptr.To(int32(3))}, }, Machines: collections.FromMachines( &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "m1"}}, @@ -475,7 +476,7 @@ func Test_setScalingDownCondition(t *testing.T) { controlPlane: &internal.ControlPlane{ KCP: &controlplanev1.KubeadmControlPlane{ Spec: controlplanev1.KubeadmControlPlaneSpec{Replicas: ptr.To(int32(3))}, - Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: 3}, + Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: ptr.To(int32(3))}, }, Machines: collections.FromMachines( &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "m1"}}, @@ -494,7 +495,7 @@ func Test_setScalingDownCondition(t *testing.T) { controlPlane: &internal.ControlPlane{ KCP: &controlplanev1.KubeadmControlPlane{ Spec: controlplanev1.KubeadmControlPlaneSpec{Replicas: ptr.To(int32(3))}, - Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: 5}, + Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: ptr.To(int32(5))}, }, Machines: collections.FromMachines( &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "m1"}}, @@ -517,7 +518,7 @@ func Test_setScalingDownCondition(t *testing.T) { KCP: &controlplanev1.KubeadmControlPlane{ ObjectMeta: metav1.ObjectMeta{DeletionTimestamp: ptr.To(metav1.Time{Time: time.Now()})}, Spec: controlplanev1.KubeadmControlPlaneSpec{Replicas: ptr.To(int32(3))}, - Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: 5}, + Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: ptr.To(int32(5))}, }, Machines: collections.FromMachines( &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "m1"}}, @@ -539,7 +540,7 @@ func Test_setScalingDownCondition(t *testing.T) { controlPlane: &internal.ControlPlane{ KCP: &controlplanev1.KubeadmControlPlane{ Spec: controlplanev1.KubeadmControlPlaneSpec{Replicas: ptr.To(int32(1))}, - Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: 3}, + Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: ptr.To(int32(3))}, }, Machines: collections.FromMachines( &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "m1", DeletionTimestamp: ptr.To(metav1.Time{Time: time.Now().Add(-1 * time.Hour)})}, @@ -579,7 +580,7 @@ After above Pods have been removed from the Node, the following Pods will be evi controlPlane: &internal.ControlPlane{ KCP: &controlplanev1.KubeadmControlPlane{ Spec: controlplanev1.KubeadmControlPlaneSpec{Replicas: ptr.To(int32(1))}, - Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: 3}, + Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: ptr.To(int32(3))}, }, Machines: collections.FromMachines( &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "m1", DeletionTimestamp: ptr.To(metav1.Time{Time: time.Now().Add(-1 * time.Hour)})}}, @@ -607,7 +608,7 @@ After above Pods have been removed from the Node, the following Pods will be evi }, KCP: &controlplanev1.KubeadmControlPlane{ Spec: controlplanev1.KubeadmControlPlaneSpec{Replicas: ptr.To(int32(1))}, - Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: 3}, + Status: controlplanev1.KubeadmControlPlaneStatus{Replicas: ptr.To(int32(3))}, }, Machines: collections.FromMachines( &clusterv1.Machine{ObjectMeta: metav1.ObjectMeta{Name: "m1"}}, diff --git a/docs/book/src/developer/providers/migrations/v1.10-to-v1.11.md b/docs/book/src/developer/providers/migrations/v1.10-to-v1.11.md index 7c4472cdcbd5..0d8252869a8b 100644 --- a/docs/book/src/developer/providers/migrations/v1.10-to-v1.11.md +++ b/docs/book/src/developer/providers/migrations/v1.10-to-v1.11.md @@ -98,6 +98,7 @@ proposal because most of the changes described below are a consequence of the wo - See changes that apply to [all CRDs](#all-crds) - The `spec.progressDeadlineSeconds` field (deprecated since CAPI v1.9) has been removed - Replica counters are now consistent with replica counters from other resources + - `status.replicas` was made a pointer and omitempty was added - `status.readyReplicas` has now a new semantic based on machine's `Ready` condition - `status.availableReplicas` has now a new semantic based on machine's `Available` condition - `status.upToDateReplicas` has now a new semantic (and name) based on machine's `UpToDate` condition @@ -111,6 +112,7 @@ proposal because most of the changes described below are a consequence of the wo - See changes that apply to [all CRDs](#all-crds) - Replica counters fields are now consistent with replica counters from other resources + - `status.replicas` was made a pointer and omitempty was added - `status.readyReplicas` has now a new semantic based on machine's `Ready` condition - `status.availableReplicas` has now a new semantic based on machine's `Available` condition - `status.upToDateReplicas` has now a new semantic (and name) based on machine's `UpToDate` condition @@ -121,6 +123,7 @@ proposal because most of the changes described below are a consequence of the wo ### MachinePool - See changes that apply to [all CRDs](#all-crds) +- `status.replicas` was made a pointer and omitempty was added - Support for terminal errors has been dropped. - `status.failureReason` and `status.failureMessage` will continue to exist temporarily under `status.deprecated.v1beta1`. - The const values for `Failed` phase has been deprecated in the enum type for `status.phase` (controllers are not setting this value anymore) @@ -165,6 +168,7 @@ proposal because most of the changes described below are a consequence of the wo - KubeadmControlPlane (and the entire KCP provider) now implements the v1beta2 Cluster API contract. - See changes that apply to [all CRDs](#all-crds) - Replica counters fields are now consistent with replica counters from other resources. + - `status.replicas` was made a pointer and omitempty was added - `status.readyReplicas` has now a new semantic based on machine's `Ready` condition - `status.availableReplicas` has now a new semantic based on machine's `Available` condition - `status.upToDateReplicas` has now a new semantic (and name) based on machine's `UpToDate` condition diff --git a/exp/api/v1beta1/conversion_test.go b/exp/api/v1beta1/conversion_test.go index 86f8146d3359..d06e1fb00f29 100644 --- a/exp/api/v1beta1/conversion_test.go +++ b/exp/api/v1beta1/conversion_test.go @@ -25,6 +25,7 @@ import ( fuzz "github.com/google/gofuzz" "k8s.io/apimachinery/pkg/api/apitesting/fuzzer" runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/utils/ptr" expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta2" utilconversion "sigs.k8s.io/cluster-api/util/conversion" @@ -63,6 +64,12 @@ func hubMachinePoolStatus(in *expv1.MachinePoolStatus, c fuzz.Continue) { in.Initialization = nil } } + + // nil becomes &0 after hub => spoke => hub conversion + // This is acceptable as usually Replicas is set and controllers using older apiVersions are not writing MachineSet status. + if in.Replicas == nil { + in.Replicas = ptr.To(int32(0)) + } } func spokeMachinePoolStatus(in *MachinePoolStatus, c fuzz.Continue) { diff --git a/exp/api/v1beta1/zz_generated.conversion.go b/exp/api/v1beta1/zz_generated.conversion.go index 31ab13aa0076..31276b4c09a9 100644 --- a/exp/api/v1beta1/zz_generated.conversion.go +++ b/exp/api/v1beta1/zz_generated.conversion.go @@ -213,7 +213,9 @@ func Convert_v1beta2_MachinePoolSpec_To_v1beta1_MachinePoolSpec(in *v1beta2.Mach func autoConvert_v1beta1_MachinePoolStatus_To_v1beta2_MachinePoolStatus(in *MachinePoolStatus, out *v1beta2.MachinePoolStatus, s conversion.Scope) error { out.NodeRefs = *(*[]corev1.ObjectReference)(unsafe.Pointer(&in.NodeRefs)) - out.Replicas = in.Replicas + if err := v1.Convert_int32_To_Pointer_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } if err := v1.Convert_int32_To_Pointer_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err } @@ -256,7 +258,9 @@ func autoConvert_v1beta2_MachinePoolStatus_To_v1beta1_MachinePoolStatus(in *v1be } // WARNING: in.Initialization requires manual conversion: does not exist in peer-type out.NodeRefs = *(*[]corev1.ObjectReference)(unsafe.Pointer(&in.NodeRefs)) - out.Replicas = in.Replicas + if err := v1.Convert_Pointer_int32_To_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } if err := v1.Convert_Pointer_int32_To_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err } diff --git a/exp/api/v1beta2/machinepool_types.go b/exp/api/v1beta2/machinepool_types.go index 54906108d988..0c4b91314cf1 100644 --- a/exp/api/v1beta2/machinepool_types.go +++ b/exp/api/v1beta2/machinepool_types.go @@ -98,7 +98,7 @@ type MachinePoolStatus struct { // replicas is the most recently observed number of replicas. // +optional - Replicas int32 `json:"replicas"` + Replicas *int32 `json:"replicas,omitempty"` // readyReplicas is the number of ready replicas for this MachinePool. A machine is considered ready when Machine's Ready condition is true. // +optional diff --git a/exp/api/v1beta2/zz_generated.deepcopy.go b/exp/api/v1beta2/zz_generated.deepcopy.go index 8ac7af8383ce..353ba1123848 100644 --- a/exp/api/v1beta2/zz_generated.deepcopy.go +++ b/exp/api/v1beta2/zz_generated.deepcopy.go @@ -178,6 +178,11 @@ func (in *MachinePoolStatus) DeepCopyInto(out *MachinePoolStatus) { *out = make([]corev1.ObjectReference, len(*in)) copy(*out, *in) } + if in.Replicas != nil { + in, out := &in.Replicas, &out.Replicas + *out = new(int32) + **out = **in + } if in.ReadyReplicas != nil { in, out := &in.ReadyReplicas, &out.ReadyReplicas *out = new(int32) diff --git a/exp/internal/controllers/machinepool_controller_noderef.go b/exp/internal/controllers/machinepool_controller_noderef.go index 364206e10625..ee96979fa6a8 100644 --- a/exp/internal/controllers/machinepool_controller_noderef.go +++ b/exp/internal/controllers/machinepool_controller_noderef.go @@ -26,6 +26,7 @@ import ( apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/klog/v2" + "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -69,7 +70,7 @@ func (r *MachinePoolReconciler) reconcileNodeRefs(ctx context.Context, s *scope) if mp.Status.Deprecated != nil && mp.Status.Deprecated.V1Beta1 != nil { readyReplicas = mp.Status.Deprecated.V1Beta1.ReadyReplicas } - if mp.Status.Replicas == readyReplicas && len(mp.Status.NodeRefs) == int(readyReplicas) { + if ptr.Deref(mp.Status.Replicas, 0) == readyReplicas && len(mp.Status.NodeRefs) == int(readyReplicas) { v1beta1conditions.MarkTrue(mp, expv1.ReplicasReadyV1Beta1Condition) return ctrl.Result{}, nil } @@ -114,7 +115,7 @@ func (r *MachinePoolReconciler) reconcileNodeRefs(ctx context.Context, s *scope) } mp.Status.Deprecated.V1Beta1.ReadyReplicas = int32(nodeRefsResult.ready) mp.Status.Deprecated.V1Beta1.AvailableReplicas = int32(nodeRefsResult.available) - mp.Status.Deprecated.V1Beta1.UnavailableReplicas = mp.Status.Replicas - mp.Status.Deprecated.V1Beta1.AvailableReplicas + mp.Status.Deprecated.V1Beta1.UnavailableReplicas = ptr.Deref(mp.Status.Replicas, 0) - mp.Status.Deprecated.V1Beta1.AvailableReplicas mp.Status.NodeRefs = nodeRefsResult.references log.Info("Set MachinePool's NodeRefs", "nodeRefs", mp.Status.NodeRefs) @@ -126,8 +127,8 @@ func (r *MachinePoolReconciler) reconcileNodeRefs(ctx context.Context, s *scope) return ctrl.Result{}, err } - if mp.Status.Replicas != mp.Status.Deprecated.V1Beta1.ReadyReplicas || len(nodeRefsResult.references) != int(mp.Status.Deprecated.V1Beta1.ReadyReplicas) { - log.Info("Not enough ready replicas or node references", "nodeRefs", len(nodeRefsResult.references), "readyReplicas", mp.Status.ReadyReplicas, "replicas", mp.Status.Replicas) + if ptr.Deref(mp.Status.Replicas, 0) != mp.Status.Deprecated.V1Beta1.ReadyReplicas || len(nodeRefsResult.references) != int(mp.Status.Deprecated.V1Beta1.ReadyReplicas) { + log.Info("Not enough ready replicas or node references", "nodeRefs", len(nodeRefsResult.references), "readyReplicas", mp.Status.ReadyReplicas, "replicas", ptr.Deref(mp.Status.Replicas, 0)) v1beta1conditions.MarkFalse(mp, expv1.ReplicasReadyV1Beta1Condition, expv1.WaitingForReplicasReadyV1Beta1Reason, clusterv1.ConditionSeverityInfo, "") return ctrl.Result{RequeueAfter: 30 * time.Second}, nil } diff --git a/exp/internal/controllers/machinepool_controller_phases.go b/exp/internal/controllers/machinepool_controller_phases.go index a35e2dec3b4a..5d4275bf93fd 100644 --- a/exp/internal/controllers/machinepool_controller_phases.go +++ b/exp/internal/controllers/machinepool_controller_phases.go @@ -346,8 +346,8 @@ func (r *MachinePoolReconciler) reconcileInfrastructure(ctx context.Context, s * } } - if len(providerIDList) == 0 && mp.Status.Replicas != 0 { - log.Info("Retrieved empty spec.providerIDList from infrastructure provider but status.replicas is not zero.", "replicas", mp.Status.Replicas) + if len(providerIDList) == 0 && ptr.Deref(mp.Status.Replicas, 0) != 0 { + log.Info("Retrieved empty spec.providerIDList from infrastructure provider but status.replicas is not zero.", "replicas", ptr.Deref(mp.Status.Replicas, 0)) return ctrl.Result{}, nil } @@ -361,7 +361,7 @@ func (r *MachinePoolReconciler) reconcileInfrastructure(ctx context.Context, s * } mp.Status.Deprecated.V1Beta1.ReadyReplicas = 0 mp.Status.Deprecated.V1Beta1.AvailableReplicas = 0 - mp.Status.Deprecated.V1Beta1.UnavailableReplicas = mp.Status.Replicas + mp.Status.Deprecated.V1Beta1.UnavailableReplicas = ptr.Deref(mp.Status.Replicas, 0) } return ctrl.Result{}, nil diff --git a/exp/internal/controllers/machinepool_controller_phases_test.go b/exp/internal/controllers/machinepool_controller_phases_test.go index 077c6ab108a6..b9027869d960 100644 --- a/exp/internal/controllers/machinepool_controller_phases_test.go +++ b/exp/internal/controllers/machinepool_controller_phases_test.go @@ -663,7 +663,7 @@ func TestReconcileMachinePoolPhases(t *testing.T) { ReadyReplicas: 1, }, } - machinePool.Status.Replicas = 1 + machinePool.Status.Replicas = ptr.To(int32(1)) fakeClient := fake.NewClientBuilder().WithObjects(defaultCluster, defaultKubeconfigSecret, machinePool, bootstrapConfig, infraConfig, builder.TestBootstrapConfigCRD, builder.TestInfrastructureMachineTemplateCRD).Build() r := &MachinePoolReconciler{ @@ -759,7 +759,7 @@ func TestReconcileMachinePoolPhases(t *testing.T) { ReadyReplicas: 1, }, } - machinePool.Status.Replicas = 1 + machinePool.Status.Replicas = ptr.To(int32(1)) fakeClient := fake.NewClientBuilder().WithObjects(defaultCluster, defaultKubeconfigSecret, machinePool, bootstrapConfig, infraConfig, builder.TestBootstrapConfigCRD, builder.TestInfrastructureMachineTemplateCRD).Build() r := &MachinePoolReconciler{ diff --git a/exp/internal/controllers/machinepool_controller_test.go b/exp/internal/controllers/machinepool_controller_test.go index 41207cb83321..effd5adb99ea 100644 --- a/exp/internal/controllers/machinepool_controller_test.go +++ b/exp/internal/controllers/machinepool_controller_test.go @@ -366,7 +366,7 @@ func TestReconcileMachinePoolRequest(t *testing.T) { }, }, Status: expv1.MachinePoolStatus{ - Replicas: 1, + Replicas: ptr.To(int32(1)), Deprecated: &expv1.MachinePoolDeprecatedStatus{ V1Beta1: &expv1.MachinePoolV1Beta1DeprecatedStatus{ ReadyReplicas: 1, @@ -1036,7 +1036,7 @@ func TestMachinePoolConditions(t *testing.T) { {Name: "node-1"}, {Name: "azure-node-4"}, } - mp.Status.Replicas = 2 + mp.Status.Replicas = ptr.To(int32(2)) if mp.Status.Deprecated == nil { mp.Status.Deprecated = &expv1.MachinePoolDeprecatedStatus{} } diff --git a/exp/topology/desiredstate/desired_state_test.go b/exp/topology/desiredstate/desired_state_test.go index 48f09cba408d..90382f354853 100644 --- a/exp/topology/desiredstate/desired_state_test.go +++ b/exp/topology/desiredstate/desired_state_test.go @@ -1858,7 +1858,7 @@ func TestComputeMachineDeployment(t *testing.T) { WithVersion(*tt.currentMDVersion). WithStatus(clusterv1.MachineDeploymentStatus{ ObservedGeneration: 2, - Replicas: 2, + Replicas: ptr.To[int32](2), ReadyReplicas: ptr.To[int32](2), UpToDateReplicas: ptr.To[int32](2), AvailableReplicas: ptr.To[int32](2), @@ -2256,7 +2256,7 @@ func TestComputeMachinePool(t *testing.T) { WithVersion(*tt.currentMPVersion). WithStatus(expv1.MachinePoolStatus{ ObservedGeneration: 2, - Replicas: 2, + Replicas: ptr.To(int32(2)), Deprecated: &expv1.MachinePoolDeprecatedStatus{ V1Beta1: &expv1.MachinePoolV1Beta1DeprecatedStatus{ ReadyReplicas: 2, diff --git a/internal/apis/controlplane/kubeadm/v1alpha3/conversion_test.go b/internal/apis/controlplane/kubeadm/v1alpha3/conversion_test.go index 56e32cc045be..fa098474e533 100644 --- a/internal/apis/controlplane/kubeadm/v1alpha3/conversion_test.go +++ b/internal/apis/controlplane/kubeadm/v1alpha3/conversion_test.go @@ -25,6 +25,7 @@ import ( fuzz "github.com/google/gofuzz" "k8s.io/apimachinery/pkg/api/apitesting/fuzzer" runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/utils/ptr" bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta2" "sigs.k8s.io/cluster-api/bootstrap/kubeadm/types/upstreamv1beta1" @@ -81,6 +82,12 @@ func hubKubeadmControlPlaneStatus(in *controlplanev1.KubeadmControlPlaneStatus, in.Initialization = nil } } + + // nil becomes &0 after hub => spoke => hub conversion + // This is acceptable as usually Replicas is set and controllers using older apiVersions are not writing MachineSet status. + if in.Replicas == nil { + in.Replicas = ptr.To(int32(0)) + } } func spokeKubeadmControlPlaneStatus(in *KubeadmControlPlaneStatus, c fuzz.Continue) { diff --git a/internal/apis/controlplane/kubeadm/v1alpha3/zz_generated.conversion.go b/internal/apis/controlplane/kubeadm/v1alpha3/zz_generated.conversion.go index 65340cc75e47..21b3648529ac 100644 --- a/internal/apis/controlplane/kubeadm/v1alpha3/zz_generated.conversion.go +++ b/internal/apis/controlplane/kubeadm/v1alpha3/zz_generated.conversion.go @@ -228,7 +228,9 @@ func autoConvert_v1beta2_KubeadmControlPlaneSpec_To_v1alpha3_KubeadmControlPlane func autoConvert_v1alpha3_KubeadmControlPlaneStatus_To_v1beta2_KubeadmControlPlaneStatus(in *KubeadmControlPlaneStatus, out *v1beta2.KubeadmControlPlaneStatus, s conversion.Scope) error { out.Selector = in.Selector - out.Replicas = in.Replicas + if err := v1.Convert_int32_To_Pointer_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } // WARNING: in.UpdatedReplicas requires manual conversion: does not exist in peer-type if err := v1.Convert_int32_To_Pointer_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err @@ -267,7 +269,9 @@ func autoConvert_v1beta2_KubeadmControlPlaneStatus_To_v1alpha3_KubeadmControlPla } // WARNING: in.Initialization requires manual conversion: does not exist in peer-type out.Selector = in.Selector - out.Replicas = in.Replicas + if err := v1.Convert_Pointer_int32_To_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } if err := v1.Convert_Pointer_int32_To_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err } diff --git a/internal/apis/controlplane/kubeadm/v1alpha4/conversion_test.go b/internal/apis/controlplane/kubeadm/v1alpha4/conversion_test.go index 67f771955c16..ff1e557eef84 100644 --- a/internal/apis/controlplane/kubeadm/v1alpha4/conversion_test.go +++ b/internal/apis/controlplane/kubeadm/v1alpha4/conversion_test.go @@ -26,6 +26,7 @@ import ( corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/apitesting/fuzzer" runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/utils/ptr" bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta2" controlplanev1 "sigs.k8s.io/cluster-api/controlplane/kubeadm/api/v1beta2" @@ -92,6 +93,12 @@ func hubKubeadmControlPlaneStatus(in *controlplanev1.KubeadmControlPlaneStatus, in.Initialization = nil } } + + // nil becomes &0 after hub => spoke => hub conversion + // This is acceptable as usually Replicas is set and controllers using older apiVersions are not writing MachineSet status. + if in.Replicas == nil { + in.Replicas = ptr.To(int32(0)) + } } func spokeKubeadmControlPlaneStatus(in *KubeadmControlPlaneStatus, c fuzz.Continue) { diff --git a/internal/apis/controlplane/kubeadm/v1alpha4/zz_generated.conversion.go b/internal/apis/controlplane/kubeadm/v1alpha4/zz_generated.conversion.go index 4c70412e0b40..de2778eddbad 100644 --- a/internal/apis/controlplane/kubeadm/v1alpha4/zz_generated.conversion.go +++ b/internal/apis/controlplane/kubeadm/v1alpha4/zz_generated.conversion.go @@ -333,7 +333,9 @@ func autoConvert_v1beta2_KubeadmControlPlaneSpec_To_v1alpha4_KubeadmControlPlane func autoConvert_v1alpha4_KubeadmControlPlaneStatus_To_v1beta2_KubeadmControlPlaneStatus(in *KubeadmControlPlaneStatus, out *v1beta2.KubeadmControlPlaneStatus, s conversion.Scope) error { out.Selector = in.Selector - out.Replicas = in.Replicas + if err := v1.Convert_int32_To_Pointer_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } out.Version = (*string)(unsafe.Pointer(in.Version)) // WARNING: in.UpdatedReplicas requires manual conversion: does not exist in peer-type if err := v1.Convert_int32_To_Pointer_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { @@ -373,7 +375,9 @@ func autoConvert_v1beta2_KubeadmControlPlaneStatus_To_v1alpha4_KubeadmControlPla } // WARNING: in.Initialization requires manual conversion: does not exist in peer-type out.Selector = in.Selector - out.Replicas = in.Replicas + if err := v1.Convert_Pointer_int32_To_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } if err := v1.Convert_Pointer_int32_To_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err } diff --git a/internal/apis/core/exp/v1alpha3/conversion_test.go b/internal/apis/core/exp/v1alpha3/conversion_test.go index 5d1aab70323a..eaf68cfdb2fc 100644 --- a/internal/apis/core/exp/v1alpha3/conversion_test.go +++ b/internal/apis/core/exp/v1alpha3/conversion_test.go @@ -25,6 +25,7 @@ import ( fuzz "github.com/google/gofuzz" "k8s.io/apimachinery/pkg/api/apitesting/fuzzer" runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/utils/ptr" expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta2" clusterv1alpha3 "sigs.k8s.io/cluster-api/internal/apis/core/v1alpha3" @@ -66,6 +67,12 @@ func hubMachinePoolStatus(in *expv1.MachinePoolStatus, c fuzz.Continue) { in.Initialization = nil } } + + // nil becomes &0 after hub => spoke => hub conversion + // This is acceptable as usually Replicas is set and controllers using older apiVersions are not writing MachineSet status. + if in.Replicas == nil { + in.Replicas = ptr.To(int32(0)) + } } func spokeBootstrap(in *clusterv1alpha3.Bootstrap, c fuzz.Continue) { diff --git a/internal/apis/core/exp/v1alpha3/zz_generated.conversion.go b/internal/apis/core/exp/v1alpha3/zz_generated.conversion.go index c9f4bf10f863..287a573e9b6b 100644 --- a/internal/apis/core/exp/v1alpha3/zz_generated.conversion.go +++ b/internal/apis/core/exp/v1alpha3/zz_generated.conversion.go @@ -199,7 +199,9 @@ func Convert_v1beta2_MachinePoolSpec_To_v1alpha3_MachinePoolSpec(in *v1beta2.Mac func autoConvert_v1alpha3_MachinePoolStatus_To_v1beta2_MachinePoolStatus(in *MachinePoolStatus, out *v1beta2.MachinePoolStatus, s conversion.Scope) error { out.NodeRefs = *(*[]corev1.ObjectReference)(unsafe.Pointer(&in.NodeRefs)) - out.Replicas = in.Replicas + if err := v1.Convert_int32_To_Pointer_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } if err := v1.Convert_int32_To_Pointer_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err } @@ -241,7 +243,9 @@ func autoConvert_v1beta2_MachinePoolStatus_To_v1alpha3_MachinePoolStatus(in *v1b } // WARNING: in.Initialization requires manual conversion: does not exist in peer-type out.NodeRefs = *(*[]corev1.ObjectReference)(unsafe.Pointer(&in.NodeRefs)) - out.Replicas = in.Replicas + if err := v1.Convert_Pointer_int32_To_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } if err := v1.Convert_Pointer_int32_To_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err } diff --git a/internal/apis/core/exp/v1alpha4/conversion_test.go b/internal/apis/core/exp/v1alpha4/conversion_test.go index 7a67734b0967..056a5526b78b 100644 --- a/internal/apis/core/exp/v1alpha4/conversion_test.go +++ b/internal/apis/core/exp/v1alpha4/conversion_test.go @@ -25,6 +25,7 @@ import ( fuzz "github.com/google/gofuzz" "k8s.io/apimachinery/pkg/api/apitesting/fuzzer" runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/utils/ptr" expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta2" utilconversion "sigs.k8s.io/cluster-api/util/conversion" @@ -62,4 +63,10 @@ func hubMachinePoolStatus(in *expv1.MachinePoolStatus, c fuzz.Continue) { in.Initialization = nil } } + + // nil becomes &0 after hub => spoke => hub conversion + // This is acceptable as usually Replicas is set and controllers using older apiVersions are not writing MachineSet status. + if in.Replicas == nil { + in.Replicas = ptr.To(int32(0)) + } } diff --git a/internal/apis/core/exp/v1alpha4/zz_generated.conversion.go b/internal/apis/core/exp/v1alpha4/zz_generated.conversion.go index d8ae37421c6d..3fd640fed1fb 100644 --- a/internal/apis/core/exp/v1alpha4/zz_generated.conversion.go +++ b/internal/apis/core/exp/v1alpha4/zz_generated.conversion.go @@ -213,7 +213,9 @@ func Convert_v1beta2_MachinePoolSpec_To_v1alpha4_MachinePoolSpec(in *v1beta2.Mac func autoConvert_v1alpha4_MachinePoolStatus_To_v1beta2_MachinePoolStatus(in *MachinePoolStatus, out *v1beta2.MachinePoolStatus, s conversion.Scope) error { out.NodeRefs = *(*[]corev1.ObjectReference)(unsafe.Pointer(&in.NodeRefs)) - out.Replicas = in.Replicas + if err := v1.Convert_int32_To_Pointer_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } if err := v1.Convert_int32_To_Pointer_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err } @@ -255,7 +257,9 @@ func autoConvert_v1beta2_MachinePoolStatus_To_v1alpha4_MachinePoolStatus(in *v1b } // WARNING: in.Initialization requires manual conversion: does not exist in peer-type out.NodeRefs = *(*[]corev1.ObjectReference)(unsafe.Pointer(&in.NodeRefs)) - out.Replicas = in.Replicas + if err := v1.Convert_Pointer_int32_To_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } if err := v1.Convert_Pointer_int32_To_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err } diff --git a/internal/apis/core/v1alpha3/conversion_test.go b/internal/apis/core/v1alpha3/conversion_test.go index 5ea7f88eec48..b2a1e0163cfb 100644 --- a/internal/apis/core/v1alpha3/conversion_test.go +++ b/internal/apis/core/v1alpha3/conversion_test.go @@ -26,6 +26,7 @@ import ( apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" "k8s.io/apimachinery/pkg/api/apitesting/fuzzer" runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/conversion" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta2" @@ -117,6 +118,11 @@ func hubMachineSetStatus(in *clusterv1.MachineSetStatus, c fuzz.Continue) { if in.Deprecated.V1Beta1 == nil { in.Deprecated.V1Beta1 = &clusterv1.MachineSetV1Beta1DeprecatedStatus{} } + // nil becomes &0 after hub => spoke => hub conversion + // This is acceptable as usually Replicas is set and controllers using older apiVersions are not writing MachineSet status. + if in.Replicas == nil { + in.Replicas = ptr.To(int32(0)) + } } func MachineDeploymentFuzzFunc(_ runtimeserializer.CodecFactory) []interface{} { @@ -137,6 +143,11 @@ func hubMachineDeploymentStatus(in *clusterv1.MachineDeploymentStatus, c fuzz.Co if in.Deprecated.V1Beta1 == nil { in.Deprecated.V1Beta1 = &clusterv1.MachineDeploymentV1Beta1DeprecatedStatus{} } + // nil becomes &0 after hub => spoke => hub conversion + // This is acceptable as usually Replicas is set and controllers using older apiVersions are not writing MachineSet status. + if in.Replicas == nil { + in.Replicas = ptr.To(int32(0)) + } } func spokeMachineDeploymentSpec(in *MachineDeploymentSpec, c fuzz.Continue) { diff --git a/internal/apis/core/v1alpha3/zz_generated.conversion.go b/internal/apis/core/v1alpha3/zz_generated.conversion.go index b3c65aa871e7..834c642aec52 100644 --- a/internal/apis/core/v1alpha3/zz_generated.conversion.go +++ b/internal/apis/core/v1alpha3/zz_generated.conversion.go @@ -806,7 +806,9 @@ func autoConvert_v1beta2_MachineDeploymentSpec_To_v1alpha3_MachineDeploymentSpec func autoConvert_v1alpha3_MachineDeploymentStatus_To_v1beta2_MachineDeploymentStatus(in *MachineDeploymentStatus, out *v1beta2.MachineDeploymentStatus, s conversion.Scope) error { out.ObservedGeneration = in.ObservedGeneration out.Selector = in.Selector - out.Replicas = in.Replicas + if err := v1.Convert_int32_To_Pointer_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } // WARNING: in.UpdatedReplicas requires manual conversion: does not exist in peer-type if err := v1.Convert_int32_To_Pointer_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err @@ -823,7 +825,9 @@ func autoConvert_v1beta2_MachineDeploymentStatus_To_v1alpha3_MachineDeploymentSt // WARNING: in.Conditions requires manual conversion: does not exist in peer-type out.ObservedGeneration = in.ObservedGeneration out.Selector = in.Selector - out.Replicas = in.Replicas + if err := v1.Convert_Pointer_int32_To_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } if err := v1.Convert_Pointer_int32_To_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err } @@ -1177,7 +1181,9 @@ func autoConvert_v1beta2_MachineSetSpec_To_v1alpha3_MachineSetSpec(in *v1beta2.M func autoConvert_v1alpha3_MachineSetStatus_To_v1beta2_MachineSetStatus(in *MachineSetStatus, out *v1beta2.MachineSetStatus, s conversion.Scope) error { out.Selector = in.Selector - out.Replicas = in.Replicas + if err := v1.Convert_int32_To_Pointer_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } // WARNING: in.FullyLabeledReplicas requires manual conversion: does not exist in peer-type if err := v1.Convert_int32_To_Pointer_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err @@ -1194,7 +1200,9 @@ func autoConvert_v1alpha3_MachineSetStatus_To_v1beta2_MachineSetStatus(in *Machi func autoConvert_v1beta2_MachineSetStatus_To_v1alpha3_MachineSetStatus(in *v1beta2.MachineSetStatus, out *MachineSetStatus, s conversion.Scope) error { // WARNING: in.Conditions requires manual conversion: does not exist in peer-type out.Selector = in.Selector - out.Replicas = in.Replicas + if err := v1.Convert_Pointer_int32_To_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } if err := v1.Convert_Pointer_int32_To_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err } diff --git a/internal/apis/core/v1alpha4/conversion_test.go b/internal/apis/core/v1alpha4/conversion_test.go index 19ab37405bb5..ecb7d53790ff 100644 --- a/internal/apis/core/v1alpha4/conversion_test.go +++ b/internal/apis/core/v1alpha4/conversion_test.go @@ -203,6 +203,11 @@ func hubMachineSetStatus(in *clusterv1.MachineSetStatus, c fuzz.Continue) { if in.Deprecated.V1Beta1 == nil { in.Deprecated.V1Beta1 = &clusterv1.MachineSetV1Beta1DeprecatedStatus{} } + // nil becomes &0 after hub => spoke => hub conversion + // This is acceptable as usually Replicas is set and controllers using older apiVersions are not writing MachineSet status. + if in.Replicas == nil { + in.Replicas = ptr.To(int32(0)) + } } func MachineDeploymentFuzzFuncs(_ runtimeserializer.CodecFactory) []interface{} { @@ -221,6 +226,11 @@ func hubMachineDeploymentStatus(in *clusterv1.MachineDeploymentStatus, c fuzz.Co if in.Deprecated.V1Beta1 == nil { in.Deprecated.V1Beta1 = &clusterv1.MachineDeploymentV1Beta1DeprecatedStatus{} } + // nil becomes &0 after hub => spoke => hub conversion + // This is acceptable as usually Replicas is set and controllers using older apiVersions are not writing MachineSet status. + if in.Replicas == nil { + in.Replicas = ptr.To(int32(0)) + } } func spokeMachineDeploymentSpec(in *MachineDeploymentSpec, c fuzz.Continue) { diff --git a/internal/apis/core/v1alpha4/zz_generated.conversion.go b/internal/apis/core/v1alpha4/zz_generated.conversion.go index 8156f2ad427e..ac8bf12c2626 100644 --- a/internal/apis/core/v1alpha4/zz_generated.conversion.go +++ b/internal/apis/core/v1alpha4/zz_generated.conversion.go @@ -1200,7 +1200,9 @@ func autoConvert_v1beta2_MachineDeploymentSpec_To_v1alpha4_MachineDeploymentSpec func autoConvert_v1alpha4_MachineDeploymentStatus_To_v1beta2_MachineDeploymentStatus(in *MachineDeploymentStatus, out *v1beta2.MachineDeploymentStatus, s conversion.Scope) error { out.ObservedGeneration = in.ObservedGeneration out.Selector = in.Selector - out.Replicas = in.Replicas + if err := v1.Convert_int32_To_Pointer_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } // WARNING: in.UpdatedReplicas requires manual conversion: does not exist in peer-type if err := v1.Convert_int32_To_Pointer_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err @@ -1238,7 +1240,9 @@ func autoConvert_v1beta2_MachineDeploymentStatus_To_v1alpha4_MachineDeploymentSt } out.ObservedGeneration = in.ObservedGeneration out.Selector = in.Selector - out.Replicas = in.Replicas + if err := v1.Convert_Pointer_int32_To_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } if err := v1.Convert_Pointer_int32_To_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err } @@ -1617,7 +1621,9 @@ func autoConvert_v1beta2_MachineSetSpec_To_v1alpha4_MachineSetSpec(in *v1beta2.M func autoConvert_v1alpha4_MachineSetStatus_To_v1beta2_MachineSetStatus(in *MachineSetStatus, out *v1beta2.MachineSetStatus, s conversion.Scope) error { out.Selector = in.Selector - out.Replicas = in.Replicas + if err := v1.Convert_int32_To_Pointer_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } // WARNING: in.FullyLabeledReplicas requires manual conversion: does not exist in peer-type if err := v1.Convert_int32_To_Pointer_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err @@ -1655,7 +1661,9 @@ func autoConvert_v1beta2_MachineSetStatus_To_v1alpha4_MachineSetStatus(in *v1bet out.Conditions = nil } out.Selector = in.Selector - out.Replicas = in.Replicas + if err := v1.Convert_Pointer_int32_To_int32(&in.Replicas, &out.Replicas, s); err != nil { + return err + } if err := v1.Convert_Pointer_int32_To_int32(&in.ReadyReplicas, &out.ReadyReplicas, s); err != nil { return err } diff --git a/internal/controllers/cluster/cluster_controller_status.go b/internal/controllers/cluster/cluster_controller_status.go index 442bf9db9ca3..e2ec14014e23 100644 --- a/internal/controllers/cluster/cluster_controller_status.go +++ b/internal/controllers/cluster/cluster_controller_status.go @@ -211,7 +211,9 @@ func setWorkersReplicas(_ context.Context, cluster *clusterv1.Cluster, machinePo if mp.Spec.Replicas != nil { desiredReplicas = ptr.To(ptr.Deref(desiredReplicas, 0) + *mp.Spec.Replicas) } - currentReplicas = ptr.To(ptr.Deref(currentReplicas, 0) + mp.Status.Replicas) + if mp.Status.Replicas != nil { + currentReplicas = ptr.To(ptr.Deref(currentReplicas, 0) + *mp.Status.Replicas) + } if mp.Status.ReadyReplicas != nil { readyReplicas = ptr.To(ptr.Deref(readyReplicas, 0) + *mp.Status.ReadyReplicas) } @@ -227,7 +229,9 @@ func setWorkersReplicas(_ context.Context, cluster *clusterv1.Cluster, machinePo if md.Spec.Replicas != nil { desiredReplicas = ptr.To(ptr.Deref(desiredReplicas, 0) + *md.Spec.Replicas) } - currentReplicas = ptr.To(ptr.Deref(currentReplicas, 0) + md.Status.Replicas) + if md.Status.Replicas != nil { + currentReplicas = ptr.To(ptr.Deref(currentReplicas, 0) + *md.Status.Replicas) + } if md.Status.ReadyReplicas != nil { readyReplicas = ptr.To(ptr.Deref(readyReplicas, 0) + *md.Status.ReadyReplicas) } @@ -246,7 +250,9 @@ func setWorkersReplicas(_ context.Context, cluster *clusterv1.Cluster, machinePo if ms.Spec.Replicas != nil { desiredReplicas = ptr.To(ptr.Deref(desiredReplicas, 0) + *ms.Spec.Replicas) } - currentReplicas = ptr.To(ptr.Deref(currentReplicas, 0) + ms.Status.Replicas) + if ms.Status.Replicas != nil { + currentReplicas = ptr.To(ptr.Deref(currentReplicas, 0) + *ms.Status.Replicas) + } if ms.Status.ReadyReplicas != nil { readyReplicas = ptr.To(ptr.Deref(readyReplicas, 0) + *ms.Status.ReadyReplicas) } diff --git a/internal/controllers/cluster/cluster_controller_status_test.go b/internal/controllers/cluster/cluster_controller_status_test.go index 79f886db900d..d7ee3d71a1fb 100644 --- a/internal/controllers/cluster/cluster_controller_status_test.go +++ b/internal/controllers/cluster/cluster_controller_status_test.go @@ -278,7 +278,7 @@ func TestSetWorkersReplicas(t *testing.T) { fakeMachine("m1"), // not owned by the cluster ), getDescendantsSucceeded: true, - expectReplicas: ptr.To(int32(0)), // Note: currently this is still not a pointer in v1beta1, but it should change in v1beta2 + expectReplicas: nil, }, { name: "should count workers from different objects", @@ -3077,15 +3077,15 @@ func (r currentReplicas) ApplyToControlPlane(cp *unstructured.Unstructured) { } func (r currentReplicas) ApplyToMachinePool(mp *expv1.MachinePool) { - mp.Status.Replicas = int32(r) + mp.Status.Replicas = ptr.To(int32(r)) } func (r currentReplicas) ApplyToMachineDeployment(md *clusterv1.MachineDeployment) { - md.Status.Replicas = int32(r) + md.Status.Replicas = ptr.To(int32(r)) } func (r currentReplicas) ApplyToMachineSet(ms *clusterv1.MachineSet) { - ms.Status.Replicas = int32(r) + ms.Status.Replicas = ptr.To(int32(r)) } type readyReplicas int32 diff --git a/internal/controllers/machinedeployment/machinedeployment_controller_test.go b/internal/controllers/machinedeployment/machinedeployment_controller_test.go index 5327d9f5f830..ff752dbe8253 100644 --- a/internal/controllers/machinedeployment/machinedeployment_controller_test.go +++ b/internal/controllers/machinedeployment/machinedeployment_controller_test.go @@ -474,7 +474,7 @@ func TestMachineDeploymentReconciler(t *testing.T) { fakeMachineNodeRef(&m, providerID, g) } - return newms.Status.Replicas == desiredMachineDeploymentReplicas + return ptr.Deref(newms.Status.Replicas, 0) == desiredMachineDeploymentReplicas }, timeout*5).Should(BeTrue()) t.Log("Verifying MachineDeployment has correct Conditions") diff --git a/internal/controllers/machinedeployment/machinedeployment_rolling_test.go b/internal/controllers/machinedeployment/machinedeployment_rolling_test.go index 5977f34b7623..57c408d985ad 100644 --- a/internal/controllers/machinedeployment/machinedeployment_rolling_test.go +++ b/internal/controllers/machinedeployment/machinedeployment_rolling_test.go @@ -167,7 +167,7 @@ func TestReconcileNewMachineSet(t *testing.T) { Replicas: ptr.To[int32](3), }, Status: clusterv1.MachineSetStatus{ - Replicas: 3, + Replicas: ptr.To[int32](3), }, }, }, @@ -211,7 +211,7 @@ func TestReconcileNewMachineSet(t *testing.T) { Replicas: ptr.To[int32](0), }, Status: clusterv1.MachineSetStatus{ - Replicas: 1, + Replicas: ptr.To[int32](1), }, }, }, @@ -425,7 +425,7 @@ func TestReconcileOldMachineSets(t *testing.T) { Replicas: ptr.To[int32](5), }, Status: clusterv1.MachineSetStatus{ - Replicas: 5, + Replicas: ptr.To[int32](5), }, }, oldMachineSets: []*clusterv1.MachineSet{ @@ -438,7 +438,7 @@ func TestReconcileOldMachineSets(t *testing.T) { Replicas: ptr.To[int32](8), }, Status: clusterv1.MachineSetStatus{ - Replicas: 10, + Replicas: ptr.To[int32](10), ReadyReplicas: ptr.To[int32](8), AvailableReplicas: ptr.To[int32](8), }, diff --git a/internal/controllers/machinedeployment/machinedeployment_status.go b/internal/controllers/machinedeployment/machinedeployment_status.go index 3fa78b49a8ef..da8d54835237 100644 --- a/internal/controllers/machinedeployment/machinedeployment_status.go +++ b/internal/controllers/machinedeployment/machinedeployment_status.go @@ -27,6 +27,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/klog/v2" + "k8s.io/utils/ptr" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -110,7 +111,7 @@ func setPhase(_ context.Context, machineDeployment *clusterv1.MachineDeployment, } desiredReplicas := *machineDeployment.Spec.Replicas - currentReplicas := mdutil.GetActualReplicaCountForMachineSets(machineSets) + currentReplicas := ptr.Deref(mdutil.GetActualReplicaCountForMachineSets(machineSets), 0) switch { case desiredReplicas == currentReplicas: @@ -278,7 +279,7 @@ func setScalingUpCondition(_ context.Context, machineDeployment *clusterv1.Machi if !machineDeployment.DeletionTimestamp.IsZero() { desiredReplicas = 0 } - currentReplicas := mdutil.GetActualReplicaCountForMachineSets(machineSets) + currentReplicas := ptr.Deref(mdutil.GetActualReplicaCountForMachineSets(machineSets), 0) missingReferencesMessage := calculateMissingReferencesMessage(machineDeployment, bootstrapObjectNotFound, infrastructureObjectNotFound) @@ -337,7 +338,7 @@ func setScalingDownCondition(_ context.Context, machineDeployment *clusterv1.Mac if !machineDeployment.DeletionTimestamp.IsZero() { desiredReplicas = 0 } - currentReplicas := mdutil.GetActualReplicaCountForMachineSets(machineSets) + currentReplicas := ptr.Deref(mdutil.GetActualReplicaCountForMachineSets(machineSets), 0) // Scaling down. if currentReplicas > desiredReplicas { diff --git a/internal/controllers/machinedeployment/machinedeployment_status_test.go b/internal/controllers/machinedeployment/machinedeployment_status_test.go index b860ab6f856b..91a7df4cd248 100644 --- a/internal/controllers/machinedeployment/machinedeployment_status_test.go +++ b/internal/controllers/machinedeployment/machinedeployment_status_test.go @@ -1317,7 +1317,7 @@ func fakeMachineSet(name string, options ...fakeMachineSetOption) *clusterv1.Mac func withStatusReplicas(n int32) fakeMachineSetOption { return func(ms *clusterv1.MachineSet) { - ms.Status.Replicas = n + ms.Status.Replicas = ptr.To(n) } } diff --git a/internal/controllers/machinedeployment/machinedeployment_sync.go b/internal/controllers/machinedeployment/machinedeployment_sync.go index 7ea66b4d7284..8899cba4a864 100644 --- a/internal/controllers/machinedeployment/machinedeployment_sync.go +++ b/internal/controllers/machinedeployment/machinedeployment_sync.go @@ -527,7 +527,7 @@ func calculateV1Beta1Status(allMSs []*clusterv1.MachineSet, newMS *clusterv1.Mac deployment.Status.Deprecated.V1Beta1 = &clusterv1.MachineDeploymentV1Beta1DeprecatedStatus{} } - deployment.Status.Deprecated.V1Beta1.UpdatedReplicas = mdutil.GetActualReplicaCountForMachineSets([]*clusterv1.MachineSet{newMS}) + deployment.Status.Deprecated.V1Beta1.UpdatedReplicas = ptr.Deref(mdutil.GetActualReplicaCountForMachineSets([]*clusterv1.MachineSet{newMS}), 0) deployment.Status.Deprecated.V1Beta1.ReadyReplicas = mdutil.GetV1Beta1ReadyReplicaCountForMachineSets(allMSs) deployment.Status.Deprecated.V1Beta1.AvailableReplicas = availableReplicas deployment.Status.Deprecated.V1Beta1.UnavailableReplicas = unavailableReplicas @@ -610,7 +610,7 @@ func (r *Reconciler) cleanupDeployment(ctx context.Context, oldMSs []*clusterv1. } // Avoid delete machine set with non-zero replica counts - if ms.Status.Replicas != 0 || *(ms.Spec.Replicas) != 0 || ms.Generation > ms.Status.ObservedGeneration || !ms.DeletionTimestamp.IsZero() { + if ptr.Deref(ms.Status.Replicas, 0) != 0 || *(ms.Spec.Replicas) != 0 || ms.Generation > ms.Status.ObservedGeneration || !ms.DeletionTimestamp.IsZero() { continue } diff --git a/internal/controllers/machinedeployment/machinedeployment_sync_test.go b/internal/controllers/machinedeployment/machinedeployment_sync_test.go index b2ec72f49cec..2217b8536cd5 100644 --- a/internal/controllers/machinedeployment/machinedeployment_sync_test.go +++ b/internal/controllers/machinedeployment/machinedeployment_sync_test.go @@ -53,7 +53,7 @@ func TestCalculateV1Beta1Status(t *testing.T) { }, Status: clusterv1.MachineSetStatus{ Selector: "", - Replicas: 2, + Replicas: ptr.To[int32](2), Deprecated: &clusterv1.MachineSetDeprecatedStatus{ V1Beta1: &clusterv1.MachineSetV1Beta1DeprecatedStatus{ AvailableReplicas: 2, @@ -69,7 +69,7 @@ func TestCalculateV1Beta1Status(t *testing.T) { }, Status: clusterv1.MachineSetStatus{ Selector: "", - Replicas: 2, + Replicas: ptr.To[int32](2), Deprecated: &clusterv1.MachineSetDeprecatedStatus{ V1Beta1: &clusterv1.MachineSetV1Beta1DeprecatedStatus{ AvailableReplicas: 2, @@ -105,7 +105,7 @@ func TestCalculateV1Beta1Status(t *testing.T) { }, Status: clusterv1.MachineSetStatus{ Selector: "", - Replicas: 2, + Replicas: ptr.To[int32](2), Deprecated: &clusterv1.MachineSetDeprecatedStatus{ V1Beta1: &clusterv1.MachineSetV1Beta1DeprecatedStatus{ AvailableReplicas: 1, @@ -121,7 +121,7 @@ func TestCalculateV1Beta1Status(t *testing.T) { }, Status: clusterv1.MachineSetStatus{ Selector: "", - Replicas: 2, + Replicas: ptr.To[int32](2), Deprecated: &clusterv1.MachineSetDeprecatedStatus{ V1Beta1: &clusterv1.MachineSetV1Beta1DeprecatedStatus{ AvailableReplicas: 1, @@ -157,7 +157,7 @@ func TestCalculateV1Beta1Status(t *testing.T) { }, Status: clusterv1.MachineSetStatus{ Selector: "", - Replicas: 2, + Replicas: ptr.To[int32](2), Deprecated: &clusterv1.MachineSetDeprecatedStatus{ V1Beta1: &clusterv1.MachineSetV1Beta1DeprecatedStatus{ AvailableReplicas: 3, @@ -173,7 +173,7 @@ func TestCalculateV1Beta1Status(t *testing.T) { }, Status: clusterv1.MachineSetStatus{ Selector: "", - Replicas: 2, + Replicas: ptr.To[int32](2), Deprecated: &clusterv1.MachineSetDeprecatedStatus{ V1Beta1: &clusterv1.MachineSetV1Beta1DeprecatedStatus{ AvailableReplicas: 3, @@ -399,7 +399,7 @@ func newTestMachineDeployment(replicas, statusReplicas, upToDateReplicas, availa }, }, Status: clusterv1.MachineDeploymentStatus{ - Replicas: statusReplicas, + Replicas: ptr.To[int32](statusReplicas), UpToDateReplicas: ptr.To[int32](upToDateReplicas), AvailableReplicas: ptr.To[int32](availableReplicas), }, @@ -419,7 +419,7 @@ func newTestMachinesetWithReplicas(name string, specReplicas, statusReplicas, av Replicas: ptr.To[int32](specReplicas), }, Status: clusterv1.MachineSetStatus{ - Replicas: statusReplicas, + Replicas: ptr.To(statusReplicas), AvailableReplicas: ptr.To[int32](availableReplicas), Deprecated: &clusterv1.MachineSetDeprecatedStatus{ V1Beta1: &clusterv1.MachineSetV1Beta1DeprecatedStatus{ diff --git a/internal/controllers/machinedeployment/mdutil/util.go b/internal/controllers/machinedeployment/mdutil/util.go index e39f07c4f82d..c09b54f3af68 100644 --- a/internal/controllers/machinedeployment/mdutil/util.go +++ b/internal/controllers/machinedeployment/mdutil/util.go @@ -362,7 +362,7 @@ func getMachineSetFraction(ms clusterv1.MachineSet, md clusterv1.MachineDeployme // will not be an accurate proportion estimation in case other machine sets have different values // which means that the deployment was scaled at some point but we at least will stay in limits // due to the min-max comparisons in getProportion. - annotatedReplicas = md.Status.Replicas + annotatedReplicas = ptr.Deref(md.Status.Replicas, 0) } // We should never proportionally scale up from zero which means ms.spec.replicas and annotatedReplicas @@ -539,11 +539,11 @@ func GetReplicaCountForMachineSets(machineSets []*clusterv1.MachineSet) int32 { } // GetActualReplicaCountForMachineSets returns the sum of actual replicas of the given machine sets. -func GetActualReplicaCountForMachineSets(machineSets []*clusterv1.MachineSet) int32 { - totalActualReplicas := int32(0) +func GetActualReplicaCountForMachineSets(machineSets []*clusterv1.MachineSet) *int32 { + var totalActualReplicas *int32 for _, ms := range machineSets { - if ms != nil { - totalActualReplicas += ms.Status.Replicas + if ms != nil && ms.Status.Replicas != nil { + totalActualReplicas = ptr.To(ptr.Deref(totalActualReplicas, 0) + *ms.Status.Replicas) } } return totalActualReplicas @@ -559,7 +559,7 @@ func TotalMachineSetsReplicaSum(machineSets []*clusterv1.MachineSet) int32 { totalReplicas := int32(0) for _, ms := range machineSets { if ms != nil { - totalReplicas += max(*(ms.Spec.Replicas), ms.Status.Replicas) + totalReplicas += max(ptr.Deref(ms.Spec.Replicas, 0), ptr.Deref(ms.Status.Replicas, 0)) } } return totalReplicas @@ -639,10 +639,11 @@ func IsRollingUpdate(deployment *clusterv1.MachineDeployment) bool { // DeploymentComplete considers a deployment to be complete once all of its desired replicas // are updated and available, and no old machines are running. func DeploymentComplete(deployment *clusterv1.MachineDeployment, newStatus *clusterv1.MachineDeploymentStatus) bool { + currentReplicas := ptr.Deref(newStatus.Replicas, 0) updatedReplicas := ptr.Deref(newStatus.UpToDateReplicas, 0) availableReplicas := ptr.Deref(newStatus.AvailableReplicas, 0) return updatedReplicas == *(deployment.Spec.Replicas) && - newStatus.Replicas == *(deployment.Spec.Replicas) && + currentReplicas == *(deployment.Spec.Replicas) && availableReplicas == *(deployment.Spec.Replicas) && newStatus.ObservedGeneration >= deployment.Generation } diff --git a/internal/controllers/machinedeployment/mdutil/util_test.go b/internal/controllers/machinedeployment/mdutil/util_test.go index f5228b732470..6fa108637db7 100644 --- a/internal/controllers/machinedeployment/mdutil/util_test.go +++ b/internal/controllers/machinedeployment/mdutil/util_test.go @@ -612,10 +612,10 @@ func TestFindOldMachineSets(t *testing.T) { func TestGetReplicaCountForMachineSets(t *testing.T) { ms1 := generateMS(generateDeployment("foo")) *(ms1.Spec.Replicas) = 1 - ms1.Status.Replicas = 2 + ms1.Status.Replicas = ptr.To[int32](2) ms2 := generateMS(generateDeployment("bar")) *(ms2.Spec.Replicas) = 5 - ms2.Status.Replicas = 3 + ms2.Status.Replicas = ptr.To[int32](3) tests := []struct { Name string @@ -645,7 +645,7 @@ func TestGetReplicaCountForMachineSets(t *testing.T) { g := NewWithT(t) g.Expect(GetReplicaCountForMachineSets(test.Sets)).To(Equal(test.ExpectedCount)) - g.Expect(GetActualReplicaCountForMachineSets(test.Sets)).To(Equal(test.ExpectedActual)) + g.Expect(ptr.Deref(GetActualReplicaCountForMachineSets(test.Sets), 0)).To(Equal(test.ExpectedActual)) g.Expect(TotalMachineSetsReplicaSum(test.Sets)).To(Equal(test.ExpectedTotal)) }) } @@ -783,7 +783,7 @@ func TestDeploymentComplete(t *testing.T) { }, }, Status: clusterv1.MachineDeploymentStatus{ - Replicas: current, + Replicas: ptr.To[int32](current), UpToDateReplicas: ptr.To[int32](upToDate), AvailableReplicas: ptr.To[int32](available), }, diff --git a/internal/controllers/machineset/machineset_controller.go b/internal/controllers/machineset/machineset_controller.go index e0389b0c5c8b..57ea0fcaa0c9 100644 --- a/internal/controllers/machineset/machineset_controller.go +++ b/internal/controllers/machineset/machineset_controller.go @@ -1178,6 +1178,7 @@ func (r *Reconciler) reconcileV1Beta1Status(ctx context.Context, s *scope) error if !ms.DeletionTimestamp.IsZero() { desiredReplicas = 0 } + currentReplicas := ptr.Deref(ms.Status.Replicas, 0) templateLabel := labels.Set(ms.Spec.Template.Labels).AsSelectorPreValidated() for _, machine := range filteredMachines { @@ -1220,18 +1221,18 @@ func (r *Reconciler) reconcileV1Beta1Status(ctx context.Context, s *scope) error switch { // We are scaling up - case ms.Status.Replicas < desiredReplicas: - v1beta1conditions.MarkFalse(ms, clusterv1.ResizedV1Beta1Condition, clusterv1.ScalingUpV1Beta1Reason, clusterv1.ConditionSeverityWarning, "Scaling up MachineSet to %d replicas (actual %d)", desiredReplicas, ms.Status.Replicas) + case currentReplicas < desiredReplicas: + v1beta1conditions.MarkFalse(ms, clusterv1.ResizedV1Beta1Condition, clusterv1.ScalingUpV1Beta1Reason, clusterv1.ConditionSeverityWarning, "Scaling up MachineSet to %d replicas (actual %d)", desiredReplicas, currentReplicas) // We are scaling down - case ms.Status.Replicas > desiredReplicas: - v1beta1conditions.MarkFalse(ms, clusterv1.ResizedV1Beta1Condition, clusterv1.ScalingDownV1Beta1Reason, clusterv1.ConditionSeverityWarning, "Scaling down MachineSet to %d replicas (actual %d)", desiredReplicas, ms.Status.Replicas) + case currentReplicas > desiredReplicas: + v1beta1conditions.MarkFalse(ms, clusterv1.ResizedV1Beta1Condition, clusterv1.ScalingDownV1Beta1Reason, clusterv1.ConditionSeverityWarning, "Scaling down MachineSet to %d replicas (actual %d)", desiredReplicas, currentReplicas) // This means that there was no error in generating the desired number of machine objects v1beta1conditions.MarkTrue(ms, clusterv1.MachinesCreatedV1Beta1Condition) default: // Make sure last resize operation is marked as completed. // NOTE: we are checking the number of machines ready so we report resize completed only when the machines // are actually provisioned (vs reporting completed immediately after the last machine object is created). This convention is also used by KCP. - if ms.Status.Deprecated.V1Beta1.ReadyReplicas == ms.Status.Replicas { + if ms.Status.Deprecated.V1Beta1.ReadyReplicas == currentReplicas { if v1beta1conditions.IsFalse(ms, clusterv1.ResizedV1Beta1Condition) { log.Info("All the replicas are ready", "replicas", ms.Status.Deprecated.V1Beta1.ReadyReplicas) } diff --git a/internal/controllers/machineset/machineset_controller_status.go b/internal/controllers/machineset/machineset_controller_status.go index 791d5a527091..5e031503d514 100644 --- a/internal/controllers/machineset/machineset_controller_status.go +++ b/internal/controllers/machineset/machineset_controller_status.go @@ -92,7 +92,7 @@ func setReplicas(_ context.Context, ms *clusterv1.MachineSet, machines []*cluste } } - ms.Status.Replicas = int32(len(machines)) + ms.Status.Replicas = ptr.To(int32(len(machines))) ms.Status.ReadyReplicas = ptr.To(readyReplicas) ms.Status.AvailableReplicas = ptr.To(availableReplicas) ms.Status.UpToDateReplicas = ptr.To(upToDateReplicas) diff --git a/internal/controllers/machineset/machineset_controller_status_test.go b/internal/controllers/machineset/machineset_controller_status_test.go index 11e310dcfe46..012864095aed 100644 --- a/internal/controllers/machineset/machineset_controller_status_test.go +++ b/internal/controllers/machineset/machineset_controller_status_test.go @@ -49,7 +49,7 @@ func Test_setReplicas(t *testing.T) { machines: nil, getAndAdoptMachinesForMachineSetSucceeded: true, expectedStatus: clusterv1.MachineSetStatus{ - Replicas: int32(0), + Replicas: ptr.To[int32](0), ReadyReplicas: ptr.To[int32](0), AvailableReplicas: ptr.To[int32](0), UpToDateReplicas: ptr.To[int32](0), @@ -72,7 +72,7 @@ func Test_setReplicas(t *testing.T) { }, getAndAdoptMachinesForMachineSetSucceeded: true, expectedStatus: clusterv1.MachineSetStatus{ - Replicas: int32(3), + Replicas: ptr.To[int32](3), ReadyReplicas: ptr.To[int32](1), AvailableReplicas: ptr.To[int32](0), UpToDateReplicas: ptr.To[int32](0), @@ -96,7 +96,7 @@ func Test_setReplicas(t *testing.T) { }, getAndAdoptMachinesForMachineSetSucceeded: true, expectedStatus: clusterv1.MachineSetStatus{ - Replicas: int32(3), + Replicas: ptr.To[int32](3), ReadyReplicas: ptr.To[int32](0), AvailableReplicas: ptr.To[int32](1), UpToDateReplicas: ptr.To[int32](0), @@ -120,7 +120,7 @@ func Test_setReplicas(t *testing.T) { }, getAndAdoptMachinesForMachineSetSucceeded: true, expectedStatus: clusterv1.MachineSetStatus{ - Replicas: int32(3), + Replicas: ptr.To[int32](3), ReadyReplicas: ptr.To[int32](0), AvailableReplicas: ptr.To[int32](0), UpToDateReplicas: ptr.To[int32](1), @@ -146,7 +146,7 @@ func Test_setReplicas(t *testing.T) { }, getAndAdoptMachinesForMachineSetSucceeded: true, expectedStatus: clusterv1.MachineSetStatus{ - Replicas: int32(1), + Replicas: ptr.To[int32](1), ReadyReplicas: ptr.To[int32](1), AvailableReplicas: ptr.To[int32](1), UpToDateReplicas: ptr.To[int32](1), diff --git a/internal/controllers/topology/cluster/conditions_test.go b/internal/controllers/topology/cluster/conditions_test.go index bfa952879ea8..d56a21f23a5c 100644 --- a/internal/controllers/topology/cluster/conditions_test.go +++ b/internal/controllers/topology/cluster/conditions_test.go @@ -277,7 +277,7 @@ func TestReconcileTopologyReconciledCondition(t *testing.T) { Object: builder.MachineDeployment("ns1", "md0-abc123"). WithReplicas(2). WithStatus(clusterv1.MachineDeploymentStatus{ - Replicas: int32(1), + Replicas: ptr.To[int32](1), ReadyReplicas: ptr.To[int32](1), UpToDateReplicas: ptr.To[int32](1), AvailableReplicas: ptr.To[int32](1), @@ -324,7 +324,7 @@ func TestReconcileTopologyReconciledCondition(t *testing.T) { Object: builder.MachinePool("ns1", "mp0-abc123"). WithReplicas(2). WithStatus(expv1.MachinePoolStatus{ - Replicas: int32(1), + Replicas: ptr.To(int32(1)), Deprecated: &expv1.MachinePoolDeprecatedStatus{ V1Beta1: &expv1.MachinePoolV1Beta1DeprecatedStatus{ ReadyReplicas: int32(1), @@ -375,7 +375,7 @@ func TestReconcileTopologyReconciledCondition(t *testing.T) { Object: builder.MachineDeployment("ns1", "md0-abc123"). WithReplicas(2). WithStatus(clusterv1.MachineDeploymentStatus{ - Replicas: int32(2), + Replicas: ptr.To[int32](2), ReadyReplicas: ptr.To[int32](2), UpToDateReplicas: ptr.To[int32](2), AvailableReplicas: ptr.To[int32](2), @@ -423,7 +423,7 @@ func TestReconcileTopologyReconciledCondition(t *testing.T) { Object: builder.MachinePool("ns1", "mp0-abc123"). WithReplicas(2). WithStatus(expv1.MachinePoolStatus{ - Replicas: int32(2), + Replicas: ptr.To(int32(2)), Deprecated: &expv1.MachinePoolDeprecatedStatus{ V1Beta1: &expv1.MachinePoolV1Beta1DeprecatedStatus{ ReadyReplicas: int32(2), @@ -545,7 +545,7 @@ func TestReconcileTopologyReconciledCondition(t *testing.T) { }). WithStatus(clusterv1.MachineDeploymentStatus{ // MD is not ready because we don't have 2 updated, ready and available replicas. - Replicas: int32(2), + Replicas: ptr.To[int32](2), ReadyReplicas: ptr.To[int32](1), UpToDateReplicas: ptr.To[int32](1), AvailableReplicas: ptr.To[int32](1), @@ -562,7 +562,7 @@ func TestReconcileTopologyReconciledCondition(t *testing.T) { }, }). WithStatus(clusterv1.MachineDeploymentStatus{ - Replicas: int32(2), + Replicas: ptr.To[int32](2), ReadyReplicas: ptr.To[int32](2), UpToDateReplicas: ptr.To[int32](2), AvailableReplicas: ptr.To[int32](2), @@ -622,7 +622,7 @@ func TestReconcileTopologyReconciledCondition(t *testing.T) { WithVersion("v1.22.0"). WithStatus(expv1.MachinePoolStatus{ // mp is not ready because we don't have 2 updated, ready and available replicas. - Replicas: int32(2), + Replicas: ptr.To(int32(2)), Deprecated: &expv1.MachinePoolDeprecatedStatus{ V1Beta1: &expv1.MachinePoolV1Beta1DeprecatedStatus{ ReadyReplicas: int32(1), @@ -638,7 +638,7 @@ func TestReconcileTopologyReconciledCondition(t *testing.T) { WithReplicas(2). WithVersion("v1.21.2"). WithStatus(expv1.MachinePoolStatus{ - Replicas: int32(2), + Replicas: ptr.To(int32(2)), Deprecated: &expv1.MachinePoolDeprecatedStatus{ V1Beta1: &expv1.MachinePoolV1Beta1DeprecatedStatus{ ReadyReplicas: int32(2), @@ -701,7 +701,7 @@ func TestReconcileTopologyReconciledCondition(t *testing.T) { WithReplicas(2). WithVersion("v1.22.0"). WithStatus(clusterv1.MachineDeploymentStatus{ - Replicas: int32(2), + Replicas: ptr.To[int32](2), ReadyReplicas: ptr.To[int32](2), UpToDateReplicas: ptr.To[int32](2), AvailableReplicas: ptr.To[int32](2), @@ -713,7 +713,7 @@ func TestReconcileTopologyReconciledCondition(t *testing.T) { WithReplicas(2). WithVersion("v1.21.2"). WithStatus(clusterv1.MachineDeploymentStatus{ - Replicas: int32(2), + Replicas: ptr.To[int32](2), ReadyReplicas: ptr.To[int32](2), UpToDateReplicas: ptr.To[int32](2), AvailableReplicas: ptr.To[int32](2), @@ -761,7 +761,7 @@ func TestReconcileTopologyReconciledCondition(t *testing.T) { WithReplicas(2). WithVersion("v1.22.0"). WithStatus(expv1.MachinePoolStatus{ - Replicas: int32(2), + Replicas: ptr.To(int32(2)), Deprecated: &expv1.MachinePoolDeprecatedStatus{ V1Beta1: &expv1.MachinePoolV1Beta1DeprecatedStatus{ ReadyReplicas: int32(2), @@ -777,7 +777,7 @@ func TestReconcileTopologyReconciledCondition(t *testing.T) { WithReplicas(2). WithVersion("v1.21.2"). WithStatus(expv1.MachinePoolStatus{ - Replicas: int32(2), + Replicas: ptr.To(int32(2)), Deprecated: &expv1.MachinePoolDeprecatedStatus{ V1Beta1: &expv1.MachinePoolV1Beta1DeprecatedStatus{ ReadyReplicas: int32(2), @@ -829,7 +829,7 @@ func TestReconcileTopologyReconciledCondition(t *testing.T) { WithReplicas(2). WithVersion("v1.22.0"). WithStatus(clusterv1.MachineDeploymentStatus{ - Replicas: int32(1), + Replicas: ptr.To[int32](1), ReadyReplicas: ptr.To[int32](1), UpToDateReplicas: ptr.To[int32](1), AvailableReplicas: ptr.To[int32](1), @@ -841,7 +841,7 @@ func TestReconcileTopologyReconciledCondition(t *testing.T) { WithReplicas(2). WithVersion("v1.22.0"). WithStatus(clusterv1.MachineDeploymentStatus{ - Replicas: int32(2), + Replicas: ptr.To[int32](2), ReadyReplicas: ptr.To[int32](2), UpToDateReplicas: ptr.To[int32](2), AvailableReplicas: ptr.To[int32](2), @@ -855,7 +855,7 @@ func TestReconcileTopologyReconciledCondition(t *testing.T) { WithReplicas(2). WithVersion("v1.22.0"). WithStatus(expv1.MachinePoolStatus{ - Replicas: int32(1), + Replicas: ptr.To(int32(1)), Deprecated: &expv1.MachinePoolDeprecatedStatus{ V1Beta1: &expv1.MachinePoolV1Beta1DeprecatedStatus{ ReadyReplicas: int32(1), @@ -871,7 +871,7 @@ func TestReconcileTopologyReconciledCondition(t *testing.T) { WithReplicas(2). WithVersion("v1.22.0"). WithStatus(expv1.MachinePoolStatus{ - Replicas: int32(2), + Replicas: ptr.To(int32(2)), Deprecated: &expv1.MachinePoolDeprecatedStatus{ V1Beta1: &expv1.MachinePoolV1Beta1DeprecatedStatus{ ReadyReplicas: int32(2), diff --git a/internal/util/tree/tree.go b/internal/util/tree/tree.go index c89a5b6cfb0a..9cc960e57ac4 100644 --- a/internal/util/tree/tree.go +++ b/internal/util/tree/tree.go @@ -560,7 +560,7 @@ func newRowDescriptor(obj ctrlclient.Object) rowDescriptor { // If the object is a MachineDeployment, returns all the replica counters and pick the available condition // as the condition to show for this object in case not all the conditions are visualized. if obj.Spec.Replicas != nil { - v.replicas = fmt.Sprintf("%d/%d", *obj.Spec.Replicas, obj.Status.Replicas) + v.replicas = fmt.Sprintf("%d/%d", *obj.Spec.Replicas, ptr.Deref(obj.Status.Replicas, 0)) } if obj.Status.AvailableReplicas != nil { v.availableCounters = fmt.Sprintf("%d", *obj.Status.AvailableReplicas) @@ -584,7 +584,7 @@ func newRowDescriptor(obj ctrlclient.Object) rowDescriptor { // If the object is a MachineSet, returns all the replica counters and pick the available condition // as the condition to show for this object in case not all the conditions are visualized. if obj.Spec.Replicas != nil { - v.replicas = fmt.Sprintf("%d/%d", *obj.Spec.Replicas, obj.Status.Replicas) + v.replicas = fmt.Sprintf("%d/%d", *obj.Spec.Replicas, ptr.Deref(obj.Status.Replicas, 0)) } if obj.Status.ReadyReplicas != nil { v.availableCounters = fmt.Sprintf("%d", *obj.Status.AvailableReplicas) diff --git a/test/framework/controlplane_helpers.go b/test/framework/controlplane_helpers.go index 53d01518bcfe..03a4f881d217 100644 --- a/test/framework/controlplane_helpers.go +++ b/test/framework/controlplane_helpers.go @@ -172,8 +172,8 @@ func WaitForControlPlaneToBeReady(ctx context.Context, input WaitForControlPlane return false, errors.Wrapf(err, "failed to get KCP") } - desiredReplicas := controlplane.Spec.Replicas - statusReplicas := controlplane.Status.Replicas + desiredReplicas := ptr.Deref(controlplane.Spec.Replicas, 0) + statusReplicas := ptr.Deref(controlplane.Status.Replicas, 0) upToDatedReplicas := ptr.Deref(controlplane.Status.UpToDateReplicas, 0) readyReplicas := ptr.Deref(controlplane.Status.ReadyReplicas, 0) availableReplicas := ptr.Deref(controlplane.Status.AvailableReplicas, 0) @@ -181,10 +181,10 @@ func WaitForControlPlaneToBeReady(ctx context.Context, input WaitForControlPlane // Control plane is still rolling out (and thus not ready) if: // * .spec.replicas, .status.replicas, .status.upToDateReplicas, // .status.readyReplicas, .status.availableReplicas are not equal. - if statusReplicas != *desiredReplicas || - upToDatedReplicas != *desiredReplicas || - readyReplicas != *desiredReplicas || - availableReplicas != *desiredReplicas { + if statusReplicas != desiredReplicas || + upToDatedReplicas != desiredReplicas || + readyReplicas != desiredReplicas || + availableReplicas != desiredReplicas { return false, nil } diff --git a/test/framework/machinedeployment_helpers.go b/test/framework/machinedeployment_helpers.go index 324fb2713d46..db9d79d68d74 100644 --- a/test/framework/machinedeployment_helpers.go +++ b/test/framework/machinedeployment_helpers.go @@ -340,7 +340,7 @@ func UpgradeMachineDeploymentInfrastructureRefAndWait(ctx context.Context, input // MachineSet should be rolled out. g.Expect(newMachineSet.Spec.Replicas).To(Equal(deployment.Spec.Replicas)) - g.Expect(*newMachineSet.Spec.Replicas).To(Equal(newMachineSet.Status.Replicas)) + g.Expect(newMachineSet.Spec.Replicas).To(Equal(newMachineSet.Status.Replicas)) g.Expect(newMachineSet.Spec.Replicas).To(Equal(newMachineSet.Status.ReadyReplicas)) g.Expect(newMachineSet.Spec.Replicas).To(Equal(newMachineSet.Status.AvailableReplicas)) @@ -803,6 +803,6 @@ func AssertMachineDeploymentReplicas(ctx context.Context, input AssertMachineDep g.Expect(input.Getter.Get(ctx, key, md)).To(Succeed(), fmt.Sprintf("failed to get MachineDeployment %s", klog.KObj(input.MachineDeployment))) g.Expect(md.Spec.Replicas).Should(Not(BeNil()), fmt.Sprintf("MachineDeployment %s replicas should not be nil", klog.KObj(md))) g.Expect(*md.Spec.Replicas).Should(Equal(input.Replicas), fmt.Sprintf("MachineDeployment %s replicas should match expected replicas", klog.KObj(md))) - g.Expect(md.Status.Replicas).Should(Equal(input.Replicas), fmt.Sprintf("MachineDeployment %s status.replicas should match expected replicas", klog.KObj(md))) + g.Expect(ptr.Deref(md.Status.Replicas, 0)).Should(Equal(input.Replicas), fmt.Sprintf("MachineDeployment %s status.replicas should match expected replicas", klog.KObj(md))) }, input.WaitForMachineDeployment...).Should(Succeed()) } diff --git a/test/framework/machinepool_helpers.go b/test/framework/machinepool_helpers.go index 35637b91bb83..9a7ebfe33b16 100644 --- a/test/framework/machinepool_helpers.go +++ b/test/framework/machinepool_helpers.go @@ -370,6 +370,6 @@ func AssertMachinePoolReplicas(ctx context.Context, input AssertMachinePoolRepli g.Expect(input.Getter.Get(ctx, key, mp)).To(Succeed(), fmt.Sprintf("failed to get MachinePool %s", klog.KObj(input.MachinePool))) g.Expect(mp.Spec.Replicas).Should(Not(BeNil()), fmt.Sprintf("MachinePool %s replicas should not be nil", klog.KObj(mp))) g.Expect(*mp.Spec.Replicas).Should(Equal(input.Replicas), fmt.Sprintf("MachinePool %s replicas should match expected replicas", klog.KObj(mp))) - g.Expect(mp.Status.Replicas).Should(Equal(input.Replicas), fmt.Sprintf("MachinePool %s status.replicas should match expected replicas", klog.KObj(mp))) + g.Expect(ptr.Deref(mp.Status.Replicas, 0)).Should(Equal(input.Replicas), fmt.Sprintf("MachinePool %s status.replicas should match expected replicas", klog.KObj(mp))) }, input.WaitForMachinePool...).Should(Succeed()) }