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 }