Repository: grpc/grpc-go
File: internal/xds/balancer/clusterresolver/configbuilder.go (Go)

Code before:
	return retConfig, retEndpoints, nil
}

func convertClusterImplMapToOutlierDetection(ciCfgs map[string]*clusterimpl.LBConfig, odCfg outlierdetection.LBConfig) map[string]*outlierdetection.LBConfig {
	odCfgs := make(map[string]*outlierdetection.LBConfig, len(ciCfgs))
	for n, c := range ciCfgs {
		odCfgs[n] = makeClusterImplOutlierDetectionChild(c, odCfg)
	}
	return odCfgs
}

func makeClusterImplOutlierDetectionChild(ciCfg *clusterimpl.LBConfig, odCfg outlierdetection.LBConfig) *outlierdetection.LBConfig {
	odCfgRet := odCfg
	odCfgRet.ChildPolicy = &internalserviceconfig.BalancerConfig{Name: clusterimpl.Name, Config: ciCfg}
	return &odCfgRet
}

func buildClusterImplConfigForDNS(g *nameGenerator, endpoints []resolver.Endpoint, mechanism DiscoveryMechanism, xdsLBPolicy *internalserviceconfig.BalancerConfig) (string, *clusterimpl.LBConfig, []resolver.Endpoint) {
	retEndpoints := make([]resolver.Endpoint, len(endpoints))
	pName := fmt.Sprintf("priority-%v", g.prefix)
	for i, e := range endpoints {
		// Use the canonical string representation for the locality to match
		// the keys expected by the parent Load Balancing policy.
		localityStr := xdsinternal.LocalityString(clients.Locality{})
		retEndpoints[i] = hierarchy.SetInEndpoint(e, []string{pName, localityStr})
		retEndpoints[i] = wrrlocality.SetAddrInfoInEndpoint(retEndpoints[i], wrrlocality.AddrInfo{LocalityWeight: 1})
		// Copy the nested address field as slice fields are shared by the
		// iteration variable and the original slice.
		retEndpoints[i].Addresses = append([]resolver.Address{}, e.Addresses...)
	}
	return pName, &clusterimpl.LBConfig{
		Cluster:               mechanism.Cluster,
		TelemetryLabels:       mechanism.TelemetryLabels,
		ChildPolicy:           xdsLBPolicy,
		MaxConcurrentRequests: mechanism.MaxConcurrentRequests,
		LoadReportingServer:   mechanism.LoadReportingServer,
	}, retEndpoints
}

// buildClusterImplConfigForEDS returns a list of cluster_impl configs, one for
// each priority, sorted by priority, and the addresses for each priority (with
// hierarchy attributes set).
//
// For example, if there are two priorities, the returned values will be
// - ["p0", "p1"]
// - map{"p0":p0_config, "p1":p1_config}
// - [p0_address_0, p0_address_1, p1_address_0, p1_address_1]
//   - p0 addresses' hierarchy attributes are set to p0
func buildClusterImplConfigForEDS(g *nameGenerator, edsResp xdsresource.EndpointsUpdate, mechanism DiscoveryMechanism, xdsLBPolicy *internalserviceconfig.BalancerConfig) ([]string, map[string]*clusterimpl.LBConfig, []resolver.Endpoint, error) {
	drops := make([]clusterimpl.DropConfig, 0, len(edsResp.Drops))
	for _, d := range edsResp.Drops {

Review comment (suggestion):
This is still not doing what we want.

The DNS resolver implementation returns addresses and not endpoints, because the DNS protocol does not know about endpoints. See: https://github.com/grpc/grpc-go/blob/4c27cc80c39c4d1b729653bba95c3b8dba14a8bf/internal/resolver/dns/dns_resolver.go#L345

We have code in the channel that converts these addresses to endpoints, with one address per endpoint. See: https://github.com/grpc/grpc-go/blob/4c27cc80c39c4d1b729653bba95c3b8dba14a8bf/resolver_wrapper.go#L213

But the above code will execute only when the DNS resolver is used on the gRPC channel. Here in the cluster_resolver LB policy, we are creating a DNS resolver ourselves, and therefore the code to convert from addresses to endpoints (that exists in the channel) will not be run here. So, the cluster_resolver will see a set of addresses and no endpoints from the DNS resolver in `[resource_resolver_dns.go](https://github.com/grpc/grpc-go/pull/8733/files#diff-6249528a41f17a06cec41f598b885840f09ef05ee3740ab297fc5a905f2875ca)`, and will probably convert it into a single endpoint with all the addresses in it (this is the change that you have in line 138 of resource_resolver_dns.go).

But, at some point, we will change the DNS resolver implementation to do what is being done today in the channel, i.e., return a set of endpoints, with one address per endpoint. That means that this code should handle multiple endpoints as input, but output a single endpoint that contains all the addresses from the input endpoints.

Code after:
	}
	return retConfig, retEndpoints, nil
}

func convertClusterImplMapToOutlierDetection(ciCfgs map[string]*clusterimpl.LBConfig, odCfg outlierdetection.LBConfig) map[string]*outlierdetection.LBConfig {
	odCfgs := make(map[string]*outlierdetection.LBConfig, len(ciCfgs))
	for n, c := range ciCfgs {
		odCfgs[n] = makeClusterImplOutlierDetectionChild(c, odCfg)
	}
	return odCfgs
}

func makeClusterImplOutlierDetectionChild(ciCfg *clusterimpl.LBConfig, odCfg outlierdetection.LBConfig) *outlierdetection.LBConfig {
	odCfgRet := odCfg
	odCfgRet.ChildPolicy = &internalserviceconfig.BalancerConfig{Name: clusterimpl.Name, Config: ciCfg}
	return &odCfgRet
}

func buildClusterImplConfigForDNS(g *nameGenerator, endpoints []resolver.Endpoint, mechanism DiscoveryMechanism, xdsLBPolicy *internalserviceconfig.BalancerConfig) (string, *clusterimpl.LBConfig, []resolver.Endpoint) {
	pName := fmt.Sprintf("priority-%v", g.prefix)
	lbconfig := &clusterimpl.LBConfig{
		Cluster:               mechanism.Cluster,
		TelemetryLabels:       mechanism.TelemetryLabels,
		ChildPolicy:           xdsLBPolicy,
		MaxConcurrentRequests: mechanism.MaxConcurrentRequests,
		LoadReportingServer:   mechanism.LoadReportingServer,
	}
	if len(endpoints) == 0 {
		return pName, lbconfig, nil
	}
	var retEndpoint resolver.Endpoint
	for _, e := range endpoints {
		// LOGICAL_DNS requires all resolved addresses to be grouped into a
		// single logical endpoint. We iterate over the input endpoints and
		// aggregate their addresses into a new endpoint variable.
		retEndpoint.Addresses = append(retEndpoint.Addresses, e.Addresses...)
	}
	// Even though localities are not a thing for the LOGICAL_DNS cluster and
	// its endpoint(s), we add an empty locality attribute here to ensure that
	// LB policies that rely on locality information (like weighted_target)
	// continue to work.
	localityStr := xdsinternal.LocalityString(clients.Locality{})
	retEndpoint = xdsresource.SetHostname(hierarchy.SetInEndpoint(retEndpoint, []string{pName, localityStr}), mechanism.DNSHostname)
	// Set the locality weight to 1. This is required because the child policy
	// like weighted_target which relies on locality weights to distribute
	// traffic. These policies may drop traffic if the weight is 0.
	retEndpoint = wrrlocality.SetAddrInfo(retEndpoint, wrrlocality.AddrInfo{LocalityWeight: 1})
	return pName, lbconfig, []resolver.Endpoint{retEndpoint}
}

// buildClusterImplConfigForEDS returns a list of cluster_impl configs, one for