diff --git a/cmd/dockerd/config.go b/cmd/dockerd/config.go index b9d586a4ba..c4ae197335 100644 --- a/cmd/dockerd/config.go +++ b/cmd/dockerd/config.go @@ -59,6 +59,8 @@ func installCommonConfigFlags(conf *config.Config, flags *pflag.FlagSet) { flags.IntVar(&maxConcurrentDownloads, "max-concurrent-downloads", config.DefaultMaxConcurrentDownloads, "Set the max concurrent downloads for each pull") flags.IntVar(&maxConcurrentUploads, "max-concurrent-uploads", config.DefaultMaxConcurrentUploads, "Set the max concurrent uploads for each push") flags.IntVar(&conf.ShutdownTimeout, "shutdown-timeout", defaultShutdownTimeout, "Set the default shutdown timeout") + flags.IntVar(&conf.NetworkDiagnosticPort, "network-diagnostic-port", 0, "TCP port number of the network diagnostic server") + flags.MarkHidden("network-diagnostic-port") flags.StringVar(&conf.SwarmDefaultAdvertiseAddr, "swarm-default-advertise-addr", "", "Set default address or interface for swarm advertised address") flags.BoolVar(&conf.Experimental, "experimental", false, "Enable experimental features") diff --git a/daemon/config/config.go b/daemon/config/config.go index 1e22a6fea7..199fae6cf1 100644 --- a/daemon/config/config.go +++ b/daemon/config/config.go @@ -85,26 +85,27 @@ type CommonTLSOptions struct { // It includes json tags to deserialize configuration from a file // using the same names that the flags in the command line use. type CommonConfig struct { - AuthzMiddleware *authorization.Middleware `json:"-"` - AuthorizationPlugins []string `json:"authorization-plugins,omitempty"` // AuthorizationPlugins holds list of authorization plugins - AutoRestart bool `json:"-"` - Context map[string][]string `json:"-"` - DisableBridge bool `json:"-"` - DNS []string `json:"dns,omitempty"` - DNSOptions []string `json:"dns-opts,omitempty"` - DNSSearch []string `json:"dns-search,omitempty"` - ExecOptions []string `json:"exec-opts,omitempty"` - GraphDriver string `json:"storage-driver,omitempty"` - GraphOptions []string `json:"storage-opts,omitempty"` - Labels []string `json:"labels,omitempty"` - Mtu int `json:"mtu,omitempty"` - Pidfile string `json:"pidfile,omitempty"` - RawLogs bool `json:"raw-logs,omitempty"` - RootDeprecated string `json:"graph,omitempty"` - Root string `json:"data-root,omitempty"` - ExecRoot string `json:"exec-root,omitempty"` - SocketGroup string `json:"group,omitempty"` - CorsHeaders string `json:"api-cors-header,omitempty"` + AuthzMiddleware *authorization.Middleware `json:"-"` + AuthorizationPlugins []string `json:"authorization-plugins,omitempty"` // AuthorizationPlugins holds list of authorization plugins + AutoRestart bool `json:"-"` + Context map[string][]string `json:"-"` + DisableBridge bool `json:"-"` + DNS []string `json:"dns,omitempty"` + DNSOptions []string `json:"dns-opts,omitempty"` + DNSSearch []string `json:"dns-search,omitempty"` + ExecOptions []string `json:"exec-opts,omitempty"` + GraphDriver string `json:"storage-driver,omitempty"` + GraphOptions []string `json:"storage-opts,omitempty"` + Labels []string `json:"labels,omitempty"` + Mtu int `json:"mtu,omitempty"` + NetworkDiagnosticPort int `json:"network-diagnostic-port,omitempty"` + Pidfile string `json:"pidfile,omitempty"` + RawLogs bool `json:"raw-logs,omitempty"` + RootDeprecated string `json:"graph,omitempty"` + Root string `json:"data-root,omitempty"` + ExecRoot string `json:"exec-root,omitempty"` + SocketGroup string `json:"group,omitempty"` + CorsHeaders string `json:"api-cors-header,omitempty"` // TrustKeyPath is used to generate the daemon ID and for signing schema 1 manifests // when pushing to a registry which does not support schema 2. This field is marked as diff --git a/daemon/reload.go b/daemon/reload.go index 0d16bc8d02..a20eb688f4 100644 --- a/daemon/reload.go +++ b/daemon/reload.go @@ -61,6 +61,9 @@ func (daemon *Daemon) Reload(conf *config.Config) (err error) { if err := daemon.reloadLiveRestore(conf, attributes); err != nil { return err } + if err := daemon.reloadNetworkDiagnosticPort(conf, attributes); err != nil { + return err + } return nil } @@ -308,3 +311,18 @@ func (daemon *Daemon) reloadLiveRestore(conf *config.Config, attributes map[stri attributes["live-restore"] = fmt.Sprintf("%t", daemon.configStore.LiveRestoreEnabled) return nil } + +// reloadNetworkDiagnosticPort updates the network controller starting the diagnose mode if the config is valid +func (daemon *Daemon) reloadNetworkDiagnosticPort(conf *config.Config, attributes map[string]string) error { + if conf == nil || daemon.netController == nil { + return nil + } + // Enable the network diagnose if the flag is set with a valid port withing the range + if conf.IsValueSet("network-diagnostic-port") && conf.NetworkDiagnosticPort > 0 && conf.NetworkDiagnosticPort < 65536 { + logrus.Warnf("Calling the diagnostic start with %d", conf.NetworkDiagnosticPort) + daemon.netController.StartDiagnose(conf.NetworkDiagnosticPort) + } else { + daemon.netController.StopDiagnose() + } + return nil +} diff --git a/daemon/reload_test.go b/daemon/reload_test.go index 96b1a2452d..03b249bada 100644 --- a/daemon/reload_test.go +++ b/daemon/reload_test.go @@ -10,6 +10,7 @@ import ( "github.com/docker/docker/pkg/discovery" _ "github.com/docker/docker/pkg/discovery/memory" "github.com/docker/docker/registry" + "github.com/docker/libnetwork" "github.com/stretchr/testify/assert" ) @@ -479,3 +480,71 @@ func TestDaemonDiscoveryReloadOnlyClusterAdvertise(t *testing.T) { t.Fatal(e) } } + +func TestDaemonReloadNetworkDiagnosticPort(t *testing.T) { + daemon := &Daemon{} + 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) + } + // Check that the diagnose is enabled + if !daemon.netController.IsDiagnoseEnabled() { + t.Fatalf("diagnosed should be enable") + } + + // Reload + if err := daemon.Reload(disableConfig); err != nil { + t.Fatal(err) + } + // Check that the diagnose is disabled + if daemon.netController.IsDiagnoseEnabled() { + t.Fatalf("diagnosed should be disable") + } + } + + enableConfig.CommonConfig.NetworkDiagnosticPort++ + // 2 times the enable should not create problems + if err := daemon.Reload(enableConfig); err != nil { + t.Fatal(err) + } + // Check that the diagnose is enabled + if !daemon.netController.IsDiagnoseEnabled() { + t.Fatalf("diagnosed should be enable") + } + + // Check that another reload does not cause issues + if err := daemon.Reload(enableConfig); err != nil { + t.Fatal(err) + } + // Check that the diagnose is enable + if !daemon.netController.IsDiagnoseEnabled() { + t.Fatalf("diagnosed should be enable") + } + +}