diff --git a/.gitignore b/.gitignore index 3889f49b..95bb841f 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ coverage.html # Project specific prog/weaver/weaver prog/weavedns/weavedns +prog/weavehosts/weavehosts prog/weaveproxy/weaveproxy prog/sigproxy/sigproxy prog/weavewait/weavewait @@ -49,6 +50,7 @@ releases .weaveexec.uptodate weave.tar prog/weaveexec/weave +prog/weaveexec/weavehosts prog/weaveexec/weaveproxy prog/weaveexec/weavewait prog/weaveexec/sigproxy diff --git a/Makefile b/Makefile index 4950d11c..3d4ca10c 100644 --- a/Makefile +++ b/Makefile @@ -13,11 +13,12 @@ WEAVER_EXE=prog/weaver/weaver WEAVEPROXY_EXE=prog/weaveproxy/weaveproxy SIGPROXY_EXE=prog/sigproxy/sigproxy WEAVEWAIT_EXE=prog/weavewait/weavewait +WEAVEHOSTS_EXE=prog/weavehosts/weavehosts NETCHECK_EXE=prog/netcheck/netcheck COVER_EXE=testing/cover/cover RUNNER_EXE=testing/runner/runner -EXES=$(WEAVER_EXE) $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(NETCHECK_EXE) $(COVER_EXE) $(RUNNER_EXE) +EXES=$(WEAVER_EXE) $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEHOSTS_EXE) $(NETCHECK_EXE) $(COVER_EXE) $(RUNNER_EXE) WEAVER_UPTODATE=.weaver.uptodate WEAVEEXEC_UPTODATE=.weaveexec.uptodate @@ -79,7 +80,7 @@ $(WEAVEHOSTS_EXE): prog/weavehosts/weavehosts.go $(COVER_EXE): testing/cover/cover.go $(RUNNER_EXE): testing/runner/runner.go -$(WEAVEWAIT_EXE) $(SIGPROXY_EXE) $(COVER_EXE) $(RUNNER_EXE): +$(WEAVEWAIT_EXE) $(SIGPROXY_EXE) $(WEAVEHOSTS_EXE) $(COVER_EXE) $(RUNNER_EXE): go get ./$(@D) go build -o $@ ./$(@D) @@ -87,11 +88,12 @@ $(WEAVER_UPTODATE): prog/weaver/Dockerfile $(WEAVER_EXE) $(SUDO) docker build -t $(WEAVER_IMAGE) prog/weaver touch $@ -$(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile $(DOCKER_DISTRIB) weave $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(NETCHECK_EXE) +$(WEAVEEXEC_UPTODATE): prog/weaveexec/Dockerfile $(DOCKER_DISTRIB) weave $(SIGPROXY_EXE) $(WEAVEPROXY_EXE) $(WEAVEWAIT_EXE) $(WEAVEHOSTS_EXE) $(NETCHECK_EXE) cp weave prog/weaveexec/weave cp $(SIGPROXY_EXE) prog/weaveexec/sigproxy cp $(WEAVEPROXY_EXE) prog/weaveexec/weaveproxy cp $(WEAVEWAIT_EXE) prog/weaveexec/weavewait + cp $(WEAVEHOSTS_EXE) prog/weaveexec/weavehosts cp $(NETCHECK_EXE) prog/weaveexec/netcheck cp $(DOCKER_DISTRIB) prog/weaveexec/docker.tgz $(SUDO) docker build -t $(WEAVEEXEC_IMAGE) prog/weaveexec diff --git a/prog/weaveexec/Dockerfile b/prog/weaveexec/Dockerfile index 9d101bd7..e17bfc25 100644 --- a/prog/weaveexec/Dockerfile +++ b/prog/weaveexec/Dockerfile @@ -17,6 +17,6 @@ RUN apk add --update \ && rm -rf /var/cache/apk/* ADD ./weave ./sigproxy ./weaveproxy /home/weave/ -ADD ./netcheck /usr/bin/ +ADD ./netcheck ./weavehosts /usr/bin/ ADD ./weavewait /w/w ADD ./docker.tgz / diff --git a/prog/weavehosts/weavehosts.go b/prog/weavehosts/weavehosts.go new file mode 100644 index 00000000..b1694365 --- /dev/null +++ b/prog/weavehosts/weavehosts.go @@ -0,0 +1,120 @@ +/* weavehosts: rewrite /etc/hosts as necessary to put the weave address(es) at the top */ +package main + +import ( + "bufio" + "bytes" + "fmt" + "io/ioutil" + "net" + "os" + "sort" + "strings" +) + +func main() { + args := os.Args + if len(args) < 4 { + fmt.Fprintln(os.Stderr, "usage: weavehosts hostpath hostname cidr [cidr ...]") + os.Exit(1) + } + + checkErr(updateHosts(args[1], args[2], args[3:])) + + os.Exit(0) +} + +func checkErr(err error) { + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } +} + +func updateHosts(path, hostname string, cidrs []string) error { + hosts, err := parseHosts(path) + if err != nil { + return err + } + + // Remove existing ips pointing to our hostname + toRemove := []string{} + for ip, addrs := range hosts { + for _, addr := range addrs { + if addr == hostname { + toRemove = append(toRemove, ip) + break + } + } + } + for _, ip := range toRemove { + delete(hosts, ip) + } + + // Add the weave ip(s) + for _, cidr := range cidrs { + ip, _, err := net.ParseCIDR(cidr) + checkErr(err) + ipStr := ip.String() + hosts[ipStr] = append(hosts[ipStr], hostname) + } + + return writeHosts(path, hosts) +} + +func parseHosts(path string) (map[string][]string, error) { + f, err := os.Open(path) + if err != nil { + return nil, err + } + defer f.Close() + ips := map[string][]string{} + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + + // Remove any comments + if i := strings.IndexByte(line, '#'); i != -1 { + line = line[:i] + } + + fields := strings.Fields(line) + if len(fields) > 0 { + ips[fields[0]] = append(ips[fields[0]], fields[1:]...) + } + } + if scanner.Err() != nil { + return nil, scanner.Err() + } + return ips, nil +} + +func writeHosts(path string, contents map[string][]string) error { + ips := []string{} + for ip := range contents { + ips = append(ips, ip) + } + sort.Strings(ips) + + buf := &bytes.Buffer{} + fmt.Fprintln(buf, "# modified by weave") + for _, ip := range ips { + if addrs := contents[ip]; len(addrs) > 0 { + fmt.Fprintf(buf, "%s\t%s\n", ip, strings.Join(uniqueStrs(addrs), " ")) + } + } + return ioutil.WriteFile(path, buf.Bytes(), 644) +} + +func uniqueStrs(s []string) []string { + m := map[string]struct{}{} + result := []string{} + for _, str := range s { + if _, ok := m[str]; !ok { + m[str] = struct{}{} + result = append(result, str) + } + } + sort.Strings(result) + return result +} diff --git a/proxy/create_exec_interceptor.go b/proxy/create_exec_interceptor.go index 99bacafc..80168c95 100644 --- a/proxy/create_exec_interceptor.go +++ b/proxy/create_exec_interceptor.go @@ -35,8 +35,7 @@ func (i *createExecInterceptor) InterceptRequest(r *http.Request) error { Log.Infof("Leaving container %s alone because %s", container.ID, err) } else if hasWeaveWait { Log.Infof("Exec in container %s with WEAVE_CIDR \"%s\"", container.ID, strings.Join(cidrs, " ")) - cmd := weaveWaitEntrypoint - options.Cmd = append(cmd, options.Cmd...) + options.Cmd = append(weaveWaitEntrypoint, options.Cmd...) } if err := marshalRequestBody(r, options); err != nil { diff --git a/proxy/start_container_interceptor.go b/proxy/start_container_interceptor.go index e17e3647..267f68c4 100644 --- a/proxy/start_container_interceptor.go +++ b/proxy/start_container_interceptor.go @@ -1,18 +1,10 @@ package proxy import ( - "bufio" - "bytes" "errors" - "fmt" - "io/ioutil" - "net" "net/http" - "os" - "sort" "strings" - "github.com/fsouza/go-dockerclient" . "github.com/weaveworks/weave/common" ) @@ -40,6 +32,9 @@ func (i *startContainerInterceptor) InterceptResponse(r *http.Response) error { 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)) @@ -48,128 +43,5 @@ func (i *startContainerInterceptor) InterceptResponse(r *http.Response) error { Log.Warningf("Attaching container %s to weave network: %s", container.ID, string(stderr)) } - if !i.proxy.NoRewriteHosts { - ips, err := weaveContainerIPs(container) - if err != nil { - return err - } - if len(ips) > 0 { - if err := updateHosts(container.HostsPath, container.Config.Hostname, ips); err != nil { - return err - } - } - } - - return i.proxy.client.KillContainer(docker.KillContainerOptions{ID: container.ID, Signal: docker.SIGUSR2}) -} - -func weaveContainerIPs(container *docker.Container) ([]net.IP, error) { - stdout, stderr, err := callWeave("ps", container.ID) - if err != nil || len(stderr) > 0 { - return nil, errors.New(string(stderr)) - } - if len(stdout) <= 0 { - return nil, nil - } - - fields := strings.Fields(string(stdout)) - if len(fields) <= 2 { - return nil, nil - } - - var ips []net.IP - for _, cidr := range fields[2:] { - ip, _, err := net.ParseCIDR(cidr) - if err != nil { - return nil, err - } - ips = append(ips, ip) - } - return ips, nil -} - -func updateHosts(path, hostname string, ips []net.IP) error { - hosts, err := parseHosts(path) - if err != nil { - return err - } - - // Remove existing ips pointing to our hostname - toRemove := []string{} - for ip, addrs := range hosts { - for _, addr := range addrs { - if addr == hostname { - toRemove = append(toRemove, ip) - break - } - } - } - for _, ip := range toRemove { - delete(hosts, ip) - } - - // Add the weave ip(s) - for _, ip := range ips { - ipStr := ip.String() - hosts[ipStr] = append(hosts[ipStr], hostname) - } - - return writeHosts(path, hosts) -} - -func parseHosts(path string) (map[string][]string, error) { - f, err := os.Open(path) - if err != nil { - return nil, err - } - defer f.Close() - ips := map[string][]string{} - scanner := bufio.NewScanner(f) - for scanner.Scan() { - line := scanner.Text() - - // Remove any comments - if i := strings.IndexByte(line, '#'); i != -1 { - line = line[:i] - } - - fields := strings.Fields(line) - if len(fields) > 0 { - ips[fields[0]] = append(ips[fields[0]], fields[1:]...) - } - } - if scanner.Err() != nil { - return nil, scanner.Err() - } - return ips, nil -} - -func writeHosts(path string, contents map[string][]string) error { - ips := []string{} - for ip := range contents { - ips = append(ips, ip) - } - sort.Strings(ips) - - buf := &bytes.Buffer{} - fmt.Fprintln(buf, "# modified by weave") - for _, ip := range ips { - if addrs := contents[ip]; len(addrs) > 0 { - fmt.Fprintf(buf, "%s\t%s\n", ip, strings.Join(uniqueStrs(addrs), " ")) - } - } - return ioutil.WriteFile(path, buf.Bytes(), 644) -} - -func uniqueStrs(s []string) []string { - m := map[string]struct{}{} - result := []string{} - for _, str := range s { - if _, ok := m[str]; !ok { - m[str] = struct{}{} - result = append(result, str) - } - } - sort.Strings(result) - return result + return nil } diff --git a/weave b/weave index cc4a74af..9a8b9855 100755 --- a/weave +++ b/weave @@ -1446,14 +1446,28 @@ case "$COMMAND" in attach) collect_cidr_args "$@" shift $CIDR_ARG_COUNT - if [ "$1" = "--or-die" ] ; then - ATTACH_TYPE="_or_die" - shift - fi + while [ $# -gt 0 ]; do + case "$1" in + --or-die) + ATTACH_TYPE="_or_die" + ;; + --rewrite-hosts) + REWRITE_HOSTS=1 + ;; + *) + break + ;; + esac + shift + done [ $# -eq 1 ] || usage CONTAINER=$(container_id $1) create_bridge ipam_cidrs$ATTACH_TYPE $CONTAINER $CIDR_ARGS + if [ -n "$REWRITE_HOSTS" ] && command_exists weavehosts ; then + PATH_AND_NAME=$(docker inspect -f '{{.HostsPath}} {{.Config.Hostname}}' $CONTAINER) + weavehosts $PATH_AND_NAME $ALL_CIDRS + fi with_container_netns$ATTACH_TYPE $CONTAINER attach $ALL_CIDRS >/dev/null when_weave_running with_container_fqdn $CONTAINER put_dns_fqdn $ALL_CIDRS show_addrs $ALL_CIDRS