2018-02-05 16:05:59 -05:00
package distribution // import "github.com/docker/docker/distribution"
2015-11-18 17:18:44 -05:00
import (
2018-04-19 18:30:59 -04:00
"context"
2015-11-04 00:03:12 -05:00
"fmt"
2015-11-18 17:18:44 -05:00
"net"
"net/http"
"time"
"github.com/docker/distribution"
2016-12-16 14:19:05 -05:00
"github.com/docker/distribution/manifest/schema2"
2017-01-25 19:54:18 -05:00
"github.com/docker/distribution/reference"
2015-11-18 17:18:44 -05:00
"github.com/docker/distribution/registry/client"
"github.com/docker/distribution/registry/client/auth"
"github.com/docker/distribution/registry/client/transport"
2016-09-06 14:18:12 -04:00
"github.com/docker/docker/api/types"
2016-01-04 13:36:01 -05:00
"github.com/docker/docker/dockerversion"
2015-11-18 17:18:44 -05:00
"github.com/docker/docker/registry"
2016-04-25 07:54:48 -04:00
"github.com/docker/go-connections/sockets"
2018-06-27 20:58:54 -04:00
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
2015-11-18 17:18:44 -05:00
)
2016-12-16 14:19:05 -05:00
// ImageTypes represents the schema2 config types for images
var ImageTypes = [ ] string {
schema2 . MediaTypeImageConfig ,
2018-06-27 20:58:54 -04:00
ocispec . MediaTypeImageConfig ,
2016-12-16 14:19:05 -05:00
// Handle unexpected values from https://github.com/docker/distribution/issues/1621
2017-01-18 21:19:12 -05:00
// (see also https://github.com/docker/docker/issues/22378,
// https://github.com/docker/docker/issues/30083)
2016-12-16 14:19:05 -05:00
"application/octet-stream" ,
2017-01-18 21:19:12 -05:00
"application/json" ,
"text/html" ,
2016-12-16 14:19:05 -05:00
// Treat defaulted values as images, newer types cannot be implied
"" ,
}
// PluginTypes represents the schema2 config types for plugins
var PluginTypes = [ ] string {
schema2 . MediaTypePluginConfig ,
}
var mediaTypeClasses map [ string ] string
func init ( ) {
// initialize media type classes with all know types for
// plugin
mediaTypeClasses = map [ string ] string { }
for _ , t := range ImageTypes {
mediaTypeClasses [ t ] = "image"
}
for _ , t := range PluginTypes {
mediaTypeClasses [ t ] = "plugin"
}
}
2016-05-07 21:36:10 -04:00
// NewV2Repository returns a repository (v2 only). It creates an HTTP transport
2015-11-18 17:18:44 -05:00
// providing timeout settings and authentication support, and also verifies the
// remote API version.
2015-12-04 16:42:33 -05:00
func NewV2Repository ( ctx context . Context , repoInfo * registry . RepositoryInfo , endpoint registry . APIEndpoint , metaHeaders http . Header , authConfig * types . AuthConfig , actions ... string ) ( repo distribution . Repository , foundVersion bool , err error ) {
2017-01-25 19:54:18 -05:00
repoName := repoInfo . Name . Name ( )
2015-11-18 17:18:44 -05:00
// If endpoint does not support CanonicalName, use the RemoteName instead
if endpoint . TrimHostname {
2017-01-25 19:54:18 -05:00
repoName = reference . Path ( repoInfo . Name )
2015-11-18 17:18:44 -05:00
}
2016-04-25 07:54:48 -04:00
direct := & net . Dialer {
Timeout : 30 * time . Second ,
KeepAlive : 30 * time . Second ,
DualStack : true ,
}
2015-11-18 17:18:44 -05:00
// TODO(dmcgowan): Call close idle connections when complete, use keep alive
base := & http . Transport {
2016-04-25 07:54:48 -04:00
Proxy : http . ProxyFromEnvironment ,
Dial : direct . Dial ,
2015-11-18 17:18:44 -05:00
TLSHandshakeTimeout : 10 * time . Second ,
TLSClientConfig : endpoint . TLSConfig ,
// TODO(dmcgowan): Call close idle connections when complete and use keep alive
DisableKeepAlives : true ,
}
2016-04-25 07:54:48 -04:00
proxyDialer , err := sockets . DialerFromEnvironment ( direct )
if err == nil {
base . Dial = proxyDialer . Dial
}
2017-10-25 08:39:51 -04:00
modifiers := registry . Headers ( dockerversion . DockerUserAgent ( ctx ) , metaHeaders )
2015-11-18 17:18:44 -05:00
authTransport := transport . NewTransport ( base , modifiers ... )
2016-02-11 18:45:29 -05:00
2016-07-13 16:30:24 -04:00
challengeManager , foundVersion , err := registry . PingV2Registry ( endpoint . URL , authTransport )
2016-03-01 02:07:41 -05:00
if err != nil {
transportOK := false
if responseErr , ok := err . ( registry . PingResponseError ) ; ok {
transportOK = true
err = responseErr . Err
2015-11-18 17:18:44 -05:00
}
2016-02-11 18:45:29 -05:00
return nil , foundVersion , fallbackError {
err : err ,
confirmedV2 : foundVersion ,
2016-03-01 02:07:41 -05:00
transportOK : transportOK ,
2016-02-11 18:45:29 -05:00
}
2015-11-18 17:18:44 -05:00
}
2015-11-04 00:03:12 -05:00
if authConfig . RegistryToken != "" {
passThruTokenHandler := & existingTokenHandler { token : authConfig . RegistryToken }
modifiers = append ( modifiers , auth . NewAuthorizer ( challengeManager , passThruTokenHandler ) )
} else {
2016-11-15 18:06:48 -05:00
scope := auth . RepositoryScope {
Repository : repoName ,
Actions : actions ,
2016-12-12 18:05:53 -05:00
Class : repoInfo . Class ,
2016-11-15 18:06:48 -05:00
}
2016-07-13 16:30:24 -04:00
creds := registry . NewStaticCredentialStore ( authConfig )
2016-02-23 18:18:04 -05:00
tokenHandlerOptions := auth . TokenHandlerOptions {
Transport : authTransport ,
Credentials : creds ,
2016-11-15 18:06:48 -05:00
Scopes : [ ] auth . Scope { scope } ,
ClientID : registry . AuthClientID ,
2016-02-23 18:18:04 -05:00
}
tokenHandler := auth . NewTokenHandlerWithOptions ( tokenHandlerOptions )
2015-11-04 00:03:12 -05:00
basicHandler := auth . NewBasicHandler ( creds )
modifiers = append ( modifiers , auth . NewAuthorizer ( challengeManager , tokenHandler , basicHandler ) )
}
2015-11-18 17:18:44 -05:00
tr := transport . NewTransport ( base , modifiers ... )
2017-01-25 19:54:18 -05:00
repoNameRef , err := reference . WithName ( repoName )
2016-01-26 14:20:14 -05:00
if err != nil {
2016-02-11 18:45:29 -05:00
return nil , foundVersion , fallbackError {
err : err ,
confirmedV2 : foundVersion ,
transportOK : true ,
}
2016-01-26 14:20:14 -05:00
}
2018-04-19 20:00:56 -04:00
repo , err = client . NewRepository ( repoNameRef , endpoint . URL . String ( ) , tr )
2016-02-11 18:45:29 -05:00
if err != nil {
err = fallbackError {
err : err ,
confirmedV2 : foundVersion ,
transportOK : true ,
}
}
return
2015-11-18 17:18:44 -05:00
}
2015-11-04 00:03:12 -05:00
type existingTokenHandler struct {
token string
}
func ( th * existingTokenHandler ) Scheme ( ) string {
return "bearer"
}
func ( th * existingTokenHandler ) AuthorizeRequest ( req * http . Request , params map [ string ] string ) error {
req . Header . Set ( "Authorization" , fmt . Sprintf ( "Bearer %s" , th . token ) )
return nil
}
2019-06-14 21:56:28 -04:00
func schema1DeprecationMessage ( ref reference . Named ) string {
return fmt . Sprintf ( "[DEPRECATION NOTICE] registry v2 schema1 support will be removed in an upcoming release. Please contact admins of the %s registry NOW to avoid future disruption." , reference . Domain ( ref ) )
}