@@ -118,22 +118,12 @@ func (sb *ServerBuilder) isWindows() bool {
118
118
return commercialTypeIsWindowsServer (sb .createReq .CommercialType )
119
119
}
120
120
121
- func (sb * ServerBuilder ) rootVolumeTemplate () * instance.VolumeServerTemplate {
122
- rootVolume , exists := sb .createReq .Volumes ["0" ]
123
- if ! exists {
124
- return nil
125
- }
126
-
127
- return rootVolume
128
- }
129
-
130
121
func (sb * ServerBuilder ) rootVolumeIsSBS () bool {
131
- rootVolume := sb .rootVolumeTemplate ()
132
- if rootVolume == nil {
122
+ if sb .rootVolume == nil {
133
123
return false
134
124
}
135
125
136
- return rootVolume .VolumeType == instance .VolumeVolumeTypeSbsVolume
126
+ return sb . rootVolume .VolumeType == instance .VolumeVolumeTypeSbsVolume
137
127
}
138
128
139
129
func (sb * ServerBuilder ) marketplaceImageType () marketplace.LocalImageType {
@@ -237,14 +227,22 @@ func (sb *ServerBuilder) AddIP(ip string) (*ServerBuilder, error) {
237
227
return sb , nil
238
228
}
239
229
230
+ func (sb * ServerBuilder ) addIPID (ipID string ) * ServerBuilder {
231
+ if sb .createReq .PublicIPs == nil {
232
+ sb .createReq .PublicIPs = new ([]string )
233
+ }
234
+
235
+ * sb .createReq .PublicIPs = append (* sb .createReq .PublicIPs , ipID )
236
+
237
+ return sb
238
+ }
239
+
240
240
// AddVolumes build volume templates from arguments.
241
241
//
242
242
// More format details in buildVolumeTemplate function.
243
243
//
244
244
// Also add default volumes to server, ex: scratch storage for GPU servers
245
245
func (sb * ServerBuilder ) AddVolumes (rootVolume string , additionalVolumes []string ) (* ServerBuilder , error ) {
246
- var err error
247
-
248
246
if len (additionalVolumes ) > 0 || rootVolume != "" {
249
247
if rootVolume != "" {
250
248
rootVolumeBuilder , err := NewVolumeBuilder (sb .createReq .Zone , rootVolume )
@@ -260,29 +258,6 @@ func (sb *ServerBuilder) AddVolumes(rootVolume string, additionalVolumes []strin
260
258
}
261
259
sb .volumes = append (sb .volumes , additionalVolumeBuilder )
262
260
}
263
-
264
- volumes := make (map [string ]* instance.VolumeServerTemplate , len (sb .volumes )+ 1 )
265
- if sb .rootVolume != nil {
266
- volumes ["0" ], err = sb .rootVolume .BuildVolumeServerTemplate (sb .apiInstance , sb .apiBlock )
267
- if err != nil {
268
- return sb , fmt .Errorf ("failed to build root volume: %w" , err )
269
- }
270
- }
271
- for i , volume := range sb .volumes {
272
- volumeTemplate , err := volume .BuildVolumeServerTemplate (sb .apiInstance , sb .apiBlock )
273
- if err != nil {
274
- return sb , fmt .Errorf ("failed to build volume template: %w" , err )
275
- }
276
- index := strconv .Itoa (i + 1 )
277
- volumeTemplate .Name = scw .StringPtr (sb .createReq .Name + "-" + index )
278
- volumes [index ] = volumeTemplate
279
- }
280
- // Sanitize the volume map to respect API schemas
281
- sb .createReq .Volumes = volumes
282
- }
283
-
284
- if sb .serverType != nil {
285
- sb .createReq .Volumes = addDefaultVolumes (sb .serverType , sb .createReq .Volumes )
286
261
}
287
262
288
263
return sb , nil
@@ -360,11 +335,148 @@ func (sb *ServerBuilder) Validate() error {
360
335
logger .Warningf ("skipping image server-type compatibility validation" )
361
336
}
362
337
363
- return sb . ValidateVolumes ()
338
+ return nil
364
339
}
365
340
366
- func (sb * ServerBuilder ) Build () (* instance.CreateServerRequest , []* instance.CreateIPRequest ) {
367
- return sb .createReq , sb .createIPReqs
341
+ func (sb * ServerBuilder ) BuildVolumes () error {
342
+ var err error
343
+
344
+ volumes := make (map [string ]* instance.VolumeServerTemplate , len (sb .volumes )+ 1 )
345
+ if sb .rootVolume != nil {
346
+ volumes ["0" ], err = sb .rootVolume .BuildVolumeServerTemplate (sb .apiInstance , sb .apiBlock )
347
+ if err != nil {
348
+ return fmt .Errorf ("failed to build root volume: %w" , err )
349
+ }
350
+ }
351
+
352
+ for i , volume := range sb .volumes {
353
+ volumeTemplate , err := volume .BuildVolumeServerTemplate (sb .apiInstance , sb .apiBlock )
354
+ if err != nil {
355
+ return fmt .Errorf ("failed to build volume template: %w" , err )
356
+ }
357
+ index := strconv .Itoa (i + 1 )
358
+ volumeTemplate .Name = scw .StringPtr (sb .createReq .Name + "-" + index )
359
+ volumes [index ] = volumeTemplate
360
+ }
361
+ // Sanitize the volume map to respect API schemas
362
+ sb .createReq .Volumes = volumes
363
+
364
+ if sb .serverType != nil {
365
+ sb .createReq .Volumes = addDefaultVolumes (sb .serverType , sb .createReq .Volumes )
366
+ }
367
+
368
+ return nil
369
+ }
370
+
371
+ func (sb * ServerBuilder ) Build () (* instance.CreateServerRequest , error ) {
372
+ err := sb .BuildVolumes ()
373
+ if err != nil {
374
+ return nil , err
375
+ }
376
+
377
+ return sb .createReq , sb .ValidateVolumes ()
378
+ }
379
+
380
+ type PreServerCreationSetupFunc func (ctx context.Context ) error
381
+
382
+ type PreServerCreationSetup struct {
383
+ setupFunctions []PreServerCreationSetupFunc
384
+ cleanFunctions []PreServerCreationSetupFunc
385
+ }
386
+
387
+ func (sb * ServerBuilder ) BuildPreCreationSetup () * PreServerCreationSetup {
388
+ setup := & PreServerCreationSetup {}
389
+
390
+ for _ , ipCreationRequest := range sb .createIPReqs {
391
+ setup .setupFunctions = append (setup .setupFunctions , func (ctx context.Context ) error {
392
+ resp , err := sb .apiInstance .CreateIP (ipCreationRequest , scw .WithContext (ctx ))
393
+ if err != nil {
394
+ return err
395
+ }
396
+
397
+ sb .addIPID (resp .IP .ID )
398
+
399
+ setup .cleanFunctions = append (setup .cleanFunctions , func (ctx context.Context ) error {
400
+ return sb .apiInstance .DeleteIP (& instance.DeleteIPRequest {
401
+ IP : resp .IP .ID ,
402
+ Zone : resp .IP .Zone ,
403
+ }, scw .WithContext (ctx ))
404
+ })
405
+
406
+ return nil
407
+ })
408
+ }
409
+
410
+ sb .BuildPreCreationVolumesSetup (setup )
411
+
412
+ return setup
413
+ }
414
+
415
+ // BuildPreCreationVolumesSetup configure PreServerCreationSetup to create required SBS volumes.
416
+ // Instance API does not support SBS volumes creation alongside the server, they must be created before then imported.
417
+ func (sb * ServerBuilder ) BuildPreCreationVolumesSetup (setup * PreServerCreationSetup ) {
418
+ for _ , volume := range sb .volumes {
419
+ if volume .VolumeType != instance .VolumeVolumeTypeSbsVolume || volume .VolumeID != nil || volume .Size == nil {
420
+ continue
421
+ }
422
+
423
+ projectID := "" // If let empty, ProjectID will be set by scaleway client to default Project ID.
424
+ if sb .createReq .Project != nil {
425
+ projectID = * sb .createReq .Project
426
+ }
427
+
428
+ setup .setupFunctions = append (setup .setupFunctions , func (ctx context.Context ) error {
429
+ vol , err := sb .apiBlock .CreateVolume (& block.CreateVolumeRequest {
430
+ Zone : volume .Zone ,
431
+ Name : core .GetRandomName ("vol" ),
432
+ PerfIops : volume .IOPS ,
433
+ ProjectID : projectID ,
434
+ FromEmpty : & block.CreateVolumeRequestFromEmpty {
435
+ Size : * volume .Size ,
436
+ },
437
+ }, scw .WithContext (ctx ))
438
+ if err != nil {
439
+ return err
440
+ }
441
+
442
+ volume .VolumeID = & vol .ID
443
+
444
+ setup .cleanFunctions = append (setup .cleanFunctions , func (ctx context.Context ) error {
445
+ return sb .apiBlock .DeleteVolume (& block.DeleteVolumeRequest {
446
+ Zone : vol .Zone ,
447
+ VolumeID : vol .ID ,
448
+ }, scw .WithContext (ctx ))
449
+ })
450
+
451
+ return nil
452
+ })
453
+ }
454
+ }
455
+
456
+ func (s * PreServerCreationSetup ) Execute (ctx context.Context ) error {
457
+ for _ , setupFunc := range s .setupFunctions {
458
+ if err := setupFunc (ctx ); err != nil {
459
+ return err
460
+ }
461
+ }
462
+
463
+ return nil
464
+ }
465
+
466
+ func (s * PreServerCreationSetup ) Clean (ctx context.Context ) error {
467
+ errs := []error (nil )
468
+
469
+ for _ , cleanFunc := range s .cleanFunctions {
470
+ if err := cleanFunc (ctx ); err != nil {
471
+ errs = append (errs , err )
472
+ }
473
+ }
474
+
475
+ if len (errs ) > 0 {
476
+ return errors .Join (errs ... )
477
+ }
478
+
479
+ return nil
368
480
}
369
481
370
482
type PostServerCreationSetupFunc func (ctx context.Context , server * instance.Server ) error
0 commit comments