in container/common/helpers.go [67:218]
func getSpecInternal(cgroupPaths map[string]string, machineInfoFactory info.MachineInfoFactory, hasNetwork, hasFilesystem, cgroup2UnifiedMode bool) (info.ContainerSpec, error) {
var spec info.ContainerSpec
// Assume unified hierarchy containers.
// Get the lowest creation time from all hierarchies as the container creation time.
now := time.Now()
lowestTime := now
for _, cgroupPathDir := range cgroupPaths {
dir, err := os.Stat(cgroupPathDir)
if err == nil && dir.ModTime().Before(lowestTime) {
lowestTime = dir.ModTime()
}
// The modified time of the cgroup directory sometimes changes whenever a subcontainer is created.
// eg. /docker will have creation time matching the creation of latest docker container.
// Use clone_children/events as a workaround as it isn't usually modified. It is only likely changed
// immediately after creating a container. If the directory modified time is lower, we use that.
cgroupPathFile := path.Join(cgroupPathDir, "cgroup.clone_children")
if cgroup2UnifiedMode {
cgroupPathFile = path.Join(cgroupPathDir, "cgroup.events")
}
fi, err := os.Stat(cgroupPathFile)
if err == nil && fi.ModTime().Before(lowestTime) {
lowestTime = fi.ModTime()
}
}
if lowestTime.Before(bootTime) {
lowestTime = bootTime
}
if lowestTime != now {
spec.CreationTime = lowestTime
}
// Get machine info.
mi, err := machineInfoFactory.GetMachineInfo()
if err != nil {
return spec, err
}
// CPU.
cpuRoot, ok := GetControllerPath(cgroupPaths, "cpu", cgroup2UnifiedMode)
if ok {
if utils.FileExists(cpuRoot) {
if cgroup2UnifiedMode {
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 {
if splits[0] != "max" {
spec.Cpu.Quota = parseUint64String(splits[0])
}
spec.Cpu.Period = parseUint64String(splits[1])
}
}
} else {
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
}
}
}
}
}
// Cpu Mask.
// This will fail for non-unified hierarchies. We'll return the whole machine mask in that case.
cpusetRoot, ok := GetControllerPath(cgroupPaths, "cpuset", cgroup2UnifiedMode)
if ok {
if utils.FileExists(cpusetRoot) {
spec.HasCpu = true
mask := ""
if cgroup2UnifiedMode {
mask = readString(cpusetRoot, "cpuset.cpus.effective")
} else {
mask = readString(cpusetRoot, "cpuset.cpus")
}
spec.Cpu.Mask = utils.FixCpuMask(mask, mi.NumCores)
}
}
// Memory
memoryRoot, ok := GetControllerPath(cgroupPaths, "memory", cgroup2UnifiedMode)
if ok {
if cgroup2UnifiedMode {
if utils.FileExists(path.Join(memoryRoot, "memory.max")) {
spec.HasMemory = true
spec.Memory.Reservation = readUInt64(memoryRoot, "memory.min")
spec.Memory.Limit = readUInt64(memoryRoot, "memory.max")
spec.Memory.SwapLimit = readUInt64(memoryRoot, "memory.swap.max")
}
} else {
if utils.FileExists(memoryRoot) {
spec.HasMemory = true
spec.Memory.Limit = readUInt64(memoryRoot, "memory.limit_in_bytes")
spec.Memory.SwapLimit = readUInt64(memoryRoot, "memory.memsw.limit_in_bytes")
spec.Memory.Reservation = readUInt64(memoryRoot, "memory.soft_limit_in_bytes")
}
}
}
// Hugepage
hugepageRoot, ok := cgroupPaths["hugetlb"]
if ok {
if utils.FileExists(hugepageRoot) {
spec.HasHugetlb = true
}
}
// Processes, read it's value from pids path directly
pidsRoot, ok := GetControllerPath(cgroupPaths, "pids", cgroup2UnifiedMode)
if ok {
if utils.FileExists(pidsRoot) {
spec.HasProcesses = true
spec.Processes.Limit = readUInt64(pidsRoot, "pids.max")
}
}
spec.HasNetwork = hasNetwork
spec.HasFilesystem = hasFilesystem
ioControllerName := "blkio"
if cgroup2UnifiedMode {
ioControllerName = "io"
}
if blkioRoot, ok := GetControllerPath(cgroupPaths, ioControllerName, cgroup2UnifiedMode); ok && utils.FileExists(blkioRoot) {
spec.HasDiskIo = true
}
return spec, nil
}