@@ -18,10 +18,8 @@ package cgroup2
18
18
19
19
import (
20
20
"bufio"
21
- "context"
22
21
"errors"
23
22
"fmt"
24
- "math"
25
23
"os"
26
24
"path/filepath"
27
25
"strconv"
@@ -30,8 +28,6 @@ import (
30
28
31
29
"github.com/containerd/cgroups/v3/cgroup2/stats"
32
30
33
- systemdDbus "github.com/coreos/go-systemd/v22/dbus"
34
- "github.com/godbus/dbus/v5"
35
31
"github.com/opencontainers/runtime-spec/specs-go"
36
32
"github.com/sirupsen/logrus"
37
33
"golang.org/x/sys/unix"
@@ -761,208 +757,3 @@ func setDevices(path string, devices []specs.LinuxDeviceCgroup) error {
761
757
}
762
758
return nil
763
759
}
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