Skip to content

Commit bb7bba5

Browse files
authored
Merge pull request #1935 from suyanhanx/1922
make prune to remove dangling images only
2 parents 1514b96 + 0e13baa commit bb7bba5

File tree

3 files changed

+60
-16
lines changed

3 files changed

+60
-16
lines changed

cmd/nerdctl/image_prune.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,15 @@ func imagePruneAction(cmd *cobra.Command, _ []string) error {
7171
}
7272

7373
if !options.Force {
74-
var confirm string
75-
msg := "This will remove all images without at least one container associated to them."
74+
var (
75+
confirm string
76+
msg string
77+
)
78+
if !options.All {
79+
msg = "This will remove all dangling images."
80+
} else {
81+
msg = "This will remove all images without at least one container associated to them."
82+
}
7683
msg += "\nAre you sure you want to continue? [y/N] "
7784

7885
fmt.Fprintf(cmd.OutOrStdout(), "WARNING! %s", msg)

cmd/nerdctl/image_prune_test.go

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ func TestImagePrune(t *testing.T) {
2929
testutil.RequiresBuild(t)
3030

3131
base := testutil.NewBase(t)
32-
defer base.Cmd("builder", "prune").Run()
32+
defer base.Cmd("builder", "prune").AssertOK()
3333
imageName := testutil.Identifier(t)
34-
defer base.Cmd("rmi", imageName).Run()
34+
defer base.Cmd("rmi", imageName).AssertOK()
3535

3636
dockerfile := fmt.Sprintf(`FROM %s
3737
CMD ["echo", "nerdctl-test-image-prune"]`, testutil.CommonImage)
@@ -40,12 +40,36 @@ func TestImagePrune(t *testing.T) {
4040
assert.NilError(t, err)
4141
defer os.RemoveAll(buildCtx)
4242

43+
base.Cmd("build", buildCtx).AssertOK()
4344
base.Cmd("build", "-t", imageName, buildCtx).AssertOK()
45+
base.Cmd("images").AssertOutContainsAll(imageName, "<none>")
46+
47+
base.Cmd("image", "prune", "--force").AssertNoOut(imageName)
48+
base.Cmd("images").AssertNoOut("<none>")
49+
base.Cmd("images").AssertOutContains(imageName)
50+
}
51+
52+
func TestImagePruneAll(t *testing.T) {
53+
testutil.RequiresBuild(t)
54+
55+
base := testutil.NewBase(t)
56+
defer base.Cmd("builder", "prune").AssertOK()
57+
imageName := testutil.Identifier(t)
58+
59+
dockerfile := fmt.Sprintf(`FROM %s
60+
CMD ["echo", "nerdctl-test-image-prune"]`, testutil.CommonImage)
61+
62+
buildCtx, err := createBuildContext(dockerfile)
63+
assert.NilError(t, err)
64+
defer os.RemoveAll(buildCtx)
65+
66+
base.Cmd("build", "-t", imageName, buildCtx).AssertOK()
67+
// The following commands will clean up all images, so it should fail at this point.
68+
defer base.Cmd("rmi", imageName).AssertFail()
4469
base.Cmd("images").AssertOutContains(imageName)
4570

4671
tID := testutil.Identifier(t)
4772
base.Cmd("run", "--name", tID, imageName).AssertOK()
48-
defer base.Cmd("rm", "-f", tID).Run()
4973
base.Cmd("image", "prune", "--force", "--all").AssertNoOut(imageName)
5074
base.Cmd("images").AssertOutContains(imageName)
5175

pkg/cmd/image/prune.go

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/containerd/containerd/images"
2525
"github.com/containerd/containerd/platforms"
2626
"github.com/containerd/nerdctl/pkg/api/types"
27+
"github.com/containerd/nerdctl/pkg/imgutil"
2728
"github.com/opencontainers/go-digest"
2829
"github.com/sirupsen/logrus"
2930
)
@@ -40,21 +41,33 @@ func Prune(ctx context.Context, client *containerd.Client, options types.ImagePr
4041
if err != nil {
4142
return err
4243
}
43-
containerList, err := containerStore.List(ctx)
44-
if err != nil {
45-
return err
46-
}
47-
usedImages := make(map[string]struct{})
48-
for _, container := range containerList {
49-
usedImages[container.Image] = struct{}{}
44+
45+
var filteredImages []images.Image
46+
47+
if options.All {
48+
containerList, err := containerStore.List(ctx)
49+
if err != nil {
50+
return err
51+
}
52+
usedImages := make(map[string]struct{})
53+
for _, container := range containerList {
54+
usedImages[container.Image] = struct{}{}
55+
}
56+
57+
for _, image := range imageList {
58+
if _, ok := usedImages[image.Name]; ok {
59+
continue
60+
}
61+
62+
filteredImages = append(filteredImages, image)
63+
}
64+
} else {
65+
filteredImages = imgutil.FilterDangling(imageList, true)
5066
}
5167

5268
delOpts := []images.DeleteOpt{images.SynchronousDelete()}
5369
removedImages := make(map[string][]digest.Digest)
54-
for _, image := range imageList {
55-
if _, ok := usedImages[image.Name]; ok {
56-
continue
57-
}
70+
for _, image := range filteredImages {
5871
digests, err := image.RootFS(ctx, contentStore, platforms.DefaultStrict())
5972
if err != nil {
6073
logrus.WithError(err).Warnf("failed to enumerate rootfs")

0 commit comments

Comments
 (0)