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 }