github.com/jen20/docker@v1.13.1/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/digest"
     9  	"github.com/docker/docker/api/types"
    10  	"github.com/docker/docker/builder"
    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/reference"
    15  	"github.com/docker/docker/registry"
    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 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.ParseNamed(image)
    28  	if err != nil {
    29  		return err
    30  	}
    31  
    32  	if tag != "" {
    33  		// The "tag" could actually be a digest.
    34  		var dgst digest.Digest
    35  		dgst, err = digest.ParseDigest(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 err
    43  		}
    44  	}
    45  
    46  	return daemon.pullImageWithReference(ctx, ref, metaHeaders, authConfig, outStream)
    47  }
    48  
    49  // PullOnBuild tells Docker to pull image referenced by `name`.
    50  func (daemon *Daemon) PullOnBuild(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer) (builder.Image, error) {
    51  	ref, err := reference.ParseNamed(name)
    52  	if err != nil {
    53  		return nil, err
    54  	}
    55  	ref = reference.WithDefaultTag(ref)
    56  
    57  	pullRegistryAuth := &types.AuthConfig{}
    58  	if len(authConfigs) > 0 {
    59  		// The request came with a full auth config file, we prefer to use that
    60  		repoInfo, err := daemon.RegistryService.ResolveRepository(ref)
    61  		if err != nil {
    62  			return nil, err
    63  		}
    64  
    65  		resolvedConfig := registry.ResolveAuthConfig(
    66  			authConfigs,
    67  			repoInfo.Index,
    68  		)
    69  		pullRegistryAuth = &resolvedConfig
    70  	}
    71  
    72  	if err := daemon.pullImageWithReference(ctx, ref, nil, pullRegistryAuth, output); err != nil {
    73  		return nil, err
    74  	}
    75  	return daemon.GetImage(name)
    76  }
    77  
    78  func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
    79  	// Include a buffer so that slow client connections don't affect
    80  	// transfer performance.
    81  	progressChan := make(chan progress.Progress, 100)
    82  
    83  	writesDone := make(chan struct{})
    84  
    85  	ctx, cancelFunc := context.WithCancel(ctx)
    86  
    87  	go func() {
    88  		progressutils.WriteDistributionProgress(cancelFunc, outStream, progressChan)
    89  		close(writesDone)
    90  	}()
    91  
    92  	imagePullConfig := &distribution.ImagePullConfig{
    93  		Config: distribution.Config{
    94  			MetaHeaders:      metaHeaders,
    95  			AuthConfig:       authConfig,
    96  			ProgressOutput:   progress.ChanOutput(progressChan),
    97  			RegistryService:  daemon.RegistryService,
    98  			ImageEventLogger: daemon.LogImageEvent,
    99  			MetadataStore:    daemon.distributionMetadataStore,
   100  			ImageStore:       distribution.NewImageConfigStoreFromStore(daemon.imageStore),
   101  			ReferenceStore:   daemon.referenceStore,
   102  		},
   103  		DownloadManager: daemon.downloadManager,
   104  		Schema2Types:    distribution.ImageTypes,
   105  	}
   106  
   107  	err := distribution.Pull(ctx, ref, imagePullConfig)
   108  	close(progressChan)
   109  	<-writesDone
   110  	return err
   111  }
   112  
   113  // GetRepository returns a repository from the registry.
   114  func (daemon *Daemon) GetRepository(ctx context.Context, ref reference.NamedTagged, authConfig *types.AuthConfig) (dist.Repository, bool, error) {
   115  	// get repository info
   116  	repoInfo, err := daemon.RegistryService.ResolveRepository(ref)
   117  	if err != nil {
   118  		return nil, false, err
   119  	}
   120  	// makes sure name is not empty or `scratch`
   121  	if err := distribution.ValidateRepoName(repoInfo.Name()); err != nil {
   122  		return nil, false, err
   123  	}
   124  
   125  	// get endpoints
   126  	endpoints, err := daemon.RegistryService.LookupPullEndpoints(repoInfo.Hostname())
   127  	if err != nil {
   128  		return nil, false, err
   129  	}
   130  
   131  	// retrieve repository
   132  	var (
   133  		confirmedV2 bool
   134  		repository  dist.Repository
   135  		lastError   error
   136  	)
   137  
   138  	for _, endpoint := range endpoints {
   139  		if endpoint.Version == registry.APIVersion1 {
   140  			continue
   141  		}
   142  
   143  		repository, confirmedV2, lastError = distribution.NewV2Repository(ctx, repoInfo, endpoint, nil, authConfig, "pull")
   144  		if lastError == nil && confirmedV2 {
   145  			break
   146  		}
   147  	}
   148  	return repository, confirmedV2, lastError
   149  }