generated from kubernetes/kubernetes-template-project
-
Notifications
You must be signed in to change notification settings - Fork 480
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Conformance test for listener isolation (#3047)
* Conformance test for listener isolation Takes #2669 forward Signed-off-by: Arko Dasgupta <[email protected]> Co-authored-by: Michael Pleshakov <[email protected]> * use features package Signed-off-by: Arko Dasgupta <[email protected]> --------- Signed-off-by: Arko Dasgupta <[email protected]> Co-authored-by: Michael Pleshakov <[email protected]>
- Loading branch information
Showing
4 changed files
with
424 additions
and
0 deletions.
There are no files selected for viewing
131 changes: 131 additions & 0 deletions
131
conformance/tests/gateway-http-listener-isolation-with-hostname-intersection.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
apiVersion: gateway.networking.k8s.io/v1 | ||
kind: Gateway | ||
metadata: | ||
name: http-listener-isolation-with-hostname-intersection | ||
namespace: gateway-conformance-infra | ||
spec: | ||
gatewayClassName: "{GATEWAY_CLASS_NAME}" | ||
listeners: | ||
- name: empty-hostname | ||
port: 80 | ||
protocol: HTTP | ||
allowedRoutes: | ||
namespaces: | ||
from: All | ||
- name: wildcard-example-com | ||
port: 80 | ||
protocol: HTTP | ||
hostname: "*.example.com" | ||
allowedRoutes: | ||
namespaces: | ||
from: All | ||
- name: wildcard-foo-example-com | ||
port: 80 | ||
protocol: HTTP | ||
hostname: "*.foo.example.com" | ||
allowedRoutes: | ||
namespaces: | ||
from: All | ||
- name: abc-foo-example-com | ||
port: 80 | ||
protocol: HTTP | ||
hostname: "abc.foo.example.com" | ||
allowedRoutes: | ||
namespaces: | ||
from: All | ||
--- | ||
apiVersion: gateway.networking.k8s.io/v1 | ||
kind: HTTPRoute | ||
metadata: | ||
name: attaches-to-empty-hostname-with-hostname-intersection | ||
namespace: gateway-conformance-infra | ||
spec: | ||
parentRefs: | ||
- name: http-listener-isolation-with-hostname-intersection | ||
namespace: gateway-conformance-infra | ||
sectionName: empty-hostname | ||
hostnames: | ||
- "bar.com" | ||
- "*.example.com" # request matching is prevented by the isolation wildcard-example-com listener | ||
- "*.foo.example.com" # request matching is prevented by the isolation wildcard-foo-example-com listener | ||
- "abc.foo.example.com" # request matching is prevented by the isolation of abc-foo-example-com listener | ||
rules: | ||
- matches: | ||
- path: | ||
type: PathPrefix | ||
value: /empty-hostname | ||
backendRefs: | ||
- name: infra-backend-v1 | ||
port: 8080 | ||
--- | ||
apiVersion: gateway.networking.k8s.io/v1 | ||
kind: HTTPRoute | ||
metadata: | ||
name: attaches-to-wildcard-example-com-with-hostname-intersection | ||
namespace: gateway-conformance-infra | ||
spec: | ||
parentRefs: | ||
- name: http-listener-isolation-with-hostname-intersection | ||
namespace: gateway-conformance-infra | ||
sectionName: wildcard-example-com | ||
hostnames: | ||
- "bar.com" # doesn't match wildcard-example-com listener | ||
- "*.example.com" | ||
- "*.foo.example.com" # request matching is prevented by the isolation of wildcard-foo-example-com listener | ||
- "abc.foo.example.com" # request matching is prevented by the isolation of abc-foo-example-com listener | ||
rules: | ||
- matches: | ||
- path: | ||
type: PathPrefix | ||
value: /wildcard-example-com | ||
backendRefs: | ||
- name: infra-backend-v1 | ||
port: 8080 | ||
--- | ||
apiVersion: gateway.networking.k8s.io/v1 | ||
kind: HTTPRoute | ||
metadata: | ||
name: attaches-to-wildcard-foo-example-com-with-hostname-intersection | ||
namespace: gateway-conformance-infra | ||
spec: | ||
parentRefs: | ||
- name: http-listener-isolation-with-hostname-intersection | ||
namespace: gateway-conformance-infra | ||
sectionName: wildcard-foo-example-com | ||
hostnames: | ||
- "bar.com" # doesn't match wildcard-foo-example-com listener | ||
- "*.example.com" # this becomes *.foo.example.com, as the hostname cannot be less specific than *.foo.example.com of the listener | ||
- "*.foo.example.com" | ||
- "abc.foo.example.com" # request matching is prevented by the isolation abc-foo-example-com listener | ||
rules: | ||
- matches: | ||
- path: | ||
type: PathPrefix | ||
value: /wildcard-foo-example-com | ||
backendRefs: | ||
- name: infra-backend-v1 | ||
port: 8080 | ||
--- | ||
apiVersion: gateway.networking.k8s.io/v1 | ||
kind: HTTPRoute | ||
metadata: | ||
name: attaches-to-abc-foo-example-com-with-hostname-intersection | ||
namespace: gateway-conformance-infra | ||
spec: | ||
parentRefs: | ||
- name: http-listener-isolation-with-hostname-intersection | ||
namespace: gateway-conformance-infra | ||
sectionName: abc-foo-example-com | ||
hostnames: | ||
- "bar.com" # doesn't match abc-foo-example-com listener | ||
- "*.example.com" # becomes abc.foo.example.com as it cannot be less specific than abc.foo.example.com of the listener | ||
- "*.foo.example.com" # becomes abc.foo.example.com as it cannot be less specific than abc.foo.example.com of the listener | ||
- "abc.foo.example.com" | ||
rules: | ||
- matches: | ||
- path: | ||
type: PathPrefix | ||
value: /abc-foo-example-com | ||
backendRefs: | ||
- name: infra-backend-v1 | ||
port: 8080 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
/* | ||
Copyright 2024 The Kubernetes Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package tests | ||
|
||
import ( | ||
"testing" | ||
|
||
"k8s.io/apimachinery/pkg/types" | ||
|
||
"sigs.k8s.io/gateway-api/conformance/utils/http" | ||
"sigs.k8s.io/gateway-api/conformance/utils/kubernetes" | ||
"sigs.k8s.io/gateway-api/conformance/utils/suite" | ||
"sigs.k8s.io/gateway-api/pkg/features" | ||
) | ||
|
||
func init() { | ||
ConformanceTests = append(ConformanceTests, GatewayHTTPListenerIsolation) | ||
} | ||
|
||
var GatewayHTTPListenerIsolation = suite.ConformanceTest{ | ||
ShortName: "GatewayHTTPListenerIsolation", | ||
Description: "Listener isolation for HTTP listeners with multiple listeners and HTTPRoutes", | ||
Features: []features.SupportedFeature{ | ||
features.SupportGateway, | ||
features.SupportGatewayHTTPListenerIsolation, | ||
features.SupportHTTPRoute, | ||
}, | ||
Manifests: []string{ | ||
"tests/gateway-http-listener-isolation.yaml", | ||
"tests/gateway-http-listener-isolation-with-hostname-intersection.yaml", | ||
}, | ||
Test: func(t *testing.T, suite *suite.ConformanceTestSuite) { | ||
ns := "gateway-conformance-infra" | ||
|
||
kubernetes.NamespacesMustBeReady(t, suite.Client, suite.TimeoutConfig, []string{ns}) | ||
|
||
testCases := []http.ExpectedResponse{ | ||
// Requests to the empty-hostname listener | ||
{ | ||
Request: http.Request{Host: "bar.com", Path: "/empty-hostname"}, | ||
Backend: "infra-backend-v1", | ||
Namespace: ns, | ||
}, | ||
{ | ||
Request: http.Request{Host: "bar.com", Path: "/wildcard-example-com"}, | ||
Response: http.Response{StatusCode: 404}, | ||
}, | ||
{ | ||
Request: http.Request{Host: "bar.com", Path: "/wildcard-foo-example-com"}, | ||
Response: http.Response{StatusCode: 404}, | ||
}, | ||
{ | ||
Request: http.Request{Host: "bar.com", Path: "/abc-foo-example-com"}, | ||
Response: http.Response{StatusCode: 404}, | ||
}, | ||
// Requests to the wildcard-example-com listener | ||
{ | ||
Request: http.Request{Host: "bar.example.com", Path: "/empty-hostname"}, | ||
Response: http.Response{StatusCode: 404}, | ||
}, | ||
{ | ||
Request: http.Request{Host: "bar.example.com", Path: "/wildcard-example-com"}, | ||
Backend: "infra-backend-v1", | ||
Namespace: ns, | ||
}, | ||
{ | ||
Request: http.Request{Host: "bar.example.com", Path: "/wildcard-foo-example-com"}, | ||
Response: http.Response{StatusCode: 404}, | ||
}, | ||
{ | ||
Request: http.Request{Host: "bar.example.com", Path: "/abc-foo-example-com"}, | ||
Response: http.Response{StatusCode: 404}, | ||
}, | ||
// Requests to the foo-wildcard-example-com listener | ||
{ | ||
Request: http.Request{Host: "bar.foo.example.com", Path: "/empty-hostname"}, | ||
Response: http.Response{StatusCode: 404}, | ||
}, | ||
{ | ||
Request: http.Request{Host: "bar.foo.example.com", Path: "/wildcard-example-com"}, | ||
Response: http.Response{StatusCode: 404}, | ||
}, | ||
{ | ||
Request: http.Request{Host: "bar.foo.example.com", Path: "/wildcard-foo-example-com"}, | ||
Backend: "infra-backend-v1", | ||
Namespace: ns, | ||
}, | ||
{ | ||
Request: http.Request{Host: "bar.foo.example.com", Path: "/abc-foo-example-com"}, | ||
Response: http.Response{StatusCode: 404}, | ||
}, | ||
// Requests to the abc-foo-example-com listener | ||
{ | ||
Request: http.Request{Host: "abc.foo.example.com", Path: "/empty-hostname"}, | ||
Response: http.Response{StatusCode: 404}, | ||
}, | ||
{ | ||
Request: http.Request{Host: "abc.foo.example.com", Path: "/wildcard-example-com"}, | ||
Response: http.Response{StatusCode: 404}, | ||
}, | ||
{ | ||
Request: http.Request{Host: "abc.foo.example.com", Path: "/wildcard-foo-example-com"}, | ||
Response: http.Response{StatusCode: 404}, | ||
Namespace: ns, | ||
}, | ||
{ | ||
Request: http.Request{Host: "abc.foo.example.com", Path: "/abc-foo-example-com"}, | ||
Backend: "infra-backend-v1", | ||
Namespace: ns, | ||
}, | ||
} | ||
|
||
t.Run("hostnames are configured only in listeners", func(t *testing.T) { | ||
gwNN := types.NamespacedName{Name: "http-listener-isolation", Namespace: ns} | ||
routes := []types.NamespacedName{ | ||
{Namespace: ns, Name: "attaches-to-empty-hostname"}, | ||
{Namespace: ns, Name: "attaches-to-wildcard-example-com"}, | ||
{Namespace: ns, Name: "attaches-to-wildcard-foo-example-com"}, | ||
{Namespace: ns, Name: "attaches-to-abc-foo-example-com"}, | ||
} | ||
|
||
gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routes...) | ||
for _, routeNN := range routes { | ||
kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN) | ||
} | ||
|
||
for i := range testCases { | ||
// Declare tc here to avoid loop variable | ||
// reuse issues across parallel tests. | ||
tc := testCases[i] | ||
t.Run(tc.GetTestCaseName(i), func(t *testing.T) { | ||
t.Parallel() | ||
http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc) | ||
}) | ||
} | ||
}) | ||
|
||
t.Run("intersecting hostnames are configured in listeners and HTTPRoutes", func(t *testing.T) { | ||
gwNN := types.NamespacedName{Name: "http-listener-isolation-with-hostname-intersection", Namespace: ns} | ||
routes := []types.NamespacedName{ | ||
{Namespace: ns, Name: "attaches-to-empty-hostname-with-hostname-intersection"}, | ||
{Namespace: ns, Name: "attaches-to-wildcard-example-com-with-hostname-intersection"}, | ||
{Namespace: ns, Name: "attaches-to-wildcard-foo-example-com-with-hostname-intersection"}, | ||
{Namespace: ns, Name: "attaches-to-abc-foo-example-com-with-hostname-intersection"}, | ||
} | ||
|
||
gwAddr := kubernetes.GatewayAndHTTPRoutesMustBeAccepted(t, suite.Client, suite.TimeoutConfig, suite.ControllerName, kubernetes.NewGatewayRef(gwNN), routes...) | ||
for _, routeNN := range routes { | ||
kubernetes.HTTPRouteMustHaveResolvedRefsConditionsTrue(t, suite.Client, suite.TimeoutConfig, routeNN, gwNN) | ||
} | ||
|
||
for i := range testCases { | ||
// Declare tc here to avoid loop variable | ||
// reuse issues across parallel tests. | ||
tc := testCases[i] | ||
t.Run(tc.GetTestCaseName(i), func(t *testing.T) { | ||
t.Parallel() | ||
http.MakeRequestAndExpectEventuallyConsistentResponse(t, suite.RoundTripper, suite.TimeoutConfig, gwAddr, tc) | ||
}) | ||
} | ||
}) | ||
}, | ||
} |
Oops, something went wrong.