diff --git a/daemon/container.go b/daemon/container.go index 046ec71e8a..c1c215ffee 100644 --- a/daemon/container.go +++ b/daemon/container.go @@ -1108,19 +1108,16 @@ func (container *Container) updateResolvConf(updatedResolvConf []byte, newResolv } func (container *Container) updateParentsHosts() error { - parents, err := container.daemon.Parents(container.Name) - if err != nil { - return err - } - for _, cid := range parents { - if cid == "0" { + refs := container.daemon.ContainerGraph().RefPaths(container.ID) + for _, ref := range refs { + if ref.ParentID == "0" { continue } - - c := container.daemon.Get(cid) + c := container.daemon.Get(ref.ParentID) if c != nil && !container.daemon.config.DisableNetwork && container.hostConfig.NetworkMode.IsPrivate() { - if err := etchosts.Update(c.HostsPath, container.NetworkSettings.IPAddress, container.Name[1:]); err != nil { - log.Errorf("Failed to update /etc/hosts in parent container: %v", err) + log.Debugf("Update /etc/hosts of %s for alias %s with ip %s", c.ID, ref.Name, container.NetworkSettings.IPAddress) + if err := etchosts.Update(c.HostsPath, container.NetworkSettings.IPAddress, ref.Name); err != nil { + log.Errorf("Failed to update /etc/hosts in parent container %s for alias %s: %v", c.ID, ref.Name, err) } } } diff --git a/integration-cli/docker_cli_links_test.go b/integration-cli/docker_cli_links_test.go index ad0638cf94..fc99ec57fb 100644 --- a/integration-cli/docker_cli_links_test.go +++ b/integration-cli/docker_cli_links_test.go @@ -1,14 +1,17 @@ package main import ( - "github.com/docker/docker/pkg/iptables" + "fmt" "io/ioutil" "os" "os/exec" "reflect" + "regexp" "strings" "testing" "time" + + "github.com/docker/docker/pkg/iptables" ) func TestLinksEtcHostsRegularFile(t *testing.T) { @@ -276,3 +279,57 @@ func TestLinksNetworkHostContainer(t *testing.T) { logDone("link - error thrown when linking to container with --net host") } + +func TestLinksUpdateOnRestart(t *testing.T) { + defer deleteAllContainers() + + if out, err := exec.Command(dockerBinary, "run", "-d", "--name", "one", "busybox", "top").CombinedOutput(); err != nil { + t.Fatal(err, string(out)) + } + out, err := exec.Command(dockerBinary, "run", "-d", "--name", "two", "--link", "one:onetwo", "--link", "one:one", "busybox", "top").CombinedOutput() + if err != nil { + t.Fatal(err, string(out)) + } + id := strings.TrimSpace(string(out)) + + realIP, err := inspectField("one", "NetworkSettings.IPAddress") + if err != nil { + t.Fatal(err) + } + content, err := readContainerFile(id, "hosts") + if err != nil { + t.Fatal(err, string(content)) + } + getIP := func(hosts []byte, hostname string) string { + re := regexp.MustCompile(fmt.Sprintf(`(\S*)\t%s`, regexp.QuoteMeta(hostname))) + matches := re.FindSubmatch(hosts) + if matches == nil { + t.Fatalf("Hostname %s have no matches in hosts", hostname) + } + return string(matches[1]) + } + if ip := getIP(content, "one"); ip != realIP { + t.Fatalf("For 'one' alias expected IP: %s, got: %s", realIP, ip) + } + if ip := getIP(content, "onetwo"); ip != realIP { + t.Fatalf("For 'onetwo' alias expected IP: %s, got: %s", realIP, ip) + } + if out, err := exec.Command(dockerBinary, "restart", "one").CombinedOutput(); err != nil { + t.Fatal(err, string(out)) + } + realIP, err = inspectField("one", "NetworkSettings.IPAddress") + if err != nil { + t.Fatal(err) + } + content, err = readContainerFile(id, "hosts") + if err != nil { + t.Fatal(err, string(content)) + } + if ip := getIP(content, "one"); ip != realIP { + t.Fatalf("For 'one' alias expected IP: %s, got: %s", realIP, ip) + } + if ip := getIP(content, "onetwo"); ip != realIP { + t.Fatalf("For 'onetwo' alias expected IP: %s, got: %s", realIP, ip) + } + logDone("link - ensure containers hosts files are updated on restart") +}