From d6d78c5581537567c742c50188f006422f4b6e98 Mon Sep 17 00:00:00 2001 From: Jordan Liggitt Date: Thu, 13 Jun 2024 18:26:15 -0400 Subject: [PATCH] Ensure controller revision data is valid json --- pkg/apis/apps/fuzzer/fuzzer.go | 6 +++ pkg/apis/apps/types.go | 2 +- pkg/apis/apps/v1/zz_generated.conversion.go | 32 ++----------- .../apps/v1beta1/zz_generated.conversion.go | 32 ++----------- .../apps/v1beta2/zz_generated.conversion.go | 32 ++----------- pkg/apis/apps/validation/validation.go | 29 +++++++++--- pkg/apis/apps/validation/validation_test.go | 45 +++++++++++++------ pkg/apis/apps/zz_generated.deepcopy.go | 4 +- .../import_known_versions_test.go | 2 + .../storage/storage_test.go | 19 +++++--- .../apps/controllerrevision/strategy.go | 2 +- .../apps/controllerrevision/strategy_test.go | 21 ++++++--- 12 files changed, 103 insertions(+), 123 deletions(-) diff --git a/pkg/apis/apps/fuzzer/fuzzer.go b/pkg/apis/apps/fuzzer/fuzzer.go index 2b34873ceb8..2d9ce888eef 100644 --- a/pkg/apis/apps/fuzzer/fuzzer.go +++ b/pkg/apis/apps/fuzzer/fuzzer.go @@ -22,6 +22,7 @@ import ( fuzz "github.com/google/gofuzz" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/kubernetes/pkg/apis/apps" @@ -30,6 +31,11 @@ import ( // Funcs returns the fuzzer functions for the apps api group. var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} { return []interface{}{ + func(r *apps.ControllerRevision, c fuzz.Continue) { + c.FuzzNoCustom(r) + // match the fuzzer default content for runtime.Object + r.Data = runtime.RawExtension{Raw: []byte(`{"apiVersion":"unknown.group/unknown","kind":"Something","someKey":"someValue"}`)} + }, func(s *apps.StatefulSet, c fuzz.Continue) { c.FuzzNoCustom(s) // fuzz self without calling this function again diff --git a/pkg/apis/apps/types.go b/pkg/apis/apps/types.go index 90d71cd1693..1a148b1999a 100644 --- a/pkg/apis/apps/types.go +++ b/pkg/apis/apps/types.go @@ -331,7 +331,7 @@ type ControllerRevision struct { metav1.ObjectMeta // Data is the Object representing the state. - Data runtime.Object + Data runtime.RawExtension // Revision indicates the revision of the state represented by Data. Revision int64 diff --git a/pkg/apis/apps/v1/zz_generated.conversion.go b/pkg/apis/apps/v1/zz_generated.conversion.go index 7783bd26113..056c52b5ff2 100644 --- a/pkg/apis/apps/v1/zz_generated.conversion.go +++ b/pkg/apis/apps/v1/zz_generated.conversion.go @@ -347,9 +347,7 @@ func RegisterConversions(s *runtime.Scheme) error { func autoConvert_v1_ControllerRevision_To_apps_ControllerRevision(in *v1.ControllerRevision, out *apps.ControllerRevision, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta - if err := runtime.Convert_runtime_RawExtension_To_runtime_Object(&in.Data, &out.Data, s); err != nil { - return err - } + out.Data = in.Data out.Revision = in.Revision return nil } @@ -361,9 +359,7 @@ func Convert_v1_ControllerRevision_To_apps_ControllerRevision(in *v1.ControllerR func autoConvert_apps_ControllerRevision_To_v1_ControllerRevision(in *apps.ControllerRevision, out *v1.ControllerRevision, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta - if err := runtime.Convert_runtime_Object_To_runtime_RawExtension(&in.Data, &out.Data, s); err != nil { - return err - } + out.Data = in.Data out.Revision = in.Revision return nil } @@ -375,17 +371,7 @@ func Convert_apps_ControllerRevision_To_v1_ControllerRevision(in *apps.Controlle func autoConvert_v1_ControllerRevisionList_To_apps_ControllerRevisionList(in *v1.ControllerRevisionList, out *apps.ControllerRevisionList, s conversion.Scope) error { out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]apps.ControllerRevision, len(*in)) - for i := range *in { - if err := Convert_v1_ControllerRevision_To_apps_ControllerRevision(&(*in)[i], &(*out)[i], s); err != nil { - return err - } - } - } else { - out.Items = nil - } + out.Items = *(*[]apps.ControllerRevision)(unsafe.Pointer(&in.Items)) return nil } @@ -396,17 +382,7 @@ func Convert_v1_ControllerRevisionList_To_apps_ControllerRevisionList(in *v1.Con func autoConvert_apps_ControllerRevisionList_To_v1_ControllerRevisionList(in *apps.ControllerRevisionList, out *v1.ControllerRevisionList, s conversion.Scope) error { out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]v1.ControllerRevision, len(*in)) - for i := range *in { - if err := Convert_apps_ControllerRevision_To_v1_ControllerRevision(&(*in)[i], &(*out)[i], s); err != nil { - return err - } - } - } else { - out.Items = nil - } + out.Items = *(*[]v1.ControllerRevision)(unsafe.Pointer(&in.Items)) return nil } diff --git a/pkg/apis/apps/v1beta1/zz_generated.conversion.go b/pkg/apis/apps/v1beta1/zz_generated.conversion.go index cbbda226aeb..6f32dd024bc 100644 --- a/pkg/apis/apps/v1beta1/zz_generated.conversion.go +++ b/pkg/apis/apps/v1beta1/zz_generated.conversion.go @@ -278,9 +278,7 @@ func RegisterConversions(s *runtime.Scheme) error { func autoConvert_v1beta1_ControllerRevision_To_apps_ControllerRevision(in *v1beta1.ControllerRevision, out *apps.ControllerRevision, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta - if err := runtime.Convert_runtime_RawExtension_To_runtime_Object(&in.Data, &out.Data, s); err != nil { - return err - } + out.Data = in.Data out.Revision = in.Revision return nil } @@ -292,9 +290,7 @@ func Convert_v1beta1_ControllerRevision_To_apps_ControllerRevision(in *v1beta1.C func autoConvert_apps_ControllerRevision_To_v1beta1_ControllerRevision(in *apps.ControllerRevision, out *v1beta1.ControllerRevision, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta - if err := runtime.Convert_runtime_Object_To_runtime_RawExtension(&in.Data, &out.Data, s); err != nil { - return err - } + out.Data = in.Data out.Revision = in.Revision return nil } @@ -306,17 +302,7 @@ func Convert_apps_ControllerRevision_To_v1beta1_ControllerRevision(in *apps.Cont func autoConvert_v1beta1_ControllerRevisionList_To_apps_ControllerRevisionList(in *v1beta1.ControllerRevisionList, out *apps.ControllerRevisionList, s conversion.Scope) error { out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]apps.ControllerRevision, len(*in)) - for i := range *in { - if err := Convert_v1beta1_ControllerRevision_To_apps_ControllerRevision(&(*in)[i], &(*out)[i], s); err != nil { - return err - } - } - } else { - out.Items = nil - } + out.Items = *(*[]apps.ControllerRevision)(unsafe.Pointer(&in.Items)) return nil } @@ -327,17 +313,7 @@ func Convert_v1beta1_ControllerRevisionList_To_apps_ControllerRevisionList(in *v func autoConvert_apps_ControllerRevisionList_To_v1beta1_ControllerRevisionList(in *apps.ControllerRevisionList, out *v1beta1.ControllerRevisionList, s conversion.Scope) error { out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]v1beta1.ControllerRevision, len(*in)) - for i := range *in { - if err := Convert_apps_ControllerRevision_To_v1beta1_ControllerRevision(&(*in)[i], &(*out)[i], s); err != nil { - return err - } - } - } else { - out.Items = nil - } + out.Items = *(*[]v1beta1.ControllerRevision)(unsafe.Pointer(&in.Items)) return nil } diff --git a/pkg/apis/apps/v1beta2/zz_generated.conversion.go b/pkg/apis/apps/v1beta2/zz_generated.conversion.go index 884bb3f0b1a..a712895bcce 100644 --- a/pkg/apis/apps/v1beta2/zz_generated.conversion.go +++ b/pkg/apis/apps/v1beta2/zz_generated.conversion.go @@ -378,9 +378,7 @@ func RegisterConversions(s *runtime.Scheme) error { func autoConvert_v1beta2_ControllerRevision_To_apps_ControllerRevision(in *v1beta2.ControllerRevision, out *apps.ControllerRevision, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta - if err := runtime.Convert_runtime_RawExtension_To_runtime_Object(&in.Data, &out.Data, s); err != nil { - return err - } + out.Data = in.Data out.Revision = in.Revision return nil } @@ -392,9 +390,7 @@ func Convert_v1beta2_ControllerRevision_To_apps_ControllerRevision(in *v1beta2.C func autoConvert_apps_ControllerRevision_To_v1beta2_ControllerRevision(in *apps.ControllerRevision, out *v1beta2.ControllerRevision, s conversion.Scope) error { out.ObjectMeta = in.ObjectMeta - if err := runtime.Convert_runtime_Object_To_runtime_RawExtension(&in.Data, &out.Data, s); err != nil { - return err - } + out.Data = in.Data out.Revision = in.Revision return nil } @@ -406,17 +402,7 @@ func Convert_apps_ControllerRevision_To_v1beta2_ControllerRevision(in *apps.Cont func autoConvert_v1beta2_ControllerRevisionList_To_apps_ControllerRevisionList(in *v1beta2.ControllerRevisionList, out *apps.ControllerRevisionList, s conversion.Scope) error { out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]apps.ControllerRevision, len(*in)) - for i := range *in { - if err := Convert_v1beta2_ControllerRevision_To_apps_ControllerRevision(&(*in)[i], &(*out)[i], s); err != nil { - return err - } - } - } else { - out.Items = nil - } + out.Items = *(*[]apps.ControllerRevision)(unsafe.Pointer(&in.Items)) return nil } @@ -427,17 +413,7 @@ func Convert_v1beta2_ControllerRevisionList_To_apps_ControllerRevisionList(in *v func autoConvert_apps_ControllerRevisionList_To_v1beta2_ControllerRevisionList(in *apps.ControllerRevisionList, out *v1beta2.ControllerRevisionList, s conversion.Scope) error { out.ListMeta = in.ListMeta - if in.Items != nil { - in, out := &in.Items, &out.Items - *out = make([]v1beta2.ControllerRevision, len(*in)) - for i := range *in { - if err := Convert_apps_ControllerRevision_To_v1beta2_ControllerRevision(&(*in)[i], &(*out)[i], s); err != nil { - return err - } - } - } else { - out.Items = nil - } + out.Items = *(*[]v1beta2.ControllerRevision)(unsafe.Pointer(&in.Items)) return nil } diff --git a/pkg/apis/apps/validation/validation.go b/pkg/apis/apps/validation/validation.go index 717751d0049..7f05624fb64 100644 --- a/pkg/apis/apps/validation/validation.go +++ b/pkg/apis/apps/validation/validation.go @@ -17,6 +17,7 @@ limitations under the License. package validation import ( + "encoding/json" "fmt" "strconv" @@ -251,20 +252,34 @@ func ValidateStatefulSetStatusUpdate(statefulSet, oldStatefulSet *apps.StatefulS // trailing dashes are allowed. var ValidateControllerRevisionName = apimachineryvalidation.NameIsDNSSubdomain -// ValidateControllerRevision collects errors for the fields of state and returns those errors as an ErrorList. If the +// validateControllerRevision collects errors for the fields of state and returns those errors as an ErrorList. If the // returned list is empty, state is valid. Validation is performed to ensure that state is a valid ObjectMeta, its name // is valid, and that it doesn't exceed the MaxControllerRevisionSize. -func ValidateControllerRevision(revision *apps.ControllerRevision) field.ErrorList { +func validateControllerRevision(revision *apps.ControllerRevision) field.ErrorList { errs := field.ErrorList{} - errs = append(errs, apivalidation.ValidateObjectMeta(&revision.ObjectMeta, true, ValidateControllerRevisionName, field.NewPath("metadata"))...) - if revision.Data == nil { - errs = append(errs, field.Required(field.NewPath("data"), "data is mandatory")) - } errs = append(errs, apivalidation.ValidateNonnegativeField(revision.Revision, field.NewPath("revision"))...) return errs } +func ValidateControllerRevisionCreate(revision *apps.ControllerRevision) field.ErrorList { + errs := field.ErrorList{} + errs = append(errs, validateControllerRevision(revision)...) + + var v any + if revision.Data.Raw == nil { + errs = append(errs, field.Required(field.NewPath("data"), "data is mandatory")) + } else if err := json.Unmarshal(revision.Data.Raw, &v); err != nil { + errs = append(errs, field.Invalid(field.NewPath("data"), "", fmt.Sprintf("error parsing data: %v", err.Error()))) + } else if v == nil { + errs = append(errs, field.Required(field.NewPath("data"), "data is mandatory")) + } else if _, isObject := v.(map[string]any); !isObject { + errs = append(errs, field.Required(field.NewPath("data"), "data must be a valid JSON object")) + } + + return errs +} + // ValidateControllerRevisionUpdate collects errors pertaining to the mutation of an ControllerRevision Object. If the // returned ErrorList is empty the update operation is valid. Any mutation to the ControllerRevision's Data or Revision // is considered to be invalid. @@ -272,7 +287,7 @@ func ValidateControllerRevisionUpdate(newHistory, oldHistory *apps.ControllerRev errs := field.ErrorList{} errs = append(errs, apivalidation.ValidateObjectMetaUpdate(&newHistory.ObjectMeta, &oldHistory.ObjectMeta, field.NewPath("metadata"))...) - errs = append(errs, ValidateControllerRevision(newHistory)...) + errs = append(errs, validateControllerRevision(newHistory)...) errs = append(errs, apivalidation.ValidateImmutableField(newHistory.Data, oldHistory.Data, field.NewPath("data"))...) return errs } diff --git a/pkg/apis/apps/validation/validation_test.go b/pkg/apis/apps/validation/validation_test.go index a2bf74e40ae..c2bc0b12143 100644 --- a/pkg/apis/apps/validation/validation_test.go +++ b/pkg/apis/apps/validation/validation_test.go @@ -17,12 +17,14 @@ limitations under the License. package validation import ( + "encoding/json" "fmt" "strings" "testing" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" @@ -969,7 +971,7 @@ func TestValidateStatefulSetUpdate(t *testing.T) { } func TestValidateControllerRevision(t *testing.T) { - newControllerRevision := func(name, namespace string, data runtime.Object, revision int64) apps.ControllerRevision { + newControllerRevision := func(name, namespace string, data runtime.RawExtension, revision int64) apps.ControllerRevision { return apps.ControllerRevision{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -993,15 +995,17 @@ func TestValidateControllerRevision(t *testing.T) { } ss := mkStatefulSet(&podTemplate) + ssJSON, _ := json.Marshal(ss) + raw := runtime.RawExtension{Raw: ssJSON} var ( - valid = newControllerRevision("validname", "validns", &ss, 0) - badRevision = newControllerRevision("validname", "validns", &ss, -1) - emptyName = newControllerRevision("", "validns", &ss, 0) - invalidName = newControllerRevision("NoUppercaseOrSpecialCharsLike=Equals", "validns", &ss, 0) - emptyNs = newControllerRevision("validname", "", &ss, 100) - invalidNs = newControllerRevision("validname", "NoUppercaseOrSpecialCharsLike=Equals", &ss, 100) - nilData = newControllerRevision("validname", "NoUppercaseOrSpecialCharsLike=Equals", nil, 100) + valid = newControllerRevision("validname", "validns", raw, 0) + badRevision = newControllerRevision("validname", "validns", raw, -1) + emptyName = newControllerRevision("", "validns", raw, 0) + invalidName = newControllerRevision("NoUppercaseOrSpecialCharsLike=Equals", "validns", raw, 0) + emptyNs = newControllerRevision("validname", "", raw, 100) + invalidNs = newControllerRevision("validname", "NoUppercaseOrSpecialCharsLike=Equals", raw, 100) + nilData = newControllerRevision("validname", "NoUppercaseOrSpecialCharsLike=Equals", runtime.RawExtension{}, 100) ) tests := map[string]struct { @@ -1015,11 +1019,19 @@ func TestValidateControllerRevision(t *testing.T) { "empty namespace": {emptyNs, false}, "invalid namespace": {invalidNs, false}, "nil data": {nilData, false}, + "json error": {newControllerRevision("validname", "validns", runtime.RawExtension{Raw: []byte(`{`)}, 0), false}, + "json bool": {newControllerRevision("validname", "validns", runtime.RawExtension{Raw: []byte(`true`)}, 0), false}, + "json int": {newControllerRevision("validname", "validns", runtime.RawExtension{Raw: []byte(`0`)}, 0), false}, + "json float": {newControllerRevision("validname", "validns", runtime.RawExtension{Raw: []byte(`0.5`)}, 0), false}, + "json null": {newControllerRevision("validname", "validns", runtime.RawExtension{Raw: []byte(`null`)}, 0), false}, + "json array": {newControllerRevision("validname", "validns", runtime.RawExtension{Raw: []byte(`[]`)}, 0), false}, + "json string": {newControllerRevision("validname", "validns", runtime.RawExtension{Raw: []byte(`"test"`)}, 0), false}, + "json object": {newControllerRevision("validname", "validns", runtime.RawExtension{Raw: []byte(`{}`)}, 0), true}, } for name, tc := range tests { t.Run(name, func(t *testing.T) { - errs := ValidateControllerRevision(&tc.history) + errs := ValidateControllerRevisionCreate(&tc.history) if tc.isValid && len(errs) > 0 { t.Errorf("%v: unexpected error: %v", name, errs) } @@ -1031,7 +1043,7 @@ func TestValidateControllerRevision(t *testing.T) { } func TestValidateControllerRevisionUpdate(t *testing.T) { - newControllerRevision := func(version, name, namespace string, data runtime.Object, revision int64) apps.ControllerRevision { + newControllerRevision := func(version, name, namespace string, data runtime.RawExtension, revision int64) apps.ControllerRevision { return apps.ControllerRevision{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -1058,11 +1070,16 @@ func TestValidateControllerRevisionUpdate(t *testing.T) { ss := mkStatefulSet(&podTemplate, tweakName("abc")) modifiedss := mkStatefulSet(&podTemplate, tweakName("cdf")) + ssJSON, _ := json.Marshal(ss) + modifiedSSJSON, _ := json.Marshal(modifiedss) + raw := runtime.RawExtension{Raw: ssJSON} + modifiedRaw := runtime.RawExtension{Raw: modifiedSSJSON} + var ( - valid = newControllerRevision("1", "validname", "validns", &ss, 0) - noVersion = newControllerRevision("", "validname", "validns", &ss, 0) - changedData = newControllerRevision("1", "validname", "validns", &modifiedss, 0) - changedRevision = newControllerRevision("1", "validname", "validns", &ss, 1) + valid = newControllerRevision("1", "validname", "validns", raw, 0) + noVersion = newControllerRevision("", "validname", "validns", raw, 0) + changedData = newControllerRevision("1", "validname", "validns", modifiedRaw, 0) + changedRevision = newControllerRevision("1", "validname", "validns", raw, 1) ) cases := []struct { diff --git a/pkg/apis/apps/zz_generated.deepcopy.go b/pkg/apis/apps/zz_generated.deepcopy.go index 3353f125077..14beed8f575 100644 --- a/pkg/apis/apps/zz_generated.deepcopy.go +++ b/pkg/apis/apps/zz_generated.deepcopy.go @@ -33,9 +33,7 @@ func (in *ControllerRevision) DeepCopyInto(out *ControllerRevision) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - if in.Data != nil { - out.Data = in.Data.DeepCopyObject() - } + in.Data.DeepCopyInto(&out.Data) return } diff --git a/pkg/controlplane/import_known_versions_test.go b/pkg/controlplane/import_known_versions_test.go index 3bb74e49940..7ba0187a497 100644 --- a/pkg/controlplane/import_known_versions_test.go +++ b/pkg/controlplane/import_known_versions_test.go @@ -23,6 +23,7 @@ import ( v1 "k8s.io/api/core/v1" apinamingtest "k8s.io/apimachinery/pkg/api/apitesting/naming" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/kubernetes/pkg/api/legacyscheme" @@ -70,6 +71,7 @@ var typesAllowedTags = map[reflect.Type]bool{ reflect.TypeOf(metav1.GroupVersionResource{}): true, reflect.TypeOf(metav1.Status{}): true, reflect.TypeOf(metav1.Condition{}): true, + reflect.TypeOf(runtime.RawExtension{}): true, } // These fields are limited exceptions to the standard JSON naming structure. diff --git a/pkg/registry/apps/controllerrevision/storage/storage_test.go b/pkg/registry/apps/controllerrevision/storage/storage_test.go index 7a531226cd5..88286807921 100644 --- a/pkg/registry/apps/controllerrevision/storage/storage_test.go +++ b/pkg/registry/apps/controllerrevision/storage/storage_test.go @@ -17,6 +17,7 @@ limitations under the License. package storage import ( + "encoding/json" "testing" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -43,7 +44,7 @@ func TestCreate(t *testing.T) { invalidName = stripObjectMeta(newControllerRevision("NoUppercaseOrSpecialCharsLike=Equals", "validns", newObject(), 0)) emptyNs = stripObjectMeta(newControllerRevision("validname", "", newObject(), 100)) invalidNs = stripObjectMeta(newControllerRevision("validname", "NoUppercaseOrSpecialCharsLike=Equals", newObject(), 100)) - nilData = stripObjectMeta(newControllerRevision("validname", "validns", nil, 0)) + nilData = stripObjectMeta(newControllerRevision("validname", "validns", runtime.RawExtension{Raw: nil}, 0)) ) test.TestCreate( valid, @@ -74,12 +75,11 @@ func TestUpdate(t *testing.T) { updateData := func(obj runtime.Object) runtime.Object { rev := obj.(*apps.ControllerRevision) - modified := newObject() - ss := modified.(*apps.StatefulSet) + ss := newStatefulSet() ss.Name = "cde" update := &apps.ControllerRevision{ ObjectMeta: rev.ObjectMeta, - Data: ss, + Data: newRawExtensionFromObject(ss), Revision: rev.Revision + 1, } return update @@ -136,7 +136,7 @@ func TestWatch(t *testing.T) { ) } -func newControllerRevision(name, namespace string, data runtime.Object, revision int64) *apps.ControllerRevision { +func newControllerRevision(name, namespace string, data runtime.RawExtension, revision int64) *apps.ControllerRevision { return &apps.ControllerRevision{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -167,7 +167,7 @@ func newStorage(t *testing.T) (*REST, *etcd3testing.EtcdTestServer) { return storage, server } -func newObject() runtime.Object { +func newStatefulSet() *apps.StatefulSet { return &apps.StatefulSet{ ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, Spec: apps.StatefulSetSpec{ @@ -184,3 +184,10 @@ func newObject() runtime.Object { }, } } +func newRawExtensionFromObject(obj runtime.Object) runtime.RawExtension { + jsonData, _ := json.Marshal(obj) + return runtime.RawExtension{Raw: jsonData} +} +func newObject() runtime.RawExtension { + return newRawExtensionFromObject(newStatefulSet()) +} diff --git a/pkg/registry/apps/controllerrevision/strategy.go b/pkg/registry/apps/controllerrevision/strategy.go index 250f0ed9eba..c0b9d680990 100644 --- a/pkg/registry/apps/controllerrevision/strategy.go +++ b/pkg/registry/apps/controllerrevision/strategy.go @@ -62,7 +62,7 @@ func (strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) { func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { revision := obj.(*apps.ControllerRevision) - return validation.ValidateControllerRevision(revision) + return validation.ValidateControllerRevisionCreate(revision) } // WarningsOnCreate returns warnings for the creation of the given object. diff --git a/pkg/registry/apps/controllerrevision/strategy_test.go b/pkg/registry/apps/controllerrevision/strategy_test.go index ed9f886e892..1d32168a2f1 100644 --- a/pkg/registry/apps/controllerrevision/strategy_test.go +++ b/pkg/registry/apps/controllerrevision/strategy_test.go @@ -17,6 +17,7 @@ limitations under the License. package controllerrevision import ( + "encoding/json" "testing" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -47,7 +48,7 @@ func TestStrategy_Validate(t *testing.T) { invalidName = newControllerRevision("NoUppercaseOrSpecialCharsLike=Equals", "validns", newObject(), 0) emptyNs = newControllerRevision("validname", "", newObject(), 100) invalidNs = newControllerRevision("validname", "NoUppercaseOrSpecialCharsLike=Equals", newObject(), 100) - nilData = newControllerRevision("validname", "validns", nil, 0) + nilData = newControllerRevision("validname", "validns", runtime.RawExtension{Raw: nil}, 0) ) tests := map[string]struct { @@ -79,11 +80,10 @@ func TestStrategy_ValidateUpdate(t *testing.T) { var ( valid = newControllerRevision("validname", "validns", newObject(), 0) changedData = newControllerRevision("validname", "validns", - func() runtime.Object { - modified := newObject() - ss := modified.(*apps.StatefulSet) + func() runtime.RawExtension { + ss := newStatefulSet() ss.Name = "cde" - return modified + return newRawExtensionFromObject(ss) }(), 0) changedRevision = newControllerRevision("validname", "validns", newObject(), 1) ) @@ -125,7 +125,7 @@ func TestStrategy_ValidateUpdate(t *testing.T) { } } -func newControllerRevision(name, namespace string, data runtime.Object, revision int64) *apps.ControllerRevision { +func newControllerRevision(name, namespace string, data runtime.RawExtension, revision int64) *apps.ControllerRevision { return &apps.ControllerRevision{ ObjectMeta: metav1.ObjectMeta{ Name: name, @@ -138,7 +138,7 @@ func newControllerRevision(name, namespace string, data runtime.Object, revision } } -func newObject() runtime.Object { +func newStatefulSet() *apps.StatefulSet { return &apps.StatefulSet{ ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault}, Spec: apps.StatefulSetSpec{ @@ -155,3 +155,10 @@ func newObject() runtime.Object { }, } } +func newRawExtensionFromObject(obj runtime.Object) runtime.RawExtension { + jsonData, _ := json.Marshal(obj) + return runtime.RawExtension{Raw: jsonData} +} +func newObject() runtime.RawExtension { + return newRawExtensionFromObject(newStatefulSet()) +}