github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/daemon/image_pull.go (about)

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