github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/pkg/sysinfo/sysinfo_linux.go (about)

     1  package sysinfo // import "github.com/docker/docker/pkg/sysinfo"
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"os"
     7  	"path"
     8  	"strings"
     9  
    10  	"github.com/opencontainers/runc/libcontainer/cgroups"
    11  	"github.com/sirupsen/logrus"
    12  	"golang.org/x/sys/unix"
    13  )
    14  
    15  func findCgroupMountpoints() (map[string]string, error) {
    16  	cgMounts, err := cgroups.GetCgroupMounts(false)
    17  	if err != nil {
    18  		return nil, fmt.Errorf("Failed to parse cgroup information: %v", err)
    19  	}
    20  	mps := make(map[string]string)
    21  	for _, m := range cgMounts {
    22  		for _, ss := range m.Subsystems {
    23  			mps[ss] = m.Mountpoint
    24  		}
    25  	}
    26  	return mps, nil
    27  }
    28  
    29  type infoCollector func(info *SysInfo, cgMounts map[string]string) (warnings []string)
    30  
    31  // New returns a new SysInfo, using the filesystem to detect which features
    32  // the kernel supports. If `quiet` is `false` warnings are printed in logs
    33  // whenever an error occurs or misconfigurations are present.
    34  func New(quiet bool) *SysInfo {
    35  	var ops []infoCollector
    36  	var warnings []string
    37  	sysInfo := &SysInfo{}
    38  	cgMounts, err := findCgroupMountpoints()
    39  	if err != nil {
    40  		logrus.Warn(err)
    41  	} else {
    42  		ops = append(ops, []infoCollector{
    43  			applyMemoryCgroupInfo,
    44  			applyCPUCgroupInfo,
    45  			applyBlkioCgroupInfo,
    46  			applyCPUSetCgroupInfo,
    47  			applyPIDSCgroupInfo,
    48  			applyDevicesCgroupInfo,
    49  		}...)
    50  	}
    51  
    52  	ops = append(ops, []infoCollector{
    53  		applyNetworkingInfo,
    54  		applyAppArmorInfo,
    55  		applySeccompInfo,
    56  	}...)
    57  
    58  	for _, o := range ops {
    59  		w := o(sysInfo, cgMounts)
    60  		warnings = append(warnings, w...)
    61  	}
    62  	if !quiet {
    63  		for _, w := range warnings {
    64  			logrus.Warn(w)
    65  		}
    66  	}
    67  	return sysInfo
    68  }
    69  
    70  // applyMemoryCgroupInfo reads the memory information from the memory cgroup mount point.
    71  func applyMemoryCgroupInfo(info *SysInfo, cgMounts map[string]string) []string {
    72  	var warnings []string
    73  	mountPoint, ok := cgMounts["memory"]
    74  	if !ok {
    75  		warnings = append(warnings, "Your kernel does not support cgroup memory limit")
    76  		return warnings
    77  	}
    78  	info.MemoryLimit = ok
    79  
    80  	info.SwapLimit = cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes")
    81  	if !info.SwapLimit {
    82  		warnings = append(warnings, "Your kernel does not support swap memory limit")
    83  	}
    84  	info.MemoryReservation = cgroupEnabled(mountPoint, "memory.soft_limit_in_bytes")
    85  	if !info.MemoryReservation {
    86  		warnings = append(warnings, "Your kernel does not support memory reservation")
    87  	}
    88  	info.OomKillDisable = cgroupEnabled(mountPoint, "memory.oom_control")
    89  	if !info.OomKillDisable {
    90  		warnings = append(warnings, "Your kernel does not support oom control")
    91  	}
    92  	info.MemorySwappiness = cgroupEnabled(mountPoint, "memory.swappiness")
    93  	if !info.MemorySwappiness {
    94  		warnings = append(warnings, "Your kernel does not support memory swappiness")
    95  	}
    96  	info.KernelMemory = cgroupEnabled(mountPoint, "memory.kmem.limit_in_bytes")
    97  	if !info.KernelMemory {
    98  		warnings = append(warnings, "Your kernel does not support kernel memory limit")
    99  	}
   100  	info.KernelMemoryTCP = cgroupEnabled(mountPoint, "memory.kmem.tcp.limit_in_bytes")
   101  	if !info.KernelMemoryTCP {
   102  		warnings = append(warnings, "Your kernel does not support kernel memory TCP limit")
   103  	}
   104  
   105  	return warnings
   106  }
   107  
   108  // applyCPUCgroupInfo reads the cpu information from the cpu cgroup mount point.
   109  func applyCPUCgroupInfo(info *SysInfo, cgMounts map[string]string) []string {
   110  	var warnings []string
   111  	mountPoint, ok := cgMounts["cpu"]
   112  	if !ok {
   113  		warnings = append(warnings, "Unable to find cpu cgroup in mounts")
   114  		return warnings
   115  	}
   116  
   117  	info.CPUShares = cgroupEnabled(mountPoint, "cpu.shares")
   118  	if !info.CPUShares {
   119  		warnings = append(warnings, "Your kernel does not support cgroup cpu shares")
   120  	}
   121  
   122  	info.CPUCfsPeriod = cgroupEnabled(mountPoint, "cpu.cfs_period_us")
   123  	if !info.CPUCfsPeriod {
   124  		warnings = append(warnings, "Your kernel does not support cgroup cfs period")
   125  	}
   126  
   127  	info.CPUCfsQuota = cgroupEnabled(mountPoint, "cpu.cfs_quota_us")
   128  	if !info.CPUCfsQuota {
   129  		warnings = append(warnings, "Your kernel does not support cgroup cfs quotas")
   130  	}
   131  
   132  	info.CPURealtimePeriod = cgroupEnabled(mountPoint, "cpu.rt_period_us")
   133  	if !info.CPURealtimePeriod {
   134  		warnings = append(warnings, "Your kernel does not support cgroup rt period")
   135  	}
   136  
   137  	info.CPURealtimeRuntime = cgroupEnabled(mountPoint, "cpu.rt_runtime_us")
   138  	if !info.CPURealtimeRuntime {
   139  		warnings = append(warnings, "Your kernel does not support cgroup rt runtime")
   140  	}
   141  
   142  	return warnings
   143  }
   144  
   145  // applyBlkioCgroupInfo reads the blkio information from the blkio cgroup mount point.
   146  func applyBlkioCgroupInfo(info *SysInfo, cgMounts map[string]string) []string {
   147  	var warnings []string
   148  	mountPoint, ok := cgMounts["blkio"]
   149  	if !ok {
   150  		warnings = append(warnings, "Unable to find blkio cgroup in mounts")
   151  		return warnings
   152  	}
   153  
   154  	info.BlkioWeight = cgroupEnabled(mountPoint, "blkio.weight")
   155  	if !info.BlkioWeight {
   156  		warnings = append(warnings, "Your kernel does not support cgroup blkio weight")
   157  	}
   158  
   159  	info.BlkioWeightDevice = cgroupEnabled(mountPoint, "blkio.weight_device")
   160  	if !info.BlkioWeightDevice {
   161  		warnings = append(warnings, "Your kernel does not support cgroup blkio weight_device")
   162  	}
   163  
   164  	info.BlkioReadBpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.read_bps_device")
   165  	if !info.BlkioReadBpsDevice {
   166  		warnings = append(warnings, "Your kernel does not support cgroup blkio throttle.read_bps_device")
   167  	}
   168  
   169  	info.BlkioWriteBpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.write_bps_device")
   170  	if !info.BlkioWriteBpsDevice {
   171  		warnings = append(warnings, "Your kernel does not support cgroup blkio throttle.write_bps_device")
   172  	}
   173  	info.BlkioReadIOpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device")
   174  	if !info.BlkioReadIOpsDevice {
   175  		warnings = append(warnings, "Your kernel does not support cgroup blkio throttle.read_iops_device")
   176  	}
   177  
   178  	info.BlkioWriteIOpsDevice = cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device")
   179  	if !info.BlkioWriteIOpsDevice {
   180  		warnings = append(warnings, "Your kernel does not support cgroup blkio throttle.write_iops_device")
   181  	}
   182  
   183  	return warnings
   184  }
   185  
   186  // applyCPUSetCgroupInfo reads the cpuset information from the cpuset cgroup mount point.
   187  func applyCPUSetCgroupInfo(info *SysInfo, cgMounts map[string]string) []string {
   188  	var warnings []string
   189  	mountPoint, ok := cgMounts["cpuset"]
   190  	if !ok {
   191  		warnings = append(warnings, "Unable to find cpuset cgroup in mounts")
   192  		return warnings
   193  	}
   194  	info.Cpuset = ok
   195  
   196  	var err error
   197  
   198  	cpus, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.cpus"))
   199  	if err != nil {
   200  		return warnings
   201  	}
   202  	info.Cpus = strings.TrimSpace(string(cpus))
   203  
   204  	mems, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.mems"))
   205  	if err != nil {
   206  		return warnings
   207  	}
   208  	info.Mems = strings.TrimSpace(string(mems))
   209  
   210  	return warnings
   211  }
   212  
   213  // applyPIDSCgroupInfo reads the pids information from the pids cgroup mount point.
   214  func applyPIDSCgroupInfo(info *SysInfo, _ map[string]string) []string {
   215  	var warnings []string
   216  	_, err := cgroups.FindCgroupMountpoint("", "pids")
   217  	if err != nil {
   218  		warnings = append(warnings, err.Error())
   219  		return warnings
   220  	}
   221  	info.PidsLimit = true
   222  	return warnings
   223  }
   224  
   225  // applyDevicesCgroupInfo reads the pids information from the devices cgroup mount point.
   226  func applyDevicesCgroupInfo(info *SysInfo, cgMounts map[string]string) []string {
   227  	var warnings []string
   228  	_, ok := cgMounts["devices"]
   229  	info.CgroupDevicesEnabled = ok
   230  	return warnings
   231  }
   232  
   233  // applyNetworkingInfo adds networking information to the info.
   234  func applyNetworkingInfo(info *SysInfo, _ map[string]string) []string {
   235  	var warnings []string
   236  	info.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward")
   237  	info.BridgeNFCallIPTablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables")
   238  	info.BridgeNFCallIP6TablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables")
   239  	return warnings
   240  }
   241  
   242  // applyAppArmorInfo adds AppArmor information to the info.
   243  func applyAppArmorInfo(info *SysInfo, _ map[string]string) []string {
   244  	var warnings []string
   245  	if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) {
   246  		if _, err := ioutil.ReadFile("/sys/kernel/security/apparmor/profiles"); err == nil {
   247  			info.AppArmor = true
   248  		}
   249  	}
   250  	return warnings
   251  }
   252  
   253  // applySeccompInfo checks if Seccomp is supported, via CONFIG_SECCOMP.
   254  func applySeccompInfo(info *SysInfo, _ map[string]string) []string {
   255  	var warnings []string
   256  	// Check if Seccomp is supported, via CONFIG_SECCOMP.
   257  	if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); err != unix.EINVAL {
   258  		// Make sure the kernel has CONFIG_SECCOMP_FILTER.
   259  		if err := unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0); err != unix.EINVAL {
   260  			info.Seccomp = true
   261  		}
   262  	}
   263  	return warnings
   264  }
   265  
   266  func cgroupEnabled(mountPoint, name string) bool {
   267  	_, err := os.Stat(path.Join(mountPoint, name))
   268  	return err == nil
   269  }
   270  
   271  func readProcBool(path string) bool {
   272  	val, err := ioutil.ReadFile(path)
   273  	if err != nil {
   274  		return false
   275  	}
   276  	return strings.TrimSpace(string(val)) == "1"
   277  }