Docker-DCO-1.1-Signed-off-by: Brian Goff <cpuguy83@gmail.com> (github: cpuguy83)
| ... | ... |
@@ -883,6 +883,7 @@ func (cli *DockerCli) CmdRm(args ...string) error {
|
| 883 | 883 |
cmd := cli.Subcmd("rm", "[OPTIONS] CONTAINER [CONTAINER...]", "Remove one or more containers")
|
| 884 | 884 |
v := cmd.Bool([]string{"v", "-volumes"}, false, "Remove the volumes associated to the container")
|
| 885 | 885 |
link := cmd.Bool([]string{"l", "#link", "-link"}, false, "Remove the specified link and not the underlying container")
|
| 886 |
+ force := cmd.Bool([]string{"f", "-force"}, false, "Force removal of running container")
|
|
| 886 | 887 |
|
| 887 | 888 |
if err := cmd.Parse(args); err != nil {
|
| 888 | 889 |
return nil |
| ... | ... |
@@ -898,6 +899,9 @@ func (cli *DockerCli) CmdRm(args ...string) error {
|
| 898 | 898 |
if *link {
|
| 899 | 899 |
val.Set("link", "1")
|
| 900 | 900 |
} |
| 901 |
+ if *force {
|
|
| 902 |
+ val.Set("force", "1")
|
|
| 903 |
+ } |
|
| 901 | 904 |
|
| 902 | 905 |
var encounteredError error |
| 903 | 906 |
for _, name := range cmd.Args() {
|
| ... | ... |
@@ -606,6 +606,7 @@ func deleteContainers(eng *engine.Engine, version version.Version, w http.Respon |
| 606 | 606 |
job := eng.Job("container_delete", vars["name"])
|
| 607 | 607 |
job.Setenv("removeVolume", r.Form.Get("v"))
|
| 608 | 608 |
job.Setenv("removeLink", r.Form.Get("link"))
|
| 609 |
+ job.Setenv("forceRemove", r.Form.Get("force"))
|
|
| 609 | 610 |
if err := job.Run(); err != nil {
|
| 610 | 611 |
return err |
| 611 | 612 |
} |
| ... | ... |
@@ -51,6 +51,11 @@ What's new |
| 51 | 51 |
**New!** You can now use the force parameter to force delete of an image, even if it's |
| 52 | 52 |
tagged in multiple repositories. |
| 53 | 53 |
|
| 54 |
+.. http:delete:: /containers/(id) |
|
| 55 |
+ |
|
| 56 |
+ **New!** You can now use the force paramter to force delete a container, even if |
|
| 57 |
+ it is currently running |
|
| 58 |
+ |
|
| 54 | 59 |
v1.9 |
| 55 | 60 |
**** |
| 56 | 61 |
|
| ... | ... |
@@ -597,6 +597,7 @@ Remove a container |
| 597 | 597 |
HTTP/1.1 204 OK |
| 598 | 598 |
|
| 599 | 599 |
:query v: 1/True/true or 0/False/false, Remove the volumes associated to the container. Default false |
| 600 |
+ :query force: 1/True/true or 0/False/false, Removes the container even if it was running. Default false |
|
| 600 | 601 |
:statuscode 204: no error |
| 601 | 602 |
:statuscode 400: bad parameter |
| 602 | 603 |
:statuscode 404: no such container |
| ... | ... |
@@ -971,7 +971,8 @@ The last container is marked as a ``Ghost`` container. It is a container that wa |
| 971 | 971 |
Usage: docker rm [OPTIONS] CONTAINER |
| 972 | 972 |
|
| 973 | 973 |
Remove one or more containers |
| 974 |
- --link="": Remove the link instead of the actual container |
|
| 974 |
+ -l, --link="": Remove the link instead of the actual container |
|
| 975 |
+ -f, --force=false: Force removal of running container |
|
| 975 | 976 |
|
| 976 | 977 |
Known Issues (rm) |
| 977 | 978 |
~~~~~~~~~~~~~~~~~ |
| ... | ... |
@@ -199,6 +199,68 @@ func TestCreateRmVolumes(t *testing.T) {
|
| 199 | 199 |
} |
| 200 | 200 |
} |
| 201 | 201 |
|
| 202 |
+func TestCreateRmRunning(t *testing.T) {
|
|
| 203 |
+ eng := NewTestEngine(t) |
|
| 204 |
+ defer mkRuntimeFromEngine(eng, t).Nuke() |
|
| 205 |
+ |
|
| 206 |
+ config, hostConfig, _, err := runconfig.Parse([]string{"-name", "foo", unitTestImageID, "sleep 300"}, nil)
|
|
| 207 |
+ if err != nil {
|
|
| 208 |
+ t.Fatal(err) |
|
| 209 |
+ } |
|
| 210 |
+ |
|
| 211 |
+ id := createTestContainer(eng, config, t) |
|
| 212 |
+ |
|
| 213 |
+ job := eng.Job("containers")
|
|
| 214 |
+ job.SetenvBool("all", true)
|
|
| 215 |
+ outs, err := job.Stdout.AddListTable() |
|
| 216 |
+ if err != nil {
|
|
| 217 |
+ t.Fatal(err) |
|
| 218 |
+ } |
|
| 219 |
+ if err := job.Run(); err != nil {
|
|
| 220 |
+ t.Fatal(err) |
|
| 221 |
+ } |
|
| 222 |
+ |
|
| 223 |
+ if len(outs.Data) != 1 {
|
|
| 224 |
+ t.Errorf("Expected 1 container, %v found", len(outs.Data))
|
|
| 225 |
+ } |
|
| 226 |
+ |
|
| 227 |
+ job = eng.Job("start", id)
|
|
| 228 |
+ if err := job.ImportEnv(hostConfig); err != nil {
|
|
| 229 |
+ t.Fatal(err) |
|
| 230 |
+ } |
|
| 231 |
+ if err := job.Run(); err != nil {
|
|
| 232 |
+ t.Fatal(err) |
|
| 233 |
+ } |
|
| 234 |
+ |
|
| 235 |
+ // Test cannot remove running container |
|
| 236 |
+ job = eng.Job("container_delete", id)
|
|
| 237 |
+ job.SetenvBool("forceRemove", false)
|
|
| 238 |
+ if err := job.Run(); err == nil {
|
|
| 239 |
+ t.Fatal("Expected container delete to fail")
|
|
| 240 |
+ } |
|
| 241 |
+ |
|
| 242 |
+ // Test can force removal of running container |
|
| 243 |
+ job = eng.Job("container_delete", id)
|
|
| 244 |
+ job.SetenvBool("forceRemove", true)
|
|
| 245 |
+ if err := job.Run(); err != nil {
|
|
| 246 |
+ t.Fatal(err) |
|
| 247 |
+ } |
|
| 248 |
+ |
|
| 249 |
+ job = eng.Job("containers")
|
|
| 250 |
+ job.SetenvBool("all", true)
|
|
| 251 |
+ outs, err = job.Stdout.AddListTable() |
|
| 252 |
+ if err != nil {
|
|
| 253 |
+ t.Fatal(err) |
|
| 254 |
+ } |
|
| 255 |
+ if err := job.Run(); err != nil {
|
|
| 256 |
+ t.Fatal(err) |
|
| 257 |
+ } |
|
| 258 |
+ |
|
| 259 |
+ if len(outs.Data) != 0 {
|
|
| 260 |
+ t.Errorf("Expected 0 container, %v found", len(outs.Data))
|
|
| 261 |
+ } |
|
| 262 |
+} |
|
| 263 |
+ |
|
| 202 | 264 |
func TestCommit(t *testing.T) {
|
| 203 | 265 |
eng := NewTestEngine(t) |
| 204 | 266 |
defer mkRuntimeFromEngine(eng, t).Nuke() |
| ... | ... |
@@ -1703,6 +1703,7 @@ func (srv *Server) ContainerDestroy(job *engine.Job) engine.Status {
|
| 1703 | 1703 |
name := job.Args[0] |
| 1704 | 1704 |
removeVolume := job.GetenvBool("removeVolume")
|
| 1705 | 1705 |
removeLink := job.GetenvBool("removeLink")
|
| 1706 |
+ forceRemove := job.GetenvBool("forceRemove")
|
|
| 1706 | 1707 |
|
| 1707 | 1708 |
container := srv.runtime.Get(name) |
| 1708 | 1709 |
|
| ... | ... |
@@ -1740,7 +1741,13 @@ func (srv *Server) ContainerDestroy(job *engine.Job) engine.Status {
|
| 1740 | 1740 |
|
| 1741 | 1741 |
if container != nil {
|
| 1742 | 1742 |
if container.State.IsRunning() {
|
| 1743 |
- return job.Errorf("Impossible to remove a running container, please stop it first")
|
|
| 1743 |
+ if forceRemove {
|
|
| 1744 |
+ if err := container.Stop(5); err != nil {
|
|
| 1745 |
+ return job.Errorf("Could not stop running container, cannot remove - %v", err)
|
|
| 1746 |
+ } |
|
| 1747 |
+ } else {
|
|
| 1748 |
+ return job.Errorf("Impossible to remove a running container, please stop it first or use -f")
|
|
| 1749 |
+ } |
|
| 1744 | 1750 |
} |
| 1745 | 1751 |
if err := srv.runtime.Destroy(container); err != nil {
|
| 1746 | 1752 |
return job.Errorf("Cannot destroy container %s: %s", name, err)
|