Moved to google.golang.org/genproto/googleapis/api/annotations
Fixes #52
This commit is contained in:
273
vendor/github.com/go-kit/kit/sd/zk/client.go
generated
vendored
Normal file
273
vendor/github.com/go-kit/kit/sd/zk/client.go
generated
vendored
Normal file
@@ -0,0 +1,273 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/samuel/go-zookeeper/zk"
|
||||
|
||||
"github.com/go-kit/kit/log"
|
||||
)
|
||||
|
||||
// DefaultACL is the default ACL to use for creating znodes.
|
||||
var (
|
||||
DefaultACL = zk.WorldACL(zk.PermAll)
|
||||
ErrInvalidCredentials = errors.New("invalid credentials provided")
|
||||
ErrClientClosed = errors.New("client service closed")
|
||||
ErrNotRegistered = errors.New("not registered")
|
||||
ErrNodeNotFound = errors.New("node not found")
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultConnectTimeout is the default timeout to establish a connection to
|
||||
// a ZooKeeper node.
|
||||
DefaultConnectTimeout = 2 * time.Second
|
||||
// DefaultSessionTimeout is the default timeout to keep the current
|
||||
// ZooKeeper session alive during a temporary disconnect.
|
||||
DefaultSessionTimeout = 5 * time.Second
|
||||
)
|
||||
|
||||
// Client is a wrapper around a lower level ZooKeeper client implementation.
|
||||
type Client interface {
|
||||
// GetEntries should query the provided path in ZooKeeper, place a watch on
|
||||
// it and retrieve data from its current child nodes.
|
||||
GetEntries(path string) ([]string, <-chan zk.Event, error)
|
||||
// CreateParentNodes should try to create the path in case it does not exist
|
||||
// yet on ZooKeeper.
|
||||
CreateParentNodes(path string) error
|
||||
// Register a service with ZooKeeper.
|
||||
Register(s *Service) error
|
||||
// Deregister a service with ZooKeeper.
|
||||
Deregister(s *Service) error
|
||||
// Stop should properly shutdown the client implementation
|
||||
Stop()
|
||||
}
|
||||
|
||||
type clientConfig struct {
|
||||
logger log.Logger
|
||||
acl []zk.ACL
|
||||
credentials []byte
|
||||
connectTimeout time.Duration
|
||||
sessionTimeout time.Duration
|
||||
rootNodePayload [][]byte
|
||||
eventHandler func(zk.Event)
|
||||
}
|
||||
|
||||
// Option functions enable friendly APIs.
|
||||
type Option func(*clientConfig) error
|
||||
|
||||
type client struct {
|
||||
*zk.Conn
|
||||
clientConfig
|
||||
active bool
|
||||
quit chan struct{}
|
||||
}
|
||||
|
||||
// ACL returns an Option specifying a non-default ACL for creating parent nodes.
|
||||
func ACL(acl []zk.ACL) Option {
|
||||
return func(c *clientConfig) error {
|
||||
c.acl = acl
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Credentials returns an Option specifying a user/password combination which
|
||||
// the client will use to authenticate itself with.
|
||||
func Credentials(user, pass string) Option {
|
||||
return func(c *clientConfig) error {
|
||||
if user == "" || pass == "" {
|
||||
return ErrInvalidCredentials
|
||||
}
|
||||
c.credentials = []byte(user + ":" + pass)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// ConnectTimeout returns an Option specifying a non-default connection timeout
|
||||
// when we try to establish a connection to a ZooKeeper server.
|
||||
func ConnectTimeout(t time.Duration) Option {
|
||||
return func(c *clientConfig) error {
|
||||
if t.Seconds() < 1 {
|
||||
return errors.New("invalid connect timeout (minimum value is 1 second)")
|
||||
}
|
||||
c.connectTimeout = t
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// SessionTimeout returns an Option specifying a non-default session timeout.
|
||||
func SessionTimeout(t time.Duration) Option {
|
||||
return func(c *clientConfig) error {
|
||||
if t.Seconds() < 1 {
|
||||
return errors.New("invalid session timeout (minimum value is 1 second)")
|
||||
}
|
||||
c.sessionTimeout = t
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// Payload returns an Option specifying non-default data values for each znode
|
||||
// created by CreateParentNodes.
|
||||
func Payload(payload [][]byte) Option {
|
||||
return func(c *clientConfig) error {
|
||||
c.rootNodePayload = payload
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// EventHandler returns an Option specifying a callback function to handle
|
||||
// incoming zk.Event payloads (ZooKeeper connection events).
|
||||
func EventHandler(handler func(zk.Event)) Option {
|
||||
return func(c *clientConfig) error {
|
||||
c.eventHandler = handler
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// NewClient returns a ZooKeeper client with a connection to the server cluster.
|
||||
// It will return an error if the server cluster cannot be resolved.
|
||||
func NewClient(servers []string, logger log.Logger, options ...Option) (Client, error) {
|
||||
defaultEventHandler := func(event zk.Event) {
|
||||
logger.Log("eventtype", event.Type.String(), "server", event.Server, "state", event.State.String(), "err", event.Err)
|
||||
}
|
||||
config := clientConfig{
|
||||
acl: DefaultACL,
|
||||
connectTimeout: DefaultConnectTimeout,
|
||||
sessionTimeout: DefaultSessionTimeout,
|
||||
eventHandler: defaultEventHandler,
|
||||
logger: logger,
|
||||
}
|
||||
for _, option := range options {
|
||||
if err := option(&config); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
// dialer overrides the default ZooKeeper library Dialer so we can configure
|
||||
// the connectTimeout. The current library has a hardcoded value of 1 second
|
||||
// and there are reports of race conditions, due to slow DNS resolvers and
|
||||
// other network latency issues.
|
||||
dialer := func(network, address string, _ time.Duration) (net.Conn, error) {
|
||||
return net.DialTimeout(network, address, config.connectTimeout)
|
||||
}
|
||||
conn, eventc, err := zk.Connect(servers, config.sessionTimeout, withLogger(logger), zk.WithDialer(dialer))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(config.credentials) > 0 {
|
||||
err = conn.AddAuth("digest", config.credentials)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
c := &client{conn, config, true, make(chan struct{})}
|
||||
|
||||
// Start listening for incoming Event payloads and callback the set
|
||||
// eventHandler.
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case event := <-eventc:
|
||||
config.eventHandler(event)
|
||||
case <-c.quit:
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// CreateParentNodes implements the ZooKeeper Client interface.
|
||||
func (c *client) CreateParentNodes(path string) error {
|
||||
if !c.active {
|
||||
return ErrClientClosed
|
||||
}
|
||||
if path[0] != '/' {
|
||||
return zk.ErrInvalidPath
|
||||
}
|
||||
payload := []byte("")
|
||||
pathString := ""
|
||||
pathNodes := strings.Split(path, "/")
|
||||
for i := 1; i < len(pathNodes); i++ {
|
||||
if i <= len(c.rootNodePayload) {
|
||||
payload = c.rootNodePayload[i-1]
|
||||
} else {
|
||||
payload = []byte("")
|
||||
}
|
||||
pathString += "/" + pathNodes[i]
|
||||
_, err := c.Create(pathString, payload, 0, c.acl)
|
||||
// not being able to create the node because it exists or not having
|
||||
// sufficient rights is not an issue. It is ok for the node to already
|
||||
// exist and/or us to only have read rights
|
||||
if err != nil && err != zk.ErrNodeExists && err != zk.ErrNoAuth {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetEntries implements the ZooKeeper Client interface.
|
||||
func (c *client) GetEntries(path string) ([]string, <-chan zk.Event, error) {
|
||||
// retrieve list of child nodes for given path and add watch to path
|
||||
znodes, _, eventc, err := c.ChildrenW(path)
|
||||
|
||||
if err != nil {
|
||||
return nil, eventc, err
|
||||
}
|
||||
|
||||
var resp []string
|
||||
for _, znode := range znodes {
|
||||
// retrieve payload for child znode and add to response array
|
||||
if data, _, err := c.Get(path + "/" + znode); err == nil {
|
||||
resp = append(resp, string(data))
|
||||
}
|
||||
}
|
||||
return resp, eventc, nil
|
||||
}
|
||||
|
||||
// Register implements the ZooKeeper Client interface.
|
||||
func (c *client) Register(s *Service) error {
|
||||
if s.Path[len(s.Path)-1] != '/' {
|
||||
s.Path += "/"
|
||||
}
|
||||
path := s.Path + s.Name
|
||||
if err := c.CreateParentNodes(path); err != nil {
|
||||
return err
|
||||
}
|
||||
node, err := c.CreateProtectedEphemeralSequential(path, s.Data, c.acl)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.node = node
|
||||
return nil
|
||||
}
|
||||
|
||||
// Deregister implements the ZooKeeper Client interface.
|
||||
func (c *client) Deregister(s *Service) error {
|
||||
if s.node == "" {
|
||||
return ErrNotRegistered
|
||||
}
|
||||
path := s.Path + s.Name
|
||||
found, stat, err := c.Exists(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !found {
|
||||
return ErrNodeNotFound
|
||||
}
|
||||
if err := c.Delete(path, stat.Version); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop implements the ZooKeeper Client interface.
|
||||
func (c *client) Stop() {
|
||||
c.active = false
|
||||
close(c.quit)
|
||||
c.Close()
|
||||
}
|
157
vendor/github.com/go-kit/kit/sd/zk/client_test.go
generated
vendored
Normal file
157
vendor/github.com/go-kit/kit/sd/zk/client_test.go
generated
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
stdzk "github.com/samuel/go-zookeeper/zk"
|
||||
|
||||
"github.com/go-kit/kit/log"
|
||||
)
|
||||
|
||||
func TestNewClient(t *testing.T) {
|
||||
var (
|
||||
acl = stdzk.WorldACL(stdzk.PermRead)
|
||||
connectTimeout = 3 * time.Second
|
||||
sessionTimeout = 20 * time.Second
|
||||
payload = [][]byte{[]byte("Payload"), []byte("Test")}
|
||||
)
|
||||
|
||||
c, err := NewClient(
|
||||
[]string{"FailThisInvalidHost!!!"},
|
||||
log.NewNopLogger(),
|
||||
)
|
||||
if err == nil {
|
||||
t.Errorf("expected error, got nil")
|
||||
}
|
||||
|
||||
hasFired := false
|
||||
calledEventHandler := make(chan struct{})
|
||||
eventHandler := func(event stdzk.Event) {
|
||||
if !hasFired {
|
||||
// test is successful if this function has fired at least once
|
||||
hasFired = true
|
||||
close(calledEventHandler)
|
||||
}
|
||||
}
|
||||
|
||||
c, err = NewClient(
|
||||
[]string{"localhost"},
|
||||
log.NewNopLogger(),
|
||||
ACL(acl),
|
||||
ConnectTimeout(connectTimeout),
|
||||
SessionTimeout(sessionTimeout),
|
||||
Payload(payload),
|
||||
EventHandler(eventHandler),
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c.Stop()
|
||||
|
||||
clientImpl, ok := c.(*client)
|
||||
if !ok {
|
||||
t.Fatal("retrieved incorrect Client implementation")
|
||||
}
|
||||
if want, have := acl, clientImpl.acl; want[0] != have[0] {
|
||||
t.Errorf("want %+v, have %+v", want, have)
|
||||
}
|
||||
if want, have := connectTimeout, clientImpl.connectTimeout; want != have {
|
||||
t.Errorf("want %d, have %d", want, have)
|
||||
}
|
||||
if want, have := sessionTimeout, clientImpl.sessionTimeout; want != have {
|
||||
t.Errorf("want %d, have %d", want, have)
|
||||
}
|
||||
if want, have := payload, clientImpl.rootNodePayload; bytes.Compare(want[0], have[0]) != 0 || bytes.Compare(want[1], have[1]) != 0 {
|
||||
t.Errorf("want %s, have %s", want, have)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-calledEventHandler:
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Errorf("event handler never called")
|
||||
}
|
||||
}
|
||||
|
||||
func TestOptions(t *testing.T) {
|
||||
_, err := NewClient([]string{"localhost"}, log.NewNopLogger(), Credentials("valid", "credentials"))
|
||||
if err != nil && err != stdzk.ErrNoServer {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
_, err = NewClient([]string{"localhost"}, log.NewNopLogger(), Credentials("nopass", ""))
|
||||
if want, have := err, ErrInvalidCredentials; want != have {
|
||||
t.Errorf("want %v, have %v", want, have)
|
||||
}
|
||||
|
||||
_, err = NewClient([]string{"localhost"}, log.NewNopLogger(), ConnectTimeout(0))
|
||||
if err == nil {
|
||||
t.Errorf("expected connect timeout error")
|
||||
}
|
||||
|
||||
_, err = NewClient([]string{"localhost"}, log.NewNopLogger(), SessionTimeout(0))
|
||||
if err == nil {
|
||||
t.Errorf("expected connect timeout error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateParentNodes(t *testing.T) {
|
||||
payload := [][]byte{[]byte("Payload"), []byte("Test")}
|
||||
|
||||
c, err := NewClient([]string{"localhost:65500"}, log.NewNopLogger())
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if c == nil {
|
||||
t.Fatal("expected new Client, got nil")
|
||||
}
|
||||
|
||||
s, err := NewSubscriber(c, "/validpath", newFactory(""), log.NewNopLogger())
|
||||
if err != stdzk.ErrNoServer {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if s != nil {
|
||||
t.Error("expected failed new Subscriber")
|
||||
}
|
||||
|
||||
s, err = NewSubscriber(c, "invalidpath", newFactory(""), log.NewNopLogger())
|
||||
if err != stdzk.ErrInvalidPath {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
_, _, err = c.GetEntries("/validpath")
|
||||
if err != stdzk.ErrNoServer {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
c.Stop()
|
||||
|
||||
err = c.CreateParentNodes("/validpath")
|
||||
if err != ErrClientClosed {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
s, err = NewSubscriber(c, "/validpath", newFactory(""), log.NewNopLogger())
|
||||
if err != ErrClientClosed {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if s != nil {
|
||||
t.Error("expected failed new Subscriber")
|
||||
}
|
||||
|
||||
c, err = NewClient([]string{"localhost:65500"}, log.NewNopLogger(), Payload(payload))
|
||||
if err != nil {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if c == nil {
|
||||
t.Fatal("expected new Client, got nil")
|
||||
}
|
||||
|
||||
s, err = NewSubscriber(c, "/validpath", newFactory(""), log.NewNopLogger())
|
||||
if err != stdzk.ErrNoServer {
|
||||
t.Errorf("unexpected error: %v", err)
|
||||
}
|
||||
if s != nil {
|
||||
t.Error("expected failed new Subscriber")
|
||||
}
|
||||
}
|
2
vendor/github.com/go-kit/kit/sd/zk/doc.go
generated
vendored
Normal file
2
vendor/github.com/go-kit/kit/sd/zk/doc.go
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
// Package zk provides subscriber and registrar implementations for ZooKeeper.
|
||||
package zk
|
201
vendor/github.com/go-kit/kit/sd/zk/integration_test.go
generated
vendored
Normal file
201
vendor/github.com/go-kit/kit/sd/zk/integration_test.go
generated
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
// +build integration
|
||||
|
||||
package zk
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
stdzk "github.com/samuel/go-zookeeper/zk"
|
||||
)
|
||||
|
||||
var (
|
||||
host []string
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
zkAddr := os.Getenv("ZK_ADDR")
|
||||
if zkAddr == "" {
|
||||
log.Fatal("ZK_ADDR is not set")
|
||||
}
|
||||
host = []string{zkAddr}
|
||||
}
|
||||
|
||||
func TestCreateParentNodesOnServer(t *testing.T) {
|
||||
payload := [][]byte{[]byte("Payload"), []byte("Test")}
|
||||
c1, err := NewClient(host, logger, Payload(payload))
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %v", err)
|
||||
}
|
||||
if c1 == nil {
|
||||
t.Fatal("Expected pointer to client, got nil")
|
||||
}
|
||||
defer c1.Stop()
|
||||
|
||||
s, err := NewSubscriber(c1, path, newFactory(""), logger)
|
||||
if err != nil {
|
||||
t.Fatalf("Unable to create Subscriber: %v", err)
|
||||
}
|
||||
defer s.Stop()
|
||||
|
||||
services, err := s.Endpoints()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if want, have := 0, len(services); want != have {
|
||||
t.Errorf("want %d, have %d", want, have)
|
||||
}
|
||||
|
||||
c2, err := NewClient(host, logger)
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %v", err)
|
||||
}
|
||||
defer c2.Stop()
|
||||
data, _, err := c2.(*client).Get(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// test Client implementation of CreateParentNodes. It should have created
|
||||
// our payload
|
||||
if bytes.Compare(data, payload[1]) != 0 {
|
||||
t.Errorf("want %s, have %s", payload[1], data)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestCreateBadParentNodesOnServer(t *testing.T) {
|
||||
c, _ := NewClient(host, logger)
|
||||
defer c.Stop()
|
||||
|
||||
_, err := NewSubscriber(c, "invalid/path", newFactory(""), logger)
|
||||
|
||||
if want, have := stdzk.ErrInvalidPath, err; want != have {
|
||||
t.Errorf("want %v, have %v", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCredentials1(t *testing.T) {
|
||||
acl := stdzk.DigestACL(stdzk.PermAll, "user", "secret")
|
||||
c, _ := NewClient(host, logger, ACL(acl), Credentials("user", "secret"))
|
||||
defer c.Stop()
|
||||
|
||||
_, err := NewSubscriber(c, "/acl-issue-test", newFactory(""), logger)
|
||||
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCredentials2(t *testing.T) {
|
||||
acl := stdzk.DigestACL(stdzk.PermAll, "user", "secret")
|
||||
c, _ := NewClient(host, logger, ACL(acl))
|
||||
defer c.Stop()
|
||||
|
||||
_, err := NewSubscriber(c, "/acl-issue-test", newFactory(""), logger)
|
||||
|
||||
if err != stdzk.ErrNoAuth {
|
||||
t.Errorf("want %v, have %v", stdzk.ErrNoAuth, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnection(t *testing.T) {
|
||||
c, _ := NewClient(host, logger)
|
||||
c.Stop()
|
||||
|
||||
_, err := NewSubscriber(c, "/acl-issue-test", newFactory(""), logger)
|
||||
|
||||
if err != ErrClientClosed {
|
||||
t.Errorf("want %v, have %v", ErrClientClosed, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetEntriesOnServer(t *testing.T) {
|
||||
var instancePayload = "10.0.3.204:8002"
|
||||
|
||||
c1, err := NewClient(host, logger)
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %v", err)
|
||||
}
|
||||
|
||||
defer c1.Stop()
|
||||
|
||||
c2, err := NewClient(host, logger)
|
||||
s, err := NewSubscriber(c2, path, newFactory(""), logger)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer c2.Stop()
|
||||
|
||||
instance1 := &Service{
|
||||
Path: path,
|
||||
Name: "instance1",
|
||||
Data: []byte(instancePayload),
|
||||
}
|
||||
if err = c2.Register(instance1); err != nil {
|
||||
t.Fatalf("Unable to create test ephemeral znode 1: %+v", err)
|
||||
}
|
||||
instance2 := &Service{
|
||||
Path: path,
|
||||
Name: "instance2",
|
||||
Data: []byte(instancePayload),
|
||||
}
|
||||
if err = c2.Register(instance2); err != nil {
|
||||
t.Fatalf("Unable to create test ephemeral znode 2: %+v", err)
|
||||
}
|
||||
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
|
||||
services, err := s.Endpoints()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if want, have := 2, len(services); want != have {
|
||||
t.Errorf("want %d, have %d", want, have)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetEntriesPayloadOnServer(t *testing.T) {
|
||||
c, err := NewClient(host, logger)
|
||||
if err != nil {
|
||||
t.Fatalf("Connect returned error: %v", err)
|
||||
}
|
||||
_, eventc, err := c.GetEntries(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
instance3 := Service{
|
||||
Path: path,
|
||||
Name: "instance3",
|
||||
Data: []byte("just some payload"),
|
||||
}
|
||||
registrar := NewRegistrar(c, instance3, logger)
|
||||
registrar.Register()
|
||||
select {
|
||||
case event := <-eventc:
|
||||
if want, have := stdzk.EventNodeChildrenChanged.String(), event.Type.String(); want != have {
|
||||
t.Errorf("want %s, have %s", want, have)
|
||||
}
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Errorf("expected incoming watch event, timeout occurred")
|
||||
}
|
||||
|
||||
_, eventc, err = c.GetEntries(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
registrar.Deregister()
|
||||
select {
|
||||
case event := <-eventc:
|
||||
if want, have := stdzk.EventNodeChildrenChanged.String(), event.Type.String(); want != have {
|
||||
t.Errorf("want %s, have %s", want, have)
|
||||
}
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
t.Errorf("expected incoming watch event, timeout occurred")
|
||||
}
|
||||
|
||||
}
|
27
vendor/github.com/go-kit/kit/sd/zk/logwrapper.go
generated
vendored
Normal file
27
vendor/github.com/go-kit/kit/sd/zk/logwrapper.go
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/samuel/go-zookeeper/zk"
|
||||
|
||||
"github.com/go-kit/kit/log"
|
||||
)
|
||||
|
||||
// wrapLogger wraps a Go kit logger so we can use it as the logging service for
|
||||
// the ZooKeeper library, which expects a Printf method to be available.
|
||||
type wrapLogger struct {
|
||||
log.Logger
|
||||
}
|
||||
|
||||
func (logger wrapLogger) Printf(format string, args ...interface{}) {
|
||||
logger.Log("msg", fmt.Sprintf(format, args...))
|
||||
}
|
||||
|
||||
// withLogger replaces the ZooKeeper library's default logging service with our
|
||||
// own Go kit logger.
|
||||
func withLogger(logger log.Logger) func(c *zk.Conn) {
|
||||
return func(c *zk.Conn) {
|
||||
c.SetLogger(wrapLogger{logger})
|
||||
}
|
||||
}
|
51
vendor/github.com/go-kit/kit/sd/zk/registrar.go
generated
vendored
Normal file
51
vendor/github.com/go-kit/kit/sd/zk/registrar.go
generated
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
package zk
|
||||
|
||||
import "github.com/go-kit/kit/log"
|
||||
|
||||
// Registrar registers service instance liveness information to ZooKeeper.
|
||||
type Registrar struct {
|
||||
client Client
|
||||
service Service
|
||||
logger log.Logger
|
||||
}
|
||||
|
||||
// Service holds the root path, service name and instance identifying data you
|
||||
// want to publish to ZooKeeper.
|
||||
type Service struct {
|
||||
Path string // discovery namespace, example: /myorganization/myplatform/
|
||||
Name string // service name, example: addscv
|
||||
Data []byte // instance data to store for discovery, example: 10.0.2.10:80
|
||||
node string // Client will record the ephemeral node name so we can deregister
|
||||
}
|
||||
|
||||
// NewRegistrar returns a ZooKeeper Registrar acting on the provided catalog
|
||||
// registration.
|
||||
func NewRegistrar(client Client, service Service, logger log.Logger) *Registrar {
|
||||
return &Registrar{
|
||||
client: client,
|
||||
service: service,
|
||||
logger: log.With(logger,
|
||||
"service", service.Name,
|
||||
"path", service.Path,
|
||||
"data", string(service.Data),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// Register implements sd.Registrar interface.
|
||||
func (r *Registrar) Register() {
|
||||
if err := r.client.Register(&r.service); err != nil {
|
||||
r.logger.Log("err", err)
|
||||
} else {
|
||||
r.logger.Log("action", "register")
|
||||
}
|
||||
}
|
||||
|
||||
// Deregister implements sd.Registrar interface.
|
||||
func (r *Registrar) Deregister() {
|
||||
if err := r.client.Deregister(&r.service); err != nil {
|
||||
r.logger.Log("err", err)
|
||||
} else {
|
||||
r.logger.Log("action", "deregister")
|
||||
}
|
||||
}
|
86
vendor/github.com/go-kit/kit/sd/zk/subscriber.go
generated
vendored
Normal file
86
vendor/github.com/go-kit/kit/sd/zk/subscriber.go
generated
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"github.com/samuel/go-zookeeper/zk"
|
||||
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
"github.com/go-kit/kit/log"
|
||||
"github.com/go-kit/kit/sd"
|
||||
"github.com/go-kit/kit/sd/cache"
|
||||
)
|
||||
|
||||
// Subscriber yield endpoints stored in a certain ZooKeeper path. Any kind of
|
||||
// change in that path is watched and will update the Subscriber endpoints.
|
||||
type Subscriber struct {
|
||||
client Client
|
||||
path string
|
||||
cache *cache.Cache
|
||||
logger log.Logger
|
||||
quitc chan struct{}
|
||||
}
|
||||
|
||||
var _ sd.Subscriber = &Subscriber{}
|
||||
|
||||
// NewSubscriber returns a ZooKeeper subscriber. ZooKeeper will start watching
|
||||
// the given path for changes and update the Subscriber endpoints.
|
||||
func NewSubscriber(c Client, path string, factory sd.Factory, logger log.Logger) (*Subscriber, error) {
|
||||
s := &Subscriber{
|
||||
client: c,
|
||||
path: path,
|
||||
cache: cache.New(factory, logger),
|
||||
logger: logger,
|
||||
quitc: make(chan struct{}),
|
||||
}
|
||||
|
||||
err := s.client.CreateParentNodes(s.path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
instances, eventc, err := s.client.GetEntries(s.path)
|
||||
if err != nil {
|
||||
logger.Log("path", s.path, "msg", "failed to retrieve entries", "err", err)
|
||||
return nil, err
|
||||
}
|
||||
logger.Log("path", s.path, "instances", len(instances))
|
||||
s.cache.Update(instances)
|
||||
|
||||
go s.loop(eventc)
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *Subscriber) loop(eventc <-chan zk.Event) {
|
||||
var (
|
||||
instances []string
|
||||
err error
|
||||
)
|
||||
for {
|
||||
select {
|
||||
case <-eventc:
|
||||
// We received a path update notification. Call GetEntries to
|
||||
// retrieve child node data, and set a new watch, as ZK watches are
|
||||
// one-time triggers.
|
||||
instances, eventc, err = s.client.GetEntries(s.path)
|
||||
if err != nil {
|
||||
s.logger.Log("path", s.path, "msg", "failed to retrieve entries", "err", err)
|
||||
continue
|
||||
}
|
||||
s.logger.Log("path", s.path, "instances", len(instances))
|
||||
s.cache.Update(instances)
|
||||
|
||||
case <-s.quitc:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Endpoints implements the Subscriber interface.
|
||||
func (s *Subscriber) Endpoints() ([]endpoint.Endpoint, error) {
|
||||
return s.cache.Endpoints(), nil
|
||||
}
|
||||
|
||||
// Stop terminates the Subscriber.
|
||||
func (s *Subscriber) Stop() {
|
||||
close(s.quitc)
|
||||
}
|
117
vendor/github.com/go-kit/kit/sd/zk/subscriber_test.go
generated
vendored
Normal file
117
vendor/github.com/go-kit/kit/sd/zk/subscriber_test.go
generated
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSubscriber(t *testing.T) {
|
||||
client := newFakeClient()
|
||||
|
||||
s, err := NewSubscriber(client, path, newFactory(""), logger)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create new Subscriber: %v", err)
|
||||
}
|
||||
defer s.Stop()
|
||||
|
||||
if _, err := s.Endpoints(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadFactory(t *testing.T) {
|
||||
client := newFakeClient()
|
||||
|
||||
s, err := NewSubscriber(client, path, newFactory("kaboom"), logger)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create new Subscriber: %v", err)
|
||||
}
|
||||
defer s.Stop()
|
||||
|
||||
// instance1 came online
|
||||
client.AddService(path+"/instance1", "kaboom")
|
||||
|
||||
// instance2 came online
|
||||
client.AddService(path+"/instance2", "zookeeper_node_data")
|
||||
|
||||
if err = asyncTest(100*time.Millisecond, 1, s); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestServiceUpdate(t *testing.T) {
|
||||
client := newFakeClient()
|
||||
|
||||
s, err := NewSubscriber(client, path, newFactory(""), logger)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create new Subscriber: %v", err)
|
||||
}
|
||||
defer s.Stop()
|
||||
|
||||
endpoints, err := s.Endpoints()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if want, have := 0, len(endpoints); want != have {
|
||||
t.Errorf("want %d, have %d", want, have)
|
||||
}
|
||||
|
||||
// instance1 came online
|
||||
client.AddService(path+"/instance1", "zookeeper_node_data1")
|
||||
|
||||
// instance2 came online
|
||||
client.AddService(path+"/instance2", "zookeeper_node_data2")
|
||||
|
||||
// we should have 2 instances
|
||||
if err = asyncTest(100*time.Millisecond, 2, s); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// TODO(pb): this bit is flaky
|
||||
//
|
||||
//// watch triggers an error...
|
||||
//client.SendErrorOnWatch()
|
||||
//
|
||||
//// test if error was consumed
|
||||
//if err = client.ErrorIsConsumedWithin(100 * time.Millisecond); err != nil {
|
||||
// t.Error(err)
|
||||
//}
|
||||
|
||||
// instance3 came online
|
||||
client.AddService(path+"/instance3", "zookeeper_node_data3")
|
||||
|
||||
// we should have 3 instances
|
||||
if err = asyncTest(100*time.Millisecond, 3, s); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
|
||||
// instance1 goes offline
|
||||
client.RemoveService(path + "/instance1")
|
||||
|
||||
// instance2 goes offline
|
||||
client.RemoveService(path + "/instance2")
|
||||
|
||||
// we should have 1 instance
|
||||
if err = asyncTest(100*time.Millisecond, 1, s); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestBadSubscriberCreate(t *testing.T) {
|
||||
client := newFakeClient()
|
||||
client.SendErrorOnWatch()
|
||||
s, err := NewSubscriber(client, path, newFactory(""), logger)
|
||||
if err == nil {
|
||||
t.Error("expected error on new Subscriber")
|
||||
}
|
||||
if s != nil {
|
||||
t.Error("expected Subscriber not to be created")
|
||||
}
|
||||
s, err = NewSubscriber(client, "BadPath", newFactory(""), logger)
|
||||
if err == nil {
|
||||
t.Error("expected error on new Subscriber")
|
||||
}
|
||||
if s != nil {
|
||||
t.Error("expected Subscriber not to be created")
|
||||
}
|
||||
}
|
134
vendor/github.com/go-kit/kit/sd/zk/util_test.go
generated
vendored
Normal file
134
vendor/github.com/go-kit/kit/sd/zk/util_test.go
generated
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
package zk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/samuel/go-zookeeper/zk"
|
||||
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
"github.com/go-kit/kit/log"
|
||||
"github.com/go-kit/kit/sd"
|
||||
)
|
||||
|
||||
var (
|
||||
path = "/gokit.test/service.name"
|
||||
e = func(context.Context, interface{}) (interface{}, error) { return struct{}{}, nil }
|
||||
logger = log.NewNopLogger()
|
||||
)
|
||||
|
||||
type fakeClient struct {
|
||||
mtx sync.Mutex
|
||||
ch chan zk.Event
|
||||
responses map[string]string
|
||||
result bool
|
||||
}
|
||||
|
||||
func newFakeClient() *fakeClient {
|
||||
return &fakeClient{
|
||||
ch: make(chan zk.Event, 1),
|
||||
responses: make(map[string]string),
|
||||
result: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *fakeClient) CreateParentNodes(path string) error {
|
||||
if path == "BadPath" {
|
||||
return errors.New("dummy error")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) GetEntries(path string) ([]string, <-chan zk.Event, error) {
|
||||
c.mtx.Lock()
|
||||
defer c.mtx.Unlock()
|
||||
if c.result == false {
|
||||
c.result = true
|
||||
return []string{}, c.ch, errors.New("dummy error")
|
||||
}
|
||||
responses := []string{}
|
||||
for _, data := range c.responses {
|
||||
responses = append(responses, data)
|
||||
}
|
||||
return responses, c.ch, nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) AddService(node, data string) {
|
||||
c.mtx.Lock()
|
||||
defer c.mtx.Unlock()
|
||||
c.responses[node] = data
|
||||
c.ch <- zk.Event{}
|
||||
}
|
||||
|
||||
func (c *fakeClient) RemoveService(node string) {
|
||||
c.mtx.Lock()
|
||||
defer c.mtx.Unlock()
|
||||
delete(c.responses, node)
|
||||
c.ch <- zk.Event{}
|
||||
}
|
||||
|
||||
func (c *fakeClient) Register(s *Service) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) Deregister(s *Service) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *fakeClient) SendErrorOnWatch() {
|
||||
c.mtx.Lock()
|
||||
defer c.mtx.Unlock()
|
||||
c.result = false
|
||||
c.ch <- zk.Event{}
|
||||
}
|
||||
|
||||
func (c *fakeClient) ErrorIsConsumedWithin(timeout time.Duration) error {
|
||||
t := time.After(timeout)
|
||||
for {
|
||||
select {
|
||||
case <-t:
|
||||
return fmt.Errorf("expected error not consumed after timeout %s", timeout)
|
||||
default:
|
||||
c.mtx.Lock()
|
||||
if c.result == false {
|
||||
c.mtx.Unlock()
|
||||
return nil
|
||||
}
|
||||
c.mtx.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *fakeClient) Stop() {}
|
||||
|
||||
func newFactory(fakeError string) sd.Factory {
|
||||
return func(instance string) (endpoint.Endpoint, io.Closer, error) {
|
||||
if fakeError == instance {
|
||||
return nil, nil, errors.New(fakeError)
|
||||
}
|
||||
return endpoint.Nop, nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
func asyncTest(timeout time.Duration, want int, s *Subscriber) (err error) {
|
||||
var endpoints []endpoint.Endpoint
|
||||
have := -1 // want can never be <0
|
||||
t := time.After(timeout)
|
||||
for {
|
||||
select {
|
||||
case <-t:
|
||||
return fmt.Errorf("want %d, have %d (timeout %s)", want, have, timeout.String())
|
||||
default:
|
||||
endpoints, err = s.Endpoints()
|
||||
have = len(endpoints)
|
||||
if err != nil || want == have {
|
||||
return
|
||||
}
|
||||
time.Sleep(timeout / 10)
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user