Merge pull request #1265 from weaveworks/1252-proxy-non-root-hosts
[proxy] rewrite /etc/hosts from outside the container Fixes #1252.
This commit is contained in:
commit
536369bc12
6 files changed
+172
-117
No files matched your search
+3
-109
@@ -1,17 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"sort"
|
||||
"strings"
|
||||
"syscall"
|
||||
|
||||
weavenet "github.com/weaveworks/weave/net"
|
||||
@@ -23,19 +17,12 @@ var (
|
||||
|
||||
func main() {
|
||||
var (
|
||||
args = os.Args[1:]
|
||||
notInExec = true
|
||||
rewriteHosts = true
|
||||
args = os.Args[1:]
|
||||
notInExec = true
|
||||
)
|
||||
|
||||
if len(args) > 0 && args[0] == "-s" {
|
||||
notInExec = false
|
||||
rewriteHosts = false
|
||||
args = args[1:]
|
||||
}
|
||||
|
||||
if len(args) > 0 && args[0] == "-h" {
|
||||
rewriteHosts = false
|
||||
args = args[1:]
|
||||
}
|
||||
|
||||
@@ -45,17 +32,13 @@ func main() {
|
||||
<-usr2
|
||||
}
|
||||
|
||||
iface, err := weavenet.EnsureInterface("ethwe", -1)
|
||||
_, err := weavenet.EnsureInterface("ethwe", -1)
|
||||
checkErr(err)
|
||||
|
||||
if len(args) == 0 {
|
||||
checkErr(ErrNoCommandSpecified)
|
||||
}
|
||||
|
||||
if rewriteHosts {
|
||||
updateHosts(iface)
|
||||
}
|
||||
|
||||
binary, err := exec.LookPath(args[0])
|
||||
checkErr(err)
|
||||
|
||||
@@ -68,92 +51,3 @@ func checkErr(err error) {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func updateHosts(iface *net.Interface) {
|
||||
addrs, err := iface.Addrs()
|
||||
checkErr(err)
|
||||
if len(addrs) == 0 {
|
||||
return
|
||||
}
|
||||
hostname, err := os.Hostname()
|
||||
checkErr(err)
|
||||
|
||||
hosts := parseHosts()
|
||||
|
||||
// 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 _, addr := range addrs {
|
||||
if addr, ok := addr.(*net.IPNet); ok {
|
||||
ip := addr.IP.String()
|
||||
hosts[ip] = append(hosts[ip], hostname)
|
||||
}
|
||||
}
|
||||
|
||||
writeHosts(hosts)
|
||||
}
|
||||
|
||||
func parseHosts() map[string][]string {
|
||||
f, err := os.Open("/etc/hosts")
|
||||
checkErr(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:]...)
|
||||
}
|
||||
}
|
||||
checkErr(scanner.Err())
|
||||
return ips
|
||||
}
|
||||
|
||||
func writeHosts(contents map[string][]string) {
|
||||
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), " "))
|
||||
}
|
||||
}
|
||||
checkErr(ioutil.WriteFile("/etc/hosts", 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
|
||||
}
|
||||
@@ -119,11 +119,7 @@ func (i *createContainerInterceptor) setWeaveWaitEntrypoint(container *docker.Co
|
||||
}
|
||||
|
||||
if len(container.Entrypoint) == 0 || container.Entrypoint[0] != weaveWaitEntrypoint[0] {
|
||||
entrypoint := weaveWaitEntrypoint
|
||||
if i.proxy.NoRewriteHosts {
|
||||
entrypoint = append(entrypoint, "-h")
|
||||
}
|
||||
container.Entrypoint = append(entrypoint, container.Entrypoint...)
|
||||
container.Entrypoint = append(weaveWaitEntrypoint, container.Entrypoint...)
|
||||
}
|
||||
|
||||
return nil
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/fsouza/go-dockerclient"
|
||||
@@ -41,5 +48,128 @@ 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
|
||||
}
|
||||
@@ -19,9 +19,6 @@ COMMITTED_IMAGE=$(proxy docker_on $HOST1 commit c1)
|
||||
assert_raises "proxy docker_on $HOST1 run --name c2 $COMMITTED_IMAGE"
|
||||
assert "entrypoint c2" "$(entrypoint $COMMITTED_IMAGE)"
|
||||
|
||||
# Check weave IP is first ip returned, so java (etc) prefer weave.
|
||||
assert "proxy docker_on $HOST1 run -e 'WEAVE_CIDR=10.2.1.1/24' $BASE_IMAGE hostname -i | cut -d' ' -f1" "10.2.1.1"
|
||||
|
||||
# Check exec works on containers without weavewait
|
||||
docker_on $HOST1 run -dit --name c3 $SMALL_IMAGE /bin/sh
|
||||
assert_raises "proxy docker_on $HOST1 exec c3 true"
|
||||
|
||||
Executable
+32
@@ -0,0 +1,32 @@
|
||||
#! /bin/bash
|
||||
|
||||
. ./config.sh
|
||||
|
||||
expected_ip=10.2.1.1
|
||||
|
||||
image_ip() {
|
||||
proxy docker_on $HOST1 run -e "WEAVE_CIDR=$expected_ip/24" $1 hostname -i | cut -d' ' -f1
|
||||
}
|
||||
|
||||
start_suite "Proxy rewrites hosts file"
|
||||
|
||||
# Default rewrites the host file
|
||||
weave_on $HOST1 launch-proxy
|
||||
assert "image_ip $SMALL_IMAGE" $expected_ip
|
||||
|
||||
# When container user is non-root
|
||||
docker_on $HOST1 build -t non-root >/dev/null - <<- EOF
|
||||
FROM $SMALL_IMAGE
|
||||
RUN adduser -D -s /bin/sh user
|
||||
ENV HOME /home/user
|
||||
USER user
|
||||
CMD true
|
||||
EOF
|
||||
assert "image_ip non-root" $expected_ip
|
||||
|
||||
# When rewrite hosts is disabled
|
||||
weave_on $HOST1 stop-proxy
|
||||
weave_on $HOST1 launch-proxy --no-rewrite-hosts
|
||||
assert_raises "image_ip $SMALL_IMAGE | grep -v $expected_ip"
|
||||
|
||||
end_suite
|
||||
@@ -1131,8 +1131,14 @@ launch_proxy() {
|
||||
# when launching the weaveproxy container.
|
||||
docker_client_args $DOCKER_CLIENT_ARGS
|
||||
proxy_args "$@"
|
||||
HOSTS_PATH=$(docker run --rm \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
--entrypoint /bin/sh \
|
||||
$EXEC_IMAGE -c 'docker inspect -f {{.HostsPath}} $(hostname)')
|
||||
CONTAINERS_PATH="$(dirname $(dirname "$HOSTS_PATH"))"
|
||||
PROXY_CONTAINER=$(docker run --privileged -d --name=$PROXY_CONTAINER_NAME --net=host \
|
||||
$PROXY_VOLUMES \
|
||||
-v "$CONTAINERS_PATH":"$CONTAINERS_PATH" \
|
||||
-v /var/run:/var/run \
|
||||
-v /proc:/hostproc \
|
||||
-e PROCFS=/hostproc \
|
||||
|
||||
Reference in new issue
Block a user