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  }