github.phpd.cn/hashicorp/packer@v1.3.2/builder/amazon/common/step_stop_ebs_instance.go (about) 1 package common 2 3 import ( 4 "context" 5 "fmt" 6 7 "github.com/aws/aws-sdk-go/aws/awserr" 8 "github.com/aws/aws-sdk-go/service/ec2" 9 "github.com/hashicorp/packer/common" 10 "github.com/hashicorp/packer/helper/multistep" 11 "github.com/hashicorp/packer/packer" 12 ) 13 14 type StepStopEBSBackedInstance struct { 15 Skip bool 16 DisableStopInstance bool 17 } 18 19 func (s *StepStopEBSBackedInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction { 20 ec2conn := state.Get("ec2").(*ec2.EC2) 21 instance := state.Get("instance").(*ec2.Instance) 22 ui := state.Get("ui").(packer.Ui) 23 24 // Skip when it is a spot instance 25 if s.Skip { 26 return multistep.ActionContinue 27 } 28 29 var err error 30 31 if !s.DisableStopInstance { 32 // Stop the instance so we can create an AMI from it 33 ui.Say("Stopping the source instance...") 34 35 // Amazon EC2 API follows an eventual consistency model. 36 37 // This means that if you run a command to modify or describe a resource 38 // that you just created, its ID might not have propagated throughout 39 // the system, and you will get an error responding that the resource 40 // does not exist. 41 42 // Work around this by retrying a few times, up to about 5 minutes. 43 err := common.Retry(10, 60, 6, func(i uint) (bool, error) { 44 ui.Message(fmt.Sprintf("Stopping instance, attempt %d", i+1)) 45 46 _, err = ec2conn.StopInstances(&ec2.StopInstancesInput{ 47 InstanceIds: []*string{instance.InstanceId}, 48 }) 49 50 if err == nil { 51 // success 52 return true, nil 53 } 54 55 if awsErr, ok := err.(awserr.Error); ok { 56 if awsErr.Code() == "InvalidInstanceID.NotFound" { 57 ui.Message(fmt.Sprintf( 58 "Error stopping instance; will retry ..."+ 59 "Error: %s", err)) 60 // retry 61 return false, nil 62 } 63 } 64 // errored, but not in expected way. Don't want to retry 65 return true, err 66 }) 67 68 if err != nil { 69 err := fmt.Errorf("Error stopping instance: %s", err) 70 state.Put("error", err) 71 ui.Error(err.Error()) 72 return multistep.ActionHalt 73 } 74 75 } else { 76 ui.Say("Automatic instance stop disabled. Please stop instance manually.") 77 } 78 79 // Wait for the instance to actually stop 80 ui.Say("Waiting for the instance to stop...") 81 err = ec2conn.WaitUntilInstanceStoppedWithContext(ctx, 82 &ec2.DescribeInstancesInput{ 83 InstanceIds: []*string{instance.InstanceId}, 84 }, 85 getWaiterOptions()...) 86 87 if err != nil { 88 err := fmt.Errorf("Error waiting for instance to stop: %s", err) 89 state.Put("error", err) 90 ui.Error(err.Error()) 91 return multistep.ActionHalt 92 } 93 94 return multistep.ActionContinue 95 } 96 97 func (s *StepStopEBSBackedInstance) Cleanup(multistep.StateBag) { 98 // No cleanup... 99 }