Explorar o código

Merge pull request #37502 from thaJeztah/you_have_been_warned

Add "Warnings" to /info endpoint, and move detection to the daemon
Sebastiaan van Stijn %!s(int64=7) %!d(string=hai) anos
pai
achega
2629fe9326
Modificáronse 6 ficheiros con 96 adicións e 0 borrados
  1. 13 0
      api/swagger.yaml
  2. 1 0
      api/types/types.go
  3. 2 0
      daemon/info.go
  4. 75 0
      daemon/info_unix.go
  5. 3 0
      daemon/info_windows.go
  6. 2 0
      docs/api/version-history.md

+ 13 - 0
api/swagger.yaml

@@ -3904,6 +3904,19 @@ definitions:
           such as number of nodes, and expiration are included.
           such as number of nodes, and expiration are included.
         type: "string"
         type: "string"
         example: "Community Engine"
         example: "Community Engine"
+      Warnings:
+        description: |
+          List of warnings / informational messages about missing features, or
+          issues related to the daemon configuration.
+
+          These messages can be printed by the client as information to the user.
+        type: "array"
+        items:
+          type: "string"
+        example:
+          - "WARNING: No memory limit support"
+          - "WARNING: bridge-nf-call-iptables is disabled"
+          - "WARNING: bridge-nf-call-ip6tables is disabled"
 
 
 
 
   # PluginsInfo is a temp struct holding Plugins name
   # PluginsInfo is a temp struct holding Plugins name

+ 1 - 0
api/types/types.go

@@ -206,6 +206,7 @@ type Info struct {
 	InitCommit         Commit
 	InitCommit         Commit
 	SecurityOptions    []string
 	SecurityOptions    []string
 	ProductLicense     string `json:",omitempty"`
 	ProductLicense     string `json:",omitempty"`
+	Warnings           []string
 }
 }
 
 
 // KeyValue holds a key/value pair
 // KeyValue holds a key/value pair

+ 2 - 0
daemon/info.go

@@ -134,6 +134,8 @@ func (daemon *Daemon) fillDriverInfo(v *types.Info) {
 
 
 	v.Driver = drivers
 	v.Driver = drivers
 	v.DriverStatus = ds
 	v.DriverStatus = ds
+
+	fillDriverWarnings(v)
 }
 }
 
 
 func (daemon *Daemon) fillPluginsInfo(v *types.Info) {
 func (daemon *Daemon) fillPluginsInfo(v *types.Info) {

+ 75 - 0
daemon/info_unix.go

@@ -4,6 +4,7 @@ package daemon // import "github.com/docker/docker/daemon"
 
 
 import (
 import (
 	"context"
 	"context"
+	"fmt"
 	"os/exec"
 	"os/exec"
 	"strings"
 	"strings"
 
 
@@ -68,6 +69,80 @@ func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo)
 		logrus.Warnf("failed to retrieve %s version: %s", defaultInitBinary, err)
 		logrus.Warnf("failed to retrieve %s version: %s", defaultInitBinary, err)
 		v.InitCommit.ID = "N/A"
 		v.InitCommit.ID = "N/A"
 	}
 	}
+
+	if !v.MemoryLimit {
+		v.Warnings = append(v.Warnings, "WARNING: No memory limit support")
+	}
+	if !v.SwapLimit {
+		v.Warnings = append(v.Warnings, "WARNING: No swap limit support")
+	}
+	if !v.KernelMemory {
+		v.Warnings = append(v.Warnings, "WARNING: No kernel memory limit support")
+	}
+	if !v.OomKillDisable {
+		v.Warnings = append(v.Warnings, "WARNING: No oom kill disable support")
+	}
+	if !v.CPUCfsQuota {
+		v.Warnings = append(v.Warnings, "WARNING: No cpu cfs quota support")
+	}
+	if !v.CPUCfsPeriod {
+		v.Warnings = append(v.Warnings, "WARNING: No cpu cfs period support")
+	}
+	if !v.CPUShares {
+		v.Warnings = append(v.Warnings, "WARNING: No cpu shares support")
+	}
+	if !v.CPUSet {
+		v.Warnings = append(v.Warnings, "WARNING: No cpuset support")
+	}
+	if !v.IPv4Forwarding {
+		v.Warnings = append(v.Warnings, "WARNING: IPv4 forwarding is disabled")
+	}
+	if !v.BridgeNfIptables {
+		v.Warnings = append(v.Warnings, "WARNING: bridge-nf-call-iptables is disabled")
+	}
+	if !v.BridgeNfIP6tables {
+		v.Warnings = append(v.Warnings, "WARNING: bridge-nf-call-ip6tables is disabled")
+	}
+}
+
+func fillDriverWarnings(v *types.Info) {
+	if v.DriverStatus == nil {
+		return
+	}
+	for _, pair := range v.DriverStatus {
+		if pair[0] == "Data loop file" {
+			msg := fmt.Sprintf("WARNING: %s: usage of loopback devices is "+
+				"strongly discouraged for production use.\n         "+
+				"Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.", v.Driver)
+
+			v.Warnings = append(v.Warnings, msg)
+			continue
+		}
+		if pair[0] == "Supports d_type" && pair[1] == "false" {
+			backingFs := getBackingFs(v)
+
+			msg := fmt.Sprintf("WARNING: %s: the backing %s filesystem is formatted without d_type support, which leads to incorrect behavior.\n", v.Driver, backingFs)
+			if backingFs == "xfs" {
+				msg += "         Reformat the filesystem with ftype=1 to enable d_type support.\n"
+			}
+			msg += "         Running without d_type support will not be supported in future releases."
+
+			v.Warnings = append(v.Warnings, msg)
+			continue
+		}
+	}
+}
+
+func getBackingFs(v *types.Info) string {
+	if v.DriverStatus == nil {
+		return ""
+	}
+	for _, pair := range v.DriverStatus {
+		if pair[0] == "Backing Filesystem" {
+			return pair[1]
+		}
+	}
+	return ""
 }
 }
 
 
 // parseInitVersion parses a Tini version string, and extracts the version.
 // parseInitVersion parses a Tini version string, and extracts the version.

+ 3 - 0
daemon/info_windows.go

@@ -8,3 +8,6 @@ import (
 // fillPlatformInfo fills the platform related info.
 // fillPlatformInfo fills the platform related info.
 func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo) {
 func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo) {
 }
 }
+
+func fillDriverWarnings(v *types.Info) {
+}

+ 2 - 0
docs/api/version-history.md

@@ -21,6 +21,8 @@ keywords: "API, Docker, rcli, REST, documentation"
   and `OperatingSystem` if the daemon was unable to obtain this information.
   and `OperatingSystem` if the daemon was unable to obtain this information.
 * `GET /info` now returns information about the product license, if a license
 * `GET /info` now returns information about the product license, if a license
   has been applied to the daemon.
   has been applied to the daemon.
+* `GET /info` now returns a `Warnings` field, containing warnings and informational
+  messages about missing features, or issues related to the daemon configuration.
 * `POST /swarm/init` now accepts a `DefaultAddrPool` property to set global scope default address pool
 * `POST /swarm/init` now accepts a `DefaultAddrPool` property to set global scope default address pool
 * `POST /swarm/init` now accepts a `SubnetSize` property to set global scope networks by giving the
 * `POST /swarm/init` now accepts a `SubnetSize` property to set global scope networks by giving the
   length of the subnet masks for every such network
   length of the subnet masks for every such network