2018-02-05 16:05:59 -05:00
|
|
|
package daemon // import "github.com/docker/docker/daemon"
|
2017-01-07 09:30:25 -05:00
|
|
|
|
|
|
|
import (
|
2018-05-22 16:12:29 -04:00
|
|
|
"os"
|
2017-05-09 17:00:31 -04:00
|
|
|
"sort"
|
2017-01-07 09:30:25 -05:00
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/docker/docker/daemon/config"
|
2018-02-07 15:52:47 -05:00
|
|
|
"github.com/docker/docker/daemon/images"
|
2021-05-27 20:15:56 -04:00
|
|
|
"github.com/docker/docker/libnetwork"
|
2017-01-07 09:30:25 -05:00
|
|
|
"github.com/docker/docker/registry"
|
2019-10-16 20:47:37 -04:00
|
|
|
"github.com/sirupsen/logrus"
|
2020-02-07 08:39:24 -05:00
|
|
|
"gotest.tools/v3/assert"
|
|
|
|
is "gotest.tools/v3/assert/cmp"
|
2017-01-07 09:30:25 -05:00
|
|
|
)
|
|
|
|
|
2019-10-16 20:47:37 -04:00
|
|
|
// muteLogs suppresses logs that are generated during the test
|
|
|
|
func muteLogs() {
|
|
|
|
logrus.SetLevel(logrus.ErrorLevel)
|
|
|
|
}
|
|
|
|
|
2017-01-07 09:30:25 -05:00
|
|
|
func TestDaemonReloadLabels(t *testing.T) {
|
2018-02-02 17:18:46 -05:00
|
|
|
daemon := &Daemon{
|
|
|
|
configStore: &config.Config{
|
|
|
|
CommonConfig: config.CommonConfig{
|
|
|
|
Labels: []string{"foo:bar"},
|
|
|
|
},
|
2017-01-07 09:30:25 -05:00
|
|
|
},
|
2018-02-07 15:52:47 -05:00
|
|
|
imageService: images.NewImageService(images.ImageServiceConfig{}),
|
2017-01-07 09:30:25 -05:00
|
|
|
}
|
2019-10-16 20:47:37 -04:00
|
|
|
muteLogs()
|
2017-01-07 09:30:25 -05:00
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-09 17:00:31 -04:00
|
|
|
func TestDaemonReloadAllowNondistributableArtifacts(t *testing.T) {
|
|
|
|
daemon := &Daemon{
|
2018-02-02 17:18:46 -05:00
|
|
|
configStore: &config.Config{},
|
2018-02-07 15:52:47 -05:00
|
|
|
imageService: images.NewImageService(images.ImageServiceConfig{}),
|
2017-05-09 17:00:31 -04:00
|
|
|
}
|
2019-10-16 20:47:37 -04:00
|
|
|
muteLogs()
|
2017-05-09 17:00:31 -04:00
|
|
|
|
2017-09-01 10:35:04 -04:00
|
|
|
var err error
|
2017-05-09 17:00:31 -04:00
|
|
|
// Initialize daemon with some registries.
|
2017-09-01 10:35:04 -04:00
|
|
|
daemon.RegistryService, err = registry.NewService(registry.ServiceOptions{
|
2017-05-09 17:00:31 -04:00
|
|
|
AllowNondistributableArtifacts: []string{
|
|
|
|
"127.0.0.0/8",
|
|
|
|
"10.10.1.11:5000",
|
|
|
|
"10.10.1.22:5000", // This will be removed during reload.
|
|
|
|
"docker1.com",
|
|
|
|
"docker2.com", // This will be removed during reload.
|
|
|
|
},
|
|
|
|
})
|
2017-09-01 10:35:04 -04:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2017-05-09 17:00:31 -04:00
|
|
|
|
|
|
|
registries := []string{
|
|
|
|
"127.0.0.0/8",
|
|
|
|
"10.10.1.11:5000",
|
|
|
|
"10.10.1.33:5000", // This will be added during reload.
|
|
|
|
"docker1.com",
|
|
|
|
"docker3.com", // This will be added during reload.
|
|
|
|
}
|
|
|
|
|
|
|
|
newConfig := &config.Config{
|
|
|
|
CommonConfig: config.CommonConfig{
|
|
|
|
ServiceOptions: registry.ServiceOptions{
|
|
|
|
AllowNondistributableArtifacts: registries,
|
|
|
|
},
|
|
|
|
ValuesSet: map[string]interface{}{
|
|
|
|
"allow-nondistributable-artifacts": registries,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := daemon.Reload(newConfig); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
|
2018-05-19 07:38:54 -04:00
|
|
|
var actual []string
|
2017-05-09 17:00:31 -04:00
|
|
|
serviceConfig := daemon.RegistryService.ServiceConfig()
|
|
|
|
for _, value := range serviceConfig.AllowNondistributableArtifactsCIDRs {
|
|
|
|
actual = append(actual, value.String())
|
|
|
|
}
|
2017-09-11 14:55:05 -04:00
|
|
|
actual = append(actual, serviceConfig.AllowNondistributableArtifactsHostnames...)
|
2017-05-09 17:00:31 -04:00
|
|
|
|
|
|
|
sort.Strings(registries)
|
|
|
|
sort.Strings(actual)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.Check(t, is.DeepEqual(registries, actual))
|
2017-05-09 17:00:31 -04:00
|
|
|
}
|
|
|
|
|
2017-01-07 09:30:25 -05:00
|
|
|
func TestDaemonReloadMirrors(t *testing.T) {
|
2018-02-02 17:18:46 -05:00
|
|
|
daemon := &Daemon{
|
2018-02-07 15:52:47 -05:00
|
|
|
imageService: images.NewImageService(images.ImageServiceConfig{}),
|
2018-02-02 17:18:46 -05:00
|
|
|
}
|
2019-10-16 20:47:37 -04:00
|
|
|
muteLogs()
|
|
|
|
|
2017-09-01 10:35:04 -04:00
|
|
|
var err error
|
|
|
|
daemon.RegistryService, err = registry.NewService(registry.ServiceOptions{
|
2017-01-07 09:30:25 -05:00
|
|
|
InsecureRegistries: []string{},
|
|
|
|
Mirrors: []string{
|
2021-04-02 08:06:27 -04:00
|
|
|
"https://mirror.test1.example.com",
|
|
|
|
"https://mirror.test2.example.com", // this will be removed when reloading
|
|
|
|
"https://mirror.test3.example.com", // this will be removed when reloading
|
2017-01-07 09:30:25 -05:00
|
|
|
},
|
|
|
|
})
|
2017-09-01 10:35:04 -04:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2017-01-07 09:30:25 -05:00
|
|
|
|
|
|
|
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,
|
2021-04-02 08:06:27 -04:00
|
|
|
mirrors: []string{"10.10.1.11:5000", "mirror.test1.example.com"}, // mirrors are invalid
|
2017-01-07 09:30:25 -05:00
|
|
|
after: []string{},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
valid: true,
|
2021-04-02 08:06:27 -04:00
|
|
|
mirrors: []string{"https://mirror.test1.example.com", "https://mirror.test4.example.com"},
|
|
|
|
after: []string{"https://mirror.test1.example.com/", "https://mirror.test4.example.com/"},
|
2017-01-07 09:30:25 -05:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
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) {
|
2018-02-02 17:18:46 -05:00
|
|
|
daemon := &Daemon{
|
2018-02-07 15:52:47 -05:00
|
|
|
imageService: images.NewImageService(images.ImageServiceConfig{}),
|
2018-02-02 17:18:46 -05:00
|
|
|
}
|
2019-10-16 20:47:37 -04:00
|
|
|
muteLogs()
|
|
|
|
|
2017-09-01 10:35:04 -04:00
|
|
|
var err error
|
2017-01-07 09:30:25 -05:00
|
|
|
// initialize daemon with existing insecure registries: "127.0.0.0/8", "10.10.1.11:5000", "10.10.1.22:5000"
|
2017-09-01 10:35:04 -04:00
|
|
|
daemon.RegistryService, err = registry.NewService(registry.ServiceOptions{
|
2017-01-07 09:30:25 -05:00
|
|
|
InsecureRegistries: []string{
|
|
|
|
"127.0.0.0/8",
|
|
|
|
"10.10.1.11:5000",
|
|
|
|
"10.10.1.22:5000", // this will be removed when reloading
|
2021-04-02 08:06:27 -04:00
|
|
|
"docker1.example.com",
|
|
|
|
"docker2.example.com", // this will be removed when reloading
|
2017-01-07 09:30:25 -05:00
|
|
|
},
|
|
|
|
})
|
2017-09-01 10:35:04 -04:00
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2017-01-07 09:30:25 -05:00
|
|
|
|
|
|
|
daemon.configStore = &config.Config{}
|
|
|
|
|
|
|
|
insecureRegistries := []string{
|
2021-04-02 08:06:27 -04:00
|
|
|
"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.example.com", // this will be kept
|
|
|
|
"docker3.example.com", // this will be newly added
|
2017-01-07 09:30:25 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2021-04-02 08:06:27 -04:00
|
|
|
if value, ok := dataMap["docker2.example.com"]; ok {
|
2017-01-07 09:30:25 -05:00
|
|
|
t.Fatalf("Expected no insecure registry of docker2.com, got %d", value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestDaemonReloadNotAffectOthers(t *testing.T) {
|
2018-02-02 17:18:46 -05:00
|
|
|
daemon := &Daemon{
|
2018-02-07 15:52:47 -05:00
|
|
|
imageService: images.NewImageService(images.ImageServiceConfig{}),
|
2018-02-02 17:18:46 -05:00
|
|
|
}
|
2019-10-16 20:47:37 -04:00
|
|
|
muteLogs()
|
|
|
|
|
2017-01-07 09:30:25 -05:00
|
|
|
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 {
|
2017-02-21 03:53:29 -05:00
|
|
|
t.Fatal("Expected debug 'enabled', got 'disabled'")
|
2017-01-07 09:30:25 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-01 14:24:14 -05:00
|
|
|
func TestDaemonReloadNetworkDiagnosticPort(t *testing.T) {
|
2018-05-22 16:12:29 -04:00
|
|
|
if os.Getuid() != 0 {
|
|
|
|
t.Skip("root required")
|
|
|
|
}
|
2018-02-02 17:18:46 -05:00
|
|
|
daemon := &Daemon{
|
2018-02-07 15:52:47 -05:00
|
|
|
imageService: images.NewImageService(images.ImageServiceConfig{}),
|
2018-02-02 17:18:46 -05:00
|
|
|
}
|
2017-12-01 14:24:14 -05:00
|
|
|
daemon.configStore = &config.Config{}
|
|
|
|
|
|
|
|
valuesSet := make(map[string]interface{})
|
|
|
|
valuesSet["network-diagnostic-port"] = 2000
|
|
|
|
enableConfig := &config.Config{
|
|
|
|
CommonConfig: config.CommonConfig{
|
|
|
|
NetworkDiagnosticPort: 2000,
|
|
|
|
ValuesSet: valuesSet,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
disableConfig := &config.Config{
|
|
|
|
CommonConfig: config.CommonConfig{},
|
|
|
|
}
|
|
|
|
|
|
|
|
netOptions, err := daemon.networkOptions(enableConfig, nil, nil)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
controller, err := libnetwork.New(netOptions...)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
daemon.netController = controller
|
|
|
|
|
|
|
|
// Enable/Disable the server for some iterations
|
|
|
|
for i := 0; i < 10; i++ {
|
|
|
|
enableConfig.CommonConfig.NetworkDiagnosticPort++
|
|
|
|
if err := daemon.Reload(enableConfig); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-01-29 14:19:37 -05:00
|
|
|
// Check that the diagnostic is enabled
|
|
|
|
if !daemon.netController.IsDiagnosticEnabled() {
|
|
|
|
t.Fatalf("diagnostic should be enable")
|
2017-12-01 14:24:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Reload
|
|
|
|
if err := daemon.Reload(disableConfig); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-01-29 14:19:37 -05:00
|
|
|
// Check that the diagnostic is disabled
|
|
|
|
if daemon.netController.IsDiagnosticEnabled() {
|
|
|
|
t.Fatalf("diagnostic should be disable")
|
2017-12-01 14:24:14 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
enableConfig.CommonConfig.NetworkDiagnosticPort++
|
|
|
|
// 2 times the enable should not create problems
|
|
|
|
if err := daemon.Reload(enableConfig); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-01-29 14:19:37 -05:00
|
|
|
// Check that the diagnostic is enabled
|
|
|
|
if !daemon.netController.IsDiagnosticEnabled() {
|
|
|
|
t.Fatalf("diagnostic should be enable")
|
2017-12-01 14:24:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check that another reload does not cause issues
|
|
|
|
if err := daemon.Reload(enableConfig); err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
2018-01-29 14:19:37 -05:00
|
|
|
// Check that the diagnostic is enable
|
|
|
|
if !daemon.netController.IsDiagnosticEnabled() {
|
|
|
|
t.Fatalf("diagnostic should be enable")
|
2017-12-01 14:24:14 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|