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