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  }