Browse code

Fix docker rename with linked containers

This fix tries to address issue raised in #23973 where the
`docker rename` does not update namedIndex and linkIndex,
thus resulting in failures when the linked containers are
referenced later on.

This fix updates the namedIndex and linkIndex during the
`docker rename` and fixes the issue.

An integration test has been added to cover the changes
in this fix.

This fix fixes #23973.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>

Yong Tang authored on 2016/06/28 10:48:11
Showing 2 changed files
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"strings"
6 6
 
7 7
 	"github.com/Sirupsen/logrus"
8
+	dockercontainer "github.com/docker/docker/container"
8 9
 	"github.com/docker/libnetwork"
9 10
 )
10 11
 
... ...
@@ -40,10 +41,23 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error {
40 40
 	container.Lock()
41 41
 	defer container.Unlock()
42 42
 
43
+	links := map[string]*dockercontainer.Container{}
44
+	for k, v := range daemon.linkIndex.children(container) {
45
+		if !strings.HasPrefix(k, oldName) {
46
+			return fmt.Errorf("Linked container %s does not match parent %s", k, oldName)
47
+		}
48
+		links[strings.TrimPrefix(k, oldName)] = v
49
+	}
50
+
43 51
 	if newName, err = daemon.reserveName(container.ID, newName); err != nil {
44 52
 		return fmt.Errorf("Error when allocating new name: %v", err)
45 53
 	}
46 54
 
55
+	for k, v := range links {
56
+		daemon.nameIndex.Reserve(newName+k, v.ID)
57
+		daemon.linkIndex.link(container, v, newName+k)
58
+	}
59
+
47 60
 	container.Name = newName
48 61
 	container.NetworkSettings.IsAnonymousEndpoint = false
49 62
 
... ...
@@ -52,10 +66,20 @@ func (daemon *Daemon) ContainerRename(oldName, newName string) error {
52 52
 			container.Name = oldName
53 53
 			container.NetworkSettings.IsAnonymousEndpoint = oldIsAnonymousEndpoint
54 54
 			daemon.reserveName(container.ID, oldName)
55
+			for k, v := range links {
56
+				daemon.nameIndex.Reserve(oldName+k, v.ID)
57
+				daemon.linkIndex.link(container, v, oldName+k)
58
+				daemon.linkIndex.unlink(newName+k, v, container)
59
+				daemon.nameIndex.Release(newName + k)
60
+			}
55 61
 			daemon.releaseName(newName)
56 62
 		}
57 63
 	}()
58 64
 
65
+	for k, v := range links {
66
+		daemon.linkIndex.unlink(oldName+k, v, container)
67
+		daemon.nameIndex.Release(oldName + k)
68
+	}
59 69
 	daemon.releaseName(oldName)
60 70
 	if err = container.ToDisk(); err != nil {
61 71
 		return err
... ...
@@ -121,3 +121,15 @@ func (s *DockerSuite) TestRenameContainerWithSameName(c *check.C) {
121 121
 	c.Assert(err, checker.NotNil, check.Commentf("Renaming a container with the same name should have failed"))
122 122
 	c.Assert(out, checker.Contains, "Renaming a container with the same name", check.Commentf("%v", err))
123 123
 }
124
+
125
+// Test case for #23973
126
+func (s *DockerSuite) TestRenameContainerWithLinkedContainer(c *check.C) {
127
+	testRequires(c, DaemonIsLinux)
128
+
129
+	db1, _ := dockerCmd(c, "run", "--name", "db1", "-d", "busybox", "top")
130
+	dockerCmd(c, "run", "--name", "app1", "-d", "--link", "db1:/mysql", "busybox", "top")
131
+	dockerCmd(c, "rename", "app1", "app2")
132
+	out, _, err := dockerCmdWithError("inspect", "--format='{{ .Id }}'", "app2/mysql")
133
+	c.Assert(err, checker.IsNil)
134
+	c.Assert(strings.TrimSpace(out), checker.Equals, strings.TrimSpace(db1))
135
+}