Skip to content

Commit 1ab82f7

Browse files
committed
[feat gw-api] implement grpcroute match
[feat-api] refactor rule precedence code
1 parent ee75e63 commit 1ab82f7

File tree

7 files changed

+929
-155
lines changed

7 files changed

+929
-155
lines changed

pkg/gateway/model/model_build_listener.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -188,18 +188,19 @@ func (l listenerBuilderImpl) buildListenerRules(stack core.Stack, ls *elbv2model
188188

189189
var albRules []elbv2model.Rule
190190
for _, ruleWithPrecedence := range rulesWithPrecedenceOrder {
191-
route := ruleWithPrecedence.RouteDescriptor
192-
rule := ruleWithPrecedence.Rule
191+
route := ruleWithPrecedence.CommonRulePrecedence.RouteDescriptor
192+
rule := ruleWithPrecedence.CommonRulePrecedence.Rule
193193

194194
var conditionsList []elbv2model.RuleCondition
195195
var err error
196196
switch route.GetRouteKind() {
197197
case routeutils.HTTPRouteKind:
198198
conditionsList, err = routeutils.BuildHttpRuleConditions(ruleWithPrecedence)
199-
if err != nil {
200-
return err
201-
}
202-
// TODO: add case for GRPC
199+
case routeutils.GRPCRouteKind:
200+
conditionsList, err = routeutils.BuildGrpcRuleConditions(ruleWithPrecedence)
201+
}
202+
if err != nil {
203+
return err
203204
}
204205
tags, tagsErr := l.tagHelper.getGatewayTags(lbCfg)
205206
if tagsErr != nil {

pkg/gateway/model/model_build_target_group.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,7 @@ func (builder *targetGroupBuilderImpl) buildTargetGroupSpec(gw *gwv1.Gateway, ro
288288
if targetType == elbv2model.TargetTypeIP {
289289
return elbv2model.TargetGroupSpec{}, errors.Errorf("TargetGroup port is empty. Are you using the correct service type?")
290290
}
291-
return elbv2model.TargetGroupSpec{}, errors.Errorf("TargetGroup port is empty. When using Instance targets, your service be must of type 'NodePort' or 'LoadBalancer'")
291+
return elbv2model.TargetGroupSpec{}, errors.Errorf("TargetGroup port is empty. When using Instance targets, your service must be of type 'NodePort' or 'LoadBalancer'")
292292
}
293293
return elbv2model.TargetGroupSpec{
294294
Name: name,

pkg/gateway/routeutils/constants.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@ var defaultProtocolToRouteKindMap = map[gwv1.ProtocolType][]RouteKind{
3232
gwv1.UDPProtocolType: {UDPRouteKind},
3333
gwv1.TLSProtocolType: {TLSRouteKind, TCPRouteKind},
3434
gwv1.HTTPProtocolType: {HTTPRouteKind},
35-
gwv1.HTTPSProtocolType: {HTTPRouteKind},
35+
gwv1.HTTPSProtocolType: {HTTPRouteKind, GRPCRouteKind},
3636
}

pkg/gateway/routeutils/route_rule_condition.go

Lines changed: 92 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
// BuildHttpRuleConditions each match will be mapped to a ruleCondition, conditions within same match will be ANDed
1212
func BuildHttpRuleConditions(rule RulePrecedence) ([]elbv2model.RuleCondition, error) {
1313
match := rule.HTTPMatch
14-
hostnamesStringList := rule.Hostnames
14+
hostnamesStringList := rule.CommonRulePrecedence.Hostnames
1515
var conditions []elbv2model.RuleCondition
1616
if hostnamesStringList != nil && len(hostnamesStringList) > 0 {
1717
conditions = append(conditions, elbv2model.RuleCondition{
@@ -141,12 +141,100 @@ func buildHttpMethodCondition(method *gwv1.HTTPMethod) []elbv2model.RuleConditio
141141
}
142142
}
143143

144-
// TODO: implement it for GRPCRoute
145-
func buildGrpcRouteRuleConditions(matches RouteRule) ([][]elbv2model.RuleCondition, error) {
146-
var conditions [][]elbv2model.RuleCondition
144+
func BuildGrpcRuleConditions(rule RulePrecedence) ([]elbv2model.RuleCondition, error) {
145+
// handle host header
146+
hostnamesStringList := rule.CommonRulePrecedence.Hostnames
147+
var conditions []elbv2model.RuleCondition
148+
if hostnamesStringList != nil && len(hostnamesStringList) > 0 {
149+
conditions = append(conditions, elbv2model.RuleCondition{
150+
Field: elbv2model.RuleConditionFieldHostHeader,
151+
HostHeaderConfig: &elbv2model.HostHeaderConditionConfig{
152+
Values: hostnamesStringList,
153+
},
154+
})
155+
}
156+
157+
match := rule.GRPCMatch
158+
159+
if match == nil {
160+
// If Method field is not specified, all services and methods will match.
161+
conditions = append(conditions, elbv2model.RuleCondition{
162+
Field: elbv2model.RuleConditionFieldPathPattern,
163+
PathPatternConfig: &elbv2model.PathPatternConditionConfig{
164+
Values: []string{"/*"},
165+
},
166+
})
167+
return conditions, nil
168+
}
169+
170+
// handle method match
171+
if match.Method == nil {
172+
conditions = append(conditions, elbv2model.RuleCondition{
173+
Field: elbv2model.RuleConditionFieldPathPattern,
174+
PathPatternConfig: &elbv2model.PathPatternConditionConfig{
175+
Values: []string{"/*"},
176+
},
177+
})
178+
} else {
179+
methodCondition, err := buildGrpcMethodCondition(match.Method)
180+
if err != nil {
181+
return nil, err
182+
}
183+
conditions = append(conditions, methodCondition...)
184+
}
185+
186+
// handle header match
187+
if match.Headers != nil && len(match.Headers) > 0 {
188+
headerConditions := buildGrpcHeaderCondition(match.Headers)
189+
conditions = append(conditions, headerConditions...)
190+
}
191+
147192
return conditions, nil
148193
}
149194

195+
func buildGrpcHeaderCondition(headers []gwv1.GRPCHeaderMatch) []elbv2model.RuleCondition {
196+
var conditions []elbv2model.RuleCondition
197+
for _, header := range headers {
198+
headerCondition := []elbv2model.RuleCondition{
199+
{
200+
Field: elbv2model.RuleConditionFieldHTTPHeader,
201+
HTTPHeaderConfig: &elbv2model.HTTPHeaderConditionConfig{
202+
HTTPHeaderName: string(header.Name),
203+
// for a given HTTPHeaderName, ALB rule can accept a list of values. However, gateway route headers only accept one value per name, and name cannot duplicate.
204+
Values: []string{header.Value},
205+
},
206+
},
207+
}
208+
conditions = append(conditions, headerCondition...)
209+
}
210+
return conditions
211+
}
212+
213+
// buildGrpcMethodCondition - we handle regex and exact type in same way since regex is taken as-is
214+
// Exact method type will not accept wildcards - this is checked by kubebuilder validation
215+
// Regular expression method type only works with wildcard * and ? for now
216+
func buildGrpcMethodCondition(method *gwv1.GRPCMethodMatch) ([]elbv2model.RuleCondition, error) {
217+
var pathValue string
218+
if method.Service != nil && method.Method != nil {
219+
pathValue = fmt.Sprintf("/%s/%s", *method.Service, *method.Method)
220+
} else if method.Service != nil {
221+
pathValue = fmt.Sprintf("/%s/*", *method.Service)
222+
} else if method.Method != nil {
223+
pathValue = fmt.Sprintf("/*/%s", *method.Method)
224+
} else {
225+
return nil, errors.Errorf("Invalid grpc method match: %v", method)
226+
}
227+
228+
return []elbv2model.RuleCondition{
229+
{
230+
Field: elbv2model.RuleConditionFieldPathPattern,
231+
PathPatternConfig: &elbv2model.PathPatternConditionConfig{
232+
Values: []string{pathValue},
233+
},
234+
},
235+
}, nil
236+
}
237+
150238
// BuildHttpRuleActionsBasedOnFilter only request redirect is supported, header modification is limited due to ALB support level.
151239
func BuildHttpRuleActionsBasedOnFilter(filters []gwv1.HTTPRouteFilter) ([]elbv2model.Action, error) {
152240
for _, filter := range filters {

0 commit comments

Comments
 (0)