Browse Source

Vendoring in libnetwork integrated with Docker Discovery

This commit brings in end to end integration of Docker Discovery with
libnetwork multi-host networking.

Signed-off-by: Madhu Venugopal <madhu@docker.com>
Madhu Venugopal 9 years ago
parent
commit
956fbccdaa
26 changed files with 1125 additions and 195 deletions
  1. 2 1
      hack/vendor.sh
  2. 22 0
      vendor/src/github.com/deckarep/golang-set/.gitignore
  3. 9 0
      vendor/src/github.com/deckarep/golang-set/.travis.yml
  4. 22 0
      vendor/src/github.com/deckarep/golang-set/LICENSE
  5. 94 0
      vendor/src/github.com/deckarep/golang-set/README.md
  6. 168 0
      vendor/src/github.com/deckarep/golang-set/set.go
  7. 204 0
      vendor/src/github.com/deckarep/golang-set/threadsafe.go
  8. 246 0
      vendor/src/github.com/deckarep/golang-set/threadunsafe.go
  9. 17 1
      vendor/src/github.com/docker/libnetwork/config/config.go
  10. 64 7
      vendor/src/github.com/docker/libnetwork/controller.go
  11. 20 0
      vendor/src/github.com/docker/libnetwork/driverapi/driverapi.go
  12. 10 0
      vendor/src/github.com/docker/libnetwork/drivers/bridge/bridge.go
  13. 10 0
      vendor/src/github.com/docker/libnetwork/drivers/host/host.go
  14. 10 0
      vendor/src/github.com/docker/libnetwork/drivers/null/null.go
  15. 3 6
      vendor/src/github.com/docker/libnetwork/drivers/overlay/joinleave.go
  16. 20 15
      vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_network.go
  17. 22 42
      vendor/src/github.com/docker/libnetwork/drivers/overlay/ov_serf.go
  18. 70 17
      vendor/src/github.com/docker/libnetwork/drivers/overlay/overlay.go
  19. 27 2
      vendor/src/github.com/docker/libnetwork/drivers/overlay/peerdb.go
  20. 16 1
      vendor/src/github.com/docker/libnetwork/drivers/remote/api/api.go
  21. 24 0
      vendor/src/github.com/docker/libnetwork/drivers/remote/driver.go
  22. 10 0
      vendor/src/github.com/docker/libnetwork/drivers/windows/windows.go
  23. 29 65
      vendor/src/github.com/docker/libnetwork/hostdiscovery/hostdiscovery.go
  24. 4 8
      vendor/src/github.com/docker/libnetwork/hostdiscovery/hostdiscovery_api.go
  25. 0 28
      vendor/src/github.com/docker/libnetwork/hostdiscovery/hostdiscovery_disabled.go
  26. 2 2
      vendor/src/github.com/docker/libnetwork/hostdiscovery/libnetwork.toml

+ 2 - 1
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

+ 22 - 0
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

+ 9 - 0
vendor/src/github.com/deckarep/golang-set/.travis.yml

@@ -0,0 +1,9 @@
+language: go
+
+go:
+    - 1.2
+
+script:
+    - go test ./...
+    #- go test -race ./...
+

+ 22 - 0
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.

+ 94 - 0
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)

+ 168 - 0
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
+}

+ 204 - 0
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
+}

+ 246 - 0
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
+}

+ 17 - 1
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 {

+ 64 - 7
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()

+ 20 - 0
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
+}

+ 10 - 0
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

+ 10 - 0
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
+}

+ 10 - 0
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
+}

+ 3 - 6
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
 }

+ 20 - 15
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
 }
 

+ 22 - 42
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
+}

+ 70 - 17
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
+}

+ 27 - 2
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
+	})
+}

+ 16 - 1
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
+}

+ 24 - 0
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 {

+ 10 - 0
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
+}

+ 29 - 65
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 {

+ 4 - 8
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
 }

+ 0 - 28
vendor/src/github.com/docker/libnetwork/hostdiscovery/hostdiscovery_disabled.go

@@ -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
-}

+ 2 - 2
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