Browse code

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 authored on 2015/10/02 12:04:31
Showing 26 changed files
... ...
@@ -22,7 +22,7 @@ clone git github.com/tchap/go-patricia v2.1.0
22 22
 clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://github.com/golang/net.git
23 23
 
24 24
 #get libnetwork packages
25
-clone git github.com/docker/libnetwork 70409acbcd661e6a7bfe04e2b81412a465d29512
25
+clone git github.com/docker/libnetwork c3a9e0d8d0c53f3db251620e5f48470e267f292b
26 26
 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
27 27
 clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
28 28
 clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
... ...
@@ -32,6 +32,7 @@ clone git github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
32 32
 clone git github.com/vishvananda/netlink 4b5dce31de6d42af5bb9811c6d265472199e0fec
33 33
 clone git github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
34 34
 clone git github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
35
+clone git github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
35 36
 clone git github.com/coreos/go-etcd v2.0.0
36 37
 clone git github.com/hashicorp/consul v0.5.2
37 38
 clone git github.com/boltdb/bolt v1.0
38 39
new file mode 100644
... ...
@@ -0,0 +1,22 @@
0
+# Compiled Object files, Static and Dynamic libs (Shared Objects)
1
+*.o
2
+*.a
3
+*.so
4
+
5
+# Folders
6
+_obj
7
+_test
8
+
9
+# Architecture specific extensions/prefixes
10
+*.[568vq]
11
+[568vq].out
12
+
13
+*.cgo1.go
14
+*.cgo2.c
15
+_cgo_defun.c
16
+_cgo_gotypes.go
17
+_cgo_export.*
18
+
19
+_testmain.go
20
+
21
+*.exe
0 22
new file mode 100644
... ...
@@ -0,0 +1,9 @@
0
+language: go
1
+
2
+go:
3
+    - 1.2
4
+
5
+script:
6
+    - go test ./...
7
+    #- go test -race ./...
8
+
0 9
new file mode 100644
... ...
@@ -0,0 +1,22 @@
0
+Open Source Initiative OSI - The MIT License (MIT):Licensing
1
+
2
+The MIT License (MIT)
3
+Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com)
4
+
5
+Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+this software and associated documentation files (the "Software"), to deal in
7
+the Software without restriction, including without limitation the rights to
8
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
+of the Software, and to permit persons to whom the Software is furnished to do
10
+so, subject to the following conditions:
11
+
12
+The above copyright notice and this permission notice shall be included in all
13
+copies or substantial portions of the Software.
14
+
15
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+SOFTWARE.
0 22
\ No newline at end of file
1 23
new file mode 100644
... ...
@@ -0,0 +1,94 @@
0
+[![Build Status](https://travis-ci.org/deckarep/golang-set.png?branch=master)](https://travis-ci.org/deckarep/golang-set)
1
+[![GoDoc](https://godoc.org/github.com/deckarep/golang-set?status.png)](http://godoc.org/github.com/deckarep/golang-set)
2
+
3
+## golang-set
4
+
5
+
6
+The missing set collection for the Go language.  Until Go has sets built-in...use this.
7
+
8
+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.
9
+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
10
+and carry-on and to the rest that find this useful please contribute in helping me make it better by:
11
+
12
+* Helping to make more idiomatic improvements to the code.
13
+* 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.)~~
14
+* Helping to make the unit-tests more robust and kick-ass.
15
+* Helping to fill in the [documentation.](http://godoc.org/github.com/deckarep/golang-set)
16
+* Simply offering feedback and suggestions.  (Positive, constructive feedback is appreciated.)
17
+
18
+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)
19
+
20
+*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.
21
+
22
+## Features (as of 9/22/2014)
23
+
24
+* a CartesionProduct() method has been added with unit-tests: [Read more about the cartesion product](http://en.wikipedia.org/wiki/Cartesian_product)
25
+
26
+## Features (as of 9/15/2014)
27
+
28
+* a PowerSet() method has been added with unit-tests: [Read more about the Power set](http://en.wikipedia.org/wiki/Power_set)
29
+
30
+## Features (as of 4/22/2014)
31
+
32
+* One common interface to both implementations
33
+* Two set implementations to choose from
34
+  * a thread-safe implementation designed for concurrent use
35
+  * a non-thread-safe implementation designed for performance
36
+* 75 benchmarks for both implementations
37
+* 35 unit tests for both implementations
38
+* 14 concurrent tests for the thread-safe implementation
39
+
40
+
41
+
42
+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
43
+however that the Python set is a built-in type and supports additional features and syntax that make it awesome.
44
+
45
+## Examples but not exhaustive:
46
+
47
+```go
48
+requiredClasses := mapset.NewSet()
49
+requiredClasses.Add("Cooking")
50
+requiredClasses.Add("English")
51
+requiredClasses.Add("Math")
52
+requiredClasses.Add("Biology")
53
+
54
+scienceSlice := []interface{}{"Biology", "Chemistry"}
55
+scienceClasses := mapset.NewSetFromSlice(scienceSlice)
56
+
57
+electiveClasses := mapset.NewSet()
58
+electiveClasses.Add("Welding")
59
+electiveClasses.Add("Music")
60
+electiveClasses.Add("Automotive")
61
+
62
+bonusClasses := mapset.NewSet()
63
+bonusClasses.Add("Go Programming")
64
+bonusClasses.Add("Python Programming")
65
+
66
+//Show me all the available classes I can take
67
+allClasses := requiredClasses.Union(scienceClasses).Union(electiveClasses).Union(bonusClasses)
68
+fmt.Println(allClasses) //Set{Cooking, English, Math, Chemistry, Welding, Biology, Music, Automotive, Go Programming, Python Programming}
69
+
70
+
71
+//Is cooking considered a science class?
72
+fmt.Println(scienceClasses.Contains("Cooking")) //false
73
+
74
+//Show me all classes that are not science classes, since I hate science.
75
+fmt.Println(allClasses.Difference(scienceClasses)) //Set{Music, Automotive, Go Programming, Python Programming, Cooking, English, Math, Welding}
76
+
77
+//Which science classes are also required classes?
78
+fmt.Println(scienceClasses.Intersect(requiredClasses)) //Set{Biology}
79
+
80
+//How many bonus classes do you offer?
81
+fmt.Println(bonusClasses.Cardinality()) //2
82
+
83
+//Do you have the following classes? Welding, Automotive and English?
84
+fmt.Println(allClasses.IsSuperset(mapset.NewSetFromSlice([]interface{}{"Welding", "Automotive", "English"}))) //true
85
+```
86
+
87
+Thanks!
88
+
89
+-Ralph
90
+
91
+[![Bitdeli Badge](https://d2weczhvl823v0.cloudfront.net/deckarep/golang-set/trend.png)](https://bitdeli.com/free "Bitdeli Badge")
92
+
93
+[![Analytics](https://ga-beacon.appspot.com/UA-42584447-2/deckarep/golang-set)](https://github.com/igrigorik/ga-beacon)
0 94
new file mode 100644
... ...
@@ -0,0 +1,168 @@
0
+/*
1
+Open Source Initiative OSI - The MIT License (MIT):Licensing
2
+
3
+The MIT License (MIT)
4
+Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com)
5
+
6
+Permission is hereby granted, free of charge, to any person obtaining a copy of
7
+this software and associated documentation files (the "Software"), to deal in
8
+the Software without restriction, including without limitation the rights to
9
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10
+of the Software, and to permit persons to whom the Software is furnished to do
11
+so, subject to the following conditions:
12
+
13
+The above copyright notice and this permission notice shall be included in all
14
+copies or substantial portions of the Software.
15
+
16
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+SOFTWARE.
23
+*/
24
+
25
+// Package mapset implements a simple and generic set collection.
26
+// Items stored within it are unordered and unique. It supports
27
+// typical set operations: membership testing, intersection, union,
28
+// difference, symmetric difference and cloning.
29
+//
30
+// Package mapset provides two implementations. The default
31
+// implementation is safe for concurrent access. There is a non-threadsafe
32
+// implementation which is slightly more performant.
33
+package mapset
34
+
35
+type Set interface {
36
+	// Adds an element to the set. Returns whether
37
+	// the item was added.
38
+	Add(i interface{}) bool
39
+
40
+	// Returns the number of elements in the set.
41
+	Cardinality() int
42
+
43
+	// Removes all elements from the set, leaving
44
+	// the emtpy set.
45
+	Clear()
46
+
47
+	// Returns a clone of the set using the same
48
+	// implementation, duplicating all keys.
49
+	Clone() Set
50
+
51
+	// Returns whether the given items
52
+	// are all in the set.
53
+	Contains(i ...interface{}) bool
54
+
55
+	// Returns the difference between this set
56
+	// and other. The returned set will contain
57
+	// all elements of this set that are not also
58
+	// elements of other.
59
+	//
60
+	// Note that the argument to Difference
61
+	// must be of the same type as the receiver
62
+	// of the method. Otherwise, Difference will
63
+	// panic.
64
+	Difference(other Set) Set
65
+
66
+	// Determines if two sets are equal to each
67
+	// other. If they have the same cardinality
68
+	// and contain the same elements, they are
69
+	// considered equal. The order in which
70
+	// the elements were added is irrelevant.
71
+	//
72
+	// Note that the argument to Equal must be
73
+	// of the same type as the receiver of the
74
+	// method. Otherwise, Equal will panic.
75
+	Equal(other Set) bool
76
+
77
+	// Returns a new set containing only the elements
78
+	// that exist only in both sets.
79
+	//
80
+	// Note that the argument to Intersect
81
+	// must be of the same type as the receiver
82
+	// of the method. Otherwise, Intersect will
83
+	// panic.
84
+	Intersect(other Set) Set
85
+
86
+	// Determines if every element in the other set
87
+	// is in this set.
88
+	//
89
+	// Note that the argument to IsSubset
90
+	// must be of the same type as the receiver
91
+	// of the method. Otherwise, IsSubset will
92
+	// panic.
93
+	IsSubset(other Set) bool
94
+
95
+	// Determines if every element in this set is in
96
+	// the other set.
97
+	//
98
+	// Note that the argument to IsSuperset
99
+	// must be of the same type as the receiver
100
+	// of the method. Otherwise, IsSuperset will
101
+	// panic.
102
+	IsSuperset(other Set) bool
103
+
104
+	// Returns a channel of elements that you can
105
+	// range over.
106
+	Iter() <-chan interface{}
107
+
108
+	// Remove a single element from the set.
109
+	Remove(i interface{})
110
+
111
+	// Provides a convenient string representation
112
+	// of the current state of the set.
113
+	String() string
114
+
115
+	// Returns a new set with all elements which are
116
+	// in either this set or the other set but not in both.
117
+	//
118
+	// Note that the argument to SymmetricDifference
119
+	// must be of the same type as the receiver
120
+	// of the method. Otherwise, SymmetricDifference
121
+	// will panic.
122
+	SymmetricDifference(other Set) Set
123
+
124
+	// Returns a new set with all elements in both sets.
125
+	//
126
+	// Note that the argument to Union must be of the
127
+	// same type as the receiver of the method.
128
+	// Otherwise, IsSuperset will panic.
129
+	Union(other Set) Set
130
+
131
+	// Returns all subsets of a given set (Power Set).
132
+	PowerSet() Set
133
+
134
+	// Returns the Cartesian Product of two sets.
135
+	CartesianProduct(other Set) Set
136
+
137
+	// Returns the members of the set as a slice.
138
+	ToSlice() []interface{}
139
+}
140
+
141
+// Creates and returns a reference to an empty set.
142
+func NewSet() Set {
143
+	set := newThreadSafeSet()
144
+	return &set
145
+}
146
+
147
+// Creates and returns a reference to a set from an existing slice
148
+func NewSetFromSlice(s []interface{}) Set {
149
+	a := NewSet()
150
+	for _, item := range s {
151
+		a.Add(item)
152
+	}
153
+	return a
154
+}
155
+
156
+func NewThreadUnsafeSet() Set {
157
+	set := newThreadUnsafeSet()
158
+	return &set
159
+}
160
+
161
+func NewThreadUnsafeSetFromSlice(s []interface{}) Set {
162
+	a := NewThreadUnsafeSet()
163
+	for _, item := range s {
164
+		a.Add(item)
165
+	}
166
+	return a
167
+}
0 168
new file mode 100644
... ...
@@ -0,0 +1,204 @@
0
+/*
1
+Open Source Initiative OSI - The MIT License (MIT):Licensing
2
+
3
+The MIT License (MIT)
4
+Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com)
5
+
6
+Permission is hereby granted, free of charge, to any person obtaining a copy of
7
+this software and associated documentation files (the "Software"), to deal in
8
+the Software without restriction, including without limitation the rights to
9
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10
+of the Software, and to permit persons to whom the Software is furnished to do
11
+so, subject to the following conditions:
12
+
13
+The above copyright notice and this permission notice shall be included in all
14
+copies or substantial portions of the Software.
15
+
16
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+SOFTWARE.
23
+*/
24
+
25
+package mapset
26
+
27
+import "sync"
28
+
29
+type threadSafeSet struct {
30
+	s threadUnsafeSet
31
+	sync.RWMutex
32
+}
33
+
34
+func newThreadSafeSet() threadSafeSet {
35
+	return threadSafeSet{s: newThreadUnsafeSet()}
36
+}
37
+
38
+func (set *threadSafeSet) Add(i interface{}) bool {
39
+	set.Lock()
40
+	ret := set.s.Add(i)
41
+	set.Unlock()
42
+	return ret
43
+}
44
+
45
+func (set *threadSafeSet) Contains(i ...interface{}) bool {
46
+	set.RLock()
47
+	ret := set.s.Contains(i...)
48
+	set.RUnlock()
49
+	return ret
50
+}
51
+
52
+func (set *threadSafeSet) IsSubset(other Set) bool {
53
+	o := other.(*threadSafeSet)
54
+
55
+	set.RLock()
56
+	o.RLock()
57
+
58
+	ret := set.s.IsSubset(&o.s)
59
+	set.RUnlock()
60
+	o.RUnlock()
61
+	return ret
62
+}
63
+
64
+func (set *threadSafeSet) IsSuperset(other Set) bool {
65
+	return other.IsSubset(set)
66
+}
67
+
68
+func (set *threadSafeSet) Union(other Set) Set {
69
+	o := other.(*threadSafeSet)
70
+
71
+	set.RLock()
72
+	o.RLock()
73
+
74
+	unsafeUnion := set.s.Union(&o.s).(*threadUnsafeSet)
75
+	ret := &threadSafeSet{s: *unsafeUnion}
76
+	set.RUnlock()
77
+	o.RUnlock()
78
+	return ret
79
+}
80
+
81
+func (set *threadSafeSet) Intersect(other Set) Set {
82
+	o := other.(*threadSafeSet)
83
+
84
+	set.RLock()
85
+	o.RLock()
86
+
87
+	unsafeIntersection := set.s.Intersect(&o.s).(*threadUnsafeSet)
88
+	ret := &threadSafeSet{s: *unsafeIntersection}
89
+	set.RUnlock()
90
+	o.RUnlock()
91
+	return ret
92
+}
93
+
94
+func (set *threadSafeSet) Difference(other Set) Set {
95
+	o := other.(*threadSafeSet)
96
+
97
+	set.RLock()
98
+	o.RLock()
99
+
100
+	unsafeDifference := set.s.Difference(&o.s).(*threadUnsafeSet)
101
+	ret := &threadSafeSet{s: *unsafeDifference}
102
+	set.RUnlock()
103
+	o.RUnlock()
104
+	return ret
105
+}
106
+
107
+func (set *threadSafeSet) SymmetricDifference(other Set) Set {
108
+	o := other.(*threadSafeSet)
109
+
110
+	unsafeDifference := set.s.SymmetricDifference(&o.s).(*threadUnsafeSet)
111
+	return &threadSafeSet{s: *unsafeDifference}
112
+}
113
+
114
+func (set *threadSafeSet) Clear() {
115
+	set.Lock()
116
+	set.s = newThreadUnsafeSet()
117
+	set.Unlock()
118
+}
119
+
120
+func (set *threadSafeSet) Remove(i interface{}) {
121
+	set.Lock()
122
+	delete(set.s, i)
123
+	set.Unlock()
124
+}
125
+
126
+func (set *threadSafeSet) Cardinality() int {
127
+	set.RLock()
128
+	defer set.RUnlock()
129
+	return len(set.s)
130
+}
131
+
132
+func (set *threadSafeSet) Iter() <-chan interface{} {
133
+	ch := make(chan interface{})
134
+	go func() {
135
+		set.RLock()
136
+
137
+		for elem := range set.s {
138
+			ch <- elem
139
+		}
140
+		close(ch)
141
+		set.RUnlock()
142
+	}()
143
+
144
+	return ch
145
+}
146
+
147
+func (set *threadSafeSet) Equal(other Set) bool {
148
+	o := other.(*threadSafeSet)
149
+
150
+	set.RLock()
151
+	o.RLock()
152
+
153
+	ret := set.s.Equal(&o.s)
154
+	set.RUnlock()
155
+	o.RUnlock()
156
+	return ret
157
+}
158
+
159
+func (set *threadSafeSet) Clone() Set {
160
+	set.RLock()
161
+
162
+	unsafeClone := set.s.Clone().(*threadUnsafeSet)
163
+	ret := &threadSafeSet{s: *unsafeClone}
164
+	set.RUnlock()
165
+	return ret
166
+}
167
+
168
+func (set *threadSafeSet) String() string {
169
+	set.RLock()
170
+	ret := set.s.String()
171
+	set.RUnlock()
172
+	return ret
173
+}
174
+
175
+func (set *threadSafeSet) PowerSet() Set {
176
+	set.RLock()
177
+	ret := set.s.PowerSet()
178
+	set.RUnlock()
179
+	return ret
180
+}
181
+
182
+func (set *threadSafeSet) CartesianProduct(other Set) Set {
183
+	o := other.(*threadSafeSet)
184
+
185
+	set.RLock()
186
+	o.RLock()
187
+
188
+	unsafeCartProduct := set.s.CartesianProduct(&o.s).(*threadUnsafeSet)
189
+	ret := &threadSafeSet{s: *unsafeCartProduct}
190
+	set.RUnlock()
191
+	o.RUnlock()
192
+	return ret
193
+}
194
+
195
+func (set *threadSafeSet) ToSlice() []interface{} {
196
+	set.RLock()
197
+	keys := make([]interface{}, 0, set.Cardinality())
198
+	for elem := range set.s {
199
+		keys = append(keys, elem)
200
+	}
201
+	set.RUnlock()
202
+	return keys
203
+}
0 204
new file mode 100644
... ...
@@ -0,0 +1,246 @@
0
+/*
1
+Open Source Initiative OSI - The MIT License (MIT):Licensing
2
+
3
+The MIT License (MIT)
4
+Copyright (c) 2013 Ralph Caraveo (deckarep@gmail.com)
5
+
6
+Permission is hereby granted, free of charge, to any person obtaining a copy of
7
+this software and associated documentation files (the "Software"), to deal in
8
+the Software without restriction, including without limitation the rights to
9
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
10
+of the Software, and to permit persons to whom the Software is furnished to do
11
+so, subject to the following conditions:
12
+
13
+The above copyright notice and this permission notice shall be included in all
14
+copies or substantial portions of the Software.
15
+
16
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+SOFTWARE.
23
+*/
24
+
25
+package mapset
26
+
27
+import (
28
+	"fmt"
29
+	"reflect"
30
+	"strings"
31
+)
32
+
33
+type threadUnsafeSet map[interface{}]struct{}
34
+
35
+type orderedPair struct {
36
+	first  interface{}
37
+	second interface{}
38
+}
39
+
40
+func newThreadUnsafeSet() threadUnsafeSet {
41
+	return make(threadUnsafeSet)
42
+}
43
+
44
+func (pair *orderedPair) Equal(other orderedPair) bool {
45
+	if pair.first == other.first &&
46
+		pair.second == other.second {
47
+		return true
48
+	}
49
+
50
+	return false
51
+}
52
+
53
+func (set *threadUnsafeSet) Add(i interface{}) bool {
54
+	_, found := (*set)[i]
55
+	(*set)[i] = struct{}{}
56
+	return !found //False if it existed already
57
+}
58
+
59
+func (set *threadUnsafeSet) Contains(i ...interface{}) bool {
60
+	for _, val := range i {
61
+		if _, ok := (*set)[val]; !ok {
62
+			return false
63
+		}
64
+	}
65
+	return true
66
+}
67
+
68
+func (set *threadUnsafeSet) IsSubset(other Set) bool {
69
+	_ = other.(*threadUnsafeSet)
70
+	for elem := range *set {
71
+		if !other.Contains(elem) {
72
+			return false
73
+		}
74
+	}
75
+	return true
76
+}
77
+
78
+func (set *threadUnsafeSet) IsSuperset(other Set) bool {
79
+	return other.IsSubset(set)
80
+}
81
+
82
+func (set *threadUnsafeSet) Union(other Set) Set {
83
+	o := other.(*threadUnsafeSet)
84
+
85
+	unionedSet := newThreadUnsafeSet()
86
+
87
+	for elem := range *set {
88
+		unionedSet.Add(elem)
89
+	}
90
+	for elem := range *o {
91
+		unionedSet.Add(elem)
92
+	}
93
+	return &unionedSet
94
+}
95
+
96
+func (set *threadUnsafeSet) Intersect(other Set) Set {
97
+	o := other.(*threadUnsafeSet)
98
+
99
+	intersection := newThreadUnsafeSet()
100
+	// loop over smaller set
101
+	if set.Cardinality() < other.Cardinality() {
102
+		for elem := range *set {
103
+			if other.Contains(elem) {
104
+				intersection.Add(elem)
105
+			}
106
+		}
107
+	} else {
108
+		for elem := range *o {
109
+			if set.Contains(elem) {
110
+				intersection.Add(elem)
111
+			}
112
+		}
113
+	}
114
+	return &intersection
115
+}
116
+
117
+func (set *threadUnsafeSet) Difference(other Set) Set {
118
+	_ = other.(*threadUnsafeSet)
119
+
120
+	difference := newThreadUnsafeSet()
121
+	for elem := range *set {
122
+		if !other.Contains(elem) {
123
+			difference.Add(elem)
124
+		}
125
+	}
126
+	return &difference
127
+}
128
+
129
+func (set *threadUnsafeSet) SymmetricDifference(other Set) Set {
130
+	_ = other.(*threadUnsafeSet)
131
+
132
+	aDiff := set.Difference(other)
133
+	bDiff := other.Difference(set)
134
+	return aDiff.Union(bDiff)
135
+}
136
+
137
+func (set *threadUnsafeSet) Clear() {
138
+	*set = newThreadUnsafeSet()
139
+}
140
+
141
+func (set *threadUnsafeSet) Remove(i interface{}) {
142
+	delete(*set, i)
143
+}
144
+
145
+func (set *threadUnsafeSet) Cardinality() int {
146
+	return len(*set)
147
+}
148
+
149
+func (set *threadUnsafeSet) Iter() <-chan interface{} {
150
+	ch := make(chan interface{})
151
+	go func() {
152
+		for elem := range *set {
153
+			ch <- elem
154
+		}
155
+		close(ch)
156
+	}()
157
+
158
+	return ch
159
+}
160
+
161
+func (set *threadUnsafeSet) Equal(other Set) bool {
162
+	_ = other.(*threadUnsafeSet)
163
+
164
+	if set.Cardinality() != other.Cardinality() {
165
+		return false
166
+	}
167
+	for elem := range *set {
168
+		if !other.Contains(elem) {
169
+			return false
170
+		}
171
+	}
172
+	return true
173
+}
174
+
175
+func (set *threadUnsafeSet) Clone() Set {
176
+	clonedSet := newThreadUnsafeSet()
177
+	for elem := range *set {
178
+		clonedSet.Add(elem)
179
+	}
180
+	return &clonedSet
181
+}
182
+
183
+func (set *threadUnsafeSet) String() string {
184
+	items := make([]string, 0, len(*set))
185
+
186
+	for elem := range *set {
187
+		items = append(items, fmt.Sprintf("%v", elem))
188
+	}
189
+	return fmt.Sprintf("Set{%s}", strings.Join(items, ", "))
190
+}
191
+
192
+func (pair orderedPair) String() string {
193
+	return fmt.Sprintf("(%v, %v)", pair.first, pair.second)
194
+}
195
+
196
+func (set *threadUnsafeSet) PowerSet() Set {
197
+	powSet := NewThreadUnsafeSet()
198
+	nullset := newThreadUnsafeSet()
199
+	powSet.Add(&nullset)
200
+
201
+	for es := range *set {
202
+		u := newThreadUnsafeSet()
203
+		j := powSet.Iter()
204
+		for er := range j {
205
+			p := newThreadUnsafeSet()
206
+			if reflect.TypeOf(er).Name() == "" {
207
+				k := er.(*threadUnsafeSet)
208
+				for ek := range *(k) {
209
+					p.Add(ek)
210
+				}
211
+			} else {
212
+				p.Add(er)
213
+			}
214
+			p.Add(es)
215
+			u.Add(&p)
216
+		}
217
+
218
+		powSet = powSet.Union(&u)
219
+	}
220
+
221
+	return powSet
222
+}
223
+
224
+func (set *threadUnsafeSet) CartesianProduct(other Set) Set {
225
+	o := other.(*threadUnsafeSet)
226
+	cartProduct := NewThreadUnsafeSet()
227
+
228
+	for i := range *set {
229
+		for j := range *o {
230
+			elem := orderedPair{first: i, second: j}
231
+			cartProduct.Add(elem)
232
+		}
233
+	}
234
+
235
+	return cartProduct
236
+}
237
+
238
+func (set *threadUnsafeSet) ToSlice() []interface{} {
239
+	keys := make([]interface{}, 0, set.Cardinality())
240
+	for elem := range *set {
241
+		keys = append(keys, elem)
242
+	}
243
+
244
+	return keys
245
+}
... ...
@@ -5,6 +5,7 @@ import (
5 5
 
6 6
 	"github.com/BurntSushi/toml"
7 7
 	log "github.com/Sirupsen/logrus"
8
+	"github.com/docker/docker/pkg/discovery"
8 9
 	"github.com/docker/libkv/store"
9 10
 	"github.com/docker/libnetwork/netlabel"
10 11
 )
... ...
@@ -27,8 +28,9 @@ type DaemonCfg struct {
27 27
 
28 28
 // ClusterCfg represents cluster configuration
29 29
 type ClusterCfg struct {
30
-	Discovery string
30
+	Watcher   discovery.Watcher
31 31
 	Address   string
32
+	Discovery string
32 33
 	Heartbeat uint64
33 34
 }
34 35
 
... ...
@@ -108,6 +110,20 @@ func OptionKVProviderURL(url string) Option {
108 108
 	}
109 109
 }
110 110
 
111
+// OptionDiscoveryWatcher function returns an option setter for discovery watcher
112
+func OptionDiscoveryWatcher(watcher discovery.Watcher) Option {
113
+	return func(c *Config) {
114
+		c.Cluster.Watcher = watcher
115
+	}
116
+}
117
+
118
+// OptionDiscoveryAddress function returns an option setter for self discovery address
119
+func OptionDiscoveryAddress(address string) Option {
120
+	return func(c *Config) {
121
+		c.Cluster.Address = address
122
+	}
123
+}
124
+
111 125
 // ProcessOptions processes options and stores it in config
112 126
 func (c *Config) ProcessOptions(options ...Option) {
113 127
 	for _, opt := range options {
... ...
@@ -47,9 +47,11 @@ import (
47 47
 	"container/heap"
48 48
 	"fmt"
49 49
 	"net"
50
+	"strings"
50 51
 	"sync"
51 52
 
52 53
 	log "github.com/Sirupsen/logrus"
54
+	"github.com/docker/docker/pkg/discovery"
53 55
 	"github.com/docker/docker/pkg/plugins"
54 56
 	"github.com/docker/docker/pkg/stringid"
55 57
 	"github.com/docker/libnetwork/config"
... ...
@@ -126,6 +128,7 @@ type controller struct {
126 126
 	sandboxes               sandboxTable
127 127
 	cfg                     *config.Config
128 128
 	globalStore, localStore datastore.DataStore
129
+	discovery               hostdiscovery.HostDiscovery
129 130
 	extKeyListener          net.Listener
130 131
 	sync.Mutex
131 132
 }
... ...
@@ -157,7 +160,7 @@ func New(cfgOptions ...config.Option) (NetworkController, error) {
157 157
 			// But it cannot fail creating the Controller
158 158
 			log.Debugf("Failed to Initialize Datastore due to %v. Operating in non-clustered mode", err)
159 159
 		}
160
-		if err := c.initDiscovery(); err != nil {
160
+		if err := c.initDiscovery(cfg.Cluster.Watcher); err != nil {
161 161
 			// Failing to initalize discovery is a bad situation to be in.
162 162
 			// But it cannot fail creating the Controller
163 163
 			log.Debugf("Failed to Initialize Discovery : %v", err)
... ...
@@ -185,19 +188,57 @@ func (c *controller) validateHostDiscoveryConfig() bool {
185 185
 	return true
186 186
 }
187 187
 
188
-func (c *controller) initDiscovery() error {
188
+func (c *controller) initDiscovery(watcher discovery.Watcher) error {
189 189
 	if c.cfg == nil {
190 190
 		return fmt.Errorf("discovery initialization requires a valid configuration")
191 191
 	}
192 192
 
193
-	hostDiscovery := hostdiscovery.NewHostDiscovery()
194
-	return hostDiscovery.StartDiscovery(&c.cfg.Cluster, c.hostJoinCallback, c.hostLeaveCallback)
193
+	c.discovery = hostdiscovery.NewHostDiscovery(watcher)
194
+	return c.discovery.Watch(c.hostJoinCallback, c.hostLeaveCallback)
195 195
 }
196 196
 
197
-func (c *controller) hostJoinCallback(hosts []net.IP) {
197
+func (c *controller) hostJoinCallback(nodes []net.IP) {
198
+	c.processNodeDiscovery(nodes, true)
198 199
 }
199 200
 
200
-func (c *controller) hostLeaveCallback(hosts []net.IP) {
201
+func (c *controller) hostLeaveCallback(nodes []net.IP) {
202
+	c.processNodeDiscovery(nodes, false)
203
+}
204
+
205
+func (c *controller) processNodeDiscovery(nodes []net.IP, add bool) {
206
+	c.Lock()
207
+	drivers := []*driverData{}
208
+	for _, d := range c.drivers {
209
+		drivers = append(drivers, d)
210
+	}
211
+	c.Unlock()
212
+
213
+	for _, d := range drivers {
214
+		c.pushNodeDiscovery(d, nodes, add)
215
+	}
216
+}
217
+
218
+func (c *controller) pushNodeDiscovery(d *driverData, nodes []net.IP, add bool) {
219
+	var self net.IP
220
+	if c.cfg != nil {
221
+		addr := strings.Split(c.cfg.Cluster.Address, ":")
222
+		self = net.ParseIP(addr[0])
223
+	}
224
+	if d == nil || d.capability.DataScope != datastore.GlobalScope || nodes == nil {
225
+		return
226
+	}
227
+	for _, node := range nodes {
228
+		nodeData := driverapi.NodeDiscoveryData{Address: node.String(), Self: node.Equal(self)}
229
+		var err error
230
+		if add {
231
+			err = d.driver.DiscoverNew(driverapi.NodeDiscovery, nodeData)
232
+		} else {
233
+			err = d.driver.DiscoverDelete(driverapi.NodeDiscovery, nodeData)
234
+		}
235
+		if err != nil {
236
+			log.Debugf("discovery notification error : %v", err)
237
+		}
238
+	}
201 239
 }
202 240
 
203 241
 func (c *controller) Config() config.Config {
... ...
@@ -219,9 +260,15 @@ func (c *controller) RegisterDriver(networkType string, driver driverapi.Driver,
219 219
 		c.Unlock()
220 220
 		return driverapi.ErrActiveRegistration(networkType)
221 221
 	}
222
-	c.drivers[networkType] = &driverData{driver, capability}
222
+	dData := &driverData{driver, capability}
223
+	c.drivers[networkType] = dData
224
+	hd := c.discovery
223 225
 	c.Unlock()
224 226
 
227
+	if hd != nil {
228
+		c.pushNodeDiscovery(dData, hd.Fetch(), true)
229
+	}
230
+
225 231
 	return nil
226 232
 }
227 233
 
... ...
@@ -487,6 +534,16 @@ func (c *controller) loadDriver(networkType string) (*driverData, error) {
487 487
 	return dd, nil
488 488
 }
489 489
 
490
+func (c *controller) getDriver(networkType string) (*driverData, error) {
491
+	c.Lock()
492
+	defer c.Unlock()
493
+	dd, ok := c.drivers[networkType]
494
+	if !ok {
495
+		return nil, types.NotFoundErrorf("driver %s not found", networkType)
496
+	}
497
+	return dd, nil
498
+}
499
+
490 500
 func (c *controller) Stop() {
491 501
 	if c.localStore != nil {
492 502
 		c.localStore.KVStore().Close()
... ...
@@ -40,6 +40,12 @@ type Driver interface {
40 40
 	// Leave method is invoked when a Sandbox detaches from an endpoint.
41 41
 	Leave(nid, eid string) error
42 42
 
43
+	// DiscoverNew is a notification for a new discovery event, Example:a new node joining a cluster
44
+	DiscoverNew(dType DiscoveryType, data interface{}) error
45
+
46
+	// DiscoverDelete is a notification for a discovery delete event, Example:a node leaving a cluster
47
+	DiscoverDelete(dType DiscoveryType, data interface{}) error
48
+
43 49
 	// Type returns the the type of this driver, the network type this driver manages
44 50
 	Type() string
45 51
 }
... ...
@@ -106,3 +112,17 @@ type DriverCallback interface {
106 106
 type Capability struct {
107 107
 	DataScope datastore.DataScope
108 108
 }
109
+
110
+// DiscoveryType represents the type of discovery element the DiscoverNew function is invoked on
111
+type DiscoveryType int
112
+
113
+const (
114
+	// NodeDiscovery represents Node join/leave events provided by discovery
115
+	NodeDiscovery = iota + 1
116
+)
117
+
118
+// NodeDiscoveryData represents the structure backing the node discovery data json string
119
+type NodeDiscoveryData struct {
120
+	Address string
121
+	Self    bool
122
+}
... ...
@@ -1375,6 +1375,16 @@ func (d *driver) Type() string {
1375 1375
 	return networkType
1376 1376
 }
1377 1377
 
1378
+// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
1379
+func (d *driver) DiscoverNew(dType driverapi.DiscoveryType, data interface{}) error {
1380
+	return nil
1381
+}
1382
+
1383
+// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
1384
+func (d *driver) DiscoverDelete(dType driverapi.DiscoveryType, data interface{}) error {
1385
+	return nil
1386
+}
1387
+
1378 1388
 func parseEndpointOptions(epOptions map[string]interface{}) (*endpointConfiguration, error) {
1379 1389
 	if epOptions == nil {
1380 1390
 		return nil, nil
... ...
@@ -65,3 +65,13 @@ func (d *driver) Leave(nid, eid string) error {
65 65
 func (d *driver) Type() string {
66 66
 	return networkType
67 67
 }
68
+
69
+// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
70
+func (d *driver) DiscoverNew(dType driverapi.DiscoveryType, data interface{}) error {
71
+	return nil
72
+}
73
+
74
+// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
75
+func (d *driver) DiscoverDelete(dType driverapi.DiscoveryType, data interface{}) error {
76
+	return nil
77
+}
... ...
@@ -65,3 +65,13 @@ func (d *driver) Leave(nid, eid string) error {
65 65
 func (d *driver) Type() string {
66 66
 	return networkType
67 67
 }
68
+
69
+// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
70
+func (d *driver) DiscoverNew(dType driverapi.DiscoveryType, data interface{}) error {
71
+	return nil
72
+}
73
+
74
+// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
75
+func (d *driver) DiscoverDelete(dType driverapi.DiscoveryType, data interface{}) error {
76
+	return nil
77
+}
... ...
@@ -2,6 +2,7 @@ package overlay
2 2
 
3 3
 import (
4 4
 	"fmt"
5
+	"net"
5 6
 
6 7
 	"github.com/docker/libnetwork/driverapi"
7 8
 	"github.com/vishvananda/netlink"
... ...
@@ -73,12 +74,8 @@ func (d *driver) Join(nid, eid string, sboxKey string, jinfo driverapi.JoinInfo,
73 73
 	}
74 74
 
75 75
 	d.peerDbAdd(nid, eid, ep.addr.IP, ep.mac,
76
-		d.serfInstance.LocalMember().Addr, true)
77
-	d.notifyCh <- ovNotify{
78
-		action: "join",
79
-		nid:    nid,
80
-		eid:    eid,
81
-	}
76
+		net.ParseIP(d.bindAddress), true)
77
+	d.pushLocalEndpointEvent("join", nid, eid)
82 78
 
83 79
 	return nil
84 80
 }
... ...
@@ -156,23 +156,8 @@ func (n *network) initSandbox() error {
156 156
 		return fmt.Errorf("could not create bridge inside the network sandbox: %v", err)
157 157
 	}
158 158
 
159
-	vxlanName, err := createVxlan(n.vxlanID())
160
-	if err != nil {
161
-		return err
162
-	}
163
-
164
-	if err := sbox.AddInterface(vxlanName, "vxlan",
165
-		sbox.InterfaceOptions().Master("bridge1")); err != nil {
166
-		return fmt.Errorf("could not add vxlan interface inside the network sandbox: %v",
167
-			err)
168
-	}
169
-
170
-	n.vxlanName = vxlanName
171
-
172 159
 	n.setSandbox(sbox)
173 160
 
174
-	n.driver.peerDbUpdateSandbox(n.id)
175
-
176 161
 	var nlSock *nl.NetlinkSocket
177 162
 	sbox.InvokeFunc(func() {
178 163
 		nlSock, err = nl.Subscribe(syscall.NETLINK_ROUTE, syscall.RTNLGRP_NEIGH)
... ...
@@ -182,7 +167,27 @@ func (n *network) initSandbox() error {
182 182
 	})
183 183
 
184 184
 	go n.watchMiss(nlSock)
185
+	return n.initVxlan()
186
+}
185 187
 
188
+func (n *network) initVxlan() error {
189
+	var vxlanName string
190
+	n.Lock()
191
+	sbox := n.sbox
192
+	n.Unlock()
193
+
194
+	vxlanName, err := createVxlan(n.vxlanID())
195
+	if err != nil {
196
+		return err
197
+	}
198
+
199
+	if err = sbox.AddInterface(vxlanName, "vxlan",
200
+		sbox.InterfaceOptions().Master("bridge1")); err != nil {
201
+		return fmt.Errorf("could not add vxlan interface inside the network sandbox: %v", err)
202
+	}
203
+
204
+	n.vxlanName = vxlanName
205
+	n.driver.peerDbUpdateSandbox(n.id)
186 206
 	return nil
187 207
 }
188 208
 
... ...
@@ -35,46 +35,12 @@ func (l *logWriter) Write(p []byte) (int, error) {
35 35
 	return len(p), nil
36 36
 }
37 37
 
38
-func getBindAddr(ifaceName string) (string, error) {
39
-	iface, err := net.InterfaceByName(ifaceName)
40
-	if err != nil {
41
-		return "", fmt.Errorf("failed to find interface %s: %v", ifaceName, err)
42
-	}
43
-
44
-	addrs, err := iface.Addrs()
45
-	if err != nil {
46
-		return "", fmt.Errorf("failed to get interface addresses: %v", err)
47
-	}
48
-
49
-	for _, a := range addrs {
50
-		addr, ok := a.(*net.IPNet)
51
-		if !ok {
52
-			continue
53
-		}
54
-		addrIP := addr.IP
55
-
56
-		if addrIP.IsLinkLocalUnicast() {
57
-			continue
58
-		}
59
-
60
-		return addrIP.String(), nil
61
-	}
62
-
63
-	return "", fmt.Errorf("failed to get bind address")
64
-}
65
-
66 38
 func (d *driver) serfInit() error {
67 39
 	var err error
68 40
 
69 41
 	config := serf.DefaultConfig()
70 42
 	config.Init()
71
-	if d.ifaceName != "" {
72
-		bindAddr, err := getBindAddr(d.ifaceName)
73
-		if err != nil {
74
-			return fmt.Errorf("getBindAddr error: %v", err)
75
-		}
76
-		config.MemberlistConfig.BindAddr = bindAddr
77
-	}
43
+	config.MemberlistConfig.BindAddr = d.bindAddress
78 44
 
79 45
 	d.eventCh = make(chan serf.Event, 4)
80 46
 	config.EventCh = d.eventCh
... ...
@@ -93,13 +59,6 @@ func (d *driver) serfInit() error {
93 93
 		}
94 94
 	}()
95 95
 
96
-	if d.neighIP != "" {
97
-		if _, err = s.Join([]string{d.neighIP}, false); err != nil {
98
-			return fmt.Errorf("Failed to join the cluster at neigh IP %s: %v",
99
-				d.neighIP, err)
100
-		}
101
-	}
102
-
103 96
 	d.serfInstance = s
104 97
 
105 98
 	d.notifyCh = make(chan ovNotify)
... ...
@@ -109,6 +68,17 @@ func (d *driver) serfInit() error {
109 109
 	return nil
110 110
 }
111 111
 
112
+func (d *driver) serfJoin(neighIP string) error {
113
+	if neighIP == "" {
114
+		return fmt.Errorf("no neighbor to join")
115
+	}
116
+	if _, err := d.serfInstance.Join([]string{neighIP}, false); err != nil {
117
+		return fmt.Errorf("Failed to join the cluster at neigh IP %s: %v",
118
+			neighIP, err)
119
+	}
120
+	return nil
121
+}
122
+
112 123
 func (d *driver) notifyEvent(event ovNotify) {
113 124
 	n := d.network(event.nid)
114 125
 	ep := n.endpoint(event.eid)
... ...
@@ -246,3 +216,13 @@ func (d *driver) startSerfLoop(eventCh chan serf.Event, notifyCh chan ovNotify,
246 246
 		}
247 247
 	}
248 248
 }
249
+
250
+func (d *driver) isSerfAlive() bool {
251
+	d.Lock()
252
+	serfInstance := d.serfInstance
253
+	d.Unlock()
254
+	if serfInstance == nil || serfInstance.State() != serf.SerfAlive {
255
+		return false
256
+	}
257
+	return true
258
+}
... ...
@@ -6,6 +6,7 @@ import (
6 6
 	"net"
7 7
 	"sync"
8 8
 
9
+	"github.com/Sirupsen/logrus"
9 10
 	"github.com/docker/libkv/store"
10 11
 	"github.com/docker/libnetwork/config"
11 12
 	"github.com/docker/libnetwork/datastore"
... ...
@@ -29,7 +30,7 @@ type driver struct {
29 29
 	eventCh      chan serf.Event
30 30
 	notifyCh     chan ovNotify
31 31
 	exitCh       chan chan struct{}
32
-	ifaceName    string
32
+	bindAddress  string
33 33
 	neighIP      string
34 34
 	config       map[string]interface{}
35 35
 	peerDb       peerNetworkMap
... ...
@@ -38,7 +39,8 @@ type driver struct {
38 38
 	store        datastore.DataStore
39 39
 	ipAllocator  *idm.Idm
40 40
 	vxlanIdm     *idm.Idm
41
-	sync.Once
41
+	once         sync.Once
42
+	joinOnce     sync.Once
42 43
 	sync.Mutex
43 44
 }
44 45
 
... ...
@@ -107,15 +109,7 @@ func (d *driver) configure() error {
107 107
 		return nil
108 108
 	}
109 109
 
110
-	d.Do(func() {
111
-		if ifaceName, ok := d.config[netlabel.OverlayBindInterface]; ok {
112
-			d.ifaceName = ifaceName.(string)
113
-		}
114
-
115
-		if neighIP, ok := d.config[netlabel.OverlayNeighborIP]; ok {
116
-			d.neighIP = neighIP.(string)
117
-		}
118
-
110
+	d.once.Do(func() {
119 111
 		provider, provOk := d.config[netlabel.KVProvider]
120 112
 		provURL, urlOk := d.config[netlabel.KVProviderURL]
121 113
 
... ...
@@ -148,12 +142,6 @@ func (d *driver) configure() error {
148 148
 			err = fmt.Errorf("failed to initalize ipam id manager: %v", err)
149 149
 			return
150 150
 		}
151
-
152
-		err = d.serfInit()
153
-		if err != nil {
154
-			err = fmt.Errorf("initializing serf instance failed: %v", err)
155
-		}
156
-
157 151
 	})
158 152
 
159 153
 	return err
... ...
@@ -162,3 +150,68 @@ func (d *driver) configure() error {
162 162
 func (d *driver) Type() string {
163 163
 	return networkType
164 164
 }
165
+
166
+func (d *driver) nodeJoin(node string, self bool) {
167
+	if self && !d.isSerfAlive() {
168
+		d.Lock()
169
+		d.bindAddress = node
170
+		d.Unlock()
171
+		err := d.serfInit()
172
+		if err != nil {
173
+			logrus.Errorf("initializing serf instance failed: %v", err)
174
+			return
175
+		}
176
+	}
177
+
178
+	d.Lock()
179
+	if !self {
180
+		d.neighIP = node
181
+	}
182
+	neighIP := d.neighIP
183
+	d.Unlock()
184
+
185
+	if d.serfInstance != nil && neighIP != "" {
186
+		var err error
187
+		d.joinOnce.Do(func() {
188
+			err = d.serfJoin(neighIP)
189
+			if err == nil {
190
+				d.pushLocalDb()
191
+			}
192
+		})
193
+		if err != nil {
194
+			logrus.Errorf("joining serf neighbor %s failed: %v", node, err)
195
+			d.Lock()
196
+			d.joinOnce = sync.Once{}
197
+			d.Unlock()
198
+			return
199
+		}
200
+	}
201
+}
202
+
203
+func (d *driver) pushLocalEndpointEvent(action, nid, eid string) {
204
+	if !d.isSerfAlive() {
205
+		return
206
+	}
207
+	d.notifyCh <- ovNotify{
208
+		action: "join",
209
+		nid:    nid,
210
+		eid:    eid,
211
+	}
212
+}
213
+
214
+// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
215
+func (d *driver) DiscoverNew(dType driverapi.DiscoveryType, data interface{}) error {
216
+	if dType == driverapi.NodeDiscovery {
217
+		nodeData, ok := data.(driverapi.NodeDiscoveryData)
218
+		if !ok || nodeData.Address == "" {
219
+			return fmt.Errorf("invalid discovery data")
220
+		}
221
+		d.nodeJoin(nodeData.Address, nodeData.Self)
222
+	}
223
+	return nil
224
+}
225
+
226
+// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
227
+func (d *driver) DiscoverDelete(dType driverapi.DiscoveryType, data interface{}) error {
228
+	return nil
229
+}
... ...
@@ -56,7 +56,23 @@ func (pKey *peerKey) Scan(state fmt.ScanState, verb rune) error {
56 56
 
57 57
 var peerDbWg sync.WaitGroup
58 58
 
59
-func (d *driver) peerDbWalk(nid string, f func(*peerKey, *peerEntry) bool) error {
59
+func (d *driver) peerDbWalk(f func(string, *peerKey, *peerEntry) bool) error {
60
+	d.peerDb.Lock()
61
+	nids := []string{}
62
+	for nid := range d.peerDb.mp {
63
+		nids = append(nids, nid)
64
+	}
65
+	d.peerDb.Unlock()
66
+
67
+	for _, nid := range nids {
68
+		d.peerDbNetworkWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool {
69
+			return f(nid, pKey, pEntry)
70
+		})
71
+	}
72
+	return nil
73
+}
74
+
75
+func (d *driver) peerDbNetworkWalk(nid string, f func(*peerKey, *peerEntry) bool) error {
60 76
 	d.peerDb.Lock()
61 77
 	pMap, ok := d.peerDb.mp[nid]
62 78
 	if !ok {
... ...
@@ -89,7 +105,7 @@ func (d *driver) peerDbSearch(nid string, peerIP net.IP) (net.HardwareAddr, net.
89 89
 		found   bool
90 90
 	)
91 91
 
92
-	err := d.peerDbWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool {
92
+	err := d.peerDbNetworkWalk(nid, func(pKey *peerKey, pEntry *peerEntry) bool {
93 93
 		if pKey.peerIP.Equal(peerIP) {
94 94
 			peerMac = pKey.peerMac
95 95
 			vtep = pEntry.vtep
... ...
@@ -280,3 +296,12 @@ func (d *driver) peerDelete(nid, eid string, peerIP net.IP,
280 280
 
281 281
 	return nil
282 282
 }
283
+
284
+func (d *driver) pushLocalDb() {
285
+	d.peerDbWalk(func(nid string, pKey *peerKey, pEntry *peerEntry) bool {
286
+		if pEntry.isLocal {
287
+			d.pushLocalEndpointEvent("join", nid, pEntry.eid)
288
+		}
289
+		return false
290
+	})
291
+}
... ...
@@ -4,7 +4,11 @@ with a remote driver.
4 4
 */
5 5
 package api
6 6
 
7
-import "net"
7
+import (
8
+	"net"
9
+
10
+	"github.com/docker/libnetwork/driverapi"
11
+)
8 12
 
9 13
 // Response is the basic response structure used in all responses.
10 14
 type Response struct {
... ...
@@ -143,3 +147,14 @@ type LeaveRequest struct {
143 143
 type LeaveResponse struct {
144 144
 	Response
145 145
 }
146
+
147
+// DiscoveryNotification represents a discovery notification
148
+type DiscoveryNotification struct {
149
+	DiscoveryType driverapi.DiscoveryType
150
+	DiscoveryData interface{}
151
+}
152
+
153
+// DiscoveryResponse is used by libnetwork to log any plugin error processing the discovery notifications
154
+type DiscoveryResponse struct {
155
+	Response
156
+}
... ...
@@ -247,6 +247,30 @@ func (d *driver) Type() string {
247 247
 	return d.networkType
248 248
 }
249 249
 
250
+// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
251
+func (d *driver) DiscoverNew(dType driverapi.DiscoveryType, data interface{}) error {
252
+	if dType != driverapi.NodeDiscovery {
253
+		return fmt.Errorf("Unknown discovery type : %v", dType)
254
+	}
255
+	notif := &api.DiscoveryNotification{
256
+		DiscoveryType: dType,
257
+		DiscoveryData: data,
258
+	}
259
+	return d.call("DiscoverNew", notif, &api.DiscoveryResponse{})
260
+}
261
+
262
+// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
263
+func (d *driver) DiscoverDelete(dType driverapi.DiscoveryType, data interface{}) error {
264
+	if dType != driverapi.NodeDiscovery {
265
+		return fmt.Errorf("Unknown discovery type : %v", dType)
266
+	}
267
+	notif := &api.DiscoveryNotification{
268
+		DiscoveryType: dType,
269
+		DiscoveryData: data,
270
+	}
271
+	return d.call("DiscoverDelete", notif, &api.DiscoveryResponse{})
272
+}
273
+
250 274
 func parseStaticRoutes(r api.JoinResponse) ([]*types.StaticRoute, error) {
251 275
 	var routes = make([]*types.StaticRoute, len(r.StaticRoutes))
252 276
 	for i, inRoute := range r.StaticRoutes {
... ...
@@ -52,3 +52,13 @@ func (d *driver) Leave(nid, eid string) error {
52 52
 func (d *driver) Type() string {
53 53
 	return networkType
54 54
 }
55
+
56
+// DiscoverNew is a notification for a new discovery event, such as a new node joining a cluster
57
+func (d *driver) DiscoverNew(dType driverapi.DiscoveryType, data interface{}) error {
58
+	return nil
59
+}
60
+
61
+// DiscoverDelete is a notification for a discovery delete event, such as a node leaving a cluster
62
+func (d *driver) DiscoverDelete(dType driverapi.DiscoveryType, data interface{}) error {
63
+	return nil
64
+}
... ...
@@ -1,73 +1,48 @@
1
-// +build libnetwork_discovery
2
-
3 1
 package hostdiscovery
4 2
 
5 3
 import (
6
-	"errors"
7
-	"fmt"
8 4
 	"net"
9 5
 	"sync"
10
-	"time"
11 6
 
12 7
 	log "github.com/Sirupsen/logrus"
13 8
 
14 9
 	mapset "github.com/deckarep/golang-set"
15
-	"github.com/docker/libnetwork/config"
16
-	"github.com/docker/swarm/discovery"
17
-	// Anonymous import will be removed after we upgrade to latest swarm
18
-	_ "github.com/docker/swarm/discovery/file"
19
-	// Anonymous import will be removed after we upgrade to latest swarm
20
-	_ "github.com/docker/swarm/discovery/kv"
21
-	// Anonymous import will be removed after we upgrade to latest swarm
22
-	_ "github.com/docker/swarm/discovery/nodes"
23
-	// Anonymous import will be removed after we upgrade to latest swarm
24
-	_ "github.com/docker/swarm/discovery/token"
10
+	"github.com/docker/docker/pkg/discovery"
11
+	// Including KV
12
+	_ "github.com/docker/docker/pkg/discovery/kv"
13
+	"github.com/docker/libkv/store/consul"
14
+	"github.com/docker/libkv/store/etcd"
15
+	"github.com/docker/libkv/store/zookeeper"
16
+	"github.com/docker/libnetwork/types"
25 17
 )
26 18
 
27
-const defaultHeartbeat = time.Duration(10) * time.Second
28
-const TTLFactor = 3
29
-
30 19
 type hostDiscovery struct {
31
-	discovery discovery.Discovery
32
-	nodes     mapset.Set
33
-	stopChan  chan struct{}
20
+	watcher  discovery.Watcher
21
+	nodes    mapset.Set
22
+	stopChan chan struct{}
34 23
 	sync.Mutex
35 24
 }
36 25
 
37
-// NewHostDiscovery function creates a host discovery object
38
-func NewHostDiscovery() HostDiscovery {
39
-	return &hostDiscovery{nodes: mapset.NewSet(), stopChan: make(chan struct{})}
26
+func init() {
27
+	consul.Register()
28
+	etcd.Register()
29
+	zookeeper.Register()
40 30
 }
41 31
 
42
-func (h *hostDiscovery) StartDiscovery(cfg *config.ClusterCfg, joinCallback JoinCallback, leaveCallback LeaveCallback) error {
43
-	if cfg == nil {
44
-		return fmt.Errorf("discovery requires a valid configuration")
45
-	}
46
-
47
-	hb := time.Duration(cfg.Heartbeat) * time.Second
48
-	if hb == 0 {
49
-		hb = defaultHeartbeat
50
-	}
51
-	d, err := discovery.New(cfg.Discovery, hb, TTLFactor*hb)
52
-	if err != nil {
53
-		return err
54
-	}
55
-
56
-	if ip := net.ParseIP(cfg.Address); ip == nil {
57
-		return errors.New("address config should be either ipv4 or ipv6 address")
58
-	}
59
-
60
-	if err := d.Register(cfg.Address + ":0"); err != nil {
61
-		return err
62
-	}
32
+// NewHostDiscovery function creates a host discovery object
33
+func NewHostDiscovery(watcher discovery.Watcher) HostDiscovery {
34
+	return &hostDiscovery{watcher: watcher, nodes: mapset.NewSet(), stopChan: make(chan struct{})}
35
+}
63 36
 
37
+func (h *hostDiscovery) Watch(joinCallback JoinCallback, leaveCallback LeaveCallback) error {
64 38
 	h.Lock()
65
-	h.discovery = d
39
+	d := h.watcher
66 40
 	h.Unlock()
67
-
41
+	if d == nil {
42
+		return types.BadRequestErrorf("invalid discovery watcher")
43
+	}
68 44
 	discoveryCh, errCh := d.Watch(h.stopChan)
69 45
 	go h.monitorDiscovery(discoveryCh, errCh, joinCallback, leaveCallback)
70
-	go h.sustainHeartbeat(d, hb, cfg)
71 46
 	return nil
72 47
 }
73 48
 
... ...
@@ -77,7 +52,9 @@ func (h *hostDiscovery) monitorDiscovery(ch <-chan discovery.Entries, errCh <-ch
77 77
 		case entries := <-ch:
78 78
 			h.processCallback(entries, joinCallback, leaveCallback)
79 79
 		case err := <-errCh:
80
-			log.Errorf("discovery error: %v", err)
80
+			if err != nil {
81
+				log.Errorf("discovery error: %v", err)
82
+			}
81 83
 		case <-h.stopChan:
82 84
 			return
83 85
 		}
... ...
@@ -87,26 +64,13 @@ func (h *hostDiscovery) monitorDiscovery(ch <-chan discovery.Entries, errCh <-ch
87 87
 func (h *hostDiscovery) StopDiscovery() error {
88 88
 	h.Lock()
89 89
 	stopChan := h.stopChan
90
-	h.discovery = nil
90
+	h.watcher = nil
91 91
 	h.Unlock()
92 92
 
93 93
 	close(stopChan)
94 94
 	return nil
95 95
 }
96 96
 
97
-func (h *hostDiscovery) sustainHeartbeat(d discovery.Discovery, hb time.Duration, config *config.ClusterCfg) {
98
-	for {
99
-		select {
100
-		case <-h.stopChan:
101
-			return
102
-		case <-time.After(hb):
103
-			if err := d.Register(config.Address + ":0"); err != nil {
104
-				log.Warn(err)
105
-			}
106
-		}
107
-	}
108
-}
109
-
110 97
 func (h *hostDiscovery) processCallback(entries discovery.Entries, joinCallback JoinCallback, leaveCallback LeaveCallback) {
111 98
 	updated := hosts(entries)
112 99
 	h.Lock()
... ...
@@ -135,14 +99,14 @@ func diff(existing mapset.Set, updated mapset.Set) (added []net.IP, removed []ne
135 135
 	return
136 136
 }
137 137
 
138
-func (h *hostDiscovery) Fetch() ([]net.IP, error) {
138
+func (h *hostDiscovery) Fetch() []net.IP {
139 139
 	h.Lock()
140 140
 	defer h.Unlock()
141 141
 	ips := []net.IP{}
142 142
 	for _, ipstr := range h.nodes.ToSlice() {
143 143
 		ips = append(ips, net.ParseIP(ipstr.(string)))
144 144
 	}
145
-	return ips, nil
145
+	return ips
146 146
 }
147 147
 
148 148
 func hosts(entries discovery.Entries) mapset.Set {
... ...
@@ -1,10 +1,6 @@
1 1
 package hostdiscovery
2 2
 
3
-import (
4
-	"net"
5
-
6
-	"github.com/docker/libnetwork/config"
7
-)
3
+import "net"
8 4
 
9 5
 // JoinCallback provides a callback event for new node joining the cluster
10 6
 type JoinCallback func(entries []net.IP)
... ...
@@ -14,10 +10,10 @@ type LeaveCallback func(entries []net.IP)
14 14
 
15 15
 // HostDiscovery primary interface
16 16
 type HostDiscovery interface {
17
-	// StartDiscovery initiates the discovery process and provides appropriate callbacks
18
-	StartDiscovery(*config.ClusterCfg, JoinCallback, LeaveCallback) error
17
+	//Watch Node join and leave cluster events
18
+	Watch(joinCallback JoinCallback, leaveCallback LeaveCallback) error
19 19
 	// StopDiscovery stops the discovery perocess
20 20
 	StopDiscovery() error
21 21
 	// Fetch returns a list of host IPs that are currently discovered
22
-	Fetch() ([]net.IP, error)
22
+	Fetch() []net.IP
23 23
 }
24 24
deleted file mode 100644
... ...
@@ -1,28 +0,0 @@
1
-// +build !libnetwork_discovery
2
-
3
-package hostdiscovery
4
-
5
-import (
6
-	"net"
7
-
8
-	"github.com/docker/libnetwork/config"
9
-)
10
-
11
-type hostDiscovery struct{}
12
-
13
-// NewHostDiscovery function creates a host discovery object
14
-func NewHostDiscovery() HostDiscovery {
15
-	return &hostDiscovery{}
16
-}
17
-
18
-func (h *hostDiscovery) StartDiscovery(cfg *config.ClusterCfg, joinCallback JoinCallback, leaveCallback LeaveCallback) error {
19
-	return nil
20
-}
21
-
22
-func (h *hostDiscovery) StopDiscovery() error {
23
-	return nil
24
-}
25
-
26
-func (h *hostDiscovery) Fetch() ([]net.IP, error) {
27
-	return []net.IP{}, nil
28
-}
... ...
@@ -1,6 +1,6 @@
1 1
 title = "LibNetwork Configuration file"
2 2
 
3 3
 [cluster]
4
-  discovery = "token://08469efb104bce980931ed24c8eb03a2"
5
-  Address = "1.1.1.1"
4
+  discovery = "consul://localhost:8500"
5
+  Address = "6.5.5.5"
6 6
   Heartbeat = 3