provider/aws: Implement IPV6 Support for ec2 / VPC (#10538)
* provider/aws: Add support for IPV6 enabled VPC ``` % make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSVpc' ==> Checking that code complies with gofmt requirements... go generate $(go list ./... | grep -v /terraform/vendor/) 2016/12/09 14:07:31 Generated command/internal_plugin_list.go TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSVpc -timeout 120m === RUN TestAccAWSVpc_importBasic --- PASS: TestAccAWSVpc_importBasic (43.03s) === RUN TestAccAWSVpc_basic --- PASS: TestAccAWSVpc_basic (36.32s) === RUN TestAccAWSVpc_enableIpv6 --- PASS: TestAccAWSVpc_enableIpv6 (29.37s) === RUN TestAccAWSVpc_dedicatedTenancy --- PASS: TestAccAWSVpc_dedicatedTenancy (36.63s) === RUN TestAccAWSVpc_tags --- PASS: TestAccAWSVpc_tags (67.54s) === RUN TestAccAWSVpc_update --- PASS: TestAccAWSVpc_update (66.16s) === RUN TestAccAWSVpc_bothDnsOptionsSet --- PASS: TestAccAWSVpc_bothDnsOptionsSet (16.82s) === RUN TestAccAWSVpc_DisabledDnsSupport --- PASS: TestAccAWSVpc_DisabledDnsSupport (36.52s) === RUN TestAccAWSVpc_classiclinkOptionSet --- PASS: TestAccAWSVpc_classiclinkOptionSet (38.13s) PASS ok github.com/hashicorp/terraform/builtin/providers/aws 739.543s ``` * provider/aws: New Resource: aws_egress_only_internet_gateway ``` make testacc TEST=./builtin/providers/aws TESTARGS='-run=TestAccAWSEgressOnlyInternetGateway_' ==> Checking that code complies with gofmt requirements... go generate $(go list ./... | grep -v /terraform/vendor/) 2016/12/09 14:22:16 Generated command/internal_plugin_list.go TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSEgressOnlyInternetGateway_ -timeout 120m === RUN TestAccAWSEgressOnlyInternetGateway_basic --- PASS: TestAccAWSEgressOnlyInternetGateway_basic (32.67s) PASS ok github.com/hashicorp/terraform/builtin/providers/aws 32.692s ``` * provider/aws: Add IPV6 support to aws_subnet ``` % make testacc TEST=./builtin/providers/aws % TESTARGS='-run=TestAccAWSSubnet_' % 1 ↵ ✹ ✭ ==> Checking that code complies with gofmt requirements... go generate $(go list ./... | grep -v /terraform/vendor/) 2017/02/27 19:08:34 Generated command/internal_plugin_list.go TF_ACC=1 go test ./builtin/providers/aws -v -run=TestAccAWSSubnet_ -timeout 120m === RUN TestAccAWSSubnet_importBasic --- PASS: TestAccAWSSubnet_importBasic (69.88s) === RUN TestAccAWSSubnet_basic --- PASS: TestAccAWSSubnet_basic (51.28s) === RUN TestAccAWSSubnet_ipv6 --- PASS: TestAccAWSSubnet_ipv6 (90.39s) PASS ok github.com/hashicorp/terraform/builtin/providers/aws211.574s ``` * provider/aws: Add support for running aws_instances with ipv6 addresses
This commit is contained in:
parent
3d198295f2
commit
177400dbbf
|
@ -275,6 +275,7 @@ func Provider() terraform.ResourceProvider {
|
|||
"aws_ecs_task_definition": resourceAwsEcsTaskDefinition(),
|
||||
"aws_efs_file_system": resourceAwsEfsFileSystem(),
|
||||
"aws_efs_mount_target": resourceAwsEfsMountTarget(),
|
||||
"aws_egress_only_internet_gateway": resourceAwsEgressOnlyInternetGateway(),
|
||||
"aws_eip": resourceAwsEip(),
|
||||
"aws_eip_association": resourceAwsEipAssociation(),
|
||||
"aws_elasticache_cluster": resourceAwsElasticacheCluster(),
|
||||
|
|
|
@ -0,0 +1,126 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/awserr"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/errwrap"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
func resourceAwsEgressOnlyInternetGateway() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceAwsEgressOnlyInternetGatewayCreate,
|
||||
Read: resourceAwsEgressOnlyInternetGatewayRead,
|
||||
Delete: resourceAwsEgressOnlyInternetGatewayDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"vpc_id": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsEgressOnlyInternetGatewayCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
resp, err := conn.CreateEgressOnlyInternetGateway(&ec2.CreateEgressOnlyInternetGatewayInput{
|
||||
VpcId: aws.String(d.Get("vpc_id").(string)),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating egress internet gateway: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(*resp.EgressOnlyInternetGateway.EgressOnlyInternetGatewayId)
|
||||
|
||||
err = resource.Retry(5*time.Minute, func() *resource.RetryError {
|
||||
igRaw, _, err := EIGWStateRefreshFunc(conn, d.Id())()
|
||||
if igRaw != nil {
|
||||
return nil
|
||||
}
|
||||
if err == nil {
|
||||
return resource.RetryableError(err)
|
||||
} else {
|
||||
return resource.NonRetryableError(err)
|
||||
}
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return errwrap.Wrapf("{{err}}", err)
|
||||
}
|
||||
|
||||
return resourceAwsEgressOnlyInternetGatewayRead(d, meta)
|
||||
}
|
||||
|
||||
func EIGWStateRefreshFunc(conn *ec2.EC2, id string) resource.StateRefreshFunc {
|
||||
return func() (interface{}, string, error) {
|
||||
resp, err := conn.DescribeEgressOnlyInternetGateways(&ec2.DescribeEgressOnlyInternetGatewaysInput{
|
||||
EgressOnlyInternetGatewayIds: []*string{aws.String(id)},
|
||||
})
|
||||
if err != nil {
|
||||
ec2err, ok := err.(awserr.Error)
|
||||
if ok && ec2err.Code() == "InvalidEgressInternetGatewayID.NotFound" {
|
||||
resp = nil
|
||||
} else {
|
||||
log.Printf("[ERROR] Error on EIGWStateRefreshFunc: %s", err)
|
||||
return nil, "", err
|
||||
}
|
||||
}
|
||||
|
||||
if resp == nil {
|
||||
// Sometimes AWS just has consistency issues and doesn't see
|
||||
// our instance yet. Return an empty state.
|
||||
return nil, "", nil
|
||||
}
|
||||
|
||||
ig := resp.EgressOnlyInternetGateways[0]
|
||||
return ig, "available", nil
|
||||
}
|
||||
}
|
||||
|
||||
func resourceAwsEgressOnlyInternetGatewayRead(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
resp, err := conn.DescribeEgressOnlyInternetGateways(&ec2.DescribeEgressOnlyInternetGatewaysInput{
|
||||
EgressOnlyInternetGatewayIds: []*string{aws.String(d.Id())},
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error describing egress internet gateway: %s", err)
|
||||
}
|
||||
|
||||
found := false
|
||||
for _, igw := range resp.EgressOnlyInternetGateways {
|
||||
if *igw.EgressOnlyInternetGatewayId == d.Id() {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
|
||||
if !found {
|
||||
log.Printf("[Error] Cannot find Egress Only Internet Gateway: %q", d.Id())
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceAwsEgressOnlyInternetGatewayDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
conn := meta.(*AWSClient).ec2conn
|
||||
|
||||
_, err := conn.DeleteEgressOnlyInternetGateway(&ec2.DeleteEgressOnlyInternetGatewayInput{
|
||||
EgressOnlyInternetGatewayId: aws.String(d.Id()),
|
||||
})
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting egress internet gateway: %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
package aws
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/service/ec2"
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccAWSEgressOnlyInternetGateway_basic(t *testing.T) {
|
||||
var igw ec2.EgressOnlyInternetGateway
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckAWSEgressOnlyInternetGatewayDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccAWSEgressOnlyInternetGatewayConfig_basic,
|
||||
Check: resource.ComposeAggregateTestCheckFunc(
|
||||
testAccCheckAWSEgressOnlyInternetGatewayExists("aws_egress_only_internet_gateway.foo", &igw),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckAWSEgressOnlyInternetGatewayDestroy(s *terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "aws_egress_only_internet_gateway" {
|
||||
continue
|
||||
}
|
||||
|
||||
describe, err := conn.DescribeEgressOnlyInternetGateways(&ec2.DescribeEgressOnlyInternetGatewaysInput{
|
||||
EgressOnlyInternetGatewayIds: []*string{aws.String(rs.Primary.ID)},
|
||||
})
|
||||
|
||||
if err == nil {
|
||||
if len(describe.EgressOnlyInternetGateways) != 0 &&
|
||||
*describe.EgressOnlyInternetGateways[0].EgressOnlyInternetGatewayId == rs.Primary.ID {
|
||||
return fmt.Errorf("Egress Only Internet Gateway %q still exists", rs.Primary.ID)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckAWSEgressOnlyInternetGatewayExists(n string, igw *ec2.EgressOnlyInternetGateway) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", n)
|
||||
}
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No Egress Only IGW ID is set")
|
||||
}
|
||||
|
||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
resp, err := conn.DescribeEgressOnlyInternetGateways(&ec2.DescribeEgressOnlyInternetGatewaysInput{
|
||||
EgressOnlyInternetGatewayIds: []*string{aws.String(rs.Primary.ID)},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(resp.EgressOnlyInternetGateways) == 0 {
|
||||
return fmt.Errorf("Egress Only IGW not found")
|
||||
}
|
||||
|
||||
*igw = *resp.EgressOnlyInternetGateways[0]
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const testAccAWSEgressOnlyInternetGatewayConfig_basic = `
|
||||
resource "aws_vpc" "foo" {
|
||||
cidr_block = "10.1.0.0/16"
|
||||
assign_generated_ipv6_cidr_block = true
|
||||
}
|
||||
|
||||
resource "aws_egress_only_internet_gateway" "foo" {
|
||||
vpc_id = "${aws_vpc.foo.id}"
|
||||
}
|
||||
`
|
|
@ -175,6 +175,23 @@ func resourceAwsInstance() *schema.Resource {
|
|||
Optional: true,
|
||||
},
|
||||
|
||||
"ipv6_address_count": {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"ipv6_addresses": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
ConflictsWith: []string{"ipv6_address_count"},
|
||||
},
|
||||
|
||||
"tenancy": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
|
@ -363,6 +380,23 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
UserData: instanceOpts.UserData64,
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("ipv6_address_count"); ok {
|
||||
runOpts.Ipv6AddressCount = aws.Int64(int64(v.(int)))
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("ipv6_addresses"); ok {
|
||||
ipv6Addresses := make([]*ec2.InstanceIpv6Address, len(v.([]interface{})))
|
||||
for _, address := range v.([]interface{}) {
|
||||
ipv6Address := &ec2.InstanceIpv6Address{
|
||||
Ipv6Address: aws.String(address.(string)),
|
||||
}
|
||||
|
||||
ipv6Addresses = append(ipv6Addresses, ipv6Address)
|
||||
}
|
||||
|
||||
runOpts.Ipv6Addresses = ipv6Addresses
|
||||
}
|
||||
|
||||
// Create the instance
|
||||
log.Printf("[DEBUG] Run configuration: %s", runOpts)
|
||||
|
||||
|
@ -501,6 +535,13 @@ func resourceAwsInstanceRead(d *schema.ResourceData, meta interface{}) error {
|
|||
d.Set("subnet_id", ni.SubnetId)
|
||||
d.Set("network_interface_id", ni.NetworkInterfaceId)
|
||||
d.Set("associate_public_ip_address", ni.Association != nil)
|
||||
d.Set("ipv6_address_count", len(ni.Ipv6Addresses))
|
||||
|
||||
var ipv6Addresses []string
|
||||
for _, address := range ni.Ipv6Addresses {
|
||||
ipv6Addresses = append(ipv6Addresses, *address.Ipv6Address)
|
||||
}
|
||||
d.Set("ipv6_addresses", ipv6Addresses)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -498,6 +498,29 @@ func TestAccAWSInstance_vpc(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSInstance_ipv6_supportAddressCount(t *testing.T) {
|
||||
var v ec2.Instance
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckInstanceDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccInstanceConfigIpv6Support,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckInstanceExists(
|
||||
"aws_instance.foo", &v),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_instance.foo",
|
||||
"ipv6_address_count",
|
||||
"1"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSInstance_multipleRegions(t *testing.T) {
|
||||
var v ec2.Instance
|
||||
|
||||
|
@ -1123,6 +1146,37 @@ resource "aws_instance" "foo" {
|
|||
}
|
||||
`
|
||||
|
||||
const testAccInstanceConfigIpv6Support = `
|
||||
resource "aws_vpc" "foo" {
|
||||
cidr_block = "10.1.0.0/16"
|
||||
assign_generated_ipv6_cidr_block = true
|
||||
tags {
|
||||
Name = "tf-ipv6-instance-acc-test"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_subnet" "foo" {
|
||||
cidr_block = "10.1.1.0/24"
|
||||
vpc_id = "${aws_vpc.foo.id}"
|
||||
ipv6_cidr_block = "${cidrsubnet(aws_vpc.foo.ipv6_cidr_block, 8, 1)}"
|
||||
tags {
|
||||
Name = "tf-ipv6-instance-acc-test"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_instance" "foo" {
|
||||
# us-west-2
|
||||
ami = "ami-c5eabbf5"
|
||||
instance_type = "t2.micro"
|
||||
subnet_id = "${aws_subnet.foo.id}"
|
||||
|
||||
ipv6_address_count = 1
|
||||
tags {
|
||||
Name = "tf-ipv6-instance-acc-test"
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const testAccInstanceConfigMultipleRegions = `
|
||||
provider "aws" {
|
||||
alias = "west"
|
||||
|
|
|
@ -23,31 +23,48 @@ func resourceAwsSubnet() *schema.Resource {
|
|||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"vpc_id": &schema.Schema{
|
||||
"vpc_id": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"cidr_block": &schema.Schema{
|
||||
"cidr_block": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"availability_zone": &schema.Schema{
|
||||
"ipv6_cidr_block": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"availability_zone": {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"map_public_ip_on_launch": &schema.Schema{
|
||||
"map_public_ip_on_launch": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
|
||||
"assign_ipv6_address_on_creation": {
|
||||
Type: schema.TypeBool,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
|
||||
"ipv6_cidr_block_association_id": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"tags": tagsSchema(),
|
||||
},
|
||||
}
|
||||
|
@ -62,6 +79,10 @@ func resourceAwsSubnetCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
VpcId: aws.String(d.Get("vpc_id").(string)),
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk("ipv6_cidr_block"); ok {
|
||||
createOpts.Ipv6CidrBlock = aws.String(v.(string))
|
||||
}
|
||||
|
||||
var err error
|
||||
resp, err := conn.CreateSubnet(createOpts)
|
||||
|
||||
|
@ -119,6 +140,11 @@ func resourceAwsSubnetRead(d *schema.ResourceData, meta interface{}) error {
|
|||
d.Set("availability_zone", subnet.AvailabilityZone)
|
||||
d.Set("cidr_block", subnet.CidrBlock)
|
||||
d.Set("map_public_ip_on_launch", subnet.MapPublicIpOnLaunch)
|
||||
d.Set("assign_ipv6_address_on_creation", subnet.AssignIpv6AddressOnCreation)
|
||||
if subnet.Ipv6CidrBlockAssociationSet != nil {
|
||||
d.Set("ipv6_cidr_block", subnet.Ipv6CidrBlockAssociationSet[0].Ipv6CidrBlock)
|
||||
d.Set("ipv6_cidr_block_association_id", subnet.Ipv6CidrBlockAssociationSet[0].AssociationId)
|
||||
}
|
||||
d.Set("tags", tagsToMap(subnet.Tags))
|
||||
|
||||
return nil
|
||||
|
@ -135,6 +161,25 @@ func resourceAwsSubnetUpdate(d *schema.ResourceData, meta interface{}) error {
|
|||
d.SetPartial("tags")
|
||||
}
|
||||
|
||||
if d.HasChange("assign_ipv6_address_on_creation") {
|
||||
modifyOpts := &ec2.ModifySubnetAttributeInput{
|
||||
SubnetId: aws.String(d.Id()),
|
||||
AssignIpv6AddressOnCreation: &ec2.AttributeBooleanValue{
|
||||
Value: aws.Bool(d.Get("assign_ipv6_address_on_creation").(bool)),
|
||||
},
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Subnet modify attributes: %#v", modifyOpts)
|
||||
|
||||
_, err := conn.ModifySubnetAttribute(modifyOpts)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
} else {
|
||||
d.SetPartial("assign_ipv6_address_on_creation")
|
||||
}
|
||||
}
|
||||
|
||||
if d.HasChange("map_public_ip_on_launch") {
|
||||
modifyOpts := &ec2.ModifySubnetAttributeInput{
|
||||
SubnetId: aws.String(d.Id()),
|
||||
|
|
|
@ -32,7 +32,7 @@ func TestAccAWSSubnet_basic(t *testing.T) {
|
|||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckSubnetDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
{
|
||||
Config: testAccSubnetConfig,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckSubnetExists(
|
||||
|
@ -44,6 +44,55 @@ func TestAccAWSSubnet_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSSubnet_ipv6(t *testing.T) {
|
||||
var v ec2.Subnet
|
||||
|
||||
testCheck := func(*terraform.State) error {
|
||||
if v.Ipv6CidrBlockAssociationSet == nil {
|
||||
return fmt.Errorf("Expected IPV6 CIDR Block Association")
|
||||
}
|
||||
|
||||
if *v.AssignIpv6AddressOnCreation != true {
|
||||
return fmt.Errorf("bad AssignIpv6AddressOnCreation: %t", *v.AssignIpv6AddressOnCreation)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
testCheckUpdated := func(*terraform.State) error {
|
||||
if *v.AssignIpv6AddressOnCreation != false {
|
||||
return fmt.Errorf("bad AssignIpv6AddressOnCreation: %t", *v.AssignIpv6AddressOnCreation)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
IDRefreshName: "aws_subnet.foo",
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckSubnetDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccSubnetConfigIpv6,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckSubnetExists(
|
||||
"aws_subnet.foo", &v),
|
||||
testCheck,
|
||||
),
|
||||
},
|
||||
{
|
||||
Config: testAccSubnetConfigIpv6Updated,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckSubnetExists(
|
||||
"aws_subnet.foo", &v),
|
||||
testCheckUpdated,
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckSubnetDestroy(s *terraform.State) error {
|
||||
conn := testAccProvider.Meta().(*AWSClient).ec2conn
|
||||
|
||||
|
@ -119,3 +168,39 @@ resource "aws_subnet" "foo" {
|
|||
}
|
||||
}
|
||||
`
|
||||
|
||||
const testAccSubnetConfigIpv6 = `
|
||||
resource "aws_vpc" "foo" {
|
||||
cidr_block = "10.10.0.0/16"
|
||||
assign_generated_ipv6_cidr_block = true
|
||||
}
|
||||
|
||||
resource "aws_subnet" "foo" {
|
||||
cidr_block = "10.10.1.0/24"
|
||||
vpc_id = "${aws_vpc.foo.id}"
|
||||
ipv6_cidr_block = "${cidrsubnet(aws_vpc.foo.ipv6_cidr_block, 8, 1)}"
|
||||
map_public_ip_on_launch = true
|
||||
assign_ipv6_address_on_creation = true
|
||||
tags {
|
||||
Name = "tf-subnet-acc-test"
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const testAccSubnetConfigIpv6Updated = `
|
||||
resource "aws_vpc" "foo" {
|
||||
cidr_block = "10.10.0.0/16"
|
||||
assign_generated_ipv6_cidr_block = true
|
||||
}
|
||||
|
||||
resource "aws_subnet" "foo" {
|
||||
cidr_block = "10.10.1.0/24"
|
||||
vpc_id = "${aws_vpc.foo.id}"
|
||||
ipv6_cidr_block = "${cidrsubnet(aws_vpc.foo.ipv6_cidr_block, 8, 3)}"
|
||||
map_public_ip_on_launch = true
|
||||
assign_ipv6_address_on_creation = false
|
||||
tags {
|
||||
Name = "tf-subnet-acc-test"
|
||||
}
|
||||
}
|
||||
`
|
||||
|
|
|
@ -55,6 +55,13 @@ func resourceAwsVpc() *schema.Resource {
|
|||
Computed: true,
|
||||
},
|
||||
|
||||
"assign_generated_ipv6_cidr_block": {
|
||||
Type: schema.TypeBool,
|
||||
ForceNew: true,
|
||||
Optional: true,
|
||||
Default: false,
|
||||
},
|
||||
|
||||
"main_route_table_id": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
|
@ -80,6 +87,16 @@ func resourceAwsVpc() *schema.Resource {
|
|||
Computed: true,
|
||||
},
|
||||
|
||||
"ipv6_association_id": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"ipv6_cidr_block": {
|
||||
Type: schema.TypeString,
|
||||
Computed: true,
|
||||
},
|
||||
|
||||
"tags": tagsSchema(),
|
||||
},
|
||||
}
|
||||
|
@ -91,11 +108,14 @@ func resourceAwsVpcCreate(d *schema.ResourceData, meta interface{}) error {
|
|||
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),
|
||||
AmazonProvidedIpv6CidrBlock: aws.Bool(d.Get("assign_generated_ipv6_cidr_block").(bool)),
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] VPC create config: %#v", *createOpts)
|
||||
vpcResp, err := conn.CreateVpc(createOpts)
|
||||
if err != nil {
|
||||
|
@ -154,6 +174,14 @@ func resourceAwsVpcRead(d *schema.ResourceData, meta interface{}) error {
|
|||
// Tags
|
||||
d.Set("tags", tagsToMap(vpc.Tags))
|
||||
|
||||
if vpc.Ipv6CidrBlockAssociationSet != nil {
|
||||
d.Set("assign_generated_ipv6_cidr_block", true)
|
||||
d.Set("ipv6_association_id", vpc.Ipv6CidrBlockAssociationSet[0].AssociationId)
|
||||
d.Set("ipv6_cidr_block", vpc.Ipv6CidrBlockAssociationSet[0].Ipv6CidrBlock)
|
||||
} else {
|
||||
d.Set("assign_generated_ipv6_cidr_block", false)
|
||||
}
|
||||
|
||||
// Attributes
|
||||
attribute := "enableDnsSupport"
|
||||
DescribeAttrOpts := &ec2.DescribeVpcAttributeInput{
|
||||
|
|
|
@ -36,6 +36,31 @@ func TestAccAWSVpc_basic(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccAWSVpc_enableIpv6(t *testing.T) {
|
||||
var vpc ec2.Vpc
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckVpcDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccVpcConfigIpv6Enabled,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckVpcExists("aws_vpc.foo", &vpc),
|
||||
testAccCheckVpcCidr(&vpc, "10.1.0.0/16"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_vpc.foo", "cidr_block", "10.1.0.0/16"),
|
||||
resource.TestCheckResourceAttrSet(
|
||||
"aws_vpc.foo", "ipv6_association_id"),
|
||||
resource.TestCheckResourceAttrSet(
|
||||
"aws_vpc.foo", "ipv6_cidr_block"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccAWSVpc_dedicatedTenancy(t *testing.T) {
|
||||
var vpc ec2.Vpc
|
||||
|
||||
|
@ -251,6 +276,13 @@ resource "aws_vpc" "foo" {
|
|||
}
|
||||
`
|
||||
|
||||
const testAccVpcConfigIpv6Enabled = `
|
||||
resource "aws_vpc" "foo" {
|
||||
cidr_block = "10.1.0.0/16"
|
||||
assign_generated_ipv6_cidr_block = true
|
||||
}
|
||||
`
|
||||
|
||||
const testAccVpcConfigUpdate = `
|
||||
resource "aws_vpc" "foo" {
|
||||
cidr_block = "10.1.0.0/16"
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
---
|
||||
layout: "aws"
|
||||
page_title: "AWS: aws_egress_only_internet_gateway"
|
||||
sidebar_current: "docs-aws-resource-egress-only-internet-gateway"
|
||||
description: |-
|
||||
Provides a resource to create a VPC Egress Only Internet Gateway.
|
||||
---
|
||||
|
||||
# aws\_egress\_only\_internet\_gateway
|
||||
|
||||
[IPv6 only] Creates an egress-only Internet gateway for your VPC.
|
||||
An egress-only Internet gateway is used to enable outbound communication
|
||||
over IPv6 from instances in your VPC to the Internet, and prevents hosts
|
||||
outside of your VPC from initiating an IPv6 connection with your instance.
|
||||
|
||||
## Example Usage
|
||||
|
||||
```
|
||||
resource "aws_vpc" "foo" {
|
||||
cidr_block = "10.1.0.0/16"
|
||||
assign_amazon_ipv6_cidr_block = true
|
||||
}
|
||||
|
||||
resource "aws_egress_only_internet_gateway" "foo" {
|
||||
vpc_id = "${aws_vpc.foo.id}"
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
||||
The following arguments are supported:
|
||||
|
||||
* `vpc_id` - (Required) The VPC ID to create in.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
The following attributes are exported:
|
||||
|
||||
* `id` - The ID of the Egress Only Internet Gateway.
|
|
@ -77,6 +77,8 @@ instances. See [Shutdown Behavior](https://docs.aws.amazon.com/AWSEC2/latest/Use
|
|||
* `user_data` - (Optional) The user data to provide when launching the instance.
|
||||
* `iam_instance_profile` - (Optional) The IAM Instance Profile to
|
||||
launch the instance with.
|
||||
* `ipv6_address_count`- (Optional) A number of IPv6 addresses to associate with the primary network interface. Amazon EC2 chooses the IPv6 addresses from the range of your subnet.
|
||||
* `ipv6_addresses` - (Optional) Specify one or more IPv6 addresses from the range of the subnet to associate with the primary network interface
|
||||
* `tags` - (Optional) A mapping of tags to assign to the resource.
|
||||
* `root_block_device` - (Optional) Customize details about the root block
|
||||
device of the instance. See [Block Devices](#block-devices) below for details.
|
||||
|
|
|
@ -29,9 +29,14 @@ The following arguments are supported:
|
|||
|
||||
* `availability_zone`- (Optional) The AZ for the subnet.
|
||||
* `cidr_block` - (Required) The CIDR block for the subnet.
|
||||
* `ipv6_cidr_block` - (Optional) The IPv6 network range for the subnet,
|
||||
in CIDR notation. The subnet size must use a /64 prefix length.
|
||||
* `map_public_ip_on_launch` - (Optional) Specify true to indicate
|
||||
that instances launched into the subnet should be assigned
|
||||
a public IP address.
|
||||
a public IP address. Default is `false`.
|
||||
* `assign_ipv6_address_on_creation` - (Optional) Specify true to indicate
|
||||
that network interfaces created in the specified subnet should be
|
||||
assigned an IPv6 address. Default is `false`
|
||||
* `vpc_id` - (Required) The VPC ID.
|
||||
* `tags` - (Optional) A mapping of tags to assign to the resource.
|
||||
|
||||
|
|
|
@ -44,6 +44,9 @@ The following arguments are supported:
|
|||
* `enable_classiclink` - (Optional) A boolean flag to enable/disable ClassicLink
|
||||
for the VPC. Only valid in regions and accounts that support EC2 Classic.
|
||||
See the [ClassicLink documentation][1] for more information. Defaults false.
|
||||
* `assign_generated_ipv6_cidr_block` - (Optional) Requests an Amazon-provided IPv6 CIDR
|
||||
block with a /56 prefix length for the VPC. You cannot specify the range of IP addresses, or
|
||||
the size of the CIDR block. Default is `false`.
|
||||
* `tags` - (Optional) A mapping of tags to assign to the resource.
|
||||
|
||||
## Attributes Reference
|
||||
|
@ -62,6 +65,8 @@ The following attributes are exported:
|
|||
* `default_network_acl_id` - The ID of the network ACL created by default on VPC creation
|
||||
* `default_security_group_id` - The ID of the security group created by default on VPC creation
|
||||
* `default_route_table_id` - The ID of the route table created by default on VPC creation
|
||||
* `ipv6_association_id` - The association ID for the IPv6 CIDR block.
|
||||
* `ipv6_cidr_block` - The IPv6 CIDR block.
|
||||
|
||||
|
||||
[1]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/vpc-classiclink.html
|
||||
|
|
|
@ -1209,7 +1209,7 @@
|
|||
</li>
|
||||
|
||||
|
||||
<li<%= sidebar_current(/^docs-aws-resource-(default|customer|flow|internet-gateway|main-route|network|route-|security-group|subnet|vpc|vpn)/) %>>
|
||||
<li<%= sidebar_current(/^docs-aws-resource-(default|customer|egress-only-internet-gateway|flow|internet-gateway|main-route|network|route-|security-group|subnet|vpc|vpn)/) %>>
|
||||
<a href="#">VPC Resources</a>
|
||||
<ul class="nav nav-visible">
|
||||
|
||||
|
@ -1229,6 +1229,10 @@
|
|||
<a href="/docs/providers/aws/r/default_security_group.html">aws_default_security_group</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-egress-only-internet-gateway") %>>
|
||||
<a href="/docs/providers/aws/r/egress_only_internet_gateway.html">aws_egress_only_internet_gateway</a>
|
||||
</li>
|
||||
|
||||
<li<%= sidebar_current("docs-aws-resource-flow-log") %>>
|
||||
<a href="/docs/providers/aws/r/flow_log.html">aws_flow_log</a>
|
||||
</li>
|
||||
|
|
Loading…
Reference in New Issue