// waitForState will spin in a loop forever waiting for state to // reach a certain target. func waitForState(errCh chan<- error, target string, refresh stateRefreshFunc) error { err := common.Retry(2, 2, 0, func() (bool, error) { state, err := refresh() if err != nil { return false, err } else if state == target { return true, nil } return false, nil }) errCh <- err return err }
// Run reads the instance metadata and looks for the log entry // indicating the startup script finished. func (s *StepWaitInstanceStartup) Run(state multistep.StateBag) multistep.StepAction { config := state.Get("config").(*Config) driver := state.Get("driver").(Driver) ui := state.Get("ui").(packer.Ui) instanceName := state.Get("instance_name").(string) ui.Say("Waiting for any running startup script to finish...") // Keep checking the serial port output to see if the startup script is done. err := common.Retry(10, 60, 0, func() (bool, error) { status, err := driver.GetInstanceMetadata(config.Zone, instanceName, StartupScriptStatusKey) if err != nil { err := fmt.Errorf("Error getting startup script status: %s", err) return false, err } if status == StartupScriptStatusError { err = errors.New("Startup script error.") return false, err } done := status == StartupScriptStatusDone if !done { ui.Say("Startup script not finished yet. Waiting...") } return done, nil }) if err != nil { err := fmt.Errorf("Error waiting for startup script to finish: %s", err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } ui.Say("Startup script, if any, has finished running.") return multistep.ActionContinue }
func (s *StepCreateTags) 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) if len(s.Tags) > 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), }) } // Declare list of resources to tag resourceIds := []*string{&ami} awsConfig := aws.Config{ Credentials: ec2conn.Config.Credentials, Region: aws.String(region), } session := session.New(&awsConfig) regionconn := ec2.New(session) // Retrieve image list for given AMI imageResp, err := regionconn.DescribeImages(&ec2.DescribeImagesInput{ ImageIds: resourceIds, }) if err != nil { err := fmt.Errorf("Error retrieving details for AMI (%s): %s", ami, err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } if len(imageResp.Images) == 0 { err := fmt.Errorf("Error retrieving details for AMI (%s), no images found", ami) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } image := imageResp.Images[0] // 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) } } // Retry creating tags for about 2.5 minutes err = retry.Retry(0.2, 30, 11, func() (bool, error) { _, err := regionconn.CreateTags(&ec2.CreateTagsInput{ Resources: resourceIds, Tags: ec2Tags, }) if err == nil { return true, nil } if awsErr, ok := err.(awserr.Error); ok { if awsErr.Code() == "InvalidAMIID.NotFound" || awsErr.Code() == "InvalidSnapshot.NotFound" { return false, nil } } return true, err }) if err != nil { err := fmt.Errorf("Error adding tags to Resources (%#v): %s", resourceIds, err) state.Put("error", err) ui.Error(err.Error()) return multistep.ActionHalt } } } return multistep.ActionContinue }