From edbf85655a12dcd9deec5cabfbb4b7c38a655dd1 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 9 May 2017 18:01:31 +0000 Subject: [PATCH] Move rewrite /etc/hosts from shell to Go --- prog/weaveutil/attach.go | 30 +++++++++++++++++++ prog/weaveutil/main.go | 1 + proxy/hosts.go | 65 ++++++++++++++++++++++++++++++++++++++++ weave | 41 +------------------------ 4 files changed, 97 insertions(+), 40 deletions(-) create mode 100644 proxy/hosts.go diff --git a/prog/weaveutil/attach.go b/prog/weaveutil/attach.go index 6de93ce4..d88c6ba6 100644 --- a/prog/weaveutil/attach.go +++ b/prog/weaveutil/attach.go @@ -3,13 +3,16 @@ package main import ( "fmt" "net" + "os" "strconv" + "strings" "syscall" docker "github.com/fsouza/go-dockerclient" "github.com/vishvananda/netns" weavenet "github.com/weaveworks/weave/net" + "github.com/weaveworks/weave/proxy" ) func attach(args []string) error { @@ -110,3 +113,30 @@ func detach(args []string) error { } return weavenet.DetachContainer(weavenet.NSPathByPid(pid), args[0], weavenet.VethName, cidrs) } + +func rewriteEtcHosts(args []string) error { + if len(args) < 4 { + cmdUsage("rewrite-etc-hosts", " ... [name:addr...]") + } + hostsPath := args[0] + fqdn := args[1] + image := args[2] + var ips []*net.IPNet + for _, cidr := range strings.Fields(args[3]) { + _, ipnet, err := net.ParseCIDR(cidr) + if err != nil { + return err + } + ips = append(ips, ipnet) + } + extraHosts := args[4:] + docker := os.Getenv("DOCKER_HOST") + if docker == "" { + docker = "unix:///var/run/docker.sock" + } + p, err := proxy.StubProxy(proxy.Config{DockerHost: docker, Image: image}) + if err != nil { + return err + } + return p.RewriteEtcHosts(hostsPath, fqdn, ips, extraHosts) +} diff --git a/prog/weaveutil/main.go b/prog/weaveutil/main.go index 531009a5..57751428 100644 --- a/prog/weaveutil/main.go +++ b/prog/weaveutil/main.go @@ -40,6 +40,7 @@ func init() { "unique-id": uniqueID, "swarm-manager-peers": swarmManagerPeers, "is-docker-plugin-enabled": isDockerPluginEnabled, + "rewrite-etc-hosts": rewriteEtcHosts, } } diff --git a/proxy/hosts.go b/proxy/hosts.go new file mode 100644 index 00000000..91b2da67 --- /dev/null +++ b/proxy/hosts.go @@ -0,0 +1,65 @@ +package proxy + +import ( + "bytes" + "fmt" + "io" + "net" + "path" + "strings" +) + +// rewrite /etc/hosts, unlinking the file (so Docker does not modify it again) but +// leaving it with valid contents... +func (proxy *Proxy) RewriteEtcHosts(hostsPath, fqdn string, ips []*net.IPNet, extraHosts []string) error { + hostsPathDir := path.Dir(hostsPath) + mnt := "/container" + mntHosts := path.Join(mnt, path.Base(hostsPath)) + var buf bytes.Buffer + writeEtcHostsContents(&buf, fqdn, ips, extraHosts) + contents := buf.String() + cmdLine := fmt.Sprintf("echo '%s' > %s && rm -f %s && echo '%s' > %s", contents, mntHosts, mntHosts, contents, mntHosts) + mounts := []string{hostsPathDir + ":" + mnt} + proxy.runTransientContainer([]string{"sh"}, []string{"-c", cmdLine}, mounts) + return nil +} + +// we assume (for compatibility with the weave script) that fqdn has a dot +// between hostname and domain. domain may be blank. +func writeEtcHostsContents(w io.Writer, fqdn string, cidrs []*net.IPNet, extraHosts []string) { + index := strings.Index(fqdn, ".") + name := fqdn[:index] + var hostnames string + if index == len(fqdn)-1 { // dot comes at the end - no domain + hostnames = name + } else { + if fqdn[len(fqdn)-1] == '.' { // strip a final trailing dot + fqdn = fqdn[:len(fqdn)-1] + } + hostnames = fqdn + " " + name + } + + fmt.Fprintln(w, "# created by Weave - BEGIN") + fmt.Fprintln(w, "# container hostname") + for _, cidr := range cidrs { + fmt.Fprintf(w, "%-15s %s\n", cidr.IP, hostnames) + } + fmt.Fprintln(w) + fmt.Fprintln(w, "# static names added with --add-host") + for _, eh := range extraHosts { + parts := strings.SplitN(eh, ":", 2) + if len(parts) != 2 { + continue + } + fmt.Fprintf(w, "%-15s %s\n", parts[1], parts[0]) + } + fmt.Fprintln(w) + fmt.Fprintln(w, "# default localhost entries") + fmt.Fprintln(w, "127.0.0.1 localhost") + fmt.Fprintln(w, "::1 ip6-localhost ip6-loopback") + fmt.Fprintln(w, "fe00::0 ip6-localnet") + fmt.Fprintln(w, "ff00::0 ip6-mcastprefix") + fmt.Fprintln(w, "ff02::1 ip6-allnodes") + fmt.Fprintln(w, "ff02::2 ip6-allrouters") + fmt.Fprintln(w, "# created by Weave - END") +} diff --git a/weave b/weave index f807492e..95a81d01 100755 --- a/weave +++ b/weave @@ -851,52 +851,13 @@ dns_args() { fi } -etc_hosts_contents() { - FQDN=$1 - shift - NAME=${FQDN%%.*} - HOSTNAMES="$NAME" - [ "$NAME" = "$FQDN" -o "$NAME." = "$FQDN" ] || HOSTNAMES="${FQDN%.} $HOSTNAMES" - - echo "# created by Weave - BEGIN" - echo "# container hostname" - for CIDR in $ALL_CIDRS ; do - echo "${CIDR%/*} $HOSTNAMES" - done - echo - echo "# static names added with --add-host" - for EXTRA_HOST in "$@" ; do - echo "${EXTRA_HOST#*:} ${EXTRA_HOST%:*}" - done - - cat <<-EOF - -# default localhost entries -127.0.0.1 localhost -::1 ip6-localhost ip6-loopback -fe00::0 ip6-localnet -ff00::0 ip6-mcastprefix -ff02::1 ip6-allnodes -ff02::2 ip6-allrouters -EOF - - echo "# created by Weave - END" -} - rewrite_etc_hosts() { HOSTS_PATH_AND_FQDN=$(docker inspect -f '{{.HostsPath}} {{.Config.Hostname}}.{{.Config.Domainname}}' $CONTAINER) || return 1 HOSTS=${HOSTS_PATH_AND_FQDN% *} FQDN=${HOSTS_PATH_AND_FQDN#* } - CONTAINERS_PATH=$(dirname $HOSTS) - MNT=/container - MNT_HOSTS=$MNT/$(basename $HOSTS) - CONTENTS="$(etc_hosts_contents $FQDN "$@")" # rewrite /etc/hosts, unlinking the file (so Docker does not modify it again) but # leaving it with valid contents... - docker run --rm --net=none -e WEAVE_CIDR=none \ - -v $CONTAINERS_PATH:$MNT \ - --entrypoint=sh \ - $EXEC_IMAGE -c "echo '$CONTENTS' > $MNT_HOSTS && rm -f $MNT_HOSTS && echo '$CONTENTS' > $MNT_HOSTS" + util_op rewrite-etc-hosts "$HOSTS" "$FQDN" "$EXEC_IMAGE" "$ALL_CIDRS" "$@" } # Print an error to stderr and return with an indicative exit status