Prevent push and pull to v1 registries by filtering the available endpoints.
Add a daemon flag to control this behaviour. Add a warning message when pulling an image from a v1 registry. The default order of pull is slightly altered with this changset. Previously it was: https v2, https v1, http v2, http v1 now it is: https v2, http v2, https v1, http v1 Prevent login to v1 registries by explicitly setting the version before ping to prevent fallback to v1. Add unit tests for v2 only mode. Create a mock server that can register handlers for various endpoints. Assert no v1 endpoints are hit with legacy registries disabled for the following commands: pull, push, build, run and login. Assert the opposite when legacy registries are not disabled. Signed-off-by: Richard Scothern <richard.scothern@gmail.com>
This commit is contained in:
parent
02eed8d666
commit
39f2f15a35
11 changed files with 385 additions and 103 deletions
|
@ -60,6 +60,9 @@ func (p *v1Puller) Pull(tag string) (fallback bool, err error) {
|
|||
// TODO(dmcgowan): Check if should fallback
|
||||
return false, err
|
||||
}
|
||||
out := p.config.OutStream
|
||||
out.Write(p.sf.FormatStatus("", "%s: this image was pulled from a legacy registry. Important: This registry version will not be supported in future versions of docker.", p.repoInfo.CanonicalName))
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -32,10 +32,13 @@ func init() {
|
|||
type DockerRegistrySuite struct {
|
||||
ds *DockerSuite
|
||||
reg *testRegistryV2
|
||||
d *Daemon
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) SetUpTest(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
s.reg = setupRegistry(c)
|
||||
s.d = NewDaemon(c)
|
||||
}
|
||||
|
||||
func (s *DockerRegistrySuite) TearDownTest(c *check.C) {
|
||||
|
@ -45,6 +48,7 @@ func (s *DockerRegistrySuite) TearDownTest(c *check.C) {
|
|||
if s.ds != nil {
|
||||
s.ds.TearDownTest(c)
|
||||
}
|
||||
s.d.Stop()
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
147
integration-cli/docker_cli_v2_only.go
Normal file
147
integration-cli/docker_cli_v2_only.go
Normal file
|
@ -0,0 +1,147 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/go-check/check"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
func makefile(contents string) (string, func(), error) {
|
||||
cleanup := func() {
|
||||
|
||||
}
|
||||
|
||||
f, err := ioutil.TempFile(".", "tmp")
|
||||
if err != nil {
|
||||
return "", cleanup, err
|
||||
}
|
||||
err = ioutil.WriteFile(f.Name(), []byte(contents), os.ModePerm)
|
||||
if err != nil {
|
||||
return "", cleanup, err
|
||||
}
|
||||
|
||||
cleanup = func() {
|
||||
err := os.Remove(f.Name())
|
||||
if err != nil {
|
||||
fmt.Println("Error removing tmpfile")
|
||||
}
|
||||
}
|
||||
return f.Name(), cleanup, nil
|
||||
|
||||
}
|
||||
|
||||
// TestV2Only ensures that a daemon in v2-only mode does not
|
||||
// attempt to contact any v1 registry endpoints.
|
||||
func (s *DockerRegistrySuite) TestV2Only(c *check.C) {
|
||||
reg, err := newTestRegistry(c)
|
||||
if err != nil {
|
||||
c.Fatal(err.Error())
|
||||
}
|
||||
|
||||
reg.registerHandler("/v2/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.WriteHeader(404)
|
||||
})
|
||||
|
||||
reg.registerHandler("/v1/.*", func(w http.ResponseWriter, r *http.Request) {
|
||||
c.Fatal("V1 registry contacted")
|
||||
})
|
||||
|
||||
repoName := fmt.Sprintf("%s/busybox", reg.hostport)
|
||||
|
||||
err = s.d.Start("--insecure-registry", reg.hostport, "--no-legacy-registry=true")
|
||||
if err != nil {
|
||||
c.Fatalf("Error starting daemon: %s", err.Error())
|
||||
}
|
||||
|
||||
dockerfileName, cleanup, err := makefile(fmt.Sprintf("FROM %s/busybox", reg.hostport))
|
||||
if err != nil {
|
||||
c.Fatalf("Unable to create test dockerfile")
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
s.d.Cmd("build", "--file", dockerfileName, ".")
|
||||
|
||||
s.d.Cmd("run", repoName)
|
||||
s.d.Cmd("login", "-u", "richard", "-p", "testtest", "-e", "testuser@testdomain.com", reg.hostport)
|
||||
s.d.Cmd("tag", "busybox", repoName)
|
||||
s.d.Cmd("push", repoName)
|
||||
s.d.Cmd("pull", repoName)
|
||||
}
|
||||
|
||||
// TestV1 starts a daemon in 'normal' mode
|
||||
// and ensure v1 endpoints are hit for the following operations:
|
||||
// login, push, pull, build & run
|
||||
func (s *DockerRegistrySuite) TestV1(c *check.C) {
|
||||
reg, err := newTestRegistry(c)
|
||||
if err != nil {
|
||||
c.Fatal(err.Error())
|
||||
}
|
||||
|
||||
v2Pings := 0
|
||||
reg.registerHandler("/v2/", func(w http.ResponseWriter, r *http.Request) {
|
||||
v2Pings++
|
||||
// V2 ping 404 causes fallback to v1
|
||||
w.WriteHeader(404)
|
||||
})
|
||||
|
||||
v1Pings := 0
|
||||
reg.registerHandler("/v1/_ping", func(w http.ResponseWriter, r *http.Request) {
|
||||
v1Pings++
|
||||
})
|
||||
|
||||
v1Logins := 0
|
||||
reg.registerHandler("/v1/users/", func(w http.ResponseWriter, r *http.Request) {
|
||||
v1Logins++
|
||||
})
|
||||
|
||||
v1Repo := 0
|
||||
reg.registerHandler("/v1/repositories/busybox/", func(w http.ResponseWriter, r *http.Request) {
|
||||
v1Repo++
|
||||
})
|
||||
|
||||
reg.registerHandler("/v1/repositories/busybox/images", func(w http.ResponseWriter, r *http.Request) {
|
||||
v1Repo++
|
||||
})
|
||||
|
||||
err = s.d.Start("--insecure-registry", reg.hostport, "--no-legacy-registry=false")
|
||||
if err != nil {
|
||||
c.Fatalf("Error starting daemon: %s", err.Error())
|
||||
}
|
||||
|
||||
dockerfileName, cleanup, err := makefile(fmt.Sprintf("FROM %s/busybox", reg.hostport))
|
||||
if err != nil {
|
||||
c.Fatalf("Unable to create test dockerfile")
|
||||
}
|
||||
defer cleanup()
|
||||
|
||||
s.d.Cmd("build", "--file", dockerfileName, ".")
|
||||
if v1Repo == 0 {
|
||||
c.Errorf("Expected v1 repository access after build")
|
||||
}
|
||||
|
||||
repoName := fmt.Sprintf("%s/busybox", reg.hostport)
|
||||
s.d.Cmd("run", repoName)
|
||||
if v1Repo == 1 {
|
||||
c.Errorf("Expected v1 repository access after run")
|
||||
}
|
||||
|
||||
s.d.Cmd("login", "-u", "richard", "-p", "testtest", "-e", "testuser@testdomain.com", reg.hostport)
|
||||
if v1Logins == 0 {
|
||||
c.Errorf("Expected v1 login attempt")
|
||||
}
|
||||
|
||||
s.d.Cmd("tag", "busybox", repoName)
|
||||
s.d.Cmd("push", repoName)
|
||||
|
||||
if v1Repo != 2 || v1Pings != 1 {
|
||||
c.Error("Not all endpoints contacted after push", v1Repo, v1Pings)
|
||||
}
|
||||
|
||||
s.d.Cmd("pull", repoName)
|
||||
if v1Repo != 3 {
|
||||
c.Errorf("Expected v1 repository access after pull")
|
||||
}
|
||||
|
||||
}
|
56
integration-cli/registry_mock.go
Normal file
56
integration-cli/registry_mock.go
Normal file
|
@ -0,0 +1,56 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/go-check/check"
|
||||
)
|
||||
|
||||
type handlerFunc func(w http.ResponseWriter, r *http.Request)
|
||||
|
||||
type testRegistry struct {
|
||||
server *httptest.Server
|
||||
hostport string
|
||||
handlers map[string]handlerFunc
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func (tr *testRegistry) registerHandler(path string, h handlerFunc) {
|
||||
tr.mu.Lock()
|
||||
defer tr.mu.Unlock()
|
||||
tr.handlers[path] = h
|
||||
}
|
||||
|
||||
func newTestRegistry(c *check.C) (*testRegistry, error) {
|
||||
testReg := &testRegistry{handlers: make(map[string]handlerFunc)}
|
||||
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
url := r.URL.String()
|
||||
|
||||
var matched bool
|
||||
var err error
|
||||
for re, function := range testReg.handlers {
|
||||
matched, err = regexp.MatchString(re, url)
|
||||
if err != nil {
|
||||
c.Fatalf("Error with handler regexp")
|
||||
return
|
||||
}
|
||||
if matched {
|
||||
function(w, r)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !matched {
|
||||
c.Fatal("Unable to match", url, "with regexp")
|
||||
}
|
||||
}))
|
||||
|
||||
testReg.server = ts
|
||||
testReg.hostport = strings.Replace(ts.URL, "http://", "", 1)
|
||||
return testReg, nil
|
||||
}
|
|
@ -44,6 +44,10 @@ var (
|
|||
ErrInvalidRepositoryName = errors.New("Invalid repository name (ex: \"registry.domain.tld/myrepos\")")
|
||||
|
||||
emptyServiceConfig = NewServiceConfig(nil)
|
||||
|
||||
// V2Only controls access to legacy registries. If it is set to true via the
|
||||
// command line flag the daemon will not attempt to contact v1 legacy registries
|
||||
V2Only = false
|
||||
)
|
||||
|
||||
// InstallFlags adds command-line options to the top-level flag parser for
|
||||
|
@ -53,6 +57,7 @@ func (options *Options) InstallFlags(cmd *flag.FlagSet, usageFn func(string) str
|
|||
cmd.Var(&options.Mirrors, []string{"-registry-mirror"}, usageFn("Preferred Docker registry mirror"))
|
||||
options.InsecureRegistries = opts.NewListOpts(ValidateIndexName)
|
||||
cmd.Var(&options.InsecureRegistries, []string{"-insecure-registry"}, usageFn("Enable insecure registry communication"))
|
||||
cmd.BoolVar(&V2Only, []string{"-no-legacy-registry"}, false, "Do not contact legacy registries")
|
||||
}
|
||||
|
||||
type netIPNet net.IPNet
|
||||
|
|
|
@ -42,8 +42,9 @@ func scanForAPIVersion(address string) (string, APIVersion) {
|
|||
return address, APIVersionUnknown
|
||||
}
|
||||
|
||||
// NewEndpoint parses the given address to return a registry endpoint.
|
||||
func NewEndpoint(index *IndexInfo, metaHeaders http.Header) (*Endpoint, error) {
|
||||
// NewEndpoint parses the given address to return a registry endpoint. v can be used to
|
||||
// specify a specific endpoint version
|
||||
func NewEndpoint(index *IndexInfo, metaHeaders http.Header, v APIVersion) (*Endpoint, error) {
|
||||
tlsConfig, err := newTLSConfig(index.Name, index.Secure)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -52,6 +53,9 @@ func NewEndpoint(index *IndexInfo, metaHeaders http.Header) (*Endpoint, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if v != APIVersionUnknown {
|
||||
endpoint.Version = v
|
||||
}
|
||||
if err := validateEndpoint(endpoint); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -111,11 +115,6 @@ func newEndpoint(address string, tlsConfig *tls.Config, metaHeaders http.Header)
|
|||
return endpoint, nil
|
||||
}
|
||||
|
||||
// GetEndpoint returns a new endpoint with the specified headers
|
||||
func (repoInfo *RepositoryInfo) GetEndpoint(metaHeaders http.Header) (*Endpoint, error) {
|
||||
return NewEndpoint(repoInfo.Index, metaHeaders)
|
||||
}
|
||||
|
||||
// Endpoint stores basic information about a registry endpoint.
|
||||
type Endpoint struct {
|
||||
client *http.Client
|
||||
|
|
|
@ -49,6 +49,10 @@ func init() {
|
|||
httpVersion = append(httpVersion, useragent.VersionInfo{"arch", runtime.GOARCH})
|
||||
|
||||
dockerUserAgent = useragent.AppendVersions("", httpVersion...)
|
||||
|
||||
if runtime.GOOS != "linux" {
|
||||
V2Only = true
|
||||
}
|
||||
}
|
||||
|
||||
func newTLSConfig(hostname string, isSecure bool) (*tls.Config, error) {
|
||||
|
|
|
@ -23,7 +23,7 @@ const (
|
|||
|
||||
func spawnTestRegistrySession(t *testing.T) *Session {
|
||||
authConfig := &cliconfig.AuthConfig{}
|
||||
endpoint, err := NewEndpoint(makeIndex("/v1/"), nil)
|
||||
endpoint, err := NewEndpoint(makeIndex("/v1/"), nil, APIVersionUnknown)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -50,7 +50,7 @@ func spawnTestRegistrySession(t *testing.T) *Session {
|
|||
|
||||
func TestPingRegistryEndpoint(t *testing.T) {
|
||||
testPing := func(index *IndexInfo, expectedStandalone bool, assertMessage string) {
|
||||
ep, err := NewEndpoint(index, nil)
|
||||
ep, err := NewEndpoint(index, nil, APIVersionUnknown)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ func TestPingRegistryEndpoint(t *testing.T) {
|
|||
func TestEndpoint(t *testing.T) {
|
||||
// Simple wrapper to fail test if err != nil
|
||||
expandEndpoint := func(index *IndexInfo) *Endpoint {
|
||||
endpoint, err := NewEndpoint(index, nil)
|
||||
endpoint, err := NewEndpoint(index, nil, APIVersionUnknown)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ func TestEndpoint(t *testing.T) {
|
|||
|
||||
assertInsecureIndex := func(index *IndexInfo) {
|
||||
index.Secure = true
|
||||
_, err := NewEndpoint(index, nil)
|
||||
_, err := NewEndpoint(index, nil, APIVersionUnknown)
|
||||
assertNotEqual(t, err, nil, index.Name+": Expected error for insecure index")
|
||||
assertEqual(t, strings.Contains(err.Error(), "insecure-registry"), true, index.Name+": Expected insecure-registry error for insecure index")
|
||||
index.Secure = false
|
||||
|
@ -87,7 +87,7 @@ func TestEndpoint(t *testing.T) {
|
|||
|
||||
assertSecureIndex := func(index *IndexInfo) {
|
||||
index.Secure = true
|
||||
_, err := NewEndpoint(index, nil)
|
||||
_, err := NewEndpoint(index, nil, APIVersionUnknown)
|
||||
assertNotEqual(t, err, nil, index.Name+": Expected cert error for secure index")
|
||||
assertEqual(t, strings.Contains(err.Error(), "certificate signed by unknown authority"), true, index.Name+": Expected cert error for secure index")
|
||||
index.Secure = false
|
||||
|
@ -153,7 +153,7 @@ func TestEndpoint(t *testing.T) {
|
|||
}
|
||||
for _, address := range badEndpoints {
|
||||
index.Name = address
|
||||
_, err := NewEndpoint(index, nil)
|
||||
_, err := NewEndpoint(index, nil, APIVersionUnknown)
|
||||
checkNotEqual(t, err, nil, "Expected error while expanding bad endpoint")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,15 +2,11 @@ package registry
|
|||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/registry/client/auth"
|
||||
"github.com/docker/docker/cliconfig"
|
||||
"github.com/docker/docker/pkg/tlsconfig"
|
||||
)
|
||||
|
||||
// Service is a registry service. It tracks configuration data such as a list
|
||||
|
@ -40,7 +36,14 @@ func (s *Service) Auth(authConfig *cliconfig.AuthConfig) (string, error) {
|
|||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
endpoint, err := NewEndpoint(index, nil)
|
||||
|
||||
endpointVersion := APIVersion(APIVersionUnknown)
|
||||
if V2Only {
|
||||
// Override the endpoint to only attempt a v2 ping
|
||||
endpointVersion = APIVersion2
|
||||
}
|
||||
|
||||
endpoint, err := NewEndpoint(index, nil, endpointVersion)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
@ -57,10 +60,11 @@ func (s *Service) Search(term string, authConfig *cliconfig.AuthConfig, headers
|
|||
}
|
||||
|
||||
// *TODO: Search multiple indexes.
|
||||
endpoint, err := repoInfo.GetEndpoint(http.Header(headers))
|
||||
endpoint, err := NewEndpoint(repoInfo.Index, http.Header(headers), APIVersionUnknown)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r, err := NewSession(endpoint.client, authConfig, endpoint)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -132,97 +136,20 @@ func (s *Service) LookupPushEndpoints(repoName string) (endpoints []APIEndpoint,
|
|||
}
|
||||
|
||||
func (s *Service) lookupEndpoints(repoName string) (endpoints []APIEndpoint, err error) {
|
||||
var cfg = tlsconfig.ServerDefault
|
||||
tlsConfig := &cfg
|
||||
if strings.HasPrefix(repoName, DefaultNamespace+"/") {
|
||||
// v2 mirrors
|
||||
for _, mirror := range s.Config.Mirrors {
|
||||
mirrorTLSConfig, err := s.tlsConfigForMirror(mirror)
|
||||
endpoints, err = s.lookupV2Endpoints(repoName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
endpoints = append(endpoints, APIEndpoint{
|
||||
URL: mirror,
|
||||
// guess mirrors are v2
|
||||
Version: APIVersion2,
|
||||
Mirror: true,
|
||||
TrimHostname: true,
|
||||
TLSConfig: mirrorTLSConfig,
|
||||
})
|
||||
}
|
||||
// v2 registry
|
||||
endpoints = append(endpoints, APIEndpoint{
|
||||
URL: DefaultV2Registry,
|
||||
Version: APIVersion2,
|
||||
Official: true,
|
||||
TrimHostname: true,
|
||||
TLSConfig: tlsConfig,
|
||||
})
|
||||
if runtime.GOOS == "linux" { // do not inherit legacy API for OSes supported in the future
|
||||
// v1 registry
|
||||
endpoints = append(endpoints, APIEndpoint{
|
||||
URL: DefaultV1Registry,
|
||||
Version: APIVersion1,
|
||||
Official: true,
|
||||
TrimHostname: true,
|
||||
TLSConfig: tlsConfig,
|
||||
})
|
||||
}
|
||||
|
||||
if V2Only {
|
||||
return endpoints, nil
|
||||
}
|
||||
|
||||
slashIndex := strings.IndexRune(repoName, '/')
|
||||
if slashIndex <= 0 {
|
||||
return nil, fmt.Errorf("invalid repo name: missing '/': %s", repoName)
|
||||
}
|
||||
hostname := repoName[:slashIndex]
|
||||
|
||||
tlsConfig, err = s.TLSConfig(hostname)
|
||||
legacyEndpoints, err := s.lookupV1Endpoints(repoName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
isSecure := !tlsConfig.InsecureSkipVerify
|
||||
|
||||
v2Versions := []auth.APIVersion{
|
||||
{
|
||||
Type: "registry",
|
||||
Version: "2.0",
|
||||
},
|
||||
}
|
||||
endpoints = []APIEndpoint{
|
||||
{
|
||||
URL: "https://" + hostname,
|
||||
Version: APIVersion2,
|
||||
TrimHostname: true,
|
||||
TLSConfig: tlsConfig,
|
||||
VersionHeader: DefaultRegistryVersionHeader,
|
||||
Versions: v2Versions,
|
||||
},
|
||||
{
|
||||
URL: "https://" + hostname,
|
||||
Version: APIVersion1,
|
||||
TrimHostname: true,
|
||||
TLSConfig: tlsConfig,
|
||||
},
|
||||
}
|
||||
|
||||
if !isSecure {
|
||||
endpoints = append(endpoints, APIEndpoint{
|
||||
URL: "http://" + hostname,
|
||||
Version: APIVersion2,
|
||||
TrimHostname: true,
|
||||
// used to check if supposed to be secure via InsecureSkipVerify
|
||||
TLSConfig: tlsConfig,
|
||||
VersionHeader: DefaultRegistryVersionHeader,
|
||||
Versions: v2Versions,
|
||||
}, APIEndpoint{
|
||||
URL: "http://" + hostname,
|
||||
Version: APIVersion1,
|
||||
TrimHostname: true,
|
||||
// used to check if supposed to be secure via InsecureSkipVerify
|
||||
TLSConfig: tlsConfig,
|
||||
})
|
||||
}
|
||||
endpoints = append(endpoints, legacyEndpoints...)
|
||||
|
||||
return endpoints, nil
|
||||
}
|
||||
|
|
54
registry/service_v1.go
Normal file
54
registry/service_v1.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
package registry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/docker/pkg/tlsconfig"
|
||||
)
|
||||
|
||||
func (s *Service) lookupV1Endpoints(repoName string) (endpoints []APIEndpoint, err error) {
|
||||
var cfg = tlsconfig.ServerDefault
|
||||
tlsConfig := &cfg
|
||||
if strings.HasPrefix(repoName, DefaultNamespace+"/") {
|
||||
endpoints = append(endpoints, APIEndpoint{
|
||||
URL: DefaultV1Registry,
|
||||
Version: APIVersion1,
|
||||
Official: true,
|
||||
TrimHostname: true,
|
||||
TLSConfig: tlsConfig,
|
||||
})
|
||||
return endpoints, nil
|
||||
}
|
||||
|
||||
slashIndex := strings.IndexRune(repoName, '/')
|
||||
if slashIndex <= 0 {
|
||||
return nil, fmt.Errorf("invalid repo name: missing '/': %s", repoName)
|
||||
}
|
||||
hostname := repoName[:slashIndex]
|
||||
|
||||
tlsConfig, err = s.TLSConfig(hostname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
endpoints = []APIEndpoint{
|
||||
{
|
||||
URL: "https://" + hostname,
|
||||
Version: APIVersion1,
|
||||
TrimHostname: true,
|
||||
TLSConfig: tlsConfig,
|
||||
},
|
||||
}
|
||||
|
||||
if tlsConfig.InsecureSkipVerify {
|
||||
endpoints = append(endpoints, APIEndpoint{ // or this
|
||||
URL: "http://" + hostname,
|
||||
Version: APIVersion1,
|
||||
TrimHostname: true,
|
||||
// used to check if supposed to be secure via InsecureSkipVerify
|
||||
TLSConfig: tlsConfig,
|
||||
})
|
||||
}
|
||||
return endpoints, nil
|
||||
}
|
83
registry/service_v2.go
Normal file
83
registry/service_v2.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
package registry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/distribution/registry/client/auth"
|
||||
"github.com/docker/docker/pkg/tlsconfig"
|
||||
)
|
||||
|
||||
func (s *Service) lookupV2Endpoints(repoName string) (endpoints []APIEndpoint, err error) {
|
||||
var cfg = tlsconfig.ServerDefault
|
||||
tlsConfig := &cfg
|
||||
if strings.HasPrefix(repoName, DefaultNamespace+"/") {
|
||||
// v2 mirrors
|
||||
for _, mirror := range s.Config.Mirrors {
|
||||
mirrorTLSConfig, err := s.tlsConfigForMirror(mirror)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
endpoints = append(endpoints, APIEndpoint{
|
||||
URL: mirror,
|
||||
// guess mirrors are v2
|
||||
Version: APIVersion2,
|
||||
Mirror: true,
|
||||
TrimHostname: true,
|
||||
TLSConfig: mirrorTLSConfig,
|
||||
})
|
||||
}
|
||||
// v2 registry
|
||||
endpoints = append(endpoints, APIEndpoint{
|
||||
URL: DefaultV2Registry,
|
||||
Version: APIVersion2,
|
||||
Official: true,
|
||||
TrimHostname: true,
|
||||
TLSConfig: tlsConfig,
|
||||
})
|
||||
|
||||
return endpoints, nil
|
||||
}
|
||||
|
||||
slashIndex := strings.IndexRune(repoName, '/')
|
||||
if slashIndex <= 0 {
|
||||
return nil, fmt.Errorf("invalid repo name: missing '/': %s", repoName)
|
||||
}
|
||||
hostname := repoName[:slashIndex]
|
||||
|
||||
tlsConfig, err = s.TLSConfig(hostname)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
v2Versions := []auth.APIVersion{
|
||||
{
|
||||
Type: "registry",
|
||||
Version: "2.0",
|
||||
},
|
||||
}
|
||||
endpoints = []APIEndpoint{
|
||||
{
|
||||
URL: "https://" + hostname,
|
||||
Version: APIVersion2,
|
||||
TrimHostname: true,
|
||||
TLSConfig: tlsConfig,
|
||||
VersionHeader: DefaultRegistryVersionHeader,
|
||||
Versions: v2Versions,
|
||||
},
|
||||
}
|
||||
|
||||
if tlsConfig.InsecureSkipVerify {
|
||||
endpoints = append(endpoints, APIEndpoint{
|
||||
URL: "http://" + hostname,
|
||||
Version: APIVersion2,
|
||||
TrimHostname: true,
|
||||
// used to check if supposed to be secure via InsecureSkipVerify
|
||||
TLSConfig: tlsConfig,
|
||||
VersionHeader: DefaultRegistryVersionHeader,
|
||||
Versions: v2Versions,
|
||||
})
|
||||
}
|
||||
|
||||
return endpoints, nil
|
||||
}
|
Loading…
Reference in a new issue