github.com/jerryclinesmith/packer@v0.3.7/builder/amazon/common/step_run_source_instance.go (about)

     1  package common
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/mitchellh/goamz/ec2"
     6  	"github.com/mitchellh/multistep"
     7  	"github.com/mitchellh/packer/packer"
     8  	"io/ioutil"
     9  	"log"
    10  )
    11  
    12  type StepRunSourceInstance struct {
    13  	Debug              bool
    14  	ExpectedRootDevice string
    15  	InstanceType       string
    16  	UserData           string
    17  	UserDataFile       string
    18  	SourceAMI          string
    19  	IamInstanceProfile string
    20  	SubnetId           string
    21  	BlockDevices       BlockDevices
    22  
    23  	instance *ec2.Instance
    24  }
    25  
    26  func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepAction {
    27  	ec2conn := state.Get("ec2").(*ec2.EC2)
    28  	keyName := state.Get("keyPair").(string)
    29  	securityGroupId := state.Get("securityGroupId").(string)
    30  	ui := state.Get("ui").(packer.Ui)
    31  
    32  	userData := s.UserData
    33  	if s.UserDataFile != "" {
    34  		contents, err := ioutil.ReadFile(s.UserDataFile)
    35  		if err != nil {
    36  			state.Put("error", fmt.Errorf("Problem reading user data file: %s", err))
    37  			return multistep.ActionHalt
    38  		}
    39  
    40  		userData = string(contents)
    41  	}
    42  
    43  	runOpts := &ec2.RunInstances{
    44  		KeyName:            keyName,
    45  		ImageId:            s.SourceAMI,
    46  		InstanceType:       s.InstanceType,
    47  		UserData:           []byte(userData),
    48  		MinCount:           0,
    49  		MaxCount:           0,
    50  		SecurityGroups:     []ec2.SecurityGroup{ec2.SecurityGroup{Id: securityGroupId}},
    51  		IamInstanceProfile: s.IamInstanceProfile,
    52  		SubnetId:           s.SubnetId,
    53  		BlockDevices:       s.BlockDevices.BuildLaunchDevices(),
    54  	}
    55  
    56  	ui.Say("Launching a source AWS instance...")
    57  	imageResp, err := ec2conn.Images([]string{s.SourceAMI}, ec2.NewFilter())
    58  	if err != nil {
    59  		state.Put("error", fmt.Errorf("There was a problem with the source AMI: %s", err))
    60  		return multistep.ActionHalt
    61  	}
    62  
    63  	if len(imageResp.Images) != 1 {
    64  		state.Put("error", fmt.Errorf("The source AMI '%s' could not be found.", s.SourceAMI))
    65  		return multistep.ActionHalt
    66  	}
    67  
    68  	if s.ExpectedRootDevice != "" && imageResp.Images[0].RootDeviceType != s.ExpectedRootDevice {
    69  		state.Put("error", fmt.Errorf(
    70  			"The provided source AMI has an invalid root device type.\n"+
    71  				"Expected '%s', got '%s'.",
    72  			s.ExpectedRootDevice, imageResp.Images[0].RootDeviceType))
    73  		return multistep.ActionHalt
    74  	}
    75  
    76  	runResp, err := ec2conn.RunInstances(runOpts)
    77  	if err != nil {
    78  		err := fmt.Errorf("Error launching source instance: %s", err)
    79  		state.Put("error", err)
    80  		ui.Error(err.Error())
    81  		return multistep.ActionHalt
    82  	}
    83  
    84  	s.instance = &runResp.Instances[0]
    85  	log.Printf("instance id: %s", s.instance.InstanceId)
    86  
    87  	ui.Say(fmt.Sprintf("Waiting for instance (%s) to become ready...", s.instance.InstanceId))
    88  	stateChange := StateChangeConf{
    89  		Conn:      ec2conn,
    90  		Pending:   []string{"pending"},
    91  		Target:    "running",
    92  		Refresh:   InstanceStateRefreshFunc(ec2conn, s.instance),
    93  		StepState: state,
    94  	}
    95  	latestInstance, err := WaitForState(&stateChange)
    96  	if err != nil {
    97  		err := fmt.Errorf("Error waiting for instance (%s) to become ready: %s", s.instance.InstanceId, err)
    98  		state.Put("error", err)
    99  		ui.Error(err.Error())
   100  		return multistep.ActionHalt
   101  	}
   102  
   103  	s.instance = latestInstance.(*ec2.Instance)
   104  
   105  	if s.Debug {
   106  		if s.instance.DNSName != "" {
   107  			ui.Message(fmt.Sprintf("Public DNS: %s", s.instance.DNSName))
   108  		}
   109  
   110  		if s.instance.PrivateIpAddress != "" {
   111  			ui.Message(fmt.Sprintf("Private IP: %s", s.instance.PrivateIpAddress))
   112  		}
   113  	}
   114  
   115  	state.Put("instance", s.instance)
   116  
   117  	return multistep.ActionContinue
   118  }
   119  
   120  func (s *StepRunSourceInstance) Cleanup(state multistep.StateBag) {
   121  	if s.instance == nil {
   122  		return
   123  	}
   124  
   125  	ec2conn := state.Get("ec2").(*ec2.EC2)
   126  	ui := state.Get("ui").(packer.Ui)
   127  
   128  	ui.Say("Terminating the source AWS instance...")
   129  	if _, err := ec2conn.TerminateInstances([]string{s.instance.InstanceId}); err != nil {
   130  		ui.Error(fmt.Sprintf("Error terminating instance, may still be around: %s", err))
   131  		return
   132  	}
   133  
   134  	stateChange := StateChangeConf{
   135  		Conn:    ec2conn,
   136  		Pending: []string{"pending", "running", "shutting-down", "stopped", "stopping"},
   137  		Refresh: InstanceStateRefreshFunc(ec2conn, s.instance),
   138  		Target:  "terminated",
   139  	}
   140  
   141  	WaitForState(&stateChange)
   142  }