github.com/vincentwoo/docker@v0.7.3-0.20160116130405-82401a4b13c0/registry/service.go (about)

     1  package registry
     2  
     3  import (
     4  	"crypto/tls"
     5  	"net/http"
     6  	"net/url"
     7  	"strings"
     8  
     9  	"github.com/docker/docker/reference"
    10  	"github.com/docker/engine-api/types"
    11  	registrytypes "github.com/docker/engine-api/types/registry"
    12  )
    13  
    14  // Service is a registry service. It tracks configuration data such as a list
    15  // of mirrors.
    16  type Service struct {
    17  	Config *registrytypes.ServiceConfig
    18  }
    19  
    20  // NewService returns a new instance of Service ready to be
    21  // installed into an engine.
    22  func NewService(options *Options) *Service {
    23  	return &Service{
    24  		Config: NewServiceConfig(options),
    25  	}
    26  }
    27  
    28  // Auth contacts the public registry with the provided credentials,
    29  // and returns OK if authentication was successful.
    30  // It can be used to verify the validity of a client's credentials.
    31  func (s *Service) Auth(authConfig *types.AuthConfig) (string, error) {
    32  	addr := authConfig.ServerAddress
    33  	if addr == "" {
    34  		// Use the official registry address if not specified.
    35  		addr = IndexServer
    36  	}
    37  	index, err := s.ResolveIndex(addr)
    38  	if err != nil {
    39  		return "", err
    40  	}
    41  
    42  	endpointVersion := APIVersion(APIVersionUnknown)
    43  	if V2Only {
    44  		// Override the endpoint to only attempt a v2 ping
    45  		endpointVersion = APIVersion2
    46  	}
    47  
    48  	endpoint, err := NewEndpoint(index, nil, endpointVersion)
    49  	if err != nil {
    50  		return "", err
    51  	}
    52  	authConfig.ServerAddress = endpoint.String()
    53  	return Login(authConfig, endpoint)
    54  }
    55  
    56  // splitReposSearchTerm breaks a search term into an index name and remote name
    57  func splitReposSearchTerm(reposName string) (string, string) {
    58  	nameParts := strings.SplitN(reposName, "/", 2)
    59  	var indexName, remoteName string
    60  	if len(nameParts) == 1 || (!strings.Contains(nameParts[0], ".") &&
    61  		!strings.Contains(nameParts[0], ":") && nameParts[0] != "localhost") {
    62  		// This is a Docker Index repos (ex: samalba/hipache or ubuntu)
    63  		// 'docker.io'
    64  		indexName = IndexName
    65  		remoteName = reposName
    66  	} else {
    67  		indexName = nameParts[0]
    68  		remoteName = nameParts[1]
    69  	}
    70  	return indexName, remoteName
    71  }
    72  
    73  // Search queries the public registry for images matching the specified
    74  // search terms, and returns the results.
    75  func (s *Service) Search(term string, authConfig *types.AuthConfig, headers map[string][]string) (*registrytypes.SearchResults, error) {
    76  	if err := validateNoSchema(term); err != nil {
    77  		return nil, err
    78  	}
    79  
    80  	indexName, remoteName := splitReposSearchTerm(term)
    81  
    82  	index, err := newIndexInfo(s.Config, indexName)
    83  	if err != nil {
    84  		return nil, err
    85  	}
    86  
    87  	// *TODO: Search multiple indexes.
    88  	endpoint, err := NewEndpoint(index, http.Header(headers), APIVersionUnknown)
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  
    93  	r, err := NewSession(endpoint.client, authConfig, endpoint)
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  
    98  	if index.Official {
    99  		localName := remoteName
   100  		if strings.HasPrefix(localName, "library/") {
   101  			// If pull "library/foo", it's stored locally under "foo"
   102  			localName = strings.SplitN(localName, "/", 2)[1]
   103  		}
   104  
   105  		return r.SearchRepositories(localName)
   106  	}
   107  	return r.SearchRepositories(remoteName)
   108  }
   109  
   110  // ResolveRepository splits a repository name into its components
   111  // and configuration of the associated registry.
   112  func (s *Service) ResolveRepository(name reference.Named) (*RepositoryInfo, error) {
   113  	return newRepositoryInfo(s.Config, name)
   114  }
   115  
   116  // ResolveIndex takes indexName and returns index info
   117  func (s *Service) ResolveIndex(name string) (*registrytypes.IndexInfo, error) {
   118  	return newIndexInfo(s.Config, name)
   119  }
   120  
   121  // APIEndpoint represents a remote API endpoint
   122  type APIEndpoint struct {
   123  	Mirror       bool
   124  	URL          string
   125  	Version      APIVersion
   126  	Official     bool
   127  	TrimHostname bool
   128  	TLSConfig    *tls.Config
   129  }
   130  
   131  // ToV1Endpoint returns a V1 API endpoint based on the APIEndpoint
   132  func (e APIEndpoint) ToV1Endpoint(metaHeaders http.Header) (*Endpoint, error) {
   133  	return newEndpoint(e.URL, e.TLSConfig, metaHeaders)
   134  }
   135  
   136  // TLSConfig constructs a client TLS configuration based on server defaults
   137  func (s *Service) TLSConfig(hostname string) (*tls.Config, error) {
   138  	return newTLSConfig(hostname, isSecureIndex(s.Config, hostname))
   139  }
   140  
   141  func (s *Service) tlsConfigForMirror(mirror string) (*tls.Config, error) {
   142  	mirrorURL, err := url.Parse(mirror)
   143  	if err != nil {
   144  		return nil, err
   145  	}
   146  	return s.TLSConfig(mirrorURL.Host)
   147  }
   148  
   149  // LookupPullEndpoints creates an list of endpoints to try to pull from, in order of preference.
   150  // It gives preference to v2 endpoints over v1, mirrors over the actual
   151  // registry, and HTTPS over plain HTTP.
   152  func (s *Service) LookupPullEndpoints(repoName reference.Named) (endpoints []APIEndpoint, err error) {
   153  	return s.lookupEndpoints(repoName)
   154  }
   155  
   156  // LookupPushEndpoints creates an list of endpoints to try to push to, in order of preference.
   157  // It gives preference to v2 endpoints over v1, and HTTPS over plain HTTP.
   158  // Mirrors are not included.
   159  func (s *Service) LookupPushEndpoints(repoName reference.Named) (endpoints []APIEndpoint, err error) {
   160  	allEndpoints, err := s.lookupEndpoints(repoName)
   161  	if err == nil {
   162  		for _, endpoint := range allEndpoints {
   163  			if !endpoint.Mirror {
   164  				endpoints = append(endpoints, endpoint)
   165  			}
   166  		}
   167  	}
   168  	return endpoints, err
   169  }
   170  
   171  func (s *Service) lookupEndpoints(repoName reference.Named) (endpoints []APIEndpoint, err error) {
   172  	endpoints, err = s.lookupV2Endpoints(repoName)
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  
   177  	if V2Only {
   178  		return endpoints, nil
   179  	}
   180  
   181  	legacyEndpoints, err := s.lookupV1Endpoints(repoName)
   182  	if err != nil {
   183  		return nil, err
   184  	}
   185  	endpoints = append(endpoints, legacyEndpoints...)
   186  
   187  	return endpoints, nil
   188  }