|
|
|
|
@ -13,7 +13,8 @@ import (
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type StepCreateTags struct {
|
|
|
|
|
Tags map[string]string
|
|
|
|
|
Tags map[string]string
|
|
|
|
|
SnapshotTags map[string]string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
|
|
|
|
|
@ -21,88 +22,100 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
|
|
|
|
|
ui := state.Get("ui").(packer.Ui)
|
|
|
|
|
amis := state.Get("amis").(map[string]string)
|
|
|
|
|
|
|
|
|
|
if len(s.Tags) > 0 {
|
|
|
|
|
for region, ami := range amis {
|
|
|
|
|
ui.Say(fmt.Sprintf("Adding tags to AMI (%s)...", ami))
|
|
|
|
|
|
|
|
|
|
var ec2Tags []*ec2.Tag
|
|
|
|
|
for key, value := range s.Tags {
|
|
|
|
|
ui.Message(fmt.Sprintf("Adding tag: \"%s\": \"%s\"", key, value))
|
|
|
|
|
ec2Tags = append(ec2Tags, &ec2.Tag{
|
|
|
|
|
Key: aws.String(key),
|
|
|
|
|
Value: aws.String(value),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
if len(s.Tags) == 0 && len(s.SnapshotTags) == 0 {
|
|
|
|
|
return multistep.ActionContinue
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Declare list of resources to tag
|
|
|
|
|
resourceIds := []*string{&ami}
|
|
|
|
|
awsConfig := aws.Config{
|
|
|
|
|
Credentials: ec2conn.Config.Credentials,
|
|
|
|
|
Region: aws.String(region),
|
|
|
|
|
}
|
|
|
|
|
session, err := session.NewSession(&awsConfig)
|
|
|
|
|
if err != nil {
|
|
|
|
|
err := fmt.Errorf("Error creating AWS session: %s", err)
|
|
|
|
|
state.Put("error", err)
|
|
|
|
|
ui.Error(err.Error())
|
|
|
|
|
return multistep.ActionHalt
|
|
|
|
|
}
|
|
|
|
|
// 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)
|
|
|
|
|
// Convert tags to ec2.Tag format
|
|
|
|
|
amiTags := ConvertToEC2Tags(s.Tags, ui)
|
|
|
|
|
ui.Say(fmt.Sprintf("Snapshot tags:"))
|
|
|
|
|
snapshotTags := ConvertToEC2Tags(s.SnapshotTags, ui)
|
|
|
|
|
|
|
|
|
|
// Retrieve image list for given AMI
|
|
|
|
|
imageResp, err := regionconn.DescribeImages(&ec2.DescribeImagesInput{
|
|
|
|
|
ImageIds: resourceIds,
|
|
|
|
|
})
|
|
|
|
|
// Declare list of resources to tag
|
|
|
|
|
awsConfig := aws.Config{
|
|
|
|
|
Credentials: ec2conn.Config.Credentials,
|
|
|
|
|
Region: aws.String(region),
|
|
|
|
|
}
|
|
|
|
|
session, err := session.NewSession(&awsConfig)
|
|
|
|
|
if err != nil {
|
|
|
|
|
err := fmt.Errorf("Error creating AWS session: %s", err)
|
|
|
|
|
state.Put("error", err)
|
|
|
|
|
ui.Error(err.Error())
|
|
|
|
|
return multistep.ActionHalt
|
|
|
|
|
}
|
|
|
|
|
regionconn := ec2.New(session)
|
|
|
|
|
|
|
|
|
|
// 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 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
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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{}
|
|
|
|
|
|
|
|
|
|
image := imageResp.Images[0]
|
|
|
|
|
// 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)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 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)
|
|
|
|
|
// Retry creating tags for about 2.5 minutes
|
|
|
|
|
err = retry.Retry(0.2, 30, 11, func() (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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Retry creating tags for about 2.5 minutes
|
|
|
|
|
err = retry.Retry(0.2, 30, 11, func() (bool, error) {
|
|
|
|
|
_, err := regionconn.CreateTags(&ec2.CreateTagsInput{
|
|
|
|
|
Resources: resourceIds,
|
|
|
|
|
Tags: ec2Tags,
|
|
|
|
|
})
|
|
|
|
|
if err == nil {
|
|
|
|
|
return true, nil
|
|
|
|
|
}
|
|
|
|
|
if awsErr, ok := err.(awserr.Error); ok {
|
|
|
|
|
if awsErr.Code() == "InvalidAMIID.NotFound" ||
|
|
|
|
|
awsErr.Code() == "InvalidSnapshot.NotFound" {
|
|
|
|
|
return false, nil
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true, err
|
|
|
|
|
// Override tags on snapshots
|
|
|
|
|
_, err = regionconn.CreateTags(&ec2.CreateTagsInput{
|
|
|
|
|
Resources: snapshotIds,
|
|
|
|
|
Tags: snapshotTags,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
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
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -112,3 +125,15 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
|
|
|
|
|
func (s *StepCreateTags) Cleanup(state multistep.StateBag) {
|
|
|
|
|
// No cleanup...
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func ConvertToEC2Tags(tags map[string]string, ui packer.Ui) []*ec2.Tag {
|
|
|
|
|
var amiTags []*ec2.Tag
|
|
|
|
|
for key, value := range tags {
|
|
|
|
|
ui.Message(fmt.Sprintf("Adding tag: \"%s\": \"%s\"", key, value))
|
|
|
|
|
amiTags = append(amiTags, &ec2.Tag{
|
|
|
|
|
Key: aws.String(key),
|
|
|
|
|
Value: aws.String(value),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
return amiTags
|
|
|
|
|
}
|
|
|
|
|
|