Browse code

Move registry service options to the daemon configuration.

Allowing to set their values in the daemon configuration file.

Signed-off-by: David Calavera <david.calavera@gmail.com>

David Calavera authored on 2016/03/09 06:03:37
Showing 11 changed files
... ...
@@ -13,6 +13,7 @@ import (
13 13
 	"github.com/docker/docker/opts"
14 14
 	"github.com/docker/docker/pkg/discovery"
15 15
 	flag "github.com/docker/docker/pkg/mflag"
16
+	"github.com/docker/docker/registry"
16 17
 	"github.com/imdario/mergo"
17 18
 )
18 19
 
... ...
@@ -96,6 +97,7 @@ type CommonConfig struct {
96 96
 	CommonTLSOptions
97 97
 	LogConfig
98 98
 	bridgeConfig // bridgeConfig holds bridge network specific configuration.
99
+	registry.ServiceOptions
99 100
 
100 101
 	reloadLock sync.Mutex
101 102
 	valuesSet  map[string]interface{}
... ...
@@ -106,6 +108,8 @@ type CommonConfig struct {
106 106
 // Subsequent calls to `flag.Parse` will populate config with values parsed
107 107
 // from the command-line.
108 108
 func (config *Config) InstallCommonFlags(cmd *flag.FlagSet, usageFn func(string) string) {
109
+	config.ServiceOptions.InstallCliFlags(cmd, usageFn)
110
+
109 111
 	cmd.Var(opts.NewNamedListOptsRef("storage-opts", &config.GraphOptions, nil), []string{"-storage-opt"}, usageFn("Set storage driver options"))
110 112
 	cmd.Var(opts.NewNamedListOptsRef("authorization-plugins", &config.AuthorizationPlugins, nil), []string{"-authorization-plugin"}, usageFn("List authorization plugins in order from first evaluator to last"))
111 113
 	cmd.Var(opts.NewNamedListOptsRef("exec-opts", &config.ExecOptions, nil), []string{"-exec-opt"}, usageFn("Set exec driver options"))
... ...
@@ -90,7 +90,7 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
90 90
 		IndexServerAddress: registry.IndexServer,
91 91
 		OSType:             platform.OSType,
92 92
 		Architecture:       platform.Architecture,
93
-		RegistryConfig:     daemon.RegistryService.Config,
93
+		RegistryConfig:     daemon.RegistryService.ServiceConfig(),
94 94
 		NCPU:               runtime.NumCPU(),
95 95
 		MemTotal:           meminfo.MemTotal,
96 96
 		DockerRootDir:      daemon.configStore.Root,
... ...
@@ -8,6 +8,7 @@ import (
8 8
 	"io"
9 9
 	"os"
10 10
 	"path/filepath"
11
+	"runtime"
11 12
 	"strings"
12 13
 	"time"
13 14
 
... ...
@@ -51,8 +52,7 @@ var (
51 51
 // DaemonCli represents the daemon CLI.
52 52
 type DaemonCli struct {
53 53
 	*daemon.Config
54
-	registryOptions *registry.Options
55
-	flags           *flag.FlagSet
54
+	flags *flag.FlagSet
56 55
 }
57 56
 
58 57
 func presentInHelp(usage string) string { return usage }
... ...
@@ -67,17 +67,17 @@ func NewDaemonCli() *DaemonCli {
67 67
 	daemonConfig.LogConfig.Config = make(map[string]string)
68 68
 	daemonConfig.ClusterOpts = make(map[string]string)
69 69
 
70
+	if runtime.GOOS != "linux" {
71
+		daemonConfig.V2Only = true
72
+	}
73
+
70 74
 	daemonConfig.InstallFlags(daemonFlags, presentInHelp)
71 75
 	daemonConfig.InstallFlags(flag.CommandLine, absentFromHelp)
72
-	registryOptions := new(registry.Options)
73
-	registryOptions.InstallFlags(daemonFlags, presentInHelp)
74
-	registryOptions.InstallFlags(flag.CommandLine, absentFromHelp)
75 76
 	daemonFlags.Require(flag.Exact, 0)
76 77
 
77 78
 	return &DaemonCli{
78
-		Config:          daemonConfig,
79
-		registryOptions: registryOptions,
80
-		flags:           daemonFlags,
79
+		Config: daemonConfig,
80
+		flags:  daemonFlags,
81 81
 	}
82 82
 }
83 83
 
... ...
@@ -263,7 +263,7 @@ func (cli *DaemonCli) CmdDaemon(args ...string) error {
263 263
 	}
264 264
 	cli.TrustKeyPath = commonFlags.TrustKey
265 265
 
266
-	registryService := registry.NewService(cli.registryOptions)
266
+	registryService := registry.NewService(cli.Config.ServiceOptions)
267 267
 	d, err := daemon.NewDaemon(cli.Config, registryService)
268 268
 	if err != nil {
269 269
 		if pfile != nil {
... ...
@@ -4,6 +4,7 @@ package main
4 4
 
5 5
 import (
6 6
 	"io/ioutil"
7
+	"os"
7 8
 	"strings"
8 9
 	"testing"
9 10
 
... ...
@@ -63,8 +64,9 @@ func TestLoadDaemonCliConfigWithConflicts(t *testing.T) {
63 63
 	if err != nil {
64 64
 		t.Fatal(err)
65 65
 	}
66
-
67 66
 	configFile := f.Name()
67
+	defer os.Remove(configFile)
68
+
68 69
 	f.Write([]byte(`{"labels": ["l3=foo"]}`))
69 70
 	f.Close()
70 71
 
... ...
@@ -103,8 +105,9 @@ func TestLoadDaemonCliConfigWithTLSVerify(t *testing.T) {
103 103
 	if err != nil {
104 104
 		t.Fatal(err)
105 105
 	}
106
-
107 106
 	configFile := f.Name()
107
+	defer os.Remove(configFile)
108
+
108 109
 	f.Write([]byte(`{"tlsverify": true}`))
109 110
 	f.Close()
110 111
 
... ...
@@ -135,8 +138,9 @@ func TestLoadDaemonCliConfigWithExplicitTLSVerifyFalse(t *testing.T) {
135 135
 	if err != nil {
136 136
 		t.Fatal(err)
137 137
 	}
138
-
139 138
 	configFile := f.Name()
139
+	defer os.Remove(configFile)
140
+
140 141
 	f.Write([]byte(`{"tlsverify": false}`))
141 142
 	f.Close()
142 143
 
... ...
@@ -167,8 +171,9 @@ func TestLoadDaemonCliConfigWithoutTLSVerify(t *testing.T) {
167 167
 	if err != nil {
168 168
 		t.Fatal(err)
169 169
 	}
170
-
171 170
 	configFile := f.Name()
171
+	defer os.Remove(configFile)
172
+
172 173
 	f.Write([]byte(`{}`))
173 174
 	f.Close()
174 175
 
... ...
@@ -194,8 +199,9 @@ func TestLoadDaemonCliConfigWithLogLevel(t *testing.T) {
194 194
 	if err != nil {
195 195
 		t.Fatal(err)
196 196
 	}
197
-
198 197
 	configFile := f.Name()
198
+	defer os.Remove(configFile)
199
+
199 200
 	f.Write([]byte(`{"log-level": "warn"}`))
200 201
 	f.Close()
201 202
 
... ...
@@ -220,6 +226,7 @@ func TestLoadDaemonCliConfigWithLogLevel(t *testing.T) {
220 220
 func TestLoadDaemonConfigWithEmbeddedOptions(t *testing.T) {
221 221
 	c := &daemon.Config{}
222 222
 	common := &cli.CommonFlags{}
223
+
223 224
 	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
224 225
 	flags.String([]string{"-tlscacert"}, "", "")
225 226
 	flags.String([]string{"-log-driver"}, "", "")
... ...
@@ -228,8 +235,9 @@ func TestLoadDaemonConfigWithEmbeddedOptions(t *testing.T) {
228 228
 	if err != nil {
229 229
 		t.Fatal(err)
230 230
 	}
231
-
232 231
 	configFile := f.Name()
232
+	defer os.Remove(configFile)
233
+
233 234
 	f.Write([]byte(`{"tlscacert": "/etc/certs/ca.pem", "log-driver": "syslog"}`))
234 235
 	f.Close()
235 236
 
... ...
@@ -247,3 +255,42 @@ func TestLoadDaemonConfigWithEmbeddedOptions(t *testing.T) {
247 247
 		t.Fatalf("expected LogConfig type syslog, got %v", loadedConfig.LogConfig.Type)
248 248
 	}
249 249
 }
250
+
251
+func TestLoadDaemonConfigWithRegistryOptions(t *testing.T) {
252
+	c := &daemon.Config{}
253
+	common := &cli.CommonFlags{}
254
+	flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
255
+	c.ServiceOptions.InstallCliFlags(flags, absentFromHelp)
256
+
257
+	f, err := ioutil.TempFile("", "docker-config-")
258
+	if err != nil {
259
+		t.Fatal(err)
260
+	}
261
+	configFile := f.Name()
262
+	defer os.Remove(configFile)
263
+
264
+	f.Write([]byte(`{"registry-mirrors": ["https://mirrors.docker.com"], "insecure-registries": ["https://insecure.docker.com"], "disable-legacy-registry": true}`))
265
+	f.Close()
266
+
267
+	loadedConfig, err := loadDaemonCliConfig(c, flags, common, configFile)
268
+	if err != nil {
269
+		t.Fatal(err)
270
+	}
271
+	if loadedConfig == nil {
272
+		t.Fatal("expected configuration, got nil")
273
+	}
274
+
275
+	m := loadedConfig.Mirrors
276
+	if len(m) != 1 {
277
+		t.Fatalf("expected 1 mirror, got %d", len(m))
278
+	}
279
+
280
+	r := loadedConfig.InsecureRegistries
281
+	if len(r) != 1 {
282
+		t.Fatalf("expected 1 insecure registries, got %d", len(r))
283
+	}
284
+
285
+	if !loadedConfig.V2Only {
286
+		t.Fatal("expected disable-legacy-registry to be true, got false")
287
+	}
288
+}
... ...
@@ -883,7 +883,10 @@ This is a full example of the allowed configuration options in the file:
883 883
 	"default-gateway": "",
884 884
 	"default-gateway-v6": "",
885 885
 	"icc": false,
886
-	"raw-logs": false
886
+	"raw-logs": false,
887
+	"registry-mirrors": [],
888
+	"insecure-registries": [],
889
+	"disable-legacy-registry": false
887 890
 }
888 891
 ```
889 892
 
... ...
@@ -13,10 +13,20 @@ import (
13 13
 	registrytypes "github.com/docker/engine-api/types/registry"
14 14
 )
15 15
 
16
-// Options holds command line options.
17
-type Options struct {
18
-	Mirrors            opts.ListOpts
19
-	InsecureRegistries opts.ListOpts
16
+// ServiceOptions holds command line options.
17
+type ServiceOptions struct {
18
+	Mirrors            []string `json:"registry-mirrors,omitempty"`
19
+	InsecureRegistries []string `json:"insecure-registries,omitempty"`
20
+
21
+	// V2Only controls access to legacy registries.  If it is set to true via the
22
+	// command line flag the daemon will not attempt to contact v1 legacy registries
23
+	V2Only bool `json:"disable-legacy-registry,omitempty"`
24
+}
25
+
26
+// serviceConfig holds daemon configuration for the registry service.
27
+type serviceConfig struct {
28
+	registrytypes.ServiceConfig
29
+	V2Only bool
20 30
 }
21 31
 
22 32
 var (
... ...
@@ -42,51 +52,45 @@ var (
42 42
 	// not have the correct form
43 43
 	ErrInvalidRepositoryName = errors.New("Invalid repository name (ex: \"registry.domain.tld/myrepos\")")
44 44
 
45
-	emptyServiceConfig = NewServiceConfig(nil)
46
-
47
-	// V2Only controls access to legacy registries.  If it is set to true via the
48
-	// command line flag the daemon will not attempt to contact v1 legacy registries
49
-	V2Only = false
45
+	emptyServiceConfig = newServiceConfig(ServiceOptions{})
50 46
 )
51 47
 
52 48
 // for mocking in unit tests
53 49
 var lookupIP = net.LookupIP
54 50
 
55
-// InstallFlags adds command-line options to the top-level flag parser for
51
+// InstallCliFlags adds command-line options to the top-level flag parser for
56 52
 // the current process.
57
-func (options *Options) InstallFlags(cmd *flag.FlagSet, usageFn func(string) string) {
58
-	options.Mirrors = opts.NewListOpts(ValidateMirror)
59
-	cmd.Var(&options.Mirrors, []string{"-registry-mirror"}, usageFn("Preferred Docker registry mirror"))
60
-	options.InsecureRegistries = opts.NewListOpts(ValidateIndexName)
61
-	cmd.Var(&options.InsecureRegistries, []string{"-insecure-registry"}, usageFn("Enable insecure registry communication"))
62
-	cmd.BoolVar(&V2Only, []string{"-disable-legacy-registry"}, false, usageFn("Do not contact legacy registries"))
63
-}
53
+func (options *ServiceOptions) InstallCliFlags(cmd *flag.FlagSet, usageFn func(string) string) {
54
+	mirrors := opts.NewNamedListOptsRef("registry-mirrors", &options.Mirrors, ValidateMirror)
55
+	cmd.Var(mirrors, []string{"-registry-mirror"}, usageFn("Preferred Docker registry mirror"))
64 56
 
65
-// NewServiceConfig returns a new instance of ServiceConfig
66
-func NewServiceConfig(options *Options) *registrytypes.ServiceConfig {
67
-	if options == nil {
68
-		options = &Options{
69
-			Mirrors:            opts.NewListOpts(nil),
70
-			InsecureRegistries: opts.NewListOpts(nil),
71
-		}
72
-	}
57
+	insecureRegistries := opts.NewNamedListOptsRef("insecure-registries", &options.InsecureRegistries, ValidateIndexName)
58
+	cmd.Var(insecureRegistries, []string{"-insecure-registry"}, usageFn("Enable insecure registry communication"))
59
+
60
+	cmd.BoolVar(&options.V2Only, []string{"-disable-legacy-registry"}, false, usageFn("Do not contact legacy registries"))
61
+}
73 62
 
63
+// newServiceConfig returns a new instance of ServiceConfig
64
+func newServiceConfig(options ServiceOptions) *serviceConfig {
74 65
 	// Localhost is by default considered as an insecure registry
75 66
 	// This is a stop-gap for people who are running a private registry on localhost (especially on Boot2docker).
76 67
 	//
77 68
 	// TODO: should we deprecate this once it is easier for people to set up a TLS registry or change
78 69
 	// daemon flags on boot2docker?
79
-	options.InsecureRegistries.Set("127.0.0.0/8")
80
-
81
-	config := &registrytypes.ServiceConfig{
82
-		InsecureRegistryCIDRs: make([]*registrytypes.NetIPNet, 0),
83
-		IndexConfigs:          make(map[string]*registrytypes.IndexInfo, 0),
84
-		// Hack: Bypass setting the mirrors to IndexConfigs since they are going away
85
-		// and Mirrors are only for the official registry anyways.
86
-		Mirrors: options.Mirrors.GetAll(),
70
+	options.InsecureRegistries = append(options.InsecureRegistries, "127.0.0.0/8")
71
+
72
+	config := &serviceConfig{
73
+		ServiceConfig: registrytypes.ServiceConfig{
74
+			InsecureRegistryCIDRs: make([]*registrytypes.NetIPNet, 0),
75
+			IndexConfigs:          make(map[string]*registrytypes.IndexInfo, 0),
76
+			// Hack: Bypass setting the mirrors to IndexConfigs since they are going away
77
+			// and Mirrors are only for the official registry anyways.
78
+			Mirrors: options.Mirrors,
79
+		},
80
+		V2Only: options.V2Only,
87 81
 	}
88 82
 	// Split --insecure-registry into CIDR and registry-specific settings.
89
-	for _, r := range options.InsecureRegistries.GetAll() {
83
+	for _, r := range options.InsecureRegistries {
90 84
 		// Check if CIDR was passed to --insecure-registry
91 85
 		_, ipnet, err := net.ParseCIDR(r)
92 86
 		if err == nil {
... ...
@@ -125,7 +129,7 @@ func NewServiceConfig(options *Options) *registrytypes.ServiceConfig {
125 125
 // or an IP address. If it is a domain name, then it will be resolved in order to check if the IP is contained
126 126
 // in a subnet. If the resolving is not successful, isSecureIndex will only try to match hostname to any element
127 127
 // of insecureRegistries.
128
-func isSecureIndex(config *registrytypes.ServiceConfig, indexName string) bool {
128
+func isSecureIndex(config *serviceConfig, indexName string) bool {
129 129
 	// Check for configured index, first.  This is needed in case isSecureIndex
130 130
 	// is called from anything besides newIndexInfo, in order to honor per-index configurations.
131 131
 	if index, ok := config.IndexConfigs[indexName]; ok {
... ...
@@ -201,7 +205,7 @@ func validateNoSchema(reposName string) error {
201 201
 }
202 202
 
203 203
 // newIndexInfo returns IndexInfo configuration from indexName
204
-func newIndexInfo(config *registrytypes.ServiceConfig, indexName string) (*registrytypes.IndexInfo, error) {
204
+func newIndexInfo(config *serviceConfig, indexName string) (*registrytypes.IndexInfo, error) {
205 205
 	var err error
206 206
 	indexName, err = ValidateIndexName(indexName)
207 207
 	if err != nil {
... ...
@@ -233,7 +237,7 @@ func GetAuthConfigKey(index *registrytypes.IndexInfo) string {
233 233
 }
234 234
 
235 235
 // newRepositoryInfo validates and breaks down a repository name into a RepositoryInfo
236
-func newRepositoryInfo(config *registrytypes.ServiceConfig, name reference.Named) (*RepositoryInfo, error) {
236
+func newRepositoryInfo(config *serviceConfig, name reference.Named) (*RepositoryInfo, error) {
237 237
 	index, err := newIndexInfo(config, name.Hostname())
238 238
 	if err != nil {
239 239
 		return nil, err
... ...
@@ -11,7 +11,6 @@ import (
11 11
 	"net/http"
12 12
 	"os"
13 13
 	"path/filepath"
14
-	"runtime"
15 14
 	"strings"
16 15
 	"time"
17 16
 
... ...
@@ -26,12 +25,6 @@ var (
26 26
 	ErrAlreadyExists = errors.New("Image already exists")
27 27
 )
28 28
 
29
-func init() {
30
-	if runtime.GOOS != "linux" {
31
-		V2Only = true
32
-	}
33
-}
34
-
35 29
 func newTLSConfig(hostname string, isSecure bool) (*tls.Config, error) {
36 30
 	// PreferredServerCipherSuites should have no effect
37 31
 	tlsConfig := tlsconfig.ServerDefault
... ...
@@ -15,7 +15,6 @@ import (
15 15
 	"testing"
16 16
 	"time"
17 17
 
18
-	"github.com/docker/docker/opts"
19 18
 	"github.com/docker/docker/reference"
20 19
 	registrytypes "github.com/docker/engine-api/types/registry"
21 20
 	"github.com/gorilla/mux"
... ...
@@ -174,23 +173,13 @@ func makePublicIndex() *registrytypes.IndexInfo {
174 174
 	return index
175 175
 }
176 176
 
177
-func makeServiceConfig(mirrors []string, insecureRegistries []string) *registrytypes.ServiceConfig {
178
-	options := &Options{
179
-		Mirrors:            opts.NewListOpts(nil),
180
-		InsecureRegistries: opts.NewListOpts(nil),
181
-	}
182
-	if mirrors != nil {
183
-		for _, mirror := range mirrors {
184
-			options.Mirrors.Set(mirror)
185
-		}
186
-	}
187
-	if insecureRegistries != nil {
188
-		for _, insecureRegistries := range insecureRegistries {
189
-			options.InsecureRegistries.Set(insecureRegistries)
190
-		}
177
+func makeServiceConfig(mirrors []string, insecureRegistries []string) *serviceConfig {
178
+	options := ServiceOptions{
179
+		Mirrors:            mirrors,
180
+		InsecureRegistries: insecureRegistries,
191 181
 	}
192 182
 
193
-	return NewServiceConfig(options)
183
+	return newServiceConfig(options)
194 184
 }
195 185
 
196 186
 func writeHeaders(w http.ResponseWriter) {
... ...
@@ -523,7 +523,7 @@ func TestParseRepositoryInfo(t *testing.T) {
523 523
 }
524 524
 
525 525
 func TestNewIndexInfo(t *testing.T) {
526
-	testIndexInfo := func(config *registrytypes.ServiceConfig, expectedIndexInfos map[string]*registrytypes.IndexInfo) {
526
+	testIndexInfo := func(config *serviceConfig, expectedIndexInfos map[string]*registrytypes.IndexInfo) {
527 527
 		for indexName, expectedIndexInfo := range expectedIndexInfos {
528 528
 			index, err := newIndexInfo(config, indexName)
529 529
 			if err != nil {
... ...
@@ -537,7 +537,7 @@ func TestNewIndexInfo(t *testing.T) {
537 537
 		}
538 538
 	}
539 539
 
540
-	config := NewServiceConfig(nil)
540
+	config := newServiceConfig(ServiceOptions{})
541 541
 	noMirrors := []string{}
542 542
 	expectedIndexInfos := map[string]*registrytypes.IndexInfo{
543 543
 		IndexName: {
... ...
@@ -661,7 +661,7 @@ func TestMirrorEndpointLookup(t *testing.T) {
661 661
 		}
662 662
 		return false
663 663
 	}
664
-	s := Service{Config: makeServiceConfig([]string{"my.mirror"}, nil)}
664
+	s := Service{config: makeServiceConfig([]string{"my.mirror"}, nil)}
665 665
 
666 666
 	imageName, err := reference.WithName(IndexName + "/test/image")
667 667
 	if err != nil {
... ...
@@ -15,17 +15,22 @@ import (
15 15
 // Service is a registry service. It tracks configuration data such as a list
16 16
 // of mirrors.
17 17
 type Service struct {
18
-	Config *registrytypes.ServiceConfig
18
+	config *serviceConfig
19 19
 }
20 20
 
21 21
 // NewService returns a new instance of Service ready to be
22 22
 // installed into an engine.
23
-func NewService(options *Options) *Service {
23
+func NewService(options ServiceOptions) *Service {
24 24
 	return &Service{
25
-		Config: NewServiceConfig(options),
25
+		config: newServiceConfig(options),
26 26
 	}
27 27
 }
28 28
 
29
+// ServiceConfig returns the public registry service configuration.
30
+func (s *Service) ServiceConfig() *registrytypes.ServiceConfig {
31
+	return &s.config.ServiceConfig
32
+}
33
+
29 34
 // Auth contacts the public registry with the provided credentials,
30 35
 // and returns OK if authentication was successful.
31 36
 // It can be used to verify the validity of a client's credentials.
... ...
@@ -82,7 +87,7 @@ func (s *Service) Search(term string, authConfig *types.AuthConfig, userAgent st
82 82
 
83 83
 	indexName, remoteName := splitReposSearchTerm(term)
84 84
 
85
-	index, err := newIndexInfo(s.Config, indexName)
85
+	index, err := newIndexInfo(s.config, indexName)
86 86
 	if err != nil {
87 87
 		return nil, err
88 88
 	}
... ...
@@ -113,12 +118,12 @@ func (s *Service) Search(term string, authConfig *types.AuthConfig, userAgent st
113 113
 // ResolveRepository splits a repository name into its components
114 114
 // and configuration of the associated registry.
115 115
 func (s *Service) ResolveRepository(name reference.Named) (*RepositoryInfo, error) {
116
-	return newRepositoryInfo(s.Config, name)
116
+	return newRepositoryInfo(s.config, name)
117 117
 }
118 118
 
119 119
 // ResolveIndex takes indexName and returns index info
120 120
 func (s *Service) ResolveIndex(name string) (*registrytypes.IndexInfo, error) {
121
-	return newIndexInfo(s.Config, name)
121
+	return newIndexInfo(s.config, name)
122 122
 }
123 123
 
124 124
 // APIEndpoint represents a remote API endpoint
... ...
@@ -138,7 +143,7 @@ func (e APIEndpoint) ToV1Endpoint(userAgent string, metaHeaders http.Header) (*V
138 138
 
139 139
 // TLSConfig constructs a client TLS configuration based on server defaults
140 140
 func (s *Service) TLSConfig(hostname string) (*tls.Config, error) {
141
-	return newTLSConfig(hostname, isSecureIndex(s.Config, hostname))
141
+	return newTLSConfig(hostname, isSecureIndex(s.config, hostname))
142 142
 }
143 143
 
144 144
 func (s *Service) tlsConfigForMirror(mirrorURL *url.URL) (*tls.Config, error) {
... ...
@@ -173,7 +178,7 @@ func (s *Service) lookupEndpoints(hostname string) (endpoints []APIEndpoint, err
173 173
 		return nil, err
174 174
 	}
175 175
 
176
-	if V2Only {
176
+	if s.config.V2Only {
177 177
 		return endpoints, nil
178 178
 	}
179 179
 
... ...
@@ -12,7 +12,7 @@ func (s *Service) lookupV2Endpoints(hostname string) (endpoints []APIEndpoint, e
12 12
 	tlsConfig := &cfg
13 13
 	if hostname == DefaultNamespace {
14 14
 		// v2 mirrors
15
-		for _, mirror := range s.Config.Mirrors {
15
+		for _, mirror := range s.config.Mirrors {
16 16
 			if !strings.HasPrefix(mirror, "http://") && !strings.HasPrefix(mirror, "https://") {
17 17
 				mirror = "https://" + mirror
18 18
 			}