mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-07 11:13:48 +00:00
Ensure controller revision data is valid json
This commit is contained in:
parent
6c556cb9c2
commit
d6d78c5581
@ -22,6 +22,7 @@ import (
|
|||||||
fuzz "github.com/google/gofuzz"
|
fuzz "github.com/google/gofuzz"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
runtimeserializer "k8s.io/apimachinery/pkg/runtime/serializer"
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
"k8s.io/kubernetes/pkg/apis/apps"
|
"k8s.io/kubernetes/pkg/apis/apps"
|
||||||
@ -30,6 +31,11 @@ import (
|
|||||||
// Funcs returns the fuzzer functions for the apps api group.
|
// Funcs returns the fuzzer functions for the apps api group.
|
||||||
var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
|
var Funcs = func(codecs runtimeserializer.CodecFactory) []interface{} {
|
||||||
return []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) {
|
func(s *apps.StatefulSet, c fuzz.Continue) {
|
||||||
c.FuzzNoCustom(s) // fuzz self without calling this function again
|
c.FuzzNoCustom(s) // fuzz self without calling this function again
|
||||||
|
|
||||||
|
@ -331,7 +331,7 @@ type ControllerRevision struct {
|
|||||||
metav1.ObjectMeta
|
metav1.ObjectMeta
|
||||||
|
|
||||||
// Data is the Object representing the state.
|
// Data is the Object representing the state.
|
||||||
Data runtime.Object
|
Data runtime.RawExtension
|
||||||
|
|
||||||
// Revision indicates the revision of the state represented by Data.
|
// Revision indicates the revision of the state represented by Data.
|
||||||
Revision int64
|
Revision int64
|
||||||
|
32
pkg/apis/apps/v1/zz_generated.conversion.go
generated
32
pkg/apis/apps/v1/zz_generated.conversion.go
generated
@ -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 {
|
func autoConvert_v1_ControllerRevision_To_apps_ControllerRevision(in *v1.ControllerRevision, out *apps.ControllerRevision, s conversion.Scope) error {
|
||||||
out.ObjectMeta = in.ObjectMeta
|
out.ObjectMeta = in.ObjectMeta
|
||||||
if err := runtime.Convert_runtime_RawExtension_To_runtime_Object(&in.Data, &out.Data, s); err != nil {
|
out.Data = in.Data
|
||||||
return err
|
|
||||||
}
|
|
||||||
out.Revision = in.Revision
|
out.Revision = in.Revision
|
||||||
return nil
|
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 {
|
func autoConvert_apps_ControllerRevision_To_v1_ControllerRevision(in *apps.ControllerRevision, out *v1.ControllerRevision, s conversion.Scope) error {
|
||||||
out.ObjectMeta = in.ObjectMeta
|
out.ObjectMeta = in.ObjectMeta
|
||||||
if err := runtime.Convert_runtime_Object_To_runtime_RawExtension(&in.Data, &out.Data, s); err != nil {
|
out.Data = in.Data
|
||||||
return err
|
|
||||||
}
|
|
||||||
out.Revision = in.Revision
|
out.Revision = in.Revision
|
||||||
return nil
|
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 {
|
func autoConvert_v1_ControllerRevisionList_To_apps_ControllerRevisionList(in *v1.ControllerRevisionList, out *apps.ControllerRevisionList, s conversion.Scope) error {
|
||||||
out.ListMeta = in.ListMeta
|
out.ListMeta = in.ListMeta
|
||||||
if in.Items != nil {
|
out.Items = *(*[]apps.ControllerRevision)(unsafe.Pointer(&in.Items))
|
||||||
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
|
|
||||||
}
|
|
||||||
return nil
|
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 {
|
func autoConvert_apps_ControllerRevisionList_To_v1_ControllerRevisionList(in *apps.ControllerRevisionList, out *v1.ControllerRevisionList, s conversion.Scope) error {
|
||||||
out.ListMeta = in.ListMeta
|
out.ListMeta = in.ListMeta
|
||||||
if in.Items != nil {
|
out.Items = *(*[]v1.ControllerRevision)(unsafe.Pointer(&in.Items))
|
||||||
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
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
32
pkg/apis/apps/v1beta1/zz_generated.conversion.go
generated
32
pkg/apis/apps/v1beta1/zz_generated.conversion.go
generated
@ -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 {
|
func autoConvert_v1beta1_ControllerRevision_To_apps_ControllerRevision(in *v1beta1.ControllerRevision, out *apps.ControllerRevision, s conversion.Scope) error {
|
||||||
out.ObjectMeta = in.ObjectMeta
|
out.ObjectMeta = in.ObjectMeta
|
||||||
if err := runtime.Convert_runtime_RawExtension_To_runtime_Object(&in.Data, &out.Data, s); err != nil {
|
out.Data = in.Data
|
||||||
return err
|
|
||||||
}
|
|
||||||
out.Revision = in.Revision
|
out.Revision = in.Revision
|
||||||
return nil
|
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 {
|
func autoConvert_apps_ControllerRevision_To_v1beta1_ControllerRevision(in *apps.ControllerRevision, out *v1beta1.ControllerRevision, s conversion.Scope) error {
|
||||||
out.ObjectMeta = in.ObjectMeta
|
out.ObjectMeta = in.ObjectMeta
|
||||||
if err := runtime.Convert_runtime_Object_To_runtime_RawExtension(&in.Data, &out.Data, s); err != nil {
|
out.Data = in.Data
|
||||||
return err
|
|
||||||
}
|
|
||||||
out.Revision = in.Revision
|
out.Revision = in.Revision
|
||||||
return nil
|
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 {
|
func autoConvert_v1beta1_ControllerRevisionList_To_apps_ControllerRevisionList(in *v1beta1.ControllerRevisionList, out *apps.ControllerRevisionList, s conversion.Scope) error {
|
||||||
out.ListMeta = in.ListMeta
|
out.ListMeta = in.ListMeta
|
||||||
if in.Items != nil {
|
out.Items = *(*[]apps.ControllerRevision)(unsafe.Pointer(&in.Items))
|
||||||
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
|
|
||||||
}
|
|
||||||
return nil
|
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 {
|
func autoConvert_apps_ControllerRevisionList_To_v1beta1_ControllerRevisionList(in *apps.ControllerRevisionList, out *v1beta1.ControllerRevisionList, s conversion.Scope) error {
|
||||||
out.ListMeta = in.ListMeta
|
out.ListMeta = in.ListMeta
|
||||||
if in.Items != nil {
|
out.Items = *(*[]v1beta1.ControllerRevision)(unsafe.Pointer(&in.Items))
|
||||||
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
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
32
pkg/apis/apps/v1beta2/zz_generated.conversion.go
generated
32
pkg/apis/apps/v1beta2/zz_generated.conversion.go
generated
@ -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 {
|
func autoConvert_v1beta2_ControllerRevision_To_apps_ControllerRevision(in *v1beta2.ControllerRevision, out *apps.ControllerRevision, s conversion.Scope) error {
|
||||||
out.ObjectMeta = in.ObjectMeta
|
out.ObjectMeta = in.ObjectMeta
|
||||||
if err := runtime.Convert_runtime_RawExtension_To_runtime_Object(&in.Data, &out.Data, s); err != nil {
|
out.Data = in.Data
|
||||||
return err
|
|
||||||
}
|
|
||||||
out.Revision = in.Revision
|
out.Revision = in.Revision
|
||||||
return nil
|
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 {
|
func autoConvert_apps_ControllerRevision_To_v1beta2_ControllerRevision(in *apps.ControllerRevision, out *v1beta2.ControllerRevision, s conversion.Scope) error {
|
||||||
out.ObjectMeta = in.ObjectMeta
|
out.ObjectMeta = in.ObjectMeta
|
||||||
if err := runtime.Convert_runtime_Object_To_runtime_RawExtension(&in.Data, &out.Data, s); err != nil {
|
out.Data = in.Data
|
||||||
return err
|
|
||||||
}
|
|
||||||
out.Revision = in.Revision
|
out.Revision = in.Revision
|
||||||
return nil
|
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 {
|
func autoConvert_v1beta2_ControllerRevisionList_To_apps_ControllerRevisionList(in *v1beta2.ControllerRevisionList, out *apps.ControllerRevisionList, s conversion.Scope) error {
|
||||||
out.ListMeta = in.ListMeta
|
out.ListMeta = in.ListMeta
|
||||||
if in.Items != nil {
|
out.Items = *(*[]apps.ControllerRevision)(unsafe.Pointer(&in.Items))
|
||||||
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
|
|
||||||
}
|
|
||||||
return nil
|
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 {
|
func autoConvert_apps_ControllerRevisionList_To_v1beta2_ControllerRevisionList(in *apps.ControllerRevisionList, out *v1beta2.ControllerRevisionList, s conversion.Scope) error {
|
||||||
out.ListMeta = in.ListMeta
|
out.ListMeta = in.ListMeta
|
||||||
if in.Items != nil {
|
out.Items = *(*[]v1beta2.ControllerRevision)(unsafe.Pointer(&in.Items))
|
||||||
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
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package validation
|
package validation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
@ -251,20 +252,34 @@ func ValidateStatefulSetStatusUpdate(statefulSet, oldStatefulSet *apps.StatefulS
|
|||||||
// trailing dashes are allowed.
|
// trailing dashes are allowed.
|
||||||
var ValidateControllerRevisionName = apimachineryvalidation.NameIsDNSSubdomain
|
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
|
// 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.
|
// 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 := field.ErrorList{}
|
||||||
|
|
||||||
errs = append(errs, apivalidation.ValidateObjectMeta(&revision.ObjectMeta, true, ValidateControllerRevisionName, field.NewPath("metadata"))...)
|
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"))...)
|
errs = append(errs, apivalidation.ValidateNonnegativeField(revision.Revision, field.NewPath("revision"))...)
|
||||||
return errs
|
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"), "<value omitted>", 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
|
// 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
|
// returned ErrorList is empty the update operation is valid. Any mutation to the ControllerRevision's Data or Revision
|
||||||
// is considered to be invalid.
|
// is considered to be invalid.
|
||||||
@ -272,7 +287,7 @@ func ValidateControllerRevisionUpdate(newHistory, oldHistory *apps.ControllerRev
|
|||||||
errs := field.ErrorList{}
|
errs := field.ErrorList{}
|
||||||
|
|
||||||
errs = append(errs, apivalidation.ValidateObjectMetaUpdate(&newHistory.ObjectMeta, &oldHistory.ObjectMeta, field.NewPath("metadata"))...)
|
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"))...)
|
errs = append(errs, apivalidation.ValidateImmutableField(newHistory.Data, oldHistory.Data, field.NewPath("data"))...)
|
||||||
return errs
|
return errs
|
||||||
}
|
}
|
||||||
|
@ -17,12 +17,14 @@ limitations under the License.
|
|||||||
package validation
|
package validation
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
"github.com/google/go-cmp/cmp/cmpopts"
|
"github.com/google/go-cmp/cmp/cmpopts"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
@ -969,7 +971,7 @@ func TestValidateStatefulSetUpdate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateControllerRevision(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{
|
return apps.ControllerRevision{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: name,
|
Name: name,
|
||||||
@ -993,15 +995,17 @@ func TestValidateControllerRevision(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ss := mkStatefulSet(&podTemplate)
|
ss := mkStatefulSet(&podTemplate)
|
||||||
|
ssJSON, _ := json.Marshal(ss)
|
||||||
|
raw := runtime.RawExtension{Raw: ssJSON}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
valid = newControllerRevision("validname", "validns", &ss, 0)
|
valid = newControllerRevision("validname", "validns", raw, 0)
|
||||||
badRevision = newControllerRevision("validname", "validns", &ss, -1)
|
badRevision = newControllerRevision("validname", "validns", raw, -1)
|
||||||
emptyName = newControllerRevision("", "validns", &ss, 0)
|
emptyName = newControllerRevision("", "validns", raw, 0)
|
||||||
invalidName = newControllerRevision("NoUppercaseOrSpecialCharsLike=Equals", "validns", &ss, 0)
|
invalidName = newControllerRevision("NoUppercaseOrSpecialCharsLike=Equals", "validns", raw, 0)
|
||||||
emptyNs = newControllerRevision("validname", "", &ss, 100)
|
emptyNs = newControllerRevision("validname", "", raw, 100)
|
||||||
invalidNs = newControllerRevision("validname", "NoUppercaseOrSpecialCharsLike=Equals", &ss, 100)
|
invalidNs = newControllerRevision("validname", "NoUppercaseOrSpecialCharsLike=Equals", raw, 100)
|
||||||
nilData = newControllerRevision("validname", "NoUppercaseOrSpecialCharsLike=Equals", nil, 100)
|
nilData = newControllerRevision("validname", "NoUppercaseOrSpecialCharsLike=Equals", runtime.RawExtension{}, 100)
|
||||||
)
|
)
|
||||||
|
|
||||||
tests := map[string]struct {
|
tests := map[string]struct {
|
||||||
@ -1015,11 +1019,19 @@ func TestValidateControllerRevision(t *testing.T) {
|
|||||||
"empty namespace": {emptyNs, false},
|
"empty namespace": {emptyNs, false},
|
||||||
"invalid namespace": {invalidNs, false},
|
"invalid namespace": {invalidNs, false},
|
||||||
"nil data": {nilData, 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 {
|
for name, tc := range tests {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
errs := ValidateControllerRevision(&tc.history)
|
errs := ValidateControllerRevisionCreate(&tc.history)
|
||||||
if tc.isValid && len(errs) > 0 {
|
if tc.isValid && len(errs) > 0 {
|
||||||
t.Errorf("%v: unexpected error: %v", name, errs)
|
t.Errorf("%v: unexpected error: %v", name, errs)
|
||||||
}
|
}
|
||||||
@ -1031,7 +1043,7 @@ func TestValidateControllerRevision(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateControllerRevisionUpdate(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{
|
return apps.ControllerRevision{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: name,
|
Name: name,
|
||||||
@ -1058,11 +1070,16 @@ func TestValidateControllerRevisionUpdate(t *testing.T) {
|
|||||||
ss := mkStatefulSet(&podTemplate, tweakName("abc"))
|
ss := mkStatefulSet(&podTemplate, tweakName("abc"))
|
||||||
modifiedss := mkStatefulSet(&podTemplate, tweakName("cdf"))
|
modifiedss := mkStatefulSet(&podTemplate, tweakName("cdf"))
|
||||||
|
|
||||||
|
ssJSON, _ := json.Marshal(ss)
|
||||||
|
modifiedSSJSON, _ := json.Marshal(modifiedss)
|
||||||
|
raw := runtime.RawExtension{Raw: ssJSON}
|
||||||
|
modifiedRaw := runtime.RawExtension{Raw: modifiedSSJSON}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
valid = newControllerRevision("1", "validname", "validns", &ss, 0)
|
valid = newControllerRevision("1", "validname", "validns", raw, 0)
|
||||||
noVersion = newControllerRevision("", "validname", "validns", &ss, 0)
|
noVersion = newControllerRevision("", "validname", "validns", raw, 0)
|
||||||
changedData = newControllerRevision("1", "validname", "validns", &modifiedss, 0)
|
changedData = newControllerRevision("1", "validname", "validns", modifiedRaw, 0)
|
||||||
changedRevision = newControllerRevision("1", "validname", "validns", &ss, 1)
|
changedRevision = newControllerRevision("1", "validname", "validns", raw, 1)
|
||||||
)
|
)
|
||||||
|
|
||||||
cases := []struct {
|
cases := []struct {
|
||||||
|
4
pkg/apis/apps/zz_generated.deepcopy.go
generated
4
pkg/apis/apps/zz_generated.deepcopy.go
generated
@ -33,9 +33,7 @@ func (in *ControllerRevision) DeepCopyInto(out *ControllerRevision) {
|
|||||||
*out = *in
|
*out = *in
|
||||||
out.TypeMeta = in.TypeMeta
|
out.TypeMeta = in.TypeMeta
|
||||||
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
||||||
if in.Data != nil {
|
in.Data.DeepCopyInto(&out.Data)
|
||||||
out.Data = in.Data.DeepCopyObject()
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
v1 "k8s.io/api/core/v1"
|
v1 "k8s.io/api/core/v1"
|
||||||
apinamingtest "k8s.io/apimachinery/pkg/api/apitesting/naming"
|
apinamingtest "k8s.io/apimachinery/pkg/api/apitesting/naming"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
@ -70,6 +71,7 @@ var typesAllowedTags = map[reflect.Type]bool{
|
|||||||
reflect.TypeOf(metav1.GroupVersionResource{}): true,
|
reflect.TypeOf(metav1.GroupVersionResource{}): true,
|
||||||
reflect.TypeOf(metav1.Status{}): true,
|
reflect.TypeOf(metav1.Status{}): true,
|
||||||
reflect.TypeOf(metav1.Condition{}): true,
|
reflect.TypeOf(metav1.Condition{}): true,
|
||||||
|
reflect.TypeOf(runtime.RawExtension{}): true,
|
||||||
}
|
}
|
||||||
|
|
||||||
// These fields are limited exceptions to the standard JSON naming structure.
|
// These fields are limited exceptions to the standard JSON naming structure.
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package storage
|
package storage
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
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))
|
invalidName = stripObjectMeta(newControllerRevision("NoUppercaseOrSpecialCharsLike=Equals", "validns", newObject(), 0))
|
||||||
emptyNs = stripObjectMeta(newControllerRevision("validname", "", newObject(), 100))
|
emptyNs = stripObjectMeta(newControllerRevision("validname", "", newObject(), 100))
|
||||||
invalidNs = stripObjectMeta(newControllerRevision("validname", "NoUppercaseOrSpecialCharsLike=Equals", 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(
|
test.TestCreate(
|
||||||
valid,
|
valid,
|
||||||
@ -74,12 +75,11 @@ func TestUpdate(t *testing.T) {
|
|||||||
|
|
||||||
updateData := func(obj runtime.Object) runtime.Object {
|
updateData := func(obj runtime.Object) runtime.Object {
|
||||||
rev := obj.(*apps.ControllerRevision)
|
rev := obj.(*apps.ControllerRevision)
|
||||||
modified := newObject()
|
ss := newStatefulSet()
|
||||||
ss := modified.(*apps.StatefulSet)
|
|
||||||
ss.Name = "cde"
|
ss.Name = "cde"
|
||||||
update := &apps.ControllerRevision{
|
update := &apps.ControllerRevision{
|
||||||
ObjectMeta: rev.ObjectMeta,
|
ObjectMeta: rev.ObjectMeta,
|
||||||
Data: ss,
|
Data: newRawExtensionFromObject(ss),
|
||||||
Revision: rev.Revision + 1,
|
Revision: rev.Revision + 1,
|
||||||
}
|
}
|
||||||
return update
|
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{
|
return &apps.ControllerRevision{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: name,
|
Name: name,
|
||||||
@ -167,7 +167,7 @@ func newStorage(t *testing.T) (*REST, *etcd3testing.EtcdTestServer) {
|
|||||||
return storage, server
|
return storage, server
|
||||||
}
|
}
|
||||||
|
|
||||||
func newObject() runtime.Object {
|
func newStatefulSet() *apps.StatefulSet {
|
||||||
return &apps.StatefulSet{
|
return &apps.StatefulSet{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
|
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
|
||||||
Spec: apps.StatefulSetSpec{
|
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())
|
||||||
|
}
|
||||||
|
@ -62,7 +62,7 @@ func (strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
|||||||
func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
|
func (strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList {
|
||||||
revision := obj.(*apps.ControllerRevision)
|
revision := obj.(*apps.ControllerRevision)
|
||||||
|
|
||||||
return validation.ValidateControllerRevision(revision)
|
return validation.ValidateControllerRevisionCreate(revision)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WarningsOnCreate returns warnings for the creation of the given object.
|
// WarningsOnCreate returns warnings for the creation of the given object.
|
||||||
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
package controllerrevision
|
package controllerrevision
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
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)
|
invalidName = newControllerRevision("NoUppercaseOrSpecialCharsLike=Equals", "validns", newObject(), 0)
|
||||||
emptyNs = newControllerRevision("validname", "", newObject(), 100)
|
emptyNs = newControllerRevision("validname", "", newObject(), 100)
|
||||||
invalidNs = newControllerRevision("validname", "NoUppercaseOrSpecialCharsLike=Equals", 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 {
|
tests := map[string]struct {
|
||||||
@ -79,11 +80,10 @@ func TestStrategy_ValidateUpdate(t *testing.T) {
|
|||||||
var (
|
var (
|
||||||
valid = newControllerRevision("validname", "validns", newObject(), 0)
|
valid = newControllerRevision("validname", "validns", newObject(), 0)
|
||||||
changedData = newControllerRevision("validname", "validns",
|
changedData = newControllerRevision("validname", "validns",
|
||||||
func() runtime.Object {
|
func() runtime.RawExtension {
|
||||||
modified := newObject()
|
ss := newStatefulSet()
|
||||||
ss := modified.(*apps.StatefulSet)
|
|
||||||
ss.Name = "cde"
|
ss.Name = "cde"
|
||||||
return modified
|
return newRawExtensionFromObject(ss)
|
||||||
}(), 0)
|
}(), 0)
|
||||||
changedRevision = newControllerRevision("validname", "validns", newObject(), 1)
|
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{
|
return &apps.ControllerRevision{
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: name,
|
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{
|
return &apps.StatefulSet{
|
||||||
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
|
ObjectMeta: metav1.ObjectMeta{Name: "abc", Namespace: metav1.NamespaceDefault},
|
||||||
Spec: apps.StatefulSetSpec{
|
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())
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user