volumes.Get was not checking for symlinked paths meanwhile when adding a
new volume it was following the symlink.
So when trying to use a bind-mount that is a symlink, the volume is
added with the correct path, but when another container tries to use the
same volume it got a "Volume exists" error because volumes.Get returned
nil and as such attempted to create a new volume.
Docker-DCO-1.1-Signed-off-by: Brian Goff <cpuguy83@gmail.com> (github: cpuguy83)
| ... | ... |
@@ -2221,3 +2221,34 @@ func TestRunRedirectStdout(t *testing.T) {
|
| 2221 | 2221 |
|
| 2222 | 2222 |
logDone("run - redirect stdout")
|
| 2223 | 2223 |
} |
| 2224 |
+ |
|
| 2225 |
+// Regression test for https://github.com/docker/docker/issues/8259 |
|
| 2226 |
+func TestRunReuseBindVolumeThatIsSymlink(t *testing.T) {
|
|
| 2227 |
+ tmpDir, err := ioutil.TempDir(os.TempDir(), "testlink") |
|
| 2228 |
+ if err != nil {
|
|
| 2229 |
+ t.Fatal(err) |
|
| 2230 |
+ } |
|
| 2231 |
+ defer os.RemoveAll(tmpDir) |
|
| 2232 |
+ |
|
| 2233 |
+ linkPath := os.TempDir() + "/testlink2" |
|
| 2234 |
+ if err := os.Symlink(tmpDir, linkPath); err != nil {
|
|
| 2235 |
+ t.Fatal(err) |
|
| 2236 |
+ } |
|
| 2237 |
+ defer os.RemoveAll(linkPath) |
|
| 2238 |
+ |
|
| 2239 |
+ // Create first container |
|
| 2240 |
+ cmd := exec.Command(dockerBinary, "run", "-v", fmt.Sprintf("%s:/tmp/test", linkPath), "busybox", "ls", "-lh", "/tmp/test")
|
|
| 2241 |
+ if _, err := runCommand(cmd); err != nil {
|
|
| 2242 |
+ t.Fatal(err) |
|
| 2243 |
+ } |
|
| 2244 |
+ |
|
| 2245 |
+ // Create second container with same symlinked path |
|
| 2246 |
+ // This will fail if the referenced issue is hit with a "Volume exists" error |
|
| 2247 |
+ cmd = exec.Command(dockerBinary, "run", "-v", fmt.Sprintf("%s:/tmp/test", linkPath), "busybox", "ls", "-lh", "/tmp/test")
|
|
| 2248 |
+ if out, _, err := runCommandWithOutput(cmd); err != nil {
|
|
| 2249 |
+ t.Fatal(err, out) |
|
| 2250 |
+ } |
|
| 2251 |
+ |
|
| 2252 |
+ deleteAllContainers() |
|
| 2253 |
+ logDone("run - can remount old bindmount volume")
|
|
| 2254 |
+} |
| ... | ... |
@@ -97,12 +97,16 @@ func (r *Repository) restore() error {
|
| 97 | 97 |
|
| 98 | 98 |
func (r *Repository) Get(path string) *Volume {
|
| 99 | 99 |
r.lock.Lock() |
| 100 |
- vol := r.volumes[path] |
|
| 100 |
+ vol := r.get(path) |
|
| 101 | 101 |
r.lock.Unlock() |
| 102 | 102 |
return vol |
| 103 | 103 |
} |
| 104 | 104 |
|
| 105 | 105 |
func (r *Repository) get(path string) *Volume {
|
| 106 |
+ path, err := filepath.EvalSymlinks(path) |
|
| 107 |
+ if err != nil {
|
|
| 108 |
+ return nil |
|
| 109 |
+ } |
|
| 106 | 110 |
return r.volumes[path] |
| 107 | 111 |
} |
| 108 | 112 |
|
| ... | ... |
@@ -129,6 +133,10 @@ func (r *Repository) remove(volume *Volume) {
|
| 129 | 129 |
func (r *Repository) Delete(path string) error {
|
| 130 | 130 |
r.lock.Lock() |
| 131 | 131 |
defer r.lock.Unlock() |
| 132 |
+ path, err := filepath.EvalSymlinks(path) |
|
| 133 |
+ if err != nil {
|
|
| 134 |
+ return err |
|
| 135 |
+ } |
|
| 132 | 136 |
volume := r.get(path) |
| 133 | 137 |
if volume == nil {
|
| 134 | 138 |
return fmt.Errorf("Volume %s does not exist", path)
|