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