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 }