Skip to content

Commit eaa5f8a

Browse files
committed
create sbs volumes for each block_volume
1 parent 2338667 commit eaa5f8a

File tree

7 files changed

+151
-54
lines changed

7 files changed

+151
-54
lines changed

builder/scaleway/builder.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func (b *Builder) Run(ctx context.Context, ui packersdk.Ui, hook packersdk.Hook)
7979
Debug: b.Config.PackerDebug,
8080
DebugKeyPath: fmt.Sprintf("scw_%s.pem", b.Config.PackerBuildName),
8181
},
82-
new(stepRemoveVolume),
82+
new(stepCreateVolume),
8383
new(stepCreateServer),
8484
new(stepServerInfo),
8585
&communicator.StepConnect{

builder/scaleway/config_block.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ import (
1212
func prepareBlockVolumes(volumes []ConfigBlockVolume) *packersdk.MultiError {
1313
var errs *packersdk.MultiError
1414

15-
for i, volume := range volumes {
15+
for i := range volumes {
16+
volume := &volumes[i]
17+
1618
if volume.Name == "" {
1719
volume.Name = fmt.Sprintf("packer-%s", uuid.TimeOrderedUUID())
1820
}

builder/scaleway/step_backup.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ func backupVolumesFromServer(server *instance.Server) map[string]*instance.Serve
100100

101101
for _, volume := range server.Volumes {
102102
backupVolumes[volume.ID] = &instance.ServerActionRequestVolumeBackupTemplate{
103-
VolumeType: instance.SnapshotVolumeTypeUnified,
103+
//VolumeType: instance.SnapshotVolumeTypeUnified,
104104
}
105105
}
106106
return backupVolumes

builder/scaleway/step_create_server.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,10 @@ func (s *stepCreateServer) Run(ctx context.Context, state multistep.StateBag) mu
6262
if createServerReq.Volumes == nil {
6363
createServerReq.Volumes = make(map[string]*instance.VolumeServerTemplate)
6464
}
65-
for i, blockVolume := range c.BlockVolumes {
65+
createdVolumes := state.Get(StateKeyCreatedVolumes).([]*instance.VolumeServerTemplate)
66+
for i, blockVolume := range createdVolumes {
6667
volumeIndex := strconv.FormatInt(int64(i+1), 10)
67-
createServerReq.Volumes[volumeIndex] = blockVolume.VolumeTemplate()
68+
createServerReq.Volumes[volumeIndex] = blockVolume
6869
}
6970
}
7071

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
package scaleway
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/hashicorp/packer-plugin-sdk/multistep"
8+
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
9+
"github.com/scaleway/packer-plugin-scaleway/internal/httperrors"
10+
block "github.com/scaleway/scaleway-sdk-go/api/block/v1alpha1"
11+
"github.com/scaleway/scaleway-sdk-go/api/instance/v1"
12+
"github.com/scaleway/scaleway-sdk-go/scw"
13+
)
14+
15+
const StateKeyCreatedVolumes = "created_volumes"
16+
17+
type stepCreateVolume struct{}
18+
19+
func (s *stepCreateVolume) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
20+
client := state.Get("client").(*scw.Client)
21+
blockAPI := block.NewAPI(client)
22+
ui := state.Get("ui").(packersdk.Ui)
23+
c := state.Get("config").(*Config)
24+
25+
volumeTemplates := []*instance.VolumeServerTemplate(nil)
26+
for _, requestedVolume := range c.BlockVolumes {
27+
volume, err := blockAPI.CreateVolume(&block.CreateVolumeRequest{
28+
Zone: scw.Zone(c.Zone),
29+
Name: requestedVolume.Name,
30+
PerfIops: scw.Uint32Ptr(5000), // TODO: configuration
31+
ProjectID: c.ProjectID,
32+
FromEmpty: &block.CreateVolumeRequestFromEmpty{
33+
Size: scw.Size(requestedVolume.Size),
34+
},
35+
FromSnapshot: nil, // TODO
36+
Tags: nil, // TODO
37+
}, scw.WithContext(ctx))
38+
if err != nil {
39+
state.Put("error", err)
40+
ui.Error(err.Error())
41+
return multistep.ActionHalt
42+
}
43+
44+
volumeTemplates = append(volumeTemplates, &instance.VolumeServerTemplate{
45+
ID: &volume.ID,
46+
VolumeType: instance.VolumeVolumeTypeSbsVolume,
47+
})
48+
}
49+
50+
state.Put(StateKeyCreatedVolumes, volumeTemplates)
51+
52+
return multistep.ActionContinue
53+
}
54+
55+
func (s *stepCreateVolume) Cleanup(state multistep.StateBag) {
56+
ui := state.Get("ui").(packersdk.Ui)
57+
c := state.Get("config").(*Config)
58+
59+
if !c.RemoveVolume {
60+
return
61+
}
62+
63+
blockAPI := block.NewAPI(state.Get("client").(*scw.Client))
64+
65+
_, serverWasCreated := state.GetOk("server_id")
66+
createdVolumesI, createdVolumesExists := state.GetOk("created_volumes")
67+
if !serverWasCreated && createdVolumesExists {
68+
// If server was not created, we need to clean up manually created volumes
69+
createdVolumes := createdVolumesI.([]*instance.VolumeServerTemplate)
70+
for _, volume := range createdVolumes {
71+
err := blockAPI.DeleteVolume(&block.DeleteVolumeRequest{
72+
Zone: scw.Zone(c.Zone),
73+
VolumeID: *volume.ID,
74+
})
75+
if err != nil {
76+
ui.Error(fmt.Sprintf("failed to cleanup block volume %s: %s", *volume.ID, err))
77+
}
78+
}
79+
}
80+
81+
if _, ok := state.GetOk("snapshots"); !ok {
82+
// volume will be detached from server only after snapshotting ... so we don't
83+
// need to remove volume before snapshot step.
84+
return
85+
}
86+
87+
instanceAPI := instance.NewAPI(state.Get("client").(*scw.Client))
88+
89+
ui.Say("Removing Volumes ...")
90+
91+
volumes := state.Get("volumes").([]*instance.VolumeServer)
92+
for _, volume := range volumes {
93+
err := instanceAPI.DeleteVolume(&instance.DeleteVolumeRequest{
94+
VolumeID: volume.ID,
95+
Zone: scw.Zone(c.Zone),
96+
})
97+
if err != nil && !httperrors.Is404(err) {
98+
err := fmt.Errorf("error removing block volume %s: %s", volume.ID, err)
99+
state.Put("error", err)
100+
ui.Error(fmt.Sprintf("Error removing block volume %s: %s. (Ignored)", volume.ID, err))
101+
}
102+
if err == nil {
103+
continue
104+
}
105+
106+
err = blockAPI.DeleteVolume(&block.DeleteVolumeRequest{
107+
Zone: scw.Zone(c.Zone),
108+
VolumeID: volume.ID,
109+
})
110+
if err != nil {
111+
err := fmt.Errorf("error removing block volume %s: %s", volume.ID, err)
112+
state.Put("error", err)
113+
ui.Error(fmt.Sprintf("Error removing block volume %s: %s. (Ignored)", volume.ID, err))
114+
}
115+
}
116+
}

builder/scaleway/step_remove_volume.go

Lines changed: 0 additions & 49 deletions
This file was deleted.

internal/httperrors/httperrors.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package httperrors
2+
3+
import (
4+
"errors"
5+
"net/http"
6+
7+
"github.com/scaleway/scaleway-sdk-go/scw"
8+
)
9+
10+
// IsHTTPCodeError returns true if err is an http error with code statusCode
11+
func IsHTTPCodeError(err error, statusCode int) bool {
12+
if err == nil {
13+
return false
14+
}
15+
16+
responseError := &scw.ResponseError{}
17+
if errors.As(err, &responseError) && responseError.StatusCode == statusCode {
18+
return true
19+
}
20+
return false
21+
}
22+
23+
// Is404 returns true if err is an HTTP 404 error
24+
func Is404(err error) bool {
25+
notFoundError := &scw.ResourceNotFoundError{}
26+
return IsHTTPCodeError(err, http.StatusNotFound) || errors.As(err, &notFoundError)
27+
}

0 commit comments

Comments
 (0)