-
Notifications
You must be signed in to change notification settings - Fork 10.2k
Open
Labels
Description
Bug report criteria
- This bug report is not security related, security issues should be disclosed privately via etcd maintainers.
- This is not a support request or question, support requests or questions should be raised in the etcd discussion forums.
- You have read the etcd bug reporting guidelines.
- Existing open issues along with etcd frequently asked questions have been checked and this is not a duplicate.
What happened?
use grpc client made by etcd resolver with google.golang.org/grpc v1.71.0 cause panic
What did you expect to happen?
call rpc method successfully
How can we reproduce it (as minimally and precisely as possible)?
get a grpc client like this
import (
"go.etcd.io/etcd/client/v3/naming/resolver"
"google.golang.org/grpc"
)
// GetGrpcClient get grpc client for serverName
//
// don't forget to close conn conn.Close()
func GetGrpcClient[T any](serverName string,
clientBuilder func(grpcConn grpc.ClientConnInterface) (client T),
opts ...grpc.DialOption) (conn *grpc.ClientConn, client T, err error) {
//refers to https://etcd.io/docs/v3.5/dev-guide/grpc_naming/
etcdResolver, err := resolver.NewBuilder(GetClient())
if err != nil {
return nil, client, err
}
options := []grpc.DialOption{
grpc.WithResolvers(etcdResolver),
grpc.WithDefaultServiceConfig(`{"loadBalancingPolicy":"round_robin"}`),
}
options = append(options, opts...)
conn, err = grpc.NewClient("etcd:///grpc/"+serverName,
options...,
)
client = clientBuilder(conn)
return conn, client, err
}and use the client call a method
Anything else we need to know?
go 1.24
google.golang.org/grpc v1.70.0 works fine
create a grpc client manually works fine
func TestPanic(t *testing.T) {
etcdCloseFunc := global_config.InitEtcdClient(false)
defer etcdCloseFunc()
_, client, err := GetClient()
if err != nil {
t.Error(err)
} else {
status, err := client.UpdateLocationOnlineStatus(context.Background(), &UpdateLocationOnlineStatus_Input{
UserId: "test",
})
if err != nil {
t.Error(err)
}
t.Log(status)
}
}
func TestWorksFine(t *testing.T) {
conn, err := grpc.NewClient("127.0.0.1:58759",
grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
client := NewRPCDaZiNearbyClient(conn)
ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*2)
defer cancelFunc()
resp, err := client.UpdateLocationOnlineStatus(ctx, &UpdateLocationOnlineStatus_Input{
UserId: "test",
})
if err != nil {
log.Fatalf("could not test: %v", err)
}
log.Printf("DeleteTest response: %v", resp)
}Etcd version (please run commands below)
deployed by docker
ss-etcd:
image: quay.io/coreos/etcd:v3.5.17-arm64
# image: quay.io/coreos/etcd:v3.5.17-amd64
container_name: ss-etcd
command:
[
"/usr/local/bin/etcd",
"--data-dir=/etcd-data",
"--name=node1",
"--initial-advertise-peer-urls=http://ss-etcd:2380",
"--listen-peer-urls=http://0.0.0.0:2380",
"--advertise-client-urls=http://ss-etcd:2379",
"--listen-client-urls=http://0.0.0.0:2379",
"--initial-cluster=node1=http://ss-etcd:2380"
]
restart: unless-stopped
ports:
- "2379:2379"
- "2380:2380"
volumes:
- ./etcd/data:/etcd-dataEtcd configuration (command line flags or environment variables)
default
Etcd debug information (please run commands below, feel free to obfuscate the IP address or FQDN in the output)
standaloneRelevant log output
=== RUN TestPanic
panic: runtime error: comparing uncomparable type map[string]interface {}
goroutine 11 [running]:
google.golang.org/grpc/balancer/pickfirst/pickfirstleaf.equalAddressIgnoringBalAttributes(0x1400031c970, 0x1400031ca10)
/Users/cruvie/go/pkg/mod/google.golang.org/grpc@v1.71.1/balancer/pickfirst/pickfirstleaf/pickfirstleaf.go:931 +0xe0
google.golang.org/grpc/balancer/pickfirst/pickfirstleaf.(*addressList).seekTo(0x14000333e20, {{0x14000040468, 0x13}, {0x0, 0x0}, 0x0, 0x140001225a0, {0x104f75a00, 0x14000414030}})
/Users/cruvie/go/pkg/mod/google.golang.org/grpc@v1.71.1/balancer/pickfirst/pickfirstleaf/pickfirstleaf.go:905 +0xc8
google.golang.org/grpc/balancer/pickfirst/pickfirstleaf.(*pickfirstBalancer).updateSubConnState(0x14000333dd0, 0x1400030d880, {0x2, {0x0, 0x0}, {{0x14000040468, 0x13}, {0x14000152ea0, 0x21}, 0x0, ...}})
/Users/cruvie/go/pkg/mod/google.golang.org/grpc@v1.71.1/balancer/pickfirst/pickfirstleaf/pickfirstleaf.go:627 +0x81c
google.golang.org/grpc/balancer/pickfirst/pickfirstleaf.(*pickfirstBalancer).newSCData.func1({0x2, {0x0, 0x0}, {{0x14000040468, 0x13}, {0x14000152ea0, 0x21}, 0x0, 0x140001225a0, {0x104f75a00, ...}}})
/Users/cruvie/go/pkg/mod/google.golang.org/grpc@v1.71.1/balancer/pickfirst/pickfirstleaf/pickfirstleaf.go:197 +0x84
google.golang.org/grpc/internal/balancer/gracefulswitch.(*Balancer).updateSubConnState(0x140000f05a0, {0x105116900, 0x1400003ba40}, {0x2, {0x0, 0x0}, {{0x14000040468, 0x13}, {0x14000152ea0, 0x21}, ...}}, ...)
/Users/cruvie/go/pkg/mod/google.golang.org/grpc@v1.71.1/internal/balancer/gracefulswitch/gracefulswitch.go:262 +0x2bc
google.golang.org/grpc/internal/balancer/gracefulswitch.(*balancerWrapper).NewSubConn.func1({0x2, {0x0, 0x0}, {{0x14000040468, 0x13}, {0x14000152ea0, 0x21}, 0x0, 0x140001225a0, {0x104f75a00, ...}}})
/Users/cruvie/go/pkg/mod/google.golang.org/grpc@v1.71.1/internal/balancer/gracefulswitch/gracefulswitch.go:378 +0x98
google.golang.org/grpc.(*acBalancerWrapper).updateState.func1({0x105112108?, 0x140004f8c30?})
/Users/cruvie/go/pkg/mod/google.golang.org/grpc@v1.71.1/balancer_wrapper.go:341 +0x274
google.golang.org/grpc/internal/grpcsync.(*CallbackSerializer).run(0x14000111d80, {0x105112108, 0x140004f8c30})
/Users/cruvie/go/pkg/mod/google.golang.org/grpc@v1.71.1/internal/grpcsync/callback_serializer.go:94 +0x10c
created by google.golang.org/grpc/internal/grpcsync.NewCallbackSerializer in goroutine 25
/Users/cruvie/go/pkg/mod/google.golang.org/grpc@v1.71.1/internal/grpcsync/callback_serializer.go:52 +0x118