service.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. package registry // import "github.com/docker/docker/registry"
  2. import (
  3. "context"
  4. "crypto/tls"
  5. "net/url"
  6. "strings"
  7. "sync"
  8. "github.com/containerd/log"
  9. "github.com/distribution/reference"
  10. "github.com/docker/docker/api/types/registry"
  11. "github.com/docker/docker/errdefs"
  12. )
  13. // Service is a registry service. It tracks configuration data such as a list
  14. // of mirrors.
  15. type Service struct {
  16. config *serviceConfig
  17. mu sync.RWMutex
  18. }
  19. // NewService returns a new instance of [Service] ready to be installed into
  20. // an engine.
  21. func NewService(options ServiceOptions) (*Service, error) {
  22. config, err := newServiceConfig(options)
  23. return &Service{config: config}, err
  24. }
  25. // ServiceConfig returns a copy of the public registry service's configuration.
  26. func (s *Service) ServiceConfig() *registry.ServiceConfig {
  27. s.mu.RLock()
  28. defer s.mu.RUnlock()
  29. return s.config.copy()
  30. }
  31. // ReplaceConfig prepares a transaction which will atomically replace the
  32. // registry service's configuration when the returned commit function is called.
  33. func (s *Service) ReplaceConfig(options ServiceOptions) (commit func(), err error) {
  34. config, err := newServiceConfig(options)
  35. if err != nil {
  36. return nil, err
  37. }
  38. return func() {
  39. s.mu.Lock()
  40. defer s.mu.Unlock()
  41. s.config = config
  42. }, nil
  43. }
  44. // Auth contacts the public registry with the provided credentials,
  45. // and returns OK if authentication was successful.
  46. // It can be used to verify the validity of a client's credentials.
  47. func (s *Service) Auth(ctx context.Context, authConfig *registry.AuthConfig, userAgent string) (status, token string, err error) {
  48. // TODO Use ctx when searching for repositories
  49. registryHostName := IndexHostname
  50. if authConfig.ServerAddress != "" {
  51. serverAddress := authConfig.ServerAddress
  52. if !strings.HasPrefix(serverAddress, "https://") && !strings.HasPrefix(serverAddress, "http://") {
  53. serverAddress = "https://" + serverAddress
  54. }
  55. u, err := url.Parse(serverAddress)
  56. if err != nil {
  57. return "", "", invalidParamWrapf(err, "unable to parse server address")
  58. }
  59. registryHostName = u.Host
  60. }
  61. // Lookup endpoints for authentication using "LookupPushEndpoints", which
  62. // excludes mirrors to prevent sending credentials of the upstream registry
  63. // to a mirror.
  64. endpoints, err := s.LookupPushEndpoints(registryHostName)
  65. if err != nil {
  66. return "", "", invalidParam(err)
  67. }
  68. for _, endpoint := range endpoints {
  69. status, token, err = loginV2(authConfig, endpoint, userAgent)
  70. if err == nil {
  71. return
  72. }
  73. if errdefs.IsUnauthorized(err) {
  74. // Failed to authenticate; don't continue with (non-TLS) endpoints.
  75. return status, token, err
  76. }
  77. log.G(ctx).WithError(err).Infof("Error logging in to endpoint, trying next endpoint")
  78. }
  79. return "", "", err
  80. }
  81. // ResolveRepository splits a repository name into its components
  82. // and configuration of the associated registry.
  83. func (s *Service) ResolveRepository(name reference.Named) (*RepositoryInfo, error) {
  84. s.mu.RLock()
  85. defer s.mu.RUnlock()
  86. return newRepositoryInfo(s.config, name)
  87. }
  88. // APIEndpoint represents a remote API endpoint
  89. type APIEndpoint struct {
  90. Mirror bool
  91. URL *url.URL
  92. Version APIVersion // Deprecated: v1 registries are deprecated, and endpoints are always v2.
  93. AllowNondistributableArtifacts bool
  94. Official bool
  95. TrimHostname bool
  96. TLSConfig *tls.Config
  97. }
  98. // LookupPullEndpoints creates a list of v2 endpoints to try to pull from, in order of preference.
  99. // It gives preference to mirrors over the actual registry, and HTTPS over plain HTTP.
  100. func (s *Service) LookupPullEndpoints(hostname string) (endpoints []APIEndpoint, err error) {
  101. s.mu.RLock()
  102. defer s.mu.RUnlock()
  103. return s.lookupV2Endpoints(hostname)
  104. }
  105. // LookupPushEndpoints creates a list of v2 endpoints to try to push to, in order of preference.
  106. // It gives preference to HTTPS over plain HTTP. Mirrors are not included.
  107. func (s *Service) LookupPushEndpoints(hostname string) (endpoints []APIEndpoint, err error) {
  108. s.mu.RLock()
  109. defer s.mu.RUnlock()
  110. allEndpoints, err := s.lookupV2Endpoints(hostname)
  111. if err == nil {
  112. for _, endpoint := range allEndpoints {
  113. if !endpoint.Mirror {
  114. endpoints = append(endpoints, endpoint)
  115. }
  116. }
  117. }
  118. return endpoints, err
  119. }
  120. // IsInsecureRegistry returns true if the registry at given host is configured as
  121. // insecure registry.
  122. func (s *Service) IsInsecureRegistry(host string) bool {
  123. s.mu.RLock()
  124. defer s.mu.RUnlock()
  125. return !s.config.isSecureIndex(host)
  126. }