Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

New resource: aws_dx_transit_virtual_interface #8522

Merged
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 @@ -441,6 +441,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