github.com/rawahars/moby@v24.0.4+incompatible/daemon/containerd/image_tag.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/distribution/reference"
     9  	"github.com/docker/docker/errdefs"
    10  	"github.com/docker/docker/image"
    11  	"github.com/pkg/errors"
    12  	"github.com/sirupsen/logrus"
    13  )
    14  
    15  // TagImage creates an image named as newTag and targeting the given descriptor id.
    16  func (i *ImageService) TagImage(ctx context.Context, imageID image.ID, newTag reference.Named) error {
    17  	target, err := i.resolveDescriptor(ctx, imageID.String())
    18  	if err != nil {
    19  		return errors.Wrapf(err, "failed to resolve image id %q to a descriptor", imageID.String())
    20  	}
    21  
    22  	newImg := containerdimages.Image{
    23  		Name:   newTag.String(),
    24  		Target: target,
    25  	}
    26  
    27  	is := i.client.ImageService()
    28  	_, err = is.Create(ctx, newImg)
    29  	if err != nil {
    30  		if !cerrdefs.IsAlreadyExists(err) {
    31  			return errdefs.System(errors.Wrapf(err, "failed to create image with name %s and target %s", newImg.Name, newImg.Target.Digest.String()))
    32  		}
    33  
    34  		replacedImg, err := is.Get(ctx, newImg.Name)
    35  		if err != nil {
    36  			return errdefs.Unknown(errors.Wrapf(err, "creating image %s failed because it already exists, but accessing it also failed", newImg.Name))
    37  		}
    38  
    39  		// Check if image we would replace already resolves to the same target.
    40  		// No need to do anything.
    41  		if replacedImg.Target.Digest == target.Digest {
    42  			i.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), "tag")
    43  			return nil
    44  		}
    45  
    46  		// If there already exists an image with this tag, delete it
    47  		if err := i.softImageDelete(ctx, replacedImg); err != nil {
    48  			return errors.Wrapf(err, "failed to delete previous image %s", replacedImg.Name)
    49  		}
    50  
    51  		if _, err = is.Create(context.Background(), newImg); err != nil {
    52  			return errdefs.System(errors.Wrapf(err, "failed to create an image %s with target %s after deleting the existing one",
    53  				newImg.Name, imageID.String()))
    54  		}
    55  	}
    56  
    57  	logger := logrus.WithFields(logrus.Fields{
    58  		"imageID": imageID.String(),
    59  		"tag":     newTag.String(),
    60  	})
    61  	logger.Info("image created")
    62  
    63  	defer i.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), "tag")
    64  
    65  	// The tag succeeded, check if the source image is dangling
    66  	sourceDanglingImg, err := is.Get(context.Background(), danglingImageName(target.Digest))
    67  	if err != nil {
    68  		if !cerrdefs.IsNotFound(err) {
    69  			logger.WithError(err).Warn("unexpected error when checking if source image is dangling")
    70  		}
    71  
    72  		return nil
    73  	}
    74  
    75  	// Delete the source dangling image, as it's no longer dangling.
    76  	if err := is.Delete(context.Background(), sourceDanglingImg.Name); err != nil {
    77  		logger.WithError(err).Warn("unexpected error when deleting dangling image")
    78  	}
    79  
    80  	return nil
    81  }