image_pull.go 4.4 KB

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