Skip to content

Commit cbea9a4

Browse files
AlinsRanCopilot
andcommitted
test: add L4RoutePolicy e2e tests for TCPRoute
- Add L4RoutePolicyMustHaveCondition and PollUntilL4RoutePolicyHaveStatus framework helpers (mirroring HTTPRoutePolicy pattern) - Add ApplyL4RoutePolicy scaffold helper - Add e2e test 'L4RoutePolicy blocks traffic via ip-restriction plugin': 1. Create TCPRoute, verify traffic works 2. Apply L4RoutePolicy with ip-restriction blacklist 0.0.0.0/0 3. Verify traffic is blocked 4. Delete L4RoutePolicy, verify traffic recovers Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 261bfc9 commit cbea9a4

3 files changed

Lines changed: 142 additions & 0 deletions

File tree

test/e2e/framework/assertion.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,38 @@ func PollUntilHTTPRoutePolicyHaveStatus(cli client.Client, timeout time.Duration
102102
return genericPollResource(new(v1alpha1.HTTPRoutePolicy), cli, timeout, hrpNN, f)
103103
}
104104

105+
func L4RoutePolicyMustHaveCondition(t testing.TestingT, client client.Client, timeout time.Duration, refNN, policyNN types.NamespacedName,
106+
condition metav1.Condition) {
107+
err := PollUntilL4RoutePolicyHaveStatus(client, timeout, policyNN, func(policy *v1alpha1.L4RoutePolicy) bool {
108+
for _, ancestor := range policy.Status.Ancestors {
109+
if err := kubernetes.ConditionsHaveLatestObservedGeneration(policy, ancestor.Conditions); err != nil {
110+
log.Printf("L4RoutePolicy %s (ancestorRef=%v) %v", policyNN, parentRefToString(ancestor.AncestorRef), err)
111+
return false
112+
}
113+
114+
if ancestor.AncestorRef.Name == gatewayv1.ObjectName(refNN.Name) &&
115+
(refNN.Namespace == "" || (ancestor.AncestorRef.Namespace != nil && string(*ancestor.AncestorRef.Namespace) == refNN.Namespace)) {
116+
if findConditionInList(ancestor.Conditions, condition) {
117+
log.Printf("found condition %v in list %v for %s reference %s", condition, ancestor.Conditions, policyNN, refNN)
118+
return true
119+
}
120+
log.Printf("NOT FOUND condition %v in %v for %s reference %s", condition, ancestor.Conditions, policyNN, refNN)
121+
}
122+
}
123+
return false
124+
})
125+
126+
require.NoError(t, err, "error waiting for L4RoutePolicy %s status to have a Condition matching %+v", policyNN, condition)
127+
}
128+
129+
func PollUntilL4RoutePolicyHaveStatus(cli client.Client, timeout time.Duration, policyNN types.NamespacedName,
130+
f func(policy *v1alpha1.L4RoutePolicy) bool) error {
131+
if err := v1alpha1.AddToScheme(cli.Scheme()); err != nil {
132+
return err
133+
}
134+
return genericPollResource(new(v1alpha1.L4RoutePolicy), cli, timeout, policyNN, f)
135+
}
136+
105137
func APIv2MustHaveCondition(t testing.TestingT, cli client.Client, timeout time.Duration, nn types.NamespacedName, obj client.Object, cond metav1.Condition) {
106138
f := func(object client.Object) bool {
107139
value := reflect.Indirect(reflect.ValueOf(object))

test/e2e/gatewayapi/tcproute.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ import (
2323

2424
. "github.com/onsi/ginkgo/v2"
2525
. "github.com/onsi/gomega"
26+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27+
"k8s.io/apimachinery/pkg/types"
28+
gatewayv1alpha2 "sigs.k8s.io/gateway-api/apis/v1alpha2"
2629

2730
"github.com/apache/apisix-ingress-controller/test/e2e/scaffold"
2831
)
@@ -105,4 +108,95 @@ spec:
105108
s.HTTPOverTCPConnectAssert(false, time.Minute*3)
106109
})
107110
})
111+
112+
Context("TCPRoute With L4RoutePolicy", func() {
113+
var tcpGateway = `
114+
apiVersion: gateway.networking.k8s.io/v1
115+
kind: Gateway
116+
metadata:
117+
name: %s
118+
spec:
119+
gatewayClassName: %s
120+
listeners:
121+
- name: tcp
122+
protocol: TCP
123+
port: 80
124+
allowedRoutes:
125+
kinds:
126+
- kind: TCPRoute
127+
infrastructure:
128+
parametersRef:
129+
group: apisix.apache.org
130+
kind: GatewayProxy
131+
name: apisix-proxy-config
132+
`
133+
134+
var tcpRoute = `
135+
apiVersion: gateway.networking.k8s.io/v1alpha2
136+
kind: TCPRoute
137+
metadata:
138+
name: tcp-l4policy
139+
spec:
140+
parentRefs:
141+
- name: %s
142+
sectionName: tcp
143+
rules:
144+
- backendRefs:
145+
- name: httpbin-service-e2e-test
146+
port: 80
147+
`
148+
149+
// ip-restriction with blacklist covering all IPv4 addresses blocks all TCP connections.
150+
var l4RoutePolicyBlockAll = `
151+
apiVersion: apisix.apache.org/v1alpha1
152+
kind: L4RoutePolicy
153+
metadata:
154+
name: tcp-block-all
155+
spec:
156+
targetRefs:
157+
- group: gateway.networking.k8s.io
158+
kind: TCPRoute
159+
name: tcp-l4policy
160+
plugins:
161+
- name: ip-restriction
162+
config:
163+
blacklist:
164+
- "0.0.0.0/0"
165+
`
166+
167+
BeforeEach(func() {
168+
Expect(s.CreateResourceFromString(s.GetGatewayProxySpec())).NotTo(HaveOccurred(), "creating GatewayProxy")
169+
Expect(s.CreateResourceFromString(s.GetGatewayClassYaml())).NotTo(HaveOccurred(), "creating GatewayClass")
170+
Expect(s.CreateResourceFromString(fmt.Sprintf(tcpGateway, s.Namespace(), s.Namespace()))).
171+
NotTo(HaveOccurred(), "creating Gateway")
172+
})
173+
174+
It("L4RoutePolicy blocks traffic via ip-restriction plugin", func() {
175+
By("creating TCPRoute")
176+
s.ResourceApplied("TCPRoute", "tcp-l4policy", fmt.Sprintf(tcpRoute, s.Namespace()), 1)
177+
178+
By("verifying TCP traffic works before applying L4RoutePolicy")
179+
s.HTTPOverTCPConnectAssert(true, time.Minute*3)
180+
181+
By("applying L4RoutePolicy with ip-restriction blacklist")
182+
s.ApplyL4RoutePolicy(
183+
types.NamespacedName{Name: s.Namespace()},
184+
types.NamespacedName{Namespace: s.Namespace(), Name: "tcp-block-all"},
185+
l4RoutePolicyBlockAll,
186+
metav1.Condition{
187+
Type: string(gatewayv1alpha2.PolicyConditionAccepted),
188+
Status: metav1.ConditionTrue,
189+
},
190+
)
191+
192+
By("verifying TCP traffic is blocked by the L4RoutePolicy")
193+
s.HTTPOverTCPConnectAssert(false, time.Minute*3)
194+
195+
By("deleting L4RoutePolicy")
196+
Expect(s.DeleteResource("L4RoutePolicy", "tcp-block-all")).NotTo(HaveOccurred(), "deleting L4RoutePolicy")
197+
198+
By("verifying TCP traffic recovers after L4RoutePolicy deletion")
199+
s.HTTPOverTCPConnectAssert(true, time.Minute*3)
200+
})
201+
})
108202
})

test/e2e/scaffold/k8s.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,22 @@ func (s *Scaffold) ApplyHTTPRoutePolicy(refNN, hrpNN types.NamespacedName, spec
292292
}
293293
}
294294

295+
func (s *Scaffold) ApplyL4RoutePolicy(refNN, policyNN types.NamespacedName, spec string, conditions ...metav1.Condition) {
296+
err := s.CreateResourceFromString(spec)
297+
Expect(err).NotTo(HaveOccurred(), "creating L4RoutePolicy %s", policyNN)
298+
if len(conditions) == 0 {
299+
conditions = []metav1.Condition{
300+
{
301+
Type: string(v1alpha2.PolicyConditionAccepted),
302+
Status: metav1.ConditionTrue,
303+
},
304+
}
305+
}
306+
for _, condition := range conditions {
307+
framework.L4RoutePolicyMustHaveCondition(s.GinkgoT, s.K8sClient, 8*time.Second, refNN, policyNN, condition)
308+
}
309+
}
310+
295311
func (s *Scaffold) GetGatewayProxySpec() string {
296312
var gatewayProxyYaml = `
297313
apiVersion: apisix.apache.org/v1alpha1

0 commit comments

Comments
 (0)