Browse code

Merge pull request #37502 from thaJeztah/you_have_been_warned

Add "Warnings" to /info endpoint, and move detection to the daemon

Sebastiaan van Stijn authored on 2018/08/21 18:37:27
Showing 6 changed files
... ...
@@ -3904,6 +3904,19 @@ definitions:
3904 3904
           such as number of nodes, and expiration are included.
3905 3905
         type: "string"
3906 3906
         example: "Community Engine"
3907
+      Warnings:
3908
+        description: |
3909
+          List of warnings / informational messages about missing features, or
3910
+          issues related to the daemon configuration.
3911
+
3912
+          These messages can be printed by the client as information to the user.
3913
+        type: "array"
3914
+        items:
3915
+          type: "string"
3916
+        example:
3917
+          - "WARNING: No memory limit support"
3918
+          - "WARNING: bridge-nf-call-iptables is disabled"
3919
+          - "WARNING: bridge-nf-call-ip6tables is disabled"
3907 3920
 
3908 3921
 
3909 3922
   # PluginsInfo is a temp struct holding Plugins name
... ...
@@ -206,6 +206,7 @@ type Info struct {
206 206
 	InitCommit         Commit
207 207
 	SecurityOptions    []string
208 208
 	ProductLicense     string `json:",omitempty"`
209
+	Warnings           []string
209 210
 }
210 211
 
211 212
 // KeyValue holds a key/value pair
... ...
@@ -134,6 +134,8 @@ func (daemon *Daemon) fillDriverInfo(v *types.Info) {
134 134
 
135 135
 	v.Driver = drivers
136 136
 	v.DriverStatus = ds
137
+
138
+	fillDriverWarnings(v)
137 139
 }
138 140
 
139 141
 func (daemon *Daemon) fillPluginsInfo(v *types.Info) {
... ...
@@ -4,6 +4,7 @@ package daemon // import "github.com/docker/docker/daemon"
4 4
 
5 5
 import (
6 6
 	"context"
7
+	"fmt"
7 8
 	"os/exec"
8 9
 	"strings"
9 10
 
... ...
@@ -68,6 +69,80 @@ func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo)
68 68
 		logrus.Warnf("failed to retrieve %s version: %s", defaultInitBinary, err)
69 69
 		v.InitCommit.ID = "N/A"
70 70
 	}
71
+
72
+	if !v.MemoryLimit {
73
+		v.Warnings = append(v.Warnings, "WARNING: No memory limit support")
74
+	}
75
+	if !v.SwapLimit {
76
+		v.Warnings = append(v.Warnings, "WARNING: No swap limit support")
77
+	}
78
+	if !v.KernelMemory {
79
+		v.Warnings = append(v.Warnings, "WARNING: No kernel memory limit support")
80
+	}
81
+	if !v.OomKillDisable {
82
+		v.Warnings = append(v.Warnings, "WARNING: No oom kill disable support")
83
+	}
84
+	if !v.CPUCfsQuota {
85
+		v.Warnings = append(v.Warnings, "WARNING: No cpu cfs quota support")
86
+	}
87
+	if !v.CPUCfsPeriod {
88
+		v.Warnings = append(v.Warnings, "WARNING: No cpu cfs period support")
89
+	}
90
+	if !v.CPUShares {
91
+		v.Warnings = append(v.Warnings, "WARNING: No cpu shares support")
92
+	}
93
+	if !v.CPUSet {
94
+		v.Warnings = append(v.Warnings, "WARNING: No cpuset support")
95
+	}
96
+	if !v.IPv4Forwarding {
97
+		v.Warnings = append(v.Warnings, "WARNING: IPv4 forwarding is disabled")
98
+	}
99
+	if !v.BridgeNfIptables {
100
+		v.Warnings = append(v.Warnings, "WARNING: bridge-nf-call-iptables is disabled")
101
+	}
102
+	if !v.BridgeNfIP6tables {
103
+		v.Warnings = append(v.Warnings, "WARNING: bridge-nf-call-ip6tables is disabled")
104
+	}
105
+}
106
+
107
+func fillDriverWarnings(v *types.Info) {
108
+	if v.DriverStatus == nil {
109
+		return
110
+	}
111
+	for _, pair := range v.DriverStatus {
112
+		if pair[0] == "Data loop file" {
113
+			msg := fmt.Sprintf("WARNING: %s: usage of loopback devices is "+
114
+				"strongly discouraged for production use.\n         "+
115
+				"Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.", v.Driver)
116
+
117
+			v.Warnings = append(v.Warnings, msg)
118
+			continue
119
+		}
120
+		if pair[0] == "Supports d_type" && pair[1] == "false" {
121
+			backingFs := getBackingFs(v)
122
+
123
+			msg := fmt.Sprintf("WARNING: %s: the backing %s filesystem is formatted without d_type support, which leads to incorrect behavior.\n", v.Driver, backingFs)
124
+			if backingFs == "xfs" {
125
+				msg += "         Reformat the filesystem with ftype=1 to enable d_type support.\n"
126
+			}
127
+			msg += "         Running without d_type support will not be supported in future releases."
128
+
129
+			v.Warnings = append(v.Warnings, msg)
130
+			continue
131
+		}
132
+	}
133
+}
134
+
135
+func getBackingFs(v *types.Info) string {
136
+	if v.DriverStatus == nil {
137
+		return ""
138
+	}
139
+	for _, pair := range v.DriverStatus {
140
+		if pair[0] == "Backing Filesystem" {
141
+			return pair[1]
142
+		}
143
+	}
144
+	return ""
71 145
 }
72 146
 
73 147
 // parseInitVersion parses a Tini version string, and extracts the version.
... ...
@@ -8,3 +8,6 @@ import (
8 8
 // fillPlatformInfo fills the platform related info.
9 9
 func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo) {
10 10
 }
11
+
12
+func fillDriverWarnings(v *types.Info) {
13
+}
... ...
@@ -21,6 +21,8 @@ keywords: "API, Docker, rcli, REST, documentation"
21 21
   and `OperatingSystem` if the daemon was unable to obtain this information.
22 22
 * `GET /info` now returns information about the product license, if a license
23 23
   has been applied to the daemon.
24
+* `GET /info` now returns a `Warnings` field, containing warnings and informational
25
+  messages about missing features, or issues related to the daemon configuration.
24 26
 * `POST /swarm/init` now accepts a `DefaultAddrPool` property to set global scope default address pool
25 27
 * `POST /swarm/init` now accepts a `SubnetSize` property to set global scope networks by giving the
26 28
   length of the subnet masks for every such network