github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/engine/plugin/registry.go (about) 1 package plugin 2 3 import ( 4 "context" 5 "crypto/tls" 6 "net" 7 "net/http" 8 "time" 9 10 "github.com/sirupsen/logrus" 11 12 "github.com/docker/docker/dockerversion" 13 14 "github.com/pkg/errors" 15 16 "github.com/containerd/containerd/remotes" 17 "github.com/containerd/containerd/remotes/docker" 18 "github.com/docker/distribution/reference" 19 "github.com/docker/docker/api/types" 20 ) 21 22 // scope builds the correct auth scope for the registry client to authorize against 23 // By default the client currently only does a "repository:" scope with out a classifier, e.g. "(plugin)" 24 // Without this, the client will not be able to authorize the request 25 func scope(ref reference.Named, push bool) string { 26 scope := "repository(plugin):" + reference.Path(reference.TrimNamed(ref)) + ":pull" 27 if push { 28 scope += ",push" 29 } 30 return scope 31 } 32 33 func (pm *Manager) newResolver(ctx context.Context, tracker docker.StatusTracker, auth *types.AuthConfig, headers http.Header, httpFallback bool) (remotes.Resolver, error) { 34 if headers == nil { 35 headers = http.Header{} 36 } 37 headers.Add("User-Agent", dockerversion.DockerUserAgent(ctx)) 38 39 return docker.NewResolver(docker.ResolverOptions{ 40 Tracker: tracker, 41 Headers: headers, 42 Hosts: pm.registryHostsFn(auth, httpFallback), 43 }), nil 44 } 45 46 func registryHTTPClient(config *tls.Config) *http.Client { 47 return &http.Client{ 48 Transport: &http.Transport{ 49 Proxy: http.ProxyFromEnvironment, 50 DialContext: (&net.Dialer{ 51 Timeout: 30 * time.Second, 52 KeepAlive: 30 * time.Second, 53 }).DialContext, 54 TLSClientConfig: config, 55 TLSHandshakeTimeout: 10 * time.Second, 56 IdleConnTimeout: 30 * time.Second, 57 }, 58 } 59 } 60 61 func (pm *Manager) registryHostsFn(auth *types.AuthConfig, httpFallback bool) docker.RegistryHosts { 62 return func(hostname string) ([]docker.RegistryHost, error) { 63 eps, err := pm.config.RegistryService.LookupPullEndpoints(hostname) 64 if err != nil { 65 return nil, errors.Wrapf(err, "error resolving repository for %s", hostname) 66 } 67 68 hosts := make([]docker.RegistryHost, 0, len(eps)) 69 70 for _, ep := range eps { 71 // forced http fallback is used only for push since the containerd pusher only ever uses the first host we 72 // pass to it. 73 // So it is the callers responsibility to retry with this flag set. 74 if httpFallback && ep.URL.Scheme != "http" { 75 logrus.WithField("registryHost", hostname).WithField("endpoint", ep).Debugf("Skipping non-http endpoint") 76 continue 77 } 78 79 caps := docker.HostCapabilityPull | docker.HostCapabilityResolve 80 if !ep.Mirror { 81 caps = caps | docker.HostCapabilityPush 82 } 83 84 host, err := docker.DefaultHost(ep.URL.Host) 85 if err != nil { 86 return nil, err 87 } 88 89 client := registryHTTPClient(ep.TLSConfig) 90 hosts = append(hosts, docker.RegistryHost{ 91 Host: host, 92 Scheme: ep.URL.Scheme, 93 Client: client, 94 Path: "/v2", 95 Capabilities: caps, 96 Authorizer: docker.NewDockerAuthorizer( 97 docker.WithAuthClient(client), 98 docker.WithAuthCreds(func(_ string) (string, string, error) { 99 if auth.IdentityToken != "" { 100 return "", auth.IdentityToken, nil 101 } 102 return auth.Username, auth.Password, nil 103 }), 104 ), 105 }) 106 } 107 logrus.WithField("registryHost", hostname).WithField("hosts", hosts).Debug("Resolved registry hosts") 108 109 return hosts, nil 110 } 111 }