Skip to content

Commit 61765df

Browse files
committed
provider: add provider_meta support
This will enable support for module-scoped User-Agent additions. Also introduces a `user_agent` provider argument for parity with the arguments available in the AWSCC provider.
1 parent 5c37ae2 commit 61765df

File tree

12 files changed

+170
-35
lines changed

12 files changed

+170
-35
lines changed

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,3 +391,5 @@ require (
391391
google.golang.org/grpc v1.75.1 // indirect
392392
google.golang.org/protobuf v1.36.9 // indirect
393393
)
394+
395+
replace github.com/hashicorp/aws-sdk-go-base/v2 => ../../aws-sdk-go-base

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -637,8 +637,6 @@ github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
637637
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
638638
github.com/hashicorp/aws-cloudformation-resource-schema-sdk-go v0.23.0 h1:l16/Vrl0+x+HjHJWEjcKPwHYoxN9EC78gAFXKlH6m84=
639639
github.com/hashicorp/aws-cloudformation-resource-schema-sdk-go v0.23.0/go.mod h1:HAmscHyzSOfB1Dr16KLc177KNbn83wscnZC+N7WyaM8=
640-
github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.68 h1:az84QLx3MwAMrOMjRpGjKQFY9/JkXveoc5TPbr8XHDQ=
641-
github.com/hashicorp/aws-sdk-go-base/v2 v2.0.0-beta.68/go.mod h1:naAMUZYs95/rPa/UchEe9VR/wa3RdTO5mQC5lKUWTmM=
642640
github.com/hashicorp/awspolicyequivalence v1.7.0 h1:HxwPEw2/31BqQa73PinGciTfG2uJ/ATelvDG8X1gScU=
643641
github.com/hashicorp/awspolicyequivalence v1.7.0/go.mod h1:+oCTxQEYt+GcRalqrqTCBcJf100SQYiWQ4aENNYxYe0=
644642
github.com/hashicorp/cli v1.1.7 h1:/fZJ+hNdwfTSfsxMBa9WWMlfjUZbX8/LnUxgAd7lCVU=

internal/conns/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ type Config struct {
6363
TokenBucketRateLimiterCapacity int
6464
UseDualStackEndpoint bool
6565
UseFIPSEndpoint bool
66+
UserAgent awsbase.UserAgentProducts
6667
}
6768

6869
// ConfigureProvider configures the provided provider Meta (instance data).
@@ -114,6 +115,7 @@ func (c *Config) ConfigureProvider(ctx context.Context, client *AWSClient) (*AWS
114115
TokenBucketRateLimiterCapacity: c.TokenBucketRateLimiterCapacity,
115116
UseDualStackEndpoint: c.UseDualStackEndpoint,
116117
UseFIPSEndpoint: c.UseFIPSEndpoint,
118+
UserAgent: c.UserAgent,
117119
}
118120

119121
if c.CustomCABundle != "" {

internal/provider/framework/provider.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/hashicorp/terraform-plugin-framework/function"
2525
"github.com/hashicorp/terraform-plugin-framework/list"
2626
"github.com/hashicorp/terraform-plugin-framework/provider"
27+
"github.com/hashicorp/terraform-plugin-framework/provider/metaschema"
2728
"github.com/hashicorp/terraform-plugin-framework/provider/schema"
2829
"github.com/hashicorp/terraform-plugin-framework/resource"
2930
resourceschema "github.com/hashicorp/terraform-plugin-framework/resource/schema"
@@ -49,6 +50,7 @@ var (
4950
_ provider.ProviderWithFunctions = &frameworkProvider{}
5051
_ provider.ProviderWithEphemeralResources = &frameworkProvider{}
5152
_ provider.ProviderWithListResources = &frameworkProvider{}
53+
_ provider.ProviderWithMetaSchema = &frameworkProvider{}
5254
)
5355

5456
type frameworkProvider struct {
@@ -223,6 +225,11 @@ func (*frameworkProvider) Schema(ctx context.Context, request provider.SchemaReq
223225
Optional: true,
224226
Description: "Resolve an endpoint with FIPS capability",
225227
},
228+
"user_agent": schema.ListAttribute{
229+
ElementType: types.StringType,
230+
Optional: true,
231+
Description: "Product details to append to the User-Agent string sent in all AWS API calls.",
232+
},
226233
},
227234
Blocks: map[string]schema.Block{
228235
"assume_role": schema.ListNestedBlock{
@@ -351,6 +358,18 @@ func (*frameworkProvider) Schema(ctx context.Context, request provider.SchemaReq
351358
}
352359
}
353360

361+
func (p *frameworkProvider) MetaSchema(ctx context.Context, req provider.MetaSchemaRequest, resp *provider.MetaSchemaResponse) {
362+
resp.Schema = metaschema.Schema{
363+
Attributes: map[string]metaschema.Attribute{
364+
"user_agent": schema.ListAttribute{
365+
ElementType: types.StringType,
366+
Optional: true,
367+
Description: "Product details to append to the User-Agent string sent in all AWS API calls.",
368+
},
369+
},
370+
}
371+
}
372+
354373
// Configure is called at the beginning of the provider lifecycle, when
355374
// Terraform sends to the provider the values the user specified in the
356375
// provider configuration block.

internal/provider/framework/wrap.go

Lines changed: 45 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,15 @@ package framework
66
import (
77
"context"
88

9+
"github.com/hashicorp/aws-sdk-go-base/v2/useragent"
910
"github.com/hashicorp/terraform-plugin-framework/action"
1011
"github.com/hashicorp/terraform-plugin-framework/datasource"
1112
"github.com/hashicorp/terraform-plugin-framework/diag"
1213
"github.com/hashicorp/terraform-plugin-framework/ephemeral"
1314
"github.com/hashicorp/terraform-plugin-framework/list"
1415
"github.com/hashicorp/terraform-plugin-framework/path"
1516
"github.com/hashicorp/terraform-plugin-framework/resource"
17+
"github.com/hashicorp/terraform-plugin-framework/tfsdk"
1618
"github.com/hashicorp/terraform-plugin-framework/types"
1719
"github.com/hashicorp/terraform-plugin-log/tflog"
1820
"github.com/hashicorp/terraform-provider-aws/internal/conns"
@@ -75,7 +77,7 @@ func newWrappedDataSource(spec *inttypes.ServicePackageFrameworkDataSource, serv
7577
}
7678

7779
// context is run on all wrapped methods before any interceptors.
78-
func (w *wrappedDataSource) context(ctx context.Context, getAttribute getAttributeFunc, c *conns.AWSClient) (context.Context, diag.Diagnostics) {
80+
func (w *wrappedDataSource) context(ctx context.Context, getAttribute getAttributeFunc, providerMeta *tfsdk.Config, c *conns.AWSClient) (context.Context, diag.Diagnostics) {
7981
var diags diag.Diagnostics
8082
var overrideRegion string
8183

@@ -101,6 +103,18 @@ func (w *wrappedDataSource) context(ctx context.Context, getAttribute getAttribu
101103
ctx = fwflex.RegisterLogger(ctx)
102104
}
103105

106+
if providerMeta != nil {
107+
var metadata []string
108+
diags.Append(providerMeta.GetAttribute(ctx, path.Root("user_agent"), &metadata)...)
109+
if diags.HasError() {
110+
return ctx, diags
111+
}
112+
113+
if metadata != nil {
114+
ctx = useragent.Context(ctx, useragent.FromSlice(metadata))
115+
}
116+
}
117+
104118
return ctx, diags
105119
}
106120

@@ -110,7 +124,7 @@ func (w *wrappedDataSource) Metadata(ctx context.Context, request datasource.Met
110124
}
111125

112126
func (w *wrappedDataSource) Schema(ctx context.Context, request datasource.SchemaRequest, response *datasource.SchemaResponse) {
113-
ctx, diags := w.context(ctx, nil, w.meta)
127+
ctx, diags := w.context(ctx, nil, nil, w.meta)
114128
response.Diagnostics.Append(diags...)
115129
if response.Diagnostics.HasError() {
116130
return
@@ -134,7 +148,7 @@ func (w *wrappedDataSource) Schema(ctx context.Context, request datasource.Schem
134148
}
135149

136150
func (w *wrappedDataSource) Read(ctx context.Context, request datasource.ReadRequest, response *datasource.ReadResponse) {
137-
ctx, diags := w.context(ctx, request.Config.GetAttribute, w.meta)
151+
ctx, diags := w.context(ctx, request.Config.GetAttribute, &request.ProviderMeta, w.meta)
138152
response.Diagnostics.Append(diags...)
139153
if response.Diagnostics.HasError() {
140154
return
@@ -148,7 +162,7 @@ func (w *wrappedDataSource) Configure(ctx context.Context, request datasource.Co
148162
w.meta = v
149163
}
150164

151-
ctx, diags := w.context(ctx, nil, w.meta)
165+
ctx, diags := w.context(ctx, nil, nil, w.meta)
152166
response.Diagnostics.Append(diags...)
153167
if response.Diagnostics.HasError() {
154168
return
@@ -159,7 +173,7 @@ func (w *wrappedDataSource) Configure(ctx context.Context, request datasource.Co
159173

160174
func (w *wrappedDataSource) ConfigValidators(ctx context.Context) []datasource.ConfigValidator {
161175
if v, ok := w.inner.(datasource.DataSourceWithConfigValidators); ok {
162-
ctx, diags := w.context(ctx, nil, w.meta)
176+
ctx, diags := w.context(ctx, nil, nil, w.meta)
163177
if diags.HasError() {
164178
tflog.Warn(ctx, "wrapping ConfigValidators", map[string]any{
165179
"data source": w.spec.TypeName,
@@ -177,7 +191,7 @@ func (w *wrappedDataSource) ConfigValidators(ctx context.Context) []datasource.C
177191

178192
func (w *wrappedDataSource) ValidateConfig(ctx context.Context, request datasource.ValidateConfigRequest, response *datasource.ValidateConfigResponse) {
179193
if v, ok := w.inner.(datasource.DataSourceWithValidateConfig); ok {
180-
ctx, diags := w.context(ctx, request.Config.GetAttribute, w.meta)
194+
ctx, diags := w.context(ctx, request.Config.GetAttribute, nil, w.meta)
181195
response.Diagnostics.Append(diags...)
182196
if response.Diagnostics.HasError() {
183197
return
@@ -584,7 +598,7 @@ func newWrappedResource(spec *inttypes.ServicePackageFrameworkResource, serviceP
584598
}
585599

586600
// context is run on all wrapped methods before any interceptors.
587-
func (w *wrappedResource) context(ctx context.Context, getAttribute getAttributeFunc, c *conns.AWSClient) (context.Context, diag.Diagnostics) {
601+
func (w *wrappedResource) context(ctx context.Context, getAttribute getAttributeFunc, providerMeta *tfsdk.Config, c *conns.AWSClient) (context.Context, diag.Diagnostics) {
588602
var diags diag.Diagnostics
589603
var overrideRegion string
590604

@@ -610,6 +624,18 @@ func (w *wrappedResource) context(ctx context.Context, getAttribute getAttribute
610624
ctx = fwflex.RegisterLogger(ctx)
611625
}
612626

627+
if providerMeta != nil {
628+
var metadata []string
629+
diags.Append(providerMeta.GetAttribute(ctx, path.Root("user_agent"), &metadata)...)
630+
if diags.HasError() {
631+
return ctx, diags
632+
}
633+
634+
if metadata != nil {
635+
ctx = useragent.Context(ctx, useragent.FromSlice(metadata))
636+
}
637+
}
638+
613639
return ctx, diags
614640
}
615641

@@ -623,7 +649,7 @@ func (w *wrappedResource) Metadata(ctx context.Context, request resource.Metadat
623649
}
624650

625651
func (w *wrappedResource) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) {
626-
ctx, diags := w.context(ctx, nil, w.meta)
652+
ctx, diags := w.context(ctx, nil, nil, w.meta)
627653
response.Diagnostics.Append(diags...)
628654
if response.Diagnostics.HasError() {
629655
return
@@ -644,7 +670,7 @@ func (w *wrappedResource) Schema(ctx context.Context, request resource.SchemaReq
644670
}
645671

646672
func (w *wrappedResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) {
647-
ctx, diags := w.context(ctx, request.Plan.GetAttribute, w.meta)
673+
ctx, diags := w.context(ctx, request.Plan.GetAttribute, &request.ProviderMeta, w.meta)
648674
response.Diagnostics.Append(diags...)
649675
if response.Diagnostics.HasError() {
650676
return
@@ -654,7 +680,7 @@ func (w *wrappedResource) Create(ctx context.Context, request resource.CreateReq
654680
}
655681

656682
func (w *wrappedResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) {
657-
ctx, diags := w.context(ctx, request.State.GetAttribute, w.meta)
683+
ctx, diags := w.context(ctx, request.State.GetAttribute, &request.ProviderMeta, w.meta)
658684
response.Diagnostics.Append(diags...)
659685
if response.Diagnostics.HasError() {
660686
return
@@ -664,7 +690,7 @@ func (w *wrappedResource) Read(ctx context.Context, request resource.ReadRequest
664690
}
665691

666692
func (w *wrappedResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) {
667-
ctx, diags := w.context(ctx, request.Plan.GetAttribute, w.meta)
693+
ctx, diags := w.context(ctx, request.Plan.GetAttribute, &request.ProviderMeta, w.meta)
668694
response.Diagnostics.Append(diags...)
669695
if response.Diagnostics.HasError() {
670696
return
@@ -674,7 +700,7 @@ func (w *wrappedResource) Update(ctx context.Context, request resource.UpdateReq
674700
}
675701

676702
func (w *wrappedResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) {
677-
ctx, diags := w.context(ctx, request.State.GetAttribute, w.meta)
703+
ctx, diags := w.context(ctx, request.State.GetAttribute, &request.ProviderMeta, w.meta)
678704
response.Diagnostics.Append(diags...)
679705
if response.Diagnostics.HasError() {
680706
return
@@ -688,7 +714,7 @@ func (w *wrappedResource) Configure(ctx context.Context, request resource.Config
688714
w.meta = v
689715
}
690716

691-
ctx, diags := w.context(ctx, nil, w.meta)
717+
ctx, diags := w.context(ctx, nil, nil, w.meta)
692718
response.Diagnostics.Append(diags...)
693719
if response.Diagnostics.HasError() {
694720
return
@@ -699,7 +725,7 @@ func (w *wrappedResource) Configure(ctx context.Context, request resource.Config
699725

700726
func (w *wrappedResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) {
701727
if v, ok := w.inner.(resource.ResourceWithImportState); ok {
702-
ctx, diags := w.context(ctx, nil, w.meta)
728+
ctx, diags := w.context(ctx, nil, nil, w.meta)
703729
response.Diagnostics.Append(diags...)
704730
if response.Diagnostics.HasError() {
705731
return
@@ -718,7 +744,7 @@ func (w *wrappedResource) ImportState(ctx context.Context, request resource.Impo
718744
}
719745

720746
func (w *wrappedResource) ModifyPlan(ctx context.Context, request resource.ModifyPlanRequest, response *resource.ModifyPlanResponse) {
721-
ctx, diags := w.context(ctx, request.Config.GetAttribute, w.meta)
747+
ctx, diags := w.context(ctx, request.Config.GetAttribute, &request.ProviderMeta, w.meta)
722748
response.Diagnostics.Append(diags...)
723749
if response.Diagnostics.HasError() {
724750
return
@@ -735,7 +761,7 @@ func (w *wrappedResource) ModifyPlan(ctx context.Context, request resource.Modif
735761

736762
func (w *wrappedResource) ConfigValidators(ctx context.Context) []resource.ConfigValidator {
737763
if v, ok := w.inner.(resource.ResourceWithConfigValidators); ok {
738-
ctx, diags := w.context(ctx, nil, w.meta)
764+
ctx, diags := w.context(ctx, nil, nil, w.meta)
739765
if diags.HasError() {
740766
tflog.Warn(ctx, "wrapping ConfigValidators", map[string]any{
741767
"resource": w.spec.TypeName,
@@ -752,7 +778,7 @@ func (w *wrappedResource) ConfigValidators(ctx context.Context) []resource.Confi
752778
}
753779

754780
func (w *wrappedResource) ValidateConfig(ctx context.Context, request resource.ValidateConfigRequest, response *resource.ValidateConfigResponse) {
755-
ctx, diags := w.context(ctx, request.Config.GetAttribute, w.meta)
781+
ctx, diags := w.context(ctx, request.Config.GetAttribute, nil, w.meta)
756782
response.Diagnostics.Append(diags...)
757783
if response.Diagnostics.HasError() {
758784
return
@@ -765,7 +791,7 @@ func (w *wrappedResource) ValidateConfig(ctx context.Context, request resource.V
765791

766792
func (w *wrappedResource) UpgradeState(ctx context.Context) map[int64]resource.StateUpgrader {
767793
if v, ok := w.inner.(resource.ResourceWithUpgradeState); ok {
768-
ctx, diags := w.context(ctx, nil, w.meta)
794+
ctx, diags := w.context(ctx, nil, nil, w.meta)
769795
if diags.HasError() {
770796
tflog.Warn(ctx, "wrapping UpgradeState", map[string]any{
771797
"resource": w.spec.TypeName,
@@ -783,7 +809,7 @@ func (w *wrappedResource) UpgradeState(ctx context.Context) map[int64]resource.S
783809

784810
func (w *wrappedResource) MoveState(ctx context.Context) []resource.StateMover {
785811
if v, ok := w.inner.(resource.ResourceWithMoveState); ok {
786-
ctx, diags := w.context(ctx, nil, w.meta)
812+
ctx, diags := w.context(ctx, nil, nil, w.meta)
787813
if diags.HasError() {
788814
tflog.Warn(ctx, "wrapping MoveState", map[string]any{
789815
"resource": w.spec.TypeName,

internal/provider/sdkv2/intercept.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ func interceptedCRUDHandler[F ~func(context.Context, *schema.ResourceData, any)
140140
return func(ctx context.Context, rd *schema.ResourceData, meta any) diag.Diagnostics {
141141
var diags diag.Diagnostics
142142

143-
ctx, err := bootstrapContext(ctx, rd.GetOk, meta)
143+
ctx, err := bootstrapContext(ctx, rd.GetOk, rd.GetProviderMeta, meta)
144144
if err != nil {
145145
return sdkdiag.AppendFromErr(diags, err)
146146
}
@@ -205,7 +205,7 @@ func interceptedCRUDHandler[F ~func(context.Context, *schema.ResourceData, any)
205205
func interceptedCustomizeDiffHandler(bootstrapContext contextFunc, interceptorInvocations interceptorInvocations, f schema.CustomizeDiffFunc) schema.CustomizeDiffFunc {
206206
// We run CustomizeDiff interceptors even if the resource has not defined a CustomizeDiff function.
207207
return func(ctx context.Context, d *schema.ResourceDiff, meta any) error {
208-
ctx, err := bootstrapContext(ctx, d.GetOk, meta)
208+
ctx, err := bootstrapContext(ctx, d.GetOk, nil, meta)
209209
if err != nil {
210210
return err
211211
}
@@ -280,7 +280,7 @@ func interceptedImportHandler(bootstrapContext contextFunc, interceptorInvocatio
280280
}
281281

282282
return func(ctx context.Context, d *schema.ResourceData, meta any) ([]*schema.ResourceData, error) {
283-
ctx, err := bootstrapContext(ctx, d.GetOk, meta)
283+
ctx, err := bootstrapContext(ctx, d.GetOk, nil, meta)
284284
if err != nil {
285285
return nil, err
286286
}

internal/provider/sdkv2/intercept_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func TestInterceptedCRUDHandler(t *testing.T) {
6969
region: "us-west-2", //lintignore:AWSAT003
7070
}
7171

72-
contextFunc := func(ctx context.Context, _ getAttributeFunc, meta any) (context.Context, error) {
72+
contextFunc := func(ctx context.Context, _ getAttributeFunc, _ getProviderMetaFunc, meta any) (context.Context, error) {
7373
return ctx, nil
7474
}
7575

@@ -374,7 +374,7 @@ func TestInterceptedCustomizeDiffHandler(t *testing.T) {
374374
region: "us-west-2", //lintignore:AWSAT003
375375
}
376376

377-
contextFunc := func(ctx context.Context, _ getAttributeFunc, meta any) (context.Context, error) {
377+
contextFunc := func(ctx context.Context, _ getAttributeFunc, _ getProviderMetaFunc, meta any) (context.Context, error) {
378378
return ctx, nil
379379
}
380380

@@ -555,7 +555,7 @@ func TestInterceptedImportHandler(t *testing.T) {
555555
region: "us-west-2", //lintignore:AWSAT003
556556
}
557557

558-
contextFunc := func(ctx context.Context, _ getAttributeFunc, meta any) (context.Context, error) {
558+
contextFunc := func(ctx context.Context, _ getAttributeFunc, _ getProviderMetaFunc, meta any) (context.Context, error) {
559559
return ctx, nil
560560
}
561561

0 commit comments

Comments
 (0)