in pilot/pkg/networking/core/v1alpha3/route/route.go [467:589]
func applyHTTPRouteDestination(
out *route.Route,
node *model.Proxy,
in *networking.HTTPRoute,
mesh *meshconfig.MeshConfig,
authority string,
serviceRegistry map[host.Name]*model.Service,
listenerPort int,
hashByDestination map[*networking.HTTPRouteDestination]*networking.LoadBalancerSettings_ConsistentHashLB,
) {
policy := in.Retries
if policy == nil {
// No VS policy set, use mesh defaults
policy = mesh.GetDefaultHttpRetryPolicy()
}
action := &route.RouteAction{
Cors: translateCORSPolicy(in.CorsPolicy),
RetryPolicy: retry.ConvertPolicy(policy),
}
// Configure timeouts specified by Virtual Service if they are provided, otherwise set it to defaults.
action.Timeout = features.DefaultRequestTimeout
if in.Timeout != nil {
action.Timeout = in.Timeout
}
if node.IsProxylessGrpc() {
// TODO(stevenctl) merge these paths; grpc's xDS impl will not read the deprecated value
action.MaxStreamDuration = &route.RouteAction_MaxStreamDuration{MaxStreamDuration: action.Timeout}
} else {
// Use deprecated value for now as the replacement MaxStreamDuration has some regressions.
// nolint: staticcheck
action.MaxGrpcTimeout = action.Timeout
}
out.Action = &route.Route_Route{Route: action}
if in.Rewrite != nil {
action.PrefixRewrite = in.Rewrite.GetUri()
if in.Rewrite.GetAuthority() != "" {
authority = in.Rewrite.GetAuthority()
}
}
if authority != "" {
action.HostRewriteSpecifier = &route.RouteAction_HostRewriteLiteral{
HostRewriteLiteral: authority,
}
}
if in.Mirror != nil {
if mp := mirrorPercent(in); mp != nil {
action.RequestMirrorPolicies = []*route.RouteAction_RequestMirrorPolicy{{
Cluster: GetDestinationCluster(in.Mirror, serviceRegistry[host.Name(in.Mirror.Host)], listenerPort),
RuntimeFraction: mp,
TraceSampled: &wrappers.BoolValue{Value: false},
}}
}
}
// TODO: eliminate this logic and use the total_weight option in envoy route
weighted := make([]*route.WeightedCluster_ClusterWeight, 0)
for _, dst := range in.Route {
weight := &wrappers.UInt32Value{Value: uint32(dst.Weight)}
if dst.Weight == 0 {
// Ignore 0 weighted clusters if there are other clusters in the route.
// But if this is the only cluster in the route, then add it as a cluster with weight 100
if len(in.Route) == 1 {
weight.Value = uint32(100)
} else {
continue
}
}
hostname := host.Name(dst.GetDestination().GetHost())
n := GetDestinationCluster(dst.Destination, serviceRegistry[hostname], listenerPort)
clusterWeight := &route.WeightedCluster_ClusterWeight{
Name: n,
Weight: weight,
}
if dst.Headers != nil {
operations := translateHeadersOperations(dst.Headers)
clusterWeight.RequestHeadersToAdd = operations.requestHeadersToAdd
clusterWeight.RequestHeadersToRemove = operations.requestHeadersToRemove
clusterWeight.ResponseHeadersToAdd = operations.responseHeadersToAdd
clusterWeight.ResponseHeadersToRemove = operations.responseHeadersToRemove
if operations.authority != "" {
clusterWeight.HostRewriteSpecifier = &route.WeightedCluster_ClusterWeight_HostRewriteLiteral{
HostRewriteLiteral: operations.authority,
}
}
}
weighted = append(weighted, clusterWeight)
hash := hashByDestination[dst]
hashPolicy := consistentHashToHashPolicy(hash)
if hashPolicy != nil {
action.HashPolicy = append(action.HashPolicy, hashPolicy)
}
}
// rewrite to a single cluster if there is only weighted cluster
if len(weighted) == 1 {
action.ClusterSpecifier = &route.RouteAction_Cluster{Cluster: weighted[0].Name}
out.RequestHeadersToAdd = append(out.RequestHeadersToAdd, weighted[0].RequestHeadersToAdd...)
out.RequestHeadersToRemove = append(out.RequestHeadersToRemove, weighted[0].RequestHeadersToRemove...)
out.ResponseHeadersToAdd = append(out.ResponseHeadersToAdd, weighted[0].ResponseHeadersToAdd...)
out.ResponseHeadersToRemove = append(out.ResponseHeadersToRemove, weighted[0].ResponseHeadersToRemove...)
if weighted[0].HostRewriteSpecifier != nil && action.HostRewriteSpecifier == nil {
// Ideally, if the weighted cluster overwrites authority, it has precedence. This mirrors behavior of headers,
// because for headers we append the weighted last which allows it to Set and wipe out previous Adds.
// However, Envoy behavior is different when we set at both cluster level and route level, and we want
// behavior to be consistent with a single cluster and multiple clusters.
// As a result, we only override if the top level rewrite is not set
action.HostRewriteSpecifier = &route.RouteAction_HostRewriteLiteral{
HostRewriteLiteral: weighted[0].GetHostRewriteLiteral(),
}
}
} else {
action.ClusterSpecifier = &route.RouteAction_WeightedClusters{
WeightedClusters: &route.WeightedCluster{
Clusters: weighted,
},
}
}
}