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 }