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