Skip to content

Commit aa4c5d5

Browse files
authored
Merge pull request #14396 from hashicorp/backport/f-cg-use-kill/admittedly-fast-pup
Backport of cgroups: refactor v2 kill path to use cgroups.kill interface file into release/1.3.x
2 parents 040a2ff + a9447e2 commit aa4c5d5

File tree

4 files changed

+80
-44
lines changed

4 files changed

+80
-44
lines changed

.changelog/14371.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:improvement
2+
cgroups: use cgroup.kill interface file when using cgroups v2
3+
```

client/lib/cgutil/editor.go

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//go:build linux
2+
3+
package cgutil
4+
5+
import (
6+
"os"
7+
"path/filepath"
8+
"strings"
9+
)
10+
11+
// editor provides a simple mechanism for reading and writing cgroup files.
12+
type editor struct {
13+
fromRoot string
14+
}
15+
16+
func (e *editor) path(file string) string {
17+
return filepath.Join(CgroupRoot, e.fromRoot, file)
18+
}
19+
20+
func (e *editor) write(file, content string) error {
21+
return os.WriteFile(e.path(file), []byte(content), 0o644)
22+
}
23+
24+
func (e *editor) read(file string) (string, error) {
25+
b, err := os.ReadFile(e.path(file))
26+
return strings.TrimSpace(string(b)), err
27+
}

client/lib/cgutil/editor_test.go

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
//go:build linux
2+
3+
package cgutil
4+
5+
import (
6+
"os"
7+
"path/filepath"
8+
"testing"
9+
10+
"github.com/hashicorp/nomad/client/testutil"
11+
"github.com/hashicorp/nomad/helper/uuid"
12+
"github.com/shoenig/test/must"
13+
)
14+
15+
func createCG(t *testing.T) (string, func()) {
16+
name := uuid.Short() + ".scope"
17+
path := filepath.Join(CgroupRoot, name)
18+
err := os.Mkdir(path, 0o755)
19+
must.NoError(t, err)
20+
21+
return name, func() {
22+
_ = os.Remove(path)
23+
}
24+
}
25+
26+
func TestCG_editor(t *testing.T) {
27+
testutil.CgroupsCompatibleV2(t)
28+
29+
cg, rm := createCG(t)
30+
t.Cleanup(rm)
31+
32+
edits := &editor{cg}
33+
writeErr := edits.write("cpu.weight.nice", "13")
34+
must.NoError(t, writeErr)
35+
36+
b, readErr := edits.read("cpu.weight.nice")
37+
must.NoError(t, readErr)
38+
must.Eq(t, "13", b)
39+
}

client/lib/cgutil/group_killer.go

+11-44
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,12 @@ import (
66
"errors"
77
"fmt"
88
"os"
9-
"path/filepath"
9+
"strconv"
1010
"time"
1111

1212
"github.com/hashicorp/go-hclog"
1313
"github.com/opencontainers/runc/libcontainer/cgroups"
1414
"github.com/opencontainers/runc/libcontainer/cgroups/fs"
15-
"github.com/opencontainers/runc/libcontainer/cgroups/fs2"
1615
"github.com/opencontainers/runc/libcontainer/configs"
1716
)
1817

@@ -96,56 +95,24 @@ func (d *killer) v1(cgroup *configs.Cgroup) error {
9695
}
9796

9897
func (d *killer) v2(cgroup *configs.Cgroup) error {
99-
if cgroup == nil {
98+
if cgroup == nil || cgroup.Path == "" {
10099
return errors.New("missing cgroup")
101100
}
102101

103-
path := filepath.Join(CgroupRoot, cgroup.Path)
104-
105-
existingPIDs, err := cgroups.GetPids(path)
106-
if err != nil {
107-
return fmt.Errorf("failed to determine pids in cgroup: %w", err)
108-
}
109-
110-
d.logger.Trace("killing processes", "cgroup_path", path, "cgroup_version", "v2", "executor_pid", d.pid, "existing_pids", existingPIDs)
111-
112-
mgr, err := fs2.NewManager(cgroup, "", rootless)
113-
if err != nil {
114-
return fmt.Errorf("failed to create v2 cgroup manager: %w", err)
115-
}
116-
117-
// move executor PID into the root init.scope so we can kill the task pids
118-
// without killing the executor (which is the process running this code, doing
119-
// the killing)
120-
init, err := fs2.NewManager(nil, filepath.Join(CgroupRoot, "init.scope"), rootless)
121-
if err != nil {
122-
return fmt.Errorf("failed to create v2 init cgroup manager: %w", err)
123-
}
124-
if err = init.Apply(d.pid); err != nil {
125-
return fmt.Errorf("failed to move executor pid into init.scope cgroup: %w", err)
126-
}
127-
128-
d.logger.Trace("move of executor pid into init.scope complete", "pid", d.pid)
129-
130-
// ability to freeze the cgroup
131-
freeze := func() {
132-
_ = mgr.Freeze(configs.Frozen)
133-
}
134-
135-
// ability to thaw the cgroup
136-
thaw := func() {
137-
_ = mgr.Freeze(configs.Thawed)
102+
// move executor (d.PID) into init.scope
103+
editSelf := &editor{"init.scope"}
104+
if err := editSelf.write("cgroup.procs", strconv.Itoa(d.pid)); err != nil {
105+
return err
138106
}
139107

140-
// do the common kill logic
141-
142-
if err = d.kill(path, freeze, thaw); err != nil {
108+
// write "1" to cgroup.kill
109+
editTask := &editor{cgroup.Path}
110+
if err := editTask.write("cgroup.kill", "1"); err != nil {
143111
return err
144112
}
145113

146-
// note: do NOT remove the cgroup from disk; leave that to the alloc-level
147-
// cpuset mananager.
148-
114+
// note: do NOT remove the cgroup from disk; leave that to the Client, at
115+
// least until #14375 is implemented.
149116
return nil
150117
}
151118

0 commit comments

Comments
 (0)