diff --git a/pkg/apis/networking/validation/validation.go b/pkg/apis/networking/validation/validation.go index cb1d1a6d331..eb08bf23c86 100644 --- a/pkg/apis/networking/validation/validation.go +++ b/pkg/apis/networking/validation/validation.go @@ -277,9 +277,9 @@ func ValidateIngressCreate(ingress *networking.Ingress) field.ErrorList { } allErrs = append(allErrs, validateIngress(ingress, opts)...) annotationVal, annotationIsSet := ingress.Annotations[annotationIngressClass] - if annotationIsSet && ingress.Spec.IngressClassName != nil { + if annotationIsSet && ingress.Spec.IngressClassName != nil && annotationVal != *ingress.Spec.IngressClassName { annotationPath := field.NewPath("annotations").Child(annotationIngressClass) - allErrs = append(allErrs, field.Invalid(annotationPath, annotationVal, "can not be set when the class field is also set")) + allErrs = append(allErrs, field.Invalid(annotationPath, annotationVal, "must match `ingressClassName` when both are specified")) } return allErrs } diff --git a/pkg/apis/networking/validation/validation_test.go b/pkg/apis/networking/validation/validation_test.go index b575d486945..65f1a494aff 100644 --- a/pkg/apis/networking/validation/validation_test.go +++ b/pkg/apis/networking/validation/validation_test.go @@ -993,12 +993,19 @@ func TestValidateIngressCreate(t *testing.T) { }, expectedErrs: field.ErrorList{}, }, - "class field and annotation set": { + "class field and annotation set with same value": { + tweakIngress: func(ingress *networking.Ingress) { + ingress.Spec.IngressClassName = utilpointer.String("foo") + ingress.Annotations = map[string]string{annotationIngressClass: "foo"} + }, + expectedErrs: field.ErrorList{}, + }, + "class field and annotation set with different value": { tweakIngress: func(ingress *networking.Ingress) { ingress.Spec.IngressClassName = utilpointer.String("bar") ingress.Annotations = map[string]string{annotationIngressClass: "foo"} }, - expectedErrs: field.ErrorList{field.Invalid(field.NewPath("annotations").Child(annotationIngressClass), "foo", "can not be set when the class field is also set")}, + expectedErrs: field.ErrorList{field.Invalid(field.NewPath("annotations").Child(annotationIngressClass), "foo", "must match `ingressClassName` when both are specified")}, }, "valid regex path": { tweakIngress: func(ingress *networking.Ingress) { diff --git a/pkg/registry/networking/ingress/strategy.go b/pkg/registry/networking/ingress/strategy.go index fc934d796d1..a23763b9f3d 100644 --- a/pkg/registry/networking/ingress/strategy.go +++ b/pkg/registry/networking/ingress/strategy.go @@ -18,6 +18,7 @@ package ingress import ( "context" + "fmt" apiequality "k8s.io/apimachinery/pkg/api/equality" "k8s.io/apimachinery/pkg/runtime" @@ -29,6 +30,10 @@ import ( "sigs.k8s.io/structured-merge-diff/v4/fieldpath" ) +const ( + annotationIngressClass = "kubernetes.io/ingress.class" +) + // ingressStrategy implements verification logic for Replication Ingress. type ingressStrategy struct { runtime.ObjectTyper @@ -93,7 +98,15 @@ func (ingressStrategy) Validate(ctx context.Context, obj runtime.Object) field.E } // WarningsOnCreate returns warnings for the creation of the given object. -func (ingressStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil } +func (ingressStrategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { + var warnings []string + ingress := obj.(*networking.Ingress) + _, annotationIsSet := ingress.Annotations[annotationIngressClass] + if annotationIsSet && ingress.Spec.IngressClassName == nil { + warnings = append(warnings, fmt.Sprintf("annotation %q is deprecated, please use 'spec.ingressClassName' instead", annotationIngressClass)) + } + return warnings +} // Canonicalize normalizes the object after validation. func (ingressStrategy) Canonicalize(obj runtime.Object) {