in pkg/ingress/kube/ingress/controller.go [746:868]
func (c *controller) ApplyCanaryIngress(convertOptions *common.ConvertOptions, wrapper *common.WrapperConfig) error {
if convertOptions == nil {
return fmt.Errorf("convertOptions is nil")
}
if wrapper == nil {
return fmt.Errorf("wrapperConfig is nil")
}
byHeader, _ := wrapper.AnnotationsConfig.CanaryKind()
cfg := wrapper.Config
ingressV1Beta, ok := cfg.Spec.(ingress.IngressSpec)
if !ok {
common.IncrementInvalidIngress(c.options.ClusterId, common.Unknown)
return fmt.Errorf("convert type is invalid in cluster %s", c.options.ClusterId)
}
if len(ingressV1Beta.Rules) == 0 && ingressV1Beta.Backend == nil {
common.IncrementInvalidIngress(c.options.ClusterId, common.EmptyRule)
return fmt.Errorf("invalid ingress rule %s:%s in cluster %s, either `defaultBackend` or `rules` must be specified", cfg.Namespace, cfg.Name, c.options.ClusterId)
}
for _, rule := range ingressV1Beta.Rules {
if rule.HTTP == nil || len(rule.HTTP.Paths) == 0 {
IngressLog.Warnf("invalid ingress rule %s:%s for host %q in cluster %s, no paths defined", cfg.Namespace, cfg.Name, rule.Host, c.options.ClusterId)
continue
}
routes, exist := convertOptions.HTTPRoutes[rule.Host]
if !exist {
continue
}
for _, httpPath := range rule.HTTP.Paths {
canary := &common.WrapperHTTPRoute{
HTTPRoute: &networking.HTTPRoute{},
WrapperConfig: wrapper,
Host: rule.Host,
ClusterId: c.options.ClusterId,
}
var pathType common.PathType
originPath := httpPath.Path
if annotationsConfig := wrapper.AnnotationsConfig; annotationsConfig.NeedRegexMatch(originPath) {
if annotationsConfig.IsFullPathRegexMatch() {
pathType = common.FullPathRegex
} else {
pathType = common.PrefixRegex
}
} else {
switch *httpPath.PathType {
case ingress.PathTypeExact:
pathType = common.Exact
case ingress.PathTypePrefix:
pathType = common.Prefix
if httpPath.Path != "/" {
originPath = strings.TrimSuffix(httpPath.Path, "/")
}
}
}
canary.OriginPath = originPath
canary.OriginPathType = pathType
ingressRouteBuilder := convertOptions.IngressRouteCache.New(canary)
// backend service check
var event common.Event
destinationConfig := wrapper.AnnotationsConfig.Destination
canary.HTTPRoute.Route, event = c.backendToRouteDestination(&httpPath.Backend, cfg.Namespace, ingressRouteBuilder, destinationConfig)
if event != common.Normal {
common.IncrementInvalidIngress(c.options.ClusterId, event)
ingressRouteBuilder.Event = event
convertOptions.IngressRouteCache.Add(ingressRouteBuilder)
continue
}
canary.RuleKey = createRuleKey(canary.WrapperConfig.Config.Annotations, canary.PathFormat())
// find the base ingress
pos := 0
var targetRoute *common.WrapperHTTPRoute
for _, route := range routes {
if isCanaryRoute(canary, route) {
targetRoute = route
break
}
pos += 1
}
if targetRoute == nil {
continue
}
canaryConfig := wrapper.AnnotationsConfig.Canary
// Header, Cookie
if byHeader {
IngressLog.Debug("Insert canary route by header")
annotations.ApplyByHeader(canary.HTTPRoute, targetRoute.HTTPRoute, canary.WrapperConfig.AnnotationsConfig)
canary.HTTPRoute.Name = common.GenerateUniqueRouteName(c.options.SystemNamespace, canary)
} else {
IngressLog.Debug("Merge canary route by weight")
if targetRoute.WeightTotal == 0 {
targetRoute.WeightTotal = int32(canaryConfig.WeightTotal)
}
annotations.ApplyByWeight(canary.HTTPRoute, targetRoute.HTTPRoute, canary.WrapperConfig.AnnotationsConfig)
}
IngressLog.Debugf("Canary route is %v", canary)
if byHeader {
// Inherit policy from normal route
canary.WrapperConfig.AnnotationsConfig.Auth = targetRoute.WrapperConfig.AnnotationsConfig.Auth
routes = append(routes[:pos+1], routes[pos:]...)
routes[pos] = canary
convertOptions.HTTPRoutes[rule.Host] = routes
// Recreate route name.
ingressRouteBuilder.RouteName = common.GenerateUniqueRouteName(c.options.SystemNamespace, canary)
convertOptions.IngressRouteCache.Add(ingressRouteBuilder)
} else {
convertOptions.IngressRouteCache.Update(targetRoute)
}
}
}
return nil
}