diff --git a/pkg/apis/networking/v1alpha1/ingress_validation.go b/pkg/apis/networking/v1alpha1/ingress_validation.go index dfad48ad2153..22ecaed51f3b 100644 --- a/pkg/apis/networking/v1alpha1/ingress_validation.go +++ b/pkg/apis/networking/v1alpha1/ingress_validation.go @@ -27,6 +27,7 @@ import ( // Validate inspects and validates Ingress object. func (i *Ingress) Validate(ctx context.Context) *apis.FieldError { + ctx = apis.WithinParent(ctx, i.ObjectMeta) return i.Spec.Validate(apis.WithinSpec(ctx)).ViaField("spec") } @@ -102,7 +103,7 @@ func (h HTTPIngressPath) Validate(ctx context.Context) *apis.FieldError { if (len(h.Splits) != 1 || totalPct != 0) && totalPct != 100 { // Total traffic split percentage must sum up to 100%. all = all.Also(&apis.FieldError{ - Message: "Traffic split percentage must total to 100, but was " + strconv.Itoa(totalPct), + Message: "traffic split percentage must total to 100, but was " + strconv.Itoa(totalPct), Paths: []string{"splits"}, }) } @@ -137,6 +138,11 @@ func (b IngressBackend) Validate(ctx context.Context) *apis.FieldError { var all *apis.FieldError if b.ServiceNamespace == "" { all = all.Also(apis.ErrMissingField("serviceNamespace")) + } else if b.ServiceNamespace != apis.ParentMeta(ctx).Namespace { + all = all.Also(&apis.FieldError{ + Message: "service namespace must match ingress namespace", + Paths: []string{"serviceNamespace"}, + }) } if b.ServiceName == "" { all = all.Also(apis.ErrMissingField("serviceName")) diff --git a/pkg/apis/networking/v1alpha1/ingress_validation_test.go b/pkg/apis/networking/v1alpha1/ingress_validation_test.go index b47ba4be20c0..6d3c501f177e 100644 --- a/pkg/apis/networking/v1alpha1/ingress_validation_test.go +++ b/pkg/apis/networking/v1alpha1/ingress_validation_test.go @@ -21,6 +21,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" "knative.dev/pkg/apis" ) @@ -245,7 +246,7 @@ func TestIngressSpecValidation(t *testing.T) { }}, }, want: &apis.FieldError{ - Message: "Traffic split percentage must total to 100, but was 30", + Message: "traffic split percentage must total to 100, but was 30", Paths: []string{"rules[0].http.paths[0].splits"}, }, }, { @@ -336,15 +337,17 @@ func TestIngressSpecValidation(t *testing.T) { want: apis.ErrMissingField("tls[0].secretName"), }} + ctx := apis.WithinParent(context.Background(), metav1.ObjectMeta{Namespace: "default", Name: "test-ingress"}) for _, test := range tests { t.Run(test.name, func(t *testing.T) { - got := test.is.Validate(context.Background()) + got := test.is.Validate(ctx) if diff := cmp.Diff(test.want.Error(), got.Error()); diff != "" { t.Errorf("Validate (-want, +got) = %v", diff) } }) } } + func TestIngressValidation(t *testing.T) { tests := []struct { name string @@ -353,6 +356,10 @@ func TestIngressValidation(t *testing.T) { }{{ name: "valid", ci: &Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "default", + Name: "test-ingress", + }, Spec: IngressSpec{ TLS: []IngressTLS{{ SecretNamespace: "secret-space", @@ -378,6 +385,41 @@ func TestIngressValidation(t *testing.T) { }, }, want: nil, + }, { + name: "ingress-namespace-different-with-service", + ci: &Ingress{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "test", + Name: "test-ingress", + }, + Spec: IngressSpec{ + TLS: []IngressTLS{{ + SecretNamespace: "secret-space", + SecretName: "secret-name", + }}, + Rules: []IngressRule{{ + Hosts: []string{"example.com"}, + HTTP: &HTTPIngressRuleValue{ + Paths: []HTTPIngressPath{{ + Splits: []IngressBackendSplit{{ + IngressBackend: IngressBackend{ + ServiceName: "revision-000", + ServiceNamespace: "default", + ServicePort: intstr.FromInt(8080), + }, + }}, + Retries: &HTTPRetry{ + Attempts: 3, + }, + }}, + }, + }}, + }, + }, + want: &apis.FieldError{ + Message: "service namespace must match ingress namespace", + Paths: []string{"spec.rules[0].http.paths[0].splits[0].serviceNamespace"}, + }, }} for _, test := range tests {