github.com/rightscale/docker@v1.9.1/graph/registry.go (about) 1 package graph 2 3 import ( 4 "errors" 5 "net" 6 "net/http" 7 "net/url" 8 "time" 9 10 "github.com/Sirupsen/logrus" 11 "github.com/docker/distribution" 12 "github.com/docker/distribution/digest" 13 "github.com/docker/distribution/manifest" 14 "github.com/docker/distribution/registry/client" 15 "github.com/docker/distribution/registry/client/auth" 16 "github.com/docker/distribution/registry/client/transport" 17 "github.com/docker/docker/cliconfig" 18 "github.com/docker/docker/registry" 19 "golang.org/x/net/context" 20 ) 21 22 type dumbCredentialStore struct { 23 auth *cliconfig.AuthConfig 24 } 25 26 func (dcs dumbCredentialStore) Basic(*url.URL) (string, string) { 27 return dcs.auth.Username, dcs.auth.Password 28 } 29 30 // NewV2Repository returns a repository (v2 only). It creates a HTTP transport 31 // providing timeout settings and authentication support, and also verifies the 32 // remote API version. 33 func NewV2Repository(repoInfo *registry.RepositoryInfo, endpoint registry.APIEndpoint, metaHeaders http.Header, authConfig *cliconfig.AuthConfig, actions ...string) (distribution.Repository, error) { 34 ctx := context.Background() 35 36 repoName := repoInfo.CanonicalName 37 // If endpoint does not support CanonicalName, use the RemoteName instead 38 if endpoint.TrimHostname { 39 repoName = repoInfo.RemoteName 40 } 41 42 // TODO(dmcgowan): Call close idle connections when complete, use keep alive 43 base := &http.Transport{ 44 Proxy: http.ProxyFromEnvironment, 45 Dial: (&net.Dialer{ 46 Timeout: 30 * time.Second, 47 KeepAlive: 30 * time.Second, 48 DualStack: true, 49 }).Dial, 50 TLSHandshakeTimeout: 10 * time.Second, 51 TLSClientConfig: endpoint.TLSConfig, 52 // TODO(dmcgowan): Call close idle connections when complete and use keep alive 53 DisableKeepAlives: true, 54 } 55 56 modifiers := registry.DockerHeaders(metaHeaders) 57 authTransport := transport.NewTransport(base, modifiers...) 58 pingClient := &http.Client{ 59 Transport: authTransport, 60 Timeout: 15 * time.Second, 61 } 62 endpointStr := endpoint.URL + "/v2/" 63 req, err := http.NewRequest("GET", endpointStr, nil) 64 if err != nil { 65 return nil, err 66 } 67 resp, err := pingClient.Do(req) 68 if err != nil { 69 return nil, err 70 } 71 defer resp.Body.Close() 72 73 versions := auth.APIVersions(resp, endpoint.VersionHeader) 74 if endpoint.VersionHeader != "" && len(endpoint.Versions) > 0 { 75 var foundVersion bool 76 for _, version := range endpoint.Versions { 77 for _, pingVersion := range versions { 78 if version == pingVersion { 79 foundVersion = true 80 } 81 } 82 } 83 if !foundVersion { 84 return nil, errors.New("endpoint does not support v2 API") 85 } 86 } 87 88 challengeManager := auth.NewSimpleChallengeManager() 89 if err := challengeManager.AddResponse(resp); err != nil { 90 return nil, err 91 } 92 93 creds := dumbCredentialStore{auth: authConfig} 94 tokenHandler := auth.NewTokenHandler(authTransport, creds, repoName, actions...) 95 basicHandler := auth.NewBasicHandler(creds) 96 modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler)) 97 tr := transport.NewTransport(base, modifiers...) 98 99 return client.NewRepository(ctx, repoName, endpoint.URL, tr) 100 } 101 102 func digestFromManifest(m *manifest.SignedManifest, localName string) (digest.Digest, int, error) { 103 payload, err := m.Payload() 104 if err != nil { 105 // If this failed, the signatures section was corrupted 106 // or missing. Treat the entire manifest as the payload. 107 payload = m.Raw 108 } 109 manifestDigest, err := digest.FromBytes(payload) 110 if err != nil { 111 logrus.Infof("Could not compute manifest digest for %s:%s : %v", localName, m.Tag, err) 112 } 113 return manifestDigest, len(payload), nil 114 }