func applyHTTPRouteDestination()

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