Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c5248da43 | ||
|
|
7fb597a8bf | ||
|
|
c50c90ea8d | ||
|
|
d220542491 | ||
|
|
181ce4cc60 | ||
|
|
65578211ef | ||
|
|
90ed76853c | ||
|
|
a3b4d6cdbf | ||
|
|
84c5c52090 | ||
|
|
bd41d114b5 | ||
|
|
94d2f84364 | ||
|
|
bf2b456af1 | ||
|
|
4961e83686 | ||
|
|
f70dc6660a | ||
|
|
360c0cb642 | ||
|
|
1ce9551ba6 | ||
|
|
4c566c8587 | ||
|
|
74eef4deda | ||
|
|
2576e819a7 | ||
|
|
e2fec3d007 | ||
|
|
12ed5cc9ee | ||
|
|
f8639a57e7 | ||
|
|
9e65cc20cb | ||
|
|
25c4a2961e | ||
|
|
f4e7c85219 | ||
|
|
475daa82b3 | ||
|
|
c3b653b1b9 | ||
|
|
ed3207afe7 | ||
|
|
8e5b0ceceb | ||
|
|
4a1bb1a33a | ||
|
|
93984e1955 | ||
|
|
67aae051d6 | ||
|
|
eee13e7dd9 | ||
|
|
7cc53c4c68 | ||
|
|
78e0e79b26 | ||
|
|
4958b8d37a | ||
|
|
e2389a4061 | ||
|
|
5e9bd5424a | ||
|
|
ba0ffd225e | ||
|
|
a14d4d9f8e | ||
|
|
d5e510f778 | ||
|
|
be8e414d5a | ||
|
|
65e94f624b | ||
|
|
a20ca49344 | ||
|
|
aa8466f688 | ||
|
|
53628fdeff | ||
|
|
dafa30725e | ||
|
|
24b9a56e0a | ||
|
|
e7f6682593 | ||
|
|
3f4b385b0f | ||
|
|
5fc16a8267 | ||
|
|
38176dcbb6 | ||
|
|
f3131fab57 | ||
|
|
397f1398ee | ||
|
|
1afdac4d2c | ||
|
|
c6fa9cb17e | ||
|
|
9619a27f8c | ||
|
|
c13154eea9 | ||
|
|
1132d26d47 | ||
|
|
77bc56751b | ||
|
|
b32c017f33 | ||
|
|
a982146cbe | ||
|
|
e4422205e8 | ||
|
|
b476bd2afe | ||
|
|
acd8bdec21 | ||
|
|
6386c1bd18 | ||
|
|
2e93a4c18e | ||
|
|
e26e7e29f2 | ||
|
|
1f3d054b09 | ||
|
|
e2f8b6f9fd | ||
|
|
f3c4a9fc6d | ||
|
|
9634526a67 | ||
|
|
b67c102fe5 | ||
|
|
835d99e6fe | ||
|
|
b93070f91a | ||
|
|
cf4ce0a07d | ||
|
|
78c4b06492 | ||
|
|
2ced8b9469 | ||
|
|
26c1bcf866 | ||
|
|
bde445df9b | ||
|
|
02715f88d5 | ||
|
|
706f9ee352 | ||
|
|
e3ab396428 | ||
|
|
df31454c30 | ||
|
|
bf73029d15 | ||
|
|
4dbd657a26 | ||
|
|
a3a7a19870 | ||
|
|
251c68e85a | ||
|
|
227cb11f25 | ||
|
|
6097dc8aaa | ||
|
|
9e32605183 | ||
|
|
9009e0eb7f | ||
|
|
243d445d1b | ||
|
|
65cd2b0e04 | ||
|
|
33b230c114 | ||
|
|
6389af6ea2 | ||
|
|
8b35f5e8fe | ||
|
|
7d5dcfafc9 | ||
|
|
af40ebcab4 | ||
|
|
d427c99161 | ||
|
|
d1a887857d | ||
|
|
3914c4c018 | ||
|
|
3bd5ae56f0 | ||
|
|
a05a3c4b26 | ||
|
|
a938608cc8 | ||
|
|
ba1e75405f | ||
|
|
0f5f671054 | ||
|
|
5b9d350002 | ||
|
|
ec62029db5 | ||
|
|
c84c5dbcdf | ||
|
|
6725c8355f | ||
|
|
c659e3448a | ||
|
|
959e5f0082 | ||
|
|
6488b0d11c | ||
|
|
9253d45968 | ||
|
|
8a4b0d536e | ||
|
|
c76f640e2e | ||
|
|
b472da18f0 | ||
|
|
c58cc449c0 | ||
|
|
af9668f130 | ||
|
|
9f784b3c31 | ||
|
|
5f95de19ce | ||
|
|
8fb00ff206 | ||
|
|
00744fb9b4 | ||
|
|
8250e05618 | ||
|
|
9ae45f6674 | ||
|
|
6c3aa99595 | ||
|
|
2c73fd6dde | ||
|
|
3b27413887 | ||
|
|
17ee829299 | ||
|
|
5db39466e8 | ||
|
|
cc4ab80f62 | ||
|
|
0e47cee661 | ||
|
|
d6dca80dd7 | ||
|
|
74c391f19c | ||
|
|
7e36dc01e8 | ||
|
|
9020c84f81 | ||
|
|
d0a1514ab6 | ||
|
|
06c3a0cf2a | ||
|
|
a1913130e7 | ||
|
|
f29ee3ad05 | ||
|
|
19a3fc6b9e | ||
|
|
043d15355c | ||
|
|
9ec1ce3225 | ||
|
|
1b4f83c067 | ||
|
|
c126c403e7 | ||
|
|
90b9b3c1bf | ||
|
|
1a17b41bc3 | ||
|
|
2e5e0a7730 | ||
|
|
b2f62cc635 | ||
|
|
0a553d6630 | ||
|
|
e51c240ea1 | ||
|
|
f5201469a3 | ||
|
|
34aa2e32d8 | ||
|
|
9a631d0ecd | ||
|
|
c8032b6b25 | ||
|
|
68ca6ebe04 | ||
|
|
1bbec56cc7 | ||
|
|
b86bae9c86 | ||
|
|
6f798f723a | ||
|
|
b1bd1d4d6a | ||
|
|
1e638be7ac | ||
|
|
acd2b9abeb | ||
|
|
6ddecfc764 | ||
|
|
f15ad71354 | ||
|
|
4d54af39b0 | ||
|
|
81d5a8f4f5 | ||
|
|
344119f42a | ||
|
|
514db8efdd | ||
|
|
0693ec55c6 | ||
|
|
56c720b078 | ||
|
|
403b9654f1 | ||
|
|
84775e414b | ||
|
|
d913ca869c | ||
|
|
3732f968d0 |
No files matched your search
@@ -1,3 +1,23 @@
|
||||
## Release 1.0.2
|
||||
|
||||
This release fixes a number of bugs, including some security
|
||||
vulnerabilities in the Weave Docker API proxy, hangs and failures in
|
||||
address allocation, and sporadic failures in name resolution.
|
||||
|
||||
More details in the
|
||||
[change log](https://github.com/weaveworks/weave/issues?q=milestone%3A1.0.2).
|
||||
|
||||
The release is fully compatible with other 1.0.x versions, so existing
|
||||
clusters can be upgraded incrementally.
|
||||
|
||||
## Release 1.0.1
|
||||
|
||||
This is a bug fix release, addressing the following issue:
|
||||
|
||||
- executing `docker run` from a Docker 1.7 client against the weave
|
||||
proxy would report a `no such image` error when the requested image
|
||||
wasn't present on the Docker host, instead of downloading it.
|
||||
|
||||
## Release 1.0.0
|
||||
|
||||
**Highlights**:
|
||||
|
||||
@@ -38,7 +38,7 @@ all: $(EXPORTS)
|
||||
|
||||
travis: $(EXES)
|
||||
|
||||
update: $(EXES)
|
||||
update:
|
||||
go get -u -f -v -tags -netgo $(addprefix ./,$(dir $(EXES)))
|
||||
|
||||
$(WEAVER_EXE) $(WEAVEDNS_EXE) $(WEAVEPROXY_EXE) $(NETCHECK_EXE): common/*.go common/*/*.go net/*.go
|
||||
|
||||
@@ -52,36 +52,38 @@ Say you have docker running on two hosts, accessible to each other as
|
||||
`$HOST1` and `$HOST2`, and want to deploy an application consisting of
|
||||
two containers, one on each host.
|
||||
|
||||
On `$HOST1` run
|
||||
On $HOST1 we run:
|
||||
|
||||
host1$ weave launch
|
||||
host1$ weave launch-dns
|
||||
host1$ weave run --name a1 -ti ubuntu
|
||||
host1$ weave launch && weave launch-dns && weave launch-proxy
|
||||
host1$ eval $(weave proxy-env)
|
||||
host1$ docker run --name a1 -ti ubuntu
|
||||
|
||||
The first two lines start the weave router and DNS, each inside their
|
||||
own container - this needs to be done once per host. Whilst the
|
||||
required docker images are downloaded automatically, there is also a
|
||||
`weave setup` command for downloading all the images required for
|
||||
weave operation; this is a strictly optional step which is especially
|
||||
useful for automated installation of weave and ensures that any
|
||||
subsequent weave commands do not encounter delays due to image
|
||||
downloading.
|
||||
> NB: If the first command results in an error like
|
||||
> `http:///var/run/docker.sock/v1.19/containers/create: dial unix
|
||||
> /var/run/docker.sock: permission denied. Are you trying to connect
|
||||
> to a TLS-enabled daemon without TLS?` then you likely need to be
|
||||
> 'root' in order to connect to the Docker daemon. If so, run the
|
||||
> above and all subsequent commands in a *single* root shell (e.g. one
|
||||
> created with `sudo -s`). Do *not* prefix individual commands with
|
||||
> `sudo`, since some commands modify environment entries and hence
|
||||
> they all need to be executed from the same shell.
|
||||
|
||||
The third line runs our application container, allocating it an IP
|
||||
address on the weave network and registering it in DNS. `weave run`
|
||||
invokes `docker run -d` behind the scenes, so we could be launching
|
||||
any container this way; here we just take a stock ubuntu container and
|
||||
launch a shell in it. There's also a `weave start` command, which
|
||||
invokes `docker start` for starting existing containers.
|
||||
The first line runs the weave router, DNS and Docker API proxy, each
|
||||
in their own container. The second line sets the `DOCKER_HOST`
|
||||
environment variable to point to the proxy, so that containers
|
||||
launched via the docker command line are automatically attached to the
|
||||
weave network. Finally, we run our application container; this happens
|
||||
via the proxy so it is automatically allocated an IP address and
|
||||
registered in DNS.
|
||||
|
||||
If our application consists of more than one container on this host we
|
||||
simply launch them with a variation on third second line.
|
||||
That's it! If our application consists of more than one container on
|
||||
this host we simply launch them with `docker run` as appropriate.
|
||||
|
||||
Next we repeat similar steps on `$HOST2`...
|
||||
|
||||
host2$ weave launch $HOST1
|
||||
host2$ weave launch-dns
|
||||
host2$ weave run --name a2 -ti ubuntu
|
||||
host2$ weave launch $HOST1 && weave launch-dns && weave launch-proxy
|
||||
host2$ eval $(weave proxy-env)
|
||||
host2$ docker run --name a2 -ti ubuntu
|
||||
|
||||
The only difference, apart from the name of the application container,
|
||||
is that we tell our weave that it should peer with the weave on
|
||||
@@ -98,21 +100,25 @@ available. Also, we can tell weave to connect to multiple peers by
|
||||
supplying multiple addresses, separated by spaces. And we can
|
||||
[add peers dynamically](http://docs.weave.works/weave/latest_release/features.html#dynamic-topologies).
|
||||
|
||||
The router, DNS and Docker API proxy need to be started once per
|
||||
host. The relevant container images are pulled down on demand, but if
|
||||
you wish you can preload them by running `weave setup` - this is
|
||||
particularly useful for automated deployments, and ensures that there
|
||||
are no delays during later operations.
|
||||
|
||||
Now that we've got everything set up, let's see whether our containers
|
||||
can talk to each other...
|
||||
|
||||
On `$HOST1`...
|
||||
In the container started on `$HOST1`...
|
||||
|
||||
host1$ docker attach a1
|
||||
root@a1:/# ping -c 1 -q a2
|
||||
PING a2.weave.local (10.160.0.2) 56(84) bytes of data.
|
||||
--- a2.weave.local ping statistics ---
|
||||
1 packets transmitted, 1 received, 0% packet loss, time 0ms
|
||||
rtt min/avg/max/mdev = 0.341/0.341/0.341/0.000 ms
|
||||
|
||||
Similarly, on `$HOST2`...
|
||||
Similarly, in the container started on `$HOST2`...
|
||||
|
||||
host2$ docker attach a2
|
||||
root@a2:/# ping -c 1 -q a1
|
||||
PING a1.weave.local (10.128.0.2) 56(84) bytes of data.
|
||||
--- a1.weave.local ping statistics ---
|
||||
@@ -125,8 +131,8 @@ to each other.
|
||||
## Find out more
|
||||
|
||||
* [Documentation homepage](http://docs.weave.works/weave/latest_release/)
|
||||
* [Getting Started Guides](http://weave.works/guides/)
|
||||
* [Features](http://docs.weave.works/weave/latest_release/features.html)
|
||||
* [Automatic Discovery with WeaveDNS](http://docs.weave.works/weave/latest_release/weavedns.html)
|
||||
* [Troubleshooting](http://docs.weave.works/weave/latest_release/troubleshooting.html)
|
||||
* [Building](http://docs.weave.works/weave/latest_release/building.html)
|
||||
* [How it works](http://docs.weave.works/weave/latest_release/how-it-works.html)
|
||||
|
||||
@@ -26,6 +26,7 @@ dependencies:
|
||||
docker save weaveworks/weave-build >$WEAVE_BUILD;
|
||||
fi
|
||||
post:
|
||||
- sudo apt-get update
|
||||
- sudo apt-get install bc
|
||||
- pip install requests
|
||||
- curl https://sdk.cloud.google.com | bash
|
||||
|
||||
+9
-3
@@ -2,6 +2,7 @@ package ipam
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/weaveworks/weave/ipam/address"
|
||||
)
|
||||
|
||||
@@ -42,9 +43,14 @@ func (g *allocate) Try(alloc *Allocator) bool {
|
||||
}
|
||||
|
||||
// out of space
|
||||
if donor, err := alloc.ring.ChoosePeerToAskForSpace(g.r.Start, g.r.End); err == nil {
|
||||
alloc.debugln("Decided to ask peer", donor, "for space in range", g.r)
|
||||
alloc.sendSpaceRequest(donor, g.r)
|
||||
donors := alloc.ring.ChoosePeersToAskForSpace(g.r.Start, g.r.End)
|
||||
for _, donor := range donors {
|
||||
if err := alloc.sendSpaceRequest(donor, g.r); err != nil {
|
||||
alloc.debugln("Problem asking peer", donor, "for space:", err)
|
||||
} else {
|
||||
alloc.debugln("Decided to ask peer", donor, "for space in range", g.r)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
|
||||
+4
-5
@@ -202,10 +202,9 @@ func (alloc *Allocator) Lookup(ident string, r address.Range) (address.Address,
|
||||
}
|
||||
|
||||
// Claim an address that we think we should own (Sync)
|
||||
func (alloc *Allocator) Claim(ident string, addr address.Address, cancelChan <-chan bool) error {
|
||||
func (alloc *Allocator) Claim(ident string, addr address.Address) error {
|
||||
resultChan := make(chan error)
|
||||
op := &claim{resultChan: resultChan, ident: ident, addr: addr,
|
||||
hasBeenCancelled: hasBeenCancelled(cancelChan)}
|
||||
op := &claim{resultChan: resultChan, ident: ident, addr: addr}
|
||||
alloc.doOperation(op, &alloc.pendingClaims)
|
||||
return <-resultChan
|
||||
}
|
||||
@@ -575,14 +574,14 @@ func (alloc *Allocator) propose() {
|
||||
alloc.gossip.GossipBroadcast(alloc.Gossip())
|
||||
}
|
||||
|
||||
func (alloc *Allocator) sendSpaceRequest(dest router.PeerName, r address.Range) {
|
||||
func (alloc *Allocator) sendSpaceRequest(dest router.PeerName, r address.Range) error {
|
||||
buf := new(bytes.Buffer)
|
||||
enc := gob.NewEncoder(buf)
|
||||
if err := enc.Encode(r); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
msg := router.Concat([]byte{msgSpaceRequest}, buf.Bytes())
|
||||
alloc.gossip.GossipUnicast(dest, msg)
|
||||
return alloc.gossip.GossipUnicast(dest, msg)
|
||||
}
|
||||
|
||||
func (alloc *Allocator) sendRingUpdate(dest router.PeerName) {
|
||||
|
||||
@@ -143,7 +143,7 @@ func TestAllocatorClaim(t *testing.T) {
|
||||
alloc.claimRingForTesting()
|
||||
addr1, _ := address.ParseIP(testAddr1)
|
||||
|
||||
err := alloc.Claim(container3, addr1, nil)
|
||||
err := alloc.Claim(container3, addr1)
|
||||
wt.AssertNoErr(t, err)
|
||||
// Check we get this address back if we try an allocate
|
||||
addr3, _ := alloc.Allocate(container3, subnet, nil)
|
||||
@@ -168,7 +168,7 @@ func TestCancel(t *testing.T) {
|
||||
CIDR = "10.0.1.7/26"
|
||||
)
|
||||
|
||||
router := TestGossipRouter{make(map[router.PeerName]chan gossipMessage), 0.0}
|
||||
router := TestGossipRouter{make(map[router.PeerName]chan interface{}), 0.0}
|
||||
|
||||
alloc1, subnet := makeAllocator("01:00:00:02:00:00", CIDR, 2)
|
||||
alloc1.SetInterfaces(router.connect(alloc1.ourName, alloc1))
|
||||
@@ -256,13 +256,17 @@ func TestTransfer(t *testing.T) {
|
||||
wt.AssertTrue(t, err == nil, "Failed to get address")
|
||||
|
||||
router.GossipBroadcast(alloc2.Gossip())
|
||||
router.flush()
|
||||
router.GossipBroadcast(alloc3.Gossip())
|
||||
router.flush()
|
||||
router.removePeer(alloc2.ourName)
|
||||
router.removePeer(alloc3.ourName)
|
||||
alloc2.Stop()
|
||||
alloc3.Stop()
|
||||
router.flush()
|
||||
wt.AssertSuccess(t, alloc1.AdminTakeoverRanges(alloc2.ourName.String()))
|
||||
wt.AssertSuccess(t, alloc1.AdminTakeoverRanges(alloc3.ourName.String()))
|
||||
router.flush()
|
||||
|
||||
wt.AssertEquals(t, alloc1.NumFreeAddresses(subnet), address.Offset(1022))
|
||||
|
||||
@@ -282,7 +286,8 @@ func TestFakeRouterSimple(t *testing.T) {
|
||||
alloc1 := allocs[0]
|
||||
//alloc2 := allocs[1]
|
||||
|
||||
alloc1.Allocate("foo", subnet, nil)
|
||||
_, err := alloc1.Allocate("foo", subnet, nil)
|
||||
wt.AssertTrue(t, err == nil, "Failed to get address")
|
||||
}
|
||||
|
||||
func TestAllocatorFuzz(t *testing.T) {
|
||||
|
||||
+24
-16
@@ -3,28 +3,35 @@ package ipam
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/weaveworks/weave/common"
|
||||
"github.com/weaveworks/weave/ipam/address"
|
||||
"github.com/weaveworks/weave/router"
|
||||
)
|
||||
|
||||
type claim struct {
|
||||
resultChan chan<- error
|
||||
ident string
|
||||
addr address.Address
|
||||
hasBeenCancelled func() bool
|
||||
resultChan chan<- error
|
||||
ident string
|
||||
addr address.Address
|
||||
}
|
||||
|
||||
func (c *claim) sendResult(result error) {
|
||||
// Make sure we only send a result once, since listener stops listening after that
|
||||
if c.resultChan != nil {
|
||||
c.resultChan <- result
|
||||
close(c.resultChan)
|
||||
c.resultChan = nil
|
||||
}
|
||||
if result != nil {
|
||||
common.Error.Println("[allocator] " + result.Error())
|
||||
}
|
||||
}
|
||||
|
||||
// Try returns true for success (or failure), false if we need to try again later
|
||||
func (c *claim) Try(alloc *Allocator) bool {
|
||||
if (c.hasBeenCancelled)() {
|
||||
c.Cancel()
|
||||
return true
|
||||
}
|
||||
|
||||
if !alloc.ring.Contains(c.addr) {
|
||||
// Address not within our universe; assume user knows what they are doing
|
||||
alloc.infof("Ignored address %s claimed by %s - not in our universe\n", c.addr, c.ident)
|
||||
c.resultChan <- nil
|
||||
c.sendResult(nil)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -34,6 +41,7 @@ func (c *claim) Try(alloc *Allocator) bool {
|
||||
owner := alloc.ring.Owner(c.addr)
|
||||
if owner == router.UnknownPeerName {
|
||||
alloc.infof("Ring is empty; will try later.\n", c.addr, owner)
|
||||
c.sendResult(nil) // don't make the caller wait
|
||||
return false
|
||||
}
|
||||
if owner != alloc.ourName {
|
||||
@@ -41,34 +49,34 @@ func (c *claim) Try(alloc *Allocator) bool {
|
||||
if found {
|
||||
name = " (" + name + ")"
|
||||
}
|
||||
c.resultChan <- fmt.Errorf("address %s is owned by other peer %s%s", c.addr.String(), owner, name)
|
||||
c.sendResult(fmt.Errorf("address %s is owned by other peer %s%s", c.addr.String(), owner, name))
|
||||
return true
|
||||
}
|
||||
// We are the owner, check we haven't given it to another container
|
||||
existingIdent := alloc.findOwner(c.addr)
|
||||
if existingIdent == c.ident {
|
||||
// same identifier is claiming same address; that's OK
|
||||
c.resultChan <- nil
|
||||
c.sendResult(nil)
|
||||
return true
|
||||
}
|
||||
if existingIdent == "" {
|
||||
err := alloc.space.Claim(c.addr)
|
||||
if err != nil {
|
||||
c.resultChan <- err
|
||||
c.sendResult(err)
|
||||
return true
|
||||
}
|
||||
alloc.debugln("Claimed", c.addr, "for", c.ident)
|
||||
alloc.addOwned(c.ident, c.addr)
|
||||
c.resultChan <- nil
|
||||
c.sendResult(nil)
|
||||
return true
|
||||
}
|
||||
// Addr already owned by container on this machine
|
||||
c.resultChan <- fmt.Errorf("address %s is already owned by %s", c.addr.String(), existingIdent)
|
||||
c.sendResult(fmt.Errorf("address %s is already owned by %s", c.addr.String(), existingIdent))
|
||||
return true
|
||||
}
|
||||
|
||||
func (c *claim) Cancel() {
|
||||
c.resultChan <- fmt.Errorf("Operation cancelled.")
|
||||
c.sendResult(fmt.Errorf("Operation cancelled."))
|
||||
}
|
||||
|
||||
func (c *claim) String() string {
|
||||
|
||||
+1
-2
@@ -19,14 +19,13 @@ func badRequest(w http.ResponseWriter, err error) {
|
||||
// HandleHTTP wires up ipams HTTP endpoints to the provided mux.
|
||||
func (alloc *Allocator) HandleHTTP(router *mux.Router, defaultSubnet address.CIDR, dockerCli *docker.Client) {
|
||||
router.Methods("PUT").Path("/ip/{id}/{ip}").HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
closedChan := w.(http.CloseNotifier).CloseNotify()
|
||||
vars := mux.Vars(r)
|
||||
ident := vars["id"]
|
||||
ipStr := vars["ip"]
|
||||
if ip, err := address.ParseIP(ipStr); err != nil {
|
||||
badRequest(w, err)
|
||||
return
|
||||
} else if err := alloc.Claim(ident, ip, closedChan); err != nil {
|
||||
} else if err := alloc.Claim(ident, ip); err != nil {
|
||||
badRequest(w, fmt.Errorf("Unable to claim: %s", err))
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package paxos
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/weaveworks/weave/router"
|
||||
)
|
||||
|
||||
|
||||
@@ -2,10 +2,11 @@ package paxos
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/weaveworks/weave/router"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/weave/router"
|
||||
)
|
||||
|
||||
type TestNode struct {
|
||||
|
||||
+28
-19
@@ -348,9 +348,9 @@ func (r *Ring) String() string {
|
||||
return buffer.String()
|
||||
}
|
||||
|
||||
// ReportFree is used by the allocator to tell the ring
|
||||
// how many free ips are in a given range, so that ChoosePeerToAskForSpace
|
||||
// can make more intelligent decisions.
|
||||
// ReportFree is used by the allocator to tell the ring how many free
|
||||
// ips are in a given range, so that ChoosePeersToAskForSpace can make
|
||||
// more intelligent decisions.
|
||||
func (r *Ring) ReportFree(freespace map[address.Address]address.Offset) {
|
||||
r.assertInvariants()
|
||||
defer r.assertInvariants()
|
||||
@@ -392,9 +392,20 @@ func (r *Ring) ReportFree(freespace map[address.Address]address.Offset) {
|
||||
}
|
||||
}
|
||||
|
||||
// ChoosePeerToAskForSpace chooses a weighted-random peer to ask
|
||||
// for space in the range [start, end). Assumes start<end.
|
||||
func (r *Ring) ChoosePeerToAskForSpace(start, end address.Address) (result router.PeerName, err error) {
|
||||
type weightedPeer struct {
|
||||
weight float64
|
||||
peername router.PeerName
|
||||
}
|
||||
type weightedPeers []weightedPeer
|
||||
|
||||
// Note Less is using > so that bigger weights sort earlier
|
||||
func (ws weightedPeers) Less(i, j int) bool { return ws[i].weight > ws[j].weight }
|
||||
func (ws weightedPeers) Len() int { return len(ws) }
|
||||
func (ws weightedPeers) Swap(i, j int) { ws[i], ws[j] = ws[j], ws[i] }
|
||||
|
||||
// ChoosePeersToAskForSpace returns all peers we can ask for space in
|
||||
// the range [start, end), in weighted-random order. Assumes start<end.
|
||||
func (r *Ring) ChoosePeersToAskForSpace(start, end address.Address) []router.PeerName {
|
||||
var (
|
||||
sum address.Offset
|
||||
totalSpacePerPeer = make(map[router.PeerName]address.Offset) // Compute total free space per peer
|
||||
@@ -423,21 +434,19 @@ func (r *Ring) ChoosePeerToAskForSpace(start, end address.Address) (result route
|
||||
sum += entry.Free
|
||||
}
|
||||
|
||||
if sum == 0 {
|
||||
err = ErrNoFreeSpace
|
||||
return
|
||||
}
|
||||
|
||||
// Pick random peer, weighted by total free space
|
||||
rn := rand.Int63n(int64(sum))
|
||||
// Compute weighted random numbers, then sort.
|
||||
// This isn't perfect, e.g. an item with weight 2 will get chosen more than
|
||||
// twice as often as an item with weight 1, but it's good enough for our purposes.
|
||||
ws := make(weightedPeers, 0, len(totalSpacePerPeer))
|
||||
for peername, space := range totalSpacePerPeer {
|
||||
rn -= int64(space)
|
||||
if rn < 0 {
|
||||
return peername, nil
|
||||
}
|
||||
ws = append(ws, weightedPeer{weight: float64(space) * rand.Float64(), peername: peername})
|
||||
}
|
||||
|
||||
panic("Should never reach this point")
|
||||
sort.Sort(ws)
|
||||
result := make([]router.PeerName, len(ws))
|
||||
for i, wp := range ws {
|
||||
result[i] = wp.peername
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func (r *Ring) PickPeerForTransfer() router.PeerName {
|
||||
|
||||
+20
-17
@@ -345,39 +345,42 @@ func TestGossip(t *testing.T) {
|
||||
func TestFindFree(t *testing.T) {
|
||||
ring1 := New(start, end, peer1name)
|
||||
|
||||
_, err := ring1.ChoosePeerToAskForSpace(start, end)
|
||||
wt.AssertTrue(t, err == ErrNoFreeSpace, "Expected ErrNoFreeSpace")
|
||||
peers := ring1.ChoosePeersToAskForSpace(start, end)
|
||||
wt.AssertTrue(t, len(peers) == 0, "Expected no peers")
|
||||
|
||||
ring1.Entries = []*entry{{Token: start, Peer: peer1name}}
|
||||
_, err = ring1.ChoosePeerToAskForSpace(start, end)
|
||||
wt.AssertTrue(t, err == ErrNoFreeSpace, "Expected ErrNoFreeSpace")
|
||||
peers = ring1.ChoosePeersToAskForSpace(start, end)
|
||||
wt.AssertTrue(t, len(peers) == 0, "Expected no peers")
|
||||
|
||||
// We shouldn't return outselves
|
||||
ring1.ReportFree(map[address.Address]address.Offset{start: 10})
|
||||
_, err = ring1.ChoosePeerToAskForSpace(start, end)
|
||||
wt.AssertTrue(t, err == ErrNoFreeSpace, "Expected ErrNoFreeSpace")
|
||||
peers = ring1.ChoosePeersToAskForSpace(start, end)
|
||||
wt.AssertTrue(t, len(peers) == 0, "Expected no peers")
|
||||
|
||||
ring1.Entries = []*entry{{Token: start, Peer: peer1name, Free: 1},
|
||||
{Token: middle, Peer: peer1name, Free: 1}}
|
||||
_, err = ring1.ChoosePeerToAskForSpace(start, end)
|
||||
wt.AssertTrue(t, err == ErrNoFreeSpace, "Expected ErrNoFreeSpace")
|
||||
peers = ring1.ChoosePeersToAskForSpace(start, end)
|
||||
wt.AssertTrue(t, len(peers) == 0, "Expected no peers")
|
||||
ring1.assertInvariants()
|
||||
|
||||
// We should return others
|
||||
ring1.Entries = []*entry{{Token: start, Peer: peer2name, Free: 1}}
|
||||
peer, err := ring1.ChoosePeerToAskForSpace(start, end)
|
||||
wt.AssertSuccess(t, err)
|
||||
wt.AssertEquals(t, peer, peer2name)
|
||||
peers = ring1.ChoosePeersToAskForSpace(start, end)
|
||||
wt.AssertTrue(t, len(peers) == 1, "Expected one peer")
|
||||
wt.AssertEquals(t, peers[0], peer2name)
|
||||
|
||||
ring1.Entries = []*entry{{Token: start, Peer: peer2name, Free: 1},
|
||||
{Token: middle, Peer: peer3name, Free: 1}}
|
||||
peer, err = ring1.ChoosePeerToAskForSpace(start, middle)
|
||||
wt.AssertSuccess(t, err)
|
||||
wt.AssertEquals(t, peer, peer2name)
|
||||
peers = ring1.ChoosePeersToAskForSpace(start, middle)
|
||||
wt.AssertTrue(t, len(peers) == 1, "Expected one peer")
|
||||
wt.AssertEquals(t, peers[0], peer2name)
|
||||
|
||||
peer, err = ring1.ChoosePeerToAskForSpace(middle, end)
|
||||
wt.AssertSuccess(t, err)
|
||||
wt.AssertEquals(t, peer, peer3name)
|
||||
peers = ring1.ChoosePeersToAskForSpace(middle, end)
|
||||
wt.AssertTrue(t, len(peers) == 1, "Expected one peer")
|
||||
wt.AssertEquals(t, peers[0], peer3name)
|
||||
|
||||
peers = ring1.ChoosePeersToAskForSpace(start, end)
|
||||
wt.AssertTrue(t, len(peers) == 2, "Expected two peers")
|
||||
ring1.assertInvariants()
|
||||
}
|
||||
|
||||
|
||||
+58
-36
@@ -200,33 +200,47 @@ func AssertNothingSentErr(t *testing.T, ch <-chan error) {
|
||||
}
|
||||
|
||||
// Router to convey gossip from one gossiper to another, for testing
|
||||
type gossipMessage struct {
|
||||
isUnicast bool
|
||||
sender *router.PeerName
|
||||
buf []byte // for unicast
|
||||
data router.GossipData // for broadcast
|
||||
exitChan chan bool
|
||||
type unicastMessage struct {
|
||||
sender router.PeerName
|
||||
buf []byte
|
||||
}
|
||||
type broadcastMessage struct {
|
||||
data router.GossipData
|
||||
}
|
||||
type exitMessage struct {
|
||||
exitChan chan struct{}
|
||||
}
|
||||
type flushMessage struct {
|
||||
flushChan chan struct{}
|
||||
}
|
||||
|
||||
type TestGossipRouter struct {
|
||||
gossipChans map[router.PeerName]chan gossipMessage
|
||||
gossipChans map[router.PeerName]chan interface{}
|
||||
loss float32 // 0.0 means no loss
|
||||
}
|
||||
|
||||
func (grouter *TestGossipRouter) GossipBroadcast(update router.GossipData) error {
|
||||
for _, gossipChan := range grouter.gossipChans {
|
||||
select {
|
||||
case gossipChan <- gossipMessage{data: update}:
|
||||
case gossipChan <- broadcastMessage{data: update}:
|
||||
default: // drop the message if we cannot send it
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (grouter *TestGossipRouter) flush() {
|
||||
for _, gossipChan := range grouter.gossipChans {
|
||||
flushChan := make(chan struct{})
|
||||
gossipChan <- flushMessage{flushChan: flushChan}
|
||||
<-flushChan
|
||||
}
|
||||
}
|
||||
|
||||
func (grouter *TestGossipRouter) removePeer(peer router.PeerName) {
|
||||
gossipChan := grouter.gossipChans[peer]
|
||||
resultChan := make(chan bool)
|
||||
gossipChan <- gossipMessage{exitChan: resultChan}
|
||||
resultChan := make(chan struct{})
|
||||
gossipChan <- exitMessage{exitChan: resultChan}
|
||||
<-resultChan
|
||||
delete(grouter.gossipChans, peer)
|
||||
}
|
||||
@@ -236,39 +250,47 @@ type TestGossipRouterClient struct {
|
||||
sender router.PeerName
|
||||
}
|
||||
|
||||
func (grouter *TestGossipRouter) connect(sender router.PeerName, gossiper router.Gossiper) router.Gossip {
|
||||
gossipChan := make(chan gossipMessage, 100)
|
||||
func (grouter *TestGossipRouter) run(gossiper router.Gossiper, gossipChan chan interface{}) {
|
||||
gossipTimer := time.Tick(10 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case gossip := <-gossipChan:
|
||||
switch message := gossip.(type) {
|
||||
case exitMessage:
|
||||
close(message.exitChan)
|
||||
return
|
||||
|
||||
go func() {
|
||||
gossipTimer := time.Tick(10 * time.Second)
|
||||
for {
|
||||
select {
|
||||
case message := <-gossipChan:
|
||||
if message.exitChan != nil {
|
||||
message.exitChan <- true
|
||||
return
|
||||
}
|
||||
case flushMessage:
|
||||
close(message.flushChan)
|
||||
|
||||
case unicastMessage:
|
||||
if rand.Float32() > (1.0 - grouter.loss) {
|
||||
continue
|
||||
}
|
||||
if err := gossiper.OnGossipUnicast(message.sender, message.buf); err != nil {
|
||||
panic(fmt.Sprintf("Error doing gossip unicast to %s: %s", message.sender, err))
|
||||
}
|
||||
|
||||
if message.isUnicast {
|
||||
if err := gossiper.OnGossipUnicast(*message.sender, message.buf); err != nil {
|
||||
panic(fmt.Sprintf("Error doing gossip unicast to %s: %s", sender, err))
|
||||
}
|
||||
} else {
|
||||
for _, msg := range message.data.Encode() {
|
||||
if _, err := gossiper.OnGossipBroadcast(msg); err != nil {
|
||||
panic(fmt.Sprintf("Error doing gossip broadcast to %s: %s", sender, err))
|
||||
}
|
||||
case broadcastMessage:
|
||||
if rand.Float32() > (1.0 - grouter.loss) {
|
||||
continue
|
||||
}
|
||||
for _, msg := range message.data.Encode() {
|
||||
if _, err := gossiper.OnGossipBroadcast(msg); err != nil {
|
||||
panic(fmt.Sprintf("Error doing gossip broadcast: %s", err))
|
||||
}
|
||||
}
|
||||
case <-gossipTimer:
|
||||
grouter.GossipBroadcast(gossiper.Gossip())
|
||||
}
|
||||
case <-gossipTimer:
|
||||
grouter.GossipBroadcast(gossiper.Gossip())
|
||||
}
|
||||
}()
|
||||
}
|
||||
}
|
||||
|
||||
func (grouter *TestGossipRouter) connect(sender router.PeerName, gossiper router.Gossiper) router.Gossip {
|
||||
gossipChan := make(chan interface{}, 100)
|
||||
|
||||
go grouter.run(gossiper, gossipChan)
|
||||
|
||||
grouter.gossipChans[sender] = gossipChan
|
||||
return TestGossipRouterClient{grouter, sender}
|
||||
@@ -276,7 +298,7 @@ func (grouter *TestGossipRouter) connect(sender router.PeerName, gossiper router
|
||||
|
||||
func (client TestGossipRouterClient) GossipUnicast(dstPeerName router.PeerName, buf []byte) error {
|
||||
select {
|
||||
case client.router.gossipChans[dstPeerName] <- gossipMessage{isUnicast: true, sender: &client.sender, buf: buf}:
|
||||
case client.router.gossipChans[dstPeerName] <- unicastMessage{sender: client.sender, buf: buf}:
|
||||
default: // drop the message if we cannot send it
|
||||
common.Error.Printf("Dropping message")
|
||||
}
|
||||
@@ -289,7 +311,7 @@ func (client TestGossipRouterClient) GossipBroadcast(update router.GossipData) e
|
||||
|
||||
func makeNetworkOfAllocators(size int, cidr string) ([]*Allocator, TestGossipRouter, address.Range) {
|
||||
|
||||
gossipRouter := TestGossipRouter{make(map[router.PeerName]chan gossipMessage), 0.0}
|
||||
gossipRouter := TestGossipRouter{make(map[router.PeerName]chan interface{}), 0.0}
|
||||
allocs := make([]*Allocator, size)
|
||||
var subnet address.Range
|
||||
|
||||
@@ -303,7 +325,7 @@ func makeNetworkOfAllocators(size int, cidr string) ([]*Allocator, TestGossipRou
|
||||
}
|
||||
|
||||
gossipRouter.GossipBroadcast(allocs[size-1].Gossip())
|
||||
time.Sleep(1000 * time.Millisecond)
|
||||
gossipRouter.flush()
|
||||
return allocs, gossipRouter, subnet
|
||||
}
|
||||
|
||||
|
||||
@@ -395,6 +395,9 @@ func (s *DNSServer) notUsHandler(proto dnsProtocol) dns.HandlerFunc {
|
||||
}
|
||||
Debug.Printf("[dns msgid %d] Given answer by %s for query %s",
|
||||
r.MsgHdr.Id, server, q.Name)
|
||||
if reply.Len() > maxLen {
|
||||
reply.Compress = true
|
||||
}
|
||||
w.WriteMsg(reply)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -3,12 +3,14 @@ package nameserver
|
||||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/miekg/dns"
|
||||
. "github.com/weaveworks/weave/common"
|
||||
"github.com/weaveworks/weave/ipam/address"
|
||||
wt "github.com/weaveworks/weave/testing"
|
||||
)
|
||||
|
||||
@@ -32,11 +34,12 @@ func TestUDPDNSServer(t *testing.T) {
|
||||
setupForTest(t)
|
||||
|
||||
const (
|
||||
successTestName = "test1.weave.local."
|
||||
failTestName = "fail.weave.local."
|
||||
nonLocalName = "weave.works."
|
||||
testAddr1 = "10.2.2.1"
|
||||
containerID = "somecontainer"
|
||||
successTestName = "test1.weave.local."
|
||||
failTestName = "fail.weave.local."
|
||||
compressedTestName = "compressed.weave.works."
|
||||
nonLocalName = "weave.works."
|
||||
testAddr1 = "10.2.2.1"
|
||||
containerID = "somecontainer"
|
||||
)
|
||||
testCIDR1 := testAddr1 + "/24"
|
||||
|
||||
@@ -72,6 +75,15 @@ func TestUDPDNSServer(t *testing.T) {
|
||||
m.Answer[0] = &dns.PTR{Hdr: dns.RR_Header{Name: m.Question[0].Name, Rrtype: dns.TypePTR, Class: dns.ClassINET, Ttl: 0}, Ptr: "ns1.google.com."}
|
||||
} else if q.Name == testRDNSfail && q.Qtype == dns.TypePTR {
|
||||
m.Rcode = dns.RcodeNameError
|
||||
} else if q.Name == compressedTestName {
|
||||
// Construct a response that is >512 when uncompressed, <512 when compressed
|
||||
header := makeHeader(m, &q, 300)
|
||||
for m.Len() <= minUDPSize {
|
||||
ip := address.Address(rand.Uint32()).IP4()
|
||||
m.Answer = append(m.Answer, &dns.A{Hdr: *header, A: ip})
|
||||
}
|
||||
m.Compress = true
|
||||
wt.AssertTrue(t, m.Len() <= minUDPSize, fmt.Sprintf("length: %d", m.Len()))
|
||||
}
|
||||
w.WriteMsg(m)
|
||||
}
|
||||
@@ -125,6 +137,9 @@ func TestUDPDNSServer(t *testing.T) {
|
||||
|
||||
assertExchange(t, testRDNSnonlocal, dns.TypePTR, testPort, 1, -1, 0)
|
||||
|
||||
_, r = assertExchange(t, compressedTestName, dns.TypeA, testPort, -1, -1, 0)
|
||||
wt.AssertTrue(t, r.Len() > minUDPSize, "unexpected message length")
|
||||
|
||||
// Not testing MDNS functionality of server here (yet), since it
|
||||
// needs two servers, each listening on its own address
|
||||
}
|
||||
|
||||
@@ -103,9 +103,11 @@ func (zone *ZoneDb) domainLookup(target string, lfun ZoneLookupFunc) (res []Zone
|
||||
for _, answer := range lanswers {
|
||||
r, err := remoteIdent.addIPToName(answer, now)
|
||||
if err != nil {
|
||||
zone.mx.Unlock()
|
||||
Warning.Printf("[zonedb] '%s' insertion for %s failed: %s", answer, target, err)
|
||||
return nil, err
|
||||
if _, ok := err.(DuplicateError); !ok {
|
||||
zone.mx.Unlock()
|
||||
Warning.Printf("[zonedb] '%s' insertion for %s failed: %s", answer, target, err)
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
uniq.add(r)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package net
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
@@ -10,11 +11,17 @@ const (
|
||||
sleepTime = 100 * time.Millisecond
|
||||
)
|
||||
|
||||
// Wait `wait` seconds for an interface to come up. Pass zero to check once
|
||||
// and return immediately, or a negative value to wait indefinitely.
|
||||
func EnsureInterface(ifaceName string, wait int) (iface *net.Interface, err error) {
|
||||
if iface, err = findInterface(ifaceName); err == nil || wait == 0 {
|
||||
return
|
||||
}
|
||||
for i := time.Duration(wait) * time.Second / sleepTime; err != nil && i > 0; i-- {
|
||||
i := int64(math.MaxInt64)
|
||||
if wait > 0 {
|
||||
i = int64(time.Duration(wait) * time.Second / sleepTime)
|
||||
}
|
||||
for ; err != nil && i > 0; i-- {
|
||||
time.Sleep(sleepTime)
|
||||
iface, err = findInterface(ifaceName)
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@ MAINTAINER Weaveworks Inc <help@weave.works>
|
||||
WORKDIR /home/weave
|
||||
ADD ./weavedns /home/weave/
|
||||
EXPOSE 53/udp
|
||||
ENTRYPOINT ["/home/weave/weavedns", "-wait", "20"]
|
||||
ENTRYPOINT ["/home/weave/weavedns"]
|
||||
@@ -46,7 +46,7 @@ func main() {
|
||||
flag.StringVar(&ifaceName, "iface", "", "name of interface to use for multicast")
|
||||
flag.StringVar(&apiPath, "api", "unix:///var/run/docker.sock", "path to Docker API socket")
|
||||
flag.StringVar(&domain, "domain", weavedns.DefaultLocalDomain, "local domain (ie, 'weave.local.')")
|
||||
flag.IntVar(&wait, "wait", 0, "number of seconds to wait for interface to be created and come up")
|
||||
flag.IntVar(&wait, "wait", -1, "number of seconds to wait for interfaces to come up (0=don't wait, -1=wait forever)")
|
||||
flag.IntVar(&dnsPort, "dnsport", weavedns.DefaultServerPort, "port to listen to DNS requests")
|
||||
flag.StringVar(&httpIfaceName, "httpiface", "", "interface on which to listen for HTTP requests (defaults to empty string which listens on all interfaces)")
|
||||
flag.IntVar(&httpPort, "httpport", weavedns.DefaultHTTPPort, "port to listen to HTTP requests")
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"code.google.com/p/getopt"
|
||||
"github.com/pborman/getopt"
|
||||
. "github.com/weaveworks/weave/common"
|
||||
"github.com/weaveworks/weave/proxy"
|
||||
)
|
||||
|
||||
@@ -2,4 +2,4 @@ FROM scratch
|
||||
MAINTAINER Weaveworks Inc <help@weave.works>
|
||||
WORKDIR /home/weave
|
||||
ADD ./weaver /home/weave/
|
||||
ENTRYPOINT ["/home/weave/weaver", "-wait", "20"]
|
||||
ENTRYPOINT ["/home/weave/weaver"]
|
||||
+2
-2
@@ -11,8 +11,8 @@ import (
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"code.google.com/p/gopacket/layers"
|
||||
"github.com/davecheney/profile"
|
||||
"github.com/google/gopacket/layers"
|
||||
"github.com/gorilla/mux"
|
||||
. "github.com/weaveworks/weave/common"
|
||||
"github.com/weaveworks/weave/common/docker"
|
||||
@@ -64,7 +64,7 @@ func main() {
|
||||
flag.StringVar(&routerName, "name", "", "name of router (defaults to MAC of interface)")
|
||||
flag.StringVar(&nickName, "nickname", "", "nickname of peer (defaults to hostname)")
|
||||
flag.StringVar(&password, "password", "", "network password")
|
||||
flag.IntVar(&wait, "wait", 0, "number of seconds to wait for interface to be created and come up (0 = don't wait)")
|
||||
flag.IntVar(&wait, "wait", -1, "number of seconds to wait for interface to come up (0=don't wait, -1=wait forever)")
|
||||
flag.BoolVar(&debug, "debug", false, "enable debug logging")
|
||||
flag.BoolVar(&pktdebug, "pktdebug", false, "enable per-packet debug logging")
|
||||
flag.StringVar(&prof, "profile", "", "enable profiling and write profiles to given path")
|
||||
|
||||
+14
-18
@@ -6,33 +6,29 @@ import (
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/weaveworks/weave/net"
|
||||
weavenet "github.com/weaveworks/weave/net"
|
||||
"github.com/weaveworks/weave/proxy"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) <= 1 {
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
args := os.Args[1:]
|
||||
signalWait := 20
|
||||
if args[0] == "-s" {
|
||||
signalWait = 0
|
||||
args = args[1:]
|
||||
}
|
||||
interfaceWait := 20 - signalWait
|
||||
|
||||
usr2 := make(chan os.Signal)
|
||||
signal.Notify(usr2, syscall.SIGUSR2)
|
||||
select {
|
||||
case <-usr2:
|
||||
case <-time.After(time.Duration(signalWait) * time.Second):
|
||||
if len(args) > 0 && args[0] == "-s" {
|
||||
args = args[1:]
|
||||
} else {
|
||||
usr2 := make(chan os.Signal)
|
||||
signal.Notify(usr2, syscall.SIGUSR2)
|
||||
<-usr2
|
||||
}
|
||||
_, err := net.EnsureInterface("ethwe", interfaceWait)
|
||||
|
||||
_, err := weavenet.EnsureInterface("ethwe", -1)
|
||||
checkErr(err)
|
||||
|
||||
if len(args) == 0 {
|
||||
checkErr(proxy.ErrNoCommandSpecified)
|
||||
}
|
||||
|
||||
binary, err := exec.LookPath(args[0])
|
||||
checkErr(err)
|
||||
|
||||
|
||||
+8
-1
@@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
|
||||
@@ -22,7 +23,13 @@ func callWeave(args ...string) ([]byte, error) {
|
||||
args = append([]string{"--local"}, args...)
|
||||
Debug.Print("Calling weave", args)
|
||||
cmd := exec.Command("./weave", args...)
|
||||
cmd.Env = []string{"PROCFS=/hostproc", "PATH=/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"}
|
||||
cmd.Env = []string{
|
||||
"PATH=/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
||||
"PROCFS=/hostproc",
|
||||
}
|
||||
if bridge := os.Getenv("DOCKER_BRIDGE"); bridge != "" {
|
||||
cmd.Env = append(cmd.Env, fmt.Sprintf("DOCKER_BRIDGE=%s", bridge))
|
||||
}
|
||||
out, err := cmd.CombinedOutput()
|
||||
return out, err
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package proxy
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
@@ -13,6 +14,12 @@ import (
|
||||
"github.com/weaveworks/weave/nameserver"
|
||||
)
|
||||
|
||||
const MaxDockerHostname = 64
|
||||
|
||||
var (
|
||||
ErrNoCommandSpecified = errors.New("No command specified")
|
||||
)
|
||||
|
||||
type createContainerInterceptor struct{ proxy *Proxy }
|
||||
|
||||
type createContainerRequestBody struct {
|
||||
@@ -21,6 +28,17 @@ type createContainerRequestBody struct {
|
||||
MacAddress string `json:"MacAddress,omitempty" yaml:"MacAddress,omitempty"`
|
||||
}
|
||||
|
||||
// ErrNoSuchImage replaces docker.NoSuchImage, which does not contain the image
|
||||
// name, which in turn breaks docker clients post 1.7.0 since they expect the
|
||||
// image name to be present in errors.
|
||||
type ErrNoSuchImage struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (err *ErrNoSuchImage) Error() string {
|
||||
return "No such image: " + err.Name
|
||||
}
|
||||
|
||||
func (i *createContainerInterceptor) InterceptRequest(r *http.Request) error {
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
@@ -33,15 +51,17 @@ func (i *createContainerInterceptor) InterceptRequest(r *http.Request) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if cidrs, ok := i.proxy.weaveCIDRsFromConfig(container.Config); ok {
|
||||
if cidrs, err := i.proxy.weaveCIDRsFromConfig(container.Config, container.HostConfig); err != nil {
|
||||
Info.Printf("Ignoring container due to %s", err)
|
||||
} else {
|
||||
Info.Printf("Creating container with WEAVE_CIDR \"%s\"", strings.Join(cidrs, " "))
|
||||
if container.HostConfig == nil {
|
||||
container.HostConfig = &docker.HostConfig{}
|
||||
}
|
||||
container.HostConfig.VolumesFrom = append(container.HostConfig.VolumesFrom, "weaveproxy")
|
||||
if container.Config == nil {
|
||||
container.Config = &docker.Config{}
|
||||
}
|
||||
i.addWeaveWaitVolume(container.HostConfig)
|
||||
if err := i.setWeaveWaitEntrypoint(container.Config); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -60,10 +80,24 @@ func (i *createContainerInterceptor) InterceptRequest(r *http.Request) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *createContainerInterceptor) addWeaveWaitVolume(hostConfig *docker.HostConfig) {
|
||||
var binds []string
|
||||
for _, bind := range hostConfig.Binds {
|
||||
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", i.proxy.weaveWaitVolume))
|
||||
}
|
||||
|
||||
func (i *createContainerInterceptor) setWeaveWaitEntrypoint(container *docker.Config) error {
|
||||
if len(container.Entrypoint) == 0 {
|
||||
image, err := i.proxy.client.InspectImage(container.Image)
|
||||
if err != nil {
|
||||
if err == docker.ErrNoSuchImage {
|
||||
return &ErrNoSuchImage{container.Image}
|
||||
} else if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -76,7 +110,14 @@ func (i *createContainerInterceptor) setWeaveWaitEntrypoint(container *docker.Co
|
||||
}
|
||||
}
|
||||
|
||||
container.Entrypoint = append(weaveWaitEntrypoint, container.Entrypoint...)
|
||||
if len(container.Entrypoint) == 0 && len(container.Cmd) == 0 {
|
||||
return ErrNoCommandSpecified
|
||||
}
|
||||
|
||||
if len(container.Entrypoint) == 0 || container.Entrypoint[0] != weaveWaitEntrypoint[0] {
|
||||
container.Entrypoint = append(weaveWaitEntrypoint, container.Entrypoint...)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -94,9 +135,14 @@ func (i *createContainerInterceptor) setWeaveDNS(container *createContainerReque
|
||||
|
||||
name := r.URL.Query().Get("name")
|
||||
if container.Hostname == "" && name != "" {
|
||||
container.Hostname = name
|
||||
// Strip trailing period because it's unusual to see it used on the end of a host name
|
||||
container.Domainname = strings.TrimSuffix(dnsDomain, ".")
|
||||
trimmedDNSDomain := strings.TrimSuffix(dnsDomain, ".")
|
||||
if len(name)+1+len(trimmedDNSDomain) > MaxDockerHostname {
|
||||
Warning.Printf("Container name [%s] too long to be used as hostname", name)
|
||||
} else {
|
||||
container.Hostname = name
|
||||
container.Domainname = trimmedDNSDomain
|
||||
}
|
||||
}
|
||||
|
||||
if len(container.HostConfig.DNSSearch) == 0 {
|
||||
|
||||
@@ -29,7 +29,11 @@ func (i *createExecInterceptor) InterceptRequest(r *http.Request) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if cidrs, ok := i.proxy.weaveCIDRsFromConfig(container.Config); ok {
|
||||
_, hasWeaveWait := container.Volumes["/w"]
|
||||
cidrs, err := i.proxy.weaveCIDRsFromConfig(container.Config, container.HostConfig)
|
||||
if err != nil {
|
||||
Info.Printf("Ignoring container %s due to %s", container.ID, err)
|
||||
} else if hasWeaveWait {
|
||||
Info.Printf("Exec in container %s with WEAVE_CIDR \"%s\"", container.ID, strings.Join(cidrs, " "))
|
||||
cmd := append(weaveWaitEntrypoint, "-s")
|
||||
options.Cmd = append(cmd, options.Cmd...)
|
||||
|
||||
+50
-8
@@ -2,6 +2,8 @@ package proxy
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
@@ -22,14 +24,18 @@ var (
|
||||
containerCreateRegexp = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/create$")
|
||||
containerStartRegexp = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/[^/]*/(re)?start$")
|
||||
execCreateRegexp = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/[^/]*/exec$")
|
||||
|
||||
ErrWeaveCIDRNone = errors.New("WEAVE_CIDR=none")
|
||||
ErrNoDefaultIPAM = errors.New("--no-default-ipam option")
|
||||
)
|
||||
|
||||
type Proxy struct {
|
||||
Config
|
||||
|
||||
dial func() (net.Conn, error)
|
||||
client *docker.Client
|
||||
dockerBridgeIP string
|
||||
dial func() (net.Conn, error)
|
||||
client *docker.Client
|
||||
dockerBridgeIP string
|
||||
weaveWaitVolume string
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
@@ -75,14 +81,41 @@ func NewProxy(c Config) (*Proxy, error) {
|
||||
Error.Fatalf("Could not configure tls for proxy: %s", err)
|
||||
}
|
||||
|
||||
p.client, err = docker.NewClient(p.DockerAddr)
|
||||
// We pin the protocol version to 1.15 (which corresponds to Docker 1.3.x;
|
||||
// the earliest version supported by weave) in order to insulate ourselves
|
||||
// from breaking changes to the API, as happened in 1.20 (Docker 1.8.0) when
|
||||
// the presentation of volumes changed in inspect.
|
||||
p.client, err = docker.NewVersionedClient(p.DockerAddr, "1.15")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = p.findWeaveWaitVolume(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
func (proxy *Proxy) findWeaveWaitVolume() error {
|
||||
container, err := proxy.client.InspectContainer("weaveproxy")
|
||||
if err != nil {
|
||||
return fmt.Errorf("Could not find the weavewait volume: %s", err)
|
||||
}
|
||||
|
||||
if container.Volumes == nil {
|
||||
return fmt.Errorf("Could not find the weavewait volume")
|
||||
}
|
||||
|
||||
volume, ok := container.Volumes["/w"]
|
||||
if !ok {
|
||||
return fmt.Errorf("Could not find the weavewait volume")
|
||||
}
|
||||
|
||||
proxy.weaveWaitVolume = volume
|
||||
return nil
|
||||
}
|
||||
|
||||
func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
Info.Printf("%s %s", r.Method, r.URL)
|
||||
path := r.URL.Path
|
||||
@@ -115,14 +148,23 @@ func (proxy *Proxy) ListenAndServe() error {
|
||||
return (&http.Server{Handler: proxy}).Serve(listener)
|
||||
}
|
||||
|
||||
func (proxy *Proxy) weaveCIDRsFromConfig(config *docker.Config) ([]string, bool) {
|
||||
func (proxy *Proxy) weaveCIDRsFromConfig(config *docker.Config, hostConfig *docker.HostConfig) ([]string, error) {
|
||||
if hostConfig != nil &&
|
||||
hostConfig.NetworkMode != "" &&
|
||||
hostConfig.NetworkMode != "default" &&
|
||||
hostConfig.NetworkMode != "bridge" {
|
||||
return nil, fmt.Errorf("--net option: %q", hostConfig.NetworkMode)
|
||||
}
|
||||
for _, e := range config.Env {
|
||||
if strings.HasPrefix(e, "WEAVE_CIDR=") {
|
||||
if e[11:] == "none" {
|
||||
return nil, false
|
||||
return nil, ErrWeaveCIDRNone
|
||||
}
|
||||
return strings.Fields(e[11:]), true
|
||||
return strings.Fields(e[11:]), nil
|
||||
}
|
||||
}
|
||||
return nil, !proxy.NoDefaultIPAM
|
||||
if proxy.NoDefaultIPAM {
|
||||
return nil, ErrNoDefaultIPAM
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
+23
-18
@@ -9,6 +9,7 @@ import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
"sync"
|
||||
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
. "github.com/weaveworks/weave/common"
|
||||
@@ -16,11 +17,10 @@ import (
|
||||
|
||||
func (proxy *Proxy) Intercept(i interceptor, w http.ResponseWriter, r *http.Request) {
|
||||
if err := i.InterceptRequest(r); err != nil {
|
||||
_, isNoSuchContainer := err.(*docker.NoSuchContainer)
|
||||
switch {
|
||||
case isNoSuchContainer:
|
||||
switch err.(type) {
|
||||
case *docker.NoSuchContainer:
|
||||
http.Error(w, err.Error(), http.StatusNotFound)
|
||||
case err == docker.ErrNoSuchImage:
|
||||
case *ErrNoSuchImage:
|
||||
http.Error(w, err.Error(), http.StatusNotFound)
|
||||
default:
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
@@ -95,25 +95,30 @@ func doRawStream(w http.ResponseWriter, resp *http.Response, client *httputil.Cl
|
||||
return
|
||||
}
|
||||
|
||||
upDone := make(chan struct{})
|
||||
downDone := make(chan struct{})
|
||||
go copyStream(down, io.MultiReader(rem, up), upDone)
|
||||
go copyStream(up, downBuf, downDone)
|
||||
<-upDone
|
||||
<-downDone
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(2)
|
||||
go copyStream(down, io.MultiReader(rem, up), &wg)
|
||||
go copyStream(up, downBuf, &wg)
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
func copyStream(dst io.Writer, src io.Reader, done chan struct{}) {
|
||||
defer close(done)
|
||||
type closeWriter interface {
|
||||
CloseWrite() error
|
||||
}
|
||||
|
||||
func copyStream(dst io.WriteCloser, src io.Reader, wg *sync.WaitGroup) {
|
||||
defer wg.Done()
|
||||
if _, err := io.Copy(dst, src); err != nil {
|
||||
Warning.Print(err)
|
||||
}
|
||||
if c, ok := dst.(interface {
|
||||
CloseWrite() error
|
||||
}); ok {
|
||||
if err := c.CloseWrite(); err != nil {
|
||||
Warning.Printf("Error closing connection: %s", err)
|
||||
}
|
||||
var err error
|
||||
if c, ok := dst.(closeWriter); ok {
|
||||
err = c.CloseWrite()
|
||||
} else {
|
||||
err = dst.Close()
|
||||
}
|
||||
if err != nil {
|
||||
Warning.Printf("Error closing connection: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,14 +16,18 @@ func (i *startContainerInterceptor) InterceptRequest(r *http.Request) error {
|
||||
}
|
||||
|
||||
func (i *startContainerInterceptor) InterceptResponse(r *http.Response) error {
|
||||
if r.StatusCode < 200 || r.StatusCode >= 300 { // Docker didn't do the start
|
||||
return nil
|
||||
}
|
||||
|
||||
container, err := inspectContainerInPath(i.proxy.client, r.Request.URL.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cidrs, ok := i.proxy.weaveCIDRsFromConfig(container.Config)
|
||||
if !ok {
|
||||
Debug.Print("No Weave CIDR, ignoring")
|
||||
cidrs, err := i.proxy.weaveCIDRsFromConfig(container.Config, container.HostConfig)
|
||||
if err != nil {
|
||||
Info.Printf("Ignoring container %s due to %s", container.ID, err)
|
||||
return nil
|
||||
}
|
||||
Info.Printf("Attaching container %s with WEAVE_CIDR \"%s\" to weave network", container.ID, strings.Join(cidrs, " "))
|
||||
|
||||
@@ -231,7 +231,7 @@ func (conn *LocalConnection) ReceivedHeartbeat(remoteUDPAddr *net.UDPAddr, connU
|
||||
if oldRemoteUDPAddr == nil {
|
||||
return conn.sendFastHeartbeats()
|
||||
} else if oldRemoteUDPAddr.String() != remoteUDPAddr.String() {
|
||||
log.Println("Peer", conn.remote, "moved from", old, "to", remoteUDPAddr)
|
||||
log.Println("Peer", conn.remote, "moved from", oldRemoteUDPAddr, "to", remoteUDPAddr)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
+4
-3
@@ -1,15 +1,16 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"code.google.com/p/go-bit/bit"
|
||||
"code.google.com/p/go.crypto/nacl/box"
|
||||
"code.google.com/p/go.crypto/nacl/secretbox"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/binary"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/andybalholm/go-bit"
|
||||
"golang.org/x/crypto/nacl/box"
|
||||
"golang.org/x/crypto/nacl/secretbox"
|
||||
)
|
||||
|
||||
func GenerateKeyPair() (publicKey, privateKey *[32]byte, err error) {
|
||||
|
||||
@@ -2,10 +2,11 @@ package router
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"code.google.com/p/gopacket"
|
||||
"code.google.com/p/gopacket/layers"
|
||||
"log"
|
||||
"net"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
)
|
||||
|
||||
type EthernetDecoder struct {
|
||||
|
||||
+3
-2
@@ -1,10 +1,11 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"code.google.com/p/gopacket"
|
||||
"code.google.com/p/gopacket/layers"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
)
|
||||
|
||||
type ForwardedFrame struct {
|
||||
|
||||
@@ -3,6 +3,7 @@ package router
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
)
|
||||
@@ -58,7 +59,12 @@ func (c *GossipChannel) deliverUnicast(srcName PeerName, origPayload []byte, dec
|
||||
return err
|
||||
}
|
||||
if c.ourself.Name != destName {
|
||||
return c.relayUnicast(destName, origPayload)
|
||||
if err := c.relayUnicast(destName, origPayload); err != nil {
|
||||
// just log errors from relayUnicast; a problem between us and destination
|
||||
// is not enough reason to break the connection from the source
|
||||
c.log(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
var payload []byte
|
||||
if err := dec.Decode(&payload); err != nil {
|
||||
@@ -160,15 +166,15 @@ func (c *GossipChannel) GossipBroadcast(update GossipData) error {
|
||||
return c.relayBroadcast(c.ourself.Name, update)
|
||||
}
|
||||
|
||||
func (c *GossipChannel) relayUnicast(dstPeerName PeerName, buf []byte) error {
|
||||
func (c *GossipChannel) relayUnicast(dstPeerName PeerName, buf []byte) (err error) {
|
||||
if relayPeerName, found := c.routes.UnicastAll(dstPeerName); !found {
|
||||
c.log("unknown relay destination:", dstPeerName)
|
||||
err = fmt.Errorf("unknown relay destination: %s", dstPeerName)
|
||||
} else if conn, found := c.ourself.ConnectionTo(relayPeerName); !found {
|
||||
c.log("unable to find connection to relay peer", relayPeerName)
|
||||
err = fmt.Errorf("unable to find connection to relay peer %s", relayPeerName)
|
||||
} else {
|
||||
conn.(ProtocolSender).SendProtocolMsg(ProtocolMsg{ProtocolGossipUnicast, buf})
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *GossipChannel) relayBroadcast(srcName PeerName, update GossipData) error {
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
wt "github.com/weaveworks/weave/testing"
|
||||
"testing"
|
||||
|
||||
wt "github.com/weaveworks/weave/testing"
|
||||
)
|
||||
|
||||
func TestFieldValidator(t *testing.T) {
|
||||
|
||||
@@ -6,8 +6,9 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
wt "github.com/weaveworks/weave/testing"
|
||||
"testing"
|
||||
|
||||
wt "github.com/weaveworks/weave/testing"
|
||||
)
|
||||
|
||||
// Add to peers a connection from peers.ourself to p
|
||||
|
||||
+2
-1
@@ -1,8 +1,9 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"code.google.com/p/gopacket/pcap"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/gopacket/pcap"
|
||||
)
|
||||
|
||||
type PcapIO struct {
|
||||
|
||||
@@ -2,9 +2,10 @@ package router
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
wt "github.com/weaveworks/weave/testing"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
wt "github.com/weaveworks/weave/testing"
|
||||
)
|
||||
|
||||
// TODO we should also test:
|
||||
|
||||
+10
-7
@@ -11,21 +11,22 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"code.google.com/p/gopacket/layers"
|
||||
"github.com/google/gopacket/layers"
|
||||
. "github.com/weaveworks/weave/common"
|
||||
)
|
||||
|
||||
const (
|
||||
macMaxAge = 10 * time.Minute // [1]
|
||||
tcpAcceptDelay = 1 * time.Millisecond // [2]
|
||||
macMaxAge = 10 * time.Minute // [1]
|
||||
acceptMaxTokens = 100 // [2]
|
||||
acceptTokenDelay = 100 * time.Millisecond // [3]
|
||||
)
|
||||
|
||||
// [1] should be greater than typical ARP cache expiries, i.e. > 3/2 *
|
||||
// /proc/sys/net/ipv4_neigh/*/base_reachable_time_ms on Linux
|
||||
|
||||
// [2] time to wait between accepting tcp connections. This guards
|
||||
// against brute-force attacks on the password when encryption is in
|
||||
// use. It is also a basic DoS defence.
|
||||
// [2] capacity of token bucket for rate limiting accepts
|
||||
|
||||
// [3] control rate at which new tokens are added to the bucket
|
||||
|
||||
type LogFrameFunc func(string, []byte, *layers.Ethernet)
|
||||
|
||||
@@ -50,6 +51,7 @@ type Router struct {
|
||||
gossipChannels GossipChannels
|
||||
TopologyGossip Gossip
|
||||
UDPListener *net.UDPConn
|
||||
acceptLimiter *TokenBucket
|
||||
}
|
||||
|
||||
type PacketSource interface {
|
||||
@@ -81,6 +83,7 @@ func NewRouter(config Config, name PeerName, nickName string) *Router {
|
||||
router.Routes = NewRoutes(router.Ourself, router.Peers)
|
||||
router.ConnectionMaker = NewConnectionMaker(router.Ourself, router.Peers, router.Port, router.PeerDiscovery)
|
||||
router.TopologyGossip = router.NewGossip("topology", router)
|
||||
router.acceptLimiter = NewTokenBucket(acceptMaxTokens, acceptTokenDelay)
|
||||
return router
|
||||
}
|
||||
|
||||
@@ -212,7 +215,7 @@ func (router *Router) listenTCP(localPort int) {
|
||||
continue
|
||||
}
|
||||
router.acceptTCP(tcpConn)
|
||||
time.Sleep(tcpAcceptDelay)
|
||||
router.acceptLimiter.Wait()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
type TokenBucket struct {
|
||||
capacity int64 // Maximum capacity of bucket
|
||||
tokenInterval time.Duration // Token replenishment rate
|
||||
refillDuration time.Duration // Time to refill from empty
|
||||
earliestUnspentToken time.Time
|
||||
}
|
||||
|
||||
func NewTokenBucket(capacity int64, tokenInterval time.Duration) *TokenBucket {
|
||||
tb := TokenBucket{
|
||||
capacity: capacity,
|
||||
tokenInterval: tokenInterval,
|
||||
refillDuration: tokenInterval * time.Duration(capacity)}
|
||||
|
||||
tb.earliestUnspentToken = tb.capacityToken()
|
||||
|
||||
return &tb
|
||||
}
|
||||
|
||||
func (tb *TokenBucket) Wait() {
|
||||
// If earliest unspent token is in the future, sleep until then
|
||||
time.Sleep(tb.earliestUnspentToken.Sub(time.Now()))
|
||||
|
||||
// Alternatively, enforce bucket capacity if necessary
|
||||
capacityToken := tb.capacityToken()
|
||||
if tb.earliestUnspentToken.Before(capacityToken) {
|
||||
tb.earliestUnspentToken = capacityToken
|
||||
}
|
||||
|
||||
// 'Remove' a token from the bucket
|
||||
tb.earliestUnspentToken = tb.earliestUnspentToken.Add(tb.tokenInterval)
|
||||
}
|
||||
|
||||
// Determine the historic token timestamp representing a full bucket
|
||||
func (tb *TokenBucket) capacityToken() time.Time {
|
||||
return time.Now().Add(-tb.refillDuration).Truncate(tb.tokenInterval)
|
||||
}
|
||||
@@ -1,11 +1,12 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"code.google.com/p/gopacket"
|
||||
"code.google.com/p/gopacket/layers"
|
||||
"log"
|
||||
"net"
|
||||
"syscall"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
)
|
||||
|
||||
type UDPSender interface {
|
||||
|
||||
@@ -2,38 +2,49 @@
|
||||
<div class="section footer">
|
||||
<div class="container">
|
||||
<div class="row clearfix">
|
||||
<div class="col-md-3 col-md-offset-2 column">
|
||||
<div class="col-sm-3 col-md-2">
|
||||
<b>Company</b><br>
|
||||
<a href="http://weave.works/about.html">About Weave</a><br>
|
||||
<!-- <a href="#">Meet the Team</a><br> -->
|
||||
<a href="http://weave.works/team.html">Meet the Team</a><br>
|
||||
<!-- <a href="#">Careers</a><br> -->
|
||||
<a href="http://blog.weave.works">Blog</a><br>
|
||||
<br>
|
||||
<a href="http://weave.works/articles/">Learn More</a><br>
|
||||
</div>
|
||||
<div class="col-sm-3 col-md-2">
|
||||
<b>Community</b><br>
|
||||
<a href="http://weave.works/help/index.html#partners">Partners</a><br>
|
||||
<a href="http://github.com/weaveworks">Code</a><br>
|
||||
</div>
|
||||
<div class="col-md-3 column">
|
||||
<div class="col-sm-3 col-md-2">
|
||||
<b>Documentation</b><br>
|
||||
<a href="http://docs.weave.works">Docs</a><br>
|
||||
<a href="http://weave.works/guides/">Getting Started Guides</a><br>
|
||||
<a href="http://weave.works/help/index.html">Help and Support</a><br>
|
||||
<a href="http://blog.weave.works">Blog</a><br>
|
||||
</div>
|
||||
<div class="col-md-3 column">
|
||||
<div class="col-sm-3 col-md-2">
|
||||
<b>Get in Touch</b><br>
|
||||
<a href="mailto:help@weave.works">help@weave.works</a><br>
|
||||
<div class="hidden-md hidden-lg">
|
||||
<a href="mailto:help@weave.works">help@weave.works</a><br>
|
||||
</div>
|
||||
<a href="http://twitter.com/weaveworks">Twitter</a><br>
|
||||
<a href="http://github.com/weaveworks">Github</a><br>
|
||||
<a href="http://slideshare.net/weaveworks">Slideshare</a><br>
|
||||
<a href="https://www.linkedin.com/company/weaveworks">Linkedin</a><br>
|
||||
<a href="https://plus.google.com/+WeaveWorksInc/">GooglePlus</a><br>
|
||||
</div>
|
||||
<div class="col-md-3 hidden-xs hidden-sm">
|
||||
<b>Talk to a human</b>
|
||||
<div align="center">
|
||||
<br>
|
||||
<a href="mailto:help@weave.works" class="btn btn-lg">Drop us a line</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row clearfix weavefooter">
|
||||
<div class="row">
|
||||
<br>
|
||||
<br>
|
||||
<div class="col-md-4 col-md-offset-2">
|
||||
<div class="col-sm-4">
|
||||
<p class="copyright">© Weaveworks 2014 ‐ 2015</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
<div class="section header navbaronly">
|
||||
<nav class="navbar navbar-inverse">
|
||||
<div class="section section-header navbaronly">
|
||||
<div class="navbar navbar-inverse">
|
||||
<div class="container">
|
||||
<div><!-- class="navbar-header"> -->
|
||||
<a class="navbar-brand" href="http://weave.works/"><img src="http://weave.works/img/weave-logo.png"></a>
|
||||
</div>
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand" href="http://weave.works/"><img src="http://weave.works/img/weave-logo.png"></a>
|
||||
</div>
|
||||
<div class="nav-wrapper">
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li>
|
||||
<a href="http://docs.weave.works">Docs</a>
|
||||
@@ -18,6 +19,7 @@
|
||||
<a href="http://weave.works/help/index.html">Help & Support</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
<!-- CSS
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
|
||||
<link rel="stylesheet" type="text/css" href="http://weave.works/less/custom.css">
|
||||
<link rel="stylesheet" type="text/css" href="assets/custom.css?v=1">
|
||||
|
||||
<!-- Favicon
|
||||
–––––––––––––––––––––––––––––––––––––––––––––––––– -->
|
||||
@@ -33,8 +33,8 @@
|
||||
|
||||
<div class="content">
|
||||
{% include header-navbaronly.html %}
|
||||
<div class="container">
|
||||
<div class="col-md-10 col-md-offset-1">
|
||||
<div class="container markdown-page">
|
||||
<div class="col-md-8 col-md-offset-2">
|
||||
{{ content }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
+18
-12
@@ -7,23 +7,29 @@ layout: default
|
||||
|
||||
If you are running Docker inside the Boot2Docker VM, e.g. because you
|
||||
are on a Mac, then the following changes are required to the weave
|
||||
instructions:
|
||||
instructions. First, we need to get Boot2Docker running:
|
||||
|
||||
host1$ boot2docker init
|
||||
host1$ boot2docker start
|
||||
host1$ eval "$(boot2docker shellinit)"
|
||||
|
||||
Assuming you have fetched the 'weave' script via curl or similar, and
|
||||
it is in the current directory, transfer it to the Boot2Docker VM and
|
||||
make it executable like this:
|
||||
it is in the current directory, launch weave on the Boot2Docker VM and
|
||||
configure our shell. Because Boot2Docker uses TLS, we have to pass a
|
||||
few extra options when launching the docker API proxy:
|
||||
|
||||
host1$ boot2docker ssh "cat > weave" < weave
|
||||
host1$ boot2docker ssh "chmod a+x weave"
|
||||
host1$ ./weave launch
|
||||
host1$ ./weave launch-dns
|
||||
host1$ ./weave launch-proxy --tls \
|
||||
--tlscacert /var/lib/boot2docker/tls/ca.pem \
|
||||
--tlscert /var/lib/boot2docker/tls/server.pem \
|
||||
--tlskey /var/lib/boot2docker/tls/serverkey.pem
|
||||
host1$ eval "$(./weave proxy-env)"
|
||||
|
||||
Then, if we were trying to create the same containers as in the first
|
||||
example above, the 'launch' command would be run like this:
|
||||
Now, we can use the docker command to run our containers, as shown in
|
||||
the [proxy documentation](proxy.html):
|
||||
|
||||
host1$ boot2docker ssh "sudo ./weave launch"
|
||||
|
||||
and the 'run' command like this:
|
||||
|
||||
host1$ C=$(boot2docker ssh "sudo ./weave run 10.2.1.1/24 -t -i ubuntu")
|
||||
host1$ docker run -it ubuntu
|
||||
|
||||
For more information about how to access services running in
|
||||
Boot2Docker from the host or other machines (i.e. outside of the weave
|
||||
|
||||
+1
-1
@@ -11,7 +11,7 @@ You only need to build weave if you want to work on the weave codebase
|
||||
Apart from the `weave` shell script, weave is delivered as a set of
|
||||
container images. There is no distribution-specific packaging, so in
|
||||
principle it shouldn't matter which Linux distribution you build
|
||||
under. But naturally, Docker is a prerequisite (version 1.3.0 or
|
||||
under. But naturally, Docker is a prerequisite (version 1.3.1 or
|
||||
later). And it is difficult to build under Fedora because [Fedora
|
||||
does not include static
|
||||
libraries](http://fedoraproject.org/wiki/Packaging:Guidelines#Packaging_Static_Libraries).
|
||||
|
||||
+88
-64
@@ -9,7 +9,9 @@ Weave has a few more features beyond those illustrated by the [basic
|
||||
example](https://github.com/weaveworks/weave#example):
|
||||
|
||||
* [Virtual ethernet switch](#virtual-ethernet-switch)
|
||||
* [Manual addressing](#manual-addressing)
|
||||
* [Seamless Docker integration](#docker)
|
||||
* [Address allocation](#addressing)
|
||||
* [Naming and discovery](#naming-and-discovery)
|
||||
* [Application isolation](#application-isolation)
|
||||
* [Dynamic network attachment](#dynamic-network-attachment)
|
||||
* [Security](#security)
|
||||
@@ -23,9 +25,6 @@ example](https://github.com/weaveworks/weave#example):
|
||||
* [Dynamic topologies](#dynamic-topologies)
|
||||
* [Container mobility](#container-mobility)
|
||||
* [Fault tolerance](#fault-tolerance)
|
||||
* [Automatic IP address management](#ipam)
|
||||
* [Automatic discovery with WeaveDNS](#dns)
|
||||
* [Working with the Docker CLI and API](#proxy)
|
||||
|
||||
### <a name="virtual-ethernet-switch"></a>Virtual Ethernet Switch
|
||||
|
||||
@@ -56,36 +55,57 @@ now re-use the same tools and techniques when deploying applications
|
||||
as containers as we would have done when deploying them 'on metal' in
|
||||
our data centre.
|
||||
|
||||
### <a name="manual-addressing"></a>Manual addressing
|
||||
### <a name="docker"></a>Seamless Docker integration
|
||||
|
||||
The examples so far have leveraged weave's [address allocation](#ipam)
|
||||
and [discovery](#dns) features, meaning that we've not had to concern
|
||||
ourselves with IP addresses at all. It is, however, possible to
|
||||
specify address and network explicitly using [CIDR
|
||||
notation](http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation)
|
||||
Weave includes a [Docker API proxy](proxy.html) so that containers
|
||||
launched via the Docker
|
||||
[command-line interface](https://docs.docker.com/reference/commandline/cli/)
|
||||
or
|
||||
[remote API](https://docs.docker.com/reference/api/docker_remote_api/)
|
||||
are attached to the weave network before they begin execution.
|
||||
|
||||
### <a name="addressing"></a>Address allocation
|
||||
|
||||
Containers are automatically allocated an IP address that is unique
|
||||
across the weave network. You can see which address was allocated with
|
||||
[`weave ps`](troubleshooting.html#list-attached-containers):
|
||||
|
||||
host1$ weave ps a1
|
||||
a7aee7233393 7a:44:d3:11:10:70 10.128.0.2/10
|
||||
|
||||
Weave detects when a container has exited and releases its
|
||||
automatically allocated addresses so they can be re-used.
|
||||
|
||||
See the [Automatic IP Address Management](ipam.html) documentation for
|
||||
further details.
|
||||
|
||||
Instead of getting weave to allocate IP addresses automatically, it is
|
||||
also possible to specify an address and network explicitly, expressed
|
||||
in
|
||||
[CIDR notation](http://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing#CIDR_notation)
|
||||
- let's see how the first example would have looked:
|
||||
|
||||
On $HOST1:
|
||||
|
||||
host1$ C=$(weave run 10.2.1.1/24 -ti ubuntu)
|
||||
host1$ docker run -e WEAVE_CIDR=10.2.1.1/24 -ti ubuntu
|
||||
root@7ca0f6ecf59f:/#
|
||||
|
||||
And $HOST2:
|
||||
|
||||
host2$ C=$(weave run 10.2.1.2/24 -ti ubuntu)
|
||||
host2$ docker run -e WEAVE_CIDR=10.2.1.2/24 -ti ubuntu
|
||||
root@04c4831fafd3:/#
|
||||
|
||||
Then on $HOST1...
|
||||
Then in the container on $HOST1...
|
||||
|
||||
host1$ docker attach $C
|
||||
root@28841bd02eff:/# ping -c 1 -q 10.2.1.2
|
||||
root@7ca0f6ecf59f:/# ping -c 1 -q 10.2.1.2
|
||||
PING 10.2.1.2 (10.2.1.2): 48 data bytes
|
||||
--- 10.2.1.2 ping statistics ---
|
||||
1 packets transmitted, 1 packets received, 0% packet loss
|
||||
round-trip min/avg/max/stddev = 1.048/1.048/1.048/0.000 ms
|
||||
|
||||
Similarly, on $HOST2...
|
||||
Similarly, in the container on $HOST2...
|
||||
|
||||
host2$ docker attach $C
|
||||
root@f76829496120:/# ping -c 1 -q 10.2.1.1
|
||||
root@04c4831fafd3:/# ping -c 1 -q 10.2.1.1
|
||||
PING 10.2.1.1 (10.2.1.1): 48 data bytes
|
||||
--- 10.2.1.1 ping statistics ---
|
||||
1 packets transmitted, 1 packets received, 0% packet loss
|
||||
@@ -93,10 +113,24 @@ Similarly, on $HOST2...
|
||||
|
||||
The IP addresses and netmasks can be anything you like, but make sure
|
||||
they don't conflict with any IP ranges in use on the hosts (including
|
||||
those delegated to IPAM) or IP addresses of external services the
|
||||
hosts or containers need to connect to. The same IP range must be used
|
||||
everywhere, and the individual IP addresses must, of course, be
|
||||
unique.
|
||||
those delegated to weave's [automatic IP address allocator](ipam.html)) or
|
||||
IP addresses of external services the hosts or containers need to
|
||||
connect to. The same IP range must be used everywhere, and the
|
||||
individual IP addresses must, of course, be unique.
|
||||
|
||||
### <a name="naming-and-discovery"></a>Naming and discovery
|
||||
|
||||
Named containers are automatically registered in
|
||||
[weaveDNS](weavedns.html), which makes them discoverable through
|
||||
simple name lookups:
|
||||
|
||||
host1$ docker run -dti --name=service ubuntu
|
||||
host1$ docker run -ti ubuntu
|
||||
root@7b21498fb103:/# ping service
|
||||
|
||||
This feature supports load balancing, fault resilience and hot
|
||||
swapping; see the [weaveDNS](weavedns.html) documentation for more
|
||||
details.
|
||||
|
||||
### <a name="application-isolation"></a>Application isolation
|
||||
|
||||
@@ -109,27 +143,27 @@ Let's begin by configuring weave's allocator to manage multiple
|
||||
subnets:
|
||||
|
||||
host1$ weave launch -iprange 10.2.0.0/16 -ipsubnet 10.2.1.0/24
|
||||
host1$ weave launch-dns
|
||||
host1$ weave launch-dns && weave launch-proxy
|
||||
host1$ eval $(weave proxy-env)
|
||||
host2$ weave launch -iprange 10.2.0.0/16 -ipsubnet 10.2.1.0/24 $HOST1
|
||||
host2$ weave launch-dns
|
||||
host2$ weave launch-dns && weave launch-proxy
|
||||
host2$ eval $(weave proxy-env)
|
||||
|
||||
This delegates the entire 10.2.0.0/16 subnet to weave, and instructs
|
||||
it to allocate from 10.2.1.0/24 within that if no specific subnet is
|
||||
specified. Now we can launch some containers in the default subnet:
|
||||
|
||||
host1$ weave run --name a1 -ti ubuntu
|
||||
host2$ weave run --name a2 -ti ubuntu
|
||||
host1$ docker run --name a1 -ti ubuntu
|
||||
host2$ docker run --name a2 -ti ubuntu
|
||||
|
||||
And some more containers in a different subnet:
|
||||
|
||||
host1$ weave run net:10.2.2.0/24 --name b1 -ti ubuntu
|
||||
host2$ weave run net:10.2.2.0.24 --name b2 -ti ubuntu
|
||||
host1$ docker run -e WEAVE_CIDR=net:10.2.2.0/24 --name b1 -ti ubuntu
|
||||
host2$ docker run -e WEAVE_CIDR=net:10.2.2.0.24 --name b2 -ti ubuntu
|
||||
|
||||
A quick 'ping' test in the containers confirms that they can talk to
|
||||
each other but not the containers of our first application...
|
||||
|
||||
host1:~$ docker attach b1
|
||||
|
||||
root@b1:/# ping -c 1 -q b2
|
||||
PING b2.weave.local (10.2.2.128) 56(84) bytes of data.
|
||||
--- b2.weave.local ping statistics ---
|
||||
@@ -153,7 +187,11 @@ well-known technique from the 'on metal' days to containers.
|
||||
If desired, a container can be attached to multiple subnets when it is
|
||||
started:
|
||||
|
||||
host1$ weave run net:default net:10.2.2.0/24 -ti ubuntu
|
||||
host1$ docker run -e WEAVE_CIDR="net:default net:10.2.2.0/24" -ti ubuntu
|
||||
|
||||
`net:default` is used here to request allocation of an address from
|
||||
the default subnet in addition to one from an explicitly specified
|
||||
range.
|
||||
|
||||
NB: By default docker permits communication between containers on the
|
||||
same host, via their docker-assigned IP addresses. For complete
|
||||
@@ -166,17 +204,19 @@ be accomplished by starting them with the `--cap-drop net_raw` option.
|
||||
|
||||
### <a name="dynamic-network-attachment"></a>Dynamic network attachment
|
||||
|
||||
In some scenarios containers are started independently, e.g. via some
|
||||
existing tool chain, or require more complex startup sequences than
|
||||
provided by `weave run`. And sometimes the decision which application
|
||||
network a container should be part of is made post-startup. For these
|
||||
situations, weave allows an existing, running container to be attached
|
||||
to the weave network. To illustrate, we can achieve the same effect as
|
||||
the first example with
|
||||
Sometimes the application network to which a container should be
|
||||
attached is not known in advance. For these situations, weave allows
|
||||
an existing, running container to be attached to the weave network. To
|
||||
illustrate, we can achieve the same effect as the first example with
|
||||
|
||||
host1$ C=$(docker run -d -t -i ubuntu)
|
||||
host1$ C=$(docker run -e WEAVE_CIDR=none -dti ubuntu)
|
||||
host1$ weave attach $C
|
||||
|
||||
(Note that since we modified `DOCKER_HOST` to point to the proxy
|
||||
earlier, we have to pass `-e WEAVE_CIDR=none` to start a container
|
||||
that _doesn't_ get automatically attached to the weave network for the
|
||||
purposes of this example.)
|
||||
|
||||
There is a matching `weave detach` command:
|
||||
|
||||
host1$ weave detach $C
|
||||
@@ -205,16 +245,21 @@ In order to connect containers across untrusted networks, weave peers
|
||||
can be told to encrypt traffic by supplying a `-password` option or
|
||||
`WEAVE_PASSWORD` environment variable when launching weave, e.g.
|
||||
|
||||
host1$ weave launch -password wEaVe
|
||||
host1$ weave launch -password wfvAwt7sj
|
||||
|
||||
or
|
||||
|
||||
host1$ export WEAVE_PASSWORD=wEaVe
|
||||
host1$ export WEAVE_PASSWORD=wfvAwt7sj
|
||||
host1$ weave launch
|
||||
|
||||
_NOTE: The command line option takes precedence over the environment
|
||||
variable._
|
||||
|
||||
> To avoid leaking your password via the kernel process table or your
|
||||
> shell history, we recommend you store it in a file and capture it
|
||||
> into a shell variable prior to launching weave: `export
|
||||
> WEAVE_PASSWORD=$(cat /path/to/password-file)`
|
||||
|
||||
The password needs to be reasonably strong to guard against online
|
||||
dictionary attacks. We recommend at least 50 bits of entropy. An easy
|
||||
way to generate a random password which satsifies this requirement is
|
||||
@@ -333,7 +378,7 @@ service.
|
||||
-j DNAT --to-destination $HOST3:2211
|
||||
|
||||
This allows any application container to reach the service by
|
||||
connecting to 10.2.1.101:3322. So if `$HOST3` is indeed running a netcat
|
||||
connecting to 10.2.1.3:3322. So if `$HOST3` is indeed running a netcat
|
||||
service on port 2211, e.g.
|
||||
|
||||
host3$ nc -lk -p 2211
|
||||
@@ -390,7 +435,7 @@ Now any host on the same network as `$HOST2` can access the service with
|
||||
Furthermore, as explained in [service-binding](#service-binding), we
|
||||
can dynamically alter the service locations without having to touch
|
||||
the applications that access them, e.g. we could move the example
|
||||
netcat service to `$HOST4:2211` while retaining its 10.2.1.101:3322
|
||||
netcat service to `$HOST4:2211` while retaining its 10.2.1.3:3322
|
||||
endpoint in the weave network.
|
||||
|
||||
### <a name="multi-cloud-networking"></a>Multi-cloud networking
|
||||
@@ -478,24 +523,3 @@ stop`) and restart it. Application containers do *not* have to be
|
||||
restarted in that event, and indeed may not even experience a
|
||||
temporary connectivity failure if the weave container is restarted
|
||||
quickly enough.
|
||||
|
||||
### <a name="ipam"></a>Automatic IP Address Management
|
||||
|
||||
Weave can automatically assign unique IP addresses to each container
|
||||
across the network. The `run`, `start`, `attach`, `expose` and `hide`
|
||||
commands will then fetch an address automatically if none is
|
||||
specified. See the [IPAM](ipam.html) documentation for details on how
|
||||
to enable and use this feature.
|
||||
|
||||
### <a name="dns"></a>Automatic discovery with WeaveDNS
|
||||
|
||||
WeaveDNS is a distributed DNS service for weave networks, enabling
|
||||
containers to address each other by name rather than IP address. Find
|
||||
out more about WeaveDNS from its [documentation](weavedns.html).
|
||||
|
||||
### <a name="proxy"></a>Working with the Docker CLI and API
|
||||
|
||||
Instead of the `weave` command-line utility, you may prefer to use the
|
||||
standard Docker command-line interface, or the Docker remote API, for
|
||||
starting weave-enabled containers. This can be accomplished with the
|
||||
[Weave Proxy](proxy.html).
|
||||
+37
-3
@@ -29,8 +29,9 @@ encrypted, which carry encapsulated network packets. These
|
||||
|
||||
Weave creates a network bridge on the host. Each container is
|
||||
connected to that bridge via a veth pair, the container side of which
|
||||
is given the IP address & netmask supplied in 'weave run'. Also
|
||||
connected to the bridge is the weave router container.
|
||||
is given an IP address & netmask supplied either by the user or
|
||||
Weave's IP address allocator. Also connected to the bridge is the
|
||||
weave router container.
|
||||
|
||||
A weave router captures Ethernet packets from its bridge-connected
|
||||
interface in promiscuous mode, using 'pcap'. This typically excludes
|
||||
@@ -277,7 +278,7 @@ password, and the result is hashed through SHA256, to form the final
|
||||
ephemeral session key. Thus the supplied password is never exchanged
|
||||
directly, and is thoroughly mixed into the shared secret. Furthermore,
|
||||
the rate at which TCP connections are accepted is limited by weave to
|
||||
1kHz, which twarts online dictionary attacks on reasonably strong
|
||||
10Hz, which twarts online dictionary attacks on reasonably strong
|
||||
passwords.
|
||||
|
||||
The shared key formed by Diffie-Hellman is 256 bits long, appending
|
||||
@@ -292,6 +293,39 @@ not be able to form valid ephemeral session keys.
|
||||
The same ephemeral session key is used for both TCP and UDP traffic
|
||||
between two peers.
|
||||
|
||||
<a name="csprng"></a> Generating fresh keys for every connection
|
||||
provides forward secrecy at the cost of placing a demand on the Linux
|
||||
CSPRNG (accessed by `GenerateKey` via `/dev/urandom`) proportional to
|
||||
the number of inbound connection attempts. Weave has accept throttling
|
||||
to mitigate against denial of service attacks that seek to deplete the
|
||||
CSPRNG entropy pool, however even at the lower bound of ten requests
|
||||
per second there may not be enough entropy gathered on a headless
|
||||
system to keep pace.
|
||||
|
||||
Under such conditions, the consequences will be limited to slowing
|
||||
down processes reading from the blocking `/dev/random` device as the
|
||||
kernel waits for enough new entropy to be harvested. It is important
|
||||
to note that contrary to intuition this low entropy state does not
|
||||
compromise the ongoing use of `/dev/urandom` - [expert
|
||||
opinion](http://blog.cr.yp.to/20140205-entropy.html)
|
||||
asserts that as long as the CSPRNG is seeded with enough entropy (e.g.
|
||||
256 bits) before random number generation commences then the output is
|
||||
entirely safe for use as key material.
|
||||
|
||||
By way of comparison, this is exactly how OpenSSL works - it reads 256
|
||||
bits of entropy at startup, and uses that to seed an internal CSPRNG
|
||||
which is used thenceforth to generate keys. Whilst we could have taken
|
||||
the same approach and built our own CSPRNG to work around the
|
||||
potential `/dev/random` blocking issue, we thought it was much more
|
||||
prudent to rely on the [heavily
|
||||
scrutinised](http://eprint.iacr.org/2012/251.pdf) Linux random number
|
||||
generator as [advised
|
||||
here](http://cr.yp.to/highspeed/coolnacl-20120725.pdf) (page 10,
|
||||
'Centralizing randomness'). The aforementioned notwithstanding, if
|
||||
weave's demand on `/dev/urandom` is causing you problems with blocking
|
||||
`/dev/random` reads, please get in touch with us - we'd love to hear
|
||||
about your use case.
|
||||
|
||||
#### TCP
|
||||
|
||||
TCP connection are only used to exchange topology information between
|
||||
|
||||
@@ -8,9 +8,6 @@ layout: default
|
||||
* [Introduction, Installation and Example](https://github.com/weaveworks/weave#readme)
|
||||
* [Getting Started Guides](http://weave.works/guides/)
|
||||
* [Features](features.html)
|
||||
* [Automatic IP Address Management](ipam.html)
|
||||
* [Automatic Discovery with WeaveDNS](weavedns.html)
|
||||
* [Working with the Docker CLI and API](proxy.html)
|
||||
* [Troubleshooting](troubleshooting.html)
|
||||
* [Building](building.html)
|
||||
* [How it works](how-it-works.html)
|
||||
|
||||
+27
-42
@@ -5,10 +5,13 @@ layout: default
|
||||
|
||||
# Automatic IP Address Management
|
||||
|
||||
Weave can automatically assign containers an IP address that is unique
|
||||
across the network.
|
||||
Weave automatically assigns containers an IP address that is unique
|
||||
across the network, and releases that address when a container
|
||||
exits. This happens for all invocations of the `run`, `start`,
|
||||
`attach`, `detach`, `expose`, `hide` and `launch-dns` commands, unless
|
||||
the user explictly specified an address. Weave can also assign
|
||||
addresses in multiple subnets.
|
||||
|
||||
* [Usage](#usage)
|
||||
* [Initialisation](#initialisation)
|
||||
* [Choosing an allocation range](#range)
|
||||
* [Automatic allocation across multiple subnets](#subnets)
|
||||
@@ -16,25 +19,6 @@ across the network.
|
||||
* [Stopping and removing peers](#stop)
|
||||
* [Troubleshooting](#troubleshooting)
|
||||
|
||||
## <a name="usage"></a>Usage
|
||||
|
||||
Containers are automatically allocated an IP address when none is
|
||||
specified when the container is started, e.g.
|
||||
|
||||
host1# C=$(weave run -ti ubuntu)
|
||||
|
||||
You can see which address was allocated with
|
||||
[`weave ps`](troubleshooting.html#list-attached-containers):
|
||||
|
||||
host1# weave ps $C
|
||||
a7aff7249393 7a:51:d1:09:21:78 10.128.0.1/10
|
||||
|
||||
Weave detects when a container has exited and releases its
|
||||
automatically allocated addresses so they can be re-used.
|
||||
|
||||
Automatic IP address assignment is available for the `run`, `start`,
|
||||
`attach`, `detach`, `expose`, `hide` and `launch-dns` commands.
|
||||
|
||||
## <a name="initialisation"></a>Initialisation
|
||||
|
||||
Just once, when the first automatic IP address allocation is requested
|
||||
@@ -106,10 +90,18 @@ would be safe wrt weave's startup quorum:
|
||||
By default, weave will allocate IP addresses in the 10.128.0.0/10
|
||||
range. This can be overridden with the `-iprange` option, e.g.
|
||||
|
||||
host1# weave launch -iprange 10.2.0.0/16
|
||||
host1$ weave launch -iprange 10.2.0.0/16
|
||||
|
||||
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
|
||||
@@ -124,14 +116,6 @@ the rest (a partition), they can continue to work with the address
|
||||
ranges they had before isolation, and can subsequently be re-connected
|
||||
to the rest of the network without any conflicts arising.
|
||||
|
||||
Once you have given a range of addresses to the IP allocator, you must
|
||||
not use any addresses in that range for anything else. If, in our
|
||||
example, you subsequently executed `weave run 10.2.3.1/24 -ti ubuntu`,
|
||||
you run the risk that the IP allocator will assign the same address to
|
||||
another container, which will make network traffic delivery
|
||||
intermittent or non-existent for the containers that share the same IP
|
||||
address.
|
||||
|
||||
## <a name="subnets"></a>Automatic allocation across multiple subnets
|
||||
|
||||
When
|
||||
@@ -140,20 +124,20 @@ 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.
|
||||
|
||||
host1# C=$(weave run net:10.2.7.0/24 -ti ubuntu)
|
||||
host1$ docker run -e WEAVE_CIDR=net:10.2.7.0/24 -ti ubuntu
|
||||
|
||||
You can ask for multiple addresses in different subnets and add in
|
||||
manually-assigned addresses (outside the automatic allocation range),
|
||||
for instance:
|
||||
|
||||
host1# C=$(weave run 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
|
||||
|
||||
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
|
||||
with others. One can specify that with `-ipsubnet`:
|
||||
|
||||
host1# weave launch -iprange 10.2.0.0/16 -ipsubnet 10.2.3.0/24
|
||||
host1$ weave launch -iprange 10.2.0.0/16 -ipsubnet 10.2.3.0/24
|
||||
|
||||
`-iprange` should cover the entire range that you will ever use for
|
||||
allocation, and `-ipsubnet` is the subnet that will be used when you
|
||||
@@ -170,7 +154,7 @@ have the containers communicate with each other*, you can choose a
|
||||
`-iprange` that is smaller than `-ipsubnet`, For example, if you
|
||||
launch weave with:
|
||||
|
||||
host1# weave launch -iprange 10.9.0.0/17 -ipsubnet 10.9.0.0/16
|
||||
host1$ weave launch -iprange 10.9.0.0/17 -ipsubnet 10.9.0.0/16
|
||||
|
||||
then you can run all containers in the 10.9.0.0/16 subnet, with
|
||||
automatic allocation using the lower half, leaving the upper half free
|
||||
@@ -213,22 +197,23 @@ The command
|
||||
reports on the current status of the weave router and IP allocator:
|
||||
|
||||
````
|
||||
weave router git-8f675f15c0b5
|
||||
...
|
||||
|
||||
Allocator universe 10.2.0.0/16
|
||||
Owned Ranges:
|
||||
10.2.1.1 -> 96:e9:e2:2e:2d:bc (host1) (v3)
|
||||
10.2.1.128 -> ea:84:25:9b:31:2e (host2) (v3)
|
||||
10.2.1.192 -> ea:6c:21:09:cf:f0 (host3) (v9)
|
||||
Allocator default subnet: 10.2.1.0/24
|
||||
|
||||
...
|
||||
````
|
||||
|
||||
The first section covers the router; see the [troubleshooting
|
||||
guide](troubleshooting.html#status-report) for full details.
|
||||
|
||||
The 'Allocator' section, which is only present if weave has been
|
||||
started with the `-iprange` option, summarises the overall position and
|
||||
lists which address ranges have been assigned to which peer. Each
|
||||
range begins at the address shown and ends just before the next
|
||||
address, or wraps around at the end of the subnet. The 'v' number
|
||||
denotes how many times that entry has been updated.
|
||||
The 'Allocator' section summarises the overall position and lists
|
||||
which address ranges have been assigned to which peer. Each range
|
||||
begins at the address shown and ends just before the next address, or
|
||||
wraps around at the end of the subnet. The 'v' number denotes how many
|
||||
times that entry has been updated.
|
||||
+43
-68
@@ -1,12 +1,12 @@
|
||||
---
|
||||
title: Weave Proxy
|
||||
title: Weave Docker API Proxy
|
||||
layout: default
|
||||
---
|
||||
|
||||
# Weave Proxy
|
||||
# Weave Docker API Proxy
|
||||
|
||||
The proxy automatically attaches containers to the weave network when
|
||||
they are started using the ordinary Docker
|
||||
The Docker API proxy automatically attaches containers to the weave
|
||||
network when they are started using the ordinary Docker
|
||||
[command-line interface](https://docs.docker.com/reference/commandline/cli/)
|
||||
or
|
||||
[remote API](https://docs.docker.com/reference/api/docker_remote_api/),
|
||||
@@ -16,8 +16,8 @@ instead of `weave run`.
|
||||
* [Usage](#usage)
|
||||
* [Automatic IP address assignment](#ipam)
|
||||
* [Automatic discovery](#dns)
|
||||
* [Multi-host example](#multi-host)
|
||||
* [Securing the docker communication with TLS](#tls)
|
||||
* [Launching containers without the proxy](#without-proxy)
|
||||
* [Troubleshooting](#troubleshooting)
|
||||
|
||||
## <a name="setup"></a>Setup
|
||||
@@ -29,17 +29,14 @@ To start the proxy, run
|
||||
|
||||
host1$ weave launch-proxy
|
||||
|
||||
By default, the proxy will connect to docker at
|
||||
`unix:///var/run/docker.sock`. This can be adjusted with the `-D`
|
||||
argument, e.g.
|
||||
|
||||
host1$ weave launch-proxy -D tcp://127.0.0.1:4243
|
||||
|
||||
By default, the proxy listens on port 12375, on all network
|
||||
interfaces. This can be adjusted with the `-H` argument, e.g.
|
||||
|
||||
host1$ weave launch-proxy -H tcp://127.0.0.1:9999
|
||||
|
||||
If you are working with a remote docker daemon, then any firewalls
|
||||
inbetween need to be configured to permit access to the proxy port.
|
||||
|
||||
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:
|
||||
@@ -52,11 +49,6 @@ Alternatively, the proxy host can be set on a per-command basis with
|
||||
|
||||
host1$ docker $(weave proxy-config) ps
|
||||
|
||||
If you are working with a remote docker daemon, then `localhost` in
|
||||
the above needs to be replaced with the docker daemon host, and any
|
||||
firewalls inbetween need to be configured to permit access to
|
||||
the proxy port.
|
||||
|
||||
The proxy can be stopped with
|
||||
|
||||
host1$ weave stop-proxy
|
||||
@@ -90,12 +82,6 @@ Multiple IP addresses and networks can be supplied in the `WEAVE_CIDR`
|
||||
variable by space-separating them, as in
|
||||
`WEAVE_CIDR="10.2.1.1/24 10.2.2.1/24"`.
|
||||
|
||||
Using the proxy brings some additional benefits over `weave run`. The
|
||||
proxy ensures that the weave network interface is available before
|
||||
starting a container's application process. Furthermore, containers
|
||||
can be started in foreground mode, and can be automatically removed
|
||||
(with the ususal `--rm`).
|
||||
|
||||
## <a name="ipam"></a>Automatic IP address assignment
|
||||
|
||||
If [automatic IP address assignment](ipam.html) is enabled in weave,
|
||||
@@ -105,9 +91,9 @@ special environment variables or other options*.
|
||||
|
||||
host1$ docker run -ti ubuntu
|
||||
|
||||
To use a specific IP, we pass a `WEAVE_CIDR` to the container, e.g.
|
||||
To use a specific subnet, we pass a `WEAVE_CIDR` to the container, e.g.
|
||||
|
||||
host1$ docker run -ti -e WEAVE_CIDR=10.2.1.1/24 ubuntu
|
||||
host1$ docker run -ti -e WEAVE_CIDR=net:10.128.0.0/24 ubuntu
|
||||
|
||||
To start a container without connecting it to the weave network, pass
|
||||
`WEAVE_CIDR=none`, e.g.
|
||||
@@ -117,7 +103,7 @@ To start a container without connecting it to the weave network, pass
|
||||
If you do not want IPAM to be used by default, the proxy needs to be
|
||||
passed the `--no-default-ipam` flag, e.g.
|
||||
|
||||
host1$ docker launch-proxy --no-default-ipam
|
||||
host1$ weave launch-proxy --no-default-ipam
|
||||
|
||||
In this configuration, containers with no `WEAVE_CIDR` environment
|
||||
variable will not be connected to the weave network. Containers
|
||||
@@ -129,48 +115,10 @@ container with a blank `WEAVE_CIDR`, e.g.
|
||||
|
||||
## <a name="dns"></a>Automatic discovery
|
||||
|
||||
Containers started via the proxy are automatically registered in
|
||||
[weaveDNS](weavedns.html) if they have a hostname in the weaveDNS
|
||||
domain (usually `.weave.local`). In order for containers to be able to
|
||||
look up such names, their DNS resolver needs to be configured to point
|
||||
at weaveDNS. This will be done automatically by the proxy while
|
||||
weaveDNS is running. To override this behaviour launch the proxy with
|
||||
either `--with-dns` or `--without-dns`, which will force the proxy to
|
||||
always/never set the resolver to weaveDNS. If there is no hostname
|
||||
provided, the container will be registered in weaveDNS using its
|
||||
container name. Otherwise, if there is no container name, and no
|
||||
hostname (or a hostname outside the weaveDNS domain), the container
|
||||
will not be registered in weaveDNS.
|
||||
|
||||
## <a name="multi-host"></a>Multi-host example
|
||||
|
||||
Here's a complete example of using weave proxies configured with
|
||||
[automatic IP address assignment](#ipam) and
|
||||
[automatic discovery](#dns) to start containers on two hosts such that
|
||||
one can reach the other by name.
|
||||
|
||||
First, let us start weave, weaveDNS and the proxy, and set DOCKER_HOST
|
||||
to point at the latter:
|
||||
|
||||
host1$ weave launch
|
||||
host1$ weave launch-dns
|
||||
host1$ weave launch-proxy
|
||||
host1$ eval "$(weave proxy-env)"
|
||||
|
||||
host2$ weave launch host1
|
||||
host2$ weave launch-dns
|
||||
host2$ weave launch-proxy
|
||||
host2$ eval "$(weave proxy-env)"
|
||||
|
||||
Now let us start a named container on one host, and ping it, by name,
|
||||
from a container on the other host.
|
||||
|
||||
host1$ docker run --name=pingme -dti ubuntu
|
||||
|
||||
host2$ docker run -ti ubuntu ping pingme
|
||||
PING pingme.weave.local (10.128.0.2) 56(84) bytes of data.
|
||||
64 bytes from pingme.weave.local (10.128.0.2): icmp_seq=1 ttl=64 time=0.047 ms
|
||||
...
|
||||
Containers launched via the proxy will use [weaveDNS](weavedns.html)
|
||||
automatically if it is running at the point when they are started -
|
||||
see the [weaveDNS usage](weavedns.html#usage) section for an in-depth
|
||||
explanation of the behaviour and how to control it.
|
||||
|
||||
## <a name="tls"></a>Securing the docker communication with TLS
|
||||
|
||||
@@ -193,7 +141,7 @@ Because the proxy connects to the docker daemon at
|
||||
listening there. To do this, you need to pass the `-H
|
||||
unix:///var/run/docker.sock` option when starting the docker daemon,
|
||||
in addition to the `-H` options for configuring the TCP listener. See
|
||||
[the Docker documentation](https://docs.docker.com/articles/basics/#bind-docker-to-another-hostport-or-a-unix-socket)
|
||||
[the Docker documentation](https://docs.docker.com/articles/basics/#bind-docker-to-another-host-port-or-a-unix-socket)
|
||||
for an example.
|
||||
|
||||
With the proxy running over TLS, we can configure our regular docker
|
||||
@@ -218,6 +166,33 @@ which is exactly the same configuration as when connecting to the
|
||||
docker daemon directly, except that the specified port is the weave
|
||||
proxy port.
|
||||
|
||||
## <a name="without-proxy"></a>Launching containers without the proxy
|
||||
|
||||
If you cannot or do not want to use the proxy you can launch
|
||||
containers on the weave network with `weave run`:
|
||||
|
||||
$ weave run -ti ubuntu
|
||||
|
||||
The arguments after `run` are passed through to `docker run` so you
|
||||
can freely specify whichever docker options are appropriate. Once the
|
||||
container is started, `weave run` attaches it to the weave network, in
|
||||
this example with an address allocated by IPAM. If you wish you can
|
||||
specify addresses manually instead:
|
||||
|
||||
$ weave run 10.2.1.1/24 -ti ubuntu
|
||||
|
||||
There are some limitations to starting containers with `weave run`:
|
||||
|
||||
* containers are always started in the background, i.e. the equivalent
|
||||
of always supplying the -d option to docker run
|
||||
* the --rm option to docker run, for automatically removing containers
|
||||
after they stop, is not available
|
||||
* the weave network interface may not be available immediately on
|
||||
container startup.
|
||||
|
||||
Finally, there is a `weave start` command which starts existing
|
||||
containers with `docker start` and attaches them to the weave network.
|
||||
|
||||
## <a name="troubleshooting"></a>Troubleshooting
|
||||
|
||||
The command
|
||||
|
||||
+5
-3
@@ -38,9 +38,11 @@ the following format:
|
||||
|
||||
You can also use the [connect][] command to add participating hosts dynamically.
|
||||
|
||||
Additionally, if you want to enable [encryption][] you can specify a password with
|
||||
`WEAVE_PASSWORD="MakeSureThisIsSecure"` in the `/etc/sysconfig/weave` environment
|
||||
file, and it will get picked up by weave on launch.
|
||||
Additionally, if you want to enable [encryption][] you can specify a
|
||||
password with e.g. `WEAVE_PASSWORD="wfvAwt7sj"` in the
|
||||
`/etc/sysconfig/weave` environment file, and it will get picked up by
|
||||
weave on launch. Recommendations for choosing a suitably strong
|
||||
password can be found [here](features.html#security).
|
||||
|
||||
You now should be able to launch weave with
|
||||
|
||||
|
||||
@@ -142,7 +142,7 @@ is waiting for a while before connecting again.
|
||||
There may also be further sections for the
|
||||
[IP address allocator](ipam.html#troubleshooting),
|
||||
[weaveDNS](weavedns.html#troubleshooting), and
|
||||
[proxy](proxy.html#troubleshooting).
|
||||
[Weave Docker API Proxy](proxy.html#troubleshooting).
|
||||
|
||||
### <a name="list-attached-containers"></a>List attached containers
|
||||
|
||||
|
||||
+58
-126
@@ -21,7 +21,6 @@ hosts.
|
||||
* [Configuring a custom TTL](#ttl)
|
||||
* [Configuring the domain search path](#domain-search-path)
|
||||
* [Using a different local domain](#local-domain)
|
||||
* [Using weaveDNS without `weave run`](#without-run)
|
||||
* [Troubleshooting](#troubleshooting)
|
||||
* [Present limitations](#limitations)
|
||||
|
||||
@@ -30,76 +29,54 @@ hosts.
|
||||
WeaveDNS is deployed as a set of containers that communicate with each
|
||||
other over the weave network. One such container needs to be started
|
||||
on every weave host, by invoking the weave script command
|
||||
`launch-dns`.
|
||||
`launch-dns`:
|
||||
|
||||
```bash
|
||||
$ weave launch
|
||||
$ weave launch-dns 10.2.254.1/24
|
||||
host1$ weave launch && weave launch-dns && weave launch-proxy
|
||||
host1$ eval $(weave proxy-env)
|
||||
```
|
||||
|
||||
Containers started while weaveDNS is running are automatically
|
||||
registered in [weaveDNS](weavedns.html) if they have a hostname in the
|
||||
weaveDNS domain (usually `.weave.local`). In order for containers to
|
||||
be able to look up such names, their DNS resolver needs to be
|
||||
configured to point at weaveDNS. This will be done automatically while
|
||||
weaveDNS is running. If there is no hostname provided, the container
|
||||
will be registered in weaveDNS using its container name. Otherwise, if
|
||||
there is no container name, and no hostname (or a hostname outside the
|
||||
weaveDNS domain), the container will not be registered in weaveDNS.
|
||||
For example, to use the container name as the hostname:
|
||||
Application containers will use weaveDNS automatically if it is
|
||||
running at the point when they are started. They will use it for name
|
||||
resolution, and will register themselves if they have either a
|
||||
hostname in the weaveDNS domain (`weave.local` by default) or have
|
||||
been given an explicit container name:
|
||||
|
||||
```bash
|
||||
$ weave run 10.2.1.25/24 -ti --name=pingme ubuntu
|
||||
$ shell1=$(weave run 10.2.1.26/24 -ti --name=ubuntu ubuntu)
|
||||
$ docker attach $shell1
|
||||
|
||||
host1$ docker run -dti --name=pingme ubuntu
|
||||
host1$ docker run -ti --hostname=ubuntu.weave.local ubuntu
|
||||
root@ubuntu:/# ping pingme
|
||||
...
|
||||
```
|
||||
|
||||
If you start an application container sans `--with-dns` you can still register
|
||||
it in weaveDNS simply by giving the container a hostname in the
|
||||
`.weave.local.` domain:
|
||||
|
||||
```
|
||||
$ weave run 10.2.1.25/24 -ti -h pingme.weave.local ubuntu
|
||||
```
|
||||
> **Please note** if both hostname and container name are specified at
|
||||
> the same time the hostname takes precedence; in this circumstance if
|
||||
> the hostname is not in the weaveDNS domain the container will *not* be
|
||||
> registered, but will still use weaveDNS for resolution.
|
||||
|
||||
It is also possible to force or forbid an application container's use
|
||||
of weaveDNS with the `--with-dns` and `--without-dns` options to
|
||||
`weave run`; these override the runtime detection of the weaveDNS
|
||||
container.
|
||||
`weave run` and `weave launch-proxy`; these override the runtime
|
||||
detection of the weaveDNS container.
|
||||
|
||||
Each weaveDNS container started with `launch-dns` needs to be given
|
||||
its own, unique, IP address, in a subnet that is common to all
|
||||
weaveDNS containers and not in use on any of the hosts.
|
||||
Each weaveDNS container started with `launch-dns` needs its own unique
|
||||
IP address in a subnet that is common to all weaveDNS containers. In
|
||||
the example above we did not specify such an address, so one was
|
||||
allocated automatically by IPAM from the default subnet; you can
|
||||
however specify an address in CIDR format manually. In this case you
|
||||
are responsible for ensuring that the IP addresses specified are
|
||||
uniquely allocated and not in use by any other container.
|
||||
|
||||
In our example the weaveDNS address is in subnet 10.2.254.0/24 and the
|
||||
application containers are in subnet 10.2.1.0/24. So, to launch and
|
||||
use weaveDNS on a second host we would run:
|
||||
|
||||
```bash
|
||||
host2$ weave launch $HOST1
|
||||
host2$ weave launch-dns 10.2.254.2/24
|
||||
host2$ shell2=$(weave run 10.2.1.36/24 -ti --name=ubuntu2 ubuntu)
|
||||
host2$ docker attach $shell2
|
||||
|
||||
root@ubuntu2:/# ping pingme
|
||||
...
|
||||
```
|
||||
|
||||
Notice the different IP address in the 10.2.254.0/24 subnet we gave to
|
||||
`weave launch-dns`, compared to what we supplied on the first host.
|
||||
|
||||
WeaveDNS containers can be stopped with `stop-dns`.
|
||||
Finally, WeaveDNS containers can be stopped with `stop-dns`.
|
||||
|
||||
## <a name="how-it-works"></a>How it works
|
||||
|
||||
The weaveDNS container running on every host acts as the nameserver
|
||||
for containers on that host. It is told about hostnames for local
|
||||
containers by the `weave run` command. If a hostname is in the
|
||||
`.weave.local` domain then weaveDNS records the association of that
|
||||
name with the container's weave IP address(es).
|
||||
for containers on that host. It learns about hostnames for local
|
||||
containers from the Weave Docker API proxy and from the `weave run`
|
||||
command. If a hostname is in the `.weave.local` domain then weaveDNS
|
||||
records the association of that name with the container's weave IP
|
||||
address(es).
|
||||
|
||||
When weaveDNS is queried for a name in the `.weave.local` domain, it
|
||||
first checks its own records. If the name is not found there, it asks
|
||||
@@ -116,7 +93,7 @@ different Docker bridge device. To supply a different bridge device,
|
||||
use the environment variable `DOCKER_BRIDGE`, e.g.,
|
||||
|
||||
```bash
|
||||
$ sudo DOCKER_BRIDGE=someother weave launch-dns 10.2.254.1/24
|
||||
$ sudo DOCKER_BRIDGE=someother weave launch-dns
|
||||
```
|
||||
|
||||
In the event that weaveDNS is launched in this way, it's important that
|
||||
@@ -136,20 +113,21 @@ Returning to our earlier example, let us start an additional `pingme`
|
||||
container, this time on the 2nd host, and then run some ping tests...
|
||||
|
||||
```bash
|
||||
host2$ weave run 10.2.1.35/24 -ti --name=pingme ubuntu
|
||||
host2$ docker attach $shell2
|
||||
host2$ weave launch && weave launch-dns && weave launch-proxy
|
||||
host2$ eval $(weave proxy-env)
|
||||
host2$ docker run -dti --name=pingme ubuntu
|
||||
|
||||
root@ubuntu2:/# ping -nq -c 1 pingme
|
||||
PING pingme.weave.local (10.2.1.35) 56(84) bytes of data.
|
||||
root@ubuntu:/# ping -nq -c 1 pingme
|
||||
PING pingme.weave.local (10.128.0.2) 56(84) bytes of data.
|
||||
...
|
||||
root@ubuntu2:/# ping -nq -c 1 pingme
|
||||
PING pingme.weave.local (10.2.1.25) 56(84) bytes of data.
|
||||
root@ubuntu:/# ping -nq -c 1 pingme
|
||||
PING pingme.weave.local (10.160.0.1) 56(84) bytes of data.
|
||||
...
|
||||
root@ubuntu2:/# ping -nq -c 1 pingme
|
||||
PING pingme.weave.local (10.2.1.25) 56(84) bytes of data.
|
||||
root@ubuntu:/# ping -nq -c 1 pingme
|
||||
PING pingme.weave.local (10.160.0.1) 56(84) bytes of data.
|
||||
...
|
||||
root@ubuntu2:/# ping -nq -c 1 pingme
|
||||
PING pingme.weave.local (10.2.1.35) 56(84) bytes of data.
|
||||
root@ubuntu:/# ping -nq -c 1 pingme
|
||||
PING pingme.weave.local (10.128.0.2) 56(84) bytes of data.
|
||||
...
|
||||
```
|
||||
|
||||
@@ -170,8 +148,8 @@ If you want to give the container a name in DNS *other* than its
|
||||
hostname, you can register it using the `dns-add` command. For example:
|
||||
|
||||
```bash
|
||||
$ shell2=(weave run 10.2.1.27/24 -ti ubuntu)
|
||||
$ weave dns-add 10.2.1.28 $shell2 -h pingme2.weave.local
|
||||
$ C=$(docker run -e WEAVE_CIDR=10.2.1.27/24 -ti ubuntu)
|
||||
$ weave dns-add 10.2.1.27 $C -h pingme2.weave.local
|
||||
```
|
||||
|
||||
You can also use `dns-add` to add the container's configured hostname
|
||||
@@ -180,7 +158,7 @@ and domain, simply by omitting `-h <fqdn>`.
|
||||
The inverse operation can be carried out using the `dns-remove` command:
|
||||
|
||||
```bash
|
||||
$ weave dns-remove 10.2.1.27 $shell2
|
||||
$ weave dns-remove 10.2.1.27 $C
|
||||
```
|
||||
|
||||
When queried about a name with multiple IPs, weaveDNS returns a random
|
||||
@@ -202,7 +180,7 @@ containers that die. You can tell it not to, by adding `--watch=false`
|
||||
to the container args:
|
||||
|
||||
```bash
|
||||
$ weave launch-dns 10.2.254.1/24 --watch=false
|
||||
$ weave launch-dns --watch=false
|
||||
```
|
||||
|
||||
## <a name="ttl"></a>Configuring a custom TTL
|
||||
@@ -215,7 +193,7 @@ However, you can force a different TTL value by launching weaveDNS with
|
||||
the `--ttl` argument:
|
||||
|
||||
```bash
|
||||
$ weave launch-dns 10.2.254.1/24 --ttl=10
|
||||
$ weave launch-dns --ttl=10
|
||||
```
|
||||
|
||||
This will shorten the lifespan of answers sent to other peers,
|
||||
@@ -240,7 +218,7 @@ hostnames across all sub-domains plus some external domains, you need
|
||||
behaviour.
|
||||
|
||||
```bash
|
||||
weave run --with-dns 10.2.1.4/24 -ti \
|
||||
docker run -ti \
|
||||
--dns-search=zone1.weave.local --dns-search=zone2.weave.local \
|
||||
--dns-search=corp1.com --dns-search=corp2.com \
|
||||
--dns-search=weave.local ubuntu
|
||||
@@ -254,60 +232,13 @@ can force weaveDNS to use a different domain by launching it
|
||||
with the `--domain` argument. For example,
|
||||
|
||||
```bash
|
||||
$ weave launch-dns 10.2.254.1/24 --domain="mycompany.local."
|
||||
$ weave launch-dns --domain="mycompany.local."
|
||||
```
|
||||
|
||||
The local domain should end with `local.`, since these names are
|
||||
link-local as per [RFC6762](https://tools.ietf.org/html/rfc6762),
|
||||
(though this is not strictly necessary).
|
||||
|
||||
## <a name="without-run"></a>Using weaveDNS without `weave run`
|
||||
|
||||
When weaveDNS is running, both `weave run` and `weave attach` register
|
||||
the hostname of the given container against the given weave network IP
|
||||
address. And if you use the `--with-dns` option, `weave run`
|
||||
automatically supplies the DNS server address to the new container.
|
||||
|
||||
In some circumstances, you may not want to use the `weave run` command
|
||||
to start containers. You can still take advantage of a running
|
||||
weaveDNS, with some extra manual steps.
|
||||
|
||||
### Supplying the DNS server
|
||||
|
||||
If you want to start containers with `docker run` rather than `weave
|
||||
run`, you can supply the docker bridge IP as the `--dns` option to
|
||||
make it use weaveDNS:
|
||||
|
||||
```bash
|
||||
$ docker_ip=$(docker inspect --format='{{ .NetworkSettings.Gateway }}' weavedns)
|
||||
$ shell2=$(docker run --dns=$docker_ip -ti ubuntu)
|
||||
$ weave attach 10.2.1.27/24 $shell2
|
||||
```
|
||||
|
||||
This isn't very useful unless the container is also attached to the
|
||||
weave network (as in the last line above).
|
||||
|
||||
Also note that this means of finding the Docker bridge's IP address
|
||||
requires a running container (any one would do); another way to find
|
||||
it is:
|
||||
|
||||
```bash
|
||||
$ docker_ip=$(ip -4 addr show dev docker0 | grep -o 'inet [0-9.]*' | cut -d ' ' -f 2)
|
||||
```
|
||||
|
||||
### Supplying the domain search path
|
||||
|
||||
By default, Docker provides containers with a `/etc/resolv.conf` that
|
||||
matches that for the host. In some circumstances, this may include a
|
||||
DNS search path, which will break the nice "bare names resolve"
|
||||
property above.
|
||||
|
||||
Therefore, when starting containers with `docker run` instead of
|
||||
`weave run`, you will usually want to supply a domain search path so
|
||||
that you can use unqualified hostnames. Use `--dns-search=.` to make
|
||||
the resolver use the container's domain, or e.g.,
|
||||
`--dns-search=weave.local` to make it look in `weave.local`.
|
||||
|
||||
## <a name="troubleshooting"></a>Troubleshooting
|
||||
|
||||
The command
|
||||
@@ -318,19 +249,20 @@ reports on the current status of various weave components, including
|
||||
DNS:
|
||||
|
||||
````
|
||||
weave router git-8f675f15c0b5
|
||||
...
|
||||
|
||||
weave DNS git-8f675f15c0b5
|
||||
Local domain weave.local.
|
||||
weave DNS 1.0.0
|
||||
Listen address :53
|
||||
mDNS interface &{26 65535 ethwe fa:b6:b1:85:ac:9b up|broadcast|multicast}
|
||||
Fallback DNS config &{[66.28.0.45 8.8.8.8] [] 53 1 5 2}
|
||||
Fallback DNS config &{[10.0.2.3] [] 53 1 5 2}
|
||||
|
||||
Local domain weave.local.
|
||||
Interface &{74 65535 ethwe 82:0c:92:84:0e:88 up|broadcast|multicast}
|
||||
Zone database:
|
||||
710978857a88 10.2.1.26 wiff.weave.local.
|
||||
e8d85b1dcdb1 10.2.1.27 waff.weave.local.
|
||||
26bd05f9a0cb 10.2.1.28 ping.weave.local.
|
||||
1ab0e8b17c39 10.2.1.29 pong.weave.local.
|
||||
144b75a9b873: pingme.weave.local.[10.160.0.1]/OBS:1
|
||||
74a5510a91ad: ubuntu.weave.local.[10.160.0.2]
|
||||
weave:remote: pingme.weave.local.[10.128.0.2]/TTL:30
|
||||
|
||||
...
|
||||
````
|
||||
|
||||
The first section covers the router; see the [troubleshooting
|
||||
|
||||
@@ -7,8 +7,8 @@ C2=10.2.1.7
|
||||
|
||||
start_suite "Ping over encrypted cross-host weave network"
|
||||
|
||||
weave_on $HOST1 launch -password notverysecure
|
||||
weave_on $HOST2 launch -password notverysecure $HOST1
|
||||
weave_on $HOST1 launch -password wfvAwt7sj
|
||||
weave_on $HOST2 launch -password wfvAwt7sj $HOST1
|
||||
|
||||
start_container $HOST1 $C1/24 --name=c1
|
||||
start_container $HOST2 $C2/24 --name=c2
|
||||
|
||||
@@ -33,4 +33,8 @@ assert_expected_fqdn "$HOSTNAME" -h $HOSTNAME --name=$NAME
|
||||
assert_expected_fqdn "$HOSTNAME" --hostname=$HOSTNAME --name=$NAME
|
||||
assert_expected_fqdn "$HOSTNAME" --hostname $HOSTNAME --name=$NAME
|
||||
|
||||
# Ensure we can launch a container with a name that is too long for hostname derivation
|
||||
SIXTY_FIVE_CHARS=01234567890123456789012345678901234567890123456789012345678901234
|
||||
assert_raises "start_container $HOST1 --name=$SIXTY_FIVE_CHARS"
|
||||
|
||||
end_suite
|
||||
@@ -4,13 +4,19 @@
|
||||
|
||||
start_suite "Run docker-py test suite against the proxy"
|
||||
|
||||
docker_on $HOST1 pull joffrey/docker-py >/dev/null
|
||||
|
||||
weave_on $HOST1 launch-proxy --no-default-ipam
|
||||
assert_raises "docker_on $HOST1 ps | grep weaveproxy"
|
||||
assert_raises "docker_on $HOST1 run \
|
||||
-e NOT_ON_HOST=true \
|
||||
-e DOCKER_HOST=tcp://172.17.42.1:12375 \
|
||||
-v /tmp:/tmp \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
joffrey/docker-py python tests/integration_test.py"
|
||||
|
||||
if docker_on $HOST1 run \
|
||||
-e NOT_ON_HOST=true \
|
||||
-e DOCKER_HOST=tcp://172.17.42.1:12375 \
|
||||
-v /tmp:/tmp \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
joffrey/docker-py python tests/integration_test.py ; then
|
||||
assert_raises "true"
|
||||
else
|
||||
assert_raises "false"
|
||||
fi
|
||||
|
||||
end_suite
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
. ./config.sh
|
||||
|
||||
entrypoint() {
|
||||
docker_on $HOST1 inspect --format="{{.Config.Entrypoint}}" "$@"
|
||||
}
|
||||
|
||||
start_suite "Proxy waits for weave to be ready before running container commands"
|
||||
weave_on $HOST1 launch-proxy
|
||||
BASE_IMAGE=busybox
|
||||
@@ -10,6 +14,28 @@ if (docker_on $HOST1 images $BASE_IMAGE | grep -q $BASE_IMAGE); then
|
||||
docker_on $HOST1 rmi $BASE_IMAGE
|
||||
fi
|
||||
|
||||
assert_raises "proxy docker_on $HOST1 run -e 'WEAVE_CIDR=10.2.1.1/24' $BASE_IMAGE $CHECK_ETHWE_UP"
|
||||
assert_raises "proxy docker_on $HOST1 run --name c1 -e 'WEAVE_CIDR=10.2.1.1/24' $BASE_IMAGE $CHECK_ETHWE_UP"
|
||||
|
||||
# Check committed containers only have one weavewait prepended
|
||||
COMMITTED_IMAGE=$(proxy docker_on $HOST1 commit c1)
|
||||
assert_raises "proxy docker_on $HOST1 run --name c2 $COMMITTED_IMAGE"
|
||||
assert "entrypoint c2" "$(entrypoint $COMMITTED_IMAGE)"
|
||||
|
||||
# Check exec works on containers without weavewait
|
||||
docker_on $HOST1 run -dit --name c3 $SMALL_IMAGE /bin/sh
|
||||
assert_raises "proxy docker_on $HOST1 exec c3 true"
|
||||
|
||||
# Check we can't modify weavewait
|
||||
assert_raises "proxy docker_on $HOST1 run -e 'WEAVE_CIDR=10.2.1.2/24' $BASE_IMAGE touch /w/w" 1
|
||||
|
||||
# Check only user-specified volumes and /w are mounted
|
||||
dirs_sans_proxy=$(docker_on $HOST1 run --rm $SMALL_IMAGE mount | wc -l)
|
||||
dirs_with_proxy=$(proxy docker_on $HOST1 run --rm -v /tmp/1:/srv1 -v /tmp/2:/srv2 -e 'WEAVE_CIDR=10.2.1.3/24' $SMALL_IMAGE mount | wc -l)
|
||||
assert "echo $((dirs_with_proxy-3))" $dirs_sans_proxy
|
||||
|
||||
# Check errors are returned (when docker returns an error code)
|
||||
assert_raises "proxy docker_on $HOST1 run -e 'WEAVE_CIDR=10.2.1.3/24' $SMALL_IMAGE foo 2>&1 | grep 'exec: \"foo\": executable file not found in \$PATH'"
|
||||
# Check errors still happen when no command is specified
|
||||
assert_raises "proxy docker_on $HOST1 run -e 'WEAVE_CIDR=10.2.1.3/24' $SMALL_IMAGE 2>&1 | grep 'Error response from daemon: No command specified'"
|
||||
|
||||
end_suite
|
||||
@@ -8,8 +8,8 @@ C1_NAME=c1.weave.local
|
||||
C2_NAME=seetwo.weave.local
|
||||
|
||||
boot_containers() {
|
||||
proxy docker_on $HOST1 run -e WEAVE_CIDR=$C2/24 -dt --name=c2 -h $C2_NAME $DNS_IMAGE /bin/sh
|
||||
proxy docker_on $HOST1 run -e WEAVE_CIDR=$C1/24 -dt --name=c1 $DNS_IMAGE /bin/sh
|
||||
proxy_start_container_with_dns $HOST1 -e WEAVE_CIDR=$C2/24 -dt --name=c2 -h $C2_NAME
|
||||
proxy_start_container_with_dns $HOST1 -e WEAVE_CIDR=$C1/24 -dt --name=c1
|
||||
}
|
||||
|
||||
kill_containers() {
|
||||
|
||||
@@ -9,19 +9,15 @@ C4=10.2.0.99
|
||||
DOMAIN=weave.local
|
||||
NAME=seeone.$DOMAIN
|
||||
|
||||
start_container() {
|
||||
proxy docker_on $HOST1 run "$@" -dt $DNS_IMAGE /bin/sh
|
||||
}
|
||||
|
||||
start_suite "Resolve unqualified names"
|
||||
|
||||
weave_on $HOST1 launch-dns 10.2.254.1/24
|
||||
weave_on $HOST1 launch-proxy
|
||||
|
||||
start_container -e WEAVE_CIDR=$C1/24 --name=c1 -h $NAME
|
||||
start_container -e WEAVE_CIDR=$C2/24 --name=c2 -h seetwo.$DOMAIN
|
||||
start_container -e WEAVE_CIDR=$C3/24 --name=c3 --dns-search=$DOMAIN
|
||||
container=$(start_container -e WEAVE_CIDR=$C4/24)
|
||||
proxy_start_container_with_dns $HOST1 -e WEAVE_CIDR=$C1/24 --name=c1 -h $NAME
|
||||
proxy_start_container_with_dns $HOST1 -e WEAVE_CIDR=$C2/24 --name=c2 -h seetwo.$DOMAIN
|
||||
proxy_start_container_with_dns $HOST1 -e WEAVE_CIDR=$C3/24 --name=c3 --dns-search=$DOMAIN
|
||||
container=$(proxy_start_container_with_dns $HOST1 -e WEAVE_CIDR=$C4/24)
|
||||
|
||||
check() {
|
||||
assert "proxy exec_on $HOST1 $1 getent hosts seeone | tr -s ' '" "$C1 $NAME"
|
||||
|
||||
@@ -10,8 +10,8 @@ start_suite "Proxy restart reattaches networking to containers"
|
||||
|
||||
launch_dns_on $HOST1 10.2.254.1/24
|
||||
weave_on $HOST1 launch-proxy --with-dns
|
||||
proxy docker_on $HOST1 run -e WEAVE_CIDR=$C2/24 -dt --name=c2 -h $NAME $SMALL_IMAGE /bin/sh
|
||||
proxy docker_on $HOST1 run -e WEAVE_CIDR=$C1/24 -dt --name=c1 $DNS_IMAGE /bin/sh
|
||||
proxy_start_container $HOST1 -e WEAVE_CIDR=$C2/24 -dt --name=c2 -h $NAME
|
||||
proxy_start_container_with_dns $HOST1 -e WEAVE_CIDR=$C1/24 -dt --name=c1
|
||||
|
||||
proxy docker_on $HOST1 restart c2
|
||||
assert_raises "proxy exec_on $HOST1 c2 $CHECK_ETHWE_UP"
|
||||
|
||||
+12
-10
@@ -4,12 +4,6 @@
|
||||
|
||||
UNIVERSE=10.2.2.0/24
|
||||
|
||||
start() {
|
||||
host=$1
|
||||
shift
|
||||
proxy docker_on "$host" run "$@" -dt $SMALL_IMAGE /bin/sh
|
||||
}
|
||||
|
||||
assert_no_ethwe() {
|
||||
assert_raises "container_ip $1 $2" 1
|
||||
assert_raises "proxy exec_on $1 $2 ip link show | grep -v ethwe"
|
||||
@@ -22,17 +16,25 @@ weave_on $HOST2 launch -iprange $UNIVERSE $HOST1
|
||||
weave_on $HOST1 launch-proxy
|
||||
weave_on $HOST2 launch-proxy --no-default-ipam
|
||||
|
||||
start $HOST1 --name=auto
|
||||
start $HOST1 --name=none -e WEAVE_CIDR=none
|
||||
start $HOST2 --name=zero -e WEAVE_CIDR=
|
||||
start $HOST2 --name=no-default
|
||||
proxy_start_container $HOST1 --name=auto
|
||||
proxy_start_container $HOST1 --name=none -e WEAVE_CIDR=none
|
||||
proxy_start_container $HOST2 --name=zero -e WEAVE_CIDR=
|
||||
proxy_start_container $HOST2 --name=no-default
|
||||
proxy_start_container $HOST1 --name=bridge --net=bridge
|
||||
proxy_start_container $HOST1 --name=host --net=host
|
||||
proxy_start_container $HOST1 --name=other --net=container:auto
|
||||
|
||||
AUTO=$(container_ip $HOST1 auto)
|
||||
ZERO=$(container_ip $HOST2 zero)
|
||||
BRIDGE=$(container_ip $HOST1 bridge)
|
||||
OTHER=$(container_ip $HOST1 other)
|
||||
assert_raises "proxy exec_on $HOST1 auto $PING $ZERO"
|
||||
assert_raises "proxy exec_on $HOST2 zero $PING $AUTO"
|
||||
assert_raises "proxy exec_on $HOST2 zero $PING $BRIDGE"
|
||||
assert_raises "proxy exec_on $HOST2 zero $PING $OTHER"
|
||||
|
||||
assert_no_ethwe $HOST1 none
|
||||
assert_no_ethwe $HOST2 no-default
|
||||
assert_no_ethwe $HOST1 host
|
||||
|
||||
end_suite
|
||||
Executable
+16
@@ -0,0 +1,16 @@
|
||||
#! /bin/bash
|
||||
|
||||
. ./config.sh
|
||||
|
||||
C1=10.2.1.13
|
||||
|
||||
start_suite "Start containers with 'weave run' via proxy"
|
||||
|
||||
weave_on $HOST1 launch
|
||||
weave_on $HOST1 launch-proxy
|
||||
|
||||
proxy start_container $HOST1 $C1/24 --name=c1
|
||||
# check we get exactly one IP back, the one specified
|
||||
assert "weave_on $HOST1 ps c1 | cut -d ' ' -f 3-" $C1/24
|
||||
|
||||
end_suite
|
||||
+13
-1
@@ -120,6 +120,18 @@ start_container_with_dns() {
|
||||
weave_on $host run --with-dns "$@" -t $DNS_IMAGE /bin/sh
|
||||
}
|
||||
|
||||
proxy_start_container() {
|
||||
host=$1
|
||||
shift 1
|
||||
proxy docker_on $host run "$@" -dt $SMALL_IMAGE /bin/sh
|
||||
}
|
||||
|
||||
proxy_start_container_with_dns() {
|
||||
host=$1
|
||||
shift 1
|
||||
proxy docker_on $host run "$@" -dt $DNS_IMAGE /bin/sh
|
||||
}
|
||||
|
||||
rm_containers() {
|
||||
host=$1
|
||||
shift
|
||||
@@ -170,8 +182,8 @@ assert_dns_ptr_record() {
|
||||
start_suite() {
|
||||
for host in $HOST1 $HOST2; do
|
||||
[ -z "$DEBUG" ] || echo "Cleaning up on $host: removing all containers and resetting weave"
|
||||
rm_containers $host $(docker_on $host ps -aq 2>/dev/null)
|
||||
weave_on $host reset 2>/dev/null
|
||||
rm_containers $host $(docker_on $host ps -aq 2>/dev/null)
|
||||
done
|
||||
whitely echo "$@"
|
||||
}
|
||||
|
||||
+7
-5
@@ -3,6 +3,7 @@
|
||||
# ./gce.sh setup - starts two VMs on GCE and configures them to run our integration tests
|
||||
# . ./gce.sh; ./run_all.sh - set a bunch of environment variables for the tests
|
||||
# ./gce.sh destroy - tear down the VMs
|
||||
# ./gce.sh make_template - make a fresh VM template; update TEMPLATE_NAME first!
|
||||
|
||||
set -ex
|
||||
|
||||
@@ -10,7 +11,7 @@ KEY_FILE=/tmp/gce_private_key.json
|
||||
SSH_KEY_FILE=$HOME/.ssh/gce_ssh_key
|
||||
PROJECT=positive-cocoa-90213
|
||||
IMAGE=ubuntu-14-04
|
||||
TEMPLATE_NAME="test-template"
|
||||
TEMPLATE_NAME="test-template-2"
|
||||
ZONE=us-central1-a
|
||||
NUM_HOSTS=2
|
||||
SUFFIX=""
|
||||
@@ -96,12 +97,13 @@ function setup {
|
||||
}
|
||||
|
||||
function make_template {
|
||||
gcloud compute instances create template --image $IMAGE --zone $ZONE
|
||||
gcloud compute instances create $TEMPLATE_NAME --image $IMAGE --zone $ZONE
|
||||
gcloud compute config-ssh --ssh-key-file $SSH_KEY_FILE
|
||||
name="template.$ZONE.$PROJECT"
|
||||
name="$TEMPLATE_NAME.$ZONE.$PROJECT"
|
||||
try_connect $name
|
||||
install_docker_on $name
|
||||
gcloud compute instances delete template --keep-disks boot -zone $ZONE
|
||||
gcloud compute images create $TEMPLATE_NAME --source-disk example-disk --source-disk-zone $ZONE
|
||||
gcloud -q compute instances delete $TEMPLATE_NAME --keep-disks boot --zone $ZONE
|
||||
gcloud compute images create $TEMPLATE_NAME --source-disk $TEMPLATE_NAME --source-disk-zone $ZONE
|
||||
}
|
||||
|
||||
function hosts {
|
||||
|
||||
@@ -93,6 +93,22 @@ check_docker_version() {
|
||||
fi
|
||||
}
|
||||
|
||||
enforce_docker_bridge_addr_assign_type() {
|
||||
if ! ADDR_ASSIGN_TYPE=$(cat /sys/class/net/$DOCKER_BRIDGE/addr_assign_type 2>/dev/null) ; then
|
||||
echo "Could not determine address assignment type of $DOCKER_BRIDGE" >&2
|
||||
return
|
||||
fi
|
||||
# From include/uapi/linux/netdevice.h
|
||||
# #define NET_ADDR_PERM 0 /* address is permanent (default) */
|
||||
# #define NET_ADDR_RANDOM 1 /* address is generated randomly */
|
||||
# #define NET_ADDR_STOLEN 2 /* address is stolen from other device */
|
||||
# #define NET_ADDR_SET 3 /* address is set using dev_set_mac_address() */
|
||||
if [ $ADDR_ASSIGN_TYPE != 3 ] ; then
|
||||
echo "Setting $DOCKER_BRIDGE MAC (mitigate https://github.com/docker/docker/issues/14908)" >&2
|
||||
ip link set dev $DOCKER_BRIDGE address $(random_mac) || true
|
||||
fi
|
||||
}
|
||||
|
||||
is_cidr() {
|
||||
echo "$1" | grep -E "^$CIDR_REGEXP$" >/dev/null
|
||||
}
|
||||
@@ -142,7 +158,7 @@ if [ "$1" = "run" ] ; then
|
||||
shift $(dns_arg_count "$@")
|
||||
collect_cidr_args "$@"
|
||||
shift $CIDR_ARG_COUNT
|
||||
CONTAINER=$(docker $DOCKER_CLIENT_ARGS run $DNS_ARGS -d "$@")
|
||||
CONTAINER=$(docker $DOCKER_CLIENT_ARGS run -e WEAVE_CIDR=none $DNS_ARGS -d "$@")
|
||||
exec_remote attach $CIDR_ARGS --or-die $CONTAINER
|
||||
echo $CONTAINER
|
||||
exit 0
|
||||
@@ -359,7 +375,7 @@ netnsenter() {
|
||||
}
|
||||
|
||||
connect_container_to_bridge() {
|
||||
if [ -h "$PROCFS/$CONTAINER_PID/ns/net" -a -h "$PROCFS/$$/ns/net" -a "$(readlink $PROCFS/$CONTAINER_PID/ns/net)" = "$(readlink $PROCFS/$$/ns/net)" ] ; then
|
||||
if [ -h "$PROCFS/$CONTAINER_PID/ns/net" -a -h "/proc/$$/ns/net" -a "$(readlink $PROCFS/$CONTAINER_PID/ns/net)" = "$(readlink /proc/$$/ns/net)" ] ; then
|
||||
echo "Container is running in the host network namespace, and therefore cannot be" >&2
|
||||
echo "connected to weave. Perhaps the container was started with --net=host." >&2
|
||||
return 1
|
||||
@@ -433,7 +449,9 @@ attach() {
|
||||
netnsenter ip route add 224.0.0.0/4 dev $CONTAINER_IFNAME
|
||||
fi
|
||||
|
||||
arp_update $CONTAINER_IFNAME $1 "netnsenter"
|
||||
for ADDR in "$@" ; do
|
||||
arp_update $CONTAINER_IFNAME $ADDR "netnsenter"
|
||||
done
|
||||
}
|
||||
|
||||
detach() {
|
||||
@@ -664,8 +682,11 @@ dns_args() {
|
||||
WITHOUT_DNS=
|
||||
while [ $# -gt 0 ] ; do
|
||||
case "$1" in
|
||||
--dns-search=*)
|
||||
DNS_SEARCH_SPECIFIED=1
|
||||
--with-dns)
|
||||
WITH_DNS=1
|
||||
;;
|
||||
--without-dns)
|
||||
WITHOUT_DNS=1
|
||||
;;
|
||||
--name)
|
||||
NAME_ARG="$2"
|
||||
@@ -677,11 +698,8 @@ dns_args() {
|
||||
-h|--hostname|--hostname=*)
|
||||
HOSTNAME_SPECIFIED=1
|
||||
;;
|
||||
--with-dns)
|
||||
WITH_DNS=1
|
||||
;;
|
||||
--without-dns)
|
||||
WITHOUT_DNS=1
|
||||
--dns-search|--dns-search=*)
|
||||
DNS_SEARCH_SPECIFIED=1
|
||||
;;
|
||||
esac
|
||||
shift
|
||||
@@ -693,8 +711,13 @@ dns_args() {
|
||||
DNS_ARGS="--dns $DOCKER_BRIDGE_IP"
|
||||
if [ -n "$NAME_ARG" -a -z "$HOSTNAME_SPECIFIED" ] ; then
|
||||
DOMAIN=$(dns_domain)
|
||||
DNS_ARGS="$DNS_ARGS --hostname=$NAME_ARG.${DOMAIN%.}"
|
||||
HOSTNAME_SPECIFIED=1
|
||||
HOSTNAME="$NAME_ARG.${DOMAIN%.}"
|
||||
if [ ${#HOSTNAME} -gt 64 ] ; then
|
||||
echo "Container name too long to be used as hostname" >&2
|
||||
else
|
||||
DNS_ARGS="$DNS_ARGS --hostname=$HOSTNAME"
|
||||
HOSTNAME_SPECIFIED=1
|
||||
fi
|
||||
fi
|
||||
if [ -z "$DNS_SEARCH_SPECIFIED" ] ; then
|
||||
if [ -z "$HOSTNAME_SPECIFIED" ] ; then
|
||||
@@ -859,7 +882,7 @@ ipam_cidrs_or_die() {
|
||||
# TODO: Handle args with spaces
|
||||
tls_arg() {
|
||||
filename=${3:-$2}
|
||||
PROXY_VOLUMES="$PROXY_VOLUMES -v $1:/home/weave/tls/$filename.pem"
|
||||
PROXY_VOLUMES="$PROXY_VOLUMES -v $1:/home/weave/tls/$filename.pem:ro"
|
||||
PROXY_ARGS="$PROXY_ARGS --tls$2 /home/weave/tls/$filename.pem"
|
||||
}
|
||||
|
||||
@@ -971,6 +994,7 @@ case "$COMMAND" in
|
||||
;;
|
||||
launch)
|
||||
check_not_running $CONTAINER_NAME $BASE_IMAGE
|
||||
enforce_docker_bridge_addr_assign_type
|
||||
create_bridge
|
||||
# We set the router name to the bridge mac since that is
|
||||
# stable across re-creations of the containers.
|
||||
@@ -1017,10 +1041,15 @@ case "$COMMAND" in
|
||||
if [ -z "$IPRANGE_SPECIFIED" ] ; then
|
||||
IPRANGE="10.128.0.0/10"
|
||||
if command_exists netcheck && ! netcheck $IPRANGE ; then
|
||||
echo "Default -iprange $IPRANGE overlaps with existing route." >&2
|
||||
echo "Please pick another range and set it on all hosts." >&2
|
||||
echo "ERROR: Default -iprange $IPRANGE overlaps with existing route on host." >&2
|
||||
echo "You must pick another range and set it on all hosts." >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
if command_exists netcheck && ! netcheck $IPRANGE ; then
|
||||
echo "WARNING: Specified -iprange $IPRANGE overlaps with existing route on host." >&2
|
||||
echo "Unless this is deliberate, you must pick another range and set it on all hosts." >&2
|
||||
fi
|
||||
fi
|
||||
# Set WEAVE_DOCKER_ARGS in the environment in order to supply
|
||||
# additional parameters, such as resource limits, to docker
|
||||
@@ -1071,6 +1100,7 @@ case "$COMMAND" in
|
||||
-v /proc:/hostproc \
|
||||
-e PROCFS=/hostproc \
|
||||
-e WEAVE_CIDR=none \
|
||||
-e DOCKER_BRIDGE \
|
||||
--entrypoint=/home/weave/weaveproxy \
|
||||
$WEAVEPROXY_DOCKER_ARGS $EXEC_IMAGE $PROXY_ARGS)
|
||||
wait_for_log $PROXY_CONTAINER_NAME "proxy listening"
|
||||
@@ -1130,7 +1160,7 @@ case "$COMMAND" in
|
||||
shift $(dns_arg_count "$@")
|
||||
collect_cidr_args "$@"
|
||||
shift $CIDR_ARG_COUNT
|
||||
CONTAINER=$(docker run $DNS_ARGS -d "$@")
|
||||
CONTAINER=$(docker run -e WEAVE_CIDR=none $DNS_ARGS -d "$@")
|
||||
create_bridge
|
||||
ipam_cidrs_or_die $CONTAINER $CIDR_ARGS
|
||||
with_container_netns_or_die $CONTAINER attach $ALL_CIDRS
|
||||
|
||||
Reference in new issue
Block a user