-
Notifications
You must be signed in to change notification settings - Fork 128
Expand file tree
/
Copy pathstep_stop_ebs_instance.go
More file actions
97 lines (78 loc) · 2.7 KB
/
step_stop_ebs_instance.go
File metadata and controls
97 lines (78 loc) · 2.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package common
import (
"context"
"fmt"
"time"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/packer-plugin-amazon/builder/common/awserrors"
"github.com/hashicorp/packer-plugin-sdk/multistep"
packersdk "github.com/hashicorp/packer-plugin-sdk/packer"
"github.com/hashicorp/packer-plugin-sdk/retry"
)
type StepStopEBSBackedInstance struct {
PollingConfig *AWSPollingConfig
Skip bool
DisableStopInstance bool
}
func (s *StepStopEBSBackedInstance) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
ec2conn := state.Get("ec2").(*ec2.EC2)
instance := state.Get("instance").(*ec2.Instance)
ui := state.Get("ui").(packersdk.Ui)
// Skip when it is a spot instance
if s.Skip {
ui.Say("Skipping instance stop, since this is a spot instance.")
return multistep.ActionContinue
}
var err error
if !s.DisableStopInstance {
// Stop the instance so we can create an AMI from it
ui.Say("Stopping the source instance...")
// Amazon EC2 API follows an eventual consistency model.
// This means that if you run a command to modify or describe a resource
// that you just created, its ID might not have propagated throughout
// the system, and you will get an error responding that the resource
// does not exist.
// Work around this by retrying a few times, up to about 5 minutes.
err := retry.Config{Tries: 6, ShouldRetry: func(error) bool {
if awserrors.Matches(err, "InvalidInstanceID.NotFound", "") {
return true
}
return false
},
RetryDelay: (&retry.Backoff{InitialBackoff: 10 * time.Second, MaxBackoff: 60 * time.Second, Multiplier: 2}).Linear,
}.Run(ctx, func(ctx context.Context) error {
ui.Message("Stopping instance")
_, err = ec2conn.StopInstances(&ec2.StopInstancesInput{
InstanceIds: []*string{instance.InstanceId},
})
return err
})
if err != nil {
err := fmt.Errorf("Error stopping instance: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
} else {
ui.Say("Automatic instance stop disabled. Please stop instance manually.")
}
// Wait for the instance to actually stop
ui.Say("Waiting for the instance to stop...")
err = ec2conn.WaitUntilInstanceStoppedWithContext(ctx,
&ec2.DescribeInstancesInput{
InstanceIds: []*string{instance.InstanceId},
},
s.PollingConfig.getWaiterOptions()...)
if err != nil {
err := fmt.Errorf("Error waiting for instance to stop: %s", err)
state.Put("error", err)
ui.Error(err.Error())
return multistep.ActionHalt
}
return multistep.ActionContinue
}
func (s *StepStopEBSBackedInstance) Cleanup(multistep.StateBag) {
// No cleanup...
}