github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/daemon/containerd/image_history.go (about) 1 package containerd 2 3 import ( 4 "context" 5 "sort" 6 7 imagetype "github.com/Prakhar-Agarwal-byte/moby/api/types/image" 8 "github.com/Prakhar-Agarwal-byte/moby/errdefs" 9 "github.com/Prakhar-Agarwal-byte/moby/pkg/platforms" 10 "github.com/containerd/containerd/images" 11 cplatforms "github.com/containerd/containerd/platforms" 12 "github.com/containerd/log" 13 "github.com/distribution/reference" 14 "github.com/opencontainers/image-spec/identity" 15 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 16 "github.com/pkg/errors" 17 ) 18 19 // ImageHistory returns a slice of HistoryResponseItem structures for the 20 // specified image name by walking the image lineage. 21 func (i *ImageService) ImageHistory(ctx context.Context, name string) ([]*imagetype.HistoryResponseItem, error) { 22 img, err := i.resolveImage(ctx, name) 23 if err != nil { 24 return nil, err 25 } 26 27 cs := i.client.ContentStore() 28 // TODO: pass platform in from the CLI 29 platform := platforms.AllPlatformsWithPreference(cplatforms.Default()) 30 31 var presentImages []ocispec.Image 32 err = i.walkImageManifests(ctx, img, func(img *ImageManifest) error { 33 conf, err := img.Config(ctx) 34 if err != nil { 35 return err 36 } 37 var ociimage ocispec.Image 38 if err := readConfig(ctx, cs, conf, &ociimage); err != nil { 39 return err 40 } 41 presentImages = append(presentImages, ociimage) 42 return nil 43 }) 44 if err != nil { 45 return nil, err 46 } 47 if len(presentImages) == 0 { 48 return nil, errdefs.NotFound(errors.New("failed to find image manifest")) 49 } 50 51 sort.SliceStable(presentImages, func(i, j int) bool { 52 return platform.Less(presentImages[i].Platform, presentImages[j].Platform) 53 }) 54 ociimage := presentImages[0] 55 56 var ( 57 history []*imagetype.HistoryResponseItem 58 sizes []int64 59 ) 60 s := i.client.SnapshotService(i.snapshotter) 61 62 diffIDs := ociimage.RootFS.DiffIDs 63 for i := range diffIDs { 64 chainID := identity.ChainID(diffIDs[0 : i+1]).String() 65 66 use, err := s.Usage(ctx, chainID) 67 if err != nil { 68 return nil, err 69 } 70 71 sizes = append(sizes, use.Size) 72 } 73 74 for _, h := range ociimage.History { 75 size := int64(0) 76 if !h.EmptyLayer { 77 if len(sizes) == 0 { 78 return nil, errors.New("unable to find the size of the layer") 79 } 80 size = sizes[0] 81 sizes = sizes[1:] 82 } 83 84 var created int64 85 if h.Created != nil { 86 created = h.Created.Unix() 87 } 88 history = append([]*imagetype.HistoryResponseItem{{ 89 ID: "<missing>", 90 Comment: h.Comment, 91 CreatedBy: h.CreatedBy, 92 Created: created, 93 Size: size, 94 Tags: nil, 95 }}, history...) 96 } 97 98 findParents := func(img images.Image) []images.Image { 99 imgs, err := i.getParentsByBuilderLabel(ctx, img) 100 if err != nil { 101 log.G(ctx).WithFields(log.Fields{ 102 "error": err, 103 "image": img, 104 }).Warn("failed to list parent images") 105 return nil 106 } 107 return imgs 108 } 109 110 is := i.client.ImageService() 111 currentImg := img 112 for _, h := range history { 113 dgst := currentImg.Target.Digest.String() 114 h.ID = dgst 115 116 imgs, err := is.List(ctx, "target.digest=="+dgst) 117 if err != nil { 118 return nil, err 119 } 120 121 tags := getImageTags(ctx, imgs) 122 h.Tags = append(h.Tags, tags...) 123 124 parents := findParents(currentImg) 125 126 foundNext := false 127 for _, img := range parents { 128 _, hasLabel := img.Labels[imageLabelClassicBuilderParent] 129 if !foundNext || hasLabel { 130 currentImg = img 131 foundNext = true 132 } 133 } 134 135 if !foundNext { 136 break 137 } 138 } 139 140 return history, nil 141 } 142 143 func getImageTags(ctx context.Context, imgs []images.Image) []string { 144 var tags []string 145 for _, img := range imgs { 146 if isDanglingImage(img) { 147 continue 148 } 149 150 name, err := reference.ParseNamed(img.Name) 151 if err != nil { 152 log.G(ctx).WithFields(log.Fields{ 153 "name": name, 154 "error": err, 155 }).Warn("image with a name that's not a valid named reference") 156 continue 157 } 158 159 tags = append(tags, reference.FamiliarString(name)) 160 } 161 162 return tags 163 }