Resolve the reference's name to an image ID in the store, if there's already one present with the same name or ID, and return the image. Returns an error matching ErrNoSuchImage if an image matching ref was not found.
(sys *types.SystemContext)
| 110 | // |
| 111 | // Returns an error matching ErrNoSuchImage if an image matching ref was not found. |
| 112 | func (s *storageReference) resolveImage(sys *types.SystemContext) (*storage.Image, error) { |
| 113 | var loadedImage *storage.Image |
| 114 | if s.id == "" && s.named != nil { |
| 115 | // Look for an image that has the expanded reference name as an explicit Name value. |
| 116 | image, err := s.transport.store.Image(s.named.String()) |
| 117 | if image != nil && err == nil { |
| 118 | loadedImage = image |
| 119 | s.id = image.ID |
| 120 | } |
| 121 | } |
| 122 | if s.id == "" && s.named != nil { |
| 123 | if digested, ok := s.named.(reference.Digested); ok { |
| 124 | // Look for an image with the specified digest that has the same name, |
| 125 | // though possibly with a different tag or digest, as a Name value, so |
| 126 | // that the canonical reference can be implicitly resolved to the image. |
| 127 | // |
| 128 | // Typically there should be at most one such image, because the same |
| 129 | // manifest digest implies the same config, and we choose the storage ID |
| 130 | // based on the config (deduplicating images), except: |
| 131 | // - the user can explicitly specify an ID when creating the image. |
| 132 | // In this case we don't have a preference among the alternatives. |
| 133 | // - when pulling an image from a multi-platform manifest list, we also |
| 134 | // store the manifest list in the image; this allows referencing a |
| 135 | // per-platform image using the manifest list digest, but that also |
| 136 | // means that we can have multiple genuinely different images in the |
| 137 | // storage matching the same manifest list digest (if pulled using different |
| 138 | // SystemContext.{OS,Architecture,Variant}Choice to the same storage). |
| 139 | // In this case we prefer the image matching the current SystemContext. |
| 140 | images, err := s.transport.store.ImagesByDigest(digested.Digest()) |
| 141 | if err == nil && len(images) > 0 { |
| 142 | for _, image := range images { |
| 143 | if imageMatchesRepo(image, s.named) { |
| 144 | if loadedImage == nil || multiArchImageMatchesSystemContext(s.transport.store, image, digested.Digest(), sys) { |
| 145 | loadedImage = image |
| 146 | s.id = image.ID |
| 147 | } |
| 148 | } |
| 149 | } |
| 150 | } |
| 151 | } |
| 152 | } |
| 153 | if s.id == "" { |
| 154 | logrus.Debugf("reference %q does not resolve to an image ID", s.StringWithinTransport()) |
| 155 | // %.0w makes the error visible to error.Unwrap() without including any text. |
| 156 | // ErrNoSuchImage ultimately is “identifier is not an image”, which is not helpful for identifying the root cause. |
| 157 | return nil, fmt.Errorf("reference %q does not resolve to an image ID%.0w", s.StringWithinTransport(), ErrNoSuchImage) |
| 158 | } |
| 159 | if loadedImage == nil { |
| 160 | img, err := s.transport.store.Image(s.id) |
| 161 | if err != nil { |
| 162 | return nil, fmt.Errorf("reading image %q: %w", s.id, err) |
| 163 | } |
| 164 | loadedImage = img |
| 165 | } |
| 166 | if s.named != nil { |
| 167 | if !imageMatchesRepo(loadedImage, s.named) { |
| 168 | logrus.Errorf("no image matching reference %q found", s.StringWithinTransport()) |
| 169 | return nil, ErrNoSuchImage |
no test coverage detected