github.com/askholme/packer@v0.7.2-0.20140924152349-70d9566a6852/builder/amazon/ebs/step_create_ami.go (about)

     1  package ebs
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/mitchellh/goamz/ec2"
     6  	"github.com/mitchellh/multistep"
     7  	awscommon "github.com/mitchellh/packer/builder/amazon/common"
     8  	"github.com/mitchellh/packer/packer"
     9  )
    10  
    11  type stepCreateAMI struct {
    12  	image *ec2.Image
    13  }
    14  
    15  func (s *stepCreateAMI) Run(state multistep.StateBag) multistep.StepAction {
    16  	config := state.Get("config").(config)
    17  	ec2conn := state.Get("ec2").(*ec2.EC2)
    18  	instance := state.Get("instance").(*ec2.Instance)
    19  	ui := state.Get("ui").(packer.Ui)
    20  
    21  	// Create the image
    22  	ui.Say(fmt.Sprintf("Creating the AMI: %s", config.AMIName))
    23  	createOpts := &ec2.CreateImage{
    24  		InstanceId:   instance.InstanceId,
    25  		Name:         config.AMIName,
    26  		BlockDevices: config.BlockDevices.BuildAMIDevices(),
    27  	}
    28  
    29  	createResp, err := ec2conn.CreateImage(createOpts)
    30  	if err != nil {
    31  		err := fmt.Errorf("Error creating AMI: %s", err)
    32  		state.Put("error", err)
    33  		ui.Error(err.Error())
    34  		return multistep.ActionHalt
    35  	}
    36  
    37  	// Set the AMI ID in the state
    38  	ui.Message(fmt.Sprintf("AMI: %s", createResp.ImageId))
    39  	amis := make(map[string]string)
    40  	amis[ec2conn.Region.Name] = createResp.ImageId
    41  	state.Put("amis", amis)
    42  
    43  	// Wait for the image to become ready
    44  	stateChange := awscommon.StateChangeConf{
    45  		Pending:   []string{"pending"},
    46  		Target:    "available",
    47  		Refresh:   awscommon.AMIStateRefreshFunc(ec2conn, createResp.ImageId),
    48  		StepState: state,
    49  	}
    50  
    51  	ui.Say("Waiting for AMI to become ready...")
    52  	if _, err := awscommon.WaitForState(&stateChange); err != nil {
    53  		err := fmt.Errorf("Error waiting for AMI: %s", err)
    54  		state.Put("error", err)
    55  		ui.Error(err.Error())
    56  		return multistep.ActionHalt
    57  	}
    58  
    59  	imagesResp, err := ec2conn.Images([]string{createResp.ImageId}, nil)
    60  	if err != nil {
    61  		err := fmt.Errorf("Error searching for AMI: %s", err)
    62  		state.Put("error", err)
    63  		ui.Error(err.Error())
    64  		return multistep.ActionHalt
    65  	}
    66  	s.image = &imagesResp.Images[0]
    67  
    68  	return multistep.ActionContinue
    69  }
    70  
    71  func (s *stepCreateAMI) Cleanup(state multistep.StateBag) {
    72  	if s.image == nil {
    73  		return
    74  	}
    75  
    76  	_, cancelled := state.GetOk(multistep.StateCancelled)
    77  	_, halted := state.GetOk(multistep.StateHalted)
    78  	if !cancelled && !halted {
    79  		return
    80  	}
    81  
    82  	ec2conn := state.Get("ec2").(*ec2.EC2)
    83  	ui := state.Get("ui").(packer.Ui)
    84  
    85  	ui.Say("Deregistering the AMI because cancelation or error...")
    86  	if resp, err := ec2conn.DeregisterImage(s.image.Id); err != nil {
    87  		ui.Error(fmt.Sprintf("Error deregistering AMI, may still be around: %s", err))
    88  		return
    89  	} else if resp.Return == false {
    90  		ui.Error(fmt.Sprintf("Error deregistering AMI, may still be around: %s", resp.Return))
    91  		return
    92  	}
    93  }