github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/daemon/images/image.go (about) 1 package images // import "github.com/docker/docker/daemon/images" 2 3 import ( 4 "fmt" 5 6 "github.com/pkg/errors" 7 8 "github.com/docker/distribution/reference" 9 "github.com/docker/docker/errdefs" 10 "github.com/docker/docker/image" 11 specs "github.com/opencontainers/image-spec/specs-go/v1" 12 ) 13 14 // ErrImageDoesNotExist is error returned when no image can be found for a reference. 15 type ErrImageDoesNotExist struct { 16 ref reference.Reference 17 } 18 19 func (e ErrImageDoesNotExist) Error() string { 20 ref := e.ref 21 if named, ok := ref.(reference.Named); ok { 22 ref = reference.TagNameOnly(named) 23 } 24 return fmt.Sprintf("No such image: %s", reference.FamiliarString(ref)) 25 } 26 27 // NotFound implements the NotFound interface 28 func (e ErrImageDoesNotExist) NotFound() {} 29 30 // GetImage returns an image corresponding to the image referred to by refOrID. 31 func (i *ImageService) GetImage(refOrID string, platform *specs.Platform) (retImg *image.Image, retErr error) { 32 defer func() { 33 if retErr != nil || retImg == nil || platform == nil { 34 return 35 } 36 37 // This allows us to tell clients that we don't have the image they asked for 38 // Where this gets hairy is the image store does not currently support multi-arch images, e.g.: 39 // An image `foo` may have a multi-arch manifest, but the image store only fetches the image for a specific platform 40 // The image store does not store the manifest list and image tags are assigned to architecture specific images. 41 // So we can have a `foo` image that is amd64 but the user requested armv7. If the user looks at the list of images. 42 // This may be confusing. 43 // The alternative to this is to return a errdefs.Conflict error with a helpful message, but clients will not be 44 // able to automatically tell what causes the conflict. 45 if retImg.OS != platform.OS { 46 retErr = errdefs.NotFound(errors.Errorf("image with reference %s was found but does not match the specified OS platform: wanted: %s, actual: %s", refOrID, platform.OS, retImg.OS)) 47 retImg = nil 48 return 49 } 50 if retImg.Architecture != platform.Architecture { 51 retErr = errdefs.NotFound(errors.Errorf("image with reference %s was found but does not match the specified platform cpu architecture: wanted: %s, actual: %s", refOrID, platform.Architecture, retImg.Architecture)) 52 retImg = nil 53 return 54 } 55 56 // Only validate variant if retImg has a variant set. 57 // The image variant may not be set since it's a newer field. 58 if platform.Variant != "" && retImg.Variant != "" && retImg.Variant != platform.Variant { 59 retErr = errdefs.NotFound(errors.Errorf("image with reference %s was found but does not match the specified platform cpu architecture variant: wanted: %s, actual: %s", refOrID, platform.Variant, retImg.Variant)) 60 retImg = nil 61 return 62 } 63 }() 64 ref, err := reference.ParseAnyReference(refOrID) 65 if err != nil { 66 return nil, errdefs.InvalidParameter(err) 67 } 68 namedRef, ok := ref.(reference.Named) 69 if !ok { 70 digested, ok := ref.(reference.Digested) 71 if !ok { 72 return nil, ErrImageDoesNotExist{ref} 73 } 74 id := image.IDFromDigest(digested.Digest()) 75 if img, err := i.imageStore.Get(id); err == nil { 76 return img, nil 77 } 78 return nil, ErrImageDoesNotExist{ref} 79 } 80 81 if digest, err := i.referenceStore.Get(namedRef); err == nil { 82 // Search the image stores to get the operating system, defaulting to host OS. 83 id := image.IDFromDigest(digest) 84 if img, err := i.imageStore.Get(id); err == nil { 85 return img, nil 86 } 87 } 88 89 // Search based on ID 90 if id, err := i.imageStore.Search(refOrID); err == nil { 91 img, err := i.imageStore.Get(id) 92 if err != nil { 93 return nil, ErrImageDoesNotExist{ref} 94 } 95 return img, nil 96 } 97 98 return nil, ErrImageDoesNotExist{ref} 99 }