-
Notifications
You must be signed in to change notification settings - Fork 4.7k
balancer: expose endpoint weight and hostname as experimental APIs #9074
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 7 commits
5ed3447
d39465e
83417df
1b58d32
0132067
3b06903
cad2a5f
9fa484c
777e7f6
f30c259
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,58 @@ | ||
| /* | ||
| * | ||
| * Copyright 2026 gRPC authors. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| * | ||
| */ | ||
|
|
||
| // Package hostname contains utilities for the endpoint hostname attribute | ||
| // (used for per-endpoint :authority / SNI override). | ||
| // | ||
| // # Experimental | ||
| // | ||
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | ||
| // later release. | ||
| package hostname | ||
|
|
||
| import "google.golang.org/grpc/resolver" | ||
|
|
||
| type hostnameKey struct{} | ||
|
|
||
| // Set returns a copy of the given endpoint with the hostname attribute set. | ||
| // If hostname is empty the endpoint is returned unmodified. | ||
| // | ||
| // # Experimental | ||
| // | ||
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | ||
| // later release. | ||
| func Set(endpoint resolver.Endpoint, hostname string) resolver.Endpoint { | ||
| if hostname == "" { | ||
| return endpoint | ||
| } | ||
| endpoint.Attributes = endpoint.Attributes.WithValue(hostnameKey{}, hostname) | ||
| return endpoint | ||
| } | ||
|
|
||
| // FromEndpoint returns the hostname attribute of endpoint. If this attribute is | ||
| // not set, it returns the empty string. | ||
| // | ||
| // # Experimental | ||
| // | ||
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | ||
| // later release. | ||
| func FromEndpoint(endpoint resolver.Endpoint) string { | ||
| h, _ := endpoint.Attributes.Value(hostnameKey{}).(string) | ||
| return h | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| /* | ||
| * | ||
| * Copyright 2026 gRPC authors. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| * | ||
| */ | ||
|
|
||
| package hostname_test | ||
|
|
||
| import ( | ||
| "testing" | ||
|
|
||
| "google.golang.org/grpc/balancer/hostname" | ||
| "google.golang.org/grpc/resolver" | ||
| ) | ||
|
|
||
| func TestHostname_SetAndGet(t *testing.T) { | ||
|
Pranjali-2501 marked this conversation as resolved.
Outdated
|
||
| ep := resolver.Endpoint{} | ||
| if h := hostname.FromEndpoint(ep); h != "" { | ||
| t.Errorf("empty = %q", h) | ||
| } | ||
|
|
||
| ep2 := hostname.Set(ep, "myservice.example.com") | ||
| if h := hostname.FromEndpoint(ep2); h != "myservice.example.com" { | ||
| t.Errorf("got %q", h) | ||
| } | ||
|
|
||
| // empty hostname returns same endpoint | ||
| ep3 := hostname.Set(ep2, "") | ||
| if hostname.FromEndpoint(ep3) != "myservice.example.com" { | ||
| t.Error("empty should not overwrite") | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,11 @@ | |
| // Package weight contains utilities to manage endpoint weights. Weights are | ||
| // used by LB policies such as ringhash to distribute load across multiple | ||
| // endpoints. | ||
| // | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of putting a deprecated message and creating new files in
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done - i also added the "Experimental" comment because this is a newly-public API. is that fine? |
||
| // # Experimental | ||
| // | ||
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | ||
| // later release. | ||
| package weight | ||
|
|
||
| import ( | ||
|
|
@@ -45,6 +50,11 @@ func (a EndpointInfo) Equal(o any) bool { | |
|
|
||
| // Set returns a copy of endpoint in which the Attributes field is updated with | ||
| // EndpointInfo. | ||
| // | ||
| // # Experimental | ||
| // | ||
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | ||
| // later release. | ||
| func Set(endpoint resolver.Endpoint, epInfo EndpointInfo) resolver.Endpoint { | ||
| endpoint.Attributes = endpoint.Attributes.WithValue(attributeKey{}, epInfo) | ||
| return endpoint | ||
|
|
@@ -59,6 +69,11 @@ func (a EndpointInfo) String() string { | |
|
|
||
| // FromEndpoint returns the EndpointInfo stored in the Attributes field of an | ||
| // endpoint. It returns an empty EndpointInfo if attribute is not found. | ||
| // | ||
| // # Experimental | ||
| // | ||
| // Notice: This API is EXPERIMENTAL and may be changed or removed in a | ||
| // later release. | ||
| func FromEndpoint(endpoint resolver.Endpoint) EndpointInfo { | ||
| v := endpoint.Attributes.Value(attributeKey{}) | ||
| ei, _ := v.(EndpointInfo) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,37 +26,23 @@ import ( | |
| v3corepb "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" | ||
| v3endpointpb "github.com/envoyproxy/go-control-plane/envoy/config/endpoint/v3" | ||
| v3typepb "github.com/envoyproxy/go-control-plane/envoy/type/v3" | ||
| "google.golang.org/protobuf/proto" | ||
| "google.golang.org/protobuf/types/known/anypb" | ||
|
|
||
|
Pranjali-2501 marked this conversation as resolved.
Outdated
|
||
| "google.golang.org/grpc/balancer/hostname" | ||
| "google.golang.org/grpc/internal/envconfig" | ||
| "google.golang.org/grpc/internal/pretty" | ||
| xdsinternal "google.golang.org/grpc/internal/xds" | ||
| "google.golang.org/grpc/internal/xds/clients" | ||
| "google.golang.org/grpc/resolver" | ||
| "google.golang.org/grpc/resolver/ringhash" | ||
| "google.golang.org/protobuf/proto" | ||
| "google.golang.org/protobuf/types/known/anypb" | ||
| ) | ||
|
|
||
| // hostnameKeyType is the key to store the hostname attribute in | ||
| // a resolver.Endpoint. | ||
| type hostnameKeyType struct{} | ||
|
|
||
| // SetHostname returns a copy of the given endpoint with hostname added | ||
| // as an attribute. | ||
| func SetHostname(endpoint resolver.Endpoint, hostname string) resolver.Endpoint { | ||
| // Only set if non-empty; xds_cluster_impl uses this to trigger :authority | ||
| // rewriting. | ||
| if hostname == "" { | ||
| return endpoint | ||
| } | ||
| endpoint.Attributes = endpoint.Attributes.WithValue(hostnameKeyType{}, hostname) | ||
| return endpoint | ||
| } | ||
|
|
||
| // Hostname returns the hostname from the BalancerAttributes of the given | ||
| // Address. If this attribute is not set, it returns the empty string. | ||
| // Hostname returns the hostname from the given legacy Address. | ||
| // If this attribute is not set, it returns the empty string. | ||
| func Hostname(addr resolver.Address) string { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please revert the changes made in this function. We have an exported function to set hostname in endpoint. And will keep the function internal to retrieve the hostname
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hi @Pranjali-2501 reverting this function causes two issues:
The current implementation delegates to
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IMO, the best way will be to move this function to
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
| hostname, _ := addr.BalancerAttributes.Value(hostnameKeyType{}).(string) | ||
| return hostname | ||
| ep := resolver.Endpoint{Attributes: addr.BalancerAttributes} | ||
| return hostname.FromEndpoint(ep) | ||
| } | ||
|
|
||
| func unmarshalEndpointsResource(r *anypb.Any) (string, EndpointsUpdate, error) { | ||
|
|
@@ -166,7 +152,7 @@ func parseEndpoints(lbEndpoints []*v3endpointpb.LbEndpoint, uniqueEndpointAddrs | |
| } | ||
| } | ||
| endpoint := resolver.Endpoint{Addresses: address} | ||
| endpoint = SetHostname(endpoint, lbEndpoint.GetEndpoint().GetHostname()) | ||
| endpoint = hostname.Set(endpoint, lbEndpoint.GetEndpoint().GetHostname()) | ||
| endpoint = ringhash.SetHashKey(endpoint, hashKey) | ||
| endpoints = append(endpoints, Endpoint{ | ||
| ResolverEndpoint: endpoint, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: wrap the comment in 80 columns.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done