This commit brings in end to end integration of Docker Discovery with
libnetwork multi-host networking.
Signed-off-by: Madhu Venugopal <madhu@docker.com>
| ... | ... |
@@ -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 | 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 |
+[](https://travis-ci.org/deckarep/golang-set) |
|
| 1 |
+[](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 |
+[](https://bitdeli.com/free "Bitdeli Badge") |
|
| 92 |
+ |
|
| 93 |
+[](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 |
-} |