Skip to content

Commit

Permalink
Merge pull request #8522 from ewbankkit/issue-8490.dx_transit_virtual…
Browse files Browse the repository at this point in the history
…_interface

New resource: aws_dx_transit_virtual_interface
  • Loading branch information
bflad authored Aug 6, 2019
2 parents f23ef76 + 9763e96 commit 1406a50
Show file tree
Hide file tree
Showing 7 changed files with 654 additions and 16 deletions.
27 changes: 11 additions & 16 deletions aws/dx_vif.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
func dxVirtualInterfaceRead(id string, conn *directconnect.DirectConnect) (*directconnect.VirtualInterface, error) {
resp, state, err := dxVirtualInterfaceStateRefresh(conn, id)()
if err != nil {
return nil, fmt.Errorf("Error reading Direct Connect virtual interface: %s", err)
return nil, fmt.Errorf("error reading Direct Connect virtual interface (%s): %s", id, err)
}
if state == directconnect.VirtualInterfaceStateDeleted {
return nil, nil
Expand All @@ -26,26 +26,21 @@ func dxVirtualInterfaceRead(id string, conn *directconnect.DirectConnect) (*dire
func dxVirtualInterfaceUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).dxconn

req := &directconnect.UpdateVirtualInterfaceAttributesInput{
VirtualInterfaceId: aws.String(d.Id()),
}

requestUpdate := false
if d.HasChange("mtu") {
req.Mtu = aws.Int64(int64(d.Get("mtu").(int)))
requestUpdate = true
}
req := &directconnect.UpdateVirtualInterfaceAttributesInput{
Mtu: aws.Int64(int64(d.Get("mtu").(int))),
VirtualInterfaceId: aws.String(d.Id()),
}

if requestUpdate {
log.Printf("[DEBUG] Modifying Direct Connect virtual interface attributes: %#v", req)
log.Printf("[DEBUG] Modifying Direct Connect virtual interface attributes: %s", req)
_, err := conn.UpdateVirtualInterfaceAttributes(req)
if err != nil {
return fmt.Errorf("Error modifying Direct Connect virtual interface (%s) attributes, error: %s", d.Id(), err)
return fmt.Errorf("error modifying Direct Connect virtual interface (%s) attributes, error: %s", d.Id(), err)
}
}

if err := setTagsDX(conn, d, d.Get("arn").(string)); err != nil {
return err
return fmt.Errorf("error setting Direct Connect virtual interface (%s) tags: %s", d.Id(), err)
}

return nil
Expand All @@ -62,7 +57,7 @@ func dxVirtualInterfaceDelete(d *schema.ResourceData, meta interface{}) error {
if isAWSErr(err, directconnect.ErrCodeClientException, "does not exist") {
return nil
}
return fmt.Errorf("Error deleting Direct Connect virtual interface: %s", err)
return fmt.Errorf("error deleting Direct Connect virtual interface (%s): %s", d.Id(), err)
}

deleteStateConf := &resource.StateChangeConf{
Expand All @@ -85,7 +80,7 @@ func dxVirtualInterfaceDelete(d *schema.ResourceData, meta interface{}) error {
}
_, err = deleteStateConf.WaitForState()
if err != nil {
return fmt.Errorf("Error waiting for Direct Connect virtual interface (%s) to be deleted: %s", d.Id(), err)
return fmt.Errorf("error waiting for Direct Connect virtual interface (%s) to be deleted: %s", d.Id(), err)
}

return nil
Expand Down Expand Up @@ -125,7 +120,7 @@ func dxVirtualInterfaceWaitUntilAvailable(conn *directconnect.DirectConnect, vif
MinTimeout: 5 * time.Second,
}
if _, err := stateConf.WaitForState(); err != nil {
return fmt.Errorf("Error waiting for Direct Connect virtual interface (%s) to become available: %s", vifId, err)
return fmt.Errorf("error waiting for Direct Connect virtual interface (%s) to become available: %s", vifId, err)
}

return nil
Expand Down
72 changes: 72 additions & 0 deletions aws/dx_vif_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package aws

import (
"fmt"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/directconnect"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)

func testAccCheckDxVirtualInterfaceExists(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
}

for _, v := range resp.VirtualInterfaces {
if aws.StringValue(v.VirtualInterfaceId) == rs.Primary.ID {
*vif = *v

return nil
}
}

return fmt.Errorf("Direct Connect virtual interface (%s) not found", rs.Primary.ID)
}
}

func testAccCheckDxVirtualInterfaceDestroy(s *terraform.State, t string) error {
conn := testAccProvider.Meta().(*AWSClient).dxconn

for _, rs := range s.RootModule().Resources {
if rs.Type != t {
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
}

for _, v := range resp.VirtualInterfaces {
if aws.StringValue(v.VirtualInterfaceId) == rs.Primary.ID && aws.StringValue(v.VirtualInterfaceState) != directconnect.VirtualInterfaceStateDeleted {
return fmt.Errorf("[DESTROY ERROR] Direct Connect virtual interface (%s) not deleted", rs.Primary.ID)
}
}
}

return nil
}
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,7 @@ func Provider() terraform.ResourceProvider {
"aws_dx_lag": resourceAwsDxLag(),
"aws_dx_private_virtual_interface": resourceAwsDxPrivateVirtualInterface(),
"aws_dx_public_virtual_interface": resourceAwsDxPublicVirtualInterface(),
"aws_dx_transit_virtual_interface": resourceAwsDxTransitVirtualInterface(),
"aws_dynamodb_table": resourceAwsDynamoDbTable(),
"aws_dynamodb_table_item": resourceAwsDynamoDbTableItem(),
"aws_dynamodb_global_table": resourceAwsDynamoDbGlobalTable(),
Expand Down
236 changes: 236 additions & 0 deletions aws/resource_aws_dx_transit_virtual_interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
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 resourceAwsDxTransitVirtualInterface() *schema.Resource {
return &schema.Resource{
Create: resourceAwsDxTransitVirtualInterfaceCreate,
Read: resourceAwsDxTransitVirtualInterfaceRead,
Update: resourceAwsDxTransitVirtualInterfaceUpdate,
Delete: resourceAwsDxTransitVirtualInterfaceDelete,
Importer: &schema.ResourceImporter{
State: resourceAwsDxTransitVirtualInterfaceImport,
},

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,
},
"dx_gateway_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"jumbo_frame_capable": {
Type: schema.TypeBool,
Computed: true,
},
"mtu": {
Type: schema.TypeInt,
Default: 1500,
Optional: true,
ValidateFunc: validation.IntInSlice([]int{1500, 8500}),
},
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"tags": tagsSchema(),
"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 resourceAwsDxTransitVirtualInterfaceCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).dxconn

req := &directconnect.CreateTransitVirtualInterfaceInput{
ConnectionId: aws.String(d.Get("connection_id").(string)),
NewTransitVirtualInterface: &directconnect.NewTransitVirtualInterface{
AddressFamily: aws.String(d.Get("address_family").(string)),
Asn: aws.Int64(int64(d.Get("bgp_asn").(int))),
DirectConnectGatewayId: aws.String(d.Get("dx_gateway_id").(string)),
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.NewTransitVirtualInterface.AmazonAddress = aws.String(v.(string))
}
if v, ok := d.GetOk("bgp_auth_key"); ok {
req.NewTransitVirtualInterface.AuthKey = aws.String(v.(string))
}
if v, ok := d.GetOk("customer_address"); ok && v.(string) != "" {
req.NewTransitVirtualInterface.CustomerAddress = aws.String(v.(string))
}
if v, ok := d.GetOk("tags"); ok {
req.NewTransitVirtualInterface.Tags = tagsFromMapDX(v.(map[string]interface{}))
}

log.Printf("[DEBUG] Creating Direct Connect transit virtual interface: %s", req)
resp, err := conn.CreateTransitVirtualInterface(req)
if err != nil {
return fmt.Errorf("error creating Direct Connect transit virtual interface: %s", err)
}

d.SetId(aws.StringValue(resp.VirtualInterface.VirtualInterfaceId))

if err := dxTransitVirtualInterfaceWaitUntilAvailable(conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil {
return err
}

return resourceAwsDxTransitVirtualInterfaceRead(d, meta)
}

func resourceAwsDxTransitVirtualInterfaceRead(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
}

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)
d.Set("connection_id", vif.ConnectionId)
d.Set("customer_address", vif.CustomerAddress)
d.Set("dx_gateway_id", vif.DirectConnectGatewayId)
d.Set("jumbo_frame_capable", vif.JumboFrameCapable)
d.Set("mtu", vif.Mtu)
d.Set("name", vif.VirtualInterfaceName)
d.Set("vlan", vif.Vlan)
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 resourceAwsDxTransitVirtualInterfaceUpdate(d *schema.ResourceData, meta interface{}) error {
if err := dxVirtualInterfaceUpdate(d, meta); err != nil {
return err
}

if err := dxTransitVirtualInterfaceWaitUntilAvailable(meta.(*AWSClient).dxconn, d.Id(), d.Timeout(schema.TimeoutUpdate)); err != nil {
return err
}

return resourceAwsDxTransitVirtualInterfaceRead(d, meta)
}

func resourceAwsDxTransitVirtualInterfaceDelete(d *schema.ResourceData, meta interface{}) error {
return dxVirtualInterfaceDelete(d, meta)
}

func resourceAwsDxTransitVirtualInterfaceImport(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)
}

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

func dxTransitVirtualInterfaceWaitUntilAvailable(conn *directconnect.DirectConnect, vifId string, timeout time.Duration) error {
return dxVirtualInterfaceWaitUntilAvailable(
conn,
vifId,
timeout,
[]string{
directconnect.VirtualInterfaceStatePending,
},
[]string{
directconnect.VirtualInterfaceStateAvailable,
directconnect.VirtualInterfaceStateDown,
})
}
Loading

0 comments on commit 1406a50

Please sign in to comment.