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 }