diff --git a/daemon/delete.go b/daemon/delete.go index 52cc39beaf..49ccc72779 100644 --- a/daemon/delete.go +++ b/daemon/delete.go @@ -76,22 +76,20 @@ func (daemon *Daemon) rm(container *Container, forceRemove bool) (err error) { } } + // Container state RemovalInProgress should be used to avoid races. + if err = container.setRemovalInProgress(); err != nil { + if err == derr.ErrorCodeAlreadyRemoving { + // do not fail when the removal is in progress started by other request. + return nil + } + return derr.ErrorCodeRmState.WithArgs(err) + } + defer container.resetRemovalInProgress() + // stop collection of stats for the container regardless // if stats are currently getting collected. daemon.statsCollector.stopCollection(container) - element := daemon.containers.Get(container.ID) - if element == nil { - return derr.ErrorCodeRmNotFound.WithArgs(container.ID) - } - - // Container state RemovalInProgress should be used to avoid races. - if err = container.setRemovalInProgress(); err != nil { - return derr.ErrorCodeRmState.WithArgs(err) - } - - defer container.resetRemovalInProgress() - if err = container.Stop(3); err != nil { return err } diff --git a/daemon/delete_test.go b/daemon/delete_test.go new file mode 100644 index 0000000000..9a82fce2d2 --- /dev/null +++ b/daemon/delete_test.go @@ -0,0 +1,39 @@ +package daemon + +import ( + "io/ioutil" + "os" + "testing" + + "github.com/docker/docker/runconfig" +) + +func TestContainerDoubleDelete(t *testing.T) { + tmp, err := ioutil.TempDir("", "docker-daemon-unix-test-") + if err != nil { + t.Fatal(err) + } + defer os.RemoveAll(tmp) + daemon := &Daemon{ + repository: tmp, + root: tmp, + } + + container := &Container{ + CommonContainer: CommonContainer{ + State: NewState(), + Config: &runconfig.Config{}, + }, + } + + // Mark the container as having a delete in progress + if err := container.setRemovalInProgress(); err != nil { + t.Fatal(err) + } + + // Try to remove the container when it's start is removalInProgress. + // It should ignore the container and not return an error. + if err := daemon.rm(container, true); err != nil { + t.Fatal(err) + } +}