github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/cgroups/manager/new.go (about) 1 package manager 2 3 import ( 4 "errors" 5 "fmt" 6 "path/filepath" 7 8 "github.com/opencontainers/runc/libcontainer/cgroups" 9 "github.com/opencontainers/runc/libcontainer/cgroups/fs" 10 "github.com/opencontainers/runc/libcontainer/cgroups/fs2" 11 "github.com/opencontainers/runc/libcontainer/cgroups/systemd" 12 "github.com/opencontainers/runc/libcontainer/configs" 13 ) 14 15 // New returns the instance of a cgroup manager, which is chosen 16 // based on the local environment (whether cgroup v1 or v2 is used) 17 // and the config (whether config.Systemd is set or not). 18 func New(config *configs.Cgroup) (cgroups.Manager, error) { 19 return NewWithPaths(config, nil) 20 } 21 22 // NewWithPaths is similar to New, and can be used in case cgroup paths 23 // are already well known, which can save some resources. 24 // 25 // For cgroup v1, the keys are controller/subsystem name, and the values 26 // are absolute filesystem paths to the appropriate cgroups. 27 // 28 // For cgroup v2, the only key allowed is "" (empty string), and the value 29 // is the unified cgroup path. 30 func NewWithPaths(config *configs.Cgroup, paths map[string]string) (cgroups.Manager, error) { 31 if config == nil { 32 return nil, errors.New("cgroups/manager.New: config must not be nil") 33 } 34 if config.Systemd && !systemd.IsRunningSystemd() { 35 return nil, errors.New("systemd not running on this host, cannot use systemd cgroups manager") 36 } 37 38 // Cgroup v2 aka unified hierarchy. 39 if cgroups.IsCgroup2UnifiedMode() { 40 path, err := getUnifiedPath(paths) 41 if err != nil { 42 return nil, fmt.Errorf("manager.NewWithPaths: inconsistent paths: %w", err) 43 } 44 if config.Systemd { 45 return systemd.NewUnifiedManager(config, path) 46 } 47 return fs2.NewManager(config, path) 48 } 49 50 // Cgroup v1. 51 if config.Systemd { 52 return systemd.NewLegacyManager(config, paths) 53 } 54 55 return fs.NewManager(config, paths) 56 } 57 58 // getUnifiedPath is an implementation detail of libcontainer. 59 // Historically, libcontainer.Create saves cgroup paths as per-subsystem path 60 // map (as returned by cm.GetPaths(""), but with v2 we only have one single 61 // unified path (with "" as a key). 62 // 63 // This function converts from that map to string (using "" as a key), 64 // and also checks that the map itself is sane. 65 func getUnifiedPath(paths map[string]string) (string, error) { 66 if len(paths) > 1 { 67 return "", fmt.Errorf("expected a single path, got %+v", paths) 68 } 69 path := paths[""] 70 // can be empty 71 if path != "" { 72 if filepath.Clean(path) != path || !filepath.IsAbs(path) { 73 return "", fmt.Errorf("invalid path: %q", path) 74 } 75 } 76 77 return path, nil 78 }