builder/amazon: Add SourceAMI and BuildRegion template
Added {{ .SourceAMI }} and {{ .BuildRegion }} template values availible in `ami_description`, `run_tags`, `run_volume_tags`, `tags`, and `snapshot_tags`.
This commit is contained in:
parent
198824a25f
commit
ba9cae5078
|
@ -64,6 +64,9 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
|||
InterpolateContext: &b.config.ctx,
|
||||
InterpolateFilter: &interpolate.RenderFilter{
|
||||
Exclude: []string{
|
||||
"ami_description",
|
||||
"snapshot_tags",
|
||||
"tags",
|
||||
"command_wrapper",
|
||||
"post_mount_commands",
|
||||
"pre_mount_commands",
|
||||
|
@ -263,10 +266,12 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
ProductCodes: b.config.AMIProductCodes,
|
||||
SnapshotUsers: b.config.SnapshotUsers,
|
||||
SnapshotGroups: b.config.SnapshotGroups,
|
||||
Ctx: b.config.ctx,
|
||||
},
|
||||
&awscommon.StepCreateTags{
|
||||
Tags: b.config.AMITags,
|
||||
SnapshotTags: b.config.SnapshotTags,
|
||||
Ctx: b.config.ctx,
|
||||
},
|
||||
)
|
||||
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
package common
|
||||
|
||||
type BuildInfoTemplate struct {
|
||||
SourceAMI string
|
||||
BuildRegion string
|
||||
}
|
|
@ -2,7 +2,6 @@ package common
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
|
@ -11,11 +10,13 @@ import (
|
|||
"github.com/mitchellh/multistep"
|
||||
retry "github.com/mitchellh/packer/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/mitchellh/packer/template/interpolate"
|
||||
)
|
||||
|
||||
type StepCreateTags struct {
|
||||
Tags map[string]string
|
||||
SnapshotTags map[string]string
|
||||
Ctx interpolate.Context
|
||||
}
|
||||
|
||||
func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
|
||||
|
@ -23,6 +24,13 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
|
|||
ui := state.Get("ui").(packer.Ui)
|
||||
amis := state.Get("amis").(map[string]string)
|
||||
|
||||
var sourceAMI string
|
||||
if rawSourceAMI, hasSourceAMI := state.GetOk("source_image"); hasSourceAMI {
|
||||
sourceAMI = *rawSourceAMI.(*ec2.Image).ImageId
|
||||
} else {
|
||||
sourceAMI = ""
|
||||
}
|
||||
|
||||
if len(s.Tags) == 0 && len(s.SnapshotTags) == 0 {
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
@ -31,6 +39,22 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
|
|||
for region, ami := range amis {
|
||||
ui.Say(fmt.Sprintf("Adding tags to AMI (%s)...", ami))
|
||||
|
||||
// Convert tags to ec2.Tag format
|
||||
amiTags, err := ConvertToEC2Tags(s.Tags, *ec2conn.Config.Region, sourceAMI, s.Ctx, ui)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
ui.Say(fmt.Sprintf("Snapshot tags:"))
|
||||
snapshotTags, err := ConvertToEC2Tags(s.SnapshotTags, *ec2conn.Config.Region, sourceAMI, s.Ctx, ui)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Declare list of resources to tag
|
||||
awsConfig := aws.Config{
|
||||
Credentials: ec2conn.Config.Credentials,
|
||||
|
@ -79,9 +103,20 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction {
|
|||
|
||||
// Convert tags to ec2.Tag format
|
||||
ui.Say("Creating AMI tags")
|
||||
amiTags := ConvertToEC2Tags(s.Tags)
|
||||
amiTags, err = ConvertToEC2Tags(s.Tags, *ec2conn.Config.Region, sourceAMI, s.Ctx, ui)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
ui.Say("Creating snapshot tags")
|
||||
snapshotTags := ConvertToEC2Tags(s.SnapshotTags)
|
||||
snapshotTags, err = ConvertToEC2Tags(s.SnapshotTags, *ec2conn.Config.Region, sourceAMI, s.Ctx, ui)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Retry creating tags for about 2.5 minutes
|
||||
err = retry.Retry(0.2, 30, 11, func() (bool, error) {
|
||||
|
@ -130,14 +165,25 @@ func (s *StepCreateTags) Cleanup(state multistep.StateBag) {
|
|||
// No cleanup...
|
||||
}
|
||||
|
||||
func ConvertToEC2Tags(tags map[string]string) []*ec2.Tag {
|
||||
var ec2tags []*ec2.Tag
|
||||
func ConvertToEC2Tags(tags map[string]string, region, sourceAmiId string, ctx interpolate.Context, ui packer.Ui) ([]*ec2.Tag, error) {
|
||||
var amiTags []*ec2.Tag
|
||||
for key, value := range tags {
|
||||
log.Printf("[DEBUG] Creating tag %s=%s", key, value)
|
||||
ec2tags = append(ec2tags, &ec2.Tag{
|
||||
|
||||
ctx.Data = &BuildInfoTemplate{
|
||||
SourceAMI: sourceAmiId,
|
||||
BuildRegion: region,
|
||||
}
|
||||
interpolatedValue, err := interpolate.Render(value, &ctx)
|
||||
if err != nil {
|
||||
return amiTags, fmt.Errorf("Error processing tag: %s:%s - %s", key, value, err)
|
||||
}
|
||||
|
||||
ui.Message(fmt.Sprintf("Adding tag: \"%s\": \"%s\"", key, interpolatedValue))
|
||||
amiTags = append(amiTags, &ec2.Tag{
|
||||
Key: aws.String(key),
|
||||
Value: aws.String(value),
|
||||
Value: aws.String(interpolatedValue),
|
||||
})
|
||||
}
|
||||
return ec2tags
|
||||
|
||||
return amiTags, nil
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/mitchellh/packer/template/interpolate"
|
||||
)
|
||||
|
||||
type StepModifyAMIAttributes struct {
|
||||
|
@ -17,12 +18,20 @@ type StepModifyAMIAttributes struct {
|
|||
SnapshotGroups []string
|
||||
ProductCodes []string
|
||||
Description string
|
||||
Ctx interpolate.Context
|
||||
}
|
||||
|
||||
func (s *StepModifyAMIAttributes) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
amis := state.Get("amis").(map[string]string)
|
||||
|
||||
var sourceAMI string
|
||||
if rawSourceAMI, hasSourceAMI := state.GetOk("source_image"); hasSourceAMI {
|
||||
sourceAMI = *rawSourceAMI.(*ec2.Image).ImageId
|
||||
} else {
|
||||
sourceAMI = ""
|
||||
}
|
||||
snapshots := state.Get("snapshots").(map[string][]string)
|
||||
|
||||
// Determine if there is any work to do.
|
||||
|
@ -38,6 +47,18 @@ func (s *StepModifyAMIAttributes) Run(state multistep.StateBag) multistep.StepAc
|
|||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
var err error
|
||||
s.Ctx.Data = &BuildInfoTemplate{
|
||||
SourceAMI: sourceAMI,
|
||||
BuildRegion: *ec2conn.Config.Region,
|
||||
}
|
||||
s.Description, err = interpolate.Render(s.Description, &s.Ctx)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error interpolating AMI description: %s", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
// Construct the modify image and snapshot attribute requests we're going
|
||||
// to make. We need to make each separately since the EC2 API only allows
|
||||
// changing one type at a kind currently.
|
||||
|
|
|
@ -13,6 +13,7 @@ import (
|
|||
|
||||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/mitchellh/packer/template/interpolate"
|
||||
)
|
||||
|
||||
type StepRunSourceInstance struct {
|
||||
|
@ -32,6 +33,7 @@ type StepRunSourceInstance struct {
|
|||
Tags map[string]string
|
||||
UserData string
|
||||
UserDataFile string
|
||||
Ctx interpolate.Context
|
||||
|
||||
instanceId string
|
||||
spotRequest *ec2.SpotInstanceRequest
|
||||
|
@ -275,7 +277,29 @@ func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepActi
|
|||
if _, exists := s.Tags["Name"]; !exists {
|
||||
s.Tags["Name"] = "Packer Builder"
|
||||
}
|
||||
ec2Tags := ConvertToEC2Tags(s.Tags)
|
||||
|
||||
ec2Tags := make([]*ec2.Tag, 1, len(s.Tags))
|
||||
for k, v := range s.Tags {
|
||||
s.Ctx.Data = &BuildInfoTemplate{
|
||||
SourceAMI: s.SourceAMI,
|
||||
BuildRegion: *ec2conn.Config.Region,
|
||||
}
|
||||
interpolatedValue, err := interpolate.Render(v, &s.Ctx)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error processing tag: %s:%s - %s", k, v, err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
ec2Tags = append(ec2Tags, &ec2.Tag{Key: aws.String(k), Value: aws.String(interpolatedValue)})
|
||||
}
|
||||
ec2Tags, err = ConvertToEC2Tags(s.Tags, *ec2conn.Config.Region, s.SourceAMI, s.Ctx, ui)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error tagging source instance: %s", err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
_, err = ec2conn.CreateTags(&ec2.CreateTagsInput{
|
||||
Tags: ec2Tags,
|
||||
|
|
|
@ -44,6 +44,15 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
|||
err := config.Decode(&b.config, &config.DecodeOpts{
|
||||
Interpolate: true,
|
||||
InterpolateContext: &b.config.ctx,
|
||||
InterpolateFilter: &interpolate.RenderFilter{
|
||||
Exclude: []string{
|
||||
"ami_description",
|
||||
"run_tags",
|
||||
"run_volume_tags",
|
||||
"snapshot_tags",
|
||||
"tags",
|
||||
},
|
||||
},
|
||||
}, raws...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -137,10 +146,12 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
AvailabilityZone: b.config.AvailabilityZone,
|
||||
BlockDevices: b.config.BlockDevices,
|
||||
Tags: b.config.RunTags,
|
||||
Ctx: b.config.ctx,
|
||||
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
|
||||
},
|
||||
&stepTagEBSVolumes{
|
||||
VolumeRunTags: b.config.VolumeRunTags,
|
||||
Ctx: b.config.ctx,
|
||||
},
|
||||
&awscommon.StepGetPassword{
|
||||
Debug: b.config.PackerDebug,
|
||||
|
@ -184,10 +195,12 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
ProductCodes: b.config.AMIProductCodes,
|
||||
SnapshotUsers: b.config.SnapshotUsers,
|
||||
SnapshotGroups: b.config.SnapshotGroups,
|
||||
Ctx: b.config.ctx,
|
||||
},
|
||||
&awscommon.StepCreateTags{
|
||||
Tags: b.config.AMITags,
|
||||
SnapshotTags: b.config.SnapshotTags,
|
||||
Ctx: b.config.ctx,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
|
@ -7,15 +7,18 @@ import (
|
|||
"github.com/mitchellh/multistep"
|
||||
"github.com/mitchellh/packer/builder/amazon/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/mitchellh/packer/template/interpolate"
|
||||
)
|
||||
|
||||
type stepTagEBSVolumes struct {
|
||||
VolumeRunTags map[string]string
|
||||
Ctx interpolate.Context
|
||||
}
|
||||
|
||||
func (s *stepTagEBSVolumes) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
instance := state.Get("instance").(*ec2.Instance)
|
||||
sourceAMI := state.Get("source_image").(*ec2.Image)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
if len(s.VolumeRunTags) == 0 {
|
||||
|
@ -33,10 +36,32 @@ func (s *stepTagEBSVolumes) Run(state multistep.StateBag) multistep.StepAction {
|
|||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
ui.Say("Adding tags to source EBS Volumes")
|
||||
tags := common.ConvertToEC2Tags(s.VolumeRunTags)
|
||||
tags := make([]*ec2.Tag, len(s.VolumeRunTags))
|
||||
for key, value := range s.VolumeRunTags {
|
||||
s.Ctx.Data = &common.BuildInfoTemplate{
|
||||
SourceAMI: *sourceAMI.ImageId,
|
||||
BuildRegion: *ec2conn.Config.Region,
|
||||
}
|
||||
interpolatedValue, err := interpolate.Render(value, &s.Ctx)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error processing volume tag: %s:%s - %s", key, value, err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
tags = append(tags, &ec2.Tag{Key: &key, Value: &interpolatedValue})
|
||||
}
|
||||
|
||||
_, err := ec2conn.CreateTags(&ec2.CreateTagsInput{
|
||||
ui.Say("Adding tags to source EBS Volumes")
|
||||
tags, err := common.ConvertToEC2Tags(s.VolumeRunTags, *ec2conn.Config.Region, *sourceAMI.ImageId, s.Ctx, ui)
|
||||
if err != nil {
|
||||
err := fmt.Errorf("Error tagging source EBS Volumes on %s: %s", *instance.InstanceId, err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
_, err = ec2conn.CreateTags(&ec2.CreateTagsInput{
|
||||
Resources: volumeIds,
|
||||
Tags: tags,
|
||||
})
|
||||
|
|
|
@ -41,6 +41,12 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
|||
err := config.Decode(&b.config, &config.DecodeOpts{
|
||||
Interpolate: true,
|
||||
InterpolateContext: &b.config.ctx,
|
||||
InterpolateFilter: &interpolate.RenderFilter{
|
||||
Exclude: []string{
|
||||
"run_tags",
|
||||
"tags",
|
||||
},
|
||||
},
|
||||
}, raws...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -128,10 +134,12 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
AvailabilityZone: b.config.AvailabilityZone,
|
||||
BlockDevices: launchBlockDevices,
|
||||
Tags: b.config.RunTags,
|
||||
Ctx: b.config.ctx,
|
||||
InstanceInitiatedShutdownBehavior: b.config.InstanceInitiatedShutdownBehavior,
|
||||
},
|
||||
&stepTagEBSVolumes{
|
||||
VolumeMapping: b.config.VolumeMappings,
|
||||
Ctx: b.config.ctx,
|
||||
},
|
||||
&awscommon.StepGetPassword{
|
||||
Debug: b.config.PackerDebug,
|
||||
|
|
|
@ -6,16 +6,20 @@ import (
|
|||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/mitchellh/multistep"
|
||||
awscommon "github.com/mitchellh/packer/builder/amazon/common"
|
||||
"github.com/mitchellh/packer/packer"
|
||||
"github.com/mitchellh/packer/template/interpolate"
|
||||
)
|
||||
|
||||
type stepTagEBSVolumes struct {
|
||||
VolumeMapping []BlockDevice
|
||||
Ctx interpolate.Context
|
||||
}
|
||||
|
||||
func (s *stepTagEBSVolumes) Run(state multistep.StateBag) multistep.StepAction {
|
||||
ec2conn := state.Get("ec2").(*ec2.EC2)
|
||||
instance := state.Get("instance").(*ec2.Instance)
|
||||
sourceAMI := state.Get("source_image").(*ec2.Image)
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
|
||||
volumes := make(EbsVolumes)
|
||||
|
@ -42,9 +46,21 @@ func (s *stepTagEBSVolumes) Run(state multistep.StateBag) multistep.StepAction {
|
|||
|
||||
tags := make([]*ec2.Tag, 0, len(mapping.Tags))
|
||||
for key, value := range mapping.Tags {
|
||||
s.Ctx.Data = &awscommon.BuildInfoTemplate{
|
||||
SourceAMI: *sourceAMI.ImageId,
|
||||
BuildRegion: *ec2conn.Config.Region,
|
||||
}
|
||||
interpolatedValue, err := interpolate.Render(value, &s.Ctx)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error processing tag: %s:%s - %s", key, value, err)
|
||||
state.Put("error", err)
|
||||
ui.Error(err.Error())
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
tags = append(tags, &ec2.Tag{
|
||||
Key: aws.String(fmt.Sprintf("%s", key)),
|
||||
Value: aws.String(fmt.Sprintf("%s", value)),
|
||||
Value: aws.String(fmt.Sprintf("%s", interpolatedValue)),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -63,8 +63,13 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) {
|
|||
InterpolateContext: &b.config.ctx,
|
||||
InterpolateFilter: &interpolate.RenderFilter{
|
||||
Exclude: []string{
|
||||
"ami_description",
|
||||
"bundle_upload_command",
|
||||
"bundle_vol_command",
|
||||
"run_tags",
|
||||
"run_volume_tags",
|
||||
"snapshot_tags",
|
||||
"tags",
|
||||
},
|
||||
},
|
||||
}, configs...)
|
||||
|
@ -223,6 +228,7 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
AvailabilityZone: b.config.AvailabilityZone,
|
||||
BlockDevices: b.config.BlockDevices,
|
||||
Tags: b.config.RunTags,
|
||||
Ctx: b.config.ctx,
|
||||
},
|
||||
&awscommon.StepGetPassword{
|
||||
Debug: b.config.PackerDebug,
|
||||
|
@ -265,10 +271,12 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe
|
|||
ProductCodes: b.config.AMIProductCodes,
|
||||
SnapshotUsers: b.config.SnapshotUsers,
|
||||
SnapshotGroups: b.config.SnapshotGroups,
|
||||
Ctx: b.config.ctx,
|
||||
},
|
||||
&awscommon.StepCreateTags{
|
||||
Tags: b.config.AMITags,
|
||||
SnapshotTags: b.config.SnapshotTags,
|
||||
Ctx: b.config.ctx,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue