package manager import ( "errors" "fmt" "path/filepath" "github.com/opencontainers/runc/libcontainer/cgroups" "github.com/opencontainers/runc/libcontainer/cgroups/fs" "github.com/opencontainers/runc/libcontainer/cgroups/fs2" "github.com/opencontainers/runc/libcontainer/cgroups/systemd" "github.com/opencontainers/runc/libcontainer/configs" ) // New returns the instance of a cgroup manager, which is chosen // based on the local environment (whether cgroup v1 or v2 is used) // and the config (whether config.Systemd is set or not). func New(config *configs.Cgroup) (cgroups.Manager, error) { return NewWithPaths(config, nil) } // NewWithPaths is similar to New, and can be used in case cgroup paths // are already well known, which can save some resources. // // For cgroup v1, the keys are controller/subsystem name, and the values // are absolute filesystem paths to the appropriate cgroups. // // For cgroup v2, the only key allowed is "" (empty string), and the value // is the unified cgroup path. func NewWithPaths(config *configs.Cgroup, paths map[string]string) (cgroups.Manager, error) { if config == nil { return nil, errors.New("cgroups/manager.New: config must not be nil") } if config.Systemd && !systemd.IsRunningSystemd() { return nil, errors.New("systemd not running on this host, cannot use systemd cgroups manager") } // Cgroup v2 aka unified hierarchy. if cgroups.IsCgroup2UnifiedMode() { path, err := getUnifiedPath(paths) if err != nil { return nil, fmt.Errorf("manager.NewWithPaths: inconsistent paths: %w", err) } if config.Systemd { return systemd.NewUnifiedManager(config, path) } return fs2.NewManager(config, path) } // Cgroup v1. if config.Systemd { return systemd.NewLegacyManager(config, paths) } return fs.NewManager(config, paths) } // getUnifiedPath is an implementation detail of libcontainer factory. // Historically, it saves cgroup paths as per-subsystem path map (as returned // by cm.GetPaths(""), but with v2 we only have one single unified path // (with "" as a key). // // This function converts from that map to string (using "" as a key), // and also checks that the map itself is sane. func getUnifiedPath(paths map[string]string) (string, error) { if len(paths) > 1 { return "", fmt.Errorf("expected a single path, got %+v", paths) } path := paths[""] // can be empty if path != "" { if filepath.Clean(path) != path || !filepath.IsAbs(path) { return "", fmt.Errorf("invalid path: %q", path) } } return path, nil }