Skip to content

Commit dd65de1

Browse files
authored
Merge pull request #44168 from chillinginchaos/f-aws_appconfig_application-new-datasource
Adds data source for appconfig application
2 parents a9346f2 + 9e81f7c commit dd65de1

File tree

5 files changed

+304
-1
lines changed

5 files changed

+304
-1
lines changed

.changelog/44168.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:new-data-source
2+
aws_appconfig_application
3+
```
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package appconfig
5+
6+
import (
7+
"context"
8+
"fmt"
9+
"iter"
10+
11+
"github.com/YakDriver/regexache"
12+
"github.com/aws/aws-sdk-go-v2/aws"
13+
"github.com/aws/aws-sdk-go-v2/service/appconfig"
14+
awstypes "github.com/aws/aws-sdk-go-v2/service/appconfig/types"
15+
"github.com/hashicorp/terraform-plugin-framework-validators/datasourcevalidator"
16+
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
17+
"github.com/hashicorp/terraform-plugin-framework/datasource"
18+
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
19+
"github.com/hashicorp/terraform-plugin-framework/path"
20+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
21+
"github.com/hashicorp/terraform-plugin-framework/types"
22+
"github.com/hashicorp/terraform-provider-aws/internal/framework"
23+
"github.com/hashicorp/terraform-provider-aws/internal/framework/flex"
24+
tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices"
25+
"github.com/hashicorp/terraform-provider-aws/internal/smerr"
26+
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
27+
"github.com/hashicorp/terraform-provider-aws/names"
28+
)
29+
30+
// @FrameworkDataSource("aws_appconfig_application", name="Application")
31+
func newDataSourceApplication(context.Context) (datasource.DataSourceWithConfigure, error) {
32+
return &dataSourceApplication{}, nil
33+
}
34+
35+
type dataSourceApplication struct {
36+
framework.DataSourceWithModel[dataSourceApplicationModel]
37+
}
38+
39+
func (d *dataSourceApplication) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
40+
resp.Schema = schema.Schema{
41+
Attributes: map[string]schema.Attribute{
42+
names.AttrARN: framework.ARNAttributeComputedOnly(),
43+
names.AttrDescription: schema.StringAttribute{
44+
Computed: true,
45+
},
46+
names.AttrID: schema.StringAttribute{
47+
Optional: true,
48+
Computed: true,
49+
Validators: []validator.String{
50+
stringvalidator.RegexMatches(
51+
regexache.MustCompile(`^[0-9a-z]{4,7}$`),
52+
"value must contain 4-7 lowercase letters or numbers",
53+
),
54+
},
55+
},
56+
names.AttrName: schema.StringAttribute{
57+
Optional: true,
58+
Computed: true,
59+
Validators: []validator.String{
60+
stringvalidator.LengthBetween(1, 64),
61+
},
62+
},
63+
},
64+
}
65+
}
66+
67+
func (d *dataSourceApplication) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
68+
conn := d.Meta().AppConfigClient(ctx)
69+
70+
var data dataSourceApplicationModel
71+
smerr.EnrichAppend(ctx, &resp.Diagnostics, req.Config.Get(ctx, &data))
72+
if resp.Diagnostics.HasError() {
73+
return
74+
}
75+
76+
var out *awstypes.Application
77+
var err error
78+
var input appconfig.ListApplicationsInput
79+
if !data.ID.IsNull() {
80+
out, err = findApplicationWithFilter(ctx, conn, &input, func(v *awstypes.Application) bool {
81+
return aws.ToString(v.Id) == data.ID.ValueString()
82+
}, tfslices.WithReturnFirstMatch)
83+
}
84+
85+
if !data.Name.IsNull() {
86+
out, err = findApplicationWithFilter(ctx, conn, &input, func(v *awstypes.Application) bool {
87+
return aws.ToString(v.Name) == data.Name.ValueString()
88+
}, tfslices.WithReturnFirstMatch)
89+
}
90+
91+
if err != nil {
92+
smerr.AddError(ctx, &resp.Diagnostics, err, smerr.ID, data.Name.String())
93+
return
94+
}
95+
96+
smerr.EnrichAppend(ctx, &resp.Diagnostics, flex.Flatten(ctx, out, &data), smerr.ID, data.Name.String())
97+
if resp.Diagnostics.HasError() {
98+
return
99+
}
100+
101+
data.ARN = flex.StringValueToFramework(ctx, d.Meta().RegionalARN(ctx, "appconfig", "application/"+data.ID.ValueString()))
102+
103+
smerr.EnrichAppend(ctx, &resp.Diagnostics, resp.State.Set(ctx, &data), smerr.ID, data.Name.String())
104+
}
105+
106+
func (d *dataSourceApplication) ConfigValidators(_ context.Context) []datasource.ConfigValidator {
107+
return []datasource.ConfigValidator{
108+
datasourcevalidator.ExactlyOneOf(
109+
path.MatchRoot(names.AttrID),
110+
path.MatchRoot(names.AttrName),
111+
),
112+
}
113+
}
114+
115+
type dataSourceApplicationModel struct {
116+
framework.WithRegionModel
117+
ARN types.String `tfsdk:"arn"`
118+
Description types.String `tfsdk:"description"`
119+
ID types.String `tfsdk:"id"`
120+
Name types.String `tfsdk:"name"`
121+
}
122+
123+
func findApplicationWithFilter(ctx context.Context, conn *appconfig.Client, input *appconfig.ListApplicationsInput, filter tfslices.Predicate[*awstypes.Application], optFns ...tfslices.FinderOptionsFunc) (*awstypes.Application, error) {
124+
opts := tfslices.NewFinderOptions(optFns)
125+
var output []awstypes.Application
126+
for value, err := range listApplications(ctx, conn, input, filter) {
127+
if err != nil {
128+
return nil, err
129+
}
130+
131+
output = append(output, value)
132+
if opts.ReturnFirstMatch() {
133+
break
134+
}
135+
}
136+
137+
return tfresource.AssertSingleValueResult(output)
138+
}
139+
140+
func listApplications(ctx context.Context, conn *appconfig.Client, input *appconfig.ListApplicationsInput, filter tfslices.Predicate[*awstypes.Application]) iter.Seq2[awstypes.Application, error] {
141+
return func(yield func(awstypes.Application, error) bool) {
142+
pages := appconfig.NewListApplicationsPaginator(conn, input)
143+
for pages.HasMorePages() {
144+
page, err := pages.NextPage(ctx)
145+
if err != nil {
146+
yield(awstypes.Application{}, fmt.Errorf("listing AppConfig Applications: %w", err))
147+
return
148+
}
149+
150+
for _, v := range page.Items {
151+
if filter(&v) {
152+
if !yield(v, nil) {
153+
return
154+
}
155+
}
156+
}
157+
}
158+
}
159+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package appconfig_test
5+
6+
import (
7+
"fmt"
8+
"testing"
9+
10+
"github.com/YakDriver/regexache"
11+
sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest"
12+
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
13+
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
14+
"github.com/hashicorp/terraform-provider-aws/names"
15+
)
16+
17+
func TestAccAppConfigApplicationDataSource_basic_name(t *testing.T) {
18+
ctx := acctest.Context(t)
19+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
20+
dataSourceName := "data.aws_appconfig_application.test"
21+
resourceName := "aws_appconfig_application.test"
22+
23+
resource.ParallelTest(t, resource.TestCase{
24+
PreCheck: func() {
25+
acctest.PreCheck(ctx, t)
26+
acctest.PreCheckPartitionHasService(t, names.AppConfigEndpointID)
27+
},
28+
ErrorCheck: acctest.ErrorCheck(t, names.AppConfigServiceID),
29+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
30+
CheckDestroy: testAccCheckApplicationDestroy(ctx),
31+
Steps: []resource.TestStep{
32+
{
33+
Config: testAccApplicationDataSourceConfig_name(rName),
34+
Check: resource.ComposeAggregateTestCheckFunc(
35+
testAccCheckApplicationExists(ctx, dataSourceName),
36+
resource.TestCheckResourceAttrPair(dataSourceName, names.AttrDescription, resourceName, names.AttrDescription),
37+
resource.TestCheckResourceAttrPair(dataSourceName, names.AttrID, resourceName, names.AttrID),
38+
resource.TestMatchResourceAttr(dataSourceName, names.AttrID, regexache.MustCompile(`[a-z\d]{4,7}`)),
39+
resource.TestCheckResourceAttrPair(dataSourceName, names.AttrName, resourceName, names.AttrName),
40+
),
41+
},
42+
},
43+
})
44+
}
45+
46+
func TestAccAppConfigApplicationDataSource_basic_id(t *testing.T) {
47+
ctx := acctest.Context(t)
48+
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
49+
dataSourceName := "data.aws_appconfig_application.test"
50+
resourceName := "aws_appconfig_application.test"
51+
52+
resource.ParallelTest(t, resource.TestCase{
53+
PreCheck: func() {
54+
acctest.PreCheck(ctx, t)
55+
acctest.PreCheckPartitionHasService(t, names.AppConfigEndpointID)
56+
},
57+
ErrorCheck: acctest.ErrorCheck(t, names.AppConfigServiceID),
58+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
59+
CheckDestroy: testAccCheckApplicationDestroy(ctx),
60+
Steps: []resource.TestStep{
61+
{
62+
Config: testAccApplicationDataSourceConfig_id(rName),
63+
Check: resource.ComposeAggregateTestCheckFunc(
64+
testAccCheckApplicationExists(ctx, dataSourceName),
65+
resource.TestCheckResourceAttrPair(dataSourceName, names.AttrDescription, resourceName, names.AttrDescription),
66+
resource.TestCheckResourceAttrPair(dataSourceName, names.AttrID, resourceName, names.AttrID),
67+
resource.TestMatchResourceAttr(dataSourceName, names.AttrID, regexache.MustCompile(`[a-z\d]{4,7}`)),
68+
resource.TestCheckResourceAttrPair(dataSourceName, names.AttrName, resourceName, names.AttrName),
69+
),
70+
},
71+
},
72+
})
73+
}
74+
75+
func testAccApplicationDataSourceConfig_baseConfig(rName string) string {
76+
return fmt.Sprintf(`
77+
resource "aws_appconfig_application" "test" {
78+
name = %[1]q
79+
description = "Example AppConfig Application"
80+
}
81+
`, rName)
82+
}
83+
84+
func testAccApplicationDataSourceConfig_name(rName string) string {
85+
return acctest.ConfigCompose(testAccApplicationDataSourceConfig_baseConfig(rName), `
86+
data "aws_appconfig_application" "test" {
87+
name = aws_appconfig_application.test.name
88+
}
89+
`)
90+
}
91+
92+
func testAccApplicationDataSourceConfig_id(rName string) string {
93+
return acctest.ConfigCompose(testAccApplicationDataSourceConfig_baseConfig(rName), `
94+
data "aws_appconfig_application" "test" {
95+
id = aws_appconfig_application.test.id
96+
}
97+
`)
98+
}

internal/service/appconfig/service_package_gen.go

Lines changed: 8 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
---
2+
subcategory: "AppConfig"
3+
layout: "aws"
4+
page_title: "AWS: aws_appconfig_application"
5+
description: |-
6+
Retrieves an AWS AppConfig Application by name.
7+
---
8+
9+
# Data Source: aws_appconfig_application
10+
11+
Provides details about an AWS AppConfig Application.
12+
13+
## Example Usage
14+
15+
### Basic Usage
16+
17+
```terraform
18+
data "aws_appconfig_application" "example" {
19+
name = "my-appconfig-application"
20+
}
21+
```
22+
23+
## Argument Reference
24+
25+
This data source supports the following arguments:
26+
27+
* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference).
28+
* `id` - (Optional) ID of the Application. Either `id` or `name` must be specified.
29+
* `name` - (Optional) AWS AppConfig Application name. Either `name` or `id` must be specified.
30+
31+
## Attribute Reference
32+
33+
This data source exports the following attributes in addition to the arguments above:
34+
35+
* `arn` - ARN of the Application.
36+
* `description` - Description of the Application.

0 commit comments

Comments
 (0)