image_pull.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  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/distribution"
  9. progressutils "github.com/docker/docker/distribution/utils"
  10. "github.com/docker/docker/pkg/progress"
  11. "github.com/docker/docker/registry"
  12. "github.com/opencontainers/go-digest"
  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.ParseNormalizedNamed(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.Parse(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. func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.Named, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
  42. // Include a buffer so that slow client connections don't affect
  43. // transfer performance.
  44. progressChan := make(chan progress.Progress, 100)
  45. writesDone := make(chan struct{})
  46. ctx, cancelFunc := context.WithCancel(ctx)
  47. go func() {
  48. progressutils.WriteDistributionProgress(cancelFunc, outStream, progressChan)
  49. close(writesDone)
  50. }()
  51. imagePullConfig := &distribution.ImagePullConfig{
  52. Config: distribution.Config{
  53. MetaHeaders: metaHeaders,
  54. AuthConfig: authConfig,
  55. ProgressOutput: progress.ChanOutput(progressChan),
  56. RegistryService: daemon.RegistryService,
  57. ImageEventLogger: daemon.LogImageEvent,
  58. MetadataStore: daemon.distributionMetadataStore,
  59. ImageStore: distribution.NewImageConfigStoreFromStore(daemon.imageStore),
  60. ReferenceStore: daemon.referenceStore,
  61. },
  62. DownloadManager: daemon.downloadManager,
  63. Schema2Types: distribution.ImageTypes,
  64. }
  65. err := distribution.Pull(ctx, ref, imagePullConfig)
  66. close(progressChan)
  67. <-writesDone
  68. return err
  69. }
  70. // GetRepository returns a repository from the registry.
  71. func (daemon *Daemon) GetRepository(ctx context.Context, ref reference.Named, authConfig *types.AuthConfig) (dist.Repository, bool, error) {
  72. // get repository info
  73. repoInfo, err := daemon.RegistryService.ResolveRepository(ref)
  74. if err != nil {
  75. return nil, false, err
  76. }
  77. // makes sure name is not empty or `scratch`
  78. if err := distribution.ValidateRepoName(repoInfo.Name); err != nil {
  79. return nil, false, err
  80. }
  81. // get endpoints
  82. endpoints, err := daemon.RegistryService.LookupPullEndpoints(reference.Domain(repoInfo.Name))
  83. if err != nil {
  84. return nil, false, err
  85. }
  86. // retrieve repository
  87. var (
  88. confirmedV2 bool
  89. repository dist.Repository
  90. lastError error
  91. )
  92. for _, endpoint := range endpoints {
  93. if endpoint.Version == registry.APIVersion1 {
  94. continue
  95. }
  96. repository, confirmedV2, lastError = distribution.NewV2Repository(ctx, repoInfo, endpoint, nil, authConfig, "pull")
  97. if lastError == nil && confirmedV2 {
  98. break
  99. }
  100. }
  101. return repository, confirmedV2, lastError
  102. }