github.com/adityamillind98/moby@v23.0.0-rc.4+incompatible/daemon/info_unix.go (about) 1 //go:build !windows 2 // +build !windows 3 4 package daemon // import "github.com/docker/docker/daemon" 5 6 import ( 7 "context" 8 "fmt" 9 "os/exec" 10 "path/filepath" 11 "strings" 12 13 "github.com/docker/docker/api/types" 14 containertypes "github.com/docker/docker/api/types/container" 15 "github.com/docker/docker/pkg/rootless" 16 "github.com/docker/docker/pkg/sysinfo" 17 "github.com/pkg/errors" 18 "github.com/sirupsen/logrus" 19 ) 20 21 // fillPlatformInfo fills the platform related info. 22 func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo) { 23 v.CgroupDriver = daemon.getCgroupDriver() 24 v.CgroupVersion = "1" 25 if sysInfo.CgroupUnified { 26 v.CgroupVersion = "2" 27 } 28 29 if v.CgroupDriver != cgroupNoneDriver { 30 v.MemoryLimit = sysInfo.MemoryLimit 31 v.SwapLimit = sysInfo.SwapLimit 32 v.KernelMemory = sysInfo.KernelMemory 33 v.KernelMemoryTCP = sysInfo.KernelMemoryTCP 34 v.OomKillDisable = sysInfo.OomKillDisable 35 v.CPUCfsPeriod = sysInfo.CPUCfs 36 v.CPUCfsQuota = sysInfo.CPUCfs 37 v.CPUShares = sysInfo.CPUShares 38 v.CPUSet = sysInfo.Cpuset 39 v.PidsLimit = sysInfo.PidsLimit 40 } 41 v.Runtimes = daemon.configStore.GetAllRuntimes() 42 v.DefaultRuntime = daemon.configStore.GetDefaultRuntimeName() 43 v.InitBinary = daemon.configStore.GetInitPath() 44 v.RuncCommit.ID = "N/A" 45 v.ContainerdCommit.ID = "N/A" 46 v.InitCommit.ID = "N/A" 47 48 if rt := daemon.configStore.GetRuntime(v.DefaultRuntime); rt != nil { 49 if rv, err := exec.Command(rt.Path, "--version").Output(); err == nil { 50 if _, _, commit, err := parseRuntimeVersion(string(rv)); err != nil { 51 logrus.Warnf("failed to parse %s version: %v", rt.Path, err) 52 } else { 53 v.RuncCommit.ID = commit 54 } 55 } else { 56 logrus.Warnf("failed to retrieve %s version: %v", rt.Path, err) 57 } 58 } 59 60 if rv, err := daemon.containerd.Version(context.Background()); err == nil { 61 v.ContainerdCommit.ID = rv.Revision 62 } else { 63 logrus.Warnf("failed to retrieve containerd version: %v", err) 64 } 65 66 defaultInitBinary := daemon.configStore.GetInitPath() 67 if rv, err := exec.Command(defaultInitBinary, "--version").Output(); err == nil { 68 if _, commit, err := parseInitVersion(string(rv)); err != nil { 69 logrus.Warnf("failed to parse %s version: %s", defaultInitBinary, err) 70 } else { 71 v.InitCommit.ID = commit 72 } 73 } else { 74 logrus.Warnf("failed to retrieve %s version: %s", defaultInitBinary, err) 75 } 76 77 // Set expected and actual commits to the same value to prevent the client 78 // showing that the version does not match the "expected" version/commit. 79 v.RuncCommit.Expected = v.RuncCommit.ID 80 v.ContainerdCommit.Expected = v.ContainerdCommit.ID 81 v.InitCommit.Expected = v.InitCommit.ID 82 83 if v.CgroupDriver == cgroupNoneDriver { 84 if v.CgroupVersion == "2" { 85 v.Warnings = append(v.Warnings, "WARNING: Running in rootless-mode without cgroups. Systemd is required to enable cgroups in rootless-mode.") 86 } else { 87 v.Warnings = append(v.Warnings, "WARNING: Running in rootless-mode without cgroups. To enable cgroups in rootless-mode, you need to boot the system in cgroup v2 mode.") 88 } 89 } else { 90 if !v.MemoryLimit { 91 v.Warnings = append(v.Warnings, "WARNING: No memory limit support") 92 } 93 if !v.SwapLimit { 94 v.Warnings = append(v.Warnings, "WARNING: No swap limit support") 95 } 96 if !v.KernelMemoryTCP && v.CgroupVersion == "1" { 97 // kernel memory is not available for cgroup v2. 98 // Warning is not printed on cgroup v2, because there is no action user can take. 99 v.Warnings = append(v.Warnings, "WARNING: No kernel memory TCP limit support") 100 } 101 if !v.OomKillDisable && v.CgroupVersion == "1" { 102 // oom kill disable is not available for cgroup v2. 103 // Warning is not printed on cgroup v2, because there is no action user can take. 104 v.Warnings = append(v.Warnings, "WARNING: No oom kill disable support") 105 } 106 if !v.CPUCfsQuota { 107 v.Warnings = append(v.Warnings, "WARNING: No cpu cfs quota support") 108 } 109 if !v.CPUCfsPeriod { 110 v.Warnings = append(v.Warnings, "WARNING: No cpu cfs period support") 111 } 112 if !v.CPUShares { 113 v.Warnings = append(v.Warnings, "WARNING: No cpu shares support") 114 } 115 if !v.CPUSet { 116 v.Warnings = append(v.Warnings, "WARNING: No cpuset support") 117 } 118 // TODO add fields for these options in types.Info 119 if !sysInfo.BlkioWeight && v.CgroupVersion == "2" { 120 // blkio weight is not available on cgroup v1 since kernel 5.0. 121 // Warning is not printed on cgroup v1, because there is no action user can take. 122 // On cgroup v2, blkio weight is implemented using io.weight 123 v.Warnings = append(v.Warnings, "WARNING: No io.weight support") 124 } 125 if !sysInfo.BlkioWeightDevice && v.CgroupVersion == "2" { 126 v.Warnings = append(v.Warnings, "WARNING: No io.weight (per device) support") 127 } 128 if !sysInfo.BlkioReadBpsDevice { 129 if v.CgroupVersion == "2" { 130 v.Warnings = append(v.Warnings, "WARNING: No io.max (rbps) support") 131 } else { 132 v.Warnings = append(v.Warnings, "WARNING: No blkio throttle.read_bps_device support") 133 } 134 } 135 if !sysInfo.BlkioWriteBpsDevice { 136 if v.CgroupVersion == "2" { 137 v.Warnings = append(v.Warnings, "WARNING: No io.max (wbps) support") 138 } else { 139 v.Warnings = append(v.Warnings, "WARNING: No blkio throttle.write_bps_device support") 140 } 141 } 142 if !sysInfo.BlkioReadIOpsDevice { 143 if v.CgroupVersion == "2" { 144 v.Warnings = append(v.Warnings, "WARNING: No io.max (riops) support") 145 } else { 146 v.Warnings = append(v.Warnings, "WARNING: No blkio throttle.read_iops_device support") 147 } 148 } 149 if !sysInfo.BlkioWriteIOpsDevice { 150 if v.CgroupVersion == "2" { 151 v.Warnings = append(v.Warnings, "WARNING: No io.max (wiops) support") 152 } else { 153 v.Warnings = append(v.Warnings, "WARNING: No blkio throttle.write_iops_device support") 154 } 155 } 156 } 157 if !v.IPv4Forwarding { 158 v.Warnings = append(v.Warnings, "WARNING: IPv4 forwarding is disabled") 159 } 160 if !v.BridgeNfIptables { 161 v.Warnings = append(v.Warnings, "WARNING: bridge-nf-call-iptables is disabled") 162 } 163 if !v.BridgeNfIP6tables { 164 v.Warnings = append(v.Warnings, "WARNING: bridge-nf-call-ip6tables is disabled") 165 } 166 } 167 168 func (daemon *Daemon) fillPlatformVersion(v *types.Version) { 169 if rv, err := daemon.containerd.Version(context.Background()); err == nil { 170 v.Components = append(v.Components, types.ComponentVersion{ 171 Name: "containerd", 172 Version: rv.Version, 173 Details: map[string]string{ 174 "GitCommit": rv.Revision, 175 }, 176 }) 177 } 178 179 defaultRuntime := daemon.configStore.GetDefaultRuntimeName() 180 if rt := daemon.configStore.GetRuntime(defaultRuntime); rt != nil { 181 if rv, err := exec.Command(rt.Path, "--version").Output(); err == nil { 182 if _, ver, commit, err := parseRuntimeVersion(string(rv)); err != nil { 183 logrus.Warnf("failed to parse %s version: %v", rt.Path, err) 184 } else { 185 v.Components = append(v.Components, types.ComponentVersion{ 186 Name: defaultRuntime, 187 Version: ver, 188 Details: map[string]string{ 189 "GitCommit": commit, 190 }, 191 }) 192 } 193 } else { 194 logrus.Warnf("failed to retrieve %s version: %v", rt.Path, err) 195 } 196 } 197 198 defaultInitBinary := daemon.configStore.GetInitPath() 199 if rv, err := exec.Command(defaultInitBinary, "--version").Output(); err == nil { 200 if ver, commit, err := parseInitVersion(string(rv)); err != nil { 201 logrus.Warnf("failed to parse %s version: %s", defaultInitBinary, err) 202 } else { 203 v.Components = append(v.Components, types.ComponentVersion{ 204 Name: filepath.Base(defaultInitBinary), 205 Version: ver, 206 Details: map[string]string{ 207 "GitCommit": commit, 208 }, 209 }) 210 } 211 } else { 212 logrus.Warnf("failed to retrieve %s version: %s", defaultInitBinary, err) 213 } 214 215 daemon.fillRootlessVersion(v) 216 } 217 218 func (daemon *Daemon) fillRootlessVersion(v *types.Version) { 219 if !rootless.RunningWithRootlessKit() { 220 return 221 } 222 rlc, err := rootless.GetRootlessKitClient() 223 if err != nil { 224 logrus.Warnf("failed to create RootlessKit client: %v", err) 225 return 226 } 227 rlInfo, err := rlc.Info(context.TODO()) 228 if err != nil { 229 logrus.Warnf("failed to retrieve RootlessKit version: %v", err) 230 return 231 } 232 v.Components = append(v.Components, types.ComponentVersion{ 233 Name: "rootlesskit", 234 Version: rlInfo.Version, 235 Details: map[string]string{ 236 "ApiVersion": rlInfo.APIVersion, 237 "StateDir": rlInfo.StateDir, 238 "NetworkDriver": rlInfo.NetworkDriver.Driver, 239 "PortDriver": rlInfo.PortDriver.Driver, 240 }, 241 }) 242 243 switch rlInfo.NetworkDriver.Driver { 244 case "slirp4netns": 245 if rv, err := exec.Command("slirp4netns", "--version").Output(); err == nil { 246 if _, ver, commit, err := parseRuntimeVersion(string(rv)); err != nil { 247 logrus.Warnf("failed to parse slirp4netns version: %v", err) 248 } else { 249 v.Components = append(v.Components, types.ComponentVersion{ 250 Name: "slirp4netns", 251 Version: ver, 252 Details: map[string]string{ 253 "GitCommit": commit, 254 }, 255 }) 256 } 257 } else { 258 logrus.Warnf("failed to retrieve slirp4netns version: %v", err) 259 } 260 case "vpnkit": 261 if rv, err := exec.Command("vpnkit", "--version").Output(); err == nil { 262 v.Components = append(v.Components, types.ComponentVersion{ 263 Name: "vpnkit", 264 Version: strings.TrimSpace(string(rv)), 265 }) 266 } else { 267 logrus.Warnf("failed to retrieve vpnkit version: %v", err) 268 } 269 } 270 } 271 272 func fillDriverWarnings(v *types.Info) { 273 for _, pair := range v.DriverStatus { 274 if pair[0] == "Data loop file" { 275 msg := fmt.Sprintf("WARNING: %s: usage of loopback devices is "+ 276 "strongly discouraged for production use.\n "+ 277 "Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.", v.Driver) 278 279 v.Warnings = append(v.Warnings, msg) 280 continue 281 } 282 if pair[0] == "Supports d_type" && pair[1] == "false" { 283 backingFs := getBackingFs(v) 284 285 msg := fmt.Sprintf("WARNING: %s: the backing %s filesystem is formatted without d_type support, which leads to incorrect behavior.\n", v.Driver, backingFs) 286 if backingFs == "xfs" { 287 msg += " Reformat the filesystem with ftype=1 to enable d_type support.\n" 288 } 289 msg += " Running without d_type support will not be supported in future releases." 290 291 v.Warnings = append(v.Warnings, msg) 292 continue 293 } 294 } 295 } 296 297 func getBackingFs(v *types.Info) string { 298 for _, pair := range v.DriverStatus { 299 if pair[0] == "Backing Filesystem" { 300 return pair[1] 301 } 302 } 303 return "" 304 } 305 306 // parseInitVersion parses a Tini version string, and extracts the "version" 307 // and "git commit" from the output. 308 // 309 // Output example from `docker-init --version`: 310 // 311 // tini version 0.18.0 - git.fec3683 312 func parseInitVersion(v string) (version string, commit string, err error) { 313 parts := strings.Split(v, " - ") 314 315 if len(parts) >= 2 { 316 gitParts := strings.Split(strings.TrimSpace(parts[1]), ".") 317 if len(gitParts) == 2 && gitParts[0] == "git" { 318 commit = gitParts[1] 319 } 320 } 321 parts[0] = strings.TrimSpace(parts[0]) 322 if strings.HasPrefix(parts[0], "tini version ") { 323 version = strings.TrimPrefix(parts[0], "tini version ") 324 } 325 if version == "" && commit == "" { 326 err = errors.Errorf("unknown output format: %s", v) 327 } 328 return version, commit, err 329 } 330 331 // parseRuntimeVersion parses the output of `[runtime] --version` and extracts the 332 // "name", "version" and "git commit" from the output. 333 // 334 // Output example from `runc --version`: 335 // 336 // runc version 1.0.0-rc5+dev 337 // commit: 69663f0bd4b60df09991c08812a60108003fa340 338 // spec: 1.0.0 339 func parseRuntimeVersion(v string) (runtime string, version string, commit string, err error) { 340 lines := strings.Split(strings.TrimSpace(v), "\n") 341 for _, line := range lines { 342 if strings.Contains(line, "version") { 343 s := strings.Split(line, "version") 344 runtime = strings.TrimSpace(s[0]) 345 version = strings.TrimSpace(s[len(s)-1]) 346 continue 347 } 348 if strings.HasPrefix(line, "commit:") { 349 commit = strings.TrimSpace(strings.TrimPrefix(line, "commit:")) 350 continue 351 } 352 } 353 if version == "" && commit == "" { 354 err = errors.Errorf("unknown output format: %s", v) 355 } 356 return runtime, version, commit, err 357 } 358 359 func (daemon *Daemon) cgroupNamespacesEnabled(sysInfo *sysinfo.SysInfo) bool { 360 return sysInfo.CgroupNamespaces && containertypes.CgroupnsMode(daemon.configStore.CgroupNamespaceMode).IsPrivate() 361 } 362 363 // Rootless returns true if daemon is running in rootless mode 364 func (daemon *Daemon) Rootless() bool { 365 return daemon.configStore.Rootless 366 }