github.com/docker/docker@v299999999.0.0-20200612211812-aaf470eca7b5+incompatible/daemon/info_unix.go (about)

     1  // +build !windows
     2  
     3  package daemon // import "github.com/docker/docker/daemon"
     4  
     5  import (
     6  	"context"
     7  	"fmt"
     8  	"os/exec"
     9  	"path/filepath"
    10  	"strings"
    11  
    12  	"github.com/docker/docker/api/types"
    13  	containertypes "github.com/docker/docker/api/types/container"
    14  	"github.com/docker/docker/dockerversion"
    15  	"github.com/docker/docker/pkg/sysinfo"
    16  	"github.com/pkg/errors"
    17  	"github.com/sirupsen/logrus"
    18  )
    19  
    20  // fillPlatformInfo fills the platform related info.
    21  func (daemon *Daemon) fillPlatformInfo(v *types.Info, sysInfo *sysinfo.SysInfo) {
    22  	v.CgroupDriver = daemon.getCgroupDriver()
    23  	v.CgroupVersion = "1"
    24  	if sysInfo.CgroupUnified {
    25  		v.CgroupVersion = "2"
    26  	}
    27  
    28  	v.MemoryLimit = sysInfo.MemoryLimit
    29  	v.SwapLimit = sysInfo.SwapLimit
    30  	v.KernelMemory = sysInfo.KernelMemory
    31  	v.KernelMemoryTCP = sysInfo.KernelMemoryTCP
    32  	v.OomKillDisable = sysInfo.OomKillDisable
    33  	v.CPUCfsPeriod = sysInfo.CPUCfsPeriod
    34  	v.CPUCfsQuota = sysInfo.CPUCfsQuota
    35  	v.CPUShares = sysInfo.CPUShares
    36  	v.CPUSet = sysInfo.Cpuset
    37  	v.PidsLimit = sysInfo.PidsLimit
    38  	v.Runtimes = daemon.configStore.GetAllRuntimes()
    39  	v.DefaultRuntime = daemon.configStore.GetDefaultRuntimeName()
    40  	v.InitBinary = daemon.configStore.GetInitPath()
    41  
    42  	defaultRuntimeBinary := daemon.configStore.GetRuntime(v.DefaultRuntime).Path
    43  	if rv, err := exec.Command(defaultRuntimeBinary, "--version").Output(); err == nil {
    44  		if _, _, commit, err := parseRuntimeVersion(string(rv)); err != nil {
    45  			logrus.Warnf("failed to parse %s version: %v", defaultRuntimeBinary, err)
    46  			v.RuncCommit.ID = "N/A"
    47  		} else {
    48  			v.RuncCommit.ID = commit
    49  		}
    50  	} else {
    51  		logrus.Warnf("failed to retrieve %s version: %v", defaultRuntimeBinary, err)
    52  		v.RuncCommit.ID = "N/A"
    53  	}
    54  
    55  	// runc is now shipped as a separate package. Set "expected" to same value
    56  	// as "ID" to prevent clients from reporting a version-mismatch
    57  	v.RuncCommit.Expected = v.RuncCommit.ID
    58  
    59  	if rv, err := daemon.containerd.Version(context.Background()); err == nil {
    60  		v.ContainerdCommit.ID = rv.Revision
    61  	} else {
    62  		logrus.Warnf("failed to retrieve containerd version: %v", err)
    63  		v.ContainerdCommit.ID = "N/A"
    64  	}
    65  
    66  	// containerd is now shipped as a separate package. Set "expected" to same
    67  	// value as "ID" to prevent clients from reporting a version-mismatch
    68  	v.ContainerdCommit.Expected = v.ContainerdCommit.ID
    69  
    70  	// TODO is there still a need to check the expected version for tini?
    71  	// if not, we can change this, and just set "Expected" to v.InitCommit.ID
    72  	v.InitCommit.Expected = dockerversion.InitCommitID
    73  
    74  	defaultInitBinary := daemon.configStore.GetInitPath()
    75  	if rv, err := exec.Command(defaultInitBinary, "--version").Output(); err == nil {
    76  		if _, commit, err := parseInitVersion(string(rv)); err != nil {
    77  			logrus.Warnf("failed to parse %s version: %s", defaultInitBinary, err)
    78  			v.InitCommit.ID = "N/A"
    79  		} else {
    80  			v.InitCommit.ID = commit
    81  			if len(dockerversion.InitCommitID) > len(commit) {
    82  				v.InitCommit.Expected = dockerversion.InitCommitID[0:len(commit)]
    83  			}
    84  		}
    85  	} else {
    86  		logrus.Warnf("failed to retrieve %s version: %s", defaultInitBinary, err)
    87  		v.InitCommit.ID = "N/A"
    88  	}
    89  
    90  	if v.CgroupDriver == cgroupNoneDriver {
    91  		if v.CgroupVersion == "2" {
    92  			v.Warnings = append(v.Warnings, "WARNING: Running in rootless-mode without cgroup. To enable cgroup in rootless-mode, you need to set exec-opt \"native.cgroupdriver=systemd\".")
    93  		} else {
    94  			v.Warnings = append(v.Warnings, "WARNING: Running in rootless-mode without cgroup. To enable cgroup in rootless-mode, you need to boot the system in cgroup v2 mode and set exec-opt \"native.cgroupdriver=systemd\".")
    95  		}
    96  	} else {
    97  		if !v.MemoryLimit {
    98  			v.Warnings = append(v.Warnings, "WARNING: No memory limit support")
    99  		}
   100  		if !v.SwapLimit {
   101  			v.Warnings = append(v.Warnings, "WARNING: No swap limit support")
   102  		}
   103  		if !v.KernelMemory {
   104  			v.Warnings = append(v.Warnings, "WARNING: No kernel memory limit support")
   105  		}
   106  		if !v.KernelMemoryTCP {
   107  			v.Warnings = append(v.Warnings, "WARNING: No kernel memory TCP limit support")
   108  		}
   109  		if !v.OomKillDisable {
   110  			v.Warnings = append(v.Warnings, "WARNING: No oom kill disable support")
   111  		}
   112  		if !v.CPUCfsQuota {
   113  			v.Warnings = append(v.Warnings, "WARNING: No cpu cfs quota support")
   114  		}
   115  		if !v.CPUCfsPeriod {
   116  			v.Warnings = append(v.Warnings, "WARNING: No cpu cfs period support")
   117  		}
   118  		if !v.CPUShares {
   119  			v.Warnings = append(v.Warnings, "WARNING: No cpu shares support")
   120  		}
   121  		if !v.CPUSet {
   122  			v.Warnings = append(v.Warnings, "WARNING: No cpuset support")
   123  		}
   124  		if v.CgroupVersion == "2" {
   125  			v.Warnings = append(v.Warnings, "WARNING: Support for cgroup v2 is experimental")
   126  		}
   127  	}
   128  	if !v.IPv4Forwarding {
   129  		v.Warnings = append(v.Warnings, "WARNING: IPv4 forwarding is disabled")
   130  	}
   131  	if !v.BridgeNfIptables {
   132  		v.Warnings = append(v.Warnings, "WARNING: bridge-nf-call-iptables is disabled")
   133  	}
   134  	if !v.BridgeNfIP6tables {
   135  		v.Warnings = append(v.Warnings, "WARNING: bridge-nf-call-ip6tables is disabled")
   136  	}
   137  }
   138  
   139  func (daemon *Daemon) fillPlatformVersion(v *types.Version) {
   140  	if rv, err := daemon.containerd.Version(context.Background()); err == nil {
   141  		v.Components = append(v.Components, types.ComponentVersion{
   142  			Name:    "containerd",
   143  			Version: rv.Version,
   144  			Details: map[string]string{
   145  				"GitCommit": rv.Revision,
   146  			},
   147  		})
   148  	}
   149  
   150  	defaultRuntime := daemon.configStore.GetDefaultRuntimeName()
   151  	defaultRuntimeBinary := daemon.configStore.GetRuntime(defaultRuntime).Path
   152  	if rv, err := exec.Command(defaultRuntimeBinary, "--version").Output(); err == nil {
   153  		if _, ver, commit, err := parseRuntimeVersion(string(rv)); err != nil {
   154  			logrus.Warnf("failed to parse %s version: %v", defaultRuntimeBinary, err)
   155  		} else {
   156  			v.Components = append(v.Components, types.ComponentVersion{
   157  				Name:    defaultRuntime,
   158  				Version: ver,
   159  				Details: map[string]string{
   160  					"GitCommit": commit,
   161  				},
   162  			})
   163  		}
   164  	} else {
   165  		logrus.Warnf("failed to retrieve %s version: %v", defaultRuntimeBinary, err)
   166  	}
   167  
   168  	defaultInitBinary := daemon.configStore.GetInitPath()
   169  	if rv, err := exec.Command(defaultInitBinary, "--version").Output(); err == nil {
   170  		if ver, commit, err := parseInitVersion(string(rv)); err != nil {
   171  			logrus.Warnf("failed to parse %s version: %s", defaultInitBinary, err)
   172  		} else {
   173  			v.Components = append(v.Components, types.ComponentVersion{
   174  				Name:    filepath.Base(defaultInitBinary),
   175  				Version: ver,
   176  				Details: map[string]string{
   177  					"GitCommit": commit,
   178  				},
   179  			})
   180  		}
   181  	} else {
   182  		logrus.Warnf("failed to retrieve %s version: %s", defaultInitBinary, err)
   183  	}
   184  }
   185  
   186  func fillDriverWarnings(v *types.Info) {
   187  	for _, pair := range v.DriverStatus {
   188  		if pair[0] == "Data loop file" {
   189  			msg := fmt.Sprintf("WARNING: %s: usage of loopback devices is "+
   190  				"strongly discouraged for production use.\n         "+
   191  				"Use `--storage-opt dm.thinpooldev` to specify a custom block storage device.", v.Driver)
   192  
   193  			v.Warnings = append(v.Warnings, msg)
   194  			continue
   195  		}
   196  		if pair[0] == "Supports d_type" && pair[1] == "false" {
   197  			backingFs := getBackingFs(v)
   198  
   199  			msg := fmt.Sprintf("WARNING: %s: the backing %s filesystem is formatted without d_type support, which leads to incorrect behavior.\n", v.Driver, backingFs)
   200  			if backingFs == "xfs" {
   201  				msg += "         Reformat the filesystem with ftype=1 to enable d_type support.\n"
   202  			}
   203  			msg += "         Running without d_type support will not be supported in future releases."
   204  
   205  			v.Warnings = append(v.Warnings, msg)
   206  			continue
   207  		}
   208  	}
   209  }
   210  
   211  func getBackingFs(v *types.Info) string {
   212  	for _, pair := range v.DriverStatus {
   213  		if pair[0] == "Backing Filesystem" {
   214  			return pair[1]
   215  		}
   216  	}
   217  	return ""
   218  }
   219  
   220  // parseInitVersion parses a Tini version string, and extracts the "version"
   221  // and "git commit" from the output.
   222  //
   223  // Output example from `docker-init --version`:
   224  //
   225  //     tini version 0.18.0 - git.fec3683
   226  func parseInitVersion(v string) (version string, commit string, err error) {
   227  	parts := strings.Split(v, " - ")
   228  
   229  	if len(parts) >= 2 {
   230  		gitParts := strings.Split(strings.TrimSpace(parts[1]), ".")
   231  		if len(gitParts) == 2 && gitParts[0] == "git" {
   232  			commit = gitParts[1]
   233  		}
   234  	}
   235  	parts[0] = strings.TrimSpace(parts[0])
   236  	if strings.HasPrefix(parts[0], "tini version ") {
   237  		version = strings.TrimPrefix(parts[0], "tini version ")
   238  	}
   239  	if version == "" && commit == "" {
   240  		err = errors.Errorf("unknown output format: %s", v)
   241  	}
   242  	return version, commit, err
   243  }
   244  
   245  // parseRuntimeVersion parses the output of `[runtime] --version` and extracts the
   246  // "name", "version" and "git commit" from the output.
   247  //
   248  // Output example from `runc --version`:
   249  //
   250  //   runc version 1.0.0-rc5+dev
   251  //   commit: 69663f0bd4b60df09991c08812a60108003fa340
   252  //   spec: 1.0.0
   253  func parseRuntimeVersion(v string) (runtime string, version string, commit string, err error) {
   254  	lines := strings.Split(strings.TrimSpace(v), "\n")
   255  	for _, line := range lines {
   256  		if strings.Contains(line, "version") {
   257  			s := strings.Split(line, "version")
   258  			runtime = strings.TrimSpace(s[0])
   259  			version = strings.TrimSpace(s[len(s)-1])
   260  			continue
   261  		}
   262  		if strings.HasPrefix(line, "commit:") {
   263  			commit = strings.TrimSpace(strings.TrimPrefix(line, "commit:"))
   264  			continue
   265  		}
   266  	}
   267  	if version == "" && commit == "" {
   268  		err = errors.Errorf("unknown output format: %s", v)
   269  	}
   270  	return runtime, version, commit, err
   271  }
   272  
   273  func (daemon *Daemon) cgroupNamespacesEnabled(sysInfo *sysinfo.SysInfo) bool {
   274  	return sysInfo.CgroupNamespaces && containertypes.CgroupnsMode(daemon.configStore.CgroupNamespaceMode).IsPrivate()
   275  }
   276  
   277  // Rootless returns true if daemon is running in rootless mode
   278  func (daemon *Daemon) Rootless() bool {
   279  	return daemon.configStore.Rootless
   280  }