func buildHTTPVirtualServices()

in pilot/pkg/config/kube/gateway/conversion.go [198:371]


func buildHTTPVirtualServices(obj config.Config, gateways map[parentKey]map[k8s.SectionName]*parentInfo, domain string,
	gatewayRoutes map[string]map[string]*config.Config, meshRoutes map[string]map[string]*config.Config) {
	route := obj.Spec.(*k8s.HTTPRouteSpec)
	for _, r := range route.Rules {
		if len(r.Matches) > 1 {
			// if a rule has multiple matches, make a deep copy to avoid impacting the obj when splitting the rule
			route = route.DeepCopy()
			break
		}
	}
	ns := obj.Namespace
	parentRefs := extractParentReferenceInfo(gateways, route.ParentRefs, route.Hostnames, gvk.HTTPRoute, ns)

	reportError := func(routeErr *ConfigError) {
		obj.Status.(*kstatus.WrappedStatus).Mutate(func(s config.Status) config.Status {
			rs := s.(*k8s.HTTPRouteStatus)
			rs.Parents = createRouteStatus(parentRefs, obj, rs.Parents, routeErr)
			return rs
		})
	}

	httproutes := []*istio.HTTPRoute{}
	hosts := hostnameToStringList(route.Hostnames)
	for i := 0; i < len(route.Rules); i++ {
		r := route.Rules[i]
		if len(r.Matches) > 1 {
			// split the rule to make sure each rule has up to one match
			for _, match := range r.Matches {
				splitRule := r
				splitRule.Matches = []k8s.HTTPRouteMatch{match}
				route.Rules = append(route.Rules, splitRule)
			}
			continue
		}
		// TODO: implement rewrite, timeout, mirror, corspolicy, retries
		vs := &istio.HTTPRoute{}
		for _, match := range r.Matches {
			uri, err := createURIMatch(match)
			if err != nil {
				reportError(err)
				return
			}
			headers, err := createHeadersMatch(match)
			if err != nil {
				reportError(err)
				return
			}
			qp, err := createQueryParamsMatch(match)
			if err != nil {
				reportError(err)
				return
			}
			method, err := createMethodMatch(match)
			if err != nil {
				reportError(err)
				return
			}
			vs.Match = append(vs.Match, &istio.HTTPMatchRequest{
				Uri:         uri,
				Headers:     headers,
				QueryParams: qp,
				Method:      method,
			})
		}
		for _, filter := range r.Filters {
			switch filter.Type {
			case k8s.HTTPRouteFilterRequestHeaderModifier:
				vs.Headers = createHeadersFilter(filter.RequestHeaderModifier)
			case k8s.HTTPRouteFilterRequestRedirect:
				vs.Redirect = createRedirectFilter(filter.RequestRedirect)
			case k8s.HTTPRouteFilterRequestMirror:
				mirror, err := createMirrorFilter(filter.RequestMirror, ns, domain)
				if err != nil {
					reportError(err)
					return
				}
				vs.Mirror = mirror
			default:
				reportError(&ConfigError{
					Reason:  InvalidFilter,
					Message: fmt.Sprintf("unsupported filter type %q", filter.Type),
				})
				return
			}
		}

		zero := true
		for _, w := range r.BackendRefs {
			if w.Weight == nil || (w.Weight != nil && int(*w.Weight) != 0) {
				zero = false
				break
			}
		}
		if zero && vs.Redirect == nil {
			// The spec requires us to 503 when there are no >0 weight backends
			vs.Fault = &istio.HTTPFaultInjection{Abort: &istio.HTTPFaultInjection_Abort{
				Percentage: &istio.Percent{
					Value: 100,
				},
				ErrorType: &istio.HTTPFaultInjection_Abort_HttpStatus{
					HttpStatus: 503,
				},
			}}
		}

		route, err := buildHTTPDestination(r.BackendRefs, ns, domain, zero)
		if err != nil {
			reportError(err)
			return
		}
		vs.Route = route

		httproutes = append(httproutes, vs)
	}
	reportError(nil)

	gatewayNames := referencesToInternalNames(parentRefs)
	if len(gatewayNames) == 0 {
		return
	}
	count := 0
	for _, gw := range gatewayNames {
		// for gateway routes, build one VS per gateway+host
		routeMap := gatewayRoutes
		routeKey := gw
		if gw == "mesh" {
			// for mesh routes, build one VS per namespace+host
			routeMap = meshRoutes
			routeKey = ns
		}
		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 _, host := range hosts {
			if cfg := routeMap[routeKey][host]; cfg != nil {
				// merge http routes
				vs := cfg.Spec.(*istio.VirtualService)
				vs.Http = append(vs.Http, httproutes...)
			} else {
				name := fmt.Sprintf("%s-%d-%s", obj.Name, count, constants.KubernetesGatewayName)
				routeMap[routeKey][host] = &config.Config{
					Meta: config.Meta{
						CreationTimestamp: obj.CreationTimestamp,
						GroupVersionKind:  gvk.VirtualService,
						Name:              name,
						Annotations:       routeMeta(obj),
						Namespace:         ns,
						Domain:            domain,
					},
					Spec: &istio.VirtualService{
						Hosts:    []string{host},
						Gateways: []string{gw},
						Http:     httproutes,
					},
				}
				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)
		}
	}
}