diff --git a/aws/resource_aws_vpc.go b/aws/resource_aws_vpc.go index 9fa19f1592d..e1687477d0a 100644 --- a/aws/resource_aws_vpc.go +++ b/aws/resource_aws_vpc.go @@ -10,6 +10,7 @@ import ( "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/terraform/helper/resource" "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/helper/validation" ) func resourceAwsVpc() *schema.Resource { @@ -21,6 +22,7 @@ func resourceAwsVpc() *schema.Resource { Importer: &schema.ResourceImporter{ State: resourceAwsVpcInstanceImport, }, + CustomizeDiff: resourceAwsVpcCustomizeDiff, SchemaVersion: 1, MigrateState: resourceAwsVpcMigrateState, @@ -34,10 +36,10 @@ func resourceAwsVpc() *schema.Resource { }, "instance_tenancy": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Computed: true, + Type: schema.TypeString, + Optional: true, + Default: ec2.TenancyDefault, + ValidateFunc: validation.StringInSlice([]string{ec2.TenancyDefault, ec2.TenancyDedicated}, false), }, "enable_dns_hostnames": { @@ -112,15 +114,11 @@ func resourceAwsVpc() *schema.Resource { func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn - instance_tenancy := "default" - if v, ok := d.GetOk("instance_tenancy"); ok { - instance_tenancy = v.(string) - } // Create the VPC createOpts := &ec2.CreateVpcInput{ CidrBlock: aws.String(d.Get("cidr_block").(string)), - InstanceTenancy: aws.String(instance_tenancy), + InstanceTenancy: aws.String(d.Get("instance_tenancy").(string)), AmazonProvidedIpv6CidrBlock: aws.Bool(d.Get("assign_generated_ipv6_cidr_block").(bool)), } @@ -452,6 +450,21 @@ func resourceAwsVpcUpdate(d *schema.ResourceData, meta interface{}) error { d.SetPartial("assign_generated_ipv6_cidr_block") } + if d.HasChange("instance_tenancy") && !d.IsNewResource() { + modifyOpts := &ec2.ModifyVpcTenancyInput{ + VpcId: aws.String(vpcid), + InstanceTenancy: aws.String(d.Get("instance_tenancy").(string)), + } + log.Printf( + "[INFO] Modifying instance_tenancy vpc attribute for %s: %#v", + d.Id(), modifyOpts) + if _, err := conn.ModifyVpcTenancy(modifyOpts); err != nil { + return err + } + + d.SetPartial("instance_tenancy") + } + if err := setTags(conn, d); err != nil { return err } else { @@ -492,6 +505,17 @@ func resourceAwsVpcDelete(d *schema.ResourceData, meta interface{}) error { }) } +func resourceAwsVpcCustomizeDiff(diff *schema.ResourceDiff, v interface{}) error { + if diff.HasChange("instance_tenancy") { + old, new := diff.GetChange("instance_tenancy") + if old.(string) != ec2.TenancyDedicated || new.(string) != ec2.TenancyDefault { + diff.ForceNew("instance_tenancy") + } + } + + return nil +} + // VPCStateRefreshFunc returns a resource.StateRefreshFunc that is used to watch // a VPC. func VPCStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc { diff --git a/aws/resource_aws_vpc_test.go b/aws/resource_aws_vpc_test.go index 457a542facf..1059b255975 100644 --- a/aws/resource_aws_vpc_test.go +++ b/aws/resource_aws_vpc_test.go @@ -89,6 +89,8 @@ func TestAccAWSVpc_basic(t *testing.T) { testAccCheckVpcCidr(&vpc, "10.1.0.0/16"), resource.TestCheckResourceAttr( "aws_vpc.foo", "cidr_block", "10.1.0.0/16"), + resource.TestCheckResourceAttr( + "aws_vpc.foo", "instance_tenancy", "default"), resource.TestCheckResourceAttrSet( "aws_vpc.foo", "default_route_table_id"), resource.TestCheckResourceAttr( @@ -163,9 +165,48 @@ func TestAccAWSVpc_dedicatedTenancy(t *testing.T) { { Config: testAccVpcDedicatedConfig, Check: resource.ComposeTestCheckFunc( - testAccCheckVpcExists("aws_vpc.bar", &vpc), + testAccCheckVpcExists("aws_vpc.foo", &vpc), + resource.TestCheckResourceAttr( + "aws_vpc.foo", "instance_tenancy", "dedicated"), + ), + }, + }, + }) +} + +func TestAccAWSVpc_modifyTenancy(t *testing.T) { + var vpcDedicated ec2.Vpc + var vpcDefault ec2.Vpc + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckVpcDestroy, + Steps: []resource.TestStep{ + { + Config: testAccVpcDedicatedConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckVpcExists("aws_vpc.foo", &vpcDedicated), + resource.TestCheckResourceAttr( + "aws_vpc.foo", "instance_tenancy", "dedicated"), + ), + }, + { + Config: testAccVpcConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckVpcExists("aws_vpc.foo", &vpcDefault), + resource.TestCheckResourceAttr( + "aws_vpc.foo", "instance_tenancy", "default"), + testAccCheckVpcIdsEqual(&vpcDedicated, &vpcDefault), + ), + }, + { + Config: testAccVpcDedicatedConfig, + Check: resource.ComposeTestCheckFunc( + testAccCheckVpcExists("aws_vpc.foo", &vpcDedicated), resource.TestCheckResourceAttr( - "aws_vpc.bar", "instance_tenancy", "dedicated"), + "aws_vpc.foo", "instance_tenancy", "dedicated"), + testAccCheckVpcIdsNotEqual(&vpcDedicated, &vpcDefault), ), }, }, @@ -277,6 +318,26 @@ func testAccCheckVpcCidr(vpc *ec2.Vpc, expected string) resource.TestCheckFunc { } } +func testAccCheckVpcIdsEqual(vpc1, vpc2 *ec2.Vpc) resource.TestCheckFunc { + return func(s *terraform.State) error { + if *vpc1.VpcId != *vpc2.VpcId { + return fmt.Errorf("VPC IDs not equal") + } + + return nil + } +} + +func testAccCheckVpcIdsNotEqual(vpc1, vpc2 *ec2.Vpc) resource.TestCheckFunc { + return func(s *terraform.State) error { + if *vpc1.VpcId == *vpc2.VpcId { + return fmt.Errorf("VPC IDs are equal") + } + + return nil + } +} + func testAccCheckVpcExists(n string, vpc *ec2.Vpc) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] @@ -438,9 +499,9 @@ resource "aws_vpc" "foo" { } ` const testAccVpcDedicatedConfig = ` -resource "aws_vpc" "bar" { +resource "aws_vpc" "foo" { instance_tenancy = "dedicated" - cidr_block = "10.2.0.0/16" + cidr_block = "10.1.0.0/16" tags { Name = "terraform-testacc-vpc-dedicated" }