CRD versioning validation and defaulting
This commit is contained in:
		@@ -17,6 +17,7 @@ limitations under the License.
 | 
				
			|||||||
package apiextensions
 | 
					package apiextensions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
 | 
						"fmt"
 | 
				
			||||||
	"time"
 | 
						"time"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
@@ -116,3 +117,33 @@ func CRDRemoveFinalizer(crd *CustomResourceDefinition, needle string) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	crd.Finalizers = newFinalizers
 | 
						crd.Finalizers = newFinalizers
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// HasServedCRDVersion returns true if `version` is in the list of CRD's versions and the Served flag is set.
 | 
				
			||||||
 | 
					func HasServedCRDVersion(crd *CustomResourceDefinition, version string) bool {
 | 
				
			||||||
 | 
						for _, v := range crd.Spec.Versions {
 | 
				
			||||||
 | 
							if v.Name == version {
 | 
				
			||||||
 | 
								return v.Served
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// GetCRDStorageVersion returns the storage version for given CRD.
 | 
				
			||||||
 | 
					func GetCRDStorageVersion(crd *CustomResourceDefinition) (string, error) {
 | 
				
			||||||
 | 
						for _, v := range crd.Spec.Versions {
 | 
				
			||||||
 | 
							if v.Storage {
 | 
				
			||||||
 | 
								return v.Name, nil
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// This should not happened if crd is valid
 | 
				
			||||||
 | 
						return "", fmt.Errorf("invalid CustomResourceDefinition, no storage version")
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func IsStoredVersion(crd *CustomResourceDefinition, version string) bool {
 | 
				
			||||||
 | 
						for _, v := range crd.Status.StoredVersions {
 | 
				
			||||||
 | 
							if version == v {
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -31,6 +31,14 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
func SetDefaults_CustomResourceDefinition(obj *CustomResourceDefinition) {
 | 
					func SetDefaults_CustomResourceDefinition(obj *CustomResourceDefinition) {
 | 
				
			||||||
	SetDefaults_CustomResourceDefinitionSpec(&obj.Spec)
 | 
						SetDefaults_CustomResourceDefinitionSpec(&obj.Spec)
 | 
				
			||||||
 | 
						if len(obj.Status.StoredVersions) == 0 {
 | 
				
			||||||
 | 
							for _, v := range obj.Spec.Versions {
 | 
				
			||||||
 | 
								if v.Storage {
 | 
				
			||||||
 | 
									obj.Status.StoredVersions = append(obj.Status.StoredVersions, v.Name)
 | 
				
			||||||
 | 
									break
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func SetDefaults_CustomResourceDefinitionSpec(obj *CustomResourceDefinitionSpec) {
 | 
					func SetDefaults_CustomResourceDefinitionSpec(obj *CustomResourceDefinitionSpec) {
 | 
				
			||||||
@@ -43,4 +51,16 @@ func SetDefaults_CustomResourceDefinitionSpec(obj *CustomResourceDefinitionSpec)
 | 
				
			|||||||
	if len(obj.Names.ListKind) == 0 && len(obj.Names.Kind) > 0 {
 | 
						if len(obj.Names.ListKind) == 0 && len(obj.Names.Kind) > 0 {
 | 
				
			||||||
		obj.Names.ListKind = obj.Names.Kind + "List"
 | 
							obj.Names.ListKind = obj.Names.Kind + "List"
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						// If there is no list of versions, create on using deprecated Version field.
 | 
				
			||||||
 | 
						if len(obj.Versions) == 0 && len(obj.Version) != 0 {
 | 
				
			||||||
 | 
							obj.Versions = []CustomResourceDefinitionVersion{{
 | 
				
			||||||
 | 
								Name:    obj.Version,
 | 
				
			||||||
 | 
								Storage: true,
 | 
				
			||||||
 | 
								Served:  true,
 | 
				
			||||||
 | 
							}}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						// For backward compatibility set the version field to the first item in versions list.
 | 
				
			||||||
 | 
						if len(obj.Version) == 0 && len(obj.Versions) != 0 {
 | 
				
			||||||
 | 
							obj.Version = obj.Versions[0].Name
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -45,6 +45,7 @@ func ValidateCustomResourceDefinition(obj *apiextensions.CustomResourceDefinitio
 | 
				
			|||||||
	allErrs := genericvalidation.ValidateObjectMeta(&obj.ObjectMeta, false, nameValidationFn, field.NewPath("metadata"))
 | 
						allErrs := genericvalidation.ValidateObjectMeta(&obj.ObjectMeta, false, nameValidationFn, field.NewPath("metadata"))
 | 
				
			||||||
	allErrs = append(allErrs, ValidateCustomResourceDefinitionSpec(&obj.Spec, field.NewPath("spec"))...)
 | 
						allErrs = append(allErrs, ValidateCustomResourceDefinitionSpec(&obj.Spec, field.NewPath("spec"))...)
 | 
				
			||||||
	allErrs = append(allErrs, ValidateCustomResourceDefinitionStatus(&obj.Status, field.NewPath("status"))...)
 | 
						allErrs = append(allErrs, ValidateCustomResourceDefinitionStatus(&obj.Status, field.NewPath("status"))...)
 | 
				
			||||||
 | 
						allErrs = append(allErrs, ValidateCustomResourceDefinitionStoredVersions(obj.Status.StoredVersions, obj.Spec.Versions, field.NewPath("status").Child("storedVersions"))...)
 | 
				
			||||||
	return allErrs
 | 
						return allErrs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -53,6 +54,34 @@ func ValidateCustomResourceDefinitionUpdate(obj, oldObj *apiextensions.CustomRes
 | 
				
			|||||||
	allErrs := genericvalidation.ValidateObjectMetaUpdate(&obj.ObjectMeta, &oldObj.ObjectMeta, field.NewPath("metadata"))
 | 
						allErrs := genericvalidation.ValidateObjectMetaUpdate(&obj.ObjectMeta, &oldObj.ObjectMeta, field.NewPath("metadata"))
 | 
				
			||||||
	allErrs = append(allErrs, ValidateCustomResourceDefinitionSpecUpdate(&obj.Spec, &oldObj.Spec, apiextensions.IsCRDConditionTrue(oldObj, apiextensions.Established), field.NewPath("spec"))...)
 | 
						allErrs = append(allErrs, ValidateCustomResourceDefinitionSpecUpdate(&obj.Spec, &oldObj.Spec, apiextensions.IsCRDConditionTrue(oldObj, apiextensions.Established), field.NewPath("spec"))...)
 | 
				
			||||||
	allErrs = append(allErrs, ValidateCustomResourceDefinitionStatus(&obj.Status, field.NewPath("status"))...)
 | 
						allErrs = append(allErrs, ValidateCustomResourceDefinitionStatus(&obj.Status, field.NewPath("status"))...)
 | 
				
			||||||
 | 
						allErrs = append(allErrs, ValidateCustomResourceDefinitionStoredVersions(obj.Status.StoredVersions, obj.Spec.Versions, field.NewPath("status").Child("storedVersions"))...)
 | 
				
			||||||
 | 
						return allErrs
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// ValidateCustomResourceDefinitionStoredVersions statically validates
 | 
				
			||||||
 | 
					func ValidateCustomResourceDefinitionStoredVersions(storedVersions []string, versions []apiextensions.CustomResourceDefinitionVersion, fldPath *field.Path) field.ErrorList {
 | 
				
			||||||
 | 
						if len(storedVersions) == 0 {
 | 
				
			||||||
 | 
							return field.ErrorList{field.Invalid(fldPath, storedVersions, "must have at least one stored version")}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						allErrs := field.ErrorList{}
 | 
				
			||||||
 | 
						storedVersionsMap := map[string]int{}
 | 
				
			||||||
 | 
						for i, v := range storedVersions {
 | 
				
			||||||
 | 
							storedVersionsMap[v] = i
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, v := range versions {
 | 
				
			||||||
 | 
							_, ok := storedVersionsMap[v.Name]
 | 
				
			||||||
 | 
							if v.Storage && !ok {
 | 
				
			||||||
 | 
								allErrs = append(allErrs, field.Invalid(fldPath, v, "must have the storage version "+v.Name))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if ok {
 | 
				
			||||||
 | 
								delete(storedVersionsMap, v.Name)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for v, i := range storedVersionsMap {
 | 
				
			||||||
 | 
							allErrs = append(allErrs, field.Invalid(fldPath.Index(i), v, "must appear in spec.versions"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return allErrs
 | 
						return allErrs
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -75,12 +104,6 @@ func ValidateCustomResourceDefinitionSpec(spec *apiextensions.CustomResourceDefi
 | 
				
			|||||||
		allErrs = append(allErrs, field.Invalid(fldPath.Child("group"), spec.Group, "should be a domain with at least one dot"))
 | 
							allErrs = append(allErrs, field.Invalid(fldPath.Child("group"), spec.Group, "should be a domain with at least one dot"))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(spec.Version) == 0 {
 | 
					 | 
				
			||||||
		allErrs = append(allErrs, field.Required(fldPath.Child("version"), ""))
 | 
					 | 
				
			||||||
	} else if errs := validationutil.IsDNS1035Label(spec.Version); len(errs) > 0 {
 | 
					 | 
				
			||||||
		allErrs = append(allErrs, field.Invalid(fldPath.Child("version"), spec.Version, strings.Join(errs, ",")))
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	switch spec.Scope {
 | 
						switch spec.Scope {
 | 
				
			||||||
	case "":
 | 
						case "":
 | 
				
			||||||
		allErrs = append(allErrs, field.Required(fldPath.Child("scope"), ""))
 | 
							allErrs = append(allErrs, field.Required(fldPath.Child("scope"), ""))
 | 
				
			||||||
@@ -89,6 +112,37 @@ func ValidateCustomResourceDefinitionSpec(spec *apiextensions.CustomResourceDefi
 | 
				
			|||||||
		allErrs = append(allErrs, field.NotSupported(fldPath.Child("scope"), spec.Scope, []string{string(apiextensions.ClusterScoped), string(apiextensions.NamespaceScoped)}))
 | 
							allErrs = append(allErrs, field.NotSupported(fldPath.Child("scope"), spec.Scope, []string{string(apiextensions.ClusterScoped), string(apiextensions.NamespaceScoped)}))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						storageFlagCount := 0
 | 
				
			||||||
 | 
						versionsMap := map[string]bool{}
 | 
				
			||||||
 | 
						uniqueNames := true
 | 
				
			||||||
 | 
						for i, version := range spec.Versions {
 | 
				
			||||||
 | 
							if version.Storage {
 | 
				
			||||||
 | 
								storageFlagCount++
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if versionsMap[version.Name] {
 | 
				
			||||||
 | 
								uniqueNames = false
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								versionsMap[version.Name] = true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if errs := validationutil.IsDNS1035Label(version.Name); len(errs) > 0 {
 | 
				
			||||||
 | 
								allErrs = append(allErrs, field.Invalid(fldPath.Child("versions").Index(i).Child("name"), spec.Versions[i].Name, strings.Join(errs, ",")))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !uniqueNames {
 | 
				
			||||||
 | 
							allErrs = append(allErrs, field.Invalid(fldPath.Child("versions"), spec.Versions, "must contain unique version names"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if storageFlagCount != 1 {
 | 
				
			||||||
 | 
							allErrs = append(allErrs, field.Invalid(fldPath.Child("versions"), spec.Versions, "must have exactly one version marked as storage version"))
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if len(spec.Version) != 0 {
 | 
				
			||||||
 | 
							if errs := validationutil.IsDNS1035Label(spec.Version); len(errs) > 0 {
 | 
				
			||||||
 | 
								allErrs = append(allErrs, field.Invalid(fldPath.Child("version"), spec.Version, strings.Join(errs, ",")))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if len(spec.Versions) >= 1 && spec.Versions[0].Name != spec.Version {
 | 
				
			||||||
 | 
								allErrs = append(allErrs, field.Invalid(fldPath.Child("version"), spec.Version, "must match the first version in spec.versions"))
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// in addition to the basic name restrictions, some names are required for spec, but not for status
 | 
						// in addition to the basic name restrictions, some names are required for spec, but not for status
 | 
				
			||||||
	if len(spec.Names.Plural) == 0 {
 | 
						if len(spec.Names.Plural) == 0 {
 | 
				
			||||||
		allErrs = append(allErrs, field.Required(fldPath.Child("names", "plural"), ""))
 | 
							allErrs = append(allErrs, field.Required(fldPath.Child("names", "plural"), ""))
 | 
				
			||||||
@@ -130,7 +184,6 @@ func ValidateCustomResourceDefinitionSpecUpdate(spec, oldSpec *apiextensions.Cus
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if established {
 | 
						if established {
 | 
				
			||||||
		// these effect the storage and cannot be changed therefore
 | 
							// these effect the storage and cannot be changed therefore
 | 
				
			||||||
		allErrs = append(allErrs, genericvalidation.ValidateImmutableField(spec.Version, oldSpec.Version, fldPath.Child("version"))...)
 | 
					 | 
				
			||||||
		allErrs = append(allErrs, genericvalidation.ValidateImmutableField(spec.Scope, oldSpec.Scope, fldPath.Child("scope"))...)
 | 
							allErrs = append(allErrs, genericvalidation.ValidateImmutableField(spec.Scope, oldSpec.Scope, fldPath.Child("scope"))...)
 | 
				
			||||||
		allErrs = append(allErrs, genericvalidation.ValidateImmutableField(spec.Names.Kind, oldSpec.Names.Kind, fldPath.Child("names", "kind"))...)
 | 
							allErrs = append(allErrs, genericvalidation.ValidateImmutableField(spec.Names.Kind, oldSpec.Names.Kind, fldPath.Child("names", "kind"))...)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -19,10 +19,9 @@ package validation
 | 
				
			|||||||
import (
 | 
					import (
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
 | 
				
			||||||
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
						metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 | 
				
			||||||
	"k8s.io/apimachinery/pkg/util/validation/field"
 | 
						"k8s.io/apimachinery/pkg/util/validation/field"
 | 
				
			||||||
 | 
					 | 
				
			||||||
	"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
 | 
					 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type validationMatch struct {
 | 
					type validationMatch struct {
 | 
				
			||||||
@@ -51,11 +50,150 @@ func (v validationMatch) matches(err *field.Error) bool {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestValidateCustomResourceDefinition(t *testing.T) {
 | 
					func TestValidateCustomResourceDefinition(t *testing.T) {
 | 
				
			||||||
 | 
						singleVersionList := []apiextensions.CustomResourceDefinitionVersion{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								Name:    "version",
 | 
				
			||||||
 | 
								Served:  true,
 | 
				
			||||||
 | 
								Storage: true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	tests := []struct {
 | 
						tests := []struct {
 | 
				
			||||||
		name     string
 | 
							name     string
 | 
				
			||||||
		resource *apiextensions.CustomResourceDefinition
 | 
							resource *apiextensions.CustomResourceDefinition
 | 
				
			||||||
		errors   []validationMatch
 | 
							errors   []validationMatch
 | 
				
			||||||
	}{
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "no_storage_version",
 | 
				
			||||||
 | 
								resource: &apiextensions.CustomResourceDefinition{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"},
 | 
				
			||||||
 | 
									Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
				
			||||||
 | 
										Group: "group.com",
 | 
				
			||||||
 | 
										Scope: apiextensions.ResourceScope("Cluster"),
 | 
				
			||||||
 | 
										Names: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
 | 
											Plural:   "plural",
 | 
				
			||||||
 | 
											Singular: "singular",
 | 
				
			||||||
 | 
											Kind:     "Plural",
 | 
				
			||||||
 | 
											ListKind: "PluralList",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Versions: []apiextensions.CustomResourceDefinitionVersion{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "version",
 | 
				
			||||||
 | 
												Served:  true,
 | 
				
			||||||
 | 
												Storage: false,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "version2",
 | 
				
			||||||
 | 
												Served:  true,
 | 
				
			||||||
 | 
												Storage: false,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Status: apiextensions.CustomResourceDefinitionStatus{
 | 
				
			||||||
 | 
										StoredVersions: []string{"version"},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								errors: []validationMatch{
 | 
				
			||||||
 | 
									invalid("spec", "versions"),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "multiple_storage_version",
 | 
				
			||||||
 | 
								resource: &apiextensions.CustomResourceDefinition{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"},
 | 
				
			||||||
 | 
									Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
				
			||||||
 | 
										Group: "group.com",
 | 
				
			||||||
 | 
										Scope: apiextensions.ResourceScope("Cluster"),
 | 
				
			||||||
 | 
										Names: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
 | 
											Plural:   "plural",
 | 
				
			||||||
 | 
											Singular: "singular",
 | 
				
			||||||
 | 
											Kind:     "Plural",
 | 
				
			||||||
 | 
											ListKind: "PluralList",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Versions: []apiextensions.CustomResourceDefinitionVersion{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "version",
 | 
				
			||||||
 | 
												Served:  true,
 | 
				
			||||||
 | 
												Storage: true,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "version2",
 | 
				
			||||||
 | 
												Served:  true,
 | 
				
			||||||
 | 
												Storage: true,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Status: apiextensions.CustomResourceDefinitionStatus{
 | 
				
			||||||
 | 
										StoredVersions: []string{"version"},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								errors: []validationMatch{
 | 
				
			||||||
 | 
									invalid("spec", "versions"),
 | 
				
			||||||
 | 
									invalid("status", "storedVersions"),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "missing_storage_version_in_stored_versions",
 | 
				
			||||||
 | 
								resource: &apiextensions.CustomResourceDefinition{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"},
 | 
				
			||||||
 | 
									Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
				
			||||||
 | 
										Group: "group.com",
 | 
				
			||||||
 | 
										Scope: apiextensions.ResourceScope("Cluster"),
 | 
				
			||||||
 | 
										Names: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
 | 
											Plural:   "plural",
 | 
				
			||||||
 | 
											Singular: "singular",
 | 
				
			||||||
 | 
											Kind:     "Plural",
 | 
				
			||||||
 | 
											ListKind: "PluralList",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Versions: []apiextensions.CustomResourceDefinitionVersion{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "version",
 | 
				
			||||||
 | 
												Served:  true,
 | 
				
			||||||
 | 
												Storage: false,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "version2",
 | 
				
			||||||
 | 
												Served:  true,
 | 
				
			||||||
 | 
												Storage: true,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Status: apiextensions.CustomResourceDefinitionStatus{
 | 
				
			||||||
 | 
										StoredVersions: []string{"version"},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								errors: []validationMatch{
 | 
				
			||||||
 | 
									invalid("status", "storedVersions"),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "empty_stored_version",
 | 
				
			||||||
 | 
								resource: &apiextensions.CustomResourceDefinition{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"},
 | 
				
			||||||
 | 
									Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
				
			||||||
 | 
										Group: "group.com",
 | 
				
			||||||
 | 
										Scope: apiextensions.ResourceScope("Cluster"),
 | 
				
			||||||
 | 
										Names: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
 | 
											Plural:   "plural",
 | 
				
			||||||
 | 
											Singular: "singular",
 | 
				
			||||||
 | 
											Kind:     "Plural",
 | 
				
			||||||
 | 
											ListKind: "PluralList",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Versions: []apiextensions.CustomResourceDefinitionVersion{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "version",
 | 
				
			||||||
 | 
												Served:  true,
 | 
				
			||||||
 | 
												Storage: true,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Status: apiextensions.CustomResourceDefinitionStatus{
 | 
				
			||||||
 | 
										StoredVersions: []string{},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								errors: []validationMatch{
 | 
				
			||||||
 | 
									invalid("status", "storedVersions"),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name: "mismatched name",
 | 
								name: "mismatched name",
 | 
				
			||||||
			resource: &apiextensions.CustomResourceDefinition{
 | 
								resource: &apiextensions.CustomResourceDefinition{
 | 
				
			||||||
@@ -68,8 +206,9 @@ func TestValidateCustomResourceDefinition(t *testing.T) {
 | 
				
			|||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			errors: []validationMatch{
 | 
								errors: []validationMatch{
 | 
				
			||||||
 | 
									invalid("status", "storedVersions"),
 | 
				
			||||||
				invalid("metadata", "name"),
 | 
									invalid("metadata", "name"),
 | 
				
			||||||
				required("spec", "version"),
 | 
									invalid("spec", "versions"),
 | 
				
			||||||
				required("spec", "scope"),
 | 
									required("spec", "scope"),
 | 
				
			||||||
				required("spec", "names", "singular"),
 | 
									required("spec", "names", "singular"),
 | 
				
			||||||
				required("spec", "names", "kind"),
 | 
									required("spec", "names", "kind"),
 | 
				
			||||||
@@ -82,9 +221,10 @@ func TestValidateCustomResourceDefinition(t *testing.T) {
 | 
				
			|||||||
				ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"},
 | 
									ObjectMeta: metav1.ObjectMeta{Name: "plural.group.com"},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			errors: []validationMatch{
 | 
								errors: []validationMatch{
 | 
				
			||||||
 | 
									invalid("status", "storedVersions"),
 | 
				
			||||||
				invalid("metadata", "name"),
 | 
									invalid("metadata", "name"),
 | 
				
			||||||
 | 
									invalid("spec", "versions"),
 | 
				
			||||||
				required("spec", "group"),
 | 
									required("spec", "group"),
 | 
				
			||||||
				required("spec", "version"),
 | 
					 | 
				
			||||||
				required("spec", "scope"),
 | 
									required("spec", "scope"),
 | 
				
			||||||
				required("spec", "names", "plural"),
 | 
									required("spec", "names", "plural"),
 | 
				
			||||||
				required("spec", "names", "singular"),
 | 
									required("spec", "names", "singular"),
 | 
				
			||||||
@@ -117,9 +257,9 @@ func TestValidateCustomResourceDefinition(t *testing.T) {
 | 
				
			|||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			errors: []validationMatch{
 | 
								errors: []validationMatch{
 | 
				
			||||||
 | 
									invalid("status", "storedVersions"),
 | 
				
			||||||
				invalid("metadata", "name"),
 | 
									invalid("metadata", "name"),
 | 
				
			||||||
				invalid("spec", "group"),
 | 
									invalid("spec", "group"),
 | 
				
			||||||
				invalid("spec", "version"),
 | 
					 | 
				
			||||||
				unsupported("spec", "scope"),
 | 
									unsupported("spec", "scope"),
 | 
				
			||||||
				invalid("spec", "names", "plural"),
 | 
									invalid("spec", "names", "plural"),
 | 
				
			||||||
				invalid("spec", "names", "singular"),
 | 
									invalid("spec", "names", "singular"),
 | 
				
			||||||
@@ -131,6 +271,8 @@ func TestValidateCustomResourceDefinition(t *testing.T) {
 | 
				
			|||||||
				invalid("status", "acceptedNames", "kind"),
 | 
									invalid("status", "acceptedNames", "kind"),
 | 
				
			||||||
				invalid("status", "acceptedNames", "listKind"), // invalid format
 | 
									invalid("status", "acceptedNames", "listKind"), // invalid format
 | 
				
			||||||
				invalid("status", "acceptedNames", "listKind"), // kind == listKind
 | 
									invalid("status", "acceptedNames", "listKind"), // kind == listKind
 | 
				
			||||||
 | 
									invalid("spec", "versions"),
 | 
				
			||||||
 | 
									invalid("spec", "version"),
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@@ -140,6 +282,7 @@ func TestValidateCustomResourceDefinition(t *testing.T) {
 | 
				
			|||||||
				Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
									Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
				
			||||||
					Group:    "group.c(*&om",
 | 
										Group:    "group.c(*&om",
 | 
				
			||||||
					Version:  "version",
 | 
										Version:  "version",
 | 
				
			||||||
 | 
										Versions: singleVersionList,
 | 
				
			||||||
					Names: apiextensions.CustomResourceDefinitionNames{
 | 
										Names: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
						Plural:   "plural",
 | 
											Plural:   "plural",
 | 
				
			||||||
						Singular: "singular",
 | 
											Singular: "singular",
 | 
				
			||||||
@@ -154,6 +297,7 @@ func TestValidateCustomResourceDefinition(t *testing.T) {
 | 
				
			|||||||
						Kind:     "matching",
 | 
											Kind:     "matching",
 | 
				
			||||||
						ListKind: "matching",
 | 
											ListKind: "matching",
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
 | 
										StoredVersions: []string{"version"},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			errors: []validationMatch{
 | 
								errors: []validationMatch{
 | 
				
			||||||
@@ -171,6 +315,7 @@ func TestValidateCustomResourceDefinition(t *testing.T) {
 | 
				
			|||||||
				Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
									Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
				
			||||||
					Group:    "group.com",
 | 
										Group:    "group.com",
 | 
				
			||||||
					Version:  "version",
 | 
										Version:  "version",
 | 
				
			||||||
 | 
										Versions: singleVersionList,
 | 
				
			||||||
					Scope:    apiextensions.NamespaceScoped,
 | 
										Scope:    apiextensions.NamespaceScoped,
 | 
				
			||||||
					Names: apiextensions.CustomResourceDefinitionNames{
 | 
										Names: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
						Plural:   "plural",
 | 
											Plural:   "plural",
 | 
				
			||||||
@@ -187,6 +332,9 @@ func TestValidateCustomResourceDefinition(t *testing.T) {
 | 
				
			|||||||
						},
 | 
											},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
 | 
									Status: apiextensions.CustomResourceDefinitionStatus{
 | 
				
			||||||
 | 
										StoredVersions: []string{"version"},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			errors: []validationMatch{
 | 
								errors: []validationMatch{
 | 
				
			||||||
				forbidden("spec", "validation", "openAPIV3Schema", "additionalProperties"),
 | 
									forbidden("spec", "validation", "openAPIV3Schema", "additionalProperties"),
 | 
				
			||||||
@@ -199,6 +347,7 @@ func TestValidateCustomResourceDefinition(t *testing.T) {
 | 
				
			|||||||
				Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
									Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
				
			||||||
					Group:    "group.com",
 | 
										Group:    "group.com",
 | 
				
			||||||
					Version:  "version",
 | 
										Version:  "version",
 | 
				
			||||||
 | 
										Versions: singleVersionList,
 | 
				
			||||||
					Scope:    apiextensions.NamespaceScoped,
 | 
										Scope:    apiextensions.NamespaceScoped,
 | 
				
			||||||
					Names: apiextensions.CustomResourceDefinitionNames{
 | 
										Names: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
						Plural:   "plural",
 | 
											Plural:   "plural",
 | 
				
			||||||
@@ -217,6 +366,9 @@ func TestValidateCustomResourceDefinition(t *testing.T) {
 | 
				
			|||||||
						},
 | 
											},
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
 | 
									Status: apiextensions.CustomResourceDefinitionStatus{
 | 
				
			||||||
 | 
										StoredVersions: []string{"version"},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			errors: []validationMatch{},
 | 
								errors: []validationMatch{},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
@@ -266,6 +418,13 @@ func TestValidateCustomResourceDefinitionUpdate(t *testing.T) {
 | 
				
			|||||||
				Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
									Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
				
			||||||
					Group:   "group.com",
 | 
										Group:   "group.com",
 | 
				
			||||||
					Version: "version",
 | 
										Version: "version",
 | 
				
			||||||
 | 
										Versions: []apiextensions.CustomResourceDefinitionVersion{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "version",
 | 
				
			||||||
 | 
												Served:  true,
 | 
				
			||||||
 | 
												Storage: true,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
					Scope: apiextensions.ResourceScope("Cluster"),
 | 
										Scope: apiextensions.ResourceScope("Cluster"),
 | 
				
			||||||
					Names: apiextensions.CustomResourceDefinitionNames{
 | 
										Names: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
						Plural:   "plural",
 | 
											Plural:   "plural",
 | 
				
			||||||
@@ -291,6 +450,13 @@ func TestValidateCustomResourceDefinitionUpdate(t *testing.T) {
 | 
				
			|||||||
				Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
									Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
				
			||||||
					Group:   "group.com",
 | 
										Group:   "group.com",
 | 
				
			||||||
					Version: "version",
 | 
										Version: "version",
 | 
				
			||||||
 | 
										Versions: []apiextensions.CustomResourceDefinitionVersion{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "version",
 | 
				
			||||||
 | 
												Served:  true,
 | 
				
			||||||
 | 
												Storage: true,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
					Scope: apiextensions.ResourceScope("Cluster"),
 | 
										Scope: apiextensions.ResourceScope("Cluster"),
 | 
				
			||||||
					Names: apiextensions.CustomResourceDefinitionNames{
 | 
										Names: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
						Plural:   "plural",
 | 
											Plural:   "plural",
 | 
				
			||||||
@@ -306,6 +472,7 @@ func TestValidateCustomResourceDefinitionUpdate(t *testing.T) {
 | 
				
			|||||||
						Kind:     "kind",
 | 
											Kind:     "kind",
 | 
				
			||||||
						ListKind: "listkind",
 | 
											ListKind: "listkind",
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
 | 
										StoredVersions: []string{"version"},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			errors: []validationMatch{},
 | 
								errors: []validationMatch{},
 | 
				
			||||||
@@ -320,6 +487,13 @@ func TestValidateCustomResourceDefinitionUpdate(t *testing.T) {
 | 
				
			|||||||
				Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
									Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
				
			||||||
					Group:   "group.com",
 | 
										Group:   "group.com",
 | 
				
			||||||
					Version: "version",
 | 
										Version: "version",
 | 
				
			||||||
 | 
										Versions: []apiextensions.CustomResourceDefinitionVersion{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "version",
 | 
				
			||||||
 | 
												Served:  true,
 | 
				
			||||||
 | 
												Storage: true,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
					Scope: apiextensions.ResourceScope("Cluster"),
 | 
										Scope: apiextensions.ResourceScope("Cluster"),
 | 
				
			||||||
					Names: apiextensions.CustomResourceDefinitionNames{
 | 
										Names: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
						Plural:   "plural",
 | 
											Plural:   "plural",
 | 
				
			||||||
@@ -348,6 +522,13 @@ func TestValidateCustomResourceDefinitionUpdate(t *testing.T) {
 | 
				
			|||||||
				Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
									Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
				
			||||||
					Group:   "group.com",
 | 
										Group:   "group.com",
 | 
				
			||||||
					Version: "version",
 | 
										Version: "version",
 | 
				
			||||||
 | 
										Versions: []apiextensions.CustomResourceDefinitionVersion{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "version",
 | 
				
			||||||
 | 
												Served:  true,
 | 
				
			||||||
 | 
												Storage: true,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
					Scope: apiextensions.ResourceScope("Cluster"),
 | 
										Scope: apiextensions.ResourceScope("Cluster"),
 | 
				
			||||||
					Names: apiextensions.CustomResourceDefinitionNames{
 | 
										Names: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
						Plural:   "plural",
 | 
											Plural:   "plural",
 | 
				
			||||||
@@ -363,10 +544,91 @@ func TestValidateCustomResourceDefinitionUpdate(t *testing.T) {
 | 
				
			|||||||
						Kind:     "kind",
 | 
											Kind:     "kind",
 | 
				
			||||||
						ListKind: "listkind",
 | 
											ListKind: "listkind",
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
 | 
										StoredVersions: []string{"version"},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			errors: []validationMatch{},
 | 
								errors: []validationMatch{},
 | 
				
			||||||
		},
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								name: "version-deleted",
 | 
				
			||||||
 | 
								old: &apiextensions.CustomResourceDefinition{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
										Name:            "plural.group.com",
 | 
				
			||||||
 | 
										ResourceVersion: "42",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
				
			||||||
 | 
										Group:   "group.com",
 | 
				
			||||||
 | 
										Version: "version",
 | 
				
			||||||
 | 
										Versions: []apiextensions.CustomResourceDefinitionVersion{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "version",
 | 
				
			||||||
 | 
												Served:  true,
 | 
				
			||||||
 | 
												Storage: true,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "version2",
 | 
				
			||||||
 | 
												Served:  true,
 | 
				
			||||||
 | 
												Storage: false,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Scope: apiextensions.ResourceScope("Cluster"),
 | 
				
			||||||
 | 
										Names: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
 | 
											Plural:   "plural",
 | 
				
			||||||
 | 
											Singular: "singular",
 | 
				
			||||||
 | 
											Kind:     "kind",
 | 
				
			||||||
 | 
											ListKind: "listkind",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Status: apiextensions.CustomResourceDefinitionStatus{
 | 
				
			||||||
 | 
										AcceptedNames: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
 | 
											Plural:   "plural",
 | 
				
			||||||
 | 
											Singular: "singular",
 | 
				
			||||||
 | 
											Kind:     "kind",
 | 
				
			||||||
 | 
											ListKind: "listkind",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										StoredVersions: []string{"version", "version2"},
 | 
				
			||||||
 | 
										Conditions: []apiextensions.CustomResourceDefinitionCondition{
 | 
				
			||||||
 | 
											{Type: apiextensions.Established, Status: apiextensions.ConditionTrue},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								resource: &apiextensions.CustomResourceDefinition{
 | 
				
			||||||
 | 
									ObjectMeta: metav1.ObjectMeta{
 | 
				
			||||||
 | 
										Name:            "plural.group.com",
 | 
				
			||||||
 | 
										ResourceVersion: "42",
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
				
			||||||
 | 
										Group:   "group.com",
 | 
				
			||||||
 | 
										Version: "version",
 | 
				
			||||||
 | 
										Versions: []apiextensions.CustomResourceDefinitionVersion{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "version",
 | 
				
			||||||
 | 
												Served:  true,
 | 
				
			||||||
 | 
												Storage: true,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										Scope: apiextensions.ResourceScope("Cluster"),
 | 
				
			||||||
 | 
										Names: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
 | 
											Plural:   "plural",
 | 
				
			||||||
 | 
											Singular: "singular",
 | 
				
			||||||
 | 
											Kind:     "kind",
 | 
				
			||||||
 | 
											ListKind: "listkind",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Status: apiextensions.CustomResourceDefinitionStatus{
 | 
				
			||||||
 | 
										AcceptedNames: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
 | 
											Plural:   "plural",
 | 
				
			||||||
 | 
											Singular: "singular",
 | 
				
			||||||
 | 
											Kind:     "kind",
 | 
				
			||||||
 | 
											ListKind: "listkind",
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
 | 
										StoredVersions: []string{"version", "version2"},
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
								errors: []validationMatch{
 | 
				
			||||||
 | 
									invalid("status", "storedVersions[1]"),
 | 
				
			||||||
 | 
								},
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			name: "changes",
 | 
								name: "changes",
 | 
				
			||||||
			old: &apiextensions.CustomResourceDefinition{
 | 
								old: &apiextensions.CustomResourceDefinition{
 | 
				
			||||||
@@ -377,6 +639,13 @@ func TestValidateCustomResourceDefinitionUpdate(t *testing.T) {
 | 
				
			|||||||
				Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
									Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
				
			||||||
					Group:   "group.com",
 | 
										Group:   "group.com",
 | 
				
			||||||
					Version: "version",
 | 
										Version: "version",
 | 
				
			||||||
 | 
										Versions: []apiextensions.CustomResourceDefinitionVersion{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "version",
 | 
				
			||||||
 | 
												Served:  true,
 | 
				
			||||||
 | 
												Storage: true,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
					Scope: apiextensions.ResourceScope("Cluster"),
 | 
										Scope: apiextensions.ResourceScope("Cluster"),
 | 
				
			||||||
					Names: apiextensions.CustomResourceDefinitionNames{
 | 
										Names: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
						Plural:   "plural",
 | 
											Plural:   "plural",
 | 
				
			||||||
@@ -405,6 +674,13 @@ func TestValidateCustomResourceDefinitionUpdate(t *testing.T) {
 | 
				
			|||||||
				Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
									Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
				
			||||||
					Group:   "abc.com",
 | 
										Group:   "abc.com",
 | 
				
			||||||
					Version: "version2",
 | 
										Version: "version2",
 | 
				
			||||||
 | 
										Versions: []apiextensions.CustomResourceDefinitionVersion{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "version2",
 | 
				
			||||||
 | 
												Served:  true,
 | 
				
			||||||
 | 
												Storage: true,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
					Scope: apiextensions.ResourceScope("Namespaced"),
 | 
										Scope: apiextensions.ResourceScope("Namespaced"),
 | 
				
			||||||
					Names: apiextensions.CustomResourceDefinitionNames{
 | 
										Names: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
						Plural:   "plural2",
 | 
											Plural:   "plural2",
 | 
				
			||||||
@@ -420,6 +696,7 @@ func TestValidateCustomResourceDefinitionUpdate(t *testing.T) {
 | 
				
			|||||||
						Kind:     "kind2",
 | 
											Kind:     "kind2",
 | 
				
			||||||
						ListKind: "listkind2",
 | 
											ListKind: "listkind2",
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
 | 
										StoredVersions: []string{"version2"},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			errors: []validationMatch{
 | 
								errors: []validationMatch{
 | 
				
			||||||
@@ -437,6 +714,13 @@ func TestValidateCustomResourceDefinitionUpdate(t *testing.T) {
 | 
				
			|||||||
				Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
									Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
				
			||||||
					Group:   "group.com",
 | 
										Group:   "group.com",
 | 
				
			||||||
					Version: "version",
 | 
										Version: "version",
 | 
				
			||||||
 | 
										Versions: []apiextensions.CustomResourceDefinitionVersion{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "version",
 | 
				
			||||||
 | 
												Served:  true,
 | 
				
			||||||
 | 
												Storage: true,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
					Scope: apiextensions.ResourceScope("Cluster"),
 | 
										Scope: apiextensions.ResourceScope("Cluster"),
 | 
				
			||||||
					Names: apiextensions.CustomResourceDefinitionNames{
 | 
										Names: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
						Plural:   "plural",
 | 
											Plural:   "plural",
 | 
				
			||||||
@@ -465,6 +749,13 @@ func TestValidateCustomResourceDefinitionUpdate(t *testing.T) {
 | 
				
			|||||||
				Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
									Spec: apiextensions.CustomResourceDefinitionSpec{
 | 
				
			||||||
					Group:   "abc.com",
 | 
										Group:   "abc.com",
 | 
				
			||||||
					Version: "version2",
 | 
										Version: "version2",
 | 
				
			||||||
 | 
										Versions: []apiextensions.CustomResourceDefinitionVersion{
 | 
				
			||||||
 | 
											{
 | 
				
			||||||
 | 
												Name:    "version2",
 | 
				
			||||||
 | 
												Served:  true,
 | 
				
			||||||
 | 
												Storage: true,
 | 
				
			||||||
 | 
											},
 | 
				
			||||||
 | 
										},
 | 
				
			||||||
					Scope: apiextensions.ResourceScope("Namespaced"),
 | 
										Scope: apiextensions.ResourceScope("Namespaced"),
 | 
				
			||||||
					Names: apiextensions.CustomResourceDefinitionNames{
 | 
										Names: apiextensions.CustomResourceDefinitionNames{
 | 
				
			||||||
						Plural:   "plural2",
 | 
											Plural:   "plural2",
 | 
				
			||||||
@@ -480,11 +771,11 @@ func TestValidateCustomResourceDefinitionUpdate(t *testing.T) {
 | 
				
			|||||||
						Kind:     "kind2",
 | 
											Kind:     "kind2",
 | 
				
			||||||
						ListKind: "listkind2",
 | 
											ListKind: "listkind2",
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
 | 
										StoredVersions: []string{"version2"},
 | 
				
			||||||
				},
 | 
									},
 | 
				
			||||||
			},
 | 
								},
 | 
				
			||||||
			errors: []validationMatch{
 | 
								errors: []validationMatch{
 | 
				
			||||||
				immutable("spec", "group"),
 | 
									immutable("spec", "group"),
 | 
				
			||||||
				immutable("spec", "version"),
 | 
					 | 
				
			||||||
				immutable("spec", "scope"),
 | 
									immutable("spec", "scope"),
 | 
				
			||||||
				immutable("spec", "names", "kind"),
 | 
									immutable("spec", "names", "kind"),
 | 
				
			||||||
				immutable("spec", "names", "plural"),
 | 
									immutable("spec", "names", "plural"),
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user