github.com/ttys3/engine@v17.12.1-ce-rc2+incompatible/pkg/sysinfo/sysinfo_linux.go (about)

     1  package 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  // New returns a new SysInfo, using the filesystem to detect which features
    30  // the kernel supports. If `quiet` is `false` warnings are printed in logs
    31  // whenever an error occurs or misconfigurations are present.
    32  func New(quiet bool) *SysInfo {
    33  	sysInfo := &SysInfo{}
    34  	cgMounts, err := findCgroupMountpoints()
    35  	if err != nil {
    36  		logrus.Warnf("Failed to parse cgroup information: %v", err)
    37  	} else {
    38  		sysInfo.cgroupMemInfo = checkCgroupMem(cgMounts, quiet)
    39  		sysInfo.cgroupCPUInfo = checkCgroupCPU(cgMounts, quiet)
    40  		sysInfo.cgroupBlkioInfo = checkCgroupBlkioInfo(cgMounts, quiet)
    41  		sysInfo.cgroupCpusetInfo = checkCgroupCpusetInfo(cgMounts, quiet)
    42  		sysInfo.cgroupPids = checkCgroupPids(quiet)
    43  	}
    44  
    45  	_, ok := cgMounts["devices"]
    46  	sysInfo.CgroupDevicesEnabled = ok
    47  
    48  	sysInfo.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward")
    49  	sysInfo.BridgeNFCallIPTablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables")
    50  	sysInfo.BridgeNFCallIP6TablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables")
    51  
    52  	// Check if AppArmor is supported.
    53  	if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) {
    54  		sysInfo.AppArmor = true
    55  	}
    56  
    57  	// Check if Seccomp is supported, via CONFIG_SECCOMP.
    58  	if err := unix.Prctl(unix.PR_GET_SECCOMP, 0, 0, 0, 0); err != unix.EINVAL {
    59  		// Make sure the kernel has CONFIG_SECCOMP_FILTER.
    60  		if err := unix.Prctl(unix.PR_SET_SECCOMP, unix.SECCOMP_MODE_FILTER, 0, 0, 0); err != unix.EINVAL {
    61  			sysInfo.Seccomp = true
    62  		}
    63  	}
    64  
    65  	return sysInfo
    66  }
    67  
    68  // checkCgroupMem reads the memory information from the memory cgroup mount point.
    69  func checkCgroupMem(cgMounts map[string]string, quiet bool) cgroupMemInfo {
    70  	mountPoint, ok := cgMounts["memory"]
    71  	if !ok {
    72  		if !quiet {
    73  			logrus.Warn("Your kernel does not support cgroup memory limit")
    74  		}
    75  		return cgroupMemInfo{}
    76  	}
    77  
    78  	swapLimit := cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes")
    79  	if !quiet && !swapLimit {
    80  		logrus.Warn("Your kernel does not support swap memory limit")
    81  	}
    82  	memoryReservation := cgroupEnabled(mountPoint, "memory.soft_limit_in_bytes")
    83  	if !quiet && !memoryReservation {
    84  		logrus.Warn("Your kernel does not support memory reservation")
    85  	}
    86  	oomKillDisable := cgroupEnabled(mountPoint, "memory.oom_control")
    87  	if !quiet && !oomKillDisable {
    88  		logrus.Warn("Your kernel does not support oom control")
    89  	}
    90  	memorySwappiness := cgroupEnabled(mountPoint, "memory.swappiness")
    91  	if !quiet && !memorySwappiness {
    92  		logrus.Warn("Your kernel does not support memory swappiness")
    93  	}
    94  	kernelMemory := cgroupEnabled(mountPoint, "memory.kmem.limit_in_bytes")
    95  	if !quiet && !kernelMemory {
    96  		logrus.Warn("Your kernel does not support kernel memory limit")
    97  	}
    98  
    99  	return cgroupMemInfo{
   100  		MemoryLimit:       true,
   101  		SwapLimit:         swapLimit,
   102  		MemoryReservation: memoryReservation,
   103  		OomKillDisable:    oomKillDisable,
   104  		MemorySwappiness:  memorySwappiness,
   105  		KernelMemory:      kernelMemory,
   106  	}
   107  }
   108  
   109  // checkCgroupCPU reads the cpu information from the cpu cgroup mount point.
   110  func checkCgroupCPU(cgMounts map[string]string, quiet bool) cgroupCPUInfo {
   111  	mountPoint, ok := cgMounts["cpu"]
   112  	if !ok {
   113  		if !quiet {
   114  			logrus.Warn("Unable to find cpu cgroup in mounts")
   115  		}
   116  		return cgroupCPUInfo{}
   117  	}
   118  
   119  	cpuShares := cgroupEnabled(mountPoint, "cpu.shares")
   120  	if !quiet && !cpuShares {
   121  		logrus.Warn("Your kernel does not support cgroup cpu shares")
   122  	}
   123  
   124  	cpuCfsPeriod := cgroupEnabled(mountPoint, "cpu.cfs_period_us")
   125  	if !quiet && !cpuCfsPeriod {
   126  		logrus.Warn("Your kernel does not support cgroup cfs period")
   127  	}
   128  
   129  	cpuCfsQuota := cgroupEnabled(mountPoint, "cpu.cfs_quota_us")
   130  	if !quiet && !cpuCfsQuota {
   131  		logrus.Warn("Your kernel does not support cgroup cfs quotas")
   132  	}
   133  
   134  	cpuRealtimePeriod := cgroupEnabled(mountPoint, "cpu.rt_period_us")
   135  	if !quiet && !cpuRealtimePeriod {
   136  		logrus.Warn("Your kernel does not support cgroup rt period")
   137  	}
   138  
   139  	cpuRealtimeRuntime := cgroupEnabled(mountPoint, "cpu.rt_runtime_us")
   140  	if !quiet && !cpuRealtimeRuntime {
   141  		logrus.Warn("Your kernel does not support cgroup rt runtime")
   142  	}
   143  
   144  	return cgroupCPUInfo{
   145  		CPUShares:          cpuShares,
   146  		CPUCfsPeriod:       cpuCfsPeriod,
   147  		CPUCfsQuota:        cpuCfsQuota,
   148  		CPURealtimePeriod:  cpuRealtimePeriod,
   149  		CPURealtimeRuntime: cpuRealtimeRuntime,
   150  	}
   151  }
   152  
   153  // checkCgroupBlkioInfo reads the blkio information from the blkio cgroup mount point.
   154  func checkCgroupBlkioInfo(cgMounts map[string]string, quiet bool) cgroupBlkioInfo {
   155  	mountPoint, ok := cgMounts["blkio"]
   156  	if !ok {
   157  		if !quiet {
   158  			logrus.Warn("Unable to find blkio cgroup in mounts")
   159  		}
   160  		return cgroupBlkioInfo{}
   161  	}
   162  
   163  	weight := cgroupEnabled(mountPoint, "blkio.weight")
   164  	if !quiet && !weight {
   165  		logrus.Warn("Your kernel does not support cgroup blkio weight")
   166  	}
   167  
   168  	weightDevice := cgroupEnabled(mountPoint, "blkio.weight_device")
   169  	if !quiet && !weightDevice {
   170  		logrus.Warn("Your kernel does not support cgroup blkio weight_device")
   171  	}
   172  
   173  	readBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_bps_device")
   174  	if !quiet && !readBpsDevice {
   175  		logrus.Warn("Your kernel does not support cgroup blkio throttle.read_bps_device")
   176  	}
   177  
   178  	writeBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_bps_device")
   179  	if !quiet && !writeBpsDevice {
   180  		logrus.Warn("Your kernel does not support cgroup blkio throttle.write_bps_device")
   181  	}
   182  	readIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_iops_device")
   183  	if !quiet && !readIOpsDevice {
   184  		logrus.Warn("Your kernel does not support cgroup blkio throttle.read_iops_device")
   185  	}
   186  
   187  	writeIOpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_iops_device")
   188  	if !quiet && !writeIOpsDevice {
   189  		logrus.Warn("Your kernel does not support cgroup blkio throttle.write_iops_device")
   190  	}
   191  	return cgroupBlkioInfo{
   192  		BlkioWeight:          weight,
   193  		BlkioWeightDevice:    weightDevice,
   194  		BlkioReadBpsDevice:   readBpsDevice,
   195  		BlkioWriteBpsDevice:  writeBpsDevice,
   196  		BlkioReadIOpsDevice:  readIOpsDevice,
   197  		BlkioWriteIOpsDevice: writeIOpsDevice,
   198  	}
   199  }
   200  
   201  // checkCgroupCpusetInfo reads the cpuset information from the cpuset cgroup mount point.
   202  func checkCgroupCpusetInfo(cgMounts map[string]string, quiet bool) cgroupCpusetInfo {
   203  	mountPoint, ok := cgMounts["cpuset"]
   204  	if !ok {
   205  		if !quiet {
   206  			logrus.Warn("Unable to find cpuset cgroup in mounts")
   207  		}
   208  		return cgroupCpusetInfo{}
   209  	}
   210  
   211  	cpus, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.cpus"))
   212  	if err != nil {
   213  		return cgroupCpusetInfo{}
   214  	}
   215  
   216  	mems, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.mems"))
   217  	if err != nil {
   218  		return cgroupCpusetInfo{}
   219  	}
   220  
   221  	return cgroupCpusetInfo{
   222  		Cpuset: true,
   223  		Cpus:   strings.TrimSpace(string(cpus)),
   224  		Mems:   strings.TrimSpace(string(mems)),
   225  	}
   226  }
   227  
   228  // checkCgroupPids reads the pids information from the pids cgroup mount point.
   229  func checkCgroupPids(quiet bool) cgroupPids {
   230  	_, err := cgroups.FindCgroupMountpoint("pids")
   231  	if err != nil {
   232  		if !quiet {
   233  			logrus.Warn(err)
   234  		}
   235  		return cgroupPids{}
   236  	}
   237  
   238  	return cgroupPids{
   239  		PidsLimit: true,
   240  	}
   241  }
   242  
   243  func cgroupEnabled(mountPoint, name string) bool {
   244  	_, err := os.Stat(path.Join(mountPoint, name))
   245  	return err == nil
   246  }
   247  
   248  func readProcBool(path string) bool {
   249  	val, err := ioutil.ReadFile(path)
   250  	if err != nil {
   251  		return false
   252  	}
   253  	return strings.TrimSpace(string(val)) == "1"
   254  }