diff --git a/hack/vendor.sh b/hack/vendor.sh index 4148805109..a3b74d0e2c 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -22,7 +22,7 @@ clone git github.com/tchap/go-patricia v2.1.0 clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://github.com/golang/net.git #get libnetwork packages -clone git github.com/docker/libnetwork 70409acbcd661e6a7bfe04e2b81412a465d29512 +clone git github.com/docker/libnetwork c3a9e0d8d0c53f3db251620e5f48470e267f292b clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4 @@ -32,6 +32,7 @@ clone git github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25 clone git github.com/vishvananda/netlink 4b5dce31de6d42af5bb9811c6d265472199e0fec clone git github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060 clone git github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374 +clone git github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d clone git github.com/coreos/go-etcd v2.0.0 clone git github.com/hashicorp/consul v0.5.2 clone git github.com/boltdb/bolt v1.0 diff --git a/vendor/src/github.com/deckarep/golang-set/.gitignore b/vendor/src/github.com/deckarep/golang-set/.gitignore new file mode 100644 index 0000000000..00268614f0 --- /dev/null +++ b/vendor/src/github.com/deckarep/golang-set/.gitignore @@ -0,0 +1,22 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe diff --git a/vendor/src/github.com/deckarep/golang-set/.travis.yml b/vendor/src/github.com/deckarep/golang-set/.travis.yml new file mode 100644 index 0000000000..db1359c72e --- /dev/null +++ b/vendor/src/github.com/deckarep/golang-set/.travis.yml @@ -0,0 +1,9 @@ +language: go + +go: + - 1.2 + +script: + - go test ./... + #- go test -race ./... + diff --git a/vendor/src/github.com/deckarep/golang-set/LICENSE b/vendor/src/github.com/deckarep/golang-set/LICENSE new file mode 100644 index 0000000000..b5768f89cf --- /dev/null +++ b/vendor/src/github.com/deckarep/golang-set/LICENSE @@ -0,0 +1,22 @@ +Open Source Initiative OSI - The MIT License (MIT):Licensing + +The MIT License (MIT) +Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/vendor/src/github.com/deckarep/golang-set/README.md b/vendor/src/github.com/deckarep/golang-set/README.md new file mode 100644 index 0000000000..744b1841cd --- /dev/null +++ b/vendor/src/github.com/deckarep/golang-set/README.md @@ -0,0 +1,94 @@ +[![Build Status](https://travis-ci.org/deckarep/golang-set.png?branch=master)](https://travis-ci.org/deckarep/golang-set) +[![GoDoc](https://godoc.org/github.com/deckarep/golang-set?status.png)](http://godoc.org/github.com/deckarep/golang-set) + +## golang-set + + +The missing set collection for the Go language. Until Go has sets built-in...use this. + +Coming from Python one of the things I miss is the superbly wonderful set collection. This is my attempt to mimic the primary features of the set from Python. +You can of course argue that there is no need for a set in Go, otherwise the creators would have added one to the standard library. To those I say simply ignore this repository +and carry-on and to the rest that find this useful please contribute in helping me make it better by: + +* Helping to make more idiomatic improvements to the code. +* Helping to increase the performance of it. ~~(So far, no attempt has been made, but since it uses a map internally, I expect it to be mostly performant.)~~ +* Helping to make the unit-tests more robust and kick-ass. +* Helping to fill in the [documentation.](http://godoc.org/github.com/deckarep/golang-set) +* Simply offering feedback and suggestions. (Positive, constructive feedback is appreciated.) + +I have to give some credit for helping seed the idea with this post on [stackoverflow.](http://programmers.stackexchange.com/questions/177428/sets-data-structure-in-golang) + +*Update* - as of 3/9/2014, you can use a compile-time generic version of this package in the [gen](http://clipperhouse.github.io/gen/) framework. This framework allows you to use the golang-set in a completely generic and type-safe way by allowing you to generate a supporting .go file based on your custom types. + +## Features (as of 9/22/2014) + +* a CartesionProduct() method has been added with unit-tests: [Read more about the cartesion product](http://en.wikipedia.org/wiki/Cartesian_product) + +## Features (as of 9/15/2014) + +* a PowerSet() method has been added with unit-tests: [Read more about the Power set](http://en.wikipedia.org/wiki/Power_set) + +## Features (as of 4/22/2014) + +* One common interface to both implementations +* Two set implementations to choose from + * a thread-safe implementation designed for concurrent use + * a non-thread-safe implementation designed for performance +* 75 benchmarks for both implementations +* 35 unit tests for both implementations +* 14 concurrent tests for the thread-safe implementation + + + +Please see the unit test file for additional usage examples. The Python set documentation will also do a better job than I can of explaining how a set typically [works.](http://docs.python.org/2/library/sets.html) Please keep in mind +however that the Python set is a built-in type and supports additional features and syntax that make it awesome. + +## Examples but not exhaustive: + +```go +requiredClasses := mapset.NewSet() +requiredClasses.Add("Cooking") +requiredClasses.Add("English") +requiredClasses.Add("Math") +requiredClasses.Add("Biology") + +scienceSlice := []interface{}{"Biology", "Chemistry"} +scienceClasses := mapset.NewSetFromSlice(scienceSlice) + +electiveClasses := mapset.NewSet() +electiveClasses.Add("Welding") +electiveClasses.Add("Music") +electiveClasses.Add("Automotive") + +bonusClasses := mapset.NewSet() +bonusClasses.Add("Go Programming") +bonusClasses.Add("Python Programming") + +//Show me all the available classes I can take +allClasses := requiredClasses.Union(scienceClasses).Union(electiveClasses).Union(bonusClasses) +fmt.Println(allClasses) //Set{Cooking, English, Math, Chemistry, Welding, Biology, Music, Automotive, Go Programming, Python Programming} + + +//Is cooking considered a science class? +fmt.Println(scienceClasses.Contains("Cooking")) //false + +//Show me all classes that are not science classes, since I hate science. +fmt.Println(allClasses.Difference(scienceClasses)) //Set{Music, Automotive, Go Programming, Python Programming, Cooking, English, Math, Welding} + +//Which science classes are also required classes? +fmt.Println(scienceClasses.Intersect(requiredClasses)) //Set{Biology} + +//How many bonus classes do you offer? +fmt.Println(bonusClasses.Cardinality()) //2 + +//Do you have the following classes? Welding, Automotive and English? +fmt.Println(allClasses.IsSuperset(mapset.NewSetFromSlice([]interface{}{"Welding", "Automotive", "English"}))) //true +``` + +Thanks! + +-Ralph + +[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/deckarep/golang-set/trend.png)](https://bitdeli.com/free "Bitdeli Badge") + +[![Analytics](https://ga-beacon.appspot.com/UA-42584447-2/deckarep/golang-set)](https://github.com/igrigorik/ga-beacon) diff --git a/vendor/src/github.com/deckarep/golang-set/set.go b/vendor/src/github.com/deckarep/golang-set/set.go new file mode 100644 index 0000000000..eccba70e44 --- /dev/null +++ b/vendor/src/github.com/deckarep/golang-set/set.go @@ -0,0 +1,168 @@ +/* +Open Source Initiative OSI - The MIT License (MIT):Licensing + +The MIT License (MIT) +Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +// Package mapset implements a simple and generic set collection. +// Items stored within it are unordered and unique. It supports +// typical set operations: membership testing, intersection, union, +// difference, symmetric difference and cloning. +// +// Package mapset provides two implementations. The default +// implementation is safe for concurrent access. There is a non-threadsafe +// implementation which is slightly more performant. +package mapset + +type Set interface { + // Adds an element to the set. Returns whether + // the item was added. + Add(i interface{}) bool + + // Returns the number of elements in the set. + Cardinality() int + + // Removes all elements from the set, leaving + // the emtpy set. + Clear() + + // Returns a clone of the set using the same + // implementation, duplicating all keys. + Clone() Set + + // Returns whether the given items + // are all in the set. + Contains(i ...interface{}) bool + + // Returns the difference between this set + // and other. The returned set will contain + // all elements of this set that are not also + // elements of other. + // + // Note that the argument to Difference + // must be of the same type as the receiver + // of the method. Otherwise, Difference will + // panic. + Difference(other Set) Set + + // Determines if two sets are equal to each + // other. If they have the same cardinality + // and contain the same elements, they are + // considered equal. The order in which + // the elements were added is irrelevant. + // + // Note that the argument to Equal must be + // of the same type as the receiver of the + // method. Otherwise, Equal will panic. + Equal(other Set) bool + + // Returns a new set containing only the elements + // that exist only in both sets. + // + // Note that the argument to Intersect + // must be of the same type as the receiver + // of the method. Otherwise, Intersect will + // panic. + Intersect(other Set) Set + + // Determines if every element in the other set + // is in this set. + // + // Note that the argument to IsSubset + // must be of the same type as the receiver + // of the method. Otherwise, IsSubset will + // panic. + IsSubset(other Set) bool + + // Determines if every element in this set is in + // the other set. + // + // Note that the argument to IsSuperset + // must be of the same type as the receiver + // of the method. Otherwise, IsSuperset will + // panic. + IsSuperset(other Set) bool + + // Returns a channel of elements that you can + // range over. + Iter() <-chan interface{} + + // Remove a single element from the set. + Remove(i interface{}) + + // Provides a convenient string representation + // of the current state of the set. + String() string + + // Returns a new set with all elements which are + // in either this set or the other set but not in both. + // + // Note that the argument to SymmetricDifference + // must be of the same type as the receiver + // of the method. Otherwise, SymmetricDifference + // will panic. + SymmetricDifference(other Set) Set + + // Returns a new set with all elements in both sets. + // + // Note that the argument to Union must be of the + // same type as the receiver of the method. + // Otherwise, IsSuperset will panic. + Union(other Set) Set + + // Returns all subsets of a given set (Power Set). + PowerSet() Set + + // Returns the Cartesian Product of two sets. + CartesianProduct(other Set) Set + + // Returns the members of the set as a slice. + ToSlice() []interface{} +} + +// Creates and returns a reference to an empty set. +func NewSet() Set { + set := newThreadSafeSet() + return &set +} + +// Creates and returns a reference to a set from an existing slice +func NewSetFromSlice(s []interface{}) Set { + a := NewSet() + for _, item := range s { + a.Add(item) + } + return a +} + +func NewThreadUnsafeSet() Set { + set := newThreadUnsafeSet() + return &set +} + +func NewThreadUnsafeSetFromSlice(s []interface{}) Set { + a := NewThreadUnsafeSet() + for _, item := range s { + a.Add(item) + } + return a +} diff --git a/vendor/src/github.com/deckarep/golang-set/threadsafe.go b/vendor/src/github.com/deckarep/golang-set/threadsafe.go new file mode 100644 index 0000000000..9dca94af73 --- /dev/null +++ b/vendor/src/github.com/deckarep/golang-set/threadsafe.go @@ -0,0 +1,204 @@ +/* +Open Source Initiative OSI - The MIT License (MIT):Licensing + +The MIT License (MIT) +Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +package mapset + +import "sync" + +type threadSafeSet struct { + s threadUnsafeSet + sync.RWMutex +} + +func newThreadSafeSet() threadSafeSet { + return threadSafeSet{s: newThreadUnsafeSet()} +} + +func (set *threadSafeSet) Add(i interface{}) bool { + set.Lock() + ret := set.s.Add(i) + set.Unlock() + return ret +} + +func (set *threadSafeSet) Contains(i ...interface{}) bool { + set.RLock() + ret := set.s.Contains(i...) + set.RUnlock() + return ret +} + +func (set *threadSafeSet) IsSubset(other Set) bool { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + ret := set.s.IsSubset(&o.s) + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) IsSuperset(other Set) bool { + return other.IsSubset(set) +} + +func (set *threadSafeSet) Union(other Set) Set { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + unsafeUnion := set.s.Union(&o.s).(*threadUnsafeSet) + ret := &threadSafeSet{s: *unsafeUnion} + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) Intersect(other Set) Set { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + unsafeIntersection := set.s.Intersect(&o.s).(*threadUnsafeSet) + ret := &threadSafeSet{s: *unsafeIntersection} + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) Difference(other Set) Set { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + unsafeDifference := set.s.Difference(&o.s).(*threadUnsafeSet) + ret := &threadSafeSet{s: *unsafeDifference} + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) SymmetricDifference(other Set) Set { + o := other.(*threadSafeSet) + + unsafeDifference := set.s.SymmetricDifference(&o.s).(*threadUnsafeSet) + return &threadSafeSet{s: *unsafeDifference} +} + +func (set *threadSafeSet) Clear() { + set.Lock() + set.s = newThreadUnsafeSet() + set.Unlock() +} + +func (set *threadSafeSet) Remove(i interface{}) { + set.Lock() + delete(set.s, i) + set.Unlock() +} + +func (set *threadSafeSet) Cardinality() int { + set.RLock() + defer set.RUnlock() + return len(set.s) +} + +func (set *threadSafeSet) Iter() <-chan interface{} { + ch := make(chan interface{}) + go func() { + set.RLock() + + for elem := range set.s { + ch <- elem + } + close(ch) + set.RUnlock() + }() + + return ch +} + +func (set *threadSafeSet) Equal(other Set) bool { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + ret := set.s.Equal(&o.s) + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) Clone() Set { + set.RLock() + + unsafeClone := set.s.Clone().(*threadUnsafeSet) + ret := &threadSafeSet{s: *unsafeClone} + set.RUnlock() + return ret +} + +func (set *threadSafeSet) String() string { + set.RLock() + ret := set.s.String() + set.RUnlock() + return ret +} + +func (set *threadSafeSet) PowerSet() Set { + set.RLock() + ret := set.s.PowerSet() + set.RUnlock() + return ret +} + +func (set *threadSafeSet) CartesianProduct(other Set) Set { + o := other.(*threadSafeSet) + + set.RLock() + o.RLock() + + unsafeCartProduct := set.s.CartesianProduct(&o.s).(*threadUnsafeSet) + ret := &threadSafeSet{s: *unsafeCartProduct} + set.RUnlock() + o.RUnlock() + return ret +} + +func (set *threadSafeSet) ToSlice() []interface{} { + set.RLock() + keys := make([]interface{}, 0, set.Cardinality()) + for elem := range set.s { + keys = append(keys, elem) + } + set.RUnlock() + return keys +} diff --git a/vendor/src/github.com/deckarep/golang-set/threadunsafe.go b/vendor/src/github.com/deckarep/golang-set/threadunsafe.go new file mode 100644 index 0000000000..124521e2ee --- /dev/null +++ b/vendor/src/github.com/deckarep/golang-set/threadunsafe.go @@ -0,0 +1,246 @@ +/* +Open Source Initiative OSI - The MIT License (MIT):Licensing + +The MIT License (MIT) +Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +package mapset + +import ( + "fmt" + "reflect" + "strings" +) + +type threadUnsafeSet map[interface{}]struct{} + +type orderedPair struct { + first interface{} + second interface{} +} + +func newThreadUnsafeSet() threadUnsafeSet { + return make(threadUnsafeSet) +} + +func (pair *orderedPair) Equal(other orderedPair) bool { + if pair.first == other.first && + pair.second == other.second { + return true + } + + return false +} + +func (set *threadUnsafeSet) Add(i interface{}) bool { + _, found := (*set)[i] + (*set)[i] = struct{}{} + return !found //False if it existed already +} + +func (set *threadUnsafeSet) Contains(i ...interface{}) bool { + for _, val := range i { + if _, ok := (*set)[val]; !ok { + return false + } + } + return true +} + +func (set *threadUnsafeSet) IsSubset(other Set) bool { + _ = other.(*threadUnsafeSet) + for elem := range *set { + if !other.Contains(elem) { + return false + } + } + return true +} + +func (set *threadUnsafeSet) IsSuperset(other Set) bool { + return other.IsSubset(set) +} + +func (set *threadUnsafeSet) Union(other Set) Set { + o := other.(*threadUnsafeSet) + + unionedSet := newThreadUnsafeSet() + + for elem := range *set { + unionedSet.Add(elem) + } + for elem := range *o { + unionedSet.Add(elem) + } + return &unionedSet +} + +func (set *threadUnsafeSet) Intersect(other Set) Set { + o := other.(*threadUnsafeSet) + + intersection := newThreadUnsafeSet() + // loop over smaller set + if set.Cardinality() < other.Cardinality() { + for elem := range *set { + if other.Contains(elem) { + intersection.Add(elem) + } + } + } else { + for elem := range *o { + if set.Contains(elem) { + intersection.Add(elem) + } + } + } + return &intersection +} + +func (set *threadUnsafeSet) Difference(other Set) Set { + _ = other.(*threadUnsafeSet) + + difference := newThreadUnsafeSet() + for elem := range *set { + if !other.Contains(elem) { + difference.Add(elem) + } + } + return &difference +} + +func (set *threadUnsafeSet) SymmetricDifference(other Set) Set { + _ = other.(*threadUnsafeSet) + + aDiff := set.Difference(other) + bDiff := other.Difference(set) + return aDiff.Union(bDiff) +} + +func (set *threadUnsafeSet) Clear() { + *set = newThreadUnsafeSet() +} + +func (set *threadUnsafeSet) Remove(i interface{}) { + delete(*set, i) +} + +func (set *threadUnsafeSet) Cardinality() int { + return len(*set) +} + +func (set *threadUnsafeSet) Iter() <-chan interface{} { + ch := make(chan interface{}) + go func() { + for elem := range *set { + ch <- elem + } + close(ch) + }() + + return ch +} + +func (set *threadUnsafeSet) Equal(other Set) bool { + _ = other.(*threadUnsafeSet) + + if set.Cardinality() != other.Cardinality() { + return false + } + for elem := range *set { + if !other.Contains(elem) { + return false + } + } + return true +} + +func (set *threadUnsafeSet) Clone() Set { + clonedSet := newThreadUnsafeSet() + for elem := range *set { + clonedSet.Add(elem) + } + return &clonedSet +} + +func (set *threadUnsafeSet) String() string { + items := make([]string, 0, len(*set)) + + for elem := range *set { + items = append(items, fmt.Sprintf("%v", elem)) + } + return fmt.Sprintf("Set{%s}", strings.Join(items, ", ")) +} + +func (pair orderedPair) String() string { + return fmt.Sprintf("(%v, %v)", pair.first, pair.second) +} + +func (set *threadUnsafeSet) PowerSet() Set { + powSet := NewThreadUnsafeSet() + nullset := newThreadUnsafeSet() + powSet.Add(&nullset) + + for es := range *set { + u := newThreadUnsafeSet() + j := powSet.Iter() + for er := range j { + p := newThreadUnsafeSet() + if reflect.TypeOf(er).Name() == "" { + k := er.(*threadUnsafeSet) + for ek := range *(k) { + p.Add(ek) + } + } else { + p.Add(er) + } + p.Add(es) + u.Add(&p) + } + + powSet = powSet.Union(&u) + } + + return powSet +} + +func (set *threadUnsafeSet) CartesianProduct(other Set) Set { + o := other.(*threadUnsafeSet) + cartProduct := NewThreadUnsafeSet() + + for i := range *set { + for j := range *o { + elem := orderedPair{first: i, second: j} + cartProduct.Add(elem) + } + } + + return cartProduct +} + +func (set *threadUnsafeSet) ToSlice() []interface{} { + keys := make([]interface{}, 0, set.Cardinality()) + for elem := range *set { + keys = append(keys, elem) + } + + return keys +} diff --git a/vendor/src/github.com/docker/libnetwork/config/config.go b/vendor/src/github.com/docker/libnetwork/config/config.go index 3163800174..96c8dab677 100644 --- a/vendor/src/github.com/docker/libnetwork/config/config.go +++ b/vendor/src/github.com/docker/libnetwork/config/config.go @@ -5,6 +5,7 @@ import ( "github.com/BurntSushi/toml" log "github.com/Sirupsen/logrus" + "github.com/docker/docker/pkg/discovery" "github.com/docker/libkv/store" "github.com/docker/libnetwork/netlabel" ) @@ -27,8 +28,9 @@ type DaemonCfg struct { // ClusterCfg represents cluster configuration type ClusterCfg struct { - Discovery string + Watcher discovery.Watcher Address string + Discovery string Heartbeat uint64 } @@ -108,6 +110,20 @@ func OptionKVProviderURL(url string) Option { } } +// OptionDiscoveryWatcher function returns an option setter for discovery watcher +func OptionDiscoveryWatcher(watcher discovery.Watcher) Option { + return func(c *Config) { + c.Cluster.Watcher = watcher + } +} + +// OptionDiscoveryAddress function returns an option setter for self discovery address +func OptionDiscoveryAddress(address string) Option { + return func(c *Config) { + c.Cluster.Address = address + } +} + // ProcessOptions processes options and stores it in config func (c *Config) ProcessOptions(options ...Option) { for _, opt := range options { diff --git a/vendor/src/github.com/docker/libnetwork/controller.go b/vendor/src/github.com/docker/libnetwork/controller.go index a646281e7c..9a364c5413 100644 --- a/vendor/src/github.com/docker/libnetwork/controller.go +++ b/vendor/src/github.com/docker/libnetwork/controller.go @@ -47,9 +47,11 @@ import ( "container/heap" "fmt" "net" + "strings" "sync" log "github.com/Sirupsen/logrus" + "github.com/docker/docker/pkg/discovery" "github.com/docker/docker/pkg/plugins" "github.com/docker/docker/pkg/stringid" "github.com/docker/libnetwork/config" @@ -126,6 +128,7 @@ type controller struct { sandboxes sandboxTable cfg *config.Config globalStore, localStore datastore.DataStore + discovery hostdiscovery.HostDiscovery extKeyListener net.Listener sync.Mutex } @@ -157,7 +160,7 @@ func New(cfgOptions ...config.Option) (NetworkController, error) { // But it cannot fail creating the Controller log.Debugf("Failed to Initialize Datastore due to %v. Operating in non-clustered mode", err) } - if err := c.initDiscovery(); err != nil { + if err := c.initDiscovery(cfg.Cluster.Watcher); err != nil { // Failing to initalize discovery is a bad situation to be in. // But it cannot fail creating the Controller log.Debugf("Failed to Initialize Discovery : %v", err) @@ -185,19 +188,57 @@ func (c *controller) validateHostDiscoveryConfig() bool { return true } -func (c *controller) initDiscovery() error { +func (c *controller) initDiscovery(watcher discovery.Watcher) error { if c.cfg == nil { return fmt.Errorf("discovery initialization requires a valid configuration") } - hostDiscovery := hostdiscovery.NewHostDiscovery() - return hostDiscovery.StartDiscovery(&c.cfg.Cluster, c.hostJoinCallback, c.hostLeaveCallback) + c.discovery = hostdiscovery.NewHostDiscovery(watcher) + return c.discovery.Watch(c.hostJoinCallback, c.hostLeaveCallback) } -func (c *controller) hostJoinCallback(hosts []net.IP) { +func (c *controller) hostJoinCallback(nodes []net.IP) { + c.processNodeDiscovery(nodes, true) } -func (c *controller) hostLeaveCallback(hosts []net.IP) { +func (c *controller) hostLeaveCallback(nodes []net.IP) { + c.processNodeDiscovery(nodes, false) +} + +func (c *controller) processNodeDiscovery(nodes []net.IP, add bool) { + c.Lock() + drivers := []*driverData{} + for _, d := range c.drivers { + drivers = append(drivers, d) + } + c.Unlock() + + for _, d := range drivers { + c.pushNodeDiscovery(d, nodes, add) + } +} + +func (c *controller) pushNodeDiscovery(d *driverData, nodes []net.IP, add bool) { + var self net.IP + if c.cfg != nil { + addr := strings.Split(c.cfg.Cluster.Address, ":") + self = net.ParseIP(addr[0]) + } + if d == nil || d.capability.DataScope != datastore.GlobalScope || nodes == nil { + return + } + for _, node := range nodes { + nodeData := driverapi.NodeDiscoveryData{Address: node.String(), Self: node.Equal(self)} + var err error + if add { + err = d.driver.DiscoverNew(driverapi.NodeDiscovery, nodeData) + } else { + err = d.driver.DiscoverDelete(driverapi.NodeDiscovery, nodeData) + } + if err != nil { + log.Debugf("discovery notification error : %v", err) + } + } } func (c *controller) Config() config.Config { @@ -219,9 +260,15 @@ func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver, c.Unlock() return driverapi.ErrActiveRegistration(networkType) } - c.drivers[networkType] = &driverData{driver, capability} + dData := &driverData{driver, capability} + c.drivers[networkType] = dData + hd := c.discovery c.Unlock() + if hd != nil { + c.pushNodeDiscovery(dData, hd.Fetch(), true) + } + return nil } @@ -487,6 +534,16 @@ func (c *controller) loadDriver(networkType string) (*driverData, error) { return dd, nil } +func (c *controller) getDriver(networkType string) (*driverData, error) { + c.Lock() + defer c.Unlock() + dd, ok := c.drivers[networkType] + if !ok { + return nil, types.NotFoundErrorf("driver %s not found", networkType) + } + return dd, nil +} + func (c *controller) Stop() { if c.localStore != nil { c.localStore.KVStore().Close() diff --git a/vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go b/vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go index 054442e753..1661c3672f 100644 --- a/vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go +++ b/vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go @@ -40,6 +40,12 @@ type Driver interface { // Leave method is invoked when a Sandbox detaches from an endpoint. Leave(nid, eid string) error + // DiscoverNew is a notification for a new discovery event, Example:a new node joining a cluster + DiscoverNew(dType DiscoveryType, data interface{}) error + + // DiscoverDelete is a notification for a discovery delete event, Example:a node leaving a cluster + DiscoverDelete(dType DiscoveryType, data interface{}) error + // Type returns the the type of this driver, the network type this driver manages Type() string } @@ -106,3 +112,17 @@ type DriverCallback interface { type Capability struct { DataScope datastore.DataScope } + +// DiscoveryType represents the type of discovery element the DiscoverNew function is invoked on +type DiscoveryType int + +const ( + // NodeDiscovery represents Node join/leave events provided by discovery + NodeDiscovery = iota + 1 +) + +// NodeDiscoveryData represents the structure backing the node discovery data json string +type NodeDiscoveryData struct { + Address string + Self bool +} diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go index 87380101dd..71cc0e7fce 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go @@ -1375,6 +1375,16 @@ func (d *driver) Type() string { return networkType } +// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster +func (d *driver) DiscoverNew(dType driverapi.DiscoveryType, data interface{}) error { + return nil +} + +// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster +func (d *driver) DiscoverDelete(dType driverapi.DiscoveryType, data interface{}) error { + return nil +} + func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfiguration, error) { if epOptions == nil { return nil, nil diff --git a/vendor/src/github.com/docker/libnetwork/drivers/host/host.go b/vendor/src/github.com/docker/libnetwork/drivers/host/host.go index 747bdc62c9..2549ed866e 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/host/host.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/host/host.go @@ -65,3 +65,13 @@ func (d *driver) Leave(nid, eid string) error { func (d *driver) Type() string { return networkType } + +// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster +func (d *driver) DiscoverNew(dType driverapi.DiscoveryType, data interface{}) error { + return nil +} + +// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster +func (d *driver) DiscoverDelete(dType driverapi.DiscoveryType, data interface{}) error { + return nil +} diff --git a/vendor/src/github.com/docker/libnetwork/drivers/null/null.go b/vendor/src/github.com/docker/libnetwork/drivers/null/null.go index 6f472e78a4..670fc68672 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/null/null.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/null/null.go @@ -65,3 +65,13 @@ func (d *driver) Leave(nid, eid string) error { func (d *driver) Type() string { return networkType } + +// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster +func (d *driver) DiscoverNew(dType driverapi.DiscoveryType, data interface{}) error { + return nil +} + +// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster +func (d *driver) DiscoverDelete(dType driverapi.DiscoveryType, data interface{}) error { + return nil +} diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go index c563b59a69..9fa73f1c33 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go @@ -2,6 +2,7 @@ package overlay import ( "fmt" + "net" "github.com/docker/libnetwork/driverapi" "github.com/vishvananda/netlink" @@ -73,12 +74,8 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo, } d.peerDbAdd(nid, eid, ep.addr.IP, ep.mac, - d.serfInstance.LocalMember().Addr, true) - d.notifyCh <- ovNotify{ - action: "join", - nid: nid, - eid: eid, - } + net.ParseIP(d.bindAddress), true) + d.pushLocalEndpointEvent("join", nid, eid) return nil } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go index 72a97670f4..9e5f9d8909 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go @@ -156,23 +156,8 @@ func (n *network) initSandbox() error { return fmt.Errorf("could not create bridge inside the network sandbox: %v", err) } - vxlanName, err := createVxlan(n.vxlanID()) - if err != nil { - return err - } - - if err := sbox.AddInterface(vxlanName, "vxlan", - sbox.InterfaceOptions().Master("bridge1")); err != nil { - return fmt.Errorf("could not add vxlan interface inside the network sandbox: %v", - err) - } - - n.vxlanName = vxlanName - n.setSandbox(sbox) - n.driver.peerDbUpdateSandbox(n.id) - var nlSock *nl.NetlinkSocket sbox.InvokeFunc(func() { nlSock, err = nl.Subscribe(syscall.NETLINK_ROUTE, syscall.RTNLGRP_NEIGH) @@ -182,7 +167,27 @@ func (n *network) initSandbox() error { }) go n.watchMiss(nlSock) + return n.initVxlan() +} +func (n *network) initVxlan() error { + var vxlanName string + n.Lock() + sbox := n.sbox + n.Unlock() + + vxlanName, err := createVxlan(n.vxlanID()) + if err != nil { + return err + } + + if err = sbox.AddInterface(vxlanName, "vxlan", + sbox.InterfaceOptions().Master("bridge1")); err != nil { + return fmt.Errorf("could not add vxlan interface inside the network sandbox: %v", err) + } + + n.vxlanName = vxlanName + n.driver.peerDbUpdateSandbox(n.id) return nil } diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_serf.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_serf.go index 453ef2c912..d717c100a6 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_serf.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_serf.go @@ -35,46 +35,12 @@ func (l *logWriter) Write(p []byte) (int, error) { return len(p), nil } -func getBindAddr(ifaceName string) (string, error) { - iface, err := net.InterfaceByName(ifaceName) - if err != nil { - return "", fmt.Errorf("failed to find interface %s: %v", ifaceName, err) - } - - addrs, err := iface.Addrs() - if err != nil { - return "", fmt.Errorf("failed to get interface addresses: %v", err) - } - - for _, a := range addrs { - addr, ok := a.(*net.IPNet) - if !ok { - continue - } - addrIP := addr.IP - - if addrIP.IsLinkLocalUnicast() { - continue - } - - return addrIP.String(), nil - } - - return "", fmt.Errorf("failed to get bind address") -} - func (d *driver) serfInit() error { var err error config := serf.DefaultConfig() config.Init() - if d.ifaceName != "" { - bindAddr, err := getBindAddr(d.ifaceName) - if err != nil { - return fmt.Errorf("getBindAddr error: %v", err) - } - config.MemberlistConfig.BindAddr = bindAddr - } + config.MemberlistConfig.BindAddr = d.bindAddress d.eventCh = make(chan serf.Event, 4) config.EventCh = d.eventCh @@ -93,13 +59,6 @@ func (d *driver) serfInit() error { } }() - if d.neighIP != "" { - if _, err = s.Join([]string{d.neighIP}, false); err != nil { - return fmt.Errorf("Failed to join the cluster at neigh IP %s: %v", - d.neighIP, err) - } - } - d.serfInstance = s d.notifyCh = make(chan ovNotify) @@ -109,6 +68,17 @@ func (d *driver) serfInit() error { return nil } +func (d *driver) serfJoin(neighIP string) error { + if neighIP == "" { + return fmt.Errorf("no neighbor to join") + } + if _, err := d.serfInstance.Join([]string{neighIP}, false); err != nil { + return fmt.Errorf("Failed to join the cluster at neigh IP %s: %v", + neighIP, err) + } + return nil +} + func (d *driver) notifyEvent(event ovNotify) { n := d.network(event.nid) ep := n.endpoint(event.eid) @@ -246,3 +216,13 @@ func (d *driver) startSerfLoop(eventCh chan serf.Event, notifyCh chan ovNotify, } } } + +func (d *driver) isSerfAlive() bool { + d.Lock() + serfInstance := d.serfInstance + d.Unlock() + if serfInstance == nil || serfInstance.State() != serf.SerfAlive { + return false + } + return true +} diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go index 900e370487..4a8a6e0137 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go @@ -6,6 +6,7 @@ import ( "net" "sync" + "github.com/Sirupsen/logrus" "github.com/docker/libkv/store" "github.com/docker/libnetwork/config" "github.com/docker/libnetwork/datastore" @@ -29,7 +30,7 @@ type driver struct { eventCh chan serf.Event notifyCh chan ovNotify exitCh chan chan struct{} - ifaceName string + bindAddress string neighIP string config map[string]interface{} peerDb peerNetworkMap @@ -38,7 +39,8 @@ type driver struct { store datastore.DataStore ipAllocator *idm.Idm vxlanIdm *idm.Idm - sync.Once + once sync.Once + joinOnce sync.Once sync.Mutex } @@ -107,15 +109,7 @@ func (d *driver) configure() error { return nil } - d.Do(func() { - if ifaceName, ok := d.config[netlabel.OverlayBindInterface]; ok { - d.ifaceName = ifaceName.(string) - } - - if neighIP, ok := d.config[netlabel.OverlayNeighborIP]; ok { - d.neighIP = neighIP.(string) - } - + d.once.Do(func() { provider, provOk := d.config[netlabel.KVProvider] provURL, urlOk := d.config[netlabel.KVProviderURL] @@ -148,12 +142,6 @@ func (d *driver) configure() error { err = fmt.Errorf("failed to initalize ipam id manager: %v", err) return } - - err = d.serfInit() - if err != nil { - err = fmt.Errorf("initializing serf instance failed: %v", err) - } - }) return err @@ -162,3 +150,68 @@ func (d *driver) configure() error { func (d *driver) Type() string { return networkType } + +func (d *driver) nodeJoin(node string, self bool) { + if self && !d.isSerfAlive() { + d.Lock() + d.bindAddress = node + d.Unlock() + err := d.serfInit() + if err != nil { + logrus.Errorf("initializing serf instance failed: %v", err) + return + } + } + + d.Lock() + if !self { + d.neighIP = node + } + neighIP := d.neighIP + d.Unlock() + + if d.serfInstance != nil && neighIP != "" { + var err error + d.joinOnce.Do(func() { + err = d.serfJoin(neighIP) + if err == nil { + d.pushLocalDb() + } + }) + if err != nil { + logrus.Errorf("joining serf neighbor %s failed: %v", node, err) + d.Lock() + d.joinOnce = sync.Once{} + d.Unlock() + return + } + } +} + +func (d *driver) pushLocalEndpointEvent(action, nid, eid string) { + if !d.isSerfAlive() { + return + } + d.notifyCh <- ovNotify{ + action: "join", + nid: nid, + eid: eid, + } +} + +// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster +func (d *driver) DiscoverNew(dType driverapi.DiscoveryType, data interface{}) error { + if dType == driverapi.NodeDiscovery { + nodeData, ok := data.(driverapi.NodeDiscoveryData) + if !ok || nodeData.Address == "" { + return fmt.Errorf("invalid discovery data") + } + d.nodeJoin(nodeData.Address, nodeData.Self) + } + return nil +} + +// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster +func (d *driver) DiscoverDelete(dType driverapi.DiscoveryType, data interface{}) error { + return nil +} diff --git a/vendor/src/github.com/docker/libnetwork/drivers/overlay/peerdb.go b/vendor/src/github.com/docker/libnetwork/drivers/overlay/peerdb.go index acb99dc688..7a56009ff7 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/overlay/peerdb.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/overlay/peerdb.go @@ -56,7 +56,23 @@ func (pKey *peerKey) Scan(state fmt.ScanState, verb rune) error { var peerDbWg sync.WaitGroup -func (d *driver) peerDbWalk(nid string, f func(*peerKey, *peerEntry) bool) error { +func (d *driver) peerDbWalk(f func(string, *peerKey, *peerEntry) bool) error { + d.peerDb.Lock() + nids := []string{} + for nid := range d.peerDb.mp { + nids = append(nids, nid) + } + d.peerDb.Unlock() + + for _, nid := range nids { + d.peerDbNetworkWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool { + return f(nid, pKey, pEntry) + }) + } + return nil +} + +func (d *driver) peerDbNetworkWalk(nid string, f func(*peerKey, *peerEntry) bool) error { d.peerDb.Lock() pMap, ok := d.peerDb.mp[nid] if !ok { @@ -89,7 +105,7 @@ func (d *driver) peerDbSearch(nid string, peerIP net.IP) (net.HardwareAddr, net. found bool ) - err := d.peerDbWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool { + err := d.peerDbNetworkWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool { if pKey.peerIP.Equal(peerIP) { peerMac = pKey.peerMac vtep = pEntry.vtep @@ -280,3 +296,12 @@ func (d *driver) peerDelete(nid, eid string, peerIP net.IP, return nil } + +func (d *driver) pushLocalDb() { + d.peerDbWalk(func(nid string, pKey *peerKey, pEntry *peerEntry) bool { + if pEntry.isLocal { + d.pushLocalEndpointEvent("join", nid, pEntry.eid) + } + return false + }) +} diff --git a/vendor/src/github.com/docker/libnetwork/drivers/remote/api/api.go b/vendor/src/github.com/docker/libnetwork/drivers/remote/api/api.go index 2d441ab7d2..2345be0a29 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/remote/api/api.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/remote/api/api.go @@ -4,7 +4,11 @@ with a remote driver. */ package api -import "net" +import ( + "net" + + "github.com/docker/libnetwork/driverapi" +) // Response is the basic response structure used in all responses. type Response struct { @@ -143,3 +147,14 @@ type LeaveRequest struct { type LeaveResponse struct { Response } + +// DiscoveryNotification represents a discovery notification +type DiscoveryNotification struct { + DiscoveryType driverapi.DiscoveryType + DiscoveryData interface{} +} + +// DiscoveryResponse is used by libnetwork to log any plugin error processing the discovery notifications +type DiscoveryResponse struct { + Response +} diff --git a/vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go b/vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go index 5f5a0f5b25..c4eb5e95c8 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go @@ -247,6 +247,30 @@ func (d *driver) Type() string { return d.networkType } +// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster +func (d *driver) DiscoverNew(dType driverapi.DiscoveryType, data interface{}) error { + if dType != driverapi.NodeDiscovery { + return fmt.Errorf("Unknown discovery type : %v", dType) + } + notif := &api.DiscoveryNotification{ + DiscoveryType: dType, + DiscoveryData: data, + } + return d.call("DiscoverNew", notif, &api.DiscoveryResponse{}) +} + +// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster +func (d *driver) DiscoverDelete(dType driverapi.DiscoveryType, data interface{}) error { + if dType != driverapi.NodeDiscovery { + return fmt.Errorf("Unknown discovery type : %v", dType) + } + notif := &api.DiscoveryNotification{ + DiscoveryType: dType, + DiscoveryData: data, + } + return d.call("DiscoverDelete", notif, &api.DiscoveryResponse{}) +} + func parseStaticRoutes(r api.JoinResponse) ([]*types.StaticRoute, error) { var routes = make([]*types.StaticRoute, len(r.StaticRoutes)) for i, inRoute := range r.StaticRoutes { diff --git a/vendor/src/github.com/docker/libnetwork/drivers/windows/windows.go b/vendor/src/github.com/docker/libnetwork/drivers/windows/windows.go index 82fc61b7c0..6872486bf4 100644 --- a/vendor/src/github.com/docker/libnetwork/drivers/windows/windows.go +++ b/vendor/src/github.com/docker/libnetwork/drivers/windows/windows.go @@ -52,3 +52,13 @@ func (d *driver) Leave(nid, eid string) error { func (d *driver) Type() string { return networkType } + +// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster +func (d *driver) DiscoverNew(dType driverapi.DiscoveryType, data interface{}) error { + return nil +} + +// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster +func (d *driver) DiscoverDelete(dType driverapi.DiscoveryType, data interface{}) error { + return nil +} diff --git a/vendor/src/github.com/docker/libnetwork/hostdiscovery/hostdiscovery.go b/vendor/src/github.com/docker/libnetwork/hostdiscovery/hostdiscovery.go index aa39baa834..cb29e45032 100644 --- a/vendor/src/github.com/docker/libnetwork/hostdiscovery/hostdiscovery.go +++ b/vendor/src/github.com/docker/libnetwork/hostdiscovery/hostdiscovery.go @@ -1,73 +1,48 @@ -// +build libnetwork_discovery - package hostdiscovery import ( - "errors" - "fmt" "net" "sync" - "time" log "github.com/Sirupsen/logrus" mapset "github.com/deckarep/golang-set" - "github.com/docker/libnetwork/config" - "github.com/docker/swarm/discovery" - // Anonymous import will be removed after we upgrade to latest swarm - _ "github.com/docker/swarm/discovery/file" - // Anonymous import will be removed after we upgrade to latest swarm - _ "github.com/docker/swarm/discovery/kv" - // Anonymous import will be removed after we upgrade to latest swarm - _ "github.com/docker/swarm/discovery/nodes" - // Anonymous import will be removed after we upgrade to latest swarm - _ "github.com/docker/swarm/discovery/token" + "github.com/docker/docker/pkg/discovery" + // Including KV + _ "github.com/docker/docker/pkg/discovery/kv" + "github.com/docker/libkv/store/consul" + "github.com/docker/libkv/store/etcd" + "github.com/docker/libkv/store/zookeeper" + "github.com/docker/libnetwork/types" ) -const defaultHeartbeat = time.Duration(10) * time.Second -const TTLFactor = 3 - type hostDiscovery struct { - discovery discovery.Discovery - nodes mapset.Set - stopChan chan struct{} + watcher discovery.Watcher + nodes mapset.Set + stopChan chan struct{} sync.Mutex } -// NewHostDiscovery function creates a host discovery object -func NewHostDiscovery() HostDiscovery { - return &hostDiscovery{nodes: mapset.NewSet(), stopChan: make(chan struct{})} +func init() { + consul.Register() + etcd.Register() + zookeeper.Register() } -func (h *hostDiscovery) StartDiscovery(cfg *config.ClusterCfg, joinCallback JoinCallback, leaveCallback LeaveCallback) error { - if cfg == nil { - return fmt.Errorf("discovery requires a valid configuration") - } - - hb := time.Duration(cfg.Heartbeat) * time.Second - if hb == 0 { - hb = defaultHeartbeat - } - d, err := discovery.New(cfg.Discovery, hb, TTLFactor*hb) - if err != nil { - return err - } - - if ip := net.ParseIP(cfg.Address); ip == nil { - return errors.New("address config should be either ipv4 or ipv6 address") - } - - if err := d.Register(cfg.Address + ":0"); err != nil { - return err - } +// NewHostDiscovery function creates a host discovery object +func NewHostDiscovery(watcher discovery.Watcher) HostDiscovery { + return &hostDiscovery{watcher: watcher, nodes: mapset.NewSet(), stopChan: make(chan struct{})} +} +func (h *hostDiscovery) Watch(joinCallback JoinCallback, leaveCallback LeaveCallback) error { h.Lock() - h.discovery = d + d := h.watcher h.Unlock() - + if d == nil { + return types.BadRequestErrorf("invalid discovery watcher") + } discoveryCh, errCh := d.Watch(h.stopChan) go h.monitorDiscovery(discoveryCh, errCh, joinCallback, leaveCallback) - go h.sustainHeartbeat(d, hb, cfg) return nil } @@ -77,7 +52,9 @@ func (h *hostDiscovery) monitorDiscovery(ch <-chan discovery.Entries, errCh <-ch case entries := <-ch: h.processCallback(entries, joinCallback, leaveCallback) case err := <-errCh: - log.Errorf("discovery error: %v", err) + if err != nil { + log.Errorf("discovery error: %v", err) + } case <-h.stopChan: return } @@ -87,26 +64,13 @@ func (h *hostDiscovery) monitorDiscovery(ch <-chan discovery.Entries, errCh <-ch func (h *hostDiscovery) StopDiscovery() error { h.Lock() stopChan := h.stopChan - h.discovery = nil + h.watcher = nil h.Unlock() close(stopChan) return nil } -func (h *hostDiscovery) sustainHeartbeat(d discovery.Discovery, hb time.Duration, config *config.ClusterCfg) { - for { - select { - case <-h.stopChan: - return - case <-time.After(hb): - if err := d.Register(config.Address + ":0"); err != nil { - log.Warn(err) - } - } - } -} - func (h *hostDiscovery) processCallback(entries discovery.Entries, joinCallback JoinCallback, leaveCallback LeaveCallback) { updated := hosts(entries) h.Lock() @@ -135,14 +99,14 @@ func diff(existing mapset.Set, updated mapset.Set) (added []net.IP, removed []ne return } -func (h *hostDiscovery) Fetch() ([]net.IP, error) { +func (h *hostDiscovery) Fetch() []net.IP { h.Lock() defer h.Unlock() ips := []net.IP{} for _, ipstr := range h.nodes.ToSlice() { ips = append(ips, net.ParseIP(ipstr.(string))) } - return ips, nil + return ips } func hosts(entries discovery.Entries) mapset.Set { diff --git a/vendor/src/github.com/docker/libnetwork/hostdiscovery/hostdiscovery_api.go b/vendor/src/github.com/docker/libnetwork/hostdiscovery/hostdiscovery_api.go index 09394e09bc..5be520fca8 100644 --- a/vendor/src/github.com/docker/libnetwork/hostdiscovery/hostdiscovery_api.go +++ b/vendor/src/github.com/docker/libnetwork/hostdiscovery/hostdiscovery_api.go @@ -1,10 +1,6 @@ package hostdiscovery -import ( - "net" - - "github.com/docker/libnetwork/config" -) +import "net" // JoinCallback provides a callback event for new node joining the cluster type JoinCallback func(entries []net.IP) @@ -14,10 +10,10 @@ type LeaveCallback func(entries []net.IP) // HostDiscovery primary interface type HostDiscovery interface { - // StartDiscovery initiates the discovery process and provides appropriate callbacks - StartDiscovery(*config.ClusterCfg, JoinCallback, LeaveCallback) error + //Watch Node join and leave cluster events + Watch(joinCallback JoinCallback, leaveCallback LeaveCallback) error // StopDiscovery stops the discovery perocess StopDiscovery() error // Fetch returns a list of host IPs that are currently discovered - Fetch() ([]net.IP, error) + Fetch() []net.IP } diff --git a/vendor/src/github.com/docker/libnetwork/hostdiscovery/hostdiscovery_disabled.go b/vendor/src/github.com/docker/libnetwork/hostdiscovery/hostdiscovery_disabled.go deleted file mode 100644 index 2dc67ccb0f..0000000000 --- a/vendor/src/github.com/docker/libnetwork/hostdiscovery/hostdiscovery_disabled.go +++ /dev/null @@ -1,28 +0,0 @@ -// +build !libnetwork_discovery - -package hostdiscovery - -import ( - "net" - - "github.com/docker/libnetwork/config" -) - -type hostDiscovery struct{} - -// NewHostDiscovery function creates a host discovery object -func NewHostDiscovery() HostDiscovery { - return &hostDiscovery{} -} - -func (h *hostDiscovery) StartDiscovery(cfg *config.ClusterCfg, joinCallback JoinCallback, leaveCallback LeaveCallback) error { - return nil -} - -func (h *hostDiscovery) StopDiscovery() error { - return nil -} - -func (h *hostDiscovery) Fetch() ([]net.IP, error) { - return []net.IP{}, nil -} diff --git a/vendor/src/github.com/docker/libnetwork/hostdiscovery/libnetwork.toml b/vendor/src/github.com/docker/libnetwork/hostdiscovery/libnetwork.toml index b8c6854103..7839d1e3a8 100644 --- a/vendor/src/github.com/docker/libnetwork/hostdiscovery/libnetwork.toml +++ b/vendor/src/github.com/docker/libnetwork/hostdiscovery/libnetwork.toml @@ -1,6 +1,6 @@ title = "LibNetwork Configuration file" [cluster] - discovery = "token://08469efb104bce980931ed24c8eb03a2" - Address = "1.1.1.1" + discovery = "consul://localhost:8500" + Address = "6.5.5.5" Heartbeat = 3