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