1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/plugin/registry.go
Brian Goff d7ba1f85ef Use containerd dist libs for plugin pull/pull
This removes the use of the old distribution code in the plugin packages
and replaces it with containerd libraries for plugin pushes and pulls.

Additionally it uses a content store from containerd which seems like
it's compatible with the old "basicBlobStore" in the plugin package.
This is being used locally isntead of through the containerd client for
now.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2020-04-02 15:03:06 -07:00

111 lines
3.2 KiB
Go

package plugin
import (
"context"
"crypto/tls"
"net"
"net/http"
"time"
"github.com/sirupsen/logrus"
"github.com/docker/docker/dockerversion"
"github.com/pkg/errors"
"github.com/containerd/containerd/remotes"
"github.com/containerd/containerd/remotes/docker"
"github.com/docker/distribution/reference"
"github.com/docker/docker/api/types"
)
// scope builds the correct auth scope for the registry client to authorize against
// By default the client currently only does a "repository:" scope with out a classifier, e.g. "(plugin)"
// Without this, the client will not be able to authorize the request
func scope(ref reference.Named, push bool) string {
scope := "repository(plugin):" + reference.Path(reference.TrimNamed(ref)) + ":pull"
if push {
scope += ",push"
}
return scope
}
func (pm *Manager) newResolver(ctx context.Context, tracker docker.StatusTracker, auth *types.AuthConfig, headers http.Header, httpFallback bool) (remotes.Resolver, error) {
if headers == nil {
headers = http.Header{}
}
headers.Add("User-Agent", dockerversion.DockerUserAgent(ctx))
return docker.NewResolver(docker.ResolverOptions{
Tracker: tracker,
Headers: headers,
Hosts: pm.registryHostsFn(auth, httpFallback),
}), nil
}
func registryHTTPClient(config *tls.Config) *http.Client {
return &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
TLSClientConfig: config,
TLSHandshakeTimeout: 10 * time.Second,
IdleConnTimeout: 30 * time.Second,
},
}
}
func (pm *Manager) registryHostsFn(auth *types.AuthConfig, httpFallback bool) docker.RegistryHosts {
return func(hostname string) ([]docker.RegistryHost, error) {
eps, err := pm.config.RegistryService.LookupPullEndpoints(hostname)
if err != nil {
return nil, errors.Wrapf(err, "error resolving repository for %s", hostname)
}
hosts := make([]docker.RegistryHost, 0, len(eps))
for _, ep := range eps {
// forced http fallback is used only for push since the containerd pusher only ever uses the first host we
// pass to it.
// So it is the callers responsibility to retry with this flag set.
if httpFallback && ep.URL.Scheme != "http" {
logrus.WithField("registryHost", hostname).WithField("endpoint", ep).Debugf("Skipping non-http endpoint")
continue
}
caps := docker.HostCapabilityPull | docker.HostCapabilityResolve
if !ep.Mirror {
caps = caps | docker.HostCapabilityPush
}
host, err := docker.DefaultHost(ep.URL.Host)
if err != nil {
return nil, err
}
client := registryHTTPClient(ep.TLSConfig)
hosts = append(hosts, docker.RegistryHost{
Host: host,
Scheme: ep.URL.Scheme,
Client: client,
Path: "/v2",
Capabilities: caps,
Authorizer: docker.NewDockerAuthorizer(
docker.WithAuthClient(client),
docker.WithAuthCreds(func(_ string) (string, string, error) {
if auth.IdentityToken != "" {
return "", auth.IdentityToken, nil
}
return auth.Username, auth.Password, nil
}),
),
})
}
logrus.WithField("registryHost", hostname).WithField("hosts", hosts).Debug("Resolved registry hosts")
return hosts, nil
}
}