func()

in pkg/ingress/kube/ingress/controller.go [504:667]


func (c *controller) ConvertHTTPRoute(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")
	}

	// Canary ingress will be processed in the end.
	if wrapper.AnnotationsConfig.IsCanary() {
		convertOptions.CanaryIngresses = append(convertOptions.CanaryIngresses, wrapper)
		return nil
	}

	cfg := wrapper.Config
	ingressV1, 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(ingressV1.Rules) == 0 && ingressV1.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)
	}

	if ingressV1.Backend != nil && (ingressV1.Backend.ServiceName != "" || ingressV1.Backend.Resource != nil) {
		convertOptions.HasDefaultBackend = true
	}

	// In one ingress, we will limit the rule conflict.
	// When the host, pathType, path of two rule are same, we think there is a conflict event.
	definedRules := sets.New[string]()

	var (
		// But in across ingresses case, we will restrict this limit.
		// When the {host, path, headers, method, params} of two rule in different ingress are same, we think there is a conflict event.
		tempRuleKey []string
	)

	for _, rule := range ingressV1.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
		}

		wrapperVS, exist := convertOptions.VirtualServices[rule.Host]
		if !exist {
			wrapperVS = &common.WrapperVirtualService{
				VirtualService: &networking.VirtualService{
					Hosts: []string{rule.Host},
				},
				WrapperConfig: wrapper,
			}
			convertOptions.VirtualServices[rule.Host] = wrapperVS
		}

		// Record the latest app root for per host.
		redirect := wrapper.AnnotationsConfig.Redirect
		if redirect != nil && redirect.AppRoot != "" {
			wrapperVS.AppRoot = redirect.AppRoot
		}

		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,
			}

			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, "/")
					}
				}
			}
			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)

			hostAndPath := wrapperHttpRoute.PathFormat()
			key := createRuleKey(cfg.Annotations, hostAndPath)
			wrapperHttpRoute.RuleKey = key
			if WrapPreIngress, exist := convertOptions.Route2Ingress[key]; exist {
				ingressRouteBuilder.PreIngress = WrapPreIngress.Config
				ingressRouteBuilder.Event = common.DuplicatedRoute
			}
			tempRuleKey = append(tempRuleKey, key)

			// Two duplicated rules in the same ingress.
			if ingressRouteBuilder.Event == common.Normal {
				pathFormat := wrapperHttpRoute.PathFormat()
				if definedRules.Contains(pathFormat) {
					ingressRouteBuilder.PreIngress = cfg
					ingressRouteBuilder.Event = common.DuplicatedRoute
				}
				definedRules.Insert(pathFormat)
			}

			// backend service check
			var event common.Event
			destinationConfig := wrapper.AnnotationsConfig.Destination
			wrapperHttpRoute.HTTPRoute.Route, event = c.backendToRouteDestination(&httpPath.Backend, cfg.Namespace, ingressRouteBuilder, destinationConfig)

			if destinationConfig != nil {
				wrapperHttpRoute.WeightTotal = int32(destinationConfig.WeightSum)
			}

			if ingressRouteBuilder.Event != common.Normal {
				event = ingressRouteBuilder.Event
			}

			if event != common.Normal {
				common.IncrementInvalidIngress(c.options.ClusterId, event)
				ingressRouteBuilder.Event = event
			} else {
				wrapperHttpRoutes = append(wrapperHttpRoutes, wrapperHttpRoute)
			}

			convertOptions.IngressRouteCache.Add(ingressRouteBuilder)
		}

		for idx, item := range tempRuleKey {
			if val, exist := convertOptions.Route2Ingress[item]; !exist || strings.Compare(val.RuleKey, tempRuleKey[idx]) != 0 {
				convertOptions.Route2Ingress[item] = &common.WrapperConfigWithRuleKey{
					Config:  cfg,
					RuleKey: tempRuleKey[idx],
				}
			}
		}

		old, f := convertOptions.HTTPRoutes[rule.Host]
		if f {
			old = append(old, wrapperHttpRoutes...)
			convertOptions.HTTPRoutes[rule.Host] = old
		} else {
			convertOptions.HTTPRoutes[rule.Host] = wrapperHttpRoutes
		}

		// Sort, exact -> prefix -> regex
		routes := convertOptions.HTTPRoutes[rule.Host]
		IngressLog.Debugf("routes of host %s is %v", rule.Host, routes)
		common.SortHTTPRoutes(routes)
	}

	return nil
}