mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
rewrite reload code
Signed-off-by: allencloud <allen.sun@daocloud.io>
This commit is contained in:
parent
946787e85e
commit
75f5d63ec8
7 changed files with 714 additions and 632 deletions
208
daemon/daemon.go
208
daemon/daemon.go
|
@ -6,7 +6,6 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
|
@ -996,213 +995,6 @@ func (daemon *Daemon) initDiscovery(conf *config.Config) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// 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
|
||||
// - Insecure registries
|
||||
// - Registry mirrors
|
||||
// - Daemon max concurrent downloads
|
||||
// - Daemon max concurrent uploads
|
||||
// - Cluster discovery (reconfigure and restart)
|
||||
// - Daemon live restore
|
||||
// - Daemon shutdown timeout (in seconds).
|
||||
func (daemon *Daemon) Reload(conf *config.Config) (err error) {
|
||||
|
||||
daemon.configStore.Lock()
|
||||
|
||||
attributes := daemon.platformReload(conf)
|
||||
|
||||
defer func() {
|
||||
// we're unlocking here, because
|
||||
// LogDaemonEventWithAttributes() -> SystemInfo() -> GetAllRuntimes()
|
||||
// holds that lock too.
|
||||
daemon.configStore.Unlock()
|
||||
if err == nil {
|
||||
daemon.LogDaemonEventWithAttributes("reload", attributes)
|
||||
}
|
||||
}()
|
||||
|
||||
if err := daemon.reloadClusterDiscovery(conf); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if conf.IsValueSet("labels") {
|
||||
daemon.configStore.Labels = conf.Labels
|
||||
}
|
||||
if conf.IsValueSet("debug") {
|
||||
daemon.configStore.Debug = conf.Debug
|
||||
}
|
||||
if conf.IsValueSet("insecure-registries") {
|
||||
daemon.configStore.InsecureRegistries = conf.InsecureRegistries
|
||||
if err := daemon.RegistryService.LoadInsecureRegistries(conf.InsecureRegistries); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if conf.IsValueSet("registry-mirrors") {
|
||||
daemon.configStore.Mirrors = conf.Mirrors
|
||||
if err := daemon.RegistryService.LoadMirrors(conf.Mirrors); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if conf.IsValueSet("live-restore") {
|
||||
daemon.configStore.LiveRestoreEnabled = conf.LiveRestoreEnabled
|
||||
if err := daemon.containerdRemote.UpdateOptions(libcontainerd.WithLiveRestore(conf.LiveRestoreEnabled)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// If no value is set for max-concurrent-downloads we assume it is the default value
|
||||
// We always "reset" as the cost is lightweight and easy to maintain.
|
||||
if conf.IsValueSet("max-concurrent-downloads") && conf.MaxConcurrentDownloads != nil {
|
||||
*daemon.configStore.MaxConcurrentDownloads = *conf.MaxConcurrentDownloads
|
||||
} else {
|
||||
maxConcurrentDownloads := config.DefaultMaxConcurrentDownloads
|
||||
daemon.configStore.MaxConcurrentDownloads = &maxConcurrentDownloads
|
||||
}
|
||||
logrus.Debugf("Reset Max Concurrent Downloads: %d", *daemon.configStore.MaxConcurrentDownloads)
|
||||
if daemon.downloadManager != nil {
|
||||
daemon.downloadManager.SetConcurrency(*daemon.configStore.MaxConcurrentDownloads)
|
||||
}
|
||||
|
||||
// If no value is set for max-concurrent-upload we assume it is the default value
|
||||
// We always "reset" as the cost is lightweight and easy to maintain.
|
||||
if conf.IsValueSet("max-concurrent-uploads") && conf.MaxConcurrentUploads != nil {
|
||||
*daemon.configStore.MaxConcurrentUploads = *conf.MaxConcurrentUploads
|
||||
} else {
|
||||
maxConcurrentUploads := config.DefaultMaxConcurrentUploads
|
||||
daemon.configStore.MaxConcurrentUploads = &maxConcurrentUploads
|
||||
}
|
||||
logrus.Debugf("Reset Max Concurrent Uploads: %d", *daemon.configStore.MaxConcurrentUploads)
|
||||
if daemon.uploadManager != nil {
|
||||
daemon.uploadManager.SetConcurrency(*daemon.configStore.MaxConcurrentUploads)
|
||||
}
|
||||
|
||||
if conf.IsValueSet("shutdown-timeout") {
|
||||
daemon.configStore.ShutdownTimeout = conf.ShutdownTimeout
|
||||
logrus.Debugf("Reset Shutdown Timeout: %d", daemon.configStore.ShutdownTimeout)
|
||||
}
|
||||
|
||||
// We emit daemon reload event here with updatable configurations
|
||||
attributes["debug"] = fmt.Sprintf("%t", daemon.configStore.Debug)
|
||||
attributes["live-restore"] = fmt.Sprintf("%t", daemon.configStore.LiveRestoreEnabled)
|
||||
|
||||
if daemon.configStore.InsecureRegistries != nil {
|
||||
insecureRegistries, err := json.Marshal(daemon.configStore.InsecureRegistries)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
attributes["insecure-registries"] = string(insecureRegistries)
|
||||
} else {
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
attributes["cluster-store-opts"] = string(opts)
|
||||
} else {
|
||||
attributes["cluster-store-opts"] = "{}"
|
||||
}
|
||||
attributes["cluster-advertise"] = daemon.configStore.ClusterAdvertise
|
||||
|
||||
if daemon.configStore.Labels != nil {
|
||||
labels, err := json.Marshal(daemon.configStore.Labels)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
attributes["labels"] = string(labels)
|
||||
} else {
|
||||
attributes["labels"] = "[]"
|
||||
}
|
||||
|
||||
attributes["max-concurrent-downloads"] = fmt.Sprintf("%d", *daemon.configStore.MaxConcurrentDownloads)
|
||||
attributes["max-concurrent-uploads"] = fmt.Sprintf("%d", *daemon.configStore.MaxConcurrentUploads)
|
||||
attributes["shutdown-timeout"] = fmt.Sprintf("%d", daemon.configStore.ShutdownTimeout)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (daemon *Daemon) reloadClusterDiscovery(conf *config.Config) error {
|
||||
var err error
|
||||
newAdvertise := daemon.configStore.ClusterAdvertise
|
||||
newClusterStore := daemon.configStore.ClusterStore
|
||||
if conf.IsValueSet("cluster-advertise") {
|
||||
if conf.IsValueSet("cluster-store") {
|
||||
newClusterStore = conf.ClusterStore
|
||||
}
|
||||
newAdvertise, err = config.ParseClusterAdvertiseSettings(newClusterStore, conf.ClusterAdvertise)
|
||||
if err != nil && err != discovery.ErrDiscoveryDisabled {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if daemon.clusterProvider != nil {
|
||||
if err := conf.IsSwarmCompatible(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// check discovery modifications
|
||||
if !config.ModifiedDiscoverySettings(daemon.configStore, newClusterStore, newAdvertise, conf.ClusterOpts) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// enable discovery for the first time if it was not previously enabled
|
||||
if daemon.discoveryWatcher == nil {
|
||||
discoveryWatcher, err := discovery.Init(newClusterStore, newAdvertise, conf.ClusterOpts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("discovery initialization failed (%v)", err)
|
||||
}
|
||||
daemon.discoveryWatcher = discoveryWatcher
|
||||
} else {
|
||||
if err == discovery.ErrDiscoveryDisabled {
|
||||
// disable discovery if it was previously enabled and it's disabled now
|
||||
daemon.discoveryWatcher.Stop()
|
||||
} else {
|
||||
// reload discovery
|
||||
if err = daemon.discoveryWatcher.Reload(conf.ClusterStore, newAdvertise, conf.ClusterOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
daemon.configStore.ClusterStore = newClusterStore
|
||||
daemon.configStore.ClusterOpts = conf.ClusterOpts
|
||||
daemon.configStore.ClusterAdvertise = newAdvertise
|
||||
|
||||
if daemon.netController == nil {
|
||||
return nil
|
||||
}
|
||||
netOptions, err := daemon.networkOptions(daemon.configStore, daemon.PluginStore, nil)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Warnf("failed to get options with network controller")
|
||||
return nil
|
||||
}
|
||||
err = daemon.netController.ReloadConfiguration(netOptions...)
|
||||
if err != nil {
|
||||
logrus.Warnf("Failed to reload configuration with network controller: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func isBridgeNetworkDisabled(conf *config.Config) bool {
|
||||
return conf.BridgeConfig.Iface == config.DisableNetworkBridge
|
||||
}
|
||||
|
|
|
@ -301,9 +301,9 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.
|
|||
return warnings, nil
|
||||
}
|
||||
|
||||
// platformReload updates configuration with platform specific options
|
||||
func (daemon *Daemon) platformReload(config *Config) map[string]string {
|
||||
return map[string]string{}
|
||||
// reloadPlatform updates configuration with platform specific options
|
||||
// and updates the passed attributes
|
||||
func (daemon *Daemon) reloadPlatform(config *Config, attributes map[string]string) {
|
||||
}
|
||||
|
||||
// verifyDaemonSettings performs validation of daemon config struct
|
||||
|
|
|
@ -6,18 +6,13 @@ import (
|
|||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
containertypes "github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/docker/container"
|
||||
"github.com/docker/docker/daemon/config"
|
||||
"github.com/docker/docker/pkg/discovery"
|
||||
_ "github.com/docker/docker/pkg/discovery/memory"
|
||||
"github.com/docker/docker/pkg/registrar"
|
||||
"github.com/docker/docker/pkg/truncindex"
|
||||
"github.com/docker/docker/registry"
|
||||
"github.com/docker/docker/volume"
|
||||
volumedrivers "github.com/docker/docker/volume/drivers"
|
||||
"github.com/docker/docker/volume/local"
|
||||
|
@ -314,409 +309,3 @@ func TestMerge(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDaemonReloadLabels(t *testing.T) {
|
||||
daemon := &Daemon{}
|
||||
daemon.configStore = &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
Labels: []string{"foo:bar"},
|
||||
},
|
||||
}
|
||||
|
||||
valuesSets := make(map[string]interface{})
|
||||
valuesSets["labels"] = "foo:baz"
|
||||
newConfig := &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
Labels: []string{"foo:baz"},
|
||||
ValuesSet: valuesSets,
|
||||
},
|
||||
}
|
||||
|
||||
if err := daemon.Reload(newConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
label := daemon.configStore.Labels[0]
|
||||
if label != "foo:baz" {
|
||||
t.Fatalf("Expected daemon label `foo:baz`, got %s", label)
|
||||
}
|
||||
}
|
||||
|
||||
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.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.Config{
|
||||
CommonConfig: config.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"
|
||||
daemon.RegistryService = registry.NewService(registry.ServiceOptions{
|
||||
InsecureRegistries: []string{
|
||||
"127.0.0.0/8",
|
||||
"10.10.1.11:5000",
|
||||
"10.10.1.22:5000", // this will be removed when reloading
|
||||
"docker1.com",
|
||||
"docker2.com", // this will be removed when reloading
|
||||
},
|
||||
})
|
||||
|
||||
daemon.configStore = &config.Config{}
|
||||
|
||||
insecureRegistries := []string{
|
||||
"127.0.0.0/8", // this will be kept
|
||||
"10.10.1.11:5000", // this will be kept
|
||||
"10.10.1.33:5000", // this will be newly added
|
||||
"docker1.com", // this will be kept
|
||||
"docker3.com", // this will be newly added
|
||||
}
|
||||
|
||||
valuesSets := make(map[string]interface{})
|
||||
valuesSets["insecure-registries"] = insecureRegistries
|
||||
|
||||
newConfig := &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
ServiceOptions: registry.ServiceOptions{
|
||||
InsecureRegistries: insecureRegistries,
|
||||
},
|
||||
ValuesSet: valuesSets,
|
||||
},
|
||||
}
|
||||
|
||||
if err := daemon.Reload(newConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// After Reload, daemon.RegistryService will be changed which is useful
|
||||
// for registry communication in daemon.
|
||||
registries := daemon.RegistryService.ServiceConfig()
|
||||
|
||||
// After Reload(), newConfig has come to registries.InsecureRegistryCIDRs and registries.IndexConfigs in daemon.
|
||||
// Then collect registries.InsecureRegistryCIDRs in dataMap.
|
||||
// When collecting, we need to convert CIDRS into string as a key,
|
||||
// while the times of key appears as value.
|
||||
dataMap := map[string]int{}
|
||||
for _, value := range registries.InsecureRegistryCIDRs {
|
||||
if _, ok := dataMap[value.String()]; !ok {
|
||||
dataMap[value.String()] = 1
|
||||
} else {
|
||||
dataMap[value.String()]++
|
||||
}
|
||||
}
|
||||
|
||||
for _, value := range registries.IndexConfigs {
|
||||
if _, ok := dataMap[value.Name]; !ok {
|
||||
dataMap[value.Name] = 1
|
||||
} else {
|
||||
dataMap[value.Name]++
|
||||
}
|
||||
}
|
||||
|
||||
// Finally compare dataMap with the original insecureRegistries.
|
||||
// Each value in insecureRegistries should appear in daemon's insecure registries,
|
||||
// and each can only appear exactly ONCE.
|
||||
for _, r := range insecureRegistries {
|
||||
if value, ok := dataMap[r]; !ok {
|
||||
t.Fatalf("Expected daemon insecure registry %s, got none", r)
|
||||
} else if value != 1 {
|
||||
t.Fatalf("Expected only 1 daemon insecure registry %s, got %d", r, value)
|
||||
}
|
||||
}
|
||||
|
||||
// assert if "10.10.1.22:5000" is removed when reloading
|
||||
if value, ok := dataMap["10.10.1.22:5000"]; ok {
|
||||
t.Fatalf("Expected no insecure registry of 10.10.1.22:5000, got %d", value)
|
||||
}
|
||||
|
||||
// assert if "docker2.com" is removed when reloading
|
||||
if value, ok := dataMap["docker2.com"]; ok {
|
||||
t.Fatalf("Expected no insecure registry of docker2.com, got %d", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDaemonReloadNotAffectOthers(t *testing.T) {
|
||||
daemon := &Daemon{}
|
||||
daemon.configStore = &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
Labels: []string{"foo:bar"},
|
||||
Debug: true,
|
||||
},
|
||||
}
|
||||
|
||||
valuesSets := make(map[string]interface{})
|
||||
valuesSets["labels"] = "foo:baz"
|
||||
newConfig := &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
Labels: []string{"foo:baz"},
|
||||
ValuesSet: valuesSets,
|
||||
},
|
||||
}
|
||||
|
||||
if err := daemon.Reload(newConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
label := daemon.configStore.Labels[0]
|
||||
if label != "foo:baz" {
|
||||
t.Fatalf("Expected daemon label `foo:baz`, got %s", label)
|
||||
}
|
||||
debug := daemon.configStore.Debug
|
||||
if !debug {
|
||||
t.Fatalf("Expected debug 'enabled', got 'disabled'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDaemonDiscoveryReload(t *testing.T) {
|
||||
daemon := &Daemon{}
|
||||
daemon.configStore = &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
ClusterStore: "memory://127.0.0.1",
|
||||
ClusterAdvertise: "127.0.0.1:3333",
|
||||
},
|
||||
}
|
||||
|
||||
if err := daemon.initDiscovery(daemon.configStore); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := discovery.Entries{
|
||||
&discovery.Entry{Host: "127.0.0.1", Port: "3333"},
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatal("timeout waiting for discovery")
|
||||
case <-daemon.discoveryWatcher.ReadyCh():
|
||||
}
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
defer close(stopCh)
|
||||
ch, errCh := daemon.discoveryWatcher.Watch(stopCh)
|
||||
|
||||
select {
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatal("failed to get discovery advertisements in time")
|
||||
case e := <-ch:
|
||||
if !reflect.DeepEqual(e, expected) {
|
||||
t.Fatalf("expected %v, got %v\n", expected, e)
|
||||
}
|
||||
case e := <-errCh:
|
||||
t.Fatal(e)
|
||||
}
|
||||
|
||||
valuesSets := make(map[string]interface{})
|
||||
valuesSets["cluster-store"] = "memory://127.0.0.1:2222"
|
||||
valuesSets["cluster-advertise"] = "127.0.0.1:5555"
|
||||
newConfig := &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
ClusterStore: "memory://127.0.0.1:2222",
|
||||
ClusterAdvertise: "127.0.0.1:5555",
|
||||
ValuesSet: valuesSets,
|
||||
},
|
||||
}
|
||||
|
||||
expected = discovery.Entries{
|
||||
&discovery.Entry{Host: "127.0.0.1", Port: "5555"},
|
||||
}
|
||||
|
||||
if err := daemon.Reload(newConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatal("timeout waiting for discovery")
|
||||
case <-daemon.discoveryWatcher.ReadyCh():
|
||||
}
|
||||
|
||||
ch, errCh = daemon.discoveryWatcher.Watch(stopCh)
|
||||
|
||||
select {
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatal("failed to get discovery advertisements in time")
|
||||
case e := <-ch:
|
||||
if !reflect.DeepEqual(e, expected) {
|
||||
t.Fatalf("expected %v, got %v\n", expected, e)
|
||||
}
|
||||
case e := <-errCh:
|
||||
t.Fatal(e)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDaemonDiscoveryReloadFromEmptyDiscovery(t *testing.T) {
|
||||
daemon := &Daemon{}
|
||||
daemon.configStore = &config.Config{}
|
||||
|
||||
valuesSet := make(map[string]interface{})
|
||||
valuesSet["cluster-store"] = "memory://127.0.0.1:2222"
|
||||
valuesSet["cluster-advertise"] = "127.0.0.1:5555"
|
||||
newConfig := &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
ClusterStore: "memory://127.0.0.1:2222",
|
||||
ClusterAdvertise: "127.0.0.1:5555",
|
||||
ValuesSet: valuesSet,
|
||||
},
|
||||
}
|
||||
|
||||
expected := discovery.Entries{
|
||||
&discovery.Entry{Host: "127.0.0.1", Port: "5555"},
|
||||
}
|
||||
|
||||
if err := daemon.Reload(newConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatal("timeout waiting for discovery")
|
||||
case <-daemon.discoveryWatcher.ReadyCh():
|
||||
}
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
defer close(stopCh)
|
||||
ch, errCh := daemon.discoveryWatcher.Watch(stopCh)
|
||||
|
||||
select {
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatal("failed to get discovery advertisements in time")
|
||||
case e := <-ch:
|
||||
if !reflect.DeepEqual(e, expected) {
|
||||
t.Fatalf("expected %v, got %v\n", expected, e)
|
||||
}
|
||||
case e := <-errCh:
|
||||
t.Fatal(e)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDaemonDiscoveryReloadOnlyClusterAdvertise(t *testing.T) {
|
||||
daemon := &Daemon{}
|
||||
daemon.configStore = &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
ClusterStore: "memory://127.0.0.1",
|
||||
},
|
||||
}
|
||||
valuesSets := make(map[string]interface{})
|
||||
valuesSets["cluster-advertise"] = "127.0.0.1:5555"
|
||||
newConfig := &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
ClusterAdvertise: "127.0.0.1:5555",
|
||||
ValuesSet: valuesSets,
|
||||
},
|
||||
}
|
||||
expected := discovery.Entries{
|
||||
&discovery.Entry{Host: "127.0.0.1", Port: "5555"},
|
||||
}
|
||||
|
||||
if err := daemon.Reload(newConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-daemon.discoveryWatcher.ReadyCh():
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatal("Timeout waiting for discovery")
|
||||
}
|
||||
stopCh := make(chan struct{})
|
||||
defer close(stopCh)
|
||||
ch, errCh := daemon.discoveryWatcher.Watch(stopCh)
|
||||
|
||||
select {
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatal("failed to get discovery advertisements in time")
|
||||
case e := <-ch:
|
||||
if !reflect.DeepEqual(e, expected) {
|
||||
t.Fatalf("expected %v, got %v\n", expected, e)
|
||||
}
|
||||
case e := <-errCh:
|
||||
t.Fatal(e)
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -568,8 +568,9 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.
|
|||
return warnings, nil
|
||||
}
|
||||
|
||||
// platformReload updates configuration with platform specific options
|
||||
func (daemon *Daemon) platformReload(conf *config.Config) map[string]string {
|
||||
// reloadPlatform updates configuration with platform specific options
|
||||
// and updates the passed attributes
|
||||
func (daemon *Daemon) reloadPlatform(conf *config.Config, attributes map[string]string) {
|
||||
if conf.IsValueSet("runtimes") {
|
||||
daemon.configStore.Runtimes = conf.Runtimes
|
||||
// Always set the default one
|
||||
|
@ -593,11 +594,9 @@ func (daemon *Daemon) platformReload(conf *config.Config) map[string]string {
|
|||
runtimeList.WriteString(fmt.Sprintf("%s:%s", name, rt))
|
||||
}
|
||||
|
||||
return map[string]string{
|
||||
"runtimes": runtimeList.String(),
|
||||
"default-runtime": daemon.configStore.DefaultRuntime,
|
||||
"default-shm-size": fmt.Sprintf("%d", daemon.configStore.ShmSize),
|
||||
}
|
||||
attributes["runtimes"] = runtimeList.String()
|
||||
attributes["default-runtime"] = daemon.configStore.DefaultRuntime
|
||||
attributes["default-shm-size"] = fmt.Sprintf("%d", daemon.configStore.ShmSize)
|
||||
}
|
||||
|
||||
// verifyDaemonSettings performs validation of daemon config struct
|
||||
|
|
|
@ -210,9 +210,9 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.
|
|||
return warnings, err
|
||||
}
|
||||
|
||||
// platformReload updates configuration with platform specific options
|
||||
func (daemon *Daemon) platformReload(config *config.Config) map[string]string {
|
||||
return map[string]string{}
|
||||
// reloadPlatform updates configuration with platform specific options
|
||||
// and updates the passed attributes
|
||||
func (daemon *Daemon) reloadPlatform(config *config.Config, attributes map[string]string) {
|
||||
}
|
||||
|
||||
// verifyDaemonSettings performs validation of daemon config struct
|
||||
|
|
284
daemon/reload.go
Normal file
284
daemon/reload.go
Normal file
|
@ -0,0 +1,284 @@
|
|||
package daemon
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/docker/docker/daemon/config"
|
||||
"github.com/docker/docker/daemon/discovery"
|
||||
"github.com/docker/docker/libcontainerd"
|
||||
)
|
||||
|
||||
// Reload reads configuration changes and modifies the
|
||||
// daemon according to those changes.
|
||||
// These are the settings that Reload changes:
|
||||
// - Platform runtime
|
||||
// - Daemon debug log level
|
||||
// - Daemon max concurrent downloads
|
||||
// - Daemon max concurrent uploads
|
||||
// - Daemon shutdown timeout (in seconds)
|
||||
// - Cluster discovery (reconfigure and restart)
|
||||
// - Daemon labels
|
||||
// - Insecure registries
|
||||
// - Registry mirrors
|
||||
// - Daemon live restore
|
||||
func (daemon *Daemon) Reload(conf *config.Config) (err error) {
|
||||
daemon.configStore.Lock()
|
||||
attributes := map[string]string{}
|
||||
|
||||
defer func() {
|
||||
// we're unlocking here, because
|
||||
// LogDaemonEventWithAttributes() -> SystemInfo() -> GetAllRuntimes()
|
||||
// holds that lock too.
|
||||
daemon.configStore.Unlock()
|
||||
if err == nil {
|
||||
daemon.LogDaemonEventWithAttributes("reload", attributes)
|
||||
}
|
||||
}()
|
||||
|
||||
daemon.reloadPlatform(conf, attributes)
|
||||
daemon.reloadDebug(conf, attributes)
|
||||
daemon.reloadMaxConcurrentDowloadsAndUploads(conf, attributes)
|
||||
daemon.reloadShutdownTimeout(conf, attributes)
|
||||
|
||||
if err := daemon.reloadClusterDiscovery(conf, attributes); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := daemon.reloadLabels(conf, attributes); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := daemon.reloadInsecureRegistries(conf, attributes); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := daemon.reloadRegistryMirrors(conf, attributes); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := daemon.reloadLiveRestore(conf, attributes); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// reloadDebug updates configuration with Debug option
|
||||
// and updates the passed attributes
|
||||
func (daemon *Daemon) reloadDebug(conf *config.Config, attributes map[string]string) {
|
||||
// update corresponding configuration
|
||||
if conf.IsValueSet("debug") {
|
||||
daemon.configStore.Debug = conf.Debug
|
||||
}
|
||||
// prepare reload event attributes with updatable configurations
|
||||
attributes["debug"] = fmt.Sprintf("%t", daemon.configStore.Debug)
|
||||
}
|
||||
|
||||
// reloadMaxConcurrentDowloadsAndUploads updates configuration with max concurrent
|
||||
// download and upload options and updates the passed attributes
|
||||
func (daemon *Daemon) reloadMaxConcurrentDowloadsAndUploads(conf *config.Config, attributes map[string]string) {
|
||||
// If no value is set for max-concurrent-downloads we assume it is the default value
|
||||
// We always "reset" as the cost is lightweight and easy to maintain.
|
||||
if conf.IsValueSet("max-concurrent-downloads") && conf.MaxConcurrentDownloads != nil {
|
||||
*daemon.configStore.MaxConcurrentDownloads = *conf.MaxConcurrentDownloads
|
||||
} else {
|
||||
maxConcurrentDownloads := config.DefaultMaxConcurrentDownloads
|
||||
daemon.configStore.MaxConcurrentDownloads = &maxConcurrentDownloads
|
||||
}
|
||||
logrus.Debugf("Reset Max Concurrent Downloads: %d", *daemon.configStore.MaxConcurrentDownloads)
|
||||
if daemon.downloadManager != nil {
|
||||
daemon.downloadManager.SetConcurrency(*daemon.configStore.MaxConcurrentDownloads)
|
||||
}
|
||||
|
||||
// prepare reload event attributes with updatable configurations
|
||||
attributes["max-concurrent-downloads"] = fmt.Sprintf("%d", *daemon.configStore.MaxConcurrentDownloads)
|
||||
|
||||
// If no value is set for max-concurrent-upload we assume it is the default value
|
||||
// We always "reset" as the cost is lightweight and easy to maintain.
|
||||
if conf.IsValueSet("max-concurrent-uploads") && conf.MaxConcurrentUploads != nil {
|
||||
*daemon.configStore.MaxConcurrentUploads = *conf.MaxConcurrentUploads
|
||||
} else {
|
||||
maxConcurrentUploads := config.DefaultMaxConcurrentUploads
|
||||
daemon.configStore.MaxConcurrentUploads = &maxConcurrentUploads
|
||||
}
|
||||
logrus.Debugf("Reset Max Concurrent Uploads: %d", *daemon.configStore.MaxConcurrentUploads)
|
||||
if daemon.uploadManager != nil {
|
||||
daemon.uploadManager.SetConcurrency(*daemon.configStore.MaxConcurrentUploads)
|
||||
}
|
||||
|
||||
// prepare reload event attributes with updatable configurations
|
||||
attributes["max-concurrent-uploads"] = fmt.Sprintf("%d", *daemon.configStore.MaxConcurrentUploads)
|
||||
}
|
||||
|
||||
// reloadShutdownTimeout updates configuration with daemon shutdown timeout option
|
||||
// and updates the passed attributes
|
||||
func (daemon *Daemon) reloadShutdownTimeout(conf *config.Config, attributes map[string]string) {
|
||||
// update corresponding configuration
|
||||
if conf.IsValueSet("shutdown-timeout") {
|
||||
daemon.configStore.ShutdownTimeout = conf.ShutdownTimeout
|
||||
logrus.Debugf("Reset Shutdown Timeout: %d", daemon.configStore.ShutdownTimeout)
|
||||
}
|
||||
|
||||
// prepare reload event attributes with updatable configurations
|
||||
attributes["shutdown-timeout"] = fmt.Sprintf("%d", daemon.configStore.ShutdownTimeout)
|
||||
}
|
||||
|
||||
// reloadClusterDiscovery updates configuration with cluster discovery options
|
||||
// and updates the passed attributes
|
||||
func (daemon *Daemon) reloadClusterDiscovery(conf *config.Config, attributes map[string]string) (err error) {
|
||||
defer func() {
|
||||
// prepare reload event attributes with updatable configurations
|
||||
attributes["cluster-store"] = conf.ClusterStore
|
||||
attributes["cluster-advertise"] = conf.ClusterAdvertise
|
||||
|
||||
attributes["cluster-store-opts"] = "{}"
|
||||
if daemon.configStore.ClusterOpts != nil {
|
||||
opts, err2 := json.Marshal(conf.ClusterOpts)
|
||||
if err != nil {
|
||||
err = err2
|
||||
}
|
||||
attributes["cluster-store-opts"] = string(opts)
|
||||
}
|
||||
}()
|
||||
|
||||
newAdvertise := conf.ClusterAdvertise
|
||||
newClusterStore := daemon.configStore.ClusterStore
|
||||
if conf.IsValueSet("cluster-advertise") {
|
||||
if conf.IsValueSet("cluster-store") {
|
||||
newClusterStore = conf.ClusterStore
|
||||
}
|
||||
newAdvertise, err = config.ParseClusterAdvertiseSettings(newClusterStore, conf.ClusterAdvertise)
|
||||
if err != nil && err != discovery.ErrDiscoveryDisabled {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if daemon.clusterProvider != nil {
|
||||
if err := conf.IsSwarmCompatible(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// check discovery modifications
|
||||
if !config.ModifiedDiscoverySettings(daemon.configStore, newClusterStore, newAdvertise, conf.ClusterOpts) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// enable discovery for the first time if it was not previously enabled
|
||||
if daemon.discoveryWatcher == nil {
|
||||
discoveryWatcher, err := discovery.Init(newClusterStore, newAdvertise, conf.ClusterOpts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to initialize discovery: %v", err)
|
||||
}
|
||||
daemon.discoveryWatcher = discoveryWatcher
|
||||
} else if err == discovery.ErrDiscoveryDisabled {
|
||||
// disable discovery if it was previously enabled and it's disabled now
|
||||
daemon.discoveryWatcher.Stop()
|
||||
} else if err = daemon.discoveryWatcher.Reload(conf.ClusterStore, newAdvertise, conf.ClusterOpts); err != nil {
|
||||
// reload discovery
|
||||
return err
|
||||
}
|
||||
|
||||
daemon.configStore.ClusterStore = newClusterStore
|
||||
daemon.configStore.ClusterOpts = conf.ClusterOpts
|
||||
daemon.configStore.ClusterAdvertise = newAdvertise
|
||||
|
||||
if daemon.netController == nil {
|
||||
return nil
|
||||
}
|
||||
netOptions, err := daemon.networkOptions(daemon.configStore, daemon.PluginStore, nil)
|
||||
if err != nil {
|
||||
logrus.WithError(err).Warnf("failed to get options with network controller")
|
||||
return nil
|
||||
}
|
||||
err = daemon.netController.ReloadConfiguration(netOptions...)
|
||||
if err != nil {
|
||||
logrus.Warnf("Failed to reload configuration with network controller: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// reloadLabels updates configuration with engine labels
|
||||
// and updates the passed attributes
|
||||
func (daemon *Daemon) reloadLabels(conf *config.Config, attributes map[string]string) error {
|
||||
// update corresponding configuration
|
||||
if conf.IsValueSet("labels") {
|
||||
daemon.configStore.Labels = conf.Labels
|
||||
}
|
||||
|
||||
// prepare reload event attributes with updatable configurations
|
||||
if daemon.configStore.Labels != nil {
|
||||
labels, err := json.Marshal(daemon.configStore.Labels)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
attributes["labels"] = string(labels)
|
||||
} else {
|
||||
attributes["labels"] = "[]"
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// reloadInsecureRegistries updates configuration with insecure registry option
|
||||
// and updates the passed attributes
|
||||
func (daemon *Daemon) reloadInsecureRegistries(conf *config.Config, attributes map[string]string) error {
|
||||
// update corresponding configuration
|
||||
if conf.IsValueSet("insecure-registries") {
|
||||
daemon.configStore.InsecureRegistries = conf.InsecureRegistries
|
||||
if err := daemon.RegistryService.LoadInsecureRegistries(conf.InsecureRegistries); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// prepare reload event attributes with updatable configurations
|
||||
if daemon.configStore.InsecureRegistries != nil {
|
||||
insecureRegistries, err := json.Marshal(daemon.configStore.InsecureRegistries)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
attributes["insecure-registries"] = string(insecureRegistries)
|
||||
} else {
|
||||
attributes["insecure-registries"] = "[]"
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// reloadRegistryMirrors updates configuration with registry mirror options
|
||||
// and updates the passed attributes
|
||||
func (daemon *Daemon) reloadRegistryMirrors(conf *config.Config, attributes map[string]string) error {
|
||||
// update corresponding configuration
|
||||
if conf.IsValueSet("registry-mirrors") {
|
||||
daemon.configStore.Mirrors = conf.Mirrors
|
||||
if err := daemon.RegistryService.LoadMirrors(conf.Mirrors); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// prepare reload event attributes with updatable configurations
|
||||
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"] = "[]"
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// reloadLiveRestore updates configuration with live retore option
|
||||
// and updates the passed attributes
|
||||
func (daemon *Daemon) reloadLiveRestore(conf *config.Config, attributes map[string]string) error {
|
||||
// update corresponding configuration
|
||||
if conf.IsValueSet("live-restore") {
|
||||
daemon.configStore.LiveRestoreEnabled = conf.LiveRestoreEnabled
|
||||
if err := daemon.containerdRemote.UpdateOptions(libcontainerd.WithLiveRestore(conf.LiveRestoreEnabled)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// prepare reload event attributes with updatable configurations
|
||||
attributes["live-restore"] = fmt.Sprintf("%t", daemon.configStore.LiveRestoreEnabled)
|
||||
return nil
|
||||
}
|
418
daemon/reload_test.go
Normal file
418
daemon/reload_test.go
Normal file
|
@ -0,0 +1,418 @@
|
|||
// +build !solaris
|
||||
|
||||
package daemon
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/docker/docker/daemon/config"
|
||||
"github.com/docker/docker/pkg/discovery"
|
||||
_ "github.com/docker/docker/pkg/discovery/memory"
|
||||
"github.com/docker/docker/registry"
|
||||
)
|
||||
|
||||
func TestDaemonReloadLabels(t *testing.T) {
|
||||
daemon := &Daemon{}
|
||||
daemon.configStore = &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
Labels: []string{"foo:bar"},
|
||||
},
|
||||
}
|
||||
|
||||
valuesSets := make(map[string]interface{})
|
||||
valuesSets["labels"] = "foo:baz"
|
||||
newConfig := &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
Labels: []string{"foo:baz"},
|
||||
ValuesSet: valuesSets,
|
||||
},
|
||||
}
|
||||
|
||||
if err := daemon.Reload(newConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
label := daemon.configStore.Labels[0]
|
||||
if label != "foo:baz" {
|
||||
t.Fatalf("Expected daemon label `foo:baz`, got %s", label)
|
||||
}
|
||||
}
|
||||
|
||||
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.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.Config{
|
||||
CommonConfig: config.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"
|
||||
daemon.RegistryService = registry.NewService(registry.ServiceOptions{
|
||||
InsecureRegistries: []string{
|
||||
"127.0.0.0/8",
|
||||
"10.10.1.11:5000",
|
||||
"10.10.1.22:5000", // this will be removed when reloading
|
||||
"docker1.com",
|
||||
"docker2.com", // this will be removed when reloading
|
||||
},
|
||||
})
|
||||
|
||||
daemon.configStore = &config.Config{}
|
||||
|
||||
insecureRegistries := []string{
|
||||
"127.0.0.0/8", // this will be kept
|
||||
"10.10.1.11:5000", // this will be kept
|
||||
"10.10.1.33:5000", // this will be newly added
|
||||
"docker1.com", // this will be kept
|
||||
"docker3.com", // this will be newly added
|
||||
}
|
||||
|
||||
valuesSets := make(map[string]interface{})
|
||||
valuesSets["insecure-registries"] = insecureRegistries
|
||||
|
||||
newConfig := &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
ServiceOptions: registry.ServiceOptions{
|
||||
InsecureRegistries: insecureRegistries,
|
||||
},
|
||||
ValuesSet: valuesSets,
|
||||
},
|
||||
}
|
||||
|
||||
if err := daemon.Reload(newConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// After Reload, daemon.RegistryService will be changed which is useful
|
||||
// for registry communication in daemon.
|
||||
registries := daemon.RegistryService.ServiceConfig()
|
||||
|
||||
// After Reload(), newConfig has come to registries.InsecureRegistryCIDRs and registries.IndexConfigs in daemon.
|
||||
// Then collect registries.InsecureRegistryCIDRs in dataMap.
|
||||
// When collecting, we need to convert CIDRS into string as a key,
|
||||
// while the times of key appears as value.
|
||||
dataMap := map[string]int{}
|
||||
for _, value := range registries.InsecureRegistryCIDRs {
|
||||
if _, ok := dataMap[value.String()]; !ok {
|
||||
dataMap[value.String()] = 1
|
||||
} else {
|
||||
dataMap[value.String()]++
|
||||
}
|
||||
}
|
||||
|
||||
for _, value := range registries.IndexConfigs {
|
||||
if _, ok := dataMap[value.Name]; !ok {
|
||||
dataMap[value.Name] = 1
|
||||
} else {
|
||||
dataMap[value.Name]++
|
||||
}
|
||||
}
|
||||
|
||||
// Finally compare dataMap with the original insecureRegistries.
|
||||
// Each value in insecureRegistries should appear in daemon's insecure registries,
|
||||
// and each can only appear exactly ONCE.
|
||||
for _, r := range insecureRegistries {
|
||||
if value, ok := dataMap[r]; !ok {
|
||||
t.Fatalf("Expected daemon insecure registry %s, got none", r)
|
||||
} else if value != 1 {
|
||||
t.Fatalf("Expected only 1 daemon insecure registry %s, got %d", r, value)
|
||||
}
|
||||
}
|
||||
|
||||
// assert if "10.10.1.22:5000" is removed when reloading
|
||||
if value, ok := dataMap["10.10.1.22:5000"]; ok {
|
||||
t.Fatalf("Expected no insecure registry of 10.10.1.22:5000, got %d", value)
|
||||
}
|
||||
|
||||
// assert if "docker2.com" is removed when reloading
|
||||
if value, ok := dataMap["docker2.com"]; ok {
|
||||
t.Fatalf("Expected no insecure registry of docker2.com, got %d", value)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDaemonReloadNotAffectOthers(t *testing.T) {
|
||||
daemon := &Daemon{}
|
||||
daemon.configStore = &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
Labels: []string{"foo:bar"},
|
||||
Debug: true,
|
||||
},
|
||||
}
|
||||
|
||||
valuesSets := make(map[string]interface{})
|
||||
valuesSets["labels"] = "foo:baz"
|
||||
newConfig := &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
Labels: []string{"foo:baz"},
|
||||
ValuesSet: valuesSets,
|
||||
},
|
||||
}
|
||||
|
||||
if err := daemon.Reload(newConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
label := daemon.configStore.Labels[0]
|
||||
if label != "foo:baz" {
|
||||
t.Fatalf("Expected daemon label `foo:baz`, got %s", label)
|
||||
}
|
||||
debug := daemon.configStore.Debug
|
||||
if !debug {
|
||||
t.Fatalf("Expected debug 'enabled', got 'disabled'")
|
||||
}
|
||||
}
|
||||
|
||||
func TestDaemonDiscoveryReload(t *testing.T) {
|
||||
daemon := &Daemon{}
|
||||
daemon.configStore = &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
ClusterStore: "memory://127.0.0.1",
|
||||
ClusterAdvertise: "127.0.0.1:3333",
|
||||
},
|
||||
}
|
||||
|
||||
if err := daemon.initDiscovery(daemon.configStore); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expected := discovery.Entries{
|
||||
&discovery.Entry{Host: "127.0.0.1", Port: "3333"},
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatal("timeout waiting for discovery")
|
||||
case <-daemon.discoveryWatcher.ReadyCh():
|
||||
}
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
defer close(stopCh)
|
||||
ch, errCh := daemon.discoveryWatcher.Watch(stopCh)
|
||||
|
||||
select {
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatal("failed to get discovery advertisements in time")
|
||||
case e := <-ch:
|
||||
if !reflect.DeepEqual(e, expected) {
|
||||
t.Fatalf("expected %v, got %v\n", expected, e)
|
||||
}
|
||||
case e := <-errCh:
|
||||
t.Fatal(e)
|
||||
}
|
||||
|
||||
valuesSets := make(map[string]interface{})
|
||||
valuesSets["cluster-store"] = "memory://127.0.0.1:2222"
|
||||
valuesSets["cluster-advertise"] = "127.0.0.1:5555"
|
||||
newConfig := &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
ClusterStore: "memory://127.0.0.1:2222",
|
||||
ClusterAdvertise: "127.0.0.1:5555",
|
||||
ValuesSet: valuesSets,
|
||||
},
|
||||
}
|
||||
|
||||
expected = discovery.Entries{
|
||||
&discovery.Entry{Host: "127.0.0.1", Port: "5555"},
|
||||
}
|
||||
|
||||
if err := daemon.Reload(newConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatal("timeout waiting for discovery")
|
||||
case <-daemon.discoveryWatcher.ReadyCh():
|
||||
}
|
||||
|
||||
ch, errCh = daemon.discoveryWatcher.Watch(stopCh)
|
||||
|
||||
select {
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatal("failed to get discovery advertisements in time")
|
||||
case e := <-ch:
|
||||
if !reflect.DeepEqual(e, expected) {
|
||||
t.Fatalf("expected %v, got %v\n", expected, e)
|
||||
}
|
||||
case e := <-errCh:
|
||||
t.Fatal(e)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDaemonDiscoveryReloadFromEmptyDiscovery(t *testing.T) {
|
||||
daemon := &Daemon{}
|
||||
daemon.configStore = &config.Config{}
|
||||
|
||||
valuesSet := make(map[string]interface{})
|
||||
valuesSet["cluster-store"] = "memory://127.0.0.1:2222"
|
||||
valuesSet["cluster-advertise"] = "127.0.0.1:5555"
|
||||
newConfig := &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
ClusterStore: "memory://127.0.0.1:2222",
|
||||
ClusterAdvertise: "127.0.0.1:5555",
|
||||
ValuesSet: valuesSet,
|
||||
},
|
||||
}
|
||||
|
||||
expected := discovery.Entries{
|
||||
&discovery.Entry{Host: "127.0.0.1", Port: "5555"},
|
||||
}
|
||||
|
||||
if err := daemon.Reload(newConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatal("timeout waiting for discovery")
|
||||
case <-daemon.discoveryWatcher.ReadyCh():
|
||||
}
|
||||
|
||||
stopCh := make(chan struct{})
|
||||
defer close(stopCh)
|
||||
ch, errCh := daemon.discoveryWatcher.Watch(stopCh)
|
||||
|
||||
select {
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatal("failed to get discovery advertisements in time")
|
||||
case e := <-ch:
|
||||
if !reflect.DeepEqual(e, expected) {
|
||||
t.Fatalf("expected %v, got %v\n", expected, e)
|
||||
}
|
||||
case e := <-errCh:
|
||||
t.Fatal(e)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDaemonDiscoveryReloadOnlyClusterAdvertise(t *testing.T) {
|
||||
daemon := &Daemon{}
|
||||
daemon.configStore = &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
ClusterStore: "memory://127.0.0.1",
|
||||
},
|
||||
}
|
||||
valuesSets := make(map[string]interface{})
|
||||
valuesSets["cluster-advertise"] = "127.0.0.1:5555"
|
||||
newConfig := &config.Config{
|
||||
CommonConfig: config.CommonConfig{
|
||||
ClusterAdvertise: "127.0.0.1:5555",
|
||||
ValuesSet: valuesSets,
|
||||
},
|
||||
}
|
||||
expected := discovery.Entries{
|
||||
&discovery.Entry{Host: "127.0.0.1", Port: "5555"},
|
||||
}
|
||||
|
||||
if err := daemon.Reload(newConfig); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
select {
|
||||
case <-daemon.discoveryWatcher.ReadyCh():
|
||||
case <-time.After(10 * time.Second):
|
||||
t.Fatal("Timeout waiting for discovery")
|
||||
}
|
||||
stopCh := make(chan struct{})
|
||||
defer close(stopCh)
|
||||
ch, errCh := daemon.discoveryWatcher.Watch(stopCh)
|
||||
|
||||
select {
|
||||
case <-time.After(1 * time.Second):
|
||||
t.Fatal("failed to get discovery advertisements in time")
|
||||
case e := <-ch:
|
||||
if !reflect.DeepEqual(e, expected) {
|
||||
t.Fatalf("expected %v, got %v\n", expected, e)
|
||||
}
|
||||
case e := <-errCh:
|
||||
t.Fatal(e)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue