diff --git a/builder/amazon/common/ami_config.go b/builder/amazon/common/ami_config.go index c261cca77..524f01eb2 100644 --- a/builder/amazon/common/ami_config.go +++ b/builder/amazon/common/ami_config.go @@ -12,6 +12,7 @@ type AMIConfig struct { AMIUsers []string `mapstructure:"ami_users"` AMIGroups []string `mapstructure:"ami_groups"` AMIProductCodes []string `mapstructure:"ami_product_codes"` + AMIRegions []string `mapstructure:"ami_regions"` } func (c *AMIConfig) Prepare(t *packer.ConfigTemplate) []error { @@ -42,6 +43,7 @@ func (c *AMIConfig) Prepare(t *packer.ConfigTemplate) []error { "ami_users": c.AMIUsers, "ami_groups": c.AMIGroups, "ami_product_codes": c.AMIProductCodes, + "ami_regions": c.AMIRegions, } for n, slice := range sliceTemplates { diff --git a/builder/amazon/common/step_ami_region_copy.go b/builder/amazon/common/step_ami_region_copy.go new file mode 100644 index 000000000..652982135 --- /dev/null +++ b/builder/amazon/common/step_ami_region_copy.go @@ -0,0 +1,79 @@ +package common + +import ( + "fmt" + "github.com/mitchellh/goamz/aws" + "github.com/mitchellh/goamz/ec2" + "github.com/mitchellh/multistep" + "github.com/mitchellh/packer/packer" +) + +type StepAMIRegionCopyAttributes struct { + Regions []string + Tags map[string]string +} + +func (s *StepAMIRegionCopyAttributes) Run(state map[string]interface{}) multistep.StepAction { + ec2conn := state["ec2"].(*ec2.EC2) + ui := state["ui"].(packer.Ui) + amis := state["amis"].(map[string]string) + ami := amis[ec2conn.Region.Name] + + if len(s.Regions) == 0 { + return multistep.ActionContinue + } + + for _, region := range s.Regions { + ui.Say(fmt.Sprintf("Copying AMI (%s) to region (%s)...", ami, region)) + + // Connect to the region where the AMI will be copied to + regionconn := ec2.New(ec2conn.Auth, aws.Regions[region]) + resp, err := regionconn.CopyImage(&ec2.CopyImage{ + SourceRegion: ec2conn.Region.Name, + SourceImageId: ami, + }) + + if err != nil { + err := fmt.Errorf("Error Copying AMI (%s) to region (%s): %s", ami, region, err) + state["error"] = err + ui.Error(err.Error()) + return multistep.ActionHalt + } + + ui.Say(fmt.Sprintf("Waiting for AMI (%s) in region (%s) to become ready...", resp.ImageId, region)) + if err := WaitForAMI(regionconn, resp.ImageId); err != nil { + err := fmt.Errorf("Error waiting for AMI (%s) in region (%s): %s", resp.ImageId, region, err) + state["error"] = err + ui.Error(err.Error()) + return multistep.ActionHalt + } + + // Need to re-apply Tags since they are not copied with the AMI + if len(s.Tags) > 0 { + ui.Say(fmt.Sprintf("Adding tags to AMI (%s)...", resp.ImageId)) + + 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, value}) + } + + _, err := regionconn.CreateTags([]string{resp.ImageId}, ec2Tags) + if err != nil { + err := fmt.Errorf("Error adding tags to AMI (%s): %s", resp.ImageId, err) + state["error"] = err + ui.Error(err.Error()) + return multistep.ActionHalt + } + } + + amis[region] = resp.ImageId + } + + state["amis"] = amis + return multistep.ActionContinue +} + +func (s *StepAMIRegionCopyAttributes) Cleanup(state map[string]interface{}) { + // No cleanup... +} diff --git a/builder/amazon/ebs/builder.go b/builder/amazon/ebs/builder.go index d358005b2..37ac4c13f 100644 --- a/builder/amazon/ebs/builder.go +++ b/builder/amazon/ebs/builder.go @@ -136,6 +136,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe Users: b.config.AMIUsers, Groups: b.config.AMIGroups, }, + &awscommon.StepAMIRegionCopyAttributes{ + Regions: b.config.AMIRegions, + Tags: b.config.Tags, + }, } // Run! diff --git a/builder/amazon/instance/builder.go b/builder/amazon/instance/builder.go index ad88e6d97..8d36d2eeb 100644 --- a/builder/amazon/instance/builder.go +++ b/builder/amazon/instance/builder.go @@ -218,6 +218,10 @@ func (b *Builder) Run(ui packer.Ui, hook packer.Hook, cache packer.Cache) (packe Groups: b.config.AMIGroups, ProductCodes: b.config.AMIProductCodes, }, + &awscommon.StepAMIRegionCopyAttributes{ + Regions: b.config.AMIRegions, + Tags: b.config.Tags, + }, } // Run!