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