diff --git a/README.md b/README.md index 453f3ccf..2e1adff8 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ it locally to control a weave network on a remote host. ## Quick Start Screencast - + diff --git a/circle.yml b/circle.yml index 7b23b9f1..4bc4d29b 100644 --- a/circle.yml +++ b/circle.yml @@ -41,9 +41,9 @@ test: parallel: true - cd $SRCDIR/test; ./gce.sh setup: parallel: true - - cd $SRCDIR/test; . ./gce.sh hosts; ./setup.sh: + - cd $SRCDIR/test; eval $(./gce.sh hosts); ./setup.sh: parallel: true - - cd $SRCDIR/test; . ./gce.sh hosts; export COVERAGE=true; ./run_all.sh: + - cd $SRCDIR/test; eval $(./gce.sh hosts); export COVERAGE=true; ./run_all.sh: parallel: true timeout: 300 post: diff --git a/docs/hello-screencast.png b/docs/hello-screencast.png index 70ac6ed3..1833429e 100644 Binary files a/docs/hello-screencast.png and b/docs/hello-screencast.png differ diff --git a/nameserver/nameserver.go b/nameserver/nameserver.go index 5a2e7cb0..c6822bec 100644 --- a/nameserver/nameserver.go +++ b/nameserver/nameserver.go @@ -137,6 +137,7 @@ func (n *Nameserver) ContainerDied(ident string) error { } func (n *Nameserver) PeerGone(peer *router.Peer) { + n.infof("peer gone %s", peer.String()) n.Lock() defer n.Unlock() n.entries.filter(func(e *Entry) bool { diff --git a/proxy/create_container_interceptor.go b/proxy/create_container_interceptor.go index 9381d983..6fa255f8 100644 --- a/proxy/create_container_interceptor.go +++ b/proxy/create_container_interceptor.go @@ -25,9 +25,9 @@ type createContainerRequestBody struct { MacAddress string `json:"MacAddress,omitempty" yaml:"MacAddress,omitempty"` } -// Replacement for 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. +// 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 } @@ -48,7 +48,9 @@ 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 { + Log.Infof("Ignoring container due to %s", err) + } else { Log.Infof("Creating container with WEAVE_CIDR \"%s\"", strings.Join(cidrs, " ")) if container.HostConfig == nil { container.HostConfig = &docker.HostConfig{} diff --git a/proxy/create_exec_interceptor.go b/proxy/create_exec_interceptor.go index 3a1af205..8b89a53a 100644 --- a/proxy/create_exec_interceptor.go +++ b/proxy/create_exec_interceptor.go @@ -30,8 +30,10 @@ func (i *createExecInterceptor) InterceptRequest(r *http.Request) error { } _, hasWeaveWait := container.Volumes["/w"] - cidrs, hasCIDRs := i.proxy.weaveCIDRsFromConfig(container.Config) - if hasCIDRs && hasWeaveWait { + cidrs, err := i.proxy.weaveCIDRsFromConfig(container.Config, container.HostConfig) + if err != nil { + Log.Infof("Ignoring container %s due to %s", container.ID, err) + } else if hasWeaveWait { Log.Infof("Exec in container %s with WEAVE_CIDR \"%s\"", container.ID, strings.Join(cidrs, " ")) cmd := append(weaveWaitEntrypoint, "-s") options.Cmd = append(cmd, options.Cmd...) diff --git a/proxy/proxy.go b/proxy/proxy.go index 214bff22..5f1bbb06 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -2,6 +2,7 @@ package proxy import ( "crypto/tls" + "errors" "fmt" "net" "net/http" @@ -26,6 +27,10 @@ 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$") + + ErrInvalidNetworkMode = errors.New("--net option") + ErrWeaveCIDRNone = errors.New("WEAVE_CIDR=none") + ErrNoDefaultIPAM = errors.New("--no-default-ipam option") ) type Config struct { @@ -191,14 +196,22 @@ func (proxy *Proxy) listen(protoAndAddr string) (net.Listener, string, error) { return listener, fmt.Sprintf("%s://%s", proto, addr), nil } -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 != "bridge" { + return nil, ErrInvalidNetworkMode + } 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 } diff --git a/proxy/start_container_interceptor.go b/proxy/start_container_interceptor.go index 1a4de456..7353c07e 100644 --- a/proxy/start_container_interceptor.go +++ b/proxy/start_container_interceptor.go @@ -21,9 +21,9 @@ func (i *startContainerInterceptor) InterceptResponse(r *http.Response) error { return err } - cidrs, ok := i.proxy.weaveCIDRsFromConfig(container.Config) - if !ok { - Log.Debug("No Weave CIDR, ignoring") + cidrs, err := i.proxy.weaveCIDRsFromConfig(container.Config, container.HostConfig) + if err != nil { + Log.Infof("Ignoring container %s due to %s", container.ID, err) return nil } Log.Infof("Attaching container %s with WEAVE_CIDR \"%s\" to weave network", container.ID, strings.Join(cidrs, " ")) diff --git a/test/210_dns_cross_hosts_test.sh b/test/210_dns_cross_hosts_test.sh index 1d936e3e..7f134654 100755 --- a/test/210_dns_cross_hosts_test.sh +++ b/test/210_dns_cross_hosts_test.sh @@ -36,6 +36,31 @@ start_container_with_dns $HOST1 --name=baz assert_dns_record $HOST1 baz foo.weave.local $FOO_IPS assert_dns_record $HOST1 baz bar.weave.local $BAR_IPS +# now stop and start the containers a bunch of times +# this tests gossip dns tombstone behaviour +for i in $(seq 5); do + for host in $HOSTS; do + proxy docker_on $host kill foo 1>/dev/null + proxy docker_on $host kill bar 1>/dev/null + done + + assert_no_dns_record $HOST1 baz foo.weave.local + assert_no_dns_record $HOST1 baz bar.weave.local + + FOO_IPS= + BAR_IPS= + for host in $HOSTS; do + proxy docker_on $host start foo 1>/dev/null + proxy docker_on $host start bar 1>/dev/null + + FOO_IPS="$FOO_IPS $(container_ip $host foo)" + BAR_IPS="$BAR_IPS $(container_ip $host bar)" + done + + assert_dns_record $HOST1 baz foo.weave.local $FOO_IPS + assert_dns_record $HOST1 baz bar.weave.local $BAR_IPS +done + # resolution for names mapped to multiple addresses weave_on $HOST2 dns-add $C2a c2 -h $NAME2 weave_on $HOST2 dns-add $C2b c2 -h $NAME2 diff --git a/test/660_proxy_ipam_test.sh b/test/660_proxy_ipam_test.sh index 0e27b5ec..24c37679 100755 --- a/test/660_proxy_ipam_test.sh +++ b/test/660_proxy_ipam_test.sh @@ -26,13 +26,21 @@ start $HOST1 --name=auto start $HOST1 --name=none -e WEAVE_CIDR=none start $HOST2 --name=zero -e WEAVE_CIDR= start $HOST2 --name=no-default +start $HOST1 --name=bridge --net=bridge +start $HOST1 --name=host --net=host +start $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 diff --git a/test/gce.sh b/test/gce.sh index 192af733..dd1cb63b 100755 --- a/test/gce.sh +++ b/test/gce.sh @@ -5,7 +5,7 @@ # ./gce.sh destroy - tear down the VMs # ./gce.sh make_template - make a fresh VM template; update TEMPLATE_NAME first! -set -ex +set -e KEY_FILE=/tmp/gce_private_key.json SSH_KEY_FILE=$HOME/.ssh/gce_ssh_key @@ -20,7 +20,7 @@ if [ -n "$CIRCLECI" ]; then fi # Setup authentication -gcloud auth activate-service-account --key-file $KEY_FILE +gcloud auth activate-service-account --key-file $KEY_FILE 1>/dev/null gcloud config set project $PROJECT function vm_names { @@ -120,9 +120,9 @@ function hosts { hosts="$hostname $hosts" args="--add-host=$hostname:$(internal_ip $name) $args" done - export SSH=ssh - export HOSTS="$hosts" - export WEAVE_DOCKER_ARGS="$args" + echo export SSH=ssh + echo export HOSTS=\"$hosts\" + echo export WEAVE_DOCKER_ARGS=\"$args\" } case "$1" in