github.com/moby/docker@v26.1.3+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 _, err = i.images.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, all, err := i.resolveAllReferences(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 } else if replacedImg == nil { 41 return errdefs.Unknown(fmt.Errorf("creating image %s failed because it already exists, but failed to resolve", newImg.Name)) 42 } 43 44 // Check if image we would replace already resolves to the same target. 45 // No need to do anything. 46 if replacedImg.Target.Digest == targetImage.Target.Digest { 47 i.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), events.ActionTag) 48 return nil 49 } 50 51 // If there already exists an image with this tag, delete it 52 if err := i.softImageDelete(ctx, *replacedImg, all); err != nil { 53 return errors.Wrapf(err, "failed to delete previous image %s", replacedImg.Name) 54 } 55 56 if _, err = i.images.Create(compatcontext.WithoutCancel(ctx), newImg); err != nil { 57 return errdefs.System(errors.Wrapf(err, "failed to create an image %s with target %s after deleting the existing one", 58 newImg.Name, imageID.String())) 59 } 60 } 61 62 logger := log.G(ctx).WithFields(log.Fields{ 63 "imageID": imageID.String(), 64 "tag": newTag.String(), 65 }) 66 logger.Info("image created") 67 68 defer i.LogImageEvent(imageID.String(), reference.FamiliarString(newTag), events.ActionTag) 69 70 // Delete the source dangling image, as it's no longer dangling. 71 if err := i.images.Delete(compatcontext.WithoutCancel(ctx), danglingImageName(targetImage.Target.Digest)); err != nil { 72 logger.WithError(err).Warn("unexpected error when deleting dangling image") 73 } 74 75 return nil 76 }