Skip to content

Commit 033790c

Browse files
committed
refactor(env): split big function into smaller chuncks
1 parent ac3b418 commit 033790c

File tree

3 files changed

+434
-312
lines changed

3 files changed

+434
-312
lines changed

env/env_cgroup_linux.go

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package env
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"os"
7+
8+
"github.com/coreos/go-systemd/v22/dbus"
9+
"github.com/criyle/go-judge/env/linuxcontainer"
10+
"github.com/criyle/go-sandbox/pkg/cgroup"
11+
ddbus "github.com/godbus/dbus/v5"
12+
"go.uber.org/zap"
13+
)
14+
15+
func setupCgroup(c Config, logger *zap.Logger) (cgroup.Cgroup, *cgroup.Controllers, error) {
16+
prefix := c.CgroupPrefix
17+
t := cgroup.DetectedCgroupType
18+
19+
ct, err := cgroup.GetAvailableController()
20+
if err != nil {
21+
logger.Error("failed to get available controllers", zap.Error(err))
22+
return nil, nil, err
23+
}
24+
25+
if t == cgroup.TypeV2 {
26+
prefix, ct, err = setupCgroupV2(prefix, logger)
27+
if err != nil {
28+
return nil, nil, err
29+
}
30+
}
31+
32+
return createAndNestCgroup(prefix, ct, logger)
33+
}
34+
35+
func setupCgroupV2(prefix string, logger *zap.Logger) (string, *cgroup.Controllers, error) {
36+
logger.Info("running with cgroup v2, connecting systemd dbus to create cgroup")
37+
conn, err := getSystemdConnection()
38+
if err != nil {
39+
logger.Info("connecting to systemd dbus failed, assuming running in container, enable cgroup v2 nesting support and take control of the whole cgroupfs", zap.Error(err))
40+
return "", getControllersWithPrefix("", logger), nil
41+
}
42+
defer conn.Close()
43+
44+
scopeName := prefix + ".scope"
45+
logger.Info("connected to systemd bus, attempting to create transient unit", zap.String("scopeName", scopeName))
46+
47+
if err := startTransientUnit(conn, scopeName, logger); err != nil {
48+
return "", nil, err
49+
}
50+
51+
scopeName, err = cgroup.GetCurrentCgroupPrefix()
52+
if err != nil {
53+
logger.Error("failed to get current cgroup prefix", zap.Error(err))
54+
return "", nil, err
55+
}
56+
logger.Info("current cgroup", zap.String("scope_name", scopeName))
57+
58+
ct, err := cgroup.GetAvailableControllerWithPrefix(scopeName)
59+
if err != nil {
60+
logger.Error("failed to get available controller with prefix", zap.Error(err))
61+
return "", nil, err
62+
}
63+
return scopeName, ct, nil
64+
}
65+
66+
func getSystemdConnection() (*dbus.Conn, error) {
67+
if os.Getuid() == 0 {
68+
return dbus.NewSystemConnectionContext(context.TODO())
69+
}
70+
return dbus.NewUserConnectionContext(context.TODO())
71+
}
72+
73+
func startTransientUnit(conn *dbus.Conn, scopeName string, logger *zap.Logger) error {
74+
properties := []dbus.Property{
75+
dbus.PropDescription("go judge - a high performance sandbox service base on container technologies"),
76+
dbus.PropWants(scopeName),
77+
dbus.PropPids(uint32(os.Getpid())),
78+
newSystemdProperty("Delegate", true),
79+
}
80+
ch := make(chan string, 1)
81+
if _, err := conn.StartTransientUnitContext(context.TODO(), scopeName, "replace", properties, ch); err != nil {
82+
logger.Error("failed to start transient unit", zap.Error(err))
83+
return fmt.Errorf("failed to start transient unit: %w", err)
84+
}
85+
s := <-ch
86+
if s != "done" {
87+
logger.Error("starting transient unit returns error", zap.String("status", s))
88+
return fmt.Errorf("starting transient unit returns error: %s", s)
89+
}
90+
return nil
91+
}
92+
93+
func getControllersWithPrefix(prefix string, logger *zap.Logger) *cgroup.Controllers {
94+
ct, err := cgroup.GetAvailableControllerWithPrefix(prefix)
95+
if err != nil {
96+
logger.Error("failed to get available controller with prefix", zap.Error(err))
97+
return nil
98+
}
99+
return ct
100+
}
101+
102+
func createAndNestCgroup(prefix string, ct *cgroup.Controllers, logger *zap.Logger) (cgroup.Cgroup, *cgroup.Controllers, error) {
103+
cgb, err := cgroup.New(prefix, ct)
104+
if err != nil {
105+
if os.Getuid() == 0 {
106+
logger.Error("failed to create cgroup", zap.String("prefix", prefix), zap.Error(err))
107+
return nil, nil, err
108+
}
109+
logger.Warn("not running in root and have no permission on cgroup, falling back to rlimit / rusage mode", zap.Error(err))
110+
return nil, nil, nil
111+
}
112+
logger.Info("creating nesting api cgroup", zap.Any("cgroup", cgb))
113+
if _, err = cgb.Nest("api"); err != nil {
114+
if os.Getuid() != 0 {
115+
logger.Warn("creating api cgroup with error, falling back to rlimit / rusage mode", zap.Error(err))
116+
cgb.Destroy()
117+
return nil, nil, nil
118+
}
119+
}
120+
121+
logger.Info("creating containers cgroup")
122+
cg, err := cgb.New("containers")
123+
if err != nil {
124+
logger.Warn("creating containers cgroup with error, falling back to rlimit / rusage mode", zap.Error(err))
125+
return nil, nil, nil
126+
}
127+
if ct != nil && !ct.Memory {
128+
logger.Warn("memory cgroup is not enabled, falling back to rlimit / rusage mode")
129+
}
130+
if ct != nil && !ct.Pids {
131+
logger.Warn("pid cgroup is not enabled, proc limit does not have effect")
132+
}
133+
return cg, ct, nil
134+
}
135+
136+
func prepareCgroupPool(cgb cgroup.Cgroup, c Config) linuxcontainer.CgroupPool {
137+
if cgb != nil {
138+
return linuxcontainer.NewFakeCgroupPool(cgb, c.CPUCfsPeriod)
139+
}
140+
return nil
141+
}
142+
143+
func getCgroupInfo(cgb cgroup.Cgroup, ct *cgroup.Controllers) (int, []string) {
144+
cgroupType := int(cgroup.DetectedCgroupType)
145+
if cgb == nil {
146+
cgroupType = 0
147+
}
148+
cgroupControllers := []string{}
149+
if ct != nil {
150+
cgroupControllers = ct.Names()
151+
}
152+
return cgroupType, cgroupControllers
153+
}
154+
155+
func newSystemdProperty(name string, units any) dbus.Property {
156+
return dbus.Property{
157+
Name: name,
158+
Value: ddbus.MakeVariant(units),
159+
}
160+
}

0 commit comments

Comments
 (0)