@@ -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
}