Compare commits

...
52 Commits
Author SHA1 Message Date
Adam Harrison ab5f4410b6 Add release v1.2.1 2015-11-05 14:34:13 +00:00
Adam Harrison 3abb657777 Document port security 2015-11-05 12:23:17 +00:00
Adam Harrison 4dd63d8f72 Bind the HTTP listener to localhost when fastdp enabled
Prevent containers from accessing the weave router control port when
fast datapath is in use.
2015-11-05 12:23:17 +00:00
Bryan Boreham 79dc464b83 Merge branch 'latest_release_doc_updates' into 1.2 2015-11-05 12:04:54 +00:00
Bryan Boreham 3dbd5b11d8 Segregate discussion of range and subnet, and explain subnet a bit 2015-11-05 11:32:06 +00:00
Bryan Boreham 0ab5c65185 Merge pull request #1630 from weaveworks/issues/1588-improve-proxy-restart-reattach-test
Improve proxy restart reattach test reliability
2015-11-05 11:25:31 +00:00
Bryan Boreham e57ccdc858 Merge branch 'latest_release_doc_updates' into 1.2 2015-11-04 16:39:43 +00:00
Bryan Boreham a73a65b48a Removed obsolete text referring to mixed auto-manual allocation, and clarify Range printout 2015-11-04 16:36:44 +00:00
Adam Harrison 7c4af88911 Merge pull request #1606 from weaveworks/issues/1578_ufw_ubuntu
Add an iptables rule for letting weaveDNS requests in
2015-11-04 15:30:34 +00:00
Alvaro Saurin 0aca173e96 Add an iptables rule for letting weaveDNS requests in 2015-11-04 14:00:26 +01:00
Matthias Radestock e95e3cc29d Merge pull request #1624 from weaveworks/1593-more-peers
Better choice of peers for IPAM to transfer ownership to on `weave reset`

Fixes #1593.
2015-11-03 17:55:40 +00:00
Bryan Boreham 67e9310cc1 Review feedback 2015-11-03 17:01:27 +00:00
Adam Harrison 861bf953bf Merge pull request #1629 from weaveworks/1626-expose-names
Always add 'weave expose -h' argument to DNS
2015-11-03 16:32:13 +00:00
Adam Harrison 06eaac8690 Don't assert ethwe carrier via the proxy
The test script runs commands inside containers via docker exec to
ensure the ethwe carrier is up. We must not run these commands via the
proxy because it will interpose weavewait, which will block forever if
attachment has failed (e.g. due to #1556).
2015-11-03 15:42:37 +00:00
Adam Harrison 6b9e8816d1 Wait for proxy to become available after docker is restarted 2015-11-03 15:33:37 +00:00
Bryan Boreham 08e043fea7 Always add 'weave expose -h' argument to DNS, and add smoke-test for this also 2015-11-03 15:23:28 +00:00
Bryan Boreham 54ba1009d3 Merge pull request #1608 from weaveworks/1600-start-networkmode
LGTM.  Fixes #1600
2015-11-03 15:14:15 +00:00
Bryan Boreham 8742957f75 Tweak naming to be closer to code changes in nameserver 2015-11-03 14:15:49 +00:00
Bryan Boreham ace372cfc6 More extensive choice of transferee 2015-11-03 12:03:28 +00:00
Bryan Boreham 27c5f5f49f Fix title of test 2015-11-03 12:03:00 +00:00
Paul Bellamy ec5a1a3977 When container is started in host (or container) networkMode, we mount a noop weavewait, so it can continue
review feedback
2015-11-03 10:18:05 +00:00
Matthias Radestock 77c7963bde Merge pull request #1615 from weaveworks/1603-resort-in-encode
Hold DNS entries sorted case-insensitively until just before sending

Fixes #1603 and #1610.
2015-11-02 20:57:40 +00:00
Bryan Boreham b80c1343c3 Take steps to avoid the test timing out 2015-11-02 20:40:17 +00:00
Bryan Boreham e5c5fbcea3 Hold on to the lower-case version of a hostname, rather than re-computing it every time 2015-11-02 20:40:05 +00:00
Bryan Boreham fc7d04ce73 Condense Entries unit tests with helper function 2015-11-02 20:03:10 +00:00
Bryan Boreham 35f57b3ed2 Move decoding code next to encoding code 2015-11-02 20:01:40 +00:00
Bryan Boreham ed9ade05ea Improve merge asserts 2015-11-02 20:01:40 +00:00
Bryan Boreham f485b729bc Hold all entries sorted case-insensitively until just before sending, when we re-sort case-sensitively in Encode() 2015-11-02 20:01:40 +00:00
Bryan Boreham 64f7953423 Add unit test to check outbound mixed-case merging 2015-11-02 20:01:40 +00:00
Bryan Boreham fc1d837501 Extend unit test to cover mixed-case hostnames and daisy-chained gossip;
reduce mock gossip timer to 2 seconds to trigger more often during tests.
2015-11-02 20:01:40 +00:00
Matthias Radestock 9800c43bfa refactor(ish): don't use reference in method that doesn't modify 2015-11-02 19:57:17 +00:00
Bryan Boreham b3cda39b0b Let IPAM pick any peer we know about to transfer ownership to, when shutting down 2015-11-02 18:34:58 +00:00
Adam Harrison ccae8d42fd Merge remote-tracking branch 'dpw/fdp-probe-vxlan' into 1.2
Fixes #1599
2015-11-02 17:24:52 +00:00
David Wragg 38f78286c7 Probe whether the kernel has ODP vxlan support
It's possible to build that kernel with openvswitch, and vxlan, but
without the vport_vxlan module that glues them together.  And at
least one distro has actually done this.
2015-11-02 15:53:16 +00:00
Bryan Boreham 2bbe6a2ad8 Merge pull request #1622 from weaveworks/fix-miekg-dns-truncation-test
LGTM
2015-11-02 15:09:57 +00:00
Adam Harrison f64f63f675 Handle truncated responses from upstream servers 2015-11-02 15:00:02 +00:00
Adam Harrison f0fb44f6d4 Update unit test for miekg DNS API change 2015-11-02 13:24:04 +00:00
Paul Bellamy fa972615e6 Merge pull request #1616 from weaveworks/1549-inspect-wait
Make inspect-rewrite wait for start
2015-11-02 11:00:23 +00:00
Bryan Boreham f7cb2ef25d have waitForStartByIdent() return an error 2015-10-30 13:46:30 +00:00
Bryan Boreham 949f8bb2e7 Move updateContainerNetworkSettings() into proxy 2015-10-30 13:34:16 +00:00
Bryan Boreham 5eaff802d4 Make inspect-rewrite wait if the start operation is still in progress 2015-10-30 13:34:16 +00:00
Matthias Radestock a6336149f8 guard against chef not running
Provisioning on ubuntu/wily64 was tripping over this.
2015-10-30 01:29:21 +00:00
Matthias Radestock ca6bce3820 Merge branch 'latest_release_doc_updates' into 1.2 2015-10-28 09:20:46 +00:00
Matthias Radestock 9b4f2297b0 drop quotes in eval "$(weave env)"
They are unnecessary and unwieldy.

Fixes #1596
2015-10-28 09:19:10 +00:00
Matthias Radestock a31b2876d0 Merge pull request #1598 from weaveworks/issues/1584-improved-proxy-router-restart
Improved detection of router container restart

Fixes #1584
2015-10-28 08:51:06 +00:00
Matthias Radestock b697b6e57b Merge pull request #1597 from weaveworks/issues/1516-weavedns-ignore-foreign-domains
Check weaveDNS subdomain on REST PUT

Fixes #1516
2015-10-28 08:50:25 +00:00
Adam Harrison 4792fe6391 Improved detection of router container restart
Use the container name in addition to the entrypoint to avoid triggering
reattachment unnecessarily.
2015-10-27 14:41:26 +00:00
Adam Harrison 7408f72de2 Check weaveDNS subdomain on REST PUT 2015-10-27 14:37:57 +00:00
Ilya Dmitrichenko 3a029686e3 Add Pardot script 2015-10-22 15:07:52 -07:00
Matthias Radestock 9fa7b3956d Merge remote-tracking branch 'upstream/master' 2015-10-22 16:17:55 +01:00
Matthias Radestock b888ace508 remove superfluous code in ApplyUpdate
If the local peer's short ID was updated, we broadcastPeerUpdate at
the end (in unlockAndNotify), so there is no need to include the local
peer in the current update.

Also, reading peers.ourself.Version is bad here - we don't take a lock
and it's written by other goroutines. Doesn't actually break anything
though since it's a uint64 and hence atomic.
2015-10-22 16:12:37 +01:00
Bryan Boreham 2e54efe34d Stop the proxy last, so we can stop the router
before being unable to communicate with docker
when $DOCKER_HOST is pointing at the proxy
2015-10-22 15:45:54 +01:00
38 changed files with 474 additions and 219 deletions

No files matched your search

+2
View File
@@ -39,6 +39,7 @@ prog/weavehosts/weavehosts
prog/weaveproxy/weaveproxy prog/weaveproxy/weaveproxy
prog/sigproxy/sigproxy prog/sigproxy/sigproxy
prog/weavewait/weavewait prog/weavewait/weavewait
prog/weavewait/weavewait_noop
prog/netcheck/netcheck prog/netcheck/netcheck
prog/docker_tls_args/docker_tls_args prog/docker_tls_args/docker_tls_args
testing/cover/cover testing/cover/cover
@@ -52,6 +53,7 @@ prog/weaveexec/weave
prog/weaveexec/weavehosts prog/weaveexec/weavehosts
prog/weaveexec/weaveproxy prog/weaveexec/weaveproxy
prog/weaveexec/weavewait prog/weaveexec/weavewait
prog/weaveexec/weavewait_noop
prog/weaveexec/sigproxy prog/weaveexec/sigproxy
prog/weaveexec/netcheck prog/weaveexec/netcheck
prog/weaveexec/docker_tls_args prog/weaveexec/docker_tls_args
+9
View File
@@ -1,3 +1,12 @@
## Release 1.2.1
This release contains a number of bug fixes and minor
enhancements. More details in the
[change log](https://github.com/weaveworks/weave/issues?q=milestone%3A1.2.1).
The release is fully compatible with 1.2.0 versions, so existing
clusters can be upgraded incrementally.
## Release 1.2.0 ## Release 1.2.0
**Highlights** **Highlights**
+9 -3
View File
@@ -13,11 +13,12 @@ WEAVER_EXE=prog/weaver/weaver
WEAVEPROXY_EXE=prog/weaveproxy/weaveproxy WEAVEPROXY_EXE=prog/weaveproxy/weaveproxy
SIGPROXY_EXE=prog/sigproxy/sigproxy SIGPROXY_EXE=prog/sigproxy/sigproxy
WEAVEWAIT_EXE=prog/weavewait/weavewait WEAVEWAIT_EXE=prog/weavewait/weavewait
WEAVEWAIT_NOOP_EXE=prog/weavewait/weavewait_noop
NETCHECK_EXE=prog/netcheck/netcheck NETCHECK_EXE=prog/netcheck/netcheck
DOCKERTLSARGS_EXE=prog/docker_tls_args/docker_tls_args DOCKERTLSARGS_EXE=prog/docker_tls_args/docker_tls_args
RUNNER_EXE=testing/runner/runner RUNNER_EXE=testing/runner/runner
EXES=$(WEAVER_EXE) $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(NETCHECK_EXE) $(DOCKERTLSARGS_EXE) $(RUNNER_EXE) EXES=$(WEAVER_EXE) $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(NETCHECK_EXE) $(DOCKERTLSARGS_EXE) $(RUNNER_EXE)
WEAVER_UPTODATE=.weaver.uptodate WEAVER_UPTODATE=.weaver.uptodate
WEAVEEXEC_UPTODATE=.weaveexec.uptodate WEAVEEXEC_UPTODATE=.weaveexec.uptodate
@@ -76,7 +77,7 @@ $(NETCHECK_EXE): prog/netcheck/netcheck.go
# Sigproxy and weavewait need separate rules as they fail the netgo check in # Sigproxy and weavewait need separate rules as they fail the netgo check in
# the main build stanza due to not importing net package # the main build stanza due to not importing net package
$(SIGPROXY_EXE): prog/sigproxy/main.go $(SIGPROXY_EXE): prog/sigproxy/main.go
$(WEAVEWAIT_EXE): prog/weavewait/main.go net/*.go $(WEAVEWAIT_EXE): prog/weavewait/*.go net/*.go
$(RUNNER_EXE): testing/runner/runner.go $(RUNNER_EXE): testing/runner/runner.go
$(DOCKERTLSARGS_EXE): prog/docker_tls_args/*.go $(DOCKERTLSARGS_EXE): prog/docker_tls_args/*.go
@@ -84,15 +85,20 @@ $(WEAVEWAIT_EXE) $(SIGPROXY_EXE) $(RUNNER_EXE) $(DOCKERTLSARGS_EXE):
go get -tags netgo ./$(@D) go get -tags netgo ./$(@D)
go build $(BUILD_FLAGS) -o $@ ./$(@D) go build $(BUILD_FLAGS) -o $@ ./$(@D)
$(WEAVEWAIT_NOOP_EXE): prog/weavewait/*.go
go get -tags netgo ./$(@D)
go build $(BUILD_FLAGS) -tags noop -o $@ ./$(@D)
$(WEAVER_UPTODATE): prog/weaver/Dockerfile $(WEAVER_EXE) $(WEAVER_UPTODATE): prog/weaver/Dockerfile $(WEAVER_EXE)
$(SUDO) docker build -t $(WEAVER_IMAGE) prog/weaver $(SUDO) docker build -t $(WEAVER_IMAGE) prog/weaver
touch $@ touch $@
$(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile $(DOCKER_DISTRIB) weave $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(NETCHECK_EXE) $(DOCKERTLSARGS_EXE) $(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile $(DOCKER_DISTRIB) weave $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(NETCHECK_EXE) $(DOCKERTLSARGS_EXE)
cp weave prog/weaveexec/weave cp weave prog/weaveexec/weave
cp $(SIGPROXY_EXE) prog/weaveexec/sigproxy cp $(SIGPROXY_EXE) prog/weaveexec/sigproxy
cp $(WEAVEPROXY_EXE) prog/weaveexec/weaveproxy cp $(WEAVEPROXY_EXE) prog/weaveexec/weaveproxy
cp $(WEAVEWAIT_EXE) prog/weaveexec/weavewait cp $(WEAVEWAIT_EXE) prog/weaveexec/weavewait
cp $(WEAVEWAIT_NOOP_EXE) prog/weaveexec/weavewait_noop
cp $(NETCHECK_EXE) prog/weaveexec/netcheck cp $(NETCHECK_EXE) prog/weaveexec/netcheck
cp $(DOCKERTLSARGS_EXE) prog/weaveexec/docker_tls_args cp $(DOCKERTLSARGS_EXE) prog/weaveexec/docker_tls_args
cp $(DOCKER_DISTRIB) prog/weaveexec/docker.tgz cp $(DOCKER_DISTRIB) prog/weaveexec/docker.tgz
+40 -12
View File
@@ -55,19 +55,21 @@ type Allocator struct {
paxos *paxos.Node paxos *paxos.Node
paxosTicker *time.Ticker paxosTicker *time.Ticker
shuttingDown bool // to avoid doing any requests while trying to shut down shuttingDown bool // to avoid doing any requests while trying to shut down
isKnownPeer func(router.PeerName) bool
now func() time.Time now func() time.Time
} }
// NewAllocator creates and initialises a new Allocator // NewAllocator creates and initialises a new Allocator
func NewAllocator(ourName router.PeerName, ourUID router.PeerUID, ourNickname string, universe address.Range, quorum uint) *Allocator { func NewAllocator(ourName router.PeerName, ourUID router.PeerUID, ourNickname string, universe address.Range, quorum uint, isKnownPeer func(name router.PeerName) bool) *Allocator {
return &Allocator{ return &Allocator{
ourName: ourName, ourName: ourName,
universe: universe, universe: universe,
ring: ring.New(universe.Start, universe.End, ourName), ring: ring.New(universe.Start, universe.End, ourName),
owned: make(map[string][]address.Address), owned: make(map[string][]address.Address),
paxos: paxos.NewNode(ourName, ourUID, quorum), paxos: paxos.NewNode(ourName, ourUID, quorum),
nicknames: map[router.PeerName]string{ourName: ourNickname}, nicknames: map[router.PeerName]string{ourName: ourNickname},
now: time.Now, isKnownPeer: isKnownPeer,
now: time.Now,
} }
} }
@@ -274,6 +276,33 @@ func (alloc *Allocator) Free(ident string, addrToFree address.Address) error {
return <-errChan return <-errChan
} }
func (alloc *Allocator) pickPeerFromNicknames(isValid func(router.PeerName) bool) router.PeerName {
for name := range alloc.nicknames {
if name != alloc.ourName && isValid(name) {
return name
}
}
return router.UnknownPeerName
}
func (alloc *Allocator) pickPeerForTransfer() router.PeerName {
// first try alive peers that actively participate in IPAM (i.e. have entries)
if heir := alloc.ring.PickPeerForTransfer(alloc.isKnownPeer); heir != router.UnknownPeerName {
return heir
}
// next try alive peers that have IPAM enabled but have no entries
if heir := alloc.pickPeerFromNicknames(alloc.isKnownPeer); heir != router.UnknownPeerName {
return heir
}
// next try disappeared peers that still have entries
t := func(router.PeerName) bool { return true }
if heir := alloc.ring.PickPeerForTransfer(t); heir != router.UnknownPeerName {
return heir
}
// finally, disappeared peers that that passively participated in IPAM
return alloc.pickPeerFromNicknames(t)
}
// Shutdown (Sync) // Shutdown (Sync)
func (alloc *Allocator) Shutdown() { func (alloc *Allocator) Shutdown() {
alloc.infof("Shutdown") alloc.infof("Shutdown")
@@ -282,7 +311,7 @@ func (alloc *Allocator) Shutdown() {
alloc.shuttingDown = true alloc.shuttingDown = true
alloc.cancelOps(&alloc.pendingClaims) alloc.cancelOps(&alloc.pendingClaims)
alloc.cancelOps(&alloc.pendingAllocates) alloc.cancelOps(&alloc.pendingAllocates)
if heir := alloc.ring.PickPeerForTransfer(); heir != router.UnknownPeerName { if heir := alloc.pickPeerForTransfer(); heir != router.UnknownPeerName {
alloc.ring.Transfer(alloc.ourName, heir) alloc.ring.Transfer(alloc.ourName, heir)
alloc.space.Clear() alloc.space.Clear()
alloc.gossip.GossipBroadcast(alloc.Gossip()) alloc.gossip.GossipBroadcast(alloc.Gossip())
@@ -310,7 +339,6 @@ func (alloc *Allocator) AdminTakeoverRanges(peerNameOrNickname string) error {
return return
} }
delete(alloc.nicknames, peername)
newRanges, err := alloc.ring.Transfer(peername, alloc.ourName) newRanges, err := alloc.ring.Transfer(peername, alloc.ourName)
alloc.space.AddRanges(newRanges) alloc.space.AddRanges(newRanges)
resultChan <- err resultChan <- err
@@ -332,11 +360,11 @@ func (alloc *Allocator) lookupPeername(name string) (router.PeerName, error) {
return router.PeerNameFromString(name) return router.PeerNameFromString(name)
} }
// Restrict the peers in "nicknames" to those in the ring and our own // Restrict the peers in "nicknames" to those in the ring plus peers known to the router
func (alloc *Allocator) pruneNicknames() { func (alloc *Allocator) pruneNicknames() {
ringPeers := alloc.ring.PeerNames() ringPeers := alloc.ring.PeerNames()
for name := range alloc.nicknames { for name := range alloc.nicknames {
if _, ok := ringPeers[name]; !ok && name != alloc.ourName { if _, ok := ringPeers[name]; !ok && !alloc.isKnownPeer(name) {
delete(alloc.nicknames, name) delete(alloc.nicknames, name)
} }
} }
+2 -2
View File
@@ -470,9 +470,9 @@ func (r *Ring) ChoosePeersToAskForSpace(start, end address.Address) []router.Pee
return result return result
} }
func (r *Ring) PickPeerForTransfer() router.PeerName { func (r *Ring) PickPeerForTransfer(isValid func(router.PeerName) bool) router.PeerName {
for _, entry := range r.Entries { for _, entry := range r.Entries {
if entry.Peer != r.Peer { if entry.Peer != r.Peer && isValid(entry.Peer) {
return entry.Peer return entry.Peer
} }
} }
+1 -1
View File
@@ -135,7 +135,7 @@ func makeAllocator(name string, cidrStr string, quorum uint) (*Allocator, addres
} }
alloc := NewAllocator(peername, router.PeerUID(rand.Int63()), alloc := NewAllocator(peername, router.PeerUID(rand.Int63()),
"nick-"+name, cidr.Range(), quorum) "nick-"+name, cidr.Range(), quorum, func(router.PeerName) bool { return true })
return alloc, cidr.HostRange() return alloc, cidr.HostRange()
} }
+1 -1
View File
@@ -216,7 +216,7 @@ func (h *handler) handleRecursive(w dns.ResponseWriter, req *dns.Msg) {
reqCopy := req.Copy() reqCopy := req.Copy()
reqCopy.Id = dns.Id() reqCopy.Id = dns.Id()
response, _, err := h.client.Exchange(reqCopy, fmt.Sprintf("%s:%s", server, h.upstream.Port)) response, _, err := h.client.Exchange(reqCopy, fmt.Sprintf("%s:%s", server, h.upstream.Port))
if err != nil || response == nil { if (err != nil && err != dns.ErrTruncated) || response == nil {
h.ns.debugf("error trying %s: %v", server, err) h.ns.debugf("error trying %s: %v", server, err)
continue continue
} }
+5 -5
View File
@@ -42,17 +42,17 @@ func TestTruncation(t *testing.T) {
nameserver.AddEntry("foo.weave.local.", "", router.UnknownPeerName, i) nameserver.AddEntry("foo.weave.local.", "", router.UnknownPeerName, i)
} }
doRequest := func(client *dns.Client, request *dns.Msg, port int) *dns.Msg { doRequest := func(client *dns.Client, request *dns.Msg, port int, expectedErr error) *dns.Msg {
request.SetQuestion("foo.weave.local.", dns.TypeA) request.SetQuestion("foo.weave.local.", dns.TypeA)
response, _, err := client.Exchange(request, fmt.Sprintf("127.0.0.1:%d", port)) response, _, err := client.Exchange(request, fmt.Sprintf("127.0.0.1:%d", port))
require.Nil(t, err) require.Equal(t, expectedErr, err)
return response return response
} }
// do a udp query, ensure we get a truncated response // do a udp query, ensure we get a truncated response
{ {
udpClient := dns.Client{Net: "udp", UDPSize: minUDPSize} udpClient := dns.Client{Net: "udp", UDPSize: minUDPSize}
response := doRequest(&udpClient, &dns.Msg{}, udpPort) response := doRequest(&udpClient, &dns.Msg{}, udpPort, dns.ErrTruncated)
require.True(t, response.MsgHdr.Truncated) require.True(t, response.MsgHdr.Truncated)
require.True(t, len(response.Answer) < 100) require.True(t, len(response.Answer) < 100)
} }
@@ -62,7 +62,7 @@ func TestTruncation(t *testing.T) {
udpClient := dns.Client{Net: "udp", UDPSize: 65535} udpClient := dns.Client{Net: "udp", UDPSize: 65535}
request := &dns.Msg{} request := &dns.Msg{}
request.SetEdns0(65535, false) request.SetEdns0(65535, false)
response := doRequest(&udpClient, request, udpPort) response := doRequest(&udpClient, request, udpPort, nil)
require.False(t, response.MsgHdr.Truncated) require.False(t, response.MsgHdr.Truncated)
require.Equal(t, len(response.Answer), 100) require.Equal(t, len(response.Answer), 100)
} }
@@ -70,7 +70,7 @@ func TestTruncation(t *testing.T) {
// do a tcp query, ensure we don't get a truncated response // do a tcp query, ensure we don't get a truncated response
{ {
tcpClient := dns.Client{Net: "tcp"} tcpClient := dns.Client{Net: "tcp"}
response := doRequest(&tcpClient, &dns.Msg{}, tcpPort) response := doRequest(&tcpClient, &dns.Msg{}, tcpPort, nil)
require.False(t, response.MsgHdr.Truncated) require.False(t, response.MsgHdr.Truncated)
require.Equal(t, len(response.Answer), 100) require.Equal(t, len(response.Answer), 100)
} }
+36 -12
View File
@@ -18,7 +18,8 @@ type Entry struct {
ContainerID string ContainerID string
Origin router.PeerName Origin router.PeerName
Addr address.Address Addr address.Address
Hostname string Hostname string // as supplied
lHostname string // lowercased (not exported, so not encoded by gob)
Version int Version int
Tombstone int64 // timestamp of when it was deleted Tombstone int64 // timestamp of when it was deleted
} }
@@ -69,7 +70,7 @@ func (e1 *Entry) less(e2 *Entry) bool {
func (e1 *Entry) insensitiveLess(e2 *Entry) bool { func (e1 *Entry) insensitiveLess(e2 *Entry) bool {
// Entries are kept sorted by Hostname, Origin, ContainerID then address // Entries are kept sorted by Hostname, Origin, ContainerID then address
e1Hostname, e2Hostname := strings.ToLower(e1.Hostname), strings.ToLower(e2.Hostname) e1Hostname, e2Hostname := e1.lHostname, e2.lHostname
switch { switch {
case e1Hostname != e2Hostname: case e1Hostname != e2Hostname:
return e1Hostname < e2Hostname return e1Hostname < e2Hostname
@@ -100,6 +101,10 @@ func (e1 *Entry) String() string {
return fmt.Sprintf("%s -> %s", e1.Hostname, e1.Addr.String()) return fmt.Sprintf("%s -> %s", e1.Hostname, e1.Addr.String())
} }
func (e1 *Entry) addLowercase() {
e1.lHostname = strings.ToLower(e1.Hostname)
}
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!")
@@ -126,7 +131,8 @@ func (es *Entries) checkAndPanic() *Entries {
func (es *Entries) add(hostname, containerid string, origin router.PeerName, addr address.Address) Entry { func (es *Entries) add(hostname, containerid string, origin router.PeerName, addr address.Address) Entry {
defer es.checkAndPanic().checkAndPanic() defer es.checkAndPanic().checkAndPanic()
entry := Entry{Hostname: hostname, Origin: origin, ContainerID: containerid, Addr: addr} entry := Entry{Hostname: hostname, lHostname: strings.ToLower(hostname),
Origin: origin, ContainerID: containerid, Addr: addr}
i := sort.Search(len(*es), func(i int) bool { i := sort.Search(len(*es), func(i int) bool {
return !(*es)[i].insensitiveLess(&entry) return !(*es)[i].insensitiveLess(&entry)
}) })
@@ -145,6 +151,7 @@ func (es *Entries) add(hostname, containerid string, origin router.PeerName, add
func (es *Entries) merge(incoming Entries) Entries { func (es *Entries) merge(incoming Entries) Entries {
defer es.checkAndPanic().checkAndPanic() defer es.checkAndPanic().checkAndPanic()
incoming.checkAndPanic()
newEntries := Entries{} newEntries := Entries{}
i := 0 i := 0
@@ -203,23 +210,23 @@ func (es Entries) lookup(hostname string) Entries {
lowerHostname := strings.ToLower(hostname) lowerHostname := strings.ToLower(hostname)
i := sort.Search(len(es), func(i int) bool { i := sort.Search(len(es), func(i int) bool {
return strings.ToLower(es[i].Hostname) >= lowerHostname return es[i].lHostname >= lowerHostname
}) })
if i >= len(es) || strings.ToLower(es[i].Hostname) != lowerHostname { if i >= len(es) || es[i].lHostname != lowerHostname {
return Entries{} return Entries{}
} }
j := sort.Search(len(es)-i, func(j int) bool { j := sort.Search(len(es)-i, func(j int) bool {
return strings.ToLower(es[i+j].Hostname) > lowerHostname return es[i+j].lHostname > lowerHostname
}) })
return es[i : i+j] return es[i : i+j]
} }
func (es *Entries) first(f func(*Entry) bool) (*Entry, error) { func (es Entries) first(f func(*Entry) bool) (*Entry, error) {
es.checkAndPanic() es.checkAndPanic()
for _, e := range *es { for _, e := range es {
if f(&e) { if f(&e) {
return &e, nil return &e, nil
} }
@@ -227,14 +234,18 @@ func (es *Entries) first(f func(*Entry) bool) (*Entry, error) {
return nil, fmt.Errorf("Not found") return nil, fmt.Errorf("Not found")
} }
func (es Entries) addLowercase() {
for i := range es {
es[i].addLowercase()
}
}
type GossipData struct { type GossipData struct {
Timestamp int64 Timestamp int64
Entries Entries
} }
func (g *GossipData) Merge(o router.GossipData) { func (g *GossipData) Merge(o router.GossipData) {
checkAndPanic(CaseSensitive(g.Entries))
defer func() { checkAndPanic(CaseSensitive(g.Entries)) }()
other := o.(*GossipData) other := o.(*GossipData)
g.Entries.merge(other.Entries) g.Entries.merge(other.Entries)
if g.Timestamp < other.Timestamp { if g.Timestamp < other.Timestamp {
@@ -242,10 +253,23 @@ func (g *GossipData) Merge(o router.GossipData) {
} }
} }
func (g *GossipData) Decode(msg []byte) error {
if err := gob.NewDecoder(bytes.NewReader(msg)).Decode(g); err != nil {
return err
}
g.Entries.addLowercase() // lowercase strings not sent on the wire
sort.Sort(CaseInsensitive(g.Entries))
return nil
}
func (g *GossipData) Encode() [][]byte { func (g *GossipData) Encode() [][]byte {
checkAndPanic(CaseSensitive(g.Entries)) // Make a copy so we can sort: all outgoing data is sent in case-sensitive order
g2 := GossipData{Timestamp: g.Timestamp, Entries: make(Entries, len(g.Entries))}
copy(g2.Entries, g.Entries)
sort.Sort(CaseSensitive(g2.Entries))
buf := &bytes.Buffer{} buf := &bytes.Buffer{}
if err := gob.NewEncoder(buf).Encode(g); err != nil { if err := gob.NewEncoder(buf).Encode(g2); err != nil {
panic(err) panic(err)
} }
return [][]byte{buf.Bytes()} return [][]byte{buf.Bytes()}
+47 -56
View File
@@ -9,6 +9,19 @@ import (
"github.com/weaveworks/weave/router" "github.com/weaveworks/weave/router"
) )
func l(es Entries) Entries {
es.addLowercase()
return es
}
func makeEntries(values string) Entries {
entries := make(Entries, len(values))
for i, c := range values {
entries[i] = Entry{Hostname: string(c)}
}
return l(entries)
}
func TestAdd(t *testing.T) { func TestAdd(t *testing.T) {
oldNow := now oldNow := now
defer func() { now = oldNow }() defer func() { now = oldNow }()
@@ -16,68 +29,46 @@ func TestAdd(t *testing.T) {
entries := Entries{} entries := Entries{}
entries.add("A", "", router.UnknownPeerName, address.Address(0)) entries.add("A", "", router.UnknownPeerName, address.Address(0))
expected := Entries{ expected := l(Entries{
Entry{Hostname: "A", Origin: router.UnknownPeerName, Addr: address.Address(0)}, Entry{Hostname: "A", Origin: router.UnknownPeerName, Addr: address.Address(0)},
} })
require.Equal(t, entries, expected) require.Equal(t, entries, expected)
entries.tombstone(router.UnknownPeerName, func(e *Entry) bool { return e.Hostname == "A" }) entries.tombstone(router.UnknownPeerName, func(e *Entry) bool { return e.Hostname == "A" })
expected = Entries{ expected = l(Entries{
Entry{Hostname: "A", Origin: router.UnknownPeerName, Addr: address.Address(0), Version: 1, Tombstone: 1234}, Entry{Hostname: "A", Origin: router.UnknownPeerName, Addr: address.Address(0), Version: 1, Tombstone: 1234},
} })
require.Equal(t, entries, expected) require.Equal(t, entries, expected)
entries.add("A", "", router.UnknownPeerName, address.Address(0)) entries.add("A", "", router.UnknownPeerName, address.Address(0))
expected = Entries{ expected = l(Entries{
Entry{Hostname: "A", Origin: router.UnknownPeerName, Addr: address.Address(0), Version: 2}, Entry{Hostname: "A", Origin: router.UnknownPeerName, Addr: address.Address(0), Version: 2},
} })
require.Equal(t, entries, expected) require.Equal(t, entries, expected)
} }
func TestMerge(t *testing.T) { func TestMerge(t *testing.T) {
e1 := Entries{ e1 := makeEntries("ACDF")
Entry{Hostname: "A"}, e2 := makeEntries("BEF")
Entry{Hostname: "C"},
Entry{Hostname: "D"},
Entry{Hostname: "F"},
}
e2 := Entries{
Entry{Hostname: "B"},
Entry{Hostname: "E"},
Entry{Hostname: "F"},
}
diff := e1.merge(e2) diff := e1.merge(e2)
expectedDiff := Entries{
Entry{Hostname: "B"},
Entry{Hostname: "E"},
}
require.Equal(t, expectedDiff, diff)
expected := Entries{ require.Equal(t, makeEntries("BE"), diff)
Entry{Hostname: "A"}, require.Equal(t, makeEntries("ABCDEF"), e1)
Entry{Hostname: "B"},
Entry{Hostname: "C"},
Entry{Hostname: "D"},
Entry{Hostname: "E"},
Entry{Hostname: "F"},
}
require.Equal(t, expected, e1)
diff = e1.merge(e1) diff = e1.merge(e1)
require.Equal(t, Entries{}, diff) require.Equal(t, Entries{}, diff)
} }
func TestOldMerge(t *testing.T) { func TestOldMerge(t *testing.T) {
e1 := Entries{Entry{Hostname: "A", Version: 0}} e1 := l(Entries{Entry{Hostname: "A", Version: 0}})
diff := e1.merge(Entries{Entry{Hostname: "A", Version: 1}}) diff := e1.merge(l(Entries{Entry{Hostname: "A", Version: 1}}))
require.Equal(t, Entries{Entry{Hostname: "A", Version: 1}}, diff) require.Equal(t, l(Entries{Entry{Hostname: "A", Version: 1}}), diff)
require.Equal(t, Entries{Entry{Hostname: "A", Version: 1}}, e1) require.Equal(t, l(Entries{Entry{Hostname: "A", Version: 1}}), e1)
diff = e1.merge(Entries{Entry{Hostname: "A", Version: 0}}) diff = e1.merge(l(Entries{Entry{Hostname: "A", Version: 0}}))
require.Equal(t, Entries{}, diff) require.Equal(t, Entries{}, diff)
require.Equal(t, Entries{Entry{Hostname: "A", Version: 1}}, e1) require.Equal(t, l(Entries{Entry{Hostname: "A", Version: 1}}), e1)
} }
func TestTombstone(t *testing.T) { func TestTombstone(t *testing.T) {
@@ -85,48 +76,48 @@ func TestTombstone(t *testing.T) {
defer func() { now = oldNow }() defer func() { now = oldNow }()
now = func() int64 { return 1234 } now = func() int64 { return 1234 }
es := Entries{ es := makeEntries("AB")
Entry{Hostname: "A"},
Entry{Hostname: "B"},
}
es.tombstone(router.UnknownPeerName, func(e *Entry) bool { es.tombstone(router.UnknownPeerName, func(e *Entry) bool {
return e.Hostname == "B" return e.Hostname == "B"
}) })
expected := Entries{ expected := l(Entries{
Entry{Hostname: "A"}, Entry{Hostname: "A"},
Entry{Hostname: "B", Version: 1, Tombstone: 1234}, Entry{Hostname: "B", Version: 1, Tombstone: 1234},
} })
require.Equal(t, expected, es) require.Equal(t, expected, es)
} }
func TestDelete(t *testing.T) { func TestDelete(t *testing.T) {
es := Entries{ es := makeEntries("AB")
Entry{Hostname: "A"},
Entry{Hostname: "B"},
}
es.filter(func(e *Entry) bool { es.filter(func(e *Entry) bool {
return e.Hostname != "A" return e.Hostname != "A"
}) })
expected := Entries{ require.Equal(t, makeEntries("B"), es)
Entry{Hostname: "B"},
}
require.Equal(t, expected, es)
} }
func TestLookup(t *testing.T) { func TestLookup(t *testing.T) {
es := Entries{ es := l(Entries{
Entry{Hostname: "A"}, Entry{Hostname: "A"},
Entry{Hostname: "B", ContainerID: "bar"}, Entry{Hostname: "B", ContainerID: "bar"},
Entry{Hostname: "B", ContainerID: "foo"}, Entry{Hostname: "B", ContainerID: "foo"},
Entry{Hostname: "C"}, Entry{Hostname: "C"},
} })
have := es.lookup("B") have := es.lookup("B")
want := Entries{ want := l(Entries{
Entry{Hostname: "B", ContainerID: "bar"}, Entry{Hostname: "B", ContainerID: "bar"},
Entry{Hostname: "B", ContainerID: "foo"}, Entry{Hostname: "B", ContainerID: "foo"},
} })
require.Equal(t, have, want) require.Equal(t, have, want)
} }
func TestGossipDataMerge(t *testing.T) {
g1 := GossipData{Entries: makeEntries("AcDf")}
g2 := GossipData{Entries: makeEntries("BEf")}
g1.Merge(&g2)
require.Equal(t, GossipData{Entries: makeEntries("ABcDEf")}, g1)
}
+5
View File
@@ -35,6 +35,11 @@ func (n *Nameserver) HandleHTTP(router *mux.Router, dockerCli *docker.Client) {
return return
} }
if !dns.IsSubDomain(n.domain, hostname) {
n.infof("Ignoring registration %s %s %s (not a subdomain of %s)", hostname, ipStr, container, n.domain)
return
}
if err := n.AddEntry(hostname, container, n.ourName, ip); err != nil { if err := n.AddEntry(hostname, container, n.ourName, ip); err != nil {
n.badRequest(w, fmt.Errorf("Unable to add entry: %v", err)) n.badRequest(w, fmt.Errorf("Unable to add entry: %v", err))
return return
+1 -8
View File
@@ -1,10 +1,7 @@
package nameserver package nameserver
import ( import (
"bytes"
"encoding/gob"
"fmt" "fmt"
"sort"
"sync" "sync"
"time" "time"
@@ -196,7 +193,6 @@ func (n *Nameserver) Gossip() router.GossipData {
Timestamp: now(), Timestamp: now(),
} }
copy(gossip.Entries, n.entries) copy(gossip.Entries, n.entries)
sort.Sort(CaseSensitive(gossip.Entries))
return gossip return gossip
} }
@@ -206,16 +202,13 @@ func (n *Nameserver) OnGossipUnicast(sender router.PeerName, msg []byte) error {
func (n *Nameserver) receiveGossip(msg []byte) (router.GossipData, router.GossipData, error) { func (n *Nameserver) receiveGossip(msg []byte) (router.GossipData, router.GossipData, error) {
var gossip GossipData var gossip GossipData
if err := gob.NewDecoder(bytes.NewReader(msg)).Decode(&gossip); err != nil { if err := gossip.Decode(msg); err != nil {
return nil, nil, err return nil, nil, err
} }
if delta := gossip.Timestamp - now(); delta > gossipWindow || delta < -gossipWindow { if delta := gossip.Timestamp - now(); delta > gossipWindow || delta < -gossipWindow {
return nil, nil, fmt.Errorf("clock skew of %d detected", delta) return nil, nil, fmt.Errorf("clock skew of %d detected", delta)
} }
sort.Sort(CaseInsensitive(gossip.Entries))
n.Lock() n.Lock()
defer n.Unlock() defer n.Unlock()
+26 -7
View File
@@ -72,7 +72,7 @@ func (m mapping) Addrs() []address.Address {
} }
func TestNameservers(t *testing.T) { func TestNameservers(t *testing.T) {
wt.RunWithTimeout(t, time.Minute, func() { wt.RunWithTimeout(t, 2*time.Minute, func() {
testNameservers(t) testNameservers(t)
}) })
} }
@@ -81,8 +81,12 @@ func testNameservers(t *testing.T) {
//common.SetLogLevel("debug") //common.SetLogLevel("debug")
lookupTimeout := 10 // ms lookupTimeout := 10 // ms
nameservers, grouter := makeNetwork(50) nameservers, grouter := makeNetwork(30)
defer stopNetwork(nameservers, grouter) defer stopNetwork(nameservers, grouter)
// This subset will sometimes lose touch with some of the others
badNameservers := nameservers[25:]
// This subset will remain well-connected, and we will deal mainly with them
nameservers = nameservers[:25]
nameserversByName := map[router.PeerName]*Nameserver{} nameserversByName := map[router.PeerName]*Nameserver{}
for _, n := range nameservers { for _, n := range nameservers {
nameserversByName[n.ourName] = n nameserversByName[n.ourName] = n
@@ -106,7 +110,13 @@ func testNameservers(t *testing.T) {
addMapping := func() { addMapping := func() {
nameserver := nameservers[rand.Intn(len(nameservers))] nameserver := nameservers[rand.Intn(len(nameservers))]
addr := address.Address(rand.Int31()) addr := address.Address(rand.Int31())
hostname := fmt.Sprintf("hostname%d", rand.Int63()) // Create a hostname which has some upper and lowercase letters,
// and a unique number so we don't have to check if we allocated it already
randomBits := rand.Int63()
firstLetter := 'H' + (randomBits&1)*32
secondLetter := 'O' + (randomBits&2)*16
randomBits = randomBits >> 2
hostname := fmt.Sprintf("%c%cstname%d", firstLetter, secondLetter, randomBits)
mapping := mapping{hostname, []pair{{nameserver.ourName, addr}}} mapping := mapping{hostname, []pair{{nameserver.ourName, addr}}}
mappings = append(mappings, mapping) mappings = append(mappings, mapping)
@@ -129,6 +139,12 @@ func testNameservers(t *testing.T) {
check(nameserver, mapping) check(nameserver, mapping)
} }
loseConnection := func() {
nameserver1 := badNameservers[rand.Intn(len(badNameservers))]
nameserver2 := nameservers[rand.Intn(len(nameservers))]
nameserver1.PeerGone(&router.Peer{Name: nameserver2.ourName})
}
deleteMapping := func() { deleteMapping := func() {
if len(mappings) <= 0 { if len(mappings) <= 0 {
return return
@@ -179,7 +195,7 @@ func testNameservers(t *testing.T) {
require.Equal(t, mapping.hostname, hostname) require.Equal(t, mapping.hostname, hostname)
} }
for i := 0; i < 1000; i++ { for i := 0; i < 800; i++ {
r := rand.Float32() r := rand.Float32()
switch { switch {
case r < 0.1: case r < 0.1:
@@ -191,7 +207,10 @@ func testNameservers(t *testing.T) {
case 0.2 <= r && r < 0.3: case 0.2 <= r && r < 0.3:
deleteMapping() deleteMapping()
case 0.3 <= r && r < 0.9: case 0.3 <= r && r < 0.35:
loseConnection()
case 0.35 <= r && r < 0.9:
doLookup() doLookup()
case 0.9 <= r: case 0.9 <= r:
@@ -241,14 +260,14 @@ func TestTombstoneDeletion(t *testing.T) {
err = nameserver.Delete("hostname", "containerid", "", address.Address(0)) err = nameserver.Delete("hostname", "containerid", "", address.Address(0))
require.Nil(t, err) require.Nil(t, err)
require.Equal(t, []address.Address{}, nameserver.Lookup("hostname")) require.Equal(t, []address.Address{}, nameserver.Lookup("hostname"))
require.Equal(t, Entries{{ require.Equal(t, l(Entries{Entry{
ContainerID: "containerid", ContainerID: "containerid",
Origin: peername, Origin: peername,
Addr: address.Address(0), Addr: address.Address(0),
Hostname: "hostname", Hostname: "hostname",
Version: 1, Version: 1,
Tombstone: 1234, Tombstone: 1234,
}}, nameserver.entries) }}), nameserver.entries)
now = func() int64 { return 1234 + int64(tombstoneTimeout/time.Second) + 1 } now = func() int64 { return 1234 + int64(tombstoneTimeout/time.Second) + 1 }
nameserver.deleteTombstones() nameserver.deleteTombstones()
+2
View File
@@ -5,6 +5,7 @@ LABEL works.weave.role=system
WORKDIR /home/weave WORKDIR /home/weave
VOLUME /w VOLUME /w
VOLUME /w-noop
ENTRYPOINT ["/home/weave/sigproxy", "/home/weave/weave"] ENTRYPOINT ["/home/weave/sigproxy", "/home/weave/weave"]
RUN apk add --update \ RUN apk add --update \
@@ -20,4 +21,5 @@ RUN apk add --update \
ADD ./weave ./sigproxy ./weaveproxy /home/weave/ ADD ./weave ./sigproxy ./weaveproxy /home/weave/
ADD ./netcheck ./docker_tls_args /usr/bin/ ADD ./netcheck ./docker_tls_args /usr/bin/
ADD ./weavewait /w/w ADD ./weavewait /w/w
ADD ./weavewait_noop /w-noop/w
ADD ./docker.tgz / ADD ./docker.tgz /
+8 -4
View File
@@ -13,7 +13,6 @@ import (
"github.com/davecheney/profile" "github.com/davecheney/profile"
"github.com/docker/docker/pkg/mflag" "github.com/docker/docker/pkg/mflag"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/weaveworks/go-odp/odp"
. "github.com/weaveworks/weave/common" . "github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/common/docker" "github.com/weaveworks/weave/common/docker"
@@ -119,8 +118,12 @@ func main() {
os.Exit(0) os.Exit(0)
case createDatapath: case createDatapath:
err := weave.CreateDatapath(datapathName) err, odp_supported := weave.CreateDatapath(datapathName)
if odp.IsKernelLacksODPError(err) { if !odp_supported {
if err != nil {
Log.Error(err)
}
// When the kernel lacks ODP support, exit // When the kernel lacks ODP support, exit
// with a special status to distinguish it for // with a special status to distinguish it for
// the weave script. // the weave script.
@@ -368,7 +371,8 @@ func createAllocator(router *weave.Router, ipRangeStr string, defaultSubnetStr s
Log.Fatalf("IP address allocation default subnet %s does not overlap with allocation range %s", defaultSubnet, ipRange) Log.Fatalf("IP address allocation default subnet %s does not overlap with allocation range %s", defaultSubnet, ipRange)
} }
} }
allocator := ipam.NewAllocator(router.Ourself.Peer.Name, router.Ourself.Peer.UID, router.Ourself.Peer.NickName, ipRange.Range(), quorum) isKnownPeer := func(name weave.PeerName) bool { return router.Peers.Fetch(name) != nil }
allocator := ipam.NewAllocator(router.Ourself.Peer.Name, router.Ourself.Peer.UID, router.Ourself.Peer.NickName, ipRange.Range(), quorum, isKnownPeer)
allocator.SetInterfaces(router.NewGossip("IPallocation", allocator)) allocator.SetInterfaces(router.NewGossip("IPallocation", allocator))
allocator.Start() allocator.Start()
+12
View File
@@ -0,0 +1,12 @@
// +build !noop
package main
import (
weavenet "github.com/weaveworks/weave/net"
)
func checkNetwork() error {
_, err := weavenet.EnsureInterfaceAndMcastRoute("ethwe")
return err
}
+1 -4
View File
@@ -6,8 +6,6 @@ import (
"os" "os"
"os/exec" "os/exec"
"syscall" "syscall"
weavenet "github.com/weaveworks/weave/net"
) )
var ( var (
@@ -19,8 +17,7 @@ func main() {
args = os.Args[1:] args = os.Args[1:]
) )
_, err := weavenet.EnsureInterfaceAndMcastRoute("ethwe") checkErr(checkNetwork())
checkErr(err)
if len(args) == 0 { if len(args) == 0 {
checkErr(ErrNoCommandSpecified) checkErr(ErrNoCommandSpecified)
+7
View File
@@ -0,0 +1,7 @@
// +build noop
package main
func checkNetwork() error {
return nil
}
+23
View File
@@ -21,6 +21,7 @@ var (
containerIDRegexp = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/([^/]*)/.*") containerIDRegexp = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/([^/]*)/.*")
weaveWaitEntrypoint = []string{"/w/w"} weaveWaitEntrypoint = []string{"/w/w"}
weaveEntrypoint = "/home/weave/weaver" weaveEntrypoint = "/home/weave/weaver"
weaveContainerName = "/weave"
) )
func callWeave(args ...string) ([]byte, []byte, error) { func callWeave(args ...string) ([]byte, []byte, error) {
@@ -154,3 +155,25 @@ func weaveContainerIPs(containerID string) (mac string, ips []net.IP, nets []*ne
} }
return return
} }
func addVolume(hostConfig jsonObject, source, target, mode string) error {
configBinds, err := hostConfig.StringArray("Binds")
if err != nil {
return err
}
var binds []string
for _, bind := range configBinds {
s := strings.Split(bind, ":")
if len(s) >= 2 && s[1] == target {
continue
}
binds = append(binds, bind)
}
bind := source + ":" + target
if mode != "" {
bind += ":" + mode
}
hostConfig["Binds"] = append(binds, bind)
return nil
}
+1 -1
View File
@@ -53,7 +53,7 @@ func (i *createContainerInterceptor) InterceptRequest(r *http.Request) error {
Log.Infof("Leaving container alone because %s", err) Log.Infof("Leaving container alone because %s", err)
} else { } else {
Log.Infof("Creating container with WEAVE_CIDR \"%s\"", strings.Join(cidrs, " ")) Log.Infof("Creating container with WEAVE_CIDR \"%s\"", strings.Join(cidrs, " "))
if err := i.proxy.addWeaveWaitVolume(hostConfig); err != nil { if err := addVolume(hostConfig, i.proxy.weaveWaitVolume, "/w", "ro"); err != nil {
return err return err
} }
if err := i.setWeaveWaitEntrypoint(container); err != nil { if err := i.setWeaveWaitEntrypoint(container); err != nil {
+1 -22
View File
@@ -22,30 +22,9 @@ func (i *inspectContainerInterceptor) InterceptResponse(r *http.Response) error
return err return err
} }
if err := updateContainerNetworkSettings(container); err != nil { if err := i.proxy.updateContainerNetworkSettings(container); err != nil {
Log.Warningf("Inspecting container %s failed: %s", container["Id"], err) Log.Warningf("Inspecting container %s failed: %s", container["Id"], err)
} }
return marshalResponseBody(r, container) return marshalResponseBody(r, container)
} }
func updateContainerNetworkSettings(container jsonObject) error {
containerID, err := container.String("Id")
if err != nil {
return err
}
mac, ips, nets, err := weaveContainerIPs(containerID)
if err != nil || len(ips) == 0 {
return err
}
networkSettings, err := container.Object("NetworkSettings")
if err != nil {
return err
}
networkSettings["MacAddress"] = mac
networkSettings["IPAddress"] = ips[0].String()
networkSettings["IPPrefixLen"], _ = nets[0].Mask.Size()
return nil
}
+1 -1
View File
@@ -27,7 +27,7 @@ func (i *inspectExecInterceptor) InterceptResponse(r *http.Response) error {
return err return err
} }
if err := updateContainerNetworkSettings(container); err != nil { if err := i.proxy.updateContainerNetworkSettings(container); err != nil {
Log.Warningf("Inspecting exec %s failed: %s", exec["Id"], err) Log.Warningf("Inspecting exec %s failed: %s", exec["Id"], err)
} }
+62 -28
View File
@@ -70,6 +70,7 @@ type Proxy struct {
dockerBridgeIP string dockerBridgeIP string
hostnameMatchRegexp *regexp.Regexp hostnameMatchRegexp *regexp.Regexp
weaveWaitVolume string weaveWaitVolume string
weaveWaitNoopVolume string
normalisedAddrs []string normalisedAddrs []string
waiters map[*http.Request]*wait waiters map[*http.Request]*wait
} }
@@ -106,7 +107,7 @@ func NewProxy(c Config) (*Proxy, error) {
return nil, err return nil, err
} }
if err = p.findWeaveWaitVolume(); err != nil { if err = p.findWeaveWaitVolumes(); err != nil {
return nil, err return nil, err
} }
@@ -135,23 +136,31 @@ func (proxy *Proxy) Dial() (net.Conn, error) {
return net.Dial("unix", dockerSock) return net.Dial("unix", dockerSock)
} }
func (proxy *Proxy) findWeaveWaitVolume() error { func (proxy *Proxy) findWeaveWaitVolumes() error {
var err error
if proxy.weaveWaitVolume, err = proxy.findVolume("/w"); err != nil {
return err
}
proxy.weaveWaitNoopVolume, err = proxy.findVolume("/w-noop")
return err
}
func (proxy *Proxy) findVolume(v string) (string, error) {
container, err := proxy.client.InspectContainer("weaveproxy") container, err := proxy.client.InspectContainer("weaveproxy")
if err != nil { if err != nil {
return fmt.Errorf("Could not find the weavewait volume: %s", err) return "", fmt.Errorf("Could not find the weavewait volume: %s", err)
} }
if container.Volumes == nil { if container.Volumes == nil {
return fmt.Errorf("Could not find the weavewait volume") return "", fmt.Errorf("Could not find the weavewait volume")
} }
volume, ok := container.Volumes["/w"] volume, ok := container.Volumes[v]
if !ok { if !ok {
return fmt.Errorf("Could not find the weavewait volume") return "", fmt.Errorf("Could not find the weavewait volume")
} }
proxy.weaveWaitVolume = volume return volume, nil
return nil
} }
func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
@@ -315,7 +324,8 @@ func containerShouldAttach(container *docker.Container) bool {
} }
func containerIsWeaveRouter(container *docker.Container) bool { func containerIsWeaveRouter(container *docker.Container) bool {
return len(container.Config.Entrypoint) > 0 && container.Config.Entrypoint[0] == weaveEntrypoint return container.Name == weaveContainerName &&
len(container.Config.Entrypoint) > 0 && container.Config.Entrypoint[0] == weaveEntrypoint
} }
func (proxy *Proxy) createWait(r *http.Request, ident string) { func (proxy *Proxy) createWait(r *http.Request, ident string) {
@@ -357,6 +367,24 @@ func (proxy *Proxy) waitForStart(r *http.Request) error {
return nil return nil
} }
// If some other operation is waiting for a container to start, join in the wait
func (proxy *Proxy) waitForStartByIdent(ident string) error {
var ch chan error
proxy.Lock()
for _, wait := range proxy.waiters {
if ident == wait.ident && !wait.done {
ch = wait.ch
break
}
}
proxy.Unlock()
if ch != nil {
Log.Debugf("Wait for start of container %s", ident)
return <-ch
}
return nil
}
func (proxy *Proxy) ContainerDied(ident string) { func (proxy *Proxy) ContainerDied(ident string) {
} }
@@ -406,7 +434,7 @@ func (proxy *Proxy) attachRouter(container *docker.Container) error {
func (proxy *Proxy) weaveCIDRs(networkMode string, env []string) ([]string, error) { func (proxy *Proxy) weaveCIDRs(networkMode string, env []string) ([]string, error) {
if networkMode == "host" || strings.HasPrefix(networkMode, "container:") { if networkMode == "host" || strings.HasPrefix(networkMode, "container:") {
return nil, fmt.Errorf("the container was created with the '--net=%s'", networkMode) return nil, fmt.Errorf("the container has '--net=%s'", networkMode)
} }
for _, e := range env { for _, e := range env {
if strings.HasPrefix(e, "WEAVE_CIDR=") { if strings.HasPrefix(e, "WEAVE_CIDR=") {
@@ -422,24 +450,6 @@ func (proxy *Proxy) weaveCIDRs(networkMode string, env []string) ([]string, erro
return nil, nil return nil, nil
} }
func (proxy *Proxy) addWeaveWaitVolume(hostConfig jsonObject) error {
configBinds, err := hostConfig.StringArray("Binds")
if err != nil {
return err
}
var binds []string
for _, bind := range configBinds {
s := strings.Split(bind, ":")
if len(s) >= 2 && s[1] == "/w" {
continue
}
binds = append(binds, bind)
}
hostConfig["Binds"] = append(binds, fmt.Sprintf("%s:/w:ro", proxy.weaveWaitVolume))
return nil
}
func (proxy *Proxy) setWeaveDNS(hostConfig jsonObject, hostname, dnsDomain string) error { func (proxy *Proxy) setWeaveDNS(hostConfig jsonObject, hostname, dnsDomain string) error {
dns, err := hostConfig.StringArray("Dns") dns, err := hostConfig.StringArray("Dns")
if err != nil { if err != nil {
@@ -494,3 +504,27 @@ func (proxy *Proxy) getDNSDomain() (domain string) {
return string(b) return string(b)
} }
func (proxy *Proxy) updateContainerNetworkSettings(container jsonObject) error {
containerID, err := container.String("Id")
if err != nil {
return err
}
if err := proxy.waitForStartByIdent(containerID); err != nil {
return err
}
mac, ips, nets, err := weaveContainerIPs(containerID)
if err != nil || len(ips) == 0 {
return err
}
networkSettings, err := container.Object("NetworkSettings")
if err != nil {
return err
}
networkSettings["MacAddress"] = mac
networkSettings["IPAddress"] = ips[0].String()
networkSettings["IPPrefixLen"], _ = nets[0].Mask.Size()
return nil
}
+16 -3
View File
@@ -2,6 +2,7 @@ package proxy
import ( import (
"net/http" "net/http"
"strings"
) )
type startContainerInterceptor struct{ proxy *Proxy } type startContainerInterceptor struct{ proxy *Proxy }
@@ -31,11 +32,23 @@ func (i *startContainerInterceptor) InterceptRequest(r *http.Request) error {
hostConfig = params hostConfig = params
} }
if hostConfig != nil { if hostConfig != nil {
i.proxy.addWeaveWaitVolume(hostConfig) networkMode, err := jsonObject(hostConfig).String("NetworkMode")
if dnsDomain := i.proxy.getDNSDomain(); dnsDomain != "" { if err != nil {
if err := i.proxy.setWeaveDNS(hostConfig, container.Config.Hostname, dnsDomain); err != nil { return err
}
if strings.HasPrefix(networkMode, "container:") || networkMode == "host" {
if err := addVolume(hostConfig, i.proxy.weaveWaitNoopVolume, "/w", "ro"); err != nil {
return err return err
} }
} else {
if err := addVolume(hostConfig, i.proxy.weaveWaitVolume, "/w", "ro"); err != nil {
return err
}
if dnsDomain := i.proxy.getDNSDomain(); dnsDomain != "" {
if err := i.proxy.setWeaveDNS(hostConfig, container.Config.Hostname, dnsDomain); err != nil {
return err
}
}
} }
// Note we marshal the original top-level dictionary to avoid disturbing anything else // Note we marshal the original top-level dictionary to avoid disturbing anything else
+38 -5
View File
@@ -1,25 +1,58 @@
package router package router
import ( import (
"fmt"
"net"
"syscall"
"github.com/weaveworks/go-odp/odp" "github.com/weaveworks/go-odp/odp"
) )
// ODP admin functionality // ODP admin functionality
func CreateDatapath(dpname string) error { func CreateDatapath(dpname string) (err error, supported bool) {
dpif, err := odp.NewDpif() dpif, err := odp.NewDpif()
if err != nil { if err != nil {
return err if odp.IsKernelLacksODPError(err) {
return nil, false
}
return err, true
} }
defer dpif.Close() defer dpif.Close()
_, err = dpif.CreateDatapath(dpname) dp, err := dpif.CreateDatapath(dpname)
if err != nil && !odp.IsDatapathNameAlreadyExistsError(err) { if err != nil && !odp.IsDatapathNameAlreadyExistsError(err) {
return err return err, true
} }
return nil // Pick an ephemeral port number to use in probing for vxlan
// support.
udpconn, err := net.ListenUDP("udp4", nil)
if err != nil {
return err, true
}
// we leave the UDP socket open, so creating a vxlan vport on
// the same port number should fail. But that's fine: It's
// still sufficient to probe for support.
portno := uint16(udpconn.LocalAddr().(*net.UDPAddr).Port)
vpid, err := dp.CreateVport(odp.NewVxlanVportSpec(
fmt.Sprintf("vxlan-%d", portno), portno))
if nlerr, ok := err.(odp.NetlinkError); ok {
if syscall.Errno(nlerr) == syscall.EAFNOSUPPORT {
dp.Delete()
return fmt.Errorf("kernel does not have Open vSwitch VXLAN support"), false
}
}
if err == nil {
dp.DeleteVport(vpid)
}
udpconn.Close()
return nil, true
} }
func DeleteDatapath(dpname string) error { func DeleteDatapath(dpname string) error {
-9
View File
@@ -327,8 +327,6 @@ func (peers *Peers) ApplyUpdate(update []byte) (PeerNameSet, PeerNameSet, error)
return nil, nil, err return nil, nil, err
} }
ourVersion := peers.ourself.Version
// By this point, we know the update doesn't refer to any peers we // By this point, we know the update doesn't refer to any peers we
// have no knowledge of. We can now apply the update. Start by // have no knowledge of. We can now apply the update. Start by
// adding in any new peers. // adding in any new peers.
@@ -349,13 +347,6 @@ func (peers *Peers) ApplyUpdate(update []byte) (PeerNameSet, PeerNameSet, error)
updateNames[peer.Name] = void updateNames[peer.Name] = void
} }
if peers.ourself.Version != ourVersion {
// Our short id changed, i.e. due to a short ID
// change. So we need to include ourself in the
// update
newUpdate[peers.ourself.Name] = void
}
return updateNames, newUpdate, nil return updateNames, newUpdate, nil
} }
+14
View File
@@ -69,3 +69,17 @@
s.parentNode.insertBefore(wf, s); s.parentNode.insertBefore(wf, s);
})(); })();
</script> </script>
<script type="text/javascript">
piAId = '124932';
piCId = '85570';
(function() {
function async_load(){
var s = document.createElement('script'); s.type = 'text/javascript';
s.src = ('https:' == document.location.protocol ? 'https://pi' : 'http://cdn') + '.pardot.com/pd.js';
var c = document.getElementsByTagName('script')[0]; c.parentNode.insertBefore(s, c);
}
if(window.attachEvent) { window.attachEvent('onload', async_load); }
else { window.addEventListener('load', async_load, false); }
})();
</script>
+9 -1
View File
@@ -219,7 +219,7 @@ NB: By default docker permits communication between containers on the
same host, via their docker-assigned IP addresses. For complete same host, via their docker-assigned IP addresses. For complete
isolation between application containers, that feature needs to be isolation between application containers, that feature needs to be
disabled by disabled by
[setting `--icc=false`](https://docs.docker.com/articles/networking/#between-containers) [setting `--icc=false`](https://docs.docker.com/engine/userguide/networking/default_network/container-communication/#communication-between-containers)
in the docker daemon configuration. Furthermore, containers should be in the docker daemon configuration. Furthermore, containers should be
prevented from capturing and injecting raw network packets - this can prevented from capturing and injecting raw network packets - this can
be accomplished by starting them with the `--cap-drop net_raw` option. be accomplished by starting them with the `--cap-drop net_raw` option.
@@ -307,6 +307,14 @@ supplying a password will [cause weave to fall back to a slower
method](#fast-data-path) for transporting data between method](#fast-data-path) for transporting data between
peers. peers.
Be aware that:
* Containers will be able to access the router REST API if you have
disabled fast datapath. You can prevent this by setting
[`--icc=false`](https://docs.docker.com/engine/userguide/networking/default_network/container-communication/#communication-between-containers)
* Containers are able to access the router control and data plane
ports, but you can mitigate this by enabling encryption
### <a name="host-network-integration"></a>Host network integration ### <a name="host-network-integration"></a>Host network integration
Weave application networks can be integrated with a host's network, Weave application networks can be integrated with a host's network,
+18 -16
View File
@@ -105,21 +105,11 @@ range. This can be overridden with the `--ipalloc-range` option, e.g.
and must be the same on every host. and must be the same on every host.
> The specified range is for *exclusive* use by the IP allocator. In
> particular, when starting containers with manually assigned IP
> addresses, these must be outside the IP allocator's range. If, in
> our example, you subsequently executed `docker run -e
> WEAVE_CIDR=10.2.3.1/24 -ti ubuntu`, the IP allocator might assign
> the same address to another container, which will break IP routing
> for the containers sharing an address.
The range parameter is written in The range parameter is written in
[CIDR notation](http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) - [CIDR notation](http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing) -
in this example "/16" means the first 16 bits of the address form the in this example "/16" means the first 16 bits of the address form the
network address and the allocator is to allocate container addresses network address and the allocator is to allocate container addresses
that all start 10.2. The ".0" and ".-1" addresses in a subnet are not that all start 10.2.
used, as required by
[RFC 1122](https://tools.ietf.org/html/rfc1122#page-29).
Weave shares the IP address range across all peers, dynamically Weave shares the IP address range across all peers, dynamically
according to their needs. If a group of peers becomes isolated from according to their needs. If a group of peers becomes isolated from
@@ -129,11 +119,16 @@ to the rest of the network without any conflicts arising.
## <a name="subnets"></a>Automatic allocation across multiple subnets ## <a name="subnets"></a>Automatic allocation across multiple subnets
When IP subnets are used to define or restrict routing. By default, weave
[running containers on different subnets](features.html#application-isolation), puts all containers in a subnet that spans the entire allocation
you may wish to request the allocation of an address from a particular range, so every weave-attached container can talk to every other
subnet. This is done by specifying the subnet with `net:<subnet>`, in weave-attached container.
CIDR notation, e.g.
If you want some [isolation](features.html#application-isolation), you
can choose to run containers on different subnets. To request the
allocation of an address from a particular subnet, set the
`WEAVE_CIDR` environment variable to `net:<subnet>` when creating the
container, e.g.
host1$ docker run -e WEAVE_CIDR=net:10.2.7.0/24 -ti ubuntu host1$ docker run -e WEAVE_CIDR=net:10.2.7.0/24 -ti ubuntu
@@ -143,6 +138,9 @@ for instance:
host1$ docker run -e WEAVE_CIDR="net:10.2.7.0/24 net:10.2.8.0/24 ip:10.3.9.1/24" -ti ubuntu host1$ docker run -e WEAVE_CIDR="net:10.2.7.0/24 net:10.2.8.0/24 ip:10.3.9.1/24" -ti ubuntu
(Note the ".0" and ".-1" addresses in a subnet are not used, as required by
[RFC 1122](https://tools.ietf.org/html/rfc1122#page-29)).
When working with multiple subnets in this way, it is usually When working with multiple subnets in this way, it is usually
desirable to constrain the default subnet - i.e. the one chosen by the desirable to constrain the default subnet - i.e. the one chosen by the
allocator when no subnet is supplied - so that it does not overlap allocator when no subnet is supplied - so that it does not overlap
@@ -227,3 +225,7 @@ 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.
Note that the 'Range' is written using interval notation - '[' means
the start of the range is included and ')' means the end of the range
is not included.
+4 -4
View File
@@ -57,13 +57,13 @@ All docker commands can be run via the proxy, so it is safe to adjust
your `DOCKER_HOST` to point at the proxy. Weave provides a convenient your `DOCKER_HOST` to point at the proxy. Weave provides a convenient
command for this: command for this:
host1$ eval "$(weave env)" host1$ eval $(weave env)
host1$ docker ps host1$ docker ps
... ...
The prior settings can be restored with The prior settings can be restored with
host1$ eval "$(weave env --restore)" host1$ eval $(weave env --restore)
Alternatively, the proxy host can be set on a per-command basis with Alternatively, the proxy host can be set on a per-command basis with
@@ -194,7 +194,7 @@ ultimately be handed over to weaveDNS for registration.
For instance, we can launch the proxy using all three flags For instance, we can launch the proxy using all three flags
host1$ weave launch-router && weave launch-proxy --hostname-from-label hostname-label --hostname-match '^aws-[0-9]+-(.*)$' --hostname-replacement 'my-app-$1' host1$ weave launch-router && weave launch-proxy --hostname-from-label hostname-label --hostname-match '^aws-[0-9]+-(.*)$' --hostname-replacement 'my-app-$1'
host1$ eval "$(weave env)" host1$ eval $(weave env)
Note how regexp substitution groups should be prepended with a dollar sign Note how regexp substitution groups should be prepended with a dollar sign
(e.g. `$1`). For further details on the regular expression syntax please see (e.g. `$1`). For further details on the regular expression syntax please see
@@ -264,7 +264,7 @@ with
$ mkdir -pv ~/.docker $ mkdir -pv ~/.docker
$ cp -v {ca,cert,key}.pem ~/.docker $ cp -v {ca,cert,key}.pem ~/.docker
$ eval "$(weave env)" $ eval $(weave env)
$ export DOCKER_TLS_VERIFY=1 $ export DOCKER_TLS_VERIFY=1
$ docker version $ docker version
... ...
+22
View File
@@ -0,0 +1,22 @@
#! /bin/bash
. ./config.sh
start_suite "Rolling restart with reset"
weave_on $HOST1 launch-router
weave_on $HOST2 launch-router $HOST1
start_container $HOST1 --name=c1
start_container $HOST2 --name=c2
# Now reset the routers so they should give their space away, and restart
weave_on $HOST1 reset
weave_on $HOST1 launch-router $HOST2
weave_on $HOST2 reset
weave_on $HOST2 launch-router $HOST1
# And try to start a container
assert_raises "timeout 10 cat <( start_container $HOST1 )"
end_suite
+7
View File
@@ -21,6 +21,13 @@ start_container_with_dns $HOST1 $C1/24 --name=c1 $STATICS_ARGS
assert_dns_record $HOST1 c1 $NAME $C2 assert_dns_record $HOST1 c1 $NAME $C2
# Check that 'weave expose -h' names are added to DNS
weave_on $HOST1 expose
EXPOSE=$(weave_on $HOST1 expose -h testexpose1.weave.local)
weave_on $HOST1 expose -h testexpose2.weave.local
assert_dns_record $HOST1 c1 testexpose1.weave.local $EXPOSE
assert_dns_record $HOST1 c1 testexpose2.weave.local
# check we respect the --add-host arguments # check we respect the --add-host arguments
for C in c1 c2 ; do for C in c1 c2 ; do
assert_dns_a_record $HOST1 $C $STATIC1_NAME $STATIC1 assert_dns_a_record $HOST1 $C $STATIC1_NAME $STATIC1
+15 -3
View File
@@ -7,10 +7,22 @@ C2=10.2.0.34
NAME=seetwo.weave.local NAME=seetwo.weave.local
check_attached() { check_attached() {
assert_raises "proxy exec_on $HOST1 c2 $CHECK_ETHWE_UP" assert_raises "exec_on $HOST1 c2 $CHECK_ETHWE_UP"
assert_dns_record $HOST1 c1 $NAME $C2 assert_dns_record $HOST1 c1 $NAME $C2
} }
wait_for_proxy() {
for i in $(seq 1 120); do
echo "Waiting for proxy to start"
if proxy docker_on $1 info > /dev/null 2>&1 ; then
return
fi
sleep 1
done
echo "Timed out waiting for proxy to start" >&2
exit 1
}
start_suite "Proxy restart reattaches networking to containers" start_suite "Proxy restart reattaches networking to containers"
WEAVE_DOCKER_ARGS=--restart=always WEAVEPROXY_DOCKER_ARGS=--restart=always weave_on $HOST1 launch WEAVE_DOCKER_ARGS=--restart=always WEAVEPROXY_DOCKER_ARGS=--restart=always weave_on $HOST1 launch
@@ -32,13 +44,13 @@ check_attached
# Restart docker itself, using different commands for systemd- and upstart-managed. # Restart docker itself, using different commands for systemd- and upstart-managed.
run_on $HOST1 sh -c "command -v systemctl >/dev/null && sudo systemctl restart docker || sudo service docker restart" run_on $HOST1 sh -c "command -v systemctl >/dev/null && sudo systemctl restart docker || sudo service docker restart"
sleep 10 wait_for_proxy $HOST1
check_attached check_attached
# Restarting proxy shouldn't kill unattachable containers # Restarting proxy shouldn't kill unattachable containers
proxy_start_container $HOST1 -di --name=c3 --restart=always # Use ipam, so it won't be attachable w/o weave proxy_start_container $HOST1 -di --name=c3 --restart=always # Use ipam, so it won't be attachable w/o weave
weave_on $HOST1 stop weave_on $HOST1 stop
weave_on $HOST1 launch-proxy weave_on $HOST1 launch-proxy
assert_raises "proxy exec_on $HOST1 c3 $CHECK_ETHWE_UP" assert_raises "exec_on $HOST1 c3 $CHECK_ETHWE_UP"
end_suite end_suite
+15 -4
View File
@@ -9,8 +9,8 @@ docker_bridge_ip=$(weave_on $HOST1 docker-bridge-ip)
proxy_start_container $HOST1 --name=c1 proxy_start_container $HOST1 --name=c1
check_hostconfig() { check_hostconfig() {
docker_on $HOST1 attach c2 >/dev/null 2>&1 || true # Wait for container to exit docker_on $HOST1 attach $1 >/dev/null 2>&1 || true # Wait for container to exit
assert "docker_on $HOST1 inspect -f '{{.HostConfig.Dns}} {{.HostConfig.NetworkMode}} {{.State.Running}} {{.State.ExitCode}}' $1" "[$docker_bridge_ip] $2 false 0" assert "docker_on $HOST1 inspect -f '{{.HostConfig.Dns}} {{.HostConfig.NetworkMode}} {{.State.Running}} {{.State.ExitCode}}' $1" "[$3] $2 false 0"
} }
# Start c2 with a sneaky HostConfig # Start c2 with a sneaky HostConfig
@@ -26,7 +26,7 @@ check_hostconfig c5 container:c1
# Start c3 with HostConfig having empty binds and null dns/networking settings # Start c3 with HostConfig having empty binds and null dns/networking settings
proxy docker_on $HOST1 create --name=c3 -v /tmp:/hosttmp $SMALL_IMAGE $CHECK_ETHWE_UP proxy docker_on $HOST1 create --name=c3 -v /tmp:/hosttmp $SMALL_IMAGE $CHECK_ETHWE_UP
proxy docker_api_on $HOST1 POST /containers/c3/start '{"Binds":[],"Dns":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,"Devices":null,"NetworkMode":""}' proxy docker_api_on $HOST1 POST /containers/c3/start '{"Binds":[],"Dns":null,"DnsSearch":null,"ExtraHosts":null,"VolumesFrom":null,"Devices":null,"NetworkMode":""}'
check_hostconfig c3 default check_hostconfig c3 default $docker_bridge_ip
# Start c4 with an 'null' HostConfig and check this doesn't remove previous parameters # Start c4 with an 'null' HostConfig and check this doesn't remove previous parameters
proxy docker_on $HOST1 create --name=c4 --memory-swap -1 $SMALL_IMAGE echo foo proxy docker_on $HOST1 create --name=c4 --memory-swap -1 $SMALL_IMAGE echo foo
@@ -42,6 +42,17 @@ check_hostconfig c6 container:c1
proxy docker_on $HOST1 create --name=c7 --memory-swap -1 $SMALL_IMAGE $CHECK_ETHWE_UP proxy docker_on $HOST1 create --name=c7 --memory-swap -1 $SMALL_IMAGE $CHECK_ETHWE_UP
proxy docker_api_on $HOST1 POST /containers/c7/start '{"HostConfig":{}}' proxy docker_api_on $HOST1 POST /containers/c7/start '{"HostConfig":{}}'
assert "docker_on $HOST1 inspect -f '{{.HostConfig.MemorySwap}}' c7" "0" assert "docker_on $HOST1 inspect -f '{{.HostConfig.MemorySwap}}' c7" "0"
check_hostconfig c7 default check_hostconfig c7 default $docker_bridge_ip
# Start c8 in host network mode
proxy docker_on $HOST1 create --name=c8 $SMALL_IMAGE $CHECK_ETHWE_MISSING
proxy docker_api_on $HOST1 POST /containers/c8/start '{"HostConfig": {"NetworkMode": "host"}}'
check_hostconfig c8 host
# Start c10 in network of host container
proxy_start_container $HOST1 --name=c9 --net=host
proxy docker_on $HOST1 create --name=c10 $SMALL_IMAGE $CHECK_ETHWE_MISSING
proxy docker_api_on $HOST1 POST /containers/c10/start '{"HostConfig": {"NetworkMode": "container:c9"}}'
check_hostconfig c10 container:c9
end_suite end_suite
+1
View File
@@ -40,6 +40,7 @@ TEST_IMAGES="$SMALL_IMAGE $DNS_IMAGE"
PING="ping -nq -W 1 -c 1" PING="ping -nq -W 1 -c 1"
CHECK_ETHWE_UP="grep ^1$ /sys/class/net/ethwe/carrier" CHECK_ETHWE_UP="grep ^1$ /sys/class/net/ethwe/carrier"
CHECK_ETHWE_MISSING="test ! -d /sys/class/net/ethwe"
DOCKER_PORT=2375 DOCKER_PORT=2375
+1 -1
View File
@@ -97,7 +97,7 @@ type TestRouterClient struct {
} }
func (grouter *TestRouter) run(sender router.PeerName, gossiper router.Gossiper, gossipChan chan interface{}) { func (grouter *TestRouter) run(sender router.PeerName, gossiper router.Gossiper, gossipChan chan interface{}) {
gossipTimer := time.Tick(10 * time.Second) gossipTimer := time.Tick(2 * time.Second)
for { for {
select { select {
case gossip := <-gossipChan: case gossip := <-gossipChan:
+1 -1
View File
@@ -60,6 +60,6 @@ export DEBIAN_FRONTEND=noninteractive
/etc/init.d/puppet stop /etc/init.d/puppet stop
apt-get -qq remove puppet chef apt-get -qq remove puppet chef
apt-get -qq autoremove apt-get -qq autoremove
killall -9 chef-client killall -9 chef-client 2>/dev/null || true
SCRIPT SCRIPT
end end
+11 -5
View File
@@ -420,6 +420,10 @@ create_bridge() {
run_iptables -t filter -I FORWARD -i $DOCKER_BRIDGE -o $BRIDGE -j DROP run_iptables -t filter -I FORWARD -i $DOCKER_BRIDGE -o $BRIDGE -j DROP
fi fi
# let DNS traffic to weaveDNS, since otherwise it might get blocked by the likes of UFW
add_iptables_rule filter INPUT -i $DOCKER_BRIDGE -p udp --dport 53 -j ACCEPT
add_iptables_rule filter INPUT -i $DOCKER_BRIDGE -p tcp --dport 53 -j ACCEPT
# Work around the situation where there are no rules allowing traffic # Work around the situation where there are no rules allowing traffic
# across our bridge. E.g. ufw # across our bridge. E.g. ufw
add_iptables_rule filter FORWARD -i $BRIDGE -o $BRIDGE -j ACCEPT add_iptables_rule filter FORWARD -i $BRIDGE -o $BRIDGE -j ACCEPT
@@ -525,6 +529,8 @@ destroy_bridge() {
run_iptables -t filter -D FORWARD -i $DOCKER_BRIDGE -o $BRIDGE -j DROP 2>/dev/null || true run_iptables -t filter -D FORWARD -i $DOCKER_BRIDGE -o $BRIDGE -j DROP 2>/dev/null || true
fi fi
run_iptables -t filter -D INPUT -i $DOCKER_BRIDGE -p udp --dport 53 -j ACCEPT >/dev/null 2>&1 || true
run_iptables -t filter -D INPUT -i $DOCKER_BRIDGE -p tcp --dport 53 -j ACCEPT >/dev/null 2>&1 || true
run_iptables -t filter -D FORWARD -i $BRIDGE -o $BRIDGE -j ACCEPT 2>/dev/null || true run_iptables -t filter -D FORWARD -i $BRIDGE -o $BRIDGE -j ACCEPT 2>/dev/null || true
run_iptables -t nat -F WEAVE >/dev/null 2>&1 || true run_iptables -t nat -F WEAVE >/dev/null 2>&1 || true
run_iptables -t nat -D POSTROUTING -j WEAVE >/dev/null 2>&1 || true run_iptables -t nat -D POSTROUTING -j WEAVE >/dev/null 2>&1 || true
@@ -1475,7 +1481,7 @@ launch_router() {
$(router_opts_$BRIDGE_TYPE) \ $(router_opts_$BRIDGE_TYPE) \
--ipalloc-range "$IPRANGE" \ --ipalloc-range "$IPRANGE" \
--dns-effective-listen-address $DOCKER_BRIDGE_IP \ --dns-effective-listen-address $DOCKER_BRIDGE_IP \
${NETHOST_OPT:+$DNS_ROUTER_OPTS} $NO_DNS_OPT \ ${NETHOST_OPT:+$DNS_ROUTER_OPTS --http-addr 127.0.0.1:$HTTP_PORT} $NO_DNS_OPT \
--docker-api "unix:///var/run/docker.sock" "$@") --docker-api "unix:///var/run/docker.sock" "$@")
with_container_netns_or_die $CONTAINER_NAME setup_router_iface_$BRIDGE_TYPE with_container_netns_or_die $CONTAINER_NAME setup_router_iface_$BRIDGE_TYPE
attach_router attach_router
@@ -1896,9 +1902,9 @@ EOF
arp_update $BRIDGE $CIDR arp_update $BRIDGE $CIDR
add_iptables_rule nat WEAVE -d $CIDR ! -s $CIDR -j MASQUERADE add_iptables_rule nat WEAVE -d $CIDR ! -s $CIDR -j MASQUERADE
add_iptables_rule nat WEAVE -s $CIDR ! -d $CIDR -j MASQUERADE add_iptables_rule nat WEAVE -s $CIDR ! -d $CIDR -j MASQUERADE
if [ -n "$FQDN" ] ; then fi
when_weave_running put_dns_fqdn_no_check_alive weave:expose $FQDN $CIDR if [ -n "$FQDN" ] ; then
fi when_weave_running put_dns_fqdn_no_check_alive weave:expose $FQDN $CIDR
fi fi
done done
show_addrs $ALL_CIDRS show_addrs $ALL_CIDRS
@@ -1927,8 +1933,8 @@ EOF
;; ;;
stop) stop)
[ $# -eq 0 ] || usage [ $# -eq 0 ] || usage
stop_proxy
stop_router stop_router
stop_proxy
;; ;;
stop-router) stop-router)
[ $# -eq 0 ] || usage [ $# -eq 0 ] || usage