From 45960f52c8ba27170402fa97e96fde70cc1a8f69 Mon Sep 17 00:00:00 2001 From: Peter Wilson Date: Tue, 9 Aug 2022 15:38:38 +1000 Subject: [PATCH 1/4] Add aws_fsx_openzfs_snapshot data source --- internal/provider/provider.go | 2 + .../service/fsx/common_schema_data_source.go | 44 ++++ internal/service/fsx/find.go | 31 +++ .../fsx/openzfs_snapshot_data_source.go | 121 ++++++++++ .../fsx/openzfs_snapshot_data_source_test.go | 226 ++++++++++++++++++ .../docs/d/fsx_openzfs_snapshot.html.markdown | 49 ++++ 6 files changed, 473 insertions(+) create mode 100644 internal/service/fsx/common_schema_data_source.go create mode 100644 internal/service/fsx/openzfs_snapshot_data_source.go create mode 100644 internal/service/fsx/openzfs_snapshot_data_source_test.go create mode 100644 website/docs/d/fsx_openzfs_snapshot.html.markdown diff --git a/internal/provider/provider.go b/internal/provider/provider.go index e2d2ef12dd7f..e5075b33a46a 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -644,6 +644,8 @@ func New(_ context.Context) (*schema.Provider, error) { "aws_kinesis_firehose_delivery_stream": firehose.DataSourceDeliveryStream(), + "aws_fsx_openzfs_snapshot": fsx.DataSourceOpenzfsSnapshot(), + "aws_globalaccelerator_accelerator": globalaccelerator.DataSourceAccelerator(), "aws_glue_connection": glue.DataSourceConnection(), diff --git a/internal/service/fsx/common_schema_data_source.go b/internal/service/fsx/common_schema_data_source.go new file mode 100644 index 000000000000..bb6c07a515f0 --- /dev/null +++ b/internal/service/fsx/common_schema_data_source.go @@ -0,0 +1,44 @@ +package fsx + +import ( + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/fsx" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func BuildSnapshotFiltersDataSource(set *schema.Set) []*fsx.SnapshotFilter { + var filters []*fsx.SnapshotFilter + for _, v := range set.List() { + m := v.(map[string]interface{}) + var filterValues []*string + for _, e := range m["values"].([]interface{}) { + filterValues = append(filterValues, aws.String(e.(string))) + } + filters = append(filters, &fsx.SnapshotFilter{ + Name: aws.String(m["name"].(string)), + Values: filterValues, + }) + } + return filters +} + +func DataSourceSnapshotFiltersSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + }, + + "values": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + } +} diff --git a/internal/service/fsx/find.go b/internal/service/fsx/find.go index 84f7beef2626..b5b3456b9444 100644 --- a/internal/service/fsx/find.go +++ b/internal/service/fsx/find.go @@ -234,3 +234,34 @@ func FindSnapshotByID(conn *fsx.FSx, id string) (*fsx.Snapshot, error) { return output.Snapshots[0], nil } + +func FindSnapshots(conn *fsx.FSx, input *fsx.DescribeSnapshotsInput) ([]*fsx.Snapshot, error) { + var output []*fsx.Snapshot + + err := conn.DescribeSnapshotsPages(input, func(page *fsx.DescribeSnapshotsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, v := range page.Snapshots { + if v != nil { + output = append(output, v) + } + } + + return !lastPage + }) + + if tfawserr.ErrCodeEquals(err, fsx.ErrCodeSnapshotNotFound) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + return output, nil +} diff --git a/internal/service/fsx/openzfs_snapshot_data_source.go b/internal/service/fsx/openzfs_snapshot_data_source.go new file mode 100644 index 000000000000..db2b81b4b24e --- /dev/null +++ b/internal/service/fsx/openzfs_snapshot_data_source.go @@ -0,0 +1,121 @@ +package fsx + +import ( + "fmt" + "sort" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/fsx" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/flex" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" +) + +func DataSourceOpenzfsSnapshot() *schema.Resource { + return &schema.Resource{ + Read: dataSourceOpenzfsSnapshotRead, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "creation_time": { + Type: schema.TypeString, + Computed: true, + }, + "filter": DataSourceSnapshotFiltersSchema(), + "most_recent": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "name": { + Type: schema.TypeString, + Optional: true, + }, + "snapshot_id": { + Type: schema.TypeString, + Computed: true, + }, + "snapshot_ids": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + "tags": tftags.TagsSchemaComputed(), + "volume_id": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceOpenzfsSnapshotRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).FSxConn + ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig + + input := &fsx.DescribeSnapshotsInput{} + + if v, ok := d.GetOk("snapshot_ids"); ok && len(v.([]interface{})) > 0 { + input.SnapshotIds = flex.ExpandStringList(v.([]interface{})) + } + + input.Filters = append(input.Filters, BuildSnapshotFiltersDataSource( + d.Get("filter").(*schema.Set), + )...) + + if len(input.Filters) == 0 { + input.Filters = nil + } + + snapshots, err := FindSnapshots(conn, input) + + if err != nil { + return fmt.Errorf("reading FSx Snapshots: %w", err) + } + + if len(snapshots) < 1 { + return fmt.Errorf("Your query returned no results. Please change your search criteria and try again.") + } + + if len(snapshots) > 1 { + if !d.Get("most_recent").(bool) { + return fmt.Errorf("Your query returned more than one result. Please try a more " + + "specific search criteria, or set `most_recent` attribute to true.") + } + + sort.Slice(snapshots, func(i, j int) bool { + return aws.TimeValue(snapshots[i].CreationTime).Unix() > aws.TimeValue(snapshots[j].CreationTime).Unix() + }) + } + + snapshot := snapshots[0] + + d.SetId(aws.StringValue(snapshot.SnapshotId)) + d.Set("arn", snapshot.ResourceARN) + d.Set("name", snapshot.Name) + d.Set("snapshot_id", snapshot.SnapshotId) + d.Set("volume_id", snapshot.VolumeId) + + if err := d.Set("creation_time", snapshot.CreationTime.Format(time.RFC3339)); err != nil { + return fmt.Errorf("error setting creation_time: %w", err) + } + + //Snapshot tags do not get returned with describe call so need to make a separate list tags call + tags, tagserr := ListTags(conn, *snapshot.ResourceARN) + + if tagserr != nil { + return fmt.Errorf("error reading Tags for FSx OpenZFS Snapshot (%s): %w", d.Id(), err) + } + + //lintignore:AWSR002 + if err := d.Set("tags", tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %w", err) + } + + return nil +} diff --git a/internal/service/fsx/openzfs_snapshot_data_source_test.go b/internal/service/fsx/openzfs_snapshot_data_source_test.go new file mode 100644 index 000000000000..f89c6aac1b97 --- /dev/null +++ b/internal/service/fsx/openzfs_snapshot_data_source_test.go @@ -0,0 +1,226 @@ +package fsx_test + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/fsx" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" +) + +func TestAccFSxOpenzfsSnapshotDataSource_basic(t *testing.T) { + dataSourceName := "data.aws_fsx_openzfs_snapshot.test" + resourceName := "aws_fsx_openzfs_snapshot.test" + mostRecentResourceName := "aws_fsx_openzfs_snapshot.latest" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + rName2 := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(fsx.EndpointsID, t) }, + ErrorCheck: acctest.ErrorCheck(t, fsx.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckOpenzfsSnapshotDestroy, + Steps: []resource.TestStep{ + { + Config: testAccOpenzfsSnapshotDataSourceConfig_basic(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "creation_time", resourceName, "creation_time"), + resource.TestCheckResourceAttrPair(dataSourceName, "id", resourceName, "id"), + resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "tags.%", resourceName, "tags.%"), + resource.TestCheckResourceAttrPair(dataSourceName, "volume_id", resourceName, "volume_id"), + ), + }, + { + Config: testAccOpenzfsSnapshotDataSourceConfig_tags1(rName, "key1", "value1"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "tags.%", resourceName, "tags.%"), + resource.TestCheckResourceAttr(dataSourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(dataSourceName, "tags.key1", "value1"), + ), + }, + { + Config: testAccOpenzfsSnapshotDataSourceConfig_tags2(rName, "key1", "value1updated", "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "tags.%", resourceName, "tags.%"), + resource.TestCheckResourceAttr(dataSourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(dataSourceName, "tags.key1", "value1updated"), + resource.TestCheckResourceAttr(dataSourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccOpenzfsSnapshotDataSourceConfig_tags1(rName, "key2", "value2"), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "tags.%", resourceName, "tags.%"), + resource.TestCheckResourceAttr(dataSourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(dataSourceName, "tags.key2", "value2"), + ), + }, + { + Config: testAccOpenzfsSnapshotDataSourceConfig_filterFileSystemId(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "creation_time", resourceName, "creation_time"), + resource.TestCheckResourceAttrPair(dataSourceName, "id", resourceName, "id"), + resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "tags.%", resourceName, "tags.%"), + resource.TestCheckResourceAttrPair(dataSourceName, "volume_id", resourceName, "volume_id"), + ), + }, + { + Config: testAccOpenzfsSnapshotDataSourceConfig_filterVolumeId(rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "creation_time", resourceName, "creation_time"), + resource.TestCheckResourceAttrPair(dataSourceName, "id", resourceName, "id"), + resource.TestCheckResourceAttrPair(dataSourceName, "name", resourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "tags.%", resourceName, "tags.%"), + resource.TestCheckResourceAttrPair(dataSourceName, "volume_id", resourceName, "volume_id"), + ), + }, + { + Config: testAccOpenzfsSnapshotDataSourceConfig_mostRecent(rName, rName2), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "arn", mostRecentResourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "creation_time", mostRecentResourceName, "creation_time"), + resource.TestCheckResourceAttrPair(dataSourceName, "id", mostRecentResourceName, "id"), + resource.TestCheckResourceAttrPair(dataSourceName, "name", mostRecentResourceName, "name"), + resource.TestCheckResourceAttrPair(dataSourceName, "tags.%", mostRecentResourceName, "tags.%"), + resource.TestCheckResourceAttrPair(dataSourceName, "volume_id", mostRecentResourceName, "volume_id"), + ), + }, + }, + }) +} + +func testAccOpenzfsSnapshotDataSourceBaseConfig(rName string) string { + return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "10.0.0.0/16" +} + +resource "aws_subnet" "test1" { + vpc_id = aws_vpc.test.id + cidr_block = "10.0.1.0/24" + availability_zone = data.aws_availability_zones.available.names[0] +} + +resource "aws_fsx_openzfs_file_system" "test" { + storage_capacity = 64 + subnet_ids = [aws_subnet.test1.id] + deployment_type = "SINGLE_AZ_1" + throughput_capacity = 64 + + tags = { + Name = %[1]q + } +} +`, rName)) +} + +func testAccOpenzfsSnapshotDataSourceConfig_basic(rName string) string { + return acctest.ConfigCompose(testAccOpenzfsSnapshotDataSourceBaseConfig(rName), fmt.Sprintf(` +resource "aws_fsx_openzfs_snapshot" "test" { + name = %[1]q + volume_id = aws_fsx_openzfs_file_system.test.root_volume_id +} + +data "aws_fsx_openzfs_snapshot" "test" { + snapshot_ids = [aws_fsx_openzfs_snapshot.test.id] +} +`, rName)) +} + +func testAccOpenzfsSnapshotDataSourceConfig_tags1(rName string, tagKey1, tagValue1 string) string { + return acctest.ConfigCompose(testAccOpenzfsSnapshotDataSourceBaseConfig(rName), fmt.Sprintf(` +resource "aws_fsx_openzfs_snapshot" "test" { + name = %[1]q + volume_id = aws_fsx_openzfs_file_system.test.root_volume_id + + tags = { + %[2]q = %[3]q + } +} + +data "aws_fsx_openzfs_snapshot" "test" { + snapshot_ids = [aws_fsx_openzfs_snapshot.test.id] +} +`, rName, tagKey1, tagValue1)) +} + +func testAccOpenzfsSnapshotDataSourceConfig_tags2(rName string, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return acctest.ConfigCompose(testAccOpenzfsSnapshotDataSourceBaseConfig(rName), fmt.Sprintf(` +resource "aws_fsx_openzfs_snapshot" "test" { + name = %[1]q + volume_id = aws_fsx_openzfs_file_system.test.root_volume_id + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} + +data "aws_fsx_openzfs_snapshot" "test" { + snapshot_ids = [aws_fsx_openzfs_snapshot.test.id] +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2)) +} + +func testAccOpenzfsSnapshotDataSourceConfig_filterFileSystemId(rName string) string { + return acctest.ConfigCompose(testAccOpenzfsSnapshotDataSourceBaseConfig(rName), fmt.Sprintf(` +resource "aws_fsx_openzfs_snapshot" "test" { + name = %[1]q + volume_id = aws_fsx_openzfs_file_system.test.root_volume_id +} + +data "aws_fsx_openzfs_snapshot" "test" { + filter { + name = "file-system-id" + values = [aws_fsx_openzfs_file_system.test.id] + } +} +`, rName)) +} + +func testAccOpenzfsSnapshotDataSourceConfig_filterVolumeId(rName string) string { + return acctest.ConfigCompose(testAccOpenzfsSnapshotDataSourceBaseConfig(rName), fmt.Sprintf(` +resource "aws_fsx_openzfs_snapshot" "test" { + name = %[1]q + volume_id = aws_fsx_openzfs_file_system.test.root_volume_id +} + +data "aws_fsx_openzfs_snapshot" "test" { + filter { + name = "volume-id" + values = [aws_fsx_openzfs_file_system.test.root_volume_id] + } +} +`, rName)) +} + +func testAccOpenzfsSnapshotDataSourceConfig_mostRecent(rName, rName2 string) string { + return acctest.ConfigCompose(testAccOpenzfsSnapshotDataSourceBaseConfig(rName), fmt.Sprintf(` +resource "aws_fsx_openzfs_snapshot" "test" { + name = %[1]q + volume_id = aws_fsx_openzfs_file_system.test.root_volume_id +} + +resource "aws_fsx_openzfs_snapshot" "latest" { + # Ensure that this snapshot is created after the other. + name = %[2]q + volume_id = aws_fsx_openzfs_snapshot.test.volume_id +} + +data "aws_fsx_openzfs_snapshot" "test" { + most_recent = true + filter { + name = "volume-id" + values = [aws_fsx_openzfs_file_system.test.root_volume_id] + } + depends_on = [aws_fsx_openzfs_snapshot.test, aws_fsx_openzfs_snapshot.latest] +} +`, rName, rName2)) +} diff --git a/website/docs/d/fsx_openzfs_snapshot.html.markdown b/website/docs/d/fsx_openzfs_snapshot.html.markdown new file mode 100644 index 000000000000..2953bbbb0a31 --- /dev/null +++ b/website/docs/d/fsx_openzfs_snapshot.html.markdown @@ -0,0 +1,49 @@ +--- +subcategory: "FSx" +layout: "aws" +page_title: "AWS: aws_fsx_openzfs_snapshot" +description: |- + Get information on an Amazon FSx for OpenZFS snapshot. +--- + +# Data Source: aws_fsx_openzfs_snapshot + +Use this data source to get information about an Amazon FSx for OpenZFS Snapshot for use when provisioning new Volumes. + +## Example Usage + +### Root volume Example + +```terraform +data "aws_fsx_openzfs_snapshot" "example" { + most_recent = true + + filter { + name = "volume-id" + values = ["fsvol-073a32b6098a73feb"] + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `most_recent` - (Optional) If more than one result is returned, use the most recent snapshot. + +* `snapshot_ids` - (Optional) Returns information on a specific snapshot_id. + +* `filter` - (Optional) One or more name/value pairs to filter off of. The +supported names are file-system-id or volume-id. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - Amazon Resource Name of the snapshot. +* `creation_time` - The time that the resource was created. +* `id` - Identifier of the snapshot, e.g., `fsvolsnap-12345678` +* `name` - The name of the snapshot. +* `snapshot_id` - The ID of the snapshot. +* `tags` - A list of Tag values, with a maximum of 50 elements. +* `volume_id` - The ID of the volume that the snapshot is of. \ No newline at end of file From 2230b8856fa63fe4c703bd69e48429d98b2170c3 Mon Sep 17 00:00:00 2001 From: Peter Wilson Date: Tue, 9 Aug 2022 20:06:16 +1000 Subject: [PATCH 2/4] Add changelog entry --- .changelog/26184.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/26184.txt diff --git a/.changelog/26184.txt b/.changelog/26184.txt new file mode 100644 index 000000000000..dbcf1dca4637 --- /dev/null +++ b/.changelog/26184.txt @@ -0,0 +1,3 @@ +```release-note:new-data-source +aws_fsx_openzfs_snapshot +``` From 08ace04577987eaa3b64f13c2fa14c66c575e9ca Mon Sep 17 00:00:00 2001 From: Peter Wilson Date: Wed, 10 Aug 2022 08:48:41 +1000 Subject: [PATCH 3/4] fix lint --- internal/service/fsx/openzfs_snapshot_data_source_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/fsx/openzfs_snapshot_data_source_test.go b/internal/service/fsx/openzfs_snapshot_data_source_test.go index f89c6aac1b97..6d5f3ce9e87e 100644 --- a/internal/service/fsx/openzfs_snapshot_data_source_test.go +++ b/internal/service/fsx/openzfs_snapshot_data_source_test.go @@ -179,7 +179,7 @@ resource "aws_fsx_openzfs_snapshot" "test" { data "aws_fsx_openzfs_snapshot" "test" { filter { name = "file-system-id" - values = [aws_fsx_openzfs_file_system.test.id] + values = [aws_fsx_openzfs_file_system.test.id] } } `, rName)) @@ -195,7 +195,7 @@ resource "aws_fsx_openzfs_snapshot" "test" { data "aws_fsx_openzfs_snapshot" "test" { filter { name = "volume-id" - values = [aws_fsx_openzfs_file_system.test.root_volume_id] + values = [aws_fsx_openzfs_file_system.test.root_volume_id] } } `, rName)) @@ -218,7 +218,7 @@ data "aws_fsx_openzfs_snapshot" "test" { most_recent = true filter { name = "volume-id" - values = [aws_fsx_openzfs_file_system.test.root_volume_id] + values = [aws_fsx_openzfs_file_system.test.root_volume_id] } depends_on = [aws_fsx_openzfs_snapshot.test, aws_fsx_openzfs_snapshot.latest] } From e229fb500dbbe8b843f57cbbede71e67088d66ea Mon Sep 17 00:00:00 2001 From: Peter Wilson Date: Wed, 10 Aug 2022 10:04:46 +1000 Subject: [PATCH 4/4] fix lint --- website/docs/d/fsx_openzfs_snapshot.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/d/fsx_openzfs_snapshot.html.markdown b/website/docs/d/fsx_openzfs_snapshot.html.markdown index 2953bbbb0a31..08cf841b137c 100644 --- a/website/docs/d/fsx_openzfs_snapshot.html.markdown +++ b/website/docs/d/fsx_openzfs_snapshot.html.markdown @@ -46,4 +46,4 @@ In addition to all arguments above, the following attributes are exported: * `name` - The name of the snapshot. * `snapshot_id` - The ID of the snapshot. * `tags` - A list of Tag values, with a maximum of 50 elements. -* `volume_id` - The ID of the volume that the snapshot is of. \ No newline at end of file +* `volume_id` - The ID of the volume that the snapshot is of.