diff --git a/common/docker/client.go b/common/docker/client.go
index 1f2ee0df..6a4eaff1 100644
--- a/common/docker/client.go
+++ b/common/docker/client.go
@@ -7,6 +7,7 @@ import (
// An observer for container events
type ContainerObserver interface {
+ ContainerStarted(ident string)
ContainerDied(ident string)
}
@@ -22,12 +23,26 @@ func NewClient(apiPath string) (*Client, error) {
}
client := &Client{dc}
- env, err := client.Version()
+ return client, client.checkWorking(apiPath)
+}
+
+func NewVersionedClient(apiPath string, apiVersionString string) (*Client, error) {
+ dc, err := docker.NewVersionedClient(apiPath, apiVersionString)
if err != nil {
return nil, err
}
+ client := &Client{dc}
+
+ return client, client.checkWorking(apiPath)
+}
+
+func (c *Client) checkWorking(apiPath string) error {
+ env, err := c.Version()
+ if err != nil {
+ return err
+ }
Log.Infof("[docker] Using Docker API on %s: %v", apiPath, env)
- return client, nil
+ return nil
}
// AddObserver adds an observer for docker events
@@ -41,6 +56,9 @@ func (c *Client) AddObserver(ob ContainerObserver) error {
go func() {
for event := range events {
switch event.Status {
+ case "start":
+ id := event.ID
+ ob.ContainerStarted(id)
case "die":
id := event.ID
ob.ContainerDied(id)
diff --git a/ipam/allocator.go b/ipam/allocator.go
index 28f2e449..e3765aca 100644
--- a/ipam/allocator.go
+++ b/ipam/allocator.go
@@ -226,6 +226,8 @@ func (alloc *Allocator) ContainerDied(ident string) {
}
}
+func (alloc *Allocator) ContainerStarted(ident string) {}
+
// Delete (Sync) - release all IP addresses for container with given name
func (alloc *Allocator) Delete(ident string) error {
errChan := make(chan error)
diff --git a/nameserver/nameserver.go b/nameserver/nameserver.go
index dd6bcd6b..356e61e0 100644
--- a/nameserver/nameserver.go
+++ b/nameserver/nameserver.go
@@ -130,6 +130,8 @@ func (n *Nameserver) ReverseLookup(ip address.Address) (string, error) {
return match.Hostname, nil
}
+func (n *Nameserver) ContainerStarted(ident string) {}
+
func (n *Nameserver) ContainerDied(ident string) {
n.Lock()
entries := n.entries.tombstone(n.ourName, func(e *Entry) bool {
diff --git a/proxy/proxy.go b/proxy/proxy.go
index beb34915..88ec5085 100644
--- a/proxy/proxy.go
+++ b/proxy/proxy.go
@@ -11,8 +11,9 @@ import (
"strings"
"syscall"
- "github.com/fsouza/go-dockerclient"
+ docker "github.com/fsouza/go-dockerclient"
. "github.com/weaveworks/weave/common"
+ weavedocker "github.com/weaveworks/weave/common/docker"
)
const (
@@ -25,7 +26,6 @@ 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$")
ErrWeaveCIDRNone = errors.New("the container was created with the '-e WEAVE_CIDR=none' option")
@@ -64,11 +64,11 @@ func NewProxy(c Config) (*Proxy, error) {
// 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`.
- client, err := docker.NewVersionedClient(dockerSockUnix, "1.15")
+ client, err := weavedocker.NewVersionedClient(dockerSockUnix, "1.15")
if err != nil {
return nil, err
}
- p.client = client
+ p.client = client.Client
if !p.WithoutDNS {
dockerBridgeIP, stderr, err := callWeave("docker-bridge-ip")
@@ -88,6 +88,8 @@ func NewProxy(c Config) (*Proxy, error) {
return nil, err
}
+ client.AddObserver(p)
+
return p, nil
}
@@ -121,8 +123,6 @@ func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch {
case containerCreateRegexp.MatchString(path):
i = &createContainerInterceptor{proxy}
- case containerStartRegexp.MatchString(path):
- i = &startContainerInterceptor{proxy}
case execCreateRegexp.MatchString(path):
i = &createExecInterceptor{proxy}
default:
@@ -224,6 +224,45 @@ func (proxy *Proxy) listen(protoAndAddr string) (net.Listener, string, error) {
return listener, fmt.Sprintf("%s://%s", proto, addr), nil
}
+// weavedocker.ContainerObserver interface
+func (proxy *Proxy) ContainerStarted(ident string) {
+ container, err := proxy.client.InspectContainer(ident)
+ if err != nil {
+ Log.Warningf("Error inspecting container %s: %v", ident, err)
+ return
+ }
+ // If this was a container we modified the entrypoint for, attach it to the network
+ if len(container.Config.Entrypoint) > 0 && container.Config.Entrypoint[0] == weaveWaitEntrypoint[0] {
+ proxy.attach(container)
+ }
+}
+
+func (proxy *Proxy) ContainerDied(ident string) {
+}
+
+func (proxy *Proxy) attach(container *docker.Container) error {
+ cidrs, err := proxy.weaveCIDRsFromConfig(container.Config, container.HostConfig)
+ if err != nil {
+ Log.Infof("Leaving container %s alone because %s", container.ID, err)
+ return nil
+ }
+ Log.Infof("Attaching container %s with WEAVE_CIDR \"%s\" to weave network", container.ID, strings.Join(cidrs, " "))
+ args := []string{"attach"}
+ args = append(args, cidrs...)
+ if !proxy.NoRewriteHosts {
+ args = append(args, "--rewrite-hosts")
+ }
+ args = append(args, "--or-die", container.ID)
+ if _, stderr, err := callWeave(args...); err != nil {
+ Log.Warningf("Attaching container %s to weave network failed: %s", container.ID, string(stderr))
+ return errors.New(string(stderr))
+ } else if len(stderr) > 0 {
+ Log.Warningf("Attaching container %s to weave network: %s", container.ID, string(stderr))
+ }
+
+ return nil
+}
+
func (proxy *Proxy) weaveCIDRsFromConfig(config *docker.Config, hostConfig *docker.HostConfig) ([]string, error) {
netMode := ""
if hostConfig != nil {
diff --git a/proxy/start_container_interceptor.go b/proxy/start_container_interceptor.go
deleted file mode 100644
index 267f68c4..00000000
--- a/proxy/start_container_interceptor.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package proxy
-
-import (
- "errors"
- "net/http"
- "strings"
-
- . "github.com/weaveworks/weave/common"
-)
-
-type startContainerInterceptor struct{ proxy *Proxy }
-
-func (i *startContainerInterceptor) InterceptRequest(r *http.Request) error {
- return nil
-}
-
-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, err := i.proxy.weaveCIDRsFromConfig(container.Config, container.HostConfig)
- if err != nil {
- Log.Infof("Leaving container %s alone because %s", container.ID, err)
- return nil
- }
- Log.Infof("Attaching container %s with WEAVE_CIDR \"%s\" to weave network", container.ID, strings.Join(cidrs, " "))
- args := []string{"attach"}
- args = append(args, cidrs...)
- if !i.proxy.NoRewriteHosts {
- args = append(args, "--rewrite-hosts")
- }
- args = append(args, "--or-die", container.ID)
- if _, stderr, err := callWeave(args...); err != nil {
- Log.Warningf("Attaching container %s to weave network failed: %s", container.ID, string(stderr))
- return errors.New(string(stderr))
- } else if len(stderr) > 0 {
- Log.Warningf("Attaching container %s to weave network: %s", container.ID, string(stderr))
- }
-
- return nil
-}
diff --git a/site/features.md b/site/features.md
index 189f9365..84e295fd 100644
--- a/site/features.md
+++ b/site/features.md
@@ -64,6 +64,10 @@ or
[remote API](https://docs.docker.com/reference/api/docker_remote_api/)
are attached to the weave network before they begin execution.
+Containers started in this way that subsequently restart, either by an
+explicit `docker restart` command or by Docker restart policy, are
+re-attached to the weave network by the weave Docker API proxy.
+
### Address allocation
Containers are automatically allocated an IP address that is unique
@@ -248,6 +252,9 @@ invocation:
host1$ weave detach net:default net:10.2.2.0/24 net:10.2.3.0/24 $C
10.2.1.3 10.2.2.3 10.2.3.1
+Note that addresses added by dynamic attachment are not re-attached
+if the container restarts.
+
### Security
In order to connect containers across untrusted networks, weave peers