Skip to content

Commit

Permalink
Fix the problem that ignoreUriCase does not work when the path type i…
Browse files Browse the repository at this point in the history
…s prefix (alibaba#260)

Signed-off-by: charlie <[email protected]>
  • Loading branch information
Charlie17Li authored Apr 4, 2023
1 parent e18557d commit affa120
Show file tree
Hide file tree
Showing 11 changed files with 551 additions and 129 deletions.
48 changes: 26 additions & 22 deletions pkg/ingress/kube/annotations/canary.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,37 +134,41 @@ func ApplyByHeader(canary, route *networking.HTTPRoute, canaryIngress *Ingress)

// Modified match base on by header
if canaryConfig.Header != "" {
canary.Match[0].Headers = map[string]*networking.StringMatch{
canaryConfig.Header: {
MatchType: &networking.StringMatch_Exact{
Exact: "always",
},
},
}
if canaryConfig.HeaderValue != "" {
canary.Match[0].Headers = map[string]*networking.StringMatch{
for _, match := range canary.Match {
match.Headers = map[string]*networking.StringMatch{
canaryConfig.Header: {
MatchType: &networking.StringMatch_Regex{
Regex: "always|" + canaryConfig.HeaderValue,
MatchType: &networking.StringMatch_Exact{
Exact: "always",
},
},
}
} else if canaryConfig.HeaderPattern != "" {
canary.Match[0].Headers = map[string]*networking.StringMatch{
canaryConfig.Header: {
MatchType: &networking.StringMatch_Regex{
Regex: canaryConfig.HeaderPattern,
if canaryConfig.HeaderValue != "" {
match.Headers = map[string]*networking.StringMatch{
canaryConfig.Header: {
MatchType: &networking.StringMatch_Regex{
Regex: "always|" + canaryConfig.HeaderValue,
},
},
},
}
} else if canaryConfig.HeaderPattern != "" {
match.Headers = map[string]*networking.StringMatch{
canaryConfig.Header: {
MatchType: &networking.StringMatch_Regex{
Regex: canaryConfig.HeaderPattern,
},
},
}
}
}
} else if canaryConfig.Cookie != "" {
canary.Match[0].Headers = map[string]*networking.StringMatch{
"cookie": {
MatchType: &networking.StringMatch_Regex{
Regex: "^(.\\*?;)?(" + canaryConfig.Cookie + "=always)(;.\\*)?$",
for _, match := range canary.Match {
match.Headers = map[string]*networking.StringMatch{
"cookie": {
MatchType: &networking.StringMatch_Regex{
Regex: "^(.\\*?;)?(" + canaryConfig.Cookie + "=always)(;.\\*)?$",
},
},
},
}
}
}

Expand Down
107 changes: 56 additions & 51 deletions pkg/ingress/kube/ingress/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"fmt"
"path"
"reflect"
"regexp"
"sort"
"strings"
"sync"
Expand Down Expand Up @@ -532,40 +531,25 @@ func (c *controller) ConvertHTTPRoute(convertOptions *common.ConvertOptions, wra
Host: rule.Host,
ClusterId: c.options.ClusterId,
}
httpMatch := &networking.HTTPMatchRequest{}

path := httpPath.Path
var pathType common.PathType
originPath := httpPath.Path
if wrapper.AnnotationsConfig.NeedRegexMatch() {
wrapperHttpRoute.OriginPathType = common.Regex
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Regex{Regex: httpPath.Path + ".*"},
}
pathType = common.Regex
} else {
switch *httpPath.PathType {
case ingress.PathTypeExact:
wrapperHttpRoute.OriginPathType = common.Exact
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Exact{Exact: httpPath.Path},
}
pathType = common.Exact
case ingress.PathTypePrefix:
wrapperHttpRoute.OriginPathType = common.Prefix
// borrow from implement of official istio code.
if path == "/" {
wrapperVS.ConfiguredDefaultBackend = true
// Optimize common case of / to not needed regex
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Prefix{Prefix: path},
}
} else {
path = strings.TrimSuffix(path, "/")
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Regex{Regex: regexp.QuoteMeta(path) + common.PrefixMatchRegex},
}
pathType = common.Prefix
if httpPath.Path != "/" {
originPath = strings.TrimSuffix(httpPath.Path, "/")
}
}
}
wrapperHttpRoute.OriginPath = path
wrapperHttpRoute.HTTPRoute.Match = []*networking.HTTPMatchRequest{httpMatch}
wrapperHttpRoute.OriginPath = originPath
wrapperHttpRoute.OriginPathType = pathType
wrapperHttpRoute.HTTPRoute.Match = c.generateHttpMatches(pathType, httpPath.Path, wrapperVS)
wrapperHttpRoute.HTTPRoute.Name = common.GenerateUniqueRouteName(c.options.SystemNamespace, wrapperHttpRoute)

ingressRouteBuilder := convertOptions.IngressRouteCache.New(wrapperHttpRoute)
Expand Down Expand Up @@ -748,46 +732,31 @@ func (c *controller) ApplyCanaryIngress(convertOptions *common.ConvertOptions, w
}

for _, httpPath := range rule.HTTP.Paths {
path := httpPath.Path

canary := &common.WrapperHTTPRoute{
HTTPRoute: &networking.HTTPRoute{},
WrapperConfig: wrapper,
Host: rule.Host,
ClusterId: c.options.ClusterId,
}
httpMatch := &networking.HTTPMatchRequest{}

var pathType common.PathType
originPath := httpPath.Path
if wrapper.AnnotationsConfig.NeedRegexMatch() {
canary.OriginPathType = common.Regex
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Regex{Regex: httpPath.Path + ".*"},
}
pathType = common.Regex
} else {
switch *httpPath.PathType {
case ingress.PathTypeExact:
canary.OriginPathType = common.Exact
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Exact{Exact: httpPath.Path},
}
pathType = common.Exact
case ingress.PathTypePrefix:
canary.OriginPathType = common.Prefix
// borrow from implement of official istio code.
if path == "/" {
// Optimize common case of / to not needed regex
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Prefix{Prefix: path},
}
} else {
path = strings.TrimSuffix(path, "/")
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Regex{Regex: regexp.QuoteMeta(path) + common.PrefixMatchRegex},
}
pathType = common.Prefix
if httpPath.Path != "/" {
originPath = strings.TrimSuffix(httpPath.Path, "/")
}
}
}
canary.OriginPath = path
canary.HTTPRoute.Match = []*networking.HTTPMatchRequest{httpMatch}
canary.OriginPath = originPath
canary.OriginPathType = pathType
canary.HTTPRoute.Match = c.generateHttpMatches(pathType, httpPath.Path, nil)
canary.HTTPRoute.Name = common.GenerateUniqueRouteName(c.options.SystemNamespace, canary)

ingressRouteBuilder := convertOptions.IngressRouteCache.New(canary)
Expand Down Expand Up @@ -1180,6 +1149,42 @@ func (c *controller) shouldProcessIngressUpdate(ing *ingress.Ingress) (bool, err
return preProcessed, nil
}

func (c *controller) generateHttpMatches(pathType common.PathType, path string, wrapperVS *common.WrapperVirtualService) []*networking.HTTPMatchRequest {
var httpMatches []*networking.HTTPMatchRequest

httpMatch := &networking.HTTPMatchRequest{}
switch pathType {
case common.Regex:
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Regex{Regex: path + ".*"},
}
case common.Exact:
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Exact{Exact: path},
}
case common.Prefix:
if path == "/" {
if wrapperVS != nil {
wrapperVS.ConfiguredDefaultBackend = true
}
// Optimize common case of / to not needed regex
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Prefix{Prefix: path},
}
} else {
newPath := strings.TrimSuffix(path, "/")
httpMatches = append(httpMatches, c.generateHttpMatches(common.Exact, newPath, wrapperVS)...)
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Prefix{Prefix: newPath + "/"},
}
}
}

httpMatches = append(httpMatches, httpMatch)

return httpMatches
}

// setDefaultMSEIngressOptionalField sets a default value for optional fields when is not defined.
func setDefaultMSEIngressOptionalField(ing *ingress.Ingress) {
if ing == nil {
Expand Down
109 changes: 58 additions & 51 deletions pkg/ingress/kube/ingressv1/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import (
"fmt"
"path"
"reflect"
"regexp"
"sort"
"strings"
"sync"
Expand Down Expand Up @@ -507,47 +506,33 @@ func (c *controller) ConvertHTTPRoute(convertOptions *common.ConvertOptions, wra
}

wrapperHttpRoutes := make([]*common.WrapperHTTPRoute, 0, len(rule.HTTP.Paths))

for _, httpPath := range rule.HTTP.Paths {
wrapperHttpRoute := &common.WrapperHTTPRoute{
HTTPRoute: &networking.HTTPRoute{},
WrapperConfig: wrapper,
Host: rule.Host,
ClusterId: c.options.ClusterId,
}
httpMatch := &networking.HTTPMatchRequest{}

path := httpPath.Path
var pathType common.PathType
originPath := httpPath.Path
if wrapper.AnnotationsConfig.NeedRegexMatch() {
wrapperHttpRoute.OriginPathType = common.Regex
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Regex{Regex: httpPath.Path + ".*"},
}
pathType = common.Regex
} else {
switch *httpPath.PathType {
case ingress.PathTypeExact:
wrapperHttpRoute.OriginPathType = common.Exact
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Exact{Exact: httpPath.Path},
}
pathType = common.Exact
case ingress.PathTypePrefix:
wrapperHttpRoute.OriginPathType = common.Prefix
// borrow from implement of official istio code.
if path == "/" {
wrapperVS.ConfiguredDefaultBackend = true
// Optimize common case of / to not needed regex
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Prefix{Prefix: path},
}
} else {
path = strings.TrimSuffix(path, "/")
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Regex{Regex: regexp.QuoteMeta(path) + common.PrefixMatchRegex},
}
pathType = common.Prefix
if httpPath.Path != "/" {
originPath = strings.TrimSuffix(httpPath.Path, "/")
}
}
}
wrapperHttpRoute.OriginPath = path
wrapperHttpRoute.HTTPRoute.Match = []*networking.HTTPMatchRequest{httpMatch}
wrapperHttpRoute.OriginPath = originPath
wrapperHttpRoute.OriginPathType = pathType
wrapperHttpRoute.HTTPRoute.Match = c.generateHttpMatches(pathType, httpPath.Path, wrapperVS)
wrapperHttpRoute.HTTPRoute.Name = common.GenerateUniqueRouteName(c.options.SystemNamespace, wrapperHttpRoute)

ingressRouteBuilder := convertOptions.IngressRouteCache.New(wrapperHttpRoute)
Expand Down Expand Up @@ -620,6 +605,42 @@ func (c *controller) ConvertHTTPRoute(convertOptions *common.ConvertOptions, wra
return nil
}

func (c *controller) generateHttpMatches(pathType common.PathType, path string, wrapperVS *common.WrapperVirtualService) []*networking.HTTPMatchRequest {
var httpMatches []*networking.HTTPMatchRequest

httpMatch := &networking.HTTPMatchRequest{}
switch pathType {
case common.Regex:
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Regex{Regex: path + ".*"},
}
case common.Exact:
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Exact{Exact: path},
}
case common.Prefix:
if path == "/" {
if wrapperVS != nil {
wrapperVS.ConfiguredDefaultBackend = true
}
// Optimize common case of / to not needed regex
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Prefix{Prefix: path},
}
} else {
newPath := strings.TrimSuffix(path, "/")
httpMatches = append(httpMatches, c.generateHttpMatches(common.Exact, newPath, wrapperVS)...)
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Prefix{Prefix: newPath + "/"},
}
}
}

httpMatches = append(httpMatches, httpMatch)

return httpMatches
}

func (c *controller) ApplyDefaultBackend(convertOptions *common.ConvertOptions, wrapper *common.WrapperConfig) error {
if wrapper.AnnotationsConfig.IsCanary() {
return nil
Expand Down Expand Up @@ -717,46 +738,31 @@ func (c *controller) ApplyCanaryIngress(convertOptions *common.ConvertOptions, w
}

for _, httpPath := range rule.HTTP.Paths {
path := httpPath.Path

canary := &common.WrapperHTTPRoute{
HTTPRoute: &networking.HTTPRoute{},
WrapperConfig: wrapper,
Host: rule.Host,
ClusterId: c.options.ClusterId,
}
httpMatch := &networking.HTTPMatchRequest{}

var pathType common.PathType
originPath := httpPath.Path
if wrapper.AnnotationsConfig.NeedRegexMatch() {
canary.OriginPathType = common.Regex
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Regex{Regex: httpPath.Path + ".*"},
}
pathType = common.Regex
} else {
switch *httpPath.PathType {
case ingress.PathTypeExact:
canary.OriginPathType = common.Exact
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Exact{Exact: httpPath.Path},
}
pathType = common.Exact
case ingress.PathTypePrefix:
canary.OriginPathType = common.Prefix
// borrow from implement of official istio code.
if path == "/" {
// Optimize common case of / to not needed regex
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Prefix{Prefix: path},
}
} else {
path = strings.TrimSuffix(path, "/")
httpMatch.Uri = &networking.StringMatch{
MatchType: &networking.StringMatch_Regex{Regex: regexp.QuoteMeta(path) + common.PrefixMatchRegex},
}
pathType = common.Prefix
if httpPath.Path != "/" {
originPath = strings.TrimSuffix(httpPath.Path, "/")
}
}
}
canary.OriginPath = path
canary.HTTPRoute.Match = []*networking.HTTPMatchRequest{httpMatch}
canary.OriginPath = originPath
canary.OriginPathType = pathType
canary.HTTPRoute.Match = c.generateHttpMatches(pathType, httpPath.Path, nil)
canary.HTTPRoute.Name = common.GenerateUniqueRouteName(c.options.SystemNamespace, canary)

ingressRouteBuilder := convertOptions.IngressRouteCache.New(canary)
Expand Down Expand Up @@ -819,6 +825,7 @@ func (c *controller) ApplyCanaryIngress(convertOptions *common.ConvertOptions, w
} else {
convertOptions.IngressRouteCache.Update(targetRoute)
}

}
}
return nil
Expand Down
Loading

0 comments on commit affa120

Please sign in to comment.