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

r/aws_dx_gateway_association: Allowed prefix support #8222

Merged
merged 2 commits into from
Apr 24, 2019
Merged
Changes from all 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
123 changes: 105 additions & 18 deletions aws/resource_aws_dx_gateway_association.go
Original file line number Diff line number Diff line change
@@ -3,6 +3,7 @@ package aws
import (
"fmt"
"log"
"strings"
"time"

"github.com/aws/aws-sdk-go/aws"
@@ -12,31 +13,49 @@ import (
)

const (
GatewayAssociationStateDeleted = "deleted"
gatewayAssociationStateDeleted = "deleted"
)

func resourceAwsDxGatewayAssociation() *schema.Resource {
return &schema.Resource{
Create: resourceAwsDxGatewayAssociationCreate,
Read: resourceAwsDxGatewayAssociationRead,
Update: resourceAwsDxGatewayAssociationUpdate,
Delete: resourceAwsDxGatewayAssociationDelete,
Importer: &schema.ResourceImporter{
State: resourceAwsDxGatewayAssociationImport,
},

Schema: map[string]*schema.Schema{
"allowed_prefixes": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it is okay to mark this as Computed: true for now, given that it automatically includes the VPC CIDR if no prefixes are provided. 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, I think a missing call to resourceAwsDxGatewayAssociationRead() at the end of resourceAwsDxGatewayAssociationCreate() doesn't help either 😄.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$ make testacc TEST=./aws/ TESTARGS='-run=TestAccAwsDxGatewayAssociation_basic'
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test ./aws/ -v -parallel 20 -run=TestAccAwsDxGatewayAssociation_basic -timeout 120m
=== RUN   TestAccAwsDxGatewayAssociation_basic
=== PAUSE TestAccAwsDxGatewayAssociation_basic
=== CONT  TestAccAwsDxGatewayAssociation_basic
--- PASS: TestAccAwsDxGatewayAssociation_basic (943.05s)
PASS
ok  	github.com/terraform-providers/terraform-provider-aws/aws	943.077s

Type: schema.TypeSet,
Optional: true,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},

"dx_gateway_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"vpn_gateway_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"dx_gateway_association_id": {
Type: schema.TypeString,
Computed: true,
},
},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(15 * time.Minute),
Delete: schema.DefaultTimeout(10 * time.Minute),
Update: schema.DefaultTimeout(10 * time.Minute),
Delete: schema.DefaultTimeout(15 * time.Minute),
},
}
}
@@ -47,14 +66,15 @@ func resourceAwsDxGatewayAssociationCreate(d *schema.ResourceData, meta interfac
dxgwId := d.Get("dx_gateway_id").(string)
vgwId := d.Get("vpn_gateway_id").(string)
req := &directconnect.CreateDirectConnectGatewayAssociationInput{
DirectConnectGatewayId: aws.String(dxgwId),
VirtualGatewayId: aws.String(vgwId),
AddAllowedPrefixesToDirectConnectGateway: expandDxRouteFilterPrefixes(d.Get("allowed_prefixes").(*schema.Set)),
DirectConnectGatewayId: aws.String(dxgwId),
VirtualGatewayId: aws.String(vgwId),
}

log.Printf("[DEBUG] Creating Direct Connect gateway association: %#v", req)
_, err := conn.CreateDirectConnectGatewayAssociation(req)
if err != nil {
return fmt.Errorf("Error creating Direct Connect gateway association: %s", err)
return fmt.Errorf("error creating Direct Connect gateway association: %s", err)
}

d.SetId(dxGatewayAssociationId(dxgwId, vgwId))
@@ -69,56 +89,123 @@ func resourceAwsDxGatewayAssociationCreate(d *schema.ResourceData, meta interfac
}
_, err = stateConf.WaitForState()
if err != nil {
return fmt.Errorf("Error waiting for Direct Connect gateway association (%s) to become available: %s", d.Id(), err)
return fmt.Errorf("error waiting for Direct Connect gateway association (%s) to become available: %s", d.Id(), err)
}

return nil
return resourceAwsDxGatewayAssociationRead(d, meta)
}

func resourceAwsDxGatewayAssociationRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).dxconn

dxgwId := d.Get("dx_gateway_id").(string)
vgwId := d.Get("vpn_gateway_id").(string)
_, state, err := dxGatewayAssociationStateRefresh(conn, dxgwId, vgwId)()
assocRaw, state, err := dxGatewayAssociationStateRefresh(conn, dxgwId, vgwId)()
if err != nil {
return fmt.Errorf("Error reading Direct Connect gateway association: %s", err)
return fmt.Errorf("error reading Direct Connect gateway association: %s", err)
}
if state == GatewayAssociationStateDeleted {
if state == gatewayAssociationStateDeleted {
log.Printf("[WARN] Direct Connect gateway association (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

assoc := assocRaw.(*directconnect.GatewayAssociation)
d.Set("dx_gateway_id", assoc.DirectConnectGatewayId)
d.Set("vpn_gateway_id", assoc.VirtualGatewayId)
d.Set("dx_gateway_association_id", assoc.AssociationId)
err = d.Set("allowed_prefixes", flattenDxRouteFilterPrefixes(assoc.AllowedPrefixesToDirectConnectGateway))
if err != nil {
return fmt.Errorf("error setting allowed_prefixes: %s", err)
}

return nil
}

func resourceAwsDxGatewayAssociationUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).dxconn

dxgwId := d.Get("dx_gateway_id").(string)
vgwId := d.Get("vpn_gateway_id").(string)

if d.HasChange("allowed_prefixes") {
oraw, nraw := d.GetChange("allowed_prefixes")
o := oraw.(*schema.Set)
n := nraw.(*schema.Set)
del := o.Difference(n)
add := n.Difference(o)

req := &directconnect.UpdateDirectConnectGatewayAssociationInput{
AddAllowedPrefixesToDirectConnectGateway: expandDxRouteFilterPrefixes(add),
AssociationId: aws.String(d.Get("dx_gateway_association_id").(string)),
RemoveAllowedPrefixesToDirectConnectGateway: expandDxRouteFilterPrefixes(del),
}

log.Printf("[DEBUG] Direct Connect gateway association: %#v", req)
_, err := conn.UpdateDirectConnectGatewayAssociation(req)
if err != nil {
return fmt.Errorf("error updating Direct Connect gateway association (%s): %s", d.Id(), err)
}

stateConf := &resource.StateChangeConf{
Pending: []string{directconnect.GatewayAssociationStateUpdating},
Target: []string{directconnect.GatewayAssociationStateAssociated},
Refresh: dxGatewayAssociationStateRefresh(conn, dxgwId, vgwId),
Timeout: d.Timeout(schema.TimeoutUpdate),
Delay: 10 * time.Second,
MinTimeout: 5 * time.Second,
}
_, err = stateConf.WaitForState()
if err != nil {
return fmt.Errorf("error waiting for Direct Connect gateway association (%s) to become available: %s", d.Id(), err)
}
}

return resourceAwsDxGatewayAssociationRead(d, meta)
}

func resourceAwsDxGatewayAssociationDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).dxconn

dxgwId := d.Get("dx_gateway_id").(string)
vgwId := d.Get("vpn_gateway_id").(string)

log.Printf("[DEBUG] Deleting Direct Connect gateway association: %s", d.Id())

_, err := conn.DeleteDirectConnectGatewayAssociation(&directconnect.DeleteDirectConnectGatewayAssociationInput{
DirectConnectGatewayId: aws.String(dxgwId),
VirtualGatewayId: aws.String(vgwId),
})
if isAWSErr(err, directconnect.ErrCodeClientException, "No association exists") {
return nil
}
if err != nil {
if isAWSErr(err, "DirectConnectClientException", "No association exists") {
return nil
}
return fmt.Errorf("Error deleting Direct Connect gateway association: %s", err)
return fmt.Errorf("error deleting Direct Connect gateway association: %s", err)
}

if err := waitForDirectConnectGatewayAssociationDeletion(conn, dxgwId, vgwId, d.Timeout(schema.TimeoutDelete)); err != nil {
return fmt.Errorf("Error waiting for Direct Connect gateway association (%s) to be deleted: %s", d.Id(), err.Error())
return fmt.Errorf("error waiting for Direct Connect gateway association (%s) to be deleted: %s", d.Id(), err.Error())
}

return nil
}

func resourceAwsDxGatewayAssociationImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
parts := strings.Split(d.Id(), "/")
if len(parts) != 2 {
return []*schema.ResourceData{}, fmt.Errorf("Wrong format of resource: %s. Please follow 'dx-gw-id/vgw-id'", d.Id())
}

dxgwId := parts[0]
vgwId := parts[1]
log.Printf("[DEBUG] Importing Direct Connect gateway association %s/%s", dxgwId, vgwId)

d.SetId(dxGatewayAssociationId(dxgwId, vgwId))
d.Set("dx_gateway_id", dxgwId)
d.Set("vpn_gateway_id", vgwId)

return []*schema.ResourceData{d}, nil
}

func dxGatewayAssociationStateRefresh(conn *directconnect.DirectConnect, dxgwId, vgwId string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
resp, err := conn.DescribeDirectConnectGatewayAssociations(&directconnect.DescribeDirectConnectGatewayAssociationsInput{
@@ -132,7 +219,7 @@ func dxGatewayAssociationStateRefresh(conn *directconnect.DirectConnect, dxgwId,
n := len(resp.DirectConnectGatewayAssociations)
switch n {
case 0:
return "", GatewayAssociationStateDeleted, nil
return "", gatewayAssociationStateDeleted, nil

case 1:
assoc := resp.DirectConnectGatewayAssociations[0]
@@ -151,7 +238,7 @@ func dxGatewayAssociationId(dxgwId, vgwId string) string {
func waitForDirectConnectGatewayAssociationDeletion(conn *directconnect.DirectConnect, directConnectGatewayID, virtualGatewayID string, timeout time.Duration) error {
stateConf := &resource.StateChangeConf{
Pending: []string{directconnect.GatewayAssociationStateDisassociating},
Target: []string{directconnect.GatewayAssociationStateDisassociated, GatewayAssociationStateDeleted},
Target: []string{directconnect.GatewayAssociationStateDisassociated, gatewayAssociationStateDeleted},
Refresh: dxGatewayAssociationStateRefresh(conn, directConnectGatewayID, virtualGatewayID),
Timeout: timeout,
Delay: 10 * time.Second,
Loading