-
Notifications
You must be signed in to change notification settings - Fork 591
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
WIP translate HTTPRoute to expression based routes
- Loading branch information
1 parent
ed05179
commit f360323
Showing
9 changed files
with
210 additions
and
14 deletions.
There are no files selected for viewing
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
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
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,165 @@ | ||
package translators | ||
|
||
import ( | ||
"sort" | ||
"strings" | ||
|
||
"github.com/kong/go-kong/kong" | ||
gatewayv1beta1 "sigs.k8s.io/gateway-api/apis/v1beta1" | ||
|
||
"github.com/kong/kubernetes-ingress-controller/v2/internal/annotations" | ||
"github.com/kong/kubernetes-ingress-controller/v2/internal/dataplane/kongstate" | ||
"github.com/kong/kubernetes-ingress-controller/v2/internal/dataplane/parser/atc" | ||
"github.com/kong/kubernetes-ingress-controller/v2/internal/util" | ||
) | ||
|
||
// GenerateKongExpressionRoutesFromHTTPRouteMatches generates Kong routes from HTTPRouteRule | ||
// pointing to a specific backend. | ||
func GenerateKongExpressionRoutesFromHTTPRouteMatches( | ||
routeName string, | ||
matches []gatewayv1beta1.HTTPRouteMatch, | ||
filters []gatewayv1beta1.HTTPRouteFilter, | ||
ingressObjectInfo util.K8sObjectInfo, | ||
hostnames []string, | ||
tags []*string, | ||
) ([]kongstate.Route, error) { | ||
// initialize the route with route name, preserve_host, and tags. | ||
r := kongstate.Route{ | ||
Ingress: ingressObjectInfo, | ||
Route: kong.Route{ | ||
Name: kong.String(routeName), | ||
PreserveHost: kong.Bool(true), | ||
Tags: tags, | ||
}, | ||
ExpressionRoutes: true, | ||
} | ||
|
||
if len(matches) == 0 { | ||
if len(hostnames) == 0 { | ||
return []kongstate.Route{}, ErrRouteValidationNoMatchRulesOrHostnamesSpecified | ||
} | ||
|
||
hostMatcher := hostMatcherFromHosts(hostnames) | ||
atc.ApplyExpression(&r.Route, hostMatcher, 1) | ||
return []kongstate.Route{r}, nil | ||
} | ||
|
||
// TODO: generate multiple routes if required by filters or priority specifications. | ||
|
||
routeMatcher := atc.And() | ||
matchers := generateMatchersFromHTTPRouteMatches(matches) | ||
routeMatcher = atc.And(atc.Or(matchers...)) | ||
|
||
// append matcher from hosts. | ||
if len(hostnames) > 0 { | ||
hostMatcher := hostMatcherFromHosts(hostnames) | ||
routeMatcher = atc.And(routeMatcher, hostMatcher) | ||
} | ||
|
||
// override protocols and TLS SNIs from annotations. | ||
// translate protocols. | ||
protocols := []string{"http", "https"} | ||
annonationProtocols := annotations.ExtractProtocolNames(ingressObjectInfo.Annotations) | ||
if len(annonationProtocols) > 0 { | ||
protocols = annonationProtocols | ||
} | ||
protocolMatcher := protocolMatcherFromProtocols(protocols) | ||
routeMatcher.And(protocolMatcher) | ||
|
||
// translate SNIs. | ||
snis, exist := annotations.ExtractSNIs(ingressObjectInfo.Annotations) | ||
if exist && len(snis) > 0 { | ||
sniMatcher := sniMatcherFromSNIs(snis) | ||
routeMatcher.And(sniMatcher) | ||
} | ||
|
||
atc.ApplyExpression(&r.Route, routeMatcher, 1) | ||
return []kongstate.Route{r}, nil | ||
} | ||
|
||
func generateMatchersFromHTTPRouteMatches(matches []gatewayv1beta1.HTTPRouteMatch) []atc.Matcher { | ||
ret := make([]atc.Matcher, 0, len(matches)) | ||
for _, match := range matches { | ||
matcher := generateMatcherFromHTTPRouteMatch(match) | ||
ret = append(ret, matcher) | ||
} | ||
return ret | ||
} | ||
|
||
func generateMatcherFromHTTPRouteMatch(match gatewayv1beta1.HTTPRouteMatch) atc.Matcher { | ||
var matcher atc.Matcher | ||
|
||
if match.Path != nil { | ||
pathMatcher := pathMatcherFromHTTPPathMatch(match.Path) | ||
matcher = atc.And(matcher, pathMatcher) | ||
} | ||
|
||
if len(match.Headers) > 0 { | ||
headerMatcher := headerMatcherFromHTTPHeaderMatches(match.Headers) | ||
matcher = atc.And(matcher, headerMatcher) | ||
} | ||
|
||
if match.Method != nil { | ||
method := *match.Method | ||
methodMatcher := methodMatcherFromMethods([]string{string(method)}) | ||
matcher = atc.And(matcher, methodMatcher) | ||
} | ||
return matcher | ||
} | ||
|
||
func appendSuffixSlashIfNotExist(path string) string { | ||
if !strings.HasSuffix(path, "/") { | ||
return path + "/" | ||
} | ||
return path | ||
} | ||
|
||
func appendRegexBeginIfNotExist(regex string) string { | ||
if !strings.HasPrefix(regex, "^") { | ||
return "^" + regex | ||
} | ||
return regex | ||
} | ||
|
||
func pathMatcherFromHTTPPathMatch(pathMatch *gatewayv1beta1.HTTPPathMatch) atc.Matcher { | ||
path := "" | ||
if pathMatch.Value != nil { | ||
path = *pathMatch.Value | ||
} | ||
switch *pathMatch.Type { | ||
case gatewayv1beta1.PathMatchExact: | ||
return atc.NewPredicateHTTPPath(atc.OpEqual, path) | ||
case gatewayv1beta1.PathMatchPathPrefix: | ||
return atc.Or( | ||
atc.NewPredicateHTTPPath(atc.OpEqual, path), | ||
atc.NewPredicateHTTPPath(atc.OpPrefixMatch, appendSuffixSlashIfNotExist(path)), | ||
) | ||
case gatewayv1beta1.PathMatchRegularExpression: | ||
return atc.NewPredicateHTTPPath(atc.OpRegexMatch, appendRegexBeginIfNotExist(path)) | ||
} | ||
|
||
return nil // should be unreachable | ||
} | ||
|
||
func headerMatcherFromHTTPHeaderMatches(headerMatches []gatewayv1beta1.HTTPHeaderMatch) atc.Matcher { | ||
// sort headerMatches by names to generate a stable output. | ||
sort.Slice(headerMatches, func(i, j int) bool { | ||
return string(headerMatches[i].Name) < string(headerMatches[j].Name) | ||
}) | ||
|
||
matchers := make([]atc.Matcher, 0, len(headerMatches)) | ||
for _, headerMatch := range headerMatches { | ||
matchType := gatewayv1beta1.HeaderMatchExact | ||
if headerMatch.Type != nil { | ||
matchType = *headerMatch.Type | ||
} | ||
headerKey := strings.ReplaceAll(strings.ToLower(string(headerMatch.Name)), "-", "_") | ||
switch matchType { | ||
case gatewayv1beta1.HeaderMatchExact: | ||
matchers = append(matchers, atc.NewPredicateHTTPHeader(headerKey, atc.OpEqual, headerMatch.Value)) | ||
case gatewayv1beta1.HeaderMatchRegularExpression: | ||
matchers = append(matchers, atc.NewPredicateHTTPHeader(headerKey, atc.OpRegexMatch, headerMatch.Value)) | ||
} | ||
} | ||
return atc.And(matchers...) | ||
} |
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
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
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,9 @@ | ||
package translators | ||
|
||
import "errors" | ||
|
||
var ( | ||
ErrRouteValidationNoRules = errors.New("no rules provided") | ||
ErrRouteValidationQueryParamMatchesUnsupported = errors.New("query param matches are not yet supported") | ||
ErrRouteValidationNoMatchRulesOrHostnamesSpecified = errors.New("no match rules or hostnames specified") | ||
) |
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
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
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