github.com/moby/docker@v26.1.3+incompatible/daemon/containerd/soft_delete.go (about) 1 package containerd 2 3 import ( 4 "context" 5 6 cerrdefs "github.com/containerd/containerd/errdefs" 7 containerdimages "github.com/containerd/containerd/images" 8 "github.com/docker/docker/errdefs" 9 "github.com/docker/docker/internal/compatcontext" 10 "github.com/opencontainers/go-digest" 11 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 12 "github.com/pkg/errors" 13 ) 14 15 const imageNameDanglingPrefix = "moby-dangling@" 16 17 // softImageDelete deletes the image, making sure that there are other images 18 // that reference the content of the deleted image. 19 // If no other image exists, a dangling one is created. 20 func (i *ImageService) softImageDelete(ctx context.Context, img containerdimages.Image, imgs []containerdimages.Image) error { 21 // From this point explicitly ignore the passed context 22 // and don't allow to interrupt operation in the middle. 23 24 // Create dangling image if this is the last image pointing to this target. 25 if len(imgs) == 1 { 26 err := i.ensureDanglingImage(compatcontext.WithoutCancel(ctx), img) 27 28 // Error out in case we couldn't persist the old image. 29 if err != nil { 30 return errdefs.System(errors.Wrapf(err, "failed to create a dangling image for the replaced image %s with digest %s", 31 img.Name, img.Target.Digest.String())) 32 } 33 } 34 35 // Free the target name. 36 // TODO: Add with target option 37 err := i.images.Delete(compatcontext.WithoutCancel(ctx), img.Name) 38 if err != nil { 39 if !cerrdefs.IsNotFound(err) { 40 return errdefs.System(errors.Wrapf(err, "failed to delete image %s which existed a moment before", img.Name)) 41 } 42 } 43 44 return nil 45 } 46 47 func (i *ImageService) ensureDanglingImage(ctx context.Context, from containerdimages.Image) error { 48 danglingImage := from 49 50 danglingImage.Labels = make(map[string]string) 51 for k, v := range from.Labels { 52 switch k { 53 case containerdimages.AnnotationImageName, ocispec.AnnotationRefName: 54 // Don't copy name labels. 55 default: 56 danglingImage.Labels[k] = v 57 } 58 } 59 danglingImage.Name = danglingImageName(from.Target.Digest) 60 61 _, err := i.images.Create(compatcontext.WithoutCancel(ctx), danglingImage) 62 // If it already exists, then just continue. 63 if cerrdefs.IsAlreadyExists(err) { 64 return nil 65 } 66 67 return err 68 } 69 70 func danglingImageName(digest digest.Digest) string { 71 return imageNameDanglingPrefix + digest.String() 72 } 73 74 func isDanglingImage(image containerdimages.Image) bool { 75 // TODO: Also check for expired 76 return image.Name == danglingImageName(image.Target.Digest) 77 }