github.com/gunjan5/docker@v1.8.2/registry/service.go (about) 1 package registry 2 3 import ( 4 "crypto/tls" 5 "fmt" 6 "net/http" 7 "net/url" 8 "strings" 9 10 "github.com/docker/distribution/registry/client/auth" 11 "github.com/docker/docker/cliconfig" 12 "github.com/docker/docker/pkg/tlsconfig" 13 ) 14 15 // Service is a registry service. It tracks configuration data such as a list 16 // of mirrors. 17 type Service struct { 18 Config *ServiceConfig 19 } 20 21 // NewService returns a new instance of Service ready to be 22 // installed into an engine. 23 func NewService(options *Options) *Service { 24 return &Service{ 25 Config: NewServiceConfig(options), 26 } 27 } 28 29 // Auth contacts the public registry with the provided credentials, 30 // and returns OK if authentication was sucessful. 31 // It can be used to verify the validity of a client's credentials. 32 func (s *Service) Auth(authConfig *cliconfig.AuthConfig) (string, error) { 33 addr := authConfig.ServerAddress 34 if addr == "" { 35 // Use the official registry address if not specified. 36 addr = IndexServer 37 } 38 index, err := s.ResolveIndex(addr) 39 if err != nil { 40 return "", err 41 } 42 endpoint, err := NewEndpoint(index, nil) 43 if err != nil { 44 return "", err 45 } 46 authConfig.ServerAddress = endpoint.String() 47 return Login(authConfig, endpoint) 48 } 49 50 // Search queries the public registry for images matching the specified 51 // search terms, and returns the results. 52 func (s *Service) Search(term string, authConfig *cliconfig.AuthConfig, headers map[string][]string) (*SearchResults, error) { 53 repoInfo, err := s.ResolveRepository(term) 54 if err != nil { 55 return nil, err 56 } 57 58 // *TODO: Search multiple indexes. 59 endpoint, err := repoInfo.GetEndpoint(http.Header(headers)) 60 if err != nil { 61 return nil, err 62 } 63 r, err := NewSession(endpoint.client, authConfig, endpoint) 64 if err != nil { 65 return nil, err 66 } 67 return r.SearchRepositories(repoInfo.GetSearchTerm()) 68 } 69 70 // ResolveRepository splits a repository name into its components 71 // and configuration of the associated registry. 72 func (s *Service) ResolveRepository(name string) (*RepositoryInfo, error) { 73 return s.Config.NewRepositoryInfo(name) 74 } 75 76 // ResolveIndex takes indexName and returns index info 77 func (s *Service) ResolveIndex(name string) (*IndexInfo, error) { 78 return s.Config.NewIndexInfo(name) 79 } 80 81 // APIEndpoint represents a remote API endpoint 82 type APIEndpoint struct { 83 Mirror bool 84 URL string 85 Version APIVersion 86 Official bool 87 TrimHostname bool 88 TLSConfig *tls.Config 89 VersionHeader string 90 Versions []auth.APIVersion 91 } 92 93 // ToV1Endpoint returns a V1 API endpoint based on the APIEndpoint 94 func (e APIEndpoint) ToV1Endpoint(metaHeaders http.Header) (*Endpoint, error) { 95 return newEndpoint(e.URL, e.TLSConfig, metaHeaders) 96 } 97 98 // TLSConfig constructs a client TLS configuration based on server defaults 99 func (s *Service) TLSConfig(hostname string) (*tls.Config, error) { 100 return newTLSConfig(hostname, s.Config.isSecureIndex(hostname)) 101 } 102 103 func (s *Service) tlsConfigForMirror(mirror string) (*tls.Config, error) { 104 mirrorURL, err := url.Parse(mirror) 105 if err != nil { 106 return nil, err 107 } 108 return s.TLSConfig(mirrorURL.Host) 109 } 110 111 // LookupPullEndpoints creates an list of endpoints to try to pull from, in order of preference. 112 // It gives preference to v2 endpoints over v1, mirrors over the actual 113 // registry, and HTTPS over plain HTTP. 114 func (s *Service) LookupPullEndpoints(repoName string) (endpoints []APIEndpoint, err error) { 115 return s.lookupEndpoints(repoName, false) 116 } 117 118 // LookupPushEndpoints creates an list of endpoints to try to push to, in order of preference. 119 // It gives preference to v2 endpoints over v1, and HTTPS over plain HTTP. 120 // Mirrors are not included. 121 func (s *Service) LookupPushEndpoints(repoName string) (endpoints []APIEndpoint, err error) { 122 return s.lookupEndpoints(repoName, true) 123 } 124 125 func (s *Service) lookupEndpoints(repoName string, isPush bool) (endpoints []APIEndpoint, err error) { 126 var cfg = tlsconfig.ServerDefault 127 tlsConfig := &cfg 128 if strings.HasPrefix(repoName, DefaultNamespace+"/") { 129 if !isPush { 130 // v2 mirrors for pull only 131 for _, mirror := range s.Config.Mirrors { 132 mirrorTLSConfig, err := s.tlsConfigForMirror(mirror) 133 if err != nil { 134 return nil, err 135 } 136 endpoints = append(endpoints, APIEndpoint{ 137 URL: mirror, 138 // guess mirrors are v2 139 Version: APIVersion2, 140 Mirror: true, 141 TrimHostname: true, 142 TLSConfig: mirrorTLSConfig, 143 }) 144 } 145 } 146 // v2 registry 147 endpoints = append(endpoints, APIEndpoint{ 148 URL: DefaultV2Registry, 149 Version: APIVersion2, 150 Official: true, 151 TrimHostname: true, 152 TLSConfig: tlsConfig, 153 }) 154 // v1 registry 155 endpoints = append(endpoints, APIEndpoint{ 156 URL: DefaultV1Registry, 157 Version: APIVersion1, 158 Official: true, 159 TrimHostname: true, 160 TLSConfig: tlsConfig, 161 }) 162 return endpoints, nil 163 } 164 165 slashIndex := strings.IndexRune(repoName, '/') 166 if slashIndex <= 0 { 167 return nil, fmt.Errorf("invalid repo name: missing '/': %s", repoName) 168 } 169 hostname := repoName[:slashIndex] 170 171 tlsConfig, err = s.TLSConfig(hostname) 172 if err != nil { 173 return nil, err 174 } 175 isSecure := !tlsConfig.InsecureSkipVerify 176 177 v2Versions := []auth.APIVersion{ 178 { 179 Type: "registry", 180 Version: "2.0", 181 }, 182 } 183 endpoints = []APIEndpoint{ 184 { 185 URL: "https://" + hostname, 186 Version: APIVersion2, 187 TrimHostname: true, 188 TLSConfig: tlsConfig, 189 VersionHeader: DefaultRegistryVersionHeader, 190 Versions: v2Versions, 191 }, 192 { 193 URL: "https://" + hostname, 194 Version: APIVersion1, 195 TrimHostname: true, 196 TLSConfig: tlsConfig, 197 }, 198 } 199 200 if !isSecure { 201 endpoints = append(endpoints, APIEndpoint{ 202 URL: "http://" + hostname, 203 Version: APIVersion2, 204 TrimHostname: true, 205 // used to check if supposed to be secure via InsecureSkipVerify 206 TLSConfig: tlsConfig, 207 VersionHeader: DefaultRegistryVersionHeader, 208 Versions: v2Versions, 209 }, APIEndpoint{ 210 URL: "http://" + hostname, 211 Version: APIVersion1, 212 TrimHostname: true, 213 // used to check if supposed to be secure via InsecureSkipVerify 214 TLSConfig: tlsConfig, 215 }) 216 } 217 218 return endpoints, nil 219 }