vendor: update dependencies

This commit is contained in:
Gyu-Ho Lee 2016-09-24 11:39:25 -07:00
parent 405e943da6
commit 624e61634e
44 changed files with 1958 additions and 757 deletions

View File

@ -798,23 +798,23 @@ var (
) )
var fileDescriptorAuth = []byte{ var fileDescriptorAuth = []byte{
// 288 bytes of a gzipped FileDescriptorProto // 280 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x90, 0xc1, 0x4a, 0xc3, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xe2, 0xe2, 0x4a, 0x2c, 0x2d, 0xc9,
0x1c, 0xc6, 0x9b, 0xb6, 0x1b, 0xed, 0x5f, 0x27, 0x25, 0x0c, 0x0c, 0x13, 0x42, 0xe9, 0xa9, 0x78, 0xd0, 0x2b, 0x28, 0xca, 0x2f, 0xc9, 0x17, 0x62, 0x03, 0xb1, 0x0b, 0x92, 0xa4, 0x44, 0xd2, 0xf3,
0xa8, 0xb0, 0x5d, 0xbc, 0x2a, 0xf6, 0x20, 0x78, 0x90, 0x50, 0xf1, 0x28, 0x1d, 0x0d, 0x75, 0x6c, 0xd3, 0xf3, 0xc1, 0x42, 0xfa, 0x20, 0x16, 0x44, 0x56, 0xc9, 0x87, 0x8b, 0x25, 0xb4, 0x38, 0xb5,
0x6d, 0x4a, 0x32, 0x91, 0xbe, 0x89, 0x07, 0x1f, 0x68, 0xc7, 0x3d, 0x82, 0xab, 0x2f, 0x22, 0x4d, 0x48, 0x48, 0x88, 0x8b, 0x25, 0x2f, 0x31, 0x37, 0x55, 0x82, 0x51, 0x81, 0x51, 0x83, 0x27, 0x08,
0x64, 0x43, 0xdc, 0xed, 0xfb, 0xbe, 0xff, 0x97, 0xe4, 0x97, 0x3f, 0x40, 0xfe, 0xb6, 0x7e, 0x4d, 0xcc, 0x16, 0x92, 0xe2, 0xe2, 0x28, 0x48, 0x2c, 0x2e, 0x2e, 0xcf, 0x2f, 0x4a, 0x91, 0x60, 0x02,
0x1a, 0x29, 0xd6, 0x02, 0x0f, 0x7b, 0xdd, 0xcc, 0x27, 0xe3, 0x52, 0x94, 0x42, 0x47, 0x57, 0xbd, 0x8b, 0xc3, 0xf9, 0x42, 0x22, 0x5c, 0xac, 0x45, 0xf9, 0x39, 0xa9, 0xc5, 0x12, 0xcc, 0x0a, 0xcc,
0x32, 0xd3, 0xe8, 0x01, 0xdc, 0x27, 0xc5, 0x25, 0xc6, 0xe0, 0xd6, 0x79, 0xc5, 0x09, 0x0a, 0x51, 0x1a, 0x9c, 0x41, 0x10, 0x8e, 0xd2, 0x1c, 0x46, 0x2e, 0xae, 0x80, 0xd4, 0xa2, 0xdc, 0xcc, 0xe2,
0x7c, 0xca, 0xb4, 0xc6, 0x13, 0xf0, 0x9a, 0x5c, 0xa9, 0x77, 0x21, 0x0b, 0x62, 0xeb, 0x7c, 0xef, 0xe2, 0xcc, 0xfc, 0x3c, 0x21, 0x63, 0xa0, 0x01, 0x40, 0x5e, 0x48, 0x65, 0x01, 0xc4, 0x60, 0x3e,
0xf1, 0x18, 0x06, 0x52, 0xac, 0xb8, 0x22, 0x4e, 0xe8, 0xc4, 0x3e, 0x33, 0x26, 0xfa, 0x44, 0x00, 0x23, 0x71, 0x3d, 0x88, 0x6b, 0xf4, 0x10, 0xaa, 0xf4, 0x40, 0xd2, 0x41, 0x70, 0x85, 0x42, 0x02,
0x8f, 0x5c, 0x56, 0x0b, 0xa5, 0x16, 0xa2, 0xc6, 0x33, 0xf0, 0x1a, 0x2e, 0xab, 0xac, 0x6d, 0xcc, 0x5c, 0xcc, 0xd9, 0xa9, 0x95, 0x50, 0x0b, 0x41, 0x4c, 0x21, 0x69, 0x2e, 0xce, 0xa2, 0xc4, 0xbc,
0xc5, 0x67, 0xd3, 0xf3, 0xc4, 0xd0, 0x24, 0x87, 0x56, 0xd2, 0x8f, 0xd9, 0xbe, 0x88, 0x03, 0x70, 0xf4, 0xd4, 0xf8, 0xd4, 0xbc, 0x14, 0xa0, 0x7d, 0x60, 0x87, 0x80, 0x05, 0x5c, 0xf3, 0x52, 0x94,
0x96, 0xbc, 0xfd, 0x7d, 0xb0, 0x97, 0xf8, 0x02, 0x7c, 0x99, 0xd7, 0x25, 0x7f, 0xe1, 0x75, 0x41, 0xb4, 0xb8, 0x58, 0xc0, 0xda, 0x38, 0xb8, 0x58, 0x82, 0x5c, 0x1d, 0x5d, 0x04, 0x18, 0x84, 0x38,
0x1c, 0x03, 0xa2, 0x83, 0xb4, 0x2e, 0xa2, 0x4b, 0x70, 0xf5, 0x31, 0x0f, 0x5c, 0x96, 0xde, 0xdc, 0xb9, 0x58, 0xc3, 0x83, 0x3c, 0x43, 0x5c, 0x05, 0x18, 0x85, 0x78, 0xb9, 0x38, 0x41, 0x82, 0x10,
0x05, 0x16, 0xf6, 0x61, 0xf0, 0xcc, 0xee, 0xb3, 0x34, 0x40, 0x78, 0x04, 0x7e, 0x1f, 0x1a, 0x6b, 0x2e, 0x93, 0x52, 0x08, 0x50, 0x0d, 0xd0, 0x9d, 0x58, 0x3d, 0x6b, 0xc1, 0xc5, 0x0b, 0xb4, 0x0b,
0x47, 0x19, 0xb8, 0x4c, 0xac, 0xf8, 0xd1, 0xcf, 0x5e, 0xc3, 0x68, 0xc9, 0xdb, 0x03, 0x16, 0xb1, 0xe1, 0x2c, 0xa0, 0x03, 0x98, 0x35, 0xb8, 0x8d, 0x84, 0x30, 0x1d, 0x1c, 0x84, 0xaa, 0xd0, 0x49,
0x43, 0x27, 0x3e, 0x99, 0xe2, 0xff, 0xc0, 0xec, 0x6f, 0xf1, 0x96, 0x6c, 0x76, 0xd4, 0xda, 0xee, 0xe2, 0xc4, 0x43, 0x39, 0x86, 0x0b, 0x40, 0x7c, 0xe2, 0x91, 0x1c, 0xe3, 0x05, 0x20, 0x7e, 0x00,
0xa8, 0xb5, 0xe9, 0x28, 0xda, 0x76, 0x14, 0x7d, 0x75, 0x14, 0x7d, 0x7c, 0x53, 0x6b, 0x3e, 0xd4, 0xc4, 0x33, 0x1e, 0xcb, 0x31, 0x24, 0xb1, 0x81, 0xc3, 0xd8, 0x18, 0x10, 0x00, 0x00, 0xff, 0xff,
0x3b, 0x9e, 0xfd, 0x04, 0x00, 0x00, 0xff, 0xff, 0xcc, 0x76, 0x8d, 0x4f, 0x8f, 0x01, 0x00, 0x00, 0xcc, 0x76, 0x8d, 0x4f, 0x8f, 0x01, 0x00, 0x00,
} }

View File

@ -8,10 +8,11 @@ package client
import ( import (
"errors" "errors"
"fmt" "fmt"
codec1978 "github.com/ugorji/go/codec"
"reflect" "reflect"
"runtime" "runtime"
time "time" time "time"
codec1978 "github.com/ugorji/go/codec"
) )
const ( const (

View File

@ -191,6 +191,10 @@ type SetOptions struct {
// Dir specifies whether or not this Node should be created as a directory. // Dir specifies whether or not this Node should be created as a directory.
Dir bool Dir bool
// NoValueOnSuccess specifies whether the response contains the current value of the Node.
// If set, the response will only contain the current value when the request fails.
NoValueOnSuccess bool
} }
type GetOptions struct { type GetOptions struct {
@ -335,6 +339,7 @@ func (k *httpKeysAPI) Set(ctx context.Context, key, val string, opts *SetOptions
act.TTL = opts.TTL act.TTL = opts.TTL
act.Refresh = opts.Refresh act.Refresh = opts.Refresh
act.Dir = opts.Dir act.Dir = opts.Dir
act.NoValueOnSuccess = opts.NoValueOnSuccess
} }
doCtx := ctx doCtx := ctx
@ -532,6 +537,7 @@ type setAction struct {
TTL time.Duration TTL time.Duration
Refresh bool Refresh bool
Dir bool Dir bool
NoValueOnSuccess bool
} }
func (a *setAction) HTTPRequest(ep url.URL) *http.Request { func (a *setAction) HTTPRequest(ep url.URL) *http.Request {
@ -565,6 +571,9 @@ func (a *setAction) HTTPRequest(ep url.URL) *http.Request {
if a.Refresh { if a.Refresh {
form.Add("refresh", "true") form.Add("refresh", "true")
} }
if a.NoValueOnSuccess {
params.Set("noValueOnSuccess", strconv.FormatBool(a.NoValueOnSuccess))
}
u.RawQuery = params.Encode() u.RawQuery = params.Encode()
body := strings.NewReader(form.Encode()) body := strings.NewReader(form.Encode())

View File

@ -43,6 +43,7 @@ type (
AuthRoleListResponse pb.AuthRoleListResponse AuthRoleListResponse pb.AuthRoleListResponse
PermissionType authpb.Permission_Type PermissionType authpb.Permission_Type
Permission authpb.Permission
) )
const ( const (

View File

@ -42,9 +42,16 @@ type simpleBalancer struct {
// upc closes when upEps transitions from empty to non-zero or the balancer closes. // upc closes when upEps transitions from empty to non-zero or the balancer closes.
upc chan struct{} upc chan struct{}
// grpc issues TLS cert checks using the string passed into dial so
// that string must be the host. To recover the full scheme://host URL,
// have a map from hosts to the original endpoint.
host2ep map[string]string
// pinAddr is the currently pinned address; set to the empty string on // pinAddr is the currently pinned address; set to the empty string on
// intialization and shutdown. // intialization and shutdown.
pinAddr string pinAddr string
closed bool
} }
func newSimpleBalancer(eps []string) *simpleBalancer { func newSimpleBalancer(eps []string) *simpleBalancer {
@ -60,6 +67,7 @@ func newSimpleBalancer(eps []string) *simpleBalancer {
readyc: make(chan struct{}), readyc: make(chan struct{}),
upEps: make(map[string]struct{}), upEps: make(map[string]struct{}),
upc: make(chan struct{}), upc: make(chan struct{}),
host2ep: getHost2ep(eps),
} }
return sb return sb
} }
@ -72,17 +80,70 @@ func (b *simpleBalancer) ConnectNotify() <-chan struct{} {
return b.upc return b.upc
} }
func (b *simpleBalancer) getEndpoint(host string) string {
b.mu.Lock()
defer b.mu.Unlock()
return b.host2ep[host]
}
func getHost2ep(eps []string) map[string]string {
hm := make(map[string]string, len(eps))
for i := range eps {
_, host, _ := parseEndpoint(eps[i])
hm[host] = eps[i]
}
return hm
}
func (b *simpleBalancer) updateAddrs(eps []string) {
np := getHost2ep(eps)
b.mu.Lock()
defer b.mu.Unlock()
match := len(np) == len(b.host2ep)
for k, v := range np {
if b.host2ep[k] != v {
match = false
break
}
}
if match {
// same endpoints, so no need to update address
return
}
b.host2ep = np
addrs := make([]grpc.Address, 0, len(eps))
for i := range eps {
addrs = append(addrs, grpc.Address{Addr: getHost(eps[i])})
}
b.addrs = addrs
b.notifyCh <- addrs
}
func (b *simpleBalancer) Up(addr grpc.Address) func(error) { func (b *simpleBalancer) Up(addr grpc.Address) func(error) {
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock()
// gRPC might call Up after it called Close. We add this check
// to "fix" it up at application layer. Or our simplerBalancer
// might panic since b.upc is closed.
if b.closed {
return func(err error) {}
}
if len(b.upEps) == 0 { if len(b.upEps) == 0 {
// notify waiting Get()s and pin first connected address // notify waiting Get()s and pin first connected address
close(b.upc) close(b.upc)
b.pinAddr = addr.Addr b.pinAddr = addr.Addr
} }
b.upEps[addr.Addr] = struct{}{} b.upEps[addr.Addr] = struct{}{}
b.mu.Unlock()
// notify client that a connection is up // notify client that a connection is up
b.readyOnce.Do(func() { close(b.readyc) }) b.readyOnce.Do(func() { close(b.readyc) })
return func(err error) { return func(err error) {
b.mu.Lock() b.mu.Lock()
delete(b.upEps, addr.Addr) delete(b.upEps, addr.Addr)
@ -128,13 +189,19 @@ func (b *simpleBalancer) Notify() <-chan []grpc.Address { return b.notifyCh }
func (b *simpleBalancer) Close() error { func (b *simpleBalancer) Close() error {
b.mu.Lock() b.mu.Lock()
defer b.mu.Unlock()
// In case gRPC calls close twice. TODO: remove the checking
// when we are sure that gRPC wont call close twice.
if b.closed {
return nil
}
b.closed = true
close(b.notifyCh) close(b.notifyCh)
// terminate all waiting Get()s // terminate all waiting Get()s
b.pinAddr = "" b.pinAddr = ""
if len(b.upEps) == 0 { if len(b.upEps) == 0 {
close(b.upc) close(b.upc)
} }
b.mu.Unlock()
return nil return nil
} }

View File

@ -99,6 +99,44 @@ func (c *Client) Ctx() context.Context { return c.ctx }
// Endpoints lists the registered endpoints for the client. // Endpoints lists the registered endpoints for the client.
func (c *Client) Endpoints() []string { return c.cfg.Endpoints } func (c *Client) Endpoints() []string { return c.cfg.Endpoints }
// SetEndpoints updates client's endpoints.
func (c *Client) SetEndpoints(eps ...string) {
c.cfg.Endpoints = eps
c.balancer.updateAddrs(eps)
}
// Sync synchronizes client's endpoints with the known endpoints from the etcd membership.
func (c *Client) Sync(ctx context.Context) error {
mresp, err := c.MemberList(ctx)
if err != nil {
return err
}
var eps []string
for _, m := range mresp.Members {
eps = append(eps, m.ClientURLs...)
}
c.SetEndpoints(eps...)
return nil
}
func (c *Client) autoSync() {
if c.cfg.AutoSyncInterval == time.Duration(0) {
return
}
for {
select {
case <-c.ctx.Done():
return
case <-time.After(c.cfg.AutoSyncInterval):
ctx, _ := context.WithTimeout(c.ctx, 5*time.Second)
if err := c.Sync(ctx); err != nil && err != c.ctx.Err() {
logger.Println("Auto sync endpoints failed:", err)
}
}
}
}
type authTokenCredential struct { type authTokenCredential struct {
token string token string
} }
@ -113,19 +151,31 @@ func (cred authTokenCredential) GetRequestMetadata(ctx context.Context, s ...str
}, nil }, nil
} }
func (c *Client) dialTarget(endpoint string) (proto string, host string, creds *credentials.TransportCredentials) { func parseEndpoint(endpoint string) (proto string, host string, scheme bool) {
proto = "tcp" proto = "tcp"
host = endpoint host = endpoint
creds = c.creds
url, uerr := url.Parse(endpoint) url, uerr := url.Parse(endpoint)
if uerr != nil || !strings.Contains(endpoint, "://") { if uerr != nil || !strings.Contains(endpoint, "://") {
return return
} }
scheme = true
// strip scheme:// prefix since grpc dials by host // strip scheme:// prefix since grpc dials by host
host = url.Host host = url.Host
switch url.Scheme { switch url.Scheme {
case "http", "https":
case "unix": case "unix":
proto = "unix" proto = "unix"
default:
proto, host = "", ""
}
return
}
func (c *Client) processCreds(protocol string) (creds *credentials.TransportCredentials) {
creds = c.creds
switch protocol {
case "unix":
case "http": case "http":
creds = nil creds = nil
case "https": case "https":
@ -136,7 +186,7 @@ func (c *Client) dialTarget(endpoint string) (proto string, host string, creds *
emptyCreds := credentials.NewTLS(tlsconfig) emptyCreds := credentials.NewTLS(tlsconfig)
creds = &emptyCreds creds = &emptyCreds
default: default:
return "", "", nil creds = nil
} }
return return
} }
@ -148,17 +198,8 @@ func (c *Client) dialSetupOpts(endpoint string, dopts ...grpc.DialOption) (opts
} }
opts = append(opts, dopts...) opts = append(opts, dopts...)
// grpc issues TLS cert checks using the string passed into dial so
// that string must be the host. To recover the full scheme://host URL,
// have a map from hosts to the original endpoint.
host2ep := make(map[string]string)
for i := range c.cfg.Endpoints {
_, host, _ := c.dialTarget(c.cfg.Endpoints[i])
host2ep[host] = c.cfg.Endpoints[i]
}
f := func(host string, t time.Duration) (net.Conn, error) { f := func(host string, t time.Duration) (net.Conn, error) {
proto, host, _ := c.dialTarget(host2ep[host]) proto, host, _ := parseEndpoint(c.balancer.getEndpoint(host))
if proto == "" { if proto == "" {
return nil, fmt.Errorf("unknown scheme for %q", host) return nil, fmt.Errorf("unknown scheme for %q", host)
} }
@ -171,7 +212,10 @@ func (c *Client) dialSetupOpts(endpoint string, dopts ...grpc.DialOption) (opts
} }
opts = append(opts, grpc.WithDialer(f)) opts = append(opts, grpc.WithDialer(f))
_, _, creds := c.dialTarget(endpoint) creds := c.creds
if proto, _, scheme := parseEndpoint(endpoint); scheme {
creds = c.processCreds(proto)
}
if creds != nil { if creds != nil {
opts = append(opts, grpc.WithTransportCredentials(*creds)) opts = append(opts, grpc.WithTransportCredentials(*creds))
} else { } else {
@ -280,6 +324,7 @@ func newClient(cfg *Config) (*Client, error) {
logger.Set(log.New(ioutil.Discard, "", 0)) logger.Set(log.New(ioutil.Discard, "", 0))
} }
go client.autoSync()
return client, nil return client, nil
} }

View File

@ -28,6 +28,10 @@ type Config struct {
// Endpoints is a list of URLs // Endpoints is a list of URLs
Endpoints []string Endpoints []string
// AutoSyncInterval is the interval to update endpoints with its latest members.
// 0 disables auto-sync. By default auto-sync is disabled.
AutoSyncInterval time.Duration
// DialTimeout is the timeout for failing to establish a connection. // DialTimeout is the timeout for failing to establish a connection.
DialTimeout time.Duration DialTimeout time.Duration
@ -46,6 +50,7 @@ type Config struct {
type yamlConfig struct { type yamlConfig struct {
Endpoints []string `json:"endpoints"` Endpoints []string `json:"endpoints"`
AutoSyncInterval time.Duration `json:"auto-sync-interval"`
DialTimeout time.Duration `json:"dial-timeout"` DialTimeout time.Duration `json:"dial-timeout"`
InsecureTransport bool `json:"insecure-transport"` InsecureTransport bool `json:"insecure-transport"`
InsecureSkipTLSVerify bool `json:"insecure-skip-tls-verify"` InsecureSkipTLSVerify bool `json:"insecure-skip-tls-verify"`
@ -69,6 +74,7 @@ func configFromFile(fpath string) (*Config, error) {
cfg := &Config{ cfg := &Config{
Endpoints: yc.Endpoints, Endpoints: yc.Endpoints,
AutoSyncInterval: yc.AutoSyncInterval,
DialTimeout: yc.DialTimeout, DialTimeout: yc.DialTimeout,
} }

View File

@ -141,21 +141,7 @@ func (kv *kv) do(ctx context.Context, op Op) (OpResponse, error) {
// TODO: handle other ops // TODO: handle other ops
case tRange: case tRange:
var resp *pb.RangeResponse var resp *pb.RangeResponse
r := &pb.RangeRequest{ resp, err = kv.remote.Range(ctx, op.toRangeRequest(), grpc.FailFast(false))
Key: op.key,
RangeEnd: op.end,
Limit: op.limit,
Revision: op.rev,
Serializable: op.serializable,
KeysOnly: op.keysOnly,
CountOnly: op.countOnly,
}
if op.sort != nil {
r.SortOrder = pb.RangeRequest_SortOrder(op.sort.Order)
r.SortTarget = pb.RangeRequest_SortTarget(op.sort.Target)
}
resp, err = kv.remote.Range(ctx, r, grpc.FailFast(false))
if err == nil { if err == nil {
return OpResponse{get: (*GetResponse)(resp)}, nil return OpResponse{get: (*GetResponse)(resp)}, nil
} }

View File

@ -44,6 +44,21 @@ type LeaseKeepAliveResponse struct {
TTL int64 TTL int64
} }
// LeaseTimeToLiveResponse is used to convert the protobuf lease timetolive response.
type LeaseTimeToLiveResponse struct {
*pb.ResponseHeader
ID LeaseID `json:"id"`
// TTL is the remaining TTL in seconds for the lease; the lease will expire in under TTL+1 seconds.
TTL int64 `json:"ttl"`
// GrantedTTL is the initial granted time in seconds upon lease creation/renewal.
GrantedTTL int64 `json:"granted-ttl"`
// Keys is the list of keys attached to this lease.
Keys [][]byte `json:"keys"`
}
const ( const (
// defaultTTL is the assumed lease TTL used for the first keepalive // defaultTTL is the assumed lease TTL used for the first keepalive
// deadline before the actual TTL is known to the client. // deadline before the actual TTL is known to the client.
@ -61,6 +76,9 @@ type Lease interface {
// Revoke revokes the given lease. // Revoke revokes the given lease.
Revoke(ctx context.Context, id LeaseID) (*LeaseRevokeResponse, error) Revoke(ctx context.Context, id LeaseID) (*LeaseRevokeResponse, error)
// TimeToLive retrieves the lease information of the given lease ID.
TimeToLive(ctx context.Context, id LeaseID, opts ...LeaseOption) (*LeaseTimeToLiveResponse, error)
// KeepAlive keeps the given lease alive forever. // KeepAlive keeps the given lease alive forever.
KeepAlive(ctx context.Context, id LeaseID) (<-chan *LeaseKeepAliveResponse, error) KeepAlive(ctx context.Context, id LeaseID) (<-chan *LeaseKeepAliveResponse, error)
@ -141,7 +159,7 @@ func (l *lessor) Grant(ctx context.Context, ttl int64) (*LeaseGrantResponse, err
return gresp, nil return gresp, nil
} }
if isHaltErr(cctx, err) { if isHaltErr(cctx, err) {
return nil, toErr(ctx, err) return nil, toErr(cctx, err)
} }
if nerr := l.newStream(); nerr != nil { if nerr := l.newStream(); nerr != nil {
return nil, nerr return nil, nerr
@ -170,6 +188,30 @@ func (l *lessor) Revoke(ctx context.Context, id LeaseID) (*LeaseRevokeResponse,
} }
} }
func (l *lessor) TimeToLive(ctx context.Context, id LeaseID, opts ...LeaseOption) (*LeaseTimeToLiveResponse, error) {
cctx, cancel := context.WithCancel(ctx)
done := cancelWhenStop(cancel, l.stopCtx.Done())
defer close(done)
for {
r := toLeaseTimeToLiveRequest(id, opts...)
resp, err := l.remote.LeaseTimeToLive(cctx, r)
if err == nil {
gresp := &LeaseTimeToLiveResponse{
ResponseHeader: resp.GetHeader(),
ID: LeaseID(resp.ID),
TTL: resp.TTL,
GrantedTTL: resp.GrantedTTL,
Keys: resp.Keys,
}
return gresp, nil
}
if isHaltErr(cctx, err) {
return nil, toErr(cctx, err)
}
}
}
func (l *lessor) KeepAlive(ctx context.Context, id LeaseID) (<-chan *LeaseKeepAliveResponse, error) { func (l *lessor) KeepAlive(ctx context.Context, id LeaseID) (<-chan *LeaseKeepAliveResponse, error) {
ch := make(chan *LeaseKeepAliveResponse, leaseResponseChSize) ch := make(chan *LeaseKeepAliveResponse, leaseResponseChSize)

View File

@ -41,6 +41,10 @@ type Op struct {
serializable bool serializable bool
keysOnly bool keysOnly bool
countOnly bool countOnly bool
minModRev int64
maxModRev int64
minCreateRev int64
maxCreateRev int64
// for range, watch // for range, watch
rev int64 rev int64
@ -61,9 +65,10 @@ type Op struct {
leaseID LeaseID leaseID LeaseID
} }
func (op Op) toRequestOp() *pb.RequestOp { func (op Op) toRangeRequest() *pb.RangeRequest {
switch op.t { if op.t != tRange {
case tRange: panic("op.t != tRange")
}
r := &pb.RangeRequest{ r := &pb.RangeRequest{
Key: op.key, Key: op.key,
RangeEnd: op.end, RangeEnd: op.end,
@ -72,18 +77,27 @@ func (op Op) toRequestOp() *pb.RequestOp {
Serializable: op.serializable, Serializable: op.serializable,
KeysOnly: op.keysOnly, KeysOnly: op.keysOnly,
CountOnly: op.countOnly, CountOnly: op.countOnly,
MinModRevision: op.minModRev,
MaxModRevision: op.maxModRev,
MinCreateRevision: op.minCreateRev,
MaxCreateRevision: op.maxCreateRev,
} }
if op.sort != nil { if op.sort != nil {
r.SortOrder = pb.RangeRequest_SortOrder(op.sort.Order) r.SortOrder = pb.RangeRequest_SortOrder(op.sort.Order)
r.SortTarget = pb.RangeRequest_SortTarget(op.sort.Target) r.SortTarget = pb.RangeRequest_SortTarget(op.sort.Target)
} }
return &pb.RequestOp{Request: &pb.RequestOp_RequestRange{RequestRange: r}} return r
}
func (op Op) toRequestOp() *pb.RequestOp {
switch op.t {
case tRange:
return &pb.RequestOp{Request: &pb.RequestOp_RequestRange{RequestRange: op.toRangeRequest()}}
case tPut: case tPut:
r := &pb.PutRequest{Key: op.key, Value: op.val, Lease: int64(op.leaseID), PrevKv: op.prevKV} r := &pb.PutRequest{Key: op.key, Value: op.val, Lease: int64(op.leaseID), PrevKv: op.prevKV}
return &pb.RequestOp{Request: &pb.RequestOp_RequestPut{RequestPut: r}} return &pb.RequestOp{Request: &pb.RequestOp_RequestPut{RequestPut: r}}
case tDeleteRange: case tDeleteRange:
r := &pb.DeleteRangeRequest{Key: op.key, RangeEnd: op.end, PrevKv: op.prevKV} r := &pb.DeleteRangeRequest{Key: op.key, RangeEnd: op.end, PrevKv: op.prevKV}
return &pb.RequestOp{Request: &pb.RequestOp_RequestDeleteRange{RequestDeleteRange: r}} return &pb.RequestOp{Request: &pb.RequestOp_RequestDeleteRange{RequestDeleteRange: r}}
default: default:
panic("Unknown Op") panic("Unknown Op")
@ -116,6 +130,10 @@ func OpDelete(key string, opts ...OpOption) Op {
panic("unexpected serializable in delete") panic("unexpected serializable in delete")
case ret.countOnly: case ret.countOnly:
panic("unexpected countOnly in delete") panic("unexpected countOnly in delete")
case ret.minModRev != 0, ret.maxModRev != 0:
panic("unexpected mod revision filter in delete")
case ret.minCreateRev != 0, ret.maxCreateRev != 0:
panic("unexpected create revision filter in delete")
case ret.filterDelete, ret.filterPut: case ret.filterDelete, ret.filterPut:
panic("unexpected filter in delete") panic("unexpected filter in delete")
case ret.createdNotify: case ret.createdNotify:
@ -140,6 +158,10 @@ func OpPut(key, val string, opts ...OpOption) Op {
panic("unexpected serializable in put") panic("unexpected serializable in put")
case ret.countOnly: case ret.countOnly:
panic("unexpected countOnly in put") panic("unexpected countOnly in put")
case ret.minModRev != 0, ret.maxModRev != 0:
panic("unexpected mod revision filter in put")
case ret.minCreateRev != 0, ret.maxCreateRev != 0:
panic("unexpected create revision filter in put")
case ret.filterDelete, ret.filterPut: case ret.filterDelete, ret.filterPut:
panic("unexpected filter in put") panic("unexpected filter in put")
case ret.createdNotify: case ret.createdNotify:
@ -162,6 +184,10 @@ func opWatch(key string, opts ...OpOption) Op {
panic("unexpected serializable in watch") panic("unexpected serializable in watch")
case ret.countOnly: case ret.countOnly:
panic("unexpected countOnly in watch") panic("unexpected countOnly in watch")
case ret.minModRev != 0, ret.maxModRev != 0:
panic("unexpected mod revision filter in watch")
case ret.minCreateRev != 0, ret.maxCreateRev != 0:
panic("unexpected create revision filter in watch")
} }
return ret return ret
} }
@ -264,6 +290,18 @@ func WithCountOnly() OpOption {
return func(op *Op) { op.countOnly = true } return func(op *Op) { op.countOnly = true }
} }
// WithMinModRev filters out keys for Get with modification revisions less than the given revision.
func WithMinModRev(rev int64) OpOption { return func(op *Op) { op.minModRev = rev } }
// WithMaxModRev filters out keys for Get with modification revisions greater than the given revision.
func WithMaxModRev(rev int64) OpOption { return func(op *Op) { op.maxModRev = rev } }
// WithMinCreateRev filters out keys for Get with creation revisions less than the given revision.
func WithMinCreateRev(rev int64) OpOption { return func(op *Op) { op.minCreateRev = rev } }
// WithMaxCreateRev filters out keys for Get with creation revisions greater than the given revision.
func WithMaxCreateRev(rev int64) OpOption { return func(op *Op) { op.maxCreateRev = rev } }
// WithFirstCreate gets the key with the oldest creation revision in the request range. // WithFirstCreate gets the key with the oldest creation revision in the request range.
func WithFirstCreate() []OpOption { return withTop(SortByCreateRevision, SortAscend) } func WithFirstCreate() []OpOption { return withTop(SortByCreateRevision, SortAscend) }
@ -320,3 +358,32 @@ func WithPrevKV() OpOption {
op.prevKV = true op.prevKV = true
} }
} }
// LeaseOp represents an Operation that lease can execute.
type LeaseOp struct {
id LeaseID
// for TimeToLive
attachedKeys bool
}
// LeaseOption configures lease operations.
type LeaseOption func(*LeaseOp)
func (op *LeaseOp) applyOpts(opts []LeaseOption) {
for _, opt := range opts {
opt(op)
}
}
// WithAttachedKeys requests lease timetolive API to return
// attached keys of given lease ID.
func WithAttachedKeys() LeaseOption {
return func(op *LeaseOp) { op.attachedKeys = true }
}
func toLeaseTimeToLiveRequest(id LeaseID, opts ...LeaseOption) *pb.LeaseTimeToLiveRequest {
ret := &LeaseOp{id: id}
ret.applyOpts(opts)
return &pb.LeaseTimeToLiveRequest{ID: int64(id), Keys: ret.attachedKeys}
}

View File

@ -131,6 +131,8 @@ type watchGrpcStream struct {
donec chan struct{} donec chan struct{}
// errc transmits errors from grpc Recv to the watch stream reconn logic // errc transmits errors from grpc Recv to the watch stream reconn logic
errc chan error errc chan error
// closingc gets the watcherStream of closing watchers
closingc chan *watcherStream
// the error that closed the watch stream // the error that closed the watch stream
closeErr error closeErr error
@ -208,6 +210,7 @@ func (w *watcher) newWatcherGrpcStream(inctx context.Context) *watchGrpcStream {
stopc: make(chan struct{}), stopc: make(chan struct{}),
donec: make(chan struct{}), donec: make(chan struct{}),
errc: make(chan error, 1), errc: make(chan error, 1),
closingc: make(chan *watcherStream),
} }
go wgs.run() go wgs.run()
return wgs return wgs
@ -268,7 +271,6 @@ func (w *watcher) Watch(ctx context.Context, key string, opts ...OpOption) Watch
case reqc <- wr: case reqc <- wr:
ok = true ok = true
case <-wr.ctx.Done(): case <-wr.ctx.Done():
wgs.stopIfEmpty()
case <-donec: case <-donec:
if wgs.closeErr != nil { if wgs.closeErr != nil {
closeCh <- WatchResponse{closeErr: wgs.closeErr} closeCh <- WatchResponse{closeErr: wgs.closeErr}
@ -378,15 +380,19 @@ func (w *watchGrpcStream) addStream(resp *pb.WatchResponse, pendingReq *watchReq
go w.serveStream(ws) go w.serveStream(ws)
} }
// closeStream closes the watcher resources and removes it func (w *watchGrpcStream) closeStream(ws *watcherStream) bool {
func (w *watchGrpcStream) closeStream(ws *watcherStream) {
w.mu.Lock() w.mu.Lock()
// cancels request stream; subscriber receives nil channel // cancels request stream; subscriber receives nil channel
close(ws.initReq.retc) close(ws.initReq.retc)
// close subscriber's channel // close subscriber's channel
close(ws.outc) close(ws.outc)
delete(w.streams, ws.id) delete(w.streams, ws.id)
empty := len(w.streams) == 0
if empty && w.stopc != nil {
w.stopc = nil
}
w.mu.Unlock() w.mu.Unlock()
return empty
} }
// run is the root of the goroutines for managing a watcher client // run is the root of the goroutines for managing a watcher client
@ -477,7 +483,7 @@ func (w *watchGrpcStream) run() {
// watch client failed to recv; spawn another if possible // watch client failed to recv; spawn another if possible
// TODO report watch client errors from errc? // TODO report watch client errors from errc?
case err := <-w.errc: case err := <-w.errc:
if toErr(w.ctx, err) == v3rpc.ErrNoLeader { if isHaltErr(w.ctx, err) || toErr(w.ctx, err) == v3rpc.ErrNoLeader {
closeErr = err closeErr = err
return return
} }
@ -491,6 +497,10 @@ func (w *watchGrpcStream) run() {
cancelSet = make(map[int64]struct{}) cancelSet = make(map[int64]struct{})
case <-stopc: case <-stopc:
return return
case ws := <-w.closingc:
if w.closeStream(ws) {
return
}
} }
// send failed; queue for retry // send failed; queue for retry
@ -553,6 +563,15 @@ func (w *watchGrpcStream) serveWatchClient(wc pb.Watch_WatchClient) {
// serveStream forwards watch responses from run() to the subscriber // serveStream forwards watch responses from run() to the subscriber
func (w *watchGrpcStream) serveStream(ws *watcherStream) { func (w *watchGrpcStream) serveStream(ws *watcherStream) {
defer func() {
// signal that this watcherStream is finished
select {
case w.closingc <- ws:
case <-w.donec:
w.closeStream(ws)
}
}()
var closeErr error var closeErr error
emptyWr := &WatchResponse{} emptyWr := &WatchResponse{}
wrs := []*WatchResponse{} wrs := []*WatchResponse{}
@ -641,20 +660,9 @@ func (w *watchGrpcStream) serveStream(ws *watcherStream) {
} }
} }
w.closeStream(ws)
w.stopIfEmpty()
// lazily send cancel message if events on missing id // lazily send cancel message if events on missing id
} }
func (wgs *watchGrpcStream) stopIfEmpty() {
wgs.mu.Lock()
if len(wgs.streams) == 0 && wgs.stopc != nil {
close(wgs.stopc)
wgs.stopc = nil
}
wgs.mu.Unlock()
}
func (w *watchGrpcStream) newWatchClient() (pb.Watch_WatchClient, error) { func (w *watchGrpcStream) newWatchClient() (pb.Watch_WatchClient, error) {
ws, rerr := w.resume() ws, rerr := w.resume()
if rerr != nil { if rerr != nil {
@ -708,6 +716,10 @@ func (w *watchGrpcStream) resumeWatchers(wc pb.Watch_WatchClient) error {
w.mu.RUnlock() w.mu.RUnlock()
for _, ws := range streams { for _, ws := range streams {
// drain recvc so no old WatchResponses (e.g., Created messages)
// are processed while resuming
ws.drain()
// pause serveStream // pause serveStream
ws.resumec <- -1 ws.resumec <- -1
@ -740,6 +752,17 @@ func (w *watchGrpcStream) resumeWatchers(wc pb.Watch_WatchClient) error {
return nil return nil
} }
// drain removes all buffered WatchResponses from the stream's receive channel.
func (ws *watcherStream) drain() {
for {
select {
case <-ws.recvc:
default:
return
}
}
}
// toPB converts an internal watch request structure to its protobuf messagefunc (wr *watchRequest) // toPB converts an internal watch request structure to its protobuf messagefunc (wr *watchRequest)
func (wr *watchRequest) toPB() *pb.WatchRequest { func (wr *watchRequest) toPB() *pb.WatchRequest {
req := &pb.WatchCreateRequest{ req := &pb.WatchCreateRequest{

View File

@ -56,6 +56,7 @@ var (
ErrGRPCStopped = grpc.Errorf(codes.Unavailable, "etcdserver: server stopped") ErrGRPCStopped = grpc.Errorf(codes.Unavailable, "etcdserver: server stopped")
ErrGRPCTimeout = grpc.Errorf(codes.Unavailable, "etcdserver: request timed out") ErrGRPCTimeout = grpc.Errorf(codes.Unavailable, "etcdserver: request timed out")
ErrGRPCTimeoutDueToLeaderFail = grpc.Errorf(codes.Unavailable, "etcdserver: request timed out, possibly due to previous leader failure") ErrGRPCTimeoutDueToLeaderFail = grpc.Errorf(codes.Unavailable, "etcdserver: request timed out, possibly due to previous leader failure")
ErrGRPCUnhealthy = grpc.Errorf(codes.Unavailable, "etcdserver: unhealthy cluster")
errStringToError = map[string]error{ errStringToError = map[string]error{
grpc.ErrorDesc(ErrGRPCEmptyKey): ErrGRPCEmptyKey, grpc.ErrorDesc(ErrGRPCEmptyKey): ErrGRPCEmptyKey,
@ -93,6 +94,7 @@ var (
grpc.ErrorDesc(ErrGRPCStopped): ErrGRPCStopped, grpc.ErrorDesc(ErrGRPCStopped): ErrGRPCStopped,
grpc.ErrorDesc(ErrGRPCTimeout): ErrGRPCTimeout, grpc.ErrorDesc(ErrGRPCTimeout): ErrGRPCTimeout,
grpc.ErrorDesc(ErrGRPCTimeoutDueToLeaderFail): ErrGRPCTimeoutDueToLeaderFail, grpc.ErrorDesc(ErrGRPCTimeoutDueToLeaderFail): ErrGRPCTimeoutDueToLeaderFail,
grpc.ErrorDesc(ErrGRPCUnhealthy): ErrGRPCUnhealthy,
} }
// client-side error // client-side error
@ -131,6 +133,7 @@ var (
ErrStopped = Error(ErrGRPCStopped) ErrStopped = Error(ErrGRPCStopped)
ErrTimeout = Error(ErrGRPCTimeout) ErrTimeout = Error(ErrGRPCTimeout)
ErrTimeoutDueToLeaderFail = Error(ErrGRPCTimeoutDueToLeaderFail) ErrTimeoutDueToLeaderFail = Error(ErrGRPCTimeoutDueToLeaderFail)
ErrUnhealthy = Error(ErrGRPCUnhealthy)
) )
// EtcdError defines gRPC server errors. // EtcdError defines gRPC server errors.

View File

@ -45,6 +45,8 @@
LeaseRevokeResponse LeaseRevokeResponse
LeaseKeepAliveRequest LeaseKeepAliveRequest
LeaseKeepAliveResponse LeaseKeepAliveResponse
LeaseTimeToLiveRequest
LeaseTimeToLiveResponse
Member Member
MemberAddRequest MemberAddRequest
MemberAddResponse MemberAddResponse
@ -1011,31 +1013,30 @@ var (
) )
var fileDescriptorEtcdserver = []byte{ var fileDescriptorEtcdserver = []byte{
// 404 bytes of a gzipped FileDescriptorProto // 396 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x5c, 0x92, 0x41, 0x6e, 0x13, 0x31, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x5c, 0x92, 0x4f, 0xae, 0xd3, 0x30,
0x14, 0x86, 0xe3, 0xc4, 0x99, 0x64, 0x4c, 0x81, 0x62, 0x45, 0xe8, 0xa9, 0x42, 0x43, 0x14, 0xb1, 0x10, 0xc6, 0x9b, 0xc4, 0x4d, 0x1b, 0xf3, 0x80, 0x87, 0x55, 0xa1, 0xd1, 0x13, 0x0a, 0xa8, 0x62,
0xc8, 0x0a, 0xee, 0x50, 0xd2, 0x45, 0x24, 0x8a, 0x4a, 0x8a, 0xca, 0xda, 0x64, 0x1e, 0x8d, 0xa5, 0xc1, 0x0a, 0xee, 0xf0, 0x68, 0x17, 0x95, 0x00, 0x95, 0x16, 0xc1, 0xda, 0x24, 0x43, 0x6b, 0xa9,
0xcc, 0x78, 0x6a, 0xbf, 0x19, 0x72, 0x03, 0xae, 0xc0, 0x91, 0xb2, 0xe4, 0x04, 0x08, 0xc2, 0x45, 0x89, 0x53, 0xdb, 0x09, 0xbd, 0x01, 0x57, 0xe0, 0x48, 0x5d, 0x72, 0x02, 0xc4, 0x9f, 0x8b, 0x60,
0x90, 0x3d, 0x9d, 0x60, 0xba, 0xb3, 0xbe, 0xff, 0xf7, 0xef, 0xdf, 0xf6, 0x13, 0xa7, 0x48, 0xeb, 0xbb, 0x4d, 0x31, 0x2c, 0x2c, 0x45, 0xbf, 0xef, 0x9b, 0xf1, 0xe7, 0x99, 0xd0, 0x6b, 0x34, 0x45,
0xdc, 0xa1, 0x6d, 0xd0, 0xbe, 0xae, 0xac, 0x21, 0x23, 0x4f, 0xfe, 0x91, 0xea, 0xf3, 0xd9, 0xe4, 0xa9, 0x51, 0x75, 0xa8, 0x9e, 0x37, 0x4a, 0x1a, 0xc9, 0xae, 0xfe, 0x92, 0xe6, 0xe3, 0xcd, 0x64,
0xd6, 0xdc, 0x9a, 0x20, 0xbc, 0xf1, 0xab, 0xd6, 0x33, 0xfb, 0xc6, 0xc5, 0x68, 0x85, 0x77, 0x35, 0x23, 0x37, 0xd2, 0x0b, 0x2f, 0xdc, 0xd7, 0xc9, 0x33, 0xfd, 0x42, 0xe8, 0x68, 0x85, 0xfb, 0x16,
0x3a, 0x92, 0x13, 0xd1, 0x5f, 0x2e, 0x80, 0x4d, 0xd9, 0x9c, 0x9f, 0xf3, 0xfd, 0xcf, 0x97, 0xbd, 0xb5, 0x61, 0x13, 0x1a, 0x2f, 0x66, 0x10, 0x3d, 0x89, 0x9e, 0x91, 0x5b, 0x72, 0xfc, 0xfe, 0x78,
0x55, 0x5f, 0x2f, 0xe4, 0x0b, 0x91, 0x5c, 0x22, 0x6d, 0x4c, 0x0e, 0xfd, 0x29, 0x9b, 0xa7, 0xf7, 0xb0, 0x8a, 0xc5, 0x8c, 0x3d, 0xa2, 0xe9, 0x6b, 0x34, 0x5b, 0x59, 0x42, 0x6c, 0x95, 0xec, 0xac,
0x4a, 0x52, 0x04, 0x26, 0x41, 0xf0, 0x2b, 0x45, 0x1b, 0x18, 0x44, 0x1a, 0xaf, 0x14, 0x6d, 0xe4, 0xa4, 0x95, 0x67, 0x0c, 0x28, 0x59, 0x72, 0xb3, 0x85, 0x24, 0xd0, 0x48, 0x63, 0x09, 0x7b, 0x48,
0x73, 0x31, 0xb8, 0x51, 0x5b, 0xe0, 0x91, 0x30, 0x68, 0xd4, 0xd6, 0xf3, 0x85, 0xb6, 0x30, 0x9c, 0x93, 0xf7, 0x7c, 0x07, 0x24, 0x10, 0x92, 0x8e, 0xef, 0x1c, 0x9f, 0x09, 0x05, 0x43, 0xcb, 0xc7,
0xb2, 0xf9, 0xb8, 0xe3, 0xb9, 0xb6, 0x72, 0x26, 0xd2, 0x2b, 0x8b, 0xcd, 0x8d, 0xda, 0xd6, 0x08, 0x3d, 0x2f, 0x85, 0x62, 0x53, 0x9a, 0x2d, 0x15, 0x76, 0xb6, 0xa6, 0x45, 0x48, 0x83, 0xaa, 0xac,
0x49, 0xb4, 0x2b, 0xad, 0x3a, 0xdc, 0x79, 0x96, 0x65, 0x8e, 0x3b, 0x18, 0x45, 0x45, 0x83, 0x27, 0xe9, 0x71, 0xef, 0x59, 0xd4, 0x25, 0x1e, 0x60, 0x14, 0x04, 0xf5, 0x1e, 0x8f, 0x7b, 0xcf, 0xfc,
0xe0, 0xce, 0x73, 0xb1, 0xd3, 0x8e, 0x60, 0x7c, 0x3c, 0x85, 0xb5, 0x9e, 0x80, 0xe5, 0x2b, 0x21, 0x20, 0xb4, 0x81, 0xf1, 0xe5, 0x96, 0xe8, 0xe4, 0xf1, 0x98, 0x3d, 0xa5, 0x74, 0x7e, 0x68, 0x84,
0x2e, 0x76, 0x95, 0xb6, 0x8a, 0xb4, 0x29, 0x21, 0x9d, 0xb2, 0xf9, 0xe0, 0x3e, 0x48, 0xe0, 0x91, 0xe2, 0x46, 0xc8, 0x1a, 0x32, 0x6b, 0x4a, 0xce, 0x8d, 0x28, 0x5e, 0xb8, 0x7b, 0xdb, 0x07, 0x2e,
0xfb, 0xbb, 0x7d, 0x52, 0x9a, 0x40, 0x44, 0x55, 0xf9, 0x57, 0xa5, 0x49, 0x9e, 0x89, 0xe1, 0xb5, 0x0c, 0xd0, 0x20, 0x2a, 0xf9, 0x6c, 0x09, 0xbb, 0xa1, 0xc3, 0xb5, 0xa8, 0x0b, 0x84, 0x3b, 0x41,
0x2e, 0xd7, 0x08, 0x8f, 0xa2, 0x0e, 0x43, 0xe7, 0x91, 0x3f, 0x7f, 0x85, 0xeb, 0xda, 0x3a, 0xdd, 0x86, 0xa1, 0x76, 0xc8, 0xdd, 0xbf, 0xc2, 0xa2, 0x55, 0x5a, 0x74, 0x08, 0x57, 0x41, 0x69, 0xa6,
0x20, 0x9c, 0x44, 0x5b, 0x53, 0xdb, 0x61, 0xff, 0xa6, 0xd7, 0xc6, 0x12, 0xe6, 0xf0, 0x38, 0x32, 0x7a, 0xec, 0x66, 0xba, 0x96, 0xca, 0x60, 0x09, 0x77, 0x03, 0x43, 0xaa, 0x3d, 0x73, 0xea, 0xdb,
0x24, 0x2e, 0x30, 0xaf, 0x7e, 0xa8, 0x8d, 0xad, 0x0b, 0x78, 0x12, 0xab, 0x77, 0x81, 0xf9, 0x56, 0x56, 0xaa, 0xb6, 0x82, 0x7b, 0xa1, 0xba, 0xf7, 0xcc, 0xa5, 0x7a, 0x27, 0x2a, 0x84, 0xfb, 0x41,
0x1f, 0x75, 0x81, 0xf0, 0x34, 0x6a, 0xcd, 0x49, 0x17, 0x6d, 0x2a, 0x59, 0x54, 0x05, 0x9c, 0xfe, 0x6a, 0x62, 0x2c, 0xf1, 0x5d, 0x8d, 0x42, 0x5e, 0xc1, 0xf5, 0x3f, 0x5d, 0x3d, 0x63, 0xb9, 0x5b,
0x97, 0x1a, 0x98, 0xcc, 0xfc, 0x47, 0x7f, 0xb1, 0xe8, 0x36, 0xf0, 0x2c, 0x7a, 0x95, 0x91, 0x6d, 0xf4, 0x27, 0x85, 0x7a, 0x0b, 0x0f, 0x82, 0xa9, 0x8c, 0xd4, 0x09, 0x4e, 0x5f, 0xd1, 0xb1, 0xdd,
0xe1, 0xec, 0x9d, 0x18, 0x5f, 0x22, 0xa9, 0x5c, 0x91, 0xf2, 0x49, 0xef, 0x4d, 0x8e, 0x0f, 0xa6, 0x33, 0x2f, 0xb9, 0xe1, 0xae, 0xd3, 0x1b, 0x59, 0xe2, 0x7f, 0x7f, 0x43, 0x5a, 0x7b, 0xe6, 0x5e,
0x21, 0x29, 0x03, 0xf3, 0x37, 0x7c, 0xbb, 0xad, 0x1d, 0xa1, 0x5d, 0x2e, 0xc2, 0x50, 0x1c, 0x7f, 0xf8, 0x72, 0xd7, 0x6a, 0x83, 0xca, 0x1a, 0xe2, 0x70, 0x0b, 0x45, 0x8f, 0x6f, 0x27, 0xc7, 0x9f,
0x61, 0xdd, 0xe1, 0xf3, 0xc9, 0xfe, 0x77, 0xd6, 0xdb, 0x1f, 0x32, 0xf6, 0xe3, 0x90, 0xb1, 0x5f, 0xf9, 0xe0, 0xf8, 0x2b, 0x8f, 0xbe, 0xd9, 0xf3, 0xc3, 0x9e, 0xaf, 0xbf, 0xf3, 0xc1, 0x9f, 0x00,
0x87, 0x8c, 0x7d, 0xff, 0x93, 0xf5, 0xfe, 0x06, 0x00, 0x00, 0xff, 0xff, 0x80, 0x62, 0xfc, 0x40, 0x00, 0x00, 0xff, 0xff, 0x80, 0x62, 0xfc, 0x40, 0xa4, 0x02, 0x00, 0x00,
0xa4, 0x02, 0x00, 0x00,
} }

View File

@ -2035,58 +2035,57 @@ var (
) )
var fileDescriptorRaftInternal = []byte{ var fileDescriptorRaftInternal = []byte{
// 837 bytes of a gzipped FileDescriptorProto // 831 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x7c, 0x96, 0xdd, 0x52, 0xd3, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x7c, 0x56, 0xdb, 0x4e, 0xdb, 0x4a,
0x14, 0xc7, 0x69, 0xf9, 0xec, 0xb6, 0x54, 0x5c, 0x40, 0xd7, 0x32, 0x53, 0xa1, 0x8c, 0x8a, 0x5f, 0x14, 0x25, 0xe1, 0x9a, 0x49, 0xc8, 0xe1, 0x0c, 0x70, 0xce, 0x9c, 0x20, 0x71, 0x20, 0xa8, 0xf7,
0xe8, 0x94, 0x07, 0xd0, 0x4a, 0x19, 0x60, 0x86, 0x61, 0x98, 0x0c, 0xce, 0x38, 0xe3, 0x45, 0x5c, 0x96, 0x56, 0xf0, 0x01, 0x6d, 0x4a, 0x10, 0x20, 0xa1, 0x0a, 0x59, 0x54, 0xaa, 0xd4, 0x07, 0x77,
0x9a, 0x43, 0x1b, 0x49, 0x93, 0xb8, 0xd9, 0x56, 0x7c, 0x13, 0x1f, 0xc3, 0xaf, 0x87, 0xe0, 0xc2, 0x88, 0xa7, 0xc1, 0xad, 0x63, 0xbb, 0xf6, 0x84, 0xd2, 0x3f, 0xe9, 0x67, 0xf4, 0xf6, 0x11, 0x3c,
0x0f, 0xd4, 0x17, 0x50, 0xbc, 0xf1, 0xca, 0x1b, 0x7d, 0x00, 0x67, 0x3f, 0x92, 0x34, 0x6d, 0xca, 0xf4, 0x42, 0xdb, 0x1f, 0xe8, 0xe5, 0xa5, 0x4f, 0x7d, 0x69, 0x3f, 0xa0, 0x73, 0xf3, 0xd8, 0x4e,
0x5d, 0x72, 0xce, 0xff, 0xfc, 0xce, 0xd9, 0xec, 0x7f, 0xbb, 0x45, 0xb3, 0x8c, 0x1e, 0x72, 0xd3, 0xc6, 0x3c, 0x44, 0xb2, 0xd7, 0xac, 0xbd, 0xd6, 0x1e, 0xef, 0x35, 0x0c, 0x60, 0x36, 0xc2, 0x0f,
0x76, 0x39, 0x30, 0x97, 0x3a, 0xab, 0x3e, 0xf3, 0xb8, 0x87, 0x0b, 0xc0, 0x1b, 0x56, 0x00, 0xac, 0xa9, 0xed, 0xfa, 0x94, 0x44, 0x3e, 0xf6, 0x56, 0xc3, 0x28, 0xa0, 0x01, 0xac, 0x11, 0xda, 0x71,
0x0b, 0xcc, 0x3f, 0x28, 0xcd, 0x35, 0xbd, 0xa6, 0x27, 0x13, 0xf7, 0xc4, 0x93, 0xd2, 0x94, 0x66, 0x62, 0x12, 0x1d, 0x91, 0x28, 0x3c, 0x68, 0xcc, 0x75, 0x83, 0x6e, 0x20, 0x16, 0xae, 0xf3, 0x27,
0x62, 0x8d, 0x8e, 0xe4, 0x98, 0xdf, 0x50, 0x8f, 0x95, 0x67, 0x68, 0xda, 0x80, 0x17, 0x1d, 0x08, 0xc9, 0x69, 0xcc, 0xa4, 0x1c, 0x85, 0x54, 0xa2, 0xb0, 0x23, 0x1f, 0x9b, 0x0f, 0xc0, 0xb4, 0x45,
0xf8, 0x16, 0x50, 0x0b, 0x18, 0x2e, 0xa2, 0xec, 0x76, 0x9d, 0x64, 0x16, 0x33, 0x2b, 0x63, 0x46, 0x9e, 0xf4, 0x49, 0x4c, 0xb7, 0x09, 0x76, 0x48, 0x04, 0xeb, 0xa0, 0xbc, 0xd3, 0x46, 0xa5, 0xa5,
0xd6, 0xae, 0xe3, 0x12, 0x9a, 0xea, 0x04, 0xa2, 0x65, 0x1b, 0x48, 0x76, 0x31, 0xb3, 0x92, 0x33, 0xd2, 0xc5, 0x31, 0xab, 0xec, 0xb6, 0x61, 0x03, 0x4c, 0xf5, 0x63, 0x6e, 0xd9, 0x23, 0xa8, 0xcc,
0xa2, 0x77, 0xbc, 0x8c, 0xa6, 0x69, 0x87, 0xb7, 0x4c, 0x06, 0x5d, 0x3b, 0xb0, 0x3d, 0x97, 0x8c, 0xd0, 0x8a, 0xa5, 0xdf, 0xe1, 0x0a, 0x98, 0xc6, 0x7d, 0x7a, 0x68, 0x47, 0xe4, 0xc8, 0x8d, 0xdd,
0xca, 0xb2, 0x82, 0x08, 0x1a, 0x3a, 0x56, 0xf9, 0x53, 0x44, 0xb3, 0xdb, 0x7a, 0x6a, 0x83, 0x1e, 0xc0, 0x47, 0xa3, 0xa2, 0xac, 0xc6, 0x41, 0x4b, 0x61, 0xcd, 0x9f, 0x75, 0x30, 0xbb, 0xa3, 0xba,
0x72, 0xdd, 0x6e, 0xa0, 0xd1, 0x35, 0x94, 0xed, 0x56, 0x65, 0x8b, 0x7c, 0x75, 0x7e, 0xb5, 0x77, 0xb6, 0xd8, 0x16, 0x94, 0xdd, 0x90, 0xd1, 0x39, 0x50, 0x3e, 0x5a, 0x13, 0x16, 0xd5, 0xb5, 0xf9,
0x5d, 0xab, 0xba, 0xc4, 0xc8, 0x76, 0xab, 0xf8, 0x3e, 0x1a, 0x67, 0xd4, 0x6d, 0x82, 0xec, 0x95, 0xd5, 0xec, 0xbe, 0x56, 0x55, 0x89, 0xc5, 0x08, 0xf0, 0x06, 0x18, 0x8f, 0xb0, 0xdf, 0x25, 0xc2,
0xaf, 0x96, 0xfa, 0x94, 0x22, 0x15, 0xca, 0x95, 0x10, 0xdf, 0x42, 0xa3, 0x7e, 0x87, 0x93, 0x31, 0xab, 0xba, 0xd6, 0x18, 0x60, 0xf2, 0xa5, 0x84, 0x2e, 0x89, 0xf0, 0x32, 0x18, 0x0d, 0xfb, 0x14,
0xa9, 0x27, 0x49, 0xfd, 0x5e, 0x27, 0x9c, 0xc7, 0x10, 0x22, 0xbc, 0x8e, 0x0a, 0x16, 0x38, 0xc0, 0x8d, 0x09, 0x3e, 0xca, 0xf3, 0xf7, 0xfa, 0x49, 0x3f, 0x16, 0x27, 0xc1, 0x0d, 0x50, 0x73, 0x88,
0xc1, 0x54, 0x4d, 0xc6, 0x65, 0xd1, 0x62, 0xb2, 0xa8, 0x2e, 0x15, 0x89, 0x56, 0x79, 0x2b, 0x8e, 0x47, 0x28, 0xb1, 0xa5, 0xc9, 0xb8, 0x28, 0x5a, 0xca, 0x17, 0xb5, 0x05, 0x23, 0x67, 0x55, 0x75,
0x89, 0x86, 0xfc, 0xd8, 0x25, 0x13, 0x69, 0x0d, 0xf7, 0x8f, 0xdd, 0xa8, 0x21, 0x3f, 0x76, 0xf1, 0x52, 0x8c, 0x1b, 0xd2, 0x63, 0x1f, 0x4d, 0x98, 0x0c, 0xf7, 0x8f, 0x7d, 0x6d, 0xc8, 0x48, 0xf0,
0x03, 0x84, 0x1a, 0x5e, 0xdb, 0xa7, 0x0d, 0x2e, 0xbe, 0xdf, 0xa4, 0x2c, 0xb9, 0x9a, 0x2c, 0x59, 0x26, 0x00, 0x9d, 0xa0, 0x17, 0xe2, 0x0e, 0xe5, 0xdf, 0x6f, 0x52, 0x94, 0xfc, 0x9f, 0x2f, 0xd9,
0x8f, 0xf2, 0x61, 0x65, 0x4f, 0x09, 0x7e, 0x88, 0xf2, 0x0e, 0xd0, 0x00, 0xcc, 0x26, 0xa3, 0x2e, 0xd0, 0xeb, 0x49, 0x65, 0xa6, 0x04, 0xde, 0x02, 0x55, 0x8f, 0xe0, 0x98, 0xd8, 0x5d, 0xd6, 0x31,
0x27, 0x53, 0x69, 0x84, 0x1d, 0x21, 0xd8, 0x14, 0xf9, 0x88, 0xe0, 0x44, 0x21, 0xb1, 0x66, 0x45, 0x45, 0x53, 0x26, 0x85, 0x5d, 0x4e, 0xd8, 0xe2, 0xeb, 0x5a, 0xc1, 0xd3, 0x10, 0xdf, 0xb3, 0x54,
0x60, 0xd0, 0xf5, 0x8e, 0x80, 0xe4, 0xd2, 0xd6, 0x2c, 0x11, 0x86, 0x14, 0x44, 0x6b, 0x76, 0xe2, 0x60, 0x63, 0x0c, 0x1e, 0x13, 0x54, 0x31, 0xed, 0x59, 0x48, 0x58, 0x82, 0xa0, 0xf7, 0xec, 0xa5,
0x98, 0xd8, 0x16, 0xea, 0x50, 0xd6, 0x26, 0x28, 0x6d, 0x5b, 0x6a, 0x22, 0x15, 0x6d, 0x8b, 0x14, 0x18, 0x1f, 0x0b, 0xf6, 0x70, 0xd4, 0x43, 0xc0, 0x34, 0x96, 0x16, 0x5f, 0xd2, 0x63, 0x11, 0x44,
0xe2, 0x35, 0x34, 0xd1, 0x92, 0x96, 0x23, 0x96, 0x2c, 0x59, 0x48, 0xdd, 0x73, 0xe5, 0x4a, 0x43, 0xb8, 0x0e, 0x26, 0x0e, 0x45, 0xe4, 0x90, 0x23, 0x4a, 0x16, 0x8c, 0x33, 0x97, 0xa9, 0xb4, 0x14,
0x4b, 0x71, 0x0d, 0xe5, 0xa5, 0xe3, 0xc0, 0xa5, 0x07, 0x0e, 0x90, 0xdf, 0xa9, 0x1f, 0xac, 0xd6, 0x15, 0xb6, 0x40, 0x55, 0x24, 0x8e, 0xf8, 0xf8, 0xc0, 0x23, 0xe8, 0x87, 0xf1, 0x83, 0xb5, 0x18,
0xe1, 0xad, 0x0d, 0x29, 0x88, 0x96, 0x4b, 0xa3, 0x10, 0xae, 0x23, 0xe9, 0x4f, 0xd3, 0xb2, 0x03, 0x63, 0x53, 0x10, 0xf4, 0x76, 0xb1, 0x86, 0x60, 0x1b, 0x88, 0x7c, 0xda, 0x8e, 0x1b, 0x0b, 0x8d,
0xc9, 0xf8, 0x3b, 0x99, 0xb6, 0x5e, 0xc1, 0xa8, 0x2b, 0x45, 0xb4, 0x5e, 0x1a, 0xc7, 0xf0, 0xae, 0x5f, 0x93, 0xa6, 0xfd, 0x72, 0x8d, 0xb6, 0x64, 0xe8, 0xfd, 0xe2, 0x14, 0x83, 0x77, 0xa4, 0x0a,
0xa2, 0x80, 0xcb, 0xed, 0x06, 0xe5, 0x40, 0xfe, 0x29, 0xca, 0xcd, 0x24, 0x25, 0xf4, 0x7d, 0xad, 0xf1, 0xa9, 0xdb, 0xc1, 0x94, 0xa0, 0xdf, 0x52, 0xe5, 0x52, 0x5e, 0x25, 0xc9, 0x7d, 0x2b, 0x43,
0x47, 0x1a, 0xe2, 0x12, 0xf5, 0x78, 0x43, 0x1f, 0x25, 0x71, 0xb6, 0x4c, 0x6a, 0x59, 0xe4, 0xe3, 0x4d, 0xe4, 0x72, 0xf5, 0x70, 0x53, 0x1d, 0x25, 0x7e, 0xb6, 0x6c, 0xec, 0x38, 0xe8, 0xed, 0x54,
0xd4, 0xb0, 0xb1, 0x1e, 0x07, 0xc0, 0x6a, 0x96, 0x95, 0x18, 0x4b, 0xc7, 0xf0, 0x2e, 0x9a, 0x89, 0x51, 0x5b, 0x77, 0xd9, 0x5b, 0xcb, 0x71, 0x72, 0x6d, 0x29, 0x8c, 0xb5, 0x35, 0x93, 0xca, 0xc8,
0x31, 0xca, 0x93, 0xe4, 0x93, 0x22, 0x2d, 0xa7, 0x93, 0xb4, 0x99, 0x35, 0xac, 0x48, 0x13, 0xe1, 0x4c, 0xa2, 0x77, 0x52, 0x69, 0xc5, 0xac, 0xa4, 0xc2, 0xac, 0xc4, 0xea, 0x38, 0x07, 0xe7, 0xdb,
0xe4, 0x58, 0x4d, 0xe0, 0xe4, 0xf3, 0xb9, 0x63, 0x6d, 0x02, 0x1f, 0x18, 0x6b, 0x13, 0x38, 0x6e, 0xea, 0x12, 0x8a, 0xde, 0x9f, 0xd9, 0xd6, 0x16, 0xa1, 0x43, 0x6d, 0x31, 0x0c, 0x76, 0xc1, 0x7f,
0xa2, 0x2b, 0x31, 0xa6, 0xd1, 0x12, 0xa7, 0xc4, 0xf4, 0x69, 0x10, 0xbc, 0xf4, 0x98, 0x45, 0xbe, 0xa9, 0x4c, 0xe7, 0x90, 0x9f, 0x12, 0x3b, 0xc4, 0x71, 0xfc, 0x34, 0x88, 0x1c, 0xf4, 0x41, 0x4a,
0x28, 0xe4, 0xed, 0x74, 0xe4, 0xba, 0x54, 0xef, 0x69, 0x71, 0x48, 0xbf, 0x44, 0x53, 0xd3, 0xf8, 0x5e, 0x31, 0x4b, 0x6e, 0x08, 0xf6, 0x9e, 0x22, 0x27, 0xea, 0xff, 0x60, 0xe3, 0x32, 0xbc, 0x07,
0x09, 0x9a, 0xeb, 0x99, 0x57, 0xd8, 0xdb, 0x64, 0x9e, 0x03, 0xe4, 0x54, 0xf5, 0xb8, 0x3e, 0x64, 0xe6, 0x32, 0xfd, 0xf2, 0x78, 0xdb, 0x51, 0xc0, 0x86, 0x7c, 0x2a, 0x3d, 0xce, 0x17, 0xb4, 0x2d,
0x6c, 0x79, 0x34, 0xbc, 0x78, 0xab, 0x2f, 0xd2, 0xfe, 0x0c, 0x7e, 0x8a, 0xe6, 0x63, 0xb2, 0x3a, 0x8e, 0x46, 0x90, 0x8e, 0xfa, 0x6f, 0x3c, 0xb8, 0x02, 0xef, 0x83, 0xf9, 0x54, 0x59, 0x9e, 0x14,
0x29, 0x0a, 0xfd, 0x55, 0xa1, 0x6f, 0xa4, 0xa3, 0xf5, 0x91, 0xe9, 0x61, 0x63, 0x3a, 0x90, 0xc2, 0x29, 0xfd, 0x51, 0x4a, 0x5f, 0x30, 0x4b, 0xab, 0x23, 0x93, 0xd1, 0x86, 0x78, 0x68, 0x09, 0x6e,
0x5b, 0xa8, 0x18, 0xc3, 0x1d, 0x3b, 0xe0, 0xe4, 0x9b, 0xa2, 0x2e, 0xa5, 0x53, 0x77, 0xec, 0x80, 0x83, 0x7a, 0x2a, 0xee, 0xb9, 0x31, 0x45, 0x9f, 0xa4, 0xea, 0xb2, 0x59, 0x75, 0x97, 0x51, 0x72,
0x27, 0x7c, 0x14, 0x06, 0x23, 0x92, 0x18, 0x4d, 0x91, 0xbe, 0x0f, 0x25, 0x89, 0xd6, 0x03, 0xa4, 0x39, 0x4a, 0x40, 0xad, 0xc4, 0x5b, 0x93, 0x4a, 0x9f, 0x0b, 0x95, 0xb8, 0xf5, 0x90, 0x52, 0x02,
0x30, 0x18, 0x6d, 0xbd, 0x24, 0x09, 0x47, 0xbe, 0xc9, 0x0d, 0xdb, 0x7a, 0x51, 0xd3, 0xef, 0x48, 0xea, 0xd1, 0x0b, 0x25, 0x9e, 0xc8, 0x17, 0x95, 0xa2, 0xd1, 0xf3, 0x9a, 0xc1, 0x44, 0x2a, 0x4c,
0x1d, 0x8b, 0x1c, 0x29, 0x31, 0xda, 0x91, 0x6f, 0x73, 0xc3, 0x1c, 0x29, 0xaa, 0x52, 0x1c, 0x19, 0x27, 0x52, 0xc8, 0xa8, 0x44, 0xbe, 0xac, 0x14, 0x25, 0x92, 0x57, 0x19, 0x12, 0x99, 0xc2, 0xf9,
0x87, 0x93, 0x63, 0x09, 0x47, 0xbe, 0x3b, 0x77, 0xac, 0x7e, 0x47, 0xea, 0x18, 0x7e, 0x8e, 0x4a, 0xb6, 0x78, 0x22, 0x5f, 0x9d, 0xd9, 0xd6, 0x60, 0x22, 0x15, 0x06, 0x1f, 0x81, 0x46, 0x46, 0x46,
0x3d, 0x18, 0x69, 0x14, 0x1f, 0x58, 0xdb, 0x0e, 0xe4, 0x3d, 0xf6, 0x5e, 0x31, 0xef, 0x0c, 0x61, 0x04, 0x25, 0x24, 0x51, 0xcf, 0x8d, 0xc5, 0x3d, 0xf6, 0x5a, 0x6a, 0x5e, 0x2d, 0xd0, 0xe4, 0xf4,
0x0a, 0xf9, 0x5e, 0xa4, 0x0e, 0xf9, 0x97, 0x69, 0x7a, 0x1e, 0xb7, 0xd1, 0x42, 0xdc, 0x4b, 0x5b, 0x3d, 0xcd, 0x4e, 0xf4, 0xff, 0xc5, 0xe6, 0x75, 0xd8, 0x03, 0x0b, 0xa9, 0x97, 0x8a, 0x4e, 0xc6,
0xa7, 0xa7, 0xd9, 0x07, 0xd5, 0xec, 0x6e, 0x7a, 0x33, 0xe5, 0x92, 0xc1, 0x6e, 0x84, 0x0e, 0x11, 0xec, 0x8d, 0x34, 0xbb, 0x66, 0x36, 0x93, 0x29, 0x19, 0x76, 0x43, 0xb8, 0x80, 0xd0, 0xfc, 0x0b,
0x54, 0x2e, 0xa0, 0xe9, 0x8d, 0xb6, 0xcf, 0x5f, 0x19, 0x10, 0xf8, 0x9e, 0x1b, 0x40, 0xc5, 0x47, 0x4c, 0x6f, 0xf6, 0x42, 0xfa, 0xcc, 0x22, 0x71, 0x18, 0xf8, 0x31, 0x69, 0x86, 0x60, 0xe1, 0x8c,
0x0b, 0xe7, 0xfc, 0x10, 0x61, 0x8c, 0xc6, 0xe4, 0xed, 0x9e, 0x91, 0xb7, 0xbb, 0x7c, 0x16, 0xb7, 0x3f, 0x44, 0x10, 0x82, 0x31, 0x71, 0xbb, 0x97, 0xc4, 0xed, 0x2e, 0x9e, 0xf9, 0xad, 0xaf, 0xcf,
0x7e, 0x74, 0x3e, 0xf5, 0xad, 0x1f, 0xbe, 0xe3, 0x25, 0x54, 0x08, 0xec, 0xb6, 0xef, 0x80, 0xc9, 0xa7, 0xba, 0xf5, 0x93, 0x77, 0xb8, 0x0c, 0x6a, 0xb1, 0xdb, 0x0b, 0xd9, 0x5e, 0x28, 0x33, 0x96,
0xbd, 0x23, 0x50, 0x97, 0x7e, 0xce, 0xc8, 0xab, 0xd8, 0xbe, 0x08, 0x3d, 0x9a, 0x3b, 0xf9, 0x59, 0x97, 0x7e, 0xc5, 0xaa, 0x4a, 0x6c, 0x9f, 0x43, 0xb7, 0xe7, 0x4e, 0xbe, 0x2e, 0x8e, 0x9c, 0x7c,
0x1e, 0x39, 0x39, 0x2b, 0x67, 0x4e, 0xcf, 0xca, 0x99, 0x1f, 0x67, 0xe5, 0xcc, 0xeb, 0x5f, 0xe5, 0x5b, 0x2c, 0x9d, 0xb2, 0xdf, 0x17, 0xf6, 0x7b, 0xfe, 0x7d, 0x71, 0xe4, 0x60, 0x42, 0xfc, 0xcb,
0x91, 0x83, 0x09, 0xf9, 0x97, 0x63, 0xed, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x02, 0x23, 0xd2, 0xb1, 0xfe, 0x27, 0x00, 0x00, 0xff, 0xff, 0x02, 0x23, 0xd2, 0x00, 0xca, 0x08, 0x00, 0x00,
0x00, 0xca, 0x08, 0x00, 0x00,
} }

File diff suppressed because it is too large Load Diff

View File

@ -222,6 +222,19 @@ func request_Lease_LeaseKeepAlive_0(ctx context.Context, marshaler runtime.Marsh
return stream, metadata, nil return stream, metadata, nil
} }
func request_Lease_LeaseTimeToLive_0(ctx context.Context, marshaler runtime.Marshaler, client LeaseClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq LeaseTimeToLiveRequest
var metadata runtime.ServerMetadata
if err := marshaler.NewDecoder(req.Body).Decode(&protoReq); err != nil {
return nil, metadata, grpc.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.LeaseTimeToLive(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func request_Cluster_MemberAdd_0(ctx context.Context, marshaler runtime.Marshaler, client ClusterClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { func request_Cluster_MemberAdd_0(ctx context.Context, marshaler runtime.Marshaler, client ClusterClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq MemberAddRequest var protoReq MemberAddRequest
var metadata runtime.ServerMetadata var metadata runtime.ServerMetadata
@ -935,6 +948,34 @@ func RegisterLeaseHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc
}) })
mux.Handle("POST", pattern_Lease_LeaseTimeToLive_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, req)
if err != nil {
runtime.HTTPError(ctx, outboundMarshaler, w, req, err)
}
resp, md, err := request_Lease_LeaseTimeToLive_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, outboundMarshaler, w, req, err)
return
}
forward_Lease_LeaseTimeToLive_0(ctx, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil return nil
} }
@ -944,6 +985,8 @@ var (
pattern_Lease_LeaseRevoke_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v3alpha", "kv", "lease", "revoke"}, "")) pattern_Lease_LeaseRevoke_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v3alpha", "kv", "lease", "revoke"}, ""))
pattern_Lease_LeaseKeepAlive_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v3alpha", "lease", "keepalive"}, "")) pattern_Lease_LeaseKeepAlive_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v3alpha", "lease", "keepalive"}, ""))
pattern_Lease_LeaseTimeToLive_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"v3alpha", "kv", "lease", "timetolive"}, ""))
) )
var ( var (
@ -952,6 +995,8 @@ var (
forward_Lease_LeaseRevoke_0 = runtime.ForwardResponseMessage forward_Lease_LeaseRevoke_0 = runtime.ForwardResponseMessage
forward_Lease_LeaseKeepAlive_0 = runtime.ForwardResponseStream forward_Lease_LeaseKeepAlive_0 = runtime.ForwardResponseStream
forward_Lease_LeaseTimeToLive_0 = runtime.ForwardResponseMessage
) )
// RegisterClusterHandlerFromEndpoint is same as RegisterClusterHandler but // RegisterClusterHandlerFromEndpoint is same as RegisterClusterHandler but

View File

@ -708,24 +708,24 @@ var (
) )
var fileDescriptorKv = []byte{ var fileDescriptorKv = []byte{
// 303 bytes of a gzipped FileDescriptorProto // 298 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x6c, 0x90, 0x41, 0x4e, 0xc2, 0x40, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x74, 0x90, 0xcf, 0x4a, 0xc3, 0x40,
0x14, 0x86, 0x3b, 0x14, 0x0a, 0x3e, 0x08, 0x36, 0x13, 0x12, 0x27, 0x2e, 0x26, 0x95, 0x8d, 0x18, 0x10, 0xc6, 0xbb, 0x4d, 0x9b, 0xd6, 0x69, 0xa9, 0x61, 0x29, 0xb8, 0x78, 0x08, 0x31, 0x17, 0x15,
0x13, 0x4c, 0xf0, 0x06, 0xc6, 0xae, 0x70, 0x61, 0x1a, 0x74, 0x4b, 0x4a, 0x79, 0x21, 0xa4, 0x94, 0x21, 0x42, 0x7d, 0x03, 0x31, 0xa7, 0x7a, 0x90, 0x10, 0xbd, 0x96, 0x34, 0x0e, 0xa5, 0xa4, 0xed,
0x69, 0x4a, 0x9d, 0xa4, 0x37, 0x71, 0xef, 0xde, 0x73, 0xb0, 0xe4, 0x08, 0x52, 0x2f, 0x62, 0xfa, 0x86, 0x34, 0x2e, 0xe4, 0x4d, 0xbc, 0x7b, 0xf7, 0x39, 0x7a, 0xec, 0x23, 0xf8, 0xe7, 0x45, 0xdc,
0xc6, 0xe2, 0xc6, 0xcd, 0xe4, 0xfd, 0xff, 0xff, 0x65, 0xe6, 0x7f, 0x03, 0x9d, 0x58, 0x8f, 0xd3, 0xcc, 0x9a, 0x7a, 0xf2, 0x30, 0xcb, 0xcc, 0xf7, 0xfd, 0xd8, 0xfd, 0x66, 0xa1, 0x9f, 0xa9, 0x20,
0x4c, 0xe5, 0x8a, 0x3b, 0x89, 0x8e, 0xa2, 0x74, 0x71, 0x39, 0x58, 0xa9, 0x95, 0x22, 0xeb, 0xae, 0x2f, 0x64, 0x29, 0xb9, 0xbd, 0x56, 0x69, 0x9a, 0xcf, 0x4f, 0xc7, 0x0b, 0xb9, 0x90, 0x24, 0x5d,
0x9a, 0x4c, 0x3a, 0xfc, 0x64, 0xd0, 0x99, 0x62, 0xf1, 0x1a, 0x6e, 0xde, 0x90, 0xbb, 0x60, 0xc7, 0xd7, 0x9d, 0x71, 0xfd, 0x77, 0x06, 0xfd, 0x29, 0x56, 0x4f, 0xc9, 0xea, 0x05, 0xb9, 0x03, 0x56,
0x58, 0x08, 0xe6, 0xb1, 0x51, 0x2f, 0xa8, 0x46, 0x7e, 0x0d, 0xe7, 0x51, 0x86, 0x61, 0x8e, 0xf3, 0x86, 0x95, 0x60, 0x1e, 0xbb, 0x18, 0x46, 0x75, 0xcb, 0xcf, 0xe1, 0x38, 0x2d, 0x30, 0x29, 0x71,
0x0c, 0xf5, 0x7a, 0xb7, 0x56, 0x5b, 0xd1, 0xf0, 0xd8, 0xc8, 0x0e, 0xfa, 0xc6, 0x0e, 0x7e, 0x5d, 0x56, 0xa0, 0x5a, 0x6e, 0x97, 0x72, 0x23, 0xda, 0xda, 0xb5, 0xa2, 0x91, 0x91, 0xa3, 0x5f, 0x95,
0x7e, 0x05, 0xbd, 0x44, 0x2d, 0xff, 0x28, 0x9b, 0xa8, 0x6e, 0xa2, 0x96, 0x27, 0x44, 0x40, 0x5b, 0x9f, 0xc1, 0x70, 0x2d, 0x9f, 0xff, 0x28, 0x8b, 0xa8, 0x81, 0xd6, 0x0e, 0x88, 0x80, 0x9e, 0xc2,
0x63, 0x46, 0x69, 0x93, 0xd2, 0x5a, 0xf2, 0x01, 0xb4, 0x74, 0x55, 0x40, 0xb4, 0xe8, 0x65, 0x23, 0x82, 0xdc, 0x0e, 0xb9, 0xcd, 0xc8, 0xc7, 0xd0, 0x55, 0x75, 0x00, 0xd1, 0xa5, 0x97, 0xcd, 0x50,
0x2a, 0x77, 0x83, 0xe1, 0x0e, 0x85, 0x43, 0xb4, 0x11, 0xc3, 0x0f, 0x06, 0x2d, 0x5f, 0xe3, 0x36, 0xab, 0x2b, 0x4c, 0xb6, 0x28, 0x6c, 0xa2, 0xcd, 0xe0, 0xbf, 0x31, 0xe8, 0x86, 0x0a, 0x37, 0x25,
0xe7, 0xb7, 0xd0, 0xcc, 0x8b, 0x14, 0xa9, 0x6e, 0x7f, 0x72, 0x31, 0x36, 0x7b, 0x8e, 0x29, 0x34, 0xbf, 0x82, 0x4e, 0x59, 0xe5, 0x48, 0x71, 0x47, 0x93, 0x93, 0xc0, 0xec, 0x19, 0x90, 0x69, 0xce,
0xe7, 0xac, 0x48, 0x31, 0x20, 0x88, 0x7b, 0xd0, 0x88, 0x35, 0x75, 0xef, 0x4e, 0xdc, 0x1a, 0xad, 0x58, 0xdb, 0x11, 0x41, 0xdc, 0x83, 0x76, 0xa6, 0x28, 0xfb, 0x60, 0xe2, 0x34, 0x68, 0xb3, 0x78,
0x17, 0x0f, 0x1a, 0xb1, 0xe6, 0x37, 0xd0, 0x4e, 0x33, 0xd4, 0xf3, 0x58, 0x53, 0xf9, 0xff, 0x30, 0xa4, 0x3d, 0x7e, 0x09, 0xbd, 0x5c, 0xc7, 0x9f, 0x69, 0xcc, 0xfa, 0x07, 0xb3, 0x6b, 0x60, 0xaa,
0xa7, 0x02, 0xa6, 0x7a, 0xe8, 0xc1, 0xd9, 0xe9, 0x7e, 0xde, 0x06, 0xfb, 0xf9, 0x65, 0xe6, 0x5a, 0x7c, 0x0f, 0x8e, 0x0e, 0xf7, 0xf3, 0x1e, 0x58, 0x0f, 0x8f, 0xb1, 0xd3, 0xe2, 0x00, 0xf6, 0x5d,
0x1c, 0xc0, 0x79, 0xf4, 0x9f, 0xfc, 0x99, 0xef, 0xb2, 0x07, 0xb1, 0x3f, 0x4a, 0xeb, 0x70, 0x94, 0x78, 0x1f, 0xc6, 0xa1, 0xc3, 0x6e, 0xc5, 0xee, 0xd3, 0x6d, 0xed, 0x75, 0xed, 0xbe, 0x5c, 0xb6,
0xd6, 0xbe, 0x94, 0xec, 0x50, 0x4a, 0xf6, 0x55, 0x4a, 0xf6, 0xfe, 0x2d, 0xad, 0x85, 0x43, 0xff, 0xd7, 0xf5, 0xa1, 0xeb, 0xf5, 0xdb, 0x6d, 0xcd, 0x6d, 0xfa, 0xf7, 0x9b, 0x9f, 0x00, 0x00, 0x00,
0x7e, 0xff, 0x13, 0x00, 0x00, 0xff, 0xff, 0xb5, 0x45, 0x92, 0x5d, 0xa1, 0x01, 0x00, 0x00, 0xff, 0xff, 0xb5, 0x45, 0x92, 0x5d, 0xa1, 0x01, 0x00, 0x00,
} }

81
vendor/github.com/hashicorp/consul/api/operator.go generated vendored Normal file
View File

@ -0,0 +1,81 @@
package api
// Operator can be used to perform low-level operator tasks for Consul.
type Operator struct {
c *Client
}
// Operator returns a handle to the operator endpoints.
func (c *Client) Operator() *Operator {
return &Operator{c}
}
// RaftServer has information about a server in the Raft configuration.
type RaftServer struct {
// ID is the unique ID for the server. These are currently the same
// as the address, but they will be changed to a real GUID in a future
// release of Consul.
ID string
// Node is the node name of the server, as known by Consul, or this
// will be set to "(unknown)" otherwise.
Node string
// Address is the IP:port of the server, used for Raft communications.
Address string
// Leader is true if this server is the current cluster leader.
Leader bool
// Voter is true if this server has a vote in the cluster. This might
// be false if the server is staging and still coming online, or if
// it's a non-voting server, which will be added in a future release of
// Consul.
Voter bool
}
// RaftConfigration is returned when querying for the current Raft configuration.
type RaftConfiguration struct {
// Servers has the list of servers in the Raft configuration.
Servers []*RaftServer
// Index has the Raft index of this configuration.
Index uint64
}
// RaftGetConfiguration is used to query the current Raft peer set.
func (op *Operator) RaftGetConfiguration(q *QueryOptions) (*RaftConfiguration, error) {
r := op.c.newRequest("GET", "/v1/operator/raft/configuration")
r.setQueryOptions(q)
_, resp, err := requireOK(op.c.doRequest(r))
if err != nil {
return nil, err
}
defer resp.Body.Close()
var out RaftConfiguration
if err := decodeBody(resp, &out); err != nil {
return nil, err
}
return &out, nil
}
// RaftRemovePeerByAddress is used to kick a stale peer (one that it in the Raft
// quorum but no longer known to Serf or the catalog) by address in the form of
// "IP:port".
func (op *Operator) RaftRemovePeerByAddress(address string, q *WriteOptions) error {
r := op.c.newRequest("DELETE", "/v1/operator/raft/peer")
r.setWriteOptions(q)
// TODO (slackpad) Currently we made address a query parameter. Once
// IDs are in place this will be DELETE /v1/operator/raft/peer/<id>.
r.params.Set("address", string(address))
_, resp, err := requireOK(op.c.doRequest(r))
if err != nil {
return err
}
resp.Body.Close()
return nil
}

View File

@ -45,8 +45,8 @@ type watchType int
const ( const (
watchTypeData = iota watchTypeData = iota
watchTypeExist = iota watchTypeExist
watchTypeChild = iota watchTypeChild
) )
type watchPathType struct { type watchPathType struct {
@ -61,6 +61,11 @@ type Logger interface {
Printf(string, ...interface{}) Printf(string, ...interface{})
} }
type authCreds struct {
scheme string
auth []byte
}
type Conn struct { type Conn struct {
lastZxid int64 lastZxid int64
sessionID int64 sessionID int64
@ -75,21 +80,28 @@ type Conn struct {
server string // remember the address/port of the current server server string // remember the address/port of the current server
conn net.Conn conn net.Conn
eventChan chan Event eventChan chan Event
eventCallback EventCallback // may be nil
shouldQuit chan struct{} shouldQuit chan struct{}
pingInterval time.Duration pingInterval time.Duration
recvTimeout time.Duration recvTimeout time.Duration
connectTimeout time.Duration connectTimeout time.Duration
creds []authCreds
credsMu sync.Mutex // protects server
sendChan chan *request sendChan chan *request
requests map[int32]*request // Xid -> pending request requests map[int32]*request // Xid -> pending request
requestsLock sync.Mutex requestsLock sync.Mutex
watchers map[watchPathType][]chan Event watchers map[watchPathType][]chan Event
watchersLock sync.Mutex watchersLock sync.Mutex
closeChan chan struct{} // channel to tell send loop stop
// Debug (used by unit tests) // Debug (used by unit tests)
reconnectDelay time.Duration reconnectDelay time.Duration
logger Logger logger Logger
buf []byte
} }
// connOption represents a connection option. // connOption represents a connection option.
@ -185,6 +197,7 @@ func Connect(servers []string, sessionTimeout time.Duration, options ...connOpti
watchers: make(map[watchPathType][]chan Event), watchers: make(map[watchPathType][]chan Event),
passwd: emptyPassword, passwd: emptyPassword,
logger: DefaultLogger, logger: DefaultLogger,
buf: make([]byte, bufferSize),
// Debug // Debug
reconnectDelay: 0, reconnectDelay: 0,
@ -224,6 +237,18 @@ func WithHostProvider(hostProvider HostProvider) connOption {
} }
} }
// EventCallback is a function that is called when an Event occurs.
type EventCallback func(Event)
// WithEventCallback returns a connection option that specifies an event
// callback.
// The callback must not block - doing so would delay the ZK go routines.
func WithEventCallback(cb EventCallback) connOption {
return func(c *Conn) {
c.eventCallback = cb
}
}
func (c *Conn) Close() { func (c *Conn) Close() {
close(c.shouldQuit) close(c.shouldQuit)
@ -238,7 +263,7 @@ func (c *Conn) State() State {
return State(atomic.LoadInt32((*int32)(&c.state))) return State(atomic.LoadInt32((*int32)(&c.state)))
} }
// SessionId returns the current session id of the connection. // SessionID returns the current session id of the connection.
func (c *Conn) SessionID() int64 { func (c *Conn) SessionID() int64 {
return atomic.LoadInt64(&c.sessionID) return atomic.LoadInt64(&c.sessionID)
} }
@ -258,8 +283,16 @@ func (c *Conn) setTimeouts(sessionTimeoutMs int32) {
func (c *Conn) setState(state State) { func (c *Conn) setState(state State) {
atomic.StoreInt32((*int32)(&c.state), int32(state)) atomic.StoreInt32((*int32)(&c.state), int32(state))
c.sendEvent(Event{Type: EventSession, State: state, Server: c.Server()})
}
func (c *Conn) sendEvent(evt Event) {
if c.eventCallback != nil {
c.eventCallback(evt)
}
select { select {
case c.eventChan <- Event{Type: EventSession, State: state, Server: c.Server()}: case c.eventChan <- evt:
default: default:
// panic("zk: event channel full - it must be monitored and never allowed to be full") // panic("zk: event channel full - it must be monitored and never allowed to be full")
} }
@ -296,6 +329,65 @@ func (c *Conn) connect() error {
} }
} }
func (c *Conn) resendZkAuth(reauthReadyChan chan struct{}) {
c.credsMu.Lock()
defer c.credsMu.Unlock()
defer close(reauthReadyChan)
c.logger.Printf("Re-submitting `%d` credentials after reconnect",
len(c.creds))
for _, cred := range c.creds {
resChan, err := c.sendRequest(
opSetAuth,
&setAuthRequest{Type: 0,
Scheme: cred.scheme,
Auth: cred.auth,
},
&setAuthResponse{},
nil)
if err != nil {
c.logger.Printf("Call to sendRequest failed during credential resubmit: %s", err)
// FIXME(prozlach): lets ignore errors for now
continue
}
res := <-resChan
if res.err != nil {
c.logger.Printf("Credential re-submit failed: %s", res.err)
// FIXME(prozlach): lets ignore errors for now
continue
}
}
}
func (c *Conn) sendRequest(
opcode int32,
req interface{},
res interface{},
recvFunc func(*request, *responseHeader, error),
) (
<-chan response,
error,
) {
rq := &request{
xid: c.nextXid(),
opcode: opcode,
pkt: req,
recvStruct: res,
recvChan: make(chan response, 1),
recvFunc: recvFunc,
}
if err := c.sendData(rq); err != nil {
return nil, err
}
return rq.recvChan, nil
}
func (c *Conn) loop() { func (c *Conn) loop() {
for { for {
if err := c.connect(); err != nil { if err := c.connect(); err != nil {
@ -314,12 +406,14 @@ func (c *Conn) loop() {
case err == nil: case err == nil:
c.logger.Printf("Authenticated: id=%d, timeout=%d", c.SessionID(), c.sessionTimeoutMs) c.logger.Printf("Authenticated: id=%d, timeout=%d", c.SessionID(), c.sessionTimeoutMs)
c.hostProvider.Connected() // mark success c.hostProvider.Connected() // mark success
closeChan := make(chan struct{}) // channel to tell send loop stop c.closeChan = make(chan struct{}) // channel to tell send loop stop
var wg sync.WaitGroup reauthChan := make(chan struct{}) // channel to tell send loop that authdata has been resubmitted
var wg sync.WaitGroup
wg.Add(1) wg.Add(1)
go func() { go func() {
err := c.sendLoop(c.conn, closeChan) <-reauthChan
err := c.sendLoop()
c.logger.Printf("Send loop terminated: err=%v", err) c.logger.Printf("Send loop terminated: err=%v", err)
c.conn.Close() // causes recv loop to EOF/exit c.conn.Close() // causes recv loop to EOF/exit
wg.Done() wg.Done()
@ -332,10 +426,12 @@ func (c *Conn) loop() {
if err == nil { if err == nil {
panic("zk: recvLoop should never return nil error") panic("zk: recvLoop should never return nil error")
} }
close(closeChan) // tell send loop to exit close(c.closeChan) // tell send loop to exit
wg.Done() wg.Done()
}() }()
c.resendZkAuth(reauthChan)
c.sendSetWatches() c.sendSetWatches()
wg.Wait() wg.Wait()
} }
@ -507,34 +603,27 @@ func (c *Conn) authenticate() error {
return nil return nil
} }
func (c *Conn) sendLoop(conn net.Conn, closeChan <-chan struct{}) error { func (c *Conn) sendData(req *request) error {
pingTicker := time.NewTicker(c.pingInterval)
defer pingTicker.Stop()
buf := make([]byte, bufferSize)
for {
select {
case req := <-c.sendChan:
header := &requestHeader{req.xid, req.opcode} header := &requestHeader{req.xid, req.opcode}
n, err := encodePacket(buf[4:], header) n, err := encodePacket(c.buf[4:], header)
if err != nil { if err != nil {
req.recvChan <- response{-1, err} req.recvChan <- response{-1, err}
continue return nil
} }
n2, err := encodePacket(buf[4+n:], req.pkt) n2, err := encodePacket(c.buf[4+n:], req.pkt)
if err != nil { if err != nil {
req.recvChan <- response{-1, err} req.recvChan <- response{-1, err}
continue return nil
} }
n += n2 n += n2
binary.BigEndian.PutUint32(buf[:4], uint32(n)) binary.BigEndian.PutUint32(c.buf[:4], uint32(n))
c.requestsLock.Lock() c.requestsLock.Lock()
select { select {
case <-closeChan: case <-c.closeChan:
req.recvChan <- response{-1, ErrConnectionClosed} req.recvChan <- response{-1, ErrConnectionClosed}
c.requestsLock.Unlock() c.requestsLock.Unlock()
return ErrConnectionClosed return ErrConnectionClosed
@ -543,30 +632,44 @@ func (c *Conn) sendLoop(conn net.Conn, closeChan <-chan struct{}) error {
c.requests[req.xid] = req c.requests[req.xid] = req
c.requestsLock.Unlock() c.requestsLock.Unlock()
conn.SetWriteDeadline(time.Now().Add(c.recvTimeout)) c.conn.SetWriteDeadline(time.Now().Add(c.recvTimeout))
_, err = conn.Write(buf[:n+4]) _, err = c.conn.Write(c.buf[:n+4])
conn.SetWriteDeadline(time.Time{}) c.conn.SetWriteDeadline(time.Time{})
if err != nil { if err != nil {
req.recvChan <- response{-1, err} req.recvChan <- response{-1, err}
conn.Close() c.conn.Close()
return err
}
return nil
}
func (c *Conn) sendLoop() error {
pingTicker := time.NewTicker(c.pingInterval)
defer pingTicker.Stop()
for {
select {
case req := <-c.sendChan:
if err := c.sendData(req); err != nil {
return err return err
} }
case <-pingTicker.C: case <-pingTicker.C:
n, err := encodePacket(buf[4:], &requestHeader{Xid: -2, Opcode: opPing}) n, err := encodePacket(c.buf[4:], &requestHeader{Xid: -2, Opcode: opPing})
if err != nil { if err != nil {
panic("zk: opPing should never fail to serialize") panic("zk: opPing should never fail to serialize")
} }
binary.BigEndian.PutUint32(buf[:4], uint32(n)) binary.BigEndian.PutUint32(c.buf[:4], uint32(n))
conn.SetWriteDeadline(time.Now().Add(c.recvTimeout)) c.conn.SetWriteDeadline(time.Now().Add(c.recvTimeout))
_, err = conn.Write(buf[:n+4]) _, err = c.conn.Write(c.buf[:n+4])
conn.SetWriteDeadline(time.Time{}) c.conn.SetWriteDeadline(time.Time{})
if err != nil { if err != nil {
conn.Close() c.conn.Close()
return err return err
} }
case <-closeChan: case <-c.closeChan:
return nil return nil
} }
} }
@ -611,10 +714,7 @@ func (c *Conn) recvLoop(conn net.Conn) error {
Path: res.Path, Path: res.Path,
Err: nil, Err: nil,
} }
select { c.sendEvent(ev)
case c.eventChan <- ev:
default:
}
wTypes := make([]watchType, 0, 2) wTypes := make([]watchType, 0, 2)
switch res.Type { switch res.Type {
case EventNodeCreated: case EventNodeCreated:
@ -706,7 +806,28 @@ func (c *Conn) request(opcode int32, req interface{}, res interface{}, recvFunc
func (c *Conn) AddAuth(scheme string, auth []byte) error { func (c *Conn) AddAuth(scheme string, auth []byte) error {
_, err := c.request(opSetAuth, &setAuthRequest{Type: 0, Scheme: scheme, Auth: auth}, &setAuthResponse{}, nil) _, err := c.request(opSetAuth, &setAuthRequest{Type: 0, Scheme: scheme, Auth: auth}, &setAuthResponse{}, nil)
if err != nil {
return err return err
}
// Remember authdata so that it can be re-submitted on reconnect
//
// FIXME(prozlach): For now we treat "userfoo:passbar" and "userfoo:passbar2"
// as two different entries, which will be re-submitted on reconnet. Some
// research is needed on how ZK treats these cases and
// then maybe switch to something like "map[username] = password" to allow
// only single password for given user with users being unique.
obj := authCreds{
scheme: scheme,
auth: auth,
}
c.credsMu.Lock()
c.creds = append(c.creds, obj)
c.credsMu.Unlock()
return nil
} }
func (c *Conn) Children(path string) ([]string, *Stat, error) { func (c *Conn) Children(path string) ([]string, *Stat, error) {
@ -867,6 +988,7 @@ func (c *Conn) Sync(path string) (string, error) {
type MultiResponse struct { type MultiResponse struct {
Stat *Stat Stat *Stat
String string String string
Error error
} }
// Multi executes multiple ZooKeeper operations or none of them. The provided // Multi executes multiple ZooKeeper operations or none of them. The provided
@ -897,7 +1019,7 @@ func (c *Conn) Multi(ops ...interface{}) ([]MultiResponse, error) {
_, err := c.request(opMulti, req, res, nil) _, err := c.request(opMulti, req, res, nil)
mr := make([]MultiResponse, len(res.Ops)) mr := make([]MultiResponse, len(res.Ops))
for i, op := range res.Ops { for i, op := range res.Ops {
mr[i] = MultiResponse{Stat: op.Stat, String: op.String} mr[i] = MultiResponse{Stat: op.Stat, String: op.String, Error: op.Err.toError()}
} }
return mr, err return mr, err
} }

View File

@ -28,18 +28,19 @@ const (
opClose = -11 opClose = -11
opSetAuth = 100 opSetAuth = 100
opSetWatches = 101 opSetWatches = 101
opError = -1
// Not in protocol, used internally // Not in protocol, used internally
opWatcherEvent = -2 opWatcherEvent = -2
) )
const ( const (
EventNodeCreated = EventType(1) EventNodeCreated EventType = 1
EventNodeDeleted = EventType(2) EventNodeDeleted EventType = 2
EventNodeDataChanged = EventType(3) EventNodeDataChanged EventType = 3
EventNodeChildrenChanged = EventType(4) EventNodeChildrenChanged EventType = 4
EventSession = EventType(-1) EventSession EventType = -1
EventNotWatching = EventType(-2) EventNotWatching EventType = -2
) )
var ( var (
@ -54,14 +55,13 @@ var (
) )
const ( const (
StateUnknown = State(-1) StateUnknown State = -1
StateDisconnected = State(0) StateDisconnected State = 0
StateConnecting = State(1) StateConnecting State = 1
StateAuthFailed = State(4) StateAuthFailed State = 4
StateConnectedReadOnly = State(5) StateConnectedReadOnly State = 5
StateSaslAuthenticated = State(6) StateSaslAuthenticated State = 6
StateExpired = State(-112) StateExpired State = -112
// StateAuthFailed = State(-113)
StateConnected = State(100) StateConnected = State(100)
StateHasSession = State(101) StateHasSession = State(101)
@ -154,20 +154,20 @@ const (
errBadArguments = -8 errBadArguments = -8
errInvalidState = -9 errInvalidState = -9
// API errors // API errors
errAPIError = ErrCode(-100) errAPIError ErrCode = -100
errNoNode = ErrCode(-101) // * errNoNode ErrCode = -101 // *
errNoAuth = ErrCode(-102) errNoAuth ErrCode = -102
errBadVersion = ErrCode(-103) // * errBadVersion ErrCode = -103 // *
errNoChildrenForEphemerals = ErrCode(-108) errNoChildrenForEphemerals ErrCode = -108
errNodeExists = ErrCode(-110) // * errNodeExists ErrCode = -110 // *
errNotEmpty = ErrCode(-111) errNotEmpty ErrCode = -111
errSessionExpired = ErrCode(-112) errSessionExpired ErrCode = -112
errInvalidCallback = ErrCode(-113) errInvalidCallback ErrCode = -113
errInvalidAcl = ErrCode(-114) errInvalidAcl ErrCode = -114
errAuthFailed = ErrCode(-115) errAuthFailed ErrCode = -115
errClosing = ErrCode(-116) errClosing ErrCode = -116
errNothing = ErrCode(-117) errNothing ErrCode = -117
errSessionMoved = ErrCode(-118) errSessionMoved ErrCode = -118
) )
// Constants for ACL permissions // Constants for ACL permissions

View File

@ -58,8 +58,16 @@ func (l *Lock) Lock() error {
parts := strings.Split(l.path, "/") parts := strings.Split(l.path, "/")
pth := "" pth := ""
for _, p := range parts[1:] { for _, p := range parts[1:] {
var exists bool
pth += "/" + p pth += "/" + p
_, err := l.c.Create(pth, []byte{}, 0, l.acl) exists, _, err = l.c.Exists(pth)
if err != nil {
return err
}
if exists == true {
continue
}
_, err = l.c.Create(pth, []byte{}, 0, l.acl)
if err != nil && err != ErrNodeExists { if err != nil && err != ErrNodeExists {
return err return err
} }

View File

@ -99,37 +99,41 @@ func StartTestCluster(size int, stdout, stderr io.Writer) (*TestCluster, error)
return cluster, nil return cluster, nil
} }
func (ts *TestCluster) Connect(idx int) (*Conn, error) { func (tc *TestCluster) Connect(idx int) (*Conn, error) {
zk, _, err := Connect([]string{fmt.Sprintf("127.0.0.1:%d", ts.Servers[idx].Port)}, time.Second*15) zk, _, err := Connect([]string{fmt.Sprintf("127.0.0.1:%d", tc.Servers[idx].Port)}, time.Second*15)
return zk, err return zk, err
} }
func (ts *TestCluster) ConnectAll() (*Conn, <-chan Event, error) { func (tc *TestCluster) ConnectAll() (*Conn, <-chan Event, error) {
return ts.ConnectAllTimeout(time.Second * 15) return tc.ConnectAllTimeout(time.Second * 15)
} }
func (ts *TestCluster) ConnectAllTimeout(sessionTimeout time.Duration) (*Conn, <-chan Event, error) { func (tc *TestCluster) ConnectAllTimeout(sessionTimeout time.Duration) (*Conn, <-chan Event, error) {
hosts := make([]string, len(ts.Servers)) return tc.ConnectWithOptions(sessionTimeout)
for i, srv := range ts.Servers { }
func (tc *TestCluster) ConnectWithOptions(sessionTimeout time.Duration, options ...connOption) (*Conn, <-chan Event, error) {
hosts := make([]string, len(tc.Servers))
for i, srv := range tc.Servers {
hosts[i] = fmt.Sprintf("127.0.0.1:%d", srv.Port) hosts[i] = fmt.Sprintf("127.0.0.1:%d", srv.Port)
} }
zk, ch, err := Connect(hosts, sessionTimeout) zk, ch, err := Connect(hosts, sessionTimeout, options...)
return zk, ch, err return zk, ch, err
} }
func (ts *TestCluster) Stop() error { func (tc *TestCluster) Stop() error {
for _, srv := range ts.Servers { for _, srv := range tc.Servers {
srv.Srv.Stop() srv.Srv.Stop()
} }
defer os.RemoveAll(ts.Path) defer os.RemoveAll(tc.Path)
return ts.waitForStop(5, time.Second) return tc.waitForStop(5, time.Second)
} }
// waitForStart blocks until the cluster is up // waitForStart blocks until the cluster is up
func (ts *TestCluster) waitForStart(maxRetry int, interval time.Duration) error { func (tc *TestCluster) waitForStart(maxRetry int, interval time.Duration) error {
// verify that the servers are up with SRVR // verify that the servers are up with SRVR
serverAddrs := make([]string, len(ts.Servers)) serverAddrs := make([]string, len(tc.Servers))
for i, s := range ts.Servers { for i, s := range tc.Servers {
serverAddrs[i] = fmt.Sprintf("127.0.0.1:%d", s.Port) serverAddrs[i] = fmt.Sprintf("127.0.0.1:%d", s.Port)
} }
@ -144,10 +148,10 @@ func (ts *TestCluster) waitForStart(maxRetry int, interval time.Duration) error
} }
// waitForStop blocks until the cluster is down // waitForStop blocks until the cluster is down
func (ts *TestCluster) waitForStop(maxRetry int, interval time.Duration) error { func (tc *TestCluster) waitForStop(maxRetry int, interval time.Duration) error {
// verify that the servers are up with RUOK // verify that the servers are up with RUOK
serverAddrs := make([]string, len(ts.Servers)) serverAddrs := make([]string, len(tc.Servers))
for i, s := range ts.Servers { for i, s := range tc.Servers {
serverAddrs[i] = fmt.Sprintf("127.0.0.1:%d", s.Port) serverAddrs[i] = fmt.Sprintf("127.0.0.1:%d", s.Port)
} }
@ -188,3 +192,25 @@ func (tc *TestCluster) StopServer(server string) {
} }
panic(fmt.Sprintf("Unknown server: %s", server)) panic(fmt.Sprintf("Unknown server: %s", server))
} }
func (tc *TestCluster) StartAllServers() error {
for _, s := range tc.Servers {
if err := s.Srv.Start(); err != nil {
return fmt.Errorf(
"Failed to start server listening on port `%d` : %+v", s.Port, err)
}
}
return nil
}
func (tc *TestCluster) StopAllServers() error {
for _, s := range tc.Servers {
if err := s.Srv.Stop(); err != nil {
return fmt.Errorf(
"Failed to stop server listening on port `%d` : %+v", s.Port, err)
}
}
return nil
}

View File

@ -270,6 +270,7 @@ type multiResponseOp struct {
Header multiHeader Header multiHeader
String string String string
Stat *Stat Stat *Stat
Err ErrCode
} }
type multiResponse struct { type multiResponse struct {
Ops []multiResponseOp Ops []multiResponseOp
@ -327,6 +328,8 @@ func (r *multiRequest) Decode(buf []byte) (int, error) {
} }
func (r *multiResponse) Decode(buf []byte) (int, error) { func (r *multiResponse) Decode(buf []byte) (int, error) {
var multiErr error
r.Ops = make([]multiResponseOp, 0) r.Ops = make([]multiResponseOp, 0)
r.DoneHeader = multiHeader{-1, true, -1} r.DoneHeader = multiHeader{-1, true, -1}
total := 0 total := 0
@ -347,6 +350,8 @@ func (r *multiResponse) Decode(buf []byte) (int, error) {
switch header.Type { switch header.Type {
default: default:
return total, ErrAPIError return total, ErrAPIError
case opError:
w = reflect.ValueOf(&res.Err)
case opCreate: case opCreate:
w = reflect.ValueOf(&res.String) w = reflect.ValueOf(&res.String)
case opSetData: case opSetData:
@ -362,8 +367,12 @@ func (r *multiResponse) Decode(buf []byte) (int, error) {
total += n total += n
} }
r.Ops = append(r.Ops, res) r.Ops = append(r.Ops, res)
if multiErr == nil && res.Err != errOk {
// Use the first error as the error returned from Multi().
multiErr = res.Err.toError()
} }
return total, nil }
return total, multiErr
} }
type watcherEvent struct { type watcherEvent struct {

View File

@ -401,10 +401,8 @@ func writeLocalNonPersistentFlag(flag *pflag.Flag, w io.Writer) error {
format += "=" format += "="
} }
format += "\")\n" format += "\")\n"
if _, err := fmt.Fprintf(w, format, name); err != nil { _, err := fmt.Fprintf(w, format, name)
return err return err
}
return nil
} }
func writeFlags(cmd *Command, w io.Writer) error { func writeFlags(cmd *Command, w io.Writer) error {

View File

@ -37,38 +37,36 @@ var templateFuncs = template.FuncMap{
var initializers []func() var initializers []func()
// automatic prefix matching can be a dangerous thing to automatically enable in CLI tools. // Automatic prefix matching can be a dangerous thing to automatically enable in CLI tools.
// Set this to true to enable it // Set this to true to enable it.
var EnablePrefixMatching = false var EnablePrefixMatching = false
//EnableCommandSorting controls sorting of the slice of commands, which is turned on by default. // EnableCommandSorting controls sorting of the slice of commands, which is turned on by default.
//To disable sorting, set it to false. // To disable sorting, set it to false.
var EnableCommandSorting = true var EnableCommandSorting = true
//AddTemplateFunc adds a template function that's available to Usage and Help // AddTemplateFunc adds a template function that's available to Usage and Help
//template generation. // template generation.
func AddTemplateFunc(name string, tmplFunc interface{}) { func AddTemplateFunc(name string, tmplFunc interface{}) {
templateFuncs[name] = tmplFunc templateFuncs[name] = tmplFunc
} }
//AddTemplateFuncs adds multiple template functions availalble to Usage and // AddTemplateFuncs adds multiple template functions availalble to Usage and
//Help template generation. // Help template generation.
func AddTemplateFuncs(tmplFuncs template.FuncMap) { func AddTemplateFuncs(tmplFuncs template.FuncMap) {
for k, v := range tmplFuncs { for k, v := range tmplFuncs {
templateFuncs[k] = v templateFuncs[k] = v
} }
} }
//OnInitialize takes a series of func() arguments and appends them to a slice of func(). // OnInitialize takes a series of func() arguments and appends them to a slice of func().
func OnInitialize(y ...func()) { func OnInitialize(y ...func()) {
for _, x := range y { initializers = append(initializers, y...)
initializers = append(initializers, x)
}
} }
//Gt takes two types and checks whether the first type is greater than the second. In case of types Arrays, Chans, // Gt takes two types and checks whether the first type is greater than the second. In case of types Arrays, Chans,
//Maps and Slices, Gt will compare their lengths. Ints are compared directly while strings are first parsed as // Maps and Slices, Gt will compare their lengths. Ints are compared directly while strings are first parsed as
//ints and then compared. // ints and then compared.
func Gt(a interface{}, b interface{}) bool { func Gt(a interface{}, b interface{}) bool {
var left, right int64 var left, right int64
av := reflect.ValueOf(a) av := reflect.ValueOf(a)
@ -96,7 +94,7 @@ func Gt(a interface{}, b interface{}) bool {
return left > right return left > right
} }
//Eq takes two types and checks whether they are equal. Supported types are int and string. Unsupported types will panic. // Eq takes two types and checks whether they are equal. Supported types are int and string. Unsupported types will panic.
func Eq(a interface{}, b interface{}) bool { func Eq(a interface{}, b interface{}) bool {
av := reflect.ValueOf(a) av := reflect.ValueOf(a)
bv := reflect.ValueOf(b) bv := reflect.ValueOf(b)
@ -116,7 +114,7 @@ func trimRightSpace(s string) string {
return strings.TrimRightFunc(s, unicode.IsSpace) return strings.TrimRightFunc(s, unicode.IsSpace)
} }
// appendIfNotPresent will append stringToAppend to the end of s, but only if it's not yet present in s // appendIfNotPresent will append stringToAppend to the end of s, but only if it's not yet present in s.
func appendIfNotPresent(s, stringToAppend string) string { func appendIfNotPresent(s, stringToAppend string) string {
if strings.Contains(s, stringToAppend) { if strings.Contains(s, stringToAppend) {
return s return s
@ -124,7 +122,7 @@ func appendIfNotPresent(s, stringToAppend string) string {
return s + " " + stringToAppend return s + " " + stringToAppend
} }
//rpad adds padding to the right of a string // rpad adds padding to the right of a string.
func rpad(s string, padding int) string { func rpad(s string, padding int) string {
template := fmt.Sprintf("%%-%ds", padding) template := fmt.Sprintf("%%-%ds", padding)
return fmt.Sprintf(template, s) return fmt.Sprintf(template, s)
@ -138,7 +136,7 @@ func tmpl(w io.Writer, text string, data interface{}) error {
return t.Execute(w, data) return t.Execute(w, data)
} }
// ld compares two strings and returns the levenshtein distance between them // ld compares two strings and returns the levenshtein distance between them.
func ld(s, t string, ignoreCase bool) int { func ld(s, t string, ignoreCase bool) int {
if ignoreCase { if ignoreCase {
s = strings.ToLower(s) s = strings.ToLower(s)

View File

@ -140,17 +140,17 @@ func (c *Command) SetOutput(output io.Writer) {
c.output = &output c.output = &output
} }
// Usage can be defined by application // Usage can be defined by application.
func (c *Command) SetUsageFunc(f func(*Command) error) { func (c *Command) SetUsageFunc(f func(*Command) error) {
c.usageFunc = f c.usageFunc = f
} }
// Can be defined by Application // Can be defined by Application.
func (c *Command) SetUsageTemplate(s string) { func (c *Command) SetUsageTemplate(s string) {
c.usageTemplate = s c.usageTemplate = s
} }
// Can be defined by Application // Can be defined by Application.
func (c *Command) SetHelpFunc(f func(*Command, []string)) { func (c *Command) SetHelpFunc(f func(*Command, []string)) {
c.helpFunc = f c.helpFunc = f
} }
@ -159,7 +159,7 @@ func (c *Command) SetHelpCommand(cmd *Command) {
c.helpCommand = cmd c.helpCommand = cmd
} }
// Can be defined by Application // Can be defined by Application.
func (c *Command) SetHelpTemplate(s string) { func (c *Command) SetHelpTemplate(s string) {
c.helpTemplate = s c.helpTemplate = s
} }
@ -195,7 +195,7 @@ func (c *Command) getOut(def io.Writer) io.Writer {
} }
// UsageFunc returns either the function set by SetUsageFunc for this command // UsageFunc returns either the function set by SetUsageFunc for this command
// or a parent, or it returns a default usage function // or a parent, or it returns a default usage function.
func (c *Command) UsageFunc() (f func(*Command) error) { func (c *Command) UsageFunc() (f func(*Command) error) {
if c.usageFunc != nil { if c.usageFunc != nil {
return c.usageFunc return c.usageFunc
@ -214,15 +214,15 @@ func (c *Command) UsageFunc() (f func(*Command) error) {
} }
} }
// Output the usage for the command // Usage puts out the usage for the command.
// Used when a user provides invalid input // Used when a user provides invalid input.
// Can be defined by user by overriding UsageFunc // Can be defined by user by overriding UsageFunc.
func (c *Command) Usage() error { func (c *Command) Usage() error {
return c.UsageFunc()(c) return c.UsageFunc()(c)
} }
// HelpFunc returns either the function set by SetHelpFunc for this command // HelpFunc returns either the function set by SetHelpFunc for this command
// or a parent, or it returns a function with default help behavior // or a parent, or it returns a function with default help behavior.
func (c *Command) HelpFunc() func(*Command, []string) { func (c *Command) HelpFunc() func(*Command, []string) {
cmd := c cmd := c
for cmd != nil { for cmd != nil {
@ -240,9 +240,9 @@ func (c *Command) HelpFunc() func(*Command, []string) {
} }
} }
// Output the help for the command // Help puts out the help for the command.
// Used when a user calls help [command] // Used when a user calls help [command].
// Can be defined by user by overriding HelpFunc // Can be defined by user by overriding HelpFunc.
func (c *Command) Help() error { func (c *Command) Help() error {
c.HelpFunc()(c, []string{}) c.HelpFunc()(c, []string{})
return nil return nil
@ -333,7 +333,7 @@ func (c *Command) HelpTemplate() string {
{{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}` {{end}}{{if or .Runnable .HasSubCommands}}{{.UsageString}}{{end}}`
} }
// Really only used when casting a command to a commander // Really only used when casting a command to a commander.
func (c *Command) resetChildrensParents() { func (c *Command) resetChildrensParents() {
for _, x := range c.commands { for _, x := range c.commands {
x.parent = c x.parent = c
@ -745,13 +745,13 @@ func (c *Command) initHelpCmd() {
c.AddCommand(c.helpCommand) c.AddCommand(c.helpCommand)
} }
// Used for testing // Used for testing.
func (c *Command) ResetCommands() { func (c *Command) ResetCommands() {
c.commands = nil c.commands = nil
c.helpCommand = nil c.helpCommand = nil
} }
// Sorts commands by their names // Sorts commands by their names.
type commandSorterByName []*Command type commandSorterByName []*Command
func (c commandSorterByName) Len() int { return len(c) } func (c commandSorterByName) Len() int { return len(c) }
@ -831,18 +831,18 @@ main:
} }
} }
// Print is a convenience method to Print to the defined output, fallback to Stderr if not set // Print is a convenience method to Print to the defined output, fallback to Stderr if not set.
func (c *Command) Print(i ...interface{}) { func (c *Command) Print(i ...interface{}) {
fmt.Fprint(c.OutOrStderr(), i...) fmt.Fprint(c.OutOrStderr(), i...)
} }
// Println is a convenience method to Println to the defined output, fallback to Stderr if not set // Println is a convenience method to Println to the defined output, fallback to Stderr if not set.
func (c *Command) Println(i ...interface{}) { func (c *Command) Println(i ...interface{}) {
str := fmt.Sprintln(i...) str := fmt.Sprintln(i...)
c.Print(str) c.Print(str)
} }
// Printf is a convenience method to Printf to the defined output, fallback to Stderr if not set // Printf is a convenience method to Printf to the defined output, fallback to Stderr if not set.
func (c *Command) Printf(format string, i ...interface{}) { func (c *Command) Printf(format string, i ...interface{}) {
str := fmt.Sprintf(format, i...) str := fmt.Sprintf(format, i...)
c.Print(str) c.Print(str)
@ -859,7 +859,7 @@ func (c *Command) CommandPath() string {
return str return str
} }
//The full usage for a given command (including parents) // UseLine puts out the full usage for a given command (including parents).
func (c *Command) UseLine() string { func (c *Command) UseLine() string {
str := "" str := ""
if c.HasParent() { if c.HasParent() {
@ -869,7 +869,7 @@ func (c *Command) UseLine() string {
} }
// For use in determining which flags have been assigned to which commands // For use in determining which flags have been assigned to which commands
// and which persist // and which persist.
func (c *Command) DebugFlags() { func (c *Command) DebugFlags() {
c.Println("DebugFlags called on", c.Name()) c.Println("DebugFlags called on", c.Name())
var debugflags func(*Command) var debugflags func(*Command)
@ -944,18 +944,18 @@ func (c *Command) HasExample() bool {
return len(c.Example) > 0 return len(c.Example) > 0
} }
// Runnable determines if the command is itself runnable // Runnable determines if the command is itself runnable.
func (c *Command) Runnable() bool { func (c *Command) Runnable() bool {
return c.Run != nil || c.RunE != nil return c.Run != nil || c.RunE != nil
} }
// HasSubCommands determines if the command has children commands // HasSubCommands determines if the command has children commands.
func (c *Command) HasSubCommands() bool { func (c *Command) HasSubCommands() bool {
return len(c.commands) > 0 return len(c.commands) > 0
} }
// IsAvailableCommand determines if a command is available as a non-help command // IsAvailableCommand determines if a command is available as a non-help command
// (this includes all non deprecated/hidden commands) // (this includes all non deprecated/hidden commands).
func (c *Command) IsAvailableCommand() bool { func (c *Command) IsAvailableCommand() bool {
if len(c.Deprecated) != 0 || c.Hidden { if len(c.Deprecated) != 0 || c.Hidden {
return false return false
@ -974,7 +974,7 @@ func (c *Command) IsAvailableCommand() bool {
// IsHelpCommand determines if a command is a 'help' command; a help command is // IsHelpCommand determines if a command is a 'help' command; a help command is
// determined by the fact that it is NOT runnable/hidden/deprecated, and has no // determined by the fact that it is NOT runnable/hidden/deprecated, and has no
// sub commands that are runnable/hidden/deprecated // sub commands that are runnable/hidden/deprecated.
func (c *Command) IsHelpCommand() bool { func (c *Command) IsHelpCommand() bool {
// if a command is runnable, deprecated, or hidden it is not a 'help' command // if a command is runnable, deprecated, or hidden it is not a 'help' command
@ -995,7 +995,7 @@ func (c *Command) IsHelpCommand() bool {
// HasHelpSubCommands determines if a command has any available 'help' sub commands // HasHelpSubCommands determines if a command has any available 'help' sub commands
// that need to be shown in the usage/help default template under 'additional help // that need to be shown in the usage/help default template under 'additional help
// topics' // topics'.
func (c *Command) HasHelpSubCommands() bool { func (c *Command) HasHelpSubCommands() bool {
// return true on the first found available 'help' sub command // return true on the first found available 'help' sub command
@ -1010,7 +1010,7 @@ func (c *Command) HasHelpSubCommands() bool {
} }
// HasAvailableSubCommands determines if a command has available sub commands that // HasAvailableSubCommands determines if a command has available sub commands that
// need to be shown in the usage/help default template under 'available commands' // need to be shown in the usage/help default template under 'available commands'.
func (c *Command) HasAvailableSubCommands() bool { func (c *Command) HasAvailableSubCommands() bool {
// return true on the first found available (non deprecated/help/hidden) // return true on the first found available (non deprecated/help/hidden)
@ -1026,17 +1026,18 @@ func (c *Command) HasAvailableSubCommands() bool {
return false return false
} }
// Determine if the command is a child command // HasParent determines if the command is a child command.
func (c *Command) HasParent() bool { func (c *Command) HasParent() bool {
return c.parent != nil return c.parent != nil
} }
// GlobalNormalizationFunc returns the global normalization function or nil if doesn't exists // GlobalNormalizationFunc returns the global normalization function or nil if doesn't exists.
func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) flag.NormalizedName { func (c *Command) GlobalNormalizationFunc() func(f *flag.FlagSet, name string) flag.NormalizedName {
return c.globNormFunc return c.globNormFunc
} }
// Get the complete FlagSet that applies to this command (local and persistent declared here and by all parents) // Flage returns the complete FlagSet that applies
// to this command (local and persistent declared here and by all parents).
func (c *Command) Flags() *flag.FlagSet { func (c *Command) Flags() *flag.FlagSet {
if c.flags == nil { if c.flags == nil {
c.flags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) c.flags = flag.NewFlagSet(c.Name(), flag.ContinueOnError)
@ -1048,7 +1049,7 @@ func (c *Command) Flags() *flag.FlagSet {
return c.flags return c.flags
} }
// LocalNonPersistentFlags are flags specific to this command which will NOT persist to subcommands // LocalNonPersistentFlags are flags specific to this command which will NOT persist to subcommands.
func (c *Command) LocalNonPersistentFlags() *flag.FlagSet { func (c *Command) LocalNonPersistentFlags() *flag.FlagSet {
persistentFlags := c.PersistentFlags() persistentFlags := c.PersistentFlags()
@ -1061,7 +1062,7 @@ func (c *Command) LocalNonPersistentFlags() *flag.FlagSet {
return out return out
} }
// Get the local FlagSet specifically set in the current command // LocalFlags returns the local FlagSet specifically set in the current command.
func (c *Command) LocalFlags() *flag.FlagSet { func (c *Command) LocalFlags() *flag.FlagSet {
c.mergePersistentFlags() c.mergePersistentFlags()
@ -1079,7 +1080,7 @@ func (c *Command) LocalFlags() *flag.FlagSet {
return local return local
} }
// All Flags which were inherited from parents commands // InheritedFlags returns all flags which were inherited from parents commands.
func (c *Command) InheritedFlags() *flag.FlagSet { func (c *Command) InheritedFlags() *flag.FlagSet {
c.mergePersistentFlags() c.mergePersistentFlags()
@ -1108,12 +1109,12 @@ func (c *Command) InheritedFlags() *flag.FlagSet {
return inherited return inherited
} }
// All Flags which were not inherited from parent commands // NonInheritedFlags returns all flags which were not inherited from parent commands.
func (c *Command) NonInheritedFlags() *flag.FlagSet { func (c *Command) NonInheritedFlags() *flag.FlagSet {
return c.LocalFlags() return c.LocalFlags()
} }
// Get the Persistent FlagSet specifically set in the current command // PersistentFlags returns the persistent FlagSet specifically set in the current command.
func (c *Command) PersistentFlags() *flag.FlagSet { func (c *Command) PersistentFlags() *flag.FlagSet {
if c.pflags == nil { if c.pflags == nil {
c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError) c.pflags = flag.NewFlagSet(c.Name(), flag.ContinueOnError)
@ -1125,7 +1126,7 @@ func (c *Command) PersistentFlags() *flag.FlagSet {
return c.pflags return c.pflags
} }
// For use in testing // ResetFlags is used in testing.
func (c *Command) ResetFlags() { func (c *Command) ResetFlags() {
c.flagErrorBuf = new(bytes.Buffer) c.flagErrorBuf = new(bytes.Buffer)
c.flagErrorBuf.Reset() c.flagErrorBuf.Reset()
@ -1135,50 +1136,50 @@ func (c *Command) ResetFlags() {
c.pflags.SetOutput(c.flagErrorBuf) c.pflags.SetOutput(c.flagErrorBuf)
} }
// Does the command contain any flags (local plus persistent from the entire structure) // Does the command contain any flags (local plus persistent from the entire structure).
func (c *Command) HasFlags() bool { func (c *Command) HasFlags() bool {
return c.Flags().HasFlags() return c.Flags().HasFlags()
} }
// Does the command contain persistent flags // Does the command contain persistent flags.
func (c *Command) HasPersistentFlags() bool { func (c *Command) HasPersistentFlags() bool {
return c.PersistentFlags().HasFlags() return c.PersistentFlags().HasFlags()
} }
// Does the command has flags specifically declared locally // Does the command has flags specifically declared locally.
func (c *Command) HasLocalFlags() bool { func (c *Command) HasLocalFlags() bool {
return c.LocalFlags().HasFlags() return c.LocalFlags().HasFlags()
} }
// Does the command have flags inherited from its parent command // Does the command have flags inherited from its parent command.
func (c *Command) HasInheritedFlags() bool { func (c *Command) HasInheritedFlags() bool {
return c.InheritedFlags().HasFlags() return c.InheritedFlags().HasFlags()
} }
// Does the command contain any flags (local plus persistent from the entire // Does the command contain any flags (local plus persistent from the entire
// structure) which are not hidden or deprecated // structure) which are not hidden or deprecated.
func (c *Command) HasAvailableFlags() bool { func (c *Command) HasAvailableFlags() bool {
return c.Flags().HasAvailableFlags() return c.Flags().HasAvailableFlags()
} }
// Does the command contain persistent flags which are not hidden or deprecated // Does the command contain persistent flags which are not hidden or deprecated.
func (c *Command) HasAvailablePersistentFlags() bool { func (c *Command) HasAvailablePersistentFlags() bool {
return c.PersistentFlags().HasAvailableFlags() return c.PersistentFlags().HasAvailableFlags()
} }
// Does the command has flags specifically declared locally which are not hidden // Does the command has flags specifically declared locally which are not hidden
// or deprecated // or deprecated.
func (c *Command) HasAvailableLocalFlags() bool { func (c *Command) HasAvailableLocalFlags() bool {
return c.LocalFlags().HasAvailableFlags() return c.LocalFlags().HasAvailableFlags()
} }
// Does the command have flags inherited from its parent command which are // Does the command have flags inherited from its parent command which are
// not hidden or deprecated // not hidden or deprecated.
func (c *Command) HasAvailableInheritedFlags() bool { func (c *Command) HasAvailableInheritedFlags() bool {
return c.InheritedFlags().HasAvailableFlags() return c.InheritedFlags().HasAvailableFlags()
} }
// Flag climbs up the command tree looking for matching flag // Flag climbs up the command tree looking for matching flag.
func (c *Command) Flag(name string) (flag *flag.Flag) { func (c *Command) Flag(name string) (flag *flag.Flag) {
flag = c.Flags().Lookup(name) flag = c.Flags().Lookup(name)
@ -1189,7 +1190,7 @@ func (c *Command) Flag(name string) (flag *flag.Flag) {
return return
} }
// recursively find matching persistent flag // Recursively find matching persistent flag.
func (c *Command) persistentFlag(name string) (flag *flag.Flag) { func (c *Command) persistentFlag(name string) (flag *flag.Flag) {
if c.HasPersistentFlags() { if c.HasPersistentFlags() {
flag = c.PersistentFlags().Lookup(name) flag = c.PersistentFlags().Lookup(name)
@ -1201,7 +1202,7 @@ func (c *Command) persistentFlag(name string) (flag *flag.Flag) {
return return
} }
// ParseFlags parses persistent flag tree & local flags // ParseFlags parses persistent flag tree and local flags.
func (c *Command) ParseFlags(args []string) (err error) { func (c *Command) ParseFlags(args []string) (err error) {
if c.DisableFlagParsing { if c.DisableFlagParsing {
return nil return nil
@ -1211,7 +1212,7 @@ func (c *Command) ParseFlags(args []string) (err error) {
return return
} }
// Parent returns a commands parent command // Parent returns a commands parent command.
func (c *Command) Parent() *Command { func (c *Command) Parent() *Command {
return c.parent return c.parent
} }

View File

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// optional interface to indicate boolean flags that can be // optional interface to indicate boolean flags that can be
// supplied without "=value" text // supplied without "=value" text
@ -30,7 +27,7 @@ func (b *boolValue) Type() string {
return "bool" return "bool"
} }
func (b *boolValue) String() string { return fmt.Sprintf("%v", *b) } func (b *boolValue) String() string { return strconv.FormatBool(bool(*b)) }
func (b *boolValue) IsBoolFlag() bool { return true } func (b *boolValue) IsBoolFlag() bool { return true }

View File

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- count Value // -- count Value
type countValue int type countValue int
@ -28,7 +25,7 @@ func (i *countValue) Type() string {
return "count" return "count"
} }
func (i *countValue) String() string { return fmt.Sprintf("%v", *i) } func (i *countValue) String() string { return strconv.Itoa(int(*i)) }
func countConv(sval string) (interface{}, error) { func countConv(sval string) (interface{}, error) {
i, err := strconv.Atoi(sval) i, err := strconv.Atoi(sval)

View File

@ -434,10 +434,20 @@ func (f *Flag) defaultIsZeroValue() bool {
return f.DefValue == "" return f.DefValue == ""
case *ipValue, *ipMaskValue, *ipNetValue: case *ipValue, *ipMaskValue, *ipNetValue:
return f.DefValue == "<nil>" return f.DefValue == "<nil>"
case *intSliceValue, *stringSliceValue: case *intSliceValue, *stringSliceValue, *stringArrayValue:
return f.DefValue == "[]" return f.DefValue == "[]"
default: default:
switch f.Value.String() {
case "false":
return true return true
case "<nil>":
return true
case "":
return true
case "0":
return true
}
return false
} }
} }

View File

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- float32 Value // -- float32 Value
type float32Value float32 type float32Value float32
@ -23,7 +20,7 @@ func (f *float32Value) Type() string {
return "float32" return "float32"
} }
func (f *float32Value) String() string { return fmt.Sprintf("%v", *f) } func (f *float32Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 32) }
func float32Conv(sval string) (interface{}, error) { func float32Conv(sval string) (interface{}, error) {
v, err := strconv.ParseFloat(sval, 32) v, err := strconv.ParseFloat(sval, 32)

View File

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- float64 Value // -- float64 Value
type float64Value float64 type float64Value float64
@ -23,7 +20,7 @@ func (f *float64Value) Type() string {
return "float64" return "float64"
} }
func (f *float64Value) String() string { return fmt.Sprintf("%v", *f) } func (f *float64Value) String() string { return strconv.FormatFloat(float64(*f), 'g', -1, 64) }
func float64Conv(sval string) (interface{}, error) { func float64Conv(sval string) (interface{}, error) {
return strconv.ParseFloat(sval, 64) return strconv.ParseFloat(sval, 64)

View File

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- int Value // -- int Value
type intValue int type intValue int
@ -23,7 +20,7 @@ func (i *intValue) Type() string {
return "int" return "int"
} }
func (i *intValue) String() string { return fmt.Sprintf("%v", *i) } func (i *intValue) String() string { return strconv.Itoa(int(*i)) }
func intConv(sval string) (interface{}, error) { func intConv(sval string) (interface{}, error) {
return strconv.Atoi(sval) return strconv.Atoi(sval)

View File

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- int32 Value // -- int32 Value
type int32Value int32 type int32Value int32
@ -23,7 +20,7 @@ func (i *int32Value) Type() string {
return "int32" return "int32"
} }
func (i *int32Value) String() string { return fmt.Sprintf("%v", *i) } func (i *int32Value) String() string { return strconv.FormatInt(int64(*i), 10) }
func int32Conv(sval string) (interface{}, error) { func int32Conv(sval string) (interface{}, error) {
v, err := strconv.ParseInt(sval, 0, 32) v, err := strconv.ParseInt(sval, 0, 32)

View File

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- int64 Value // -- int64 Value
type int64Value int64 type int64Value int64
@ -23,7 +20,7 @@ func (i *int64Value) Type() string {
return "int64" return "int64"
} }
func (i *int64Value) String() string { return fmt.Sprintf("%v", *i) } func (i *int64Value) String() string { return strconv.FormatInt(int64(*i), 10) }
func int64Conv(sval string) (interface{}, error) { func int64Conv(sval string) (interface{}, error) {
return strconv.ParseInt(sval, 0, 64) return strconv.ParseInt(sval, 0, 64)

View File

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- int8 Value // -- int8 Value
type int8Value int8 type int8Value int8
@ -23,7 +20,7 @@ func (i *int8Value) Type() string {
return "int8" return "int8"
} }
func (i *int8Value) String() string { return fmt.Sprintf("%v", *i) } func (i *int8Value) String() string { return strconv.FormatInt(int64(*i), 10) }
func int8Conv(sval string) (interface{}, error) { func int8Conv(sval string) (interface{}, error) {
v, err := strconv.ParseInt(sval, 0, 8) v, err := strconv.ParseInt(sval, 0, 8)

View File

@ -1,7 +1,5 @@
package pflag package pflag
import "fmt"
// -- string Value // -- string Value
type stringValue string type stringValue string
@ -18,7 +16,7 @@ func (s *stringValue) Type() string {
return "string" return "string"
} }
func (s *stringValue) String() string { return fmt.Sprintf("%s", *s) } func (s *stringValue) String() string { return string(*s) }
func stringConv(sval string) (interface{}, error) { func stringConv(sval string) (interface{}, error) {
return sval, nil return sval, nil

110
vendor/github.com/spf13/pflag/string_array.go generated vendored Normal file
View File

@ -0,0 +1,110 @@
package pflag
import (
"fmt"
"strings"
)
var _ = fmt.Fprint
// -- stringArray Value
type stringArrayValue struct {
value *[]string
changed bool
}
func newStringArrayValue(val []string, p *[]string) *stringArrayValue {
ssv := new(stringArrayValue)
ssv.value = p
*ssv.value = val
return ssv
}
func (s *stringArrayValue) Set(val string) error {
if !s.changed {
*s.value = []string{val}
s.changed = true
} else {
*s.value = append(*s.value, val)
}
return nil
}
func (s *stringArrayValue) Type() string {
return "stringArray"
}
func (s *stringArrayValue) String() string {
str, _ := writeAsCSV(*s.value)
return "[" + str + "]"
}
func stringArrayConv(sval string) (interface{}, error) {
sval = strings.Trim(sval, "[]")
// An empty string would cause a array with one (empty) string
if len(sval) == 0 {
return []string{}, nil
}
return readAsCSV(sval)
}
// GetStringArray return the []string value of a flag with the given name
func (f *FlagSet) GetStringArray(name string) ([]string, error) {
val, err := f.getFlagType(name, "stringArray", stringArrayConv)
if err != nil {
return []string{}, err
}
return val.([]string), nil
}
// StringArrayVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a []string variable in which to store the values of the multiple flags.
// The value of each argument will not try to be separated by comma
func (f *FlagSet) StringArrayVar(p *[]string, name string, value []string, usage string) {
f.VarP(newStringArrayValue(value, p), name, "", usage)
}
// StringArrayVarP is like StringArrayVar, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) StringArrayVarP(p *[]string, name, shorthand string, value []string, usage string) {
f.VarP(newStringArrayValue(value, p), name, shorthand, usage)
}
// StringArrayVar defines a string flag with specified name, default value, and usage string.
// The argument p points to a []string variable in which to store the value of the flag.
// The value of each argument will not try to be separated by comma
func StringArrayVar(p *[]string, name string, value []string, usage string) {
CommandLine.VarP(newStringArrayValue(value, p), name, "", usage)
}
// StringArrayVarP is like StringArrayVar, but accepts a shorthand letter that can be used after a single dash.
func StringArrayVarP(p *[]string, name, shorthand string, value []string, usage string) {
CommandLine.VarP(newStringArrayValue(value, p), name, shorthand, usage)
}
// StringArray defines a string flag with specified name, default value, and usage string.
// The return value is the address of a []string variable that stores the value of the flag.
// The value of each argument will not try to be separated by comma
func (f *FlagSet) StringArray(name string, value []string, usage string) *[]string {
p := []string{}
f.StringArrayVarP(&p, name, "", value, usage)
return &p
}
// StringArrayP is like StringArray, but accepts a shorthand letter that can be used after a single dash.
func (f *FlagSet) StringArrayP(name, shorthand string, value []string, usage string) *[]string {
p := []string{}
f.StringArrayVarP(&p, name, shorthand, value, usage)
return &p
}
// StringArray defines a string flag with specified name, default value, and usage string.
// The return value is the address of a []string variable that stores the value of the flag.
// The value of each argument will not try to be separated by comma
func StringArray(name string, value []string, usage string) *[]string {
return CommandLine.StringArrayP(name, "", value, usage)
}
// StringArrayP is like StringArray, but accepts a shorthand letter that can be used after a single dash.
func StringArrayP(name, shorthand string, value []string, usage string) *[]string {
return CommandLine.StringArrayP(name, shorthand, value, usage)
}

View File

@ -31,6 +31,17 @@ func readAsCSV(val string) ([]string, error) {
return csvReader.Read() return csvReader.Read()
} }
func writeAsCSV(vals []string) (string, error) {
b := &bytes.Buffer{}
w := csv.NewWriter(b)
err := w.Write(vals)
if err != nil {
return "", err
}
w.Flush()
return strings.TrimSuffix(b.String(), fmt.Sprintln()), nil
}
func (s *stringSliceValue) Set(val string) error { func (s *stringSliceValue) Set(val string) error {
v, err := readAsCSV(val) v, err := readAsCSV(val)
if err != nil { if err != nil {
@ -50,11 +61,8 @@ func (s *stringSliceValue) Type() string {
} }
func (s *stringSliceValue) String() string { func (s *stringSliceValue) String() string {
b := &bytes.Buffer{} str, _ := writeAsCSV(*s.value)
w := csv.NewWriter(b) return "[" + str + "]"
w.Write(*s.value)
w.Flush()
return "[" + strings.TrimSuffix(b.String(), fmt.Sprintln()) + "]"
} }
func stringSliceConv(sval string) (interface{}, error) { func stringSliceConv(sval string) (interface{}, error) {

View File

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- uint Value // -- uint Value
type uintValue uint type uintValue uint
@ -23,7 +20,7 @@ func (i *uintValue) Type() string {
return "uint" return "uint"
} }
func (i *uintValue) String() string { return fmt.Sprintf("%v", *i) } func (i *uintValue) String() string { return strconv.FormatUint(uint64(*i), 10) }
func uintConv(sval string) (interface{}, error) { func uintConv(sval string) (interface{}, error) {
v, err := strconv.ParseUint(sval, 0, 0) v, err := strconv.ParseUint(sval, 0, 0)

View File

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- uint16 value // -- uint16 value
type uint16Value uint16 type uint16Value uint16
@ -12,7 +9,7 @@ func newUint16Value(val uint16, p *uint16) *uint16Value {
*p = val *p = val
return (*uint16Value)(p) return (*uint16Value)(p)
} }
func (i *uint16Value) String() string { return fmt.Sprintf("%d", *i) }
func (i *uint16Value) Set(s string) error { func (i *uint16Value) Set(s string) error {
v, err := strconv.ParseUint(s, 0, 16) v, err := strconv.ParseUint(s, 0, 16)
*i = uint16Value(v) *i = uint16Value(v)
@ -23,6 +20,8 @@ func (i *uint16Value) Type() string {
return "uint16" return "uint16"
} }
func (i *uint16Value) String() string { return strconv.FormatUint(uint64(*i), 10) }
func uint16Conv(sval string) (interface{}, error) { func uint16Conv(sval string) (interface{}, error) {
v, err := strconv.ParseUint(sval, 0, 16) v, err := strconv.ParseUint(sval, 0, 16)
if err != nil { if err != nil {

View File

@ -1,18 +1,15 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- uint16 value // -- uint32 value
type uint32Value uint32 type uint32Value uint32
func newUint32Value(val uint32, p *uint32) *uint32Value { func newUint32Value(val uint32, p *uint32) *uint32Value {
*p = val *p = val
return (*uint32Value)(p) return (*uint32Value)(p)
} }
func (i *uint32Value) String() string { return fmt.Sprintf("%d", *i) }
func (i *uint32Value) Set(s string) error { func (i *uint32Value) Set(s string) error {
v, err := strconv.ParseUint(s, 0, 32) v, err := strconv.ParseUint(s, 0, 32)
*i = uint32Value(v) *i = uint32Value(v)
@ -23,6 +20,8 @@ func (i *uint32Value) Type() string {
return "uint32" return "uint32"
} }
func (i *uint32Value) String() string { return strconv.FormatUint(uint64(*i), 10) }
func uint32Conv(sval string) (interface{}, error) { func uint32Conv(sval string) (interface{}, error) {
v, err := strconv.ParseUint(sval, 0, 32) v, err := strconv.ParseUint(sval, 0, 32)
if err != nil { if err != nil {

View File

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- uint64 Value // -- uint64 Value
type uint64Value uint64 type uint64Value uint64
@ -23,7 +20,7 @@ func (i *uint64Value) Type() string {
return "uint64" return "uint64"
} }
func (i *uint64Value) String() string { return fmt.Sprintf("%v", *i) } func (i *uint64Value) String() string { return strconv.FormatUint(uint64(*i), 10) }
func uint64Conv(sval string) (interface{}, error) { func uint64Conv(sval string) (interface{}, error) {
v, err := strconv.ParseUint(sval, 0, 64) v, err := strconv.ParseUint(sval, 0, 64)

View File

@ -1,9 +1,6 @@
package pflag package pflag
import ( import "strconv"
"fmt"
"strconv"
)
// -- uint8 Value // -- uint8 Value
type uint8Value uint8 type uint8Value uint8
@ -23,7 +20,7 @@ func (i *uint8Value) Type() string {
return "uint8" return "uint8"
} }
func (i *uint8Value) String() string { return fmt.Sprintf("%v", *i) } func (i *uint8Value) String() string { return strconv.FormatUint(uint64(*i), 10) }
func uint8Conv(sval string) (interface{}, error) { func uint8Conv(sval string) (interface{}, error) {
v, err := strconv.ParseUint(sval, 0, 8) v, err := strconv.ParseUint(sval, 0, 8)

View File

@ -53,7 +53,7 @@ import (
const ( const (
// The primary user agent // The primary user agent
primaryUA = "grpc-go/1.0" primaryUA = "grpc-go/0.11"
// http2MaxFrameLen specifies the max length of a HTTP2 frame. // http2MaxFrameLen specifies the max length of a HTTP2 frame.
http2MaxFrameLen = 16384 // 16KB frame http2MaxFrameLen = 16384 // 16KB frame
// http://http2.github.io/http2-spec/#SettingValues // http://http2.github.io/http2-spec/#SettingValues