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  }