github.com/ssdev-go/moby@v17.12.1-ce-rc2+incompatible/daemon/image_pull.go (about)

     1  package daemon
     2  
     3  import (
     4  	"io"
     5  	"runtime"
     6  	"strings"
     7  
     8  	dist "github.com/docker/distribution"
     9  	"github.com/docker/distribution/reference"
    10  	"github.com/docker/docker/api/types"
    11  	"github.com/docker/docker/distribution"
    12  	progressutils "github.com/docker/docker/distribution/utils"
    13  	"github.com/docker/docker/pkg/progress"
    14  	"github.com/docker/docker/registry"
    15  	"github.com/opencontainers/go-digest"
    16  	"golang.org/x/net/context"
    17  )
    18  
    19  // PullImage initiates a pull operation. image is the repository name to pull, and
    20  // tag may be either empty, or indicate a specific tag to pull.
    21  func (daemon *Daemon) PullImage(ctx context.Context, image, tag, platform string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
    22  	// Special case: "pull -a" may send an image name with a
    23  	// trailing :. This is ugly, but let's not break API
    24  	// compatibility.
    25  	image = strings.TrimSuffix(image, ":")
    26  
    27  	ref, err := reference.ParseNormalizedNamed(image)
    28  	if err != nil {
    29  		return validationError{err}
    30  	}
    31  
    32  	if tag != "" {
    33  		// The "tag" could actually be a digest.
    34  		var dgst digest.Digest
    35  		dgst, err = digest.Parse(tag)
    36  		if err == nil {
    37  			ref, err = reference.WithDigest(reference.TrimNamed(ref), dgst)
    38  		} else {
    39  			ref, err = reference.WithTag(ref, tag)
    40  		}
    41  		if err != nil {
    42  			return validationError{err}
    43  		}
    44  	}
    45  
    46  	return daemon.pullImageWithReference(ctx, ref, platform, metaHeaders, authConfig, outStream)
    47  }
    48  
    49  func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.Named, platform string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
    50  	// Include a buffer so that slow client connections don't affect
    51  	// transfer performance.
    52  	progressChan := make(chan progress.Progress, 100)
    53  
    54  	writesDone := make(chan struct{})
    55  
    56  	ctx, cancelFunc := context.WithCancel(ctx)
    57  
    58  	go func() {
    59  		progressutils.WriteDistributionProgress(cancelFunc, outStream, progressChan)
    60  		close(writesDone)
    61  	}()
    62  
    63  	// Default to the host OS platform in case it hasn't been populated with an explicit value.
    64  	if platform == "" {
    65  		platform = runtime.GOOS
    66  	}
    67  
    68  	imagePullConfig := &distribution.ImagePullConfig{
    69  		Config: distribution.Config{
    70  			MetaHeaders:      metaHeaders,
    71  			AuthConfig:       authConfig,
    72  			ProgressOutput:   progress.ChanOutput(progressChan),
    73  			RegistryService:  daemon.RegistryService,
    74  			ImageEventLogger: daemon.LogImageEvent,
    75  			MetadataStore:    daemon.stores[platform].distributionMetadataStore,
    76  			ImageStore:       distribution.NewImageConfigStoreFromStore(daemon.stores[platform].imageStore),
    77  			ReferenceStore:   daemon.referenceStore,
    78  		},
    79  		DownloadManager: daemon.downloadManager,
    80  		Schema2Types:    distribution.ImageTypes,
    81  		Platform:        platform,
    82  	}
    83  
    84  	err := distribution.Pull(ctx, ref, imagePullConfig)
    85  	close(progressChan)
    86  	<-writesDone
    87  	return err
    88  }
    89  
    90  // GetRepository returns a repository from the registry.
    91  func (daemon *Daemon) GetRepository(ctx context.Context, ref reference.Named, authConfig *types.AuthConfig) (dist.Repository, bool, error) {
    92  	// get repository info
    93  	repoInfo, err := daemon.RegistryService.ResolveRepository(ref)
    94  	if err != nil {
    95  		return nil, false, err
    96  	}
    97  	// makes sure name is not empty or `scratch`
    98  	if err := distribution.ValidateRepoName(repoInfo.Name); err != nil {
    99  		return nil, false, validationError{err}
   100  	}
   101  
   102  	// get endpoints
   103  	endpoints, err := daemon.RegistryService.LookupPullEndpoints(reference.Domain(repoInfo.Name))
   104  	if err != nil {
   105  		return nil, false, err
   106  	}
   107  
   108  	// retrieve repository
   109  	var (
   110  		confirmedV2 bool
   111  		repository  dist.Repository
   112  		lastError   error
   113  	)
   114  
   115  	for _, endpoint := range endpoints {
   116  		if endpoint.Version == registry.APIVersion1 {
   117  			continue
   118  		}
   119  
   120  		repository, confirmedV2, lastError = distribution.NewV2Repository(ctx, repoInfo, endpoint, nil, authConfig, "pull")
   121  		if lastError == nil && confirmedV2 {
   122  			break
   123  		}
   124  	}
   125  	return repository, confirmedV2, lastError
   126  }