From 26d9069a4a6a6f4eab28458f77b95567a2169586 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 3 May 2019 16:23:16 -0400 Subject: [PATCH 01/12] Add 'aws_dx_hosted_transit_virtual_interface' and 'aws_dx_hosted_transit_virtual_interface_accepter' resources. --- aws/provider.go | 2 + ...aws_dx_hosted_transit_virtual_interface.go | 214 ++++++++++++++++++ ...sted_transit_virtual_interface_accepter.go | 148 ++++++++++++ ...x_hosted_transit_virtual_interface_test.go | 173 ++++++++++++++ website/aws.erb | 6 + ...ed_transit_virtual_interface.html.markdown | 67 ++++++ ...t_virtual_interface_accepter.html.markdown | 102 +++++++++ 7 files changed, 712 insertions(+) create mode 100644 aws/resource_aws_dx_hosted_transit_virtual_interface.go create mode 100644 aws/resource_aws_dx_hosted_transit_virtual_interface_accepter.go create mode 100644 aws/resource_aws_dx_hosted_transit_virtual_interface_test.go create mode 100644 website/docs/r/dx_hosted_transit_virtual_interface.html.markdown create mode 100644 website/docs/r/dx_hosted_transit_virtual_interface_accepter.html.markdown diff --git a/aws/provider.go b/aws/provider.go index 0655be2d4c6..53cd84c4412 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -445,6 +445,8 @@ func Provider() terraform.ResourceProvider { "aws_dx_hosted_private_virtual_interface_accepter": resourceAwsDxHostedPrivateVirtualInterfaceAccepter(), "aws_dx_hosted_public_virtual_interface": resourceAwsDxHostedPublicVirtualInterface(), "aws_dx_hosted_public_virtual_interface_accepter": resourceAwsDxHostedPublicVirtualInterfaceAccepter(), + "aws_dx_hosted_transit_virtual_interface": resourceAwsDxHostedTransitVirtualInterface(), + "aws_dx_hosted_transit_virtual_interface_accepter": resourceAwsDxHostedTransitVirtualInterfaceAccepter(), "aws_dx_lag": resourceAwsDxLag(), "aws_dx_private_virtual_interface": resourceAwsDxPrivateVirtualInterface(), "aws_dx_public_virtual_interface": resourceAwsDxPublicVirtualInterface(), diff --git a/aws/resource_aws_dx_hosted_transit_virtual_interface.go b/aws/resource_aws_dx_hosted_transit_virtual_interface.go new file mode 100644 index 00000000000..d70435cee55 --- /dev/null +++ b/aws/resource_aws_dx_hosted_transit_virtual_interface.go @@ -0,0 +1,214 @@ +package aws + +import ( + "fmt" + "log" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go/service/directconnect" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" +) + +func resourceAwsDxHostedTransitVirtualInterface() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsDxHostedTransitVirtualInterfaceCreate, + Read: resourceAwsDxHostedTransitVirtualInterfaceRead, + Delete: resourceAwsDxHostedTransitVirtualInterfaceDelete, + Importer: &schema.ResourceImporter{ + State: resourceAwsDxHostedTransitVirtualInterfaceImport, + }, + + Schema: map[string]*schema.Schema{ + "address_family": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + directconnect.AddressFamilyIpv4, + directconnect.AddressFamilyIpv6, + }, false), + }, + "amazon_address": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "aws_device": { + Type: schema.TypeString, + Computed: true, + }, + "bgp_asn": { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + }, + "bgp_auth_key": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "connection_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "customer_address": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + }, + "jumbo_frame_capable": { + Type: schema.TypeBool, + Computed: true, + }, + "mtu": { + Type: schema.TypeInt, + Default: 1500, + Optional: true, + ForceNew: true, + ValidateFunc: validation.IntInSlice([]int{1500, 8500}), + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "owner_account_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateAwsAccountId, + }, + "vlan": { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + ValidateFunc: validation.IntBetween(1, 4094), + }, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Update: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + } +} + +func resourceAwsDxHostedTransitVirtualInterfaceCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).dxconn + + req := &directconnect.AllocateTransitVirtualInterfaceInput{ + ConnectionId: aws.String(d.Get("connection_id").(string)), + OwnerAccount: aws.String(d.Get("owner_account_id").(string)), + NewTransitVirtualInterfaceAllocation: &directconnect.NewTransitVirtualInterfaceAllocation{ + AddressFamily: aws.String(d.Get("address_family").(string)), + Asn: aws.Int64(int64(d.Get("bgp_asn").(int))), + Mtu: aws.Int64(int64(d.Get("mtu").(int))), + VirtualInterfaceName: aws.String(d.Get("name").(string)), + Vlan: aws.Int64(int64(d.Get("vlan").(int))), + }, + } + if v, ok := d.GetOk("amazon_address"); ok && v.(string) != "" { + req.NewTransitVirtualInterfaceAllocation.AmazonAddress = aws.String(v.(string)) + } + if v, ok := d.GetOk("bgp_auth_key"); ok && v.(string) != "" { + req.NewTransitVirtualInterfaceAllocation.AuthKey = aws.String(v.(string)) + } + if v, ok := d.GetOk("customer_address"); ok && v.(string) != "" { + req.NewTransitVirtualInterfaceAllocation.CustomerAddress = aws.String(v.(string)) + } + + log.Printf("[DEBUG] Creating Direct Connect hosted transit virtual interface: %#v", req) + resp, err := conn.AllocateTransitVirtualInterface(req) + if err != nil { + return fmt.Errorf("error creating Direct Connect hosted transit virtual interface: %s", err) + } + + d.SetId(aws.StringValue(resp.VirtualInterface.VirtualInterfaceId)) + arn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Region: meta.(*AWSClient).region, + Service: "directconnect", + AccountID: meta.(*AWSClient).accountid, + Resource: fmt.Sprintf("dxvif/%s", d.Id()), + }.String() + d.Set("arn", arn) + + if err := dxHostedTransitVirtualInterfaceWaitUntilAvailable(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return err + } + + return resourceAwsDxHostedTransitVirtualInterfaceRead(d, meta) +} + +func resourceAwsDxHostedTransitVirtualInterfaceRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).dxconn + + vif, err := dxVirtualInterfaceRead(d.Id(), conn) + if err != nil { + return err + } + if vif == nil { + log.Printf("[WARN] Direct Connect hosted transit virtual interface (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + d.Set("address_family", vif.AddressFamily) + d.Set("amazon_address", vif.AmazonAddress) + d.Set("aws_device", vif.AwsDeviceV2) + d.Set("bgp_asn", vif.Asn) + d.Set("bgp_auth_key", vif.AuthKey) + d.Set("connection_id", vif.ConnectionId) + d.Set("customer_address", vif.CustomerAddress) + d.Set("jumbo_frame_capable", vif.JumboFrameCapable) + d.Set("mtu", vif.Mtu) + d.Set("name", vif.VirtualInterfaceName) + d.Set("owner_account_id", vif.OwnerAccount) + d.Set("vlan", vif.Vlan) + + return nil +} + +func resourceAwsDxHostedTransitVirtualInterfaceDelete(d *schema.ResourceData, meta interface{}) error { + return dxVirtualInterfaceDelete(d, meta) +} + +func resourceAwsDxHostedTransitVirtualInterfaceImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + arn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Region: meta.(*AWSClient).region, + Service: "directconnect", + AccountID: meta.(*AWSClient).accountid, + Resource: fmt.Sprintf("dxvif/%s", d.Id()), + }.String() + d.Set("arn", arn) + + return []*schema.ResourceData{d}, nil +} + +func dxHostedTransitVirtualInterfaceWaitUntilAvailable(conn *directconnect.DirectConnect, vifId string, timeout time.Duration) error { + return dxVirtualInterfaceWaitUntilAvailable( + conn, + vifId, + timeout, + []string{ + directconnect.VirtualInterfaceStatePending, + }, + []string{ + directconnect.VirtualInterfaceStateAvailable, + directconnect.VirtualInterfaceStateConfirming, + directconnect.VirtualInterfaceStateDown, + }) +} diff --git a/aws/resource_aws_dx_hosted_transit_virtual_interface_accepter.go b/aws/resource_aws_dx_hosted_transit_virtual_interface_accepter.go new file mode 100644 index 00000000000..89f980b40ee --- /dev/null +++ b/aws/resource_aws_dx_hosted_transit_virtual_interface_accepter.go @@ -0,0 +1,148 @@ +package aws + +import ( + "fmt" + "log" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go/service/directconnect" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsDxHostedTransitVirtualInterfaceAccepter() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsDxHostedTransitVirtualInterfaceAccepterCreate, + Read: resourceAwsDxHostedTransitVirtualInterfaceAccepterRead, + Update: resourceAwsDxHostedTransitVirtualInterfaceAccepterUpdate, + Delete: resourceAwsDxHostedTransitVirtualInterfaceAccepterDelete, + Importer: &schema.ResourceImporter{ + State: resourceAwsDxHostedTransitVirtualInterfaceAccepterImport, + }, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "dx_gateway_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "tags": tagsSchema(), + "virtual_interface_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + + Timeouts: &schema.ResourceTimeout{ + Create: schema.DefaultTimeout(10 * time.Minute), + Delete: schema.DefaultTimeout(10 * time.Minute), + }, + } +} + +func resourceAwsDxHostedTransitVirtualInterfaceAccepterCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).dxconn + + vifId := d.Get("virtual_interface_id").(string) + req := &directconnect.ConfirmTransitVirtualInterfaceInput{ + DirectConnectGatewayId: aws.String(d.Get("dx_gateway_id").(string)), + VirtualInterfaceId: aws.String(vifId), + } + + log.Printf("[DEBUG] Accepting Direct Connect hosted transit virtual interface: %#v", req) + _, err := conn.ConfirmTransitVirtualInterface(req) + if err != nil { + return fmt.Errorf("error accepting Direct Connect hosted transit virtual interface (%s): %s", vifId, err) + } + + d.SetId(vifId) + arn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Region: meta.(*AWSClient).region, + Service: "directconnect", + AccountID: meta.(*AWSClient).accountid, + Resource: fmt.Sprintf("dxvif/%s", d.Id()), + }.String() + d.Set("arn", arn) + + if err := dxHostedTransitVirtualInterfaceAccepterWaitUntilAvailable(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return err + } + + return resourceAwsDxHostedTransitVirtualInterfaceAccepterUpdate(d, meta) +} + +func resourceAwsDxHostedTransitVirtualInterfaceAccepterRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).dxconn + + vif, err := dxVirtualInterfaceRead(d.Id(), conn) + if err != nil { + return err + } + if vif == nil { + log.Printf("[WARN] Direct Connect transit virtual interface (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + vifState := aws.StringValue(vif.VirtualInterfaceState) + if vifState != directconnect.VirtualInterfaceStateAvailable && vifState != directconnect.VirtualInterfaceStateDown { + log.Printf("[WARN] Direct Connect virtual interface (%s) is '%s', removing from state", vifState, d.Id()) + d.SetId("") + return nil + } + + d.Set("dx_gateway_id", vif.DirectConnectGatewayId) + d.Set("virtual_interface_id", vif.VirtualInterfaceId) + if err := getTagsDX(conn, d, d.Get("arn").(string)); err != nil { + return fmt.Errorf("error getting Direct Connect transit virtual interface (%s) tags: %s", d.Id(), err) + } + + return nil +} + +func resourceAwsDxHostedTransitVirtualInterfaceAccepterUpdate(d *schema.ResourceData, meta interface{}) error { + if err := dxVirtualInterfaceUpdate(d, meta); err != nil { + return err + } + + return resourceAwsDxHostedTransitVirtualInterfaceAccepterRead(d, meta) +} + +func resourceAwsDxHostedTransitVirtualInterfaceAccepterDelete(d *schema.ResourceData, meta interface{}) error { + log.Printf("[WARN] Will not delete Direct Connect virtual interface. Terraform will remove this resource from the state file, however resources may remain.") + return nil +} + +func resourceAwsDxHostedTransitVirtualInterfaceAccepterImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + arn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Region: meta.(*AWSClient).region, + Service: "directconnect", + AccountID: meta.(*AWSClient).accountid, + Resource: fmt.Sprintf("dxvif/%s", d.Id()), + }.String() + d.Set("arn", arn) + + return []*schema.ResourceData{d}, nil +} + +func dxHostedTransitVirtualInterfaceAccepterWaitUntilAvailable(conn *directconnect.DirectConnect, vifId string, timeout time.Duration) error { + return dxVirtualInterfaceWaitUntilAvailable( + conn, + vifId, + timeout, + []string{ + directconnect.VirtualInterfaceStateConfirming, + directconnect.VirtualInterfaceStatePending, + }, + []string{ + directconnect.VirtualInterfaceStateAvailable, + directconnect.VirtualInterfaceStateDown, + }) +} diff --git a/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go b/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go new file mode 100644 index 00000000000..a6a5638da00 --- /dev/null +++ b/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go @@ -0,0 +1,173 @@ +package aws + +import ( + "fmt" + "os" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/directconnect" + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccAwsDxHostedTransitVirtualInterface_basic(t *testing.T) { + key := "DX_CONNECTION_ID" + connectionId := os.Getenv(key) + if connectionId == "" { + t.Skipf("Environment variable %s is not set", key) + } + + var providers []*schema.Provider + resourceNameHostedVif := "aws_dx_hosted_transit_virtual_interface.test" + resourceNameHostedVifAccepter := "aws_dx_hosted_transit_virtual_interface_accepter.test" + rName := fmt.Sprintf("tf-testacc-transit-vif-%s", acctest.RandString(9)) + amzAsn := randIntRange(64512, 65534) + bgpAsn := randIntRange(64512, 65534) + vlan := randIntRange(2049, 4094) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccAlternateAccountPreCheck(t) + }, + ProviderFactories: testAccProviderFactories(&providers), + CheckDestroy: testAccCheckAwsDxHostedTransitVirtualInterfaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDxHostedTransitVirtualInterfaceConfig_basic(connectionId, rName, amzAsn, bgpAsn, vlan), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsDxHostedTransitVirtualInterfaceExists(resourceNameHostedVif), + testAccCheckAwsDxHostedTransitVirtualInterfaceAccepterExists(resourceNameHostedVifAccepter), + resource.TestCheckResourceAttr(resourceNameHostedVif, "name", rName), + resource.TestCheckResourceAttr(resourceNameHostedVif, "mtu", "1500"), + resource.TestCheckResourceAttr(resourceNameHostedVif, "jumbo_frame_capable", "true"), + resource.TestCheckResourceAttr(resourceNameHostedVifAccepter, "tags.%", "0"), + ), + }, + { + Config: testAccDxHostedTransitVirtualInterfaceConfig_updated(connectionId, rName, amzAsn, bgpAsn, vlan), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsDxHostedTransitVirtualInterfaceExists(resourceNameHostedVif), + testAccCheckAwsDxHostedTransitVirtualInterfaceAccepterExists(resourceNameHostedVifAccepter), + resource.TestCheckResourceAttr(resourceNameHostedVif, "name", rName), + resource.TestCheckResourceAttr(resourceNameHostedVifAccepter, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceNameHostedVifAccepter, "tags.Environment", "test"), + ), + }, + // Test import. + { + Config: testAccDxHostedTransitVirtualInterfaceConfig_updated(connectionId, rName, amzAsn, bgpAsn, vlan), + ResourceName: resourceNameHostedVif, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckAwsDxHostedTransitVirtualInterfaceDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).dxconn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_dx_hosted_transit_virtual_interface" { + continue + } + + input := &directconnect.DescribeVirtualInterfacesInput{ + VirtualInterfaceId: aws.String(rs.Primary.ID), + } + + resp, err := conn.DescribeVirtualInterfaces(input) + if err != nil { + return err + } + for _, v := range resp.VirtualInterfaces { + if *v.VirtualInterfaceId == rs.Primary.ID && !(*v.VirtualInterfaceState == directconnect.VirtualInterfaceStateDeleted) { + return fmt.Errorf("[DESTROY ERROR] Dx Private VIF (%s) not deleted", rs.Primary.ID) + } + } + } + return nil +} + +func testAccCheckAwsDxHostedTransitVirtualInterfaceExists(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + _, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + + return nil + } +} + +func testAccCheckAwsDxHostedTransitVirtualInterfaceAccepterExists(name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + _, ok := s.RootModule().Resources[name] + if !ok { + return fmt.Errorf("Not found: %s", name) + } + + return nil + } +} + +func testAccDxHostedTransitVirtualInterfaceConfig_base(cid, rName string, amzAsn, bgpAsn, vlan int) string { + return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` +# Creator +resource "aws_dx_hosted_transit_virtual_interface" "test" { + connection_id = %[1]q + owner_account_id = "${data.aws_caller_identity.accepter.account_id}" + + name = %[2]q + vlan = %[5]d + address_family = "ipv4" + bgp_asn = %[4]d + + # The aws_dx_hosted_transit_virtual_interface + # must be destroyed before the aws_dx_gateway. + depends_on = ["aws_dx_gateway.test"] +} + +# Accepter +data "aws_caller_identity" "accepter" { + provider = "aws.alternate" +} + +resource "aws_dx_gateway" "test" { + provider = "aws.alternate" + + name = %[2]q + amazon_side_asn = %[3]d +} +`, cid, rName, amzAsn, bgpAsn, vlan) +} + +func testAccDxHostedTransitVirtualInterfaceConfig_basic(cid, rName string, amzAsn, bgpAsn, vlan int) string { + return testAccDxHostedTransitVirtualInterfaceConfig_base(cid, rName, amzAsn, bgpAsn, vlan) + fmt.Sprintf(` +resource "aws_dx_hosted_transit_virtual_interface_accepter" "test" { + provider = "aws.alternate" + + virtual_interface_id = "${aws_dx_hosted_transit_virtual_interface.test.id}" + dx_gateway_id = "${aws_dx_gateway.test.id}" +} +`) +} + +func testAccDxHostedTransitVirtualInterfaceConfig_updated(cid, rName string, amzAsn, bgpAsn, vlan int) string { + return testAccDxHostedTransitVirtualInterfaceConfig_base(cid, rName, amzAsn, bgpAsn, vlan) + fmt.Sprintf(` +resource "aws_dx_hosted_transit_virtual_interface_accepter" "test" { + provider = "aws.alternate" + + virtual_interface_id = "${aws_dx_hosted_transit_virtual_interface.test.id}" + dx_gateway_id = "${aws_dx_gateway.test.id}" + + tags = { + Environment = "test" + } +} +`) +} diff --git a/website/aws.erb b/website/aws.erb index 8b880c6a1b0..3b0fb8e0bbd 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -876,6 +876,12 @@
  • aws_dx_hosted_public_virtual_interface_accepter
  • +
  • + aws_dx_hosted_transit_virtual_interface +
  • +
  • + aws_dx_hosted_transit_virtual_interface_accepter +
  • aws_dx_lag
  • diff --git a/website/docs/r/dx_hosted_transit_virtual_interface.html.markdown b/website/docs/r/dx_hosted_transit_virtual_interface.html.markdown new file mode 100644 index 00000000000..e017704bb06 --- /dev/null +++ b/website/docs/r/dx_hosted_transit_virtual_interface.html.markdown @@ -0,0 +1,67 @@ +--- +layout: "aws" +page_title: "AWS: aws_dx_hosted_transit_virtual_interface" +sidebar_current: "docs-aws-resource-dx-hosted-transit-virtual-interface" +description: |- + Provides a Direct Connect hosted transit virtual interface resource. +--- + +# Resource: aws_dx_hosted_transit_virtual_interface + +Provides a Direct Connect hosted transit virtual interface resource. +This resource represents the allocator's side of the hosted virtual interface. +A hosted virtual interface is a virtual interface that is owned by another AWS account. + +## Example Usage + +```hcl +resource "aws_dx_hosted_transit_virtual_interface" "example" { + connection_id = "dxcon-zzzzzzzz" + + name = "tf-transit-vif-example" + vlan = 4094 + address_family = "ipv4" + bgp_asn = 65352 +} +``` + +## Argument Reference + +The following arguments are supported: + +* `address_family` - (Required) The address family for the BGP peer. `ipv4 ` or `ipv6`. +* `bgp_asn` - (Required) The autonomous system (AS) number for Border Gateway Protocol (BGP) configuration. +* `connection_id` - (Required) The ID of the Direct Connect connection (or LAG) on which to create the virtual interface. +* `name` - (Required) The name for the virtual interface. +* `owner_account_id` - (Required) The AWS account that will own the new virtual interface. +* `vlan` - (Required) The VLAN ID. +* `amazon_address` - (Optional) The IPv4 CIDR address to use to send traffic to Amazon. Required for IPv4 BGP peers. +* `bgp_auth_key` - (Optional) The authentication key for BGP configuration. +* `customer_address` - (Optional) The IPv4 CIDR destination address to which Amazon should send traffic. Required for IPv4 BGP peers. +* `mtu` - (Optional) The maximum transmission unit (MTU) is the size, in bytes, of the largest permissible packet that can be passed over the connection. The MTU of a virtual transit interface can be either `1500` or `8500` (jumbo frames). Default is `1500`. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The ID of the virtual interface. +* `arn` - The ARN of the virtual interface. +* `aws_device` - The Direct Connect endpoint on which the virtual interface terminates. +* `jumbo_frame_capable` - Indicates whether jumbo frames (9001 MTU) are supported. + +## Timeouts + +`aws_dx_hosted_transit_virtual_interface` provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - (Default `10 minutes`) Used for creating virtual interface +- `update` - (Default `10 minutes`) Used for virtual interface modifications +- `delete` - (Default `10 minutes`) Used for destroying virtual interface + +## Import + +Direct Connect hosted transit virtual interfaces can be imported using the `vif id`, e.g. + +``` +$ terraform import aws_dx_hosted_transit_virtual_interface.test dxvif-33cc44dd +``` diff --git a/website/docs/r/dx_hosted_transit_virtual_interface_accepter.html.markdown b/website/docs/r/dx_hosted_transit_virtual_interface_accepter.html.markdown new file mode 100644 index 00000000000..9b6952680e6 --- /dev/null +++ b/website/docs/r/dx_hosted_transit_virtual_interface_accepter.html.markdown @@ -0,0 +1,102 @@ +--- +layout: "aws" +page_title: "AWS: aws_dx_hosted_transit_virtual_interface_accepter" +sidebar_current: "docs-aws-resource-dx-hosted-transit-virtual-interface-accepter" +description: |- + Provides a resource to manage the accepter's side of a Direct Connect hosted transit virtual interface. +--- + +# Resource: aws_dx_hosted_transit_virtual_interface_accepter + +Provides a resource to manage the accepter's side of a Direct Connect hosted transit virtual interface. +This resource accepts ownership of a transit virtual interface created by another AWS account. + +## Example Usage + +```hcl +provider "aws" { + # Creator's credentials. +} + +provider "aws" { + alias = "accepter" + + # Accepter's credentials. +} + +data "aws_caller_identity" "accepter" { + provider = "aws.accepter" +} + +# Creator's side of the VIF +resource "aws_dx_hosted_transit_virtual_interface" "creator" { + connection_id = "dxcon-zzzzzzzz" + owner_account_id = "${data.aws_caller_identity.accepter.account_id}" + + name = "tf-transit-vif-example" + vlan = 4094 + address_family = "ipv4" + bgp_asn = 65352 + + # The aws_dx_hosted_transit_virtual_interface + # must be destroyed before the aws_dx_gateway. + depends_on = ["aws_dx_gateway.example"] +} + +# Accepter's side of the VIF. +resource "aws_dx_gateway" "example" { + provider = "aws.accepter" + + name = "tf-dxg-example" + amazon_side_asn = 64512 +} + +resource "aws_dx_hosted_transit_virtual_interface_accepter" "accepter" { + provider = "aws.accepter" + virtual_interface_id = "${aws_dx_hosted_transit_virtual_interface.creator.id}" + dx_gateway_id = "${aws_dx_gateway.example.id}" + + tags = { + Side = "Accepter" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `dx_gateway_id` - (Required) The ID of the [Direct Connect gateway](dx_gateway.html) to which to connect the virtual interface. +* `virtual_interface_id` - (Required) The ID of the Direct Connect virtual interface to accept. +* `tags` - (Optional) A mapping of tags to assign to the resource. + +### Removing `aws_dx_hosted_transit_virtual_interface_accepter` from your configuration + +AWS allows a Direct Connect hosted transit virtual interface to be deleted from either the allocator's or accepter's side. +However, Terraform only allows the Direct Connect hosted transit virtual interface to be deleted from the allocator's side +by removing the corresponding `aws_dx_hosted_transit_virtual_interface` resource from your configuration. +Removing a `aws_dx_hosted_transit_virtual_interface_accepter` resource from your configuration will remove it +from your statefile and management, **but will not delete the Direct Connect virtual interface.** + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The ID of the virtual interface. +* `arn` - The ARN of the virtual interface. + +## Timeouts + +`aws_dx_hosted_transit_virtual_interface_accepter` provides the following +[Timeouts](/docs/configuration/resources.html#timeouts) configuration options: + +- `create` - (Default `10 minutes`) Used for creating virtual interface +- `delete` - (Default `10 minutes`) Used for destroying virtual interface + +## Import + +Direct Connect hosted transit virtual interfaces can be imported using the `vif id`, e.g. + +``` +$ terraform import aws_dx_hosted_transit_virtual_interface_accepter.test dxvif-33cc44dd +``` From 9041922429f7b2abf579cc3007bfa120d21b6323 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 7 May 2019 14:54:54 -0400 Subject: [PATCH 02/12] Documentation fix after review. --- .../docs/r/dx_hosted_transit_virtual_interface.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/dx_hosted_transit_virtual_interface.html.markdown b/website/docs/r/dx_hosted_transit_virtual_interface.html.markdown index e017704bb06..8269241a835 100644 --- a/website/docs/r/dx_hosted_transit_virtual_interface.html.markdown +++ b/website/docs/r/dx_hosted_transit_virtual_interface.html.markdown @@ -47,7 +47,7 @@ In addition to all arguments above, the following attributes are exported: * `id` - The ID of the virtual interface. * `arn` - The ARN of the virtual interface. * `aws_device` - The Direct Connect endpoint on which the virtual interface terminates. -* `jumbo_frame_capable` - Indicates whether jumbo frames (9001 MTU) are supported. +* `jumbo_frame_capable` - Indicates whether jumbo frames (8500 MTU) are supported. ## Timeouts From 97b730717cc1ccdda9d06f72afe55c585d9cd5a5 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 29 Jul 2019 14:21:06 -0400 Subject: [PATCH 03/12] Update website/docs/r/dx_hosted_transit_virtual_interface.html.markdown Co-Authored-By: Brian Flad --- .../docs/r/dx_hosted_transit_virtual_interface.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/dx_hosted_transit_virtual_interface.html.markdown b/website/docs/r/dx_hosted_transit_virtual_interface.html.markdown index 8269241a835..93fcfc98ef5 100644 --- a/website/docs/r/dx_hosted_transit_virtual_interface.html.markdown +++ b/website/docs/r/dx_hosted_transit_virtual_interface.html.markdown @@ -16,7 +16,7 @@ A hosted virtual interface is a virtual interface that is owned by another AWS a ```hcl resource "aws_dx_hosted_transit_virtual_interface" "example" { - connection_id = "dxcon-zzzzzzzz" + connection_id = "${aws_dx_connection.example.id}" name = "tf-transit-vif-example" vlan = 4094 From 96871b848d58485fc19b5b122c3aeb8f23aca088 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 29 Jul 2019 14:29:33 -0400 Subject: [PATCH 04/12] Code changes after review. --- ...x_hosted_transit_virtual_interface_test.go | 39 +++++++++++++++---- website/aws.erb | 6 --- ...t_virtual_interface_accepter.html.markdown | 10 +---- 3 files changed, 34 insertions(+), 21 deletions(-) diff --git a/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go b/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go index a6a5638da00..90d8d869ec5 100644 --- a/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go +++ b/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go @@ -75,30 +75,55 @@ func testAccCheckAwsDxHostedTransitVirtualInterfaceDestroy(s *terraform.State) e if rs.Type != "aws_dx_hosted_transit_virtual_interface" { continue } + if rs.Primary.ID == "" { + return fmt.Errorf("No ID is set") + } - input := &directconnect.DescribeVirtualInterfacesInput{ + resp, err := conn.DescribeVirtualInterfaces(&directconnect.DescribeVirtualInterfacesInput{ VirtualInterfaceId: aws.String(rs.Primary.ID), + }) + if isAWSErr(err, directconnect.ErrCodeClientException, "does not exist") { + continue } - - resp, err := conn.DescribeVirtualInterfaces(input) if err != nil { return err } - for _, v := range resp.VirtualInterfaces { - if *v.VirtualInterfaceId == rs.Primary.ID && !(*v.VirtualInterfaceState == directconnect.VirtualInterfaceStateDeleted) { - return fmt.Errorf("[DESTROY ERROR] Dx Private VIF (%s) not deleted", rs.Primary.ID) + + n := len(resp.VirtualInterfaces) + switch n { + case 0: + continue + case 1: + if aws.StringValue(resp.VirtualInterfaces[0].VirtualInterfaceState) == directconnect.VirtualInterfaceStateDeleted { + continue } + return fmt.Errorf("still exist.") + default: + return fmt.Errorf("Found %d Direct Connect virtual interfaces for %s, expected 1", n, rs.Primary.ID) } } + return nil } func testAccCheckAwsDxHostedTransitVirtualInterfaceExists(name string) resource.TestCheckFunc { return func(s *terraform.State) error { - _, ok := s.RootModule().Resources[name] + conn := testAccProvider.Meta().(*AWSClient).dxconn + + 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") + } + + _, err := conn.DescribeVirtualInterfaces(&directconnect.DescribeVirtualInterfacesInput{ + VirtualInterfaceId: aws.String(rs.Primary.ID), + }) + if err != nil { + return err + } return nil } diff --git a/website/aws.erb b/website/aws.erb index 3b0fb8e0bbd..13d868ca19c 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -885,12 +885,6 @@
  • aws_dx_lag
  • -
  • - aws_dx_private_virtual_interface -
  • -
  • - aws_dx_public_virtual_interface -
  • aws_dx_transit_virtual_interface
  • diff --git a/website/docs/r/dx_hosted_transit_virtual_interface_accepter.html.markdown b/website/docs/r/dx_hosted_transit_virtual_interface_accepter.html.markdown index 9b6952680e6..672cbd5c0cd 100644 --- a/website/docs/r/dx_hosted_transit_virtual_interface_accepter.html.markdown +++ b/website/docs/r/dx_hosted_transit_virtual_interface_accepter.html.markdown @@ -11,6 +11,8 @@ description: |- Provides a resource to manage the accepter's side of a Direct Connect hosted transit virtual interface. This resource accepts ownership of a transit virtual interface created by another AWS account. +-> **NOTE:** AWS allows a Direct Connect hosted transit virtual interface to be deleted from either the allocator's or accepter's side. However, Terraform only allows the Direct Connect hosted transit virtual interface to be deleted from the allocator's side by removing the corresponding `aws_dx_hosted_transit_virtual_interface` resource from your configuration. Removing a `aws_dx_hosted_transit_virtual_interface_accepter` resource from your configuration will remove it from your statefile and management, **but will not delete the Direct Connect virtual interface.** + ## Example Usage ```hcl @@ -70,14 +72,6 @@ The following arguments are supported: * `virtual_interface_id` - (Required) The ID of the Direct Connect virtual interface to accept. * `tags` - (Optional) A mapping of tags to assign to the resource. -### Removing `aws_dx_hosted_transit_virtual_interface_accepter` from your configuration - -AWS allows a Direct Connect hosted transit virtual interface to be deleted from either the allocator's or accepter's side. -However, Terraform only allows the Direct Connect hosted transit virtual interface to be deleted from the allocator's side -by removing the corresponding `aws_dx_hosted_transit_virtual_interface` resource from your configuration. -Removing a `aws_dx_hosted_transit_virtual_interface_accepter` resource from your configuration will remove it -from your statefile and management, **but will not delete the Direct Connect virtual interface.** - ## Attributes Reference In addition to all arguments above, the following attributes are exported: From cd20140aa27624692969554d8031b7613d65649c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 30 Jul 2019 15:15:18 -0400 Subject: [PATCH 05/12] Ensure correct VIF type during import of Direct Connect Virtual Interfaces - #8843. --- ...ce_aws_dx_hosted_transit_virtual_interface.go | 16 +++++++++++++++- ..._hosted_transit_virtual_interface_accepter.go | 16 +++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/aws/resource_aws_dx_hosted_transit_virtual_interface.go b/aws/resource_aws_dx_hosted_transit_virtual_interface.go index d70435cee55..f63cbbb268d 100644 --- a/aws/resource_aws_dx_hosted_transit_virtual_interface.go +++ b/aws/resource_aws_dx_hosted_transit_virtual_interface.go @@ -129,7 +129,7 @@ func resourceAwsDxHostedTransitVirtualInterfaceCreate(d *schema.ResourceData, me req.NewTransitVirtualInterfaceAllocation.CustomerAddress = aws.String(v.(string)) } - log.Printf("[DEBUG] Creating Direct Connect hosted transit virtual interface: %#v", req) + log.Printf("[DEBUG] Creating Direct Connect hosted transit virtual interface: %s", req) resp, err := conn.AllocateTransitVirtualInterface(req) if err != nil { return fmt.Errorf("error creating Direct Connect hosted transit virtual interface: %s", err) @@ -186,6 +186,20 @@ func resourceAwsDxHostedTransitVirtualInterfaceDelete(d *schema.ResourceData, me } func resourceAwsDxHostedTransitVirtualInterfaceImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + conn := meta.(*AWSClient).dxconn + + vif, err := dxVirtualInterfaceRead(d.Id(), conn) + if err != nil { + return nil, err + } + if vif == nil { + return nil, fmt.Errorf("virtual interface (%s) not found", d.Id()) + } + + if vifType := aws.StringValue(vif.VirtualInterfaceType); vifType != "transit" { + return nil, fmt.Errorf("virtual interface (%s) has incorrect type: %s", d.Id(), vifType) + } + arn := arn.ARN{ Partition: meta.(*AWSClient).partition, Region: meta.(*AWSClient).region, diff --git a/aws/resource_aws_dx_hosted_transit_virtual_interface_accepter.go b/aws/resource_aws_dx_hosted_transit_virtual_interface_accepter.go index 89f980b40ee..a9245701cdd 100644 --- a/aws/resource_aws_dx_hosted_transit_virtual_interface_accepter.go +++ b/aws/resource_aws_dx_hosted_transit_virtual_interface_accepter.go @@ -55,7 +55,7 @@ func resourceAwsDxHostedTransitVirtualInterfaceAccepterCreate(d *schema.Resource VirtualInterfaceId: aws.String(vifId), } - log.Printf("[DEBUG] Accepting Direct Connect hosted transit virtual interface: %#v", req) + log.Printf("[DEBUG] Accepting Direct Connect hosted transit virtual interface: %s", req) _, err := conn.ConfirmTransitVirtualInterface(req) if err != nil { return fmt.Errorf("error accepting Direct Connect hosted transit virtual interface (%s): %s", vifId, err) @@ -120,6 +120,20 @@ func resourceAwsDxHostedTransitVirtualInterfaceAccepterDelete(d *schema.Resource } func resourceAwsDxHostedTransitVirtualInterfaceAccepterImport(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + conn := meta.(*AWSClient).dxconn + + vif, err := dxVirtualInterfaceRead(d.Id(), conn) + if err != nil { + return nil, err + } + if vif == nil { + return nil, fmt.Errorf("virtual interface (%s) not found", d.Id()) + } + + if vifType := aws.StringValue(vif.VirtualInterfaceType); vifType != "transit" { + return nil, fmt.Errorf("virtual interface (%s) has incorrect type: %s", d.Id(), vifType) + } + arn := arn.ARN{ Partition: meta.(*AWSClient).partition, Region: meta.(*AWSClient).region, From 570cc624d2ac9c8713697db5ee9f3883e23cfd05 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 30 Jul 2019 16:24:09 -0400 Subject: [PATCH 06/12] Run acceptance tests serially: 'Only one Transit Virtual Interface is allowed on a Connection'. --- ...x_hosted_transit_virtual_interface_test.go | 205 ++++++++++++++---- 1 file changed, 161 insertions(+), 44 deletions(-) diff --git a/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go b/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go index 90d8d869ec5..1f5cb18e6e9 100644 --- a/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go +++ b/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go @@ -3,6 +3,8 @@ package aws import ( "fmt" "os" + "regexp" + "strconv" "testing" "github.com/aws/aws-sdk-go/aws" @@ -13,7 +15,21 @@ import ( "github.com/hashicorp/terraform/terraform" ) -func TestAccAwsDxHostedTransitVirtualInterface_basic(t *testing.T) { +func TestAccAwsDxHostedTransitVirtualInterface(t *testing.T) { + testCases := map[string]func(t *testing.T){ + "basic": testAccAwsDxHostedTransitVirtualInterface_basic, + "accepterTags": testAccAwsDxHostedTransitVirtualInterface_accepterTags, + } + + for name, tc := range testCases { + tc := tc + t.Run(name, func(t *testing.T) { + tc(t) + }) + } +} + +func testAccAwsDxHostedTransitVirtualInterface_basic(t *testing.T) { key := "DX_CONNECTION_ID" connectionId := os.Getenv(key) if connectionId == "" { @@ -21,14 +37,16 @@ func TestAccAwsDxHostedTransitVirtualInterface_basic(t *testing.T) { } var providers []*schema.Provider - resourceNameHostedVif := "aws_dx_hosted_transit_virtual_interface.test" - resourceNameHostedVifAccepter := "aws_dx_hosted_transit_virtual_interface_accepter.test" + var vif directconnect.VirtualInterface + resourceName := "aws_dx_hosted_transit_virtual_interface.test" + accepterResourceName := "aws_dx_hosted_transit_virtual_interface_accepter.test" + dxGatewayResourceName := "aws_dx_gateway.test" rName := fmt.Sprintf("tf-testacc-transit-vif-%s", acctest.RandString(9)) amzAsn := randIntRange(64512, 65534) bgpAsn := randIntRange(64512, 65534) vlan := randIntRange(2049, 4094) - resource.ParallelTest(t, resource.TestCase{ + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) testAccAlternateAccountPreCheck(t) @@ -39,30 +57,116 @@ func TestAccAwsDxHostedTransitVirtualInterface_basic(t *testing.T) { { Config: testAccDxHostedTransitVirtualInterfaceConfig_basic(connectionId, rName, amzAsn, bgpAsn, vlan), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsDxHostedTransitVirtualInterfaceExists(resourceNameHostedVif), - testAccCheckAwsDxHostedTransitVirtualInterfaceAccepterExists(resourceNameHostedVifAccepter), - resource.TestCheckResourceAttr(resourceNameHostedVif, "name", rName), - resource.TestCheckResourceAttr(resourceNameHostedVif, "mtu", "1500"), - resource.TestCheckResourceAttr(resourceNameHostedVif, "jumbo_frame_capable", "true"), - resource.TestCheckResourceAttr(resourceNameHostedVifAccepter, "tags.%", "0"), + testAccCheckAwsDxHostedTransitVirtualInterfaceExists(resourceName, &vif), + resource.TestCheckResourceAttr(resourceName, "address_family", "ipv4"), + resource.TestCheckResourceAttrSet(resourceName, "amazon_address"), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "directconnect", regexp.MustCompile(fmt.Sprintf("dxvif/%s", aws.StringValue(vif.VirtualInterfaceId)))), + resource.TestCheckResourceAttrSet(resourceName, "aws_device"), + resource.TestCheckResourceAttr(resourceName, "bgp_asn", strconv.Itoa(bgpAsn)), + resource.TestCheckResourceAttrSet(resourceName, "bgp_auth_key"), + resource.TestCheckResourceAttr(resourceName, "connection_id", connectionId), + resource.TestCheckResourceAttrSet(resourceName, "customer_address"), + resource.TestCheckResourceAttr(resourceName, "jumbo_frame_capable", "true"), + resource.TestCheckResourceAttr(resourceName, "mtu", "1500"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttrSet(resourceName, "owner_account_id"), + resource.TestCheckResourceAttr(resourceName, "vlan", strconv.Itoa(vlan)), + // Accepter's attributes: + resource.TestCheckResourceAttrSet(accepterResourceName, "arn"), + resource.TestCheckResourceAttrPair(accepterResourceName, "dx_gateway_id", dxGatewayResourceName, "id"), + resource.TestCheckResourceAttr(accepterResourceName, "tags.%", "0"), + resource.TestCheckResourceAttrPair(accepterResourceName, "virtual_interface_id", resourceName, "id"), ), }, + // Test import. { - Config: testAccDxHostedTransitVirtualInterfaceConfig_updated(connectionId, rName, amzAsn, bgpAsn, vlan), + Config: testAccDxHostedTransitVirtualInterfaceConfig_basic(connectionId, rName, amzAsn, bgpAsn, vlan), + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccAwsDxHostedTransitVirtualInterface_accepterTags(t *testing.T) { + key := "DX_CONNECTION_ID" + connectionId := os.Getenv(key) + if connectionId == "" { + t.Skipf("Environment variable %s is not set", key) + } + + var providers []*schema.Provider + var vif directconnect.VirtualInterface + resourceName := "aws_dx_hosted_transit_virtual_interface.test" + accepterResourceName := "aws_dx_hosted_transit_virtual_interface_accepter.test" + dxGatewayResourceName := "aws_dx_gateway.test" + rName := fmt.Sprintf("tf-testacc-transit-vif-%s", acctest.RandString(9)) + amzAsn := randIntRange(64512, 65534) + bgpAsn := randIntRange(64512, 65534) + vlan := randIntRange(2049, 4094) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + testAccPreCheck(t) + testAccAlternateAccountPreCheck(t) + }, + ProviderFactories: testAccProviderFactories(&providers), + CheckDestroy: testAccCheckAwsDxHostedTransitVirtualInterfaceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccDxHostedTransitVirtualInterfaceConfig_accepterTags(connectionId, rName, amzAsn, bgpAsn, vlan), Check: resource.ComposeTestCheckFunc( - testAccCheckAwsDxHostedTransitVirtualInterfaceExists(resourceNameHostedVif), - testAccCheckAwsDxHostedTransitVirtualInterfaceAccepterExists(resourceNameHostedVifAccepter), - resource.TestCheckResourceAttr(resourceNameHostedVif, "name", rName), - resource.TestCheckResourceAttr(resourceNameHostedVifAccepter, "tags.%", "1"), - resource.TestCheckResourceAttr(resourceNameHostedVifAccepter, "tags.Environment", "test"), + testAccCheckAwsDxHostedTransitVirtualInterfaceExists(resourceName, &vif), + resource.TestCheckResourceAttr(resourceName, "address_family", "ipv4"), + resource.TestCheckResourceAttrSet(resourceName, "amazon_address"), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "directconnect", regexp.MustCompile(fmt.Sprintf("dxvif/%s", aws.StringValue(vif.VirtualInterfaceId)))), + resource.TestCheckResourceAttrSet(resourceName, "aws_device"), + resource.TestCheckResourceAttr(resourceName, "bgp_asn", strconv.Itoa(bgpAsn)), + resource.TestCheckResourceAttrSet(resourceName, "bgp_auth_key"), + resource.TestCheckResourceAttr(resourceName, "connection_id", connectionId), + resource.TestCheckResourceAttrSet(resourceName, "customer_address"), + resource.TestCheckResourceAttr(resourceName, "jumbo_frame_capable", "true"), + resource.TestCheckResourceAttr(resourceName, "mtu", "1500"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttrSet(resourceName, "owner_account_id"), + resource.TestCheckResourceAttr(resourceName, "vlan", strconv.Itoa(vlan)), + // Accepter's attributes: + resource.TestCheckResourceAttrSet(accepterResourceName, "arn"), + resource.TestCheckResourceAttrPair(accepterResourceName, "dx_gateway_id", dxGatewayResourceName, "id"), + resource.TestCheckResourceAttr(accepterResourceName, "tags.%", "3"), + resource.TestCheckResourceAttr(accepterResourceName, "tags.Name", rName), + resource.TestCheckResourceAttr(accepterResourceName, "tags.Key1", "Value1"), + resource.TestCheckResourceAttr(accepterResourceName, "tags.Key2", "Value2a"), + resource.TestCheckResourceAttrPair(accepterResourceName, "virtual_interface_id", resourceName, "id"), ), }, - // Test import. { - Config: testAccDxHostedTransitVirtualInterfaceConfig_updated(connectionId, rName, amzAsn, bgpAsn, vlan), - ResourceName: resourceNameHostedVif, - ImportState: true, - ImportStateVerify: true, + Config: testAccDxHostedTransitVirtualInterfaceConfig_accepterTagsUpdated(connectionId, rName, amzAsn, bgpAsn, vlan), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsDxHostedTransitVirtualInterfaceExists(resourceName, &vif), + resource.TestCheckResourceAttr(resourceName, "address_family", "ipv4"), + resource.TestCheckResourceAttrSet(resourceName, "amazon_address"), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "directconnect", regexp.MustCompile(fmt.Sprintf("dxvif/%s", aws.StringValue(vif.VirtualInterfaceId)))), + resource.TestCheckResourceAttrSet(resourceName, "aws_device"), + resource.TestCheckResourceAttr(resourceName, "bgp_asn", strconv.Itoa(bgpAsn)), + resource.TestCheckResourceAttrSet(resourceName, "bgp_auth_key"), + resource.TestCheckResourceAttr(resourceName, "connection_id", connectionId), + resource.TestCheckResourceAttrSet(resourceName, "customer_address"), + resource.TestCheckResourceAttr(resourceName, "jumbo_frame_capable", "true"), + resource.TestCheckResourceAttr(resourceName, "mtu", "1500"), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttrSet(resourceName, "owner_account_id"), + resource.TestCheckResourceAttr(resourceName, "vlan", strconv.Itoa(vlan)), + // Accepter's attributes: + resource.TestCheckResourceAttrSet(accepterResourceName, "arn"), + resource.TestCheckResourceAttrPair(accepterResourceName, "dx_gateway_id", dxGatewayResourceName, "id"), + resource.TestCheckResourceAttr(accepterResourceName, "tags.%", "3"), + resource.TestCheckResourceAttr(accepterResourceName, "tags.Name", rName), + resource.TestCheckResourceAttr(accepterResourceName, "tags.Key2", "Value2b"), + resource.TestCheckResourceAttr(accepterResourceName, "tags.Key3", "Value3"), + resource.TestCheckResourceAttrPair(accepterResourceName, "virtual_interface_id", resourceName, "id"), + ), }, }, }) @@ -106,7 +210,7 @@ func testAccCheckAwsDxHostedTransitVirtualInterfaceDestroy(s *terraform.State) e return nil } -func testAccCheckAwsDxHostedTransitVirtualInterfaceExists(name string) resource.TestCheckFunc { +func testAccCheckAwsDxHostedTransitVirtualInterfaceExists(name string, vif *directconnect.VirtualInterface) resource.TestCheckFunc { return func(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).dxconn @@ -118,24 +222,19 @@ func testAccCheckAwsDxHostedTransitVirtualInterfaceExists(name string) resource. return fmt.Errorf("No ID is set") } - _, err := conn.DescribeVirtualInterfaces(&directconnect.DescribeVirtualInterfacesInput{ + resp, err := conn.DescribeVirtualInterfaces(&directconnect.DescribeVirtualInterfacesInput{ VirtualInterfaceId: aws.String(rs.Primary.ID), }) if err != nil { return err } - return nil - } -} - -func testAccCheckAwsDxHostedTransitVirtualInterfaceAccepterExists(name string) resource.TestCheckFunc { - return func(s *terraform.State) error { - _, ok := s.RootModule().Resources[name] - if !ok { - return fmt.Errorf("Not found: %s", name) + if n := len(resp.VirtualInterfaces); n != 1 { + return fmt.Errorf("Found %d Direct Connect virtual interfaces for %s, expected 1", n, rs.Primary.ID) } + *vif = *resp.VirtualInterfaces[0] + return nil } } @@ -144,13 +243,12 @@ func testAccDxHostedTransitVirtualInterfaceConfig_base(cid, rName string, amzAsn return testAccAlternateAccountProviderConfig() + fmt.Sprintf(` # Creator resource "aws_dx_hosted_transit_virtual_interface" "test" { + address_family = "ipv4" + bgp_asn = %[4]d connection_id = %[1]q + name = %[2]q owner_account_id = "${data.aws_caller_identity.accepter.account_id}" - - name = %[2]q - vlan = %[5]d - address_family = "ipv4" - bgp_asn = %[4]d + vlan = %[5]d # The aws_dx_hosted_transit_virtual_interface # must be destroyed before the aws_dx_gateway. @@ -165,8 +263,8 @@ data "aws_caller_identity" "accepter" { resource "aws_dx_gateway" "test" { provider = "aws.alternate" - name = %[2]q amazon_side_asn = %[3]d + name = %[2]q } `, cid, rName, amzAsn, bgpAsn, vlan) } @@ -174,25 +272,44 @@ resource "aws_dx_gateway" "test" { func testAccDxHostedTransitVirtualInterfaceConfig_basic(cid, rName string, amzAsn, bgpAsn, vlan int) string { return testAccDxHostedTransitVirtualInterfaceConfig_base(cid, rName, amzAsn, bgpAsn, vlan) + fmt.Sprintf(` resource "aws_dx_hosted_transit_virtual_interface_accepter" "test" { - provider = "aws.alternate" + provider = "aws.alternate" - virtual_interface_id = "${aws_dx_hosted_transit_virtual_interface.test.id}" dx_gateway_id = "${aws_dx_gateway.test.id}" + virtual_interface_id = "${aws_dx_hosted_transit_virtual_interface.test.id}" } `) } -func testAccDxHostedTransitVirtualInterfaceConfig_updated(cid, rName string, amzAsn, bgpAsn, vlan int) string { +func testAccDxHostedTransitVirtualInterfaceConfig_accepterTags(cid, rName string, amzAsn, bgpAsn, vlan int) string { return testAccDxHostedTransitVirtualInterfaceConfig_base(cid, rName, amzAsn, bgpAsn, vlan) + fmt.Sprintf(` resource "aws_dx_hosted_transit_virtual_interface_accepter" "test" { - provider = "aws.alternate" + provider = "aws.alternate" + dx_gateway_id = "${aws_dx_gateway.test.id}" virtual_interface_id = "${aws_dx_hosted_transit_virtual_interface.test.id}" + + tags = { + Name = %[1]q + Key1 = "Value1" + Key2 = "Value2a" + } +} +`, rName) +} + +func testAccDxHostedTransitVirtualInterfaceConfig_accepterTagsUpdated(cid, rName string, amzAsn, bgpAsn, vlan int) string { + return testAccDxHostedTransitVirtualInterfaceConfig_base(cid, rName, amzAsn, bgpAsn, vlan) + fmt.Sprintf(` +resource "aws_dx_hosted_transit_virtual_interface_accepter" "test" { + provider = "aws.alternate" + dx_gateway_id = "${aws_dx_gateway.test.id}" + virtual_interface_id = "${aws_dx_hosted_transit_virtual_interface.test.id}" tags = { - Environment = "test" + Name = %[1]q + Key2 = "Value2b" + Key3 = "Value3" } } -`) +`, rName) } From 9606b7fe8bf7a4d4ce171ca1e7d46365fd7953d2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 30 Jul 2019 17:55:10 -0400 Subject: [PATCH 07/12] 'amazon_address' and 'customer_address' aren't set until the hosted VIF has been accepted. --- ...resource_aws_dx_hosted_transit_virtual_interface_test.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go b/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go index 1f5cb18e6e9..28c0d7076dc 100644 --- a/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go +++ b/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go @@ -59,13 +59,11 @@ func testAccAwsDxHostedTransitVirtualInterface_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxHostedTransitVirtualInterfaceExists(resourceName, &vif), resource.TestCheckResourceAttr(resourceName, "address_family", "ipv4"), - resource.TestCheckResourceAttrSet(resourceName, "amazon_address"), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "directconnect", regexp.MustCompile(fmt.Sprintf("dxvif/%s", aws.StringValue(vif.VirtualInterfaceId)))), resource.TestCheckResourceAttrSet(resourceName, "aws_device"), resource.TestCheckResourceAttr(resourceName, "bgp_asn", strconv.Itoa(bgpAsn)), resource.TestCheckResourceAttrSet(resourceName, "bgp_auth_key"), resource.TestCheckResourceAttr(resourceName, "connection_id", connectionId), - resource.TestCheckResourceAttrSet(resourceName, "customer_address"), resource.TestCheckResourceAttr(resourceName, "jumbo_frame_capable", "true"), resource.TestCheckResourceAttr(resourceName, "mtu", "1500"), resource.TestCheckResourceAttr(resourceName, "name", rName), @@ -119,13 +117,11 @@ func testAccAwsDxHostedTransitVirtualInterface_accepterTags(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxHostedTransitVirtualInterfaceExists(resourceName, &vif), resource.TestCheckResourceAttr(resourceName, "address_family", "ipv4"), - resource.TestCheckResourceAttrSet(resourceName, "amazon_address"), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "directconnect", regexp.MustCompile(fmt.Sprintf("dxvif/%s", aws.StringValue(vif.VirtualInterfaceId)))), resource.TestCheckResourceAttrSet(resourceName, "aws_device"), resource.TestCheckResourceAttr(resourceName, "bgp_asn", strconv.Itoa(bgpAsn)), resource.TestCheckResourceAttrSet(resourceName, "bgp_auth_key"), resource.TestCheckResourceAttr(resourceName, "connection_id", connectionId), - resource.TestCheckResourceAttrSet(resourceName, "customer_address"), resource.TestCheckResourceAttr(resourceName, "jumbo_frame_capable", "true"), resource.TestCheckResourceAttr(resourceName, "mtu", "1500"), resource.TestCheckResourceAttr(resourceName, "name", rName), @@ -146,13 +142,11 @@ func testAccAwsDxHostedTransitVirtualInterface_accepterTags(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAwsDxHostedTransitVirtualInterfaceExists(resourceName, &vif), resource.TestCheckResourceAttr(resourceName, "address_family", "ipv4"), - resource.TestCheckResourceAttrSet(resourceName, "amazon_address"), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "directconnect", regexp.MustCompile(fmt.Sprintf("dxvif/%s", aws.StringValue(vif.VirtualInterfaceId)))), resource.TestCheckResourceAttrSet(resourceName, "aws_device"), resource.TestCheckResourceAttr(resourceName, "bgp_asn", strconv.Itoa(bgpAsn)), resource.TestCheckResourceAttrSet(resourceName, "bgp_auth_key"), resource.TestCheckResourceAttr(resourceName, "connection_id", connectionId), - resource.TestCheckResourceAttrSet(resourceName, "customer_address"), resource.TestCheckResourceAttr(resourceName, "jumbo_frame_capable", "true"), resource.TestCheckResourceAttr(resourceName, "mtu", "1500"), resource.TestCheckResourceAttr(resourceName, "name", rName), From b0434eab617a25f6bf038e66c1519656415f81eb Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 31 Jul 2019 13:17:45 -0400 Subject: [PATCH 08/12] Set 'arn' in Read method. Remove duplicate code. --- ...aws_dx_hosted_transit_virtual_interface.go | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/aws/resource_aws_dx_hosted_transit_virtual_interface.go b/aws/resource_aws_dx_hosted_transit_virtual_interface.go index f63cbbb268d..350ad8119a4 100644 --- a/aws/resource_aws_dx_hosted_transit_virtual_interface.go +++ b/aws/resource_aws_dx_hosted_transit_virtual_interface.go @@ -136,14 +136,6 @@ func resourceAwsDxHostedTransitVirtualInterfaceCreate(d *schema.ResourceData, me } d.SetId(aws.StringValue(resp.VirtualInterface.VirtualInterfaceId)) - arn := arn.ARN{ - Partition: meta.(*AWSClient).partition, - Region: meta.(*AWSClient).region, - Service: "directconnect", - AccountID: meta.(*AWSClient).accountid, - Resource: fmt.Sprintf("dxvif/%s", d.Id()), - }.String() - d.Set("arn", arn) if err := dxHostedTransitVirtualInterfaceWaitUntilAvailable(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { return err @@ -167,6 +159,14 @@ func resourceAwsDxHostedTransitVirtualInterfaceRead(d *schema.ResourceData, meta d.Set("address_family", vif.AddressFamily) d.Set("amazon_address", vif.AmazonAddress) + arn := arn.ARN{ + Partition: meta.(*AWSClient).partition, + Region: meta.(*AWSClient).region, + Service: "directconnect", + AccountID: meta.(*AWSClient).accountid, + Resource: fmt.Sprintf("dxvif/%s", d.Id()), + }.String() + d.Set("arn", arn) d.Set("aws_device", vif.AwsDeviceV2) d.Set("bgp_asn", vif.Asn) d.Set("bgp_auth_key", vif.AuthKey) @@ -200,15 +200,6 @@ func resourceAwsDxHostedTransitVirtualInterfaceImport(d *schema.ResourceData, me return nil, fmt.Errorf("virtual interface (%s) has incorrect type: %s", d.Id(), vifType) } - arn := arn.ARN{ - Partition: meta.(*AWSClient).partition, - Region: meta.(*AWSClient).region, - Service: "directconnect", - AccountID: meta.(*AWSClient).accountid, - Resource: fmt.Sprintf("dxvif/%s", d.Id()), - }.String() - d.Set("arn", arn) - return []*schema.ResourceData{d}, nil } From 90f397e1b48de81b59a72b3765c3c8579688f7f4 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 2 Aug 2019 17:36:52 -0400 Subject: [PATCH 09/12] Use common 'Exists' and 'Destroy' methods - https://github.com/terraform-providers/terraform-provider-aws/pull/9572. --- ...x_hosted_transit_virtual_interface_test.go | 67 ++----------------- 1 file changed, 4 insertions(+), 63 deletions(-) diff --git a/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go b/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go index 28c0d7076dc..cbc746f0b9b 100644 --- a/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go +++ b/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go @@ -166,71 +166,12 @@ func testAccAwsDxHostedTransitVirtualInterface_accepterTags(t *testing.T) { }) } -func testAccCheckAwsDxHostedTransitVirtualInterfaceDestroy(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).dxconn - - for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_dx_hosted_transit_virtual_interface" { - continue - } - if rs.Primary.ID == "" { - return fmt.Errorf("No ID is set") - } - - resp, err := conn.DescribeVirtualInterfaces(&directconnect.DescribeVirtualInterfacesInput{ - VirtualInterfaceId: aws.String(rs.Primary.ID), - }) - if isAWSErr(err, directconnect.ErrCodeClientException, "does not exist") { - continue - } - if err != nil { - return err - } - - n := len(resp.VirtualInterfaces) - switch n { - case 0: - continue - case 1: - if aws.StringValue(resp.VirtualInterfaces[0].VirtualInterfaceState) == directconnect.VirtualInterfaceStateDeleted { - continue - } - return fmt.Errorf("still exist.") - default: - return fmt.Errorf("Found %d Direct Connect virtual interfaces for %s, expected 1", n, rs.Primary.ID) - } - } - - return nil -} - func testAccCheckAwsDxHostedTransitVirtualInterfaceExists(name string, vif *directconnect.VirtualInterface) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).dxconn - - 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") - } - - resp, err := conn.DescribeVirtualInterfaces(&directconnect.DescribeVirtualInterfacesInput{ - VirtualInterfaceId: aws.String(rs.Primary.ID), - }) - if err != nil { - return err - } - - if n := len(resp.VirtualInterfaces); n != 1 { - return fmt.Errorf("Found %d Direct Connect virtual interfaces for %s, expected 1", n, rs.Primary.ID) - } - - *vif = *resp.VirtualInterfaces[0] + return testAccCheckDxVirtualInterfaceExists(name, vif) +} - return nil - } +func testAccCheckAwsDxHostedTransitVirtualInterfaceDestroy(s *terraform.State) error { + return testAccCheckDxVirtualInterfaceDestroy(s, "aws_dx_hosted_transit_virtual_interface") } func testAccDxHostedTransitVirtualInterfaceConfig_base(cid, rName string, amzAsn, bgpAsn, vlan int) string { From fea2d7388d9b4e08c22018e51b64a1f0b86b4ebf Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 4 Oct 2019 17:00:41 -0400 Subject: [PATCH 10/12] Terraform Plugin SDK migration. --- aws/resource_aws_dx_hosted_transit_virtual_interface.go | 4 ++-- ...ce_aws_dx_hosted_transit_virtual_interface_accepter.go | 2 +- ...source_aws_dx_hosted_transit_virtual_interface_test.go | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/aws/resource_aws_dx_hosted_transit_virtual_interface.go b/aws/resource_aws_dx_hosted_transit_virtual_interface.go index 350ad8119a4..194eac432cc 100644 --- a/aws/resource_aws_dx_hosted_transit_virtual_interface.go +++ b/aws/resource_aws_dx_hosted_transit_virtual_interface.go @@ -8,8 +8,8 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/directconnect" - "github.com/hashicorp/terraform/helper/schema" - "github.com/hashicorp/terraform/helper/validation" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" ) func resourceAwsDxHostedTransitVirtualInterface() *schema.Resource { diff --git a/aws/resource_aws_dx_hosted_transit_virtual_interface_accepter.go b/aws/resource_aws_dx_hosted_transit_virtual_interface_accepter.go index a9245701cdd..ba69cd5dd7e 100644 --- a/aws/resource_aws_dx_hosted_transit_virtual_interface_accepter.go +++ b/aws/resource_aws_dx_hosted_transit_virtual_interface_accepter.go @@ -8,7 +8,7 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/directconnect" - "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" ) func resourceAwsDxHostedTransitVirtualInterfaceAccepter() *schema.Resource { diff --git a/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go b/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go index cbc746f0b9b..dd2a51b2989 100644 --- a/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go +++ b/aws/resource_aws_dx_hosted_transit_virtual_interface_test.go @@ -9,10 +9,10 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/directconnect" - "github.com/hashicorp/terraform/helper/acctest" - "github.com/hashicorp/terraform/helper/resource" - "github.com/hashicorp/terraform/helper/schema" - "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/terraform" ) func TestAccAwsDxHostedTransitVirtualInterface(t *testing.T) { From 05377e1045b08e62b40222b9a24cac6169ec727d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 22 Nov 2019 12:29:50 +0000 Subject: [PATCH 11/12] Add 'subcategory'. --- website/docs/r/dx_hosted_transit_virtual_interface.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/dx_hosted_transit_virtual_interface.html.markdown b/website/docs/r/dx_hosted_transit_virtual_interface.html.markdown index 93fcfc98ef5..4448670de55 100644 --- a/website/docs/r/dx_hosted_transit_virtual_interface.html.markdown +++ b/website/docs/r/dx_hosted_transit_virtual_interface.html.markdown @@ -1,4 +1,5 @@ --- +subcategory: "Direct Connect" layout: "aws" page_title: "AWS: aws_dx_hosted_transit_virtual_interface" sidebar_current: "docs-aws-resource-dx-hosted-transit-virtual-interface" From 63b0344fde82ebda252c82df0befb1bed49aa039 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 22 Nov 2019 12:30:40 +0000 Subject: [PATCH 12/12] Add 'subcategory'. --- .../r/dx_hosted_transit_virtual_interface_accepter.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/r/dx_hosted_transit_virtual_interface_accepter.html.markdown b/website/docs/r/dx_hosted_transit_virtual_interface_accepter.html.markdown index 672cbd5c0cd..48b0935556b 100644 --- a/website/docs/r/dx_hosted_transit_virtual_interface_accepter.html.markdown +++ b/website/docs/r/dx_hosted_transit_virtual_interface_accepter.html.markdown @@ -1,4 +1,5 @@ --- +subcategory: "Direct Connect" layout: "aws" page_title: "AWS: aws_dx_hosted_transit_virtual_interface_accepter" sidebar_current: "docs-aws-resource-dx-hosted-transit-virtual-interface-accepter"