func (s *StepRegisterAMI) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) ec2conn := state.Get("ec2").(*ec2.EC2) image := state.Get("source_image").(*ec2.Image) snapshotId := state.Get("snapshot_id").(string) ui := state.Get("ui").(packer.Ui) ui.Say("Registering the AMI...") blockDevices := make([]*ec2.BlockDeviceMapping, len(image.BlockDeviceMappings)) for i, device := range image.BlockDeviceMappings { newDevice := device if newDevice.DeviceName == image.RootDeviceName { if newDevice.EBS != nil { newDevice.EBS.SnapshotID = &snapshotId } else { newDevice.EBS = &ec2.EBSBlockDevice{SnapshotID: &snapshotId} } } blockDevices[i] = newDevice } registerOpts := buildRegisterOpts(config, image, blockDevices) // Set SriovNetSupport to "simple". See http://goo.gl/icuXh5 if config.AMIEnhancedNetworking { registerOpts.SRIOVNetSupport = aws.String("simple") } registerResp, err := ec2conn.RegisterImage(registerOpts) if err != nil { state.Put("error", fmt.Errorf("Error registering AMI: %s", err)) ui.Error(state.Get("error").(error).Error()) return multistep.ActionHalt } // Set the AMI ID in the state ui.Say(fmt.Sprintf("AMI: %s", *registerResp.ImageID)) amis := make(map[string]string) amis[ec2conn.Config.Region] = *registerResp.ImageID state.Put("amis", amis) // Wait for the image to become ready stateChange := awscommon.StateChangeConf{ Pending: []string{"pending"}, Target: "available", Refresh: awscommon.AMIStateRefreshFunc(ec2conn, *registerResp.ImageID), StepState: state, } ui.Say("Waiting for AMI to become ready...") if _, err := awscommon.WaitForState(&stateChange); err != nil { err := fmt.Errorf("Error waiting for AMI: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } return multistep.ActionContinue }
func (s *StepRegisterAMI) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) ec2conn := state.Get("ec2").(ec2.EC2) image := state.Get("source_image").(*ec2.Image) snapshotId := state.Get("snapshot_id").(string) ui := state.Get("ui").(packer.Ui) ui.Say("Registering the AMI...") blockDevices := make([]ec2.BlockDeviceMapping, len(image.BlockDevices)) for i, device := range image.BlockDevices { newDevice := device if newDevice.DeviceName == image.RootDeviceName { newDevice.SnapshotId = snapshotId } blockDevices[i] = newDevice } registerOpts := &ec2.RegisterImage{ Name: config.AMIName, Architecture: image.Architecture, KernelId: image.KernelId, RamdiskId: image.RamdiskId, RootDeviceName: image.RootDeviceName, BlockDevices: blockDevices, } registerResp, err := ec2conn.RegisterImage(registerOpts) if err != nil { state.Put("error", fmt.Errorf("Error registering AMI: %s", err)) ui.Error(state.Get("error").(error).Error()) return multistep.ActionHalt } // Set the AMI ID in the state ui.Say(fmt.Sprintf("AMI: %s", registerResp.ImageId)) amis := make(map[string]string) amis[ec2conn.Region.Name] = registerResp.ImageId state.Put("amis", amis) // Wait for the image to become ready stateChange := awscommon.StateChangeConf{ Conn: ec2conn, Pending: []string{"pending"}, Target: "available", Refresh: awscommon.AMIStateRefreshFunc(ec2conn, registerResp.ImageId), StepState: state, } ui.Say("Waiting for AMI to become ready...") if _, err := awscommon.WaitForState(&stateChange); err != nil { err := fmt.Errorf("Error waiting for AMI: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } return multistep.ActionContinue }
func (s *stepCreateAMI) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(Config) ec2conn := state.Get("ec2").(*ec2.EC2) instance := state.Get("instance").(*ec2.Instance) ui := state.Get("ui").(packer.Ui) // Create the image ui.Say(fmt.Sprintf("Creating the AMI: %s", config.AMIName)) createOpts := &ec2.CreateImageInput{ InstanceID: instance.InstanceID, Name: &config.AMIName, BlockDeviceMappings: config.BlockDevices.BuildAMIDevices(), } createResp, err := ec2conn.CreateImage(createOpts) if err != nil { err := fmt.Errorf("Error creating AMI: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // Set the AMI ID in the state ui.Message(fmt.Sprintf("AMI: %s", *createResp.ImageID)) amis := make(map[string]string) amis[*ec2conn.Config.Region] = *createResp.ImageID state.Put("amis", amis) // Wait for the image to become ready stateChange := awscommon.StateChangeConf{ Pending: []string{"pending"}, Target: "available", Refresh: awscommon.AMIStateRefreshFunc(ec2conn, *createResp.ImageID), StepState: state, } ui.Say("Waiting for AMI to become ready...") if _, err := awscommon.WaitForState(&stateChange); err != nil { err := fmt.Errorf("Error waiting for AMI: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } imagesResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{ImageIDs: []*string{createResp.ImageID}}) if err != nil { err := fmt.Errorf("Error searching for AMI: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } s.image = imagesResp.Images[0] return multistep.ActionContinue }
func (s *StepRegisterAMI) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) ec2conn := state.Get("ec2").(*ec2.EC2) manifestPath := state.Get("remote_manifest_path").(string) ui := state.Get("ui").(packer.Ui) ui.Say("Registering the AMI...") registerOpts := &ec2.RegisterImageInput{ ImageLocation: &manifestPath, Name: aws.String(config.AMIName), BlockDeviceMappings: config.BlockDevices.BuildAMIDevices(), } if config.AMIVirtType != "" { registerOpts.VirtualizationType = aws.String(config.AMIVirtType) } // Set SriovNetSupport to "simple". See http://goo.gl/icuXh5 if config.AMIEnhancedNetworking { registerOpts.SriovNetSupport = aws.String("simple") } registerResp, err := ec2conn.RegisterImage(registerOpts) if err != nil { state.Put("error", fmt.Errorf("Error registering AMI: %s", err)) ui.Error(state.Get("error").(error).Error()) return multistep.ActionHalt } // Set the AMI ID in the state ui.Say(fmt.Sprintf("AMI: %s", *registerResp.ImageId)) amis := make(map[string]string) amis[*ec2conn.Config.Region] = *registerResp.ImageId state.Put("amis", amis) // Wait for the image to become ready stateChange := awscommon.StateChangeConf{ Pending: []string{"pending"}, Target: "available", Refresh: awscommon.AMIStateRefreshFunc(ec2conn, *registerResp.ImageId), StepState: state, } ui.Say("Waiting for AMI to become ready...") if _, err := awscommon.WaitForState(&stateChange); err != nil { err := fmt.Errorf("Error waiting for AMI: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } return multistep.ActionContinue }
func (s *stepCreateAMI) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(config) ec2conn := state.Get("ec2").(*ec2.EC2) instance := state.Get("instance").(*ec2.Instance) ui := state.Get("ui").(packer.Ui) // Create the image ui.Say(fmt.Sprintf("Creating the AMI: %s", config.AMIName)) createOpts := &ec2.CreateImage{ InstanceId: instance.InstanceId, Name: config.AMIName, BlockDevices: config.BlockDevices.BuildAMIDevices(), } createResp, err := ec2conn.CreateImage(createOpts) if err != nil { err := fmt.Errorf("Error creating AMI: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // Set the AMI ID in the state ui.Say(fmt.Sprintf("AMI: %s", createResp.ImageId)) amis := make(map[string]string) amis[ec2conn.Region.Name] = createResp.ImageId state.Put("amis", amis) // Wait for the image to become ready stateChange := awscommon.StateChangeConf{ Conn: ec2conn, Pending: []string{"pending"}, Target: "available", Refresh: awscommon.AMIStateRefreshFunc(ec2conn, createResp.ImageId), StepState: state, } ui.Say("Waiting for AMI to become ready...") if _, err := awscommon.WaitForState(&stateChange); err != nil { err := fmt.Errorf("Error waiting for AMI: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } return multistep.ActionContinue }
func (s *StepRegisterAMI) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) ec2conn := state.Get("ec2").(*ec2.EC2) manifestPath := state.Get("remote_manifest_path").(string) ui := state.Get("ui").(packer.Ui) ui.Say("Registering the AMI...") registerOpts := &ec2.RegisterImage{ ImageLocation: manifestPath, Name: config.AMIName, BlockDevices: config.BlockDevices.BuildAMIDevices(), } registerResp, err := ec2conn.RegisterImage(registerOpts) if err != nil { state.Put("error", fmt.Errorf("Error registering AMI: %s", err)) ui.Error(state.Get("error").(error).Error()) return multistep.ActionHalt } // Set the AMI ID in the state ui.Say(fmt.Sprintf("AMI: %s", registerResp.ImageId)) amis := make(map[string]string) amis[ec2conn.Region.Name] = registerResp.ImageId state.Put("amis", amis) // Wait for the image to become ready stateChange := awscommon.StateChangeConf{ Conn: ec2conn, Pending: []string{"pending"}, Target: "available", Refresh: awscommon.AMIStateRefreshFunc(ec2conn, registerResp.ImageId), StepState: state, } ui.Say("Waiting for AMI to become ready...") if _, err := awscommon.WaitForState(&stateChange); err != nil { err := fmt.Errorf("Error waiting for AMI: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } return multistep.ActionContinue }
func (s *StepRegisterAMI) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) ec2conn := state.Get("ec2").(*ec2.EC2) image := state.Get("source_image").(*ec2.Image) snapshotId := state.Get("snapshot_id").(string) ui := state.Get("ui").(packer.Ui) ui.Say("Registering the AMI...") blockDevices := make([]*ec2.BlockDeviceMapping, len(image.BlockDeviceMappings)) for i, device := range image.BlockDeviceMappings { newDevice := device if *newDevice.DeviceName == *image.RootDeviceName { if newDevice.Ebs != nil { newDevice.Ebs.SnapshotId = aws.String(snapshotId) } else { newDevice.Ebs = &ec2.EbsBlockDevice{SnapshotId: aws.String(snapshotId)} } if s.RootVolumeSize > *newDevice.Ebs.VolumeSize { newDevice.Ebs.VolumeSize = aws.Int64(s.RootVolumeSize) } } // assume working from a snapshot, so we unset the Encrypted field if set, // otherwise AWS API will return InvalidParameter if newDevice.Ebs != nil && newDevice.Ebs.Encrypted != nil { newDevice.Ebs.Encrypted = nil } blockDevices[i] = newDevice } registerOpts := buildRegisterOpts(config, image, blockDevices) // Set SriovNetSupport to "simple". See http://goo.gl/icuXh5 if config.AMIEnhancedNetworking { registerOpts.SriovNetSupport = aws.String("simple") } registerResp, err := ec2conn.RegisterImage(registerOpts) if err != nil { state.Put("error", fmt.Errorf("Error registering AMI: %s", err)) ui.Error(state.Get("error").(error).Error()) return multistep.ActionHalt } // Set the AMI ID in the state ui.Say(fmt.Sprintf("AMI: %s", *registerResp.ImageId)) amis := make(map[string]string) amis[*ec2conn.Config.Region] = *registerResp.ImageId state.Put("amis", amis) // Wait for the image to become ready stateChange := awscommon.StateChangeConf{ Pending: []string{"pending"}, Target: "available", Refresh: awscommon.AMIStateRefreshFunc(ec2conn, *registerResp.ImageId), StepState: state, } ui.Say("Waiting for AMI to become ready...") if _, err := awscommon.WaitForState(&stateChange); err != nil { err := fmt.Errorf("Error waiting for AMI: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } return multistep.ActionContinue }
func (s *stepCreateEncryptedAMICopy) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(Config) ec2conn := state.Get("ec2").(*ec2.EC2) ui := state.Get("ui").(packer.Ui) // Encrypt boot not set, so skip step if !config.AMIConfig.AMIEncryptBootVolume { return multistep.ActionContinue } ui.Say("Creating Encrypted AMI Copy") amis := state.Get("amis").(map[string]string) var region, id string if amis != nil { for region, id = range amis { break // Only get the first } } ui.Say(fmt.Sprintf("Copying AMI: %s(%s)", region, id)) copyOpts := &ec2.CopyImageInput{ Name: &config.AMIName, // Try to overwrite existing AMI SourceImageId: aws.String(id), SourceRegion: aws.String(region), Encrypted: aws.Bool(true), } copyResp, err := ec2conn.CopyImage(copyOpts) if err != nil { err := fmt.Errorf("Error copying AMI: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // Wait for the copy to become ready stateChange := awscommon.StateChangeConf{ Pending: []string{"pending"}, Target: "available", Refresh: awscommon.AMIStateRefreshFunc(ec2conn, *copyResp.ImageId), StepState: state, } ui.Say("Waiting for AMI copy to become ready...") if _, err := awscommon.WaitForState(&stateChange); err != nil { err := fmt.Errorf("Error waiting for AMI Copy: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // Get the unencrypted AMI image unencImagesResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{ImageIds: []*string{aws.String(id)}}) if err != nil { err := fmt.Errorf("Error searching for AMI: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } unencImage := unencImagesResp.Images[0] // Remove unencrypted AMI ui.Say("Deregistering unecrypted AMI") deregisterOpts := &ec2.DeregisterImageInput{ImageId: aws.String(id)} if _, err := ec2conn.DeregisterImage(deregisterOpts); err != nil { ui.Error(fmt.Sprintf("Error deregistering AMI, may still be around: %s", err)) return multistep.ActionHalt } // Remove associated unencrypted snapshot(s) ui.Say("Deleting unencrypted snapshots") for _, blockDevice := range unencImage.BlockDeviceMappings { if blockDevice.Ebs != nil { if blockDevice.Ebs.SnapshotId != nil { ui.Message(fmt.Sprintf("Snapshot ID: %s", *blockDevice.Ebs.SnapshotId)) deleteSnapOpts := &ec2.DeleteSnapshotInput{ SnapshotId: aws.String(*blockDevice.Ebs.SnapshotId), } if _, err := ec2conn.DeleteSnapshot(deleteSnapOpts); err != nil { ui.Error(fmt.Sprintf("Error deleting snapshot, may still be around: %s", err)) return multistep.ActionHalt } } } } // Replace original AMI ID with Encrypted ID in state amis[region] = *copyResp.ImageId state.Put("amis", amis) imagesResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{ImageIds: []*string{copyResp.ImageId}}) if err != nil { err := fmt.Errorf("Error searching for AMI: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } s.image = imagesResp.Images[0] return multistep.ActionContinue }
func (p *PostProcessor) PostProcess(ui packer.Ui, artifact packer.Artifact) (packer.Artifact, bool, error) { var err error config, err := p.config.Config() if err != nil { return nil, false, err } // Render this key since we didn't in the configure phase p.config.S3Key, err = interpolate.Render(p.config.S3Key, &p.config.ctx) if err != nil { return nil, false, fmt.Errorf("Error rendering s3_key_name template: %s", err) } log.Printf("Rendered s3_key_name as %s", p.config.S3Key) log.Println("Looking for OVA in artifact") // Locate the files output from the builder source := "" for _, path := range artifact.Files() { if strings.HasSuffix(path, ".ova") { source = path break } } // Hope we found something useful if source == "" { return nil, false, fmt.Errorf("No OVA file found in artifact from builder") } // Set up the AWS session log.Println("Creating AWS session") session, err := session.NewSession(config) if err != nil { return nil, false, err } // open the source file log.Printf("Opening file %s to upload", source) file, err := os.Open(source) if err != nil { return nil, false, fmt.Errorf("Failed to open %s: %s", source, err) } ui.Message(fmt.Sprintf("Uploading %s to s3://%s/%s", source, p.config.S3Bucket, p.config.S3Key)) // Copy the OVA file into the S3 bucket specified uploader := s3manager.NewUploader(session) _, err = uploader.Upload(&s3manager.UploadInput{ Body: file, Bucket: &p.config.S3Bucket, Key: &p.config.S3Key, }) if err != nil { return nil, false, fmt.Errorf("Failed to upload %s: %s", source, err) } // May as well stop holding this open now file.Close() ui.Message(fmt.Sprintf("Completed upload of %s to s3://%s/%s", source, p.config.S3Bucket, p.config.S3Key)) // Call EC2 image import process log.Printf("Calling EC2 to import from s3://%s/%s", p.config.S3Bucket, p.config.S3Key) ec2conn := ec2.New(session) import_start, err := ec2conn.ImportImage(&ec2.ImportImageInput{ DiskContainers: []*ec2.ImageDiskContainer{ { UserBucket: &ec2.UserBucket{ S3Bucket: &p.config.S3Bucket, S3Key: &p.config.S3Key, }, }, }, }) if err != nil { return nil, false, fmt.Errorf("Failed to start import from s3://%s/%s: %s", p.config.S3Bucket, p.config.S3Key, err) } ui.Message(fmt.Sprintf("Started import of s3://%s/%s, task id %s", p.config.S3Bucket, p.config.S3Key, *import_start.ImportTaskId)) // Wait for import process to complete, this takess a while ui.Message(fmt.Sprintf("Waiting for task %s to complete (may take a while)", *import_start.ImportTaskId)) stateChange := awscommon.StateChangeConf{ Pending: []string{"pending", "active"}, Refresh: awscommon.ImportImageRefreshFunc(ec2conn, *import_start.ImportTaskId), Target: "completed", } // Actually do the wait for state change // We ignore errors out of this and check job state in AWS API awscommon.WaitForState(&stateChange) // Retrieve what the outcome was for the import task import_result, err := ec2conn.DescribeImportImageTasks(&ec2.DescribeImportImageTasksInput{ ImportTaskIds: []*string{ import_start.ImportTaskId, }, }) if err != nil { return nil, false, fmt.Errorf("Failed to find import task %s: %s", *import_start.ImportTaskId, err) } // Check it was actually completed if *import_result.ImportImageTasks[0].Status != "completed" { // The most useful error message is from the job itself return nil, false, fmt.Errorf("Import task %s failed: %s", *import_start.ImportTaskId, *import_result.ImportImageTasks[0].StatusMessage) } ui.Message(fmt.Sprintf("Import task %s complete", *import_start.ImportTaskId)) // Pull AMI ID out of the completed job createdami := *import_result.ImportImageTasks[0].ImageId if p.config.Name != "" { ui.Message(fmt.Sprintf("Starting rename of AMI (%s)", createdami)) resp, err := ec2conn.CopyImage(&ec2.CopyImageInput{ Name: &p.config.Name, SourceImageId: &createdami, SourceRegion: config.Region, }) if err != nil { return nil, false, fmt.Errorf("Error Copying AMI (%s): %s", createdami, err) } ui.Message(fmt.Sprintf("Waiting for AMI rename to complete (may take a while)")) stateChange := awscommon.StateChangeConf{ Pending: []string{"pending"}, Target: "available", Refresh: awscommon.AMIStateRefreshFunc(ec2conn, *resp.ImageId), } if _, err := awscommon.WaitForState(&stateChange); err != nil { return nil, false, fmt.Errorf("Error waiting for AMI (%s): %s", *resp.ImageId, err) } ec2conn.DeregisterImage(&ec2.DeregisterImageInput{ ImageId: &createdami, }) if err != nil { return nil, false, fmt.Errorf("Error deregistering existing AMI: %s", err) } ui.Message(fmt.Sprintf("AMI rename completed")) createdami = *resp.ImageId } // If we have tags, then apply them now to both the AMI and snaps // created by the import if len(p.config.Tags) > 0 { var ec2Tags []*ec2.Tag log.Printf("Repacking tags into AWS format") for key, value := range p.config.Tags { ui.Message(fmt.Sprintf("Adding tag \"%s\": \"%s\"", key, value)) ec2Tags = append(ec2Tags, &ec2.Tag{ Key: aws.String(key), Value: aws.String(value), }) } resourceIds := []*string{&createdami} log.Printf("Getting details of %s", createdami) imageResp, err := ec2conn.DescribeImages(&ec2.DescribeImagesInput{ ImageIds: resourceIds, }) if err != nil { return nil, false, fmt.Errorf("Failed to retrieve details for AMI %s: %s", createdami, err) } if len(imageResp.Images) == 0 { return nil, false, fmt.Errorf("AMI %s has no images", createdami) } image := imageResp.Images[0] log.Printf("Walking block device mappings for %s to find snapshots", createdami) for _, device := range image.BlockDeviceMappings { if device.Ebs != nil && device.Ebs.SnapshotId != nil { ui.Message(fmt.Sprintf("Tagging snapshot %s", *device.Ebs.SnapshotId)) resourceIds = append(resourceIds, device.Ebs.SnapshotId) } } ui.Message(fmt.Sprintf("Tagging AMI %s", createdami)) _, err = ec2conn.CreateTags(&ec2.CreateTagsInput{ Resources: resourceIds, Tags: ec2Tags, }) if err != nil { return nil, false, fmt.Errorf("Failed to add tags to resources %#v: %s", resourceIds, err) } } // Add the reported AMI ID to the artifact list log.Printf("Adding created AMI ID %s in region %s to output artifacts", createdami, *config.Region) artifact = &awscommon.Artifact{ Amis: map[string]string{ *config.Region: createdami, }, BuilderIdValue: BuilderId, Conn: ec2conn, } if !p.config.SkipClean { ui.Message(fmt.Sprintf("Deleting import source s3://%s/%s", p.config.S3Bucket, p.config.S3Key)) s3conn := s3.New(session) _, err = s3conn.DeleteObject(&s3.DeleteObjectInput{ Bucket: &p.config.S3Bucket, Key: &p.config.S3Key, }) if err != nil { return nil, false, fmt.Errorf("Failed to delete s3://%s/%s: %s", p.config.S3Bucket, p.config.S3Key, err) } } return artifact, false, nil }
func (step *StepRegisterAMI) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) ec2conn := state.Get("ec2").(*ec2.EC2) instance := state.Get("instance").(*ec2.Instance) snapshotId := state.Get("snapshot_id").(string) ui := state.Get("ui").(packer.Ui) step.ensureRootDeviceMapping(snapshotId, config) // Create the image ui.Say(fmt.Sprintf("Registering the AMI: %s", config.AMIName)) opts := &ec2.RegisterImage{ Name: config.AMIName, Description: config.AMIDescription, Architecture: instance.Architecture, BlockDevices: config.BlockDevices.BuildAMIDevices(), RootDeviceName: step.RootDeviceName, VirtType: instance.VirtType, } if config.AMIEnhancedNetworking { opts.SriovNetSupport = "simple" } registerResp, err := ec2conn.RegisterImage(opts) if err != nil { err := fmt.Errorf("Error registering AMI: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } // Set the AMI ID in the state ui.Message(fmt.Sprintf("AMI: %s", registerResp.ImageId)) amis := make(map[string]string) amis[ec2conn.Region.Name] = registerResp.ImageId state.Put("amis", amis) // Wait for the image to become ready stateChange := awscommon.StateChangeConf{ Pending: []string{"pending"}, Target: "available", Refresh: awscommon.AMIStateRefreshFunc(ec2conn, registerResp.ImageId), StepState: state, } ui.Say("Waiting for AMI to become ready...") if _, err := awscommon.WaitForState(&stateChange); err != nil { err := fmt.Errorf("Error waiting for AMI: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } imagesResp, err := ec2conn.Images([]string{registerResp.ImageId}, nil) if err != nil { err := fmt.Errorf("Error searching for AMI: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } step.image = &imagesResp.Images[0] return multistep.ActionContinue }