Skip to content

Commit

Permalink
Merge branch 'ewbankkit-issue-3248'
Browse files Browse the repository at this point in the history
  • Loading branch information
bflad committed Jun 25, 2018
2 parents eedf978 + 4e6ac46 commit 66b5ec4
Show file tree
Hide file tree
Showing 5 changed files with 430 additions and 0 deletions.
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,7 @@ func Provider() terraform.ResourceProvider {
"aws_dx_hosted_private_virtual_interface": resourceAwsDxHostedPrivateVirtualInterface(),
"aws_dx_hosted_private_virtual_interface_accepter": resourceAwsDxHostedPrivateVirtualInterfaceAccepter(),
"aws_dx_private_virtual_interface": resourceAwsDxPrivateVirtualInterface(),
"aws_dx_public_virtual_interface": resourceAwsDxPublicVirtualInterface(),
"aws_dynamodb_table": resourceAwsDynamoDbTable(),
"aws_dynamodb_table_item": resourceAwsDynamoDbTableItem(),
"aws_dynamodb_global_table": resourceAwsDynamoDbGlobalTable(),
Expand Down
223 changes: 223 additions & 0 deletions aws/resource_aws_dx_public_virtual_interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
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 resourceAwsDxPublicVirtualInterface() *schema.Resource {
return &schema.Resource{
Create: resourceAwsDxPublicVirtualInterfaceCreate,
Read: resourceAwsDxPublicVirtualInterfaceRead,
Update: resourceAwsDxPublicVirtualInterfaceUpdate,
Delete: resourceAwsDxPublicVirtualInterfaceDelete,
Importer: &schema.ResourceImporter{
State: resourceAwsDxPublicVirtualInterfaceImport,
},
CustomizeDiff: resourceAwsDxPublicVirtualInterfaceCustomizeDiff,

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,
},
"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,
},
"route_filter_prefixes": &schema.Schema{
Type: schema.TypeSet,
Required: true,
ForceNew: true,
Elem: &schema.Schema{Type: schema.TypeString},
MinItems: 1,
},
"tags": tagsSchema(),
},

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

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

req := &directconnect.CreatePublicVirtualInterfaceInput{
ConnectionId: aws.String(d.Get("connection_id").(string)),
NewPublicVirtualInterface: &directconnect.NewPublicVirtualInterface{
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 v, ok := d.GetOk("bgp_auth_key"); ok && v.(string) != "" {
req.NewPublicVirtualInterface.AuthKey = aws.String(v.(string))
}
if v, ok := d.GetOk("customer_address"); ok && v.(string) != "" {
req.NewPublicVirtualInterface.CustomerAddress = aws.String(v.(string))
}
if v, ok := d.GetOk("amazon_address"); ok && v.(string) != "" {
req.NewPublicVirtualInterface.AmazonAddress = aws.String(v.(string))
}
if v, ok := d.GetOk("route_filter_prefixes"); ok {
req.NewPublicVirtualInterface.RouteFilterPrefixes = expandDxRouteFilterPrefixes(v.(*schema.Set).List())
}

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

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 := dxPublicVirtualInterfaceWaitUntilAvailable(d, conn); err != nil {
return err
}

return resourceAwsDxPublicVirtualInterfaceUpdate(d, meta)
}

func resourceAwsDxPublicVirtualInterfaceRead(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("route_filter_prefixes", flattenDxRouteFilterPrefixes(vif.RouteFilterPrefixes))
if err := getTagsDX(conn, d, d.Get("arn").(string)); err != nil {
return err
}

return nil
}

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

return resourceAwsDxPublicVirtualInterfaceRead(d, meta)
}

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

func resourceAwsDxPublicVirtualInterfaceImport(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 resourceAwsDxPublicVirtualInterfaceCustomizeDiff(diff *schema.ResourceDiff, meta interface{}) error {
if diff.Id() == "" {
// New resource.
if addressFamily := diff.Get("address_family").(string); addressFamily == directconnect.AddressFamilyIpv4 {
if _, ok := diff.GetOk("customer_address"); !ok {
return fmt.Errorf("'customer_address' must be set when 'address_family' is '%s'", addressFamily)
}
if _, ok := diff.GetOk("amazon_address"); !ok {
return fmt.Errorf("'amazon_address' must be set when 'address_family' is '%s'", addressFamily)
}
}
}

return nil
}

func dxPublicVirtualInterfaceWaitUntilAvailable(d *schema.ResourceData, conn *directconnect.DirectConnect) error {
return dxVirtualInterfaceWaitUntilAvailable(
d,
conn,
[]string{
directconnect.VirtualInterfaceStatePending,
},
[]string{
directconnect.VirtualInterfaceStateAvailable,
directconnect.VirtualInterfaceStateDown,
directconnect.VirtualInterfaceStateVerifying,
})
}
134 changes: 134 additions & 0 deletions aws/resource_aws_dx_public_virtual_interface_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
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/terraform"
)

func TestAccAwsDxPublicVirtualInterface_basic(t *testing.T) {
key := "DX_CONNECTION_ID"
connectionId := os.Getenv(key)
if connectionId == "" {
t.Skipf("Environment variable %s is not set", key)
}
vifName := fmt.Sprintf("terraform-testacc-dxvif-%s", acctest.RandString(5))
bgpAsn := randIntRange(64512, 65534)

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAwsDxPublicVirtualInterfaceDestroy,
Steps: []resource.TestStep{
{
Config: testAccDxPublicVirtualInterfaceConfig_noTags(connectionId, vifName, bgpAsn),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsDxPublicVirtualInterfaceExists("aws_dx_public_virtual_interface.foo"),
resource.TestCheckResourceAttr("aws_dx_public_virtual_interface.foo", "name", vifName),
resource.TestCheckResourceAttr("aws_dx_public_virtual_interface.foo", "tags.%", "0"),
),
},
{
Config: testAccDxPublicVirtualInterfaceConfig_tags(connectionId, vifName, bgpAsn),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsDxPublicVirtualInterfaceExists("aws_dx_public_virtual_interface.foo"),
resource.TestCheckResourceAttr("aws_dx_public_virtual_interface.foo", "name", vifName),
resource.TestCheckResourceAttr("aws_dx_public_virtual_interface.foo", "tags.%", "1"),
resource.TestCheckResourceAttr("aws_dx_public_virtual_interface.foo", "tags.Environment", "test"),
),
},
// Test import.
{
ResourceName: "aws_dx_public_virtual_interface.foo",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccCheckAwsDxPublicVirtualInterfaceDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).dxconn

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_dx_public_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 Public VIF (%s) not deleted", rs.Primary.ID)
}
}
}
return nil
}

func testAccCheckAwsDxPublicVirtualInterfaceExists(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 testAccDxPublicVirtualInterfaceConfig_noTags(cid, n string, bgpAsn int) string {
return fmt.Sprintf(`
resource "aws_dx_public_virtual_interface" "foo" {
connection_id = "%s"
name = "%s"
vlan = 4094
address_family = "ipv4"
bgp_asn = %d
customer_address = "175.45.176.1/30"
amazon_address = "175.45.176.2/30"
route_filter_prefixes = [
"210.52.109.0/24",
"175.45.176.0/22"
]
}
`, cid, n, bgpAsn)
}

func testAccDxPublicVirtualInterfaceConfig_tags(cid, n string, bgpAsn int) string {
return fmt.Sprintf(`
resource "aws_dx_public_virtual_interface" "foo" {
connection_id = "%s"
name = "%s"
vlan = 4094
address_family = "ipv4"
bgp_asn = %d
customer_address = "175.45.176.1/30"
amazon_address = "175.45.176.2/30"
route_filter_prefixes = [
"210.52.109.0/24",
"175.45.176.0/22"
]
tags {
Environment = "test"
}
}
`, cid, n, bgpAsn)
}
3 changes: 3 additions & 0 deletions website/aws.erb
Original file line number Diff line number Diff line change
Expand Up @@ -788,6 +788,9 @@
<li<%= sidebar_current("docs-aws-resource-dx-private-virtual-interface") %>>
<a href="/docs/providers/aws/r/dx_private_virtual_interface.html">aws_dx_private_virtual_interface</a>
</li>
<li<%= sidebar_current("docs-aws-resource-dx-public-virtual-interface") %>>
<a href="/docs/providers/aws/r/dx_public_virtual_interface.html">aws_dx_public_virtual_interface</a>
</li>
</ul>
</li>

Expand Down
Loading

0 comments on commit 66b5ec4

Please sign in to comment.