/
step_create_image.go
144 lines (115 loc) · 4.51 KB
/
step_create_image.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package ecs
import (
"context"
"fmt"
"time"
"github.com/hashicorp/packer/common/random"
"github.com/aliyun/alibaba-cloud-sdk-go/sdk/responses"
"github.com/aliyun/alibaba-cloud-sdk-go/services/ecs"
"github.com/hashicorp/packer/common/uuid"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
)
type stepCreateAlicloudImage struct {
AlicloudImageIgnoreDataDisks bool
WaitSnapshotReadyTimeout int
image *ecs.Image
}
var createImageRetryErrors = []string{
"IdempotentProcessing",
}
func (s *stepCreateAlicloudImage) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
config := state.Get("config").(*Config)
client := state.Get("client").(*ClientWrapper)
ui := state.Get("ui").(packer.Ui)
tempImageName := config.AlicloudImageName
if config.ImageEncrypted.True() {
tempImageName = fmt.Sprintf("packer_%s", random.AlphaNum(7))
ui.Say(fmt.Sprintf("Creating temporary image for encryption: %s", tempImageName))
} else {
ui.Say(fmt.Sprintf("Creating image: %s", tempImageName))
}
createImageRequest := s.buildCreateImageRequest(state, tempImageName)
createImageResponse, err := client.WaitForExpected(&WaitForExpectArgs{
RequestFunc: func() (responses.AcsResponse, error) {
return client.CreateImage(createImageRequest)
},
EvalFunc: client.EvalCouldRetryResponse(createImageRetryErrors, EvalRetryErrorType),
})
if err != nil {
return halt(state, err, "Error creating image")
}
imageId := createImageResponse.(*ecs.CreateImageResponse).ImageId
imagesResponse, err := client.WaitForImageStatus(config.AlicloudRegion, imageId, ImageStatusAvailable, time.Duration(s.WaitSnapshotReadyTimeout)*time.Second)
// save image first for cleaning up if timeout
images := imagesResponse.(*ecs.DescribeImagesResponse).Images.Image
if len(images) == 0 {
return halt(state, err, "Unable to find created image")
}
s.image = &images[0]
if err != nil {
return halt(state, err, "Timeout waiting for image to be created")
}
var snapshotIds []string
for _, device := range images[0].DiskDeviceMappings.DiskDeviceMapping {
snapshotIds = append(snapshotIds, device.SnapshotId)
}
state.Put("alicloudimage", imageId)
state.Put("alicloudsnapshots", snapshotIds)
alicloudImages := make(map[string]string)
alicloudImages[config.AlicloudRegion] = images[0].ImageId
state.Put("alicloudimages", alicloudImages)
return multistep.ActionContinue
}
func (s *stepCreateAlicloudImage) Cleanup(state multistep.StateBag) {
if s.image == nil {
return
}
config := state.Get("config").(*Config)
encryptedSet := config.ImageEncrypted.True()
_, cancelled := state.GetOk(multistep.StateCancelled)
_, halted := state.GetOk(multistep.StateHalted)
if !cancelled && !halted && !encryptedSet {
return
}
client := state.Get("client").(*ClientWrapper)
ui := state.Get("ui").(packer.Ui)
if !cancelled && !halted && encryptedSet {
ui.Say(fmt.Sprintf("Deleting temporary image %s(%s) and related snapshots after finishing encryption...", s.image.ImageId, s.image.ImageName))
} else {
ui.Say("Deleting the image and related snapshots because of cancellation or error...")
}
deleteImageRequest := ecs.CreateDeleteImageRequest()
deleteImageRequest.RegionId = config.AlicloudRegion
deleteImageRequest.ImageId = s.image.ImageId
if _, err := client.DeleteImage(deleteImageRequest); err != nil {
ui.Error(fmt.Sprintf("Error deleting image, it may still be around: %s", err))
return
}
//Delete the snapshot of this image
for _, diskDevices := range s.image.DiskDeviceMappings.DiskDeviceMapping {
deleteSnapshotRequest := ecs.CreateDeleteSnapshotRequest()
deleteSnapshotRequest.SnapshotId = diskDevices.SnapshotId
if _, err := client.DeleteSnapshot(deleteSnapshotRequest); err != nil {
ui.Error(fmt.Sprintf("Error deleting snapshot, it may still be around: %s", err))
return
}
}
}
func (s *stepCreateAlicloudImage) buildCreateImageRequest(state multistep.StateBag, imageName string) *ecs.CreateImageRequest {
config := state.Get("config").(*Config)
request := ecs.CreateCreateImageRequest()
request.ClientToken = uuid.TimeOrderedUUID()
request.RegionId = config.AlicloudRegion
request.ImageName = imageName
request.ImageVersion = config.AlicloudImageVersion
request.Description = config.AlicloudImageDescription
if s.AlicloudImageIgnoreDataDisks {
snapshotId := state.Get("alicloudsnapshot").(string)
request.SnapshotId = snapshotId
} else {
instance := state.Get("instance").(*ecs.Instance)
request.InstanceId = instance.InstanceId
}
return request
}