github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/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/Prakhar-Agarwal-byte/moby/errdefs" 9 "github.com/Prakhar-Agarwal-byte/moby/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) error { 21 is := i.client.ImageService() 22 23 // If the image already exists, persist it as dangling image 24 // but only if no other image has the same target. 25 dgst := img.Target.Digest.String() 26 imgs, err := is.List(ctx, "target.digest=="+dgst) 27 if err != nil { 28 return errdefs.System(errors.Wrapf(err, "failed to check if there are images targeting digest %s", dgst)) 29 } 30 31 // From this point explicitly ignore the passed context 32 // and don't allow to interrupt operation in the middle. 33 34 // Create dangling image if this is the last image pointing to this target. 35 if len(imgs) == 1 { 36 err = i.ensureDanglingImage(compatcontext.WithoutCancel(ctx), img) 37 38 // Error out in case we couldn't persist the old image. 39 if err != nil { 40 return errdefs.System(errors.Wrapf(err, "failed to create a dangling image for the replaced image %s with digest %s", 41 img.Name, img.Target.Digest.String())) 42 } 43 } 44 45 // Free the target name. 46 err = is.Delete(compatcontext.WithoutCancel(ctx), img.Name) 47 if err != nil { 48 if !cerrdefs.IsNotFound(err) { 49 return errdefs.System(errors.Wrapf(err, "failed to delete image %s which existed a moment before", img.Name)) 50 } 51 } 52 53 return nil 54 } 55 56 func (i *ImageService) ensureDanglingImage(ctx context.Context, from containerdimages.Image) error { 57 danglingImage := from 58 59 danglingImage.Labels = make(map[string]string) 60 for k, v := range from.Labels { 61 switch k { 62 case containerdimages.AnnotationImageName, ocispec.AnnotationRefName: 63 // Don't copy name labels. 64 default: 65 danglingImage.Labels[k] = v 66 } 67 } 68 danglingImage.Name = danglingImageName(from.Target.Digest) 69 70 _, err := i.client.ImageService().Create(compatcontext.WithoutCancel(ctx), danglingImage) 71 // If it already exists, then just continue. 72 if cerrdefs.IsAlreadyExists(err) { 73 return nil 74 } 75 76 return err 77 } 78 79 func danglingImageName(digest digest.Digest) string { 80 return imageNameDanglingPrefix + digest.String() 81 } 82 83 func isDanglingImage(image containerdimages.Image) bool { 84 return image.Name == danglingImageName(image.Target.Digest) 85 }