func buildHTTPVirtualServices()

in pkg/ingress/kube/gateway/istio/conversion.go [296:426]


func buildHTTPVirtualServices(
	ctx configContext,
	obj config.Config,
	gatewayRoutes map[string]map[string]*config.Config,
	meshRoutes map[string]map[string]*config.Config,
) {
	route := obj.Spec.(*k8s.HTTPRouteSpec)
	parentRefs := extractParentReferenceInfo(ctx.GatewayReferences, route.ParentRefs, route.Hostnames, gvk.HTTPRoute, obj.Namespace)
	reportStatus := func(results []RouteParentResult) {
		obj.Status.(*kstatus.WrappedStatus).Mutate(func(s config.Status) config.Status {
			rs := s.(*k8s.HTTPRouteStatus)
			rs.Parents = createRouteStatus(results, obj, rs.Parents)
			return rs
		})
	}

	type conversionResult struct {
		error  *ConfigError
		routes []*istio.HTTPRoute
	}
	convertRules := func(mesh bool) conversionResult {
		res := conversionResult{}
		for n, r := range route.Rules {
			// split the rule to make sure each rule has up to one match
			matches := slices.Reference(r.Matches)
			if len(matches) == 0 {
				matches = append(matches, nil)
			}
			for _, m := range matches {
				if m != nil {
					r.Matches = []k8s.HTTPRouteMatch{*m}
				}
				vs, err := convertHTTPRoute(r, ctx, obj, n, !mesh)
				// This was a hard error
				if vs == nil {
					res.error = err
					return conversionResult{error: err}
				}
				// Got an error but also routes
				if err != nil {
					res.error = err
				}

				res.routes = append(res.routes, vs)
			}
		}
		return res
	}
	meshResult, gwResult := buildMeshAndGatewayRoutes(parentRefs, convertRules)

	reportStatus(slices.Map(parentRefs, func(r routeParentReference) RouteParentResult {
		res := RouteParentResult{
			OriginalReference: r.OriginalReference,
			DeniedReason:      r.DeniedReason,
			RouteError:        gwResult.error,
		}
		if r.IsMesh() {
			res.RouteError = meshResult.error
		}
		return res
	}))
	count := 0
	for _, parent := range filteredReferences(parentRefs) {
		// for gateway routes, build one VS per gateway+host
		routeMap := gatewayRoutes
		routeKey := parent.InternalName
		vsHosts := hostnameToStringList(route.Hostnames)
		routes := gwResult.routes
		if parent.IsMesh() {
			routes = meshResult.routes
			// for mesh routes, build one VS per namespace/port->host
			routeMap = meshRoutes
			routeKey = obj.Namespace
			if parent.OriginalReference.Port != nil {
				routes = augmentPortMatch(routes, *parent.OriginalReference.Port)
				routeKey += fmt.Sprintf("/%d", *parent.OriginalReference.Port)
			}
			vsHosts = []string{fmt.Sprintf("%s.%s.svc.%s",
				parent.OriginalReference.Name, ptr.OrDefault(parent.OriginalReference.Namespace, k8s.Namespace(obj.Namespace)), ctx.Domain)}
		}
		if len(routes) == 0 {
			continue
		}
		if _, f := routeMap[routeKey]; !f {
			routeMap[routeKey] = make(map[string]*config.Config)
		}

		// Create one VS per hostname with a single hostname.
		// This ensures we can treat each hostname independently, as the spec requires
		for _, h := range vsHosts {
			if cfg := routeMap[routeKey][h]; cfg != nil {
				// merge http routes
				vs := cfg.Spec.(*istio.VirtualService)
				vs.Http = append(vs.Http, routes...)
				// append parents
				cfg.Annotations[constants.InternalParentNames] = fmt.Sprintf("%s,%s/%s.%s",
					cfg.Annotations[constants.InternalParentNames], obj.GroupVersionKind.Kind, obj.Name, obj.Namespace)
			} else {
				name := fmt.Sprintf("%s-%d-%s", obj.Name, count, constants.KubernetesGatewayName)
				routeMap[routeKey][h] = &config.Config{
					Meta: config.Meta{
						CreationTimestamp: obj.CreationTimestamp,
						GroupVersionKind:  gvk.VirtualService,
						Name:              name,
						Annotations:       routeMeta(obj),
						Namespace:         obj.Namespace,
						Domain:            ctx.Domain,
					},
					Spec: &istio.VirtualService{
						Hosts:    []string{h},
						Gateways: []string{parent.InternalName},
						Http:     routes,
					},
				}
				count++
			}
		}
	}
	for _, vsByHost := range gatewayRoutes {
		for _, cfg := range vsByHost {
			vs := cfg.Spec.(*istio.VirtualService)
			sortHTTPRoutes(vs.Http)
		}
	}
	for _, vsByHost := range meshRoutes {
		for _, cfg := range vsByHost {
			vs := cfg.Spec.(*istio.VirtualService)
			sortHTTPRoutes(vs.Http)
		}
	}
}