|
@@ -6,6 +6,7 @@ import (
|
|
"net/http"
|
|
"net/http"
|
|
"net/url"
|
|
"net/url"
|
|
"strings"
|
|
"strings"
|
|
|
|
+ "sync"
|
|
|
|
|
|
"golang.org/x/net/context"
|
|
"golang.org/x/net/context"
|
|
|
|
|
|
@@ -30,12 +31,14 @@ type Service interface {
|
|
Search(ctx context.Context, term string, limit int, authConfig *types.AuthConfig, userAgent string, headers map[string][]string) (*registrytypes.SearchResults, error)
|
|
Search(ctx context.Context, term string, limit int, authConfig *types.AuthConfig, userAgent string, headers map[string][]string) (*registrytypes.SearchResults, error)
|
|
ServiceConfig() *registrytypes.ServiceConfig
|
|
ServiceConfig() *registrytypes.ServiceConfig
|
|
TLSConfig(hostname string) (*tls.Config, error)
|
|
TLSConfig(hostname string) (*tls.Config, error)
|
|
|
|
+ LoadInsecureRegistries([]string) error
|
|
}
|
|
}
|
|
|
|
|
|
// DefaultService is a registry service. It tracks configuration data such as a list
|
|
// DefaultService is a registry service. It tracks configuration data such as a list
|
|
// of mirrors.
|
|
// of mirrors.
|
|
type DefaultService struct {
|
|
type DefaultService struct {
|
|
config *serviceConfig
|
|
config *serviceConfig
|
|
|
|
+ mu sync.Mutex
|
|
}
|
|
}
|
|
|
|
|
|
// NewService returns a new instance of DefaultService ready to be
|
|
// NewService returns a new instance of DefaultService ready to be
|
|
@@ -48,7 +51,34 @@ func NewService(options ServiceOptions) *DefaultService {
|
|
|
|
|
|
// ServiceConfig returns the public registry service configuration.
|
|
// ServiceConfig returns the public registry service configuration.
|
|
func (s *DefaultService) ServiceConfig() *registrytypes.ServiceConfig {
|
|
func (s *DefaultService) ServiceConfig() *registrytypes.ServiceConfig {
|
|
- return &s.config.ServiceConfig
|
|
|
|
|
|
+ s.mu.Lock()
|
|
|
|
+ defer s.mu.Unlock()
|
|
|
|
+
|
|
|
|
+ servConfig := registrytypes.ServiceConfig{
|
|
|
|
+ InsecureRegistryCIDRs: make([]*(registrytypes.NetIPNet), 0),
|
|
|
|
+ IndexConfigs: make(map[string]*(registrytypes.IndexInfo)),
|
|
|
|
+ Mirrors: make([]string, 0),
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // construct a new ServiceConfig which will not retrieve s.Config directly,
|
|
|
|
+ // and look up items in s.config with mu locked
|
|
|
|
+ servConfig.InsecureRegistryCIDRs = append(servConfig.InsecureRegistryCIDRs, s.config.ServiceConfig.InsecureRegistryCIDRs...)
|
|
|
|
+
|
|
|
|
+ for key, value := range s.config.ServiceConfig.IndexConfigs {
|
|
|
|
+ servConfig.IndexConfigs[key] = value
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ servConfig.Mirrors = append(servConfig.Mirrors, s.config.ServiceConfig.Mirrors...)
|
|
|
|
+
|
|
|
|
+ return &servConfig
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// LoadInsecureRegistries loads insecure registries for Service
|
|
|
|
+func (s *DefaultService) LoadInsecureRegistries(registries []string) error {
|
|
|
|
+ s.mu.Lock()
|
|
|
|
+ defer s.mu.Unlock()
|
|
|
|
+
|
|
|
|
+ return s.config.LoadInsecureRegistries(registries)
|
|
}
|
|
}
|
|
|
|
|
|
// Auth contacts the public registry with the provided credentials,
|
|
// Auth contacts the public registry with the provided credentials,
|
|
@@ -121,7 +151,11 @@ func (s *DefaultService) Search(ctx context.Context, term string, limit int, aut
|
|
|
|
|
|
indexName, remoteName := splitReposSearchTerm(term)
|
|
indexName, remoteName := splitReposSearchTerm(term)
|
|
|
|
|
|
|
|
+ // Search is a long-running operation, just lock s.config to avoid block others.
|
|
|
|
+ s.mu.Lock()
|
|
index, err := newIndexInfo(s.config, indexName)
|
|
index, err := newIndexInfo(s.config, indexName)
|
|
|
|
+ s.mu.Unlock()
|
|
|
|
+
|
|
if err != nil {
|
|
if err != nil {
|
|
return nil, err
|
|
return nil, err
|
|
}
|
|
}
|
|
@@ -185,6 +219,8 @@ func (s *DefaultService) Search(ctx context.Context, term string, limit int, aut
|
|
// ResolveRepository splits a repository name into its components
|
|
// ResolveRepository splits a repository name into its components
|
|
// and configuration of the associated registry.
|
|
// and configuration of the associated registry.
|
|
func (s *DefaultService) ResolveRepository(name reference.Named) (*RepositoryInfo, error) {
|
|
func (s *DefaultService) ResolveRepository(name reference.Named) (*RepositoryInfo, error) {
|
|
|
|
+ s.mu.Lock()
|
|
|
|
+ defer s.mu.Unlock()
|
|
return newRepositoryInfo(s.config, name)
|
|
return newRepositoryInfo(s.config, name)
|
|
}
|
|
}
|
|
|
|
|
|
@@ -205,17 +241,28 @@ func (e APIEndpoint) ToV1Endpoint(userAgent string, metaHeaders http.Header) (*V
|
|
|
|
|
|
// TLSConfig constructs a client TLS configuration based on server defaults
|
|
// TLSConfig constructs a client TLS configuration based on server defaults
|
|
func (s *DefaultService) TLSConfig(hostname string) (*tls.Config, error) {
|
|
func (s *DefaultService) TLSConfig(hostname string) (*tls.Config, error) {
|
|
|
|
+ s.mu.Lock()
|
|
|
|
+ defer s.mu.Unlock()
|
|
|
|
+
|
|
|
|
+ return newTLSConfig(hostname, isSecureIndex(s.config, hostname))
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// tlsConfig constructs a client TLS configuration based on server defaults
|
|
|
|
+func (s *DefaultService) tlsConfig(hostname string) (*tls.Config, error) {
|
|
return newTLSConfig(hostname, isSecureIndex(s.config, hostname))
|
|
return newTLSConfig(hostname, isSecureIndex(s.config, hostname))
|
|
}
|
|
}
|
|
|
|
|
|
func (s *DefaultService) tlsConfigForMirror(mirrorURL *url.URL) (*tls.Config, error) {
|
|
func (s *DefaultService) tlsConfigForMirror(mirrorURL *url.URL) (*tls.Config, error) {
|
|
- return s.TLSConfig(mirrorURL.Host)
|
|
|
|
|
|
+ return s.tlsConfig(mirrorURL.Host)
|
|
}
|
|
}
|
|
|
|
|
|
// LookupPullEndpoints creates a list of endpoints to try to pull from, in order of preference.
|
|
// LookupPullEndpoints creates a list of endpoints to try to pull from, in order of preference.
|
|
// It gives preference to v2 endpoints over v1, mirrors over the actual
|
|
// It gives preference to v2 endpoints over v1, mirrors over the actual
|
|
// registry, and HTTPS over plain HTTP.
|
|
// registry, and HTTPS over plain HTTP.
|
|
func (s *DefaultService) LookupPullEndpoints(hostname string) (endpoints []APIEndpoint, err error) {
|
|
func (s *DefaultService) LookupPullEndpoints(hostname string) (endpoints []APIEndpoint, err error) {
|
|
|
|
+ s.mu.Lock()
|
|
|
|
+ defer s.mu.Unlock()
|
|
|
|
+
|
|
return s.lookupEndpoints(hostname)
|
|
return s.lookupEndpoints(hostname)
|
|
}
|
|
}
|
|
|
|
|
|
@@ -223,6 +270,9 @@ func (s *DefaultService) LookupPullEndpoints(hostname string) (endpoints []APIEn
|
|
// It gives preference to v2 endpoints over v1, and HTTPS over plain HTTP.
|
|
// It gives preference to v2 endpoints over v1, and HTTPS over plain HTTP.
|
|
// Mirrors are not included.
|
|
// Mirrors are not included.
|
|
func (s *DefaultService) LookupPushEndpoints(hostname string) (endpoints []APIEndpoint, err error) {
|
|
func (s *DefaultService) LookupPushEndpoints(hostname string) (endpoints []APIEndpoint, err error) {
|
|
|
|
+ s.mu.Lock()
|
|
|
|
+ defer s.mu.Unlock()
|
|
|
|
+
|
|
allEndpoints, err := s.lookupEndpoints(hostname)
|
|
allEndpoints, err := s.lookupEndpoints(hostname)
|
|
if err == nil {
|
|
if err == nil {
|
|
for _, endpoint := range allEndpoints {
|
|
for _, endpoint := range allEndpoints {
|