diff --git a/container/common/helpers.go b/container/common/helpers.go index 4eba4af2c3a..1801c606618 100644 --- a/container/common/helpers.go +++ b/container/common/helpers.go @@ -17,6 +17,7 @@ package common import ( "fmt" "io/ioutil" + "math" "os" "path" "path/filepath" @@ -122,18 +123,43 @@ func GetSpec(cgroupPaths map[string]string, machineInfoFactory info.MachineInfoF cpuRoot, ok := cgroupPaths["cpu"] if ok { if utils.FileExists(cpuRoot) { - spec.HasCpu = true - spec.Cpu.Limit = readUInt64(cpuRoot, "cpu.shares") - spec.Cpu.Period = readUInt64(cpuRoot, "cpu.cfs_period_us") - quota := readString(cpuRoot, "cpu.cfs_quota_us") - - if quota != "" && quota != "-1" { - val, err := strconv.ParseUint(quota, 10, 64) - if err != nil { - klog.Errorf("GetSpec: Failed to parse CPUQuota from %q: %s", path.Join(cpuRoot, "cpu.cfs_quota_us"), err) - } else { - spec.Cpu.Quota = val + if !cgroups.IsCgroup2UnifiedMode() { + spec.HasCpu = true + spec.Cpu.Limit = readUInt64(cpuRoot, "cpu.shares") + spec.Cpu.Period = readUInt64(cpuRoot, "cpu.cfs_period_us") + quota := readString(cpuRoot, "cpu.cfs_quota_us") + + if quota != "" && quota != "-1" { + val, err := strconv.ParseUint(quota, 10, 64) + if err != nil { + klog.Errorf("GetSpec: Failed to parse CPUQuota from %q: %s", path.Join(cpuRoot, "cpu.cfs_quota_us"), err) + } else { + spec.Cpu.Quota = val + } + } + } else { + spec.HasCpu = true + + weight := readUInt64(cpuRoot, "cpu.weight") + if weight > 0 { + limit, err := convertCPUWeightToCPULimit(weight) + if err != nil { + klog.Errorf("GetSpec: Failed to read CPULimit from %q: %s", path.Join(cpuRoot, "cpu.weight"), err) + } else { + spec.Cpu.Limit = limit + } } + max := readString(cpuRoot, "cpu.max") + if max != "" { + splits := strings.SplitN(max, " ", 2) + if len(splits) != 2 { + klog.Errorf("GetSpec: Failed to parse CPUmax from %q", path.Join(cpuRoot, "cpu.max")) + } else { + spec.Cpu.Quota = parseUint64String(splits[0]) + spec.Cpu.Period = parseUint64String(splits[1]) + } + } + } } } @@ -224,6 +250,31 @@ func readString(dirpath string, file string) string { return strings.TrimSpace(string(out)) } +// Convert from [1-10000] to [2-262144] +func convertCPUWeightToCPULimit(weight uint64) (uint64, error) { + if weight < 1 || weight > 10000 { + return 0, fmt.Errorf("convertCPUWeightToCPULimit: invalid cpu weight: %v", weight) + } + return 2 + ((weight-1)*262142)/9999, nil +} + +func parseUint64String(strValue string) uint64 { + if strValue == "max" { + return math.MaxUint64 + } + if strValue == "" { + return 0 + } + + val, err := strconv.ParseUint(strValue, 10, 64) + if err != nil { + klog.Errorf("readUInt64: Failed to parse int %q: %s", strValue, err) + return 0 + } + + return val +} + func readUInt64(dirpath string, file string) uint64 { out := readString(dirpath, file) if out == "" || out == "max" { diff --git a/container/common/helpers_test.go b/container/common/helpers_test.go index 071349a6e17..a31d8a911a0 100644 --- a/container/common/helpers_test.go +++ b/container/common/helpers_test.go @@ -26,3 +26,28 @@ func BenchmarkListDirectories(b *testing.B) { } } } + +func TestConvertCpuWeightToCpuLimit(t *testing.T) { + limit, err := convertCPUWeightToCPULimit(1) + if err != nil { + t.Fatalf("Error in convertCPUWeightToCPULimit: %s", err) + } + if limit != 2 { + t.Fatalf("convertCPUWeightToCPULimit(1) != 2") + } + limit, err = convertCPUWeightToCPULimit(10000) + if err != nil { + t.Fatalf("Error in convertCPUWeightToCPULimit: %s", err) + } + if limit != 262144 { + t.Fatalf("convertCPUWeightToCPULimit(10000) != 262144") + } + _, err = convertCPUWeightToCPULimit(0) + if err == nil { + t.Fatalf("convertCPUWeightToCPULimit(0) must raise an error") + } + _, err = convertCPUWeightToCPULimit(10001) + if err == nil { + t.Fatalf("convertCPUWeightToCPULimit(10001) must raise an error") + } +}