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 }