Implement ImageDelete for containerd

Signed-off-by: Djordje Lukic <djordje.lukic@docker.com>
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
Djordje Lukic 2022-07-08 14:26:17 +02:00 committed by Sebastiaan van Stijn
parent 71cb54cec4
commit 26c65447df
No known key found for this signature in database
GPG Key ID: 76698F39D527CE8C
6 changed files with 33 additions and 10 deletions

View File

@ -21,7 +21,7 @@ type Backend interface {
} }
type imageBackend interface { type imageBackend interface {
ImageDelete(imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error) ImageDelete(ctx context.Context, imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error)
ImageHistory(imageName string) ([]*image.HistoryResponseItem, error) ImageHistory(imageName string) ([]*image.HistoryResponseItem, error)
Images(ctx context.Context, opts types.ImageListOptions) ([]*types.ImageSummary, error) Images(ctx context.Context, opts types.ImageListOptions) ([]*types.ImageSummary, error)
GetImage(refOrID string, platform *specs.Platform) (retImg *dockerimage.Image, retErr error) GetImage(refOrID string, platform *specs.Platform) (retImg *dockerimage.Image, retErr error)

View File

@ -195,7 +195,7 @@ func (s *imageRouter) deleteImages(ctx context.Context, w http.ResponseWriter, r
force := httputils.BoolValue(r, "force") force := httputils.BoolValue(r, "force")
prune := !httputils.BoolValue(r, "noprune") prune := !httputils.BoolValue(r, "noprune")
list, err := s.backend.ImageDelete(name, force, prune) list, err := s.backend.ImageDelete(ctx, name, force, prune)
if err != nil { if err != nil {
return err return err
} }

View File

@ -1,6 +1,12 @@
package containerd package containerd
import "github.com/docker/docker/api/types" import (
"context"
"github.com/containerd/containerd/images"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types"
)
// ImageDelete deletes the image referenced by the given imageRef from this // ImageDelete deletes the image referenced by the given imageRef from this
// daemon. The given imageRef can be an image ID, ID prefix, or a repository // daemon. The given imageRef can be an image ID, ID prefix, or a repository
@ -35,6 +41,22 @@ import "github.com/docker/docker/api/types"
// If prune is true, ancestor images will each attempt to be deleted quietly, // If prune is true, ancestor images will each attempt to be deleted quietly,
// meaning any delete conflicts will cause the image to not be deleted and the // meaning any delete conflicts will cause the image to not be deleted and the
// conflict will not be reported. // conflict will not be reported.
func (i *ImageService) ImageDelete(imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error) { //
panic("not implemented") // TODO(thaJeztah): implement ImageDelete "force" options; see https://github.com/moby/moby/issues/43850
// TODO(thaJeztah): implement ImageDelete "prune" options; see https://github.com/moby/moby/issues/43849
// TODO(thaJeztah): add support for image delete using image (short)ID; see https://github.com/moby/moby/issues/43854
// TODO(thaJeztah): mage delete should send image "untag" events and prometheus counters; see https://github.com/moby/moby/issues/43855
func (i *ImageService) ImageDelete(ctx context.Context, imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error) {
parsedRef, err := reference.ParseNormalizedNamed(imageRef)
if err != nil {
return nil, err
}
ref := reference.TagNameOnly(parsedRef)
err = i.client.ImageService().Delete(ctx, ref.String(), images.SynchronousDelete())
if err != nil {
return nil, err
}
return []types.ImageDeleteResponseItem{{Untagged: reference.FamiliarString(parsedRef)}}, nil
} }

View File

@ -28,7 +28,7 @@ type ImageService interface {
PullImage(ctx context.Context, image, tag string, platform *v1.Platform, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error PullImage(ctx context.Context, image, tag string, platform *v1.Platform, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error PushImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error
CreateImage(config []byte, parent string) (builder.Image, error) CreateImage(config []byte, parent string) (builder.Image, error)
ImageDelete(imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error) ImageDelete(ctx context.Context, imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error)
ExportImage(names []string, outStream io.Writer) error ExportImage(names []string, outStream io.Writer) error
LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error LoadImage(inTar io.ReadCloser, outStream io.Writer, quiet bool) error
Images(ctx context.Context, opts types.ImageListOptions) ([]*types.ImageSummary, error) Images(ctx context.Context, opts types.ImageListOptions) ([]*types.ImageSummary, error)

View File

@ -1,6 +1,7 @@
package images // import "github.com/docker/docker/daemon/images" package images // import "github.com/docker/docker/daemon/images"
import ( import (
"context"
"fmt" "fmt"
"strings" "strings"
"time" "time"
@ -58,7 +59,7 @@ const (
// If prune is true, ancestor images will each attempt to be deleted quietly, // If prune is true, ancestor images will each attempt to be deleted quietly,
// meaning any delete conflicts will cause the image to not be deleted and the // meaning any delete conflicts will cause the image to not be deleted and the
// conflict will not be reported. // conflict will not be reported.
func (i *ImageService) ImageDelete(imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error) { func (i *ImageService) ImageDelete(ctx context.Context, imageRef string, force, prune bool) ([]types.ImageDeleteResponseItem, error) {
start := time.Now() start := time.Now()
records := []types.ImageDeleteResponseItem{} records := []types.ImageDeleteResponseItem{}

View File

@ -119,7 +119,7 @@ deleteImagesLoop:
if shouldDelete { if shouldDelete {
for _, ref := range refs { for _, ref := range refs {
imgDel, err := i.ImageDelete(ref.String(), false, true) imgDel, err := i.ImageDelete(ctx, ref.String(), false, true)
if imageDeleteFailed(ref.String(), err) { if imageDeleteFailed(ref.String(), err) {
continue continue
} }
@ -128,7 +128,7 @@ deleteImagesLoop:
} }
} else { } else {
hex := id.Digest().Hex() hex := id.Digest().Hex()
imgDel, err := i.ImageDelete(hex, false, true) imgDel, err := i.ImageDelete(ctx, hex, false, true)
if imageDeleteFailed(hex, err) { if imageDeleteFailed(hex, err) {
continue continue
} }
@ -163,7 +163,7 @@ func imageDeleteFailed(ref string, err error) bool {
switch { switch {
case err == nil: case err == nil:
return false return false
case errdefs.IsConflict(err): case errdefs.IsConflict(err), errors.Is(err, context.Canceled), errors.Is(err, context.DeadlineExceeded):
return true return true
default: default:
logrus.Warnf("failed to prune image %s: %v", ref, err) logrus.Warnf("failed to prune image %s: %v", ref, err)