image_pull.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. package daemon
  2. import (
  3. "io"
  4. "strings"
  5. dist "github.com/docker/distribution"
  6. "github.com/docker/distribution/digest"
  7. "github.com/docker/docker/api/types"
  8. "github.com/docker/docker/builder"
  9. "github.com/docker/docker/distribution"
  10. "github.com/docker/docker/pkg/progress"
  11. "github.com/docker/docker/reference"
  12. "github.com/docker/docker/registry"
  13. "golang.org/x/net/context"
  14. )
  15. // PullImage initiates a pull operation. image is the repository name to pull, and
  16. // tag may be either empty, or indicate a specific tag to pull.
  17. func (daemon *Daemon) PullImage(ctx context.Context, image, tag string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
  18. // Special case: "pull -a" may send an image name with a
  19. // trailing :. This is ugly, but let's not break API
  20. // compatibility.
  21. image = strings.TrimSuffix(image, ":")
  22. ref, err := reference.ParseNamed(image)
  23. if err != nil {
  24. return err
  25. }
  26. if tag != "" {
  27. // The "tag" could actually be a digest.
  28. var dgst digest.Digest
  29. dgst, err = digest.ParseDigest(tag)
  30. if err == nil {
  31. ref, err = reference.WithDigest(reference.TrimNamed(ref), dgst)
  32. } else {
  33. ref, err = reference.WithTag(ref, tag)
  34. }
  35. if err != nil {
  36. return err
  37. }
  38. }
  39. return daemon.pullImageWithReference(ctx, ref, metaHeaders, authConfig, outStream)
  40. }
  41. // PullOnBuild tells Docker to pull image referenced by `name`.
  42. func (daemon *Daemon) PullOnBuild(ctx context.Context, name string, authConfigs map[string]types.AuthConfig, output io.Writer) (builder.Image, error) {
  43. ref, err := reference.ParseNamed(name)
  44. if err != nil {
  45. return nil, err
  46. }
  47. ref = reference.WithDefaultTag(ref)
  48. pullRegistryAuth := &types.AuthConfig{}
  49. if len(authConfigs) > 0 {
  50. // The request came with a full auth config file, we prefer to use that
  51. repoInfo, err := daemon.RegistryService.ResolveRepository(ref)
  52. if err != nil {
  53. return nil, err
  54. }
  55. resolvedConfig := registry.ResolveAuthConfig(
  56. authConfigs,
  57. repoInfo.Index,
  58. )
  59. pullRegistryAuth = &resolvedConfig
  60. }
  61. if err := daemon.pullImageWithReference(ctx, ref, nil, pullRegistryAuth, output); err != nil {
  62. return nil, err
  63. }
  64. return daemon.GetImage(name)
  65. }
  66. func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
  67. // Include a buffer so that slow client connections don't affect
  68. // transfer performance.
  69. progressChan := make(chan progress.Progress, 100)
  70. writesDone := make(chan struct{})
  71. ctx, cancelFunc := context.WithCancel(ctx)
  72. go func() {
  73. writeDistributionProgress(cancelFunc, outStream, progressChan)
  74. close(writesDone)
  75. }()
  76. imagePullConfig := &distribution.ImagePullConfig{
  77. MetaHeaders: metaHeaders,
  78. AuthConfig: authConfig,
  79. ProgressOutput: progress.ChanOutput(progressChan),
  80. RegistryService: daemon.RegistryService,
  81. ImageEventLogger: daemon.LogImageEvent,
  82. MetadataStore: daemon.distributionMetadataStore,
  83. ImageStore: daemon.imageStore,
  84. ReferenceStore: daemon.referenceStore,
  85. DownloadManager: daemon.downloadManager,
  86. }
  87. err := distribution.Pull(ctx, ref, imagePullConfig)
  88. close(progressChan)
  89. <-writesDone
  90. return err
  91. }
  92. // GetRepository returns a repository from the registry.
  93. func (daemon *Daemon) GetRepository(ctx context.Context, ref reference.NamedTagged, authConfig *types.AuthConfig) (dist.Repository, bool, error) {
  94. // get repository info
  95. repoInfo, err := daemon.RegistryService.ResolveRepository(ref)
  96. if err != nil {
  97. return nil, false, err
  98. }
  99. // makes sure name is not empty or `scratch`
  100. if err := distribution.ValidateRepoName(repoInfo.Name()); err != nil {
  101. return nil, false, err
  102. }
  103. // get endpoints
  104. endpoints, err := daemon.RegistryService.LookupPullEndpoints(repoInfo.Hostname())
  105. if err != nil {
  106. return nil, false, err
  107. }
  108. // retrieve repository
  109. var (
  110. confirmedV2 bool
  111. repository dist.Repository
  112. lastError error
  113. )
  114. for _, endpoint := range endpoints {
  115. if endpoint.Version == registry.APIVersion1 {
  116. continue
  117. }
  118. repository, confirmedV2, lastError = distribution.NewV2Repository(ctx, repoInfo, endpoint, nil, authConfig, "pull")
  119. if lastError == nil && confirmedV2 {
  120. break
  121. }
  122. }
  123. return repository, confirmedV2, lastError
  124. }