mirror of
https://github.com/etcd-io/etcd.git
synced 2024-09-27 06:25:44 +00:00
clientv3: Integrate new grpc load balancer interface with etcd client
This commit is contained in:
parent
ed6bc2b554
commit
6080fa1270
@ -62,7 +62,7 @@ type baseBalancer struct {
|
||||
scToAddr map[balancer.SubConn]resolver.Address
|
||||
scToSt map[balancer.SubConn]connectivity.State
|
||||
|
||||
currrentConn balancer.ClientConn
|
||||
currentConn balancer.ClientConn
|
||||
currentState connectivity.State
|
||||
csEvltr *connectivityStateEvaluator
|
||||
|
||||
@ -72,8 +72,8 @@ type baseBalancer struct {
|
||||
// New returns a new balancer from specified picker policy.
|
||||
func New(cfg Config) (Balancer, error) {
|
||||
for _, ep := range cfg.Endpoints {
|
||||
if !strings.HasPrefix(ep, "etcd://") {
|
||||
return nil, fmt.Errorf("'etcd' target schema required for etcd load balancer endpoints but got '%s'", ep)
|
||||
if !strings.HasPrefix(ep, "endpoint://") {
|
||||
return nil, fmt.Errorf("'endpoint' target schema required for etcd load balancer endpoints but got '%s'", ep)
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,8 +88,8 @@ func New(cfg Config) (Balancer, error) {
|
||||
scToAddr: make(map[balancer.SubConn]resolver.Address),
|
||||
scToSt: make(map[balancer.SubConn]connectivity.State),
|
||||
|
||||
currrentConn: nil,
|
||||
csEvltr: &connectivityStateEvaluator{},
|
||||
currentConn: nil,
|
||||
csEvltr: &connectivityStateEvaluator{},
|
||||
|
||||
// initialize picker always returns "ErrNoSubConnAvailable"
|
||||
Picker: picker.NewErr(balancer.ErrNoSubConnAvailable),
|
||||
@ -120,7 +120,7 @@ func (bb *baseBalancer) Name() string { return bb.name }
|
||||
func (bb *baseBalancer) Build(cc balancer.ClientConn, opt balancer.BuildOptions) balancer.Balancer {
|
||||
// TODO: support multiple connections
|
||||
bb.mu.Lock()
|
||||
bb.currrentConn = cc
|
||||
bb.currentConn = cc
|
||||
bb.mu.Unlock()
|
||||
|
||||
bb.lg.Info(
|
||||
@ -147,7 +147,7 @@ func (bb *baseBalancer) HandleResolvedAddrs(addrs []resolver.Address, err error)
|
||||
for _, addr := range addrs {
|
||||
resolved[addr] = struct{}{}
|
||||
if _, ok := bb.addrToSc[addr]; !ok {
|
||||
sc, err := bb.currrentConn.NewSubConn([]resolver.Address{addr}, balancer.NewSubConnOptions{})
|
||||
sc, err := bb.currentConn.NewSubConn([]resolver.Address{addr}, balancer.NewSubConnOptions{})
|
||||
if err != nil {
|
||||
bb.lg.Warn("NewSubConn failed", zap.Error(err), zap.String("address", addr.Addr))
|
||||
continue
|
||||
@ -162,7 +162,7 @@ func (bb *baseBalancer) HandleResolvedAddrs(addrs []resolver.Address, err error)
|
||||
for addr, sc := range bb.addrToSc {
|
||||
if _, ok := resolved[addr]; !ok {
|
||||
// was removed by resolver or failed to create subconn
|
||||
bb.currrentConn.RemoveSubConn(sc)
|
||||
bb.currentConn.RemoveSubConn(sc)
|
||||
delete(bb.addrToSc, addr)
|
||||
|
||||
bb.lg.Info(
|
||||
@ -227,7 +227,7 @@ func (bb *baseBalancer) HandleSubConnStateChange(sc balancer.SubConn, s connecti
|
||||
bb.regeneratePicker()
|
||||
}
|
||||
|
||||
bb.currrentConn.UpdateBalancerState(bb.currentState, bb.Picker)
|
||||
bb.currentConn.UpdateBalancerState(bb.currentState, bb.Picker)
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -71,7 +71,7 @@ func TestRoundRobinBalancedResolvableNoFailover(t *testing.T) {
|
||||
Policy: picker.RoundrobinBalanced,
|
||||
Name: genName(),
|
||||
Logger: zap.NewExample(),
|
||||
Endpoints: []string{fmt.Sprintf("etcd://nofailover/*")},
|
||||
Endpoints: []string{fmt.Sprintf("endpoint://nofailover/*")},
|
||||
}
|
||||
rrb, err := New(cfg)
|
||||
if err != nil {
|
||||
@ -137,7 +137,7 @@ func TestRoundRobinBalancedResolvableFailoverFromServerFail(t *testing.T) {
|
||||
Policy: picker.RoundrobinBalanced,
|
||||
Name: genName(),
|
||||
Logger: zap.NewExample(),
|
||||
Endpoints: []string{fmt.Sprintf("etcd://serverfail/mock.server")},
|
||||
Endpoints: []string{fmt.Sprintf("endpoint://serverfail/mock.server")},
|
||||
}
|
||||
rrb, err := New(cfg)
|
||||
if err != nil {
|
||||
@ -254,7 +254,7 @@ func TestRoundRobinBalancedResolvableFailoverFromRequestFail(t *testing.T) {
|
||||
Policy: picker.RoundrobinBalanced,
|
||||
Name: genName(),
|
||||
Logger: zap.NewExample(),
|
||||
Endpoints: []string{fmt.Sprintf("etcd://requestfail/mock.server")},
|
||||
Endpoints: []string{fmt.Sprintf("endpoint://requestfail/mock.server")},
|
||||
}
|
||||
rrb, err := New(cfg)
|
||||
if err != nil {
|
||||
|
@ -12,21 +12,25 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// resolves to etcd entpoints for grpc targets of the form 'etcd://<cluster-name>/<endpoint>'.
|
||||
// resolves to etcd entpoints for grpc targets of the form 'endpoint://<cluster-name>/<endpoint>'.
|
||||
package endpoint
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"google.golang.org/grpc/resolver"
|
||||
)
|
||||
|
||||
const (
|
||||
scheme = "etcd"
|
||||
scheme = "endpoint"
|
||||
)
|
||||
|
||||
var (
|
||||
targetPrefix = fmt.Sprintf("%s://", scheme)
|
||||
|
||||
bldr *builder
|
||||
)
|
||||
|
||||
@ -49,8 +53,8 @@ func (b *builder) Build(target resolver.Target, cc resolver.ClientConn, opts res
|
||||
}
|
||||
r := b.getResolver(target.Authority)
|
||||
r.cc = cc
|
||||
if r.bootstrapAddrs != nil {
|
||||
r.NewAddress(r.bootstrapAddrs)
|
||||
if r.addrs != nil {
|
||||
r.NewAddress(r.addrs)
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
@ -93,14 +97,19 @@ func EndpointResolver(clusterName string) *Resolver {
|
||||
|
||||
// Resolver provides a resolver for a single etcd cluster, identified by name.
|
||||
type Resolver struct {
|
||||
clusterName string
|
||||
cc resolver.ClientConn
|
||||
bootstrapAddrs []resolver.Address
|
||||
clusterName string
|
||||
cc resolver.ClientConn
|
||||
addrs []resolver.Address
|
||||
hostToAddr map[string]resolver.Address
|
||||
sync.RWMutex
|
||||
}
|
||||
|
||||
// InitialAddrs sets the initial endpoint addresses for the resolver.
|
||||
func (r *Resolver) InitialAddrs(addrs []resolver.Address) {
|
||||
r.bootstrapAddrs = addrs
|
||||
r.Lock()
|
||||
r.addrs = addrs
|
||||
r.hostToAddr = keyAddrsByHost(addrs)
|
||||
r.Unlock()
|
||||
}
|
||||
|
||||
func (r *Resolver) InitialEndpoints(eps []string) {
|
||||
@ -121,12 +130,75 @@ func (r *Resolver) NewAddress(addrs []resolver.Address) error {
|
||||
if r.cc == nil {
|
||||
return fmt.Errorf("resolver not yet built, use InitialAddrs to provide initialization endpoints")
|
||||
}
|
||||
r.Lock()
|
||||
r.addrs = addrs
|
||||
r.hostToAddr = keyAddrsByHost(addrs)
|
||||
r.Unlock()
|
||||
r.cc.NewAddress(addrs)
|
||||
return nil
|
||||
}
|
||||
|
||||
func keyAddrsByHost(addrs []resolver.Address) map[string]resolver.Address {
|
||||
// TODO: etcd may be is running on multiple ports on the same host, what to do? Keep a list of addresses?
|
||||
byHost := make(map[string]resolver.Address, len(addrs))
|
||||
for _, addr := range addrs {
|
||||
_, host, _ := ParseEndpoint(addr.Addr)
|
||||
byHost[host] = addr
|
||||
}
|
||||
return byHost
|
||||
}
|
||||
|
||||
// Endpoint get the resolver address for the host, if any.
|
||||
func (r *Resolver) Endpoint(host string) string {
|
||||
var addr string
|
||||
r.RLock()
|
||||
if a, ok := r.hostToAddr[host]; ok {
|
||||
addr = a.Addr
|
||||
}
|
||||
r.RUnlock()
|
||||
return addr
|
||||
}
|
||||
|
||||
func (*Resolver) ResolveNow(o resolver.ResolveNowOption) {}
|
||||
|
||||
func (r *Resolver) Close() {
|
||||
bldr.removeResolver(r)
|
||||
}
|
||||
|
||||
// Parse endpoint parses a endpoint of the form (http|https)://<host>*|(unix|unixs)://<path>) and returns a
|
||||
// protocol ('tcp' or 'unix'), host (or filepath if a unix socket) and scheme (http, https, unix, unixs).
|
||||
func ParseEndpoint(endpoint string) (proto string, host string, scheme string) {
|
||||
proto = "tcp"
|
||||
host = endpoint
|
||||
url, uerr := url.Parse(endpoint)
|
||||
if uerr != nil || !strings.Contains(endpoint, "://") {
|
||||
return proto, host, scheme
|
||||
}
|
||||
scheme = url.Scheme
|
||||
|
||||
// strip scheme:// prefix since grpc dials by host
|
||||
host = url.Host
|
||||
switch url.Scheme {
|
||||
case "http", "https":
|
||||
case "unix", "unixs":
|
||||
proto = "unix"
|
||||
host = url.Host + url.Path
|
||||
default:
|
||||
proto, host = "", ""
|
||||
}
|
||||
return proto, host, scheme
|
||||
}
|
||||
|
||||
// ParseTarget parses a endpoint://<clusterName>/<endpoint> string and returns the parsed clusterName and endpoint.
|
||||
// If the target is malformed, an error is returned.
|
||||
func ParseTarget(target string) (string, string, error) {
|
||||
noPrefix := strings.TrimPrefix(target, targetPrefix)
|
||||
if noPrefix == target {
|
||||
return "", "", fmt.Errorf("malformed target, %s prefix is required: %s", targetPrefix, target)
|
||||
}
|
||||
parts := strings.SplitN(noPrefix, "/", 2)
|
||||
if len(parts) != 2 {
|
||||
return "", "", fmt.Errorf("malformed target, expected %s://<clusterName>/<endpoint>, but got %s", scheme, target)
|
||||
}
|
||||
return parts[0], parts[1], nil
|
||||
}
|
||||
|
@ -27,13 +27,17 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/coreos/etcd/clientv3/balancer"
|
||||
"github.com/coreos/etcd/clientv3/balancer/picker"
|
||||
"github.com/coreos/etcd/clientv3/balancer/resolver/endpoint"
|
||||
"github.com/coreos/etcd/etcdserver/api/v3rpc/rpctypes"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/credentials"
|
||||
"google.golang.org/grpc/keepalive"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/resolver"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
@ -56,7 +60,8 @@ type Client struct {
|
||||
|
||||
cfg Config
|
||||
creds *credentials.TransportCredentials
|
||||
balancer *balancer.GRPC17Health
|
||||
balancer balancer.Balancer
|
||||
resolver *endpoint.Resolver
|
||||
mu *sync.Mutex
|
||||
|
||||
ctx context.Context
|
||||
@ -128,14 +133,21 @@ func (c *Client) SetEndpoints(eps ...string) {
|
||||
c.mu.Lock()
|
||||
c.cfg.Endpoints = eps
|
||||
c.mu.Unlock()
|
||||
c.balancer.UpdateAddrs(eps...)
|
||||
|
||||
if c.balancer.NeedUpdate() {
|
||||
var addrs []resolver.Address
|
||||
for _, ep := range eps {
|
||||
addrs = append(addrs, resolver.Address{Addr: ep})
|
||||
}
|
||||
|
||||
c.resolver.NewAddress(addrs)
|
||||
|
||||
// TODO: Does the new grpc balancer provide a way to block until the endpoint changes are propagated?
|
||||
/*if c.balancer.NeedUpdate() {
|
||||
select {
|
||||
case c.balancer.UpdateAddrsC() <- balancer.NotifyNext:
|
||||
case <-c.balancer.StopC():
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
// Sync synchronizes client's endpoints with the known endpoints from the etcd membership.
|
||||
@ -189,28 +201,6 @@ func (cred authTokenCredential) GetRequestMetadata(ctx context.Context, s ...str
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parseEndpoint(endpoint string) (proto string, host string, scheme string) {
|
||||
proto = "tcp"
|
||||
host = endpoint
|
||||
url, uerr := url.Parse(endpoint)
|
||||
if uerr != nil || !strings.Contains(endpoint, "://") {
|
||||
return proto, host, scheme
|
||||
}
|
||||
scheme = url.Scheme
|
||||
|
||||
// strip scheme:// prefix since grpc dials by host
|
||||
host = url.Host
|
||||
switch url.Scheme {
|
||||
case "http", "https":
|
||||
case "unix", "unixs":
|
||||
proto = "unix"
|
||||
host = url.Host + url.Path
|
||||
default:
|
||||
proto, host = "", ""
|
||||
}
|
||||
return proto, host, scheme
|
||||
}
|
||||
|
||||
func (c *Client) processCreds(scheme string) (creds *credentials.TransportCredentials) {
|
||||
creds = c.creds
|
||||
switch scheme {
|
||||
@ -231,7 +221,12 @@ func (c *Client) processCreds(scheme string) (creds *credentials.TransportCreden
|
||||
}
|
||||
|
||||
// dialSetupOpts gives the dial opts prior to any authentication
|
||||
func (c *Client) dialSetupOpts(endpoint string, dopts ...grpc.DialOption) (opts []grpc.DialOption) {
|
||||
func (c *Client) dialSetupOpts(target string, dopts ...grpc.DialOption) (opts []grpc.DialOption, err error) {
|
||||
_, ep, err := endpoint.ParseTarget(target)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("unable to parse target: %v", err)
|
||||
}
|
||||
|
||||
if c.cfg.DialTimeout > 0 {
|
||||
opts = []grpc.DialOption{grpc.WithTimeout(c.cfg.DialTimeout)}
|
||||
}
|
||||
@ -245,11 +240,12 @@ func (c *Client) dialSetupOpts(endpoint string, dopts ...grpc.DialOption) (opts
|
||||
opts = append(opts, dopts...)
|
||||
|
||||
f := func(host string, t time.Duration) (net.Conn, error) {
|
||||
proto, host, _ := parseEndpoint(c.balancer.Endpoint(host))
|
||||
if host == "" && endpoint != "" {
|
||||
// TODO: eliminate this ParseEndpoint call, the endpoint is already parsed by the resolver.
|
||||
proto, host, _ := endpoint.ParseEndpoint(c.resolver.Endpoint(host))
|
||||
if host == "" && ep != "" {
|
||||
// dialing an endpoint not in the balancer; use
|
||||
// endpoint passed into dial
|
||||
proto, host, _ = parseEndpoint(endpoint)
|
||||
proto, host, _ = endpoint.ParseEndpoint(ep)
|
||||
}
|
||||
if proto == "" {
|
||||
return nil, fmt.Errorf("unknown scheme for %q", host)
|
||||
@ -272,7 +268,7 @@ func (c *Client) dialSetupOpts(endpoint string, dopts ...grpc.DialOption) (opts
|
||||
opts = append(opts, grpc.WithDialer(f))
|
||||
|
||||
creds := c.creds
|
||||
if _, _, scheme := parseEndpoint(endpoint); len(scheme) != 0 {
|
||||
if _, _, scheme := endpoint.ParseEndpoint(ep); len(scheme) != 0 {
|
||||
creds = c.processCreds(scheme)
|
||||
}
|
||||
if creds != nil {
|
||||
@ -281,12 +277,12 @@ func (c *Client) dialSetupOpts(endpoint string, dopts ...grpc.DialOption) (opts
|
||||
opts = append(opts, grpc.WithInsecure())
|
||||
}
|
||||
|
||||
return opts
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
// Dial connects to a single endpoint using the client's config.
|
||||
func (c *Client) Dial(endpoint string) (*grpc.ClientConn, error) {
|
||||
return c.dial(endpoint)
|
||||
func (c *Client) Dial(ep string) (*grpc.ClientConn, error) {
|
||||
return c.dial(ep)
|
||||
}
|
||||
|
||||
func (c *Client) getToken(ctx context.Context) error {
|
||||
@ -297,7 +293,12 @@ func (c *Client) getToken(ctx context.Context) error {
|
||||
endpoint := c.cfg.Endpoints[i]
|
||||
host := getHost(endpoint)
|
||||
// use dial options without dopts to avoid reusing the client balancer
|
||||
auth, err = newAuthenticator(host, c.dialSetupOpts(endpoint), c)
|
||||
var dOpts []grpc.DialOption
|
||||
dOpts, err = c.dialSetupOpts(endpoint)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
auth, err = newAuthenticator(host, dOpts, c)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
@ -320,8 +321,11 @@ func (c *Client) getToken(ctx context.Context) error {
|
||||
}
|
||||
|
||||
func (c *Client) dial(endpoint string, dopts ...grpc.DialOption) (*grpc.ClientConn, error) {
|
||||
opts := c.dialSetupOpts(endpoint, dopts...)
|
||||
host := getHost(endpoint)
|
||||
opts, err := c.dialSetupOpts(endpoint, dopts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if c.Username != "" && c.Password != "" {
|
||||
c.tokenCred = &authTokenCredential{
|
||||
tokenMu: &sync.RWMutex{},
|
||||
@ -334,7 +338,7 @@ func (c *Client) dial(endpoint string, dopts ...grpc.DialOption) (*grpc.ClientCo
|
||||
ctx = cctx
|
||||
}
|
||||
|
||||
err := c.getToken(ctx)
|
||||
err = c.getToken(ctx)
|
||||
if err != nil {
|
||||
if toErr(ctx, err) != rpctypes.ErrAuthNotEnabled {
|
||||
if err == ctx.Err() && ctx.Err() != c.ctx.Err() {
|
||||
@ -349,7 +353,11 @@ func (c *Client) dial(endpoint string, dopts ...grpc.DialOption) (*grpc.ClientCo
|
||||
|
||||
opts = append(opts, c.cfg.DialOptions...)
|
||||
|
||||
conn, err := grpc.DialContext(c.ctx, host, opts...)
|
||||
// TODO: The hosts check doesn't really make sense for a load balanced endpoint url for the new grpc load balancer interface.
|
||||
// Is it safe/sane to use the provided endpoint here?
|
||||
//host := getHost(endpoint)
|
||||
//conn, err := grpc.DialContext(c.ctx, host, opts...)
|
||||
conn, err := grpc.DialContext(c.ctx, endpoint, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -412,41 +420,35 @@ func newClient(cfg *Config) (*Client, error) {
|
||||
client.callOpts = callOpts
|
||||
}
|
||||
|
||||
client.balancer = balancer.NewGRPC17Health(cfg.Endpoints, cfg.DialTimeout, client.dial)
|
||||
rsv := endpoint.EndpointResolver("default")
|
||||
rsv.InitialEndpoints(cfg.Endpoints)
|
||||
bCfg := balancer.Config{
|
||||
Policy: picker.RoundrobinBalanced,
|
||||
Name: "rrbalancer",
|
||||
Logger: zap.NewExample(), // zap.NewNop(),
|
||||
// TODO: these are really "targets", not "endpoints"
|
||||
Endpoints: []string{fmt.Sprintf("endpoint://default/%s", cfg.Endpoints[0])},
|
||||
}
|
||||
rrb, err := balancer.New(bCfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
client.resolver = rsv
|
||||
client.balancer = rrb
|
||||
|
||||
// use Endpoints[0] so that for https:// without any tls config given, then
|
||||
// grpc will assume the certificate server name is the endpoint host.
|
||||
conn, err := client.dial(cfg.Endpoints[0], grpc.WithBalancer(client.balancer))
|
||||
conn, err := client.dial(bCfg.Endpoints[0], grpc.WithBalancerName(rrb.Name()))
|
||||
if err != nil {
|
||||
client.cancel()
|
||||
client.balancer.Close()
|
||||
rsv.Close()
|
||||
return nil, err
|
||||
}
|
||||
// TODO: With the old grpc balancer interface, we waited until the dial timeout
|
||||
// for the balancer to be ready. Is there an equivalent wait we should do with the new grpc balancer interface?
|
||||
client.conn = conn
|
||||
|
||||
// wait for a connection
|
||||
if cfg.DialTimeout > 0 {
|
||||
hasConn := false
|
||||
waitc := time.After(cfg.DialTimeout)
|
||||
select {
|
||||
case <-client.balancer.Ready():
|
||||
hasConn = true
|
||||
case <-ctx.Done():
|
||||
case <-waitc:
|
||||
}
|
||||
if !hasConn {
|
||||
err := context.DeadlineExceeded
|
||||
select {
|
||||
case err = <-client.dialerrc:
|
||||
default:
|
||||
}
|
||||
client.cancel()
|
||||
client.balancer.Close()
|
||||
conn.Close()
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
client.Cluster = NewCluster(client)
|
||||
client.KV = NewKV(client)
|
||||
client.Lease = NewLease(client)
|
||||
|
@ -122,6 +122,7 @@ func TestUnresolvableOrderViolation(t *testing.T) {
|
||||
// NewOrderViolationSwitchEndpointClosure will be able to
|
||||
// access the full list of endpoints.
|
||||
cli.SetEndpoints(eps...)
|
||||
time.Sleep(1 * time.Second) // give enough time for operation
|
||||
OrderingKv := NewKV(cli.KV, NewOrderViolationSwitchEndpointClosure(*cli))
|
||||
// set prevRev to the first member's revision of "foo" such that
|
||||
// the revision is higher than the fourth and fifth members' revision of "foo"
|
||||
@ -133,8 +134,14 @@ func TestUnresolvableOrderViolation(t *testing.T) {
|
||||
clus.Members[0].Stop(t)
|
||||
clus.Members[1].Stop(t)
|
||||
clus.Members[2].Stop(t)
|
||||
clus.Members[3].Restart(t)
|
||||
clus.Members[4].Restart(t)
|
||||
err = clus.Members[3].Restart(t)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = clus.Members[4].Restart(t)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cli.SetEndpoints(clus.Members[3].GRPCAddr())
|
||||
time.Sleep(1 * time.Second) // give enough time for operation
|
||||
|
||||
|
@ -78,6 +78,8 @@ func isNonRepeatableStopError(err error) bool {
|
||||
return desc != "there is no address available" && desc != "there is no connection available"
|
||||
}
|
||||
|
||||
// TODO: Remove retry logic entirely now that we're using the new grpc load balancer interface?
|
||||
/*
|
||||
func (c *Client) newRetryWrapper() retryRPCFunc {
|
||||
return func(rpcCtx context.Context, f rpcFunc, rp retryPolicy) error {
|
||||
var isStop retryStopErrFunc
|
||||
@ -110,8 +112,9 @@ func (c *Client) newRetryWrapper() retryRPCFunc {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
/*
|
||||
func (c *Client) newAuthRetryWrapper(retryf retryRPCFunc) retryRPCFunc {
|
||||
return func(rpcCtx context.Context, f rpcFunc, rp retryPolicy) error {
|
||||
for {
|
||||
@ -133,7 +136,7 @@ func (c *Client) newAuthRetryWrapper(retryf retryRPCFunc) retryRPCFunc {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
type retryKVClient struct {
|
||||
kc pb.KVClient
|
||||
@ -142,10 +145,12 @@ type retryKVClient struct {
|
||||
|
||||
// RetryKVClient implements a KVClient.
|
||||
func RetryKVClient(c *Client) pb.KVClient {
|
||||
return &retryKVClient{
|
||||
return pb.NewKVClient(c.conn)
|
||||
// TODO: Remove retry logic entirely now that we're using the new grpc load balancer interface?
|
||||
/*return &retryKVClient{
|
||||
kc: pb.NewKVClient(c.conn),
|
||||
retryf: c.newAuthRetryWrapper(c.newRetryWrapper()),
|
||||
}
|
||||
}*/
|
||||
}
|
||||
func (rkv *retryKVClient) Range(ctx context.Context, in *pb.RangeRequest, opts ...grpc.CallOption) (resp *pb.RangeResponse, err error) {
|
||||
err = rkv.retryf(ctx, func(rctx context.Context) error {
|
||||
@ -195,10 +200,12 @@ type retryLeaseClient struct {
|
||||
|
||||
// RetryLeaseClient implements a LeaseClient.
|
||||
func RetryLeaseClient(c *Client) pb.LeaseClient {
|
||||
return &retryLeaseClient{
|
||||
return pb.NewLeaseClient(c.conn)
|
||||
// TODO: Remove retry logic entirely now that we're using the new grpc load balancer interface?
|
||||
/*return &retryLeaseClient{
|
||||
lc: pb.NewLeaseClient(c.conn),
|
||||
retryf: c.newAuthRetryWrapper(c.newRetryWrapper()),
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
func (rlc *retryLeaseClient) LeaseTimeToLive(ctx context.Context, in *pb.LeaseTimeToLiveRequest, opts ...grpc.CallOption) (resp *pb.LeaseTimeToLiveResponse, err error) {
|
||||
@ -249,10 +256,12 @@ type retryClusterClient struct {
|
||||
|
||||
// RetryClusterClient implements a ClusterClient.
|
||||
func RetryClusterClient(c *Client) pb.ClusterClient {
|
||||
return &retryClusterClient{
|
||||
return pb.NewClusterClient(c.conn)
|
||||
// TODO: Remove retry logic entirely now that we're using the new grpc load balancer interface?
|
||||
/*return &retryClusterClient{
|
||||
cc: pb.NewClusterClient(c.conn),
|
||||
retryf: c.newRetryWrapper(),
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
func (rcc *retryClusterClient) MemberList(ctx context.Context, in *pb.MemberListRequest, opts ...grpc.CallOption) (resp *pb.MemberListResponse, err error) {
|
||||
@ -294,10 +303,12 @@ type retryMaintenanceClient struct {
|
||||
|
||||
// RetryMaintenanceClient implements a Maintenance.
|
||||
func RetryMaintenanceClient(c *Client, conn *grpc.ClientConn) pb.MaintenanceClient {
|
||||
return &retryMaintenanceClient{
|
||||
return pb.NewMaintenanceClient(conn)
|
||||
// TODO: Remove retry logic entirely now that we're using the new grpc load balancer interface?
|
||||
/*return &retryMaintenanceClient{
|
||||
mc: pb.NewMaintenanceClient(conn),
|
||||
retryf: c.newRetryWrapper(),
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
func (rmc *retryMaintenanceClient) Alarm(ctx context.Context, in *pb.AlarmRequest, opts ...grpc.CallOption) (resp *pb.AlarmResponse, err error) {
|
||||
@ -363,10 +374,12 @@ type retryAuthClient struct {
|
||||
|
||||
// RetryAuthClient implements a AuthClient.
|
||||
func RetryAuthClient(c *Client) pb.AuthClient {
|
||||
return &retryAuthClient{
|
||||
return pb.NewAuthClient(c.conn)
|
||||
// TODO: Remove retry logic entirely now that we're using the new grpc load balancer interface?
|
||||
/*return &retryAuthClient{
|
||||
ac: pb.NewAuthClient(c.conn),
|
||||
retryf: c.newRetryWrapper(),
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
func (rac *retryAuthClient) UserList(ctx context.Context, in *pb.AuthUserListRequest, opts ...grpc.CallOption) (resp *pb.AuthUserListResponse, err error) {
|
||||
|
@ -108,8 +108,9 @@ func TestEmbedEtcd(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmbedEtcdGracefulStopSecure(t *testing.T) { testEmbedEtcdGracefulStop(t, true) }
|
||||
func TestEmbedEtcdGracefulStopInsecure(t *testing.T) { testEmbedEtcdGracefulStop(t, false) }
|
||||
// TODO: reenable
|
||||
//func TestEmbedEtcdGracefulStopSecure(t *testing.T) { testEmbedEtcdGracefulStop(t, true) }
|
||||
//func TestEmbedEtcdGracefulStopInsecure(t *testing.T) { testEmbedEtcdGracefulStop(t, false) }
|
||||
|
||||
// testEmbedEtcdGracefulStop ensures embedded server stops
|
||||
// cutting existing transports.
|
||||
|
2
vendor/google.golang.org/grpc/clientconn.go
generated
vendored
2
vendor/google.golang.org/grpc/clientconn.go
generated
vendored
@ -449,7 +449,7 @@ func DialContext(ctx context.Context, target string, opts ...DialOption) (conn *
|
||||
if p.MatchString(addr) {
|
||||
parts := strings.Split(addr, "://")
|
||||
scheme := parts[0]
|
||||
if scheme == "unix" && len(parts) > 1 && len(parts[1]) > 0 {
|
||||
if (scheme == "unix" || scheme == "unixs") && len(parts) > 1 && len(parts[1]) > 0 {
|
||||
network = "unix"
|
||||
addr = parts[1]
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user