From 93d189d322672aee6e74793a35433d59e32357a0 Mon Sep 17 00:00:00 2001 From: Piotr Tabor Date: Fri, 11 Oct 2024 22:34:08 +0200 Subject: [PATCH] Expose image 'DeleteTag' method in the 'daemon' MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The method is needed to enable image cleanup in the container-structure-tests. The problem I'm trying to solve is that container-structure-tests are writing an image to docker https://github.com/GoogleContainerTools/container-structure-test/blob/c35e48dcd5dd[…]ec6d50d688235d4a36/cmd/container-structure-test/app/cmd/test.go but they are not deleting it at all. This leads to leaked registry.structure_test.oci.local/image that accumulate in CICD. --- pkg/v1/daemon/image_test.go | 2 ++ pkg/v1/daemon/options.go | 1 + pkg/v1/daemon/write.go | 19 +++++++++++++++++-- pkg/v1/daemon/write_test.go | 7 +++++++ 4 files changed, 27 insertions(+), 2 deletions(-) diff --git a/pkg/v1/daemon/image_test.go b/pkg/v1/daemon/image_test.go index 3dd49579e..cdb550e3b 100644 --- a/pkg/v1/daemon/image_test.go +++ b/pkg/v1/daemon/image_test.go @@ -82,6 +82,8 @@ type MockClient struct { inspectBody []byte tagErr error + + imageRemoveErr error } func (m *MockClient) NegotiateAPIVersion(_ context.Context) { diff --git a/pkg/v1/daemon/options.go b/pkg/v1/daemon/options.go index b80646369..1f1cd3bfc 100644 --- a/pkg/v1/daemon/options.go +++ b/pkg/v1/daemon/options.go @@ -102,4 +102,5 @@ type Client interface { ImageTag(context.Context, string, string) error ImageInspectWithRaw(context.Context, string) (types.ImageInspect, []byte, error) ImageHistory(context.Context, string) ([]api.HistoryResponseItem, error) + ImageRemove(context.Context, string, types.ImageRemoveOptions) ([]types.ImageDeleteResponseItem, error) } diff --git a/pkg/v1/daemon/write.go b/pkg/v1/daemon/write.go index 3ca5b52dd..fb68d995b 100644 --- a/pkg/v1/daemon/write.go +++ b/pkg/v1/daemon/write.go @@ -16,11 +16,11 @@ package daemon import ( "fmt" - "io" - + "github.com/docker/docker/api/types" "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/tarball" + "io" ) // Tag adds a tag to an already existent image. @@ -76,3 +76,18 @@ func Write(tag name.Tag, img v1.Image, options ...Option) (string, error) { } return response, nil } + +// DeleteTag - Deletes given tag: +// - force - delete the image even if it is being used by stopped containers or has other tags +// - pruneChildren - deletes untagged parent images +func DeleteTag(tag name.Tag, pruneChildren bool, force bool, options ...Option) error { + o, err := makeOptions(options...) + if err != nil { + return err + } + _, err = o.client.ImageRemove(o.ctx, tag.Name(), types.ImageRemoveOptions{PruneChildren: pruneChildren, Force: force}) + if err != nil { + return fmt.Errorf("error deleting image %s: %w", tag.Name(), err) + } + return nil +} diff --git a/pkg/v1/daemon/write_test.go b/pkg/v1/daemon/write_test.go index 6f70f7a27..d6bfb0496 100644 --- a/pkg/v1/daemon/write_test.go +++ b/pkg/v1/daemon/write_test.go @@ -61,6 +61,10 @@ func (m *MockClient) ImageTag(ctx context.Context, _, _ string) error { return m.tagErr } +func (m *MockClient) ImageRemove(context.Context, string, types.ImageRemoveOptions) ([]types.ImageDeleteResponseItem, error) { + return nil, m.imageRemoveErr +} + func TestWriteImage(t *testing.T) { for _, tc := range []struct { name string @@ -165,4 +169,7 @@ func TestWriteDefaultClient(t *testing.T) { if _, err := Write(tag, empty.Image, WithContext(ctx)); err != nil { t.Fatal(err) } + if err := DeleteTag(tag, false, false, WithContext(ctx)); err != nil { + t.Fatal(err) + } }