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