Add namespace scoped ParametersReference to IngressClass

This commit is contained in:
Harry Bagdi
2021-03-06 03:03:20 +05:30
parent a954818194
commit a7fc92089a
44 changed files with 2535 additions and 225 deletions

View File

@@ -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
}
}

View File

@@ -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)
}
})
}
}