Skip to content

Commit 91a7977

Browse files
authored
Merge pull request #4577 from zac-nixon/main
correct regex value handling in gateway api
2 parents 98b2f37 + d9f7fee commit 91a7977

File tree

5 files changed

+200
-3
lines changed

5 files changed

+200
-3
lines changed

pkg/gateway/routeutils/route_rule_condition.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,16 @@ func buildHttpPathCondition(path *gwv1.HTTPPathMatch) ([]elbv2model.RuleConditio
7777
pathValues = append(pathValues, pathValue)
7878
}
7979

80-
// for regex match, we do not need special processing, it will be taken as it is
80+
// for regex match, use RegexValues so ALB applies regex matching instead of glob/value matching
8181
if pathType == gwv1.PathMatchRegularExpression {
82-
pathValues = append(pathValues, pathValue)
82+
return []elbv2model.RuleCondition{
83+
{
84+
Field: elbv2model.RuleConditionFieldPathPattern,
85+
PathPatternConfig: &elbv2model.PathPatternConditionConfig{
86+
RegexValues: []string{pathValue},
87+
},
88+
},
89+
}, nil
8390
}
8491

8592
return []elbv2model.RuleCondition{

pkg/gateway/routeutils/route_rule_condition_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,7 @@ func Test_buildHttpPathCondition(t *testing.T) {
213213
{
214214
Field: elbv2model.RuleConditionFieldPathPattern,
215215
PathPatternConfig: &elbv2model.PathPatternConditionConfig{
216-
Values: []string{regexPathValue},
216+
RegexValues: []string{regexPathValue},
217217
},
218218
},
219219
},

test/e2e/gateway/alb_ip_target_test.go

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1954,4 +1954,150 @@ var _ = Describe("test k8s alb gateway using ip targets reconciled by the aws lo
19541954
})
19551955
})
19561956
})
1957+
Context("with ALB ip target configuration with HTTPRoute path match types (Exact, Prefix, RegularExpression)", func() {
1958+
BeforeEach(func() {})
1959+
It("should create listener rules with correct path-pattern condition types on the ALB", func() {
1960+
interf := elbv2gw.LoadBalancerSchemeInternetFacing
1961+
lbcSpec := elbv2gw.LoadBalancerConfigurationSpec{
1962+
Scheme: &interf,
1963+
}
1964+
ipTargetType := elbv2gw.TargetTypeIP
1965+
tgSpec := elbv2gw.TargetGroupConfigurationSpec{
1966+
DefaultConfiguration: elbv2gw.TargetGroupProps{
1967+
TargetType: &ipTargetType,
1968+
},
1969+
}
1970+
lrcSpec := elbv2gw.ListenerRuleConfigurationSpec{}
1971+
gwListeners := []gwv1.Listener{
1972+
{
1973+
Name: "test-listener",
1974+
Port: 80,
1975+
Protocol: gwv1.HTTPProtocolType,
1976+
},
1977+
}
1978+
1979+
httpr := BuildHTTPRoute([]string{}, httpRouteRulesWithPathMatchers, nil)
1980+
By("deploying stack", func() {
1981+
err := stack.DeployHTTP(ctx, nil, tf, gwListeners, []*gwv1.HTTPRoute{httpr}, lbcSpec, tgSpec, lrcSpec, nil, true)
1982+
Expect(err).NotTo(HaveOccurred())
1983+
})
1984+
1985+
By("checking gateway status for lb dns name", func() {
1986+
dnsName = stack.GetLoadBalancerIngressHostName()
1987+
Expect(dnsName).ToNot(BeEmpty())
1988+
})
1989+
1990+
By("querying AWS loadbalancer from the dns name", func() {
1991+
var err error
1992+
lbARN, err = tf.LBManager.FindLoadBalancerByDNSName(ctx, dnsName)
1993+
Expect(err).NotTo(HaveOccurred())
1994+
Expect(lbARN).ToNot(BeEmpty())
1995+
})
1996+
1997+
By("verifying AWS loadbalancer resources", func() {
1998+
expectedTargetGroups := []verifier.ExpectedTargetGroup{
1999+
{
2000+
Protocol: "HTTP",
2001+
Port: 80,
2002+
NumTargets: int(*stack.albResourceStack.commonStack.dps[0].Spec.Replicas),
2003+
TargetType: "ip",
2004+
TargetGroupHC: DEFAULT_ALB_TARGET_GROUP_HC,
2005+
},
2006+
}
2007+
err := verifier.VerifyAWSLoadBalancerResources(ctx, tf, lbARN, verifier.LoadBalancerExpectation{
2008+
Type: "application",
2009+
Scheme: "internet-facing",
2010+
Listeners: stack.albResourceStack.getListenersPortMap(),
2011+
TargetGroups: expectedTargetGroups,
2012+
})
2013+
Expect(err).NotTo(HaveOccurred())
2014+
})
2015+
2016+
By("verifying listener rules have correct path condition types", func() {
2017+
err := verifier.VerifyLoadBalancerListenerRules(ctx, tf, lbARN, int32(gwListeners[0].Port), []verifier.ListenerRuleExpectation{
2018+
{
2019+
// Rule 1: Exact path match uses Values
2020+
Conditions: []elbv2types.RuleCondition{
2021+
{
2022+
Field: awssdk.String(string(elbv2model.RuleConditionFieldPathPattern)),
2023+
PathPatternConfig: &elbv2types.PathPatternConditionConfig{
2024+
Values: []string{testExactPath},
2025+
},
2026+
},
2027+
},
2028+
Actions: []elbv2types.Action{
2029+
{
2030+
Type: elbv2types.ActionTypeEnum(elbv2model.ActionTypeForward),
2031+
ForwardConfig: &elbv2types.ForwardActionConfig{
2032+
TargetGroups: []elbv2types.TargetGroupTuple{
2033+
{
2034+
TargetGroupArn: awssdk.String(testTargetGroupArn),
2035+
Weight: awssdk.Int32(1),
2036+
},
2037+
},
2038+
},
2039+
},
2040+
},
2041+
Priority: 1,
2042+
},
2043+
{
2044+
// Rule 2: Prefix path match uses Values with wildcard expansion
2045+
Conditions: []elbv2types.RuleCondition{
2046+
{
2047+
Field: awssdk.String(string(elbv2model.RuleConditionFieldPathPattern)),
2048+
PathPatternConfig: &elbv2types.PathPatternConditionConfig{
2049+
Values: []string{testPrefixPath, fmt.Sprintf("%s/*", testPrefixPath)},
2050+
},
2051+
},
2052+
},
2053+
Actions: []elbv2types.Action{
2054+
{
2055+
Type: elbv2types.ActionTypeEnum(elbv2model.ActionTypeForward),
2056+
ForwardConfig: &elbv2types.ForwardActionConfig{
2057+
TargetGroups: []elbv2types.TargetGroupTuple{
2058+
{
2059+
TargetGroupArn: awssdk.String(testTargetGroupArn),
2060+
Weight: awssdk.Int32(1),
2061+
},
2062+
},
2063+
},
2064+
},
2065+
},
2066+
Priority: 2,
2067+
},
2068+
{
2069+
// Rule 3: RegularExpression path match uses RegexValues
2070+
Conditions: []elbv2types.RuleCondition{
2071+
{
2072+
Field: awssdk.String(string(elbv2model.RuleConditionFieldPathPattern)),
2073+
PathPatternConfig: &elbv2types.PathPatternConditionConfig{
2074+
RegexValues: []string{testRegexPath},
2075+
},
2076+
},
2077+
},
2078+
Actions: []elbv2types.Action{
2079+
{
2080+
Type: elbv2types.ActionTypeEnum(elbv2model.ActionTypeForward),
2081+
ForwardConfig: &elbv2types.ForwardActionConfig{
2082+
TargetGroups: []elbv2types.TargetGroupTuple{
2083+
{
2084+
TargetGroupArn: awssdk.String(testTargetGroupArn),
2085+
Weight: awssdk.Int32(1),
2086+
},
2087+
},
2088+
},
2089+
},
2090+
},
2091+
Priority: 3,
2092+
},
2093+
})
2094+
Expect(err).NotTo(HaveOccurred())
2095+
})
2096+
2097+
By("waiting for target group targets to be healthy", func() {
2098+
err := verifier.WaitUntilTargetsAreHealthy(ctx, tf, lbARN, int(*stack.albResourceStack.commonStack.dps[0].Spec.Replicas))
2099+
Expect(err).NotTo(HaveOccurred())
2100+
})
2101+
})
2102+
})
19572103
})

test/e2e/gateway/consts.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,4 +318,45 @@ const (
318318
testOidcAuthorizationEndpoint = "https://test-oidc-provider.example.com/oauth2/authorize"
319319
testOidcTokenEndpoint = "https://test-oidc-provider.example.com/oauth2/token"
320320
testOidcUserInfoEndpoint = "https://test-oidc-provider.example.com/oauth2/userinfo"
321+
// constants used in path matcher tests
322+
testExactPath = "/exact-match-path"
323+
testPrefixPath = "/prefix-match"
324+
testRegexPath = "/regex/[a-z]+/items"
321325
)
326+
327+
// httpRouteRulesWithPathMatchers defines HTTPRoute rules exercising Exact, Prefix, and RegularExpression path types.
328+
var httpRouteRulesWithPathMatchers = []gwv1.HTTPRouteRule{
329+
{
330+
Matches: []gwv1.HTTPRouteMatch{
331+
{
332+
Path: &gwv1.HTTPPathMatch{
333+
Type: &[]gwv1.PathMatchType{gwv1.PathMatchExact}[0],
334+
Value: awssdk.String(testExactPath),
335+
},
336+
},
337+
},
338+
BackendRefs: DefaultHttpRouteRuleBackendRefs,
339+
},
340+
{
341+
Matches: []gwv1.HTTPRouteMatch{
342+
{
343+
Path: &gwv1.HTTPPathMatch{
344+
Type: &[]gwv1.PathMatchType{gwv1.PathMatchPathPrefix}[0],
345+
Value: awssdk.String(testPrefixPath),
346+
},
347+
},
348+
},
349+
BackendRefs: DefaultHttpRouteRuleBackendRefs,
350+
},
351+
{
352+
Matches: []gwv1.HTTPRouteMatch{
353+
{
354+
Path: &gwv1.HTTPPathMatch{
355+
Type: &[]gwv1.PathMatchType{gwv1.PathMatchRegularExpression}[0],
356+
Value: awssdk.String(testRegexPath),
357+
},
358+
},
359+
},
360+
BackendRefs: DefaultHttpRouteRuleBackendRefs,
361+
},
362+
}

test/framework/verifier/aws_resource_verifier.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,9 @@ func verifyListenerRuleConditions(actual, expected []elbv2types.RuleCondition) e
490490
if !slices.Equal(actualCondition.PathPatternConfig.Values, expectedCondition.PathPatternConfig.Values) {
491491
return errors.Errorf("expected listener rule condition path-pattern values %v, got %v", expectedCondition.PathPatternConfig.Values, actualCondition.PathPatternConfig.Values)
492492
}
493+
if !slices.Equal(actualCondition.PathPatternConfig.RegexValues, expectedCondition.PathPatternConfig.RegexValues) {
494+
return errors.Errorf("expected listener rule condition path-pattern regex values %v, got %v", expectedCondition.PathPatternConfig.RegexValues, actualCondition.PathPatternConfig.RegexValues)
495+
}
493496
}
494497
}
495498
if !foundPath {

0 commit comments

Comments
 (0)