1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package cgroups
17
18 import (
19 "fmt"
20 "os/exec"
21
22 "github.com/containerd/cgroups"
23 "github.com/pkg/errors"
24 )
25
26 type CGroupInfo struct {
27 CGMode cgroups.CGMode
28 V1Path cgroups.Path
29 V2CGroupPath string
30 }
31
32 type AttachCGroup interface {
33 TargetCGroup() CGroupInfo
34 AttachProcess(pid int) error
35 }
36
37 var _ AttachCGroup = (*AttachCGroupV1)(nil)
38
39 type AttachCGroupV1 struct {
40 mode cgroups.CGMode
41 path cgroups.Path
42 }
43
44 func (a *AttachCGroupV1) TargetCGroup() CGroupInfo {
45 return CGroupInfo{
46 CGMode: a.mode,
47 V1Path: a.path,
48 V2CGroupPath: "",
49 }
50 }
51
52 func (a *AttachCGroupV1) AttachProcess(pid int) error {
53 cgroupv1, err := cgroups.Load(V1, a.path)
54 if err != nil {
55 cpuCGroupPath, _ := a.path("cpu")
56 memoryCGroupPath, _ := a.path("memory")
57 return errors.Wrapf(err, "load cgroup v1 manager, pid %d, cpu path %s, memory path %s", pid, cpuCGroupPath, memoryCGroupPath)
58 }
59 err = cgroupv1.Add(cgroups.Process{Pid: pid})
60 if err != nil {
61 cpuCGroupPath, _ := a.path("cpu")
62 memoryCGroupPath, _ := a.path("memory")
63 return errors.Wrapf(err, "add process to cgroup, pid %d, cpu path %s, memory path %s", pid, cpuCGroupPath, memoryCGroupPath)
64 }
65 return nil
66 }
67
68 var _ AttachCGroup = (*AttachCGroupV2)(nil)
69
70 type AttachCGroupV2 struct {
71 mode cgroups.CGMode
72 path string
73 }
74
75 func (a *AttachCGroupV2) TargetCGroup() CGroupInfo {
76 return CGroupInfo{
77 CGMode: a.mode,
78 V1Path: nil,
79 V2CGroupPath: a.path,
80 }
81 }
82
83 func (a *AttachCGroupV2) AttachProcess(pid int) error {
84
85
86 targetFile := fmt.Sprintf("/host-sys/fs/cgroup%s/cgroup.procs", a.path)
87 command := exec.Command("nsenter", "-C", "-t", "1", "--", "sh", "-c", fmt.Sprintf("echo %d >> %s", pid, targetFile))
88 output, err := command.CombinedOutput()
89 if err != nil {
90 return errors.Wrapf(err, "attach process to cgroup, pid %d, target cgourp file %s, output %s", pid, targetFile, string(output))
91 }
92 return nil
93 }
94
95
96 func GetAttacherForPID(targetPID int) (AttachCGroup, error) {
97 if cgroups.Mode() == cgroups.Unified {
98 groupPath, err := V2PidGroupPath(targetPID)
99 if err != nil {
100 return nil, err
101 }
102 return &AttachCGroupV2{
103 mode: cgroups.Unified,
104 path: groupPath,
105 }, nil
106 }
107
108
109 return &AttachCGroupV1{
110 mode: cgroups.Mode(),
111 path: PidPath(targetPID),
112 }, nil
113 }
114