Previously, the proxy would run the weave script in ways that did not run the weaver executable. Now they can. This is a problem because of the contortions involved in using golang's code coverage support in the integration tests, which require the weaver command line args to be slightly mangled.
152 lines
3.5 KiB
Go
152 lines
3.5 KiB
Go
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"
|
|
)
|
|
|
|
var (
|
|
containerIDRegexp = regexp.MustCompile("^(/v[0-9\\.]*)?/containers/([^/]*)/.*")
|
|
weaveWaitEntrypoint = []string{"/w/w"}
|
|
)
|
|
|
|
func callWeave(args ...string) ([]byte, []byte, error) {
|
|
args = append([]string{"--local"}, args...)
|
|
cmd := exec.Command("./weave", args...)
|
|
cmd.Env = []string{
|
|
"PATH=/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
|
|
"PROCFS=/hostproc",
|
|
}
|
|
|
|
propagateEnv := func(key string) {
|
|
if val := os.Getenv(key); val != "" {
|
|
cmd.Env = append(cmd.Env, fmt.Sprintf("%s=%s", key, val))
|
|
}
|
|
}
|
|
|
|
propagateEnv("DOCKER_BRIDGE")
|
|
|
|
// Propogage WEAVE_DEBUG, to make debugging easier.
|
|
propagateEnv("WEAVE_DEBUG")
|
|
|
|
// This prevents the code coverage contortions in our
|
|
// integration test suite breaking things.
|
|
propagateEnv("COVERAGE")
|
|
|
|
Log.Debug("Calling weave args: ", args, "env: ", cmd.Env)
|
|
var stdout, stderr bytes.Buffer
|
|
cmd.Stdout = &stdout
|
|
cmd.Stderr = &stderr
|
|
err := cmd.Run()
|
|
return stdout.Bytes(), stderr.Bytes(), err
|
|
}
|
|
|
|
func unmarshalRequestBody(r *http.Request, target interface{}) error {
|
|
body, err := ioutil.ReadAll(r.Body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := r.Body.Close(); err != nil {
|
|
return err
|
|
}
|
|
r.Body = ioutil.NopCloser(bytes.NewReader(body))
|
|
|
|
d := json.NewDecoder(bytes.NewReader(body))
|
|
d.UseNumber() // don't want large numbers in scientific format
|
|
return d.Decode(&target)
|
|
}
|
|
|
|
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 unmarshalResponseBody(r *http.Response, target interface{}) error {
|
|
body, err := ioutil.ReadAll(r.Body)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := r.Body.Close(); err != nil {
|
|
return err
|
|
}
|
|
r.Body = ioutil.NopCloser(bytes.NewReader(body))
|
|
|
|
d := json.NewDecoder(bytes.NewReader(body))
|
|
d.UseNumber() // don't want large numbers in scientific format
|
|
return d.Decode(&target)
|
|
}
|
|
|
|
func marshalResponseBody(r *http.Response, 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))
|
|
// Stop it being chunked, because that hangs
|
|
r.TransferEncoding = nil
|
|
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)
|
|
Log.Warningln(err)
|
|
return nil, err
|
|
}
|
|
containerID := subs[2]
|
|
|
|
container, err := client.InspectContainer(containerID)
|
|
if err != nil {
|
|
Log.Warningf("Error inspecting container %s: %v", containerID, err)
|
|
}
|
|
return container, err
|
|
}
|
|
|
|
func weaveContainerIPs(containerID string) (mac string, ips []net.IP, nets []*net.IPNet, err error) {
|
|
stdout, stderr, err := callWeave("ps", containerID)
|
|
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
|
|
}
|