mirror of https://github.com/docker/cli.git
internal/registry: remove code related to mirrors
The CLI does not have information about mirrors, and doesn't
configure them, so we can remove these parts.
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit e0b351b3d9)
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
This commit is contained in:
parent
ecd54bc6dd
commit
72f85ccd16
|
|
@ -22,7 +22,6 @@ import (
|
|||
|
||||
// ServiceOptions holds command line options.
|
||||
type ServiceOptions struct {
|
||||
Mirrors []string `json:"registry-mirrors,omitempty"`
|
||||
InsecureRegistries []string `json:"insecure-registries,omitempty"`
|
||||
}
|
||||
|
||||
|
|
@ -93,51 +92,6 @@ func CertsDir() string {
|
|||
return certsDir
|
||||
}
|
||||
|
||||
// newServiceConfig returns a new instance of ServiceConfig
|
||||
func newServiceConfig(options ServiceOptions) (*serviceConfig, error) {
|
||||
config := &serviceConfig{}
|
||||
if err := config.loadMirrors(options.Mirrors); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := config.loadInsecureRegistries(options.InsecureRegistries); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
// loadMirrors loads mirrors to config, after removing duplicates.
|
||||
// Returns an error if mirrors contains an invalid mirror.
|
||||
func (config *serviceConfig) loadMirrors(mirrors []string) error {
|
||||
mMap := map[string]struct{}{}
|
||||
unique := []string{}
|
||||
|
||||
for _, mirror := range mirrors {
|
||||
m, err := ValidateMirror(mirror)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, exist := mMap[m]; !exist {
|
||||
mMap[m] = struct{}{}
|
||||
unique = append(unique, m)
|
||||
}
|
||||
}
|
||||
|
||||
config.Mirrors = unique
|
||||
|
||||
// Configure public registry since mirrors may have changed.
|
||||
config.IndexConfigs = map[string]*registry.IndexInfo{
|
||||
IndexName: {
|
||||
Name: IndexName,
|
||||
Mirrors: unique,
|
||||
Secure: true,
|
||||
Official: true,
|
||||
},
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// loadInsecureRegistries loads insecure registries to config
|
||||
func (config *serviceConfig) loadInsecureRegistries(registries []string) error {
|
||||
// Localhost is by default considered as an insecure registry. This is a
|
||||
|
|
@ -184,7 +138,6 @@ skip:
|
|||
// Assume `host:port` if not CIDR.
|
||||
indexConfigs[r] = ®istry.IndexInfo{
|
||||
Name: r,
|
||||
Mirrors: []string{},
|
||||
Secure: false,
|
||||
Official: false,
|
||||
}
|
||||
|
|
@ -194,7 +147,6 @@ skip:
|
|||
// Configure public registry.
|
||||
indexConfigs[IndexName] = ®istry.IndexInfo{
|
||||
Name: IndexName,
|
||||
Mirrors: config.Mirrors,
|
||||
Secure: true,
|
||||
Official: true,
|
||||
}
|
||||
|
|
@ -267,35 +219,6 @@ func isCIDRMatch(cidrs []*registry.NetIPNet, urlHost string) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// ValidateMirror validates and normalizes an HTTP(S) registry mirror. It
|
||||
// returns an error if the given mirrorURL is invalid, or the normalized
|
||||
// format for the URL otherwise.
|
||||
//
|
||||
// It is used by the daemon to validate the daemon configuration.
|
||||
func ValidateMirror(mirrorURL string) (string, error) {
|
||||
// Fast path for missing scheme, as url.Parse splits by ":", which can
|
||||
// cause the hostname to be considered the "scheme" when using "hostname:port".
|
||||
if scheme, _, ok := strings.Cut(mirrorURL, "://"); !ok || scheme == "" {
|
||||
return "", invalidParamf("invalid mirror: no scheme specified for %q: must use either 'https://' or 'http://'", mirrorURL)
|
||||
}
|
||||
uri, err := url.Parse(mirrorURL)
|
||||
if err != nil {
|
||||
return "", invalidParamWrapf(err, "invalid mirror: %q is not a valid URI", mirrorURL)
|
||||
}
|
||||
if uri.Scheme != "http" && uri.Scheme != "https" {
|
||||
return "", invalidParamf("invalid mirror: unsupported scheme %q in %q: must use either 'https://' or 'http://'", uri.Scheme, uri)
|
||||
}
|
||||
if uri.RawQuery != "" || uri.Fragment != "" {
|
||||
return "", invalidParamf("invalid mirror: query or fragment at end of the URI %q", uri)
|
||||
}
|
||||
if uri.User != nil {
|
||||
// strip password from output
|
||||
uri.User = url.UserPassword(uri.User.Username(), "xxxxx")
|
||||
return "", invalidParamf("invalid mirror: username/password not allowed in URI %q", uri)
|
||||
}
|
||||
return strings.TrimSuffix(mirrorURL, "/") + "/", nil
|
||||
}
|
||||
|
||||
// ValidateIndexName validates an index name. It is used by the daemon to
|
||||
// validate the daemon configuration.
|
||||
func ValidateIndexName(val string) (string, error) {
|
||||
|
|
@ -348,7 +271,6 @@ func ParseRepositoryInfo(reposName reference.Named) (*RepositoryInfo, error) {
|
|||
Name: reference.TrimNamed(reposName),
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: IndexName,
|
||||
Mirrors: []string{},
|
||||
Secure: true,
|
||||
Official: true,
|
||||
},
|
||||
|
|
@ -358,9 +280,8 @@ func ParseRepositoryInfo(reposName reference.Named) (*RepositoryInfo, error) {
|
|||
return &RepositoryInfo{
|
||||
Name: reference.TrimNamed(reposName),
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: indexName,
|
||||
Mirrors: []string{},
|
||||
Secure: !isInsecure(indexName),
|
||||
Name: indexName,
|
||||
Secure: !isInsecure(indexName),
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,138 +8,6 @@ import (
|
|||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
func TestValidateMirror(t *testing.T) {
|
||||
tests := []struct {
|
||||
input string
|
||||
output string
|
||||
expectedErr string
|
||||
}{
|
||||
// Valid cases
|
||||
{
|
||||
input: "http://mirror-1.example.com",
|
||||
output: "http://mirror-1.example.com/",
|
||||
},
|
||||
{
|
||||
input: "http://mirror-1.example.com/",
|
||||
output: "http://mirror-1.example.com/",
|
||||
},
|
||||
{
|
||||
input: "https://mirror-1.example.com",
|
||||
output: "https://mirror-1.example.com/",
|
||||
},
|
||||
{
|
||||
input: "https://mirror-1.example.com/",
|
||||
output: "https://mirror-1.example.com/",
|
||||
},
|
||||
{
|
||||
input: "http://localhost",
|
||||
output: "http://localhost/",
|
||||
},
|
||||
{
|
||||
input: "https://localhost",
|
||||
output: "https://localhost/",
|
||||
},
|
||||
{
|
||||
input: "http://localhost:5000",
|
||||
output: "http://localhost:5000/",
|
||||
},
|
||||
{
|
||||
input: "https://localhost:5000",
|
||||
output: "https://localhost:5000/",
|
||||
},
|
||||
{
|
||||
input: "http://127.0.0.1",
|
||||
output: "http://127.0.0.1/",
|
||||
},
|
||||
{
|
||||
input: "https://127.0.0.1",
|
||||
output: "https://127.0.0.1/",
|
||||
},
|
||||
{
|
||||
input: "http://127.0.0.1:5000",
|
||||
output: "http://127.0.0.1:5000/",
|
||||
},
|
||||
{
|
||||
input: "https://127.0.0.1:5000",
|
||||
output: "https://127.0.0.1:5000/",
|
||||
},
|
||||
{
|
||||
input: "http://mirror-1.example.com/v1/",
|
||||
output: "http://mirror-1.example.com/v1/",
|
||||
},
|
||||
{
|
||||
input: "https://mirror-1.example.com/v1/",
|
||||
output: "https://mirror-1.example.com/v1/",
|
||||
},
|
||||
|
||||
// Invalid cases
|
||||
{
|
||||
input: "!invalid!://%as%",
|
||||
expectedErr: `invalid mirror: "!invalid!://%as%" is not a valid URI: parse "!invalid!://%as%": first path segment in URL cannot contain colon`,
|
||||
},
|
||||
{
|
||||
input: "mirror-1.example.com",
|
||||
expectedErr: `invalid mirror: no scheme specified for "mirror-1.example.com": must use either 'https://' or 'http://'`,
|
||||
},
|
||||
{
|
||||
input: "mirror-1.example.com:5000",
|
||||
expectedErr: `invalid mirror: no scheme specified for "mirror-1.example.com:5000": must use either 'https://' or 'http://'`,
|
||||
},
|
||||
{
|
||||
input: "ftp://mirror-1.example.com",
|
||||
expectedErr: `invalid mirror: unsupported scheme "ftp" in "ftp://mirror-1.example.com": must use either 'https://' or 'http://'`,
|
||||
},
|
||||
{
|
||||
input: "http://mirror-1.example.com/?q=foo",
|
||||
expectedErr: `invalid mirror: query or fragment at end of the URI "http://mirror-1.example.com/?q=foo"`,
|
||||
},
|
||||
{
|
||||
input: "http://mirror-1.example.com/v1/?q=foo",
|
||||
expectedErr: `invalid mirror: query or fragment at end of the URI "http://mirror-1.example.com/v1/?q=foo"`,
|
||||
},
|
||||
{
|
||||
input: "http://mirror-1.example.com/v1/?q=foo#frag",
|
||||
expectedErr: `invalid mirror: query or fragment at end of the URI "http://mirror-1.example.com/v1/?q=foo#frag"`,
|
||||
},
|
||||
{
|
||||
input: "http://mirror-1.example.com?q=foo",
|
||||
expectedErr: `invalid mirror: query or fragment at end of the URI "http://mirror-1.example.com?q=foo"`,
|
||||
},
|
||||
{
|
||||
input: "https://mirror-1.example.com#frag",
|
||||
expectedErr: `invalid mirror: query or fragment at end of the URI "https://mirror-1.example.com#frag"`,
|
||||
},
|
||||
{
|
||||
input: "https://mirror-1.example.com/#frag",
|
||||
expectedErr: `invalid mirror: query or fragment at end of the URI "https://mirror-1.example.com/#frag"`,
|
||||
},
|
||||
{
|
||||
input: "http://foo:bar@mirror-1.example.com/",
|
||||
expectedErr: `invalid mirror: username/password not allowed in URI "http://foo:xxxxx@mirror-1.example.com/"`,
|
||||
},
|
||||
{
|
||||
input: "https://mirror-1.example.com/v1/#frag",
|
||||
expectedErr: `invalid mirror: query or fragment at end of the URI "https://mirror-1.example.com/v1/#frag"`,
|
||||
},
|
||||
{
|
||||
input: "https://mirror-1.example.com?q",
|
||||
expectedErr: `invalid mirror: query or fragment at end of the URI "https://mirror-1.example.com?q"`,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.input, func(t *testing.T) {
|
||||
out, err := ValidateMirror(tc.input)
|
||||
if tc.expectedErr != "" {
|
||||
assert.Error(t, err, tc.expectedErr)
|
||||
} else {
|
||||
assert.NilError(t, err)
|
||||
}
|
||||
assert.Check(t, is.Equal(out, tc.output))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadInsecureRegistries(t *testing.T) {
|
||||
testCases := []struct {
|
||||
registries []string
|
||||
|
|
@ -229,56 +97,6 @@ func TestLoadInsecureRegistries(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestNewServiceConfig(t *testing.T) {
|
||||
tests := []struct {
|
||||
doc string
|
||||
opts ServiceOptions
|
||||
errStr string
|
||||
}{
|
||||
{
|
||||
doc: "empty config",
|
||||
},
|
||||
{
|
||||
doc: "invalid mirror",
|
||||
opts: ServiceOptions{
|
||||
Mirrors: []string{"example.com:5000"},
|
||||
},
|
||||
errStr: `invalid mirror: no scheme specified for "example.com:5000": must use either 'https://' or 'http://'`,
|
||||
},
|
||||
{
|
||||
doc: "valid mirror",
|
||||
opts: ServiceOptions{
|
||||
Mirrors: []string{"https://example.com:5000"},
|
||||
},
|
||||
},
|
||||
{
|
||||
doc: "invalid insecure registry",
|
||||
opts: ServiceOptions{
|
||||
InsecureRegistries: []string{"[fe80::]/64"},
|
||||
},
|
||||
errStr: `insecure registry [fe80::]/64 is not valid: invalid host "[fe80::]/64"`,
|
||||
},
|
||||
{
|
||||
doc: "valid insecure registry",
|
||||
opts: ServiceOptions{
|
||||
InsecureRegistries: []string{"102.10.8.1/24"},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.doc, func(t *testing.T) {
|
||||
_, err := newServiceConfig(tc.opts)
|
||||
if tc.errStr != "" {
|
||||
assert.Check(t, is.Error(err, tc.errStr))
|
||||
assert.Check(t, cerrdefs.IsInvalidArgument(err))
|
||||
} else {
|
||||
assert.Check(t, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidateIndexName(t *testing.T) {
|
||||
valid := []struct {
|
||||
index string
|
||||
|
|
|
|||
|
|
@ -1,8 +1,6 @@
|
|||
package registry
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
"testing"
|
||||
|
||||
"github.com/distribution/reference"
|
||||
|
|
@ -11,46 +9,6 @@ import (
|
|||
is "gotest.tools/v3/assert/cmp"
|
||||
)
|
||||
|
||||
// overrideLookupIP overrides net.LookupIP for testing.
|
||||
func overrideLookupIP(t *testing.T) {
|
||||
t.Helper()
|
||||
restoreLookup := lookupIP
|
||||
|
||||
// override net.LookupIP
|
||||
lookupIP = func(host string) ([]net.IP, error) {
|
||||
mockHosts := map[string][]net.IP{
|
||||
"": {net.ParseIP("0.0.0.0")},
|
||||
"localhost": {net.ParseIP("127.0.0.1"), net.ParseIP("::1")},
|
||||
"example.com": {net.ParseIP("42.42.42.42")},
|
||||
"other.com": {net.ParseIP("43.43.43.43")},
|
||||
}
|
||||
if addrs, ok := mockHosts[host]; ok {
|
||||
return addrs, nil
|
||||
}
|
||||
return nil, errors.New("lookup: no such host")
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
lookupIP = restoreLookup
|
||||
})
|
||||
}
|
||||
|
||||
// newIndexInfo returns IndexInfo configuration from indexName
|
||||
func newIndexInfo(config *serviceConfig, indexName string) *registry.IndexInfo {
|
||||
indexName = normalizeIndexName(indexName)
|
||||
|
||||
// Return any configured index info, first.
|
||||
if index, ok := config.IndexConfigs[indexName]; ok {
|
||||
return index
|
||||
}
|
||||
|
||||
// Construct a non-configured index info.
|
||||
return ®istry.IndexInfo{
|
||||
Name: indexName,
|
||||
Mirrors: []string{},
|
||||
Secure: config.isSecureIndex(indexName),
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseRepositoryInfo(t *testing.T) {
|
||||
type staticRepositoryInfo struct {
|
||||
Index *registry.IndexInfo
|
||||
|
|
@ -63,7 +21,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"fooo/bar": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: IndexName,
|
||||
Mirrors: []string{},
|
||||
Official: true,
|
||||
Secure: true,
|
||||
},
|
||||
|
|
@ -74,7 +31,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"library/ubuntu": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: IndexName,
|
||||
Mirrors: []string{},
|
||||
Official: true,
|
||||
Secure: true,
|
||||
},
|
||||
|
|
@ -85,7 +41,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"nonlibrary/ubuntu": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: IndexName,
|
||||
Mirrors: []string{},
|
||||
Official: true,
|
||||
Secure: true,
|
||||
},
|
||||
|
|
@ -96,7 +51,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"ubuntu": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: IndexName,
|
||||
Mirrors: []string{},
|
||||
Official: true,
|
||||
Secure: true,
|
||||
},
|
||||
|
|
@ -107,7 +61,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"other/library": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: IndexName,
|
||||
Mirrors: []string{},
|
||||
Official: true,
|
||||
Secure: true,
|
||||
},
|
||||
|
|
@ -118,7 +71,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"127.0.0.1:8000/private/moonbase": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: "127.0.0.1:8000",
|
||||
Mirrors: []string{},
|
||||
Official: false,
|
||||
Secure: false,
|
||||
},
|
||||
|
|
@ -129,7 +81,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"127.0.0.1:8000/privatebase": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: "127.0.0.1:8000",
|
||||
Mirrors: []string{},
|
||||
Official: false,
|
||||
Secure: false,
|
||||
},
|
||||
|
|
@ -140,7 +91,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"[::1]:8000/private/moonbase": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: "[::1]:8000",
|
||||
Mirrors: []string{},
|
||||
Official: false,
|
||||
Secure: false,
|
||||
},
|
||||
|
|
@ -151,7 +101,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"[::1]:8000/privatebase": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: "[::1]:8000",
|
||||
Mirrors: []string{},
|
||||
Official: false,
|
||||
Secure: false,
|
||||
},
|
||||
|
|
@ -164,7 +113,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"[::2]:8000/private/moonbase": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: "[::2]:8000",
|
||||
Mirrors: []string{},
|
||||
Official: false,
|
||||
Secure: true,
|
||||
},
|
||||
|
|
@ -177,7 +125,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"[::2]:8000/privatebase": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: "[::2]:8000",
|
||||
Mirrors: []string{},
|
||||
Official: false,
|
||||
Secure: true,
|
||||
},
|
||||
|
|
@ -188,7 +135,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"localhost:8000/private/moonbase": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: "localhost:8000",
|
||||
Mirrors: []string{},
|
||||
Official: false,
|
||||
Secure: false,
|
||||
},
|
||||
|
|
@ -199,7 +145,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"localhost:8000/privatebase": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: "localhost:8000",
|
||||
Mirrors: []string{},
|
||||
Official: false,
|
||||
Secure: false,
|
||||
},
|
||||
|
|
@ -210,7 +155,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"example.com/private/moonbase": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: "example.com",
|
||||
Mirrors: []string{},
|
||||
Official: false,
|
||||
Secure: true,
|
||||
},
|
||||
|
|
@ -221,7 +165,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"example.com/privatebase": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: "example.com",
|
||||
Mirrors: []string{},
|
||||
Official: false,
|
||||
Secure: true,
|
||||
},
|
||||
|
|
@ -232,7 +175,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"example.com:8000/private/moonbase": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: "example.com:8000",
|
||||
Mirrors: []string{},
|
||||
Official: false,
|
||||
Secure: true,
|
||||
},
|
||||
|
|
@ -243,7 +185,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"example.com:8000/privatebase": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: "example.com:8000",
|
||||
Mirrors: []string{},
|
||||
Official: false,
|
||||
Secure: true,
|
||||
},
|
||||
|
|
@ -254,7 +195,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"localhost/private/moonbase": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: "localhost",
|
||||
Mirrors: []string{},
|
||||
Official: false,
|
||||
Secure: false,
|
||||
},
|
||||
|
|
@ -265,7 +205,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"localhost/privatebase": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: "localhost",
|
||||
Mirrors: []string{},
|
||||
Official: false,
|
||||
Secure: false,
|
||||
},
|
||||
|
|
@ -276,7 +215,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
IndexName + "/public/moonbase": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: IndexName,
|
||||
Mirrors: []string{},
|
||||
Official: true,
|
||||
Secure: true,
|
||||
},
|
||||
|
|
@ -287,7 +225,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"index." + IndexName + "/public/moonbase": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: IndexName,
|
||||
Mirrors: []string{},
|
||||
Official: true,
|
||||
Secure: true,
|
||||
},
|
||||
|
|
@ -298,7 +235,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"ubuntu-12.04-base": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: IndexName,
|
||||
Mirrors: []string{},
|
||||
Official: true,
|
||||
Secure: true,
|
||||
},
|
||||
|
|
@ -309,7 +245,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
IndexName + "/ubuntu-12.04-base": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: IndexName,
|
||||
Mirrors: []string{},
|
||||
Official: true,
|
||||
Secure: true,
|
||||
},
|
||||
|
|
@ -320,7 +255,6 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
"index." + IndexName + "/ubuntu-12.04-base": {
|
||||
Index: ®istry.IndexInfo{
|
||||
Name: IndexName,
|
||||
Mirrors: []string{},
|
||||
Official: true,
|
||||
Secure: true,
|
||||
},
|
||||
|
|
@ -345,310 +279,3 @@ func TestParseRepositoryInfo(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewIndexInfo(t *testing.T) {
|
||||
overrideLookupIP(t)
|
||||
|
||||
// ipv6Loopback is the CIDR for the IPv6 loopback address ("::1"); "::1/128"
|
||||
ipv6Loopback := &net.IPNet{
|
||||
IP: net.IPv6loopback,
|
||||
Mask: net.CIDRMask(128, 128),
|
||||
}
|
||||
|
||||
// ipv4Loopback is the CIDR for IPv4 loopback addresses ("127.0.0.0/8")
|
||||
ipv4Loopback := &net.IPNet{
|
||||
IP: net.IPv4(127, 0, 0, 0),
|
||||
Mask: net.CIDRMask(8, 32),
|
||||
}
|
||||
|
||||
// emptyServiceConfig is a default service-config for situations where
|
||||
// no config-file is available (e.g. when used in the CLI). It won't
|
||||
// have mirrors configured, but does have the default insecure registry
|
||||
// CIDRs for loopback interfaces configured.
|
||||
emptyServiceConfig := &serviceConfig{
|
||||
IndexConfigs: map[string]*registry.IndexInfo{
|
||||
IndexName: {
|
||||
Name: IndexName,
|
||||
Mirrors: []string{},
|
||||
Secure: true,
|
||||
Official: true,
|
||||
},
|
||||
},
|
||||
InsecureRegistryCIDRs: []*registry.NetIPNet{
|
||||
(*registry.NetIPNet)(ipv6Loopback),
|
||||
(*registry.NetIPNet)(ipv4Loopback),
|
||||
},
|
||||
}
|
||||
|
||||
expectedIndexInfos := map[string]*registry.IndexInfo{
|
||||
IndexName: {
|
||||
Name: IndexName,
|
||||
Official: true,
|
||||
Secure: true,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
"index." + IndexName: {
|
||||
Name: IndexName,
|
||||
Official: true,
|
||||
Secure: true,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
"example.com": {
|
||||
Name: "example.com",
|
||||
Official: false,
|
||||
Secure: true,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
"127.0.0.1:5000": {
|
||||
Name: "127.0.0.1:5000",
|
||||
Official: false,
|
||||
Secure: false,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
}
|
||||
t.Run("no mirrors", func(t *testing.T) {
|
||||
for indexName, expected := range expectedIndexInfos {
|
||||
t.Run(indexName, func(t *testing.T) {
|
||||
actual := newIndexInfo(emptyServiceConfig, indexName)
|
||||
assert.Check(t, is.DeepEqual(actual, expected))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
expectedIndexInfos = map[string]*registry.IndexInfo{
|
||||
IndexName: {
|
||||
Name: IndexName,
|
||||
Official: true,
|
||||
Secure: true,
|
||||
Mirrors: []string{"http://mirror1.local/", "http://mirror2.local/"},
|
||||
},
|
||||
"index." + IndexName: {
|
||||
Name: IndexName,
|
||||
Official: true,
|
||||
Secure: true,
|
||||
Mirrors: []string{"http://mirror1.local/", "http://mirror2.local/"},
|
||||
},
|
||||
"example.com": {
|
||||
Name: "example.com",
|
||||
Official: false,
|
||||
Secure: false,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
"example.com:5000": {
|
||||
Name: "example.com:5000",
|
||||
Official: false,
|
||||
Secure: true,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
"127.0.0.1": {
|
||||
Name: "127.0.0.1",
|
||||
Official: false,
|
||||
Secure: false,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
"127.0.0.1:5000": {
|
||||
Name: "127.0.0.1:5000",
|
||||
Official: false,
|
||||
Secure: false,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
"127.255.255.255": {
|
||||
Name: "127.255.255.255",
|
||||
Official: false,
|
||||
Secure: false,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
"127.255.255.255:5000": {
|
||||
Name: "127.255.255.255:5000",
|
||||
Official: false,
|
||||
Secure: false,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
"::1": {
|
||||
Name: "::1",
|
||||
Official: false,
|
||||
Secure: false,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
"[::1]:5000": {
|
||||
Name: "[::1]:5000",
|
||||
Official: false,
|
||||
Secure: false,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
// IPv6 only has a single loopback address, so ::2 is not a loopback,
|
||||
// hence not marked "insecure".
|
||||
"::2": {
|
||||
Name: "::2",
|
||||
Official: false,
|
||||
Secure: true,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
// IPv6 only has a single loopback address, so ::2 is not a loopback,
|
||||
// hence not marked "insecure".
|
||||
"[::2]:5000": {
|
||||
Name: "[::2]:5000",
|
||||
Official: false,
|
||||
Secure: true,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
"other.com": {
|
||||
Name: "other.com",
|
||||
Official: false,
|
||||
Secure: true,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
}
|
||||
t.Run("mirrors", func(t *testing.T) {
|
||||
// Note that newServiceConfig calls ValidateMirror internally, which normalizes
|
||||
// mirror-URLs to have a trailing slash.
|
||||
config, err := newServiceConfig(ServiceOptions{
|
||||
Mirrors: []string{"http://mirror1.local", "http://mirror2.local"},
|
||||
InsecureRegistries: []string{"example.com"},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
for indexName, expected := range expectedIndexInfos {
|
||||
t.Run(indexName, func(t *testing.T) {
|
||||
actual := newIndexInfo(config, indexName)
|
||||
assert.Check(t, is.DeepEqual(actual, expected))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
expectedIndexInfos = map[string]*registry.IndexInfo{
|
||||
"example.com": {
|
||||
Name: "example.com",
|
||||
Official: false,
|
||||
Secure: false,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
"example.com:5000": {
|
||||
Name: "example.com:5000",
|
||||
Official: false,
|
||||
Secure: false,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
"127.0.0.1": {
|
||||
Name: "127.0.0.1",
|
||||
Official: false,
|
||||
Secure: false,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
"127.0.0.1:5000": {
|
||||
Name: "127.0.0.1:5000",
|
||||
Official: false,
|
||||
Secure: false,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
"42.42.0.1:5000": {
|
||||
Name: "42.42.0.1:5000",
|
||||
Official: false,
|
||||
Secure: false,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
"42.43.0.1:5000": {
|
||||
Name: "42.43.0.1:5000",
|
||||
Official: false,
|
||||
Secure: true,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
"other.com": {
|
||||
Name: "other.com",
|
||||
Official: false,
|
||||
Secure: true,
|
||||
Mirrors: []string{},
|
||||
},
|
||||
}
|
||||
t.Run("custom insecure", func(t *testing.T) {
|
||||
config, err := newServiceConfig(ServiceOptions{
|
||||
InsecureRegistries: []string{"42.42.0.0/16"},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
for indexName, expected := range expectedIndexInfos {
|
||||
t.Run(indexName, func(t *testing.T) {
|
||||
actual := newIndexInfo(config, indexName)
|
||||
assert.Check(t, is.DeepEqual(actual, expected))
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestMirrorEndpointLookup(t *testing.T) {
|
||||
containsMirror := func(endpoints []APIEndpoint) bool {
|
||||
for _, pe := range endpoints {
|
||||
if pe.URL.Host == "my.mirror" {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
cfg, err := newServiceConfig(ServiceOptions{
|
||||
Mirrors: []string{"https://my.mirror"},
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
s := Service{config: cfg}
|
||||
|
||||
imageName, err := reference.WithName(IndexName + "/test/image")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
pushAPIEndpoints, err := s.LookupPushEndpoints(reference.Domain(imageName))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if containsMirror(pushAPIEndpoints) {
|
||||
t.Fatal("Push endpoint should not contain mirror")
|
||||
}
|
||||
|
||||
pullAPIEndpoints, err := s.LookupPullEndpoints(reference.Domain(imageName))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !containsMirror(pullAPIEndpoints) {
|
||||
t.Fatal("Pull endpoint should contain mirror")
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsSecureIndex(t *testing.T) {
|
||||
overrideLookupIP(t)
|
||||
tests := []struct {
|
||||
addr string
|
||||
insecureRegistries []string
|
||||
expected bool
|
||||
}{
|
||||
{IndexName, nil, true},
|
||||
{"example.com", []string{}, true},
|
||||
{"example.com", []string{"example.com"}, false},
|
||||
{"localhost", []string{"localhost:5000"}, false},
|
||||
{"localhost:5000", []string{"localhost:5000"}, false},
|
||||
{"localhost", []string{"example.com"}, false},
|
||||
{"127.0.0.1:5000", []string{"127.0.0.1:5000"}, false},
|
||||
{"localhost", nil, false},
|
||||
{"localhost:5000", nil, false},
|
||||
{"127.0.0.1", nil, false},
|
||||
{"localhost", []string{"example.com"}, false},
|
||||
{"127.0.0.1", []string{"example.com"}, false},
|
||||
{"example.com", nil, true},
|
||||
{"example.com", []string{"example.com"}, false},
|
||||
{"127.0.0.1", []string{"example.com"}, false},
|
||||
{"127.0.0.1:5000", []string{"example.com"}, false},
|
||||
{"example.com:5000", []string{"42.42.0.0/16"}, false},
|
||||
{"example.com", []string{"42.42.0.0/16"}, false},
|
||||
{"example.com:5000", []string{"42.42.42.42/8"}, false},
|
||||
{"127.0.0.1:5000", []string{"127.0.0.0/8"}, false},
|
||||
{"42.42.42.42:5000", []string{"42.1.1.1/8"}, false},
|
||||
{"invalid.example.com", []string{"42.42.0.0/16"}, true},
|
||||
{"invalid.example.com", []string{"invalid.example.com"}, false},
|
||||
{"invalid.example.com:5000", []string{"invalid.example.com"}, true},
|
||||
{"invalid.example.com:5000", []string{"invalid.example.com:5000"}, false},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
config, err := newServiceConfig(ServiceOptions{
|
||||
InsecureRegistries: tc.insecureRegistries,
|
||||
})
|
||||
assert.NilError(t, err)
|
||||
|
||||
sec := config.isSecureIndex(tc.addr)
|
||||
assert.Equal(t, sec, tc.expected, "isSecureIndex failed for %q %v, expected %v got %v", tc.addr, tc.insecureRegistries, tc.expected, sec)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,12 +21,13 @@ type Service struct {
|
|||
// NewService returns a new instance of [Service] ready to be installed into
|
||||
// an engine.
|
||||
func NewService(options ServiceOptions) (*Service, error) {
|
||||
config, err := newServiceConfig(options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
config := &serviceConfig{}
|
||||
if len(options.InsecureRegistries) > 0 {
|
||||
if err := config.loadInsecureRegistries(options.InsecureRegistries); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &Service{config: config}, err
|
||||
return &Service{config: config}, nil
|
||||
}
|
||||
|
||||
// Auth contacts the public registry with the provided credentials,
|
||||
|
|
@ -48,9 +49,8 @@ func (s *Service) Auth(ctx context.Context, authConfig *registry.AuthConfig, use
|
|||
registryHostName = u.Host
|
||||
}
|
||||
|
||||
// Lookup endpoints for authentication but exclude mirrors to prevent
|
||||
// sending credentials of the upstream registry to a mirror.
|
||||
endpoints, err := s.lookupV2Endpoints(ctx, registryHostName, false)
|
||||
// Lookup endpoints for authentication.
|
||||
endpoints, err := s.lookupV2Endpoints(ctx, registryHostName)
|
||||
if err != nil {
|
||||
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
|
||||
return "", "", err
|
||||
|
|
@ -84,7 +84,6 @@ func (s *Service) Auth(ctx context.Context, authConfig *registry.AuthConfig, use
|
|||
|
||||
// APIEndpoint represents a remote API endpoint
|
||||
type APIEndpoint struct {
|
||||
Mirror bool
|
||||
URL *url.URL
|
||||
TLSConfig *tls.Config
|
||||
}
|
||||
|
|
@ -92,11 +91,11 @@ type APIEndpoint struct {
|
|||
// LookupPullEndpoints creates a list of v2 endpoints to try to pull from, in order of preference.
|
||||
// It gives preference to mirrors over the actual registry, and HTTPS over plain HTTP.
|
||||
func (s *Service) LookupPullEndpoints(hostname string) ([]APIEndpoint, error) {
|
||||
return s.lookupV2Endpoints(context.TODO(), hostname, true)
|
||||
return s.lookupV2Endpoints(context.TODO(), hostname)
|
||||
}
|
||||
|
||||
// LookupPushEndpoints creates a list of v2 endpoints to try to push to, in order of preference.
|
||||
// It gives preference to HTTPS over plain HTTP. Mirrors are not included.
|
||||
func (s *Service) LookupPushEndpoints(hostname string) ([]APIEndpoint, error) {
|
||||
return s.lookupV2Endpoints(context.TODO(), hostname, false)
|
||||
return s.lookupV2Endpoints(context.TODO(), hostname)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,38 +3,13 @@ package registry
|
|||
import (
|
||||
"context"
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"github.com/docker/go-connections/tlsconfig"
|
||||
)
|
||||
|
||||
func (s *Service) lookupV2Endpoints(ctx context.Context, hostname string, includeMirrors bool) ([]APIEndpoint, error) {
|
||||
func (s *Service) lookupV2Endpoints(ctx context.Context, hostname string) ([]APIEndpoint, error) {
|
||||
var endpoints []APIEndpoint
|
||||
if hostname == DefaultNamespace || hostname == IndexHostname {
|
||||
if includeMirrors {
|
||||
for _, mirror := range s.config.Mirrors {
|
||||
if ctx.Err() != nil {
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
if !strings.HasPrefix(mirror, "http://") && !strings.HasPrefix(mirror, "https://") {
|
||||
mirror = "https://" + mirror
|
||||
}
|
||||
mirrorURL, err := url.Parse(mirror)
|
||||
if err != nil {
|
||||
return nil, invalidParam(err)
|
||||
}
|
||||
// TODO(thaJeztah); this should all be memoized when loading the config. We're resolving mirrors and loading TLS config every time.
|
||||
mirrorTLSConfig, err := newTLSConfig(ctx, mirrorURL.Host, s.config.isSecureIndex(mirrorURL.Host))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
endpoints = append(endpoints, APIEndpoint{
|
||||
URL: mirrorURL,
|
||||
Mirror: true,
|
||||
TLSConfig: mirrorTLSConfig,
|
||||
})
|
||||
}
|
||||
}
|
||||
endpoints = append(endpoints, APIEndpoint{
|
||||
URL: DefaultV2Registry,
|
||||
TLSConfig: tlsconfig.ServerDefault(),
|
||||
|
|
|
|||
Loading…
Reference in New Issue