From 191e73fbb102efc8ecaa766575b45a307c7b9189 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 5 Apr 2019 09:07:03 -0400 Subject: [PATCH 1/2] r/aws_dx_gateway_association: Allowed prefix support. --- aws/resource_aws_dx_gateway_association.go | 118 +++++++++++++++--- ...esource_aws_dx_gateway_association_test.go | 68 +++++++--- aws/resource_aws_dx_gateway_test.go | 6 +- ..._aws_dx_hosted_public_virtual_interface.go | 2 +- ...esource_aws_dx_public_virtual_interface.go | 2 +- aws/structure.go | 29 +++-- website/docs/r/dx_bgp_peer.html.markdown | 2 +- .../r/dx_gateway_association.html.markdown | 49 +++++++- 8 files changed, 223 insertions(+), 53 deletions(-) diff --git a/aws/resource_aws_dx_gateway_association.go b/aws/resource_aws_dx_gateway_association.go index 615aca3926c..4c7d83f5391 100644 --- a/aws/resource_aws_dx_gateway_association.go +++ b/aws/resource_aws_dx_gateway_association.go @@ -3,6 +3,7 @@ package aws import ( "fmt" "log" + "strings" "time" "github.com/aws/aws-sdk-go/aws" @@ -12,30 +13,47 @@ 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": { + Type: schema.TypeSet, + Optional: 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), + Update: schema.DefaultTimeout(10 * time.Minute), Delete: schema.DefaultTimeout(10 * time.Minute), }, } @@ -47,14 +65,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,7 +88,7 @@ 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 @@ -80,19 +99,70 @@ func resourceAwsDxGatewayAssociationRead(d *schema.ResourceData, meta interface{ 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 @@ -100,25 +170,41 @@ func resourceAwsDxGatewayAssociationDelete(d *schema.ResourceData, meta interfac 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 +218,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 +237,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, diff --git a/aws/resource_aws_dx_gateway_association_test.go b/aws/resource_aws_dx_gateway_association_test.go index b5f405ed48e..cdec456813c 100644 --- a/aws/resource_aws_dx_gateway_association_test.go +++ b/aws/resource_aws_dx_gateway_association_test.go @@ -102,32 +102,59 @@ func testSweepDirectConnectGatewayAssociations(region string) error { } func TestAccAwsDxGatewayAssociation_basic(t *testing.T) { + resourceName := "aws_dx_gateway_association.test" + resourceNameDxGw := "aws_dx_gateway.test" + resourceNameVgw := "aws_vpn_gateway.test" + rName := fmt.Sprintf("terraform-testacc-dxgwassoc-%d", acctest.RandInt()) + rBgpAsn := randIntRange(64512, 65534) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAwsDxGatewayAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccDxGatewayAssociationConfig(acctest.RandString(5), randIntRange(64512, 65534)), + Config: testAccDxGatewayAssociationConfig(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsDxGatewayAssociationExists("aws_dx_gateway_association.test"), + testAccCheckAwsDxGatewayAssociationExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), + resource.TestCheckResourceAttrPair(resourceName, "vpn_gateway_id", resourceNameVgw, "id"), ), }, + { + ResourceName: resourceName, + ImportStateIdFunc: func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return "", fmt.Errorf("Not Found: %s", resourceName) + } + + return fmt.Sprintf("%s/%s", rs.Primary.Attributes["dx_gateway_id"], rs.Primary.Attributes["vpn_gateway_id"]), nil + }, + ImportState: true, + ImportStateVerify: true, + }, }, }) } func TestAccAwsDxGatewayAssociation_multiVgws(t *testing.T) { + resourceName1 := "aws_dx_gateway_association.test1" + resourceName2 := "aws_dx_gateway_association.test2" + rName1 := fmt.Sprintf("terraform-testacc-dxgwassoc-%d", acctest.RandInt()) + rName2 := fmt.Sprintf("terraform-testacc-dxgwassoc-%d", acctest.RandInt()) + rBgpAsn := randIntRange(64512, 65534) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAwsDxGatewayAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccDxGatewayAssociationConfig_multiVgws(acctest.RandString(5), randIntRange(64512, 65534)), + Config: testAccDxGatewayAssociationConfig_multiVgws(rName1, rName2, rBgpAsn), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsDxGatewayAssociationExists("aws_dx_gateway_association.test1"), - testAccCheckAwsDxGatewayAssociationExists("aws_dx_gateway_association.test2"), + testAccCheckAwsDxGatewayAssociationExists(resourceName1), + testAccCheckAwsDxGatewayAssociationExists(resourceName2), ), }, }, @@ -156,10 +183,13 @@ func testAccCheckAwsDxGatewayAssociationDestroy(s *terraform.State) error { func testAccCheckAwsDxGatewayAssociationExists(name string) resource.TestCheckFunc { return func(s *terraform.State) error { - _, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[name] if !ok { return fmt.Errorf("Not found: %s", name) } + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } return nil } @@ -168,20 +198,20 @@ func testAccCheckAwsDxGatewayAssociationExists(name string) resource.TestCheckFu func testAccDxGatewayAssociationConfig(rName string, rBgpAsn int) string { return fmt.Sprintf(` resource "aws_dx_gateway" "test" { - name = "terraform-testacc-dxgwassoc-%s" - amazon_side_asn = "%d" + name = %[1]q + amazon_side_asn = "%[2]d" } resource "aws_vpc" "test" { cidr_block = "10.255.255.0/28" tags = { - Name = "terraform-testacc-dxgwassoc-%s" + Name = %[1]q } } resource "aws_vpn_gateway" "test" { tags = { - Name = "terraform-testacc-dxgwassoc-%s" + Name = %[1]q } } @@ -194,26 +224,26 @@ resource "aws_dx_gateway_association" "test" { dx_gateway_id = "${aws_dx_gateway.test.id}" vpn_gateway_id = "${aws_vpn_gateway_attachment.test.vpn_gateway_id}" } -`, rName, rBgpAsn, rName, rName) +`, rName, rBgpAsn) } -func testAccDxGatewayAssociationConfig_multiVgws(rName string, rBgpAsn int) string { +func testAccDxGatewayAssociationConfig_multiVgws(rName1, rName2 string, rBgpAsn int) string { return fmt.Sprintf(` resource "aws_dx_gateway" "test" { - name = "terraform-testacc-dxgwassoc-%s" - amazon_side_asn = "%d" + name = %[1]q + amazon_side_asn = "%[3]d" } resource "aws_vpc" "test1" { cidr_block = "10.255.255.16/28" tags = { - Name = "terraform-testacc-dxgwassoc-%s-1" + Name = %[1]q } } resource "aws_vpn_gateway" "test1" { tags = { - Name = "terraform-testacc-dxgwassoc-%s-1" + Name = %[1]q } } @@ -230,13 +260,13 @@ resource "aws_dx_gateway_association" "test1" { resource "aws_vpc" "test2" { cidr_block = "10.255.255.32/28" tags = { - Name = "terraform-testacc-dxgwassoc-%s-2" + Name = %[2]q } } resource "aws_vpn_gateway" "test2" { tags = { - Name = "terraform-testacc-dxgwassoc-%s-2" + Name = %[2]q } } @@ -249,5 +279,5 @@ resource "aws_dx_gateway_association" "test2" { dx_gateway_id = "${aws_dx_gateway.test.id}" vpn_gateway_id = "${aws_vpn_gateway_attachment.test2.vpn_gateway_id}" } -`, rName, rBgpAsn, rName, rName, rName, rName) +`, rName1, rName2, rBgpAsn) } diff --git a/aws/resource_aws_dx_gateway_test.go b/aws/resource_aws_dx_gateway_test.go index 43c1512d221..68a61704871 100644 --- a/aws/resource_aws_dx_gateway_test.go +++ b/aws/resource_aws_dx_gateway_test.go @@ -111,13 +111,17 @@ func TestAccAwsDxGateway_importComplex(t *testing.T) { return nil } + rName1 := fmt.Sprintf("terraform-testacc-dxgwassoc-%d", acctest.RandInt()) + rName2 := fmt.Sprintf("terraform-testacc-dxgwassoc-%d", acctest.RandInt()) + rBgpAsn := randIntRange(64512, 65534) + resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckAwsDxGatewayDestroy, Steps: []resource.TestStep{ { - Config: testAccDxGatewayAssociationConfig_multiVgws(acctest.RandString(5), randIntRange(64512, 65534)), + Config: testAccDxGatewayAssociationConfig_multiVgws(rName1, rName2, rBgpAsn), }, { diff --git a/aws/resource_aws_dx_hosted_public_virtual_interface.go b/aws/resource_aws_dx_hosted_public_virtual_interface.go index c62781ebde9..d69a72f932f 100644 --- a/aws/resource_aws_dx_hosted_public_virtual_interface.go +++ b/aws/resource_aws_dx_hosted_public_virtual_interface.go @@ -132,7 +132,7 @@ func resourceAwsDxHostedPublicVirtualInterfaceCreate(d *schema.ResourceData, met req.NewPublicVirtualInterfaceAllocation.AmazonAddress = aws.String(aaRaw.(string)) } if v, ok := d.GetOk("route_filter_prefixes"); ok { - req.NewPublicVirtualInterfaceAllocation.RouteFilterPrefixes = expandDxRouteFilterPrefixes(v.(*schema.Set).List()) + req.NewPublicVirtualInterfaceAllocation.RouteFilterPrefixes = expandDxRouteFilterPrefixes(v.(*schema.Set)) } log.Printf("[DEBUG] Allocating Direct Connect hosted public virtual interface: %#v", req) diff --git a/aws/resource_aws_dx_public_virtual_interface.go b/aws/resource_aws_dx_public_virtual_interface.go index bbf72ed990a..fc8405dd6fc 100644 --- a/aws/resource_aws_dx_public_virtual_interface.go +++ b/aws/resource_aws_dx_public_virtual_interface.go @@ -116,7 +116,7 @@ func resourceAwsDxPublicVirtualInterfaceCreate(d *schema.ResourceData, meta inte req.NewPublicVirtualInterface.AmazonAddress = aws.String(v.(string)) } if v, ok := d.GetOk("route_filter_prefixes"); ok { - req.NewPublicVirtualInterface.RouteFilterPrefixes = expandDxRouteFilterPrefixes(v.(*schema.Set).List()) + req.NewPublicVirtualInterface.RouteFilterPrefixes = expandDxRouteFilterPrefixes(v.(*schema.Set)) } log.Printf("[DEBUG] Creating Direct Connect public virtual interface: %#v", req) diff --git a/aws/structure.go b/aws/structure.go index ffc0799e8a3..2b9b38e730c 100644 --- a/aws/structure.go +++ b/aws/structure.go @@ -4642,23 +4642,26 @@ func expandVpcPeeringConnectionOptions(m map[string]interface{}) *ec2.PeeringCon return options } -func expandDxRouteFilterPrefixes(cfg []interface{}) []*directconnect.RouteFilterPrefix { - prefixes := make([]*directconnect.RouteFilterPrefix, len(cfg)) - for i, p := range cfg { - prefix := &directconnect.RouteFilterPrefix{ - Cidr: aws.String(p.(string)), - } - prefixes[i] = prefix +func expandDxRouteFilterPrefixes(vPrefixes *schema.Set) []*directconnect.RouteFilterPrefix { + routeFilterPrefixes := []*directconnect.RouteFilterPrefix{} + + for _, vPrefix := range vPrefixes.List() { + routeFilterPrefixes = append(routeFilterPrefixes, &directconnect.RouteFilterPrefix{ + Cidr: aws.String(vPrefix.(string)), + }) } - return prefixes + + return routeFilterPrefixes } -func flattenDxRouteFilterPrefixes(prefixes []*directconnect.RouteFilterPrefix) *schema.Set { - out := make([]interface{}, 0) - for _, prefix := range prefixes { - out = append(out, aws.StringValue(prefix.Cidr)) +func flattenDxRouteFilterPrefixes(routeFilterPrefixes []*directconnect.RouteFilterPrefix) *schema.Set { + vPrefixes := []interface{}{} + + for _, routeFilterPrefix := range routeFilterPrefixes { + vPrefixes = append(vPrefixes, aws.StringValue(routeFilterPrefix.Cidr)) } - return schema.NewSet(schema.HashString, out) + + return schema.NewSet(schema.HashString, vPrefixes) } func expandMacieClassificationType(d *schema.ResourceData) *macie.ClassificationType { diff --git a/website/docs/r/dx_bgp_peer.html.markdown b/website/docs/r/dx_bgp_peer.html.markdown index cb0c5444965..97ef08f3709 100644 --- a/website/docs/r/dx_bgp_peer.html.markdown +++ b/website/docs/r/dx_bgp_peer.html.markdown @@ -37,7 +37,7 @@ Required for IPv4 BGP peers on public virtual interfaces. In addition to all arguments above, the following attributes are exported: -* `id` - The ID of the BGP peer. +* `id` - The ID of the BGP peer resource. * `bgp_status` - The Up/Down state of the BGP peer. * `bgp_peer_id` - The ID of the BGP peer. * `aws_device` - The Direct Connect endpoint on which the BGP peer terminates. diff --git a/website/docs/r/dx_gateway_association.html.markdown b/website/docs/r/dx_gateway_association.html.markdown index adfee793565..21003f9060a 100644 --- a/website/docs/r/dx_gateway_association.html.markdown +++ b/website/docs/r/dx_gateway_association.html.markdown @@ -12,6 +12,8 @@ Associates a Direct Connect Gateway with a VGW. ## Example Usage +### Basic + ```hcl resource "aws_dx_gateway" "example" { name = "example" @@ -32,12 +34,47 @@ resource "aws_dx_gateway_association" "example" { } ``` +### Allowed Prefixes + +```hcl +resource "aws_dx_gateway" "example" { + name = "example" + amazon_side_asn = "64512" +} + +resource "aws_vpc" "example" { + cidr_block = "10.255.255.0/28" +} + +resource "aws_vpn_gateway" "example" { + vpc_id = "${aws_vpc.test.id}" +} + +resource "aws_dx_gateway_association" "example" { + dx_gateway_id = "${aws_dx_gateway.example.id}" + vpn_gateway_id = "${aws_vpn_gateway.example.id}" + + allowed_prefixes = [ + "210.52.109.0/24", + "175.45.176.0/22", + ] +} +``` + ## Argument Reference The following arguments are supported: -* `dx_gateway_id` - (Required) The ID of the Direct Connect Gateway. +* `dx_gateway_id` - (Required) The ID of the Direct Connect gateway. * `vpn_gateway_id` - (Required) The ID of the VGW with which to associate the gateway. +* `allowed_prefixes` - (Optional) The Amazon VPC prefixes to advertise to the Direct Connect gateway. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The ID of the Direct Connect gateway association resource. +* `dx_gateway_association_id` - The ID of the Direct Connect gateway association. ## Timeouts @@ -45,4 +82,14 @@ The following arguments are supported: [Timeouts](/docs/configuration/resources.html#timeouts) configuration options: - `create` - (Default `15 minutes`) Used for creating the association +- `update` - (Default `10 minutes`) Used for updating the association - `delete` - (Default `10 minutes`) Used for destroying the association + +## Import + +Direct Connect gateway associations can be imported using `dx_gateway_id` together with `vpn_gateway_id`, +e.g. + +``` +$ terraform import aws_dx_gateway_association.example dxgw-12345678/vgw-98765432 +``` From c1021a3ca6e952ff91ead5ca1b02cae4e3e123af Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 19 Apr 2019 14:46:36 -0400 Subject: [PATCH 2/2] Add Direct Connect gateway association allow prefix acceptance tests. --- aws/resource_aws_dx_gateway_association.go | 5 +- ...esource_aws_dx_gateway_association_test.go | 120 +++++++++++++++++- .../r/dx_gateway_association.html.markdown | 2 +- 3 files changed, 122 insertions(+), 5 deletions(-) diff --git a/aws/resource_aws_dx_gateway_association.go b/aws/resource_aws_dx_gateway_association.go index 4c7d83f5391..36fa5f4b3e6 100644 --- a/aws/resource_aws_dx_gateway_association.go +++ b/aws/resource_aws_dx_gateway_association.go @@ -30,6 +30,7 @@ func resourceAwsDxGatewayAssociation() *schema.Resource { "allowed_prefixes": { Type: schema.TypeSet, Optional: true, + Computed: true, Elem: &schema.Schema{Type: schema.TypeString}, }, @@ -54,7 +55,7 @@ func resourceAwsDxGatewayAssociation() *schema.Resource { Timeouts: &schema.ResourceTimeout{ Create: schema.DefaultTimeout(15 * time.Minute), Update: schema.DefaultTimeout(10 * time.Minute), - Delete: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(15 * time.Minute), }, } } @@ -91,7 +92,7 @@ func resourceAwsDxGatewayAssociationCreate(d *schema.ResourceData, meta interfac 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 { diff --git a/aws/resource_aws_dx_gateway_association_test.go b/aws/resource_aws_dx_gateway_association_test.go index cdec456813c..9d9af3e6b81 100644 --- a/aws/resource_aws_dx_gateway_association_test.go +++ b/aws/resource_aws_dx_gateway_association_test.go @@ -114,11 +114,14 @@ func TestAccAwsDxGatewayAssociation_basic(t *testing.T) { CheckDestroy: testAccCheckAwsDxGatewayAssociationDestroy, Steps: []resource.TestStep{ { - Config: testAccDxGatewayAssociationConfig(rName, rBgpAsn), + Config: testAccDxGatewayAssociationConfig_basic(rName, rBgpAsn), Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxGatewayAssociationExists(resourceName), resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), resource.TestCheckResourceAttrPair(resourceName, "vpn_gateway_id", resourceNameVgw, "id"), + resource.TestCheckResourceAttrSet(resourceName, "dx_gateway_association_id"), + resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.#", "1"), + resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.1216997074", "10.255.255.0/28"), ), }, { @@ -155,6 +158,48 @@ func TestAccAwsDxGatewayAssociation_multiVgws(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxGatewayAssociationExists(resourceName1), testAccCheckAwsDxGatewayAssociationExists(resourceName2), + resource.TestCheckResourceAttrSet(resourceName1, "dx_gateway_association_id"), + resource.TestCheckResourceAttr(resourceName1, "allowed_prefixes.#", "1"), + resource.TestCheckResourceAttr(resourceName1, "allowed_prefixes.704201654", "10.255.255.16/28"), + resource.TestCheckResourceAttrSet(resourceName2, "dx_gateway_association_id"), + resource.TestCheckResourceAttr(resourceName2, "allowed_prefixes.#", "1"), + resource.TestCheckResourceAttr(resourceName2, "allowed_prefixes.2444313725", "10.255.255.32/28"), + ), + }, + }, + }) +} + +func TestAccAwsDxGatewayAssociation_allowedPrefixes(t *testing.T) { + resourceName := "aws_dx_gateway_association.test" + resourceNameDxGw := "aws_dx_gateway.test" + resourceNameVgw := "aws_vpn_gateway.test" + rName := fmt.Sprintf("terraform-testacc-dxgwassoc-%d", acctest.RandInt()) + rBgpAsn := randIntRange(64512, 65534) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsDxGatewayAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDxGatewayAssociationConfig_allowedPrefixes(rName, rBgpAsn), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsDxGatewayAssociationExists(resourceName), + resource.TestCheckResourceAttrPair(resourceName, "dx_gateway_id", resourceNameDxGw, "id"), + resource.TestCheckResourceAttrPair(resourceName, "vpn_gateway_id", resourceNameVgw, "id"), + resource.TestCheckResourceAttrSet(resourceName, "dx_gateway_association_id"), + resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.#", "2"), + resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.2173830893", "10.255.255.0/30"), + resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.2984398124", "10.255.255.8/30"), + ), + }, + { + Config: testAccDxGatewayAssociationConfig_allowedPrefixesUpdated(rName, rBgpAsn), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsDxGatewayAssociationExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.#", "1"), + resource.TestCheckResourceAttr(resourceName, "allowed_prefixes.1642241106", "10.255.255.8/29"), ), }, }, @@ -195,7 +240,7 @@ func testAccCheckAwsDxGatewayAssociationExists(name string) resource.TestCheckFu } } -func testAccDxGatewayAssociationConfig(rName string, rBgpAsn int) string { +func testAccDxGatewayAssociationConfig_basic(rName string, rBgpAsn int) string { return fmt.Sprintf(` resource "aws_dx_gateway" "test" { name = %[1]q @@ -281,3 +326,74 @@ resource "aws_dx_gateway_association" "test2" { } `, rName1, rName2, rBgpAsn) } + +func testAccDxGatewayAssociationConfig_allowedPrefixes(rName string, rBgpAsn int) string { + return fmt.Sprintf(` +resource "aws_dx_gateway" "test" { + name = %[1]q + amazon_side_asn = "%[2]d" +} + +resource "aws_vpc" "test" { + cidr_block = "10.255.255.0/28" + tags = { + Name = %[1]q + } +} + +resource "aws_vpn_gateway" "test" { + tags = { + Name = %[1]q + } +} + +resource "aws_vpn_gateway_attachment" "test" { + vpc_id = "${aws_vpc.test.id}" + vpn_gateway_id = "${aws_vpn_gateway.test.id}" +} + +resource "aws_dx_gateway_association" "test" { + dx_gateway_id = "${aws_dx_gateway.test.id}" + vpn_gateway_id = "${aws_vpn_gateway_attachment.test.vpn_gateway_id}" + allowed_prefixes = [ + "10.255.255.0/30", + "10.255.255.8/30", + ] +} +`, rName, rBgpAsn) +} + +func testAccDxGatewayAssociationConfig_allowedPrefixesUpdated(rName string, rBgpAsn int) string { + return fmt.Sprintf(` +resource "aws_dx_gateway" "test" { + name = %[1]q + amazon_side_asn = "%[2]d" +} + +resource "aws_vpc" "test" { + cidr_block = "10.255.255.0/28" + tags = { + Name = %[1]q + } +} + +resource "aws_vpn_gateway" "test" { + tags = { + Name = %[1]q + } +} + +resource "aws_vpn_gateway_attachment" "test" { + vpc_id = "${aws_vpc.test.id}" + vpn_gateway_id = "${aws_vpn_gateway.test.id}" +} + +resource "aws_dx_gateway_association" "test" { + dx_gateway_id = "${aws_dx_gateway.test.id}" + vpn_gateway_id = "${aws_vpn_gateway_attachment.test.vpn_gateway_id}" + allowed_prefixes = [ + "10.255.255.8/29", + ] +} +`, rName, rBgpAsn) +} diff --git a/website/docs/r/dx_gateway_association.html.markdown b/website/docs/r/dx_gateway_association.html.markdown index 21003f9060a..97c6c2eb46c 100644 --- a/website/docs/r/dx_gateway_association.html.markdown +++ b/website/docs/r/dx_gateway_association.html.markdown @@ -83,7 +83,7 @@ In addition to all arguments above, the following attributes are exported: - `create` - (Default `15 minutes`) Used for creating the association - `update` - (Default `10 minutes`) Used for updating the association -- `delete` - (Default `10 minutes`) Used for destroying the association +- `delete` - (Default `15 minutes`) Used for destroying the association ## Import