new.go 2.5 KB

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