image_pull.go 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. package daemon
  2. import (
  3. "io"
  4. "runtime"
  5. "strings"
  6. dist "github.com/docker/distribution"
  7. "github.com/docker/distribution/reference"
  8. "github.com/docker/docker/api/types"
  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, platform 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 validationError{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 validationError{err}
  38. }
  39. }
  40. return daemon.pullImageWithReference(ctx, ref, platform, metaHeaders, authConfig, outStream)
  41. }
  42. func (daemon *Daemon) pullImageWithReference(ctx context.Context, ref reference.Named, platform string, metaHeaders map[string][]string, authConfig *types.AuthConfig, outStream io.Writer) error {
  43. // Include a buffer so that slow client connections don't affect
  44. // transfer performance.
  45. progressChan := make(chan progress.Progress, 100)
  46. writesDone := make(chan struct{})
  47. ctx, cancelFunc := context.WithCancel(ctx)
  48. go func() {
  49. progressutils.WriteDistributionProgress(cancelFunc, outStream, progressChan)
  50. close(writesDone)
  51. }()
  52. // Default to the host OS platform in case it hasn't been populated with an explicit value.
  53. if platform == "" {
  54. platform = runtime.GOOS
  55. }
  56. imagePullConfig := &distribution.ImagePullConfig{
  57. Config: distribution.Config{
  58. MetaHeaders: metaHeaders,
  59. AuthConfig: authConfig,
  60. ProgressOutput: progress.ChanOutput(progressChan),
  61. RegistryService: daemon.RegistryService,
  62. ImageEventLogger: daemon.LogImageEvent,
  63. MetadataStore: daemon.stores[platform].distributionMetadataStore,
  64. ImageStore: distribution.NewImageConfigStoreFromStore(daemon.stores[platform].imageStore),
  65. ReferenceStore: daemon.referenceStore,
  66. },
  67. DownloadManager: daemon.downloadManager,
  68. Schema2Types: distribution.ImageTypes,
  69. Platform: platform,
  70. }
  71. err := distribution.Pull(ctx, ref, imagePullConfig)
  72. close(progressChan)
  73. <-writesDone
  74. return err
  75. }
  76. // GetRepository returns a repository from the registry.
  77. func (daemon *Daemon) GetRepository(ctx context.Context, ref reference.Named, authConfig *types.AuthConfig) (dist.Repository, bool, error) {
  78. // get repository info
  79. repoInfo, err := daemon.RegistryService.ResolveRepository(ref)
  80. if err != nil {
  81. return nil, false, err
  82. }
  83. // makes sure name is not empty or `scratch`
  84. if err := distribution.ValidateRepoName(repoInfo.Name); err != nil {
  85. return nil, false, validationError{err}
  86. }
  87. // get endpoints
  88. endpoints, err := daemon.RegistryService.LookupPullEndpoints(reference.Domain(repoInfo.Name))
  89. if err != nil {
  90. return nil, false, err
  91. }
  92. // retrieve repository
  93. var (
  94. confirmedV2 bool
  95. repository dist.Repository
  96. lastError error
  97. )
  98. for _, endpoint := range endpoints {
  99. if endpoint.Version == registry.APIVersion1 {
  100. continue
  101. }
  102. repository, confirmedV2, lastError = distribution.NewV2Repository(ctx, repoInfo, endpoint, nil, authConfig, "pull")
  103. if lastError == nil && confirmedV2 {
  104. break
  105. }
  106. }
  107. return repository, confirmedV2, lastError
  108. }