func checkCgroupMem(quiet bool) *cgroupMemInfo { info := &cgroupMemInfo{} mountPoint, err := cgroups.FindCgroupMountpoint("memory") if err != nil { if !quiet { logrus.Warnf("Your kernel does not support cgroup memory limit: %v", err) } return info } info.MemoryLimit = true info.SwapLimit = cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes") if !quiet && !info.SwapLimit { logrus.Warn("Your kernel does not support swap memory limit.") } info.OomKillDisable = cgroupEnabled(mountPoint, "memory.oom_control") if !quiet && !info.OomKillDisable { logrus.Warnf("Your kernel does not support oom control.") } info.MemorySwappiness = cgroupEnabled(mountPoint, "memory.swappiness") if !quiet && !info.MemorySwappiness { logrus.Warnf("Your kernel does not support memory swappiness.") } return info }
func checkCgroupCPU(quiet bool) *cgroupCPUInfo { info := &cgroupCPUInfo{} mountPoint, err := cgroups.FindCgroupMountpoint("cpu") if err != nil { if !quiet { logrus.Warn(err) } return info } info.CPUShares = cgroupEnabled(mountPoint, "cpu.shares") if !quiet && !info.CPUShares { logrus.Warn("Your kernel does not support cgroup cpu shares") } info.CPUCfsPeriod = cgroupEnabled(mountPoint, "cpu.cfs_period_us") if !quiet && !info.CPUCfsPeriod { logrus.Warn("Your kernel does not support cgroup cfs period") } info.CPUCfsQuota = cgroupEnabled(mountPoint, "cpu.cfs_quota_us") if !quiet && !info.CPUCfsQuota { logrus.Warn("Your kernel does not support cgroup cfs quotas") } return info }
func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) { mountpoint, err := cgroups.FindCgroupMountpoint(subsystem) if err != nil { return "", err } initPath, err := cgroups.GetInitCgroupDir(subsystem) if err != nil { return "", err } // if pid 1 is systemd 226 or later, it will be in init.scope, not the root initPath = strings.TrimSuffix(filepath.Clean(initPath), "init.scope") slice := "system.slice" if c.Parent != "" { slice = c.Parent } slice, err = ExpandSlice(slice) if err != nil { return "", err } return filepath.Join(mountpoint, initPath, slice, getUnitName(c)), nil }
// checkCgroupBlkioInfo reads the blkio information from the blkio cgroup mount point. func checkCgroupBlkioInfo(quiet bool) cgroupBlkioInfo { mountPoint, err := cgroups.FindCgroupMountpoint("blkio") if err != nil { if !quiet { logrus.Warn(err) } return cgroupBlkioInfo{} } weight := cgroupEnabled(mountPoint, "blkio.weight") if !quiet && !weight { logrus.Warn("Your kernel does not support cgroup blkio weight") } weightDevice := cgroupEnabled(mountPoint, "blkio.weight_device") if !quiet && !weightDevice { logrus.Warn("Your kernel does not support cgroup blkio weight_device") } readBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.read_bps_device") if !quiet && !readBpsDevice { logrus.Warn("Your kernel does not support cgroup blkio throttle.read_bps_device") } writeBpsDevice := cgroupEnabled(mountPoint, "blkio.throttle.write_bps_device") if !quiet && !writeBpsDevice { logrus.Warn("Your kernel does not support cgroup blkio throttle.write_bps_device") } return cgroupBlkioInfo{ BlkioWeight: weight, BlkioWeightDevice: weightDevice, BlkioReadBpsDevice: readBpsDevice, BlkioWriteBpsDevice: writeBpsDevice, } }
// New returns a new SysInfo, using the filesystem to detect which features // the kernel supports. If `quiet` is `false` warnings are printed in logs // whenever an error occurs or misconfigurations are present. func New(quiet bool) *SysInfo { sysInfo := &SysInfo{} sysInfo.cgroupMemInfo = checkCgroupMem(quiet) sysInfo.cgroupCPUInfo = checkCgroupCPU(quiet) sysInfo.cgroupBlkioInfo = checkCgroupBlkioInfo(quiet) sysInfo.cgroupCpusetInfo = checkCgroupCpusetInfo(quiet) _, err := cgroups.FindCgroupMountpoint("devices") sysInfo.CgroupDevicesEnabled = err == nil sysInfo.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward") sysInfo.BridgeNfCallIptablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables") sysInfo.BridgeNfCallIP6tablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables") // Check if AppArmor is supported. if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) { sysInfo.AppArmor = true } // Check if Seccomp is supported, via CONFIG_SECCOMP. if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_GET_SECCOMP, 0, 0); err != syscall.EINVAL { // Make sure the kernel has CONFIG_SECCOMP_FILTER. if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_SECCOMP, SeccompModeFilter, 0); err != syscall.EINVAL { sysInfo.Seccomp = true } } return sysInfo }
// checkCgroupMem reads the memory information from the memory cgroup mount point. func checkCgroupMem(quiet bool) cgroupMemInfo { mountPoint, err := cgroups.FindCgroupMountpoint("memory") if err != nil { if !quiet { logrus.Warnf("Your kernel does not support cgroup memory limit: %v", err) } return cgroupMemInfo{} } swapLimit := cgroupEnabled(mountPoint, "memory.memsw.limit_in_bytes") if !quiet && !swapLimit { logrus.Warn("Your kernel does not support swap memory limit.") } oomKillDisable := cgroupEnabled(mountPoint, "memory.oom_control") if !quiet && !oomKillDisable { logrus.Warnf("Your kernel does not support oom control.") } memorySwappiness := cgroupEnabled(mountPoint, "memory.swappiness") if !quiet && !memorySwappiness { logrus.Warnf("Your kernel does not support memory swappiness.") } return cgroupMemInfo{ MemoryLimit: true, SwapLimit: swapLimit, OomKillDisable: oomKillDisable, MemorySwappiness: memorySwappiness, } }
// checkCgroupCpusetInfo reads the cpuset information from the cpuset cgroup mount point. func checkCgroupCpusetInfo(quiet bool) cgroupCpusetInfo { mountPoint, err := cgroups.FindCgroupMountpoint("cpuset") if err != nil { if !quiet { logrus.Warn(err) } return cgroupCpusetInfo{} } cpus, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.cpus")) if err != nil { return cgroupCpusetInfo{} } mems, err := ioutil.ReadFile(path.Join(mountPoint, "cpuset.mems")) if err != nil { return cgroupCpusetInfo{} } return cgroupCpusetInfo{ Cpuset: true, Cpus: strings.TrimSpace(string(cpus)), Mems: strings.TrimSpace(string(mems)), } }
// checkCgroupCPU reads the cpu information from the cpu cgroup mount point. func checkCgroupCPU(quiet bool) cgroupCPUInfo { mountPoint, err := cgroups.FindCgroupMountpoint("cpu") if err != nil { if !quiet { logrus.Warn(err) } return cgroupCPUInfo{} } cpuShares := cgroupEnabled(mountPoint, "cpu.shares") if !quiet && !cpuShares { logrus.Warn("Your kernel does not support cgroup cpu shares") } cpuCfsPeriod := cgroupEnabled(mountPoint, "cpu.cfs_period_us") if !quiet && !cpuCfsPeriod { logrus.Warn("Your kernel does not support cgroup cfs period") } cpuCfsQuota := cgroupEnabled(mountPoint, "cpu.cfs_quota_us") if !quiet && !cpuCfsQuota { logrus.Warn("Your kernel does not support cgroup cfs quotas") } return cgroupCPUInfo{ CPUShares: cpuShares, CPUCfsPeriod: cpuCfsPeriod, CPUCfsQuota: cpuCfsQuota, } }
func setupCGroups(partitions map[string]int64) error { subsystems, err := cgroups.GetAllSubsystems() if err != nil { return fmt.Errorf("error getting cgroup subsystems: %s", err) } else if len(subsystems) == 0 { return fmt.Errorf("failed to detect any cgroup subsystems") } for _, subsystem := range subsystems { if _, err := cgroups.FindCgroupMountpoint(subsystem); err == nil { // subsystem already mounted continue } path := filepath.Join(cgroupRoot, subsystem) if err := os.Mkdir(path, 0755); err != nil && !os.IsExist(err) { return fmt.Errorf("error creating %s cgroup directory: %s", subsystem, err) } if err := syscall.Mount("cgroup", path, "cgroup", 0, subsystem); err != nil { return fmt.Errorf("error mounting %s cgroup: %s", subsystem, err) } } for name, shares := range partitions { if err := createCGroupPartition(name, shares); err != nil { return err } } return nil }
func getSubsystemPath(subsystem string, id string) (string, error) { var subsystemPath string systemSlice := "system.slice" // hack for finding proper mount point for shares // cpu shares are part of cpu group, but openlibcontainers does not support it if subsystem == "shares" { subsystem = "cpu" } groupPath, err := cgroups.FindCgroupMountpoint(subsystem) if err != nil { fmt.Fprintf(os.Stderr, "[WARNING] Could not find mount point for %v\n", subsystem) return "", err } if isHost(id) { if isRunningSystemd() { subsystemPath = filepath.Join(groupPath, systemSlice) } else { subsystemPath = groupPath } return subsystemPath, nil } if isFsCgroupParent(groupPath) { // default cgroupfs parent is used for container subsystemPath = filepath.Join(groupPath, "docker", id) } else { // cgroup is created under systemd.slice subsystemPath = filepath.Join(groupPath, systemSlice, "docker-"+id+".scope") } return subsystemPath, nil }
// checkCgroupCpusetInfo reads the cpuset information from the cpuset cgroup mount point. func checkCgroupCpusetInfo(quiet bool) cgroupCpusetInfo { _, err := cgroups.FindCgroupMountpoint("cpuset") if err != nil { if !quiet { logrus.Warn(err) } return cgroupCpusetInfo{} } return cgroupCpusetInfo{Cpuset: true} }
func findCgroupRootAndDir(subsystem string) (string, string, error) { cgroupRoot, err := cgroups.FindCgroupMountpoint(subsystem) if err != nil { return "", "", err } cgroupDir, err := cgroups.GetThisCgroupDir(subsystem) if err != nil { return "", "", err } return cgroupRoot, cgroupDir, nil }
func createCgroupdir(dir string) error { for _, subsystem := range []string{"memory", "cpu", "cpuset", "blkio"} { subsystemDir, err := cgroups.FindCgroupMountpoint(subsystem) if err != nil { return err } if err := os.MkdirAll(filepath.Join(subsystemDir, dir), 0700); err != nil { return err } } return nil }
func (h *cgroupfsHelper) apply(subsystem, file, data string) error { subsystemDir, err := cgroups.FindCgroupMountpoint(subsystem) if err != nil { return err } if err := os.MkdirAll(filepath.Join(subsystemDir, h.cgroupDir), 0700); err != nil { return err } if err := writeFile(filepath.Join(subsystemDir, h.cgroupDir), file, data); err != nil { return err } return nil }
func checkCgroupCpusetInfo(quiet bool) *cgroupCpusetInfo { info := &cgroupCpusetInfo{} _, err := cgroups.FindCgroupMountpoint("cpuset") if err != nil { if !quiet { logrus.Warn(err) } return info } info.Cpuset = true return info }
// checkCgroupPids reads the pids information from the pids cgroup mount point. func checkCgroupPids(quiet bool) cgroupPids { _, err := cgroups.FindCgroupMountpoint("pids") if err != nil { if !quiet { logrus.Warn(err) } return cgroupPids{} } return cgroupPids{ PidsLimit: true, } }
func (d Dir) Lookup(ctx context.Context, name string) (fusefs.Node, error) { if name == "hello" { return File{}, nil } else if fileInfo, ok := fileMap[name]; ok { mountPoint, err := cgroups.FindCgroupMountpoint(fileInfo.subsysName) if err != nil { return nil, fuse.ENODATA } fileInfo.initFunc(filepath.Join(mountPoint, d.cgroupdir), fileInfo) return fileInfo.node, nil } return nil, fuse.ENOENT }
// checkCgroupBlkioInfo reads the blkio information from the blkio cgroup mount point. func checkCgroupBlkioInfo(quiet bool) cgroupBlkioInfo { mountPoint, err := cgroups.FindCgroupMountpoint("blkio") if err != nil { if !quiet { logrus.Warn(err) } return cgroupBlkioInfo{} } w := cgroupEnabled(mountPoint, "blkio.weight") if !quiet && !w { logrus.Warn("Your kernel does not support cgroup blkio weight") } return cgroupBlkioInfo{BlkioWeight: w} }
func checkCgroupBlkioInfo(quiet bool) *cgroupBlkioInfo { info := &cgroupBlkioInfo{} mountPoint, err := cgroups.FindCgroupMountpoint("blkio") if err != nil { if !quiet { logrus.Warn(err) } return info } info.BlkioWeight = cgroupEnabled(mountPoint, "blkio.weight") if !quiet && !info.BlkioWeight { logrus.Warn("Your kernel does not support cgroup blkio weight") } return info }
func validateCgroupMounts() (string, string) { const recommendedMount = "/sys/fs/cgroup" desc := fmt.Sprintf("\tAny cgroup mount point that is detectible and accessible is supported. %s is recommended as a standard location.\n", recommendedMount) mnt, err := cgroups.FindCgroupMountpoint("cpu") if err != nil { out := "Could not locate cgroup mount point.\n" out += desc return Unknown, out } mnt = path.Dir(mnt) if !utils.FileExists(mnt) { out := fmt.Sprintf("Cgroup mount directory %s inaccessible.\n", mnt) out += desc return Unsupported, out } mounts, err := ioutil.ReadDir(mnt) if err != nil { out := fmt.Sprintf("Could not read cgroup mount directory %s.\n", mnt) out += desc return Unsupported, out } mountNames := "\tCgroup mount directories: " for _, mount := range mounts { mountNames += mount.Name() + " " } mountNames += "\n" out := fmt.Sprintf("Cgroups are mounted at %s.\n", mnt) out += mountNames out += desc info, err := ioutil.ReadFile("/proc/mounts") if err != nil { out := fmt.Sprintf("Could not read /proc/mounts.\n") out += desc return Unsupported, out } out += "\tCgroup mounts:\n" for _, line := range strings.Split(string(info), "\n") { if strings.Contains(line, " cgroup ") { out += "\t" + line + "\n" } } if mnt == recommendedMount { return Recommended, out } return Supported, out }
func getSubsystemPath(c *configs.Cgroup, subsystem string) (string, error) { mountpoint, err := cgroups.FindCgroupMountpoint(subsystem) if err != nil { return "", err } initPath, err := cgroups.GetInitCgroupDir(subsystem) if err != nil { return "", err } slice := "system.slice" if c.Slice != "" { slice = c.Slice } return filepath.Join(mountpoint, initPath, slice, getUnitName(c)), nil }
func (raw *data) path(subsystem string) (string, error) { mnt, err := cgroups.FindCgroupMountpoint(subsystem) // If we didn't mount the subsystem, there is no point we make the path. if err != nil { return "", err } // If the cgroup name/path is absolute do not look relative to the cgroup of the init process. if filepath.IsAbs(raw.cgroup) { return filepath.Join(raw.root, subsystem, raw.cgroup), nil } parent, err := raw.parent(subsystem, mnt) if err != nil { return "", err } return filepath.Join(parent, raw.cgroup), nil }
// New returns a new SysInfo, using the filesystem to detect which features the kernel supports. func New(quiet bool) *SysInfo { sysInfo := &SysInfo{} sysInfo.cgroupMemInfo = checkCgroupMem(quiet) sysInfo.cgroupCpuInfo = checkCgroupCpu(quiet) _, err := cgroups.FindCgroupMountpoint("devices") sysInfo.CgroupDevicesEnabled = err == nil sysInfo.IPv4ForwardingDisabled = !readProcBool("/proc/sys/net/ipv4/ip_forward") sysInfo.BridgeNfCallIptablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-iptables") sysInfo.BridgeNfCallIp6tablesDisabled = !readProcBool("/proc/sys/net/bridge/bridge-nf-call-ip6tables") // Check if AppArmor is supported. if _, err := os.Stat("/sys/kernel/security/apparmor"); !os.IsNotExist(err) { sysInfo.AppArmor = true } return sysInfo }
func UseSystemd() bool { check.Do(func() { if *noSystemd { return } // Check for system.slice in systemd and cpu cgroup. for _, cgroupType := range []string{"name=systemd", "cpu"} { mnt, err := cgroups.FindCgroupMountpoint(cgroupType) if err == nil { // systemd presence does not mean systemd controls cgroups. // If system.slice cgroup exists, then systemd is taking control. // This breaks if user creates system.slice manually :) if utils.FileExists(path.Join(mnt, "system.slice")) { useSystemd = true break } } } }) return useSystemd }
func newCgroupfsHelper(mountpoint, cgroupDir string) (*cgroupfsHelper, error) { var err error if mountpoint == "" { if mountpoint, err = ioutil.TempDir("", ""); err != nil { return nil, err } } memCgroupDir, err := cgroups.FindCgroupMountpoint("memory") if err != nil { return nil, err } if cgroupDir == "" { if cgroupDir, err = ioutil.TempDir(memCgroupDir, ""); err != nil { return nil, err } cgroupDir = strings.TrimPrefix(cgroupDir, memCgroupDir) } if err := createCgroupdir(cgroupDir); err != nil { return nil, err } return &cgroupfsHelper{mountpoint, cgroupDir}, nil }
func validateMemoryAccounting(available_cgroups map[string]int) string { ok, _ := areCgroupsPresent(available_cgroups, []string{"memory"}) if !ok { return "\tHierarchical memory accounting status unknown: memory cgroup not enabled.\n" } mnt, err := cgroups.FindCgroupMountpoint("memory") if err != nil { return "\tHierarchical memory accounting status unknown: memory cgroup not mounted.\n" } hier, err := ioutil.ReadFile(path.Join(mnt, "memory.use_hierarchy")) if err != nil { return "\tHierarchical memory accounting status unknown: hierarchy interface unavailable.\n" } var enabled int n, err := fmt.Sscanf(string(hier), "%d", &enabled) if err != nil || n != 1 { return "\tHierarchical memory accounting status unknown: hierarchy interface unreadable.\n" } if enabled == 1 { return "\tHierarchical memory accounting enabled. Reported memory usage includes memory used by child containers.\n" } return "\tHierarchical memory accounting disabled. Memory usage does not include usage from child containers.\n" }
// +build !windows package main import ( "io/ioutil" "path" "github.com/opencontainers/runc/libcontainer/cgroups" ) var ( cpuCfsPeriod = testRequirement{ func() bool { cgroupCPUMountpoint, err := cgroups.FindCgroupMountpoint("cpu") if err != nil { return false } if _, err := ioutil.ReadFile(path.Join(cgroupCPUMountpoint, "cpu.cfs_period_us")); err != nil { return false } return true }, "Test requires an environment that supports cgroup cfs period.", } cpuCfsQuota = testRequirement{ func() bool { cgroupCPUMountpoint, err := cgroups.FindCgroupMountpoint("cpu") if err != nil { return false }
// FindCgroupMountpoint returns cgroup mountpoint of a given subsystem func (dc *DockerClient) FindCgroupMountpoint(subsystem string) (string, error) { return cgroups.FindCgroupMountpoint(subsystem) }