mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #494 from mrjana/bugs
Fix bridge driver panic in CreateNetwork
This commit is contained in:
commit
82181e0da9
15 changed files with 217 additions and 121 deletions
4
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/.travis.yml
generated
vendored
4
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/.travis.yml
generated
vendored
|
@ -11,8 +11,8 @@ sudo: false
|
||||||
before_install:
|
before_install:
|
||||||
# Symlink below is needed for Travis CI to work correctly on personal forks of libkv
|
# Symlink below is needed for Travis CI to work correctly on personal forks of libkv
|
||||||
- ln -s $HOME/gopath/src/github.com/${TRAVIS_REPO_SLUG///libkv/} $HOME/gopath/src/github.com/docker
|
- ln -s $HOME/gopath/src/github.com/${TRAVIS_REPO_SLUG///libkv/} $HOME/gopath/src/github.com/docker
|
||||||
- go get code.google.com/p/go.tools/cmd/vet
|
- go get golang.org/x/tools/cmd/vet
|
||||||
- go get code.google.com/p/go.tools/cmd/cover
|
- go get golang.org/x/tools/cmd/cover
|
||||||
- go get github.com/mattn/goveralls
|
- go get github.com/mattn/goveralls
|
||||||
- go get github.com/golang/lint/golint
|
- go get github.com/golang/lint/golint
|
||||||
- go get github.com/GeertJohan/fgt
|
- go get github.com/GeertJohan/fgt
|
||||||
|
|
10
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/libkv.go
generated
vendored
10
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/libkv.go
generated
vendored
|
@ -1,11 +1,9 @@
|
||||||
package libkv
|
package libkv
|
||||||
|
|
||||||
import (
|
import (
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/libkv/store"
|
"github.com/docker/libkv/store"
|
||||||
"github.com/docker/libkv/store/consul"
|
"github.com/docker/libkv/store/consul"
|
||||||
"github.com/docker/libkv/store/etcd"
|
"github.com/docker/libkv/store/etcd"
|
||||||
"github.com/docker/libkv/store/mock"
|
|
||||||
"github.com/docker/libkv/store/zookeeper"
|
"github.com/docker/libkv/store/zookeeper"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -15,17 +13,15 @@ type Initialize func(addrs []string, options *store.Config) (store.Store, error)
|
||||||
var (
|
var (
|
||||||
// Backend initializers
|
// Backend initializers
|
||||||
initializers = map[store.Backend]Initialize{
|
initializers = map[store.Backend]Initialize{
|
||||||
store.MOCK: mock.InitializeMock,
|
store.CONSUL: consul.New,
|
||||||
store.CONSUL: consul.InitializeConsul,
|
store.ETCD: etcd.New,
|
||||||
store.ETCD: etcd.InitializeEtcd,
|
store.ZK: zookeeper.New,
|
||||||
store.ZK: zookeeper.InitializeZookeeper,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewStore creates a an instance of store
|
// NewStore creates a an instance of store
|
||||||
func NewStore(backend store.Backend, addrs []string, options *store.Config) (store.Store, error) {
|
func NewStore(backend store.Backend, addrs []string, options *store.Config) (store.Store, error) {
|
||||||
if init, exists := initializers[backend]; exists {
|
if init, exists := initializers[backend]; exists {
|
||||||
log.WithFields(log.Fields{"backend": backend}).Debug("Initializing store service")
|
|
||||||
return init(addrs, options)
|
return init(addrs, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
11
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/libkv_test.go
generated
vendored
11
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/libkv_test.go
generated
vendored
|
@ -7,7 +7,6 @@ import (
|
||||||
"github.com/docker/libkv/store"
|
"github.com/docker/libkv/store"
|
||||||
"github.com/docker/libkv/store/consul"
|
"github.com/docker/libkv/store/consul"
|
||||||
"github.com/docker/libkv/store/etcd"
|
"github.com/docker/libkv/store/etcd"
|
||||||
"github.com/docker/libkv/store/mock"
|
|
||||||
"github.com/docker/libkv/store/zookeeper"
|
"github.com/docker/libkv/store/zookeeper"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
@ -66,16 +65,6 @@ func TestNewStoreZookeeper(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewStoreMock(t *testing.T) {
|
|
||||||
kv, err := NewStore(store.MOCK, []string{}, &store.Config{})
|
|
||||||
assert.NoError(t, err)
|
|
||||||
assert.NotNil(t, kv)
|
|
||||||
|
|
||||||
if _, ok := kv.(*mock.Mock); !ok {
|
|
||||||
t.Fatal("Error while initializing mock store")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNewStoreUnsupported(t *testing.T) {
|
func TestNewStoreUnsupported(t *testing.T) {
|
||||||
client := "localhost:9999"
|
client := "localhost:9999"
|
||||||
|
|
||||||
|
|
2
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/script/travis_consul.sh
generated
vendored
2
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/script/travis_consul.sh
generated
vendored
|
@ -12,7 +12,7 @@ unzip "${CONSUL_VERSION}_linux_amd64.zip"
|
||||||
|
|
||||||
# make config for minimum ttl
|
# make config for minimum ttl
|
||||||
touch config.json
|
touch config.json
|
||||||
echo "{\"session_ttl_min\": \"2s\"}" >> config.json
|
echo "{\"session_ttl_min\": \"1s\"}" >> config.json
|
||||||
|
|
||||||
# check
|
# check
|
||||||
./consul --version
|
./consul --version
|
||||||
|
|
51
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/store/consul/consul.go
generated
vendored
51
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/store/consul/consul.go
generated
vendored
|
@ -7,7 +7,6 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/libkv/store"
|
"github.com/docker/libkv/store"
|
||||||
api "github.com/hashicorp/consul/api"
|
api "github.com/hashicorp/consul/api"
|
||||||
)
|
)
|
||||||
|
@ -32,9 +31,9 @@ type consulLock struct {
|
||||||
lock *api.Lock
|
lock *api.Lock
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitializeConsul creates a new Consul client given
|
// New creates a new Consul client given a list
|
||||||
// a list of endpoints and optional tls config
|
// of endpoints and optional tls config
|
||||||
func InitializeConsul(endpoints []string, options *store.Config) (store.Store, error) {
|
func New(endpoints []string, options *store.Config) (store.Store, error) {
|
||||||
s := &Consul{}
|
s := &Consul{}
|
||||||
|
|
||||||
// Create Consul client
|
// Create Consul client
|
||||||
|
@ -60,7 +59,6 @@ func InitializeConsul(endpoints []string, options *store.Config) (store.Store, e
|
||||||
// Creates a new client
|
// Creates a new client
|
||||||
client, err := api.NewClient(config)
|
client, err := api.NewClient(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("Couldn't initialize consul client..")
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
s.client = client
|
s.client = client
|
||||||
|
@ -101,8 +99,9 @@ func (s *Consul) refreshSession(pair *api.KVPair) error {
|
||||||
|
|
||||||
if session == "" {
|
if session == "" {
|
||||||
entry := &api.SessionEntry{
|
entry := &api.SessionEntry{
|
||||||
Behavior: api.SessionBehaviorDelete,
|
Behavior: api.SessionBehaviorDelete, // Delete the key when the session expires
|
||||||
TTL: s.ephemeralTTL.String(),
|
TTL: ((s.ephemeralTTL) / 2).String(), // Consul multiplies the TTL by 2x
|
||||||
|
LockDelay: 1 * time.Millisecond, // Virtually disable lock delay
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the key session
|
// Create the key session
|
||||||
|
@ -110,19 +109,19 @@ func (s *Consul) refreshSession(pair *api.KVPair) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
lockOpts := &api.LockOptions{
|
lockOpts := &api.LockOptions{
|
||||||
Key: pair.Key,
|
Key: pair.Key,
|
||||||
Session: session,
|
Session: session,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock and ignore if lock is held
|
// Lock and ignore if lock is held
|
||||||
// It's just a placeholder for the
|
// It's just a placeholder for the
|
||||||
// ephemeral behavior
|
// ephemeral behavior
|
||||||
lock, _ := s.client.LockOpts(lockOpts)
|
lock, _ := s.client.LockOpts(lockOpts)
|
||||||
if lock != nil {
|
if lock != nil {
|
||||||
lock.Lock(nil)
|
lock.Lock(nil)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, _, err = s.client.Session().Renew(session, nil)
|
_, _, err = s.client.Session().Renew(session, nil)
|
||||||
|
@ -312,7 +311,6 @@ func (s *Consul) WatchTree(directory string, stopCh <-chan struct{}) (<-chan []*
|
||||||
// Get all the childrens
|
// Get all the childrens
|
||||||
pairs, meta, err := kv.List(directory, opts)
|
pairs, meta, err := kv.List(directory, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("consul: %v", err)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -324,18 +322,18 @@ func (s *Consul) WatchTree(directory string, stopCh <-chan struct{}) (<-chan []*
|
||||||
opts.WaitIndex = meta.LastIndex
|
opts.WaitIndex = meta.LastIndex
|
||||||
|
|
||||||
// Return children KV pairs to the channel
|
// Return children KV pairs to the channel
|
||||||
kv := []*store.KVPair{}
|
kvpairs := []*store.KVPair{}
|
||||||
for _, pair := range pairs {
|
for _, pair := range pairs {
|
||||||
if pair.Key == directory {
|
if pair.Key == directory {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
kv = append(kv, &store.KVPair{
|
kvpairs = append(kvpairs, &store.KVPair{
|
||||||
Key: pair.Key,
|
Key: pair.Key,
|
||||||
Value: pair.Value,
|
Value: pair.Value,
|
||||||
LastIndex: pair.ModifyIndex,
|
LastIndex: pair.ModifyIndex,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
watchCh <- kv
|
watchCh <- kvpairs
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -377,11 +375,16 @@ func (l *consulLock) Unlock() error {
|
||||||
// AtomicPut put a value at "key" if the key has not been
|
// AtomicPut put a value at "key" if the key has not been
|
||||||
// modified in the meantime, throws an error if this is the case
|
// modified in the meantime, throws an error if this is the case
|
||||||
func (s *Consul) AtomicPut(key string, value []byte, previous *store.KVPair, options *store.WriteOptions) (bool, *store.KVPair, error) {
|
func (s *Consul) AtomicPut(key string, value []byte, previous *store.KVPair, options *store.WriteOptions) (bool, *store.KVPair, error) {
|
||||||
|
|
||||||
|
p := &api.KVPair{Key: s.normalize(key), Value: value}
|
||||||
|
|
||||||
if previous == nil {
|
if previous == nil {
|
||||||
return false, nil, store.ErrPreviousNotSpecified
|
// Consul interprets ModifyIndex = 0 as new key.
|
||||||
|
p.ModifyIndex = 0
|
||||||
|
} else {
|
||||||
|
p.ModifyIndex = previous.LastIndex
|
||||||
}
|
}
|
||||||
|
|
||||||
p := &api.KVPair{Key: s.normalize(key), Value: value, ModifyIndex: previous.LastIndex}
|
|
||||||
if work, _, err := s.client.KV().CAS(p, nil); err != nil {
|
if work, _, err := s.client.KV().CAS(p, nil); err != nil {
|
||||||
return false, nil, err
|
return false, nil, err
|
||||||
} else if !work {
|
} else if !work {
|
||||||
|
|
5
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/store/consul/consul_test.go
generated
vendored
5
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/store/consul/consul_test.go
generated
vendored
|
@ -5,13 +5,14 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/libkv/store"
|
"github.com/docker/libkv/store"
|
||||||
|
"github.com/docker/libkv/testutils"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeConsulClient(t *testing.T) store.Store {
|
func makeConsulClient(t *testing.T) store.Store {
|
||||||
client := "localhost:8500"
|
client := "localhost:8500"
|
||||||
|
|
||||||
kv, err := InitializeConsul(
|
kv, err := New(
|
||||||
[]string{client},
|
[]string{client},
|
||||||
&store.Config{
|
&store.Config{
|
||||||
ConnectionTimeout: 3 * time.Second,
|
ConnectionTimeout: 3 * time.Second,
|
||||||
|
@ -30,7 +31,7 @@ func TestConsulStore(t *testing.T) {
|
||||||
kv := makeConsulClient(t)
|
kv := makeConsulClient(t)
|
||||||
backup := makeConsulClient(t)
|
backup := makeConsulClient(t)
|
||||||
|
|
||||||
store.TestStore(t, kv, backup)
|
testutils.RunTestStore(t, kv, backup)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetActiveSession(t *testing.T) {
|
func TestGetActiveSession(t *testing.T) {
|
||||||
|
|
35
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/store/etcd/etcd.go
generated
vendored
35
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/store/etcd/etcd.go
generated
vendored
|
@ -33,9 +33,9 @@ const (
|
||||||
defaultUpdateTime = 5 * time.Second
|
defaultUpdateTime = 5 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
// InitializeEtcd creates a new Etcd client given
|
// New creates a new Etcd client given a list
|
||||||
// a list of endpoints and an optional tls config
|
// of endpoints and an optional tls config
|
||||||
func InitializeEtcd(addrs []string, options *store.Config) (store.Store, error) {
|
func New(addrs []string, options *store.Config) (store.Store, error) {
|
||||||
s := &Etcd{}
|
s := &Etcd{}
|
||||||
|
|
||||||
entries := store.CreateEndpoints(addrs, "http")
|
entries := store.CreateEndpoints(addrs, "http")
|
||||||
|
@ -278,11 +278,32 @@ func (s *Etcd) WatchTree(directory string, stopCh <-chan struct{}) (<-chan []*st
|
||||||
// AtomicPut put a value at "key" if the key has not been
|
// AtomicPut put a value at "key" if the key has not been
|
||||||
// modified in the meantime, throws an error if this is the case
|
// modified in the meantime, throws an error if this is the case
|
||||||
func (s *Etcd) AtomicPut(key string, value []byte, previous *store.KVPair, options *store.WriteOptions) (bool, *store.KVPair, error) {
|
func (s *Etcd) AtomicPut(key string, value []byte, previous *store.KVPair, options *store.WriteOptions) (bool, *store.KVPair, error) {
|
||||||
if previous == nil {
|
|
||||||
return false, nil, store.ErrPreviousNotSpecified
|
|
||||||
}
|
|
||||||
|
|
||||||
meta, err := s.client.CompareAndSwap(store.Normalize(key), string(value), 0, "", previous.LastIndex)
|
var meta *etcd.Response
|
||||||
|
var err error
|
||||||
|
if previous != nil {
|
||||||
|
meta, err = s.client.CompareAndSwap(store.Normalize(key), string(value), 0, "", previous.LastIndex)
|
||||||
|
} else {
|
||||||
|
// Interpret previous == nil as Atomic Create
|
||||||
|
meta, err = s.client.Create(store.Normalize(key), string(value), 0)
|
||||||
|
if etcdError, ok := err.(*etcd.EtcdError); ok {
|
||||||
|
|
||||||
|
// Directory doesn't exist.
|
||||||
|
if etcdError.ErrorCode == 104 {
|
||||||
|
// Remove the last element (the actual key)
|
||||||
|
// and create the full directory path
|
||||||
|
err = s.createDirectory(store.GetDirectory(key))
|
||||||
|
if err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that the directory is created, create the key
|
||||||
|
if _, err := s.client.Create(key, string(value), 0); err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if etcdError, ok := err.(*etcd.EtcdError); ok {
|
if etcdError, ok := err.(*etcd.EtcdError); ok {
|
||||||
// Compare Failed
|
// Compare Failed
|
||||||
|
|
5
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/store/etcd/etcd_test.go
generated
vendored
5
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/store/etcd/etcd_test.go
generated
vendored
|
@ -5,12 +5,13 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/libkv/store"
|
"github.com/docker/libkv/store"
|
||||||
|
"github.com/docker/libkv/testutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeEtcdClient(t *testing.T) store.Store {
|
func makeEtcdClient(t *testing.T) store.Store {
|
||||||
client := "localhost:4001"
|
client := "localhost:4001"
|
||||||
|
|
||||||
kv, err := InitializeEtcd(
|
kv, err := New(
|
||||||
[]string{client},
|
[]string{client},
|
||||||
&store.Config{
|
&store.Config{
|
||||||
ConnectionTimeout: 3 * time.Second,
|
ConnectionTimeout: 3 * time.Second,
|
||||||
|
@ -29,5 +30,5 @@ func TestEtcdStore(t *testing.T) {
|
||||||
kv := makeEtcdClient(t)
|
kv := makeEtcdClient(t)
|
||||||
backup := makeEtcdClient(t)
|
backup := makeEtcdClient(t)
|
||||||
|
|
||||||
store.TestStore(t, kv, backup)
|
testutils.RunTestStore(t, kv, backup)
|
||||||
}
|
}
|
||||||
|
|
4
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/store/mock/mock.go
generated
vendored
4
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/store/mock/mock.go
generated
vendored
|
@ -16,8 +16,8 @@ type Mock struct {
|
||||||
Options *store.Config
|
Options *store.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitializeMock creates a Mock store.
|
// New creates a Mock store
|
||||||
func InitializeMock(endpoints []string, options *store.Config) (store.Store, error) {
|
func New(endpoints []string, options *store.Config) (store.Store, error) {
|
||||||
s := &Mock{}
|
s := &Mock{}
|
||||||
s.Endpoints = endpoints
|
s.Endpoints = endpoints
|
||||||
s.Options = options
|
s.Options = options
|
||||||
|
|
11
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/store/store.go
generated
vendored
11
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/store/store.go
generated
vendored
|
@ -10,14 +10,12 @@ import (
|
||||||
type Backend string
|
type Backend string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// MOCK backend
|
|
||||||
MOCK Backend = "mock"
|
|
||||||
// CONSUL backend
|
// CONSUL backend
|
||||||
CONSUL = "consul"
|
CONSUL Backend = "consul"
|
||||||
// ETCD backend
|
// ETCD backend
|
||||||
ETCD = "etcd"
|
ETCD Backend = "etcd"
|
||||||
// ZK backend
|
// ZK backend
|
||||||
ZK = "zk"
|
ZK Backend = "zk"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
@ -79,7 +77,8 @@ type Store interface {
|
||||||
// DeleteTree deletes a range of keys under a given directory
|
// DeleteTree deletes a range of keys under a given directory
|
||||||
DeleteTree(directory string) error
|
DeleteTree(directory string) error
|
||||||
|
|
||||||
// Atomic operation on a single value
|
// Atomic CAS operation on a single value.
|
||||||
|
// Pass previous = nil to create a new key.
|
||||||
AtomicPut(key string, value []byte, previous *KVPair, options *WriteOptions) (bool, *KVPair, error)
|
AtomicPut(key string, value []byte, previous *KVPair, options *WriteOptions) (bool, *KVPair, error)
|
||||||
|
|
||||||
// Atomic delete of a single value
|
// Atomic delete of a single value
|
||||||
|
|
52
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/store/zookeeper/zookeeper.go
generated
vendored
52
libnetwork/Godeps/_workspace/src/github.com/docker/libkv/store/zookeeper/zookeeper.go
generated
vendored
|
@ -4,7 +4,6 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
|
||||||
"github.com/docker/libkv/store"
|
"github.com/docker/libkv/store"
|
||||||
zk "github.com/samuel/go-zookeeper/zk"
|
zk "github.com/samuel/go-zookeeper/zk"
|
||||||
)
|
)
|
||||||
|
@ -25,9 +24,9 @@ type zookeeperLock struct {
|
||||||
value []byte
|
value []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitializeZookeeper creates a new Zookeeper client
|
// New creates a new Zookeeper client given a
|
||||||
// given a list of endpoints and an optional tls config
|
// list of endpoints and an optional tls config
|
||||||
func InitializeZookeeper(endpoints []string, options *store.Config) (store.Store, error) {
|
func New(endpoints []string, options *store.Config) (store.Store, error) {
|
||||||
s := &Zookeeper{}
|
s := &Zookeeper{}
|
||||||
s.timeout = defaultTimeout
|
s.timeout = defaultTimeout
|
||||||
|
|
||||||
|
@ -41,7 +40,6 @@ func InitializeZookeeper(endpoints []string, options *store.Config) (store.Store
|
||||||
// Connect to Zookeeper
|
// Connect to Zookeeper
|
||||||
conn, _, err := zk.Connect(endpoints, s.timeout)
|
conn, _, err := zk.Connect(endpoints, s.timeout)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error(err)
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
s.client = conn
|
s.client = conn
|
||||||
|
@ -267,23 +265,47 @@ func (s *Zookeeper) DeleteTree(directory string) error {
|
||||||
// AtomicPut put a value at "key" if the key has not been
|
// AtomicPut put a value at "key" if the key has not been
|
||||||
// modified in the meantime, throws an error if this is the case
|
// modified in the meantime, throws an error if this is the case
|
||||||
func (s *Zookeeper) AtomicPut(key string, value []byte, previous *store.KVPair, _ *store.WriteOptions) (bool, *store.KVPair, error) {
|
func (s *Zookeeper) AtomicPut(key string, value []byte, previous *store.KVPair, _ *store.WriteOptions) (bool, *store.KVPair, error) {
|
||||||
if previous == nil {
|
|
||||||
return false, nil, store.ErrPreviousNotSpecified
|
|
||||||
}
|
|
||||||
|
|
||||||
meta, err := s.client.Set(store.Normalize(key), value, int32(previous.LastIndex))
|
var lastIndex uint64
|
||||||
if err != nil {
|
if previous != nil {
|
||||||
// Compare Failed
|
meta, err := s.client.Set(store.Normalize(key), value, int32(previous.LastIndex))
|
||||||
if err == zk.ErrBadVersion {
|
if err != nil {
|
||||||
return false, nil, store.ErrKeyModified
|
// Compare Failed
|
||||||
|
if err == zk.ErrBadVersion {
|
||||||
|
return false, nil, store.ErrKeyModified
|
||||||
|
}
|
||||||
|
return false, nil, err
|
||||||
}
|
}
|
||||||
return false, nil, err
|
lastIndex = uint64(meta.Version)
|
||||||
|
} else {
|
||||||
|
// Interpret previous == nil as create operation.
|
||||||
|
_, err := s.client.Create(store.Normalize(key), value, 0, zk.WorldACL(zk.PermAll))
|
||||||
|
if err != nil {
|
||||||
|
// Zookeeper will complain if the directory doesn't exist.
|
||||||
|
if err == zk.ErrNoNode {
|
||||||
|
// Create the directory
|
||||||
|
parts := store.SplitKey(key)
|
||||||
|
parts = parts[:len(parts)-1]
|
||||||
|
if err = s.createFullPath(parts, false); err != nil {
|
||||||
|
// Failed to create the directory.
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
if _, err := s.client.Create(store.Normalize(key), value, 0, zk.WorldACL(zk.PermAll)); err != nil {
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// Unhandled error
|
||||||
|
return false, nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lastIndex = 0 // Newly created nodes have version 0.
|
||||||
}
|
}
|
||||||
|
|
||||||
pair := &store.KVPair{
|
pair := &store.KVPair{
|
||||||
Key: key,
|
Key: key,
|
||||||
Value: value,
|
Value: value,
|
||||||
LastIndex: uint64(meta.Version),
|
LastIndex: lastIndex,
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, pair, nil
|
return true, pair, nil
|
||||||
|
|
|
@ -5,12 +5,13 @@ import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/libkv/store"
|
"github.com/docker/libkv/store"
|
||||||
|
"github.com/docker/libkv/testutils"
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeZkClient(t *testing.T) store.Store {
|
func makeZkClient(t *testing.T) store.Store {
|
||||||
client := "localhost:2181"
|
client := "localhost:2181"
|
||||||
|
|
||||||
kv, err := InitializeZookeeper(
|
kv, err := New(
|
||||||
[]string{client},
|
[]string{client},
|
||||||
&store.Config{
|
&store.Config{
|
||||||
ConnectionTimeout: 3 * time.Second,
|
ConnectionTimeout: 3 * time.Second,
|
||||||
|
@ -29,5 +30,5 @@ func TestZkStore(t *testing.T) {
|
||||||
kv := makeZkClient(t)
|
kv := makeZkClient(t)
|
||||||
backup := makeZkClient(t)
|
backup := makeZkClient(t)
|
||||||
|
|
||||||
store.TestStore(t, kv, backup)
|
testutils.RunTestStore(t, kv, backup)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
package store
|
package testutils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/docker/libkv/store"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestStore is an helper testing method that is
|
// RunTestStore is an helper testing method that is
|
||||||
// called by each K/V backend sub-package testing
|
// called by each K/V backend sub-package testing
|
||||||
func TestStore(t *testing.T, kv Store, backup Store) {
|
func RunTestStore(t *testing.T, kv store.Store, backup store.Store) {
|
||||||
testPutGetDelete(t, kv)
|
testPutGetDelete(t, kv)
|
||||||
testWatch(t, kv)
|
testWatch(t, kv)
|
||||||
testWatchTree(t, kv)
|
testWatchTree(t, kv)
|
||||||
testAtomicPut(t, kv)
|
testAtomicPut(t, kv)
|
||||||
|
testAtomicPutCreate(t, kv)
|
||||||
testAtomicDelete(t, kv)
|
testAtomicDelete(t, kv)
|
||||||
testLockUnlock(t, kv)
|
testLockUnlock(t, kv)
|
||||||
testPutEphemeral(t, kv, backup)
|
testPutEphemeral(t, kv, backup)
|
||||||
|
@ -21,7 +23,7 @@ func TestStore(t *testing.T, kv Store, backup Store) {
|
||||||
testDeleteTree(t, kv)
|
testDeleteTree(t, kv)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPutGetDelete(t *testing.T, kv Store) {
|
func testPutGetDelete(t *testing.T, kv store.Store) {
|
||||||
key := "foo"
|
key := "foo"
|
||||||
value := []byte("bar")
|
value := []byte("bar")
|
||||||
|
|
||||||
|
@ -48,7 +50,7 @@ func testPutGetDelete(t *testing.T, kv Store) {
|
||||||
assert.Nil(t, pair)
|
assert.Nil(t, pair)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testWatch(t *testing.T, kv Store) {
|
func testWatch(t *testing.T, kv store.Store) {
|
||||||
key := "hello"
|
key := "hello"
|
||||||
value := []byte("world")
|
value := []byte("world")
|
||||||
newValue := []byte("world!")
|
newValue := []byte("world!")
|
||||||
|
@ -105,7 +107,7 @@ func testWatch(t *testing.T, kv Store) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testWatchTree(t *testing.T, kv Store) {
|
func testWatchTree(t *testing.T, kv store.Store) {
|
||||||
dir := "tree"
|
dir := "tree"
|
||||||
|
|
||||||
node1 := "tree/node1"
|
node1 := "tree/node1"
|
||||||
|
@ -159,7 +161,7 @@ func testWatchTree(t *testing.T, kv Store) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAtomicPut(t *testing.T, kv Store) {
|
func testAtomicPut(t *testing.T, kv store.Store) {
|
||||||
key := "hello"
|
key := "hello"
|
||||||
value := []byte("world")
|
value := []byte("world")
|
||||||
|
|
||||||
|
@ -176,7 +178,7 @@ func testAtomicPut(t *testing.T, kv Store) {
|
||||||
assert.Equal(t, pair.Value, value)
|
assert.Equal(t, pair.Value, value)
|
||||||
assert.NotEqual(t, pair.LastIndex, 0)
|
assert.NotEqual(t, pair.LastIndex, 0)
|
||||||
|
|
||||||
// This CAS should fail: no previous
|
// This CAS should fail: previous exists.
|
||||||
success, _, err := kv.AtomicPut("hello", []byte("WORLD"), nil, nil)
|
success, _, err := kv.AtomicPut("hello", []byte("WORLD"), nil, nil)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.False(t, success)
|
assert.False(t, success)
|
||||||
|
@ -186,14 +188,48 @@ func testAtomicPut(t *testing.T, kv Store) {
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.True(t, success)
|
assert.True(t, success)
|
||||||
|
|
||||||
// This CAS should fail
|
// This CAS should fail, key exists.
|
||||||
pair.LastIndex = 0
|
pair.LastIndex = 0
|
||||||
success, _, err = kv.AtomicPut("hello", []byte("WORLDWORLD"), pair, nil)
|
success, _, err = kv.AtomicPut("hello", []byte("WORLDWORLD"), pair, nil)
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.False(t, success)
|
assert.False(t, success)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAtomicDelete(t *testing.T, kv Store) {
|
func testAtomicPutCreate(t *testing.T, kv store.Store) {
|
||||||
|
// Use a key in a new directory to ensure Stores will create directories
|
||||||
|
// that don't yet exist.
|
||||||
|
key := "put/create"
|
||||||
|
value := []byte("putcreate")
|
||||||
|
|
||||||
|
// AtomicPut the key, previous = nil indicates create.
|
||||||
|
success, _, err := kv.AtomicPut(key, value, nil, nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, success)
|
||||||
|
|
||||||
|
// Get should return the value and an incremented index
|
||||||
|
pair, err := kv.Get(key)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
if assert.NotNil(t, pair) {
|
||||||
|
assert.NotNil(t, pair.Value)
|
||||||
|
}
|
||||||
|
assert.Equal(t, pair.Value, value)
|
||||||
|
|
||||||
|
// Attempting to create again should fail.
|
||||||
|
success, _, err = kv.AtomicPut(key, value, nil, nil)
|
||||||
|
assert.Error(t, err)
|
||||||
|
assert.False(t, success)
|
||||||
|
|
||||||
|
// This CAS should succeed, since it has the value from Get()
|
||||||
|
success, _, err = kv.AtomicPut(key, []byte("PUTCREATE"), pair, nil)
|
||||||
|
assert.NoError(t, err)
|
||||||
|
assert.True(t, success)
|
||||||
|
|
||||||
|
// Delete the key, ensures runs of the test don't interfere with each other.
|
||||||
|
err = kv.DeleteTree("put")
|
||||||
|
assert.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAtomicDelete(t *testing.T, kv store.Store) {
|
||||||
key := "atomic"
|
key := "atomic"
|
||||||
value := []byte("world")
|
value := []byte("world")
|
||||||
|
|
||||||
|
@ -225,12 +261,12 @@ func testAtomicDelete(t *testing.T, kv Store) {
|
||||||
assert.True(t, success)
|
assert.True(t, success)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testLockUnlock(t *testing.T, kv Store) {
|
func testLockUnlock(t *testing.T, kv store.Store) {
|
||||||
key := "foo"
|
key := "foo"
|
||||||
value := []byte("bar")
|
value := []byte("bar")
|
||||||
|
|
||||||
// We should be able to create a new lock on key
|
// We should be able to create a new lock on key
|
||||||
lock, err := kv.NewLock(key, &LockOptions{Value: value})
|
lock, err := kv.NewLock(key, &store.LockOptions{Value: value})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.NotNil(t, lock)
|
assert.NotNil(t, lock)
|
||||||
|
|
||||||
|
@ -262,7 +298,7 @@ func testLockUnlock(t *testing.T, kv Store) {
|
||||||
assert.NotEqual(t, pair.LastIndex, 0)
|
assert.NotEqual(t, pair.LastIndex, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPutEphemeral(t *testing.T, kv Store, otherConn Store) {
|
func testPutEphemeral(t *testing.T, kv store.Store, otherConn store.Store) {
|
||||||
firstKey := "first"
|
firstKey := "first"
|
||||||
firstValue := []byte("foo")
|
firstValue := []byte("foo")
|
||||||
|
|
||||||
|
@ -270,11 +306,11 @@ func testPutEphemeral(t *testing.T, kv Store, otherConn Store) {
|
||||||
secondValue := []byte("bar")
|
secondValue := []byte("bar")
|
||||||
|
|
||||||
// Put the first key with the Ephemeral flag
|
// Put the first key with the Ephemeral flag
|
||||||
err := otherConn.Put(firstKey, firstValue, &WriteOptions{Ephemeral: true})
|
err := otherConn.Put(firstKey, firstValue, &store.WriteOptions{Ephemeral: true})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Put a second key with the Ephemeral flag
|
// Put a second key with the Ephemeral flag
|
||||||
err = otherConn.Put(secondKey, secondValue, &WriteOptions{Ephemeral: true})
|
err = otherConn.Put(secondKey, secondValue, &store.WriteOptions{Ephemeral: true})
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
|
|
||||||
// Get on firstKey should work
|
// Get on firstKey should work
|
||||||
|
@ -291,7 +327,7 @@ func testPutEphemeral(t *testing.T, kv Store, otherConn Store) {
|
||||||
otherConn.Close()
|
otherConn.Close()
|
||||||
|
|
||||||
// Let the session expire
|
// Let the session expire
|
||||||
time.Sleep(5 * time.Second)
|
time.Sleep(3 * time.Second)
|
||||||
|
|
||||||
// Get on firstKey shouldn't work
|
// Get on firstKey shouldn't work
|
||||||
pair, err = kv.Get(firstKey)
|
pair, err = kv.Get(firstKey)
|
||||||
|
@ -304,7 +340,7 @@ func testPutEphemeral(t *testing.T, kv Store, otherConn Store) {
|
||||||
assert.Nil(t, pair)
|
assert.Nil(t, pair)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testList(t *testing.T, kv Store) {
|
func testList(t *testing.T, kv store.Store) {
|
||||||
prefix := "nodes"
|
prefix := "nodes"
|
||||||
|
|
||||||
firstKey := "nodes/first"
|
firstKey := "nodes/first"
|
||||||
|
@ -344,7 +380,7 @@ func testList(t *testing.T, kv Store) {
|
||||||
assert.Nil(t, pairs)
|
assert.Nil(t, pairs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDeleteTree(t *testing.T, kv Store) {
|
func testDeleteTree(t *testing.T, kv store.Store) {
|
||||||
prefix := "nodes"
|
prefix := "nodes"
|
||||||
|
|
||||||
firstKey := "nodes/first"
|
firstKey := "nodes/first"
|
|
@ -98,6 +98,7 @@ type bridgeNetwork struct {
|
||||||
|
|
||||||
type driver struct {
|
type driver struct {
|
||||||
config *configuration
|
config *configuration
|
||||||
|
configured bool
|
||||||
network *bridgeNetwork
|
network *bridgeNetwork
|
||||||
natChain *iptables.ChainInfo
|
natChain *iptables.ChainInfo
|
||||||
filterChain *iptables.ChainInfo
|
filterChain *iptables.ChainInfo
|
||||||
|
@ -108,7 +109,7 @@ type driver struct {
|
||||||
// New constructs a new bridge driver
|
// New constructs a new bridge driver
|
||||||
func newDriver() driverapi.Driver {
|
func newDriver() driverapi.Driver {
|
||||||
ipAllocator = ipallocator.New()
|
ipAllocator = ipallocator.New()
|
||||||
return &driver{networks: map[string]*bridgeNetwork{}}
|
return &driver{networks: map[string]*bridgeNetwork{}, config: &configuration{}}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Init registers a new instance of bridge driver
|
// Init registers a new instance of bridge driver
|
||||||
|
@ -433,29 +434,26 @@ func (d *driver) Config(option map[string]interface{}) error {
|
||||||
d.Lock()
|
d.Lock()
|
||||||
defer d.Unlock()
|
defer d.Unlock()
|
||||||
|
|
||||||
if d.config != nil {
|
if d.configured {
|
||||||
return &ErrConfigExists{}
|
return &ErrConfigExists{}
|
||||||
}
|
}
|
||||||
|
|
||||||
genericData, ok := option[netlabel.GenericData]
|
genericData, ok := option[netlabel.GenericData]
|
||||||
if ok && genericData != nil {
|
if !ok || genericData == nil {
|
||||||
switch opt := genericData.(type) {
|
return nil
|
||||||
case options.Generic:
|
}
|
||||||
opaqueConfig, err := options.GenerateFromModel(opt, &configuration{})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
config = opaqueConfig.(*configuration)
|
|
||||||
case *configuration:
|
|
||||||
config = opt
|
|
||||||
default:
|
|
||||||
return &ErrInvalidDriverConfig{}
|
|
||||||
}
|
|
||||||
|
|
||||||
d.config = config
|
switch opt := genericData.(type) {
|
||||||
} else {
|
case options.Generic:
|
||||||
config = &configuration{}
|
opaqueConfig, err := options.GenerateFromModel(opt, &configuration{})
|
||||||
d.config = config
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
config = opaqueConfig.(*configuration)
|
||||||
|
case *configuration:
|
||||||
|
config = opt
|
||||||
|
default:
|
||||||
|
return &ErrInvalidDriverConfig{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.EnableIPForwarding {
|
if config.EnableIPForwarding {
|
||||||
|
@ -467,9 +465,13 @@ func (d *driver) Config(option map[string]interface{}) error {
|
||||||
|
|
||||||
if config.EnableIPTables {
|
if config.EnableIPTables {
|
||||||
d.natChain, d.filterChain, err = setupIPChains(config)
|
d.natChain, d.filterChain, err = setupIPChains(config)
|
||||||
return err
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d.configured = true
|
||||||
|
d.config = config
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -566,12 +568,20 @@ func (d *driver) getNetworks() []*bridgeNetwork {
|
||||||
|
|
||||||
// Create a new network using bridge plugin
|
// Create a new network using bridge plugin
|
||||||
func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
|
func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
|
||||||
var err error
|
var (
|
||||||
|
err error
|
||||||
|
configLocked bool
|
||||||
|
)
|
||||||
|
|
||||||
defer osl.InitOSContext()()
|
defer osl.InitOSContext()()
|
||||||
|
|
||||||
// Sanity checks
|
// Sanity checks
|
||||||
d.Lock()
|
d.Lock()
|
||||||
|
if !d.configured {
|
||||||
|
configLocked = true
|
||||||
|
d.configured = true
|
||||||
|
}
|
||||||
|
|
||||||
if _, ok := d.networks[id]; ok {
|
if _, ok := d.networks[id]; ok {
|
||||||
d.Unlock()
|
d.Unlock()
|
||||||
return types.ForbiddenErrorf("network %s exists", id)
|
return types.ForbiddenErrorf("network %s exists", id)
|
||||||
|
@ -610,6 +620,10 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
|
||||||
defer func() {
|
defer func() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
d.Lock()
|
d.Lock()
|
||||||
|
if configLocked {
|
||||||
|
d.configured = false
|
||||||
|
}
|
||||||
|
|
||||||
delete(d.networks, id)
|
delete(d.networks, id)
|
||||||
d.Unlock()
|
d.Unlock()
|
||||||
}
|
}
|
||||||
|
@ -651,7 +665,7 @@ func (d *driver) CreateNetwork(id string, option map[string]interface{}) error {
|
||||||
bridgeSetup.queueStep(setupBridgeIPv4)
|
bridgeSetup.queueStep(setupBridgeIPv4)
|
||||||
|
|
||||||
enableIPv6Forwarding := false
|
enableIPv6Forwarding := false
|
||||||
if d.config != nil && d.config.EnableIPForwarding && config.FixedCIDRv6 != nil {
|
if d.config.EnableIPForwarding && config.FixedCIDRv6 != nil {
|
||||||
enableIPv6Forwarding = true
|
enableIPv6Forwarding = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,19 @@ func TestCreateFullOptions(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateNoConfig(t *testing.T) {
|
||||||
|
defer osl.SetupTestOSContext(t)()
|
||||||
|
d := newDriver()
|
||||||
|
|
||||||
|
netconfig := &networkConfiguration{BridgeName: DefaultBridgeName}
|
||||||
|
genericOption := make(map[string]interface{})
|
||||||
|
genericOption[netlabel.GenericData] = netconfig
|
||||||
|
|
||||||
|
if err := d.CreateNetwork("dummy", genericOption); err != nil {
|
||||||
|
t.Fatalf("Failed to create bridge: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCreate(t *testing.T) {
|
func TestCreate(t *testing.T) {
|
||||||
defer testutils.SetupTestOSContext(t)()
|
defer testutils.SetupTestOSContext(t)()
|
||||||
d := newDriver()
|
d := newDriver()
|
||||||
|
|
Loading…
Add table
Reference in a new issue