From ba9cae50782844580f7ee1f797e79c328109631f Mon Sep 17 00:00:00 2001 From: Rickard von Essen Date: Tue, 10 Jan 2017 11:41:28 +0100 Subject: [PATCH 1/4] 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`. --- builder/amazon/chroot/builder.go | 5 ++ .../amazon/common/interpolate_build_info.go | 6 ++ builder/amazon/common/step_create_tags.go | 64 ++++++++++++++++--- .../common/step_modify_ami_attributes.go | 21 ++++++ .../amazon/common/step_run_source_instance.go | 26 +++++++- builder/amazon/ebs/builder.go | 13 ++++ builder/amazon/ebs/step_tag_ebs_volumes.go | 31 ++++++++- builder/amazon/ebsvolume/builder.go | 8 +++ .../amazon/ebsvolume/step_tag_ebs_volumes.go | 18 +++++- builder/amazon/instance/builder.go | 8 +++ 10 files changed, 186 insertions(+), 14 deletions(-) create mode 100644 builder/amazon/common/interpolate_build_info.go diff --git a/builder/amazon/chroot/builder.go b/builder/amazon/chroot/builder.go index 507ff46ff..973d1c1b6 100644 --- a/builder/amazon/chroot/builder.go +++ b/builder/amazon/chroot/builder.go @@ -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, }, ) diff --git a/builder/amazon/common/interpolate_build_info.go b/builder/amazon/common/interpolate_build_info.go new file mode 100644 index 000000000..a279a2f72 --- /dev/null +++ b/builder/amazon/common/interpolate_build_info.go @@ -0,0 +1,6 @@ +package common + +type BuildInfoTemplate struct { + SourceAMI string + BuildRegion string +} diff --git a/builder/amazon/common/step_create_tags.go b/builder/amazon/common/step_create_tags.go index b3a811bad..c4203e9f2 100644 --- a/builder/amazon/common/step_create_tags.go +++ b/builder/amazon/common/step_create_tags.go @@ -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 } diff --git a/builder/amazon/common/step_modify_ami_attributes.go b/builder/amazon/common/step_modify_ami_attributes.go index 514b84c86..647a37a25 100644 --- a/builder/amazon/common/step_modify_ami_attributes.go +++ b/builder/amazon/common/step_modify_ami_attributes.go @@ -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. diff --git a/builder/amazon/common/step_run_source_instance.go b/builder/amazon/common/step_run_source_instance.go index 3b61a2485..68b0c2951 100644 --- a/builder/amazon/common/step_run_source_instance.go +++ b/builder/amazon/common/step_run_source_instance.go @@ -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, diff --git a/builder/amazon/ebs/builder.go b/builder/amazon/ebs/builder.go index 725a43adc..e8a1a15f6 100644 --- a/builder/amazon/ebs/builder.go +++ b/builder/amazon/ebs/builder.go @@ -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, }, } diff --git a/builder/amazon/ebs/step_tag_ebs_volumes.go b/builder/amazon/ebs/step_tag_ebs_volumes.go index bf7355c8d..0ecee7264 100644 --- a/builder/amazon/ebs/step_tag_ebs_volumes.go +++ b/builder/amazon/ebs/step_tag_ebs_volumes.go @@ -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, }) diff --git a/builder/amazon/ebsvolume/builder.go b/builder/amazon/ebsvolume/builder.go index cb70aec47..c61bfdc7d 100644 --- a/builder/amazon/ebsvolume/builder.go +++ b/builder/amazon/ebsvolume/builder.go @@ -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, diff --git a/builder/amazon/ebsvolume/step_tag_ebs_volumes.go b/builder/amazon/ebsvolume/step_tag_ebs_volumes.go index 297f8683f..3528c92d1 100644 --- a/builder/amazon/ebsvolume/step_tag_ebs_volumes.go +++ b/builder/amazon/ebsvolume/step_tag_ebs_volumes.go @@ -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)), }) } diff --git a/builder/amazon/instance/builder.go b/builder/amazon/instance/builder.go index 62644a2cd..ce5664d26 100644 --- a/builder/amazon/instance/builder.go +++ b/builder/amazon/instance/builder.go @@ -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, }, } From ce411a0d17ae40960ce2954b0fc0fe8680699f45 Mon Sep 17 00:00:00 2001 From: Rickard von Essen Date: Tue, 10 Jan 2017 14:47:53 +0100 Subject: [PATCH 2/4] Added docs for SourceAMI and BuildRegion template --- .../docs/builders/amazon-chroot.html.md | 19 +++++++++++--- .../source/docs/builders/amazon-ebs.html.md | 25 +++++++++++++++---- .../docs/builders/amazon-ebsvolume.html.md | 10 ++++++-- .../docs/builders/amazon-instance.html.md | 15 ++++++++--- 4 files changed, 56 insertions(+), 13 deletions(-) diff --git a/website/source/docs/builders/amazon-chroot.html.md b/website/source/docs/builders/amazon-chroot.html.md index a58e3ccea..97f575b2e 100644 --- a/website/source/docs/builders/amazon-chroot.html.md +++ b/website/source/docs/builders/amazon-chroot.html.md @@ -75,7 +75,11 @@ each category, the available configuration keys are alphabetized. ### Optional: - `ami_description` (string) - The description to set for the - resulting AMI(s). By default this description is empty. + resulting AMI(s). By default this description is empty. This is a + [configuration template](/docs/templates/configuration-templates.html) + where the `SourceAMI` variable is replaced with the source AMI ID and + `BuildRegion` variable is replaced with name of the region where this + is built. - `ami_groups` (array of strings) - A list of groups that have access to launch the resulting AMI(s). By default no groups have permission to launch @@ -210,7 +214,11 @@ each category, the available configuration keys are alphabetized. validation of the `ami_regions` configuration option. Default `false`. - `snapshot_tags` (object of key/value strings) - Tags to apply to snapshot. - They will override AMI tags if already applied to snapshot. + They will override AMI tags if already applied to snapshot. This is a + [configuration template](/docs/templates/configuration-templates.html) + where the `SourceAMI` variable is replaced with the source AMI ID and + `BuildRegion` variable is replaced with name of the region where this + is built. - `snapshot_groups` (array of strings) - A list of groups that have access to create volumes from the snapshot(s). By default no groups have permission to create @@ -250,7 +258,12 @@ 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. -- `tags` (object of key/value strings) - Tags applied to the AMI. +- `tags` (object of key/value strings) - Tags applied to the AMI. This is a + [configuration template](/docs/templates/configuration-templates.html) + where the `SourceAMI` variable is replaced with the source AMI ID and + `BuildRegion` variable is replaced with name of the region where this + is built. + ## Basic Example diff --git a/website/source/docs/builders/amazon-ebs.html.md b/website/source/docs/builders/amazon-ebs.html.md index 51dc0ca67..a055f6878 100644 --- a/website/source/docs/builders/amazon-ebs.html.md +++ b/website/source/docs/builders/amazon-ebs.html.md @@ -105,7 +105,10 @@ builder. volumes - `ami_description` (string) - The description to set for the - resulting AMI(s). By default this description is empty. + resulting AMI(s). By default this description is empty. This is a + [configuration template](/docs/templates/configuration-templates.html) + where the `SourceAMI` variable is replaced with the source AMI ID and + `BuildRegion` variable is replaced with the value of `region`. - `ami_groups` (array of strings) - A list of groups that have access to launch the resulting AMI(s). By default no groups have permission to launch @@ -182,11 +185,17 @@ builder. - `run_tags` (object of key/value strings) - Tags to apply to the instance that is *launched* to create the AMI. These tags are *not* applied to the - resulting AMI unless they're duplicated in `tags`. + resulting AMI unless they're duplicated in `tags`. This is a + [configuration template](/docs/templates/configuration-templates.html) + where the `SourceAMI` variable is replaced with the source AMI ID and + `BuildRegion` variable is replaced with the value of `region`. - `run_volume_tags` (object of key/value strings) - Tags to apply to the volumes that are *launched* to create the AMI. These tags are *not* applied to the - resulting AMI unless they're duplicated in `tags`. + resulting AMI unless they're duplicated in `tags`. This is a + [configuration template](/docs/templates/configuration-templates.html) + where the `SourceAMI` variable is replaced with the source AMI ID and + `BuildRegion` variable is replaced with the value of `region`. - `security_group_id` (string) - The ID (*not* the name) of the security group to assign to the instance. By default this is not set and Packer will @@ -214,7 +223,10 @@ builder. user creating the AMI has permissions to create volumes from the backing snapshot(s). - `snapshot_tags` (object of key/value strings) - Tags to apply to snapshot. - They will override AMI tags if already applied to snapshot. + They will override AMI tags if already applied to snapshot. This is a + [configuration template](/docs/templates/configuration-templates.html) + where the `SourceAMI` variable is replaced with the source AMI ID and + `BuildRegion` variable is replaced with the value of `region`. - `source_ami_filter` (object) - Filters used to populate the `source_ami` field. Example: @@ -283,7 +295,10 @@ builder. required if you are using an non-default VPC. - `tags` (object of key/value strings) - Tags applied to the AMI and - relevant snapshots. + relevant snapshots. This is a + [configuration template](/docs/templates/configuration-templates.html) + where the `SourceAMI` variable is replaced with the source AMI ID and + `BuildRegion` variable is replaced with the value of `region`. - `temporary_key_pair_name` (string) - The name of the temporary keypair to generate. By default, Packer generates a name with a UUID. diff --git a/website/source/docs/builders/amazon-ebsvolume.html.md b/website/source/docs/builders/amazon-ebsvolume.html.md index 8cd97c09c..436d38e38 100644 --- a/website/source/docs/builders/amazon-ebsvolume.html.md +++ b/website/source/docs/builders/amazon-ebsvolume.html.md @@ -79,7 +79,10 @@ builder. volumes, `io1` for Provisioned IOPS (SSD) volumes, and `standard` for Magnetic volumes - `tags` (map) - Tags to apply to the volume. These are retained after the - builder completes. + builder completes. This is a [configuration template] + (/docs/templates/configuration-templates.html) where the `SourceAMI` + variable is replaced with the source AMI ID and `BuildRegion` variable + is replaced with the value of `region`. - `associate_public_ip_address` (boolean) - If using a non-default VPC, public IP addresses are not provided by default. If this is toggled, your new @@ -102,7 +105,10 @@ builder. - `run_tags` (object of key/value strings) - Tags to apply to the instance that is *launched* to create the AMI. These tags are *not* applied to the - resulting AMI unless they're duplicated in `tags`. + resulting AMI unless they're duplicated in `tags`. This is a + [configuration template](/docs/templates/configuration-templates.html) + where the `SourceAMI` variable is replaced with the source AMI ID and + `BuildRegion` variable is replaced with the value of `region`. - `security_group_id` (string) - The ID (*not* the name) of the security group to assign to the instance. By default this is not set and Packer will diff --git a/website/source/docs/builders/amazon-instance.html.md b/website/source/docs/builders/amazon-instance.html.md index 5ce36610e..28c2e36fc 100644 --- a/website/source/docs/builders/amazon-instance.html.md +++ b/website/source/docs/builders/amazon-instance.html.md @@ -127,7 +127,10 @@ builder. volumes - `ami_description` (string) - The description to set for the - resulting AMI(s). By default this description is empty. + resulting AMI(s). By default this description is empty. This is a + [configuration template](/docs/templates/configuration-templates.html) + where the `SourceAMI` variable is replaced with the source AMI ID and + `BuildRegion` variable is replaced with the value of `region`. - `ami_groups` (array of strings) - A list of groups that have access to launch the resulting AMI(s). By default no groups have permission to launch @@ -198,7 +201,10 @@ builder. - `run_tags` (object of key/value strings) - Tags to apply to the instance that is *launched* to create the AMI. These tags are *not* applied to the - resulting AMI unless they're duplicated in `tags`. + resulting AMI unless they're duplicated in `tags`. This is a + [configuration template](/docs/templates/configuration-templates.html) + where the `SourceAMI` variable is replaced with the source AMI ID and + `BuildRegion` variable is replaced with the value of `region`. - `security_group_id` (string) - The ID (*not* the name) of the security group to assign to the instance. By default this is not set and Packer will @@ -290,7 +296,10 @@ builder. `subnet-12345def`, where Packer will launch the EC2 instance. This field is required if you are using an non-default VPC. -- `tags` (object of key/value strings) - Tags applied to the AMI. +- `tags` (object of key/value strings) - Tags applied to the AMI. This is a + [configuration template](/docs/templates/configuration-templates.html) + where the `SourceAMI` variable is replaced with the source AMI ID and + `BuildRegion` variable is replaced with the value of `region`. - `temporary_key_pair_name` (string) - The name of the temporary key pair to generate. By default, Packer generates a name with an UUID. From 6e891cf682b40c641a7d454addb91276877c365a Mon Sep 17 00:00:00 2001 From: Rickard von Essen Date: Sun, 22 Jan 2017 21:57:23 +0100 Subject: [PATCH 3/4] Fixed botched merge and review comments --- builder/amazon/common/step_create_tags.go | 33 +++++-------------- .../amazon/common/step_run_source_instance.go | 17 +--------- builder/amazon/ebs/step_tag_ebs_volumes.go | 18 +--------- .../amazon/ebsvolume/step_tag_ebs_volumes.go | 25 ++++---------- 4 files changed, 17 insertions(+), 76 deletions(-) diff --git a/builder/amazon/common/step_create_tags.go b/builder/amazon/common/step_create_tags.go index c4203e9f2..195c577f9 100644 --- a/builder/amazon/common/step_create_tags.go +++ b/builder/amazon/common/step_create_tags.go @@ -2,6 +2,7 @@ package common import ( "fmt" + "log" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" @@ -39,22 +40,6 @@ 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, @@ -103,7 +88,7 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction { // Convert tags to ec2.Tag format ui.Say("Creating AMI tags") - amiTags, err = ConvertToEC2Tags(s.Tags, *ec2conn.Config.Region, sourceAMI, s.Ctx, ui) + amiTags, err := ConvertToEC2Tags(s.Tags, *ec2conn.Config.Region, sourceAMI, s.Ctx) if err != nil { state.Put("error", err) ui.Error(err.Error()) @@ -111,7 +96,7 @@ func (s *StepCreateTags) Run(state multistep.StateBag) multistep.StepAction { } ui.Say("Creating snapshot tags") - snapshotTags, err = ConvertToEC2Tags(s.SnapshotTags, *ec2conn.Config.Region, sourceAMI, s.Ctx, ui) + snapshotTags, err := ConvertToEC2Tags(s.SnapshotTags, *ec2conn.Config.Region, sourceAMI, s.Ctx) if err != nil { state.Put("error", err) ui.Error(err.Error()) @@ -165,8 +150,8 @@ func (s *StepCreateTags) Cleanup(state multistep.StateBag) { // No cleanup... } -func ConvertToEC2Tags(tags map[string]string, region, sourceAmiId string, ctx interpolate.Context, ui packer.Ui) ([]*ec2.Tag, error) { - var amiTags []*ec2.Tag +func ConvertToEC2Tags(tags map[string]string, region, sourceAmiId string, ctx interpolate.Context) ([]*ec2.Tag, error) { + var ec2Tags []*ec2.Tag for key, value := range tags { ctx.Data = &BuildInfoTemplate{ @@ -175,15 +160,15 @@ func ConvertToEC2Tags(tags map[string]string, region, sourceAmiId string, ctx in } interpolatedValue, err := interpolate.Render(value, &ctx) if err != nil { - return amiTags, fmt.Errorf("Error processing tag: %s:%s - %s", key, value, err) + return ec2Tags, 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{ + log.Printf("Adding tag: \"%s\": \"%s\"", key, interpolatedValue) + ec2Tags = append(ec2Tags, &ec2.Tag{ Key: aws.String(key), Value: aws.String(interpolatedValue), }) } - return amiTags, nil + return ec2Tags, nil } diff --git a/builder/amazon/common/step_run_source_instance.go b/builder/amazon/common/step_run_source_instance.go index 68b0c2951..e9b1f5216 100644 --- a/builder/amazon/common/step_run_source_instance.go +++ b/builder/amazon/common/step_run_source_instance.go @@ -278,22 +278,7 @@ func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepActi s.Tags["Name"] = "Packer Builder" } - 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) + ec2Tags, err := ConvertToEC2Tags(s.Tags, *ec2conn.Config.Region, s.SourceAMI, s.Ctx) if err != nil { err := fmt.Errorf("Error tagging source instance: %s", err) state.Put("error", err) diff --git a/builder/amazon/ebs/step_tag_ebs_volumes.go b/builder/amazon/ebs/step_tag_ebs_volumes.go index 0ecee7264..ffadb16ae 100644 --- a/builder/amazon/ebs/step_tag_ebs_volumes.go +++ b/builder/amazon/ebs/step_tag_ebs_volumes.go @@ -36,24 +36,8 @@ func (s *stepTagEBSVolumes) Run(state multistep.StateBag) multistep.StepAction { return multistep.ActionContinue } - 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}) - } - ui.Say("Adding tags to source EBS Volumes") - tags, err := common.ConvertToEC2Tags(s.VolumeRunTags, *ec2conn.Config.Region, *sourceAMI.ImageId, s.Ctx, ui) + tags, err := common.ConvertToEC2Tags(s.VolumeRunTags, *ec2conn.Config.Region, *sourceAMI.ImageId, s.Ctx) if err != nil { err := fmt.Errorf("Error tagging source EBS Volumes on %s: %s", *instance.InstanceId, err) state.Put("error", err) diff --git a/builder/amazon/ebsvolume/step_tag_ebs_volumes.go b/builder/amazon/ebsvolume/step_tag_ebs_volumes.go index 3528c92d1..ba6c9ccfa 100644 --- a/builder/amazon/ebsvolume/step_tag_ebs_volumes.go +++ b/builder/amazon/ebsvolume/step_tag_ebs_volumes.go @@ -3,7 +3,6 @@ package ebsvolume import ( "fmt" - "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" @@ -44,24 +43,12 @@ func (s *stepTagEBSVolumes) Run(state multistep.StateBag) multistep.StepAction { continue } - 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", interpolatedValue)), - }) + tags, err := awscommon.ConvertToEC2Tags(mapping.Tags, *ec2conn.Config.Region, *sourceAMI.ImageId, s.Ctx) + if err != nil { + err := fmt.Errorf("Error tagging device %s with %s", mapping.DeviceName, err) + state.Put("error", err) + ui.Error(err.Error()) + return multistep.ActionHalt } for _, v := range instance.BlockDeviceMappings { From de7388fa0a283b636abf60df97dd2bb7aa6f8e0c Mon Sep 17 00:00:00 2001 From: Rickard von Essen Date: Wed, 25 Jan 2017 19:40:43 +0100 Subject: [PATCH 4/4] builder/amazon-ebsvolume: Fixed interpolation of tags --- builder/amazon/ebsvolume/builder.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/builder/amazon/ebsvolume/builder.go b/builder/amazon/ebsvolume/builder.go index c61bfdc7d..397f160f7 100644 --- a/builder/amazon/ebsvolume/builder.go +++ b/builder/amazon/ebsvolume/builder.go @@ -44,7 +44,7 @@ func (b *Builder) Prepare(raws ...interface{}) ([]string, error) { InterpolateFilter: &interpolate.RenderFilter{ Exclude: []string{ "run_tags", - "tags", + "ebs_volumes", }, }, }, raws...)