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 |
No files matched your search
+5
-20
@@ -1,28 +1,13 @@
|
||||
language: go
|
||||
language: python
|
||||
sudo: false
|
||||
go:
|
||||
- 1.4
|
||||
|
||||
env:
|
||||
- PATH="${PATH}:${HOME}/.local/bin"
|
||||
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libpcap-dev
|
||||
- PATH="${PATH}:${HOME}/gsutil"
|
||||
|
||||
install:
|
||||
- go clean -i net
|
||||
- go install -tags netgo std
|
||||
- go get github.com/golang/lint/golint
|
||||
- pip install --user --upgrade gsutil
|
||||
- pip install pyopenssl
|
||||
- curl --silent --location https://storage.googleapis.com/pub/gsutil.tar.gz | tar xz -C $HOME
|
||||
- bin/setup-ci-secrets $encrypted_5ba036e89377_key $encrypted_5ba036e89377_iv
|
||||
- make travis
|
||||
- go get ./...
|
||||
|
||||
script:
|
||||
- make tests
|
||||
|
||||
after_success:
|
||||
- go get github.com/mattn/goveralls
|
||||
- test "${TRAVIS_PULL_REQUEST}" = "false" && site/build-and-publish.sh
|
||||
- 'test "${TRAVIS_PULL_REQUEST}" = "true" || site/build-and-publish.sh'
|
||||
@@ -1,3 +1,39 @@
|
||||
## 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
|
||||
|
||||
+33
-15
@@ -4,12 +4,18 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
docker "github.com/fsouza/go-dockerclient"
|
||||
|
||||
. "github.com/weaveworks/weave/common"
|
||||
)
|
||||
|
||||
const (
|
||||
InitialInterval = 1 * time.Second
|
||||
MaxInterval = 20 * time.Second
|
||||
)
|
||||
|
||||
// An observer for container events
|
||||
type ContainerObserver interface {
|
||||
ContainerStarted(ident string)
|
||||
@@ -72,21 +78,33 @@ func (c *Client) Info() string {
|
||||
|
||||
// AddObserver adds an observer for docker events
|
||||
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() {
|
||||
for event := range events {
|
||||
switch event.Status {
|
||||
case "start":
|
||||
id := event.ID
|
||||
ob.ContainerStarted(id)
|
||||
case "die":
|
||||
id := event.ID
|
||||
ob.ContainerDied(id)
|
||||
retryInterval := InitialInterval
|
||||
for {
|
||||
events := make(chan *docker.APIEvents)
|
||||
if err := c.AddEventListener(events); err != nil {
|
||||
Log.Errorf("[docker] Unable to add listener to Docker API: %s - retrying in %ds", err, retryInterval/time.Second)
|
||||
} else {
|
||||
start := time.Now()
|
||||
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 {
|
||||
container, err := c.InspectContainer(idStr)
|
||||
if err == nil {
|
||||
return !container.State.Running
|
||||
return !container.State.Running || container.State.Restarting
|
||||
}
|
||||
if _, notThere := err.(*docker.NoSuchContainer); notThere {
|
||||
return true
|
||||
|
||||
+15
-18
@@ -140,29 +140,23 @@ func (alloc *Allocator) cancelOpsFor(ops *[]operation, ident string) bool {
|
||||
return found
|
||||
}
|
||||
|
||||
// Try all pending operations
|
||||
func (alloc *Allocator) tryPendingOps() {
|
||||
// The slightly different semantics requires us to operate on 'claims' and
|
||||
// 'allocates' separately:
|
||||
// Claims must be tried before Allocates
|
||||
for i := 0; i < len(alloc.pendingClaims); {
|
||||
op := alloc.pendingClaims[i]
|
||||
// Try all operations in a queue
|
||||
func (alloc *Allocator) tryOps(ops *[]operation) {
|
||||
for i := 0; i < len(*ops); {
|
||||
op := (*ops)[i]
|
||||
if !op.Try(alloc) {
|
||||
i++
|
||||
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
|
||||
// send too many begs for space.
|
||||
for i := 0; i < len(alloc.pendingAllocates); {
|
||||
op := alloc.pendingAllocates[i]
|
||||
if !op.Try(alloc) {
|
||||
break
|
||||
}
|
||||
alloc.pendingAllocates = append(alloc.pendingAllocates[:i], alloc.pendingAllocates[i+1:]...)
|
||||
}
|
||||
// Try all pending operations
|
||||
func (alloc *Allocator) tryPendingOps() {
|
||||
// Process existing claims before servicing new allocations
|
||||
alloc.tryOps(&alloc.pendingClaims)
|
||||
alloc.tryOps(&alloc.pendingAllocates)
|
||||
}
|
||||
|
||||
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)
|
||||
alloc.space.AddRanges(newRanges)
|
||||
if err == nil && len(newRanges) > 0 {
|
||||
alloc.space.AddRanges(newRanges)
|
||||
alloc.gossip.GossipBroadcast(alloc.Gossip())
|
||||
}
|
||||
resultChan <- err
|
||||
}
|
||||
return <-resultChan
|
||||
|
||||
+16
-9
@@ -46,33 +46,37 @@ var (
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// Check no token appears twice
|
||||
// We know it's sorted...
|
||||
for i := 1; i < len(r.Entries); i++ {
|
||||
if r.Entries[i-1].Token == r.Entries[i].Token {
|
||||
for i := 1; i < len(entries); i++ {
|
||||
if entries[i-1].Token == entries[i].Token {
|
||||
return ErrTokenRepeated
|
||||
}
|
||||
}
|
||||
|
||||
if len(r.Entries) == 0 {
|
||||
if len(entries) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Check tokens are in range
|
||||
if r.Entries.entry(0).Token < r.Start {
|
||||
if entries.entry(0).Token < r.Start {
|
||||
return ErrTokenOutOfRange
|
||||
}
|
||||
if r.Entries.entry(-1).Token >= r.End {
|
||||
if entries.entry(-1).Token >= r.End {
|
||||
return ErrTokenOutOfRange
|
||||
}
|
||||
|
||||
// Check all the freespaces are in range
|
||||
for i, entry := range r.Entries {
|
||||
next := r.Entries.entry(i + 1)
|
||||
for i, entry := range entries {
|
||||
next := entries.entry(i + 1)
|
||||
distance := r.distance(entry.Token, next.Token)
|
||||
|
||||
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
|
||||
func (r *Ring) Merge(gossip Ring) error {
|
||||
r.assertInvariants()
|
||||
defer r.assertInvariants()
|
||||
defer r.updateExportedVariables()
|
||||
|
||||
// Don't panic when checking the gossiped in ring.
|
||||
@@ -267,6 +270,10 @@ func (r *Ring) Merge(gossip Ring) error {
|
||||
previousOwner = nil
|
||||
}
|
||||
|
||||
if err := r.checkEntries(result); err != nil {
|
||||
return fmt.Errorf("Merge of incoming data causes: %s", err)
|
||||
}
|
||||
|
||||
if len(r.Seeds) == 0 {
|
||||
r.Seeds = gossip.Seeds
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ const (
|
||||
TargetWaiting TargetState = iota // we are waiting to connect there
|
||||
TargetAttempting // we are attempting to connect there
|
||||
TargetConnected // we are connected to there
|
||||
TargetSuspended // not currently attempting to connect here
|
||||
)
|
||||
|
||||
// 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
|
||||
after := MaxDuration
|
||||
for address, target := range cm.targets {
|
||||
if target.state != TargetWaiting {
|
||||
if target.state != TargetWaiting && target.state != TargetSuspended {
|
||||
continue
|
||||
}
|
||||
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
|
||||
}
|
||||
if target.tryAfter.IsZero() {
|
||||
continue
|
||||
}
|
||||
target.state = TargetWaiting
|
||||
switch duration := target.tryAfter.Sub(now); {
|
||||
case duration <= 0:
|
||||
target.state = TargetAttempting
|
||||
|
||||
@@ -181,6 +181,7 @@ func NewLocalConnectionStatusSlice(cm *ConnectionMaker) []LocalConnectionStatus
|
||||
add("retrying", target.lastError.Error())
|
||||
}
|
||||
case TargetConnected:
|
||||
case TargetSuspended:
|
||||
}
|
||||
}
|
||||
resultChan <- slice
|
||||
|
||||
+20
-2
@@ -93,6 +93,9 @@ func (e1 *Entry) merge(e2 *Entry) bool {
|
||||
e1.Version = e2.Version
|
||||
e1.Tombstone = e2.Tombstone
|
||||
return true
|
||||
} else if e2.Version == e1.Version && e2.Tombstone > e1.Tombstone {
|
||||
e1.Tombstone = e2.Tombstone
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
@@ -105,6 +108,11 @@ func (e1 *Entry) addLowercase() {
|
||||
e1.lHostname = strings.ToLower(e1.Hostname)
|
||||
}
|
||||
|
||||
func (e1 *Entry) tombstone() {
|
||||
e1.Version++
|
||||
e1.Tombstone = now()
|
||||
}
|
||||
|
||||
func check(es SortableEntries) error {
|
||||
if !sort.IsSorted(es) {
|
||||
return fmt.Errorf("Not sorted!")
|
||||
@@ -182,8 +190,7 @@ func (es *Entries) tombstone(ourname mesh.PeerName, f func(*Entry) bool) Entries
|
||||
tombstoned := Entries{}
|
||||
for i, e := range *es {
|
||||
if f(&e) && e.Origin == ourname {
|
||||
e.Version++
|
||||
e.Tombstone = now()
|
||||
e.tombstone()
|
||||
(*es)[i] = e
|
||||
tombstoned = append(tombstoned, e)
|
||||
}
|
||||
@@ -191,6 +198,7 @@ func (es *Entries) tombstone(ourname mesh.PeerName, f func(*Entry) bool) Entries
|
||||
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) {
|
||||
defer es.checkAndPanic().checkAndPanic()
|
||||
|
||||
@@ -205,6 +213,16 @@ func (es *Entries) filter(f func(*Entry) bool) {
|
||||
*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 {
|
||||
es.checkAndPanic()
|
||||
|
||||
|
||||
@@ -86,6 +86,21 @@ func TestTombstone(t *testing.T) {
|
||||
Entry{Hostname: "B", Version: 1, Tombstone: 1234},
|
||||
})
|
||||
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) {
|
||||
|
||||
@@ -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 {
|
||||
n.infof("adding entry %s -> %s", hostname, addr.String())
|
||||
n.Lock()
|
||||
n.infof("adding entry for %s: %s -> %s", containerid, hostname, addr.String())
|
||||
entry := n.entries.add(hostname, containerid, origin, addr)
|
||||
n.Unlock()
|
||||
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)
|
||||
}
|
||||
|
||||
// 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()
|
||||
defer n.Unlock()
|
||||
|
||||
// Check entries claiming to originate from us against our current data
|
||||
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)
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/docker/libnetwork/discoverapi"
|
||||
"github.com/docker/libnetwork/ipamapi"
|
||||
"github.com/docker/libnetwork/netlabel"
|
||||
godocker "github.com/fsouza/go-dockerclient"
|
||||
@@ -67,3 +68,13 @@ func (i *ipam) ReleaseAddress(poolID string, address net.IP) error {
|
||||
Log.Debugln("ReleaseAddress", poolID, address)
|
||||
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
|
||||
}
|
||||
+2
-1
@@ -132,7 +132,8 @@ func (proxy *Proxy) AttachExistingContainers() {
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
+8
-4
@@ -775,10 +775,10 @@ func (fwd *fastDatapathForwarder) Forward(key ForwardPacketKey) FlowOp {
|
||||
defer fwd.lock.RUnlock()
|
||||
|
||||
if fwd.remoteAddr == nil {
|
||||
// Returning nil would discard the packet, but also
|
||||
// result in a flow rule, which we would have to
|
||||
// invalidate when we learn the remote IP. So for
|
||||
// now, just prevent flows.
|
||||
// Returning a DiscardingFlowOp would discard the
|
||||
// packet, but also result in a flow rule, which we
|
||||
// would have to invalidate when we learn the remote
|
||||
// IP. So for now, just prevent flows.
|
||||
return vetoFlowCreationFlowOp{}
|
||||
}
|
||||
|
||||
@@ -1086,6 +1086,10 @@ func (fastdp *FastDatapath) send(fops FlowOp, frame []byte, lock *fastDatapathLo
|
||||
case vetoFlowCreationFlowOp:
|
||||
createFlow = false
|
||||
default:
|
||||
if xfop.Discards() {
|
||||
continue
|
||||
}
|
||||
|
||||
// A foreign FlowOp (e.g. a sleeve forwarding
|
||||
// FlowOp), so send the packet through the
|
||||
// FlowOp interface, decoding the packet
|
||||
|
||||
+1
-4
@@ -84,15 +84,12 @@ func (mfop *MultiFlowOp) Discards() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Flatten out a FlowOp to eliminate any MultiFlowOps
|
||||
func FlattenFlowOp(fop FlowOp) []FlowOp {
|
||||
return collectFlowOps(nil, fop)
|
||||
}
|
||||
|
||||
func collectFlowOps(into []FlowOp, fop FlowOp) []FlowOp {
|
||||
if fop == nil {
|
||||
return into
|
||||
}
|
||||
|
||||
if mfop, ok := fop.(*MultiFlowOp); ok {
|
||||
for _, op := range mfop.ops {
|
||||
into = collectFlowOps(into, op)
|
||||
|
||||
+9
-1
@@ -87,7 +87,12 @@ launched via the Docker
|
||||
[command-line interface](https://docs.docker.com/reference/commandline/cli/)
|
||||
or
|
||||
[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
|
||||
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
|
||||
|
||||
> 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).
|
||||
|
||||
### <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
|
||||
|
||||
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`
|
||||
|
||||
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
|
||||
Consensus: waiting(quorum: 2, known: 0)
|
||||
Status: awaiting consensus (quorum: 2, known: 0)
|
||||
Range: 10.32.0.0-10.47.255.255
|
||||
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.
|
||||
|
||||
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`
|
||||
+22
-2
@@ -18,13 +18,33 @@ Subsequently you can start containers with, e.g.
|
||||
|
||||
on any of the hosts, and they can all communicate with each other.
|
||||
|
||||
> WARNING: It is inadvisable to attach containers to the weave network
|
||||
> 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 bar.weave.local $(weave dns-args) -ti ubuntu
|
||||
# ping foo
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ $ weave status
|
||||
TrustedSubnets: none
|
||||
|
||||
Service: ipam
|
||||
Consensus: achieved
|
||||
Status: ready
|
||||
Range: 10.32.0.0-10.47.255.255
|
||||
DefaultSubnet: 10.32.0.0/12
|
||||
|
||||
@@ -124,6 +124,13 @@ Proxy](proxy.html#troubleshooting).
|
||||
|
||||
### <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
|
||||
obtained with `weave status connections`:
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ hosts.
|
||||
* [Adding and removing extra DNS entries](#add-remove)
|
||||
* [Resolve weaveDNS entries from host](#resolve-weavedns-entries-from-host)
|
||||
* [Hot-swapping service containers](#hot-swapping)
|
||||
* [Retaining DNS entries when containers stop](#retain-stopped)
|
||||
* [Configuring a custom TTL](#ttl)
|
||||
* [Configuring the domain search path](#domain-search-path)
|
||||
* [Using a different local domain](#local-domain)
|
||||
|
||||
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
|
||||
@@ -34,8 +34,8 @@ assert_raises "proxy docker_on $HOST1 ps"
|
||||
weave_on $HOST1 stop-proxy
|
||||
|
||||
# Booting it over tls errors
|
||||
assert_raises "DOCKER_CLIENT_ARGS='--tls' weave_on $HOST1 launch-proxy" 1
|
||||
assert_raises "DOCKER_CERT_PATH='./tls' DOCKER_TLS_VERIFY=1 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"
|
||||
|
||||
# Booting it with a specific -H overrides defaults
|
||||
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
|
||||
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?'"
|
||||
|
||||
end_suite
|
||||
+1
-1
@@ -11,7 +11,7 @@ set -e
|
||||
: ${SSH_KEY_FILE:=$HOME/.ssh/gce_ssh_key}
|
||||
: ${PROJECT:=positive-cocoa-90213}
|
||||
: ${IMAGE:=ubuntu-14-04}
|
||||
: ${TEMPLATE_NAME:=test-template-9}
|
||||
: ${TEMPLATE_NAME:=test-template-10}
|
||||
: ${ZONE:=us-central1-a}
|
||||
: ${NUM_HOSTS:=5}
|
||||
SUFFIX=""
|
||||
|
||||
@@ -536,7 +536,9 @@ create_bridge() {
|
||||
add_iptables_rule nat POSTROUTING -j WEAVE
|
||||
else
|
||||
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
|
||||
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
|
||||
|
||||
Reference in new issue
Block a user