Browse code

Do not fail when a container is being removed and we request its delete again.

Abort the process and return a success response, letting the original
request finish its job.

Signed-off-by: David Calavera <david.calavera@gmail.com>

David Calavera authored on 2015/10/21 05:36:09
Showing 2 changed files
... ...
@@ -76,22 +76,20 @@ func (daemon *Daemon) rm(container *Container, forceRemove bool) (err error) {
76 76
 		}
77 77
 	}
78 78
 
79
-	// stop collection of stats for the container regardless
80
-	// if stats are currently getting collected.
81
-	daemon.statsCollector.stopCollection(container)
82
-
83
-	element := daemon.containers.Get(container.ID)
84
-	if element == nil {
85
-		return derr.ErrorCodeRmNotFound.WithArgs(container.ID)
86
-	}
87
-
88 79
 	// Container state RemovalInProgress should be used to avoid races.
89 80
 	if err = container.setRemovalInProgress(); err != nil {
81
+		if err == derr.ErrorCodeAlreadyRemoving {
82
+			// do not fail when the removal is in progress started by other request.
83
+			return nil
84
+		}
90 85
 		return derr.ErrorCodeRmState.WithArgs(err)
91 86
 	}
92
-
93 87
 	defer container.resetRemovalInProgress()
94 88
 
89
+	// stop collection of stats for the container regardless
90
+	// if stats are currently getting collected.
91
+	daemon.statsCollector.stopCollection(container)
92
+
95 93
 	if err = container.Stop(3); err != nil {
96 94
 		return err
97 95
 	}
98 96
new file mode 100644
... ...
@@ -0,0 +1,39 @@
0
+package daemon
1
+
2
+import (
3
+	"io/ioutil"
4
+	"os"
5
+	"testing"
6
+
7
+	"github.com/docker/docker/runconfig"
8
+)
9
+
10
+func TestContainerDoubleDelete(t *testing.T) {
11
+	tmp, err := ioutil.TempDir("", "docker-daemon-unix-test-")
12
+	if err != nil {
13
+		t.Fatal(err)
14
+	}
15
+	defer os.RemoveAll(tmp)
16
+	daemon := &Daemon{
17
+		repository: tmp,
18
+		root:       tmp,
19
+	}
20
+
21
+	container := &Container{
22
+		CommonContainer: CommonContainer{
23
+			State:  NewState(),
24
+			Config: &runconfig.Config{},
25
+		},
26
+	}
27
+
28
+	// Mark the container as having a delete in progress
29
+	if err := container.setRemovalInProgress(); err != nil {
30
+		t.Fatal(err)
31
+	}
32
+
33
+	// Try to remove the container when it's start is removalInProgress.
34
+	// It should ignore the container and not return an error.
35
+	if err := daemon.rm(container, true); err != nil {
36
+		t.Fatal(err)
37
+	}
38
+}