Closes #3908: Adds snapshot tag overrides
This commit adds the ability to configure unique tags on snapshots that are separate from the tags defined on the AMI. Anything applied to the AMI will also be applied to the snapshots, but `snapshot_tags` will override and append tags to the tags already applied to the snapshots
This commit is contained in:
parent
929ca30141
commit
2e65867cba
|
@ -262,7 +262,8 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
ProductCodes: b.config.AMIProductCodes,
|
||||
},
|
||||
&awscommon.StepCreateTags{
|
||||
Tags: b.config.AMITags,
|
||||
Tags: b.config.AMITags,
|
||||
SnapshotTags: b.config.SnapshotTags,
|
||||
},
|
||||
)
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@ type AMIConfig struct {
|
|||
AMIEnhancedNetworking bool `mapstructure:"enhanced_networking"`
|
||||
AMIForceDeregister bool `mapstructure:"force_deregister"`
|
||||
AMIEncryptBootVolume bool `mapstructure:"encrypt_boot"`
|
||||
SnapshotTags map[string]string `mapstructure:"snapshot_tags"`
|
||||
}
|
||||
|
||||
func (c *AMIConfig) Prepare(ctx *interpolate.Context) []error {
|
||||
|
|
|
@ -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,21 +22,15 @@ 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 {
|
||||
if len(s.Tags) > 0 || len(s.SnapshotTags) > 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),
|
||||
})
|
||||
}
|
||||
// Convert tags to ec2.Tag format
|
||||
ec2Tags := ConvertToEC2Tags(s.Tags, ui)
|
||||
snapshotTags := ConvertToEC2Tags(s.SnapshotTags, ui)
|
||||
|
||||
// Declare list of resources to tag
|
||||
resourceIds := []*string{&ami}
|
||||
awsConfig := aws.Config{
|
||||
Credentials: ec2conn.Config.Credentials,
|
||||
Region: aws.String(region),
|
||||
|
@ -47,10 +42,10 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
|
|||
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,
|
||||
})
|
||||
|
@ -70,17 +65,20 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
|
|||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
// 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: ec2Tags,
|
||||
|
@ -94,6 +92,20 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
|
|||
return false, nil
|
||||
}
|
||||
}
|
||||
|
||||
// Override tags on snapshots
|
||||
_, 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
|
||||
})
|
||||
|
||||
|
@ -112,3 +124,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 ec2Tags []*ec2.Tag
|
||||
for key, value := range tags {
|
||||
ui.Message(fmt.Sprintf("Adding tag: \"%s\": \"%s\"", key, value))
|
||||
ec2Tags = append(ec2Tags, &ec2.Tag{
|
||||
Key: aws.String(key),
|
||||
Value: aws.String(value),
|
||||
})
|
||||
}
|
||||
return ec2Tags
|
||||
}
|
||||
|
|
|
@ -182,7 +182,8 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
ProductCodes: b.config.AMIProductCodes,
|
||||
},
|
||||
&awscommon.StepCreateTags{
|
||||
Tags: b.config.AMITags,
|
||||
Tags: b.config.AMITags,
|
||||
SnapshotTags: b.config.SnapshotTags,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -263,7 +263,8 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
ProductCodes: b.config.AMIProductCodes,
|
||||
},
|
||||
&awscommon.StepCreateTags{
|
||||
Tags: b.config.AMITags,
|
||||
Tags: b.config.AMITags,
|
||||
SnapshotTags: b.config.SnapshotTags,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -200,6 +200,9 @@ each category, the available configuration keys are alphabetized.
|
|||
- `most_recent` (bool) - Selects the newest created image when true.
|
||||
This is most useful for selecting a daily distro build.
|
||||
|
||||
- `snapshot_tags` (object of key/value strings) - Tags to apply to snapshot.
|
||||
They will override AMI tags if already applied to snapshot.
|
||||
|
||||
- `tags` (object of key/value strings) - Tags applied to the AMI.
|
||||
|
||||
## Basic Example
|
||||
|
|
|
@ -203,6 +203,9 @@ builder.
|
|||
- `most_recent` (bool) - Selects the newest created image when true.
|
||||
This is most useful for selecting a daily distro build.
|
||||
|
||||
- `snapshot_tags` (object of key/value strings) - Tags to apply to snapshot.
|
||||
They will override AMI tags if already applied to snapshot.
|
||||
|
||||
- `spot_price` (string) - The maximum hourly price to pay for a spot instance
|
||||
to create the AMI. Spot instances are a type of instance that EC2 starts
|
||||
when the current spot price is less than the maximum price you specify. Spot
|
||||
|
|
|
@ -219,6 +219,9 @@ builder.
|
|||
- `most_recent` (bool) - Selects the newest created image when true.
|
||||
This is most useful for selecting a daily distro build.
|
||||
|
||||
- `snapshot_tags` (object of key/value strings) - Tags to apply to snapshot.
|
||||
They will override AMI tags if already applied to snapshot.
|
||||
|
||||
- `spot_price` (string) - The maximum hourly price to launch a spot instance
|
||||
to create the AMI. It is a type of instances that EC2 starts when the
|
||||
maximum price that you specify exceeds the current spot price. Spot price
|
||||
|
|
Loading…
Reference in New Issue