| package cgroups |
| |
| import ( |
| "fmt" |
| "path/filepath" |
| "strings" |
| "sync" |
| |
| systemdDbus "github.com/coreos/go-systemd/dbus" |
| "github.com/godbus/dbus" |
| specs "github.com/opencontainers/runtime-spec/specs-go" |
| ) |
| |
| const ( |
| SystemdDbus Name = "systemd" |
| defaultSlice = "system.slice" |
| ) |
| |
| func Systemd() ([]Subsystem, error) { |
| root, err := v1MountPoint() |
| if err != nil { |
| return nil, err |
| } |
| defaultSubsystems, err := defaults(root) |
| if err != nil { |
| return nil, err |
| } |
| s, err := NewSystemd(root) |
| if err != nil { |
| return nil, err |
| } |
| // make sure the systemd controller is added first |
| return append([]Subsystem{s}, defaultSubsystems...), nil |
| } |
| |
| func Slice(slice, name string) Path { |
| if slice == "" { |
| slice = defaultSlice |
| } |
| return func(subsystem Name) (string, error) { |
| return filepath.Join(slice, unitName(name)), nil |
| } |
| } |
| |
| func NewSystemd(root string) (*SystemdController, error) { |
| return &SystemdController{ |
| root: root, |
| }, nil |
| } |
| |
| type SystemdController struct { |
| mu sync.Mutex |
| root string |
| } |
| |
| func (s *SystemdController) Name() Name { |
| return SystemdDbus |
| } |
| |
| func (s *SystemdController) Create(path string, resources *specs.LinuxResources) error { |
| conn, err := systemdDbus.New() |
| if err != nil { |
| return err |
| } |
| defer conn.Close() |
| slice, name := splitName(path) |
| properties := []systemdDbus.Property{ |
| systemdDbus.PropDescription(fmt.Sprintf("cgroup %s", name)), |
| systemdDbus.PropWants(slice), |
| newProperty("DefaultDependencies", false), |
| newProperty("Delegate", true), |
| newProperty("MemoryAccounting", true), |
| newProperty("CPUAccounting", true), |
| newProperty("BlockIOAccounting", true), |
| } |
| ch := make(chan string) |
| _, err = conn.StartTransientUnit(name, "replace", properties, ch) |
| if err != nil { |
| return err |
| } |
| <-ch |
| return nil |
| } |
| |
| func (s *SystemdController) Delete(path string) error { |
| conn, err := systemdDbus.New() |
| if err != nil { |
| return err |
| } |
| defer conn.Close() |
| _, name := splitName(path) |
| ch := make(chan string) |
| _, err = conn.StopUnit(name, "replace", ch) |
| if err != nil { |
| return err |
| } |
| <-ch |
| return nil |
| } |
| |
| func newProperty(name string, units interface{}) systemdDbus.Property { |
| return systemdDbus.Property{ |
| Name: name, |
| Value: dbus.MakeVariant(units), |
| } |
| } |
| |
| func unitName(name string) string { |
| return fmt.Sprintf("%s.slice", name) |
| } |
| |
| func splitName(path string) (slice string, unit string) { |
| slice, unit = filepath.Split(path) |
| return strings.TrimSuffix(slice, "/"), unit |
| } |