github.com/rish1988/moby@v25.0.2+incompatible/daemon/containerd/image_tag.go (about)

     1  package containerd
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	cerrdefs "github.com/containerd/containerd/errdefs"
     8  	containerdimages "github.com/containerd/containerd/images"
     9  	"github.com/containerd/log"
    10  	"github.com/distribution/reference"
    11  	"github.com/docker/docker/api/types/events"
    12  	"github.com/docker/docker/errdefs"
    13  	"github.com/docker/docker/image"
    14  	"github.com/docker/docker/internal/compatcontext"
    15  	"github.com/pkg/errors"
    16  )
    17  
    18  // TagImage creates an image named as newTag and targeting the given descriptor id.
    19  func (i *ImageService) TagImage(ctx context.Context, imageID image.ID, newTag reference.Named) error {
    20  	targetImage, err := i.resolveImage(ctx, imageID.String())
    21  	if err != nil {
    22  		return errors.Wrapf(err, "failed to resolve image id %q to a descriptor", imageID.String())
    23  	}
    24  
    25  	newImg := containerdimages.Image{
    26  		Name:   newTag.String(),
    27  		Target: targetImage.Target,
    28  		Labels: targetImage.Labels,
    29  	}
    30  
    31  	is := i.client.ImageService()
    32  	_, err = is.Create(ctx, newImg)
    33  	if err != nil {
    34  		if !cerrdefs.IsAlreadyExists(err) {
    35  			return errdefs.System(errors.Wrapf(err, "failed to create image with name %s and target %s", newImg.Name, newImg.Target.Digest.String()))
    36  		}
    37  
    38  		replacedImg, all, err := i.resolveAllReferences(ctx, newImg.Name)
    39  		if err != nil {
    40  			return errdefs.Unknown(errors.Wrapf(err, "creating image %s failed because it already exists, but accessing it also failed", newImg.Name))
    41  		} else if replacedImg == nil {
    42  			return errdefs.Unknown(fmt.Errorf("creating image %s failed because it already exists, but failed to resolve", newImg.Name))
    43  		}
    44  
    45  		// Check if image we would replace already resolves to the same target.
    46  		// No need to do anything.
    47  		if replacedImg.Target.Digest == targetImage.Target.Digest {
    48  			i.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), events.ActionTag)
    49  			return nil
    50  		}
    51  
    52  		// If there already exists an image with this tag, delete it
    53  		if err := i.softImageDelete(ctx, *replacedImg, all); err != nil {
    54  			return errors.Wrapf(err, "failed to delete previous image %s", replacedImg.Name)
    55  		}
    56  
    57  		if _, err = is.Create(compatcontext.WithoutCancel(ctx), newImg); err != nil {
    58  			return errdefs.System(errors.Wrapf(err, "failed to create an image %s with target %s after deleting the existing one",
    59  				newImg.Name, imageID.String()))
    60  		}
    61  	}
    62  
    63  	logger := log.G(ctx).WithFields(log.Fields{
    64  		"imageID": imageID.String(),
    65  		"tag":     newTag.String(),
    66  	})
    67  	logger.Info("image created")
    68  
    69  	defer i.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), events.ActionTag)
    70  
    71  	// Delete the source dangling image, as it's no longer dangling.
    72  	if err := is.Delete(compatcontext.WithoutCancel(ctx), danglingImageName(targetImage.Target.Digest)); err != nil {
    73  		logger.WithError(err).Warn("unexpected error when deleting dangling image")
    74  	}
    75  
    76  	return nil
    77  }