soft_delete.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566
  1. package containerd
  2. import (
  3. "context"
  4. cerrdefs "github.com/containerd/containerd/errdefs"
  5. containerdimages "github.com/containerd/containerd/images"
  6. "github.com/docker/docker/errdefs"
  7. "github.com/opencontainers/go-digest"
  8. ocispec "github.com/opencontainers/image-spec/specs-go/v1"
  9. "github.com/pkg/errors"
  10. )
  11. // softImageDelete deletes the image, making sure that there are other images
  12. // that reference the content of the deleted image.
  13. // If no other image exists, a dangling one is created.
  14. func (i *ImageService) softImageDelete(ctx context.Context, img containerdimages.Image) error {
  15. is := i.client.ImageService()
  16. // If the image already exists, persist it as dangling image
  17. // but only if no other image has the same target.
  18. digest := img.Target.Digest.String()
  19. imgs, err := is.List(ctx, "target.digest=="+digest)
  20. if err != nil {
  21. return errdefs.System(errors.Wrapf(err, "failed to check if there are images targeting digest %s", digest))
  22. }
  23. // From this point explicitly ignore the passed context
  24. // and don't allow to interrupt operation in the middle.
  25. // Create dangling image if this is the last image pointing to this target.
  26. if len(imgs) == 1 {
  27. danglingImage := img
  28. danglingImage.Name = danglingImageName(img.Target.Digest)
  29. delete(danglingImage.Labels, containerdimages.AnnotationImageName)
  30. delete(danglingImage.Labels, ocispec.AnnotationRefName)
  31. _, err = is.Create(context.Background(), danglingImage)
  32. // Error out in case we couldn't persist the old image.
  33. // If it already exists, then just continue.
  34. if err != nil && !cerrdefs.IsAlreadyExists(err) {
  35. return errdefs.System(errors.Wrapf(err, "failed to create a dangling image for the replaced image %s with digest %s",
  36. danglingImage.Name, danglingImage.Target.Digest.String()))
  37. }
  38. }
  39. // Free the target name.
  40. err = is.Delete(context.Background(), img.Name)
  41. if err != nil {
  42. if !cerrdefs.IsNotFound(err) {
  43. return errdefs.System(errors.Wrapf(err, "failed to delete image %s which existed a moment before", img.Name))
  44. }
  45. }
  46. return nil
  47. }
  48. func danglingImageName(digest digest.Digest) string {
  49. return "moby-dangling@" + digest.String()
  50. }
  51. func isDanglingImage(image containerdimages.Image) bool {
  52. return image.Name == danglingImageName(image.Target.Digest)
  53. }