Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Resource aws client vpn net addl sgs #14146

Merged
merged 18 commits into from
Aug 20, 2020
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ GOFMT_FILES?=$$(find . -name '*.go' |grep -v vendor)
PKG_NAME=aws
WEBSITE_REPO=github.com/hashicorp/terraform-website
TEST_COUNT?=1
ACCTEST_TIMEOUT?=120m

default: build

Expand All @@ -23,7 +24,7 @@ test: fmtcheck
go test $(TEST) $(TESTARGS) -timeout=120s -parallel=4

testacc: fmtcheck
TF_ACC=1 go test $(TEST) -v -count $(TEST_COUNT) -parallel 20 $(TESTARGS) -timeout 120m
TF_ACC=1 go test $(TEST) -v -count $(TEST_COUNT) -parallel 20 $(TESTARGS) -timeout $(ACCTEST_TIMEOUT)

fmt:
@echo "==> Fixing source code with gofmt..."
Expand Down
8 changes: 7 additions & 1 deletion aws/internal/experimental/sync/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package sync

import (
"fmt"
"log"
"os"
"strconv"
"testing"
Expand Down Expand Up @@ -34,7 +35,12 @@ func (s Semaphore) Wait() {
// Notify releases a semaphore
// NOTE: this is currently an experimental feature and is likely to change. DO NOT USE.
func (s Semaphore) Notify() {
<-s
// Make the Notify non-blocking. This can happen if a Wait was never issued
select {
case <-s:
default:
log.Println("[WARN] Notifying semaphore without Wait")
}
}

// TestAccPreCheckSyncronized waits for a semaphore and skips the test if there is no capacity
Expand Down
19 changes: 19 additions & 0 deletions aws/internal/service/ec2/id.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,25 @@ func ClientVpnAuthorizationRuleParseID(id string) (string, string, string, error
clientVpnAuthorizationRuleIDSeparator+"group-id", id)
}

const clientVpnNetworkAssociationIDSeparator = ","

func ClientVpnNetworkAssociationCreateID(endpointID, associationID string) string {
parts := []string{endpointID, associationID}
id := strings.Join(parts, clientVpnNetworkAssociationIDSeparator)
return id
}

func ClientVpnNetworkAssociationParseID(id string) (string, string, error) {
parts := strings.Split(id, clientVpnNetworkAssociationIDSeparator)
if len(parts) == 2 && parts[0] != "" && parts[1] != "" {
return parts[0], parts[1], nil
}

return "", "",
fmt.Errorf("unexpected format for ID (%q), expected endpoint-id"+clientVpnNetworkAssociationIDSeparator+
"association-id", id)
}

const clientVpnRouteIDSeparator = ","

func ClientVpnRouteCreateID(endpointID, targetSubnetID, destinationCidr string) string {
Expand Down
33 changes: 33 additions & 0 deletions aws/internal/service/ec2/waiter/status.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,39 @@ func ClientVpnAuthorizationRuleStatus(conn *ec2.EC2, authorizationRuleID string)
}
}

const (
ClientVpnNetworkAssociationStatusNotFound = "NotFound"

ClientVpnNetworkAssociationStatusUnknown = "Unknown"
)

func ClientVpnNetworkAssociationStatus(conn *ec2.EC2, cvnaID string, cvepID string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
result, err := conn.DescribeClientVpnTargetNetworks(&ec2.DescribeClientVpnTargetNetworksInput{
ClientVpnEndpointId: aws.String(cvepID),
AssociationIds: []*string{aws.String(cvnaID)},
})

if tfec2.ErrCodeEquals(err, tfec2.ErrCodeClientVpnAssociationIdNotFound) || tfec2.ErrCodeEquals(err, tfec2.ErrCodeClientVpnEndpointIdNotFound) {
return nil, ClientVpnNetworkAssociationStatusNotFound, nil
}
if err != nil {
return nil, ClientVpnNetworkAssociationStatusUnknown, err
}

if result == nil || len(result.ClientVpnTargetNetworks) == 0 || result.ClientVpnTargetNetworks[0] == nil {
return nil, ClientVpnNetworkAssociationStatusNotFound, nil
}

network := result.ClientVpnTargetNetworks[0]
if network.Status == nil || network.Status.Code == nil {
return network, ClientVpnNetworkAssociationStatusUnknown, nil
}

return network, aws.StringValue(network.Status.Code), nil
}
}

const (
ClientVpnRouteStatusNotFound = "NotFound"

Expand Down
50 changes: 50 additions & 0 deletions aws/internal/service/ec2/waiter/waiter.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,56 @@ func ClientVpnAuthorizationRuleRevoked(conn *ec2.EC2, authorizationRuleID string
return nil, err
}

const (
ClientVpnNetworkAssociationAssociatedTimeout = 10 * time.Minute

ClientVpnNetworkAssociationAssociatedDelay = 4 * time.Minute

ClientVpnNetworkAssociationDisassociatedTimeout = 10 * time.Minute

ClientVpnNetworkAssociationDisassociatedDelay = 4 * time.Minute

ClientVpnNetworkAssociationStatusPollInterval = 10 * time.Second
)

func ClientVpnNetworkAssociationAssociated(conn *ec2.EC2, networkAssociationID, clientVpnEndpointID string) (*ec2.TargetNetwork, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{ec2.AssociationStatusCodeAssociating},
Target: []string{ec2.AssociationStatusCodeAssociated},
Refresh: ClientVpnNetworkAssociationStatus(conn, networkAssociationID, clientVpnEndpointID),
Timeout: ClientVpnNetworkAssociationAssociatedTimeout,
Delay: ClientVpnNetworkAssociationAssociatedDelay,
PollInterval: ClientVpnNetworkAssociationStatusPollInterval,
}

outputRaw, err := stateConf.WaitForState()

if output, ok := outputRaw.(*ec2.TargetNetwork); ok {
return output, err
}

return nil, err
}

func ClientVpnNetworkAssociationDisassociated(conn *ec2.EC2, networkAssociationID, clientVpnEndpointID string) (*ec2.TargetNetwork, error) {
stateConf := &resource.StateChangeConf{
Pending: []string{ec2.AssociationStatusCodeDisassociating},
Target: []string{},
Refresh: ClientVpnNetworkAssociationStatus(conn, networkAssociationID, clientVpnEndpointID),
Timeout: ClientVpnNetworkAssociationDisassociatedTimeout,
Delay: ClientVpnNetworkAssociationDisassociatedDelay,
PollInterval: ClientVpnNetworkAssociationStatusPollInterval,
}

outputRaw, err := stateConf.WaitForState()

if output, ok := outputRaw.(*ec2.TargetNetwork); ok {
return output, err
}

return nil, err
}

const (
ClientVpnRouteDeletedTimeout = 1 * time.Minute
)
Expand Down
47 changes: 26 additions & 21 deletions aws/resource_aws_ec2_client_vpn_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/terraform-plugin-sdk/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
Expand All @@ -28,6 +29,7 @@ func init() {
F: testSweepEc2ClientVpnEndpoints,
Dependencies: []string{
"aws_directory_service_directory",
"aws_ec2_client_vpn_network_association",
},
})
}
Expand All @@ -40,37 +42,38 @@ func testSweepEc2ClientVpnEndpoints(region string) error {
}

conn := client.(*AWSClient).ec2conn
input := &ec2.DescribeClientVpnEndpointsInput{}

for {
output, err := conn.DescribeClientVpnEndpoints(input)

if testSweepSkipSweepError(err) {
log.Printf("[WARN] Skipping Client VPN Endpoint sweep for %s: %s", region, err)
return nil
}
var sweeperErrs *multierror.Error

if err != nil {
return fmt.Errorf("error retrieving Client VPN Endpoints: %w", err)
input := &ec2.DescribeClientVpnEndpointsInput{}
err = conn.DescribeClientVpnEndpointsPages(input, func(page *ec2.DescribeClientVpnEndpointsOutput, isLast bool) bool {
if page == nil {
return !isLast
}

for _, clientVpnEndpoint := range output.ClientVpnEndpoints {
for _, clientVpnEndpoint := range page.ClientVpnEndpoints {
id := aws.StringValue(clientVpnEndpoint.ClientVpnEndpointId)
log.Printf("[INFO] Deleting Client VPN Endpoint: %s", id)
log.Printf("[INFO] Deleting Client VPN endpoint: %s", id)
err := deleteClientVpnEndpoint(conn, id)
if err != nil {
return fmt.Errorf("error deleting Client VPN Endpoint (%s): %w", id, err)
sweeperErr := fmt.Errorf("error deleting Client VPN endpoint (%s): %w", id, err)
log.Printf("[ERROR] %s", sweeperErr)
sweeperErrs = multierror.Append(sweeperErrs, sweeperErr)
continue
}
}

if aws.StringValue(output.NextToken) == "" {
break
}

input.NextToken = output.NextToken
return !isLast
})
if testSweepSkipSweepError(err) {
log.Printf("[WARN] Skipping Client VPN endpoint sweep for %s: %s", region, err)
return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors
}
if err != nil {
sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error retrieving Client VPN endpoints: %w", err))
}

return nil
return sweeperErrs.ErrorOrNil()
}

// This is part of an experimental feature, do not use this as a starting point for tests
Expand All @@ -96,8 +99,9 @@ func TestAccAwsEc2ClientVpn(t *testing.T) {
"disappears": testAccAwsEc2ClientVpnAuthorizationRule_disappears,
},
"NetworkAssociation": {
"basic": testAccAwsEc2ClientVpnNetworkAssociation_basic,
"disappears": testAccAwsEc2ClientVpnNetworkAssociation_disappears,
"basic": testAccAwsEc2ClientVpnNetworkAssociation_basic,
"disappears": testAccAwsEc2ClientVpnNetworkAssociation_disappears,
"securityGroups": testAccAwsEc2ClientVpnNetworkAssociation_securityGroups,
},
"Route": {
"basic": testAccAwsEc2ClientVpnRoute_basic,
Expand All @@ -106,6 +110,7 @@ func TestAccAwsEc2ClientVpn(t *testing.T) {
},
}

t.Parallel()
for group, m := range testCases {
m := m
for name, tc := range m {
Expand Down
Loading