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  }