@@ -80,6 +80,21 @@ func New(opts Options) *Runner {
80
80
81
81
type ScriptCompletedFunc func (context.Context , * proto.WorkspaceAgentScriptCompletedRequest ) (* proto.WorkspaceAgentScriptCompletedResponse , error )
82
82
83
+ type runnerScript struct {
84
+ runOnPostStart bool
85
+ codersdk.WorkspaceAgentScript
86
+ }
87
+
88
+ func toRunnerScript (scripts ... codersdk.WorkspaceAgentScript ) []runnerScript {
89
+ var rs []runnerScript
90
+ for _ , s := range scripts {
91
+ rs = append (rs , runnerScript {
92
+ WorkspaceAgentScript : s ,
93
+ })
94
+ }
95
+ return rs
96
+ }
97
+
83
98
type Runner struct {
84
99
Options
85
100
@@ -90,7 +105,7 @@ type Runner struct {
90
105
closeMutex sync.Mutex
91
106
cron * cron.Cron
92
107
initialized atomic.Bool
93
- scripts []codersdk. WorkspaceAgentScript
108
+ scripts []runnerScript
94
109
dataDir string
95
110
scriptCompleted ScriptCompletedFunc
96
111
@@ -119,30 +134,49 @@ func (r *Runner) RegisterMetrics(reg prometheus.Registerer) {
119
134
reg .MustRegister (r .scriptsExecuted )
120
135
}
121
136
137
+ // InitOption describes an option for the runner initialization.
138
+ type InitOption func (* Runner )
139
+
140
+ // WithPostStartScripts adds scripts that should be run after the workspace
141
+ // start scripts but before the workspace is marked as started.
142
+ func WithPostStartScripts (scripts ... codersdk.WorkspaceAgentScript ) InitOption {
143
+ return func (r * Runner ) {
144
+ for _ , s := range scripts {
145
+ r .scripts = append (r .scripts , runnerScript {
146
+ runOnPostStart : true ,
147
+ WorkspaceAgentScript : s ,
148
+ })
149
+ }
150
+ }
151
+ }
152
+
122
153
// Init initializes the runner with the provided scripts.
123
154
// It also schedules any scripts that have a schedule.
124
155
// This function must be called before Execute.
125
- func (r * Runner ) Init (scripts []codersdk.WorkspaceAgentScript , scriptCompleted ScriptCompletedFunc ) error {
156
+ func (r * Runner ) Init (scripts []codersdk.WorkspaceAgentScript , scriptCompleted ScriptCompletedFunc , opts ... InitOption ) error {
126
157
if r .initialized .Load () {
127
158
return xerrors .New ("init: already initialized" )
128
159
}
129
160
r .initialized .Store (true )
130
- r .scripts = scripts
161
+ r .scripts = toRunnerScript ( scripts ... )
131
162
r .scriptCompleted = scriptCompleted
163
+ for _ , opt := range opts {
164
+ opt (r )
165
+ }
132
166
r .Logger .Info (r .cronCtx , "initializing agent scripts" , slog .F ("script_count" , len (scripts )), slog .F ("log_dir" , r .LogDir ))
133
167
134
168
err := r .Filesystem .MkdirAll (r .ScriptBinDir (), 0o700 )
135
169
if err != nil {
136
170
return xerrors .Errorf ("create script bin dir: %w" , err )
137
171
}
138
172
139
- for _ , script := range scripts {
173
+ for _ , script := range r . scripts {
140
174
if script .Cron == "" {
141
175
continue
142
176
}
143
177
script := script
144
178
_ , err := r .cron .AddFunc (script .Cron , func () {
145
- err := r .trackRun (r .cronCtx , script , ExecuteCronScripts )
179
+ err := r .trackRun (r .cronCtx , script . WorkspaceAgentScript , ExecuteCronScripts )
146
180
if err != nil {
147
181
r .Logger .Warn (context .Background (), "run agent script on schedule" , slog .Error (err ))
148
182
}
@@ -186,6 +220,7 @@ type ExecuteOption int
186
220
const (
187
221
ExecuteAllScripts ExecuteOption = iota
188
222
ExecuteStartScripts
223
+ ExecutePostStartScripts
189
224
ExecuteStopScripts
190
225
ExecuteCronScripts
191
226
)
@@ -196,6 +231,7 @@ func (r *Runner) Execute(ctx context.Context, option ExecuteOption) error {
196
231
for _ , script := range r .scripts {
197
232
runScript := (option == ExecuteStartScripts && script .RunOnStart ) ||
198
233
(option == ExecuteStopScripts && script .RunOnStop ) ||
234
+ (option == ExecutePostStartScripts && script .runOnPostStart ) ||
199
235
(option == ExecuteCronScripts && script .Cron != "" ) ||
200
236
option == ExecuteAllScripts
201
237
@@ -205,7 +241,7 @@ func (r *Runner) Execute(ctx context.Context, option ExecuteOption) error {
205
241
206
242
script := script
207
243
eg .Go (func () error {
208
- err := r .trackRun (ctx , script , option )
244
+ err := r .trackRun (ctx , script . WorkspaceAgentScript , option )
209
245
if err != nil {
210
246
return xerrors .Errorf ("run agent script %q: %w" , script .LogSourceID , err )
211
247
}
0 commit comments