@@ -20,60 +20,101 @@ const (
20
20
EnvProcPrioMgmt = "CODER_PROC_PRIO_MGMT"
21
21
EnvProcOOMScore = "CODER_PROC_OOM_SCORE"
22
22
EnvProcNiceScore = "CODER_PROC_NICE_SCORE"
23
- )
24
23
25
- // CommandContext returns an exec.Cmd that calls "coder agent-exec" prior to exec'ing
26
- // the provided command if CODER_PROC_PRIO_MGMT is set, otherwise a normal exec.Cmd
27
- // is returned. All instances of exec.Cmd should flow through this function to ensure
28
- // proper resource constraints are applied to the child process.
29
- func CommandContext (ctx context.Context , cmd string , args ... string ) (* exec.Cmd , error ) {
30
- cmd , args , err := agentExecCmd (cmd , args ... )
31
- if err != nil {
32
- return nil , xerrors .Errorf ("agent exec cmd: %w" , err )
33
- }
34
- return exec .CommandContext (ctx , cmd , args ... ), nil
35
- }
24
+ // unset is set to an invalid value for nice and oom scores.
25
+ unset = - 2000
26
+ )
36
27
37
- // PTYCommandContext returns an pty.Cmd that calls "coder agent-exec" prior to exec'ing
38
- // the provided command if CODER_PROC_PRIO_MGMT is set, otherwise a normal pty.Cmd
39
- // is returned. All instances of pty.Cmd should flow through this function to ensure
40
- // proper resource constraints are applied to the child process.
41
- func PTYCommandContext (ctx context.Context , cmd string , args ... string ) (* pty.Cmd , error ) {
42
- cmd , args , err := agentExecCmd (cmd , args ... )
43
- if err != nil {
44
- return nil , xerrors .Errorf ("agent exec cmd: %w" , err )
45
- }
46
- return pty .CommandContext (ctx , cmd , args ... ), nil
28
+ var DefaultExecer Execer = execer {}
29
+
30
+ // Execer defines an abstraction for creating exec.Cmd variants. It's unfortunately
31
+ // necessary because we need to be able to wrap child processes with "coder agent-exec"
32
+ // for templates that expect the agent to manage process priority.
33
+ type Execer interface {
34
+ // CommandContext returns an exec.Cmd that calls "coder agent-exec" prior to exec'ing
35
+ // the provided command if CODER_PROC_PRIO_MGMT is set, otherwise a normal exec.Cmd
36
+ // is returned. All instances of exec.Cmd should flow through this function to ensure
37
+ // proper resource constraints are applied to the child process.
38
+ CommandContext (ctx context.Context , cmd string , args ... string ) * exec.Cmd
39
+ // PTYCommandContext returns an pty.Cmd that calls "coder agent-exec" prior to exec'ing
40
+ // the provided command if CODER_PROC_PRIO_MGMT is set, otherwise a normal pty.Cmd
41
+ // is returned. All instances of pty.Cmd should flow through this function to ensure
42
+ // proper resource constraints are applied to the child process.
43
+ PTYCommandContext (ctx context.Context , cmd string , args ... string ) * pty.Cmd
47
44
}
48
45
49
- func agentExecCmd ( cmd string , args ... string ) (string , [] string , error ) {
46
+ func NewExecer ( ) (Execer , error ) {
50
47
_ , enabled := os .LookupEnv (EnvProcPrioMgmt )
51
48
if runtime .GOOS != "linux" || ! enabled {
52
- return cmd , args , nil
49
+ return DefaultExecer , nil
53
50
}
54
51
55
52
executable , err := os .Executable ()
56
53
if err != nil {
57
- return "" , nil , xerrors .Errorf ("get executable: %w" , err )
54
+ return nil , xerrors .Errorf ("get executable: %w" , err )
58
55
}
59
56
60
57
bin , err := filepath .EvalSymlinks (executable )
61
58
if err != nil {
62
- return "" , nil , xerrors .Errorf ("eval symlinks: %w" , err )
59
+ return nil , xerrors .Errorf ("eval symlinks: %w" , err )
60
+ }
61
+
62
+ oomScore , ok := envValInt (EnvProcOOMScore )
63
+ if ! ok {
64
+ oomScore = unset
65
+ }
66
+
67
+ niceScore , ok := envValInt (EnvProcNiceScore )
68
+ if ! ok {
69
+ niceScore = unset
63
70
}
64
71
72
+ return priorityExecer {
73
+ binPath : bin ,
74
+ oomScore : oomScore ,
75
+ niceScore : niceScore ,
76
+ }, nil
77
+ }
78
+
79
+ type execer struct {}
80
+
81
+ func (execer ) CommandContext (ctx context.Context , cmd string , args ... string ) * exec.Cmd {
82
+ return exec .CommandContext (ctx , cmd , args ... )
83
+ }
84
+
85
+ func (execer ) PTYCommandContext (ctx context.Context , cmd string , args ... string ) * pty.Cmd {
86
+ return pty .CommandContext (ctx , cmd , args ... )
87
+ }
88
+
89
+ type priorityExecer struct {
90
+ binPath string
91
+ oomScore int
92
+ niceScore int
93
+ }
94
+
95
+ func (e priorityExecer ) CommandContext (ctx context.Context , cmd string , args ... string ) * exec.Cmd {
96
+ cmd , args = e .agentExecCmd (cmd , args ... )
97
+ return exec .CommandContext (ctx , cmd , args ... )
98
+ }
99
+
100
+ func (e priorityExecer ) PTYCommandContext (ctx context.Context , cmd string , args ... string ) * pty.Cmd {
101
+ cmd , args = e .agentExecCmd (cmd , args ... )
102
+ return pty .CommandContext (ctx , cmd , args ... )
103
+ }
104
+
105
+ func (e priorityExecer ) agentExecCmd (cmd string , args ... string ) (string , []string ) {
65
106
execArgs := []string {"agent-exec" }
66
- if score , ok := envValInt ( EnvProcOOMScore ); ok {
67
- execArgs = append (execArgs , oomScoreArg (score ))
107
+ if e . oomScore != unset {
108
+ execArgs = append (execArgs , oomScoreArg (e . oomScore ))
68
109
}
69
110
70
- if score , ok := envValInt ( EnvProcNiceScore ); ok {
71
- execArgs = append (execArgs , niceScoreArg (score ))
111
+ if e . niceScore != unset {
112
+ execArgs = append (execArgs , niceScoreArg (e . niceScore ))
72
113
}
73
114
execArgs = append (execArgs , "--" , cmd )
74
115
execArgs = append (execArgs , args ... )
75
116
76
- return bin , execArgs , nil
117
+ return e . binPath , execArgs
77
118
}
78
119
79
120
// envValInt searches for a key in a list of environment variables and parses it to an int.
0 commit comments