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 }