mirror of
				https://github.com/moby/moby.git
				synced 2022-11-09 12:21:53 -05:00 
			
		
		
		
	support registry mirror config reload
Signed-off-by: allencloud <allen.sun@daocloud.io>
This commit is contained in:
		
							parent
							
								
									355f2ae972
								
							
						
					
					
						commit
						5b9348c553
					
				
					 8 changed files with 174 additions and 18 deletions
				
			
		| 
						 | 
				
			
			@ -995,14 +995,15 @@ func (daemon *Daemon) initDiscovery(config *Config) error {
 | 
			
		|||
// Reload reads configuration changes and modifies the
 | 
			
		||||
// daemon according to those changes.
 | 
			
		||||
// These are the settings that Reload changes:
 | 
			
		||||
// - Daemon labels.
 | 
			
		||||
// - Daemon debug log level.
 | 
			
		||||
// - Daemon insecure registries.
 | 
			
		||||
// - Daemon labels
 | 
			
		||||
// - Daemon debug log level
 | 
			
		||||
// - Insecure registries
 | 
			
		||||
// - Registry mirrors
 | 
			
		||||
// - Daemon max concurrent downloads
 | 
			
		||||
// - Daemon max concurrent uploads
 | 
			
		||||
// - Cluster discovery (reconfigure and restart).
 | 
			
		||||
// - Cluster discovery (reconfigure and restart)
 | 
			
		||||
// - Daemon live restore
 | 
			
		||||
// - Daemon shutdown timeout (in seconds).
 | 
			
		||||
// - Daemon shutdown timeout (in seconds)
 | 
			
		||||
func (daemon *Daemon) Reload(config *Config) (err error) {
 | 
			
		||||
 | 
			
		||||
	daemon.configStore.reloadLock.Lock()
 | 
			
		||||
| 
						 | 
				
			
			@ -1035,6 +1036,14 @@ func (daemon *Daemon) Reload(config *Config) (err error) {
 | 
			
		|||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if config.IsValueSet("registry-mirrors") {
 | 
			
		||||
		daemon.configStore.Mirrors = config.Mirrors
 | 
			
		||||
		if err := daemon.RegistryService.LoadMirrors(config.Mirrors); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if config.IsValueSet("live-restore") {
 | 
			
		||||
		daemon.configStore.LiveRestoreEnabled = config.LiveRestoreEnabled
 | 
			
		||||
		if err := daemon.containerdRemote.UpdateOptions(libcontainerd.WithLiveRestore(config.LiveRestoreEnabled)); err != nil {
 | 
			
		||||
| 
						 | 
				
			
			@ -1087,6 +1096,16 @@ func (daemon *Daemon) Reload(config *Config) (err error) {
 | 
			
		|||
		attributes["insecure-registries"] = "[]"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if daemon.configStore.Mirrors != nil {
 | 
			
		||||
		mirrors, err := json.Marshal(daemon.configStore.Mirrors)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		attributes["registry-mirrors"] = string(mirrors)
 | 
			
		||||
	} else {
 | 
			
		||||
		attributes["registry-mirrors"] = "[]"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	attributes["cluster-store"] = daemon.configStore.ClusterStore
 | 
			
		||||
	if daemon.configStore.ClusterOpts != nil {
 | 
			
		||||
		opts, err := json.Marshal(daemon.configStore.ClusterOpts)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -341,6 +341,100 @@ func TestDaemonReloadLabels(t *testing.T) {
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDaemonReloadMirrors(t *testing.T) {
 | 
			
		||||
	daemon := &Daemon{}
 | 
			
		||||
 | 
			
		||||
	daemon.RegistryService = registry.NewService(registry.ServiceOptions{
 | 
			
		||||
		InsecureRegistries: []string{},
 | 
			
		||||
		Mirrors: []string{
 | 
			
		||||
			"https://mirror.test1.com",
 | 
			
		||||
			"https://mirror.test2.com", // this will be removed when reloading
 | 
			
		||||
			"https://mirror.test3.com", // this will be removed when reloading
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	daemon.configStore = &Config{}
 | 
			
		||||
 | 
			
		||||
	type pair struct {
 | 
			
		||||
		valid   bool
 | 
			
		||||
		mirrors []string
 | 
			
		||||
		after   []string
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	loadMirrors := []pair{
 | 
			
		||||
		{
 | 
			
		||||
			valid:   false,
 | 
			
		||||
			mirrors: []string{"10.10.1.11:5000"}, // this mirror is invalid
 | 
			
		||||
			after:   []string{},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			valid:   false,
 | 
			
		||||
			mirrors: []string{"mirror.test1.com"}, // this mirror is invalid
 | 
			
		||||
			after:   []string{},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			valid:   false,
 | 
			
		||||
			mirrors: []string{"10.10.1.11:5000", "mirror.test1.com"}, // mirrors are invalid
 | 
			
		||||
			after:   []string{},
 | 
			
		||||
		},
 | 
			
		||||
		{
 | 
			
		||||
			valid:   true,
 | 
			
		||||
			mirrors: []string{"https://mirror.test1.com", "https://mirror.test4.com"},
 | 
			
		||||
			after:   []string{"https://mirror.test1.com/", "https://mirror.test4.com/"},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, value := range loadMirrors {
 | 
			
		||||
		valuesSets := make(map[string]interface{})
 | 
			
		||||
		valuesSets["registry-mirrors"] = value.mirrors
 | 
			
		||||
 | 
			
		||||
		newConfig := &Config{
 | 
			
		||||
			CommonConfig: CommonConfig{
 | 
			
		||||
				ServiceOptions: registry.ServiceOptions{
 | 
			
		||||
					Mirrors: value.mirrors,
 | 
			
		||||
				},
 | 
			
		||||
				valuesSet: valuesSets,
 | 
			
		||||
			},
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		err := daemon.Reload(newConfig)
 | 
			
		||||
		if !value.valid && err == nil {
 | 
			
		||||
			// mirrors should be invalid, should be a non-nil error
 | 
			
		||||
			t.Fatalf("Expected daemon reload error with invalid mirrors: %s, while get nil", value.mirrors)
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if value.valid {
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				// mirrors should be valid, should be no error
 | 
			
		||||
				t.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
			registryService := daemon.RegistryService.ServiceConfig()
 | 
			
		||||
 | 
			
		||||
			if len(registryService.Mirrors) != len(value.after) {
 | 
			
		||||
				t.Fatalf("Expected %d daemon mirrors %s while get %d with %s",
 | 
			
		||||
					len(value.after),
 | 
			
		||||
					value.after,
 | 
			
		||||
					len(registryService.Mirrors),
 | 
			
		||||
					registryService.Mirrors)
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			dataMap := map[string]struct{}{}
 | 
			
		||||
 | 
			
		||||
			for _, mirror := range registryService.Mirrors {
 | 
			
		||||
				if _, exist := dataMap[mirror]; !exist {
 | 
			
		||||
					dataMap[mirror] = struct{}{}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			for _, address := range value.after {
 | 
			
		||||
				if _, exist := dataMap[address]; !exist {
 | 
			
		||||
					t.Fatalf("Expected %s in daemon mirrors, while get none", address)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func TestDaemonReloadInsecureRegistries(t *testing.T) {
 | 
			
		||||
	daemon := &Daemon{}
 | 
			
		||||
	// initialize daemon with existing insecure registries: "127.0.0.0/8", "10.10.1.11:5000", "10.10.1.22:5000"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1289,6 +1289,7 @@ The list of currently supported options that can be reconfigured is this:
 | 
			
		|||
  be used to run containers
 | 
			
		||||
- `authorization-plugin`: specifies the authorization plugins to use.
 | 
			
		||||
- `insecure-registries`: it replaces the daemon insecure registries with a new set of insecure registries. If some existing insecure registries in daemon's configuration are not in newly reloaded insecure resgitries, these existing ones will be removed from daemon's config.
 | 
			
		||||
- `registry-mirrors`: it replaces the daemon registry mirrors with a new set of registry mirrors. If some existing registry mirrors in daemon's configuration are not in newly reloaded registry mirrors, these existing ones will be removed from daemon's config.
 | 
			
		||||
 | 
			
		||||
Updating and reloading the cluster configurations such as `--cluster-store`,
 | 
			
		||||
`--cluster-advertise` and `--cluster-store-opts` will take effect only if
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -429,7 +429,7 @@ func (s *DockerDaemonSuite) TestDaemonEvents(c *check.C) {
 | 
			
		|||
	out, err = s.d.Cmd("events", "--since=0", "--until", daemonUnixTime(c))
 | 
			
		||||
	c.Assert(err, checker.IsNil)
 | 
			
		||||
 | 
			
		||||
	c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s (cluster-advertise=, cluster-store=, cluster-store-opts={}, debug=true, default-runtime=runc, insecure-registries=[], labels=[\"bar=foo\"], live-restore=false, max-concurrent-downloads=1, max-concurrent-uploads=5, name=%s, runtimes=runc:{docker-runc []}, shutdown-timeout=10)", daemonID, daemonName))
 | 
			
		||||
	c.Assert(out, checker.Contains, fmt.Sprintf("daemon reload %s (cluster-advertise=, cluster-store=, cluster-store-opts={}, debug=true, default-runtime=runc, insecure-registries=[], labels=[\"bar=foo\"], live-restore=false, max-concurrent-downloads=1, max-concurrent-uploads=5, name=%s, registry-mirrors=[], runtimes=runc:{docker-runc []}, shutdown-timeout=10)", daemonID, daemonName))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *DockerDaemonSuite) TestDaemonEventsWithFilters(c *check.C) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -84,16 +84,46 @@ func newServiceConfig(options ServiceOptions) *serviceConfig {
 | 
			
		|||
			IndexConfigs:          make(map[string]*registrytypes.IndexInfo, 0),
 | 
			
		||||
			// Hack: Bypass setting the mirrors to IndexConfigs since they are going away
 | 
			
		||||
			// and Mirrors are only for the official registry anyways.
 | 
			
		||||
			Mirrors: options.Mirrors,
 | 
			
		||||
		},
 | 
			
		||||
		V2Only: options.V2Only,
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	config.LoadMirrors(options.Mirrors)
 | 
			
		||||
	config.LoadInsecureRegistries(options.InsecureRegistries)
 | 
			
		||||
 | 
			
		||||
	return config
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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[IndexName] = ®istrytypes.IndexInfo{
 | 
			
		||||
		Name:     IndexName,
 | 
			
		||||
		Mirrors:  config.Mirrors,
 | 
			
		||||
		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
 | 
			
		||||
| 
						 | 
				
			
			@ -208,18 +238,20 @@ func isSecureIndex(config *serviceConfig, indexName string) bool {
 | 
			
		|||
func ValidateMirror(val string) (string, error) {
 | 
			
		||||
	uri, err := url.Parse(val)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return "", fmt.Errorf("%s is not a valid URI", val)
 | 
			
		||||
		return "", fmt.Errorf("invalid mirror: %q is not a valid URI", val)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if uri.Scheme != "http" && uri.Scheme != "https" {
 | 
			
		||||
		return "", fmt.Errorf("Unsupported scheme %s", uri.Scheme)
 | 
			
		||||
		return "", fmt.Errorf("invalid mirror: unsupported scheme %q in %q", uri.Scheme, uri)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if uri.Path != "" || uri.RawQuery != "" || uri.Fragment != "" {
 | 
			
		||||
		return "", fmt.Errorf("Unsupported path/query/fragment at end of the URI")
 | 
			
		||||
	if (uri.Path != "" && uri.Path != "/") || uri.RawQuery != "" || uri.Fragment != "" {
 | 
			
		||||
		return "", fmt.Errorf("invalid mirror: path, query, or fragment at end of the URI %q", uri)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return fmt.Sprintf("%s://%s/", uri.Scheme, uri.Host), nil
 | 
			
		||||
	if uri.User != nil {
 | 
			
		||||
		// strip password from output
 | 
			
		||||
		uri.User = url.UserPassword(uri.User.Username(), "xxxxx")
 | 
			
		||||
		return "", fmt.Errorf("invalid mirror: username/password not allowed in URI %q", uri)
 | 
			
		||||
	}
 | 
			
		||||
	return strings.TrimSuffix(val, "/") + "/", nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ValidateIndexName validates an index name.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -7,7 +7,9 @@ import (
 | 
			
		|||
func TestValidateMirror(t *testing.T) {
 | 
			
		||||
	valid := []string{
 | 
			
		||||
		"http://mirror-1.com",
 | 
			
		||||
		"http://mirror-1.com/",
 | 
			
		||||
		"https://mirror-1.com",
 | 
			
		||||
		"https://mirror-1.com/",
 | 
			
		||||
		"http://localhost",
 | 
			
		||||
		"https://localhost",
 | 
			
		||||
		"http://localhost:5000",
 | 
			
		||||
| 
						 | 
				
			
			@ -21,15 +23,14 @@ func TestValidateMirror(t *testing.T) {
 | 
			
		|||
	invalid := []string{
 | 
			
		||||
		"!invalid!://%as%",
 | 
			
		||||
		"ftp://mirror-1.com",
 | 
			
		||||
		"http://mirror-1.com/",
 | 
			
		||||
		"http://mirror-1.com/?q=foo",
 | 
			
		||||
		"http://mirror-1.com/v1/",
 | 
			
		||||
		"http://mirror-1.com/v1/?q=foo",
 | 
			
		||||
		"http://mirror-1.com/v1/?q=foo#frag",
 | 
			
		||||
		"http://mirror-1.com?q=foo",
 | 
			
		||||
		"https://mirror-1.com#frag",
 | 
			
		||||
		"https://mirror-1.com/",
 | 
			
		||||
		"https://mirror-1.com/#frag",
 | 
			
		||||
		"http://foo:bar@mirror-1.com/",
 | 
			
		||||
		"https://mirror-1.com/v1/",
 | 
			
		||||
		"https://mirror-1.com/v1/#",
 | 
			
		||||
		"https://mirror-1.com?q",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -663,7 +663,7 @@ func TestMirrorEndpointLookup(t *testing.T) {
 | 
			
		|||
		}
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	s := DefaultService{config: makeServiceConfig([]string{"my.mirror"}, nil)}
 | 
			
		||||
	s := DefaultService{config: makeServiceConfig([]string{"https://my.mirror"}, nil)}
 | 
			
		||||
 | 
			
		||||
	imageName, err := reference.WithName(IndexName + "/test/image")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,6 +31,7 @@ type Service interface {
 | 
			
		|||
	Search(ctx context.Context, term string, limit int, authConfig *types.AuthConfig, userAgent string, headers map[string][]string) (*registrytypes.SearchResults, error)
 | 
			
		||||
	ServiceConfig() *registrytypes.ServiceConfig
 | 
			
		||||
	TLSConfig(hostname string) (*tls.Config, error)
 | 
			
		||||
	LoadMirrors([]string) error
 | 
			
		||||
	LoadInsecureRegistries([]string) error
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -73,6 +74,14 @@ func (s *DefaultService) ServiceConfig() *registrytypes.ServiceConfig {
 | 
			
		|||
	return &servConfig
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadMirrors loads registry mirrors for Service
 | 
			
		||||
func (s *DefaultService) LoadMirrors(mirrors []string) error {
 | 
			
		||||
	s.mu.Lock()
 | 
			
		||||
	defer s.mu.Unlock()
 | 
			
		||||
 | 
			
		||||
	return s.config.LoadMirrors(mirrors)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// LoadInsecureRegistries loads insecure registries for Service
 | 
			
		||||
func (s *DefaultService) LoadInsecureRegistries(registries []string) error {
 | 
			
		||||
	s.mu.Lock()
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue