github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/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/containerd/log"
     9  	"github.com/distribution/reference"
    10  	"github.com/Prakhar-Agarwal-byte/moby/api/types/events"
    11  	"github.com/Prakhar-Agarwal-byte/moby/errdefs"
    12  	"github.com/Prakhar-Agarwal-byte/moby/image"
    13  	"github.com/Prakhar-Agarwal-byte/moby/internal/compatcontext"
    14  	"github.com/pkg/errors"
    15  )
    16  
    17  // TagImage creates an image named as newTag and targeting the given descriptor id.
    18  func (i *ImageService) TagImage(ctx context.Context, imageID image.ID, newTag reference.Named) error {
    19  	targetImage, err := i.resolveImage(ctx, imageID.String())
    20  	if err != nil {
    21  		return errors.Wrapf(err, "failed to resolve image id %q to a descriptor", imageID.String())
    22  	}
    23  
    24  	newImg := containerdimages.Image{
    25  		Name:   newTag.String(),
    26  		Target: targetImage.Target,
    27  		Labels: targetImage.Labels,
    28  	}
    29  
    30  	is := i.client.ImageService()
    31  	_, err = is.Create(ctx, newImg)
    32  	if err != nil {
    33  		if !cerrdefs.IsAlreadyExists(err) {
    34  			return errdefs.System(errors.Wrapf(err, "failed to create image with name %s and target %s", newImg.Name, newImg.Target.Digest.String()))
    35  		}
    36  
    37  		replacedImg, err := is.Get(ctx, newImg.Name)
    38  		if err != nil {
    39  			return errdefs.Unknown(errors.Wrapf(err, "creating image %s failed because it already exists, but accessing it also failed", newImg.Name))
    40  		}
    41  
    42  		// Check if image we would replace already resolves to the same target.
    43  		// No need to do anything.
    44  		if replacedImg.Target.Digest == targetImage.Target.Digest {
    45  			i.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), events.ActionTag)
    46  			return nil
    47  		}
    48  
    49  		// If there already exists an image with this tag, delete it
    50  		if err := i.softImageDelete(ctx, replacedImg); err != nil {
    51  			return errors.Wrapf(err, "failed to delete previous image %s", replacedImg.Name)
    52  		}
    53  
    54  		if _, err = is.Create(compatcontext.WithoutCancel(ctx), newImg); err != nil {
    55  			return errdefs.System(errors.Wrapf(err, "failed to create an image %s with target %s after deleting the existing one",
    56  				newImg.Name, imageID.String()))
    57  		}
    58  	}
    59  
    60  	logger := log.G(ctx).WithFields(log.Fields{
    61  		"imageID": imageID.String(),
    62  		"tag":     newTag.String(),
    63  	})
    64  	logger.Info("image created")
    65  
    66  	defer i.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), events.ActionTag)
    67  
    68  	// The tag succeeded, check if the source image is dangling
    69  	sourceDanglingImg, err := is.Get(compatcontext.WithoutCancel(ctx), danglingImageName(targetImage.Target.Digest))
    70  	if err != nil {
    71  		if !cerrdefs.IsNotFound(err) {
    72  			logger.WithError(err).Warn("unexpected error when checking if source image is dangling")
    73  		}
    74  
    75  		return nil
    76  	}
    77  
    78  	builderLabel, ok := sourceDanglingImg.Labels[imageLabelClassicBuilderParent]
    79  	if ok {
    80  		newImg.Labels = map[string]string{
    81  			imageLabelClassicBuilderParent: builderLabel,
    82  		}
    83  
    84  		if _, err := is.Update(compatcontext.WithoutCancel(ctx), newImg, "labels"); err != nil {
    85  			logger.WithError(err).Warnf("failed to set %s label on the newly tagged image", imageLabelClassicBuilderParent)
    86  		}
    87  	}
    88  
    89  	// Delete the source dangling image, as it's no longer dangling.
    90  	if err := is.Delete(compatcontext.WithoutCancel(ctx), sourceDanglingImg.Name); err != nil {
    91  		logger.WithError(err).Warn("unexpected error when deleting dangling image")
    92  	}
    93  
    94  	return nil
    95  }