From 56dea14cad60c0b049d07ee8f00b20d81df7d863 Mon Sep 17 00:00:00 2001 From: Richard Hillmann Date: Mon, 17 Oct 2022 12:03:11 +0200 Subject: [PATCH 1/4] feat(vpc): Enable additional amazon provided ipv6 cidr * Extend existing `vpc_ipv6_cidr_block_association` resource to allow requesting additional ipv6 CIDR from the amazon pool --- .changelog/27274.txt | 3 + .../ec2/vpc_ipv6_cidr_block_association.go | 35 ++++++++--- .../vpc_ipv6_cidr_block_association_test.go | 61 +++++++++++++++++++ ..._ipv6_cidr_block_association.html.markdown | 17 +++--- 4 files changed, 100 insertions(+), 16 deletions(-) create mode 100644 .changelog/27274.txt diff --git a/.changelog/27274.txt b/.changelog/27274.txt new file mode 100644 index 00000000000..0808fab494f --- /dev/null +++ b/.changelog/27274.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_vpc_ipv6_cidr_block_association: Add `assign_generated_ipv6_cidr_block` and `ipv6_pool` argument +``` diff --git a/internal/service/ec2/vpc_ipv6_cidr_block_association.go b/internal/service/ec2/vpc_ipv6_cidr_block_association.go index 9894a5703a2..f310423f702 100644 --- a/internal/service/ec2/vpc_ipv6_cidr_block_association.go +++ b/internal/service/ec2/vpc_ipv6_cidr_block_association.go @@ -37,6 +37,12 @@ func ResourceVPCIPv6CIDRBlockAssociation() *schema.Resource { return nil }, Schema: map[string]*schema.Schema{ + "assign_generated_ipv6_cidr_block": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"ipv6_pool", "ipv6_ipam_pool_id", "ipv6_cidr_block", "ipv6_netmask_length"}, + }, "ipv6_cidr_block": { Type: schema.TypeString, Optional: true, @@ -46,13 +52,11 @@ func ResourceVPCIPv6CIDRBlockAssociation() *schema.Resource { verify.ValidIPv6CIDRNetworkAddress, validation.IsCIDRNetwork(VPCCIDRMaxIPv6, VPCCIDRMaxIPv6)), }, - // ipam parameters are not required by the API but other usage mechanisms are not implemented yet. TODO ipv6 options: - // --amazon-provided-ipv6-cidr-block - // --ipv6-pool "ipv6_ipam_pool_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"assign_generated_ipv6_cidr_block", "ipv6_pool"}, }, "ipv6_netmask_length": { Type: schema.TypeInt, @@ -63,6 +67,12 @@ func ResourceVPCIPv6CIDRBlockAssociation() *schema.Resource { // This RequiredWith setting should be applied once L57 is completed // RequiredWith: []string{"ipv6_ipam_pool_id"}, }, + "ipv6_pool": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"assign_generated_ipv6_cidr_block", "ipv6_ipam_pool_id"}, + }, "vpc_id": { Type: schema.TypeString, Required: true, @@ -85,18 +95,26 @@ func resourceVPCIPv6CIDRBlockAssociationCreate(d *schema.ResourceData, meta inte VpcId: aws.String(vpcID), } - if v, ok := d.GetOk("ipv6_cidr_block"); ok { - input.Ipv6CidrBlock = aws.String(v.(string)) + if v, ok := d.GetOk("assign_generated_ipv6_cidr_block"); ok { + input.AmazonProvidedIpv6CidrBlock = aws.Bool(v.(bool)) } if v, ok := d.GetOk("ipv6_ipam_pool_id"); ok { input.Ipv6IpamPoolId = aws.String(v.(string)) } + if v, ok := d.GetOk("ipv6_cidr_block"); ok { + input.Ipv6CidrBlock = aws.String(v.(string)) + } + if v, ok := d.GetOk("ipv6_netmask_length"); ok { input.Ipv6NetmaskLength = aws.Int64(int64(v.(int))) } + if v, ok := d.GetOk("ipv6_pool"); ok { + input.Ipv6Pool = aws.String(v.(string)) + } + log.Printf("[DEBUG] Creating EC2 VPC IPv6 CIDR Block Association: %s", input) output, err := conn.AssociateVpcCidrBlock(input) @@ -132,7 +150,6 @@ func resourceVPCIPv6CIDRBlockAssociationRead(d *schema.ResourceData, meta interf d.Set("ipv6_cidr_block", vpcIpv6CidrBlockAssociation.Ipv6CidrBlock) d.Set("vpc_id", vpc.VpcId) - return nil } diff --git a/internal/service/ec2/vpc_ipv6_cidr_block_association_test.go b/internal/service/ec2/vpc_ipv6_cidr_block_association_test.go index 66cbe9e7807..955fe90ba81 100644 --- a/internal/service/ec2/vpc_ipv6_cidr_block_association_test.go +++ b/internal/service/ec2/vpc_ipv6_cidr_block_association_test.go @@ -3,9 +3,11 @@ package ec2_test import ( "fmt" "strings" + "testing" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" @@ -72,3 +74,62 @@ func testAccCheckVPCAssociationIPv6CIDRPrefix(association *ec2.VpcIpv6CidrBlockA return nil } } + +func TestAccVPCIPv6CIDRBlockAssociation_basic(t *testing.T) { + var associationSecondary, associationTertiary ec2.VpcIpv6CidrBlockAssociation + resource1Name := "aws_vpc_ipv6_cidr_block_association.secondary_cidr" + resource2Name := "aws_vpc_ipv6_cidr_block_association.tertiary_cidr" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckVPCIPv6CIDRBlockAssociationDestroy, + Steps: []resource.TestStep{ + { + Config: testAccVPCIPv6CIDRBlockAssociationConfig_amazon_provided(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckVPCIPv6CIDRBlockAssociationExists(resource1Name, &associationSecondary), + testAccCheckVPCIPv6CIDRBlockAssociationExists(resource2Name, &associationTertiary), + ), + }, + { + ResourceName: resource1Name, + ImportState: true, + ImportStateVerify: true, + }, + { + ResourceName: resource2Name, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccVPCIPv6CIDRBlockAssociationConfig_amazon_provided(rName string) string { + return fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.1.0.0/16" + + assign_generated_ipv6_cidr_block = true + + tags = { + Name = %[1]q + } +} + +resource "aws_vpc_ipv6_cidr_block_association" "secondary_cidr" { + vpc_id = aws_vpc.test.id + + assign_generated_ipv6_cidr_block = true +} + +resource "aws_vpc_ipv6_cidr_block_association" "tertiary_cidr" { + vpc_id = aws_vpc.test.id + + assign_generated_ipv6_cidr_block = true +} +`, rName) +} diff --git a/website/docs/r/vpc_ipv6_cidr_block_association.html.markdown b/website/docs/r/vpc_ipv6_cidr_block_association.html.markdown index 52992b273ff..2ca45164d76 100644 --- a/website/docs/r/vpc_ipv6_cidr_block_association.html.markdown +++ b/website/docs/r/vpc_ipv6_cidr_block_association.html.markdown @@ -20,8 +20,8 @@ resource "aws_vpc" "test" { } resource "aws_vpc_ipv6_cidr_block_association" "test" { - ipv6_ipam_pool_id = aws_vpc_ipam_pool.test.id - vpc_id = aws_vpc.test.id + assign_generated_ipv6_cidr_block = true + vpc_id = aws_vpc.test.id } ``` @@ -29,10 +29,12 @@ resource "aws_vpc_ipv6_cidr_block_association" "test" { The following arguments are supported: -* `ipv6_cidr_block` - (Optional) The IPv6 CIDR block for the VPC. CIDR can be explicitly set or it can be derived from IPAM using `ipv6_netmask_length`. This parameter is required if `ipv6_netmask_length` is not set and he IPAM pool does not have `allocation_default_netmask` set. -* `ipv6_ipam_pool_id` - (Required) The ID of an IPv6 IPAM pool you want to use for allocating this VPC's CIDR. IPAM is a VPC feature that you can use to automate your IP address management workflows including assigning, tracking, troubleshooting, and auditing IP addresses across AWS Regions and accounts. -* `ipv6_netmask_length` - (Optional) The netmask length of the IPv6 CIDR you want to allocate to this VPC. Requires specifying a `ipv6_ipam_pool_id`. This parameter is optional if the IPAM pool has `allocation_default_netmask` set, otherwise it or `cidr_block` are required -* `vpc_id` - (Required) The ID of the VPC to make the association with. +- `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 IPv6 addresses, or the size of the CIDR block. Default is `false`. Conflicts with `ipv6_pam_pool_id`, `ipv6_pool`, `ipv6_cidr_block` and `ipv6_netmask_length`. +- `ipv6_cidr_block` - (Optional) The IPv6 CIDR block for the VPC. CIDR can be explicitly set or it can be derived from IPAM using `ipv6_netmask_length`. This parameter is required if `ipv6_netmask_length` is not set and he IPAM pool does not have `allocation_default_netmask` set. Conflicts with `assign_generated_ipv6_cidr_block`. +- `ipv6_ipam_pool_id` - (Optional) The ID of an IPv6 IPAM pool you want to use for allocating this VPC's CIDR. IPAM is a VPC feature that you can use to automate your IP address management workflows including assigning, tracking, troubleshooting, and auditing IP addresses across AWS Regions and accounts. Conflict with `assign_generated_ipv6_cidr_block` and `ipv6_ipam_pool_id`. +- `ipv6_netmask_length` - (Optional) The netmask length of the IPv6 CIDR you want to allocate to this VPC. Requires specifying a `ipv6_ipam_pool_id`. This parameter is optional if the IPAM pool has `allocation_default_netmask` set, otherwise it or `cidr_block` are required. Conflicts with `assign_generated_ipv6_cidr_block` and `ipv6_ipam_pool_id`. +- `ipv6_pool` - (Optional) The ID of an IPv6 address pool from which to allocate the IPv6 CIDR block. Conflicts with `ipv6_pam_pool_id`, `ipv6_pool`. +- `vpc_id` - (Required) The ID of the VPC to make the association with. ## Timeouts @@ -45,7 +47,8 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: -* `id` - The ID of the VPC CIDR association +- `id` - The ID of the VPC CIDR association +- `ipv6_cidr_block` - The assigned IPv6 CIDR blok ## Import From 4740e6fa06dc81767495052733ec5e08a9418cc1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 26 Jul 2024 13:55:34 -0400 Subject: [PATCH 2/4] Revert "feat(vpc): Enable additional amazon provided ipv6 cidr" This reverts commit 56dea14cad60c0b049d07ee8f00b20d81df7d863. --- .changelog/27274.txt | 3 - .../ec2/vpc_ipv6_cidr_block_association.go | 35 +++-------- .../vpc_ipv6_cidr_block_association_test.go | 61 ------------------- ..._ipv6_cidr_block_association.html.markdown | 17 +++--- 4 files changed, 16 insertions(+), 100 deletions(-) delete mode 100644 .changelog/27274.txt diff --git a/.changelog/27274.txt b/.changelog/27274.txt deleted file mode 100644 index 0808fab494f..00000000000 --- a/.changelog/27274.txt +++ /dev/null @@ -1,3 +0,0 @@ -```release-note:enhancement -resource/aws_vpc_ipv6_cidr_block_association: Add `assign_generated_ipv6_cidr_block` and `ipv6_pool` argument -``` diff --git a/internal/service/ec2/vpc_ipv6_cidr_block_association.go b/internal/service/ec2/vpc_ipv6_cidr_block_association.go index f310423f702..9894a5703a2 100644 --- a/internal/service/ec2/vpc_ipv6_cidr_block_association.go +++ b/internal/service/ec2/vpc_ipv6_cidr_block_association.go @@ -37,12 +37,6 @@ func ResourceVPCIPv6CIDRBlockAssociation() *schema.Resource { return nil }, Schema: map[string]*schema.Schema{ - "assign_generated_ipv6_cidr_block": { - Type: schema.TypeBool, - Optional: true, - ForceNew: true, - ConflictsWith: []string{"ipv6_pool", "ipv6_ipam_pool_id", "ipv6_cidr_block", "ipv6_netmask_length"}, - }, "ipv6_cidr_block": { Type: schema.TypeString, Optional: true, @@ -52,11 +46,13 @@ func ResourceVPCIPv6CIDRBlockAssociation() *schema.Resource { verify.ValidIPv6CIDRNetworkAddress, validation.IsCIDRNetwork(VPCCIDRMaxIPv6, VPCCIDRMaxIPv6)), }, + // ipam parameters are not required by the API but other usage mechanisms are not implemented yet. TODO ipv6 options: + // --amazon-provided-ipv6-cidr-block + // --ipv6-pool "ipv6_ipam_pool_id": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ConflictsWith: []string{"assign_generated_ipv6_cidr_block", "ipv6_pool"}, + Type: schema.TypeString, + Required: true, + ForceNew: true, }, "ipv6_netmask_length": { Type: schema.TypeInt, @@ -67,12 +63,6 @@ func ResourceVPCIPv6CIDRBlockAssociation() *schema.Resource { // This RequiredWith setting should be applied once L57 is completed // RequiredWith: []string{"ipv6_ipam_pool_id"}, }, - "ipv6_pool": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - ConflictsWith: []string{"assign_generated_ipv6_cidr_block", "ipv6_ipam_pool_id"}, - }, "vpc_id": { Type: schema.TypeString, Required: true, @@ -95,26 +85,18 @@ func resourceVPCIPv6CIDRBlockAssociationCreate(d *schema.ResourceData, meta inte VpcId: aws.String(vpcID), } - if v, ok := d.GetOk("assign_generated_ipv6_cidr_block"); ok { - input.AmazonProvidedIpv6CidrBlock = aws.Bool(v.(bool)) + if v, ok := d.GetOk("ipv6_cidr_block"); ok { + input.Ipv6CidrBlock = aws.String(v.(string)) } if v, ok := d.GetOk("ipv6_ipam_pool_id"); ok { input.Ipv6IpamPoolId = aws.String(v.(string)) } - if v, ok := d.GetOk("ipv6_cidr_block"); ok { - input.Ipv6CidrBlock = aws.String(v.(string)) - } - if v, ok := d.GetOk("ipv6_netmask_length"); ok { input.Ipv6NetmaskLength = aws.Int64(int64(v.(int))) } - if v, ok := d.GetOk("ipv6_pool"); ok { - input.Ipv6Pool = aws.String(v.(string)) - } - log.Printf("[DEBUG] Creating EC2 VPC IPv6 CIDR Block Association: %s", input) output, err := conn.AssociateVpcCidrBlock(input) @@ -150,6 +132,7 @@ func resourceVPCIPv6CIDRBlockAssociationRead(d *schema.ResourceData, meta interf d.Set("ipv6_cidr_block", vpcIpv6CidrBlockAssociation.Ipv6CidrBlock) d.Set("vpc_id", vpc.VpcId) + return nil } diff --git a/internal/service/ec2/vpc_ipv6_cidr_block_association_test.go b/internal/service/ec2/vpc_ipv6_cidr_block_association_test.go index 955fe90ba81..66cbe9e7807 100644 --- a/internal/service/ec2/vpc_ipv6_cidr_block_association_test.go +++ b/internal/service/ec2/vpc_ipv6_cidr_block_association_test.go @@ -3,11 +3,9 @@ package ec2_test import ( "fmt" "strings" - "testing" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" - sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" @@ -74,62 +72,3 @@ func testAccCheckVPCAssociationIPv6CIDRPrefix(association *ec2.VpcIpv6CidrBlockA return nil } } - -func TestAccVPCIPv6CIDRBlockAssociation_basic(t *testing.T) { - var associationSecondary, associationTertiary ec2.VpcIpv6CidrBlockAssociation - resource1Name := "aws_vpc_ipv6_cidr_block_association.secondary_cidr" - resource2Name := "aws_vpc_ipv6_cidr_block_association.tertiary_cidr" - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - - resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t) }, - ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckVPCIPv6CIDRBlockAssociationDestroy, - Steps: []resource.TestStep{ - { - Config: testAccVPCIPv6CIDRBlockAssociationConfig_amazon_provided(rName), - Check: resource.ComposeTestCheckFunc( - testAccCheckVPCIPv6CIDRBlockAssociationExists(resource1Name, &associationSecondary), - testAccCheckVPCIPv6CIDRBlockAssociationExists(resource2Name, &associationTertiary), - ), - }, - { - ResourceName: resource1Name, - ImportState: true, - ImportStateVerify: true, - }, - { - ResourceName: resource2Name, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func testAccVPCIPv6CIDRBlockAssociationConfig_amazon_provided(rName string) string { - return fmt.Sprintf(` -resource "aws_vpc" "test" { - cidr_block = "10.1.0.0/16" - - assign_generated_ipv6_cidr_block = true - - tags = { - Name = %[1]q - } -} - -resource "aws_vpc_ipv6_cidr_block_association" "secondary_cidr" { - vpc_id = aws_vpc.test.id - - assign_generated_ipv6_cidr_block = true -} - -resource "aws_vpc_ipv6_cidr_block_association" "tertiary_cidr" { - vpc_id = aws_vpc.test.id - - assign_generated_ipv6_cidr_block = true -} -`, rName) -} diff --git a/website/docs/r/vpc_ipv6_cidr_block_association.html.markdown b/website/docs/r/vpc_ipv6_cidr_block_association.html.markdown index 2ca45164d76..52992b273ff 100644 --- a/website/docs/r/vpc_ipv6_cidr_block_association.html.markdown +++ b/website/docs/r/vpc_ipv6_cidr_block_association.html.markdown @@ -20,8 +20,8 @@ resource "aws_vpc" "test" { } resource "aws_vpc_ipv6_cidr_block_association" "test" { - assign_generated_ipv6_cidr_block = true - vpc_id = aws_vpc.test.id + ipv6_ipam_pool_id = aws_vpc_ipam_pool.test.id + vpc_id = aws_vpc.test.id } ``` @@ -29,12 +29,10 @@ resource "aws_vpc_ipv6_cidr_block_association" "test" { The following arguments are supported: -- `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 IPv6 addresses, or the size of the CIDR block. Default is `false`. Conflicts with `ipv6_pam_pool_id`, `ipv6_pool`, `ipv6_cidr_block` and `ipv6_netmask_length`. -- `ipv6_cidr_block` - (Optional) The IPv6 CIDR block for the VPC. CIDR can be explicitly set or it can be derived from IPAM using `ipv6_netmask_length`. This parameter is required if `ipv6_netmask_length` is not set and he IPAM pool does not have `allocation_default_netmask` set. Conflicts with `assign_generated_ipv6_cidr_block`. -- `ipv6_ipam_pool_id` - (Optional) The ID of an IPv6 IPAM pool you want to use for allocating this VPC's CIDR. IPAM is a VPC feature that you can use to automate your IP address management workflows including assigning, tracking, troubleshooting, and auditing IP addresses across AWS Regions and accounts. Conflict with `assign_generated_ipv6_cidr_block` and `ipv6_ipam_pool_id`. -- `ipv6_netmask_length` - (Optional) The netmask length of the IPv6 CIDR you want to allocate to this VPC. Requires specifying a `ipv6_ipam_pool_id`. This parameter is optional if the IPAM pool has `allocation_default_netmask` set, otherwise it or `cidr_block` are required. Conflicts with `assign_generated_ipv6_cidr_block` and `ipv6_ipam_pool_id`. -- `ipv6_pool` - (Optional) The ID of an IPv6 address pool from which to allocate the IPv6 CIDR block. Conflicts with `ipv6_pam_pool_id`, `ipv6_pool`. -- `vpc_id` - (Required) The ID of the VPC to make the association with. +* `ipv6_cidr_block` - (Optional) The IPv6 CIDR block for the VPC. CIDR can be explicitly set or it can be derived from IPAM using `ipv6_netmask_length`. This parameter is required if `ipv6_netmask_length` is not set and he IPAM pool does not have `allocation_default_netmask` set. +* `ipv6_ipam_pool_id` - (Required) The ID of an IPv6 IPAM pool you want to use for allocating this VPC's CIDR. IPAM is a VPC feature that you can use to automate your IP address management workflows including assigning, tracking, troubleshooting, and auditing IP addresses across AWS Regions and accounts. +* `ipv6_netmask_length` - (Optional) The netmask length of the IPv6 CIDR you want to allocate to this VPC. Requires specifying a `ipv6_ipam_pool_id`. This parameter is optional if the IPAM pool has `allocation_default_netmask` set, otherwise it or `cidr_block` are required +* `vpc_id` - (Required) The ID of the VPC to make the association with. ## Timeouts @@ -47,8 +45,7 @@ The following arguments are supported: In addition to all arguments above, the following attributes are exported: -- `id` - The ID of the VPC CIDR association -- `ipv6_cidr_block` - The assigned IPv6 CIDR blok +* `id` - The ID of the VPC CIDR association ## Import From bc2b5349a2b31a0d6ca023f2bf40fe5c04cc4c37 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 26 Jul 2024 14:15:11 -0400 Subject: [PATCH 3/4] r/aws_vpc_ipv6_cidr_block_association: Add `assign_generated_ipv6_cidr_block` and `ipv6_pool` arguments. --- .changelog/27274.txt | 3 + .../ec2/vpc_ipv6_cidr_block_association.go | 42 ++++++++----- .../vpc_ipv6_cidr_block_association_test.go | 60 +++++++++++++++++++ ..._ipv6_cidr_block_association.html.markdown | 8 ++- 4 files changed, 95 insertions(+), 18 deletions(-) create mode 100644 .changelog/27274.txt diff --git a/.changelog/27274.txt b/.changelog/27274.txt new file mode 100644 index 00000000000..1facac6ae86 --- /dev/null +++ b/.changelog/27274.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_vpc_ipv6_cidr_block_association: Add `assign_generated_ipv6_cidr_block` and `ipv6_pool` arguments +``` \ No newline at end of file diff --git a/internal/service/ec2/vpc_ipv6_cidr_block_association.go b/internal/service/ec2/vpc_ipv6_cidr_block_association.go index e79c4dd0847..f71bc7770b3 100644 --- a/internal/service/ec2/vpc_ipv6_cidr_block_association.go +++ b/internal/service/ec2/vpc_ipv6_cidr_block_association.go @@ -42,6 +42,12 @@ func resourceVPCIPv6CIDRBlockAssociation() *schema.Resource { return nil }, Schema: map[string]*schema.Schema{ + "assign_generated_ipv6_cidr_block": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"ipv6_pool", "ipv6_ipam_pool_id", "ipv6_cidr_block", "ipv6_netmask_length"}, + }, "ipv6_cidr_block": { Type: schema.TypeString, Optional: true, @@ -49,13 +55,11 @@ func resourceVPCIPv6CIDRBlockAssociation() *schema.Resource { ForceNew: true, ValidateFunc: validVPCIPv6CIDRBlock, }, - // ipam parameters are not required by the API but other usage mechanisms are not implemented yet. TODO ipv6 options: - // --amazon-provided-ipv6-cidr-block - // --ipv6-pool "ipv6_ipam_pool_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"assign_generated_ipv6_cidr_block", "ipv6_pool"}, }, "ipv6_netmask_length": { Type: schema.TypeInt, @@ -63,8 +67,12 @@ func resourceVPCIPv6CIDRBlockAssociation() *schema.Resource { ForceNew: true, ValidateFunc: validation.IntInSlice(vpcCIDRValidIPv6Netmasks), ConflictsWith: []string{"ipv6_cidr_block"}, - // This RequiredWith setting should be applied once L57 is completed - // RequiredWith: []string{"ipv6_ipam_pool_id"}, + }, + "ipv6_pool": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ConflictsWith: []string{"assign_generated_ipv6_cidr_block", "ipv6_ipam_pool_id"}, }, names.AttrVPCID: { Type: schema.TypeString, @@ -89,6 +97,10 @@ func resourceVPCIPv6CIDRBlockAssociationCreate(ctx context.Context, d *schema.Re VpcId: aws.String(vpcID), } + if v, ok := d.GetOk("assign_generated_ipv6_cidr_block"); ok { + input.AmazonProvidedIpv6CidrBlock = aws.Bool(v.(bool)) + } + if v, ok := d.GetOk("ipv6_cidr_block"); ok { input.Ipv6CidrBlock = aws.String(v.(string)) } @@ -101,7 +113,10 @@ func resourceVPCIPv6CIDRBlockAssociationCreate(ctx context.Context, d *schema.Re input.Ipv6NetmaskLength = aws.Int32(int32(v.(int))) } - log.Printf("[DEBUG] Creating EC2 VPC IPv6 CIDR Block Association: %#v", input) + if v, ok := d.GetOk("ipv6_pool"); ok { + input.Ipv6Pool = aws.String(v.(string)) + } + output, err := conn.AssociateVpcCidrBlock(ctx, input) if err != nil { @@ -110,9 +125,7 @@ func resourceVPCIPv6CIDRBlockAssociationCreate(ctx context.Context, d *schema.Re d.SetId(aws.ToString(output.Ipv6CidrBlockAssociation.AssociationId)) - _, err = waitVPCIPv6CIDRBlockAssociationCreated(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)) - - if err != nil { + if _, err := waitVPCIPv6CIDRBlockAssociationCreated(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { return sdkdiag.AppendErrorf(diags, "waiting for EC2 VPC (%s) IPv6 CIDR block (%s) to become associated: %s", vpcID, d.Id(), err) } @@ -136,6 +149,7 @@ func resourceVPCIPv6CIDRBlockAssociationRead(ctx context.Context, d *schema.Reso } d.Set("ipv6_cidr_block", vpcIpv6CidrBlockAssociation.Ipv6CidrBlock) + d.Set("ipv6_pool", vpcIpv6CidrBlockAssociation.Ipv6Pool) d.Set(names.AttrVPCID, vpc.VpcId) return diags @@ -158,9 +172,7 @@ func resourceVPCIPv6CIDRBlockAssociationDelete(ctx context.Context, d *schema.Re return sdkdiag.AppendErrorf(diags, "deleting EC2 VPC IPv6 CIDR Block Association (%s): %s", d.Id(), err) } - err = waitVPCIPv6CIDRBlockAssociationDeleted(ctx, conn, d.Id(), d.Timeout(schema.TimeoutDelete)) - - if err != nil { + if err := waitVPCIPv6CIDRBlockAssociationDeleted(ctx, conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { return sdkdiag.AppendErrorf(diags, "waiting for EC2 VPC IPv6 CIDR block (%s) to become disassociated: %s", d.Id(), err) } diff --git a/internal/service/ec2/vpc_ipv6_cidr_block_association_test.go b/internal/service/ec2/vpc_ipv6_cidr_block_association_test.go index 6cd2e6f7af3..665be228b4b 100644 --- a/internal/service/ec2/vpc_ipv6_cidr_block_association_test.go +++ b/internal/service/ec2/vpc_ipv6_cidr_block_association_test.go @@ -7,17 +7,54 @@ import ( "context" "fmt" "strings" + "testing" "github.com/aws/aws-sdk-go-v2/aws" awstypes "github.com/aws/aws-sdk-go-v2/service/ec2/types" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" ) +func TestAccVPCIPv6CIDRBlockAssociation_basic(t *testing.T) { + ctx := acctest.Context(t) + var associationSecondary, associationTertiary awstypes.VpcIpv6CidrBlockAssociation + resource1Name := "aws_vpc_ipv6_cidr_block_association.secondary_cidr" + resource2Name := "aws_vpc_ipv6_cidr_block_association.tertiary_cidr" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckVPCIPv6CIDRBlockAssociationDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccVPCIPv6CIDRBlockAssociationConfig_amazonProvided(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckVPCIPv6CIDRBlockAssociationExists(ctx, resource1Name, &associationSecondary), + testAccCheckVPCIPv6CIDRBlockAssociationExists(ctx, resource2Name, &associationTertiary), + ), + }, + { + ResourceName: resource1Name, + ImportState: true, + ImportStateVerify: true, + }, + { + ResourceName: resource2Name, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckVPCIPv6CIDRBlockAssociationDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Client(ctx) @@ -78,3 +115,26 @@ func testAccCheckVPCAssociationIPv6CIDRPrefix(association *awstypes.VpcIpv6CidrB return nil } } + +func testAccVPCIPv6CIDRBlockAssociationConfig_amazonProvided(rName string) string { + return fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.1.0.0/16" + assign_generated_ipv6_cidr_block = true + + tags = { + Name = %[1]q + } +} + +resource "aws_vpc_ipv6_cidr_block_association" "secondary_cidr" { + vpc_id = aws_vpc.test.id + assign_generated_ipv6_cidr_block = true +} + +resource "aws_vpc_ipv6_cidr_block_association" "tertiary_cidr" { + vpc_id = aws_vpc.test.id + assign_generated_ipv6_cidr_block = true +} +`, rName) +} diff --git a/website/docs/r/vpc_ipv6_cidr_block_association.html.markdown b/website/docs/r/vpc_ipv6_cidr_block_association.html.markdown index e11ebc8da37..b4a4275de59 100644 --- a/website/docs/r/vpc_ipv6_cidr_block_association.html.markdown +++ b/website/docs/r/vpc_ipv6_cidr_block_association.html.markdown @@ -29,9 +29,11 @@ resource "aws_vpc_ipv6_cidr_block_association" "test" { This resource supports the following arguments: -* `ipv6_cidr_block` - (Optional) The IPv6 CIDR block for the VPC. CIDR can be explicitly set or it can be derived from IPAM using `ipv6_netmask_length`. This parameter is required if `ipv6_netmask_length` is not set and the IPAM pool does not have `allocation_default_netmask` set. -* `ipv6_ipam_pool_id` - (Required) The ID of an IPv6 IPAM pool you want to use for allocating this VPC's CIDR. IPAM is a VPC feature that you can use to automate your IP address management workflows including assigning, tracking, troubleshooting, and auditing IP addresses across AWS Regions and accounts. -* `ipv6_netmask_length` - (Optional) The netmask length of the IPv6 CIDR you want to allocate to this VPC. Requires specifying a `ipv6_ipam_pool_id`. This parameter is optional if the IPAM pool has `allocation_default_netmask` set, otherwise it or `cidr_block` are required +* `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 IPv6 addresses, or the size of the CIDR block. Default is `false`. Conflicts with `ipv6_pam_pool_id`, `ipv6_pool`, `ipv6_cidr_block` and `ipv6_netmask_length`. +* `ipv6_cidr_block` - (Optional) The IPv6 CIDR block for the VPC. CIDR can be explicitly set or it can be derived from IPAM using `ipv6_netmask_length`. This parameter is required if `ipv6_netmask_length` is not set and the IPAM pool does not have `allocation_default_netmask` set. Conflicts with `assign_generated_ipv6_cidr_block`. +* `ipv6_ipam_pool_id` - - (Optional) The ID of an IPv6 IPAM pool you want to use for allocating this VPC's CIDR. IPAM is a VPC feature that you can use to automate your IP address management workflows including assigning, tracking, troubleshooting, and auditing IP addresses across AWS Regions and accounts. Conflict with `assign_generated_ipv6_cidr_block` and `ipv6_ipam_pool_id`. +* `ipv6_netmask_length` - (Optional) The netmask length of the IPv6 CIDR you want to allocate to this VPC. Requires specifying a `ipv6_ipam_pool_id`. This parameter is optional if the IPAM pool has `allocation_default_netmask` set, otherwise it or `ipv6_cidr_block` are required. Conflicts with `assign_generated_ipv6_cidr_block` and `ipv6_ipam_pool_id`. +* `ipv6_pool` - (Optional) The ID of an IPv6 address pool from which to allocate the IPv6 CIDR block. Conflicts with `ipv6_pam_pool_id`, `ipv6_pool`. * `vpc_id` - (Required) The ID of the VPC to make the association with. ## Timeouts From 6d045a3011a50f3ca71da283547c723ea6d39548 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 26 Jul 2024 14:32:14 -0400 Subject: [PATCH 4/4] Add 'TestAccVPCIPv6CIDRBlockAssociation_disappears'. --- internal/service/ec2/exports_test.go | 1 + .../ec2/vpc_ipv6_cidr_block_association.go | 8 ++++- .../vpc_ipv6_cidr_block_association_test.go | 30 ++++++++++++++++++- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/internal/service/ec2/exports_test.go b/internal/service/ec2/exports_test.go index 776ebab657c..a8c5021245b 100644 --- a/internal/service/ec2/exports_test.go +++ b/internal/service/ec2/exports_test.go @@ -105,6 +105,7 @@ var ( ResourceVPCEndpointService = resourceVPCEndpointService ResourceVPCEndpointSubnetAssociation = resourceVPCEndpointSubnetAssociation ResourceVPCIPv4CIDRBlockAssociation = resourceVPCIPv4CIDRBlockAssociation + ResourceVPCIPv6CIDRBlockAssociation = resourceVPCIPv6CIDRBlockAssociation ResourceVPCPeeringConnection = resourceVPCPeeringConnection ResourceVPNConnection = resourceVPNConnection ResourceVPNConnectionRoute = resourceVPNConnectionRoute diff --git a/internal/service/ec2/vpc_ipv6_cidr_block_association.go b/internal/service/ec2/vpc_ipv6_cidr_block_association.go index f71bc7770b3..916684e69a2 100644 --- a/internal/service/ec2/vpc_ipv6_cidr_block_association.go +++ b/internal/service/ec2/vpc_ipv6_cidr_block_association.go @@ -45,6 +45,7 @@ func resourceVPCIPv6CIDRBlockAssociation() *schema.Resource { "assign_generated_ipv6_cidr_block": { Type: schema.TypeBool, Optional: true, + Computed: true, ForceNew: true, ConflictsWith: []string{"ipv6_pool", "ipv6_ipam_pool_id", "ipv6_cidr_block", "ipv6_netmask_length"}, }, @@ -71,6 +72,7 @@ func resourceVPCIPv6CIDRBlockAssociation() *schema.Resource { "ipv6_pool": { Type: schema.TypeString, Optional: true, + Computed: true, ForceNew: true, ConflictsWith: []string{"assign_generated_ipv6_cidr_block", "ipv6_ipam_pool_id"}, }, @@ -148,8 +150,12 @@ func resourceVPCIPv6CIDRBlockAssociationRead(ctx context.Context, d *schema.Reso return sdkdiag.AppendErrorf(diags, "reading EC2 VPC IPv6 CIDR Block Association (%s): %s", d.Id(), err) } + ipv6PoolID := aws.ToString(vpcIpv6CidrBlockAssociation.Ipv6Pool) + isAmazonIPv6Pool := ipv6PoolID == amazonIPv6PoolID + + d.Set("assign_generated_ipv6_cidr_block", isAmazonIPv6Pool) d.Set("ipv6_cidr_block", vpcIpv6CidrBlockAssociation.Ipv6CidrBlock) - d.Set("ipv6_pool", vpcIpv6CidrBlockAssociation.Ipv6Pool) + d.Set("ipv6_pool", ipv6PoolID) d.Set(names.AttrVPCID, vpc.VpcId) return diags diff --git a/internal/service/ec2/vpc_ipv6_cidr_block_association_test.go b/internal/service/ec2/vpc_ipv6_cidr_block_association_test.go index 665be228b4b..be53c000c7d 100644 --- a/internal/service/ec2/vpc_ipv6_cidr_block_association_test.go +++ b/internal/service/ec2/vpc_ipv6_cidr_block_association_test.go @@ -36,9 +36,11 @@ func TestAccVPCIPv6CIDRBlockAssociation_basic(t *testing.T) { Steps: []resource.TestStep{ { Config: testAccVPCIPv6CIDRBlockAssociationConfig_amazonProvided(rName), - Check: resource.ComposeTestCheckFunc( + Check: resource.ComposeAggregateTestCheckFunc( testAccCheckVPCIPv6CIDRBlockAssociationExists(ctx, resource1Name, &associationSecondary), testAccCheckVPCIPv6CIDRBlockAssociationExists(ctx, resource2Name, &associationTertiary), + resource.TestCheckResourceAttr(resource1Name, "ipv6_pool", "Amazon"), + resource.TestCheckResourceAttr(resource2Name, "ipv6_pool", "Amazon"), ), }, { @@ -55,6 +57,32 @@ func TestAccVPCIPv6CIDRBlockAssociation_basic(t *testing.T) { }) } +func TestAccVPCIPv6CIDRBlockAssociation_disappears(t *testing.T) { + ctx := acctest.Context(t) + var associationSecondary, associationTertiary awstypes.VpcIpv6CidrBlockAssociation + resource1Name := "aws_vpc_ipv6_cidr_block_association.secondary_cidr" + resource2Name := "aws_vpc_ipv6_cidr_block_association.tertiary_cidr" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckVPCIPv6CIDRBlockAssociationDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccVPCIPv6CIDRBlockAssociationConfig_amazonProvided(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckVPCIPv6CIDRBlockAssociationExists(ctx, resource1Name, &associationSecondary), + testAccCheckVPCIPv6CIDRBlockAssociationExists(ctx, resource2Name, &associationTertiary), + acctest.CheckResourceDisappears(ctx, acctest.Provider, tfec2.ResourceVPCIPv6CIDRBlockAssociation(), resource1Name), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + func testAccCheckVPCIPv6CIDRBlockAssociationDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Client(ctx)