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