mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-17 23:57:49 +00:00
Merge pull request #81965 from roycaihw/crd-feature-gates-to-ga
Bump the CRD feature gates to GA
This commit is contained in:
commit
f3828b776b
@ -575,10 +575,10 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
||||
|
||||
// inherited features from apiextensions-apiserver, relisted here to get a conflict if it is changed
|
||||
// unintentionally on either side:
|
||||
apiextensionsfeatures.CustomResourceValidation: {Default: true, PreRelease: featuregate.Beta},
|
||||
apiextensionsfeatures.CustomResourceSubresources: {Default: true, PreRelease: featuregate.Beta},
|
||||
apiextensionsfeatures.CustomResourceWebhookConversion: {Default: true, PreRelease: featuregate.Beta},
|
||||
apiextensionsfeatures.CustomResourcePublishOpenAPI: {Default: true, PreRelease: featuregate.Beta},
|
||||
apiextensionsfeatures.CustomResourceValidation: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
|
||||
apiextensionsfeatures.CustomResourceSubresources: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
|
||||
apiextensionsfeatures.CustomResourceWebhookConversion: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
|
||||
apiextensionsfeatures.CustomResourcePublishOpenAPI: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
|
||||
apiextensionsfeatures.CustomResourceDefaulting: {Default: true, PreRelease: featuregate.Beta},
|
||||
|
||||
// features that enable backwards compatibility but are scheduled to be removed
|
||||
|
@ -31,12 +31,15 @@ const (
|
||||
// owner: @sttts, @nikhita
|
||||
// alpha: v1.8
|
||||
// beta: v1.9
|
||||
// GA: v1.16
|
||||
//
|
||||
// CustomResourceValidation is a list of validation methods for CustomResources
|
||||
CustomResourceValidation featuregate.Feature = "CustomResourceValidation"
|
||||
|
||||
// owner: @roycaihw, @sttts
|
||||
// alpha: v1.14
|
||||
// beta: v1.15
|
||||
// GA: v1.16
|
||||
//
|
||||
// CustomResourcePublishOpenAPI enables publishing of CRD OpenAPI specs.
|
||||
CustomResourcePublishOpenAPI featuregate.Feature = "CustomResourcePublishOpenAPI"
|
||||
@ -44,12 +47,15 @@ const (
|
||||
// owner: @sttts, @nikhita
|
||||
// alpha: v1.10
|
||||
// beta: v1.11
|
||||
// GA: v1.16
|
||||
//
|
||||
// CustomResourceSubresources defines the subresources for CustomResources
|
||||
CustomResourceSubresources featuregate.Feature = "CustomResourceSubresources"
|
||||
|
||||
// owner: @mbohlool, @roycaihw
|
||||
// alpha: v1.13
|
||||
// beta: v1.15
|
||||
// GA: v1.16
|
||||
//
|
||||
// CustomResourceWebhookConversion defines the webhook conversion for Custom Resources.
|
||||
CustomResourceWebhookConversion featuregate.Feature = "CustomResourceWebhookConversion"
|
||||
@ -69,9 +75,9 @@ func init() {
|
||||
// To add a new feature, define a key for it above and add it here. The features will be
|
||||
// available throughout Kubernetes binaries.
|
||||
var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureSpec{
|
||||
CustomResourceValidation: {Default: true, PreRelease: featuregate.Beta},
|
||||
CustomResourceSubresources: {Default: true, PreRelease: featuregate.Beta},
|
||||
CustomResourceWebhookConversion: {Default: true, PreRelease: featuregate.Beta},
|
||||
CustomResourcePublishOpenAPI: {Default: true, PreRelease: featuregate.Beta},
|
||||
CustomResourceValidation: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
|
||||
CustomResourceSubresources: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
|
||||
CustomResourceWebhookConversion: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
|
||||
CustomResourcePublishOpenAPI: {Default: true, PreRelease: featuregate.GA, LockToDefault: true},
|
||||
CustomResourceDefaulting: {Default: true, PreRelease: featuregate.Beta},
|
||||
}
|
||||
|
@ -55,13 +55,10 @@ go_test(
|
||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions:go_default_library",
|
||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1:go_default_library",
|
||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation:go_default_library",
|
||||
"//staging/src/k8s.io/apiextensions-apiserver/pkg/features:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/runtime/schema:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/diff:go_default_library",
|
||||
"//staging/src/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||
"//staging/src/k8s.io/apiserver/pkg/util/feature:go_default_library",
|
||||
"//staging/src/k8s.io/component-base/featuregate/testing:go_default_library",
|
||||
"//vendor/k8s.io/utils/pointer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -24,456 +24,333 @@ import (
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
|
||||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/validation"
|
||||
apiextensionsfeatures "k8s.io/apiextensions-apiserver/pkg/features"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"k8s.io/apimachinery/pkg/util/diff"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
"k8s.io/utils/pointer"
|
||||
)
|
||||
|
||||
func TestDropDisableFieldsCustomResourceDefinition(t *testing.T) {
|
||||
t.Log("testing unversioned validation..")
|
||||
for _, validationEnabled := range []bool{true, false} {
|
||||
crdWithUnversionedValidation := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd with non-versioned validation
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{
|
||||
Validation: &apiextensions.CustomResourceValidation{
|
||||
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{},
|
||||
},
|
||||
crdWithUnversionedValidation := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd with non-versioned validation
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{
|
||||
Validation: &apiextensions.CustomResourceValidation{
|
||||
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{},
|
||||
},
|
||||
}
|
||||
}
|
||||
crdWithoutUnversionedValidation := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd with non-versioned validation
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{},
|
||||
}
|
||||
}
|
||||
crdInfos := []struct {
|
||||
name string
|
||||
hasCRValidation bool
|
||||
crd func() *apiextensions.CustomResourceDefinition
|
||||
}{
|
||||
{
|
||||
name: "has unversioned validation",
|
||||
hasCRValidation: true,
|
||||
crd: crdWithUnversionedValidation,
|
||||
},
|
||||
{
|
||||
name: "doesn't have unversioned validation",
|
||||
hasCRValidation: false,
|
||||
crd: crdWithoutUnversionedValidation,
|
||||
},
|
||||
{
|
||||
name: "nil",
|
||||
hasCRValidation: false,
|
||||
crd: func() *apiextensions.CustomResourceDefinition { return nil },
|
||||
},
|
||||
}
|
||||
for _, oldCRDInfo := range crdInfos {
|
||||
for _, newCRDInfo := range crdInfos {
|
||||
oldCRDHasValidation, oldCRD := oldCRDInfo.hasCRValidation, oldCRDInfo.crd()
|
||||
newCRDHasValidation, newCRD := newCRDInfo.hasCRValidation, newCRDInfo.crd()
|
||||
if newCRD == nil {
|
||||
continue
|
||||
}
|
||||
t.Run(fmt.Sprintf("validation feature enabled=%v, old CRD %v, new CRD %v", validationEnabled, oldCRDInfo.name, newCRDInfo.name),
|
||||
func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, apiextensionsfeatures.CustomResourceValidation, validationEnabled)()
|
||||
var oldCRDSpec *apiextensions.CustomResourceDefinitionSpec
|
||||
if oldCRD != nil {
|
||||
oldCRDSpec = &oldCRD.Spec
|
||||
}
|
||||
dropDisabledFields(&newCRD.Spec, oldCRDSpec)
|
||||
// old CRD should never be changed
|
||||
if !reflect.DeepEqual(oldCRD, oldCRDInfo.crd()) {
|
||||
t.Errorf("old crd changed: %v", diff.ObjectReflectDiff(oldCRD, oldCRDInfo.crd()))
|
||||
}
|
||||
switch {
|
||||
case validationEnabled || oldCRDHasValidation:
|
||||
if !reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd changed: %v", diff.ObjectReflectDiff(newCRD, newCRDInfo.crd()))
|
||||
}
|
||||
case newCRDHasValidation:
|
||||
if reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd was not changed")
|
||||
}
|
||||
if !reflect.DeepEqual(newCRD, crdWithoutUnversionedValidation()) {
|
||||
t.Errorf("new crd had unversioned validation: %v", diff.ObjectReflectDiff(newCRD, crdWithoutUnversionedValidation()))
|
||||
}
|
||||
default:
|
||||
if !reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd changed: %v", diff.ObjectReflectDiff(newCRD, newCRDInfo.crd()))
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
crdWithoutUnversionedValidation := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd with non-versioned validation
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{},
|
||||
}
|
||||
}
|
||||
crdInfos := []struct {
|
||||
name string
|
||||
crd func() *apiextensions.CustomResourceDefinition
|
||||
}{
|
||||
{
|
||||
name: "has unversioned validation",
|
||||
crd: crdWithUnversionedValidation,
|
||||
},
|
||||
{
|
||||
name: "doesn't have unversioned validation",
|
||||
crd: crdWithoutUnversionedValidation,
|
||||
},
|
||||
{
|
||||
name: "nil",
|
||||
crd: func() *apiextensions.CustomResourceDefinition { return nil },
|
||||
},
|
||||
}
|
||||
for _, oldCRDInfo := range crdInfos {
|
||||
for _, newCRDInfo := range crdInfos {
|
||||
oldCRD := oldCRDInfo.crd()
|
||||
newCRD := newCRDInfo.crd()
|
||||
if newCRD == nil {
|
||||
continue
|
||||
}
|
||||
t.Run(fmt.Sprintf("old CRD %v, new CRD %v", oldCRDInfo.name, newCRDInfo.name),
|
||||
func(t *testing.T) {
|
||||
var oldCRDSpec *apiextensions.CustomResourceDefinitionSpec
|
||||
if oldCRD != nil {
|
||||
oldCRDSpec = &oldCRD.Spec
|
||||
}
|
||||
dropDisabledFields(&newCRD.Spec, oldCRDSpec)
|
||||
// old CRD should never be changed
|
||||
if !reflect.DeepEqual(oldCRD, oldCRDInfo.crd()) {
|
||||
t.Errorf("old crd changed: %v", diff.ObjectReflectDiff(oldCRD, oldCRDInfo.crd()))
|
||||
}
|
||||
if !reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd changed: %v", diff.ObjectReflectDiff(newCRD, newCRDInfo.crd()))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
t.Log("testing unversioned subresources...")
|
||||
for _, validationEnabled := range []bool{true, false} {
|
||||
crdWithUnversionedSubresources := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd with unversioned subresources
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{
|
||||
Subresources: &apiextensions.CustomResourceSubresources{},
|
||||
crdWithUnversionedSubresources := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd with unversioned subresources
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{
|
||||
Subresources: &apiextensions.CustomResourceSubresources{},
|
||||
},
|
||||
}
|
||||
}
|
||||
crdWithoutUnversionedSubresources := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd without unversioned subresources
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{},
|
||||
}
|
||||
}
|
||||
crdInfos = []struct {
|
||||
name string
|
||||
crd func() *apiextensions.CustomResourceDefinition
|
||||
}{
|
||||
{
|
||||
name: "has unversioned subresources",
|
||||
crd: crdWithUnversionedSubresources,
|
||||
},
|
||||
{
|
||||
name: "doesn't have unversioned subresources",
|
||||
crd: crdWithoutUnversionedSubresources,
|
||||
},
|
||||
{
|
||||
name: "nil",
|
||||
crd: func() *apiextensions.CustomResourceDefinition { return nil },
|
||||
},
|
||||
}
|
||||
for _, oldCRDInfo := range crdInfos {
|
||||
for _, newCRDInfo := range crdInfos {
|
||||
oldCRD := oldCRDInfo.crd()
|
||||
newCRD := newCRDInfo.crd()
|
||||
if newCRD == nil {
|
||||
continue
|
||||
}
|
||||
t.Run(fmt.Sprintf("old CRD %v, new CRD %v", oldCRDInfo.name, newCRDInfo.name),
|
||||
func(t *testing.T) {
|
||||
var oldCRDSpec *apiextensions.CustomResourceDefinitionSpec
|
||||
if oldCRD != nil {
|
||||
oldCRDSpec = &oldCRD.Spec
|
||||
}
|
||||
dropDisabledFields(&newCRD.Spec, oldCRDSpec)
|
||||
// old CRD should never be changed
|
||||
if !reflect.DeepEqual(oldCRD, oldCRDInfo.crd()) {
|
||||
t.Errorf("old crd changed: %v", diff.ObjectReflectDiff(oldCRD, oldCRDInfo.crd()))
|
||||
}
|
||||
if !reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd changed: %v", diff.ObjectReflectDiff(newCRD, newCRDInfo.crd()))
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
crdWithoutUnversionedSubresources := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd without unversioned subresources
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{},
|
||||
}
|
||||
}
|
||||
crdInfos := []struct {
|
||||
name string
|
||||
hasCRSubresources bool
|
||||
crd func() *apiextensions.CustomResourceDefinition
|
||||
}{
|
||||
{
|
||||
name: "has unversioned subresources",
|
||||
hasCRSubresources: true,
|
||||
crd: crdWithUnversionedSubresources,
|
||||
},
|
||||
{
|
||||
name: "doesn't have unversioned subresources",
|
||||
hasCRSubresources: false,
|
||||
crd: crdWithoutUnversionedSubresources,
|
||||
},
|
||||
{
|
||||
name: "nil",
|
||||
hasCRSubresources: false,
|
||||
crd: func() *apiextensions.CustomResourceDefinition { return nil },
|
||||
},
|
||||
}
|
||||
for _, oldCRDInfo := range crdInfos {
|
||||
for _, newCRDInfo := range crdInfos {
|
||||
oldCRDHasSubresources, oldCRD := oldCRDInfo.hasCRSubresources, oldCRDInfo.crd()
|
||||
newCRDHasSubresources, newCRD := newCRDInfo.hasCRSubresources, newCRDInfo.crd()
|
||||
if newCRD == nil {
|
||||
continue
|
||||
}
|
||||
t.Run(fmt.Sprintf("subresources feature enabled=%v, old CRD %v, new CRD %v", validationEnabled, oldCRDInfo.name, newCRDInfo.name),
|
||||
func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, apiextensionsfeatures.CustomResourceSubresources, validationEnabled)()
|
||||
var oldCRDSpec *apiextensions.CustomResourceDefinitionSpec
|
||||
if oldCRD != nil {
|
||||
oldCRDSpec = &oldCRD.Spec
|
||||
}
|
||||
dropDisabledFields(&newCRD.Spec, oldCRDSpec)
|
||||
// old CRD should never be changed
|
||||
if !reflect.DeepEqual(oldCRD, oldCRDInfo.crd()) {
|
||||
t.Errorf("old crd changed: %v", diff.ObjectReflectDiff(oldCRD, oldCRDInfo.crd()))
|
||||
}
|
||||
switch {
|
||||
case validationEnabled || oldCRDHasSubresources:
|
||||
if !reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd changed: %v", diff.ObjectReflectDiff(newCRD, newCRDInfo.crd()))
|
||||
}
|
||||
case newCRDHasSubresources:
|
||||
if reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd was not changed")
|
||||
}
|
||||
if !reflect.DeepEqual(newCRD, crdWithoutUnversionedSubresources()) {
|
||||
t.Errorf("new crd had unversioned subresources: %v", diff.ObjectReflectDiff(newCRD, crdWithoutUnversionedSubresources()))
|
||||
}
|
||||
default:
|
||||
if !reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd changed: %v", diff.ObjectReflectDiff(newCRD, newCRDInfo.crd()))
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
t.Log("testing versioned validation..")
|
||||
for _, conversionEnabled := range []bool{true, false} {
|
||||
for _, validationEnabled := range []bool{true, false} {
|
||||
crdWithVersionedValidation := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd with versioned validation
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{
|
||||
Versions: []apiextensions.CustomResourceDefinitionVersion{
|
||||
{
|
||||
Name: "v1",
|
||||
Schema: &apiextensions.CustomResourceValidation{
|
||||
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{},
|
||||
},
|
||||
},
|
||||
crdWithVersionedValidation := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd with versioned validation
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{
|
||||
Versions: []apiextensions.CustomResourceDefinitionVersion{
|
||||
{
|
||||
Name: "v1",
|
||||
Schema: &apiextensions.CustomResourceValidation{
|
||||
OpenAPIV3Schema: &apiextensions.JSONSchemaProps{},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
crdWithoutVersionedValidation := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd with versioned validation
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{
|
||||
Versions: []apiextensions.CustomResourceDefinitionVersion{
|
||||
{
|
||||
Name: "v1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
crdWithoutVersionedValidation := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd with versioned validation
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{
|
||||
Versions: []apiextensions.CustomResourceDefinitionVersion{
|
||||
{
|
||||
Name: "v1",
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
crdInfos = []struct {
|
||||
name string
|
||||
crd func() *apiextensions.CustomResourceDefinition
|
||||
}{
|
||||
{
|
||||
name: "has versioned validation",
|
||||
crd: crdWithVersionedValidation,
|
||||
},
|
||||
{
|
||||
name: "doesn't have versioned validation",
|
||||
crd: crdWithoutVersionedValidation,
|
||||
},
|
||||
{
|
||||
name: "nil",
|
||||
crd: func() *apiextensions.CustomResourceDefinition { return nil },
|
||||
},
|
||||
}
|
||||
for _, oldCRDInfo := range crdInfos {
|
||||
for _, newCRDInfo := range crdInfos {
|
||||
oldCRD := oldCRDInfo.crd()
|
||||
newCRD := newCRDInfo.crd()
|
||||
if newCRD == nil {
|
||||
continue
|
||||
}
|
||||
crdInfos := []struct {
|
||||
name string
|
||||
hasCRValidation bool
|
||||
crd func() *apiextensions.CustomResourceDefinition
|
||||
}{
|
||||
{
|
||||
name: "has versioned validation",
|
||||
hasCRValidation: true,
|
||||
crd: crdWithVersionedValidation,
|
||||
},
|
||||
{
|
||||
name: "doesn't have versioned validation",
|
||||
hasCRValidation: false,
|
||||
crd: crdWithoutVersionedValidation,
|
||||
},
|
||||
{
|
||||
name: "nil",
|
||||
hasCRValidation: false,
|
||||
crd: func() *apiextensions.CustomResourceDefinition { return nil },
|
||||
},
|
||||
}
|
||||
for _, oldCRDInfo := range crdInfos {
|
||||
for _, newCRDInfo := range crdInfos {
|
||||
oldCRDHasValidation, oldCRD := oldCRDInfo.hasCRValidation, oldCRDInfo.crd()
|
||||
newCRDHasValidation, newCRD := newCRDInfo.hasCRValidation, newCRDInfo.crd()
|
||||
if newCRD == nil {
|
||||
continue
|
||||
t.Run(fmt.Sprintf("old CRD %v, new CRD %v", oldCRDInfo.name, newCRDInfo.name),
|
||||
func(t *testing.T) {
|
||||
var oldCRDSpec *apiextensions.CustomResourceDefinitionSpec
|
||||
if oldCRD != nil {
|
||||
oldCRDSpec = &oldCRD.Spec
|
||||
}
|
||||
t.Run(fmt.Sprintf("validation feature enabled=%v, old CRD %v, new CRD %v", validationEnabled, oldCRDInfo.name, newCRDInfo.name),
|
||||
func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, apiextensionsfeatures.CustomResourceValidation, validationEnabled)()
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, apiextensionsfeatures.CustomResourceWebhookConversion, conversionEnabled)()
|
||||
var oldCRDSpec *apiextensions.CustomResourceDefinitionSpec
|
||||
if oldCRD != nil {
|
||||
oldCRDSpec = &oldCRD.Spec
|
||||
}
|
||||
dropDisabledFields(&newCRD.Spec, oldCRDSpec)
|
||||
// old CRD should never be changed
|
||||
if !reflect.DeepEqual(oldCRD, oldCRDInfo.crd()) {
|
||||
t.Errorf("old crd changed: %v", diff.ObjectReflectDiff(oldCRD, oldCRDInfo.crd()))
|
||||
}
|
||||
switch {
|
||||
case (conversionEnabled && validationEnabled) || oldCRDHasValidation:
|
||||
if !reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd changed: %v", diff.ObjectReflectDiff(newCRD, newCRDInfo.crd()))
|
||||
}
|
||||
case !conversionEnabled && !oldCRDHasValidation:
|
||||
if !reflect.DeepEqual(newCRD, crdWithoutVersionedValidation()) {
|
||||
t.Errorf("new crd was not changed")
|
||||
}
|
||||
case newCRDHasValidation:
|
||||
if reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd was not changed")
|
||||
}
|
||||
if !reflect.DeepEqual(newCRD, crdWithoutVersionedValidation()) {
|
||||
t.Errorf("new crd had unversioned validation: %v", diff.ObjectReflectDiff(newCRD, crdWithoutVersionedValidation()))
|
||||
}
|
||||
default:
|
||||
if !reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd changed: %v", diff.ObjectReflectDiff(newCRD, newCRDInfo.crd()))
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
dropDisabledFields(&newCRD.Spec, oldCRDSpec)
|
||||
// old CRD should never be changed
|
||||
if !reflect.DeepEqual(oldCRD, oldCRDInfo.crd()) {
|
||||
t.Errorf("old crd changed: %v", diff.ObjectReflectDiff(oldCRD, oldCRDInfo.crd()))
|
||||
}
|
||||
if !reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd changed: %v", diff.ObjectReflectDiff(newCRD, newCRDInfo.crd()))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
t.Log("testing versioned subresources w/ conversion enabled..")
|
||||
for _, conversionEnabled := range []bool{true, false} {
|
||||
for _, validationEnabled := range []bool{true, false} {
|
||||
crdWithVersionedSubresources := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd with versioned subresources
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{
|
||||
Versions: []apiextensions.CustomResourceDefinitionVersion{
|
||||
{
|
||||
Name: "v1",
|
||||
Subresources: &apiextensions.CustomResourceSubresources{},
|
||||
},
|
||||
},
|
||||
crdWithVersionedSubresources := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd with versioned subresources
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{
|
||||
Versions: []apiextensions.CustomResourceDefinitionVersion{
|
||||
{
|
||||
Name: "v1",
|
||||
Subresources: &apiextensions.CustomResourceSubresources{},
|
||||
},
|
||||
}
|
||||
}
|
||||
crdWithoutVersionedSubresources := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd without versioned subresources
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{
|
||||
Versions: []apiextensions.CustomResourceDefinitionVersion{
|
||||
{
|
||||
Name: "v1",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
crdWithoutVersionedSubresources := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd without versioned subresources
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{
|
||||
Versions: []apiextensions.CustomResourceDefinitionVersion{
|
||||
{
|
||||
Name: "v1",
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
crdInfos = []struct {
|
||||
name string
|
||||
crd func() *apiextensions.CustomResourceDefinition
|
||||
}{
|
||||
{
|
||||
name: "has versioned subresources",
|
||||
crd: crdWithVersionedSubresources,
|
||||
},
|
||||
{
|
||||
name: "doesn't have versioned subresources",
|
||||
crd: crdWithoutVersionedSubresources,
|
||||
},
|
||||
{
|
||||
name: "nil",
|
||||
crd: func() *apiextensions.CustomResourceDefinition { return nil },
|
||||
},
|
||||
}
|
||||
for _, oldCRDInfo := range crdInfos {
|
||||
for _, newCRDInfo := range crdInfos {
|
||||
oldCRD := oldCRDInfo.crd()
|
||||
newCRD := newCRDInfo.crd()
|
||||
if newCRD == nil {
|
||||
continue
|
||||
}
|
||||
crdInfos := []struct {
|
||||
name string
|
||||
hasCRSubresources bool
|
||||
crd func() *apiextensions.CustomResourceDefinition
|
||||
}{
|
||||
{
|
||||
name: "has versioned subresources",
|
||||
hasCRSubresources: true,
|
||||
crd: crdWithVersionedSubresources,
|
||||
},
|
||||
{
|
||||
name: "doesn't have versioned subresources",
|
||||
hasCRSubresources: false,
|
||||
crd: crdWithoutVersionedSubresources,
|
||||
},
|
||||
{
|
||||
name: "nil",
|
||||
hasCRSubresources: false,
|
||||
crd: func() *apiextensions.CustomResourceDefinition { return nil },
|
||||
},
|
||||
}
|
||||
for _, oldCRDInfo := range crdInfos {
|
||||
for _, newCRDInfo := range crdInfos {
|
||||
oldCRDHasSubresources, oldCRD := oldCRDInfo.hasCRSubresources, oldCRDInfo.crd()
|
||||
newCRDHasSubresources, newCRD := newCRDInfo.hasCRSubresources, newCRDInfo.crd()
|
||||
if newCRD == nil {
|
||||
continue
|
||||
t.Run(fmt.Sprintf("old CRD %v, new CRD %v", oldCRDInfo.name, newCRDInfo.name),
|
||||
func(t *testing.T) {
|
||||
var oldCRDSpec *apiextensions.CustomResourceDefinitionSpec
|
||||
if oldCRD != nil {
|
||||
oldCRDSpec = &oldCRD.Spec
|
||||
}
|
||||
t.Run(fmt.Sprintf("subresources feature enabled=%v, old CRD %v, new CRD %v", validationEnabled, oldCRDInfo.name, newCRDInfo.name),
|
||||
func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, apiextensionsfeatures.CustomResourceSubresources, validationEnabled)()
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, apiextensionsfeatures.CustomResourceWebhookConversion, conversionEnabled)()
|
||||
var oldCRDSpec *apiextensions.CustomResourceDefinitionSpec
|
||||
if oldCRD != nil {
|
||||
oldCRDSpec = &oldCRD.Spec
|
||||
}
|
||||
dropDisabledFields(&newCRD.Spec, oldCRDSpec)
|
||||
// old CRD should never be changed
|
||||
if !reflect.DeepEqual(oldCRD, oldCRDInfo.crd()) {
|
||||
t.Errorf("old crd changed: %v", diff.ObjectReflectDiff(oldCRD, oldCRDInfo.crd()))
|
||||
}
|
||||
switch {
|
||||
case (conversionEnabled && validationEnabled) || oldCRDHasSubresources:
|
||||
if !reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd changed: %v", diff.ObjectReflectDiff(newCRD, newCRDInfo.crd()))
|
||||
}
|
||||
case !conversionEnabled && !oldCRDHasSubresources:
|
||||
if !reflect.DeepEqual(newCRD, crdWithoutVersionedSubresources()) {
|
||||
t.Errorf("new crd was not changed")
|
||||
}
|
||||
case newCRDHasSubresources:
|
||||
if reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd was not changed")
|
||||
}
|
||||
if !reflect.DeepEqual(newCRD, crdWithoutVersionedSubresources()) {
|
||||
t.Errorf("new crd had versioned subresources: %v", diff.ObjectReflectDiff(newCRD, crdWithoutVersionedSubresources()))
|
||||
}
|
||||
default:
|
||||
if !reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd changed: %v", diff.ObjectReflectDiff(newCRD, newCRDInfo.crd()))
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
dropDisabledFields(&newCRD.Spec, oldCRDSpec)
|
||||
// old CRD should never be changed
|
||||
if !reflect.DeepEqual(oldCRD, oldCRDInfo.crd()) {
|
||||
t.Errorf("old crd changed: %v", diff.ObjectReflectDiff(oldCRD, oldCRDInfo.crd()))
|
||||
}
|
||||
if !reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd changed: %v", diff.ObjectReflectDiff(newCRD, newCRDInfo.crd()))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
t.Log("testing conversion webhook..")
|
||||
for _, validationEnabled := range []bool{true, false} {
|
||||
crdWithUnversionedConversionWebhook := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd with conversion webhook
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{
|
||||
Conversion: &apiextensions.CustomResourceConversion{
|
||||
WebhookClientConfig: &apiextensions.WebhookClientConfig{},
|
||||
},
|
||||
crdWithUnversionedConversionWebhook := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd with conversion webhook
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{
|
||||
Conversion: &apiextensions.CustomResourceConversion{
|
||||
WebhookClientConfig: &apiextensions.WebhookClientConfig{},
|
||||
},
|
||||
}
|
||||
}
|
||||
crdWithoutUnversionedConversionWebhook := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd with conversion webhook
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{
|
||||
Conversion: &apiextensions.CustomResourceConversion{},
|
||||
},
|
||||
}
|
||||
}
|
||||
crdInfos := []struct {
|
||||
name string
|
||||
hasCRConversionWebhook bool
|
||||
crd func() *apiextensions.CustomResourceDefinition
|
||||
}{
|
||||
{
|
||||
name: "has conversion webhook",
|
||||
hasCRConversionWebhook: true,
|
||||
crd: crdWithUnversionedConversionWebhook,
|
||||
},
|
||||
{
|
||||
name: "doesn't have conversion webhook",
|
||||
hasCRConversionWebhook: false,
|
||||
crd: crdWithoutUnversionedConversionWebhook,
|
||||
},
|
||||
{
|
||||
name: "nil",
|
||||
hasCRConversionWebhook: false,
|
||||
crd: func() *apiextensions.CustomResourceDefinition { return nil },
|
||||
},
|
||||
}
|
||||
for _, oldCRDInfo := range crdInfos {
|
||||
for _, newCRDInfo := range crdInfos {
|
||||
oldCRDHasConversionWebhook, oldCRD := oldCRDInfo.hasCRConversionWebhook, oldCRDInfo.crd()
|
||||
newCRDHasConversionWebhook, newCRD := newCRDInfo.hasCRConversionWebhook, newCRDInfo.crd()
|
||||
if newCRD == nil {
|
||||
continue
|
||||
}
|
||||
t.Run(fmt.Sprintf("subresources feature enabled=%v, old CRD %v, new CRD %v", validationEnabled, oldCRDInfo.name, newCRDInfo.name),
|
||||
func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, apiextensionsfeatures.CustomResourceWebhookConversion, validationEnabled)()
|
||||
var oldCRDSpec *apiextensions.CustomResourceDefinitionSpec
|
||||
if oldCRD != nil {
|
||||
oldCRDSpec = &oldCRD.Spec
|
||||
}
|
||||
dropDisabledFields(&newCRD.Spec, oldCRDSpec)
|
||||
// old CRD should never be changed
|
||||
if !reflect.DeepEqual(oldCRD, oldCRDInfo.crd()) {
|
||||
t.Errorf("old crd changed: %v", diff.ObjectReflectDiff(oldCRD, oldCRDInfo.crd()))
|
||||
}
|
||||
switch {
|
||||
case validationEnabled || oldCRDHasConversionWebhook:
|
||||
if !reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd changed: %v", diff.ObjectReflectDiff(newCRD, newCRDInfo.crd()))
|
||||
}
|
||||
case newCRDHasConversionWebhook:
|
||||
if reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd was not changed")
|
||||
}
|
||||
if !reflect.DeepEqual(newCRD, crdWithoutUnversionedConversionWebhook()) {
|
||||
t.Errorf("new crd had webhook conversion: %v", diff.ObjectReflectDiff(newCRD, crdWithoutUnversionedConversionWebhook()))
|
||||
}
|
||||
default:
|
||||
if !reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd changed: %v", diff.ObjectReflectDiff(newCRD, newCRDInfo.crd()))
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crdWithoutUnversionedConversionWebhook := func() *apiextensions.CustomResourceDefinition {
|
||||
// crd with conversion webhook
|
||||
return &apiextensions.CustomResourceDefinition{
|
||||
Spec: apiextensions.CustomResourceDefinitionSpec{
|
||||
Conversion: &apiextensions.CustomResourceConversion{},
|
||||
},
|
||||
}
|
||||
}
|
||||
crdInfos = []struct {
|
||||
name string
|
||||
crd func() *apiextensions.CustomResourceDefinition
|
||||
}{
|
||||
{
|
||||
name: "has conversion webhook",
|
||||
crd: crdWithUnversionedConversionWebhook,
|
||||
},
|
||||
{
|
||||
name: "doesn't have conversion webhook",
|
||||
crd: crdWithoutUnversionedConversionWebhook,
|
||||
},
|
||||
{
|
||||
name: "nil",
|
||||
crd: func() *apiextensions.CustomResourceDefinition { return nil },
|
||||
},
|
||||
}
|
||||
for _, oldCRDInfo := range crdInfos {
|
||||
for _, newCRDInfo := range crdInfos {
|
||||
oldCRD := oldCRDInfo.crd()
|
||||
newCRD := newCRDInfo.crd()
|
||||
if newCRD == nil {
|
||||
continue
|
||||
}
|
||||
t.Run(fmt.Sprintf("old CRD %v, new CRD %v", oldCRDInfo.name, newCRDInfo.name),
|
||||
func(t *testing.T) {
|
||||
var oldCRDSpec *apiextensions.CustomResourceDefinitionSpec
|
||||
if oldCRD != nil {
|
||||
oldCRDSpec = &oldCRD.Spec
|
||||
}
|
||||
dropDisabledFields(&newCRD.Spec, oldCRDSpec)
|
||||
// old CRD should never be changed
|
||||
if !reflect.DeepEqual(oldCRD, oldCRDInfo.crd()) {
|
||||
t.Errorf("old crd changed: %v", diff.ObjectReflectDiff(oldCRD, oldCRDInfo.crd()))
|
||||
}
|
||||
if !reflect.DeepEqual(newCRD, newCRDInfo.crd()) {
|
||||
t.Errorf("new crd changed: %v", diff.ObjectReflectDiff(newCRD, newCRDInfo.crd()))
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func strPtr(in string) *string {
|
||||
|
Loading…
Reference in New Issue
Block a user