Files
VictoriaMetrics/lib/cgroup/util.go
andriibeee a3df0f890b lib/cgroup: support reading cpu/memory limits from systemd slices
cgroup v2 version supports slices ( aka path hierarchy) for resource limits. It's mostly supported by systemd
and container runtime build on top of it.

 This commit reads subpath for systemd slices and traverse it with reading minimal limit value.

Related docs:
https://docs.oracle.com/en/operating-systems/oracle-linux/9/systemd/SystemdMngCgroupsV2.html#SlicesServicesScopesHierarchy
https://www.freedesktop.org/software/systemd/man/latest/systemd.slice.html

Fixes https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10635
2026-04-22 10:18:03 +02:00

72 lines
2.1 KiB
Go

package cgroup
import (
"fmt"
"os"
"path"
"strconv"
"strings"
)
func getStatGeneric(statName, sysfsPrefix, cgroupPath, cgroupGrepLine string) (int64, error) {
data, err := getFileContents(statName, sysfsPrefix, cgroupPath, cgroupGrepLine)
if err != nil {
return 0, err
}
data = strings.TrimSpace(data)
n, err := strconv.ParseInt(data, 10, 64)
if err != nil {
return 0, fmt.Errorf("cannot parse %q: %w", cgroupPath, err)
}
return n, nil
}
func getFileContents(statName, sysfsPrefix, cgroupPath, cgroupGrepLine string) (string, error) {
filepath := path.Join(sysfsPrefix, statName)
data, err := os.ReadFile(filepath)
if err == nil {
return string(data), nil
}
cgroupData, err := os.ReadFile(cgroupPath)
if err != nil {
return "", err
}
subPath, err := grepFirstMatch(string(cgroupData), cgroupGrepLine, 2, ":")
if err != nil {
return "", fmt.Errorf("cannot find cgroup path for %q in %q: %w", cgroupGrepLine, cgroupPath, err)
}
filepath = path.Join(sysfsPrefix, subPath, statName)
data, err = os.ReadFile(filepath)
if err != nil {
return "", err
}
return string(data), nil
}
// readCgroupV2SubPath reads cgroupv2 sub-path
// for example 0::/user.slice/user-1000.slice/session-5.scope
// See https://www.freedesktop.org/software/systemd/man/latest/systemd.slice.html
// and https://docs.oracle.com/en/operating-systems/oracle-linux/9/systemd/SystemdMngCgroupsV2.html#SystemdScopes
func readCgroupV2SubPath(cgroupPath string) (string, error) {
data, err := os.ReadFile(cgroupPath)
if err != nil {
return "", err
}
return grepFirstMatch(string(data), "", 2, ":")
}
// grepFirstMatch searches match line at data and returns item from it by index with given delimiter.
func grepFirstMatch(data string, match string, index int, delimiter string) (string, error) {
lines := strings.Split(string(data), "\n")
for _, s := range lines {
if !strings.Contains(s, match) {
continue
}
parts := strings.Split(s, delimiter)
if index < len(parts) {
return strings.TrimSpace(parts[index]), nil
}
}
return "", fmt.Errorf("cannot find %q in %q", match, data)
}