From 5602cecd80b98007cf925823bc58052e402ffabf Mon Sep 17 00:00:00 2001 From: Prabhav Pawar Date: Tue, 14 May 2024 21:34:47 +0530 Subject: [PATCH 01/20] Added resource and data source for aws ec2 capacity block reservation. --- ...ec2_capacity_block_offering_data_source.go | 135 ++++++++++++++++++ ...apacity_block_offering_data_source_test.go | 54 +++++++ .../ec2/ec2_capacity_block_reservation.go | 130 +++++++++++++++++ .../ec2_capacity_block_reservation_test.go | 105 ++++++++++++++ .../ec2_capacity_block_offering.html.markdown | 48 +++++++ ...2_capacity_block_reservation.html.markdown | 58 ++++++++ 6 files changed, 530 insertions(+) create mode 100644 internal/service/ec2/ec2_capacity_block_offering_data_source.go create mode 100644 internal/service/ec2/ec2_capacity_block_offering_data_source_test.go create mode 100644 internal/service/ec2/ec2_capacity_block_reservation.go create mode 100644 internal/service/ec2/ec2_capacity_block_reservation_test.go create mode 100644 website/docs/r/ec2_capacity_block_offering.html.markdown create mode 100644 website/docs/r/ec2_capacity_block_reservation.html.markdown diff --git a/internal/service/ec2/ec2_capacity_block_offering_data_source.go b/internal/service/ec2/ec2_capacity_block_offering_data_source.go new file mode 100644 index 00000000000..cfa35c7a88a --- /dev/null +++ b/internal/service/ec2/ec2_capacity_block_offering_data_source.go @@ -0,0 +1,135 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ec2 + +import ( + "context" + "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/names" + "time" + + aws_sdkv2 "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" +) + +const ( + ResNameCapacityBlockOffering = "Capacity Block Offering" +) + +// @SDKDataSource("aws_ec2_capacity_block_offering") +func DataSourceCapacityBlockOffering() *schema.Resource { + return &schema.Resource{ + ReadWithoutTimeout: dataSourceCapacityBlockOfferingRead, + Schema: map[string]*schema.Schema{ + "availability_zone": { + Type: schema.TypeString, + Computed: true, + }, + "capacity_duration": { + Type: schema.TypeInt, + Required: true, + }, + "currency_code": { + Type: schema.TypeString, + Computed: true, + }, + "end_date": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsRFC3339Time, + }, + "instance_count": { + Type: schema.TypeInt, + Required: true, + }, + "instance_type": { + Type: schema.TypeString, + Required: true, + }, + "start_date": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsRFC3339Time, + }, + "tenancy": { + Type: schema.TypeString, + Computed: true, + }, + "upfront_fee": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceCapacityBlockOfferingRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).EC2Conn(ctx) + + input := &ec2.DescribeCapacityBlockOfferingsInput{ + CapacityDurationHours: aws.Int64(int64(d.Get("capacity_duration").(int))), + InstanceCount: aws.Int64(int64(d.Get("instance_count").(int))), + InstanceType: aws.String(d.Get("instance_type").(string)), + } + + if v, ok := d.GetOk("start_date"); ok { + v, _ := time.Parse(time.RFC3339, v.(string)) + input.StartDateRange = aws.Time(v) + } + + if v, ok := d.GetOk("end_date"); ok { + v, _ := time.Parse(time.RFC3339, v.(string)) + input.EndDateRange = aws.Time(v) + } + + output, err := conn.DescribeCapacityBlockOfferingsWithContext(ctx, input) + + if err != nil { + return create.DiagError(names.EC2, create.ErrActionReading, ResNameCapacityBlockOffering, "unknown", err) + } + + if len(output.CapacityBlockOfferings) == 0 { + return diag.Errorf("no %s %s found matching criteria; try different search", names.EC2, ResNameCapacityBlockOffering) + } + + if len(output.CapacityBlockOfferings) > 1 { + return diag.Errorf("More than one %s %s found matching criteria; try different search", names.EC2, ResNameCapacityBlockOffering) + } + + if err != nil { + + return sdkdiag.AppendErrorf(diags, "creating EC2 Capacity Reservation: %s", err) + } + + cbo := output.CapacityBlockOfferings[0] + { + d.SetId(aws_sdkv2.ToString(cbo.CapacityBlockOfferingId)) + d.Set("availability_zone", cbo.AvailabilityZone) + d.Set("capacity_duration", cbo.CapacityBlockDurationHours) + d.Set("currency_code", cbo.CurrencyCode) + if cbo.EndDate != nil { + d.Set("end_date", aws.TimeValue(cbo.EndDate).Format(time.RFC3339)) + } else { + d.Set("end_date", nil) + } + d.Set("instance_count", cbo.InstanceCount) + d.Set("instance_type", cbo.InstanceType) + if cbo.StartDate != nil { + d.Set("start_date", aws.TimeValue(cbo.StartDate).Format(time.RFC3339)) + } else { + d.Set("start_date", nil) + } + d.Set("tenancy", cbo.Tenancy) + d.Set("upfront_fee", cbo.UpfrontFee) + } + + return nil +} diff --git a/internal/service/ec2/ec2_capacity_block_offering_data_source_test.go b/internal/service/ec2/ec2_capacity_block_offering_data_source_test.go new file mode 100644 index 00000000000..4a55df7763d --- /dev/null +++ b/internal/service/ec2/ec2_capacity_block_offering_data_source_test.go @@ -0,0 +1,54 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ec2 + +import ( + "fmt" + "testing" + "time" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccEC2CapacityBlockOffering_basic(t *testing.T) { + ctx := acctest.Context(t) + dataSourceName := "data.aws_ec2_capacity_block_offering.test" + startDate := time.Now().UTC().Add(25 * time.Hour).Format(time.RFC3339) + endDate := time.Now().UTC().Add(720 * time.Hour).Format(time.RFC3339) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: nil, + ErrorCheck: acctest.ErrorCheck(t, names.EC2), + Steps: []resource.TestStep{ + { + Config: testAccCapacityBlockOfferingConfig_basic(startDate, endDate), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(dataSourceName, "availability_zone"), + resource.TestCheckResourceAttr(dataSourceName, "capacity_duration", "24"), + resource.TestCheckResourceAttr(dataSourceName, "instance_count", "1"), + resource.TestCheckResourceAttr(dataSourceName, "instance_type", "p4d.24xlarge"), + resource.TestCheckResourceAttrSet(dataSourceName, "id"), + resource.TestCheckResourceAttr(dataSourceName, "tenancy", "default"), + resource.TestCheckResourceAttrSet(dataSourceName, "upfront_fee"), + ), + }, + }, + }) +} + +func testAccCapacityBlockOfferingConfig_basic(startDate, endDate string) string { + return fmt.Sprintf(` +data "aws_ec2_capacity_block_offering" "test" { + instance_type = "p4d.24xlarge" + capacity_duration = 24 + instance_count = 1 + start_date = %[1]q + end_date = %[2]q +} +`, startDate, endDate) +} diff --git a/internal/service/ec2/ec2_capacity_block_reservation.go b/internal/service/ec2/ec2_capacity_block_reservation.go new file mode 100644 index 00000000000..7e29551a4d2 --- /dev/null +++ b/internal/service/ec2/ec2_capacity_block_reservation.go @@ -0,0 +1,130 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ec2 + +import ( + "context" + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/verify" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @SDKResource("aws_ec2_capacity_block_reservation", name="Capacity Block Reservation") +// @Tags(identifierAttribute="id") +func ResourceCapacityBlockReservation() *schema.Resource { + return &schema.Resource{ + CreateWithoutTimeout: resourceCapacityBlockReservationCreate, + ReadWithoutTimeout: resourceCapacityReservationRead, + UpdateWithoutTimeout: schema.NoopContext, + DeleteWithoutTimeout: schema.NoopContext, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + + CustomizeDiff: verify.SetTagsDiff, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "availability_zone": { + Type: schema.TypeString, + Computed: true, + }, + "capacity_block_offering_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "ebs_optimized": { + Type: schema.TypeBool, + Computed: true, + }, + "end_date": { + Type: schema.TypeString, + Computed: true, + }, + "end_date_type": { + Type: schema.TypeString, + Computed: true, + }, + "ephemeral_storage": { + Type: schema.TypeBool, + Computed: true, + }, + "instance_count": { + Type: schema.TypeInt, + Computed: true, + }, + "instance_match_criteria": { + Type: schema.TypeString, + Computed: true, + }, + "instance_platform": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(ec2.CapacityReservationInstancePlatform_Values(), false), + }, + "instance_type": { + Type: schema.TypeString, + Computed: true, + }, + "outpost_arn": { + Type: schema.TypeString, + Computed: true, + }, + "owner_id": { + Type: schema.TypeString, + Computed: true, + }, + "placement_group_arn": { + Type: schema.TypeString, + Computed: true, + }, + "start_date": { + Type: schema.TypeString, + Computed: true, + }, + names.AttrTags: tftags.TagsSchema(), + names.AttrTagsAll: tftags.TagsSchemaComputed(), + "tenancy": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceCapacityBlockReservationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).EC2Conn(ctx) + + input := &ec2.PurchaseCapacityBlockInput{ + CapacityBlockOfferingId: aws.String(d.Get("capacity_block_offering_id").(string)), + InstancePlatform: aws.String(d.Get("instance_platform").(string)), + TagSpecifications: getTagSpecificationsIn(ctx, ec2.ResourceTypeCapacityReservation), + } + + output, err := conn.PurchaseCapacityBlock(input) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "creating EC2 Capacity Reservation: %s", err) + } + d.SetId(aws.StringValue(output.CapacityReservation.CapacityReservationId)) + + if _, err := WaitCapacityReservationActive(ctx, conn, d.Id()); err != nil { + return sdkdiag.AppendErrorf(diags, "waiting for EC2 Capacity Reservation (%s) create: %s", d.Id(), err) + } + + return append(diags, resourceCapacityReservationRead(ctx, d, meta)...) +} diff --git a/internal/service/ec2/ec2_capacity_block_reservation_test.go b/internal/service/ec2/ec2_capacity_block_reservation_test.go new file mode 100644 index 00000000000..fc3a5ff0f18 --- /dev/null +++ b/internal/service/ec2/ec2_capacity_block_reservation_test.go @@ -0,0 +1,105 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ec2_test + +import ( + "context" + "fmt" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "os" + "testing" + "time" + + "github.com/YakDriver/regexache" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccEC2CapacityBlockReservation_basic(t *testing.T) { + ctx := acctest.Context(t) + key := "RUN_EC2_CAPACITY_BLOCK_RESERVATION_TESTS" + vifId := os.Getenv(key) + if vifId != "true" { + t.Skipf("Environment variable %s is not set to true", key) + } + + var reservation ec2.CapacityReservation + resourceName := "aws_ec2_capacity_block_reservation.test" + dataSourceName := "data.aws_ec2_capacity_block_offering.test" + startDate := time.Now().UTC().Add(25 * time.Hour).Format(time.RFC3339) + endDate := time.Now().UTC().Add(720 * time.Hour).Format(time.RFC3339) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: nil, + ErrorCheck: acctest.ErrorCheck(t, names.EC2ServiceID), + Steps: []resource.TestStep{ + { + Config: testAccCapacityBlockReservationConfig_basic(startDate, endDate), + Check: resource.ComposeTestCheckFunc( + testAccCheckCapacityBlockReservationExists(ctx, resourceName, &reservation), + acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexache.MustCompile(`capacity-reservation/cr-:.+`)), + resource.TestCheckResourceAttrPair(dataSourceName, "availability_zone", resourceName, "availability_zone"), + resource.TestCheckResourceAttrPair(dataSourceName, "capacity_block_offering_id", resourceName, "capacity_block_offering_id"), + resource.TestCheckResourceAttrPair(dataSourceName, "start_date", resourceName, "start_date"), + resource.TestCheckResourceAttrPair(dataSourceName, "end_date", resourceName, "end_date"), + resource.TestCheckResourceAttrPair(dataSourceName, "instance_count", resourceName, "instance_count"), + resource.TestCheckResourceAttrPair(dataSourceName, "instance_platform", resourceName, "instance_platform"), + resource.TestCheckResourceAttrPair(dataSourceName, "instance_type", resourceName, "instance_type"), + resource.TestCheckResourceAttrPair(dataSourceName, "tenancy", resourceName, "tenancy"), + ), + }, + }, + }) +} + +func testAccCheckCapacityBlockReservationExists(ctx context.Context, n string, v *ec2.CapacityReservation) 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 EC2 Capacity Reservation ID is set") + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Conn(ctx) + + output, err := tfec2.FindCapacityReservationByID(ctx, conn, rs.Primary.ID) + + if err != nil { + return err + } + + *v = *output + + return nil + } +} + +func testAccCapacityBlockReservationConfig_basic(startDate, endDate string) string { + return fmt.Sprintf(` +data "aws_ec2_capacity_block_offering" "test" { + instance_type = "p4d.24xlarge" + capacity_duration = 24 + instance_count = 1 + start_date = %[1]q + end_date = %[2]q +} + +resource "aws_ec2_capacity_block_reservation" "test" { + capacity_block_offering_id = data.aws_ec2_capacity_block_offering.test.id + instance_platform = "Linux/UNIX" + tags = { + "Environment" = "dev" + } +} +`, startDate, endDate) +} diff --git a/website/docs/r/ec2_capacity_block_offering.html.markdown b/website/docs/r/ec2_capacity_block_offering.html.markdown new file mode 100644 index 00000000000..ba80bdd6e1b --- /dev/null +++ b/website/docs/r/ec2_capacity_block_offering.html.markdown @@ -0,0 +1,48 @@ +--- +subcategory: "EC2 (Elastic Compute Cloud)" +layout: "aws" +page_title: "AWS: aws_ec2_capacity_block_offering" +description: |- + Information about a single EC2 Capacity Block Reservation. +--- + +# Data Source: aws_ec2_capacity_block_offering + +Information about a single EC2 Capacity Block Reservation. + +## Example Usage + +```terraform + + +data "aws_ec2_capacity_block_offering" "test" { + capacity_duration = 24 + end_date = "2024-05-30T15:04:05Z" + instance_count = 1 + instance_platform = "Linux/UNIX" + instance_type = "p4d.24xlarge" + start_date = "2024-04-28T15:04:05Z" +} + +``` + +## Argument Reference + +This resource supports the following arguments: + +* `capacity_duration` - (Required) The amount of time of the Capacity Block reservation in hours. +* `end_date` - (Optional) The date and time at which the Capacity Block Reservation expires. When a Capacity Reservation expires, the reserved capacity is released and you can no longer launch instances into it. Valid values: [RFC3339 time string](https://tools.ietf.org/html/rfc3339#section-5.8) (`YYYY-MM-DDTHH:MM:SSZ`) +* `instance_count` - (Required) The number of instances for which to reserve capacity. +* `instance_type` - (Required) The instance type for which to reserve capacity. +* `start_date` - (Optional) The date and time at which the Capacity Block Reservation starts. Valid values: [RFC3339 time string](https://tools.ietf.org/html/rfc3339#section-5.8) (`YYYY-MM-DDTHH:MM:SSZ`) + +## Attribute Reference + +This resource exports the following attributes in addition to the arguments above: + +* `availability_zone` - The Availability Zone in which to create the Capacity Reservation. +* `currency_code` - The currency of the payment for the Capacity Block. +* `id` - The Capacity Block Reservation ID. +* `instance_platform` - The type of operating system for which to reserve capacity. Valid options are `Linux/UNIX`, `Red Hat Enterprise Linux`, `SUSE Linux`, `Windows`, `Windows with SQL Server`, `Windows with SQL Server Enterprise`, `Windows with SQL Server Standard` or `Windows with SQL Server Web`. +* `upfront_fee` - The total price to be paid up front. +* `tenancy` - Indicates the tenancy of the Capacity Reservation. Specify either `default` or `dedicated`. diff --git a/website/docs/r/ec2_capacity_block_reservation.html.markdown b/website/docs/r/ec2_capacity_block_reservation.html.markdown new file mode 100644 index 00000000000..d8d8374402b --- /dev/null +++ b/website/docs/r/ec2_capacity_block_reservation.html.markdown @@ -0,0 +1,58 @@ +--- +subcategory: "EC2 (Elastic Compute Cloud)" +layout: "aws" +page_title: "AWS: aws_ec2_capacity_block_reservation" +description: |- + Provides an EC2 Capacity Block Reservation. This allows you to purchase capacity block for your Amazon EC2 instances in a specific Availability Zone for machine learning (ML) Workloads. +--- + +# Resource: aws_ec2_capacity_block_reservation + +Provides an EC2 Capacity Block Reservation. This allows you to purchase capacity block for your Amazon EC2 instances in a specific Availability Zone for machine learning (ML) Workloads. + +~> **NOTE:** Once created, a reservation is valid for the `duration` of the provided `capacity_block_offering_id` and cannot be deleted. Performing a `destroy` will only remove the resource from state. For more information see [EC2 Capacity Block Reservation Documentation](https://aws.amazon.com/ec2/instance-types/p5/) and [PurchaseReservedDBInstancesOffering](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/capacity-blocks-pricing-billing.html). + +~> **NOTE:** Due to the expense of testing this resource, we provide it as best effort. If you find it useful, and have the ability to help test or notice issues, consider reaching out to us on [GitHub](https://github.com/hashicorp/terraform-provider-aws). + +## Example Usage + +```terraform + + +data "aws_ec2_capacity_block_offering" "test" { + capacity_duration = 24 + end_date = "2024-05-30T15:04:05Z" + instance_count = 1 + instance_platform = "Linux/UNIX" + instance_type = "p4d.24xlarge" + start_date = "2024-04-28T15:04:05Z" +} + +resource "aws_ec2_capacity_block_reservation" "test" { + capacity_block_offering_id = data.aws_ec2_capacity_block_offering.test.id + instance_platform = "Linux/UNIX" + tags = { + "Environment" = "dev" + } +} +``` + +## Argument Reference + +This resource supports the following arguments: + +* `capacity_block_offering_id` - (Required) The Capacity Block Reservation ID. +* `instance_platform` - (Required) The type of operating system for which to reserve capacity. Valid options are `Linux/UNIX`, `Red Hat Enterprise Linux`, `SUSE Linux`, `Windows`, `Windows with SQL Server`, `Windows with SQL Server Enterprise`, `Windows with SQL Server Standard` or `Windows with SQL Server Web`. +* `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. + +## Attribute Reference + +This resource exports the following attributes in addition to the arguments above: + +* `availability_zone` - The Availability Zone in which to create the Capacity Block Reservation. +* `end_date` - The date and time at which the Capacity Block Reservation expires. When a Capacity Block Reservation expires, the reserved capacity is released and you can no longer launch instances into it. Valid values: [RFC3339 time string](https://tools.ietf.org/html/rfc3339#section-5.8) (`YYYY-MM-DDTHH:MM:SSZ`) +* `instance_count` - The number of instances for which to reserve capacity. +* `instance_type` - The instance type for which to reserve capacity. +* `start_date` - The date and time at which the Capacity Block Reservation starts. Valid values: [RFC3339 time string](https://tools.ietf.org/html/rfc3339#section-5.8) (`YYYY-MM-DDTHH:MM:SSZ`) +* `tenancy` - Indicates the tenancy of the Capacity Block Reservation. Specify either `default` or `dedicated`. +* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) From 6198823bbdb301211c39f5a618af85137ff3ccfb Mon Sep 17 00:00:00 2001 From: Prabhav Pawar Date: Thu, 16 May 2024 12:55:44 +0530 Subject: [PATCH 02/20] Add changelog --- .changelog/37528.txt | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changelog/37528.txt diff --git a/.changelog/37528.txt b/.changelog/37528.txt new file mode 100644 index 00000000000..f1d4ce8772b --- /dev/null +++ b/.changelog/37528.txt @@ -0,0 +1,7 @@ +```release-note:new-resource +aws_ec2_capacity_block_reservation +``` + +```release-note:new-data-source +aws_ec2_capacity_block_offering +``` \ No newline at end of file From ce01151ee0fa11ff9bc4dca8c85afdddfe53d510 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 4 Jun 2024 13:22:15 -0500 Subject: [PATCH 03/20] aws_ec2_capacity_block_offering: refactor to framework --- ...ec2_capacity_block_offering_data_source.go | 177 ++++++++++-------- ...apacity_block_offering_data_source_test.go | 22 ++- .../ec2/ec2_capacity_block_reservation.go | 2 +- .../ec2_capacity_block_reservation_test.go | 6 +- internal/service/ec2/service_package_gen.go | 9 + 5 files changed, 119 insertions(+), 97 deletions(-) diff --git a/internal/service/ec2/ec2_capacity_block_offering_data_source.go b/internal/service/ec2/ec2_capacity_block_offering_data_source.go index cfa35c7a88a..f92e20a5caf 100644 --- a/internal/service/ec2/ec2_capacity_block_offering_data_source.go +++ b/internal/service/ec2/ec2_capacity_block_offering_data_source.go @@ -5,131 +5,142 @@ package ec2 import ( "context" + + "github.com/aws/aws-sdk-go-v2/service/ec2" + awstypes "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" - "time" - - aws_sdkv2 "github.com/aws/aws-sdk-go-v2/aws" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "github.com/hashicorp/terraform-provider-aws/internal/conns" - "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" ) -const ( - ResNameCapacityBlockOffering = "Capacity Block Offering" -) +// @FrameworkDataSource(name="Capacity Block Offering") +// @Testing(tagsTest=false) +func newDataSourceCapacityBlockOffering(_ context.Context) (datasource.DataSourceWithConfigure, error) { + d := &dataSourceCapacityBlockOffering{} + + return d, nil +} + +type dataSourceCapacityBlockOffering struct { + framework.DataSourceWithConfigure +} + +func (d *dataSourceCapacityBlockOffering) Metadata(_ context.Context, _ datasource.MetadataRequest, response *datasource.MetadataResponse) { + response.TypeName = "aws_ec2_capacity_block_offering" +} -// @SDKDataSource("aws_ec2_capacity_block_offering") -func DataSourceCapacityBlockOffering() *schema.Resource { - return &schema.Resource{ - ReadWithoutTimeout: dataSourceCapacityBlockOfferingRead, - Schema: map[string]*schema.Schema{ - "availability_zone": { - Type: schema.TypeString, +func (d *dataSourceCapacityBlockOffering) Schema(_ context.Context, _ datasource.SchemaRequest, response *datasource.SchemaResponse) { + response.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "availability_zone": schema.StringAttribute{ Computed: true, }, - "capacity_duration": { - Type: schema.TypeInt, + "capacity_block_offering_id": framework.IDAttribute(), + "capacity_duration_hours": schema.Int64Attribute{ Required: true, }, - "currency_code": { - Type: schema.TypeString, + "currency_code": schema.StringAttribute{ Computed: true, }, - "end_date": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.IsRFC3339Time, + "end_date_range": schema.StringAttribute{ + CustomType: timetypes.RFC3339Type{}, + Optional: true, + Computed: true, }, - "instance_count": { - Type: schema.TypeInt, + "instance_count": schema.Int64Attribute{ Required: true, }, - "instance_type": { - Type: schema.TypeString, + "instance_type": schema.StringAttribute{ Required: true, }, - "start_date": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.IsRFC3339Time, + "start_date_range": schema.StringAttribute{ + CustomType: timetypes.RFC3339Type{}, + Optional: true, + Computed: true, }, - "tenancy": { - Type: schema.TypeString, + "tenancy": schema.StringAttribute{ Computed: true, }, - "upfront_fee": { - Type: schema.TypeString, + "upfront_fee": schema.StringAttribute{ Computed: true, }, }, } } -func dataSourceCapacityBlockOfferingRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).EC2Conn(ctx) +const ( + DSNameCapacityBlockOffering = "Capacity Block Offering" +) - input := &ec2.DescribeCapacityBlockOfferingsInput{ - CapacityDurationHours: aws.Int64(int64(d.Get("capacity_duration").(int))), - InstanceCount: aws.Int64(int64(d.Get("instance_count").(int))), - InstanceType: aws.String(d.Get("instance_type").(string)), - } +func (d *dataSourceCapacityBlockOffering) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) { + conn := d.Meta().EC2Client(ctx) + var data dataSourceCapacityBlockOfferingData - if v, ok := d.GetOk("start_date"); ok { - v, _ := time.Parse(time.RFC3339, v.(string)) - input.StartDateRange = aws.Time(v) + response.Diagnostics.Append(request.Config.Get(ctx, &data)...) + + if response.Diagnostics.HasError() { + return } - if v, ok := d.GetOk("end_date"); ok { - v, _ := time.Parse(time.RFC3339, v.(string)) - input.EndDateRange = aws.Time(v) + input := &ec2.DescribeCapacityBlockOfferingsInput{} + response.Diagnostics.Append(fwflex.Expand(ctx, data, input)...) + + if response.Diagnostics.HasError() { + return } - output, err := conn.DescribeCapacityBlockOfferingsWithContext(ctx, input) + output, err := findCapacityBLockOffering(ctx, conn, input) if err != nil { - return create.DiagError(names.EC2, create.ErrActionReading, ResNameCapacityBlockOffering, "unknown", err) + response.Diagnostics.AddError( + create.ProblemStandardMessage(names.EC2, create.ErrActionReading, DSNameCapacityBlockOffering, data.InstanceType.String(), err), + err.Error(), + ) + return } - if len(output.CapacityBlockOfferings) == 0 { - return diag.Errorf("no %s %s found matching criteria; try different search", names.EC2, ResNameCapacityBlockOffering) - } + response.Diagnostics.Append(fwflex.Flatten(ctx, output, &data)...) - if len(output.CapacityBlockOfferings) > 1 { - return diag.Errorf("More than one %s %s found matching criteria; try different search", names.EC2, ResNameCapacityBlockOffering) + if response.Diagnostics.HasError() { + return } + response.Diagnostics.Append(response.State.Set(ctx, &data)...) +} + +type dataSourceCapacityBlockOfferingData struct { + AvailabilityZone types.String `tfsdk:"availability_zone"` + CapacityDurationHours types.Int64 `tfsdk:"capacity_duration_hours"` + CurrencyCode types.String `tfsdk:"currency_code"` + EndDateRange timetypes.RFC3339 `tfsdk:"end_date_range"` + CapacityBlockOfferingID types.String `tfsdk:"capacity_block_offering_id"` + InstanceCount types.Int64 `tfsdk:"instance_count"` + InstanceType types.String `tfsdk:"instance_type"` + StartDateRange timetypes.RFC3339 `tfsdk:"start_date_range"` + Tenancy types.String `tfsdk:"tenancy"` + UpfrontFee types.String `tfsdk:"upfront_fee"` +} + +func findCapacityBLockOffering(ctx context.Context, conn *ec2.Client, in *ec2.DescribeCapacityBlockOfferingsInput) (*awstypes.CapacityBlockOffering, error) { + output, err := conn.DescribeCapacityBlockOfferings(ctx, in) + if err != nil { + return nil, err + } - return sdkdiag.AppendErrorf(diags, "creating EC2 Capacity Reservation: %s", err) + if output == nil || len(output.CapacityBlockOfferings) == 0 { + return nil, tfresource.NewEmptyResultError(in) } - cbo := output.CapacityBlockOfferings[0] - { - d.SetId(aws_sdkv2.ToString(cbo.CapacityBlockOfferingId)) - d.Set("availability_zone", cbo.AvailabilityZone) - d.Set("capacity_duration", cbo.CapacityBlockDurationHours) - d.Set("currency_code", cbo.CurrencyCode) - if cbo.EndDate != nil { - d.Set("end_date", aws.TimeValue(cbo.EndDate).Format(time.RFC3339)) - } else { - d.Set("end_date", nil) - } - d.Set("instance_count", cbo.InstanceCount) - d.Set("instance_type", cbo.InstanceType) - if cbo.StartDate != nil { - d.Set("start_date", aws.TimeValue(cbo.StartDate).Format(time.RFC3339)) - } else { - d.Set("start_date", nil) - } - d.Set("tenancy", cbo.Tenancy) - d.Set("upfront_fee", cbo.UpfrontFee) + if len(output.CapacityBlockOfferings) > 1 { + return nil, tfresource.NewTooManyResultsError(len(output.CapacityBlockOfferings), in) } - return nil + return tfresource.AssertSingleValueResult(output.CapacityBlockOfferings) } diff --git a/internal/service/ec2/ec2_capacity_block_offering_data_source_test.go b/internal/service/ec2/ec2_capacity_block_offering_data_source_test.go index 4a55df7763d..f8c7bed83ad 100644 --- a/internal/service/ec2/ec2_capacity_block_offering_data_source_test.go +++ b/internal/service/ec2/ec2_capacity_block_offering_data_source_test.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -package ec2 +package ec2_test import ( "fmt" @@ -20,19 +20,21 @@ func TestAccEC2CapacityBlockOffering_basic(t *testing.T) { endDate := time.Now().UTC().Add(720 * time.Hour).Format(time.RFC3339) resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(ctx, t) }, + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: nil, ErrorCheck: acctest.ErrorCheck(t, names.EC2), + CheckDestroy: nil, Steps: []resource.TestStep{ { Config: testAccCapacityBlockOfferingConfig_basic(startDate, endDate), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet(dataSourceName, "availability_zone"), - resource.TestCheckResourceAttr(dataSourceName, "capacity_duration", "24"), + resource.TestCheckResourceAttr(dataSourceName, "capacity_duration_hours", "24"), resource.TestCheckResourceAttr(dataSourceName, "instance_count", "1"), resource.TestCheckResourceAttr(dataSourceName, "instance_type", "p4d.24xlarge"), - resource.TestCheckResourceAttrSet(dataSourceName, "id"), + resource.TestCheckResourceAttrSet(dataSourceName, "capacity_block_offering_id"), resource.TestCheckResourceAttr(dataSourceName, "tenancy", "default"), resource.TestCheckResourceAttrSet(dataSourceName, "upfront_fee"), ), @@ -44,11 +46,11 @@ func TestAccEC2CapacityBlockOffering_basic(t *testing.T) { func testAccCapacityBlockOfferingConfig_basic(startDate, endDate string) string { return fmt.Sprintf(` data "aws_ec2_capacity_block_offering" "test" { - instance_type = "p4d.24xlarge" - capacity_duration = 24 - instance_count = 1 - start_date = %[1]q - end_date = %[2]q + instance_type = "p4d.24xlarge" + capacity_duration_hours = 24 + instance_count = 1 + start_date_range = %[1]q + end_date_range = %[2]q } `, startDate, endDate) } diff --git a/internal/service/ec2/ec2_capacity_block_reservation.go b/internal/service/ec2/ec2_capacity_block_reservation.go index 7e29551a4d2..3f3dac0abe5 100644 --- a/internal/service/ec2/ec2_capacity_block_reservation.go +++ b/internal/service/ec2/ec2_capacity_block_reservation.go @@ -5,6 +5,7 @@ package ec2 import ( "context" + "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -18,7 +19,6 @@ import ( ) // @SDKResource("aws_ec2_capacity_block_reservation", name="Capacity Block Reservation") -// @Tags(identifierAttribute="id") func ResourceCapacityBlockReservation() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceCapacityBlockReservationCreate, diff --git a/internal/service/ec2/ec2_capacity_block_reservation_test.go b/internal/service/ec2/ec2_capacity_block_reservation_test.go index fc3a5ff0f18..b10b9d761ee 100644 --- a/internal/service/ec2/ec2_capacity_block_reservation_test.go +++ b/internal/service/ec2/ec2_capacity_block_reservation_test.go @@ -90,13 +90,13 @@ data "aws_ec2_capacity_block_offering" "test" { instance_type = "p4d.24xlarge" capacity_duration = 24 instance_count = 1 - start_date = %[1]q - end_date = %[2]q + start_date = %[1]q + end_date = %[2]q } resource "aws_ec2_capacity_block_reservation" "test" { capacity_block_offering_id = data.aws_ec2_capacity_block_offering.test.id - instance_platform = "Linux/UNIX" + instance_platform = "Linux/UNIX" tags = { "Environment" = "dev" } diff --git a/internal/service/ec2/service_package_gen.go b/internal/service/ec2/service_package_gen.go index f2265c2afaf..3d06f556cd8 100644 --- a/internal/service/ec2/service_package_gen.go +++ b/internal/service/ec2/service_package_gen.go @@ -14,6 +14,10 @@ type servicePackage struct{} func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*types.ServicePackageFrameworkDataSource { return []*types.ServicePackageFrameworkDataSource{ + { + Factory: newDataSourceCapacityBlockOffering, + Name: "Capacity Block Offering", + }, { Factory: newSecurityGroupRuleDataSource, Name: "Security Group Rule", @@ -556,6 +560,11 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka Factory: ResourceAvailabilityZoneGroup, TypeName: "aws_ec2_availability_zone_group", }, + { + Factory: ResourceCapacityBlockReservation, + TypeName: "aws_ec2_capacity_block_reservation", + Name: "Capacity Block Reservation", + }, { Factory: ResourceCapacityReservation, TypeName: "aws_ec2_capacity_reservation", From c0ca30608118abba1b65e0e84b821128e50205df Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 4 Jun 2024 13:26:20 -0500 Subject: [PATCH 04/20] aws_ec2_capacity_block_offering: update documentation --- .../r/ec2_capacity_block_offering.html.markdown | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/website/docs/r/ec2_capacity_block_offering.html.markdown b/website/docs/r/ec2_capacity_block_offering.html.markdown index ba80bdd6e1b..07355eebe21 100644 --- a/website/docs/r/ec2_capacity_block_offering.html.markdown +++ b/website/docs/r/ec2_capacity_block_offering.html.markdown @@ -16,12 +16,12 @@ Information about a single EC2 Capacity Block Reservation. data "aws_ec2_capacity_block_offering" "test" { - capacity_duration = 24 - end_date = "2024-05-30T15:04:05Z" + capacity_duration_hours = 24 + end_date_range = "2024-05-30T15:04:05Z" instance_count = 1 instance_platform = "Linux/UNIX" instance_type = "p4d.24xlarge" - start_date = "2024-04-28T15:04:05Z" + start_date_range = "2024-04-28T15:04:05Z" } ``` @@ -30,11 +30,11 @@ data "aws_ec2_capacity_block_offering" "test" { This resource supports the following arguments: -* `capacity_duration` - (Required) The amount of time of the Capacity Block reservation in hours. -* `end_date` - (Optional) The date and time at which the Capacity Block Reservation expires. When a Capacity Reservation expires, the reserved capacity is released and you can no longer launch instances into it. Valid values: [RFC3339 time string](https://tools.ietf.org/html/rfc3339#section-5.8) (`YYYY-MM-DDTHH:MM:SSZ`) +* `capacity_duration_hours` - (Required) The amount of time of the Capacity Block reservation in hours. +* `end_date_range` - (Optional) The date and time at which the Capacity Block Reservation expires. When a Capacity Reservation expires, the reserved capacity is released and you can no longer launch instances into it. Valid values: [RFC3339 time string](https://tools.ietf.org/html/rfc3339#section-5.8) (`YYYY-MM-DDTHH:MM:SSZ`) * `instance_count` - (Required) The number of instances for which to reserve capacity. * `instance_type` - (Required) The instance type for which to reserve capacity. -* `start_date` - (Optional) The date and time at which the Capacity Block Reservation starts. Valid values: [RFC3339 time string](https://tools.ietf.org/html/rfc3339#section-5.8) (`YYYY-MM-DDTHH:MM:SSZ`) +* `start_date_range` - (Optional) The date and time at which the Capacity Block Reservation starts. Valid values: [RFC3339 time string](https://tools.ietf.org/html/rfc3339#section-5.8) (`YYYY-MM-DDTHH:MM:SSZ`) ## Attribute Reference @@ -42,7 +42,6 @@ This resource exports the following attributes in addition to the arguments abov * `availability_zone` - The Availability Zone in which to create the Capacity Reservation. * `currency_code` - The currency of the payment for the Capacity Block. -* `id` - The Capacity Block Reservation ID. -* `instance_platform` - The type of operating system for which to reserve capacity. Valid options are `Linux/UNIX`, `Red Hat Enterprise Linux`, `SUSE Linux`, `Windows`, `Windows with SQL Server`, `Windows with SQL Server Enterprise`, `Windows with SQL Server Standard` or `Windows with SQL Server Web`. +* `capacity_block_offering_id` - The Capacity Block Reservation ID. * `upfront_fee` - The total price to be paid up front. * `tenancy` - Indicates the tenancy of the Capacity Reservation. Specify either `default` or `dedicated`. From 4bfafad62eb5937c92c7f18280c20d04c2d49356 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 4 Jun 2024 13:30:29 -0500 Subject: [PATCH 05/20] aws_ec2_capacity_block_offering: update documentation --- .../r/ec2_capacity_block_offering.html.markdown | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/website/docs/r/ec2_capacity_block_offering.html.markdown b/website/docs/r/ec2_capacity_block_offering.html.markdown index 07355eebe21..0a9eb333587 100644 --- a/website/docs/r/ec2_capacity_block_offering.html.markdown +++ b/website/docs/r/ec2_capacity_block_offering.html.markdown @@ -13,17 +13,14 @@ Information about a single EC2 Capacity Block Reservation. ## Example Usage ```terraform - - -data "aws_ec2_capacity_block_offering" "test" { - capacity_duration_hours = 24 - end_date_range = "2024-05-30T15:04:05Z" - instance_count = 1 - instance_platform = "Linux/UNIX" - instance_type = "p4d.24xlarge" - start_date_range = "2024-04-28T15:04:05Z" +data "aws_ec2_capacity_block_offering" "test" { + capacity_duration_hours = 24 + end_date_range = "2024-05-30T15:04:05Z" + instance_count = 1 + instance_platform = "Linux/UNIX" + instance_type = "p4d.24xlarge" + start_date_range = "2024-04-28T15:04:05Z" } - ``` ## Argument Reference From c79bcbe19adaccfaeb91149c31146a30bca9cf5e Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 4 Jun 2024 13:35:50 -0500 Subject: [PATCH 06/20] aws_ec2_capacity_block_offering: remove testing directive --- internal/service/ec2/ec2_capacity_block_offering_data_source.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/service/ec2/ec2_capacity_block_offering_data_source.go b/internal/service/ec2/ec2_capacity_block_offering_data_source.go index f92e20a5caf..8de33862f7f 100644 --- a/internal/service/ec2/ec2_capacity_block_offering_data_source.go +++ b/internal/service/ec2/ec2_capacity_block_offering_data_source.go @@ -20,7 +20,6 @@ import ( ) // @FrameworkDataSource(name="Capacity Block Offering") -// @Testing(tagsTest=false) func newDataSourceCapacityBlockOffering(_ context.Context) (datasource.DataSourceWithConfigure, error) { d := &dataSourceCapacityBlockOffering{} From 77b77bdb8b44ce0f32937682dd3be74c8c19979a Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 4 Jun 2024 14:31:19 -0500 Subject: [PATCH 07/20] fix semgrep errors --- ...ec2_capacity_block_offering_data_source.go | 6 +- ...apacity_block_offering_data_source_test.go | 6 +- .../ec2/ec2_capacity_block_reservation.go | 10 +- .../ec2/ec2_capacity_block_reservation_fw.go | 235 ++++++++++++++++++ .../ec2_capacity_block_reservation_test.go | 12 +- 5 files changed, 252 insertions(+), 17 deletions(-) create mode 100644 internal/service/ec2/ec2_capacity_block_reservation_fw.go diff --git a/internal/service/ec2/ec2_capacity_block_offering_data_source.go b/internal/service/ec2/ec2_capacity_block_offering_data_source.go index 8de33862f7f..9c36a9ccab7 100644 --- a/internal/service/ec2/ec2_capacity_block_offering_data_source.go +++ b/internal/service/ec2/ec2_capacity_block_offering_data_source.go @@ -37,7 +37,7 @@ func (d *dataSourceCapacityBlockOffering) Metadata(_ context.Context, _ datasour func (d *dataSourceCapacityBlockOffering) Schema(_ context.Context, _ datasource.SchemaRequest, response *datasource.SchemaResponse) { response.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ - "availability_zone": schema.StringAttribute{ + names.AttrAvailabilityZone: schema.StringAttribute{ Computed: true, }, "capacity_block_offering_id": framework.IDAttribute(), @@ -52,10 +52,10 @@ func (d *dataSourceCapacityBlockOffering) Schema(_ context.Context, _ datasource Optional: true, Computed: true, }, - "instance_count": schema.Int64Attribute{ + names.AttrInstanceCount: schema.Int64Attribute{ Required: true, }, - "instance_type": schema.StringAttribute{ + names.AttrInstanceType: schema.StringAttribute{ Required: true, }, "start_date_range": schema.StringAttribute{ diff --git a/internal/service/ec2/ec2_capacity_block_offering_data_source_test.go b/internal/service/ec2/ec2_capacity_block_offering_data_source_test.go index f8c7bed83ad..9fe051bd2df 100644 --- a/internal/service/ec2/ec2_capacity_block_offering_data_source_test.go +++ b/internal/service/ec2/ec2_capacity_block_offering_data_source_test.go @@ -30,10 +30,10 @@ func TestAccEC2CapacityBlockOffering_basic(t *testing.T) { { Config: testAccCapacityBlockOfferingConfig_basic(startDate, endDate), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet(dataSourceName, "availability_zone"), + resource.TestCheckResourceAttrSet(dataSourceName, names.AttrAvailabilityZone), resource.TestCheckResourceAttr(dataSourceName, "capacity_duration_hours", "24"), - resource.TestCheckResourceAttr(dataSourceName, "instance_count", "1"), - resource.TestCheckResourceAttr(dataSourceName, "instance_type", "p4d.24xlarge"), + resource.TestCheckResourceAttr(dataSourceName, names.AttrInstanceCount, acctest.Ct1), + resource.TestCheckResourceAttr(dataSourceName, names.AttrInstanceType, "p4d.24xlarge"), resource.TestCheckResourceAttrSet(dataSourceName, "capacity_block_offering_id"), resource.TestCheckResourceAttr(dataSourceName, "tenancy", "default"), resource.TestCheckResourceAttrSet(dataSourceName, "upfront_fee"), diff --git a/internal/service/ec2/ec2_capacity_block_reservation.go b/internal/service/ec2/ec2_capacity_block_reservation.go index 3f3dac0abe5..07a47aff197 100644 --- a/internal/service/ec2/ec2_capacity_block_reservation.go +++ b/internal/service/ec2/ec2_capacity_block_reservation.go @@ -32,11 +32,11 @@ func ResourceCapacityBlockReservation() *schema.Resource { CustomizeDiff: verify.SetTagsDiff, Schema: map[string]*schema.Schema{ - "arn": { + names.AttrARN: { Type: schema.TypeString, Computed: true, }, - "availability_zone": { + names.AttrAvailabilityZone: { Type: schema.TypeString, Computed: true, }, @@ -61,7 +61,7 @@ func ResourceCapacityBlockReservation() *schema.Resource { Type: schema.TypeBool, Computed: true, }, - "instance_count": { + names.AttrInstanceCount: { Type: schema.TypeInt, Computed: true, }, @@ -75,7 +75,7 @@ func ResourceCapacityBlockReservation() *schema.Resource { ForceNew: true, ValidateFunc: validation.StringInSlice(ec2.CapacityReservationInstancePlatform_Values(), false), }, - "instance_type": { + names.AttrInstanceType: { Type: schema.TypeString, Computed: true, }, @@ -83,7 +83,7 @@ func ResourceCapacityBlockReservation() *schema.Resource { Type: schema.TypeString, Computed: true, }, - "owner_id": { + names.AttrOwnerID: { Type: schema.TypeString, Computed: true, }, diff --git a/internal/service/ec2/ec2_capacity_block_reservation_fw.go b/internal/service/ec2/ec2_capacity_block_reservation_fw.go new file mode 100644 index 00000000000..5dbde67938c --- /dev/null +++ b/internal/service/ec2/ec2_capacity_block_reservation_fw.go @@ -0,0 +1,235 @@ +// Code generated by tools/tfsdk2fw/main.go. Manual editing is required. + +package ec2 + +import ( + "context" + + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/names" + + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-provider-aws/internal/framework" +) + +// @FrameworkResource("aws_ec2_capacity_block_reservation") +// @Tags(identifierAttribute="id") +// @Testing(tagsTest=false) +func newResourceCapacityBlockReservation(context.Context) (resource.ResourceWithConfigure, error) { + r := &resourceCapacityBlockReservation{} + + return r, nil +} + +type resourceCapacityBlockReservation struct { + framework.ResourceWithConfigure + framework.WithNoOpUpdate[resourceCapacityBlockReservationData] + framework.WithNoOpDelete +} + +// Metadata should return the full name of the resource, such as +// examplecloud_thing. +func (r *resourceCapacityBlockReservation) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) { + response.TypeName = "aws_ec2_capacity_block_reservation" +} + +// Schema returns the schema for this resource. +func (r *resourceCapacityBlockReservation) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) { + s := schema.Schema{ + Attributes: map[string]schema.Attribute{ + names.AttrARN: schema.StringAttribute{ + Computed: true, + }, + names.AttrAvailabilityZone: schema.StringAttribute{ + Computed: true, + }, + "capacity_block_offering_id": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "ebs_optimized": schema.BoolAttribute{ + Computed: true, + }, + "end_date": schema.StringAttribute{ + Computed: true, + }, + "end_date_type": schema.StringAttribute{ + Computed: true, + }, + "ephemeral_storage": schema.BoolAttribute{ + Computed: true, + }, + names.AttrID: // TODO framework.IDAttribute() + schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + names.AttrInstanceCount: schema.Int64Attribute{ + Computed: true, + }, + "instance_match_criteria": schema.StringAttribute{ + Computed: true, + }, + "instance_platform": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + // TODO Validate, + }, + names.AttrInstanceType: schema.StringAttribute{ + Computed: true, + }, + "outpost_arn": schema.StringAttribute{ + Computed: true, + }, + names.AttrOwnerID: schema.StringAttribute{ + Computed: true, + }, + "placement_group_arn": schema.StringAttribute{ + Computed: true, + }, + "start_date": schema.StringAttribute{ + Computed: true, + }, + names.AttrTags: tftags.TagsAttribute(), + names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), + "tenancy": schema.StringAttribute{ + Computed: true, + }, + }, + } + + response.Schema = s +} + +// Create is called when the provider must create a new resource. +// Config and planned state values should be read from the CreateRequest and new state values set on the CreateResponse. +func (r *resourceCapacityBlockReservation) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { + var data resourceCapacityBlockReservationData + + response.Diagnostics.Append(request.Plan.Get(ctx, &data)...) + + if response.Diagnostics.HasError() { + return + } + + data.ID = types.StringValue("TODO") + + response.Diagnostics.Append(response.State.Set(ctx, &data)...) +} + +// Read is called when the provider must read resource values in order to update state. +// Planned state values should be read from the ReadRequest and new state values set on the ReadResponse. +func (r *resourceCapacityBlockReservation) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) { + var data resourceCapacityBlockReservationData + + response.Diagnostics.Append(request.State.Get(ctx, &data)...) + + if response.Diagnostics.HasError() { + return + } + + response.Diagnostics.Append(response.State.Set(ctx, &data)...) +} + +// Update is called to update the state of the resource. +// Config, planned state, and prior state values should be read from the UpdateRequest and new state values set on the UpdateResponse. +func (r *resourceCapacityBlockReservation) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) { + var old, new resourceCapacityBlockReservationData + + response.Diagnostics.Append(request.State.Get(ctx, &old)...) + + if response.Diagnostics.HasError() { + return + } + + response.Diagnostics.Append(request.Plan.Get(ctx, &new)...) + + if response.Diagnostics.HasError() { + return + } + + response.Diagnostics.Append(response.State.Set(ctx, &new)...) +} + +// Delete is called when the provider must delete the resource. +// Config values may be read from the DeleteRequest. +// +// If execution completes without error, the framework will automatically call DeleteResponse.State.RemoveResource(), +// so it can be omitted from provider logic. +func (r *resourceCapacityBlockReservation) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) { + var data resourceCapacityBlockReservationData + + response.Diagnostics.Append(request.State.Get(ctx, &data)...) + + if response.Diagnostics.HasError() { + return + } + + tflog.Debug(ctx, "deleting TODO", map[string]interface{}{ + names.AttrID: data.ID.ValueString(), + }) +} + +// ImportState is called when the provider must import the state of a resource instance. +// This method must return enough state so the Read method can properly refresh the full resource. +// +// If setting an attribute with the import identifier, it is recommended to use the ImportStatePassthroughID() call in this method. +func (r *resourceCapacityBlockReservation) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { + resource.ImportStatePassthroughID(ctx, path.Root(names.AttrID), request, response) +} + +// ModifyPlan is called when the provider has an opportunity to modify +// the plan: once during the plan phase when Terraform is determining +// the diff that should be shown to the user for approval, and once +// during the apply phase with any unknown values from configuration +// filled in with their final values. +// +// The planned new state is represented by +// ModifyPlanResponse.Plan. It must meet the following +// constraints: +// 1. Any non-Computed attribute set in config must preserve the exact +// config value or return the corresponding attribute value from the +// prior state (ModifyPlanRequest.State). +// 2. Any attribute with a known value must not have its value changed +// in subsequent calls to ModifyPlan or Create/Read/Update. +// 3. Any attribute with an unknown value may either remain unknown +// or take on any value of the expected type. +// +// Any errors will prevent further resource-level plan modifications. +func (r *resourceCapacityBlockReservation) ModifyPlan(ctx context.Context, request resource.ModifyPlanRequest, response *resource.ModifyPlanResponse) { + r.SetTagsAll(ctx, request, response) +} + +type resourceCapacityBlockReservationData struct { + ARN types.String `tfsdk:"arn"` + AvailabilityZone types.String `tfsdk:"availability_zone"` + CapacityBlockOfferingID types.String `tfsdk:"capacity_block_offering_id"` + EbsOptimized types.Bool `tfsdk:"ebs_optimized"` + EndDate types.String `tfsdk:"end_date"` + EndDateType types.String `tfsdk:"end_date_type"` + EphemeralStorage types.Bool `tfsdk:"ephemeral_storage"` + ID types.String `tfsdk:"id"` + InstanceCount types.Int64 `tfsdk:"instance_count"` + InstanceMatchCriteria types.String `tfsdk:"instance_match_criteria"` + InstancePlatform types.String `tfsdk:"instance_platform"` + InstanceType types.String `tfsdk:"instance_type"` + OutpostARN types.String `tfsdk:"outpost_arn"` + OwnerID types.String `tfsdk:"owner_id"` + PlacementGroupARN types.String `tfsdk:"placement_group_arn"` + StartDate types.String `tfsdk:"start_date"` + Tags types.Map `tfsdk:"tags"` + TagsAll types.Map `tfsdk:"tags_all"` + Tenancy types.String `tfsdk:"tenancy"` +} diff --git a/internal/service/ec2/ec2_capacity_block_reservation_test.go b/internal/service/ec2/ec2_capacity_block_reservation_test.go index b10b9d761ee..17b6cebfc2e 100644 --- a/internal/service/ec2/ec2_capacity_block_reservation_test.go +++ b/internal/service/ec2/ec2_capacity_block_reservation_test.go @@ -6,7 +6,6 @@ package ec2_test import ( "context" "fmt" - "github.com/hashicorp/terraform-provider-aws/internal/conns" "os" "testing" "time" @@ -16,6 +15,7 @@ import ( "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/names" ) @@ -24,7 +24,7 @@ func TestAccEC2CapacityBlockReservation_basic(t *testing.T) { ctx := acctest.Context(t) key := "RUN_EC2_CAPACITY_BLOCK_RESERVATION_TESTS" vifId := os.Getenv(key) - if vifId != "true" { + if vifId != acctest.CtTrue { t.Skipf("Environment variable %s is not set to true", key) } @@ -44,14 +44,14 @@ func TestAccEC2CapacityBlockReservation_basic(t *testing.T) { Config: testAccCapacityBlockReservationConfig_basic(startDate, endDate), Check: resource.ComposeTestCheckFunc( testAccCheckCapacityBlockReservationExists(ctx, resourceName, &reservation), - acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexache.MustCompile(`capacity-reservation/cr-:.+`)), - resource.TestCheckResourceAttrPair(dataSourceName, "availability_zone", resourceName, "availability_zone"), + acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, "ec2", regexache.MustCompile(`capacity-reservation/cr-:.+`)), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrAvailabilityZone, resourceName, names.AttrAvailabilityZone), resource.TestCheckResourceAttrPair(dataSourceName, "capacity_block_offering_id", resourceName, "capacity_block_offering_id"), resource.TestCheckResourceAttrPair(dataSourceName, "start_date", resourceName, "start_date"), resource.TestCheckResourceAttrPair(dataSourceName, "end_date", resourceName, "end_date"), - resource.TestCheckResourceAttrPair(dataSourceName, "instance_count", resourceName, "instance_count"), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrInstanceCount, resourceName, names.AttrInstanceCount), resource.TestCheckResourceAttrPair(dataSourceName, "instance_platform", resourceName, "instance_platform"), - resource.TestCheckResourceAttrPair(dataSourceName, "instance_type", resourceName, "instance_type"), + resource.TestCheckResourceAttrPair(dataSourceName, names.AttrInstanceType, resourceName, names.AttrInstanceType), resource.TestCheckResourceAttrPair(dataSourceName, "tenancy", resourceName, "tenancy"), ), }, From 64936e626a94dd389eb1682799ddcf7c8dd313ef Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 4 Jun 2024 20:28:02 -0500 Subject: [PATCH 08/20] aws_ec2_capacity_block_reservation: WIP framework migration --- .../ec2/ec2_capacity_block_reservation.go | 249 +++++++++--------- .../ec2/ec2_capacity_block_reservation_fw.go | 7 +- internal/service/ec2/service_package_gen.go | 11 +- 3 files changed, 136 insertions(+), 131 deletions(-) diff --git a/internal/service/ec2/ec2_capacity_block_reservation.go b/internal/service/ec2/ec2_capacity_block_reservation.go index 07a47aff197..bb72c343d9d 100644 --- a/internal/service/ec2/ec2_capacity_block_reservation.go +++ b/internal/service/ec2/ec2_capacity_block_reservation.go @@ -3,128 +3,127 @@ package ec2 -import ( - "context" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/ec2" - "github.com/hashicorp/terraform-plugin-sdk/v2/diag" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "github.com/hashicorp/terraform-provider-aws/internal/conns" - "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" - tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" - "github.com/hashicorp/terraform-provider-aws/internal/verify" - "github.com/hashicorp/terraform-provider-aws/names" -) - -// @SDKResource("aws_ec2_capacity_block_reservation", name="Capacity Block Reservation") -func ResourceCapacityBlockReservation() *schema.Resource { - return &schema.Resource{ - CreateWithoutTimeout: resourceCapacityBlockReservationCreate, - ReadWithoutTimeout: resourceCapacityReservationRead, - UpdateWithoutTimeout: schema.NoopContext, - DeleteWithoutTimeout: schema.NoopContext, - Importer: &schema.ResourceImporter{ - StateContext: schema.ImportStatePassthroughContext, - }, - - CustomizeDiff: verify.SetTagsDiff, - - Schema: map[string]*schema.Schema{ - names.AttrARN: { - Type: schema.TypeString, - Computed: true, - }, - names.AttrAvailabilityZone: { - Type: schema.TypeString, - Computed: true, - }, - "capacity_block_offering_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "ebs_optimized": { - Type: schema.TypeBool, - Computed: true, - }, - "end_date": { - Type: schema.TypeString, - Computed: true, - }, - "end_date_type": { - Type: schema.TypeString, - Computed: true, - }, - "ephemeral_storage": { - Type: schema.TypeBool, - Computed: true, - }, - names.AttrInstanceCount: { - Type: schema.TypeInt, - Computed: true, - }, - "instance_match_criteria": { - Type: schema.TypeString, - Computed: true, - }, - "instance_platform": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice(ec2.CapacityReservationInstancePlatform_Values(), false), - }, - names.AttrInstanceType: { - Type: schema.TypeString, - Computed: true, - }, - "outpost_arn": { - Type: schema.TypeString, - Computed: true, - }, - names.AttrOwnerID: { - Type: schema.TypeString, - Computed: true, - }, - "placement_group_arn": { - Type: schema.TypeString, - Computed: true, - }, - "start_date": { - Type: schema.TypeString, - Computed: true, - }, - names.AttrTags: tftags.TagsSchema(), - names.AttrTagsAll: tftags.TagsSchemaComputed(), - "tenancy": { - Type: schema.TypeString, - Computed: true, - }, - }, - } -} - -func resourceCapacityBlockReservationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).EC2Conn(ctx) - - input := &ec2.PurchaseCapacityBlockInput{ - CapacityBlockOfferingId: aws.String(d.Get("capacity_block_offering_id").(string)), - InstancePlatform: aws.String(d.Get("instance_platform").(string)), - TagSpecifications: getTagSpecificationsIn(ctx, ec2.ResourceTypeCapacityReservation), - } - - output, err := conn.PurchaseCapacityBlock(input) - - if err != nil { - return sdkdiag.AppendErrorf(diags, "creating EC2 Capacity Reservation: %s", err) - } - d.SetId(aws.StringValue(output.CapacityReservation.CapacityReservationId)) - - if _, err := WaitCapacityReservationActive(ctx, conn, d.Id()); err != nil { - return sdkdiag.AppendErrorf(diags, "waiting for EC2 Capacity Reservation (%s) create: %s", d.Id(), err) - } - - return append(diags, resourceCapacityReservationRead(ctx, d, meta)...) -} +//import ( +// "context" +// +// "github.com/aws/aws-sdk-go/aws" +// "github.com/aws/aws-sdk-go/service/ec2" +// "github.com/hashicorp/terraform-plugin-sdk/v2/diag" +// "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +// "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" +// "github.com/hashicorp/terraform-provider-aws/internal/conns" +// "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" +// tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" +// "github.com/hashicorp/terraform-provider-aws/internal/verify" +// "github.com/hashicorp/terraform-provider-aws/names" +//) +// +//func ResourceCapacityBlockReservation() *schema.Resource { +// return &schema.Resource{ +// CreateWithoutTimeout: resourceCapacityBlockReservationCreate, +// ReadWithoutTimeout: resourceCapacityReservationRead, +// UpdateWithoutTimeout: schema.NoopContext, +// DeleteWithoutTimeout: schema.NoopContext, +// Importer: &schema.ResourceImporter{ +// StateContext: schema.ImportStatePassthroughContext, +// }, +// +// CustomizeDiff: verify.SetTagsDiff, +// +// Schema: map[string]*schema.Schema{ +// names.AttrARN: { +// Type: schema.TypeString, +// Computed: true, +// }, +// names.AttrAvailabilityZone: { +// Type: schema.TypeString, +// Computed: true, +// }, +// "capacity_block_offering_id": { +// Type: schema.TypeString, +// Required: true, +// ForceNew: true, +// }, +// "ebs_optimized": { +// Type: schema.TypeBool, +// Computed: true, +// }, +// "end_date": { +// Type: schema.TypeString, +// Computed: true, +// }, +// "end_date_type": { +// Type: schema.TypeString, +// Computed: true, +// }, +// "ephemeral_storage": { +// Type: schema.TypeBool, +// Computed: true, +// }, +// names.AttrInstanceCount: { +// Type: schema.TypeInt, +// Computed: true, +// }, +// "instance_match_criteria": { +// Type: schema.TypeString, +// Computed: true, +// }, +// "instance_platform": { +// Type: schema.TypeString, +// Required: true, +// ForceNew: true, +// ValidateFunc: validation.StringInSlice(ec2.CapacityReservationInstancePlatform_Values(), false), +// }, +// names.AttrInstanceType: { +// Type: schema.TypeString, +// Computed: true, +// }, +// "outpost_arn": { +// Type: schema.TypeString, +// Computed: true, +// }, +// names.AttrOwnerID: { +// Type: schema.TypeString, +// Computed: true, +// }, +// "placement_group_arn": { +// Type: schema.TypeString, +// Computed: true, +// }, +// "start_date": { +// Type: schema.TypeString, +// Computed: true, +// }, +// names.AttrTags: tftags.TagsSchema(), +// names.AttrTagsAll: tftags.TagsSchemaComputed(), +// "tenancy": { +// Type: schema.TypeString, +// Computed: true, +// }, +// }, +// } +//} +// +//func resourceCapacityBlockReservationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +// var diags diag.Diagnostics +// conn := meta.(*conns.AWSClient).EC2Conn(ctx) +// +// input := &ec2.PurchaseCapacityBlockInput{ +// CapacityBlockOfferingId: aws.String(d.Get("capacity_block_offering_id").(string)), +// InstancePlatform: aws.String(d.Get("instance_platform").(string)), +// TagSpecifications: getTagSpecificationsIn(ctx, ec2.ResourceTypeCapacityReservation), +// } +// +// output, err := conn.PurchaseCapacityBlock(input) +// +// if err != nil { +// return sdkdiag.AppendErrorf(diags, "creating EC2 Capacity Reservation: %s", err) +// } +// d.SetId(aws.StringValue(output.CapacityReservation.CapacityReservationId)) +// +// if _, err := WaitCapacityReservationActive(ctx, conn, d.Id()); err != nil { +// return sdkdiag.AppendErrorf(diags, "waiting for EC2 Capacity Reservation (%s) create: %s", d.Id(), err) +// } +// +// return append(diags, resourceCapacityReservationRead(ctx, d, meta)...) +//} diff --git a/internal/service/ec2/ec2_capacity_block_reservation_fw.go b/internal/service/ec2/ec2_capacity_block_reservation_fw.go index 5dbde67938c..61fda5ae93f 100644 --- a/internal/service/ec2/ec2_capacity_block_reservation_fw.go +++ b/internal/service/ec2/ec2_capacity_block_reservation_fw.go @@ -1,4 +1,5 @@ -// Code generated by tools/tfsdk2fw/main.go. Manual editing is required. +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 package ec2 @@ -113,6 +114,10 @@ func (r *resourceCapacityBlockReservation) Schema(ctx context.Context, request r response.Schema = s } +const ( + ResNameCapacityBlockReservation = "Capacity Block Reservation" +) + // Create is called when the provider must create a new resource. // Config and planned state values should be read from the CreateRequest and new state values set on the CreateResponse. func (r *resourceCapacityBlockReservation) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { diff --git a/internal/service/ec2/service_package_gen.go b/internal/service/ec2/service_package_gen.go index 3d06f556cd8..54cd4e1c01a 100644 --- a/internal/service/ec2/service_package_gen.go +++ b/internal/service/ec2/service_package_gen.go @@ -50,6 +50,12 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.Servic Factory: newInstanceMetadataDefaultsResource, Name: "Instance Metadata Defaults", }, + { + Factory: newResourceCapacityBlockReservation, + Tags: &types.ServicePackageResourceTags{ + IdentifierAttribute: names.AttrID, + }, + }, { Factory: newResourceEndpointPrivateDNS, Name: "Endpoint Private DNS", @@ -560,11 +566,6 @@ func (p *servicePackage) SDKResources(ctx context.Context) []*types.ServicePacka Factory: ResourceAvailabilityZoneGroup, TypeName: "aws_ec2_availability_zone_group", }, - { - Factory: ResourceCapacityBlockReservation, - TypeName: "aws_ec2_capacity_block_reservation", - Name: "Capacity Block Reservation", - }, { Factory: ResourceCapacityReservation, TypeName: "aws_ec2_capacity_reservation", From 195ce7328cce4499db245091bf153cc348fa7c0b Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Wed, 5 Jun 2024 15:41:19 -0500 Subject: [PATCH 09/20] aws_ec2_capacity_block_reservation: migrate to framework --- .../ec2/ec2_capacity_block_reservation.go | 507 +++++++++++++----- .../ec2/ec2_capacity_block_reservation_fw.go | 240 --------- internal/service/ec2/errors.go | 1 + 3 files changed, 384 insertions(+), 364 deletions(-) delete mode 100644 internal/service/ec2/ec2_capacity_block_reservation_fw.go diff --git a/internal/service/ec2/ec2_capacity_block_reservation.go b/internal/service/ec2/ec2_capacity_block_reservation.go index bb72c343d9d..d9850c2654a 100644 --- a/internal/service/ec2/ec2_capacity_block_reservation.go +++ b/internal/service/ec2/ec2_capacity_block_reservation.go @@ -3,127 +3,386 @@ package ec2 -//import ( -// "context" -// -// "github.com/aws/aws-sdk-go/aws" -// "github.com/aws/aws-sdk-go/service/ec2" -// "github.com/hashicorp/terraform-plugin-sdk/v2/diag" -// "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" -// "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" -// "github.com/hashicorp/terraform-provider-aws/internal/conns" -// "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" -// tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" -// "github.com/hashicorp/terraform-provider-aws/internal/verify" -// "github.com/hashicorp/terraform-provider-aws/names" -//) -// -//func ResourceCapacityBlockReservation() *schema.Resource { -// return &schema.Resource{ -// CreateWithoutTimeout: resourceCapacityBlockReservationCreate, -// ReadWithoutTimeout: resourceCapacityReservationRead, -// UpdateWithoutTimeout: schema.NoopContext, -// DeleteWithoutTimeout: schema.NoopContext, -// Importer: &schema.ResourceImporter{ -// StateContext: schema.ImportStatePassthroughContext, -// }, -// -// CustomizeDiff: verify.SetTagsDiff, -// -// Schema: map[string]*schema.Schema{ -// names.AttrARN: { -// Type: schema.TypeString, -// Computed: true, -// }, -// names.AttrAvailabilityZone: { -// Type: schema.TypeString, -// Computed: true, -// }, -// "capacity_block_offering_id": { -// Type: schema.TypeString, -// Required: true, -// ForceNew: true, -// }, -// "ebs_optimized": { -// Type: schema.TypeBool, -// Computed: true, -// }, -// "end_date": { -// Type: schema.TypeString, -// Computed: true, -// }, -// "end_date_type": { -// Type: schema.TypeString, -// Computed: true, -// }, -// "ephemeral_storage": { -// Type: schema.TypeBool, -// Computed: true, -// }, -// names.AttrInstanceCount: { -// Type: schema.TypeInt, -// Computed: true, -// }, -// "instance_match_criteria": { -// Type: schema.TypeString, -// Computed: true, -// }, -// "instance_platform": { -// Type: schema.TypeString, -// Required: true, -// ForceNew: true, -// ValidateFunc: validation.StringInSlice(ec2.CapacityReservationInstancePlatform_Values(), false), -// }, -// names.AttrInstanceType: { -// Type: schema.TypeString, -// Computed: true, -// }, -// "outpost_arn": { -// Type: schema.TypeString, -// Computed: true, -// }, -// names.AttrOwnerID: { -// Type: schema.TypeString, -// Computed: true, -// }, -// "placement_group_arn": { -// Type: schema.TypeString, -// Computed: true, -// }, -// "start_date": { -// Type: schema.TypeString, -// Computed: true, -// }, -// names.AttrTags: tftags.TagsSchema(), -// names.AttrTagsAll: tftags.TagsSchemaComputed(), -// "tenancy": { -// Type: schema.TypeString, -// Computed: true, -// }, -// }, -// } -//} -// -//func resourceCapacityBlockReservationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { -// var diags diag.Diagnostics -// conn := meta.(*conns.AWSClient).EC2Conn(ctx) -// -// input := &ec2.PurchaseCapacityBlockInput{ -// CapacityBlockOfferingId: aws.String(d.Get("capacity_block_offering_id").(string)), -// InstancePlatform: aws.String(d.Get("instance_platform").(string)), -// TagSpecifications: getTagSpecificationsIn(ctx, ec2.ResourceTypeCapacityReservation), -// } -// -// output, err := conn.PurchaseCapacityBlock(input) -// -// if err != nil { -// return sdkdiag.AppendErrorf(diags, "creating EC2 Capacity Reservation: %s", err) -// } -// d.SetId(aws.StringValue(output.CapacityReservation.CapacityReservationId)) -// -// if _, err := WaitCapacityReservationActive(ctx, conn, d.Id()); err != nil { -// return sdkdiag.AppendErrorf(diags, "waiting for EC2 Capacity Reservation (%s) create: %s", d.Id(), err) -// } -// -// return append(diags, resourceCapacityReservationRead(ctx, d, meta)...) -//} +import ( + "context" + "errors" + "time" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/ec2" + awstypes "github.com/aws/aws-sdk-go-v2/service/ec2/types" + "github.com/hashicorp/aws-sdk-go-base/v2/tfawserr" + "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" + "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/boolplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkResource("aws_ec2_capacity_block_reservation") +// @Tags(identifierAttribute="id") +// @Testing(tagsTest=false) +func newResourceCapacityBlockReservation(context.Context) (resource.ResourceWithConfigure, error) { + r := &resourceCapacityBlockReservation{} + r.SetDefaultCreateTimeout(40 * time.Minute) + + return r, nil +} + +type resourceCapacityBlockReservation struct { + framework.ResourceWithConfigure + framework.WithTimeouts + framework.WithImportByID + framework.WithNoOpUpdate[resourceCapacityBlockReservationData] + framework.WithNoOpDelete +} + +func (r *resourceCapacityBlockReservation) Metadata(_ context.Context, _ resource.MetadataRequest, response *resource.MetadataResponse) { + response.TypeName = "aws_ec2_capacity_block_reservation" +} + +func (r *resourceCapacityBlockReservation) Schema(ctx context.Context, _ resource.SchemaRequest, response *resource.SchemaResponse) { + s := schema.Schema{ + Attributes: map[string]schema.Attribute{ + names.AttrARN: schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + names.AttrAvailabilityZone: schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "capacity_block_offering_id": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "created_date": schema.StringAttribute{ + CustomType: timetypes.RFC3339Type{}, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "ebs_optimized": schema.BoolAttribute{ + Computed: true, + PlanModifiers: []planmodifier.Bool{ + boolplanmodifier.UseStateForUnknown(), + }, + }, + "end_date": schema.StringAttribute{ + CustomType: timetypes.RFC3339Type{}, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "end_date_type": schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.EndDateType](), + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "ephemeral_storage": schema.BoolAttribute{ + Computed: true, + PlanModifiers: []planmodifier.Bool{ + boolplanmodifier.UseStateForUnknown(), + }, + }, + names.AttrID: framework.IDAttribute(), + names.AttrInstanceCount: schema.Int64Attribute{ + Computed: true, + PlanModifiers: []planmodifier.Int64{ + int64planmodifier.UseStateForUnknown(), + }, + }, + "instance_match_criteria": schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.InstanceMatchCriteria](), + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "instance_platform": schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.CapacityReservationInstancePlatform](), + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + names.AttrInstanceType: schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "outpost_arn": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + names.AttrOwnerID: schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "reservation_type": schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.CapacityReservationType](), + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "placement_group_arn": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + "start_date": schema.StringAttribute{ + CustomType: timetypes.RFC3339Type{}, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + names.AttrTags: tftags.TagsAttribute(), + names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), + "tenancy": schema.StringAttribute{ + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + }, + }, + }, + Blocks: map[string]schema.Block{ + names.AttrTimeouts: timeouts.Block(ctx, timeouts.Opts{ + Create: true, + }), + }, + } + + response.Schema = s +} + +const ( + ResNameCapacityBlockReservation = "Capacity Block Reservation" +) + +func (r *resourceCapacityBlockReservation) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { + conn := r.Meta().EC2Client(ctx) + var plan resourceCapacityBlockReservationData + + response.Diagnostics.Append(request.Plan.Get(ctx, &plan)...) + + if response.Diagnostics.HasError() { + return + } + + input := &ec2.PurchaseCapacityBlockInput{} + response.Diagnostics.Append(fwflex.Expand(ctx, plan, input)...) + + if response.Diagnostics.HasError() { + return + } + + input.TagSpecifications = getTagSpecificationsInV2(ctx, awstypes.ResourceTypeCapacityReservation) + + output, err := conn.PurchaseCapacityBlock(ctx, input) + if err != nil { + response.Diagnostics.AddError( + create.ProblemStandardMessage(names.EC2, create.ErrActionCreating, ResNameCapacityBlockReservation, plan.CapacityBlockOfferingID.String(), err), + err.Error(), + ) + return + } + + if output == nil || output.CapacityReservation == nil { + response.Diagnostics.AddError( + create.ProblemStandardMessage(names.EC2, create.ErrActionCreating, ResNameCapacityBlockReservation, plan.CapacityBlockOfferingID.String(), nil), + errors.New("empty output").Error(), + ) + return + } + + cp := output.CapacityReservation + state := plan + state.ID = fwflex.StringToFramework(ctx, cp.CapacityReservationId) + + createTimeout := r.CreateTimeout(ctx, plan.Timeouts) + out, err := waitCapacityBlockReservationActive(ctx, conn, createTimeout, state.ID.ValueString()) + + if err != nil { + response.Diagnostics.AddError( + create.ProblemStandardMessage(names.EC2, create.ErrActionWaitingForCreation, ResNameCapacityBlockReservation, state.ID.String(), err), + err.Error(), + ) + return + } + + response.Diagnostics.Append(fwflex.Flatten(ctx, out, &state)...) + + if response.Diagnostics.HasError() { + return + } + + response.Diagnostics.Append(response.State.Set(ctx, &state)...) +} + +func (r *resourceCapacityBlockReservation) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) { + conn := r.Meta().EC2Client(ctx) + var data resourceCapacityBlockReservationData + + response.Diagnostics.Append(request.State.Get(ctx, &data)...) + + if response.Diagnostics.HasError() { + return + } + + output, err := findCapacityBlockReservationByID(ctx, conn, data.ID.ValueString()) + + if tfresource.NotFound(err) { + response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) + response.State.RemoveResource(ctx) + return + } + + response.Diagnostics.Append(fwflex.Flatten(ctx, output, &data)...) + + if response.Diagnostics.HasError() { + return + } + + response.Diagnostics.Append(response.State.Set(ctx, &data)...) +} + +func (r *resourceCapacityBlockReservation) ModifyPlan(ctx context.Context, request resource.ModifyPlanRequest, response *resource.ModifyPlanResponse) { + r.SetTagsAll(ctx, request, response) +} + +type resourceCapacityBlockReservationData struct { + ARN types.String `tfsdk:"arn"` + AvailabilityZone types.String `tfsdk:"availability_zone"` + CapacityBlockOfferingID types.String `tfsdk:"capacity_block_offering_id"` + EbsOptimized types.Bool `tfsdk:"ebs_optimized"` + EndDate timetypes.RFC3339 `tfsdk:"end_date"` + EndDateType fwtypes.StringEnum[awstypes.EndDateType] `tfsdk:"end_date_type"` + EphemeralStorage types.Bool `tfsdk:"ephemeral_storage"` + ID types.String `tfsdk:"id"` + InstanceCount types.Int64 `tfsdk:"instance_count"` + InstanceMatchCriteria fwtypes.StringEnum[awstypes.InstanceMatchCriteria] `tfsdk:"instance_match_criteria"` + InstancePlatform fwtypes.StringEnum[awstypes.CapacityReservationInstancePlatform] `tfsdk:"instance_platform"` + InstanceType types.String `tfsdk:"instance_type"` + OutpostARN types.String `tfsdk:"outpost_arn"` + OwnerID types.String `tfsdk:"owner_id"` + PlacementGroupARN types.String `tfsdk:"placement_group_arn"` + ReservationType fwtypes.StringEnum[awstypes.CapacityReservationType] `tfsdk:"reservation_type"` + StartDate timetypes.RFC3339 `tfsdk:"start_date"` + Tags types.Map `tfsdk:"tags"` + TagsAll types.Map `tfsdk:"tags_all"` + Tenancy types.String `tfsdk:"tenancy"` + Timeouts timeouts.Value `tfsdk:"timeouts"` +} + +func findCapacityBlockReservationByID(ctx context.Context, conn *ec2.Client, id string) (*awstypes.CapacityReservation, error) { + input := &ec2.DescribeCapacityReservationsInput{ + CapacityReservationIds: []string{id}, + } + + output, err := conn.DescribeCapacityReservations(ctx, input) + + if tfawserr.ErrCodeEquals(err, errCodeInvalidReservationNotFound, errCodeInvalidCapacityReservationIdNotFound) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || len(output.CapacityReservations) == 0 { + return nil, tfresource.NewEmptyResultError(input) + } + + reservation, err := tfresource.AssertSingleValueResult(output.CapacityReservations) + + if err != nil { + return nil, err + } + + // https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/capacity-reservations-using.html#capacity-reservations-view. + if state := reservation.State; state == awstypes.CapacityReservationStateCancelled || state == awstypes.CapacityReservationStateExpired { + return nil, &retry.NotFoundError{ + Message: string(state), + LastRequest: input, + } + } + + // Eventual consistency check. + if aws.ToString(reservation.CapacityReservationId) != id { + return nil, &retry.NotFoundError{ + LastRequest: input, + } + } + + return reservation, nil +} + +func waitCapacityBlockReservationActive(ctx context.Context, conn *ec2.Client, timeout time.Duration, id string) (*awstypes.CapacityReservation, error) { + stateConf := &retry.StateChangeConf{ + Pending: enum.Slice(awstypes.CapacityReservationStatePaymentPending), + Target: enum.Slice(awstypes.CapacityReservationStateActive), + Refresh: statusCapacityBlockReservation(ctx, conn, id), + Timeout: timeout, + MinTimeout: 10 * time.Second, + Delay: 30 * time.Second, + } + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*awstypes.CapacityReservation); ok { + return output, err + } + + return nil, err +} + +func statusCapacityBlockReservation(ctx context.Context, conn *ec2.Client, id string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := findCapacityBlockReservationByID(ctx, conn, id) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, string(output.State), nil + } +} diff --git a/internal/service/ec2/ec2_capacity_block_reservation_fw.go b/internal/service/ec2/ec2_capacity_block_reservation_fw.go deleted file mode 100644 index 61fda5ae93f..00000000000 --- a/internal/service/ec2/ec2_capacity_block_reservation_fw.go +++ /dev/null @@ -1,240 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package ec2 - -import ( - "context" - - "github.com/hashicorp/terraform-plugin-framework/path" - "github.com/hashicorp/terraform-plugin-framework/resource" - "github.com/hashicorp/terraform-plugin-framework/resource/schema" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" - "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" - tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" - "github.com/hashicorp/terraform-provider-aws/names" - - "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-plugin-log/tflog" - "github.com/hashicorp/terraform-provider-aws/internal/framework" -) - -// @FrameworkResource("aws_ec2_capacity_block_reservation") -// @Tags(identifierAttribute="id") -// @Testing(tagsTest=false) -func newResourceCapacityBlockReservation(context.Context) (resource.ResourceWithConfigure, error) { - r := &resourceCapacityBlockReservation{} - - return r, nil -} - -type resourceCapacityBlockReservation struct { - framework.ResourceWithConfigure - framework.WithNoOpUpdate[resourceCapacityBlockReservationData] - framework.WithNoOpDelete -} - -// Metadata should return the full name of the resource, such as -// examplecloud_thing. -func (r *resourceCapacityBlockReservation) Metadata(_ context.Context, request resource.MetadataRequest, response *resource.MetadataResponse) { - response.TypeName = "aws_ec2_capacity_block_reservation" -} - -// Schema returns the schema for this resource. -func (r *resourceCapacityBlockReservation) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) { - s := schema.Schema{ - Attributes: map[string]schema.Attribute{ - names.AttrARN: schema.StringAttribute{ - Computed: true, - }, - names.AttrAvailabilityZone: schema.StringAttribute{ - Computed: true, - }, - "capacity_block_offering_id": schema.StringAttribute{ - Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - }, - "ebs_optimized": schema.BoolAttribute{ - Computed: true, - }, - "end_date": schema.StringAttribute{ - Computed: true, - }, - "end_date_type": schema.StringAttribute{ - Computed: true, - }, - "ephemeral_storage": schema.BoolAttribute{ - Computed: true, - }, - names.AttrID: // TODO framework.IDAttribute() - schema.StringAttribute{ - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, - names.AttrInstanceCount: schema.Int64Attribute{ - Computed: true, - }, - "instance_match_criteria": schema.StringAttribute{ - Computed: true, - }, - "instance_platform": schema.StringAttribute{ - Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - // TODO Validate, - }, - names.AttrInstanceType: schema.StringAttribute{ - Computed: true, - }, - "outpost_arn": schema.StringAttribute{ - Computed: true, - }, - names.AttrOwnerID: schema.StringAttribute{ - Computed: true, - }, - "placement_group_arn": schema.StringAttribute{ - Computed: true, - }, - "start_date": schema.StringAttribute{ - Computed: true, - }, - names.AttrTags: tftags.TagsAttribute(), - names.AttrTagsAll: tftags.TagsAttributeComputedOnly(), - "tenancy": schema.StringAttribute{ - Computed: true, - }, - }, - } - - response.Schema = s -} - -const ( - ResNameCapacityBlockReservation = "Capacity Block Reservation" -) - -// Create is called when the provider must create a new resource. -// Config and planned state values should be read from the CreateRequest and new state values set on the CreateResponse. -func (r *resourceCapacityBlockReservation) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) { - var data resourceCapacityBlockReservationData - - response.Diagnostics.Append(request.Plan.Get(ctx, &data)...) - - if response.Diagnostics.HasError() { - return - } - - data.ID = types.StringValue("TODO") - - response.Diagnostics.Append(response.State.Set(ctx, &data)...) -} - -// Read is called when the provider must read resource values in order to update state. -// Planned state values should be read from the ReadRequest and new state values set on the ReadResponse. -func (r *resourceCapacityBlockReservation) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) { - var data resourceCapacityBlockReservationData - - response.Diagnostics.Append(request.State.Get(ctx, &data)...) - - if response.Diagnostics.HasError() { - return - } - - response.Diagnostics.Append(response.State.Set(ctx, &data)...) -} - -// Update is called to update the state of the resource. -// Config, planned state, and prior state values should be read from the UpdateRequest and new state values set on the UpdateResponse. -func (r *resourceCapacityBlockReservation) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) { - var old, new resourceCapacityBlockReservationData - - response.Diagnostics.Append(request.State.Get(ctx, &old)...) - - if response.Diagnostics.HasError() { - return - } - - response.Diagnostics.Append(request.Plan.Get(ctx, &new)...) - - if response.Diagnostics.HasError() { - return - } - - response.Diagnostics.Append(response.State.Set(ctx, &new)...) -} - -// Delete is called when the provider must delete the resource. -// Config values may be read from the DeleteRequest. -// -// If execution completes without error, the framework will automatically call DeleteResponse.State.RemoveResource(), -// so it can be omitted from provider logic. -func (r *resourceCapacityBlockReservation) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) { - var data resourceCapacityBlockReservationData - - response.Diagnostics.Append(request.State.Get(ctx, &data)...) - - if response.Diagnostics.HasError() { - return - } - - tflog.Debug(ctx, "deleting TODO", map[string]interface{}{ - names.AttrID: data.ID.ValueString(), - }) -} - -// ImportState is called when the provider must import the state of a resource instance. -// This method must return enough state so the Read method can properly refresh the full resource. -// -// If setting an attribute with the import identifier, it is recommended to use the ImportStatePassthroughID() call in this method. -func (r *resourceCapacityBlockReservation) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) { - resource.ImportStatePassthroughID(ctx, path.Root(names.AttrID), request, response) -} - -// ModifyPlan is called when the provider has an opportunity to modify -// the plan: once during the plan phase when Terraform is determining -// the diff that should be shown to the user for approval, and once -// during the apply phase with any unknown values from configuration -// filled in with their final values. -// -// The planned new state is represented by -// ModifyPlanResponse.Plan. It must meet the following -// constraints: -// 1. Any non-Computed attribute set in config must preserve the exact -// config value or return the corresponding attribute value from the -// prior state (ModifyPlanRequest.State). -// 2. Any attribute with a known value must not have its value changed -// in subsequent calls to ModifyPlan or Create/Read/Update. -// 3. Any attribute with an unknown value may either remain unknown -// or take on any value of the expected type. -// -// Any errors will prevent further resource-level plan modifications. -func (r *resourceCapacityBlockReservation) ModifyPlan(ctx context.Context, request resource.ModifyPlanRequest, response *resource.ModifyPlanResponse) { - r.SetTagsAll(ctx, request, response) -} - -type resourceCapacityBlockReservationData struct { - ARN types.String `tfsdk:"arn"` - AvailabilityZone types.String `tfsdk:"availability_zone"` - CapacityBlockOfferingID types.String `tfsdk:"capacity_block_offering_id"` - EbsOptimized types.Bool `tfsdk:"ebs_optimized"` - EndDate types.String `tfsdk:"end_date"` - EndDateType types.String `tfsdk:"end_date_type"` - EphemeralStorage types.Bool `tfsdk:"ephemeral_storage"` - ID types.String `tfsdk:"id"` - InstanceCount types.Int64 `tfsdk:"instance_count"` - InstanceMatchCriteria types.String `tfsdk:"instance_match_criteria"` - InstancePlatform types.String `tfsdk:"instance_platform"` - InstanceType types.String `tfsdk:"instance_type"` - OutpostARN types.String `tfsdk:"outpost_arn"` - OwnerID types.String `tfsdk:"owner_id"` - PlacementGroupARN types.String `tfsdk:"placement_group_arn"` - StartDate types.String `tfsdk:"start_date"` - Tags types.Map `tfsdk:"tags"` - TagsAll types.Map `tfsdk:"tags_all"` - Tenancy types.String `tfsdk:"tenancy"` -} diff --git a/internal/service/ec2/errors.go b/internal/service/ec2/errors.go index faeccad399f..91a8ed1fe69 100644 --- a/internal/service/ec2/errors.go +++ b/internal/service/ec2/errors.go @@ -80,6 +80,7 @@ const ( errCodeInvalidPrefixListIDNotFound = "InvalidPrefixListID.NotFound" errCodeInvalidPrefixListIdNotFound = "InvalidPrefixListId.NotFound" errCodeInvalidPublicIpv4PoolIDNotFound = "InvalidPublicIpv4PoolID.NotFound" // nosemgrep:ci.caps5-in-const-name,ci.caps5-in-var-name + errCodeInvalidReservationNotFound = "InvalidReservationID.NotFound" errCodeInvalidRouteNotFound = "InvalidRoute.NotFound" errCodeInvalidRouteTableIDNotFound = "InvalidRouteTableID.NotFound" errCodeInvalidRouteTableIdNotFound = "InvalidRouteTableId.NotFound" From b58d0e0205144da28e03a73128baca7269ee1648 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Thu, 6 Jun 2024 11:03:34 -0500 Subject: [PATCH 10/20] chore: semgrep --- internal/service/ec2/ec2_capacity_block_reservation.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/ec2/ec2_capacity_block_reservation.go b/internal/service/ec2/ec2_capacity_block_reservation.go index d9850c2654a..baa0b45f1f1 100644 --- a/internal/service/ec2/ec2_capacity_block_reservation.go +++ b/internal/service/ec2/ec2_capacity_block_reservation.go @@ -76,7 +76,7 @@ func (r *resourceCapacityBlockReservation) Schema(ctx context.Context, _ resourc stringplanmodifier.RequiresReplace(), }, }, - "created_date": schema.StringAttribute{ + names.AttrCreatedDate: schema.StringAttribute{ CustomType: timetypes.RFC3339Type{}, Computed: true, PlanModifiers: []planmodifier.String{ @@ -355,7 +355,7 @@ func findCapacityBlockReservationByID(ctx context.Context, conn *ec2.Client, id func waitCapacityBlockReservationActive(ctx context.Context, conn *ec2.Client, timeout time.Duration, id string) (*awstypes.CapacityReservation, error) { stateConf := &retry.StateChangeConf{ Pending: enum.Slice(awstypes.CapacityReservationStatePaymentPending), - Target: enum.Slice(awstypes.CapacityReservationStateActive), + Target: enum.Slice(awstypes.CapacityReservationStateActive, awstypes.CapacityReservationStateScheduled), Refresh: statusCapacityBlockReservation(ctx, conn, id), Timeout: timeout, MinTimeout: 10 * time.Second, From 70ab38ad5e37f3ca21c0bf263d328ca2de7900b1 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Thu, 6 Jun 2024 11:19:13 -0500 Subject: [PATCH 11/20] chore: fix documentation formatting --- .../ec2_capacity_block_offering.html.markdown | 12 +++++----- ...2_capacity_block_reservation.html.markdown | 22 +++++++++---------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/website/docs/r/ec2_capacity_block_offering.html.markdown b/website/docs/r/ec2_capacity_block_offering.html.markdown index 0a9eb333587..f2c7e42056e 100644 --- a/website/docs/r/ec2_capacity_block_offering.html.markdown +++ b/website/docs/r/ec2_capacity_block_offering.html.markdown @@ -13,13 +13,13 @@ Information about a single EC2 Capacity Block Reservation. ## Example Usage ```terraform -data "aws_ec2_capacity_block_offering" "test" { +data "aws_ec2_capacity_block_offering" "test" { capacity_duration_hours = 24 - end_date_range = "2024-05-30T15:04:05Z" - instance_count = 1 - instance_platform = "Linux/UNIX" - instance_type = "p4d.24xlarge" - start_date_range = "2024-04-28T15:04:05Z" + end_date_range = "2024-05-30T15:04:05Z" + instance_count = 1 + instance_platform = "Linux/UNIX" + instance_type = "p4d.24xlarge" + start_date_range = "2024-04-28T15:04:05Z" } ``` diff --git a/website/docs/r/ec2_capacity_block_reservation.html.markdown b/website/docs/r/ec2_capacity_block_reservation.html.markdown index d8d8374402b..c1a15b4d469 100644 --- a/website/docs/r/ec2_capacity_block_reservation.html.markdown +++ b/website/docs/r/ec2_capacity_block_reservation.html.markdown @@ -20,20 +20,20 @@ Provides an EC2 Capacity Block Reservation. This allows you to purchase capacity data "aws_ec2_capacity_block_offering" "test" { - capacity_duration = 24 - end_date = "2024-05-30T15:04:05Z" - instance_count = 1 - instance_platform = "Linux/UNIX" - instance_type = "p4d.24xlarge" - start_date = "2024-04-28T15:04:05Z" + capacity_duration = 24 + end_date = "2024-05-30T15:04:05Z" + instance_count = 1 + instance_platform = "Linux/UNIX" + instance_type = "p4d.24xlarge" + start_date = "2024-04-28T15:04:05Z" } resource "aws_ec2_capacity_block_reservation" "test" { - capacity_block_offering_id = data.aws_ec2_capacity_block_offering.test.id - instance_platform = "Linux/UNIX" - tags = { - "Environment" = "dev" - } + capacity_block_offering_id = data.aws_ec2_capacity_block_offering.test.id + instance_platform = "Linux/UNIX" + tags = { + "Environment" = "dev" + } } ``` From 0221a8ee74094721eda3cd3991073b341659c11f Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Thu, 6 Jun 2024 11:22:20 -0500 Subject: [PATCH 12/20] move data source documentation to the correct location --- website/docs/{r => d}/ec2_capacity_block_offering.html.markdown | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename website/docs/{r => d}/ec2_capacity_block_offering.html.markdown (100%) diff --git a/website/docs/r/ec2_capacity_block_offering.html.markdown b/website/docs/d/ec2_capacity_block_offering.html.markdown similarity index 100% rename from website/docs/r/ec2_capacity_block_offering.html.markdown rename to website/docs/d/ec2_capacity_block_offering.html.markdown From 5695aedc5a1730012b277b40c67699db891e9e33 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Thu, 6 Jun 2024 11:28:36 -0500 Subject: [PATCH 13/20] fmt --- internal/service/ec2/errors.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/ec2/errors.go b/internal/service/ec2/errors.go index f891b18e5c6..8ac08f6f175 100644 --- a/internal/service/ec2/errors.go +++ b/internal/service/ec2/errors.go @@ -82,7 +82,7 @@ const ( errCodeInvalidPrefixListIDNotFound = "InvalidPrefixListID.NotFound" errCodeInvalidPrefixListIdNotFound = "InvalidPrefixListId.NotFound" errCodeInvalidPublicIpv4PoolIDNotFound = "InvalidPublicIpv4PoolID.NotFound" // nosemgrep:ci.caps5-in-const-name,ci.caps5-in-var-name - errCodeInvalidReservationNotFound = "InvalidReservationID.NotFound" + errCodeInvalidReservationNotFound = "InvalidReservationID.NotFound" errCodeInvalidRouteNotFound = "InvalidRoute.NotFound" errCodeInvalidRouteTableIDNotFound = "InvalidRouteTableID.NotFound" errCodeInvalidRouteTableIdNotFound = "InvalidRouteTableId.NotFound" From db7352b846828ca38e48aac08ff982db19cc075c Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 11 Jun 2024 10:55:37 -0500 Subject: [PATCH 14/20] chore: tidy up test names --- .../ec2/ec2_capacity_block_offering_data_source_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/ec2/ec2_capacity_block_offering_data_source_test.go b/internal/service/ec2/ec2_capacity_block_offering_data_source_test.go index 9fe051bd2df..e018d24ec07 100644 --- a/internal/service/ec2/ec2_capacity_block_offering_data_source_test.go +++ b/internal/service/ec2/ec2_capacity_block_offering_data_source_test.go @@ -13,7 +13,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -func TestAccEC2CapacityBlockOffering_basic(t *testing.T) { +func TestAccEC2CapacityBlockOfferingDataSource_basic(t *testing.T) { ctx := acctest.Context(t) dataSourceName := "data.aws_ec2_capacity_block_offering.test" startDate := time.Now().UTC().Add(25 * time.Hour).Format(time.RFC3339) @@ -28,7 +28,7 @@ func TestAccEC2CapacityBlockOffering_basic(t *testing.T) { CheckDestroy: nil, Steps: []resource.TestStep{ { - Config: testAccCapacityBlockOfferingConfig_basic(startDate, endDate), + Config: testAccCapacityBlockOfferingDataSourceConfig_basic(startDate, endDate), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet(dataSourceName, names.AttrAvailabilityZone), resource.TestCheckResourceAttr(dataSourceName, "capacity_duration_hours", "24"), @@ -43,7 +43,7 @@ func TestAccEC2CapacityBlockOffering_basic(t *testing.T) { }) } -func testAccCapacityBlockOfferingConfig_basic(startDate, endDate string) string { +func testAccCapacityBlockOfferingDataSourceConfig_basic(startDate, endDate string) string { return fmt.Sprintf(` data "aws_ec2_capacity_block_offering" "test" { instance_type = "p4d.24xlarge" From 58a30ad35bf5589ac816173190ae527c1a757609 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 11 Jun 2024 11:06:34 -0500 Subject: [PATCH 15/20] aws_ec2_capacity_block_reservation: tidy docs --- internal/service/ec2/ec2_capacity_block_reservation.go | 2 +- internal/service/ec2/service_package_gen.go | 1 + website/docs/r/ec2_capacity_block_reservation.html.markdown | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/internal/service/ec2/ec2_capacity_block_reservation.go b/internal/service/ec2/ec2_capacity_block_reservation.go index baa0b45f1f1..39854f5d3c8 100644 --- a/internal/service/ec2/ec2_capacity_block_reservation.go +++ b/internal/service/ec2/ec2_capacity_block_reservation.go @@ -33,7 +33,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// @FrameworkResource("aws_ec2_capacity_block_reservation") +// @FrameworkResource("aws_ec2_capacity_block_reservation",name="Capacity BLock Reservation") // @Tags(identifierAttribute="id") // @Testing(tagsTest=false) func newResourceCapacityBlockReservation(context.Context) (resource.ResourceWithConfigure, error) { diff --git a/internal/service/ec2/service_package_gen.go b/internal/service/ec2/service_package_gen.go index 389c1213516..fd9dd5a55b4 100644 --- a/internal/service/ec2/service_package_gen.go +++ b/internal/service/ec2/service_package_gen.go @@ -52,6 +52,7 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.Servic }, { Factory: newResourceCapacityBlockReservation, + Name: "Capacity BLock Reservation", Tags: &types.ServicePackageResourceTags{ IdentifierAttribute: names.AttrID, }, diff --git a/website/docs/r/ec2_capacity_block_reservation.html.markdown b/website/docs/r/ec2_capacity_block_reservation.html.markdown index c1a15b4d469..e053cf264df 100644 --- a/website/docs/r/ec2_capacity_block_reservation.html.markdown +++ b/website/docs/r/ec2_capacity_block_reservation.html.markdown @@ -19,7 +19,7 @@ Provides an EC2 Capacity Block Reservation. This allows you to purchase capacity ```terraform -data "aws_ec2_capacity_block_offering" "test" { +data "aws_ec2_capacity_block_offering" "example" { capacity_duration = 24 end_date = "2024-05-30T15:04:05Z" instance_count = 1 @@ -28,7 +28,7 @@ data "aws_ec2_capacity_block_offering" "test" { start_date = "2024-04-28T15:04:05Z" } -resource "aws_ec2_capacity_block_reservation" "test" { +resource "aws_ec2_capacity_block_reservation" "example" { capacity_block_offering_id = data.aws_ec2_capacity_block_offering.test.id instance_platform = "Linux/UNIX" tags = { From bc72e8a8d2fcd3ee53ce991692be7534fd371a71 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 11 Jun 2024 13:48:13 -0500 Subject: [PATCH 16/20] aws_ec2_capacity_block_reservation: add additional attribes to documentation --- .../ec2/ec2_capacity_block_reservation.go | 24 +------------------ ...2_capacity_block_reservation.html.markdown | 10 ++++++-- 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/internal/service/ec2/ec2_capacity_block_reservation.go b/internal/service/ec2/ec2_capacity_block_reservation.go index 39854f5d3c8..eb5dd297648 100644 --- a/internal/service/ec2/ec2_capacity_block_reservation.go +++ b/internal/service/ec2/ec2_capacity_block_reservation.go @@ -103,12 +103,6 @@ func (r *resourceCapacityBlockReservation) Schema(ctx context.Context, _ resourc stringplanmodifier.UseStateForUnknown(), }, }, - "ephemeral_storage": schema.BoolAttribute{ - Computed: true, - PlanModifiers: []planmodifier.Bool{ - boolplanmodifier.UseStateForUnknown(), - }, - }, names.AttrID: framework.IDAttribute(), names.AttrInstanceCount: schema.Int64Attribute{ Computed: true, @@ -116,13 +110,6 @@ func (r *resourceCapacityBlockReservation) Schema(ctx context.Context, _ resourc int64planmodifier.UseStateForUnknown(), }, }, - "instance_match_criteria": schema.StringAttribute{ - CustomType: fwtypes.StringEnumType[awstypes.InstanceMatchCriteria](), - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, "instance_platform": schema.StringAttribute{ CustomType: fwtypes.StringEnumType[awstypes.CapacityReservationInstancePlatform](), Required: true, @@ -142,7 +129,7 @@ func (r *resourceCapacityBlockReservation) Schema(ctx context.Context, _ resourc stringplanmodifier.UseStateForUnknown(), }, }, - names.AttrOwnerID: schema.StringAttribute{ + "placement_group_arn": schema.StringAttribute{ Computed: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.UseStateForUnknown(), @@ -155,12 +142,6 @@ func (r *resourceCapacityBlockReservation) Schema(ctx context.Context, _ resourc stringplanmodifier.UseStateForUnknown(), }, }, - "placement_group_arn": schema.StringAttribute{ - Computed: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.UseStateForUnknown(), - }, - }, "start_date": schema.StringAttribute{ CustomType: timetypes.RFC3339Type{}, Computed: true, @@ -289,14 +270,11 @@ type resourceCapacityBlockReservationData struct { EbsOptimized types.Bool `tfsdk:"ebs_optimized"` EndDate timetypes.RFC3339 `tfsdk:"end_date"` EndDateType fwtypes.StringEnum[awstypes.EndDateType] `tfsdk:"end_date_type"` - EphemeralStorage types.Bool `tfsdk:"ephemeral_storage"` ID types.String `tfsdk:"id"` InstanceCount types.Int64 `tfsdk:"instance_count"` - InstanceMatchCriteria fwtypes.StringEnum[awstypes.InstanceMatchCriteria] `tfsdk:"instance_match_criteria"` InstancePlatform fwtypes.StringEnum[awstypes.CapacityReservationInstancePlatform] `tfsdk:"instance_platform"` InstanceType types.String `tfsdk:"instance_type"` OutpostARN types.String `tfsdk:"outpost_arn"` - OwnerID types.String `tfsdk:"owner_id"` PlacementGroupARN types.String `tfsdk:"placement_group_arn"` ReservationType fwtypes.StringEnum[awstypes.CapacityReservationType] `tfsdk:"reservation_type"` StartDate timetypes.RFC3339 `tfsdk:"start_date"` diff --git a/website/docs/r/ec2_capacity_block_reservation.html.markdown b/website/docs/r/ec2_capacity_block_reservation.html.markdown index e053cf264df..05b09180428 100644 --- a/website/docs/r/ec2_capacity_block_reservation.html.markdown +++ b/website/docs/r/ec2_capacity_block_reservation.html.markdown @@ -17,8 +17,6 @@ Provides an EC2 Capacity Block Reservation. This allows you to purchase capacity ## Example Usage ```terraform - - data "aws_ec2_capacity_block_offering" "example" { capacity_duration = 24 end_date = "2024-05-30T15:04:05Z" @@ -49,10 +47,18 @@ This resource supports the following arguments: This resource exports the following attributes in addition to the arguments above: +* `arn` - The ARN of the reservation. * `availability_zone` - The Availability Zone in which to create the Capacity Block Reservation. +* `created_date` - The date and time at which the Capacity Block Reservation was created. +* `ebs_optimized` - Indicates whether the Capacity Reservation supports EBS-optimized instances. * `end_date` - The date and time at which the Capacity Block Reservation expires. When a Capacity Block Reservation expires, the reserved capacity is released and you can no longer launch instances into it. Valid values: [RFC3339 time string](https://tools.ietf.org/html/rfc3339#section-5.8) (`YYYY-MM-DDTHH:MM:SSZ`) +* `end_date_type` - Indicates the way in which the Capacity Reservation ends. +* `id` - The ID of the Capacity Block Reservation. * `instance_count` - The number of instances for which to reserve capacity. * `instance_type` - The instance type for which to reserve capacity. +* `outpost_arn` - The ARN of the Outpost on which to create the Capacity Block Reservation. +* `placement_group_arn` - The ARN of the placement group in which to create the Capacity Block Reservation. +* `reservation_type` - The type of Capacity Reservation. * `start_date` - The date and time at which the Capacity Block Reservation starts. Valid values: [RFC3339 time string](https://tools.ietf.org/html/rfc3339#section-5.8) (`YYYY-MM-DDTHH:MM:SSZ`) * `tenancy` - Indicates the tenancy of the Capacity Block Reservation. Specify either `default` or `dedicated`. * `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) From a6aa0bcd0b8a1bf912b3c1bc73026fac404a19fa Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 11 Jun 2024 13:53:55 -0500 Subject: [PATCH 17/20] update CHANGELOG --- .changelog/37528.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.changelog/37528.txt b/.changelog/37528.txt index f1d4ce8772b..5a5c51a7fe8 100644 --- a/.changelog/37528.txt +++ b/.changelog/37528.txt @@ -4,4 +4,8 @@ aws_ec2_capacity_block_reservation ```release-note:new-data-source aws_ec2_capacity_block_offering +``` + +```release-note:note +resource/aws_ec2_capacity_block_reservation: Because we cannot easily test this functionality, it is best effort and we ask for community help in testing ``` \ No newline at end of file From 51ce3532916fe0fd05c046c0c2b28ed3a1dd3096 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 11 Jun 2024 13:57:12 -0500 Subject: [PATCH 18/20] tidy --- internal/service/ec2/ec2_capacity_block_reservation.go | 2 +- internal/service/ec2/service_package_gen.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/ec2/ec2_capacity_block_reservation.go b/internal/service/ec2/ec2_capacity_block_reservation.go index eb5dd297648..eecf8cf1a99 100644 --- a/internal/service/ec2/ec2_capacity_block_reservation.go +++ b/internal/service/ec2/ec2_capacity_block_reservation.go @@ -33,7 +33,7 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// @FrameworkResource("aws_ec2_capacity_block_reservation",name="Capacity BLock Reservation") +// @FrameworkResource("aws_ec2_capacity_block_reservation",name="Capacity Block Reservation") // @Tags(identifierAttribute="id") // @Testing(tagsTest=false) func newResourceCapacityBlockReservation(context.Context) (resource.ResourceWithConfigure, error) { diff --git a/internal/service/ec2/service_package_gen.go b/internal/service/ec2/service_package_gen.go index 7da85693524..b88047d7565 100644 --- a/internal/service/ec2/service_package_gen.go +++ b/internal/service/ec2/service_package_gen.go @@ -52,7 +52,7 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.Servic }, { Factory: newResourceCapacityBlockReservation, - Name: "Capacity BLock Reservation", + Name: "Capacity Block Reservation", Tags: &types.ServicePackageResourceTags{ IdentifierAttribute: names.AttrID, }, From 5341a02b2343fd151c160f69562e0c0dd21b67f0 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 11 Jun 2024 13:58:39 -0500 Subject: [PATCH 19/20] aws_ec2_capacity_block_offering: tidy docs --- website/docs/d/ec2_capacity_block_offering.html.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/website/docs/d/ec2_capacity_block_offering.html.markdown b/website/docs/d/ec2_capacity_block_offering.html.markdown index f2c7e42056e..0abf08cc9b6 100644 --- a/website/docs/d/ec2_capacity_block_offering.html.markdown +++ b/website/docs/d/ec2_capacity_block_offering.html.markdown @@ -3,17 +3,17 @@ subcategory: "EC2 (Elastic Compute Cloud)" layout: "aws" page_title: "AWS: aws_ec2_capacity_block_offering" description: |- - Information about a single EC2 Capacity Block Reservation. + Information about a single EC2 Capacity Block Offering. --- # Data Source: aws_ec2_capacity_block_offering -Information about a single EC2 Capacity Block Reservation. +Information about a single EC2 Capacity Block Offering. ## Example Usage ```terraform -data "aws_ec2_capacity_block_offering" "test" { +data "aws_ec2_capacity_block_offering" "example" { capacity_duration_hours = 24 end_date_range = "2024-05-30T15:04:05Z" instance_count = 1 From f34722162e8afb4d51734f7fd34e2d9d215623d7 Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 11 Jun 2024 14:08:21 -0500 Subject: [PATCH 20/20] aws_ec2_capacity_block_reservation: fix test types --- .../service/ec2/ec2_capacity_block_reservation_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/ec2/ec2_capacity_block_reservation_test.go b/internal/service/ec2/ec2_capacity_block_reservation_test.go index 17b6cebfc2e..49f38a20c2f 100644 --- a/internal/service/ec2/ec2_capacity_block_reservation_test.go +++ b/internal/service/ec2/ec2_capacity_block_reservation_test.go @@ -11,7 +11,7 @@ import ( "time" "github.com/YakDriver/regexache" - "github.com/aws/aws-sdk-go/service/ec2" + awstypes "github.com/aws/aws-sdk-go-v2/service/ec2/types" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" @@ -28,7 +28,7 @@ func TestAccEC2CapacityBlockReservation_basic(t *testing.T) { t.Skipf("Environment variable %s is not set to true", key) } - var reservation ec2.CapacityReservation + var reservation awstypes.CapacityReservation resourceName := "aws_ec2_capacity_block_reservation.test" dataSourceName := "data.aws_ec2_capacity_block_offering.test" startDate := time.Now().UTC().Add(25 * time.Hour).Format(time.RFC3339) @@ -59,7 +59,7 @@ func TestAccEC2CapacityBlockReservation_basic(t *testing.T) { }) } -func testAccCheckCapacityBlockReservationExists(ctx context.Context, n string, v *ec2.CapacityReservation) resource.TestCheckFunc { +func testAccCheckCapacityBlockReservationExists(ctx context.Context, n string, v *awstypes.CapacityReservation) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -70,7 +70,7 @@ func testAccCheckCapacityBlockReservationExists(ctx context.Context, n string, v return fmt.Errorf("No EC2 Capacity Reservation ID is set") } - conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Conn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Client(ctx) output, err := tfec2.FindCapacityReservationByID(ctx, conn, rs.Primary.ID)