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  }