From 9bb69f9726e7f8cba0cdf681e5060e47b9c45298 Mon Sep 17 00:00:00 2001 From: Jana Radhakrishnan Date: Wed, 24 Jun 2015 10:23:00 -0700 Subject: [PATCH] Fix endpoint leave failure for --net=host mode When a container is started with `--net=host` with a particular name and it is subsequently destroyed, then all subsequent creations of the container with the same name will fail. This is because in `--net=host` the namespace is shared i.e the host namespace so trying to destroy the host namespace by calling `LeaveAll` will fail and the endpoint is left with the dangling state. So the fix is, for this mode, do not attempt to destroy the namespace but just cleanup the endpoint state and return. Signed-off-by: Jana Radhakrishnan --- daemon/container_linux.go | 48 ++++++++++++------- hack/vendor.sh | 2 +- integration-cli/docker_cli_run_test.go | 26 ++++++++-- .../docker/libnetwork/etchosts/etchosts.go | 8 ++++ .../github.com/docker/libnetwork/network.go | 5 ++ 5 files changed, 66 insertions(+), 23 deletions(-) diff --git a/daemon/container_linux.go b/daemon/container_linux.go index 0a5bf38725..77010220c9 100644 --- a/daemon/container_linux.go +++ b/daemon/container_linux.go @@ -1003,33 +1003,47 @@ func (container *Container) ReleaseNetwork() { return } - err := container.daemon.netController.LeaveAll(container.ID) - if err != nil { - logrus.Errorf("Leave all failed for %s: %v", container.ID, err) - return - } - eid := container.NetworkSettings.EndpointID nid := container.NetworkSettings.NetworkID container.NetworkSettings = &network.Settings{} + if nid == "" || eid == "" { + return + } + + n, err := container.daemon.netController.NetworkByID(nid) + if err != nil { + logrus.Errorf("error locating network id %s: %v", nid, err) + return + } + + ep, err := n.EndpointByID(eid) + if err != nil { + logrus.Errorf("error locating endpoint id %s: %v", eid, err) + return + } + + switch { + case container.hostConfig.NetworkMode.IsHost(): + if err := ep.Leave(container.ID); err != nil { + logrus.Errorf("Error leaving endpoint id %s for container %s: %v", eid, container.ID, err) + return + } + default: + if err := container.daemon.netController.LeaveAll(container.ID); err != nil { + logrus.Errorf("Leave all failed for %s: %v", container.ID, err) + return + } + } + // In addition to leaving all endpoints, delete implicitly created endpoint - if container.Config.PublishService == "" && eid != "" && nid != "" { - n, err := container.daemon.netController.NetworkByID(nid) - if err != nil { - logrus.Errorf("error locating network id %s: %v", nid, err) - return - } - ep, err := n.EndpointByID(eid) - if err != nil { - logrus.Errorf("error locating endpoint id %s: %v", eid, err) - return - } + if container.Config.PublishService == "" { if err := ep.Delete(); err != nil { logrus.Errorf("deleting endpoint failed: %v", err) } } + } func disableAllActiveLinks(container *Container) { diff --git a/hack/vendor.sh b/hack/vendor.sh index 21c72893c9..a678d9cb98 100755 --- a/hack/vendor.sh +++ b/hack/vendor.sh @@ -18,7 +18,7 @@ clone git golang.org/x/net 3cffabab72adf04f8e3b01c5baf775361837b5fe https://gith clone hg code.google.com/p/gosqlite 74691fb6f837 #get libnetwork packages -clone git github.com/docker/libnetwork 1aaf1047fd48345619a875184538a0eb6c6cfb2a +clone git github.com/docker/libnetwork 82a1f5634904b57e619fd715ded6903727e00143 clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4 diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index 1ec776ecc0..2c5d65b6af 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -1480,10 +1480,10 @@ func (s *DockerSuite) TestRunResolvconfUpdate(c *check.C) { c.Fatalf("Restarted container does not have updated resolv.conf; expected %q, got %q", tmpResolvConf, string(containerResolv)) } - /* //make a change to resolv.conf (in this case replacing our tmp copy with orig copy) - if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil { - c.Fatal(err) - } */ + /* //make a change to resolv.conf (in this case replacing our tmp copy with orig copy) + if err := ioutil.WriteFile("/etc/resolv.conf", resolvConfSystem, 0644); err != nil { + c.Fatal(err) + } */ //2. test that a restarting container does not receive resolv.conf updates // if it modified the container copy of the starting point resolv.conf cmd = exec.Command(dockerBinary, "run", "--name='second'", "busybox", "sh", "-c", "echo 'search mylittlepony.com' >>/etc/resolv.conf") @@ -1793,7 +1793,7 @@ func (s *DockerSuite) TestRunCleanupCmdOnEntrypoint(c *check.C) { if _, err := buildImage(name, `FROM busybox ENTRYPOINT ["echo"] - CMD ["testingpoint"]`, + CMD ["testingpoint"]`, true); err != nil { c.Fatal(err) } @@ -2820,6 +2820,22 @@ func (s *DockerSuite) TestRunNetHost(c *check.C) { } } +func (s *DockerSuite) TestRunNetHostTwiceSameName(c *check.C) { + testRequires(c, SameHostDaemon) + + cmd := exec.Command(dockerBinary, "run", "--rm", "--name=thost", "--net=host", "busybox", "true") + out2, _, err := runCommandWithOutput(cmd) + if err != nil { + c.Fatal(err, out2) + } + + cmd = exec.Command(dockerBinary, "run", "--rm", "--name=thost", "--net=host", "busybox", "true") + out2, _, err = runCommandWithOutput(cmd) + if err != nil { + c.Fatal(err, out2) + } +} + func (s *DockerSuite) TestRunNetContainerWhichHost(c *check.C) { testRequires(c, SameHostDaemon) diff --git a/vendor/src/github.com/docker/libnetwork/etchosts/etchosts.go b/vendor/src/github.com/docker/libnetwork/etchosts/etchosts.go index 9095b483b4..466143baee 100644 --- a/vendor/src/github.com/docker/libnetwork/etchosts/etchosts.go +++ b/vendor/src/github.com/docker/libnetwork/etchosts/etchosts.go @@ -68,6 +68,10 @@ func Build(path, IP, hostname, domainname string, extraContent []Record) error { // Add adds an arbitrary number of Records to an already existing /etc/hosts file func Add(path string, recs []Record) error { + if len(recs) == 0 { + return nil + } + f, err := os.Open(path) if err != nil { return err @@ -91,6 +95,10 @@ func Add(path string, recs []Record) error { // Delete deletes an arbitrary number of Records already existing in /etc/hosts file func Delete(path string, recs []Record) error { + if len(recs) == 0 { + return nil + } + old, err := ioutil.ReadFile(path) if err != nil { return err diff --git a/vendor/src/github.com/docker/libnetwork/network.go b/vendor/src/github.com/docker/libnetwork/network.go index de1bbb6684..e52f3bf43e 100644 --- a/vendor/src/github.com/docker/libnetwork/network.go +++ b/vendor/src/github.com/docker/libnetwork/network.go @@ -416,6 +416,11 @@ func (n *network) updateSvcRecord(ep *endpoint, isAdd bool) { } n.Unlock() + // If there are no records to add or delete then simply return here + if len(recs) == 0 { + return + } + var epList []*endpoint n.WalkEndpoints(func(e Endpoint) bool { cEp := e.(*endpoint)