From 9c8908e083058afb66ba2773020f2e06e862ea24 Mon Sep 17 00:00:00 2001 From: AurelienNober Date: Wed, 30 Mar 2022 09:12:08 +0200 Subject: [PATCH] support aws_vpc_ipam cascade for easier deletes --- .changelog/23973.txt | 3 ++ internal/service/ec2/vpc_ipam.go | 10 ++++- internal/service/ec2/vpc_ipam_test.go | 62 +++++++++++++++++++++++++++ website/docs/r/vpc_ipam.html.markdown | 1 + 4 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 .changelog/23973.txt diff --git a/.changelog/23973.txt b/.changelog/23973.txt new file mode 100644 index 00000000000..bd0d3e296f8 --- /dev/null +++ b/.changelog/23973.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_vpc_ipam: add `cascade` argument +``` \ No newline at end of file diff --git a/internal/service/ec2/vpc_ipam.go b/internal/service/ec2/vpc_ipam.go index 4ecf3c7ff59..e679302031b 100644 --- a/internal/service/ec2/vpc_ipam.go +++ b/internal/service/ec2/vpc_ipam.go @@ -60,6 +60,10 @@ func ResourceVPCIpam() *schema.Resource { Type: schema.TypeInt, Computed: true, }, + "cascade": { + Type: schema.TypeBool, + Optional: true, + }, "tags": tftags.TagsSchema(), "tags_all": tftags.TagsSchemaComputed(), }, @@ -209,6 +213,10 @@ func resourceVPCIpamDelete(d *schema.ResourceData, meta interface{}) error { IpamId: aws.String(d.Id()), } + if v, ok := d.GetOk("cascade"); ok { + input.Cascade = aws.Bool(v.(bool)) + } + log.Printf("[DEBUG] Deleting IPAM: %s", d.Id()) _, err := conn.DeleteIpam(input) if err != nil { @@ -263,7 +271,7 @@ func WaitIpamAvailable(conn *ec2.EC2, ipamId string, timeout time.Duration) (*ec func WaiterIpamDeleted(conn *ec2.EC2, ipamId string, timeout time.Duration) (*ec2.Ipam, error) { stateConf := &resource.StateChangeConf{ - Pending: []string{ec2.IpamStateCreateComplete, ec2.IpamStateModifyComplete}, + Pending: []string{ec2.IpamStateCreateComplete, ec2.IpamStateModifyComplete, ec2.IpamStateDeleteInProgress}, Target: []string{InvalidIpamIdNotFound}, Refresh: statusIpamStatus(conn, ipamId), Timeout: timeout, diff --git a/internal/service/ec2/vpc_ipam_test.go b/internal/service/ec2/vpc_ipam_test.go index 3f731596a87..e1b5c51689c 100644 --- a/internal/service/ec2/vpc_ipam_test.go +++ b/internal/service/ec2/vpc_ipam_test.go @@ -96,6 +96,36 @@ func TestAccVPCIpam_modify(t *testing.T) { }) } +func TestAccVPCIpam_cascade(t *testing.T) { + resourceName := "aws_vpc_ipam.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t); testAccIPAMPreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckVPCIpamDestroy, + Steps: []resource.TestStep{ + { + Config: testAccVPCIpamCascade(), + Check: resource.ComposeTestCheckFunc( + acctest.MatchResourceAttrGlobalARN(resourceName, "arn", "ec2", regexp.MustCompile(`ipam/ipam-[\da-f]+$`)), + resource.TestCheckResourceAttr(resourceName, "operating_regions.#", "1"), + resource.TestCheckResourceAttr(resourceName, "scope_count", "2"), + resource.TestMatchResourceAttr(resourceName, "private_default_scope_id", regexp.MustCompile(`^ipam-scope-[\da-f]+`)), + resource.TestMatchResourceAttr(resourceName, "public_default_scope_id", regexp.MustCompile(`^ipam-scope-[\da-f]+`)), + testAccCheckVPCIpamScopeCreate(resourceName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"cascade"}, + }, + }, + }) +} + func TestAccVPCIpam_tags(t *testing.T) { resourceName := "aws_vpc_ipam.test" @@ -157,6 +187,24 @@ func testAccCheckVPCIpamDestroy(s *terraform.State) error { return nil } +func testAccCheckVPCIpamScopeCreate(resourceName string) resource.TestCheckFunc { + return func(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_vpc_ipam" { + continue + } + conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Conn + input := &ec2.CreateIpamScopeInput{ + ClientToken: aws.String(resource.UniqueId()), + IpamId: aws.String(rs.Primary.ID), + } + _, err := conn.CreateIpamScope(input) + return err + } + return fmt.Errorf("could not create VPC IPAM Scope") + } +} + const testAccVPCIpamBase = ` data "aws_region" "current" {} @@ -168,6 +216,20 @@ resource "aws_vpc_ipam" "test" { } ` +func testAccVPCIpamCascade() string { + return ` +data "aws_region" "current" {} + +resource "aws_vpc_ipam" "test" { + description = "test" + operating_regions { + region_name = data.aws_region.current.name + } + cascade = true +} + ` +} + const testAccVPCIpamBaseAlternateDescription = ` data "aws_region" "current" {} diff --git a/website/docs/r/vpc_ipam.html.markdown b/website/docs/r/vpc_ipam.html.markdown index e73be7d8f37..b755644434d 100644 --- a/website/docs/r/vpc_ipam.html.markdown +++ b/website/docs/r/vpc_ipam.html.markdown @@ -55,6 +55,7 @@ The following arguments are supported: * `description` - (Optional) A description for the IPAM. * `operating_regions` - (Required) Determines which locales can be chosen when you create pools. Locale is the Region where you want to make an IPAM pool available for allocations. You can only create pools with locales that match the operating Regions of the IPAM. You can only create VPCs from a pool whose locale matches the VPC's Region. You specify a region using the [region_name](#operating_regions) parameter. You **must** set your provider block region as an operating_region. * `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. +* `cascade` - (Optional) Enables you to quickly delete an IPAM, private scopes, pools in private scopes, and any allocations in the pools in private scopes. ### operating_regions