From e6b587ea8dbee3869a2124b8ce4d74200eafd86b Mon Sep 17 00:00:00 2001 From: Paul Bellamy Date: Tue, 19 May 2015 16:25:10 +0100 Subject: [PATCH] proxy needs to add weavewait to execs as well Bug came up in a test where we are restarting and doing an exec checking a network interface right away. weavewait is only added if the container has a WEAVE_CIDR var set, the same as at container creation. --- proxy/common.go | 37 ++++++++++++++++ proxy/create_container_interceptor.go | 2 +- proxy/create_exec_interceptor.go | 51 +++++++++++++++++++++++ proxy/proxy.go | 3 ++ proxy/start_container_interceptor.go | 21 +++------- test/640_proxy_restart_reattaches_test.sh | 2 +- test/config.sh | 8 ++++ 7 files changed, 106 insertions(+), 18 deletions(-) create mode 100644 proxy/create_exec_interceptor.go diff --git a/proxy/common.go b/proxy/common.go index 4d29d95e..ddfa85e6 100644 --- a/proxy/common.go +++ b/proxy/common.go @@ -1,13 +1,24 @@ package proxy import ( + "bytes" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" "os/exec" + "regexp" "strings" "github.com/fsouza/go-dockerclient" . "github.com/weaveworks/weave/common" ) +var ( + containerIDRegexp = regexp.MustCompile("^/v[0-9\\.]*/containers/([^/]*)/.*") + weaveWaitEntrypoint = []string{"/home/weavewait/weavewait"} +) + func callWeave(args ...string) ([]byte, error) { args = append([]string{"--local"}, args...) Debug.Print("Calling weave", args) @@ -26,3 +37,29 @@ func weaveCIDRsFromConfig(config *docker.Config) ([]string, bool) { } return nil, false } + +func marshalRequestBody(r *http.Request, body interface{}) error { + newBody, err := json.Marshal(body) + if err != nil { + return err + } + r.Body = ioutil.NopCloser(bytes.NewReader(newBody)) + r.ContentLength = int64(len(newBody)) + return nil +} + +func inspectContainerInPath(client *docker.Client, path string) (*docker.Container, error) { + subs := containerIDRegexp.FindStringSubmatch(path) + if subs == nil { + err := fmt.Errorf("No container id found in request with path %s", path) + Warning.Println(err) + return nil, err + } + containerID := subs[1] + + container, err := client.InspectContainer(containerID) + if err != nil { + Warning.Printf("Error inspecting container %s: %v", containerID, err) + } + return container, err +} diff --git a/proxy/create_container_interceptor.go b/proxy/create_container_interceptor.go index 35841a9b..20f978ae 100644 --- a/proxy/create_container_interceptor.go +++ b/proxy/create_container_interceptor.go @@ -75,7 +75,7 @@ func (i *createContainerInterceptor) setWeaveWaitEntrypoint(container *docker.Co command = image.Cmd } - container.Entrypoint = []string{"/home/weavewait/weavewait"} + container.Entrypoint = weaveWaitEntrypoint container.Cmd = append(entry, command...) return nil } diff --git a/proxy/create_exec_interceptor.go b/proxy/create_exec_interceptor.go new file mode 100644 index 00000000..aba8f138 --- /dev/null +++ b/proxy/create_exec_interceptor.go @@ -0,0 +1,51 @@ +package proxy + +import ( + "encoding/json" + "io/ioutil" + "net/http" + + "github.com/fsouza/go-dockerclient" +) + +type createExecInterceptor struct { + client *docker.Client +} + +type createExecRequestBody struct { + *docker.Config + HostConfig *docker.HostConfig `json:"HostConfig,omitempty" yaml:"HostConfig,omitempty"` + MacAddress string `json:"MacAddress,omitempty" yaml:"MacAddress,omitempty"` +} + +func (i *createExecInterceptor) InterceptRequest(r *http.Request) error { + body, err := ioutil.ReadAll(r.Body) + if err != nil { + return err + } + r.Body.Close() + + options := docker.CreateExecOptions{} + if err := json.Unmarshal(body, &options); err != nil { + return err + } + + container, err := inspectContainerInPath(i.client, r.URL.Path) + if err != nil { + return err + } + + if _, ok := weaveCIDRsFromConfig(container.Config); ok { + options.Cmd = append(weaveWaitEntrypoint, options.Cmd...) + } + + if err := marshalRequestBody(r, options); err != nil { + return err + } + + return nil +} + +func (i *createExecInterceptor) InterceptResponse(r *http.Response) error { + return nil +} diff --git a/proxy/proxy.go b/proxy/proxy.go index 7681230e..de565f6b 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -14,6 +14,7 @@ import ( 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$") ) type Proxy struct { @@ -68,6 +69,8 @@ func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) { 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 execCreateRegexp.MatchString(path): + proxy.serveWithInterceptor(&createExecInterceptor{proxy.client}, w, r) case strings.HasPrefix(path, "/weave"): w.WriteHeader(http.StatusOK) default: diff --git a/proxy/start_container_interceptor.go b/proxy/start_container_interceptor.go index ca628cbb..82cefd23 100644 --- a/proxy/start_container_interceptor.go +++ b/proxy/start_container_interceptor.go @@ -2,15 +2,12 @@ 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 @@ -21,17 +18,9 @@ func (i *startContainerInterceptor) InterceptRequest(r *http.Request) error { } func (i *startContainerInterceptor) InterceptResponse(r *http.Response) error { - subs := containerIDRegexp.FindStringSubmatch(r.Request.URL.Path) - if 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) + container, err := inspectContainerInPath(i.client, r.Request.URL.Path) if err != nil { - Warning.Printf("Error inspecting container %s: %v", containerID, err) - return nil + return err } cidrs, ok := weaveCIDRsFromConfig(container.Config) @@ -39,12 +28,12 @@ func (i *startContainerInterceptor) InterceptResponse(r *http.Response) error { Debug.Print("No Weave CIDR, ignoring") return nil } - Info.Printf("Container %s was started with CIDR \"%s\"", containerID, strings.Join(cidrs, " ")) + Info.Printf("Container %s was started with CIDR \"%s\"", container.ID, strings.Join(cidrs, " ")) args := []string{"attach"} args = append(args, cidrs...) - args = append(args, containerID) + args = append(args, container.ID) if _, err := callWeave(args...); err != nil { - Warning.Printf("Attaching container %s to weave failed: %v", containerID, err) + Warning.Printf("Attaching container %s to weave failed: %v", container.ID, err) return nil } return nil diff --git a/test/640_proxy_restart_reattaches_test.sh b/test/640_proxy_restart_reattaches_test.sh index 01017764..78c0cb0a 100755 --- a/test/640_proxy_restart_reattaches_test.sh +++ b/test/640_proxy_restart_reattaches_test.sh @@ -14,7 +14,7 @@ docker_proxy_on $HOST1 run -e WEAVE_CIDR=$C2/24 -dt --name=c2 -h $NAME gliderlab 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_raises "proxy_exec_on $HOST1 c2 ip link show ethwe | grep 'state \\(UP\\|UNKNOWN\\)'" assert_dns_record $HOST1 c1 $NAME $C2 end_suite diff --git a/test/config.sh b/test/config.sh index 48de3afb..3c4d1b06 100644 --- a/test/config.sh +++ b/test/config.sh @@ -97,6 +97,14 @@ exec_on() { docker -H tcp://$host:2375 exec $container "$@" } +proxy_exec_on() { + host=$1 + container=$2 + shift 2 + docker -H tcp://$host:12375 exec $container "$@" +} + + start_container() { host=$1 shift 1