mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-22 11:21:47 +00:00
Graduate IngressClassNamespacedParams to GA
This commit is contained in:
parent
bafa87c553
commit
d09a8c0a88
2
api/openapi-spec/swagger.json
generated
2
api/openapi-spec/swagger.json
generated
@ -11944,7 +11944,7 @@
|
|||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"scope": {
|
"scope": {
|
||||||
"description": "Scope represents if this refers to a cluster or namespace scoped resource. This may be set to \"Cluster\" (default) or \"Namespace\". Field can be enabled with IngressClassNamespacedParams feature gate.",
|
"description": "Scope represents if this refers to a cluster or namespace scoped resource. This may be set to \"Cluster\" (default) or \"Namespace\".",
|
||||||
"type": "string"
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -339,15 +339,12 @@ type IngressClassParametersReference struct {
|
|||||||
Name string
|
Name string
|
||||||
// Scope represents if this refers to a cluster or namespace scoped resource.
|
// Scope represents if this refers to a cluster or namespace scoped resource.
|
||||||
// This may be set to "Cluster" (default) or "Namespace".
|
// This may be set to "Cluster" (default) or "Namespace".
|
||||||
// Field can be enabled with IngressClassNamespacedParams feature gate.
|
|
||||||
// +optional
|
// +optional
|
||||||
// +featureGate=IngressClassNamespacedParams
|
|
||||||
Scope *string
|
Scope *string
|
||||||
// Namespace is the namespace of the resource being referenced. This field is
|
// Namespace is the namespace of the resource being referenced. This field is
|
||||||
// required when scope is set to "Namespace" and must be unset when scope is set to
|
// required when scope is set to "Namespace" and must be unset when scope is set to
|
||||||
// "Cluster".
|
// "Cluster".
|
||||||
// +optional
|
// +optional
|
||||||
// +featureGate=IngressClassNamespacedParams
|
|
||||||
Namespace *string
|
Namespace *string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,8 +20,6 @@ import (
|
|||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
networkingv1 "k8s.io/api/networking/v1"
|
networkingv1 "k8s.io/api/networking/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
utilpointer "k8s.io/utils/pointer"
|
utilpointer "k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -48,9 +46,6 @@ func SetDefaults_NetworkPolicy(obj *networkingv1.NetworkPolicy) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func SetDefaults_IngressClass(obj *networkingv1.IngressClass) {
|
func SetDefaults_IngressClass(obj *networkingv1.IngressClass) {
|
||||||
if !utilfeature.DefaultFeatureGate.Enabled(features.IngressClassNamespacedParams) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if obj.Spec.Parameters != nil && obj.Spec.Parameters.Scope == nil {
|
if obj.Spec.Parameters != nil && obj.Spec.Parameters.Scope == nil {
|
||||||
obj.Spec.Parameters.Scope = utilpointer.StringPtr(networkingv1.IngressClassParametersReferenceScopeCluster)
|
obj.Spec.Parameters.Scope = utilpointer.StringPtr(networkingv1.IngressClassParametersReferenceScopeCluster)
|
||||||
}
|
}
|
||||||
|
@ -24,13 +24,10 @@ import (
|
|||||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
|
||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
_ "k8s.io/kubernetes/pkg/apis/core/install"
|
_ "k8s.io/kubernetes/pkg/apis/core/install"
|
||||||
_ "k8s.io/kubernetes/pkg/apis/networking/install"
|
_ "k8s.io/kubernetes/pkg/apis/networking/install"
|
||||||
. "k8s.io/kubernetes/pkg/apis/networking/v1"
|
. "k8s.io/kubernetes/pkg/apis/networking/v1"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
utilpointer "k8s.io/utils/pointer"
|
utilpointer "k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -240,13 +237,12 @@ func TestSetDefaultNetworkPolicy(t *testing.T) {
|
|||||||
|
|
||||||
func TestSetDefaultsForIngressClassParametersReference(t *testing.T) {
|
func TestSetDefaultsForIngressClassParametersReference(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
original *networkingv1.IngressClass
|
original *networkingv1.IngressClass
|
||||||
expected *networkingv1.IngressClass
|
expected *networkingv1.IngressClass
|
||||||
enableNamespaceScopedParamsGate bool
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "populated parameters sets the default Scope when feature is enabled",
|
name: "populated parameters sets the default Scope",
|
||||||
original: &networkingv1.IngressClass{
|
original: &networkingv1.IngressClass{
|
||||||
Spec: networkingv1.IngressClassSpec{
|
Spec: networkingv1.IngressClassSpec{
|
||||||
Controller: "controller",
|
Controller: "controller",
|
||||||
@ -266,10 +262,9 @@ func TestSetDefaultsForIngressClassParametersReference(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
enableNamespaceScopedParamsGate: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "existing scope is not overridden when feature is enabled",
|
name: "existing scope is not overridden",
|
||||||
original: &networkingv1.IngressClass{
|
original: &networkingv1.IngressClass{
|
||||||
Spec: networkingv1.IngressClassSpec{
|
Spec: networkingv1.IngressClassSpec{
|
||||||
Controller: "controller",
|
Controller: "controller",
|
||||||
@ -292,10 +287,9 @@ func TestSetDefaultsForIngressClassParametersReference(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
enableNamespaceScopedParamsGate: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "empty Parameters does not set the default Scope when feature is enabled",
|
name: "empty Parameters does not set the default Scope",
|
||||||
original: &networkingv1.IngressClass{
|
original: &networkingv1.IngressClass{
|
||||||
Spec: networkingv1.IngressClassSpec{
|
Spec: networkingv1.IngressClassSpec{
|
||||||
Controller: "controller",
|
Controller: "controller",
|
||||||
@ -306,43 +300,6 @@ func TestSetDefaultsForIngressClassParametersReference(t *testing.T) {
|
|||||||
Controller: "controller",
|
Controller: "controller",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
enableNamespaceScopedParamsGate: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "populated parameters does not set the default Scope when feature is disabled",
|
|
||||||
original: &networkingv1.IngressClass{
|
|
||||||
Spec: networkingv1.IngressClassSpec{
|
|
||||||
Controller: "controller",
|
|
||||||
Parameters: &networkingv1.IngressClassParametersReference{
|
|
||||||
Kind: "k",
|
|
||||||
Name: "n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expected: &networkingv1.IngressClass{
|
|
||||||
Spec: networkingv1.IngressClassSpec{
|
|
||||||
Controller: "controller",
|
|
||||||
Parameters: &networkingv1.IngressClassParametersReference{
|
|
||||||
Kind: "k",
|
|
||||||
Name: "n",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
enableNamespaceScopedParamsGate: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "empty Parameters does not set the default Scope when feature is disabled",
|
|
||||||
original: &networkingv1.IngressClass{
|
|
||||||
Spec: networkingv1.IngressClassSpec{
|
|
||||||
Controller: "controller",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
expected: &networkingv1.IngressClass{
|
|
||||||
Spec: networkingv1.IngressClassSpec{
|
|
||||||
Controller: "controller",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
enableNamespaceScopedParamsGate: false,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,7 +307,6 @@ func TestSetDefaultsForIngressClassParametersReference(t *testing.T) {
|
|||||||
t.Run(test.name, func(t *testing.T) {
|
t.Run(test.name, func(t *testing.T) {
|
||||||
original := test.original
|
original := test.original
|
||||||
expected := test.expected
|
expected := test.expected
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.IngressClassNamespacedParams, test.enableNamespaceScopedParamsGate)()
|
|
||||||
obj2 := roundTrip(t, runtime.Object(original))
|
obj2 := roundTrip(t, runtime.Object(original))
|
||||||
got, ok := obj2.(*networkingv1.IngressClass)
|
got, ok := obj2.(*networkingv1.IngressClass)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -27,11 +27,9 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
"k8s.io/apimachinery/pkg/util/validation"
|
"k8s.io/apimachinery/pkg/util/validation"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
apivalidation "k8s.io/kubernetes/pkg/apis/core/validation"
|
apivalidation "k8s.io/kubernetes/pkg/apis/core/validation"
|
||||||
"k8s.io/kubernetes/pkg/apis/networking"
|
"k8s.io/kubernetes/pkg/apis/networking"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
netutils "k8s.io/utils/net"
|
netutils "k8s.io/utils/net"
|
||||||
utilpointer "k8s.io/utils/pointer"
|
utilpointer "k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
@ -537,7 +535,7 @@ func validateIngressClassParametersReference(params *networking.IngressClassPara
|
|||||||
Name: params.Name,
|
Name: params.Name,
|
||||||
}, fldPath)...)
|
}, fldPath)...)
|
||||||
|
|
||||||
if utilfeature.DefaultFeatureGate.Enabled(features.IngressClassNamespacedParams) && params.Scope == nil {
|
if params.Scope == nil {
|
||||||
allErrs = append(allErrs, field.Required(fldPath.Child("scope"), ""))
|
allErrs = append(allErrs, field.Required(fldPath.Child("scope"), ""))
|
||||||
return allErrs
|
return allErrs
|
||||||
}
|
}
|
||||||
|
@ -25,11 +25,8 @@ import (
|
|||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/intstr"
|
"k8s.io/apimachinery/pkg/util/intstr"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
featuregatetesting "k8s.io/component-base/featuregate/testing"
|
|
||||||
api "k8s.io/kubernetes/pkg/apis/core"
|
api "k8s.io/kubernetes/pkg/apis/core"
|
||||||
"k8s.io/kubernetes/pkg/apis/networking"
|
"k8s.io/kubernetes/pkg/apis/networking"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
utilpointer "k8s.io/utils/pointer"
|
utilpointer "k8s.io/utils/pointer"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -1444,9 +1441,8 @@ func TestValidateIngressClass(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
testCases := map[string]struct {
|
testCases := map[string]struct {
|
||||||
ingressClass *networking.IngressClass
|
ingressClass *networking.IngressClass
|
||||||
expectedErrs field.ErrorList
|
expectedErrs field.ErrorList
|
||||||
enableNamespaceScopedParamsGate bool
|
|
||||||
}{
|
}{
|
||||||
"valid name, valid controller": {
|
"valid name, valid controller": {
|
||||||
ingressClass: makeValidIngressClass("test123", "foo.co/bar"),
|
ingressClass: makeValidIngressClass("test123", "foo.co/bar"),
|
||||||
@ -1470,25 +1466,25 @@ func TestValidateIngressClass(t *testing.T) {
|
|||||||
},
|
},
|
||||||
"valid name, valid controller, valid params": {
|
"valid name, valid controller, valid params": {
|
||||||
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
||||||
setParams(makeIngressClassParams(utilpointer.StringPtr("example.com"), "foo", "bar", nil, nil)),
|
setParams(makeIngressClassParams(utilpointer.StringPtr("example.com"), "foo", "bar", utilpointer.StringPtr("Cluster"), nil)),
|
||||||
),
|
),
|
||||||
expectedErrs: field.ErrorList{},
|
expectedErrs: field.ErrorList{},
|
||||||
},
|
},
|
||||||
"valid name, valid controller, invalid params (no kind)": {
|
"valid name, valid controller, invalid params (no kind)": {
|
||||||
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
||||||
setParams(makeIngressClassParams(utilpointer.StringPtr("example.com"), "", "bar", nil, nil)),
|
setParams(makeIngressClassParams(utilpointer.StringPtr("example.com"), "", "bar", utilpointer.StringPtr("Cluster"), nil)),
|
||||||
),
|
),
|
||||||
expectedErrs: field.ErrorList{field.Required(field.NewPath("spec.parameters.kind"), "kind is required")},
|
expectedErrs: field.ErrorList{field.Required(field.NewPath("spec.parameters.kind"), "kind is required")},
|
||||||
},
|
},
|
||||||
"valid name, valid controller, invalid params (no name)": {
|
"valid name, valid controller, invalid params (no name)": {
|
||||||
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
||||||
setParams(makeIngressClassParams(utilpointer.StringPtr("example.com"), "foo", "", nil, nil)),
|
setParams(makeIngressClassParams(utilpointer.StringPtr("example.com"), "foo", "", utilpointer.StringPtr("Cluster"), nil)),
|
||||||
),
|
),
|
||||||
expectedErrs: field.ErrorList{field.Required(field.NewPath("spec.parameters.name"), "name is required")},
|
expectedErrs: field.ErrorList{field.Required(field.NewPath("spec.parameters.name"), "name is required")},
|
||||||
},
|
},
|
||||||
"valid name, valid controller, invalid params (bad kind)": {
|
"valid name, valid controller, invalid params (bad kind)": {
|
||||||
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
||||||
setParams(makeIngressClassParams(nil, "foo/", "bar", nil, nil)),
|
setParams(makeIngressClassParams(nil, "foo/", "bar", utilpointer.StringPtr("Cluster"), nil)),
|
||||||
),
|
),
|
||||||
expectedErrs: field.ErrorList{field.Invalid(field.NewPath("spec.parameters.kind"), "foo/", "may not contain '/'")},
|
expectedErrs: field.ErrorList{field.Invalid(field.NewPath("spec.parameters.kind"), "foo/", "may not contain '/'")},
|
||||||
},
|
},
|
||||||
@ -1496,7 +1492,6 @@ func TestValidateIngressClass(t *testing.T) {
|
|||||||
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
||||||
setParams(makeIngressClassParams(nil, "foo", "bar", utilpointer.StringPtr("bad-scope"), nil)),
|
setParams(makeIngressClassParams(nil, "foo", "bar", utilpointer.StringPtr("bad-scope"), nil)),
|
||||||
),
|
),
|
||||||
enableNamespaceScopedParamsGate: true,
|
|
||||||
expectedErrs: field.ErrorList{field.NotSupported(field.NewPath("spec.parameters.scope"),
|
expectedErrs: field.ErrorList{field.NotSupported(field.NewPath("spec.parameters.scope"),
|
||||||
"bad-scope", []string{"Cluster", "Namespace"})},
|
"bad-scope", []string{"Cluster", "Namespace"})},
|
||||||
},
|
},
|
||||||
@ -1504,14 +1499,12 @@ func TestValidateIngressClass(t *testing.T) {
|
|||||||
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
||||||
setParams(makeIngressClassParams(nil, "foo", "bar", utilpointer.StringPtr("Namespace"), utilpointer.StringPtr("foo-ns"))),
|
setParams(makeIngressClassParams(nil, "foo", "bar", utilpointer.StringPtr("Namespace"), utilpointer.StringPtr("foo-ns"))),
|
||||||
),
|
),
|
||||||
enableNamespaceScopedParamsGate: true,
|
expectedErrs: field.ErrorList{},
|
||||||
expectedErrs: field.ErrorList{},
|
|
||||||
},
|
},
|
||||||
"valid name, valid controller, valid scope, invalid namespace": {
|
"valid name, valid controller, valid scope, invalid namespace": {
|
||||||
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
||||||
setParams(makeIngressClassParams(nil, "foo", "bar", utilpointer.StringPtr("Namespace"), utilpointer.StringPtr("foo_ns"))),
|
setParams(makeIngressClassParams(nil, "foo", "bar", utilpointer.StringPtr("Namespace"), utilpointer.StringPtr("foo_ns"))),
|
||||||
),
|
),
|
||||||
enableNamespaceScopedParamsGate: true,
|
|
||||||
expectedErrs: field.ErrorList{field.Invalid(field.NewPath("spec.parameters.namespace"), "foo_ns",
|
expectedErrs: field.ErrorList{field.Invalid(field.NewPath("spec.parameters.namespace"), "foo_ns",
|
||||||
"a lowercase RFC 1123 label must consist of lower case alphanumeric characters or '-',"+
|
"a lowercase RFC 1123 label must consist of lower case alphanumeric characters or '-',"+
|
||||||
" and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', "+
|
" and must start and end with an alphanumeric character (e.g. 'my-name', or '123-abc', "+
|
||||||
@ -1521,14 +1514,12 @@ func TestValidateIngressClass(t *testing.T) {
|
|||||||
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
||||||
setParams(makeIngressClassParams(nil, "foo", "bar", utilpointer.StringPtr("Cluster"), nil)),
|
setParams(makeIngressClassParams(nil, "foo", "bar", utilpointer.StringPtr("Cluster"), nil)),
|
||||||
),
|
),
|
||||||
enableNamespaceScopedParamsGate: true,
|
expectedErrs: field.ErrorList{},
|
||||||
expectedErrs: field.ErrorList{},
|
|
||||||
},
|
},
|
||||||
"namespace not set when scope is Namespace": {
|
"namespace not set when scope is Namespace": {
|
||||||
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
||||||
setParams(makeIngressClassParams(nil, "foo", "bar", utilpointer.StringPtr("Namespace"), nil)),
|
setParams(makeIngressClassParams(nil, "foo", "bar", utilpointer.StringPtr("Namespace"), nil)),
|
||||||
),
|
),
|
||||||
enableNamespaceScopedParamsGate: true,
|
|
||||||
expectedErrs: field.ErrorList{field.Required(field.NewPath("spec.parameters.namespace"),
|
expectedErrs: field.ErrorList{field.Required(field.NewPath("spec.parameters.namespace"),
|
||||||
"`parameters.scope` is set to 'Namespace'")},
|
"`parameters.scope` is set to 'Namespace'")},
|
||||||
},
|
},
|
||||||
@ -1536,7 +1527,6 @@ func TestValidateIngressClass(t *testing.T) {
|
|||||||
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
||||||
setParams(makeIngressClassParams(nil, "foo", "bar", utilpointer.StringPtr("Cluster"), utilpointer.StringPtr("foo-ns"))),
|
setParams(makeIngressClassParams(nil, "foo", "bar", utilpointer.StringPtr("Cluster"), utilpointer.StringPtr("foo-ns"))),
|
||||||
),
|
),
|
||||||
enableNamespaceScopedParamsGate: true,
|
|
||||||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec.parameters.namespace"),
|
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec.parameters.namespace"),
|
||||||
"`parameters.scope` is set to 'Cluster'")},
|
"`parameters.scope` is set to 'Cluster'")},
|
||||||
},
|
},
|
||||||
@ -1544,38 +1534,13 @@ func TestValidateIngressClass(t *testing.T) {
|
|||||||
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
||||||
setParams(makeIngressClassParams(nil, "foo", "bar", utilpointer.StringPtr("Cluster"), utilpointer.StringPtr(""))),
|
setParams(makeIngressClassParams(nil, "foo", "bar", utilpointer.StringPtr("Cluster"), utilpointer.StringPtr(""))),
|
||||||
),
|
),
|
||||||
enableNamespaceScopedParamsGate: true,
|
|
||||||
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec.parameters.namespace"),
|
expectedErrs: field.ErrorList{field.Forbidden(field.NewPath("spec.parameters.namespace"),
|
||||||
"`parameters.scope` is set to 'Cluster'")},
|
"`parameters.scope` is set to 'Cluster'")},
|
||||||
},
|
},
|
||||||
"validation is performed when feature gate is disabled and scope is not empty": {
|
|
||||||
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
|
||||||
setParams(makeIngressClassParams(nil, "foo", "bar", utilpointer.StringPtr("bad-scope"), nil)),
|
|
||||||
),
|
|
||||||
enableNamespaceScopedParamsGate: false,
|
|
||||||
expectedErrs: field.ErrorList{field.NotSupported(field.NewPath("spec.parameters.scope"),
|
|
||||||
"bad-scope", []string{"Cluster", "Namespace"})},
|
|
||||||
},
|
|
||||||
"validation fails when feature gate is enabled and scope is not set": {
|
|
||||||
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
|
||||||
setParams(makeIngressClassParams(nil, "foo", "bar", nil, nil)),
|
|
||||||
),
|
|
||||||
enableNamespaceScopedParamsGate: true,
|
|
||||||
expectedErrs: field.ErrorList{field.Required(field.NewPath("spec.parameters.scope"), "")},
|
|
||||||
},
|
|
||||||
"validation is performed when feature gate is disabled and namespace is not empty": {
|
|
||||||
ingressClass: makeValidIngressClass("test123", "foo.co/bar",
|
|
||||||
setParams(makeIngressClassParams(nil, "foo", "bar", nil, utilpointer.StringPtr("foo-ns"))),
|
|
||||||
),
|
|
||||||
enableNamespaceScopedParamsGate: false,
|
|
||||||
expectedErrs: field.ErrorList{field.NotSupported(field.NewPath("spec.parameters.scope"),
|
|
||||||
"", []string{"Cluster", "Namespace"})},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, testCase := range testCases {
|
for name, testCase := range testCases {
|
||||||
t.Run(name, func(t *testing.T) {
|
t.Run(name, func(t *testing.T) {
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.IngressClassNamespacedParams, testCase.enableNamespaceScopedParamsGate)()
|
|
||||||
errs := ValidateIngressClass(testCase.ingressClass)
|
errs := ValidateIngressClass(testCase.ingressClass)
|
||||||
|
|
||||||
if len(errs) != len(testCase.expectedErrs) {
|
if len(errs) != len(testCase.expectedErrs) {
|
||||||
|
@ -630,6 +630,7 @@ const (
|
|||||||
// kep: http://kep.k8s.io/2365
|
// kep: http://kep.k8s.io/2365
|
||||||
// alpha: v1.21
|
// alpha: v1.21
|
||||||
// beta: v1.22
|
// beta: v1.22
|
||||||
|
// GA: v1.23
|
||||||
//
|
//
|
||||||
// Enable Scope and Namespace fields on IngressClassParametersReference.
|
// Enable Scope and Namespace fields on IngressClassParametersReference.
|
||||||
IngressClassNamespacedParams featuregate.Feature = "IngressClassNamespacedParams"
|
IngressClassNamespacedParams featuregate.Feature = "IngressClassNamespacedParams"
|
||||||
@ -882,7 +883,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
|||||||
TopologyAwareHints: {Default: false, PreRelease: featuregate.Alpha},
|
TopologyAwareHints: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
PodAffinityNamespaceSelector: {Default: true, PreRelease: featuregate.Beta},
|
PodAffinityNamespaceSelector: {Default: true, PreRelease: featuregate.Beta},
|
||||||
ServiceLoadBalancerClass: {Default: true, PreRelease: featuregate.Beta},
|
ServiceLoadBalancerClass: {Default: true, PreRelease: featuregate.Beta},
|
||||||
IngressClassNamespacedParams: {Default: true, PreRelease: featuregate.Beta},
|
IngressClassNamespacedParams: {Default: true, PreRelease: featuregate.GA, LockToDefault: true}, // remove in 1.24
|
||||||
ServiceInternalTrafficPolicy: {Default: true, PreRelease: featuregate.Beta},
|
ServiceInternalTrafficPolicy: {Default: true, PreRelease: featuregate.Beta},
|
||||||
LogarithmicScaleDown: {Default: true, PreRelease: featuregate.Beta},
|
LogarithmicScaleDown: {Default: true, PreRelease: featuregate.Beta},
|
||||||
SuspendJob: {Default: true, PreRelease: featuregate.Beta},
|
SuspendJob: {Default: true, PreRelease: featuregate.Beta},
|
||||||
|
@ -23,11 +23,9 @@ import (
|
|||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
"k8s.io/apiserver/pkg/storage/names"
|
"k8s.io/apiserver/pkg/storage/names"
|
||||||
utilfeature "k8s.io/apiserver/pkg/util/feature"
|
|
||||||
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
"k8s.io/kubernetes/pkg/api/legacyscheme"
|
||||||
"k8s.io/kubernetes/pkg/apis/networking"
|
"k8s.io/kubernetes/pkg/apis/networking"
|
||||||
"k8s.io/kubernetes/pkg/apis/networking/validation"
|
"k8s.io/kubernetes/pkg/apis/networking/validation"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ingressClassStrategy implements verification logic for IngressClass
|
// ingressClassStrategy implements verification logic for IngressClass
|
||||||
@ -51,10 +49,6 @@ func (ingressClassStrategy) NamespaceScoped() bool {
|
|||||||
func (ingressClassStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
func (ingressClassStrategy) PrepareForCreate(ctx context.Context, obj runtime.Object) {
|
||||||
ingressClass := obj.(*networking.IngressClass)
|
ingressClass := obj.(*networking.IngressClass)
|
||||||
ingressClass.Generation = 1
|
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
|
// PrepareForUpdate clears fields that are not allowed to be set by end users on
|
||||||
@ -68,10 +62,6 @@ func (ingressClassStrategy) PrepareForUpdate(ctx context.Context, obj, old runti
|
|||||||
if !apiequality.Semantic.DeepEqual(oldIngressClass.Spec, newIngressClass.Spec) {
|
if !apiequality.Semantic.DeepEqual(oldIngressClass.Spec, newIngressClass.Spec) {
|
||||||
newIngressClass.Generation = oldIngressClass.Generation + 1
|
newIngressClass.Generation = oldIngressClass.Generation + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if !utilfeature.DefaultFeatureGate.Enabled(features.IngressClassNamespacedParams) && !scopeInUse(oldIngressClass) {
|
|
||||||
dropIngressClassParametersReferenceScope(newIngressClass)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate validates a new IngressClass.
|
// Validate validates a new IngressClass.
|
||||||
@ -113,15 +103,3 @@ func (ingressClassStrategy) WarningsOnUpdate(ctx context.Context, obj, old runti
|
|||||||
func (ingressClassStrategy) AllowUnconditionalUpdate() bool {
|
func (ingressClassStrategy) AllowUnconditionalUpdate() bool {
|
||||||
return true
|
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,15 +19,9 @@ package ingressclass
|
|||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
apiequality "k8s.io/apimachinery/pkg/api/equality"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
|
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/apis/networking"
|
||||||
"k8s.io/kubernetes/pkg/features"
|
|
||||||
utilpointer "k8s.io/utils/pointer"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestIngressClassStrategy(t *testing.T) {
|
func TestIngressClassStrategy(t *testing.T) {
|
||||||
@ -76,282 +70,3 @@ func TestIngressClassStrategy(t *testing.T) {
|
|||||||
t.Errorf("Expected 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)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -167,16 +167,13 @@ message IngressClassParametersReference {
|
|||||||
|
|
||||||
// Scope represents if this refers to a cluster or namespace scoped resource.
|
// Scope represents if this refers to a cluster or namespace scoped resource.
|
||||||
// This may be set to "Cluster" (default) or "Namespace".
|
// This may be set to "Cluster" (default) or "Namespace".
|
||||||
// Field can be enabled with IngressClassNamespacedParams feature gate.
|
|
||||||
// +optional
|
// +optional
|
||||||
// +featureGate=IngressClassNamespacedParams
|
|
||||||
optional string scope = 4;
|
optional string scope = 4;
|
||||||
|
|
||||||
// Namespace is the namespace of the resource being referenced. This field is
|
// Namespace is the namespace of the resource being referenced. This field is
|
||||||
// required when scope is set to "Namespace" and must be unset when scope is set to
|
// required when scope is set to "Namespace" and must be unset when scope is set to
|
||||||
// "Cluster".
|
// "Cluster".
|
||||||
// +optional
|
// +optional
|
||||||
// +featureGate=IngressClassNamespacedParams
|
|
||||||
optional string namespace = 5;
|
optional string namespace = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -534,15 +534,12 @@ type IngressClassParametersReference struct {
|
|||||||
Name string `json:"name" protobuf:"bytes,3,opt,name=name"`
|
Name string `json:"name" protobuf:"bytes,3,opt,name=name"`
|
||||||
// Scope represents if this refers to a cluster or namespace scoped resource.
|
// Scope represents if this refers to a cluster or namespace scoped resource.
|
||||||
// This may be set to "Cluster" (default) or "Namespace".
|
// This may be set to "Cluster" (default) or "Namespace".
|
||||||
// Field can be enabled with IngressClassNamespacedParams feature gate.
|
|
||||||
// +optional
|
// +optional
|
||||||
// +featureGate=IngressClassNamespacedParams
|
|
||||||
Scope *string `json:"scope" protobuf:"bytes,4,opt,name=scope"`
|
Scope *string `json:"scope" protobuf:"bytes,4,opt,name=scope"`
|
||||||
// Namespace is the namespace of the resource being referenced. This field is
|
// Namespace is the namespace of the resource being referenced. This field is
|
||||||
// required when scope is set to "Namespace" and must be unset when scope is set to
|
// required when scope is set to "Namespace" and must be unset when scope is set to
|
||||||
// "Cluster".
|
// "Cluster".
|
||||||
// +optional
|
// +optional
|
||||||
// +featureGate=IngressClassNamespacedParams
|
|
||||||
Namespace *string `json:"namespace,omitempty" protobuf:"bytes,5,opt,name=namespace"`
|
Namespace *string `json:"namespace,omitempty" protobuf:"bytes,5,opt,name=namespace"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ var map_IngressClassParametersReference = map[string]string{
|
|||||||
"apiGroup": "APIGroup is the group for the resource being referenced. If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required.",
|
"apiGroup": "APIGroup is the group for the resource being referenced. If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required.",
|
||||||
"kind": "Kind is the type of resource being referenced.",
|
"kind": "Kind is the type of resource being referenced.",
|
||||||
"name": "Name is the name of resource being referenced.",
|
"name": "Name is the name of resource being referenced.",
|
||||||
"scope": "Scope represents if this refers to a cluster or namespace scoped resource. This may be set to \"Cluster\" (default) or \"Namespace\". Field can be enabled with IngressClassNamespacedParams feature gate.",
|
"scope": "Scope represents if this refers to a cluster or namespace scoped resource. This may be set to \"Cluster\" (default) or \"Namespace\".",
|
||||||
"namespace": "Namespace is the namespace of the resource being referenced. This field is required when scope is set to \"Namespace\" and must be unset when scope is set to \"Cluster\".",
|
"namespace": "Namespace is the namespace of the resource being referenced. This field is required when scope is set to \"Namespace\" and must be unset when scope is set to \"Cluster\".",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,16 +154,12 @@ message IngressClassParametersReference {
|
|||||||
|
|
||||||
// Scope represents if this refers to a cluster or namespace scoped resource.
|
// Scope represents if this refers to a cluster or namespace scoped resource.
|
||||||
// This may be set to "Cluster" (default) or "Namespace".
|
// This may be set to "Cluster" (default) or "Namespace".
|
||||||
// Field can be enabled with IngressClassNamespacedParams feature gate.
|
|
||||||
// +optional
|
|
||||||
// +featureGate=IngressClassNamespacedParams
|
|
||||||
optional string scope = 4;
|
optional string scope = 4;
|
||||||
|
|
||||||
// Namespace is the namespace of the resource being referenced. This field is
|
// Namespace is the namespace of the resource being referenced. This field is
|
||||||
// required when scope is set to "Namespace" and must be unset when scope is set to
|
// required when scope is set to "Namespace" and must be unset when scope is set to
|
||||||
// "Cluster".
|
// "Cluster".
|
||||||
// +optional
|
// +optional
|
||||||
// +featureGate=IngressClassNamespacedParams
|
|
||||||
optional string namespace = 5;
|
optional string namespace = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,15 +337,11 @@ type IngressClassParametersReference struct {
|
|||||||
Name string `json:"name" protobuf:"bytes,3,opt,name=name"`
|
Name string `json:"name" protobuf:"bytes,3,opt,name=name"`
|
||||||
// Scope represents if this refers to a cluster or namespace scoped resource.
|
// Scope represents if this refers to a cluster or namespace scoped resource.
|
||||||
// This may be set to "Cluster" (default) or "Namespace".
|
// This may be set to "Cluster" (default) or "Namespace".
|
||||||
// Field can be enabled with IngressClassNamespacedParams feature gate.
|
|
||||||
// +optional
|
|
||||||
// +featureGate=IngressClassNamespacedParams
|
|
||||||
Scope *string `json:"scope" protobuf:"bytes,4,opt,name=scope"`
|
Scope *string `json:"scope" protobuf:"bytes,4,opt,name=scope"`
|
||||||
// Namespace is the namespace of the resource being referenced. This field is
|
// Namespace is the namespace of the resource being referenced. This field is
|
||||||
// required when scope is set to "Namespace" and must be unset when scope is set to
|
// required when scope is set to "Namespace" and must be unset when scope is set to
|
||||||
// "Cluster".
|
// "Cluster".
|
||||||
// +optional
|
// +optional
|
||||||
// +featureGate=IngressClassNamespacedParams
|
|
||||||
Namespace *string `json:"namespace,omitempty" protobuf:"bytes,5,opt,name=namespace"`
|
Namespace *string `json:"namespace,omitempty" protobuf:"bytes,5,opt,name=namespace"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ var map_IngressClassParametersReference = map[string]string{
|
|||||||
"apiGroup": "APIGroup is the group for the resource being referenced. If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required.",
|
"apiGroup": "APIGroup is the group for the resource being referenced. If APIGroup is not specified, the specified Kind must be in the core API group. For any other third-party types, APIGroup is required.",
|
||||||
"kind": "Kind is the type of resource being referenced.",
|
"kind": "Kind is the type of resource being referenced.",
|
||||||
"name": "Name is the name of resource being referenced.",
|
"name": "Name is the name of resource being referenced.",
|
||||||
"scope": "Scope represents if this refers to a cluster or namespace scoped resource. This may be set to \"Cluster\" (default) or \"Namespace\". Field can be enabled with IngressClassNamespacedParams feature gate.",
|
"scope": "Scope represents if this refers to a cluster or namespace scoped resource. This may be set to \"Cluster\" (default) or \"Namespace\".",
|
||||||
"namespace": "Namespace is the namespace of the resource being referenced. This field is required when scope is set to \"Namespace\" and must be unset when scope is set to \"Cluster\".",
|
"namespace": "Namespace is the namespace of the resource being referenced. This field is required when scope is set to \"Namespace\" and must be unset when scope is set to \"Cluster\".",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@ import (
|
|||||||
clientset "k8s.io/client-go/kubernetes"
|
clientset "k8s.io/client-go/kubernetes"
|
||||||
"k8s.io/kubernetes/test/e2e/framework"
|
"k8s.io/kubernetes/test/e2e/framework"
|
||||||
"k8s.io/kubernetes/test/e2e/network/common"
|
"k8s.io/kubernetes/test/e2e/network/common"
|
||||||
|
utilpointer "k8s.io/utils/pointer"
|
||||||
|
|
||||||
"github.com/onsi/ginkgo"
|
"github.com/onsi/ginkgo"
|
||||||
)
|
)
|
||||||
@ -96,6 +97,43 @@ var _ = common.SIGDescribe("IngressClass [Feature:Ingress]", func() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
ginkgo.It("should allow IngressClass to have Namespace-scoped parameters [Serial]", func() {
|
||||||
|
ingressClass := &networkingv1.IngressClass{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: "ingressclass1",
|
||||||
|
Labels: map[string]string{
|
||||||
|
"ingressclass": f.UniqueName,
|
||||||
|
"special-label": "generic",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Spec: networkingv1.IngressClassSpec{
|
||||||
|
Controller: "example.com/controller",
|
||||||
|
Parameters: &networkingv1.IngressClassParametersReference{
|
||||||
|
Scope: utilpointer.StringPtr("Namespace"),
|
||||||
|
Namespace: utilpointer.StringPtr("foo-ns"),
|
||||||
|
Kind: "fookind",
|
||||||
|
Name: "fooname",
|
||||||
|
APIGroup: utilpointer.StringPtr("example.com"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
createdIngressClass, err := cs.NetworkingV1().IngressClasses().Create(context.TODO(), ingressClass, metav1.CreateOptions{})
|
||||||
|
framework.ExpectNoError(err)
|
||||||
|
defer deleteIngressClass(cs, createdIngressClass.Name)
|
||||||
|
|
||||||
|
if createdIngressClass.Spec.Parameters == nil {
|
||||||
|
framework.Failf("Expected IngressClass.spec.parameters to be set")
|
||||||
|
}
|
||||||
|
scope := ""
|
||||||
|
if createdIngressClass.Spec.Parameters.Scope != nil {
|
||||||
|
scope = *createdIngressClass.Spec.Parameters.Scope
|
||||||
|
}
|
||||||
|
|
||||||
|
if scope != "Namespace" {
|
||||||
|
framework.Failf("Expected IngressClass.spec.parameters.scope to be set to 'Namespace', got %v", scope)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
func createIngressClass(cs clientset.Interface, name string, isDefault bool, uniqueName string) (*networkingv1.IngressClass, error) {
|
func createIngressClass(cs clientset.Interface, name string, isDefault bool, uniqueName string) (*networkingv1.IngressClass, error) {
|
||||||
|
Loading…
Reference in New Issue
Block a user