Add namespace scoped ParametersReference to IngressClass
This commit is contained in:
@@ -23,9 +23,11 @@ import (
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||
"k8s.io/apiserver/pkg/storage/names"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||
"k8s.io/kubernetes/pkg/apis/networking"
|
||||
"k8s.io/kubernetes/pkg/apis/networking/validation"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
)
|
||||
|
||||
// ingressClassStrategy implements verification logic for IngressClass
|
||||
@@ -49,6 +51,10 @@ func (ingressClassStrategy) NamespaceScoped() bool {
|
||||
func (ingressClassStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||
ingressClass := obj.(*networking.IngressClass)
|
||||
ingressClass.Generation = 1
|
||||
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.IngressClassNamespacedParams) {
|
||||
dropIngressClassParametersReferenceScope(ingressClass)
|
||||
}
|
||||
}
|
||||
|
||||
// PrepareForUpdate clears fields that are not allowed to be set by end users on
|
||||
@@ -63,6 +69,9 @@ func (ingressClassStrategy) PrepareForUpdate(ctx context.Context, obj, old runti
|
||||
newIngressClass.Generation = oldIngressClass.Generation + 1
|
||||
}
|
||||
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.IngressClassNamespacedParams) && !scopeInUse(oldIngressClass) {
|
||||
dropIngressClassParametersReferenceScope(newIngressClass)
|
||||
}
|
||||
}
|
||||
|
||||
// Validate validates a new IngressClass.
|
||||
@@ -94,3 +103,15 @@ func (ingressClassStrategy) ValidateUpdate(ctx context.Context, obj, old runtime
|
||||
func (ingressClassStrategy) AllowUnconditionalUpdate() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func scopeInUse(ingressClass *networking.IngressClass) bool {
|
||||
return ingressClass.Spec.Parameters != nil && ingressClass.Spec.Parameters.Scope != nil
|
||||
}
|
||||
|
||||
// Drops Scope and Namespace field from IngressClass's parameters.
|
||||
func dropIngressClassParametersReferenceScope(ingressClass *networking.IngressClass) {
|
||||
if ingressClass.Spec.Parameters != nil {
|
||||
ingressClass.Spec.Parameters.Scope = nil
|
||||
ingressClass.Spec.Parameters.Namespace = nil
|
||||
}
|
||||
}
|
||||
|
@@ -19,9 +19,15 @@ package ingressclass
|
||||
import (
|
||||
"testing"
|
||||
|
||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
||||
"k8s.io/kubernetes/pkg/apis/networking"
|
||||
"k8s.io/kubernetes/pkg/features"
|
||||
utilpointer "k8s.io/utils/pointer"
|
||||
)
|
||||
|
||||
func TestIngressClassStrategy(t *testing.T) {
|
||||
@@ -67,6 +73,285 @@ func TestIngressClassStrategy(t *testing.T) {
|
||||
}
|
||||
errs = Strategy.ValidateUpdate(ctx, &ingressClass, &ingressClass)
|
||||
if len(errs) == 0 {
|
||||
t.Errorf("Unexpected error from update validation for IngressClass, got none")
|
||||
t.Errorf("Expected error from update validation for IngressClass, got none")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIngressClassPrepareForCreate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
original *networking.IngressClass
|
||||
expected *networking.IngressClass
|
||||
enableNamespaceScopedParamsGate bool
|
||||
}{
|
||||
{
|
||||
name: "cluster scope is removed when feature is not enabled",
|
||||
original: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
Scope: utilpointer.StringPtr(networking.IngressClassParametersReferenceScopeCluster),
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
},
|
||||
},
|
||||
},
|
||||
enableNamespaceScopedParamsGate: false,
|
||||
},
|
||||
{
|
||||
name: "namespace scope and namespace fields are removed when feature is not enabled",
|
||||
original: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
Scope: utilpointer.StringPtr(networking.IngressClassParametersReferenceScopeNamespace),
|
||||
Namespace: utilpointer.StringPtr("foo-ns"),
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
},
|
||||
},
|
||||
},
|
||||
enableNamespaceScopedParamsGate: false,
|
||||
},
|
||||
{
|
||||
name: "cluster scope is not removed when feature is enabled",
|
||||
original: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
Scope: utilpointer.StringPtr(networking.IngressClassParametersReferenceScopeCluster),
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
Scope: utilpointer.StringPtr(networking.IngressClassParametersReferenceScopeCluster),
|
||||
},
|
||||
},
|
||||
},
|
||||
enableNamespaceScopedParamsGate: true,
|
||||
},
|
||||
{
|
||||
name: "namespace scope and namespace fields are not removed when feature is enabled",
|
||||
original: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
Scope: utilpointer.StringPtr(networking.IngressClassParametersReferenceScopeNamespace),
|
||||
Namespace: utilpointer.StringPtr("foo-ns"),
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
Scope: utilpointer.StringPtr(networking.IngressClassParametersReferenceScopeNamespace),
|
||||
Namespace: utilpointer.StringPtr("foo-ns"),
|
||||
},
|
||||
},
|
||||
},
|
||||
enableNamespaceScopedParamsGate: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
original := test.original
|
||||
expected := test.expected
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.IngressClassNamespacedParams, test.enableNamespaceScopedParamsGate)()
|
||||
ctx := genericapirequest.NewDefaultContext()
|
||||
Strategy.PrepareForCreate(ctx, runtime.Object(original))
|
||||
if !apiequality.Semantic.DeepEqual(original.Spec, expected.Spec) {
|
||||
t.Errorf("got different than expected\ngot:\n\t%+v\nexpected:\n\t%+v", original.Spec, expected.Spec)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIngressClassPrepareForUpdate(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
newIngressClass *networking.IngressClass
|
||||
oldIngressClass *networking.IngressClass
|
||||
expected *networking.IngressClass
|
||||
enableNamespaceScopedParamsGate bool
|
||||
}{
|
||||
{
|
||||
name: "scope can be updated if already set when feature is disabled",
|
||||
newIngressClass: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
Scope: utilpointer.StringPtr(networking.IngressClassParametersReferenceScopeNamespace),
|
||||
Namespace: utilpointer.StringPtr("foo-ns"),
|
||||
},
|
||||
},
|
||||
},
|
||||
oldIngressClass: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
Scope: utilpointer.StringPtr(networking.IngressClassParametersReferenceScopeCluster),
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
Scope: utilpointer.StringPtr(networking.IngressClassParametersReferenceScopeNamespace),
|
||||
Namespace: utilpointer.StringPtr("foo-ns"),
|
||||
},
|
||||
},
|
||||
},
|
||||
enableNamespaceScopedParamsGate: false,
|
||||
},
|
||||
{
|
||||
name: "scope is removed if not already set previously when feature is disabled",
|
||||
newIngressClass: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
Scope: utilpointer.StringPtr(networking.IngressClassParametersReferenceScopeNamespace),
|
||||
Namespace: utilpointer.StringPtr("foo-ns"),
|
||||
},
|
||||
},
|
||||
},
|
||||
oldIngressClass: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
},
|
||||
},
|
||||
},
|
||||
enableNamespaceScopedParamsGate: false,
|
||||
},
|
||||
{
|
||||
name: "scope can be set when feature is enabled",
|
||||
newIngressClass: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
Scope: utilpointer.StringPtr(networking.IngressClassParametersReferenceScopeNamespace),
|
||||
Namespace: utilpointer.StringPtr("foo-ns"),
|
||||
},
|
||||
},
|
||||
},
|
||||
oldIngressClass: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
Scope: utilpointer.StringPtr(networking.IngressClassParametersReferenceScopeNamespace),
|
||||
Namespace: utilpointer.StringPtr("foo-ns"),
|
||||
},
|
||||
},
|
||||
},
|
||||
enableNamespaceScopedParamsGate: true,
|
||||
},
|
||||
{
|
||||
name: "scope can be removed when feature is enabled",
|
||||
newIngressClass: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
},
|
||||
},
|
||||
},
|
||||
oldIngressClass: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
Scope: utilpointer.StringPtr(networking.IngressClassParametersReferenceScopeNamespace),
|
||||
Namespace: utilpointer.StringPtr("foo-ns"),
|
||||
},
|
||||
},
|
||||
},
|
||||
expected: &networking.IngressClass{
|
||||
Spec: networking.IngressClassSpec{
|
||||
Controller: "controller",
|
||||
Parameters: &networking.IngressClassParametersReference{
|
||||
Kind: "k",
|
||||
Name: "n",
|
||||
},
|
||||
},
|
||||
},
|
||||
enableNamespaceScopedParamsGate: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.IngressClassNamespacedParams, test.enableNamespaceScopedParamsGate)()
|
||||
ctx := genericapirequest.NewDefaultContext()
|
||||
Strategy.PrepareForUpdate(ctx, runtime.Object(test.newIngressClass), runtime.Object(test.oldIngressClass))
|
||||
if !apiequality.Semantic.DeepEqual(test.newIngressClass.Spec, test.expected.Spec) {
|
||||
t.Errorf("got different than expected\ngot:\n\t%+v\nexpected:\n\t%+v", test.newIngressClass.Spec, test.expected.Spec)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user