github.com/sams1990/dockerrepo@v17.12.1-ce-rc2+incompatible/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/pkg/progress" 14 "github.com/docker/docker/registry" 15 "github.com/opencontainers/go-digest" 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, platform 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.ParseNormalizedNamed(image) 28 if err != nil { 29 return validationError{err} 30 } 31 32 if tag != "" { 33 // The "tag" could actually be a digest. 34 var dgst digest.Digest 35 dgst, err = digest.Parse(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 validationError{err} 43 } 44 } 45 46 return daemon.pullImageWithReference(ctx, ref, platform, metaHeaders, authConfig, outStream) 47 } 48 49 func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.Named, platform string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error { 50 // Include a buffer so that slow client connections don't affect 51 // transfer performance. 52 progressChan := make(chan progress.Progress, 100) 53 54 writesDone := make(chan struct{}) 55 56 ctx, cancelFunc := context.WithCancel(ctx) 57 58 go func() { 59 progressutils.WriteDistributionProgress(cancelFunc, outStream, progressChan) 60 close(writesDone) 61 }() 62 63 // Default to the host OS platform in case it hasn't been populated with an explicit value. 64 if platform == "" { 65 platform = runtime.GOOS 66 } 67 68 imagePullConfig := &distribution.ImagePullConfig{ 69 Config: distribution.Config{ 70 MetaHeaders: metaHeaders, 71 AuthConfig: authConfig, 72 ProgressOutput: progress.ChanOutput(progressChan), 73 RegistryService: daemon.RegistryService, 74 ImageEventLogger: daemon.LogImageEvent, 75 MetadataStore: daemon.stores[platform].distributionMetadataStore, 76 ImageStore: distribution.NewImageConfigStoreFromStore(daemon.stores[platform].imageStore), 77 ReferenceStore: daemon.referenceStore, 78 }, 79 DownloadManager: daemon.downloadManager, 80 Schema2Types: distribution.ImageTypes, 81 Platform: platform, 82 } 83 84 err := distribution.Pull(ctx, ref, imagePullConfig) 85 close(progressChan) 86 <-writesDone 87 return err 88 } 89 90 // GetRepository returns a repository from the registry. 91 func (daemon *Daemon) GetRepository(ctx context.Context, ref reference.Named, authConfig *types.AuthConfig) (dist.Repository, bool, error) { 92 // get repository info 93 repoInfo, err := daemon.RegistryService.ResolveRepository(ref) 94 if err != nil { 95 return nil, false, err 96 } 97 // makes sure name is not empty or `scratch` 98 if err := distribution.ValidateRepoName(repoInfo.Name); err != nil { 99 return nil, false, validationError{err} 100 } 101 102 // get endpoints 103 endpoints, err := daemon.RegistryService.LookupPullEndpoints(reference.Domain(repoInfo.Name)) 104 if err != nil { 105 return nil, false, err 106 } 107 108 // retrieve repository 109 var ( 110 confirmedV2 bool 111 repository dist.Repository 112 lastError error 113 ) 114 115 for _, endpoint := range endpoints { 116 if endpoint.Version == registry.APIVersion1 { 117 continue 118 } 119 120 repository, confirmedV2, lastError = distribution.NewV2Repository(ctx, repoInfo, endpoint, nil, authConfig, "pull") 121 if lastError == nil && confirmedV2 { 122 break 123 } 124 } 125 return repository, confirmedV2, lastError 126 }