Skip to content

Commit 5b496db

Browse files
authored
service/ec2: Increase default VPN Gateway detach timeout to 30 mins (#15201)
* r/aws_vpn_gateway_attachment: Refactor using internal 'finder' and 'waiter' packages. Increase detachment timeout to 30m. Acceptance test output: $ make testacc TEST=./aws TESTARGS='-run=TestAccAWSVpnGatewayAttachment_' ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 20 -run=TestAccAWSVpnGatewayAttachment_ -timeout 120m === RUN TestAccAWSVpnGatewayAttachment_basic === PAUSE TestAccAWSVpnGatewayAttachment_basic === RUN TestAccAWSVpnGatewayAttachment_deleted === PAUSE TestAccAWSVpnGatewayAttachment_deleted === CONT TestAccAWSVpnGatewayAttachment_basic === CONT TestAccAWSVpnGatewayAttachment_deleted resource_aws_vpn_gateway_attachment_test.go:40: [INFO] Got non-empty plan, as expected --- PASS: TestAccAWSVpnGatewayAttachment_deleted (33.77s) --- PASS: TestAccAWSVpnGatewayAttachment_basic (38.51s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 38.552s * r/aws_vpn_gateway: Refactor test sweeper to call aws_vpn_gateway and aws_vpn_gateway_attachment Delete methods. Acceptance test output: $ TEST=./aws SWEEP=us-west-2,us-east-1 SWEEPARGS=-sweep-run=aws_vpn_gateway make sweep WARNING: This will destroy infrastructure. Use only in development accounts. go test ./aws -v -sweep=us-west-2,us-east-1 -sweep-run=aws_vpn_gateway -timeout 60m 2020/09/17 14:01:43 [DEBUG] Running Sweepers for region (us-west-2): 2020/09/17 14:01:43 [DEBUG] Sweeper (aws_vpn_gateway) has dependency (aws_dx_gateway_association), running.. 2020/09/17 14:01:43 [DEBUG] Sweeper (aws_dx_gateway_association) has dependency (aws_dx_gateway_association_proposal), running.. 2020/09/17 14:01:43 [DEBUG] Running Sweeper (aws_dx_gateway_association_proposal) in region (us-west-2) 2020/09/17 14:01:43 [INFO] AWS Auth provider used: "EnvProvider" 2020/09/17 14:01:43 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2020/09/17 14:01:44 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2020/09/17 14:01:45 [DEBUG] Running Sweeper (aws_dx_gateway_association) in region (us-west-2) 2020/09/17 14:01:46 [DEBUG] Running Sweeper (aws_vpn_gateway) in region (us-west-2) 2020/09/17 14:01:46 [INFO] Deleting VPN Gateway (vgw-0b8054188ab62b680) Attachment (vpc-f2e16e8b) 2020/09/17 14:01:47 [DEBUG] Waiting for state to become: [detached] 2020/09/17 14:01:47 [DEBUG] Not detaching VPN Gateway 'vgw-0b8054188ab62b680' as no VPC ID is set 2020/09/17 14:01:47 [INFO] Deleting VPN gateway: vgw-0b8054188ab62b680 2020/09/17 14:01:47 [DEBUG] Waiting for state to become: [success] 2020/09/17 14:01:48 [DEBUG] Sweeper (aws_dx_gateway_association) has dependency (aws_dx_gateway_association_proposal), running.. 2020/09/17 14:01:48 [DEBUG] Sweeper (aws_dx_gateway_association_proposal) already ran in region (us-west-2) 2020/09/17 14:01:48 [DEBUG] Sweeper (aws_dx_gateway_association) already ran in region (us-west-2) 2020/09/17 14:01:48 [DEBUG] Sweeper (aws_dx_gateway_association_proposal) already ran in region (us-west-2) 2020/09/17 14:01:48 Sweeper Tests ran successfully: - aws_vpn_gateway - aws_dx_gateway_association_proposal - aws_dx_gateway_association 2020/09/17 14:01:48 [DEBUG] Running Sweepers for region (us-east-1): 2020/09/17 14:01:48 [DEBUG] Sweeper (aws_vpn_gateway) has dependency (aws_dx_gateway_association), running.. 2020/09/17 14:01:48 [DEBUG] Sweeper (aws_dx_gateway_association) has dependency (aws_dx_gateway_association_proposal), running.. 2020/09/17 14:01:48 [DEBUG] Running Sweeper (aws_dx_gateway_association_proposal) in region (us-east-1) 2020/09/17 14:01:48 [INFO] AWS Auth provider used: "EnvProvider" 2020/09/17 14:01:48 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2020/09/17 14:01:48 [DEBUG] Trying to get account information via sts:GetCallerIdentity 2020/09/17 14:01:48 [DEBUG] Running Sweeper (aws_dx_gateway_association) in region (us-east-1) 2020/09/17 14:01:49 [DEBUG] Running Sweeper (aws_vpn_gateway) in region (us-east-1) 2020/09/17 14:01:49 [DEBUG] No VPN Gateways to sweep 2020/09/17 14:01:49 [DEBUG] Sweeper (aws_dx_gateway_association) has dependency (aws_dx_gateway_association_proposal), running.. 2020/09/17 14:01:49 [DEBUG] Sweeper (aws_dx_gateway_association_proposal) already ran in region (us-east-1) 2020/09/17 14:01:49 [DEBUG] Sweeper (aws_dx_gateway_association) already ran in region (us-east-1) 2020/09/17 14:01:49 [DEBUG] Sweeper (aws_dx_gateway_association_proposal) already ran in region (us-east-1) 2020/09/17 14:01:49 Sweeper Tests ran successfully: - aws_dx_gateway_association_proposal - aws_dx_gateway_association - aws_vpn_gateway ok github.com/terraform-providers/terraform-provider-aws/aws 5.308s * r/aws_vpn_gateway: Refactor using internal 'waiter' package. Increase detachment timeout to 30m. Acceptance test output: $ make testacc TEST=./aws/ TESTARGS='-run=TestAccAWSVpnGateway_' ACCTEST_PARALLELISM=2 ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./aws -v -count 1 -parallel 2 -run=TestAccAWSVpnGateway_ -timeout 120m === RUN TestAccAWSVpnGateway_basic === PAUSE TestAccAWSVpnGateway_basic === RUN TestAccAWSVpnGateway_withAvailabilityZoneSetToState === PAUSE TestAccAWSVpnGateway_withAvailabilityZoneSetToState === RUN TestAccAWSVpnGateway_withAmazonSideAsnSetToState === PAUSE TestAccAWSVpnGateway_withAmazonSideAsnSetToState === RUN TestAccAWSVpnGateway_disappears === PAUSE TestAccAWSVpnGateway_disappears === RUN TestAccAWSVpnGateway_reattach === PAUSE TestAccAWSVpnGateway_reattach === RUN TestAccAWSVpnGateway_delete === PAUSE TestAccAWSVpnGateway_delete === RUN TestAccAWSVpnGateway_tags === PAUSE TestAccAWSVpnGateway_tags === CONT TestAccAWSVpnGateway_basic === CONT TestAccAWSVpnGateway_reattach --- PASS: TestAccAWSVpnGateway_basic (87.01s) === CONT TestAccAWSVpnGateway_tags --- PASS: TestAccAWSVpnGateway_reattach (123.40s) === CONT TestAccAWSVpnGateway_delete --- PASS: TestAccAWSVpnGateway_delete (60.46s) === CONT TestAccAWSVpnGateway_withAmazonSideAsnSetToState --- PASS: TestAccAWSVpnGateway_tags (97.73s) === CONT TestAccAWSVpnGateway_disappears resource_aws_vpn_gateway_test.go:195: [INFO] Got non-empty plan, as expected --- PASS: TestAccAWSVpnGateway_disappears (40.79s) === CONT TestAccAWSVpnGateway_withAvailabilityZoneSetToState --- PASS: TestAccAWSVpnGateway_withAmazonSideAsnSetToState (52.12s) --- PASS: TestAccAWSVpnGateway_withAvailabilityZoneSetToState (47.02s) PASS ok github.com/terraform-providers/terraform-provider-aws/aws 272.597s * 'TestAccAWSVpnGatewayAttachment_deleted' -> 'TestAccAWSVpnGatewayAttachment_disappears' (#13826, #13527).
1 parent df23954 commit 5b496db

9 files changed

Lines changed: 232 additions & 271 deletions

aws/internal/service/ec2/errors.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,8 @@ const (
2828
InvalidSecurityGroupIDNotFound = "InvalidSecurityGroupID.NotFound"
2929
InvalidGroupNotFound = "InvalidGroup.NotFound"
3030
)
31+
32+
const (
33+
InvalidVpnGatewayAttachmentNotFound = "InvalidVpnGatewayAttachment.NotFound"
34+
InvalidVpnGatewayIDNotFound = "InvalidVpnGatewayID.NotFound"
35+
)

aws/internal/service/ec2/finder/finder.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,3 +71,43 @@ func SecurityGroupByID(conn *ec2.EC2, id string) (*ec2.SecurityGroup, error) {
7171

7272
return result.SecurityGroups[0], nil
7373
}
74+
75+
// VpnGatewayVpcAttachment returns the attachment between the specified VPN gateway and VPC.
76+
// Returns nil and potentially an error if no attachment is found.
77+
func VpnGatewayVpcAttachment(conn *ec2.EC2, vpnGatewayID, vpcID string) (*ec2.VpcAttachment, error) {
78+
vpnGateway, err := VpnGatewayByID(conn, vpnGatewayID)
79+
if err != nil {
80+
return nil, err
81+
}
82+
83+
if vpnGateway == nil {
84+
return nil, nil
85+
}
86+
87+
for _, vpcAttachment := range vpnGateway.VpcAttachments {
88+
if aws.StringValue(vpcAttachment.VpcId) == vpcID {
89+
return vpcAttachment, nil
90+
}
91+
}
92+
93+
return nil, nil
94+
}
95+
96+
// VpnGatewayByID returns the VPN gateway corresponding to the specified identifier.
97+
// Returns nil and potentially an error if no VPN gateway is found.
98+
func VpnGatewayByID(conn *ec2.EC2, id string) (*ec2.VpnGateway, error) {
99+
input := &ec2.DescribeVpnGatewaysInput{
100+
VpnGatewayIds: aws.StringSlice([]string{id}),
101+
}
102+
103+
output, err := conn.DescribeVpnGateways(input)
104+
if err != nil {
105+
return nil, err
106+
}
107+
108+
if output == nil || len(output.VpnGateways) == 0 {
109+
return nil, nil
110+
}
111+
112+
return output.VpnGateways[0], nil
113+
}

aws/internal/service/ec2/id.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package ec2
33
import (
44
"fmt"
55
"strings"
6+
7+
"github.com/terraform-providers/terraform-provider-aws/aws/internal/hashcode"
68
)
79

810
const clientVpnAuthorizationRuleIDSeparator = ","
@@ -68,3 +70,7 @@ func ClientVpnRouteParseID(id string) (string, string, string, error) {
6870
fmt.Errorf("unexpected format for ID (%q), expected endpoint-id"+clientVpnRouteIDSeparator+
6971
"target-subnet-id"+clientVpnRouteIDSeparator+"destination-cidr-block", id)
7072
}
73+
74+
func VpnGatewayVpcAttachmentCreateID(vpnGatewayID, vpcID string) string {
75+
return fmt.Sprintf("vpn-attachment-%x", hashcode.String(fmt.Sprintf("%s-%s", vpcID, vpnGatewayID)))
76+
}

aws/internal/service/ec2/waiter/status.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,3 +204,27 @@ func SecurityGroupStatus(conn *ec2.EC2, id string) resource.StateRefreshFunc {
204204
return group, SecurityGroupStatusCreated, nil
205205
}
206206
}
207+
208+
const (
209+
attachmentStateNotFound = "NotFound"
210+
attachmentStateUnknown = "Unknown"
211+
)
212+
213+
// VpnGatewayVpcAttachmentState fetches the attachment between the specified VPN gateway and VPC and its state
214+
func VpnGatewayVpcAttachmentState(conn *ec2.EC2, vpnGatewayID, vpcID string) resource.StateRefreshFunc {
215+
return func() (interface{}, string, error) {
216+
vpcAttachment, err := finder.VpnGatewayVpcAttachment(conn, vpnGatewayID, vpcID)
217+
if tfec2.ErrCodeEquals(err, tfec2.InvalidVpnGatewayIDNotFound) {
218+
return nil, attachmentStateNotFound, nil
219+
}
220+
if err != nil {
221+
return nil, attachmentStateUnknown, err
222+
}
223+
224+
if vpcAttachment == nil {
225+
return nil, attachmentStateNotFound, nil
226+
}
227+
228+
return vpcAttachment, aws.StringValue(vpcAttachment.State), nil
229+
}
230+
}

aws/internal/service/ec2/waiter/waiter.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,3 +199,43 @@ func SecurityGroupCreated(conn *ec2.EC2, id string, timeout time.Duration) (*ec2
199199

200200
return nil, err
201201
}
202+
203+
const (
204+
VpnGatewayVpcAttachmentAttachedTimeout = 15 * time.Minute
205+
206+
VpnGatewayVpcAttachmentDetachedTimeout = 30 * time.Minute
207+
)
208+
209+
func VpnGatewayVpcAttachmentAttached(conn *ec2.EC2, vpnGatewayID, vpcID string) (*ec2.VpcAttachment, error) {
210+
stateConf := &resource.StateChangeConf{
211+
Pending: []string{ec2.AttachmentStatusDetached, ec2.AttachmentStatusAttaching},
212+
Target: []string{ec2.AttachmentStatusAttached},
213+
Refresh: VpnGatewayVpcAttachmentState(conn, vpnGatewayID, vpcID),
214+
Timeout: VpnGatewayVpcAttachmentAttachedTimeout,
215+
}
216+
217+
outputRaw, err := stateConf.WaitForState()
218+
219+
if output, ok := outputRaw.(*ec2.VpcAttachment); ok {
220+
return output, err
221+
}
222+
223+
return nil, err
224+
}
225+
226+
func VpnGatewayVpcAttachmentDetached(conn *ec2.EC2, vpnGatewayID, vpcID string) (*ec2.VpcAttachment, error) {
227+
stateConf := &resource.StateChangeConf{
228+
Pending: []string{ec2.AttachmentStatusAttached, ec2.AttachmentStatusDetaching},
229+
Target: []string{ec2.AttachmentStatusDetached},
230+
Refresh: VpnGatewayVpcAttachmentState(conn, vpnGatewayID, vpcID),
231+
Timeout: VpnGatewayVpcAttachmentDetachedTimeout,
232+
}
233+
234+
outputRaw, err := stateConf.WaitForState()
235+
236+
if output, ok := outputRaw.(*ec2.VpcAttachment); ok {
237+
return output, err
238+
}
239+
240+
return nil, err
241+
}

aws/resource_aws_vpn_gateway.go

Lines changed: 15 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import (
1212
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
1313
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
1414
"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
15+
tfec2 "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2"
16+
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/ec2/waiter"
1517
)
1618

1719
func resourceAwsVpnGateway() *schema.Resource {
@@ -233,7 +235,7 @@ func resourceAwsVpnGatewayAttach(d *schema.ResourceData, meta interface{}) error
233235
err := resource.Retry(1*time.Minute, func() *resource.RetryError {
234236
_, err := conn.AttachVpnGateway(req)
235237
if err != nil {
236-
if isAWSErr(err, "InvalidVpnGatewayID.NotFound", "") {
238+
if isAWSErr(err, tfec2.InvalidVpnGatewayIDNotFound, "") {
237239
return resource.RetryableError(err)
238240
}
239241
return resource.NonRetryableError(err)
@@ -250,14 +252,10 @@ func resourceAwsVpnGatewayAttach(d *schema.ResourceData, meta interface{}) error
250252

251253
// Wait for it to be fully attached before continuing
252254
log.Printf("[DEBUG] Waiting for VPN gateway (%s) to attach", d.Id())
253-
stateConf := &resource.StateChangeConf{
254-
Pending: []string{ec2.AttachmentStatusDetached, ec2.AttachmentStatusAttaching},
255-
Target: []string{ec2.AttachmentStatusAttached},
256-
Refresh: vpnGatewayAttachmentStateRefresh(conn, vpcId, d.Id()),
257-
Timeout: 15 * time.Minute,
258-
}
259-
if _, err := stateConf.WaitForState(); err != nil {
260-
return fmt.Errorf("Error waiting for VPN gateway (%s) to attach: %s", d.Id(), err)
255+
_, err = waiter.VpnGatewayVpcAttachmentAttached(conn, d.Id(), vpcId)
256+
257+
if err != nil {
258+
return fmt.Errorf("error waiting for VPN Gateway (%s) Attachment (%s) to become attached: %w", d.Id(), vpcId, err)
261259
}
262260

263261
return nil
@@ -282,40 +280,24 @@ func resourceAwsVpnGatewayDetach(d *schema.ResourceData, meta interface{}) error
282280
d.Id(),
283281
vpcId)
284282

285-
wait := true
286283
_, err := conn.DetachVpnGateway(&ec2.DetachVpnGatewayInput{
287284
VpnGatewayId: aws.String(d.Id()),
288285
VpcId: aws.String(vpcId),
289286
})
290-
if err != nil {
291-
if isAWSErr(err, "InvalidVpnGatewayID.NotFound", "") {
292-
err = nil
293-
wait = false
294-
}
295-
if isAWSErr(err, "InvalidVpnGatewayAttachment.NotFound", "") {
296-
err = nil
297-
wait = false
298-
}
299287

300-
if err != nil {
301-
return err
302-
}
288+
if isAWSErr(err, tfec2.InvalidVpnGatewayAttachmentNotFound, "") || isAWSErr(err, tfec2.InvalidVpnGatewayIDNotFound, "") {
289+
return nil
303290
}
304291

305-
if !wait {
306-
return nil
292+
if err != nil {
293+
return fmt.Errorf("error deleting VPN Gateway (%s) Attachment (%s): %w", d.Id(), vpcId, err)
307294
}
308295

309296
// Wait for it to be fully detached before continuing
310-
log.Printf("[DEBUG] Waiting for VPN gateway (%s) to detach", d.Id())
311-
stateConf := &resource.StateChangeConf{
312-
Pending: []string{ec2.AttachmentStatusAttached, ec2.AttachmentStatusDetaching, "available"},
313-
Target: []string{ec2.AttachmentStatusDetached},
314-
Refresh: vpnGatewayAttachmentStateRefresh(conn, vpcId, d.Id()),
315-
Timeout: 10 * time.Minute,
316-
}
317-
if _, err := stateConf.WaitForState(); err != nil {
318-
return fmt.Errorf("Error waiting for vpn gateway (%s) to detach: %s", d.Id(), err)
297+
_, err = waiter.VpnGatewayVpcAttachmentDetached(conn, d.Id(), vpcId)
298+
299+
if err != nil {
300+
return fmt.Errorf("error waiting for VPN Gateway (%s) Attachment (%s) to become detached: %w", d.Id(), vpcId, err)
319301
}
320302

321303
return nil

0 commit comments

Comments
 (0)