Skip to content

Commit

Permalink
Merge pull request #3253 from ewbankkit/issue-3249
Browse files Browse the repository at this point in the history
New Resource: aws_dx_private_virtual_interface
  • Loading branch information
bflad authored Jun 25, 2018
2 parents 7baa704 + 173e1d9 commit 53e19f2
Show file tree
Hide file tree
Showing 8 changed files with 604 additions and 1 deletion.
114 changes: 114 additions & 0 deletions aws/dx_vif.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package aws

import (
"fmt"
"log"
"time"

"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/helper/schema"
)

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)
}
if state == directconnect.VirtualInterfaceStateDeleted {
return nil, nil
}

return resp.(*directconnect.VirtualInterface), nil
}

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

if err := setTagsDX(conn, d, d.Get("arn").(string)); err != nil {
return err
}

return nil
}

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

log.Printf("[DEBUG] Deleting Direct Connect virtual interface: %s", d.Id())
_, err := conn.DeleteVirtualInterface(&directconnect.DeleteVirtualInterfaceInput{
VirtualInterfaceId: aws.String(d.Id()),
})
if err != nil {
if isAWSErr(err, directconnect.ErrCodeClientException, "does not exist") {
return nil
}
return fmt.Errorf("Error deleting Direct Connect virtual interface: %s", err)
}

deleteStateConf := &resource.StateChangeConf{
Pending: []string{
directconnect.VirtualInterfaceStateAvailable,
directconnect.VirtualInterfaceStateConfirming,
directconnect.VirtualInterfaceStateDeleting,
directconnect.VirtualInterfaceStateDown,
directconnect.VirtualInterfaceStatePending,
directconnect.VirtualInterfaceStateRejected,
directconnect.VirtualInterfaceStateVerifying,
},
Target: []string{
directconnect.VirtualInterfaceStateDeleted,
},
Refresh: dxVirtualInterfaceStateRefresh(conn, d.Id()),
Timeout: d.Timeout(schema.TimeoutDelete),
Delay: 10 * time.Second,
MinTimeout: 5 * time.Second,
}
_, 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 nil
}

func dxVirtualInterfaceStateRefresh(conn *directconnect.DirectConnect, vifId string) resource.StateRefreshFunc {
return func() (interface{}, string, error) {
resp, err := conn.DescribeVirtualInterfaces(&directconnect.DescribeVirtualInterfacesInput{
VirtualInterfaceId: aws.String(vifId),
})
if err != nil {
return nil, "", err
}

n := len(resp.VirtualInterfaces)
switch n {
case 0:
return "", directconnect.VirtualInterfaceStateDeleted, nil

case 1:
vif := resp.VirtualInterfaces[0]
return vif, aws.StringValue(vif.VirtualInterfaceState), nil

default:
return nil, "", fmt.Errorf("Found %d Direct Connect virtual interfaces for %s, expected 1", n, vifId)
}
}
}

func dxVirtualInterfaceWaitUntilAvailable(d *schema.ResourceData, conn *directconnect.DirectConnect, pending, target []string) error {
stateConf := &resource.StateChangeConf{
Pending: pending,
Target: target,
Refresh: dxVirtualInterfaceStateRefresh(conn, d.Id()),
Timeout: d.Timeout(schema.TimeoutCreate),
Delay: 10 * time.Second,
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", d.Id(), err)
}

return nil
}
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -372,6 +372,7 @@ func Provider() terraform.ResourceProvider {
"aws_dx_connection_association": resourceAwsDxConnectionAssociation(),
"aws_dx_gateway": resourceAwsDxGateway(),
"aws_dx_gateway_association": resourceAwsDxGatewayAssociation(),
"aws_dx_private_virtual_interface": resourceAwsDxPrivateVirtualInterface(),
"aws_dynamodb_table": resourceAwsDynamoDbTable(),
"aws_dynamodb_table_item": resourceAwsDynamoDbTableItem(),
"aws_dynamodb_global_table": resourceAwsDynamoDbGlobalTable(),
Expand Down
221 changes: 221 additions & 0 deletions aws/resource_aws_dx_private_virtual_interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
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 resourceAwsDxPrivateVirtualInterface() *schema.Resource {
return &schema.Resource{
Create: resourceAwsDxPrivateVirtualInterfaceCreate,
Read: resourceAwsDxPrivateVirtualInterfaceRead,
Update: resourceAwsDxPrivateVirtualInterfaceUpdate,
Delete: resourceAwsDxPrivateVirtualInterfaceDelete,
Importer: &schema.ResourceImporter{
State: resourceAwsDxPrivateVirtualInterfaceImport,
},

Schema: map[string]*schema.Schema{
"arn": {
Type: schema.TypeString,
Computed: true,
},
"connection_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"vpn_gateway_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ConflictsWith: []string{"dx_gateway_id"},
},
"dx_gateway_id": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ConflictsWith: []string{"vpn_gateway_id"},
},
"vlan": {
Type: schema.TypeInt,
Required: true,
ForceNew: true,
ValidateFunc: validation.IntBetween(1, 4094),
},
"bgp_asn": {
Type: schema.TypeInt,
Required: true,
ForceNew: true,
},
"bgp_auth_key": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
"address_family": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice([]string{directconnect.AddressFamilyIpv4, directconnect.AddressFamilyIpv6}, false),
},
"customer_address": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
"amazon_address": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
},
"tags": tagsSchema(),
},

Timeouts: &schema.ResourceTimeout{
Create: schema.DefaultTimeout(10 * time.Minute),
Delete: schema.DefaultTimeout(10 * time.Minute),
},
}
}

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

vgwIdRaw, vgwOk := d.GetOk("vpn_gateway_id")
dxgwIdRaw, dxgwOk := d.GetOk("dx_gateway_id")
if vgwOk == dxgwOk {
return fmt.Errorf(
"One of ['vpn_gateway_id', 'dx_gateway_id'] must be set to create a Direct Connect private virtual interface")
}

req := &directconnect.CreatePrivateVirtualInterfaceInput{
ConnectionId: aws.String(d.Get("connection_id").(string)),
NewPrivateVirtualInterface: &directconnect.NewPrivateVirtualInterface{
VirtualInterfaceName: aws.String(d.Get("name").(string)),
Vlan: aws.Int64(int64(d.Get("vlan").(int))),
Asn: aws.Int64(int64(d.Get("bgp_asn").(int))),
AddressFamily: aws.String(d.Get("address_family").(string)),
},
}
if vgwOk && vgwIdRaw.(string) != "" {
req.NewPrivateVirtualInterface.VirtualGatewayId = aws.String(vgwIdRaw.(string))
}
if dxgwOk && dxgwIdRaw.(string) != "" {
req.NewPrivateVirtualInterface.DirectConnectGatewayId = aws.String(dxgwIdRaw.(string))
}
if v, ok := d.GetOk("bgp_auth_key"); ok {
req.NewPrivateVirtualInterface.AuthKey = aws.String(v.(string))
}
if v, ok := d.GetOk("customer_address"); ok && v.(string) != "" {
req.NewPrivateVirtualInterface.CustomerAddress = aws.String(v.(string))
}
if v, ok := d.GetOk("amazon_address"); ok && v.(string) != "" {
req.NewPrivateVirtualInterface.AmazonAddress = aws.String(v.(string))
}

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

d.SetId(aws.StringValue(resp.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 := dxPrivateVirtualInterfaceWaitUntilAvailable(d, conn); err != nil {
return err
}

return resourceAwsDxPrivateVirtualInterfaceUpdate(d, meta)
}

func resourceAwsDxPrivateVirtualInterfaceRead(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 virtual interface (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

d.Set("connection_id", vif.ConnectionId)
d.Set("name", vif.VirtualInterfaceName)
d.Set("vlan", vif.Vlan)
d.Set("bgp_asn", vif.Asn)
d.Set("bgp_auth_key", vif.AuthKey)
d.Set("address_family", vif.AddressFamily)
d.Set("customer_address", vif.CustomerAddress)
d.Set("amazon_address", vif.AmazonAddress)
d.Set("vpn_gateway_id", vif.VirtualGatewayId)
d.Set("dx_gateway_id", vif.DirectConnectGatewayId)
if err := getTagsDX(conn, d, d.Get("arn").(string)); err != nil {
return err
}

return nil
}

func resourceAwsDxPrivateVirtualInterfaceUpdate(d *schema.ResourceData, meta interface{}) error {
if err := dxVirtualInterfaceUpdate(d, meta); err != nil {
return err
}

return resourceAwsDxPrivateVirtualInterfaceRead(d, meta)
}

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

func resourceAwsDxPrivateVirtualInterfaceImport(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 dxPrivateVirtualInterfaceWaitUntilAvailable(d *schema.ResourceData, conn *directconnect.DirectConnect) error {
return dxVirtualInterfaceWaitUntilAvailable(
d,
conn,
[]string{
directconnect.VirtualInterfaceStatePending,
},
[]string{
directconnect.VirtualInterfaceStateAvailable,
directconnect.VirtualInterfaceStateDown,
})
}
Loading

0 comments on commit 53e19f2

Please sign in to comment.