diff --git a/cmd/nerdctl/image/image_remove_test.go b/cmd/nerdctl/image/image_remove_test.go index 5e48372332c..c95f94ba600 100644 --- a/cmd/nerdctl/image/image_remove_test.go +++ b/cmd/nerdctl/image/image_remove_test.go @@ -351,3 +351,18 @@ func TestIssue3016(t *testing.T) { testCase.Run(t) } + +func TestForceRemoveImage(t *testing.T) { + base := testutil.NewBase(t) + tID := testutil.Identifier(t) + base.Cmd("image", "prune", "--force", "--all").AssertOK() + base.Cmd("pull", testutil.CommonImage).AssertOK() + base.Cmd("run", "-d", "--name", tID+"-force", testutil.CommonImage, "sleep", "10s").AssertOK() + base.Cmd("rmi", "-f", testutil.CommonImage).AssertOK() + // Ensure that the image is deleted + base.Cmd("images").AssertOutNotContains(testutil.ImageRepo(testutil.CommonImage)) + // Ensure that the container is still running + base.Cmd("ps", "-a").AssertOutContains(tID + "-force") + // Force remove to clean + base.Cmd("rm", "-f", tID+"-force").AssertOK() +} diff --git a/pkg/cmd/image/remove.go b/pkg/cmd/image/remove.go index 3afa2bff80b..7218755beb4 100644 --- a/pkg/cmd/image/remove.go +++ b/pkg/cmd/image/remove.go @@ -77,8 +77,8 @@ func Remove(ctx context.Context, client *containerd.Client, args []string, optio return nil } - if cid, ok := runningImages[found.Image.Name]; ok { - return fmt.Errorf("conflict: unable to delete %s (cannot be forced) - image is being used by running container %s", found.Req, cid) + if cid, ok := runningImages[found.Image.Name]; !options.Force && ok { + return fmt.Errorf("conflict: unable to delete %s - image is being used by running container %s", found.Req, cid) } if cid, ok := usedImages[found.Image.Name]; ok && !options.Force { return fmt.Errorf("conflict: unable to delete %s (must be forced) - image is being used by stopped container %s", found.Req, cid)