diff --git a/prog/weaveproxy/main.go b/prog/weaveproxy/main.go
index 23073b74..a6318321 100644
--- a/prog/weaveproxy/main.go
+++ b/prog/weaveproxy/main.go
@@ -29,6 +29,7 @@ func main() {
mflagext.ListVar(&c.ListenAddrs, []string{"H"}, nil, "addresses on which to listen")
mflag.StringVar(&c.HostnameMatch, []string{"-hostname-match"}, "(.*)", "Regexp pattern to apply on container names (e.g. '^aws-[0-9]+-(.*)$')")
mflag.StringVar(&c.HostnameReplacement, []string{"-hostname-replacement"}, "$1", "Expression to generate hostnames based on matches from --hostname-match (e.g. 'my-app-$1')")
+ mflag.BoolVar(&c.RewriteInspect, []string{"-rewrite-inspect"}, false, "Rewrite 'inspect' calls to return the weave network settings (if attached)")
mflag.BoolVar(&c.NoDefaultIPAM, []string{"#-no-default-ipam", "-no-default-ipalloc"}, false, "do not automatically allocate addresses for containers without a WEAVE_CIDR")
mflag.BoolVar(&c.NoRewriteHosts, []string{"-no-rewrite-hosts"}, false, "do not automatically rewrite /etc/hosts. Use if you need the docker IP to remain in /etc/hosts")
mflag.StringVar(&c.TLSConfig.CACert, []string{"#tlscacert", "-tlscacert"}, "", "Trust certs signed only by this CA")
diff --git a/proxy/common.go b/proxy/common.go
index 69d337e3..9da06f82 100644
--- a/proxy/common.go
+++ b/proxy/common.go
@@ -3,12 +3,15 @@ package proxy
import (
"bytes"
"encoding/json"
+ "errors"
"fmt"
"io/ioutil"
+ "net"
"net/http"
"os"
"os/exec"
"regexp"
+ "strings"
"github.com/fsouza/go-dockerclient"
. "github.com/weaveworks/weave/common"
@@ -62,3 +65,32 @@ func inspectContainerInPath(client *docker.Client, path string) (*docker.Contain
}
return container, err
}
+
+func weaveContainerIPs(container *docker.Container) (mac string, ips []net.IP, nets []*net.IPNet, err error) {
+ stdout, stderr, err := callWeave("ps", container.ID)
+ if err != nil || len(stderr) > 0 {
+ err = errors.New(string(stderr))
+ return
+ }
+ if len(stdout) <= 0 {
+ return
+ }
+
+ fields := strings.Fields(string(stdout))
+ if len(fields) < 2 {
+ return
+ }
+ mac = fields[1]
+
+ var ip net.IP
+ var ipnet *net.IPNet
+ for _, cidr := range fields[2:] {
+ ip, ipnet, err = net.ParseCIDR(cidr)
+ if err != nil {
+ return
+ }
+ ips = append(ips, ip)
+ nets = append(nets, ipnet)
+ }
+ return
+}
diff --git a/proxy/inspect_container_interceptor.go b/proxy/inspect_container_interceptor.go
new file mode 100644
index 00000000..791fd653
--- /dev/null
+++ b/proxy/inspect_container_interceptor.go
@@ -0,0 +1,60 @@
+package proxy
+
+import (
+ "bytes"
+ "encoding/json"
+ "io/ioutil"
+ "net/http"
+
+ "github.com/fsouza/go-dockerclient"
+ . "github.com/weaveworks/weave/common"
+)
+
+type inspectContainerInterceptor struct{ proxy *Proxy }
+
+func (i *inspectContainerInterceptor) InterceptRequest(r *http.Request) error {
+ return nil
+}
+
+func (i *inspectContainerInterceptor) InterceptResponse(r *http.Response) error {
+ if !i.proxy.RewriteInspect {
+ return nil
+ }
+
+ body, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return err
+ }
+ r.Body.Close()
+
+ container := &docker.Container{}
+ if err := json.Unmarshal(body, container); err != nil {
+ return err
+ }
+
+ if err := updateContainerNetworkSettings(container); err != nil {
+ Log.Warningf("Inspecting container %s failed: %s", container.ID, err)
+ }
+
+ newBody, err := json.Marshal(container)
+ if err != nil {
+ return err
+ }
+ r.Body = ioutil.NopCloser(bytes.NewReader(newBody))
+ r.ContentLength = int64(len(newBody))
+ r.TransferEncoding = nil // Stop it being chunked, because that hangs
+
+ return nil
+}
+
+func updateContainerNetworkSettings(container *docker.Container) error {
+ mac, ips, nets, err := weaveContainerIPs(container)
+ if err != nil || len(ips) == 0 {
+ return err
+ }
+
+ container.NetworkSettings.MacAddress = mac
+ container.NetworkSettings.IPAddress = ips[0].String()
+ container.NetworkSettings.IPPrefixLen, _ = nets[0].Mask.Size()
+ return nil
+}
diff --git a/proxy/inspect_exec_interceptor.go b/proxy/inspect_exec_interceptor.go
new file mode 100644
index 00000000..f12ecbcb
--- /dev/null
+++ b/proxy/inspect_exec_interceptor.go
@@ -0,0 +1,48 @@
+package proxy
+
+import (
+ "bytes"
+ "encoding/json"
+ "io/ioutil"
+ "net/http"
+
+ "github.com/fsouza/go-dockerclient"
+ . "github.com/weaveworks/weave/common"
+)
+
+type inspectExecInterceptor struct{ proxy *Proxy }
+
+func (i *inspectExecInterceptor) InterceptRequest(r *http.Request) error {
+ return nil
+}
+
+func (i *inspectExecInterceptor) InterceptResponse(r *http.Response) error {
+ if !i.proxy.RewriteInspect {
+ return nil
+ }
+
+ body, err := ioutil.ReadAll(r.Body)
+ if err != nil {
+ return err
+ }
+ r.Body.Close()
+
+ exec := &docker.ExecInspect{}
+ if err := json.Unmarshal(body, exec); err != nil {
+ return err
+ }
+
+ if err := updateContainerNetworkSettings(&exec.Container); err != nil {
+ Log.Warningf("Inspecting exec %s failed: %s", exec.ID, err)
+ }
+
+ newBody, err := json.Marshal(exec)
+ if err != nil {
+ return err
+ }
+ r.Body = ioutil.NopCloser(bytes.NewReader(newBody))
+ r.ContentLength = int64(len(newBody))
+ r.TransferEncoding = nil // Stop it being chunked, because that hangs
+
+ return nil
+}
diff --git a/proxy/proxy.go b/proxy/proxy.go
index 7d9f6ee8..0d91fe9e 100644
--- a/proxy/proxy.go
+++ b/proxy/proxy.go
@@ -24,9 +24,11 @@ const (
)
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$")
+ containerCreateRegexp = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/create$")
+ containerStartRegexp = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/[^/]*/(re)?start$")
+ containerInspectRegexp = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/[^/]*/json$")
+ execCreateRegexp = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/[^/]*/exec$")
+ execInspectRegexp = regexp.MustCompile("^(/v[0-9\\.]*)?/exec/[^/]*/json$")
ErrWeaveCIDRNone = errors.New("the container was created with the '-e WEAVE_CIDR=none' option")
ErrNoDefaultIPAM = errors.New("the container was created without specifying an IP address with '-e WEAVE_CIDR=...' and the proxy was started with the '--no-default-ipalloc' option")
@@ -36,6 +38,7 @@ type Config struct {
HostnameMatch string
HostnameReplacement string
ListenAddrs []string
+ RewriteInspect bool
NoDefaultIPAM bool
NoRewriteHosts bool
TLSConfig TLSConfig
@@ -123,8 +126,12 @@ func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
i = &createContainerInterceptor{proxy}
case containerStartRegexp.MatchString(path):
i = &startContainerInterceptor{proxy}
+ case containerInspectRegexp.MatchString(path):
+ i = &inspectContainerInterceptor{proxy}
case execCreateRegexp.MatchString(path):
i = &createExecInterceptor{proxy}
+ case execInspectRegexp.MatchString(path):
+ i = &inspectExecInterceptor{proxy}
default:
i = &nullInterceptor{}
}
diff --git a/site/proxy.md b/site/proxy.md
index 847ba8bb..ed54bd40 100644
--- a/site/proxy.md
+++ b/site/proxy.md
@@ -104,6 +104,12 @@ 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"`.
+The docker IP will still be returned by `docker inspect`. If you want
+`docker inspect` to return the weave IP instead, then the proxy must
+be launced with the `--rewrite-inspect` flag.
+
+ host1$ weave launch-router && weave launch-proxy --rewrite-inspect
+
## Automatic IP address assignment
If [automatic IP address assignment](ipam.html) is enabled in weave,
diff --git a/test/605_proxy_inspect_test.sh b/test/605_proxy_inspect_test.sh
new file mode 100755
index 00000000..15ba4fc5
--- /dev/null
+++ b/test/605_proxy_inspect_test.sh
@@ -0,0 +1,16 @@
+#! /bin/bash
+
+. ./config.sh
+
+start_suite "Check that docker inspect returns the weave IP"
+
+weave_on $HOST1 launch-router
+weave_on $HOST1 launch-proxy --rewrite-inspect
+
+proxy docker_on $HOST1 run -dt --name c1 $SMALL_IMAGE /bin/sh
+inspect_format="{{.Name}} {{.NetworkSettings.MacAddress}} {{.NetworkSettings.IPAddress}}/{{.NetworkSettings.IPPrefixLen}}"
+expected="/$(weave_on $HOST1 ps c1)"
+
+assert "proxy docker_on $HOST1 inspect --format='$inspect_format' c1" "$expected"
+
+end_suite
diff --git a/weave b/weave
index a1c4039b..6d6af191 100755
--- a/weave
+++ b/weave
@@ -56,6 +56,7 @@ weave launch-proxy [-H ] [--with-dns | --without-dns]
[--no-default-ipalloc] [--no-rewrite-hosts]
[--hostname-match ]
[--hostname-replacement ]
+ [--rewrite-inspect]
weave env [--restore]
weave config
weave connect [--replace] [ ...]