forked from hashicorp/packer
/
step_create_tags.go
137 lines (118 loc) · 3.63 KB
/
step_create_tags.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
package common
import (
"context"
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/ec2"
retry "github.com/hashicorp/packer/common"
"github.com/hashicorp/packer/helper/multistep"
"github.com/hashicorp/packer/packer"
"github.com/hashicorp/packer/template/interpolate"
)
type StepCreateTags struct {
Tags TagMap
SnapshotTags TagMap
Ctx interpolate.Context
}
func (s *StepCreateTags) Run(_ context.Context, state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(*ec2.EC2)
session := state.Get("awsSession").(*session.Session)
ui := state.Get("ui").(packer.Ui)
amis := state.Get("amis").(map[string]string)
if !s.Tags.IsSet() && !s.SnapshotTags.IsSet() {
return multistep.ActionContinue
}
// Adds tags to AMIs and snapshots
for region, ami := range amis {
ui.Say(fmt.Sprintf("Adding tags to AMI (%s)...", ami))
regionConn := ec2.New(session, &aws.Config{
Region: aws.String(region),
})
// Retrieve image list for given AMI
resourceIds := []*string{&ami}
imageResp, err := regionConn.DescribeImages(&ec2.DescribeImagesInput{
ImageIds: resourceIds,
})
if err != nil {
err := fmt.Errorf("Error retrieving details for AMI (%s): %s", ami, err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
if len(imageResp.Images) == 0 {
err := fmt.Errorf("Error retrieving details for AMI (%s), no images found", ami)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
image := imageResp.Images[0]
snapshotIds := []*string{}
// Add only those with a Snapshot ID, i.e. not Ephemeral
for _, device := range image.BlockDeviceMappings {
if device.Ebs != nil && device.Ebs.SnapshotId != nil {
ui.Say(fmt.Sprintf("Tagging snapshot: %s", *device.Ebs.SnapshotId))
resourceIds = append(resourceIds, device.Ebs.SnapshotId)
snapshotIds = append(snapshotIds, device.Ebs.SnapshotId)
}
}
// Convert tags to ec2.Tag format
ui.Say("Creating AMI tags")
amiTags, err := s.Tags.EC2Tags(s.Ctx, *ec2conn.Config.Region, state)
if err != nil {
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
amiTags.Report(ui)
ui.Say("Creating snapshot tags")
snapshotTags, err := s.SnapshotTags.EC2Tags(s.Ctx, *ec2conn.Config.Region, state)
if err != nil {
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
snapshotTags.Report(ui)
// Retry creating tags for about 2.5 minutes
err = retry.Retry(0.2, 30, 11, func(_ uint) (bool, error) {
// Tag images and snapshots
_, err := regionConn.CreateTags(&ec2.CreateTagsInput{
Resources: resourceIds,
Tags: amiTags,
})
if awsErr, ok := err.(awserr.Error); ok {
if awsErr.Code() == "InvalidAMIID.NotFound" ||
awsErr.Code() == "InvalidSnapshot.NotFound" {
return false, nil
}
}
// Override tags on snapshots
if len(snapshotTags) > 0 {
_, err = regionConn.CreateTags(&ec2.CreateTagsInput{
Resources: snapshotIds,
Tags: snapshotTags,
})
}
if err == nil {
return true, nil
}
if awsErr, ok := err.(awserr.Error); ok {
if awsErr.Code() == "InvalidSnapshot.NotFound" {
return false, nil
}
}
return true, err
})
if err != nil {
err := fmt.Errorf("Error adding tags to Resources (%#v): %s", resourceIds, err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
}
return multistep.ActionContinue
}
func (s *StepCreateTags) Cleanup(state multistep.StateBag) {
// No cleanup...
}