mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Merge pull request #3959 from cpuguy83/3958_add_ability_to_remove_running_container_in_single_command
Add ability to force removal of running container via docker rm -f
This commit is contained in:
commit
e388b6aba5
7 changed files with 83 additions and 2 deletions
|
@ -890,6 +890,7 @@ func (cli *DockerCli) CmdRm(args ...string) error {
|
|||
cmd := cli.Subcmd("rm", "[OPTIONS] CONTAINER [CONTAINER...]", "Remove one or more containers")
|
||||
v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated to the container")
|
||||
link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link and not the underlying container")
|
||||
force := cmd.Bool([]string{"f", "-force"}, false, "Force removal of running container")
|
||||
|
||||
if err := cmd.Parse(args); err != nil {
|
||||
return nil
|
||||
|
@ -905,6 +906,9 @@ func (cli *DockerCli) CmdRm(args ...string) error {
|
|||
if *link {
|
||||
val.Set("link", "1")
|
||||
}
|
||||
if *force {
|
||||
val.Set("force", "1")
|
||||
}
|
||||
|
||||
var encounteredError error
|
||||
for _, name := range cmd.Args() {
|
||||
|
|
|
@ -606,6 +606,7 @@ func deleteContainers(eng *engine.Engine, version version.Version, w http.Respon
|
|||
job := eng.Job("container_delete", vars["name"])
|
||||
job.Setenv("removeVolume", r.Form.Get("v"))
|
||||
job.Setenv("removeLink", r.Form.Get("link"))
|
||||
job.Setenv("forceRemove", r.Form.Get("force"))
|
||||
if err := job.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -51,6 +51,11 @@ What's new
|
|||
**New!** You can now use the force parameter to force delete of an image, even if it's
|
||||
tagged in multiple repositories.
|
||||
|
||||
.. http:delete:: /containers/(id)
|
||||
|
||||
**New!** You can now use the force paramter to force delete a container, even if
|
||||
it is currently running
|
||||
|
||||
v1.9
|
||||
****
|
||||
|
||||
|
|
|
@ -597,6 +597,7 @@ Remove a container
|
|||
HTTP/1.1 204 OK
|
||||
|
||||
:query v: 1/True/true or 0/False/false, Remove the volumes associated to the container. Default false
|
||||
:query force: 1/True/true or 0/False/false, Removes the container even if it was running. Default false
|
||||
:statuscode 204: no error
|
||||
:statuscode 400: bad parameter
|
||||
:statuscode 404: no such container
|
||||
|
|
|
@ -995,7 +995,8 @@ The last container is marked as a ``Ghost`` container. It is a container that wa
|
|||
Usage: docker rm [OPTIONS] CONTAINER
|
||||
|
||||
Remove one or more containers
|
||||
--link="": Remove the link instead of the actual container
|
||||
-l, --link="": Remove the link instead of the actual container
|
||||
-f, --force=false: Force removal of running container
|
||||
|
||||
Known Issues (rm)
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -199,6 +199,68 @@ func TestCreateRmVolumes(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestCreateRmRunning(t *testing.T) {
|
||||
eng := NewTestEngine(t)
|
||||
defer mkRuntimeFromEngine(eng, t).Nuke()
|
||||
|
||||
config, hostConfig, _, err := runconfig.Parse([]string{"-name", "foo", unitTestImageID, "sleep 300"}, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
id := createTestContainer(eng, config, t)
|
||||
|
||||
job := eng.Job("containers")
|
||||
job.SetenvBool("all", true)
|
||||
outs, err := job.Stdout.AddListTable()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := job.Run(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(outs.Data) != 1 {
|
||||
t.Errorf("Expected 1 container, %v found", len(outs.Data))
|
||||
}
|
||||
|
||||
job = eng.Job("start", id)
|
||||
if err := job.ImportEnv(hostConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := job.Run(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Test cannot remove running container
|
||||
job = eng.Job("container_delete", id)
|
||||
job.SetenvBool("forceRemove", false)
|
||||
if err := job.Run(); err == nil {
|
||||
t.Fatal("Expected container delete to fail")
|
||||
}
|
||||
|
||||
// Test can force removal of running container
|
||||
job = eng.Job("container_delete", id)
|
||||
job.SetenvBool("forceRemove", true)
|
||||
if err := job.Run(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
job = eng.Job("containers")
|
||||
job.SetenvBool("all", true)
|
||||
outs, err = job.Stdout.AddListTable()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := job.Run(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(outs.Data) != 0 {
|
||||
t.Errorf("Expected 0 container, %v found", len(outs.Data))
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommit(t *testing.T) {
|
||||
eng := NewTestEngine(t)
|
||||
defer mkRuntimeFromEngine(eng, t).Nuke()
|
||||
|
|
|
@ -1713,6 +1713,7 @@ func (srv *Server) ContainerDestroy(job *engine.Job) engine.Status {
|
|||
name := job.Args[0]
|
||||
removeVolume := job.GetenvBool("removeVolume")
|
||||
removeLink := job.GetenvBool("removeLink")
|
||||
forceRemove := job.GetenvBool("forceRemove")
|
||||
|
||||
container := srv.runtime.Get(name)
|
||||
|
||||
|
@ -1750,7 +1751,13 @@ func (srv *Server) ContainerDestroy(job *engine.Job) engine.Status {
|
|||
|
||||
if container != nil {
|
||||
if container.State.IsRunning() {
|
||||
return job.Errorf("Impossible to remove a running container, please stop it first")
|
||||
if forceRemove {
|
||||
if err := container.Stop(5); err != nil {
|
||||
return job.Errorf("Could not stop running container, cannot remove - %v", err)
|
||||
}
|
||||
} else {
|
||||
return job.Errorf("Impossible to remove a running container, please stop it first or use -f")
|
||||
}
|
||||
}
|
||||
if err := srv.runtime.Destroy(container); err != nil {
|
||||
return job.Errorf("Cannot destroy container %s: %s", name, err)
|
||||
|
|
Loading…
Add table
Reference in a new issue