diff --git a/internal/registry/config.go b/internal/registry/config.go index dac5e7fd6c..78a2e8f520 100644 --- a/internal/registry/config.go +++ b/internal/registry/config.go @@ -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 } diff --git a/internal/registry/config_test.go b/internal/registry/config_test.go index 699e763be6..f3d8b4c44a 100644 --- a/internal/registry/config_test.go +++ b/internal/registry/config_test.go @@ -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 diff --git a/internal/registry/registry_test.go b/internal/registry/registry_test.go index 94d05eb472..f0b061b23f 100644 --- a/internal/registry/registry_test.go +++ b/internal/registry/registry_test.go @@ -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) - } -} diff --git a/internal/registry/service.go b/internal/registry/service.go index 0b6052cb5e..9e1accc04c 100644 --- a/internal/registry/service.go +++ b/internal/registry/service.go @@ -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) } diff --git a/internal/registry/service_v2.go b/internal/registry/service_v2.go index df343a155d..0f00595330 100644 --- a/internal/registry/service_v2.go +++ b/internal/registry/service_v2.go @@ -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(),