Merge pull request #130732 from thockin/master_replicationcontroller_replicas_pointer

Change internal-version RC.Spec.Relicas to a ptr
This commit is contained in:
Kubernetes Prow Robot 2025-03-13 16:05:46 -07:00 committed by GitHub
commit 32d8e0ce4f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 89 additions and 46 deletions

View File

@ -21,8 +21,6 @@ import (
"strconv"
"time"
"sigs.k8s.io/randfill"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -32,6 +30,7 @@ import (
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/kubernetes/pkg/apis/core"
"k8s.io/utils/ptr"
"sigs.k8s.io/randfill"
)
// Funcs returns the fuzzer functions for the core group.
@ -119,6 +118,12 @@ var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
func(j *core.ReplicationControllerSpec, c randfill.Continue) {
c.FillNoCustom(j) // fuzz self without calling this function again
//j.TemplateRef = nil // this is required for round trip
// match defaulting
if j.Replicas == nil {
replicas := int32(0)
j.Replicas = &replicas
}
},
func(j *core.List, c randfill.Continue) {
c.FillNoCustom(j) // fuzz self without calling this function again

View File

@ -4332,7 +4332,7 @@ type PodTemplateList struct {
// a TemplateRef or a Template set.
type ReplicationControllerSpec struct {
// Replicas is the number of desired replicas.
Replicas int32
Replicas *int32
// Minimum number of seconds for which a newly created pod should be ready
// without any of its container crashing, for it to be considered available.

View File

@ -199,7 +199,9 @@ func Convert_apps_ReplicaSetStatus_To_v1_ReplicationControllerStatus(in *apps.Re
}
func Convert_core_ReplicationControllerSpec_To_v1_ReplicationControllerSpec(in *core.ReplicationControllerSpec, out *v1.ReplicationControllerSpec, s conversion.Scope) error {
out.Replicas = &in.Replicas
if err := autoConvert_core_ReplicationControllerSpec_To_v1_ReplicationControllerSpec(in, out, s); err != nil {
return err
}
out.MinReadySeconds = in.MinReadySeconds
out.Selector = in.Selector
if in.Template != nil {
@ -214,8 +216,8 @@ func Convert_core_ReplicationControllerSpec_To_v1_ReplicationControllerSpec(in *
}
func Convert_v1_ReplicationControllerSpec_To_core_ReplicationControllerSpec(in *v1.ReplicationControllerSpec, out *core.ReplicationControllerSpec, s conversion.Scope) error {
if in.Replicas != nil {
out.Replicas = *in.Replicas
if err := autoConvert_v1_ReplicationControllerSpec_To_core_ReplicationControllerSpec(in, out, s); err != nil {
return err
}
out.MinReadySeconds = in.MinReadySeconds
out.Selector = in.Selector

View File

@ -7416,9 +7416,7 @@ func Convert_core_ReplicationControllerList_To_v1_ReplicationControllerList(in *
}
func autoConvert_v1_ReplicationControllerSpec_To_core_ReplicationControllerSpec(in *corev1.ReplicationControllerSpec, out *core.ReplicationControllerSpec, s conversion.Scope) error {
if err := metav1.Convert_Pointer_int32_To_int32(&in.Replicas, &out.Replicas, s); err != nil {
return err
}
out.Replicas = (*int32)(unsafe.Pointer(in.Replicas))
out.MinReadySeconds = in.MinReadySeconds
out.Selector = *(*map[string]string)(unsafe.Pointer(&in.Selector))
if in.Template != nil {
@ -7434,9 +7432,7 @@ func autoConvert_v1_ReplicationControllerSpec_To_core_ReplicationControllerSpec(
}
func autoConvert_core_ReplicationControllerSpec_To_v1_ReplicationControllerSpec(in *core.ReplicationControllerSpec, out *corev1.ReplicationControllerSpec, s conversion.Scope) error {
if err := metav1.Convert_int32_To_Pointer_int32(&in.Replicas, &out.Replicas, s); err != nil {
return err
}
out.Replicas = (*int32)(unsafe.Pointer(in.Replicas))
out.MinReadySeconds = in.MinReadySeconds
out.Selector = *(*map[string]string)(unsafe.Pointer(&in.Selector))
if in.Template != nil {

View File

@ -6291,7 +6291,7 @@ func ValidateNonEmptySelector(selectorMap map[string]string, fldPath *field.Path
}
// Validates the given template and ensures that it is in accordance with the desired selector and replicas.
func ValidatePodTemplateSpecForRC(template *core.PodTemplateSpec, selectorMap map[string]string, replicas int32, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
func ValidatePodTemplateSpecForRC(template *core.PodTemplateSpec, selectorMap map[string]string, fldPath *field.Path, opts PodValidationOptions) field.ErrorList {
allErrs := field.ErrorList{}
if template == nil {
allErrs = append(allErrs, field.Required(fldPath, ""))
@ -6321,8 +6321,12 @@ func ValidateReplicationControllerSpec(spec, oldSpec *core.ReplicationController
allErrs := field.ErrorList{}
allErrs = append(allErrs, ValidateNonnegativeField(int64(spec.MinReadySeconds), fldPath.Child("minReadySeconds"))...)
allErrs = append(allErrs, ValidateNonEmptySelector(spec.Selector, fldPath.Child("selector"))...)
allErrs = append(allErrs, ValidateNonnegativeField(int64(spec.Replicas), fldPath.Child("replicas"))...)
allErrs = append(allErrs, ValidatePodTemplateSpecForRC(spec.Template, spec.Selector, spec.Replicas, fldPath.Child("template"), opts)...)
if spec.Replicas == nil {
allErrs = append(allErrs, field.Required(fldPath.Child("replicas"), ""))
} else {
allErrs = append(allErrs, ValidateNonnegativeField(int64(*spec.Replicas), fldPath.Child("replicas"))...)
}
allErrs = append(allErrs, ValidatePodTemplateSpecForRC(spec.Template, spec.Selector, fldPath.Child("template"), opts)...)
return allErrs
}

View File

@ -16670,7 +16670,7 @@ func TestValidateReplicationControllerStatusUpdate(t *testing.T) {
update: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Replicas: 3,
Replicas: ptr.To[int32](3),
Selector: validSelector,
Template: &validPodTemplate.Template,
},
@ -16702,7 +16702,7 @@ func TestValidateReplicationControllerStatusUpdate(t *testing.T) {
update: core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Replicas: 2,
Replicas: ptr.To[int32](2),
Selector: validSelector,
Template: &validPodTemplate.Template,
},
@ -16725,7 +16725,7 @@ func mkValidReplicationController(tweaks ...func(rc *core.ReplicationController)
rc := core.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
Spec: core.ReplicationControllerSpec{
Replicas: 1,
Replicas: ptr.To[int32](1),
Selector: map[string]string{"a": "b"},
Template: &core.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
@ -16748,17 +16748,17 @@ func TestValidateReplicationControllerUpdate(t *testing.T) {
}{{
old: mkValidReplicationController(func(rc *core.ReplicationController) {}),
update: mkValidReplicationController(func(rc *core.ReplicationController) {
rc.Spec.Replicas = 0
rc.Spec.Replicas = ptr.To[int32](0)
}),
}, {
old: mkValidReplicationController(func(rc *core.ReplicationController) {}),
update: mkValidReplicationController(func(rc *core.ReplicationController) {
rc.Spec.Replicas = 3
rc.Spec.Replicas = ptr.To[int32](3)
}),
}, {
old: mkValidReplicationController(func(rc *core.ReplicationController) {}),
update: mkValidReplicationController(func(rc *core.ReplicationController) {
rc.Spec.Replicas = 2
rc.Spec.Replicas = ptr.To[int32](2)
rc.Spec.Template.Spec = podtest.MakePodSpec(
podtest.SetVolumes(
core.Volume{
@ -16816,12 +16816,21 @@ func TestValidateReplicationControllerUpdate(t *testing.T) {
"negative replicas": {
old: mkValidReplicationController(func(rc *core.ReplicationController) {}),
update: mkValidReplicationController(func(rc *core.ReplicationController) {
rc.Spec.Replicas = -1
rc.Spec.Replicas = ptr.To[int32](-1)
}),
expectedErrs: field.ErrorList{
field.Invalid(field.NewPath("spec.replicas"), nil, "").WithOrigin("minimum"),
},
},
"nil replicas": {
old: mkValidReplicationController(func(rc *core.ReplicationController) {}),
update: mkValidReplicationController(func(rc *core.ReplicationController) {
rc.Spec.Replicas = nil
}),
expectedErrs: field.ErrorList{
field.Required(field.NewPath("spec.replicas"), ""),
},
},
}
for k, tc := range errorCases {
t.Run(k, func(t *testing.T) {
@ -16839,7 +16848,7 @@ func TestValidateReplicationController(t *testing.T) {
mkValidReplicationController(func(rc *core.ReplicationController) {}),
mkValidReplicationController(func(rc *core.ReplicationController) { rc.Name = "abc-123" }),
mkValidReplicationController(func(rc *core.ReplicationController) {
rc.Spec.Replicas = 2
rc.Spec.Replicas = ptr.To[int32](2)
rc.Spec.Template.Spec = podtest.MakePodSpec(
podtest.SetVolumes(
core.Volume{
@ -16860,9 +16869,9 @@ func TestValidateReplicationController(t *testing.T) {
}))),
)
}),
mkValidReplicationController(func(rc *core.ReplicationController) { rc.Spec.Replicas = 0 }),
mkValidReplicationController(func(rc *core.ReplicationController) { rc.Spec.Replicas = 1 }),
mkValidReplicationController(func(rc *core.ReplicationController) { rc.Spec.Replicas = 100 }),
mkValidReplicationController(func(rc *core.ReplicationController) { rc.Spec.Replicas = ptr.To[int32](0) }),
mkValidReplicationController(func(rc *core.ReplicationController) { rc.Spec.Replicas = ptr.To[int32](1) }),
mkValidReplicationController(func(rc *core.ReplicationController) { rc.Spec.Replicas = ptr.To[int32](100) }),
}
for _, tc := range successCases {
if errs := ValidateReplicationController(&tc, PodValidationOptions{}); len(errs) != 0 {
@ -16905,11 +16914,17 @@ func TestValidateReplicationController(t *testing.T) {
},
},
"negative replicas": {
input: mkValidReplicationController(func(rc *core.ReplicationController) { rc.Spec.Replicas = -1 }),
input: mkValidReplicationController(func(rc *core.ReplicationController) { rc.Spec.Replicas = ptr.To[int32](-1) }),
expectedErrs: field.ErrorList{
field.Invalid(field.NewPath("spec.replicas"), nil, "").WithOrigin("minimum"),
},
},
"nil replicas": {
input: mkValidReplicationController(func(rc *core.ReplicationController) { rc.Spec.Replicas = nil }),
expectedErrs: field.ErrorList{
field.Required(field.NewPath("spec.replicas"), ""),
},
},
"invalid label": {
input: mkValidReplicationController(func(rc *core.ReplicationController) {
rc.Labels = map[string]string{

View File

@ -4920,6 +4920,11 @@ func (in *ReplicationControllerList) DeepCopyObject() runtime.Object {
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ReplicationControllerSpec) DeepCopyInto(out *ReplicationControllerSpec) {
*out = *in
if in.Replicas != nil {
in, out := &in.Replicas, &out.Replicas
*out = new(int32)
**out = **in
}
if in.Selector != nil {
in, out := &in.Selector, &out.Selector
*out = make(map[string]string, len(*in))

View File

@ -51,6 +51,7 @@ import (
"k8s.io/apimachinery/pkg/util/duration"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/client-go/util/certificate/csr"
"k8s.io/utils/ptr"
podutil "k8s.io/kubernetes/pkg/api/pod"
podutilv1 "k8s.io/kubernetes/pkg/api/v1/pod"
@ -1123,7 +1124,7 @@ func printReplicationController(obj *api.ReplicationController, options printers
Object: runtime.RawExtension{Object: obj},
}
desiredReplicas := obj.Spec.Replicas
desiredReplicas := ptr.Deref(obj.Spec.Replicas, 0)
currentReplicas := obj.Status.Replicas
readyReplicas := obj.Status.ReadyReplicas

View File

@ -25,7 +25,6 @@ import (
"time"
"github.com/google/go-cmp/cmp"
apiv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -4559,18 +4558,21 @@ func TestPrintCertificateSigningRequest(t *testing.T) {
func TestPrintReplicationController(t *testing.T) {
tests := []struct {
name string
rc api.ReplicationController
options printers.GenerateOptions
expected []metav1.TableRow
}{
// Basic print replication controller without replicas or status.
{
name: "basic",
rc: api.ReplicationController{
ObjectMeta: metav1.ObjectMeta{
Name: "rc1",
Namespace: "test-namespace",
},
Spec: api.ReplicationControllerSpec{
Replicas: ptr.To[int32](0),
Selector: map[string]string{"a": "b"},
Template: &api.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
@ -4597,13 +4599,14 @@ func TestPrintReplicationController(t *testing.T) {
},
// Basic print replication controller with replicas; does not print containers or labels
{
name: "basic with replicas",
rc: api.ReplicationController{
ObjectMeta: metav1.ObjectMeta{
Name: "rc1",
Namespace: "test-namespace",
},
Spec: api.ReplicationControllerSpec{
Replicas: 5,
Replicas: ptr.To[int32](5),
Selector: map[string]string{"a": "b"},
Template: &api.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
@ -4634,12 +4637,13 @@ func TestPrintReplicationController(t *testing.T) {
},
// Generate options: Wide; print containers and labels.
{
name: "wide",
rc: api.ReplicationController{
ObjectMeta: metav1.ObjectMeta{
Name: "rc1",
},
Spec: api.ReplicationControllerSpec{
Replicas: 5,
Replicas: ptr.To[int32](5),
Selector: map[string]string{"a": "b"},
Template: &api.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
@ -4670,12 +4674,16 @@ func TestPrintReplicationController(t *testing.T) {
},
{
// make sure Bookmark event will not lead a panic
name: "no panic",
rc: api.ReplicationController{
ObjectMeta: metav1.ObjectMeta{
Annotations: map[string]string{
metav1.InitialEventsAnnotationKey: "true",
},
},
Spec: api.ReplicationControllerSpec{
Replicas: ptr.To[int32](0),
},
},
options: printers.GenerateOptions{Wide: true},
// Columns: Name, Desired, Current, Ready, Age, Containers, Images, Selector

View File

@ -28,6 +28,7 @@ import (
apitesting "k8s.io/kubernetes/pkg/api/testing"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/features"
"k8s.io/utils/ptr"
)
func TestDeclarativeValidateForDeclarative(t *testing.T) {
@ -121,7 +122,7 @@ func TestValidateUpdateForDeclarative(t *testing.T) {
// The equivalenceMatcher is used to verify the output errors from hand-written imperative validation
// are equivalent to the output errors when DeclarativeValidationTakeover is enabled.
equivalenceMatcher := field.ErrorMatcher{}.ByType().ByField().ByOrigin()
// TODO: remove this once ErrorMatcher has been extended to handle this form of deduplication.
// TODO: remove this once RC's validation is fixed to not return duplicate errors.
dedupedImperativeErrs := field.ErrorList{}
for _, err := range imperativeErrs {
found := false
@ -142,12 +143,13 @@ func TestValidateUpdateForDeclarative(t *testing.T) {
}
}
// Helper function for RC tests.
// mkValidReplicationController produces a ReplicationController which passes
// validation with no tweaks.
func mkValidReplicationController(tweaks ...func(rc *api.ReplicationController)) api.ReplicationController {
rc := api.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
Spec: api.ReplicationControllerSpec{
Replicas: 1,
Replicas: ptr.To[int32](1),
Selector: map[string]string{"a": "b"},
Template: &api.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{

View File

@ -244,7 +244,7 @@ func scaleFromRC(rc *api.ReplicationController) *autoscaling.Scale {
CreationTimestamp: rc.CreationTimestamp,
},
Spec: autoscaling.ScaleSpec{
Replicas: rc.Spec.Replicas,
Replicas: *rc.Spec.Replicas,
},
Status: autoscaling.ScaleStatus{
Replicas: rc.Status.Replicas,
@ -325,7 +325,7 @@ func (i *scaleUpdatedObjectInfo) UpdatedObject(ctx context.Context, oldObj runti
}
// move replicas/resourceVersion fields to object and return
replicationcontroller.Spec.Replicas = scale.Spec.Replicas
replicationcontroller.Spec.Replicas = &scale.Spec.Replicas
replicationcontroller.ResourceVersion = scale.ResourceVersion
updatedEntries, err := managedFieldsHandler.ToParent(scale.ManagedFields)

View File

@ -38,6 +38,7 @@ import (
"k8s.io/kubernetes/pkg/apis/autoscaling"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/kubernetes/pkg/registry/registrytest"
"k8s.io/utils/ptr"
)
const (
@ -85,6 +86,7 @@ func validNewController() *api.ReplicationController {
},
Spec: podtest.MakePodSpec(),
},
Replicas: ptr.To[int32](1),
},
}
}
@ -104,7 +106,7 @@ func TestCreate(t *testing.T) {
// invalid (invalid selector)
&api.ReplicationController{
Spec: api.ReplicationControllerSpec{
Replicas: 2,
Replicas: ptr.To[int32](2),
Selector: map[string]string{},
Template: validController.Spec.Template,
},
@ -123,7 +125,7 @@ func TestUpdate(t *testing.T) {
// valid updateFunc
func(obj runtime.Object) runtime.Object {
object := obj.(*api.ReplicationController)
object.Spec.Replicas = object.Spec.Replicas + 1
object.Spec.Replicas = ptr.To[int32](*object.Spec.Replicas + 1)
return object
},
// invalid updateFunc
@ -172,7 +174,7 @@ func TestGenerationNumber(t *testing.T) {
}
// Updates to spec should increment the generation number
controller.Spec.Replicas++
(*controller.Spec.Replicas)++
if _, _, err := storage.Controller.Update(ctx, controller.Name, rest.DefaultUpdatedObjectInfo(controller), rest.ValidateAllObjectFunc, rest.ValidateAllObjectUpdateFunc, false, &metav1.UpdateOptions{}); err != nil {
t.Errorf("unexpected error: %v", err)
}
@ -297,7 +299,7 @@ func TestScaleGet(t *testing.T) {
CreationTimestamp: rc.CreationTimestamp,
},
Spec: autoscaling.ScaleSpec{
Replicas: validController.Spec.Replicas,
Replicas: *validController.Spec.Replicas,
},
Status: autoscaling.ScaleStatus{
Replicas: validController.Status.Replicas,
@ -341,7 +343,7 @@ func TestScaleUpdate(t *testing.T) {
}
scale := obj.(*autoscaling.Scale)
if scale.Spec.Replicas != replicas {
t.Errorf("wrong replicas count expected: %d got: %d", replicas, rc.Spec.Replicas)
t.Errorf("wrong replicas count expected: %d got: %d", replicas, *rc.Spec.Replicas)
}
update.ResourceVersion = rc.ResourceVersion

View File

@ -25,6 +25,7 @@ import (
podtest "k8s.io/kubernetes/pkg/api/pod/testing"
apitesting "k8s.io/kubernetes/pkg/api/testing"
api "k8s.io/kubernetes/pkg/apis/core"
"k8s.io/utils/ptr"
// ensure types are installed
_ "k8s.io/kubernetes/pkg/apis/core/install"
@ -53,6 +54,7 @@ func TestControllerStrategy(t *testing.T) {
Spec: api.ReplicationControllerSpec{
Selector: validSelector,
Template: &validPodTemplate.Template,
Replicas: ptr.To[int32](1),
},
Status: api.ReplicationControllerStatus{
Replicas: 1,
@ -67,6 +69,7 @@ func TestControllerStrategy(t *testing.T) {
if rc.Status.ObservedGeneration != int64(0) {
t.Error("ReplicationController should not allow setting status.observedGeneration on create")
}
errs := Strategy.Validate(ctx, rc)
if len(errs) != 0 {
t.Errorf("Unexpected error validating %v", errs)
@ -109,7 +112,7 @@ func TestControllerStatusStrategy(t *testing.T) {
oldController := &api.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault, ResourceVersion: "10"},
Spec: api.ReplicationControllerSpec{
Replicas: 3,
Replicas: ptr.To[int32](3),
Selector: validSelector,
Template: &validPodTemplate.Template,
},
@ -121,7 +124,7 @@ func TestControllerStatusStrategy(t *testing.T) {
newController := &api.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault, ResourceVersion: "9"},
Spec: api.ReplicationControllerSpec{
Replicas: 1,
Replicas: ptr.To[int32](1),
Selector: validSelector,
Template: &validPodTemplate.Template,
},
@ -134,7 +137,7 @@ func TestControllerStatusStrategy(t *testing.T) {
if newController.Status.Replicas != 3 {
t.Errorf("Replication controller status updates should allow change of replicas: %v", newController.Status.Replicas)
}
if newController.Spec.Replicas != 3 {
if *newController.Spec.Replicas != 3 {
t.Errorf("PrepareForUpdate should have preferred spec")
}
errs := StatusStrategy.ValidateUpdate(ctx, newController, oldController)
@ -166,7 +169,7 @@ func TestValidateUpdate(t *testing.T) {
oldController := &api.ReplicationController{
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: api.NamespaceDefault, ResourceVersion: "10", Annotations: make(map[string]string)},
Spec: api.ReplicationControllerSpec{
Replicas: 3,
Replicas: ptr.To[int32](3),
Selector: validSelector,
Template: &validPodTemplate.Template,
},
@ -182,7 +185,7 @@ func TestValidateUpdate(t *testing.T) {
newController := oldController.DeepCopy()
// Irrelevant (to the selector) update for the replication controller.
newController.Spec.Replicas = 5
newController.Spec.Replicas = ptr.To[int32](5)
// If they didn't try to update the selector then we should not return any error.
errs := Strategy.ValidateUpdate(ctx, newController, oldController)