1
1
package provisionerd
2
2
3
3
import (
4
+ "archive/tar"
5
+ "bytes"
4
6
"context"
7
+ "errors"
5
8
"fmt"
9
+ "io"
10
+ "os"
11
+ "path/filepath"
12
+ "reflect"
13
+ "strings"
6
14
"sync"
7
15
"time"
8
16
@@ -23,6 +31,7 @@ type Provisioners map[string]provisionersdkproto.DRPCProvisionerClient
23
31
type Options struct {
24
32
AcquireInterval time.Duration
25
33
Logger slog.Logger
34
+ WorkDirectory string
26
35
}
27
36
28
37
func New (apiDialer Dialer , provisioners Provisioners , opts * Options ) * API {
@@ -152,6 +161,90 @@ func (a *API) acquireJob() {
152
161
a .cancelActiveJob (fmt .Sprintf ("provisioner %q not registered" , a .activeJob .Provisioner ))
153
162
return
154
163
}
164
+ defer func () {
165
+ // Cleanup the work directory after execution.
166
+ err = os .RemoveAll (a .opts .WorkDirectory )
167
+ if err != nil {
168
+ a .cancelActiveJob (fmt .Sprintf ("remove all from %q directory: %s" , a .opts .WorkDirectory , err ))
169
+ return
170
+ }
171
+ }()
172
+
173
+ err = os .MkdirAll (a .opts .WorkDirectory , 0600 )
174
+ if err != nil {
175
+ a .cancelActiveJob (fmt .Sprintf ("create work directory %q: %s" , a .opts .WorkDirectory , err ))
176
+ return
177
+ }
178
+
179
+ a .opts .Logger .Debug (context .Background (), "unpacking project source archive" , slog .F ("size_bytes" , len (a .activeJob .ProjectSourceArchive )))
180
+ reader := tar .NewReader (bytes .NewBuffer (a .activeJob .ProjectSourceArchive ))
181
+ for {
182
+ header , err := reader .Next ()
183
+ if errors .Is (err , io .EOF ) {
184
+ break
185
+ }
186
+ if err != nil {
187
+ a .cancelActiveJob (fmt .Sprintf ("read project source archive: %s" , err ))
188
+ return
189
+ }
190
+ // #nosec
191
+ path := filepath .Join (a .opts .WorkDirectory , header .Name )
192
+ if ! strings .HasPrefix (path , filepath .Clean (a .opts .WorkDirectory )) {
193
+ a .cancelActiveJob ("tar attempts to target relative upper directory" )
194
+ return
195
+ }
196
+ switch header .Typeflag {
197
+ case tar .TypeDir :
198
+ err = os .MkdirAll (path , header .FileInfo ().Mode ())
199
+ if err != nil {
200
+ a .cancelActiveJob (fmt .Sprintf ("mkdir %q: %s" , path , err ))
201
+ return
202
+ }
203
+ a .opts .Logger .Debug (context .Background (), "extracted directory" , slog .F ("path" , path ))
204
+ case tar .TypeReg :
205
+ file , err := os .Create (path )
206
+ if err != nil {
207
+ a .cancelActiveJob (fmt .Sprintf ("create file %q: %s" , path , err ))
208
+ return
209
+ }
210
+ // Max file size of 10MB.
211
+ size , err := io .CopyN (file , reader , (1 << 20 )* 10 )
212
+ if errors .Is (err , io .EOF ) {
213
+ err = nil
214
+ }
215
+ if err != nil {
216
+ a .cancelActiveJob (fmt .Sprintf ("copy file %q: %s" , path , err ))
217
+ return
218
+ }
219
+ err = file .Close ()
220
+ if err != nil {
221
+ a .cancelActiveJob (fmt .Sprintf ("close file %q: %s" , path , err ))
222
+ return
223
+ }
224
+ a .opts .Logger .Debug (context .Background (), "extracted file" ,
225
+ slog .F ("size_bytes" , size ),
226
+ slog .F ("path" , path ),
227
+ )
228
+ }
229
+ }
230
+
231
+ switch jobType := a .activeJob .Type .(type ) {
232
+ case * proto.AcquiredJob_ProjectImport_ :
233
+ a .opts .Logger .Debug (context .Background (), "acquired job is project import" ,
234
+ slog .F ("project_history_name" , jobType .ProjectImport .ProjectHistoryName ),
235
+ )
236
+ case * proto.AcquiredJob_WorkspaceProvision_ :
237
+ a .opts .Logger .Debug (context .Background (), "acquired job is workspace provision" ,
238
+ slog .F ("workspace_name" , jobType .WorkspaceProvision .WorkspaceName ),
239
+ slog .F ("state_length" , len (jobType .WorkspaceProvision .State )),
240
+ slog .F ("parameters" , jobType .WorkspaceProvision .ParameterValues ),
241
+ )
242
+
243
+ default :
244
+ a .cancelActiveJob (fmt .Sprintf ("unknown job type %q; ensure your provisioner daemon is up-to-date" , reflect .TypeOf (a .activeJob .Type ).String ()))
245
+ return
246
+ }
247
+
155
248
fmt .Printf ("Provisioner: %s\n " , provisioner )
156
249
// Work!
157
250
}
@@ -204,7 +297,7 @@ func (a *API) closeWithError(err error) error {
204
297
}
205
298
206
299
if a .activeJob != nil {
207
- errMsg := ""
300
+ errMsg := "provisioner daemon was shutdown gracefully "
208
301
if err != nil {
209
302
errMsg = err .Error ()
210
303
}
0 commit comments