func()

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
}