@@ -18,10 +18,8 @@ package cgroup2
1818
1919import (
2020 "bufio"
21- "context"
2221 "errors"
2322 "fmt"
24- "math"
2523 "os"
2624 "path/filepath"
2725 "strconv"
@@ -30,8 +28,6 @@ import (
3028
3129 "github.com/containerd/cgroups/v3/cgroup2/stats"
3230
33- systemdDbus "github.com/coreos/go-systemd/v22/dbus"
34- "github.com/godbus/dbus/v5"
3531 "github.com/opencontainers/runtime-spec/specs-go"
3632 "github.com/sirupsen/logrus"
3733 "golang.org/x/sys/unix"
@@ -761,208 +757,3 @@ func setDevices(path string, devices []specs.LinuxDeviceCgroup) error {
761757 }
762758 return nil
763759}
764-
765- // getSystemdFullPath returns the full systemd path when creating a systemd slice group.
766- // the reason this is necessary is because the "-" character has a special meaning in
767- // systemd slice. For example, when creating a slice called "my-group-112233.slice",
768- // systemd will create a hierarchy like this:
769- //
770- // /sys/fs/cgroup/my.slice/my-group.slice/my-group-112233.slice
771- func getSystemdFullPath (slice , group string ) string {
772- return filepath .Join (defaultCgroup2Path , dashesToPath (slice ), dashesToPath (group ))
773- }
774-
775- // dashesToPath converts a slice name with dashes to it's corresponding systemd filesystem path.
776- func dashesToPath (in string ) string {
777- path := ""
778- if strings .HasSuffix (in , ".slice" ) && strings .Contains (in , "-" ) {
779- parts := strings .Split (in , "-" )
780- for i := range parts {
781- s := strings .Join (parts [0 :i + 1 ], "-" )
782- if ! strings .HasSuffix (s , ".slice" ) {
783- s += ".slice"
784- }
785- path = filepath .Join (path , s )
786- }
787- } else {
788- path = filepath .Join (path , in )
789- }
790- return path
791- }
792-
793- func NewSystemd (slice , group string , pid int , resources * Resources ) (* Manager , error ) {
794- if slice == "" {
795- slice = defaultSlice
796- }
797- ctx := context .TODO ()
798- path := getSystemdFullPath (slice , group )
799- conn , err := systemdDbus .NewWithContext (ctx )
800- if err != nil {
801- return & Manager {}, err
802- }
803- defer conn .Close ()
804-
805- properties := []systemdDbus.Property {
806- systemdDbus .PropDescription ("cgroup " + group ),
807- newSystemdProperty ("DefaultDependencies" , false ),
808- newSystemdProperty ("MemoryAccounting" , true ),
809- newSystemdProperty ("CPUAccounting" , true ),
810- newSystemdProperty ("IOAccounting" , true ),
811- }
812-
813- // if we create a slice, the parent is defined via a Wants=
814- if strings .HasSuffix (group , ".slice" ) {
815- properties = append (properties , systemdDbus .PropWants (defaultSlice ))
816- } else {
817- // otherwise, we use Slice=
818- properties = append (properties , systemdDbus .PropSlice (defaultSlice ))
819- }
820-
821- // only add pid if its valid, -1 is used w/ general slice creation.
822- if pid != - 1 {
823- properties = append (properties , newSystemdProperty ("PIDs" , []uint32 {uint32 (pid )}))
824- }
825-
826- if resources .Memory != nil && resources .Memory .Min != nil && * resources .Memory .Min != 0 {
827- properties = append (properties ,
828- newSystemdProperty ("MemoryMin" , uint64 (* resources .Memory .Min )))
829- }
830-
831- if resources .Memory != nil && resources .Memory .Max != nil && * resources .Memory .Max != 0 {
832- properties = append (properties ,
833- newSystemdProperty ("MemoryMax" , uint64 (* resources .Memory .Max )))
834- }
835-
836- if resources .CPU != nil && resources .CPU .Weight != nil && * resources .CPU .Weight != 0 {
837- properties = append (properties ,
838- newSystemdProperty ("CPUWeight" , * resources .CPU .Weight ))
839- }
840-
841- if resources .CPU != nil && resources .CPU .Max != "" {
842- quota , period := resources .CPU .Max .extractQuotaAndPeriod ()
843- // cpu.cfs_quota_us and cpu.cfs_period_us are controlled by systemd.
844- // corresponds to USEC_INFINITY in systemd
845- // if USEC_INFINITY is provided, CPUQuota is left unbound by systemd
846- // always setting a property value ensures we can apply a quota and remove it later
847- cpuQuotaPerSecUSec := uint64 (math .MaxUint64 )
848- if quota > 0 {
849- // systemd converts CPUQuotaPerSecUSec (microseconds per CPU second) to CPUQuota
850- // (integer percentage of CPU) internally. This means that if a fractional percent of
851- // CPU is indicated by Resources.CpuQuota, we need to round up to the nearest
852- // 10ms (1% of a second) such that child cgroups can set the cpu.cfs_quota_us they expect.
853- cpuQuotaPerSecUSec = uint64 (quota * 1000000 ) / period
854- if cpuQuotaPerSecUSec % 10000 != 0 {
855- cpuQuotaPerSecUSec = ((cpuQuotaPerSecUSec / 10000 ) + 1 ) * 10000
856- }
857- }
858- properties = append (properties ,
859- newSystemdProperty ("CPUQuotaPerSecUSec" , cpuQuotaPerSecUSec ))
860- }
861-
862- // If we can delegate, we add the property back in
863- if canDelegate {
864- properties = append (properties , newSystemdProperty ("Delegate" , true ))
865- }
866-
867- if resources .Pids != nil && resources .Pids .Max > 0 {
868- properties = append (properties ,
869- newSystemdProperty ("TasksAccounting" , true ),
870- newSystemdProperty ("TasksMax" , uint64 (resources .Pids .Max )))
871- }
872-
873- if err := startUnit (conn , group , properties , pid == - 1 ); err != nil {
874- return & Manager {}, err
875- }
876-
877- return & Manager {
878- path : path ,
879- }, nil
880- }
881-
882- func startUnit (conn * systemdDbus.Conn , group string , properties []systemdDbus.Property , ignoreExists bool ) error {
883- ctx := context .TODO ()
884-
885- statusChan := make (chan string , 1 )
886- defer close (statusChan )
887-
888- retry := true
889- started := false
890-
891- for ! started {
892- if _ , err := conn .StartTransientUnitContext (ctx , group , "replace" , properties , statusChan ); err != nil {
893- if ! isUnitExists (err ) {
894- return err
895- }
896-
897- if ignoreExists {
898- return nil
899- }
900-
901- if retry {
902- retry = false
903- // When a unit of the same name already exists, it may be a leftover failed unit.
904- // If we reset it once, systemd can try to remove it.
905- attemptFailedUnitReset (conn , group )
906- continue
907- }
908-
909- return err
910- } else {
911- started = true
912- }
913- }
914-
915- select {
916- case s := <- statusChan :
917- if s != "done" {
918- attemptFailedUnitReset (conn , group )
919- return fmt .Errorf ("error creating systemd unit `%s`: got `%s`" , group , s )
920- }
921- case <- time .After (30 * time .Second ):
922- logrus .Warnf ("Timed out while waiting for StartTransientUnit(%s) completion signal from dbus. Continuing..." , group )
923- }
924-
925- return nil
926- }
927-
928- func attemptFailedUnitReset (conn * systemdDbus.Conn , group string ) {
929- err := conn .ResetFailedUnitContext (context .TODO (), group )
930-
931- if err != nil {
932- logrus .Warnf ("Unable to reset failed unit: %v" , err )
933- }
934- }
935-
936- func LoadSystemd (slice , group string ) (* Manager , error ) {
937- if slice == "" {
938- slice = defaultSlice
939- }
940- path := getSystemdFullPath (slice , group )
941- return & Manager {
942- path : path ,
943- }, nil
944- }
945-
946- func (c * Manager ) DeleteSystemd () error {
947- ctx := context .TODO ()
948- conn , err := systemdDbus .NewWithContext (ctx )
949- if err != nil {
950- return err
951- }
952- defer conn .Close ()
953- group := systemdUnitFromPath (c .path )
954- ch := make (chan string )
955- _ , err = conn .StopUnitContext (ctx , group , "replace" , ch )
956- if err != nil {
957- return err
958- }
959- <- ch
960- return nil
961- }
962-
963- func newSystemdProperty (name string , units interface {}) systemdDbus.Property {
964- return systemdDbus.Property {
965- Name : name ,
966- Value : dbus .MakeVariant (units ),
967- }
968- }
0 commit comments