diff --git a/Makefile b/Makefile index d802efc0..c27dbc3d 100644 --- a/Makefile +++ b/Makefile @@ -96,7 +96,7 @@ $(WEAVER_UPTODATE): prog/weaver/Dockerfile $(WEAVER_EXE) $(SUDO) docker build -t $(WEAVER_IMAGE) prog/weaver touch $@ -$(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile $(DOCKER_DISTRIB) weave $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(NETCHECK_EXE) $(DOCKERTLSARGS_EXE) +$(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile prog/weaveexec/symlink $(DOCKER_DISTRIB) weave $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEWAIT_NOOP_EXE) $(NETCHECK_EXE) $(DOCKERTLSARGS_EXE) cp weave prog/weaveexec/weave cp $(SIGPROXY_EXE) prog/weaveexec/sigproxy cp $(WEAVEPROXY_EXE) prog/weaveexec/weaveproxy diff --git a/prog/weaveexec/Dockerfile b/prog/weaveexec/Dockerfile index 3003d03e..2b44f344 100644 --- a/prog/weaveexec/Dockerfile +++ b/prog/weaveexec/Dockerfile @@ -18,7 +18,7 @@ RUN apk add --update \ bind-tools \ && rm -rf /var/cache/apk/* -ADD ./weave ./sigproxy ./weaveproxy /home/weave/ +ADD ./weave ./sigproxy ./weaveproxy ./symlink /home/weave/ ADD ./netcheck ./docker_tls_args /usr/bin/ ADD ./weavewait /w/w ADD ./weavewait_noop /w-noop/w diff --git a/prog/weaveexec/symlink b/prog/weaveexec/symlink new file mode 100755 index 00000000..56078149 --- /dev/null +++ b/prog/weaveexec/symlink @@ -0,0 +1,18 @@ +#!/bin/sh +# This lets us force-symlink a bunch of stuff all at once, so we can minimize +# running containers. + +set -e + +[ -z "$DEBUG" ] || set -x + +target="$1" +user="$(stat -c '%u:%g' "$target")" +mode="$(stat -c '%a' "$target")" +shift 1 + +for link in "$@" ; do + ln -sfT "$target" "$link" +done +chown -h "$user" "$@" +chmod "$mode" "$@" diff --git a/prog/weaveproxy/main.go b/prog/weaveproxy/main.go index b166d5b3..9db07cd5 100644 --- a/prog/weaveproxy/main.go +++ b/prog/weaveproxy/main.go @@ -19,7 +19,7 @@ func main() { var ( justVersion bool logLevel = "info" - c = proxy.Config{ListenAddrs: []string{}} + c = proxy.Config{Image: "weaveworks/weaveexec"} ) c.Version = version @@ -53,6 +53,10 @@ func main() { SetLogLevel(logLevel) + if image := os.Getenv("EXEC_IMAGE"); image != "" { + c.Image = image + } + Log.Infoln("weave proxy", version) Log.Infoln("Command line arguments:", strings.Join(os.Args[1:], " ")) diff --git a/proxy/proxy.go b/proxy/proxy.go index d6fdaa13..b43a288f 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -1,6 +1,7 @@ package proxy import ( + "bytes" "crypto/tls" "errors" "fmt" @@ -8,6 +9,7 @@ import ( "net" "net/http" "os" + "path/filepath" "regexp" "strings" "sync" @@ -25,6 +27,9 @@ const ( defaultCertFile = "cert.pem" dockerSock = "/var/run/docker.sock" dockerSockUnix = "unix://" + dockerSock + + weaveSock = "/var/run/weave/weave.sock" + weaveSockUnix = "unix://" + weaveSock ) var ( @@ -46,6 +51,7 @@ type Config struct { HostnameFromLabel string HostnameMatch string HostnameReplacement string + Image string ListenAddrs []string RewriteInspect bool NoDefaultIPAM bool @@ -186,7 +192,12 @@ func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (proxy *Proxy) Listen() []net.Listener { listeners := []net.Listener{} proxy.normalisedAddrs = []string{} + unixAddrs := []string{} for _, addr := range proxy.ListenAddrs { + if strings.HasPrefix(addr, "unix://") { + unixAddrs = append(unixAddrs, addr) + continue + } listener, normalisedAddr, err := proxy.listen(addr) if err != nil { Log.Fatalf("Cannot listen on %s: %s", addr, err) @@ -195,6 +206,20 @@ func (proxy *Proxy) Listen() []net.Listener { proxy.normalisedAddrs = append(proxy.normalisedAddrs, normalisedAddr) } + if len(unixAddrs) > 0 { + listener, _, err := proxy.listen(weaveSockUnix) + if err != nil { + Log.Fatalf("Cannot listen on %s: %s", weaveSockUnix, err) + } + listeners = append(listeners, listener) + + if err := proxy.symlink(unixAddrs); err != nil { + Log.Fatalf("Cannot listen on unix sockets: %s", err) + } + + proxy.normalisedAddrs = append(proxy.normalisedAddrs, weaveSockUnix) + } + for _, addr := range proxy.normalisedAddrs { Log.Infoln("proxy listening on", addr) } @@ -527,3 +552,74 @@ func (proxy *Proxy) updateContainerNetworkSettings(container jsonObject) error { networkSettings["IPPrefixLen"], _ = nets[0].Mask.Size() return nil } + +func (proxy *Proxy) symlink(unixAddrs []string) (err error) { + var container *docker.Container + binds := []string{"/var/run/weave:/var/run/weave"} + froms := []string{} + for _, addr := range unixAddrs { + if addr == weaveSockUnix { + continue + } + from := strings.TrimPrefix(addr, "unix://") + dir := filepath.Dir(from) + binds = append(binds, dir+":"+filepath.Join("/host", dir)) + froms = append(froms, filepath.Join("/host", from)) + proxy.normalisedAddrs = append(proxy.normalisedAddrs, addr) + } + if len(froms) == 0 { + return nil + } + + env := []string{ + "PATH=/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + } + + if val := os.Getenv("DEBUG"); val != "" { + env = append(env, fmt.Sprintf("%s=%s", "DEBUG", val)) + } + + container, err = proxy.client.CreateContainer(docker.CreateContainerOptions{ + Config: &docker.Config{ + Image: proxy.Image, + Entrypoint: []string{"/home/weave/symlink", weaveSock}, + Cmd: froms, + Env: env, + }, + HostConfig: &docker.HostConfig{Binds: binds}, + }) + if err != nil { + return err + } + + defer func() { + err2 := proxy.client.RemoveContainer(docker.RemoveContainerOptions{ID: container.ID}) + if err == nil { + err = err2 + } + }() + + if err := proxy.client.StartContainer(container.ID, nil); err != nil { + return err + } + + var buf bytes.Buffer + err = proxy.client.AttachToContainer(docker.AttachToContainerOptions{ + Container: container.ID, + ErrorStream: &buf, + Logs: true, + Stderr: true, + }) + if err != nil { + return err + } + + rc, err := proxy.client.WaitContainer(container.ID) + if err != nil { + return err + } + if rc != 0 { + return errors.New(buf.String()) + } + return nil +} diff --git a/test/650_proxy_env_test.sh b/test/650_proxy_env_test.sh index 593f3d6d..345f661e 100755 --- a/test/650_proxy_env_test.sh +++ b/test/650_proxy_env_test.sh @@ -28,4 +28,10 @@ weave_on $HOST1 stop weave_on $HOST1 launch-proxy -H tcp://0.0.0.0:12375 -H unix:///var/run/weave/weave.sock check +# Check we can use weave env/config with unix -Hs specified +weave_on $HOST1 stop +weave_on $HOST1 launch-proxy -H unix:///var/run/weave/weave.sock +assert_raises "run_on $HOST1 'eval \$(weave env) ; docker $CMD'" +assert_raises "run_on $HOST1 'docker \$(weave config) $CMD'" + end_suite diff --git a/test/690_proxy_autoconfig_test.sh b/test/690_proxy_config_test.sh similarity index 81% rename from test/690_proxy_autoconfig_test.sh rename to test/690_proxy_config_test.sh index ce6e18b2..6293a3f5 100755 --- a/test/690_proxy_autoconfig_test.sh +++ b/test/690_proxy_config_test.sh @@ -2,7 +2,7 @@ . ./config.sh -start_suite "Boot the proxy should only listen on client's interface" +start_suite "Various launch-proxy configurations" # Booting it over unix socket listens on unix socket run_on $HOST1 COVERAGE=$COVERAGE sudo -E weave launch-proxy @@ -22,6 +22,11 @@ assert_raises "run_on $HOST1 sudo docker -H unix:///var/run/weave/weave.sock ps" assert_raises "proxy docker_on $HOST1 ps" weave_on $HOST1 stop-proxy +# Booting it with -H outside /var/run/weave, still works +socket="$(mktemp -d)/weave.sock" +weave_on $HOST1 launch-proxy -H unix://$socket +assert_raises "run_on $HOST1 sudo docker -H unix:///$socket ps" 0 +weave_on $HOST1 stop-proxy # Booting it over tls errors assert_raises "DOCKER_CLIENT_ARGS='--tls' weave_on $HOST1 launch-proxy" 1 diff --git a/weave b/weave index 30acc00e..55300e55 100755 --- a/weave +++ b/weave @@ -1275,17 +1275,30 @@ tls_arg() { PROXY_ARGS="$PROXY_ARGS $1 /home/weave/tls/$3.pem" } +# TODO: Handle relative paths for args +# TODO: Handle args with spaces +host_arg() { + PROXY_HOST="$1" + if [ "$PROXY_HOST" != "${PROXY_HOST#unix://}" ]; then + host=$(dirname ${PROXY_HOST#unix://}) + if [ "$host" = "${host#/}" ]; then + echo "When launching the proxy, unix sockets must be specified as an absolute path." >&2 + exit 1 + fi + PROXY_VOLUMES="$PROXY_VOLUMES -v /var/run/weave:/var/run/weave" + fi + PROXY_ARGS="$PROXY_ARGS -H $1" +} + proxy_parse_args() { while [ $# -gt 0 ]; do case "$1" in -H) - PROXY_HOST="$2" - PROXY_ARGS="$PROXY_ARGS $1 $2" + host_arg "$2" shift ;; -H=*) - PROXY_HOST="${1#*=}" - PROXY_ARGS="$PROXY_ARGS $1" + host_arg "${1#*=}" ;; -no-detect-tls|--no-detect-tls) PROXY_TLS_DETECTION_DISABLED=1 @@ -1346,7 +1359,7 @@ proxy_args() { PROXY_HOST="tcp://0.0.0.0:12375" ;; esac - PROXY_ARGS="$PROXY_ARGS -H $PROXY_HOST" + host_arg "$PROXY_HOST" fi } @@ -1559,6 +1572,7 @@ launch_proxy() { -e DOCKER_BRIDGE \ -e WEAVE_DEBUG \ -e COVERAGE \ + -e EXEC_IMAGE=$EXEC_IMAGE \ --entrypoint=/home/weave/weaveproxy \ $WEAVEPROXY_DOCKER_ARGS $EXEC_IMAGE $COVERAGE_ARGS $PROXY_ARGS) wait_for_status $PROXY_CONTAINER_NAME http_call_unix $PROXY_CONTAINER_NAME status.sock