github.com/kaixiang/packer@v0.5.2-0.20140114230416-1f5786b0d7f1/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  )
    10  
    11  type StepRunSourceInstance struct {
    12  	AssociatePublicIpAddress bool
    13  	AvailabilityZone         string
    14  	BlockDevices             BlockDevices
    15  	Debug                    bool
    16  	ExpectedRootDevice       string
    17  	InstanceType             string
    18  	IamInstanceProfile       string
    19  	SourceAMI                string
    20  	SubnetId                 string
    21  	Tags                     map[string]string
    22  	UserData                 string
    23  	UserDataFile             string
    24  
    25  	instance *ec2.Instance
    26  }
    27  
    28  func (s *StepRunSourceInstance) Run(state multistep.StateBag) multistep.StepAction {
    29  	ec2conn := state.Get("ec2").(*ec2.EC2)
    30  	keyName := state.Get("keyPair").(string)
    31  	securityGroupIds := state.Get("securityGroupIds").([]string)
    32  	ui := state.Get("ui").(packer.Ui)
    33  
    34  	userData := s.UserData
    35  	if s.UserDataFile != "" {
    36  		contents, err := ioutil.ReadFile(s.UserDataFile)
    37  		if err != nil {
    38  			state.Put("error", fmt.Errorf("Problem reading user data file: %s", err))
    39  			return multistep.ActionHalt
    40  		}
    41  
    42  		userData = string(contents)
    43  	}
    44  
    45  	securityGroups := make([]ec2.SecurityGroup, len(securityGroupIds))
    46  	for n, securityGroupId := range securityGroupIds {
    47  		securityGroups[n] = ec2.SecurityGroup{Id: securityGroupId}
    48  	}
    49  
    50  	runOpts := &ec2.RunInstances{
    51  		KeyName:                  keyName,
    52  		ImageId:                  s.SourceAMI,
    53  		InstanceType:             s.InstanceType,
    54  		UserData:                 []byte(userData),
    55  		MinCount:                 0,
    56  		MaxCount:                 0,
    57  		SecurityGroups:           securityGroups,
    58  		IamInstanceProfile:       s.IamInstanceProfile,
    59  		SubnetId:                 s.SubnetId,
    60  		AssociatePublicIpAddress: s.AssociatePublicIpAddress,
    61  		BlockDevices:             s.BlockDevices.BuildLaunchDevices(),
    62  		AvailZone:                s.AvailabilityZone,
    63  	}
    64  
    65  	ui.Say("Launching a source AWS instance...")
    66  	imageResp, err := ec2conn.Images([]string{s.SourceAMI}, ec2.NewFilter())
    67  	if err != nil {
    68  		state.Put("error", fmt.Errorf("There was a problem with the source AMI: %s", err))
    69  		return multistep.ActionHalt
    70  	}
    71  
    72  	if len(imageResp.Images) != 1 {
    73  		state.Put("error", fmt.Errorf("The source AMI '%s' could not be found.", s.SourceAMI))
    74  		return multistep.ActionHalt
    75  	}
    76  
    77  	if s.ExpectedRootDevice != "" && imageResp.Images[0].RootDeviceType != s.ExpectedRootDevice {
    78  		state.Put("error", fmt.Errorf(
    79  			"The provided source AMI has an invalid root device type.\n"+
    80  				"Expected '%s', got '%s'.",
    81  			s.ExpectedRootDevice, imageResp.Images[0].RootDeviceType))
    82  		return multistep.ActionHalt
    83  	}
    84  
    85  	runResp, err := ec2conn.RunInstances(runOpts)
    86  	if err != nil {
    87  		err := fmt.Errorf("Error launching source instance: %s", err)
    88  		state.Put("error", err)
    89  		ui.Error(err.Error())
    90  		return multistep.ActionHalt
    91  	}
    92  
    93  	s.instance = &runResp.Instances[0]
    94  	ui.Message(fmt.Sprintf("Instance ID: %s", s.instance.InstanceId))
    95  
    96  	ec2Tags := make([]ec2.Tag, 1, len(s.Tags)+1)
    97  	ec2Tags[0] = ec2.Tag{"Name", "Packer Builder"}
    98  	for k, v := range s.Tags {
    99  		ec2Tags = append(ec2Tags, ec2.Tag{k, v})
   100  	}
   101  
   102  	_, err = ec2conn.CreateTags([]string{s.instance.InstanceId}, ec2Tags)
   103  	if err != nil {
   104  		ui.Message(
   105  			fmt.Sprintf("Failed to tag a Name on the builder instance: %s", err))
   106  	}
   107  
   108  	ui.Say(fmt.Sprintf("Waiting for instance (%s) to become ready...", s.instance.InstanceId))
   109  	stateChange := StateChangeConf{
   110  		Pending:   []string{"pending"},
   111  		Target:    "running",
   112  		Refresh:   InstanceStateRefreshFunc(ec2conn, s.instance),
   113  		StepState: state,
   114  	}
   115  	latestInstance, err := WaitForState(&stateChange)
   116  	if err != nil {
   117  		err := fmt.Errorf("Error waiting for instance (%s) to become ready: %s", s.instance.InstanceId, err)
   118  		state.Put("error", err)
   119  		ui.Error(err.Error())
   120  		return multistep.ActionHalt
   121  	}
   122  
   123  	s.instance = latestInstance.(*ec2.Instance)
   124  
   125  	if s.Debug {
   126  		if s.instance.DNSName != "" {
   127  			ui.Message(fmt.Sprintf("Public DNS: %s", s.instance.DNSName))
   128  		}
   129  
   130  		if s.instance.PublicIpAddress != "" {
   131  			ui.Message(fmt.Sprintf("Public IP: %s", s.instance.PublicIpAddress))
   132  		}
   133  
   134  		if s.instance.PrivateIpAddress != "" {
   135  			ui.Message(fmt.Sprintf("Private IP: %s", s.instance.PrivateIpAddress))
   136  		}
   137  	}
   138  
   139  	state.Put("instance", s.instance)
   140  
   141  	return multistep.ActionContinue
   142  }
   143  
   144  func (s *StepRunSourceInstance) Cleanup(state multistep.StateBag) {
   145  	if s.instance == nil {
   146  		return
   147  	}
   148  
   149  	ec2conn := state.Get("ec2").(*ec2.EC2)
   150  	ui := state.Get("ui").(packer.Ui)
   151  
   152  	ui.Say("Terminating the source AWS instance...")
   153  	if _, err := ec2conn.TerminateInstances([]string{s.instance.InstanceId}); err != nil {
   154  		ui.Error(fmt.Sprintf("Error terminating instance, may still be around: %s", err))
   155  		return
   156  	}
   157  
   158  	stateChange := StateChangeConf{
   159  		Pending: []string{"pending", "running", "shutting-down", "stopped", "stopping"},
   160  		Refresh: InstanceStateRefreshFunc(ec2conn, s.instance),
   161  		Target:  "terminated",
   162  	}
   163  
   164  	WaitForState(&stateChange)
   165  }