Merge pull request #655 from paulbellamy/proxy-minimal

Minimal implementation of the proxy

closes #47, closes #230, closes #251, closes #400.
This commit is contained in:
Matthias Radestock committed 2015-05-19 10:59:00 +01:00
commit 8b66b8ae47
22 files changed
+787 -7

No files matched your search

+4
View File
@@ -32,7 +32,9 @@ coverage.html
# Project specific
weaver/weaver
weavedns/weavedns
weaveproxy/weaveproxy
sigproxy/sigproxy
weavewait/weavewait
tools/bin
tools/build
releases
@@ -40,6 +42,8 @@ weave.tar
weavedns.tar
weaveexec.tar
weaveexec/weave
weaveexec/weaveproxy
weaveexec/weavewait
weaveexec/sigproxy
weaveexec/docker*.tgz
Vagrantfile.local
+11 -5
View File
@@ -10,7 +10,9 @@ DOCKERHUB_USER=weaveworks
WEAVE_VERSION=git-$(shell git rev-parse --short=12 HEAD)
WEAVER_EXE=weaver/weaver
WEAVEDNS_EXE=weavedns/weavedns
WEAVEPROXY_EXE=weaveproxy/weaveproxy
SIGPROXY_EXE=sigproxy/sigproxy
WEAVEWAIT_EXE=weavewait/weavewait
WEAVER_IMAGE=$(DOCKERHUB_USER)/weave
WEAVEDNS_IMAGE=$(DOCKERHUB_USER)/weavedns
WEAVEEXEC_IMAGE=$(DOCKERHUB_USER)/weaveexec
@@ -27,9 +29,9 @@ all: $(WEAVER_EXPORT) $(WEAVEDNS_EXPORT) $(WEAVEEXEC_EXPORT)
travis: $(WEAVER_EXE) $(WEAVEDNS_EXE)
update:
go get -u -f -v -tags -netgo ./$(dir $(WEAVER_EXE)) ./$(dir $(WEAVEDNS_EXE)) ./$(dir $(SIGPROXY_EXE))
go get -u -f -v -tags -netgo ./$(dir $(WEAVER_EXE)) ./$(dir $(WEAVEDNS_EXE)) ./$(dir $(SIGPROXY_EXE)) ./$(dir $(WEAVEPROXY_EXE))
$(WEAVER_EXE) $(WEAVEDNS_EXE): common/*.go
$(WEAVER_EXE) $(WEAVEDNS_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE): common/*.go
go get -tags netgo ./$(@D)
go build -ldflags "-extldflags \"-static\" -X main.version $(WEAVE_VERSION)" -tags netgo -o $@ ./$(@D)
@strings $@ | grep cgo_stub\\\.go >/dev/null || { \
@@ -43,6 +45,8 @@ $(WEAVER_EXE) $(WEAVEDNS_EXE): common/*.go
$(WEAVER_EXE): router/*.go ipam/*.go ipam/*/*.go weaver/main.go
$(WEAVEDNS_EXE): nameserver/*.go weavedns/main.go
$(WEAVEPROXY_EXE): proxy/*.go weaveproxy/main.go
$(WEAVEWAIT_EXE): weavewait/*.go weavewait/main.go
# Sigproxy needs separate rule as it fails the netgo check in the main
# build stanza due to not importing net package
@@ -57,9 +61,11 @@ $(WEAVEDNS_EXPORT): weavedns/Dockerfile $(WEAVEDNS_EXE)
$(SUDO) docker build -t $(WEAVEDNS_IMAGE) weavedns
$(SUDO) docker save $(WEAVEDNS_IMAGE):latest > $@
$(WEAVEEXEC_EXPORT): weaveexec/Dockerfile $(DOCKER_DISTRIB) weave $(SIGPROXY_EXE)
$(WEAVEEXEC_EXPORT): weaveexec/Dockerfile $(DOCKER_DISTRIB) weave $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE)
cp weave weaveexec/weave
cp sigproxy/sigproxy weaveexec/sigproxy
cp $(SIGPROXY_EXE) weaveexec/sigproxy
cp $(WEAVEWAIT_EXE) weaveexec/weavewait
cp $(WEAVEPROXY_EXE) weaveexec/weaveproxy
cp $(DOCKER_DISTRIB) weaveexec/docker.tgz
$(SUDO) docker build -t $(WEAVEEXEC_IMAGE) weaveexec
$(SUDO) docker save $(WEAVEEXEC_IMAGE):latest > $@
@@ -92,7 +98,7 @@ publish: $(PUBLISH)
clean:
-$(SUDO) docker rmi $(WEAVER_IMAGE) $(WEAVEDNS_IMAGE) $(WEAVEEXEC_IMAGE)
rm -f $(WEAVER_EXE) $(WEAVEDNS_EXE) $(SIGPROXY_EXE) $(WEAVER_EXPORT) $(WEAVEDNS_EXPORT) $(WEAVEEXEC_EXPORT)
rm -f $(WEAVER_EXE) $(WEAVEDNS_EXE) $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVER_EXPORT) $(WEAVEDNS_EXPORT) $(WEAVEEXEC_EXPORT)
build:
$(SUDO) go clean -i net
+167
View File
@@ -0,0 +1,167 @@
package proxy
import (
"bufio"
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/http/httputil"
"github.com/fsouza/go-dockerclient"
. "github.com/weaveworks/weave/common"
)
type client struct {
interceptor
Dial func() (net.Conn, error)
}
func newClient(dial func() (net.Conn, error), i interceptor) *client {
return &client{
interceptor: i,
Dial: dial,
}
}
func (c *client) ServeHTTP(w http.ResponseWriter, r *http.Request) {
err := c.InterceptRequest(r)
if err == docker.ErrNoSuchImage {
http.NotFound(w, r)
return
}
if err != nil {
http.Error(w, "Unable to intercept request", http.StatusInternalServerError)
Warning.Print("Error intercepting request: ", err)
return
}
conn, err := c.Dial()
if err != nil {
http.Error(w, "Could not connect to target", http.StatusInternalServerError)
Warning.Print(err)
return
}
client := httputil.NewClientConn(conn, nil)
defer client.Close()
resp, err := client.Do(r)
if err != nil && err != httputil.ErrPersistEOF {
http.Error(w, fmt.Sprintf("Could not make request to target: %v", err), http.StatusInternalServerError)
Warning.Print("Error forwarding request: ", err)
return
}
err = c.InterceptResponse(resp)
if err != nil {
http.Error(w, "Unable to intercept response", http.StatusInternalServerError)
Warning.Print("Error intercepting response: ", err)
return
}
hdr := w.Header()
for k, vs := range resp.Header {
for _, v := range vs {
hdr.Add(k, v)
}
}
Debug.Printf("Response from target: %s %v", resp.Status, w.Header())
if resp.Header.Get("Content-Type") == "application/vnd.docker.raw-stream" {
doRawStream(w, resp, client)
} else if resp.TransferEncoding != nil && resp.TransferEncoding[0] == "chunked" {
doChunkedResponse(w, resp, client)
} else {
w.WriteHeader(resp.StatusCode)
if _, err := io.Copy(w, resp.Body); err != nil {
Warning.Print(err)
}
}
}
func doRawStream(w http.ResponseWriter, resp *http.Response, client *httputil.ClientConn) {
down, downBuf, up, rem, err := hijack(w, client)
if err != nil {
http.Error(w, "Unable to hijack connection for raw stream mode", http.StatusInternalServerError)
return
}
defer down.Close()
defer up.Close()
if _, err := down.Write([]byte("HTTP/1.1 200 OK\n")); err != nil {
Warning.Print(err)
return
}
if err := resp.Header.Write(down); err != nil {
Warning.Print(err)
return
}
if _, err := down.Write([]byte("\n")); err != nil {
Warning.Print(err)
return
}
upDone := make(chan struct{})
downDone := make(chan struct{})
go copyStream(down, io.MultiReader(rem, up), upDone)
go copyStream(up, downBuf, downDone)
<-upDone
<-downDone
}
func copyStream(dst io.Writer, src io.Reader, done chan struct{}) {
defer close(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)
}
}
}
func doChunkedResponse(w http.ResponseWriter, resp *http.Response, client *httputil.ClientConn) {
// Because we can't go back to request/response after we
// hijack the connection, we need to close it and make the
// client open another.
w.Header().Add("Connection", "close")
w.WriteHeader(resp.StatusCode)
down, _, up, rem, err := hijack(w, client)
if err != nil {
http.Error(w, "Unable to hijack response stream for chunked response", http.StatusInternalServerError)
return
}
defer up.Close()
defer down.Close()
// Copy the chunked response body to downstream,
// stopping at the end of the chunked section.
rawResponseBody := io.MultiReader(rem, up)
if _, err := io.Copy(ioutil.Discard, httputil.NewChunkedReader(io.TeeReader(rawResponseBody, down))); err != nil {
http.Error(w, "Error copying chunked response body", http.StatusInternalServerError)
return
}
resp.Trailer.Write(down)
// a chunked response ends with a CRLF
down.Write([]byte("\r\n"))
}
func hijack(w http.ResponseWriter, client *httputil.ClientConn) (down net.Conn, downBuf *bufio.ReadWriter, up net.Conn, rem io.Reader, err error) {
hj, ok := w.(http.Hijacker)
if !ok {
err = errors.New("Unable to cast to Hijack")
return
}
down, downBuf, err = hj.Hijack()
if err != nil {
return
}
up, rem = client.Hijack()
return
}
+28
View File
@@ -0,0 +1,28 @@
package proxy
import (
"os/exec"
"strings"
"github.com/fsouza/go-dockerclient"
. "github.com/weaveworks/weave/common"
)
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"}
out, err := cmd.CombinedOutput()
return out, err
}
func weaveCIDRsFromConfig(config *docker.Config) ([]string, bool) {
for _, e := range config.Env {
if strings.HasPrefix(e, "WEAVE_CIDR=") {
result := strings.Trim(e[11:], " ")
return strings.Split(strings.TrimSpace(result), " "), result != ""
}
}
return nil, false
}
+105
View File
@@ -0,0 +1,105 @@
package proxy
import (
"bytes"
"encoding/json"
"io/ioutil"
"net/http"
"github.com/fsouza/go-dockerclient"
)
type createContainerInterceptor struct {
client *docker.Client
withDNS bool
dockerBridgeIP string
}
type createContainerRequestBody struct {
*docker.Config
HostConfig *docker.HostConfig `json:"HostConfig,omitempty" yaml:"HostConfig,omitempty"`
MacAddress string `json:"MacAddress,omitempty" yaml:"MacAddress,omitempty"`
}
func (i *createContainerInterceptor) InterceptRequest(r *http.Request) error {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
return err
}
r.Body.Close()
container := createContainerRequestBody{}
if err := json.Unmarshal(body, &container); err != nil {
return err
}
if _, ok := weaveCIDRsFromConfig(container.Config); ok {
container.HostConfig.VolumesFrom = append(container.HostConfig.VolumesFrom, "weaveproxy")
if err := i.setWeaveWaitEntrypoint(container.Config); err != nil {
return err
}
if err := i.setWeaveDNS(&container); err != nil {
return err
}
}
newBody, err := json.Marshal(container)
if err != nil {
return err
}
r.Body = ioutil.NopCloser(bytes.NewReader(newBody))
r.ContentLength = int64(len(newBody))
return nil
}
func (i *createContainerInterceptor) setWeaveWaitEntrypoint(container *docker.Config) error {
var image *docker.Config
if !configHasEntrypoint(container) || !configHasCmd(container) {
imageInfo, err := i.client.InspectImage(container.Image)
if err != nil {
return err
}
image = imageInfo.Config
}
var entry, command []string
if configHasEntrypoint(container) {
entry = container.Entrypoint
} else if configHasEntrypoint(image) {
entry = image.Entrypoint
}
if configHasCmd(container) {
command = container.Cmd
} else if configHasCmd(image) {
command = image.Cmd
}
container.Entrypoint = []string{"/home/weavewait/weavewait"}
container.Cmd = append(entry, command...)
return nil
}
func configHasEntrypoint(c *docker.Config) bool {
return c != nil && len(c.Entrypoint) > 0
}
func configHasCmd(c *docker.Config) bool {
return c != nil && len(c.Cmd) > 0
}
func (i *createContainerInterceptor) setWeaveDNS(container *createContainerRequestBody) error {
if !i.withDNS {
return nil
}
container.HostConfig.DNS = append(container.HostConfig.DNS, i.dockerBridgeIP)
if len(container.HostConfig.DNSSearch) == 0 {
container.HostConfig.DNSSearch = []string{"."}
}
return nil
}
func (i *createContainerInterceptor) InterceptResponse(r *http.Response) error {
return nil
}
+19
View File
@@ -0,0 +1,19 @@
package proxy
import "net/http"
type interceptor interface {
InterceptRequest(*http.Request) error
InterceptResponse(*http.Response) error
}
type nullInterceptor struct {
}
func (i nullInterceptor) InterceptRequest(r *http.Request) error {
return nil
}
func (i nullInterceptor) InterceptResponse(r *http.Response) error {
return nil
}
+80
View File
@@ -0,0 +1,80 @@
package proxy
import (
"net"
"net/http"
"net/url"
"regexp"
"strings"
"github.com/fsouza/go-dockerclient"
. "github.com/weaveworks/weave/common"
)
var (
containerCreateRegexp = regexp.MustCompile("/v[0-9\\.]*/containers/create")
containerStartRegexp = regexp.MustCompile("^/v[0-9\\.]*/containers/[^/]*/(re)?start$")
)
type Proxy struct {
Dial func() (net.Conn, error)
client *docker.Client
withDNS bool
dockerBridgeIP string
}
func NewProxy(targetURL string, withDNS bool) (*Proxy, error) {
u, err := url.Parse(targetURL)
if err != nil {
return nil, err
}
var dockerBridgeIP []byte
if withDNS {
dockerBridgeIP, err = callWeave("docker-bridge-ip")
if err != nil {
return nil, err
}
}
client, err := docker.NewClient(targetURL)
if err != nil {
return nil, err
}
targetAddr := ""
switch u.Scheme {
case "tcp":
targetAddr = u.Host
case "unix":
targetAddr = u.Path
}
return &Proxy{
Dial: func() (net.Conn, error) {
return net.Dial(u.Scheme, targetAddr)
},
client: client,
withDNS: withDNS,
dockerBridgeIP: string(dockerBridgeIP),
}, nil
}
func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
Info.Printf("%s %s", r.Method, r.URL)
path := r.URL.Path
switch {
case containerCreateRegexp.MatchString(path):
proxy.serveWithInterceptor(&createContainerInterceptor{proxy.client, proxy.withDNS, proxy.dockerBridgeIP}, w, r)
case containerStartRegexp.MatchString(path):
proxy.serveWithInterceptor(&startContainerInterceptor{proxy.client, proxy.withDNS}, w, r)
case strings.HasPrefix(path, "/weave"):
w.WriteHeader(http.StatusOK)
default:
proxy.serveWithInterceptor(&nullInterceptor{}, w, r)
}
}
func (proxy *Proxy) serveWithInterceptor(i interceptor, w http.ResponseWriter, r *http.Request) {
newClient(proxy.Dial, i).ServeHTTP(w, r)
}
+50
View File
@@ -0,0 +1,50 @@
package proxy
import (
"net/http"
"regexp"
"strings"
"github.com/fsouza/go-dockerclient"
. "github.com/weaveworks/weave/common"
)
var containerIDRegexp = regexp.MustCompile("^/v[0-9\\.]*/containers/([^/]*)/.*")
type startContainerInterceptor struct {
client *docker.Client
withDNS bool
}
func (i *startContainerInterceptor) InterceptRequest(r *http.Request) error {
return nil
}
func (i *startContainerInterceptor) InterceptResponse(r *http.Response) error {
if subs := containerIDRegexp.FindStringSubmatch(r.Request.URL.Path); subs == nil {
Warning.Printf("No container id found in request with path %s", r.Request.URL.Path)
return nil
}
containerID := subs[1]
container, err := i.client.InspectContainer(containerID)
if err != nil {
Warning.Printf("Error inspecting container %s: %v", containerID, err)
return nil
}
cidrs, ok := weaveCIDRsFromConfig(container.Config)
if !ok {
Debug.Print("No Weave CIDR, ignoring")
return nil
}
Info.Printf("Container %s was started with CIDR \"%s\"", containerID, strings.Join(cidrs, " "))
args := []string{"attach"}
args = append(args, cidrs...)
args = append(args, containerID)
if _, err := callWeave(args...); err != nil {
Warning.Printf("Attaching container %s to weave failed: %v", containerID, err)
return nil
}
return nil
}
+9 -1
View File
@@ -24,6 +24,7 @@ example](https://github.com/weaveworks/weave#example):
* [Fault tolerance](#fault-tolerance)
* [Automatic IP address management](#ipam)
* [Automatic discovery with WeaveDNS](#dns)
* [Proxy](#proxy)
### <a name="virtual-ethernet-switch"></a>Virtual Ethernet Switch
@@ -403,4 +404,11 @@ to enable and use this feature.
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).
out more about WeaveDNS from its [documentation](weavedns.html).
### <a name="proxy"></a>Proxy
The weave proxy enables you to use the docker command-line utility, allowing
weave-enabled containers to be started in the foreground, and to wait for the
weave network interface before running. Find out more about the weave proxy
from its [documentation](proxy.html).
+59
View File
@@ -0,0 +1,59 @@
---
title: Weave Proxy
layout: default
---
# <a name="weave-proxy"></a>Weave Proxy
Instead of the weave command-line utility, you may prefer to use the standard
docker command-line utility to manage containers. This will allow containers to
be started in foreground mode. It will also ensure that the weave network
interface is available before running your container.
## Setup
To do this, while still connecting containers to the weave network, you can use
the weave proxy. We can start the proxy with
host1$ weave launch-proxy
By default, the proxy will connect to docker at `unix:///var/run/docker.sock`,
and listen on port 12375. However, we can adjust the connection to docker via
the `-H` argument. All docker commands can be run via the proxy, so it is safe
to globally adjust your `DOCKER_HOST`.
host1$ export DOCKER_HOST="tcp://host1:12375"
host1$ docker ps
## Usage
When containers are created via the weave proxy, their entrypoint will be
modified to wait for the weave network interface to become available. When they are
started via the weave proxy, any IP addresses and networks specified in the
`WEAVE_CIDR` environment variable will be attached. We can create and start a
container via the weave proxy with
host1$ docker run -e WEAVE_CIDR=10.2.1.1/24 -ti ubuntu /bin/sh
or, equivalently with
host1$ docker create -e WEAVE_CIDR=10.2.1.1/24 -ti ubuntu /bin/sh
5ef831df61d50a1a49272357155a976595e7268e590f0a2c75693337b14e1382
host1$ docker start 5ef831df61d50a1a49272357155a976595e7268e590f0a2c75693337b14e1382
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`.
## Usage with WeaveDNS
Containers started via the proxy can be automatically configured to use WeaveDNS for name resolution. To accomplish this we need to launch the proxy with the `--with-dns` option
host1$ weave launch
host1$ weave launch-dns 10.2.254.1/24
host1$ weave launch-proxy --with-dns
With this done, any containers launched through the proxy will use weaveDNS for name resolution. WeaveDNS is used in addition to any dns servers specified via the `--dns` option. More details on weaveDNS can be found in the [weaveDNS documentation](weavedns.html).
## Limitations
* The proxy does not currently support TLS.
* If you have a firewall, you will need to make sure port 12375 is open.
+1 -1
View File
@@ -10,7 +10,7 @@ run_on $HOST1 sudo ./weave --local launch -iprange 10.2.5.0/24
assert_raises "docker_on $HOST1 ps | grep weave"
run_on $HOST1 sudo ./weave --local run 10.2.6.5/24 -ti --name=c1 gliderlabs/alpine /bin/sh
assert_raises "exec_on $HOST1 c1 ifconfig | grep ethwe"
assert_raises "exec_on $HOST1 c1 ip link show ethwe"
run_on $HOST1 sudo ./weave --local run -ti --name=c2 gliderlabs/alpine /bin/sh
assert_raises "exec_on $HOST1 c2 ifconfig | grep ethwe"
+16
View File
@@ -0,0 +1,16 @@
#! /bin/bash
. ./config.sh
start_suite "Run docker-py test suite against the proxy"
weave_on $HOST1 launch-proxy
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"
end_suite
+15
View File
@@ -0,0 +1,15 @@
#! /bin/bash
. ./config.sh
start_suite "Proxy waits for weave to be ready before running container commands"
weave_on $HOST1 launch-proxy
BASE_IMAGE=busybox
# Ensure the base image does not exist, so that it will be pulled
if (docker_on $HOST1 images $BASE_IMAGE | grep $BASE_IMAGE); then
docker_on $HOST1 rmi $BASE_IMAGE
fi
assert_raises "docker_proxy_on $HOST1 run -e 'WEAVE_CIDR=10.2.1.1/24' $BASE_IMAGE ip link show ethwe | grep 'state UP'"
end_suite
+14
View File
@@ -0,0 +1,14 @@
#! /bin/bash
. ./config.sh
start_suite "Proxy uses entrypoint from the image with weavewait"
weave_on $HOST1 launch-proxy
docker_on $HOST1 build -t inspect-ethwe - <<- EOF
FROM gliderlabs/alpine
ENTRYPOINT ["ip", "link", "show", "ethwe"]
EOF
assert_raises "docker_proxy_on $HOST1 run -e 'WEAVE_CIDR=10.2.1.1/24' inspect-ethwe | grep 'state UP'"
end_suite
+18
View File
@@ -0,0 +1,18 @@
#! /bin/bash
. ./config.sh
C1=10.2.0.78
C2=10.2.0.34
NAME=seetwo.weave.local
start_suite "Proxy registers containers with dns"
weave_on $HOST1 launch-dns 10.2.254.1/24
weave_on $HOST1 launch-proxy --with-dns
docker_proxy_on $HOST1 run -e WEAVE_CIDR=$C2/24 -dt --name=c2 -h $NAME gliderlabs/alpine /bin/sh
docker_proxy_on $HOST1 run -e WEAVE_CIDR=$C1/24 -dt --name=c1 aanand/docker-dnsutils /bin/sh
assert_dns_record $HOST1 c1 $NAME $C2
end_suite
+20
View File
@@ -0,0 +1,20 @@
#! /bin/bash
. ./config.sh
C1=10.2.0.78
C2=10.2.0.34
NAME=seetwo.weave.local
start_suite "Proxy restart reattaches networking to containers"
weave_on $HOST1 launch-dns 10.2.254.1/24
weave_on $HOST1 launch-proxy --with-dns
docker_proxy_on $HOST1 run -e WEAVE_CIDR=$C2/24 -dt --name=c2 -h $NAME gliderlabs/alpine /bin/sh
docker_proxy_on $HOST1 run -e WEAVE_CIDR=$C1/24 -dt --name=c1 aanand/docker-dnsutils /bin/sh
docker_proxy_on $HOST1 restart c2
assert_raises "exec_on $HOST1 c2 ip link show ethwe | grep 'state UP'"
assert_dns_record $HOST1 c1 $NAME $C2
end_suite
+14
View File
@@ -0,0 +1,14 @@
#! /bin/bash
. ./config.sh
start_suite "Proxy allows overridden entrypoint from the container with weavewait"
weave_on $HOST1 launch-proxy
docker_on $HOST1 build -t false - <<- EOF
FROM gliderlabs/alpine
ENTRYPOINT ["/bin/false"]
EOF
assert_raises "docker_proxy_on $HOST1 run -e 'WEAVE_CIDR=10.2.1.1/24' --entrypoint '/sbin/ip' false link show ethwe | grep 'state UP'"
end_suite
+7
View File
@@ -76,6 +76,13 @@ docker_on() {
docker -H tcp://$host:2375 "$@"
}
docker_proxy_on() {
host=$1
shift 1
greyly echo "Docker (with proxy) on $host: $@" >&2
docker -H tcp://$host:12375 "$@"
}
weave_on() {
host=$1
shift 1
+66
View File
@@ -27,6 +27,7 @@ usage() {
echo "weave setup"
echo "weave launch [-password <password>] [-nickname <nickname>] [-iprange <cidr>] <peer> ..."
echo "weave launch-dns <cidr>"
echo "weave launch-proxy [-H <docker_endpoint>] [--with-dns]"
echo "weave connect <peer>"
echo "weave forget <peer>"
echo "weave run [--with-dns] [<cidr> ...] <docker run args> ..."
@@ -679,6 +680,63 @@ get_ipam_cidr() {
fi
}
######################################################################
# weave proxy helpers
######################################################################
PROXY_PORT=12375
PROXY_CONTAINER_NAME=weaveproxy
proxy_host() {
case $DOCKER_HOST in
tcp://*)
PROXY_HOST=$(echo $DOCKER_HOST | sed -e "s|tcp://\([^:]*\):[0-9]*|\1|")
;;
*)
PROXY_HOST="localhost"
;;
esac
}
wait_for_proxy_to_boot() {
proxy_host
for n in `seq 1 10`; do
if curl --max-time 1 --connect-timeout 1 -s -X GET http://$PROXY_HOST:$PROXY_PORT/weave ; then
return 0
fi
sleep 1
done
echo "Proxy did not start within 10 seconds" >&2
return 1
}
ensure_proxy_running() {
case $(docker inspect --format '{{.State.Running}} {{.Config.Image}}' $PROXY_CONTAINER_NAME 2>/dev/null) in
"true $EXEC_IMAGE")
return 0
;;
true*)
echo "Proxy already running with unknown image" >&2
exit 1
;;
false*)
docker rm -f $PROXY_CONTAINER_NAME >/dev/null
;;
esac
# Set WEAVEPROXY_DOCKER_ARGS in the environment in order to supply
# additional parameters, such as resource limits, to docker
# when launching the weave proxy container.
PROXY_CONTAINER=$(docker run --privileged --net=host -d \
--name=$PROXY_CONTAINER_NAME \
-p $PROXY_PORT:$PROXY_PORT/tcp -v /var/run/docker.sock:/var/run/docker.sock \
-v /proc:/hostproc -e PROCFS=/hostproc \
--entrypoint=/home/weave/weaveproxy \
$WEAVE_DOCKER_ARGS $WEAVEPROXY_DOCKER_ARGS \
$EXEC_IMAGE "$@")
wait_for_proxy_to_boot
}
##########################################################################################
[ $(id -u) = 0 ] || {
@@ -807,6 +865,10 @@ case "$COMMAND" in
populate_dns
echo $DNS_CONTAINER
;;
launch-proxy)
ensure_proxy_running "$@"
echo $PROXY_CONTAINER
;;
connect)
[ $# -eq 1 ] || usage
http_call $CONTAINER_NAME $HTTP_PORT POST /connect -d "peer=$1"
@@ -859,6 +921,10 @@ case "$COMMAND" in
dns_args "$@"
echo -n $DNS_ARGS
;;
docker-bridge-ip)
docker_bridge_ip
echo -n $DOCKER_BRIDGE_IP
;;
start)
collect_cidr_args "$@"
shift $CIDR_COUNT
+4
View File
@@ -15,6 +15,10 @@ WORKDIR /home/weave
ADD ./weave /home/weave/
ADD ./sigproxy /home/weave/
ADD ./weaveproxy /home/weave/
ADD ./weavewait /home/weavewait/weavewait
ADD ./docker.tgz /
VOLUME /home/weavewait
ENTRYPOINT ["/home/weave/sigproxy", "/home/weave/weave"]
+54
View File
@@ -0,0 +1,54 @@
package main
import (
"fmt"
"net/http"
"code.google.com/p/getopt"
. "github.com/weaveworks/weave/common"
"github.com/weaveworks/weave/proxy"
)
var (
defaultTarget = "unix:///var/run/docker.sock"
defaultListen = ":12375"
)
func main() {
var target, listen string
var withDNS, debug bool
getopt.BoolVarLong(&debug, "debug", 'd', "log debugging information")
getopt.StringVar(&target, 'H', fmt.Sprintf("docker daemon URL to proxy (default %s)", defaultTarget))
getopt.StringVar(&listen, 'L', fmt.Sprintf("address on which to listen (default %s)", defaultListen))
getopt.BoolVarLong(&withDNS, "with-dns", 'w', "instruct created containers to use weaveDNS as their nameserver")
getopt.Parse()
if target == "" {
target = defaultTarget
}
if listen == "" {
listen = defaultListen
}
if debug {
InitDefaultLogging(true)
}
p, err := proxy.NewProxy(target, withDNS)
if err != nil {
Error.Fatalf("Could not start proxy: %s", err)
}
s := &http.Server{
Addr: listen,
Handler: p,
}
Info.Printf("Listening on %s", listen)
Info.Printf("Proxying %s", target)
if err := s.ListenAndServe(); err != nil {
Error.Fatalf("Could not listen on %s: %s", listen, err)
}
}
+26
View File
@@ -0,0 +1,26 @@
package main
import (
"fmt"
"os"
"os/exec"
"github.com/weaveworks/weave/net"
)
func main() {
if _, err := net.EnsureInterface("ethwe", 20); err != nil {
fmt.Fprintln(os.Stderr, err)
}
if len(os.Args) <= 1 {
os.Exit(0)
}
cmd := exec.Command(os.Args[1], os.Args[2:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
if err := cmd.Run(); err != nil {
os.Exit(1)
}
}