-
Notifications
You must be signed in to change notification settings - Fork 9.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[New Data Source]: aws_appstream_image #38225
Merged
ThomasZalewski
merged 20 commits into
hashicorp:main
from
ThomasZalewski:f/appstream-image-describe
Jul 2, 2024
Merged
Changes from 18 commits
Commits
Show all changes
20 commits
Select commit
Hold shift + click to select a range
45a7168
with '#' will be ignored, and an empty message aborts the commit.
ThomasZalewski e5c9252
Formatting change in find.go
ThomasZalewski 4573af4
Formatting changes for CI checks.
ThomasZalewski e003695
Formatting change for CI test.
ThomasZalewski 0ad39d2
Spelling mistake.
ThomasZalewski 1a2394f
Fixed function name.
ThomasZalewski ebb4019
Results of go mod tidy.
ThomasZalewski 38b35ec
Update image_data_source.go
ThomasZalewski d314581
Formatted image_data_source_test.go
ThomasZalewski fd7bf50
Formatted image_data_source.go
ThomasZalewski ac9842a
Updated appstream_image.html.markdown
ThomasZalewski a4813f2
Resolved merge conflicts
ThomasZalewski 280eb5f
Added support for name_regex
ThomasZalewski 4d8398f
Merge branch 'main' into f/appstream-image-describe
ThomasZalewski 3acc510
Merge branch 'hashicorp:main' into f/appstream-image-describe
ThomasZalewski 5c701fb
Finalized name_regex support.
ThomasZalewski 747dfd4
Merge branch 'f/appstream-image-describe' of github.com:ThomasZalewsk…
ThomasZalewski 278af46
Fixed whitespaces for CI tests.
ThomasZalewski b0527c0
Fixed formatting issues.
ThomasZalewski e600a77
Added changelog.
ThomasZalewski File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,279 @@ | ||||||
// Copyright (c) HashiCorp, Inc. | ||||||
// SPDX-License-Identifier: MPL-2.0 | ||||||
|
||||||
package appstream | ||||||
|
||||||
import ( | ||||||
"context" | ||||||
"sort" | ||||||
"time" | ||||||
|
||||||
"github.com/YakDriver/regexache" | ||||||
"github.com/aws/aws-sdk-go-v2/aws" | ||||||
"github.com/aws/aws-sdk-go-v2/service/appstream" | ||||||
awstypes "github.com/aws/aws-sdk-go-v2/service/appstream/types" | ||||||
"github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" | ||||||
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" | ||||||
"github.com/hashicorp/terraform-plugin-framework/datasource" | ||||||
"github.com/hashicorp/terraform-plugin-framework/datasource/schema" | ||||||
"github.com/hashicorp/terraform-plugin-framework/path" | ||||||
"github.com/hashicorp/terraform-plugin-framework/schema/validator" | ||||||
"github.com/hashicorp/terraform-plugin-framework/types" | ||||||
"github.com/hashicorp/terraform-provider-aws/internal/create" | ||||||
"github.com/hashicorp/terraform-provider-aws/internal/framework" | ||||||
"github.com/hashicorp/terraform-provider-aws/internal/framework/flex" | ||||||
fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" | ||||||
"github.com/hashicorp/terraform-provider-aws/names" | ||||||
) | ||||||
|
||||||
// @FrameworkDataSource(name="Image") | ||||||
func newDataSourceImage(context.Context) (datasource.DataSourceWithConfigure, error) { | ||||||
return &dataSourceImage{}, nil | ||||||
} | ||||||
|
||||||
const ( | ||||||
DSNameImage = "Image Data Source" | ||||||
) | ||||||
|
||||||
type dataSourceImage struct { | ||||||
framework.DataSourceWithConfigure | ||||||
} | ||||||
|
||||||
func (d *dataSourceImage) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { // nosemgrep:ci.meta-in-func-name | ||||||
resp.TypeName = "aws_appstream_image" | ||||||
} | ||||||
|
||||||
func (d *dataSourceImage) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { | ||||||
{ | ||||||
resp.Schema = schema.Schema{ | ||||||
Attributes: map[string]schema.Attribute{ | ||||||
|
||||||
names.AttrARN: schema.StringAttribute{ | ||||||
CustomType: fwtypes.ARNType, | ||||||
Computed: true, | ||||||
Optional: true, | ||||||
Validators: []validator.String{ | ||||||
stringvalidator.ConflictsWith(path.Expressions{ | ||||||
path.MatchRoot(names.AttrName), | ||||||
}...), | ||||||
stringvalidator.ConflictsWith(path.Expressions{ | ||||||
path.MatchRoot("name_regex"), | ||||||
}...), | ||||||
}, | ||||||
}, | ||||||
"applications": schema.ListAttribute{ | ||||||
CustomType: fwtypes.NewListNestedObjectTypeOf[dsApplications](ctx), | ||||||
Computed: true, | ||||||
}, | ||||||
"appstream_agent_version": schema.StringAttribute{ | ||||||
Computed: true, | ||||||
}, | ||||||
names.AttrMostRecent: schema.BoolAttribute{ | ||||||
Optional: true, | ||||||
}, | ||||||
"base_image_arn": schema.StringAttribute{ | ||||||
Computed: true, | ||||||
}, | ||||||
names.AttrCreatedTime: schema.StringAttribute{ | ||||||
CustomType: timetypes.RFC3339Type{}, | ||||||
Computed: true, | ||||||
}, | ||||||
names.AttrDescription: schema.StringAttribute{ | ||||||
Computed: true, | ||||||
}, | ||||||
names.AttrDisplayName: schema.StringAttribute{ | ||||||
Computed: true, | ||||||
}, | ||||||
"image_builder_name": schema.StringAttribute{ | ||||||
Computed: true, | ||||||
}, | ||||||
"image_builder_supported": schema.BoolAttribute{ | ||||||
Computed: true, | ||||||
}, | ||||||
"image_permissions": schema.ListAttribute{ | ||||||
CustomType: fwtypes.NewListNestedObjectTypeOf[dsImagePermissions](ctx), | ||||||
Computed: true, | ||||||
}, | ||||||
names.AttrName: schema.StringAttribute{ | ||||||
Computed: true, | ||||||
Optional: true, | ||||||
Validators: []validator.String{ | ||||||
stringvalidator.ConflictsWith(path.Expressions{ | ||||||
path.MatchRoot(names.AttrARN), | ||||||
}...), | ||||||
stringvalidator.ConflictsWith(path.Expressions{ | ||||||
path.MatchRoot("name_regex"), | ||||||
}...), | ||||||
}, | ||||||
}, | ||||||
"name_regex": schema.StringAttribute{ | ||||||
CustomType: fwtypes.RegexpType, | ||||||
Optional: true, | ||||||
Validators: []validator.String{ | ||||||
stringvalidator.ConflictsWith(path.Expressions{ | ||||||
path.MatchRoot(names.AttrName), | ||||||
}...), | ||||||
stringvalidator.ConflictsWith(path.Expressions{ | ||||||
path.MatchRoot(names.AttrARN), | ||||||
}...), | ||||||
}, | ||||||
}, | ||||||
|
||||||
"platform": schema.StringAttribute{ | ||||||
Computed: true, | ||||||
}, | ||||||
"public_base_image_released_date": schema.StringAttribute{ | ||||||
CustomType: timetypes.RFC3339Type{}, | ||||||
Computed: true, | ||||||
}, | ||||||
names.AttrState: schema.StringAttribute{ | ||||||
Computed: true, | ||||||
}, | ||||||
"state_change_reason": schema.ListAttribute{ | ||||||
CustomType: fwtypes.NewListNestedObjectTypeOf[dsStateChange](ctx), | ||||||
Computed: true, | ||||||
}, | ||||||
names.AttrType: schema.StringAttribute{ | ||||||
CustomType: fwtypes.StringEnumType[awstypes.VisibilityType](), | ||||||
Optional: true, | ||||||
}, | ||||||
}, | ||||||
} | ||||||
} | ||||||
} | ||||||
func (d *dataSourceImage) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { | ||||||
conn := d.Meta().AppStreamClient(ctx) | ||||||
|
||||||
var data dsImage | ||||||
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) | ||||||
if resp.Diagnostics.HasError() { | ||||||
return | ||||||
} | ||||||
var describeImagesInput appstream.DescribeImagesInput // camel case | ||||||
if !data.Name.IsNull() { | ||||||
describeImagesInput.Names = []string{data.Name.ValueString()} | ||||||
} | ||||||
if !data.Arn.IsNull() { | ||||||
describeImagesInput.Arns = []string{data.Arn.ValueString()} | ||||||
} | ||||||
// | ||||||
images, err := findImages(ctx, conn, &describeImagesInput) | ||||||
if err != nil { | ||||||
resp.Diagnostics.AddError( | ||||||
create.ProblemStandardMessage(names.AppStream, create.ErrActionReading, DSNameImage, data.Arn.String(), err), | ||||||
err.Error(), | ||||||
) | ||||||
return | ||||||
} | ||||||
|
||||||
var filteredImages []awstypes.Image | ||||||
if !data.NameRegex.IsNull() { | ||||||
r := regexache.MustCompile(data.NameRegex.ValueString()) | ||||||
for _, img := range images { | ||||||
name := aws.ToString(img.Name) | ||||||
|
||||||
// Check for a very rare case where the response would include no | ||||||
// image name. No name means nothing to attempt a match against, | ||||||
// therefore we are skipping such image. | ||||||
if name == "" { | ||||||
continue | ||||||
} | ||||||
|
||||||
if r.MatchString(name) { | ||||||
filteredImages = append(filteredImages, img) | ||||||
} | ||||||
} | ||||||
} else { | ||||||
filteredImages = images[:] | ||||||
} | ||||||
|
||||||
if len(filteredImages) < 1 { | ||||||
resp.Diagnostics.AddError( | ||||||
create.ProblemStandardMessage(names.AppStream, create.ErrActionReading, DSNameImage, data.Arn.String(), err), | ||||||
"Your query returned no results. Please change your search criteria and try again.", | ||||||
) | ||||||
return | ||||||
} | ||||||
|
||||||
if len(filteredImages) > 1 { | ||||||
if !data.MostRecent.ValueBool() { | ||||||
resp.Diagnostics.AddError( | ||||||
create.ProblemStandardMessage(names.AppStream, create.ErrActionReading, DSNameImage, data.Arn.String(), err), | ||||||
"Your query returned more than one result. Please try a more specific search criteria, or set `most_recent` attribute to true.", | ||||||
) | ||||||
return | ||||||
} | ||||||
sort.Slice(filteredImages, func(i, j int) bool { | ||||||
itime, _ := time.Parse(time.RFC3339, images[i].CreatedTime.Month().String()) | ||||||
jtime, _ := time.Parse(time.RFC3339, images[j].CreatedTime.Month().String()) | ||||||
return itime.Unix() > jtime.Unix() | ||||||
}) | ||||||
} | ||||||
image := filteredImages[0] | ||||||
|
||||||
data.Type = fwtypes.StringEnum[awstypes.VisibilityType]{}.StringEnumValue(string(image.Visibility)) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can be simplified by using the following
Suggested change
|
||||||
resp.Diagnostics.Append(flex.Flatten(ctx, &image, &data)...) | ||||||
if resp.Diagnostics.HasError() { | ||||||
return | ||||||
} | ||||||
|
||||||
if image.PublicBaseImageReleasedDate != nil { | ||||||
data.PubilcBaseImageReleasedDate = timetypes.NewRFC3339TimeValue(*image.PublicBaseImageReleasedDate) | ||||||
} | ||||||
|
||||||
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) | ||||||
} | ||||||
|
||||||
type dsApplications struct { | ||||||
AppBlockArn types.String `tfsdk:"app_block_arn"` | ||||||
Arn fwtypes.ARN `tfsdk:"arn"` | ||||||
CreatedTime timetypes.RFC3339 `tfsdk:"created_time"` | ||||||
Description types.String `tfsdk:"description"` | ||||||
DisplayName types.String `tfsdk:"display_name"` | ||||||
Enabled types.Bool `tfsdk:"enabled"` | ||||||
IconS3Location fwtypes.ListNestedObjectValueOf[dsIconS3] `tfsdk:"icon_s3_location"` | ||||||
IconUrl types.String `tfsdk:"icon_url"` | ||||||
InstanceFamilies fwtypes.ListValueOf[types.String] `tfsdk:"instance_families"` | ||||||
LaunchParameters types.String `tfsdk:"launch_parameters"` | ||||||
LaunchPath types.String `tfsdk:"launch_path"` | ||||||
Metadata fwtypes.MapValueOf[types.String] `tfsdk:"metadata"` | ||||||
Name types.String `tfsdk:"name"` | ||||||
Platforms fwtypes.ListValueOf[types.String] `tfsdk:"platforms"` | ||||||
WorkingDirectory types.String `tfsdk:"working_directory"` | ||||||
} | ||||||
|
||||||
type dsIconS3 struct { | ||||||
S3Bucket types.String `tfsdk:"s3_bucket"` | ||||||
S3Key types.String `tfsdk:"s3_key"` | ||||||
} | ||||||
|
||||||
type dsStateChange struct { | ||||||
Code types.String `tfsdk:"code"` | ||||||
Message types.String `tfsdk:"message"` | ||||||
} | ||||||
|
||||||
type dsImage struct { | ||||||
Applications fwtypes.ListNestedObjectValueOf[dsApplications] `tfsdk:"applications"` | ||||||
AppStreamAgentVersion types.String `tfsdk:"appstream_agent_version"` | ||||||
Arn fwtypes.ARN `tfsdk:"arn"` | ||||||
BaseImageArn types.String `tfsdk:"base_image_arn"` | ||||||
CreatedTime timetypes.RFC3339 `tfsdk:"created_time"` | ||||||
Description types.String `tfsdk:"description"` | ||||||
DisplayName types.String `tfsdk:"display_name"` | ||||||
ImageBuilderName types.String `tfsdk:"image_builder_name"` | ||||||
ImageBuilderSupported types.Bool `tfsdk:"image_builder_supported"` | ||||||
ImagePermissions fwtypes.ListNestedObjectValueOf[dsImagePermissions] `tfsdk:"image_permissions"` | ||||||
MostRecent types.Bool `tfsdk:"most_recent"` | ||||||
Name types.String `tfsdk:"name"` | ||||||
NameRegex fwtypes.Regexp `tfsdk:"name_regex"` | ||||||
Platform types.String `tfsdk:"platform"` | ||||||
PubilcBaseImageReleasedDate timetypes.RFC3339 `tfsdk:"public_base_image_released_date"` | ||||||
State types.String `tfsdk:"state"` | ||||||
StateChangeReason fwtypes.ListNestedObjectValueOf[dsStateChange] `tfsdk:"state_change_reason"` | ||||||
Type fwtypes.StringEnum[awstypes.VisibilityType] `tfsdk:"type"` | ||||||
} | ||||||
|
||||||
type dsImagePermissions struct { | ||||||
AllowFleet types.Bool `tfsdk:"allow_fleet"` | ||||||
AllowImageBuilder types.Bool `tfsdk:"allow_image_builder"` | ||||||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// Copyright (c) HashiCorp, Inc. | ||
// SPDX-License-Identifier: MPL-2.0 | ||
|
||
package appstream_test | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform-plugin-testing/helper/resource" | ||
"github.com/hashicorp/terraform-provider-aws/internal/acctest" | ||
"github.com/hashicorp/terraform-provider-aws/names" | ||
) | ||
|
||
func TestAccAppStreamImageDataSource_basic(t *testing.T) { | ||
ctx := acctest.Context(t) | ||
if testing.Short() { | ||
t.Skip("skipping long-running test in short mode") | ||
} | ||
dataSourceName := "data.aws_appstream_image.test" | ||
|
||
resource.ParallelTest(t, resource.TestCase{ | ||
PreCheck: func() { | ||
acctest.PreCheck(ctx, t) | ||
acctest.PreCheckPartitionHasService(t, names.AppStreamEndpointID) | ||
}, | ||
ErrorCheck: acctest.ErrorCheck(t, names.AppStreamServiceID), | ||
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccImageDataSourceConfig_basic(), | ||
Check: resource.ComposeTestCheckFunc( | ||
|
||
resource.TestCheckResourceAttrSet(dataSourceName, "applications.#"), | ||
resource.TestCheckResourceAttrSet(dataSourceName, "appstream_agent_version"), | ||
resource.TestCheckResourceAttrSet(dataSourceName, names.AttrARN), | ||
resource.TestCheckResourceAttrSet(dataSourceName, names.AttrCreatedTime), | ||
resource.TestCheckResourceAttrSet(dataSourceName, names.AttrDescription), | ||
resource.TestCheckResourceAttrSet(dataSourceName, names.AttrDisplayName), | ||
resource.TestCheckResourceAttrSet(dataSourceName, "image_builder_supported"), | ||
resource.TestCheckResourceAttrSet(dataSourceName, names.AttrName), | ||
resource.TestCheckResourceAttrSet(dataSourceName, "name_regex"), | ||
resource.TestCheckResourceAttrSet(dataSourceName, "platform"), | ||
resource.TestCheckResourceAttrSet(dataSourceName, "public_base_image_released_date"), | ||
resource.TestCheckResourceAttrSet(dataSourceName, names.AttrType), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
// name = "AppStream-WinServer2019-06-17-2024" | ||
func testAccImageDataSourceConfig_basic() string { | ||
return (` | ||
data "aws_appstream_image" "test" { | ||
name_regex = "^AppStream-WinServer.*$" | ||
type = "PUBLIC" | ||
most_recent = true | ||
} | ||
`) | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cleanup comment