From 7fac1ab1f69b813ee2fc0dd1590d9b15a178d9fc Mon Sep 17 00:00:00 2001 From: Bryan Burgers Date: Mon, 17 Apr 2017 07:18:06 -0500 Subject: [PATCH] provider/aws: Allow IPv6/IPv4 addresses to coexist Fix an issue when trying to get a public IPv4 address and a public IPv6 address that results in the following error: Error launching source instance: InvalidParameterCombination: Network interfaces and an instance-level IPv6 address count may not be specified on the same request To fix, in situations where we want a IPv6 addresses AND we need to manually specify network interfaces on the instance, create the IPv6 addresses on the network interface that we're creating rather than on the instance itself. Fixes #13250 --- .../providers/aws/resource_aws_instance.go | 59 +++++++++++++------ .../aws/resource_aws_instance_test.go | 55 +++++++++++++++++ 2 files changed, 95 insertions(+), 19 deletions(-) diff --git a/builtin/providers/aws/resource_aws_instance.go b/builtin/providers/aws/resource_aws_instance.go index 153334ded3..1e655f3c8a 100644 --- a/builtin/providers/aws/resource_aws_instance.go +++ b/builtin/providers/aws/resource_aws_instance.go @@ -408,6 +408,8 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error { ImageId: instanceOpts.ImageID, InstanceInitiatedShutdownBehavior: instanceOpts.InstanceInitiatedShutdownBehavior, InstanceType: instanceOpts.InstanceType, + Ipv6AddressCount: instanceOpts.Ipv6AddressCount, + Ipv6Addresses: instanceOpts.Ipv6Addresses, KeyName: instanceOpts.KeyName, MaxCount: aws.Int64(int64(1)), MinCount: aws.Int64(int64(1)), @@ -420,30 +422,13 @@ func resourceAwsInstanceCreate(d *schema.ResourceData, meta interface{}) error { UserData: instanceOpts.UserData64, } - ipv6Count, ipv6CountOk := d.GetOk("ipv6_address_count") - ipv6Address, ipv6AddressOk := d.GetOk("ipv6_addresses") + _, ipv6CountOk := d.GetOk("ipv6_address_count") + _, ipv6AddressOk := d.GetOk("ipv6_addresses") if ipv6AddressOk && ipv6CountOk { return fmt.Errorf("Only 1 of `ipv6_address_count` or `ipv6_addresses` can be specified") } - if ipv6CountOk { - runOpts.Ipv6AddressCount = aws.Int64(int64(ipv6Count.(int))) - } - - if ipv6AddressOk { - ipv6Addresses := make([]*ec2.InstanceIpv6Address, len(ipv6Address.([]interface{}))) - for _, address := range ipv6Address.([]interface{}) { - ipv6Address := &ec2.InstanceIpv6Address{ - Ipv6Address: aws.String(address.(string)), - } - - ipv6Addresses = append(ipv6Addresses, ipv6Address) - } - - runOpts.Ipv6Addresses = ipv6Addresses - } - restricted := meta.(*AWSClient).IsGovCloud() || meta.(*AWSClient).IsChinaCloud() if !restricted { tagsSpec := make([]*ec2.TagSpecification, 0) @@ -1202,6 +1187,23 @@ func buildNetworkInterfaceOpts(d *schema.ResourceData, groups []*string, nInterf ni.PrivateIpAddress = aws.String(v.(string)) } + if v, ok := d.GetOk("ipv6_address_count"); ok { + ni.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) + } + + ni.Ipv6Addresses = ipv6Addresses + } + if v := d.Get("vpc_security_group_ids").(*schema.Set); v.Len() > 0 { for _, v := range v.List() { ni.Groups = append(ni.Groups, aws.String(v.(string))) @@ -1436,6 +1438,8 @@ type awsInstanceOpts struct { ImageID *string InstanceInitiatedShutdownBehavior *string InstanceType *string + Ipv6AddressCount *int64 + Ipv6Addresses []*ec2.InstanceIpv6Address KeyName *string NetworkInterfaces []*ec2.InstanceNetworkInterfaceSpecification Placement *ec2.Placement @@ -1533,6 +1537,23 @@ func buildAwsInstanceOpts( opts.SecurityGroups = groups } + if v, ok := d.GetOk("ipv6_address_count"); ok { + opts.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) + } + + opts.Ipv6Addresses = ipv6Addresses + } + if v := d.Get("vpc_security_group_ids").(*schema.Set); v.Len() > 0 { for _, v := range v.List() { opts.SecurityGroupIDs = append(opts.SecurityGroupIDs, aws.String(v.(string))) diff --git a/builtin/providers/aws/resource_aws_instance_test.go b/builtin/providers/aws/resource_aws_instance_test.go index e8f93547e1..9e4e725c6d 100644 --- a/builtin/providers/aws/resource_aws_instance_test.go +++ b/builtin/providers/aws/resource_aws_instance_test.go @@ -538,6 +538,29 @@ func TestAccAWSInstance_ipv6AddressCountAndSingleAddressCausesError(t *testing.T }) } +func TestAccAWSInstance_ipv6_supportAddressCountWithIpv4(t *testing.T) { + var v ec2.Instance + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckInstanceDestroy, + Steps: []resource.TestStep{ + { + Config: testAccInstanceConfigIpv6SupportWithIpv4, + 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 @@ -1463,6 +1486,38 @@ resource "aws_instance" "foo" { } ` +const testAccInstanceConfigIpv6SupportWithIpv4 = ` +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}" + + associate_public_ip_address = true + ipv6_address_count = 1 + tags { + Name = "tf-ipv6-instance-acc-test" + } +} +` + const testAccInstanceConfigMultipleRegions = ` provider "aws" { alias = "west"