mirror of
https://github.com/distribution/distribution.git
synced 2025-08-18 23:07:38 +00:00
Merge 41e19fe9fe
into 1b01625dae
This commit is contained in:
commit
bddfc81175
@ -51,6 +51,10 @@ proxy:
|
||||
remoteurl: https://registry-1.docker.io
|
||||
username: username
|
||||
password: password
|
||||
remotehostquerykey: ns
|
||||
remotehostconfigmap:
|
||||
registry.k8s.io:
|
||||
remoteurl: https://registry.k8s.io
|
||||
health:
|
||||
storagedriver:
|
||||
enabled: true
|
||||
|
@ -595,6 +595,9 @@ type Middleware struct {
|
||||
|
||||
// Proxy configures the registry as a pull through cache
|
||||
type Proxy struct {
|
||||
RemoteHostQueryKey string `yaml:"remotehostquerykey"`
|
||||
RemoteHostConfigMap map[string]RemoteHostConfig `yaml:"remotehostconfigmap"`
|
||||
|
||||
// RemoteURL is the URL of the remote registry
|
||||
RemoteURL string `yaml:"remoteurl"`
|
||||
|
||||
@ -614,6 +617,19 @@ type Proxy struct {
|
||||
TTL *time.Duration `yaml:"ttl,omitempty"`
|
||||
}
|
||||
|
||||
type RemoteHostConfig struct {
|
||||
RemoteURL string `yaml:"remoteurl"`
|
||||
// Username of the hub user
|
||||
Username string `yaml:"username"`
|
||||
|
||||
// Password of the hub user
|
||||
Password string `yaml:"password"`
|
||||
|
||||
// Exec specifies a custom exec-based command to retrieve credentials.
|
||||
// If set, Username and Password are ignored.
|
||||
Exec *ExecConfig `yaml:"exec,omitempty"`
|
||||
}
|
||||
|
||||
type ExecConfig struct {
|
||||
// Command is the command to execute.
|
||||
Command string `yaml:"command"`
|
||||
|
15
internal/dcontext/registry_host.go
Normal file
15
internal/dcontext/registry_host.go
Normal file
@ -0,0 +1,15 @@
|
||||
package dcontext
|
||||
|
||||
import "context"
|
||||
|
||||
type registryHostKey struct{}
|
||||
|
||||
func (registryHostKey) String() string { return "registryHost" }
|
||||
|
||||
func WithRegistryHost(ctx context.Context, host string) context.Context {
|
||||
return context.WithValue(ctx, registryHostKey{}, host)
|
||||
}
|
||||
|
||||
func GetRegistryHost(ctx context.Context) string {
|
||||
return GetStringValue(ctx, registryHostKey{})
|
||||
}
|
@ -96,7 +96,7 @@ func NewApp(ctx context.Context, config *configuration.Configuration) *App {
|
||||
Config: config,
|
||||
Context: ctx,
|
||||
router: v2.RouterWithPrefix(config.HTTP.Prefix),
|
||||
isCache: config.Proxy.RemoteURL != "",
|
||||
isCache: config.Proxy.RemoteURL != "" || config.Proxy.RemoteHostQueryKey != "",
|
||||
}
|
||||
|
||||
// Register the handler dispatchers.
|
||||
@ -347,13 +347,12 @@ func NewApp(ctx context.Context, config *configuration.Configuration) *App {
|
||||
}
|
||||
|
||||
// configure as a pull through cache
|
||||
if config.Proxy.RemoteURL != "" {
|
||||
if config.Proxy.RemoteURL != "" || config.Proxy.RemoteHostQueryKey != "" {
|
||||
app.registry, err = proxy.NewRegistryPullThroughCache(ctx, app.registry, app.driver, config.Proxy)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
app.isCache = true
|
||||
dcontext.GetLogger(app).Info("Registry configured as a proxy cache to ", config.Proxy.RemoteURL)
|
||||
}
|
||||
var ok bool
|
||||
app.repoRemover, ok = app.registry.(distribution.RepositoryRemover)
|
||||
@ -690,8 +689,13 @@ func (app *App) dispatcher(dispatch dispatchFunc) http.Handler {
|
||||
return
|
||||
}
|
||||
|
||||
// dcontext.WithValues(context)
|
||||
|
||||
// Add username to request logging
|
||||
context.Context = dcontext.WithLogger(context.Context, dcontext.GetLogger(context.Context, userNameKey))
|
||||
if registryHost, ok := r.URL.Query()["ns"]; ok {
|
||||
context.Context = dcontext.WithRegistryHost(context.Context, registryHost[0])
|
||||
}
|
||||
|
||||
// sync up context on the request.
|
||||
r = r.WithContext(context)
|
||||
|
@ -26,20 +26,19 @@ var repositoryTTL = 24 * 7 * time.Hour
|
||||
|
||||
// proxyingRegistry fetches content from a remote registry and caches it locally
|
||||
type proxyingRegistry struct {
|
||||
embedded distribution.Namespace // provides local registry functionality
|
||||
scheduler *scheduler.TTLExpirationScheduler
|
||||
ttl *time.Duration
|
||||
remoteURL url.URL
|
||||
authChallenger authChallenger
|
||||
basicAuth auth.CredentialStore
|
||||
embedded distribution.Namespace // provides local registry functionality
|
||||
scheduler *scheduler.TTLExpirationScheduler
|
||||
ttl *time.Duration
|
||||
defaultRemoteURL url.URL
|
||||
defaultAuthChallenger authChallenger
|
||||
defaultBasicAuth auth.CredentialStore
|
||||
remoteURLMap map[string]url.URL
|
||||
authChallengerMap map[string]authChallenger
|
||||
basicAuthMap map[string]auth.CredentialStore
|
||||
}
|
||||
|
||||
// NewRegistryPullThroughCache creates a registry acting as a pull through cache
|
||||
func NewRegistryPullThroughCache(ctx context.Context, registry distribution.Namespace, driver driver.StorageDriver, config configuration.Proxy) (distribution.Namespace, error) {
|
||||
remoteURL, err := url.Parse(config.RemoteURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v := storage.NewVacuum(ctx, driver)
|
||||
|
||||
@ -108,37 +107,70 @@ func NewRegistryPullThroughCache(ctx context.Context, registry distribution.Name
|
||||
return nil
|
||||
})
|
||||
|
||||
err = s.Start()
|
||||
err := s.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
cs, b, err := func() (auth.CredentialStore, auth.CredentialStore, error) {
|
||||
getAuth := func(username, password, remoteurl string, exec *configuration.ExecConfig) (auth.CredentialStore, auth.CredentialStore, error) {
|
||||
switch {
|
||||
case config.Exec != nil:
|
||||
cs, err := configureExecAuth(*config.Exec)
|
||||
case exec != nil:
|
||||
cs, err := configureExecAuth(*exec)
|
||||
return cs, cs, err
|
||||
default:
|
||||
return configureAuth(config.Username, config.Password, config.RemoteURL)
|
||||
return configureAuth(username, password, remoteurl)
|
||||
}
|
||||
}()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &proxyingRegistry{
|
||||
reg := &proxyingRegistry{
|
||||
embedded: registry,
|
||||
scheduler: s,
|
||||
ttl: ttl,
|
||||
remoteURL: *remoteURL,
|
||||
authChallenger: &remoteAuthChallenger{
|
||||
}
|
||||
if config.RemoteURL != "" {
|
||||
remoteURL, err := url.Parse(config.RemoteURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cs, b, err := getAuth(config.Username, config.Password, config.RemoteURL, config.Exec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reg.defaultRemoteURL = *remoteURL
|
||||
reg.defaultAuthChallenger = &remoteAuthChallenger{
|
||||
remoteURL: *remoteURL,
|
||||
cm: challenge.NewSimpleManager(),
|
||||
cs: cs,
|
||||
},
|
||||
basicAuth: b,
|
||||
}, nil
|
||||
}
|
||||
reg.defaultBasicAuth = b
|
||||
}
|
||||
|
||||
if config.RemoteHostConfigMap != nil {
|
||||
reg.remoteURLMap = make(map[string]url.URL)
|
||||
reg.authChallengerMap = make(map[string]authChallenger)
|
||||
reg.basicAuthMap = make(map[string]auth.CredentialStore)
|
||||
for key, value := range config.RemoteHostConfigMap {
|
||||
remoteURL, err := url.Parse(value.RemoteURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cs, b, err := getAuth(value.Username, value.Password, value.RemoteURL, value.Exec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
reg.remoteURLMap[key] = *remoteURL
|
||||
reg.authChallengerMap[key] = &remoteAuthChallenger{
|
||||
remoteURL: *remoteURL,
|
||||
cm: challenge.NewSimpleManager(),
|
||||
cs: cs,
|
||||
}
|
||||
reg.basicAuthMap[key] = b
|
||||
}
|
||||
}
|
||||
|
||||
return reg, nil
|
||||
}
|
||||
|
||||
func (pr *proxyingRegistry) Scope() distribution.Scope {
|
||||
@ -150,11 +182,26 @@ func (pr *proxyingRegistry) Repositories(ctx context.Context, repos []string, la
|
||||
}
|
||||
|
||||
func (pr *proxyingRegistry) Repository(ctx context.Context, name reference.Named) (distribution.Repository, error) {
|
||||
c := pr.authChallenger
|
||||
var err error
|
||||
localRepoName := name
|
||||
authChallenger := pr.defaultAuthChallenger
|
||||
registryURL := pr.defaultRemoteURL
|
||||
basicAuth := pr.defaultBasicAuth
|
||||
if registryHost := dcontext.GetRegistryHost(ctx); registryHost != "" {
|
||||
if _, ok := pr.remoteURLMap[registryHost]; ok {
|
||||
localRepoName, err = reference.WithName(fmt.Sprintf("%s/%s", registryHost, name.Name()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
registryURL = pr.remoteURLMap[registryHost]
|
||||
authChallenger = pr.authChallengerMap[registryHost]
|
||||
basicAuth = pr.basicAuthMap[registryHost]
|
||||
}
|
||||
}
|
||||
|
||||
tkopts := auth.TokenHandlerOptions{
|
||||
Transport: http.DefaultTransport,
|
||||
Credentials: c.credentialStore(),
|
||||
Credentials: authChallenger.credentialStore(),
|
||||
Scopes: []auth.Scope{
|
||||
auth.RepositoryScope{
|
||||
Repository: name.Name(),
|
||||
@ -165,11 +212,11 @@ func (pr *proxyingRegistry) Repository(ctx context.Context, name reference.Named
|
||||
}
|
||||
|
||||
tr := transport.NewTransport(http.DefaultTransport,
|
||||
auth.NewAuthorizer(c.challengeManager(),
|
||||
auth.NewAuthorizer(authChallenger.challengeManager(),
|
||||
auth.NewTokenHandlerWithOptions(tkopts),
|
||||
auth.NewBasicHandler(pr.basicAuth)))
|
||||
auth.NewBasicHandler(basicAuth)))
|
||||
|
||||
localRepo, err := pr.embedded.Repository(ctx, name)
|
||||
localRepo, err := pr.embedded.Repository(ctx, localRepoName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -178,7 +225,7 @@ func (pr *proxyingRegistry) Repository(ctx context.Context, name reference.Named
|
||||
return nil, err
|
||||
}
|
||||
|
||||
remoteRepo, err := client.NewRepository(name, pr.remoteURL.String(), tr)
|
||||
remoteRepo, err := client.NewRepository(name, registryURL.String(), tr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -195,7 +242,7 @@ func (pr *proxyingRegistry) Repository(ctx context.Context, name reference.Named
|
||||
scheduler: pr.scheduler,
|
||||
ttl: pr.ttl,
|
||||
repositoryName: name,
|
||||
authChallenger: pr.authChallenger,
|
||||
authChallenger: authChallenger,
|
||||
},
|
||||
manifests: &proxyManifestStore{
|
||||
repositoryName: name,
|
||||
@ -204,13 +251,13 @@ func (pr *proxyingRegistry) Repository(ctx context.Context, name reference.Named
|
||||
ctx: ctx,
|
||||
scheduler: pr.scheduler,
|
||||
ttl: pr.ttl,
|
||||
authChallenger: pr.authChallenger,
|
||||
authChallenger: authChallenger,
|
||||
},
|
||||
name: name,
|
||||
tags: &proxyTagService{
|
||||
localTags: localRepo.Tags(ctx),
|
||||
remoteTags: remoteRepo.Tags(ctx),
|
||||
authChallenger: pr.authChallenger,
|
||||
authChallenger: authChallenger,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user