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