Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c0075ab82 | ||
|
|
ae0a4fef50 | ||
|
|
8360024e06 | ||
|
|
2e4d56efd6 | ||
|
|
6bc199a8bc | ||
|
|
537868008f | ||
|
|
1664fce9d1 | ||
|
|
c2cf825cdf | ||
|
|
38a79b7f59 | ||
|
|
010766fe9e | ||
|
|
6b33f4215b | ||
|
|
cc43782d87 | ||
|
|
c2eb900dd3 | ||
|
|
001322751f | ||
|
|
b1ec2b788a | ||
|
|
f42e275884 | ||
|
|
5dfd104728 | ||
|
|
9c096526b8 | ||
|
|
922f465ecb | ||
|
|
08e9db900a | ||
|
|
30b9d33276 | ||
|
|
be3f88656b | ||
|
|
27367ab292 | ||
|
|
20620f0002 | ||
|
|
8d79e33ba1 | ||
|
|
ce4857f5dc | ||
|
|
bceabe32a2 | ||
|
|
6a9f9f66dc | ||
|
|
639e0e82c9 | ||
|
|
4b0a6e1433 | ||
|
|
cb6db91b09 | ||
|
|
6a02e2dc17 | ||
|
|
b377207faf | ||
|
|
24ebb7cc7c | ||
|
|
b5518db03c | ||
|
|
2aa4e6a83a | ||
|
|
7c655cc3ba | ||
|
|
75cda01167 | ||
|
|
4f0f3cf98d | ||
|
|
e014140134 | ||
|
|
c8ae128e59 | ||
|
|
12d848162d | ||
|
|
b12096bd6c | ||
|
|
1430982166 | ||
|
|
2a83aad1d6 | ||
|
|
4a7157959a | ||
|
|
e52abafc48 | ||
|
|
ee531b8023 | ||
|
|
5e761a62b0 | ||
|
|
b442567406 | ||
|
|
17d53af2a2 | ||
|
|
1228dbddb9 | ||
|
|
c00b00d623 | ||
|
|
7bbc9f1b82 | ||
|
|
15a92f9c92 | ||
|
|
9386c01845 | ||
|
|
5232a9af6b | ||
|
|
c393b23b31 | ||
|
|
955fbca44a | ||
|
|
18c26e9fbb | ||
|
|
b54efbde69 | ||
|
|
be9d64b2cc | ||
|
|
c6f356a167 | ||
|
|
eae45ebc94 | ||
|
|
ea50b3d5cc | ||
|
|
3297b93edb | ||
|
|
6d0e867ad0 | ||
|
|
1cea9c1c87 | ||
|
|
3320a9e7d4 | ||
|
|
9b90a938f5 | ||
|
|
c6d0149ba6 | ||
|
|
598efe5d1a | ||
|
|
3679065258 | ||
|
|
4649f1158a | ||
|
|
de17a44f35 | ||
|
|
52ce4df18e | ||
|
|
f1ed5bf838 | ||
|
|
256a801d16 | ||
|
|
c416cf8da5 | ||
|
|
75e812a061 | ||
|
|
4cc7b01940 | ||
|
|
a2ff7e5981 | ||
|
|
cda98a6375 | ||
|
|
3b7a754b0a | ||
|
|
c01c6bcb91 | ||
|
|
e47360f8dc | ||
|
|
6035b54277 | ||
|
|
a238130613 | ||
|
|
998be42a52 | ||
|
|
14944da396 | ||
|
|
a3974c2aeb | ||
|
|
13ec517f94 | ||
|
|
43419815f4 | ||
|
|
b5256f7b71 | ||
|
|
0caa9dd652 | ||
|
|
5e1e8ec543 |
No files matched your search
+5
-20
@@ -1,28 +1,13 @@
|
|||||||
language: go
|
language: python
|
||||||
sudo: false
|
sudo: false
|
||||||
go:
|
|
||||||
- 1.4
|
|
||||||
|
|
||||||
env:
|
env:
|
||||||
- PATH="${PATH}:${HOME}/.local/bin"
|
- PATH="${PATH}:${HOME}/gsutil"
|
||||||
|
|
||||||
addons:
|
|
||||||
apt:
|
|
||||||
packages:
|
|
||||||
- libpcap-dev
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- go clean -i net
|
- pip install pyopenssl
|
||||||
- go install -tags netgo std
|
- curl --silent --location https://storage.googleapis.com/pub/gsutil.tar.gz | tar xz -C $HOME
|
||||||
- go get github.com/golang/lint/golint
|
|
||||||
- pip install --user --upgrade gsutil
|
|
||||||
- bin/setup-ci-secrets $encrypted_5ba036e89377_key $encrypted_5ba036e89377_iv
|
- bin/setup-ci-secrets $encrypted_5ba036e89377_key $encrypted_5ba036e89377_iv
|
||||||
- make travis
|
|
||||||
- go get ./...
|
|
||||||
|
|
||||||
script:
|
script:
|
||||||
- make tests
|
- 'test "${TRAVIS_PULL_REQUEST}" = "true" || site/build-and-publish.sh'
|
||||||
|
|
||||||
after_success:
|
|
||||||
- go get github.com/mattn/goveralls
|
|
||||||
- test "${TRAVIS_PULL_REQUEST}" = "false" && site/build-and-publish.sh
|
|
||||||
@@ -1,3 +1,77 @@
|
|||||||
|
## Release 1.4.6
|
||||||
|
|
||||||
|
Fixes some issues encountered by our users.
|
||||||
|
|
||||||
|
* Restarting a peer could leave stale entries in WeaveDNS
|
||||||
|
#1867/#2023/#2081
|
||||||
|
* Weave proxy occasionally failing to attach any new containers
|
||||||
|
#2016/#2049
|
||||||
|
|
||||||
|
Other fixes:
|
||||||
|
|
||||||
|
* Resolved a crash when a restarting peer re-connected to a peer that
|
||||||
|
had not received the latest IPAM data #2083/#2092
|
||||||
|
* Make IP address space available immediately after a dead peer is
|
||||||
|
removed #2068
|
||||||
|
|
||||||
|
## Release 1.4.5
|
||||||
|
|
||||||
|
Higher performance for multicast and broadcast traffic when using
|
||||||
|
Weave's Fast Datapath
|
||||||
|
|
||||||
|
* The flow rule to deliver broadcast and multicast packets in-kernel
|
||||||
|
was not created correctly, hence every such packet caused a
|
||||||
|
context-switch to the software router #2003/#2008
|
||||||
|
|
||||||
|
Other fixes:
|
||||||
|
|
||||||
|
* Remove DNS entries for containers that are being restarted by Docker
|
||||||
|
but are not live yet #1977/#1989
|
||||||
|
* Don't let one failing allocation attempt prevent others from
|
||||||
|
succeeding; they could be in different subnets which are more
|
||||||
|
available #1996/#2001
|
||||||
|
* Don't complain on second router launch on kernels that lack support
|
||||||
|
for Fast Datapath #1929/#1983
|
||||||
|
* Fix build broken by change in libnetwork IPAM API #1984/#1985
|
||||||
|
|
||||||
|
## Release 1.4.4
|
||||||
|
|
||||||
|
Fixing a rather serious issue that slipped through our preparations
|
||||||
|
for Docker 1.10:
|
||||||
|
|
||||||
|
* Restarting Docker or rebooting your machine while the Weave Net
|
||||||
|
plugin is running causes Docker 1.10.0 to fail to start #1959/#1963
|
||||||
|
|
||||||
|
Also one other small fix:
|
||||||
|
|
||||||
|
* Avoid a hang when trying to use plugin and proxy at the same time
|
||||||
|
#1956/#1961
|
||||||
|
|
||||||
|
## Release 1.4.3
|
||||||
|
|
||||||
|
Preparing for Docker 1.10, plus some bug-fixes.
|
||||||
|
|
||||||
|
* Avoid hang in Docker v1.10 on `docker volume ls` after `weave stop`,
|
||||||
|
`weave stop-plugin` or `weave reset` #1934/#1936
|
||||||
|
* Fix "unexpected EOF" from Docker 1.10 on `docker exec` with Weave
|
||||||
|
proxy `--rewrite-inspect` enabled #1911/#1917
|
||||||
|
* Avoid losing DNS entries and potentially double-allocating IP
|
||||||
|
Addresses allocated via plugin, on router restart; also extend
|
||||||
|
`weave ps` to show IP addresses allocated via plugin #1745/#1921
|
||||||
|
* Stop creating lots of copies of `weavewait` program in Docker
|
||||||
|
volumes #1757/#1935
|
||||||
|
* Prevent container starting prematurely when proxy in
|
||||||
|
`--no-multicast-route` mode #1942/#1943
|
||||||
|
* Log error message from plugin rather than crashing when weave not
|
||||||
|
running #1906/#1918
|
||||||
|
* Warn, don't error, if unable to remove plugin network in 'weave
|
||||||
|
stop', to avoid breaking the usual upgrade or config change process
|
||||||
|
#1900/#1919
|
||||||
|
* Don't crash if network conditions suggest only very small packets
|
||||||
|
will get through #1905/#1926
|
||||||
|
* Cope with unexpected errors during route traversal when starting
|
||||||
|
container via proxy #1909/#1910/#1932
|
||||||
|
|
||||||
## Release 1.4.2
|
## Release 1.4.2
|
||||||
|
|
||||||
Bug-fixes and minor improvements.
|
Bug-fixes and minor improvements.
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ $(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile prog/weaveexec/symlink $(DOCKER
|
|||||||
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker build -t $(WEAVEEXEC_IMAGE) prog/weaveexec
|
$(SUDO) DOCKER_HOST=$(DOCKER_HOST) docker build -t $(WEAVEEXEC_IMAGE) prog/weaveexec
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
$(DOCKERPLUGIN_UPTODATE): prog/plugin/Dockerfile $(DOCKERPLUGIN_EXE)
|
$(DOCKERPLUGIN_UPTODATE): prog/plugin/Dockerfile $(DOCKERPLUGIN_EXE) $(WEAVEEXEC_UPTODATE)
|
||||||
$(SUDO) docker build -t $(DOCKERPLUGIN_IMAGE) prog/plugin
|
$(SUDO) docker build -t $(DOCKERPLUGIN_IMAGE) prog/plugin
|
||||||
touch $@
|
touch $@
|
||||||
|
|
||||||
|
|||||||
+33
-15
@@ -4,12 +4,18 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
docker "github.com/fsouza/go-dockerclient"
|
docker "github.com/fsouza/go-dockerclient"
|
||||||
|
|
||||||
. "github.com/weaveworks/weave/common"
|
. "github.com/weaveworks/weave/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
InitialInterval = 1 * time.Second
|
||||||
|
MaxInterval = 20 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
// An observer for container events
|
// An observer for container events
|
||||||
type ContainerObserver interface {
|
type ContainerObserver interface {
|
||||||
ContainerStarted(ident string)
|
ContainerStarted(ident string)
|
||||||
@@ -72,21 +78,33 @@ func (c *Client) Info() string {
|
|||||||
|
|
||||||
// AddObserver adds an observer for docker events
|
// AddObserver adds an observer for docker events
|
||||||
func (c *Client) AddObserver(ob ContainerObserver) error {
|
func (c *Client) AddObserver(ob ContainerObserver) error {
|
||||||
events := make(chan *docker.APIEvents)
|
|
||||||
if err := c.AddEventListener(events); err != nil {
|
|
||||||
Log.Errorf("[docker] Unable to add listener to Docker API: %s", err)
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for event := range events {
|
retryInterval := InitialInterval
|
||||||
switch event.Status {
|
for {
|
||||||
case "start":
|
events := make(chan *docker.APIEvents)
|
||||||
id := event.ID
|
if err := c.AddEventListener(events); err != nil {
|
||||||
ob.ContainerStarted(id)
|
Log.Errorf("[docker] Unable to add listener to Docker API: %s - retrying in %ds", err, retryInterval/time.Second)
|
||||||
case "die":
|
} else {
|
||||||
id := event.ID
|
start := time.Now()
|
||||||
ob.ContainerDied(id)
|
for event := range events {
|
||||||
|
switch event.Status {
|
||||||
|
case "start":
|
||||||
|
id := event.ID
|
||||||
|
ob.ContainerStarted(id)
|
||||||
|
case "die":
|
||||||
|
id := event.ID
|
||||||
|
ob.ContainerDied(id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if time.Since(start) > retryInterval {
|
||||||
|
retryInterval = InitialInterval
|
||||||
|
}
|
||||||
|
Log.Errorf("[docker] Event listener channel closed - retrying subscription in %ds", retryInterval/time.Second)
|
||||||
|
}
|
||||||
|
time.Sleep(retryInterval)
|
||||||
|
retryInterval = retryInterval * 3 / 2
|
||||||
|
if retryInterval > MaxInterval {
|
||||||
|
retryInterval = MaxInterval
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
@@ -97,7 +115,7 @@ func (c *Client) AddObserver(ob ContainerObserver) error {
|
|||||||
func (c *Client) IsContainerNotRunning(idStr string) bool {
|
func (c *Client) IsContainerNotRunning(idStr string) bool {
|
||||||
container, err := c.InspectContainer(idStr)
|
container, err := c.InspectContainer(idStr)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return !container.State.Running
|
return !container.State.Running || container.State.Restarting
|
||||||
}
|
}
|
||||||
if _, notThere := err.(*docker.NoSuchContainer); notThere {
|
if _, notThere := err.(*docker.NoSuchContainer); notThere {
|
||||||
return true
|
return true
|
||||||
|
|||||||
+15
-18
@@ -140,29 +140,23 @@ func (alloc *Allocator) cancelOpsFor(ops *[]operation, ident string) bool {
|
|||||||
return found
|
return found
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try all pending operations
|
// Try all operations in a queue
|
||||||
func (alloc *Allocator) tryPendingOps() {
|
func (alloc *Allocator) tryOps(ops *[]operation) {
|
||||||
// The slightly different semantics requires us to operate on 'claims' and
|
for i := 0; i < len(*ops); {
|
||||||
// 'allocates' separately:
|
op := (*ops)[i]
|
||||||
// Claims must be tried before Allocates
|
|
||||||
for i := 0; i < len(alloc.pendingClaims); {
|
|
||||||
op := alloc.pendingClaims[i]
|
|
||||||
if !op.Try(alloc) {
|
if !op.Try(alloc) {
|
||||||
i++
|
i++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
alloc.pendingClaims = append(alloc.pendingClaims[:i], alloc.pendingClaims[i+1:]...)
|
*ops = append((*ops)[:i], (*ops)[i+1:]...)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// When the first Allocate fails, bail - no need to
|
// Try all pending operations
|
||||||
// send too many begs for space.
|
func (alloc *Allocator) tryPendingOps() {
|
||||||
for i := 0; i < len(alloc.pendingAllocates); {
|
// Process existing claims before servicing new allocations
|
||||||
op := alloc.pendingAllocates[i]
|
alloc.tryOps(&alloc.pendingClaims)
|
||||||
if !op.Try(alloc) {
|
alloc.tryOps(&alloc.pendingAllocates)
|
||||||
break
|
|
||||||
}
|
|
||||||
alloc.pendingAllocates = append(alloc.pendingAllocates[:i], alloc.pendingAllocates[i+1:]...)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (alloc *Allocator) spaceRequestDenied(sender mesh.PeerName, r address.Range) {
|
func (alloc *Allocator) spaceRequestDenied(sender mesh.PeerName, r address.Range) {
|
||||||
@@ -340,7 +334,10 @@ func (alloc *Allocator) AdminTakeoverRanges(peerNameOrNickname string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
newRanges, err := alloc.ring.Transfer(peername, alloc.ourName)
|
newRanges, err := alloc.ring.Transfer(peername, alloc.ourName)
|
||||||
alloc.space.AddRanges(newRanges)
|
if err == nil && len(newRanges) > 0 {
|
||||||
|
alloc.space.AddRanges(newRanges)
|
||||||
|
alloc.gossip.GossipBroadcast(alloc.Gossip())
|
||||||
|
}
|
||||||
resultChan <- err
|
resultChan <- err
|
||||||
}
|
}
|
||||||
return <-resultChan
|
return <-resultChan
|
||||||
|
|||||||
+16
-9
@@ -46,33 +46,37 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (r *Ring) checkInvariants() error {
|
func (r *Ring) checkInvariants() error {
|
||||||
if !sort.IsSorted(r.Entries) {
|
return r.checkEntries(r.Entries)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *Ring) checkEntries(entries entries) error {
|
||||||
|
if !sort.IsSorted(entries) {
|
||||||
return ErrNotSorted
|
return ErrNotSorted
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check no token appears twice
|
// Check no token appears twice
|
||||||
// We know it's sorted...
|
// We know it's sorted...
|
||||||
for i := 1; i < len(r.Entries); i++ {
|
for i := 1; i < len(entries); i++ {
|
||||||
if r.Entries[i-1].Token == r.Entries[i].Token {
|
if entries[i-1].Token == entries[i].Token {
|
||||||
return ErrTokenRepeated
|
return ErrTokenRepeated
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(r.Entries) == 0 {
|
if len(entries) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check tokens are in range
|
// Check tokens are in range
|
||||||
if r.Entries.entry(0).Token < r.Start {
|
if entries.entry(0).Token < r.Start {
|
||||||
return ErrTokenOutOfRange
|
return ErrTokenOutOfRange
|
||||||
}
|
}
|
||||||
if r.Entries.entry(-1).Token >= r.End {
|
if entries.entry(-1).Token >= r.End {
|
||||||
return ErrTokenOutOfRange
|
return ErrTokenOutOfRange
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check all the freespaces are in range
|
// Check all the freespaces are in range
|
||||||
for i, entry := range r.Entries {
|
for i, entry := range entries {
|
||||||
next := r.Entries.entry(i + 1)
|
next := entries.entry(i + 1)
|
||||||
distance := r.distance(entry.Token, next.Token)
|
distance := r.distance(entry.Token, next.Token)
|
||||||
|
|
||||||
if entry.Free > distance {
|
if entry.Free > distance {
|
||||||
@@ -181,7 +185,6 @@ func (r *Ring) GrantRangeToHost(start, end address.Address, peer mesh.PeerName)
|
|||||||
// Merge the given ring into this ring and return any new ranges added
|
// Merge the given ring into this ring and return any new ranges added
|
||||||
func (r *Ring) Merge(gossip Ring) error {
|
func (r *Ring) Merge(gossip Ring) error {
|
||||||
r.assertInvariants()
|
r.assertInvariants()
|
||||||
defer r.assertInvariants()
|
|
||||||
defer r.updateExportedVariables()
|
defer r.updateExportedVariables()
|
||||||
|
|
||||||
// Don't panic when checking the gossiped in ring.
|
// Don't panic when checking the gossiped in ring.
|
||||||
@@ -267,6 +270,10 @@ func (r *Ring) Merge(gossip Ring) error {
|
|||||||
previousOwner = nil
|
previousOwner = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err := r.checkEntries(result); err != nil {
|
||||||
|
return fmt.Errorf("Merge of incoming data causes: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
if len(r.Seeds) == 0 {
|
if len(r.Seeds) == 0 {
|
||||||
r.Seeds = gossip.Seeds
|
r.Seeds = gossip.Seeds
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ const (
|
|||||||
TargetWaiting TargetState = iota // we are waiting to connect there
|
TargetWaiting TargetState = iota // we are waiting to connect there
|
||||||
TargetAttempting // we are attempting to connect there
|
TargetAttempting // we are attempting to connect there
|
||||||
TargetConnected // we are connected to there
|
TargetConnected // we are connected to there
|
||||||
|
TargetSuspended // not currently attempting to connect here
|
||||||
)
|
)
|
||||||
|
|
||||||
// Information about an address where we may find a peer
|
// Information about an address where we may find a peer
|
||||||
@@ -266,16 +267,23 @@ func (cm *ConnectionMaker) connectToTargets(validTarget map[string]struct{}, dir
|
|||||||
now := time.Now() // make sure we catch items just added
|
now := time.Now() // make sure we catch items just added
|
||||||
after := MaxDuration
|
after := MaxDuration
|
||||||
for address, target := range cm.targets {
|
for address, target := range cm.targets {
|
||||||
if target.state != TargetWaiting {
|
if target.state != TargetWaiting && target.state != TargetSuspended {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if _, valid := validTarget[address]; !valid {
|
if _, valid := validTarget[address]; !valid {
|
||||||
delete(cm.targets, address)
|
// Not valid: suspend reconnects if direct peer,
|
||||||
|
// otherwise forget this target entirely
|
||||||
|
if _, direct := directTarget[address]; direct {
|
||||||
|
target.state = TargetSuspended
|
||||||
|
} else {
|
||||||
|
delete(cm.targets, address)
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if target.tryAfter.IsZero() {
|
if target.tryAfter.IsZero() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
target.state = TargetWaiting
|
||||||
switch duration := target.tryAfter.Sub(now); {
|
switch duration := target.tryAfter.Sub(now); {
|
||||||
case duration <= 0:
|
case duration <= 0:
|
||||||
target.state = TargetAttempting
|
target.state = TargetAttempting
|
||||||
|
|||||||
@@ -181,6 +181,7 @@ func NewLocalConnectionStatusSlice(cm *ConnectionMaker) []LocalConnectionStatus
|
|||||||
add("retrying", target.lastError.Error())
|
add("retrying", target.lastError.Error())
|
||||||
}
|
}
|
||||||
case TargetConnected:
|
case TargetConnected:
|
||||||
|
case TargetSuspended:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resultChan <- slice
|
resultChan <- slice
|
||||||
|
|||||||
+20
-2
@@ -93,6 +93,9 @@ func (e1 *Entry) merge(e2 *Entry) bool {
|
|||||||
e1.Version = e2.Version
|
e1.Version = e2.Version
|
||||||
e1.Tombstone = e2.Tombstone
|
e1.Tombstone = e2.Tombstone
|
||||||
return true
|
return true
|
||||||
|
} else if e2.Version == e1.Version && e2.Tombstone > e1.Tombstone {
|
||||||
|
e1.Tombstone = e2.Tombstone
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -105,6 +108,11 @@ func (e1 *Entry) addLowercase() {
|
|||||||
e1.lHostname = strings.ToLower(e1.Hostname)
|
e1.lHostname = strings.ToLower(e1.Hostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e1 *Entry) tombstone() {
|
||||||
|
e1.Version++
|
||||||
|
e1.Tombstone = now()
|
||||||
|
}
|
||||||
|
|
||||||
func check(es SortableEntries) error {
|
func check(es SortableEntries) error {
|
||||||
if !sort.IsSorted(es) {
|
if !sort.IsSorted(es) {
|
||||||
return fmt.Errorf("Not sorted!")
|
return fmt.Errorf("Not sorted!")
|
||||||
@@ -182,8 +190,7 @@ func (es *Entries) tombstone(ourname mesh.PeerName, f func(*Entry) bool) Entries
|
|||||||
tombstoned := Entries{}
|
tombstoned := Entries{}
|
||||||
for i, e := range *es {
|
for i, e := range *es {
|
||||||
if f(&e) && e.Origin == ourname {
|
if f(&e) && e.Origin == ourname {
|
||||||
e.Version++
|
e.tombstone()
|
||||||
e.Tombstone = now()
|
|
||||||
(*es)[i] = e
|
(*es)[i] = e
|
||||||
tombstoned = append(tombstoned, e)
|
tombstoned = append(tombstoned, e)
|
||||||
}
|
}
|
||||||
@@ -191,6 +198,7 @@ func (es *Entries) tombstone(ourname mesh.PeerName, f func(*Entry) bool) Entries
|
|||||||
return tombstoned
|
return tombstoned
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// note f() may only modify entries such that they remain in order defined by less()
|
||||||
func (es *Entries) filter(f func(*Entry) bool) {
|
func (es *Entries) filter(f func(*Entry) bool) {
|
||||||
defer es.checkAndPanic().checkAndPanic()
|
defer es.checkAndPanic().checkAndPanic()
|
||||||
|
|
||||||
@@ -205,6 +213,16 @@ func (es *Entries) filter(f func(*Entry) bool) {
|
|||||||
*es = (*es)[:i]
|
*es = (*es)[:i]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (es Entries) findEqual(e *Entry) (*Entry, bool) {
|
||||||
|
i := sort.Search(len(es), func(i int) bool {
|
||||||
|
return !es[i].insensitiveLess(e)
|
||||||
|
})
|
||||||
|
if i < len(es) && es[i].equal(*e) {
|
||||||
|
return &es[i], true
|
||||||
|
}
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
func (es Entries) lookup(hostname string) Entries {
|
func (es Entries) lookup(hostname string) Entries {
|
||||||
es.checkAndPanic()
|
es.checkAndPanic()
|
||||||
|
|
||||||
|
|||||||
@@ -86,6 +86,21 @@ func TestTombstone(t *testing.T) {
|
|||||||
Entry{Hostname: "B", Version: 1, Tombstone: 1234},
|
Entry{Hostname: "B", Version: 1, Tombstone: 1234},
|
||||||
})
|
})
|
||||||
require.Equal(t, expected, es)
|
require.Equal(t, expected, es)
|
||||||
|
|
||||||
|
// Now try a merge including two entries which differ only in tombstone
|
||||||
|
e2 := make(Entries, len(es))
|
||||||
|
copy(e2, es)
|
||||||
|
e2[1].Tombstone = 5555
|
||||||
|
|
||||||
|
diff := es.merge(e2)
|
||||||
|
|
||||||
|
expected2 := l(Entries{
|
||||||
|
Entry{Hostname: "A"},
|
||||||
|
Entry{Hostname: "B", Version: 1, Tombstone: 5555},
|
||||||
|
})
|
||||||
|
require.Equal(t, expected2, es)
|
||||||
|
expectedDiff := l(Entries{Entry{Hostname: "B", Version: 1, Tombstone: 5555}})
|
||||||
|
require.Equal(t, expectedDiff, diff)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDelete(t *testing.T) {
|
func TestDelete(t *testing.T) {
|
||||||
|
|||||||
@@ -84,8 +84,8 @@ func (n *Nameserver) broadcastEntries(es ...Entry) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (n *Nameserver) AddEntry(hostname, containerid string, origin mesh.PeerName, addr address.Address) error {
|
func (n *Nameserver) AddEntry(hostname, containerid string, origin mesh.PeerName, addr address.Address) error {
|
||||||
n.infof("adding entry %s -> %s", hostname, addr.String())
|
|
||||||
n.Lock()
|
n.Lock()
|
||||||
|
n.infof("adding entry for %s: %s -> %s", containerid, hostname, addr.String())
|
||||||
entry := n.entries.add(hostname, containerid, origin, addr)
|
entry := n.entries.add(hostname, containerid, origin, addr)
|
||||||
n.Unlock()
|
n.Unlock()
|
||||||
return n.broadcastEntries(entry)
|
return n.broadcastEntries(entry)
|
||||||
@@ -203,11 +203,31 @@ func (n *Nameserver) receiveGossip(msg []byte) (mesh.GossipData, mesh.GossipData
|
|||||||
return nil, nil, fmt.Errorf("clock skew of %d detected", delta)
|
return nil, nil, fmt.Errorf("clock skew of %d detected", delta)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter to remove entries from unknown peers, done before we take
|
||||||
|
// the nameserver lock, so we don't have to worry what isKnownPeer locks.
|
||||||
|
gossip.Entries.filter(func(e *Entry) bool {
|
||||||
|
return n.isKnownPeer(e.Origin)
|
||||||
|
})
|
||||||
|
|
||||||
n.Lock()
|
n.Lock()
|
||||||
defer n.Unlock()
|
defer n.Unlock()
|
||||||
|
|
||||||
|
// Check entries claiming to originate from us against our current data
|
||||||
gossip.Entries.filter(func(e *Entry) bool {
|
gossip.Entries.filter(func(e *Entry) bool {
|
||||||
return n.isKnownPeer(e.Origin)
|
if e.Origin == n.ourName {
|
||||||
|
if ourEntry, ok := n.entries.findEqual(e); ok {
|
||||||
|
if ourEntry.Version < e.Version ||
|
||||||
|
(ourEntry.Version == e.Version && ourEntry.Tombstone != e.Tombstone) {
|
||||||
|
// Take our version of the data, but make the version higher than the incoming
|
||||||
|
nextVersion := e.Version + 1
|
||||||
|
*e = *ourEntry
|
||||||
|
e.Version = nextVersion
|
||||||
|
}
|
||||||
|
} else { // We have no entry matching the one that came in with us as Origin
|
||||||
|
e.tombstone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
newEntries := n.entries.merge(gossip.Entries)
|
newEntries := n.entries.merge(gossip.Entries)
|
||||||
|
|||||||
@@ -52,16 +52,25 @@ func EnsureInterfaceAndMcastRoute(ifaceName string) (*net.Interface, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
dest := net.IPv4(224, 0, 0, 0)
|
dest := net.IPv4(224, 0, 0, 0)
|
||||||
// check for currently-existing route after subscribing, to avoid race
|
check := func(route netlink.Route) bool {
|
||||||
if CheckRouteExists(ifaceName, dest) {
|
return route.Dst != nil && route.Dst.IP.Equal(dest)
|
||||||
return iface, err
|
|
||||||
}
|
}
|
||||||
for update := range ch {
|
// check for currently-existing route after subscribing, to avoid race
|
||||||
link, _ := netlink.LinkByIndex(update.Route.LinkIndex)
|
routes, err := netlink.RouteList(nil, netlink.FAMILY_V4)
|
||||||
if link.Attrs().Name == ifaceName && update.Route.Dst.IP.Equal(dest) {
|
if err != nil {
|
||||||
break
|
return nil, err
|
||||||
|
}
|
||||||
|
for _, route := range routes {
|
||||||
|
if check(route) {
|
||||||
|
return iface, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for update := range ch {
|
||||||
|
if check(update.Route) {
|
||||||
|
return iface, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// should never get here
|
||||||
return iface, nil
|
return iface, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-20
@@ -10,7 +10,7 @@ import (
|
|||||||
// A network is considered free if it does not overlap any existing
|
// A network is considered free if it does not overlap any existing
|
||||||
// routes on this host. This is the same approach taken by Docker.
|
// routes on this host. This is the same approach taken by Docker.
|
||||||
func CheckNetworkFree(subnet *net.IPNet, ignoreIfaceNames map[string]struct{}) error {
|
func CheckNetworkFree(subnet *net.IPNet, ignoreIfaceNames map[string]struct{}) error {
|
||||||
return forEachRoute(ignoreIfaceNames, func(name string, route netlink.Route) error {
|
return forEachRoute(ignoreIfaceNames, func(route netlink.Route) error {
|
||||||
if route.Dst != nil && overlaps(route.Dst, subnet) {
|
if route.Dst != nil && overlaps(route.Dst, subnet) {
|
||||||
return fmt.Errorf("Network %s overlaps with existing route %s on host.", subnet, route.Dst)
|
return fmt.Errorf("Network %s overlaps with existing route %s on host.", subnet, route.Dst)
|
||||||
}
|
}
|
||||||
@@ -26,7 +26,7 @@ func overlaps(n1, n2 *net.IPNet) bool {
|
|||||||
// For a specific address, we only care if it is actually *inside* an
|
// For a specific address, we only care if it is actually *inside* an
|
||||||
// existing route, because weave-local traffic never hits IP routing.
|
// existing route, because weave-local traffic never hits IP routing.
|
||||||
func CheckAddressOverlap(addr net.IP, ignoreIfaceNames map[string]struct{}) error {
|
func CheckAddressOverlap(addr net.IP, ignoreIfaceNames map[string]struct{}) error {
|
||||||
return forEachRoute(ignoreIfaceNames, func(name string, route netlink.Route) error {
|
return forEachRoute(ignoreIfaceNames, func(route netlink.Route) error {
|
||||||
if route.Dst != nil && route.Dst.Contains(addr) {
|
if route.Dst != nil && route.Dst.Contains(addr) {
|
||||||
return fmt.Errorf("Address %s overlaps with existing route %s on host.", addr, route.Dst)
|
return fmt.Errorf("Address %s overlaps with existing route %s on host.", addr, route.Dst)
|
||||||
}
|
}
|
||||||
@@ -34,32 +34,24 @@ func CheckAddressOverlap(addr net.IP, ignoreIfaceNames map[string]struct{}) erro
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func forEachRoute(ignoreIfaceNames map[string]struct{}, check func(name string, r netlink.Route) error) error {
|
func forEachRoute(ignoreIfaceNames map[string]struct{}, check func(r netlink.Route) error) error {
|
||||||
|
ignoreIfaceIndices := make(map[int]struct{})
|
||||||
|
for ifaceName := range ignoreIfaceNames {
|
||||||
|
if iface, err := net.InterfaceByName(ifaceName); err == nil {
|
||||||
|
ignoreIfaceIndices[iface.Index] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
routes, err := netlink.RouteList(nil, netlink.FAMILY_V4)
|
routes, err := netlink.RouteList(nil, netlink.FAMILY_V4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, route := range routes {
|
for _, route := range routes {
|
||||||
link, err := netlink.LinkByIndex(route.LinkIndex)
|
if _, found := ignoreIfaceIndices[route.LinkIndex]; found {
|
||||||
if err == nil {
|
continue
|
||||||
if _, found := ignoreIfaceNames[link.Attrs().Name]; found {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if err := check(link.Attrs().Name, route); err != nil {
|
if err := check(route); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func CheckRouteExists(ifaceName string, dest net.IP) bool {
|
|
||||||
found := false
|
|
||||||
forEachRoute(map[string]struct{}{}, func(name string, route netlink.Route) error {
|
|
||||||
if name == ifaceName && route.Dst.IP.Equal(dest) {
|
|
||||||
found = true
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
return found
|
|
||||||
}
|
|
||||||
+23
-1
@@ -1,10 +1,13 @@
|
|||||||
package ipamplugin
|
package ipamplugin
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
|
"github.com/docker/libnetwork/discoverapi"
|
||||||
"github.com/docker/libnetwork/ipamapi"
|
"github.com/docker/libnetwork/ipamapi"
|
||||||
"github.com/docker/libnetwork/netlabel"
|
"github.com/docker/libnetwork/netlabel"
|
||||||
|
godocker "github.com/fsouza/go-dockerclient"
|
||||||
"github.com/weaveworks/weave/api"
|
"github.com/weaveworks/weave/api"
|
||||||
. "github.com/weaveworks/weave/common"
|
. "github.com/weaveworks/weave/common"
|
||||||
"github.com/weaveworks/weave/common/docker"
|
"github.com/weaveworks/weave/common/docker"
|
||||||
@@ -20,7 +23,13 @@ type ipam struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewIpam(client *docker.Client, version string) (ipamapi.Ipam, error) {
|
func NewIpam(client *docker.Client, version string) (ipamapi.Ipam, error) {
|
||||||
resolver := func() (string, error) { return client.GetContainerIP(WeaveContainer) }
|
resolver := func() (string, error) {
|
||||||
|
addr, err := client.GetContainerIP(WeaveContainer)
|
||||||
|
if _, ok := err.(*godocker.NoSuchContainer); ok {
|
||||||
|
return "", fmt.Errorf("%s container is not present. Have you launched it?", WeaveContainer)
|
||||||
|
}
|
||||||
|
return addr, err
|
||||||
|
}
|
||||||
return &ipam{client: client, weave: api.NewClientWithResolver(resolver)}, nil
|
return &ipam{client: client, weave: api.NewClientWithResolver(resolver)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,6 +42,9 @@ func (i *ipam) RequestPool(addressSpace, pool, subPool string, options map[strin
|
|||||||
Log.Debugln("RequestPool", addressSpace, pool, subPool, options)
|
Log.Debugln("RequestPool", addressSpace, pool, subPool, options)
|
||||||
cidr, err := i.weave.DefaultSubnet()
|
cidr, err := i.weave.DefaultSubnet()
|
||||||
Log.Debugln("RequestPool returning ", cidr, err)
|
Log.Debugln("RequestPool returning ", cidr, err)
|
||||||
|
if err != nil {
|
||||||
|
return "", nil, nil, err
|
||||||
|
}
|
||||||
// Pass back a fake "gateway address"; we don't actually use it,
|
// Pass back a fake "gateway address"; we don't actually use it,
|
||||||
// so just give the network address.
|
// so just give the network address.
|
||||||
data := map[string]string{netlabel.Gateway: cidr.String()}
|
data := map[string]string{netlabel.Gateway: cidr.String()}
|
||||||
@@ -56,3 +68,13 @@ func (i *ipam) ReleaseAddress(poolID string, address net.IP) error {
|
|||||||
Log.Debugln("ReleaseAddress", poolID, address)
|
Log.Debugln("ReleaseAddress", poolID, address)
|
||||||
return i.weave.ReleaseIP(address.String())
|
return i.weave.ReleaseIP(address.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Functions required by ipamapi "contract" but not actually used.
|
||||||
|
|
||||||
|
func (i *ipam) DiscoverNew(discoverapi.DiscoveryType, interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *ipam) DiscoverDelete(discoverapi.DiscoveryType, interface{}) error {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -265,6 +265,7 @@ func sendError(w http.ResponseWriter, msg string, code int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func errorResponse(w http.ResponseWriter, fmtString string, item ...interface{}) {
|
func errorResponse(w http.ResponseWriter, fmtString string, item ...interface{}) {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
json.NewEncoder(w).Encode(map[string]string{
|
json.NewEncoder(w).Encode(map[string]string{
|
||||||
"Err": fmt.Sprintf(fmtString, item...),
|
"Err": fmt.Sprintf(fmtString, item...),
|
||||||
})
|
})
|
||||||
|
|||||||
+19
-15
@@ -69,25 +69,35 @@ func main() {
|
|||||||
Log.Println("Weave plugin", version, "Command line options:", os.Args[1:])
|
Log.Println("Weave plugin", version, "Command line options:", os.Args[1:])
|
||||||
Log.Info(dockerClient.Info())
|
Log.Info(dockerClient.Info())
|
||||||
|
|
||||||
var globalListener, meshListener net.Listener
|
err = run(dockerClient, address, meshAddress, meshNetworkName, nameserver, noMulticastRoute)
|
||||||
|
if err != nil {
|
||||||
|
Log.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func run(dockerClient *docker.Client, address, meshAddress, meshNetworkName, nameserver string, noMulticastRoute bool) error {
|
||||||
endChan := make(chan error, 1)
|
endChan := make(chan error, 1)
|
||||||
if address != "" {
|
if address != "" {
|
||||||
globalListener, err := listenAndServe(dockerClient, address, nameserver, noMulticastRoute, endChan, "global", false)
|
globalListener, err := listenAndServe(dockerClient, address, nameserver, noMulticastRoute, endChan, "global", false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Log.Fatalf("unable to create driver: %s", err)
|
return err
|
||||||
}
|
}
|
||||||
|
defer os.Remove(address)
|
||||||
defer globalListener.Close()
|
defer globalListener.Close()
|
||||||
}
|
}
|
||||||
if meshAddress != "" {
|
if meshAddress != "" {
|
||||||
meshListener, err := listenAndServe(dockerClient, meshAddress, nameserver, noMulticastRoute, endChan, "local", true)
|
meshListener, err := listenAndServe(dockerClient, meshAddress, nameserver, noMulticastRoute, endChan, "local", true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Log.Fatalf("unable to create driver: %s", err)
|
return err
|
||||||
}
|
}
|
||||||
|
defer os.Remove(meshAddress)
|
||||||
defer meshListener.Close()
|
defer meshListener.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
if meshNetworkName != "" {
|
if meshNetworkName != "" {
|
||||||
createNetwork(dockerClient, meshNetworkName, meshAddress)
|
if err := createNetwork(dockerClient, meshNetworkName, meshAddress); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sigChan := make(chan os.Signal, 1)
|
sigChan := make(chan os.Signal, 1)
|
||||||
@@ -96,16 +106,9 @@ func main() {
|
|||||||
select {
|
select {
|
||||||
case sig := <-sigChan:
|
case sig := <-sigChan:
|
||||||
Log.Debugf("Caught signal %s; shutting down", sig)
|
Log.Debugf("Caught signal %s; shutting down", sig)
|
||||||
if err := dockerClient.Client.RemoveNetwork(meshNetworkName); err != nil {
|
return nil
|
||||||
Log.Fatal(err)
|
|
||||||
}
|
|
||||||
case err := <-endChan:
|
case err := <-endChan:
|
||||||
if err != nil {
|
return err
|
||||||
Log.Errorf("Error from listener: %s", err)
|
|
||||||
globalListener.Close()
|
|
||||||
meshListener.Close()
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,7 +144,7 @@ func listenAndServe(dockerClient *docker.Client, address, nameserver string, noM
|
|||||||
return listener, nil
|
return listener, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func createNetwork(dockerClient *docker.Client, networkName, address string) {
|
func createNetwork(dockerClient *docker.Client, networkName, address string) error {
|
||||||
if _, err := dockerClient.Client.NetworkInfo(networkName); err == nil {
|
if _, err := dockerClient.Client.NetworkInfo(networkName); err == nil {
|
||||||
Log.Printf("Docker network '%s' already exists", networkName)
|
Log.Printf("Docker network '%s' already exists", networkName)
|
||||||
} else if _, ok := err.(*go_docker.NoSuchNetwork); ok {
|
} else if _, ok := err.(*go_docker.NoSuchNetwork); ok {
|
||||||
@@ -157,7 +160,8 @@ func createNetwork(dockerClient *docker.Client, networkName, address string) {
|
|||||||
}
|
}
|
||||||
_, err := dockerClient.Client.CreateNetwork(options)
|
_, err := dockerClient.Client.CreateNetwork(options)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Log.Fatalf("Error creating network: %s", err)
|
return fmt.Errorf("Error creating network: %s", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
@@ -4,9 +4,6 @@ MAINTAINER Weaveworks Inc <help@weave.works>
|
|||||||
LABEL works.weave.role=system
|
LABEL works.weave.role=system
|
||||||
|
|
||||||
WORKDIR /home/weave
|
WORKDIR /home/weave
|
||||||
VOLUME /w
|
|
||||||
VOLUME /w-noop
|
|
||||||
VOLUME /w-nomcast
|
|
||||||
ENTRYPOINT ["/home/weave/sigproxy", "/home/weave/weave"]
|
ENTRYPOINT ["/home/weave/sigproxy", "/home/weave/weave"]
|
||||||
|
|
||||||
RUN apk add --update \
|
RUN apk add --update \
|
||||||
|
|||||||
@@ -22,6 +22,10 @@ func (i *inspectExecInterceptor) InterceptResponse(r *http.Response) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _, ok := exec["Container"]; !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
container, err := exec.Object("Container")
|
container, err := exec.Object("Container")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
+2
-1
@@ -132,7 +132,8 @@ func (proxy *Proxy) AttachExistingContainers() {
|
|||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if containerShouldAttach(container) && (container.State.Running || container.State.Paused) {
|
// The 'Running' check is purely an optimisation.
|
||||||
|
if containerShouldAttach(container) && container.State.Running {
|
||||||
proxy.attach(container, false)
|
proxy.attach(container, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-4
@@ -775,10 +775,10 @@ func (fwd *fastDatapathForwarder) Forward(key ForwardPacketKey) FlowOp {
|
|||||||
defer fwd.lock.RUnlock()
|
defer fwd.lock.RUnlock()
|
||||||
|
|
||||||
if fwd.remoteAddr == nil {
|
if fwd.remoteAddr == nil {
|
||||||
// Returning nil would discard the packet, but also
|
// Returning a DiscardingFlowOp would discard the
|
||||||
// result in a flow rule, which we would have to
|
// packet, but also result in a flow rule, which we
|
||||||
// invalidate when we learn the remote IP. So for
|
// would have to invalidate when we learn the remote
|
||||||
// now, just prevent flows.
|
// IP. So for now, just prevent flows.
|
||||||
return vetoFlowCreationFlowOp{}
|
return vetoFlowCreationFlowOp{}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1086,6 +1086,10 @@ func (fastdp *FastDatapath) send(fops FlowOp, frame []byte, lock *fastDatapathLo
|
|||||||
case vetoFlowCreationFlowOp:
|
case vetoFlowCreationFlowOp:
|
||||||
createFlow = false
|
createFlow = false
|
||||||
default:
|
default:
|
||||||
|
if xfop.Discards() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// A foreign FlowOp (e.g. a sleeve forwarding
|
// A foreign FlowOp (e.g. a sleeve forwarding
|
||||||
// FlowOp), so send the packet through the
|
// FlowOp), so send the packet through the
|
||||||
// FlowOp interface, decoding the packet
|
// FlowOp interface, decoding the packet
|
||||||
|
|||||||
+1
-4
@@ -84,15 +84,12 @@ func (mfop *MultiFlowOp) Discards() bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flatten out a FlowOp to eliminate any MultiFlowOps
|
||||||
func FlattenFlowOp(fop FlowOp) []FlowOp {
|
func FlattenFlowOp(fop FlowOp) []FlowOp {
|
||||||
return collectFlowOps(nil, fop)
|
return collectFlowOps(nil, fop)
|
||||||
}
|
}
|
||||||
|
|
||||||
func collectFlowOps(into []FlowOp, fop FlowOp) []FlowOp {
|
func collectFlowOps(into []FlowOp, fop FlowOp) []FlowOp {
|
||||||
if fop == nil {
|
|
||||||
return into
|
|
||||||
}
|
|
||||||
|
|
||||||
if mfop, ok := fop.(*MultiFlowOp); ok {
|
if mfop, ok := fop.(*MultiFlowOp); ok {
|
||||||
for _, op := range mfop.ops {
|
for _, op := range mfop.ops {
|
||||||
into = collectFlowOps(into, op)
|
into = collectFlowOps(into, op)
|
||||||
|
|||||||
+1
-1
@@ -917,7 +917,7 @@ func (fwd *sleeveForwarder) processSendError(err error) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
fwd.mtuHighestGood = 8
|
fwd.mtuHighestGood = 552
|
||||||
fwd.mtuLowestBad = mtu + 1
|
fwd.mtuLowestBad = mtu + 1
|
||||||
fwd.mtuCandidate = mtu
|
fwd.mtuCandidate = mtu
|
||||||
fwd.mtuTestsSent = 0
|
fwd.mtuTestsSent = 0
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="navbar navbar-inverse">
|
<div class="navbar navbar-inverse">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<a class="navbar-brand" href="http://weave.works/"><img src="http://weave.works/img/weave-logo.png"></a>
|
<a class="navbar-brand" href="http://weave.works/"><img src="http://www.weave.works/wp-content/uploads/2015/11/weave-logo-nav.png" class=" img-responsive" align="left"></a>
|
||||||
</div>
|
</div>
|
||||||
<div class="nav-wrapper">
|
<div class="nav-wrapper">
|
||||||
<ul class="nav navbar-nav navbar-right">
|
<ul class="nav navbar-nav navbar-right">
|
||||||
|
|||||||
+9
-1
@@ -87,7 +87,12 @@ launched via the Docker
|
|||||||
[command-line interface](https://docs.docker.com/reference/commandline/cli/)
|
[command-line interface](https://docs.docker.com/reference/commandline/cli/)
|
||||||
or
|
or
|
||||||
[remote API](https://docs.docker.com/reference/api/docker_remote_api/)
|
[remote API](https://docs.docker.com/reference/api/docker_remote_api/)
|
||||||
are attached to the weave network before they begin execution.
|
are attached to the weave network before they begin execution. To use
|
||||||
|
the proxy, run
|
||||||
|
|
||||||
|
$ eval $(weave env)
|
||||||
|
|
||||||
|
and then start containers as usual.
|
||||||
|
|
||||||
Containers started in this way that subsequently restart, either by an
|
Containers started in this way that subsequently restart, either by an
|
||||||
explicit `docker restart` command or by Docker restart policy, are
|
explicit `docker restart` command or by Docker restart policy, are
|
||||||
@@ -100,6 +105,9 @@ named `weave` is created by `weave launch`, which you can use like this:
|
|||||||
|
|
||||||
$ docker run --net=weave -ti ubuntu
|
$ docker run --net=weave -ti ubuntu
|
||||||
|
|
||||||
|
> NB: The plugin is an *alternative* to the proxy, hence one should
|
||||||
|
> *not* run `eval $(weave env)` beforehand.
|
||||||
|
|
||||||
For more details see the [plugin documentation](plugin.html).
|
For more details see the [plugin documentation](plugin.html).
|
||||||
|
|
||||||
### <a name="addressing"></a>Address allocation
|
### <a name="addressing"></a>Address allocation
|
||||||
|
|||||||
+19
-13
@@ -48,17 +48,6 @@ time, you can give the number of peers like this:
|
|||||||
|
|
||||||
host3$ weave launch --init-peer-count 3 $HOST2
|
host3$ weave launch --init-peer-count 3 $HOST2
|
||||||
|
|
||||||
The consensus mechanism used to determine a majority transitions
|
|
||||||
through three states: 'deferred', 'waiting' and 'achieved':
|
|
||||||
|
|
||||||
* 'deferred' - no allocation requests or claims have been made yet;
|
|
||||||
consensus is deferred until then
|
|
||||||
* 'waiting' - an attempt to achieve consensus is ongoing, triggered by
|
|
||||||
an allocation or claim request; allocations will block. This state
|
|
||||||
persists until a quorum of peers are able to communicate amongst
|
|
||||||
themselves successfully
|
|
||||||
* 'achieved' - consensus achieved; allocations proceed normally
|
|
||||||
|
|
||||||
### More on `--init-peer-count`
|
### More on `--init-peer-count`
|
||||||
|
|
||||||
TL;DR: it isn't a problem to over-estimate by a bit, but if you supply
|
TL;DR: it isn't a problem to over-estimate by a bit, but if you supply
|
||||||
@@ -214,7 +203,7 @@ reports on the current status of the weave router and IP allocator:
|
|||||||
...
|
...
|
||||||
|
|
||||||
Service: ipam
|
Service: ipam
|
||||||
Consensus: waiting(quorum: 2, known: 0)
|
Status: awaiting consensus (quorum: 2, known: 0)
|
||||||
Range: 10.32.0.0-10.47.255.255
|
Range: 10.32.0.0-10.47.255.255
|
||||||
DefaultSubnet: 10.32.0.0/12
|
DefaultSubnet: 10.32.0.0/12
|
||||||
|
|
||||||
@@ -225,4 +214,21 @@ The first section covers the router; see the [troubleshooting
|
|||||||
guide](troubleshooting.html#weave-status) for full details.
|
guide](troubleshooting.html#weave-status) for full details.
|
||||||
|
|
||||||
The 'Service: ipam' section displays the consensus state as well as
|
The 'Service: ipam' section displays the consensus state as well as
|
||||||
the total allocation range and default subnet.
|
the total allocation range and default subnet. Columns are as follows:
|
||||||
|
|
||||||
|
* 'Status' - allocator state
|
||||||
|
* 'idle' - no allocation requests or claims have been made yet;
|
||||||
|
consensus is deferred until then
|
||||||
|
* 'awaiting consensus' - an attempt to achieve consensus is
|
||||||
|
ongoing, triggered by an allocation or claim request;
|
||||||
|
allocations will block. This state persists until a quorum of
|
||||||
|
peers are able to communicate amongst themselves successfully
|
||||||
|
* 'ready' - consensus achieved; allocations proceed normally
|
||||||
|
* 'waiting for IP range grant from peers' - peer has exhausted its
|
||||||
|
agreed portion of the range and is waiting to be granted some
|
||||||
|
more
|
||||||
|
* 'all IP ranges owned by unreachable peers' - peer has exhausted
|
||||||
|
its agreed portion of the range but cannot reach anyone to ask
|
||||||
|
for more
|
||||||
|
* 'Range' - total allocation range set by `--ipalloc-range`
|
||||||
|
* 'DefaultSubnet' - default subnet set by `--ipalloc-default-subnet`
|
||||||
+48
-25
@@ -5,36 +5,53 @@ layout: default
|
|||||||
|
|
||||||
# Weave Plugin
|
# Weave Plugin
|
||||||
|
|
||||||
New in Docker version 1.9 is a plugin mechanism to add different
|
Docker versions 1.9 and later have a plugin mechanism for adding
|
||||||
network providers.
|
different network providers. Weave installs itself as a network plugin
|
||||||
|
when you start it with `weave launch`. To create a network that spans
|
||||||
|
multiple docker hosts, the weave peers must be connected in the usual
|
||||||
|
way, i.e. by specifying other hosts in `weave launch` or
|
||||||
|
[`weave connect`](features.html#dynamic-topologies).
|
||||||
|
|
||||||
To install, download the `weave` script as per the [readme][].
|
Subsequently you can start containers with, e.g.
|
||||||
|
|
||||||
The Weave Net plugin runs automatically when you `weave launch`. You
|
|
||||||
must still tell the weave peers to connect to one another, either via
|
|
||||||
`weave launch` or `weave connect`.
|
|
||||||
|
|
||||||
## Starting a container
|
|
||||||
|
|
||||||
$ docker run --net=weave -ti ubuntu
|
$ docker run --net=weave -ti ubuntu
|
||||||
|
|
||||||
## Using WeaveDNS for Service Discovery
|
on any of the hosts, and they can all communicate with each other.
|
||||||
|
|
||||||
You need to pass the additional arguments `--dns` and `-dns-search`,
|
> WARNING: It is inadvisable to attach containers to the weave network
|
||||||
for which we provide a helper in the weave script:
|
> using both the Weave Docker Networking Plugin and
|
||||||
|
> [Weave Docker API Proxy](proxy.html) simultaneously. Such containers
|
||||||
|
> will end up with two weave network interfaces and two IP addresses,
|
||||||
|
> which is rarely desirable. To ensure the proxy is not being used,
|
||||||
|
> *do not run `eval $(weave env)`, or `docker $(weave config) ...`*.
|
||||||
|
|
||||||
|
In order to use Weave's [Service Discovery](weavedns.html), you
|
||||||
|
need to pass the additional arguments `--dns` and `-dns-search`, for
|
||||||
|
which we provide a helper in the weave script:
|
||||||
|
|
||||||
$ docker run --net=weave -h foo.weave.local $(weave dns-args) -tdi ubuntu
|
$ docker run --net=weave -h foo.weave.local $(weave dns-args) -tdi ubuntu
|
||||||
$ docker run --net=weave -h bar.weave.local $(weave dns-args) -ti ubuntu
|
|
||||||
# ping foo
|
|
||||||
|
|
||||||
For more details see the [Weave Service Discovery documentation][service-discovery].
|
Here is a complete example of using the plugin for connectivity
|
||||||
|
between two containers running on different hosts:
|
||||||
|
|
||||||
|
host1$ weave launch
|
||||||
|
host1$ docker run --net=weave -h foo.weave.local $(weave dns-args) -tdi ubuntu
|
||||||
|
|
||||||
|
host2$ weave launch $HOST1
|
||||||
|
host2$ docker run --net=weave $(weave dns-args) -ti ubuntu
|
||||||
|
root@cb73d1a8aece:/# ping -c1 -q foo
|
||||||
|
PING foo (10.32.0.1) 56(84) bytes of data.
|
||||||
|
|
||||||
|
--- foo ping statistics ---
|
||||||
|
1 packets transmitted, 1 received, 0% packet loss, time 0ms
|
||||||
|
rtt min/avg/max/mdev = 1.341/1.341/1.341/0.000 ms
|
||||||
|
|
||||||
## Under the hood
|
## Under the hood
|
||||||
|
|
||||||
The Weave Net plugin actually provides *two* network drivers to Docker
|
The Weave plugin actually provides *two* network drivers to Docker
|
||||||
- one named `weavemesh` that can operate without a [cluster
|
- one named `weavemesh` that can operate without a cluster store and
|
||||||
store](#cluster-store) (like Docker's overlay driver) and one named
|
one named `weave` that can only work with one (like Docker's overlay
|
||||||
`weave` that can only work with one.
|
driver).
|
||||||
|
|
||||||
### `weavemesh` driver
|
### `weavemesh` driver
|
||||||
|
|
||||||
@@ -54,7 +71,8 @@ networks.
|
|||||||
* Used with Docker's cluster store based IPAM
|
* Used with Docker's cluster store based IPAM
|
||||||
|
|
||||||
There's no specific documentation from Docker on using a cluster
|
There's no specific documentation from Docker on using a cluster
|
||||||
store, but the first part of [Getting Started with Docker Multi-host Networking][docker-net]
|
store, but the first part of
|
||||||
|
[Getting Started with Docker Multi-host Networking](https://github.com/docker/docker/blob/master/docs/userguide/networking/get-started-overlay.md)
|
||||||
should point the way.
|
should point the way.
|
||||||
|
|
||||||
Note that in the case of multiple networks using the `weave` driver, all containers are
|
Note that in the case of multiple networks using the `weave` driver, all containers are
|
||||||
@@ -87,9 +105,14 @@ route, add the `--no-multicast-route` flag to `weave launch-plugin`.
|
|||||||
We start the plugin with a policy of `--restart=always`, so that it is
|
We start the plugin with a policy of `--restart=always`, so that it is
|
||||||
there after a restart or reboot. If you remove this container
|
there after a restart or reboot. If you remove this container
|
||||||
(e.g. using `weave reset`) before removing all endpoints created using
|
(e.g. using `weave reset`) before removing all endpoints created using
|
||||||
`--net=weave`, Docker can
|
`--net=weave`, Docker may hang for a long time when it subsequently
|
||||||
[hang](https://github.com/docker/libnetwork/issues/813).
|
tries to talk to the plugin.
|
||||||
|
|
||||||
[readme]: https://github.com/weaveworks/weave/blob/master/README.md#installation
|
Unfortunately, [Docker 1.9 may also try to talk to the plugin before it has even started it](https://github.com/docker/libnetwork/issues/813).
|
||||||
[service-discovery]: weavedns.html
|
If using `systemd`, we advise that you modify the Docker unit to
|
||||||
[docker-net]: https://github.com/docker/docker/blob/master/docs/userguide/networking/get-started-overlay.md
|
remove the timeout on startup, to give Docker enough time to abandon
|
||||||
|
its attempts.
|
||||||
|
|
||||||
|
E.g. in the file `/lib/systemd/system/docker.service`, add under `[Service]`:
|
||||||
|
|
||||||
|
TimeoutStartSec=0
|
||||||
@@ -62,7 +62,7 @@ $ weave status
|
|||||||
TrustedSubnets: none
|
TrustedSubnets: none
|
||||||
|
|
||||||
Service: ipam
|
Service: ipam
|
||||||
Consensus: achieved
|
Status: ready
|
||||||
Range: 10.32.0.0-10.47.255.255
|
Range: 10.32.0.0-10.47.255.255
|
||||||
DefaultSubnet: 10.32.0.0/12
|
DefaultSubnet: 10.32.0.0/12
|
||||||
|
|
||||||
@@ -124,6 +124,13 @@ Proxy](proxy.html#troubleshooting).
|
|||||||
|
|
||||||
### <a name="weave-status-connections"></a>List connections
|
### <a name="weave-status-connections"></a>List connections
|
||||||
|
|
||||||
|
Connections between weave peers carry control traffic over TCP and
|
||||||
|
data traffic over UDP. For a connection to be fully established, the
|
||||||
|
TCP connection and UDP data path must be able to transmit information
|
||||||
|
in both directions. Weave routers check this regularly with
|
||||||
|
heartbeats. Failed connections are automatically retried, with an
|
||||||
|
exponential back-off.
|
||||||
|
|
||||||
Detailed information on the local weave router's connections can be
|
Detailed information on the local weave router's connections can be
|
||||||
obtained with `weave status connections`:
|
obtained with `weave status connections`:
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@ hosts.
|
|||||||
* [Adding and removing extra DNS entries](#add-remove)
|
* [Adding and removing extra DNS entries](#add-remove)
|
||||||
* [Resolve weaveDNS entries from host](#resolve-weavedns-entries-from-host)
|
* [Resolve weaveDNS entries from host](#resolve-weavedns-entries-from-host)
|
||||||
* [Hot-swapping service containers](#hot-swapping)
|
* [Hot-swapping service containers](#hot-swapping)
|
||||||
* [Retaining DNS entries when containers stop](#retain-stopped)
|
|
||||||
* [Configuring a custom TTL](#ttl)
|
* [Configuring a custom TTL](#ttl)
|
||||||
* [Configuring the domain search path](#domain-search-path)
|
* [Configuring the domain search path](#domain-search-path)
|
||||||
* [Using a different local domain](#local-domain)
|
* [Using a different local domain](#local-domain)
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ C2=10.2.1.71
|
|||||||
# 700 = Linux's minimum PMTU (552) + weave framing overheads
|
# 700 = Linux's minimum PMTU (552) + weave framing overheads
|
||||||
# (currently about 60, but we leave some margin). That way the PMTUs
|
# (currently about 60, but we leave some margin). That way the PMTUs
|
||||||
# seen by containers is still >= 552.
|
# seen by containers is still >= 552.
|
||||||
drop_large_udp_packets="FORWARD -p udp --destination-port 6783 -m length '!' --length 0:700 -j DROP"
|
drop_large_sleeve_packets="INPUT -p udp --destination-port 6783 -m length '!' --length 0:700 -j DROP"
|
||||||
|
drop_large_fastdp_packets="INPUT -p udp --destination-port 6784 -m length '!' --length 0:700 -j DROP"
|
||||||
|
|
||||||
start_suite "PMTU discovery and packet fragmentation"
|
start_suite "PMTU discovery and packet fragmentation"
|
||||||
|
|
||||||
@@ -18,7 +19,8 @@ weave_on $HOST2 launch
|
|||||||
start_container $HOST1 $C1/24 --name=c1
|
start_container $HOST1 $C1/24 --name=c1
|
||||||
start_container $HOST2 $C2/24 --name=c2
|
start_container $HOST2 $C2/24 --name=c2
|
||||||
|
|
||||||
run_on $HOST2 "sudo iptables -I $drop_large_udp_packets"
|
run_on $HOST1 "sudo iptables -I $drop_large_sleeve_packets"
|
||||||
|
run_on $HOST1 "sudo iptables -I $drop_large_fastdp_packets"
|
||||||
assert_raises "weave_on $HOST2 connect $HOST1"
|
assert_raises "weave_on $HOST2 connect $HOST1"
|
||||||
sleep 35 # give weave time to discover the PMTU
|
sleep 35 # give weave time to discover the PMTU
|
||||||
|
|
||||||
@@ -28,6 +30,7 @@ sleep 35 # give weave time to discover the PMTU
|
|||||||
exec_on $HOST2 c2 $PING -s 10000 $C1 1>/dev/null 2>&1 || true
|
exec_on $HOST2 c2 $PING -s 10000 $C1 1>/dev/null 2>&1 || true
|
||||||
assert_raises "exec_on $HOST2 c2 $PING -s 10000 $C1"
|
assert_raises "exec_on $HOST2 c2 $PING -s 10000 $C1"
|
||||||
|
|
||||||
run_on $HOST2 "sudo iptables -D $drop_large_udp_packets"
|
run_on $HOST1 "sudo iptables -D $drop_large_fastdp_packets"
|
||||||
|
run_on $HOST1 "sudo iptables -D $drop_large_sleeve_packets"
|
||||||
|
|
||||||
end_suite
|
end_suite
|
||||||
Executable
+31
@@ -0,0 +1,31 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
. ./config.sh
|
||||||
|
|
||||||
|
start_suite "Check propagation of DNS entries when gossip is delayed"
|
||||||
|
|
||||||
|
weave_on $HOST1 launch-router --no-discovery
|
||||||
|
weave_on $HOST2 launch-router --no-discovery $HOST1
|
||||||
|
weave_on $HOST3 launch-router --no-discovery $HOST2
|
||||||
|
|
||||||
|
start_container $HOST1 --name=c1
|
||||||
|
C1=$(container_ip $HOST1 c1)
|
||||||
|
start_container_with_dns $HOST3 --name=c3
|
||||||
|
|
||||||
|
assert_dns_record $HOST3 c3 c1.weave.local $C1
|
||||||
|
|
||||||
|
# Stall the propagation of gossip, stop weave and kill the container
|
||||||
|
run_on $HOST3 "sudo iptables -A INPUT -s $HOST2 -j DROP"
|
||||||
|
|
||||||
|
weave_on $HOST1 stop-router
|
||||||
|
docker_on $HOST1 rm -f c1
|
||||||
|
|
||||||
|
weave_on $HOST1 launch-router --no-discovery $HOST3
|
||||||
|
|
||||||
|
# Now re-enable gossip
|
||||||
|
run_on $HOST3 "sudo iptables -D INPUT -s $HOST2 -j DROP"
|
||||||
|
|
||||||
|
# Currently failing due to Mesh #28
|
||||||
|
# assert_no_dns_record $HOST3 c3 c1.weave.local
|
||||||
|
|
||||||
|
end_suite
|
||||||
@@ -6,15 +6,26 @@ entrypoint() {
|
|||||||
docker_on $HOST1 inspect --format="{{.Config.Entrypoint}}" "$@"
|
docker_on $HOST1 inspect --format="{{.Config.Entrypoint}}" "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_iface_ready() {
|
||||||
|
assert_raises "proxy docker_on $HOST1 run -e 'WEAVE_CIDR=$1' $BASE_IMAGE $CHECK_ETHWE_UP"
|
||||||
|
assert_raises "proxy docker_on $HOST1 run -e 'WEAVE_CIDR=$1' $BASE_IMAGE ip -4 -o addr show ethwe | grep -q '$1'"
|
||||||
|
}
|
||||||
|
|
||||||
start_suite "Proxy waits for weave to be ready before running container commands"
|
start_suite "Proxy waits for weave to be ready before running container commands"
|
||||||
weave_on $HOST1 launch-proxy
|
|
||||||
BASE_IMAGE=busybox
|
BASE_IMAGE=busybox
|
||||||
# Ensure the base image does not exist, so that it will be pulled
|
# Ensure the base image does not exist, so that it will be pulled
|
||||||
! docker_on $HOST1 inspect --format=" " $BASE_IMAGE >/dev/null 2>&1 || docker_on $HOST1 rmi $BASE_IMAGE
|
! docker_on $HOST1 inspect --format=" " $BASE_IMAGE >/dev/null 2>&1 || docker_on $HOST1 rmi $BASE_IMAGE
|
||||||
|
|
||||||
assert_raises "proxy docker_on $HOST1 run --name c1 -e 'WEAVE_CIDR=10.2.1.1/24' $BASE_IMAGE $CHECK_ETHWE_UP"
|
# check that interface is ready, with and without --no-multicast-route
|
||||||
|
weave_on $HOST1 launch-proxy --no-multicast-route
|
||||||
|
check_iface_ready 10.2.1.1/24
|
||||||
|
weave_on $HOST1 stop-proxy
|
||||||
|
weave_on $HOST1 launch-proxy
|
||||||
|
check_iface_ready 10.2.1.1/24
|
||||||
|
|
||||||
# Check committed containers only have one weavewait prepended
|
# Check committed containers only have one weavewait prepended
|
||||||
|
proxy_start_container $HOST1 --name c1 -e 'WEAVE_CIDR=10.2.1.1/24'
|
||||||
COMMITTED_IMAGE=$(proxy docker_on $HOST1 commit c1)
|
COMMITTED_IMAGE=$(proxy docker_on $HOST1 commit c1)
|
||||||
assert_raises "proxy docker_on $HOST1 run --name c2 $COMMITTED_IMAGE"
|
assert_raises "proxy docker_on $HOST1 run --name c2 $COMMITTED_IMAGE"
|
||||||
assert "entrypoint c2" "$(entrypoint $COMMITTED_IMAGE)"
|
assert "entrypoint c2" "$(entrypoint $COMMITTED_IMAGE)"
|
||||||
|
|||||||
@@ -34,8 +34,8 @@ assert_raises "proxy docker_on $HOST1 ps"
|
|||||||
weave_on $HOST1 stop-proxy
|
weave_on $HOST1 stop-proxy
|
||||||
|
|
||||||
# Booting it over tls errors
|
# Booting it over tls errors
|
||||||
assert_raises "DOCKER_CLIENT_ARGS='--tls' weave_on $HOST1 launch-proxy" 1
|
assert_raises "! DOCKER_CLIENT_ARGS='--tls' weave_on $HOST1 launch-proxy"
|
||||||
assert_raises "DOCKER_CERT_PATH='./tls' DOCKER_TLS_VERIFY=1 weave_on $HOST1 launch-proxy" 1
|
assert_raises "! DOCKER_CERT_PATH='./tls' DOCKER_TLS_VERIFY=1 weave_on $HOST1 launch-proxy"
|
||||||
|
|
||||||
# Booting it with a specific -H overrides defaults
|
# Booting it with a specific -H overrides defaults
|
||||||
weave_on $HOST1 launch-proxy -H tcp://0.0.0.0:12345
|
weave_on $HOST1 launch-proxy -H tcp://0.0.0.0:12345
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ start_suite "Proxy failure modes"
|
|||||||
|
|
||||||
# docker run should fail when weave router is not running
|
# docker run should fail when weave router is not running
|
||||||
weave_on $HOST1 launch-proxy
|
weave_on $HOST1 launch-proxy
|
||||||
assert_raises "proxy docker_on $HOST1 run --rm $SMALL_IMAGE true" 1
|
assert_raises "! proxy docker_on $HOST1 run --rm $SMALL_IMAGE true"
|
||||||
assert_raises "proxy docker_on $HOST1 run --rm $SMALL_IMAGE true 2>&1 1>/dev/null | grep 'Error response from daemon: weave container is not present. Have you launched it?'"
|
assert_raises "proxy docker_on $HOST1 run --rm $SMALL_IMAGE true 2>&1 1>/dev/null | grep 'Error response from daemon: weave container is not present. Have you launched it?'"
|
||||||
|
|
||||||
end_suite
|
end_suite
|
||||||
Executable
+24
@@ -0,0 +1,24 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
. ./config.sh
|
||||||
|
|
||||||
|
C1_NAME=c1.weave.local
|
||||||
|
|
||||||
|
start_suite "Recovery of container details on router restart (via 'local' plugin)"
|
||||||
|
|
||||||
|
weave_on $HOST1 launch
|
||||||
|
start_container_local_plugin $HOST1 --name=c1 --hostname=$C1_NAME
|
||||||
|
c1ip=$(container_ip $HOST1 c1)
|
||||||
|
|
||||||
|
weave_on $HOST1 stop-router
|
||||||
|
weave_on $HOST1 launch-router
|
||||||
|
|
||||||
|
assert "container_ip $HOST1 c1" "$c1ip"
|
||||||
|
assert "weave_on $HOST1 dns-lookup $C1_NAME" "$c1ip"
|
||||||
|
|
||||||
|
# check that c1 IP has been reclaimed and doesn't get assigned to a
|
||||||
|
# fresh container
|
||||||
|
start_container $HOST1 --name=c2
|
||||||
|
assert_raises "container_ip $HOST1 c2 | grep -v $c1ip"
|
||||||
|
|
||||||
|
end_suite
|
||||||
+1
-1
@@ -176,7 +176,7 @@ proxy_start_container_with_dns() {
|
|||||||
rm_containers() {
|
rm_containers() {
|
||||||
host=$1
|
host=$1
|
||||||
shift
|
shift
|
||||||
[ $# -eq 0 ] || docker_on $host rm -f "$@" >/dev/null
|
[ $# -eq 0 ] || docker_on $host rm -f -v "$@" >/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
container_ip() {
|
container_ip() {
|
||||||
|
|||||||
+1
-1
@@ -11,7 +11,7 @@ set -e
|
|||||||
: ${SSH_KEY_FILE:=$HOME/.ssh/gce_ssh_key}
|
: ${SSH_KEY_FILE:=$HOME/.ssh/gce_ssh_key}
|
||||||
: ${PROJECT:=positive-cocoa-90213}
|
: ${PROJECT:=positive-cocoa-90213}
|
||||||
: ${IMAGE:=ubuntu-14-04}
|
: ${IMAGE:=ubuntu-14-04}
|
||||||
: ${TEMPLATE_NAME:=test-template-9}
|
: ${TEMPLATE_NAME:=test-template-10}
|
||||||
: ${ZONE:=us-central1-a}
|
: ${ZONE:=us-central1-a}
|
||||||
: ${NUM_HOSTS:=5}
|
: ${NUM_HOSTS:=5}
|
||||||
SUFFIX=""
|
SUFFIX=""
|
||||||
|
|||||||
@@ -344,6 +344,7 @@ IMAGE=$BASE_IMAGE:$IMAGE_VERSION
|
|||||||
BASE_PLUGIN_IMAGE=$DOCKERHUB_USER/plugin
|
BASE_PLUGIN_IMAGE=$DOCKERHUB_USER/plugin
|
||||||
PLUGIN_IMAGE=$BASE_PLUGIN_IMAGE:$IMAGE_VERSION
|
PLUGIN_IMAGE=$BASE_PLUGIN_IMAGE:$IMAGE_VERSION
|
||||||
PLUGIN_CONTAINER_NAME=weaveplugin
|
PLUGIN_CONTAINER_NAME=weaveplugin
|
||||||
|
VOLUMES_CONTAINER_NAME=weavevolumes-$IMAGE_VERSION
|
||||||
|
|
||||||
PROCFS=${PROCFS:-/proc}
|
PROCFS=${PROCFS:-/proc}
|
||||||
DOCKER_BRIDGE=${DOCKER_BRIDGE:-docker0}
|
DOCKER_BRIDGE=${DOCKER_BRIDGE:-docker0}
|
||||||
@@ -535,7 +536,9 @@ create_bridge() {
|
|||||||
add_iptables_rule nat POSTROUTING -j WEAVE
|
add_iptables_rule nat POSTROUTING -j WEAVE
|
||||||
else
|
else
|
||||||
if [ -n "$LAUNCHING_ROUTER" ] ; then
|
if [ -n "$LAUNCHING_ROUTER" ] ; then
|
||||||
if [ "$BRIDGE_TYPE" = bridge -a -z "$WEAVE_NO_FASTDP" ] ; then
|
if [ "$BRIDGE_TYPE" = bridge -a -z "$WEAVE_NO_FASTDP" ] &&
|
||||||
|
util_op create-datapath $DATAPATH 2>/dev/null &&
|
||||||
|
util_op delete-datapath $DATAPATH 2>/dev/null ; then
|
||||||
cat <<EOF >&1
|
cat <<EOF >&1
|
||||||
WEAVE_NO_FASTDP is not set, but there is already a bridge present of
|
WEAVE_NO_FASTDP is not set, but there is already a bridge present of
|
||||||
the wrong type for fast datapath. Please do 'weave reset' to remove
|
the wrong type for fast datapath. Please do 'weave reset' to remove
|
||||||
@@ -762,11 +765,11 @@ connect_container_to_bridge() {
|
|||||||
# veth pair in the 'up' or 'down' state. Furthermore, moving one
|
# veth pair in the 'up' or 'down' state. Furthermore, moving one
|
||||||
# end into a netns normally sets them to 'down'. But, moving an
|
# end into a netns normally sets them to 'down'. But, moving an
|
||||||
# end into the default netns is a null operation, so they stay up,
|
# end into the default netns is a null operation, so they stay up,
|
||||||
# which leads to errors later on. So to get a consistent result,
|
# which leads to errors in 'set name' since that requires the
|
||||||
# we have to be explicit in setting them 'up' or 'down' as
|
# interface to be down. So to get a consistent result, we set the
|
||||||
# necessary.
|
# interface 'down' to begin with.
|
||||||
if ! netnsenter ip link set $GUEST_IFNAME down ||
|
if ! netnsenter ip link set $GUEST_IFNAME down ||
|
||||||
! netnsenter ip link set $GUEST_IFNAME name $1 up ||
|
! netnsenter ip link set $GUEST_IFNAME name $1 ||
|
||||||
! ip link set $LOCAL_IFNAME up ||
|
! ip link set $LOCAL_IFNAME up ||
|
||||||
! add_iface_$BRIDGE_TYPE $LOCAL_IFNAME ||
|
! add_iface_$BRIDGE_TYPE $LOCAL_IFNAME ||
|
||||||
! configure_arp_cache $1 "netnsenter" ; then
|
! configure_arp_cache $1 "netnsenter" ; then
|
||||||
@@ -833,8 +836,12 @@ setup_router_iface_bridged_fastdp() {
|
|||||||
setup_router_iface_fastdp "$@"
|
setup_router_iface_fastdp "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
container_in_host_ns() {
|
||||||
|
[ -h "$PROCFS/$CONTAINER_PID/ns/net" -a -h "/proc/self/ns/net" -a "$(readlink $PROCFS/$CONTAINER_PID/ns/net)" = "$(readlink /proc/self/ns/net)" ]
|
||||||
|
}
|
||||||
|
|
||||||
attach() {
|
attach() {
|
||||||
if [ -h "$PROCFS/$CONTAINER_PID/ns/net" -a -h "/proc/self/ns/net" -a "$(readlink $PROCFS/$CONTAINER_PID/ns/net)" = "$(readlink /proc/self/ns/net)" ] ; then
|
if container_in_host_ns ; then
|
||||||
echo "Container is running in the host network namespace, and therefore cannot be" >&2
|
echo "Container is running in the host network namespace, and therefore cannot be" >&2
|
||||||
echo "connected to weave. Perhaps the container was started with --net=host." >&2
|
echo "connected to weave. Perhaps the container was started with --net=host." >&2
|
||||||
return 1
|
return 1
|
||||||
@@ -895,8 +902,8 @@ detach() {
|
|||||||
netnsenter ip link del $CONTAINER_IFNAME type veth
|
netnsenter ip link del $CONTAINER_IFNAME type veth
|
||||||
}
|
}
|
||||||
|
|
||||||
container_weave_addrs() {
|
container_ip_addr_show() {
|
||||||
netnsenter ip addr show dev $CONTAINER_IFNAME
|
! container_in_host_ns && netnsenter ip addr show
|
||||||
}
|
}
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
@@ -1027,6 +1034,17 @@ wait_for_status() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Parse the output of `ip addr show`, outputing weave addresses of kind $1
|
||||||
|
addrs_from_ip_addr_show() {
|
||||||
|
while read first second rest ; do
|
||||||
|
if [ "$first" != "${first%:}" ] ; then
|
||||||
|
iname="${second%:}"
|
||||||
|
elif [ "$first" = "$1" -a \( "$iname" = "weave" -o "$iname" != "${iname#ethwe}" \) ] ; then
|
||||||
|
echo $second
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
# Call $1 for all containers, passing container ID, all MACs and all IPs
|
# Call $1 for all containers, passing container ID, all MACs and all IPs
|
||||||
with_container_addresses() {
|
with_container_addresses() {
|
||||||
COMMAND=$1
|
COMMAND=$1
|
||||||
@@ -1035,12 +1053,14 @@ with_container_addresses() {
|
|||||||
if [ "$CONTAINER_ID" = "weave:expose" ] ; then
|
if [ "$CONTAINER_ID" = "weave:expose" ] ; then
|
||||||
ADDRS_CMD="ip addr show dev $BRIDGE"
|
ADDRS_CMD="ip addr show dev $BRIDGE"
|
||||||
else
|
else
|
||||||
ADDRS_CMD="with_container_netns $CONTAINER_ID container_weave_addrs"
|
ADDRS_CMD="with_container_netns $CONTAINER_ID container_ip_addr_show"
|
||||||
fi
|
fi
|
||||||
if CONTAINER_ADDRS=$($ADDRS_CMD 2>/dev/null) ; then
|
if CONTAINER_ADDRS=$($ADDRS_CMD 2>/dev/null) ; then
|
||||||
CONTAINER_MAC=$(echo "$CONTAINER_ADDRS" | grep -o 'link/ether .*' | cut -d ' ' -f 2)
|
CONTAINER_MAC=$(echo "$CONTAINER_ADDRS" | addrs_from_ip_addr_show 'link/ether')
|
||||||
CONTAINER_IPS=$(echo "$CONTAINER_ADDRS" | grep -o 'inet .*' | cut -d ' ' -f 2)
|
CONTAINER_IPS=$(echo "$CONTAINER_ADDRS" | addrs_from_ip_addr_show 'inet')
|
||||||
$COMMAND "$CONTAINER_ID" "$CONTAINER_MAC" "$CONTAINER_IPS"
|
if [ -n "$CONTAINER_MAC$CONTAINER_IPS" ] ; then
|
||||||
|
$COMMAND "$CONTAINER_ID" "$CONTAINER_MAC" "$CONTAINER_IPS"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
@@ -1278,7 +1298,7 @@ collect_dns_add_remove_args() {
|
|||||||
# with_container_addresses.
|
# with_container_addresses.
|
||||||
ipam_reclaim() {
|
ipam_reclaim() {
|
||||||
for CIDR in $3 ; do
|
for CIDR in $3 ; do
|
||||||
# NB: CONTAINER_IP is the IP of the weave container; it is set by wait_for_status.
|
# NB: CONTAINER_IP is the IP of the weave container.
|
||||||
http_call $CONTAINER_IP:$HTTP_PORT PUT /ip/$1/${CIDR%/*}?noErrorOnUnknown=true
|
http_call $CONTAINER_IP:$HTTP_PORT PUT /ip/$1/${CIDR%/*}?noErrorOnUnknown=true
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
@@ -1476,7 +1496,7 @@ proxy_args() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
proxy_addrs() {
|
proxy_addrs() {
|
||||||
if addr="$(http_call_unix $PROXY_CONTAINER_NAME status.sock GET /status 2>&1)" ; then
|
if addr="$(http_call_unix $PROXY_CONTAINER_NAME status.sock GET /status 2>/dev/null)" ; then
|
||||||
echo "$addr" | sed "s/0.0.0.0/$PROXY_HOST/g"
|
echo "$addr" | sed "s/0.0.0.0/$PROXY_HOST/g"
|
||||||
|
|
||||||
else
|
else
|
||||||
@@ -1650,7 +1670,7 @@ attach_router() {
|
|||||||
if [ -z "$NO_DNS_OPT" ] ; then
|
if [ -z "$NO_DNS_OPT" ] ; then
|
||||||
# Tell the newly-started weaveDNS about existing weave IPs
|
# Tell the newly-started weaveDNS about existing weave IPs
|
||||||
for CONTAINER in $(docker ps -q --no-trunc) ; do
|
for CONTAINER in $(docker ps -q --no-trunc) ; do
|
||||||
if CONTAINER_IPS=$(with_container_netns $CONTAINER container_weave_addrs 2>&1 | sed -n -e 's/inet \([^/]*\)\/\(.*\)/\1/p') ; then
|
if CONTAINER_IPS=$(with_container_netns $CONTAINER container_ip_addr_show 2>/dev/null | addrs_from_ip_addr_show 'inet') && [ -n "$CONTAINER_IPS" ] ; then
|
||||||
with_container_fqdn $CONTAINER put_dns_fqdn $CONTAINER_IPS
|
with_container_fqdn $CONTAINER put_dns_fqdn $CONTAINER_IPS
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
@@ -1669,8 +1689,14 @@ launch_proxy() {
|
|||||||
docker_client_args $DOCKER_CLIENT_ARGS
|
docker_client_args $DOCKER_CLIENT_ARGS
|
||||||
proxy_args "$@"
|
proxy_args "$@"
|
||||||
mkdir -p /var/run/weave
|
mkdir -p /var/run/weave
|
||||||
|
# Create a data-only container to mount the weavewait files from
|
||||||
|
if ! docker inspect -f ' ' $VOLUMES_CONTAINER_NAME > /dev/null 2>&1 ; then
|
||||||
|
docker create -v /w -v /w-noop -v /w-nomcast --name=$VOLUMES_CONTAINER_NAME \
|
||||||
|
--label=weavevolumes --entrypoint=/bin/false $EXEC_IMAGE >/dev/null
|
||||||
|
fi
|
||||||
PROXY_CONTAINER=$(docker run --privileged -d --name=$PROXY_CONTAINER_NAME --net=host \
|
PROXY_CONTAINER=$(docker run --privileged -d --name=$PROXY_CONTAINER_NAME --net=host \
|
||||||
$PROXY_VOLUMES \
|
$PROXY_VOLUMES \
|
||||||
|
--volumes-from $VOLUMES_CONTAINER_NAME \
|
||||||
$(docker_sock_options) \
|
$(docker_sock_options) \
|
||||||
-v /var/run/weave:/var/run/weave \
|
-v /var/run/weave:/var/run/weave \
|
||||||
-v /proc:/hostproc \
|
-v /proc:/hostproc \
|
||||||
@@ -1715,8 +1741,12 @@ remove_plugin_network() {
|
|||||||
$PLUGIN_IMAGE --remove-network
|
$PLUGIN_IMAGE --remove-network
|
||||||
}
|
}
|
||||||
|
|
||||||
|
warn_plugin_active() {
|
||||||
|
echo "WARNING: docker may hang in this state; re-launch weave and remove attached containers before shutting down" >&2
|
||||||
|
}
|
||||||
|
|
||||||
stop_plugin() {
|
stop_plugin() {
|
||||||
remove_plugin_network
|
remove_plugin_network || warn_plugin_active
|
||||||
stop $PLUGIN_CONTAINER_NAME "Plugin"
|
stop $PLUGIN_CONTAINER_NAME "Plugin"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2152,14 +2182,15 @@ EOF
|
|||||||
;;
|
;;
|
||||||
reset)
|
reset)
|
||||||
[ $# -eq 0 ] || usage
|
[ $# -eq 0 ] || usage
|
||||||
plugin_disabled || remove_plugin_network || \
|
plugin_disabled || remove_plugin_network || warn_plugin_active
|
||||||
echo "WARNING: docker may hang in this state; re-launch weave and remove attached containers before shutting down" >&2
|
|
||||||
warn_if_stopping_proxy_in_env
|
warn_if_stopping_proxy_in_env
|
||||||
call_weave DELETE /peer >/dev/null 2>&1 || true
|
call_weave DELETE /peer >/dev/null 2>&1 || true
|
||||||
for NAME in $PLUGIN_CONTAINER_NAME $CONTAINER_NAME $PROXY_CONTAINER_NAME ; do
|
for NAME in $PLUGIN_CONTAINER_NAME $CONTAINER_NAME $PROXY_CONTAINER_NAME ; do
|
||||||
docker stop $NAME >/dev/null 2>&1 || true
|
docker stop $NAME >/dev/null 2>&1 || true
|
||||||
docker rm -f $NAME >/dev/null 2>&1 || true
|
docker rm -f $NAME >/dev/null 2>&1 || true
|
||||||
done
|
done
|
||||||
|
VOLUME_CONTAINERS=$(docker ps -qa --filter label=weavevolumes)
|
||||||
|
[ -n "$VOLUME_CONTAINERS" ] && docker rm -v $VOLUME_CONTAINERS >/dev/null 2>&1 || true
|
||||||
conntrack -D -p udp --dport $PORT >/dev/null 2>&1 || true
|
conntrack -D -p udp --dport $PORT >/dev/null 2>&1 || true
|
||||||
destroy_bridge
|
destroy_bridge
|
||||||
for LOCAL_IFNAME in $(ip link show | grep v${CONTAINER_IFNAME}pl | cut -d ' ' -f 2 | tr -d ':') ; do
|
for LOCAL_IFNAME in $(ip link show | grep v${CONTAINER_IFNAME}pl | cut -d ' ' -f 2 | tr -d ':') ; do
|
||||||
|
|||||||
Reference in new issue
Block a user