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/sigproxy/sigproxy
prog/weavewait/weavewait
prog/weavewait/weavewait_noop
prog/netcheck/netcheck
prog/docker_tls_args/docker_tls_args
testing/cover/cover
@@ -52,6 +53,7 @@ prog/weaveexec/weave
prog/weaveexec/weavehosts
prog/weaveexec/weaveproxy
prog/weaveexec/weavewait
prog/weaveexec/weavewait_noop
prog/weaveexec/sigproxy
prog/weaveexec/netcheck
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
**Highlights**
+9 -3
View File
@@ -13,11 +13,12 @@ WEAVER_EXE=prog/weaver/weaver
WEAVEPROXY_EXE=prog/weaveproxy/weaveproxy
SIGPROXY_EXE=prog/sigproxy/sigproxy
WEAVEWAIT_EXE=prog/weavewait/weavewait
WEAVEWAIT_NOOP_EXE=prog/weavewait/weavewait_noop
NETCHECK_EXE=prog/netcheck/netcheck
DOCKERTLSARGS_EXE=prog/docker_tls_args/docker_tls_args
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
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
# the main build stanza due to not importing net package
$(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
$(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 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)
$(SUDO) docker build -t $(WEAVER_IMAGE) prog/weaver
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 $(SIGPROXY_EXE) prog/weaveexec/sigproxy
cp $(WEAVEPROXY_EXE) prog/weaveexec/weaveproxy
cp $(WEAVEWAIT_EXE) prog/weaveexec/weavewait
cp $(WEAVEWAIT_NOOP_EXE) prog/weaveexec/weavewait_noop
cp $(NETCHECK_EXE) prog/weaveexec/netcheck
cp $(DOCKERTLSARGS_EXE) prog/weaveexec/docker_tls_args
cp $(DOCKER_DISTRIB) prog/weaveexec/docker.tgz
+40 -12
View File
@@ -55,19 +55,21 @@ type Allocator struct {
paxos *paxos.Node
paxosTicker *time.Ticker
shuttingDown bool // to avoid doing any requests while trying to shut down
isKnownPeer func(router.PeerName) bool
now func() time.Time
}
// 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{
ourName: ourName,
universe: universe,
ring: ring.New(universe.Start, universe.End, ourName),
owned: make(map[string][]address.Address),
paxos: paxos.NewNode(ourName, ourUID, quorum),
nicknames: map[router.PeerName]string{ourName: ourNickname},
now: time.Now,
ourName: ourName,
universe: universe,
ring: ring.New(universe.Start, universe.End, ourName),
owned: make(map[string][]address.Address),
paxos: paxos.NewNode(ourName, ourUID, quorum),
nicknames: map[router.PeerName]string{ourName: ourNickname},
isKnownPeer: isKnownPeer,
now: time.Now,
}
}
@@ -274,6 +276,33 @@ func (alloc *Allocator) Free(ident string, addrToFree address.Address) error {
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)
func (alloc *Allocator) Shutdown() {
alloc.infof("Shutdown")
@@ -282,7 +311,7 @@ func (alloc *Allocator) Shutdown() {
alloc.shuttingDown = true
alloc.cancelOps(&alloc.pendingClaims)
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.space.Clear()
alloc.gossip.GossipBroadcast(alloc.Gossip())
@@ -310,7 +339,6 @@ func (alloc *Allocator) AdminTakeoverRanges(peerNameOrNickname string) error {
return
}
delete(alloc.nicknames, peername)
newRanges, err := alloc.ring.Transfer(peername, alloc.ourName)
alloc.space.AddRanges(newRanges)
resultChan <- err
@@ -332,11 +360,11 @@ func (alloc *Allocator) lookupPeername(name string) (router.PeerName, error) {
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() {
ringPeers := alloc.ring.PeerNames()
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)
}
}
+2 -2
View File
@@ -470,9 +470,9 @@ func (r *Ring) ChoosePeersToAskForSpace(start, end address.Address) []router.Pee
return result
}
func (r *Ring) PickPeerForTransfer() router.PeerName {
func (r *Ring) PickPeerForTransfer(isValid func(router.PeerName) bool) router.PeerName {
for _, entry := range r.Entries {
if entry.Peer != r.Peer {
if entry.Peer != r.Peer && isValid(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()),
"nick-"+name, cidr.Range(), quorum)
"nick-"+name, cidr.Range(), quorum, func(router.PeerName) bool { return true })
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.Id = dns.Id()
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)
continue
}
+5 -5
View File
@@ -42,17 +42,17 @@ func TestTruncation(t *testing.T) {
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)
response, _, err := client.Exchange(request, fmt.Sprintf("127.0.0.1:%d", port))
require.Nil(t, err)
require.Equal(t, expectedErr, err)
return response
}
// do a udp query, ensure we get a truncated response
{
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, len(response.Answer) < 100)
}
@@ -62,7 +62,7 @@ func TestTruncation(t *testing.T) {
udpClient := dns.Client{Net: "udp", UDPSize: 65535}
request := &dns.Msg{}
request.SetEdns0(65535, false)
response := doRequest(&udpClient, request, udpPort)
response := doRequest(&udpClient, request, udpPort, nil)
require.False(t, response.MsgHdr.Truncated)
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
{
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.Equal(t, len(response.Answer), 100)
}
+36 -12
View File
@@ -18,7 +18,8 @@ type Entry struct {
ContainerID string
Origin router.PeerName
Addr address.Address
Hostname string
Hostname string // as supplied
lHostname string // lowercased (not exported, so not encoded by gob)
Version int
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 {
// 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 {
case e1Hostname != e2Hostname:
return e1Hostname < e2Hostname
@@ -100,6 +101,10 @@ func (e1 *Entry) String() 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 {
if !sort.IsSorted(es) {
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 {
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 {
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 {
defer es.checkAndPanic().checkAndPanic()
incoming.checkAndPanic()
newEntries := Entries{}
i := 0
@@ -203,23 +210,23 @@ func (es Entries) lookup(hostname string) Entries {
lowerHostname := strings.ToLower(hostname)
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{}
}
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]
}
func (es *Entries) first(f func(*Entry) bool) (*Entry, error) {
func (es Entries) first(f func(*Entry) bool) (*Entry, error) {
es.checkAndPanic()
for _, e := range *es {
for _, e := range es {
if f(&e) {
return &e, nil
}
@@ -227,14 +234,18 @@ func (es *Entries) first(f func(*Entry) bool) (*Entry, error) {
return nil, fmt.Errorf("Not found")
}
func (es Entries) addLowercase() {
for i := range es {
es[i].addLowercase()
}
}
type GossipData struct {
Timestamp int64
Entries
}
func (g *GossipData) Merge(o router.GossipData) {
checkAndPanic(CaseSensitive(g.Entries))
defer func() { checkAndPanic(CaseSensitive(g.Entries)) }()
other := o.(*GossipData)
g.Entries.merge(other.Entries)
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 {
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{}
if err := gob.NewEncoder(buf).Encode(g); err != nil {
if err := gob.NewEncoder(buf).Encode(g2); err != nil {
panic(err)
}
return [][]byte{buf.Bytes()}
+47 -56
View File
@@ -9,6 +9,19 @@ import (
"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) {
oldNow := now
defer func() { now = oldNow }()
@@ -16,68 +29,46 @@ func TestAdd(t *testing.T) {
entries := Entries{}
entries.add("A", "", router.UnknownPeerName, address.Address(0))
expected := Entries{
expected := l(Entries{
Entry{Hostname: "A", Origin: router.UnknownPeerName, Addr: address.Address(0)},
}
})
require.Equal(t, entries, expected)
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},
}
})
require.Equal(t, entries, expected)
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},
}
})
require.Equal(t, entries, expected)
}
func TestMerge(t *testing.T) {
e1 := Entries{
Entry{Hostname: "A"},
Entry{Hostname: "C"},
Entry{Hostname: "D"},
Entry{Hostname: "F"},
}
e2 := Entries{
Entry{Hostname: "B"},
Entry{Hostname: "E"},
Entry{Hostname: "F"},
}
e1 := makeEntries("ACDF")
e2 := makeEntries("BEF")
diff := e1.merge(e2)
expectedDiff := Entries{
Entry{Hostname: "B"},
Entry{Hostname: "E"},
}
require.Equal(t, expectedDiff, diff)
expected := Entries{
Entry{Hostname: "A"},
Entry{Hostname: "B"},
Entry{Hostname: "C"},
Entry{Hostname: "D"},
Entry{Hostname: "E"},
Entry{Hostname: "F"},
}
require.Equal(t, expected, e1)
require.Equal(t, makeEntries("BE"), diff)
require.Equal(t, makeEntries("ABCDEF"), e1)
diff = e1.merge(e1)
require.Equal(t, Entries{}, diff)
}
func TestOldMerge(t *testing.T) {
e1 := Entries{Entry{Hostname: "A", Version: 0}}
diff := e1.merge(Entries{Entry{Hostname: "A", Version: 1}})
require.Equal(t, Entries{Entry{Hostname: "A", Version: 1}}, diff)
require.Equal(t, Entries{Entry{Hostname: "A", Version: 1}}, e1)
e1 := l(Entries{Entry{Hostname: "A", Version: 0}})
diff := e1.merge(l(Entries{Entry{Hostname: "A", Version: 1}}))
require.Equal(t, l(Entries{Entry{Hostname: "A", Version: 1}}), diff)
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{Entry{Hostname: "A", Version: 1}}, e1)
require.Equal(t, l(Entries{Entry{Hostname: "A", Version: 1}}), e1)
}
func TestTombstone(t *testing.T) {
@@ -85,48 +76,48 @@ func TestTombstone(t *testing.T) {
defer func() { now = oldNow }()
now = func() int64 { return 1234 }
es := Entries{
Entry{Hostname: "A"},
Entry{Hostname: "B"},
}
es := makeEntries("AB")
es.tombstone(router.UnknownPeerName, func(e *Entry) bool {
return e.Hostname == "B"
})
expected := Entries{
expected := l(Entries{
Entry{Hostname: "A"},
Entry{Hostname: "B", Version: 1, Tombstone: 1234},
}
})
require.Equal(t, expected, es)
}
func TestDelete(t *testing.T) {
es := Entries{
Entry{Hostname: "A"},
Entry{Hostname: "B"},
}
es := makeEntries("AB")
es.filter(func(e *Entry) bool {
return e.Hostname != "A"
})
expected := Entries{
Entry{Hostname: "B"},
}
require.Equal(t, expected, es)
require.Equal(t, makeEntries("B"), es)
}
func TestLookup(t *testing.T) {
es := Entries{
es := l(Entries{
Entry{Hostname: "A"},
Entry{Hostname: "B", ContainerID: "bar"},
Entry{Hostname: "B", ContainerID: "foo"},
Entry{Hostname: "C"},
}
})
have := es.lookup("B")
want := Entries{
want := l(Entries{
Entry{Hostname: "B", ContainerID: "bar"},
Entry{Hostname: "B", ContainerID: "foo"},
}
})
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
}
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 {
n.badRequest(w, fmt.Errorf("Unable to add entry: %v", err))
return
+1 -8
View File
@@ -1,10 +1,7 @@
package nameserver
import (
"bytes"
"encoding/gob"
"fmt"
"sort"
"sync"
"time"
@@ -196,7 +193,6 @@ func (n *Nameserver) Gossip() router.GossipData {
Timestamp: now(),
}
copy(gossip.Entries, n.entries)
sort.Sort(CaseSensitive(gossip.Entries))
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) {
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
}
if delta := gossip.Timestamp - now(); delta > gossipWindow || delta < -gossipWindow {
return nil, nil, fmt.Errorf("clock skew of %d detected", delta)
}
sort.Sort(CaseInsensitive(gossip.Entries))
n.Lock()
defer n.Unlock()
+26 -7
View File
@@ -72,7 +72,7 @@ func (m mapping) Addrs() []address.Address {
}
func TestNameservers(t *testing.T) {
wt.RunWithTimeout(t, time.Minute, func() {
wt.RunWithTimeout(t, 2*time.Minute, func() {
testNameservers(t)
})
}
@@ -81,8 +81,12 @@ func testNameservers(t *testing.T) {
//common.SetLogLevel("debug")
lookupTimeout := 10 // ms
nameservers, grouter := makeNetwork(50)
nameservers, grouter := makeNetwork(30)
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{}
for _, n := range nameservers {
nameserversByName[n.ourName] = n
@@ -106,7 +110,13 @@ func testNameservers(t *testing.T) {
addMapping := func() {
nameserver := nameservers[rand.Intn(len(nameservers))]
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}}}
mappings = append(mappings, mapping)
@@ -129,6 +139,12 @@ func testNameservers(t *testing.T) {
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() {
if len(mappings) <= 0 {
return
@@ -179,7 +195,7 @@ func testNameservers(t *testing.T) {
require.Equal(t, mapping.hostname, hostname)
}
for i := 0; i < 1000; i++ {
for i := 0; i < 800; i++ {
r := rand.Float32()
switch {
case r < 0.1:
@@ -191,7 +207,10 @@ func testNameservers(t *testing.T) {
case 0.2 <= r && r < 0.3:
deleteMapping()
case 0.3 <= r && r < 0.9:
case 0.3 <= r && r < 0.35:
loseConnection()
case 0.35 <= r && r < 0.9:
doLookup()
case 0.9 <= r:
@@ -241,14 +260,14 @@ func TestTombstoneDeletion(t *testing.T) {
err = nameserver.Delete("hostname", "containerid", "", address.Address(0))
require.Nil(t, err)
require.Equal(t, []address.Address{}, nameserver.Lookup("hostname"))
require.Equal(t, Entries{{
require.Equal(t, l(Entries{Entry{
ContainerID: "containerid",
Origin: peername,
Addr: address.Address(0),
Hostname: "hostname",
Version: 1,
Tombstone: 1234,
}}, nameserver.entries)
}}), nameserver.entries)
now = func() int64 { return 1234 + int64(tombstoneTimeout/time.Second) + 1 }
nameserver.deleteTombstones()
+2
View File
@@ -5,6 +5,7 @@ LABEL works.weave.role=system
WORKDIR /home/weave
VOLUME /w
VOLUME /w-noop
ENTRYPOINT ["/home/weave/sigproxy", "/home/weave/weave"]
RUN apk add --update \
@@ -20,4 +21,5 @@ RUN apk add --update \
ADD ./weave ./sigproxy ./weaveproxy /home/weave/
ADD ./netcheck ./docker_tls_args /usr/bin/
ADD ./weavewait /w/w
ADD ./weavewait_noop /w-noop/w
ADD ./docker.tgz /
+8 -4
View File
@@ -13,7 +13,6 @@ import (
"github.com/davecheney/profile"
"github.com/docker/docker/pkg/mflag"
"github.com/gorilla/mux"
"github.com/weaveworks/go-odp/odp"
. "github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/common/docker"
@@ -119,8 +118,12 @@ func main() {
os.Exit(0)
case createDatapath:
err := weave.CreateDatapath(datapathName)
if odp.IsKernelLacksODPError(err) {
err, odp_supported := weave.CreateDatapath(datapathName)
if !odp_supported {
if err != nil {
Log.Error(err)
}
// When the kernel lacks ODP support, exit
// with a special status to distinguish it for
// 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)
}
}
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.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/exec"
"syscall"
weavenet "github.com/weaveworks/weave/net"
)
var (
@@ -19,8 +17,7 @@ func main() {
args = os.Args[1:]
)
_, err := weavenet.EnsureInterfaceAndMcastRoute("ethwe")
checkErr(err)
checkErr(checkNetwork())
if len(args) == 0 {
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/([^/]*)/.*")
weaveWaitEntrypoint = []string{"/w/w"}
weaveEntrypoint = "/home/weave/weaver"
weaveContainerName = "/weave"
)
func callWeave(args ...string) ([]byte, []byte, error) {
@@ -154,3 +155,25 @@ func weaveContainerIPs(containerID string) (mac string, ips []net.IP, nets []*ne
}
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)
} else {
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
}
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
}
if err := updateContainerNetworkSettings(container); err != nil {
if err := i.proxy.updateContainerNetworkSettings(container); err != nil {
Log.Warningf("Inspecting container %s failed: %s", container["Id"], err)
}
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
}
if err := updateContainerNetworkSettings(container); err != nil {
if err := i.proxy.updateContainerNetworkSettings(container); err != nil {
Log.Warningf("Inspecting exec %s failed: %s", exec["Id"], err)
}
+62 -28
View File
@@ -70,6 +70,7 @@ type Proxy struct {
dockerBridgeIP string
hostnameMatchRegexp *regexp.Regexp
weaveWaitVolume string
weaveWaitNoopVolume string
normalisedAddrs []string
waiters map[*http.Request]*wait
}
@@ -106,7 +107,7 @@ func NewProxy(c Config) (*Proxy, error) {
return nil, err
}
if err = p.findWeaveWaitVolume(); err != nil {
if err = p.findWeaveWaitVolumes(); err != nil {
return nil, err
}
@@ -135,23 +136,31 @@ func (proxy *Proxy) Dial() (net.Conn, error) {
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")
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 {
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 {
return fmt.Errorf("Could not find the weavewait volume")
return "", fmt.Errorf("Could not find the weavewait volume")
}
proxy.weaveWaitVolume = volume
return nil
return volume, nil
}
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 {
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) {
@@ -357,6 +367,24 @@ func (proxy *Proxy) waitForStart(r *http.Request) error {
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) {
}
@@ -406,7 +434,7 @@ func (proxy *Proxy) attachRouter(container *docker.Container) error {
func (proxy *Proxy) weaveCIDRs(networkMode string, env []string) ([]string, error) {
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 {
if strings.HasPrefix(e, "WEAVE_CIDR=") {
@@ -422,24 +450,6 @@ func (proxy *Proxy) weaveCIDRs(networkMode string, env []string) ([]string, erro
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 {
dns, err := hostConfig.StringArray("Dns")
if err != nil {
@@ -494,3 +504,27 @@ func (proxy *Proxy) getDNSDomain() (domain string) {
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 (
"net/http"
"strings"
)
type startContainerInterceptor struct{ proxy *Proxy }
@@ -31,11 +32,23 @@ func (i *startContainerInterceptor) InterceptRequest(r *http.Request) error {
hostConfig = params
}
if hostConfig != nil {
i.proxy.addWeaveWaitVolume(hostConfig)
if dnsDomain := i.proxy.getDNSDomain(); dnsDomain != "" {
if err := i.proxy.setWeaveDNS(hostConfig, container.Config.Hostname, dnsDomain); err != nil {
networkMode, err := jsonObject(hostConfig).String("NetworkMode")
if err != nil {
return err
}
if strings.HasPrefix(networkMode, "container:") || networkMode == "host" {
if err := addVolume(hostConfig, i.proxy.weaveWaitNoopVolume, "/w", "ro"); err != nil {
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
+38 -5
View File
@@ -1,25 +1,58 @@
package router
import (
"fmt"
"net"
"syscall"
"github.com/weaveworks/go-odp/odp"
)
// ODP admin functionality
func CreateDatapath(dpname string) error {
func CreateDatapath(dpname string) (err error, supported bool) {
dpif, err := odp.NewDpif()
if err != nil {
return err
if odp.IsKernelLacksODPError(err) {
return nil, false
}
return err, true
}
defer dpif.Close()
_, err = dpif.CreateDatapath(dpname)
dp, err := dpif.CreateDatapath(dpname)
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 {
-9
View File
@@ -327,8 +327,6 @@ func (peers *Peers) ApplyUpdate(update []byte) (PeerNameSet, PeerNameSet, error)
return nil, nil, err
}
ourVersion := peers.ourself.Version
// 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
// adding in any new peers.
@@ -349,13 +347,6 @@ func (peers *Peers) ApplyUpdate(update []byte) (PeerNameSet, PeerNameSet, error)
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
}
+14
View File
@@ -69,3 +69,17 @@
s.parentNode.insertBefore(wf, s);
})();
</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
isolation between application containers, that feature needs to be
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
prevented from capturing and injecting raw network packets - this can
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
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
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.
> 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
[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
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
used, as required by
[RFC 1122](https://tools.ietf.org/html/rfc1122#page-29).
that all start 10.2.
Weave shares the IP address range across all peers, dynamically
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
When
[running containers on different subnets](features.html#application-isolation),
you may wish to request the allocation of an address from a particular
subnet. This is done by specifying the subnet with `net:<subnet>`, in
CIDR notation, e.g.
IP subnets are used to define or restrict routing. By default, weave
puts all containers in a subnet that spans the entire allocation
range, so every weave-attached container can talk to every other
weave-attached container.
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
@@ -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
(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
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
@@ -227,3 +225,7 @@ 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.
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
command for this:
host1$ eval "$(weave env)"
host1$ eval $(weave env)
host1$ docker ps
...
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
@@ -194,7 +194,7 @@ ultimately be handed over to weaveDNS for registration.
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$ eval "$(weave env)"
host1$ eval $(weave env)
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
@@ -264,7 +264,7 @@ with
$ mkdir -pv ~/.docker
$ cp -v {ca,cert,key}.pem ~/.docker
$ eval "$(weave env)"
$ eval $(weave env)
$ export DOCKER_TLS_VERIFY=1
$ 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
# 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
for C in c1 c2 ; do
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
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
}
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"
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.
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
# 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
weave_on $HOST1 stop
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
+15 -4
View File
@@ -9,8 +9,8 @@ docker_bridge_ip=$(weave_on $HOST1 docker-bridge-ip)
proxy_start_container $HOST1 --name=c1
check_hostconfig() {
docker_on $HOST1 attach c2 >/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"
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" "[$3] $2 false 0"
}
# 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
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":""}'
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
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_api_on $HOST1 POST /containers/c7/start '{"HostConfig":{}}'
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
+1
View File
@@ -40,6 +40,7 @@ TEST_IMAGES="$SMALL_IMAGE $DNS_IMAGE"
PING="ping -nq -W 1 -c 1"
CHECK_ETHWE_UP="grep ^1$ /sys/class/net/ethwe/carrier"
CHECK_ETHWE_MISSING="test ! -d /sys/class/net/ethwe"
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{}) {
gossipTimer := time.Tick(10 * time.Second)
gossipTimer := time.Tick(2 * time.Second)
for {
select {
case gossip := <-gossipChan:
+1 -1
View File
@@ -60,6 +60,6 @@ export DEBIAN_FRONTEND=noninteractive
/etc/init.d/puppet stop
apt-get -qq remove puppet chef
apt-get -qq autoremove
killall -9 chef-client
killall -9 chef-client 2>/dev/null || true
SCRIPT
end
+11 -5
View File
@@ -420,6 +420,10 @@ create_bridge() {
run_iptables -t filter -I FORWARD -i $DOCKER_BRIDGE -o $BRIDGE -j DROP
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
# across our bridge. E.g. ufw
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
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 nat -F 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) \
--ipalloc-range "$IPRANGE" \
--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" "$@")
with_container_netns_or_die $CONTAINER_NAME setup_router_iface_$BRIDGE_TYPE
attach_router
@@ -1896,9 +1902,9 @@ EOF
arp_update $BRIDGE $CIDR
add_iptables_rule nat WEAVE -d $CIDR ! -s $CIDR -j MASQUERADE
add_iptables_rule nat WEAVE -s $CIDR ! -d $CIDR -j MASQUERADE
if [ -n "$FQDN" ] ; then
when_weave_running put_dns_fqdn_no_check_alive weave:expose $FQDN $CIDR
fi
fi
if [ -n "$FQDN" ] ; then
when_weave_running put_dns_fqdn_no_check_alive weave:expose $FQDN $CIDR
fi
done
show_addrs $ALL_CIDRS
@@ -1927,8 +1933,8 @@ EOF
;;
stop)
[ $# -eq 0 ] || usage
stop_proxy
stop_router
stop_proxy
;;
stop-router)
[ $# -eq 0 ] || usage