Skip to content

Commit c4eadf3

Browse files
authored
Use acceptance tests to test handling of the credentials provider configuration argument, add new data source that surfaces configuration of SDK and plugin-framework providers to facilitate acctests (#11599)
1 parent b2c4823 commit c4eadf3

11 files changed

+960
-554
lines changed

mmv1/third_party/terraform/acctest/vcr_utils.go

+15
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ import (
3131
"github.com/dnaeon/go-vcr/recorder"
3232

3333
"github.com/hashicorp/terraform-plugin-framework/attr"
34+
"github.com/hashicorp/terraform-plugin-framework/datasource"
35+
3436
fwDiags "github.com/hashicorp/terraform-plugin-framework/diag"
3537
"github.com/hashicorp/terraform-plugin-framework/provider"
3638
"github.com/hashicorp/terraform-plugin-framework/types"
@@ -436,6 +438,14 @@ func (p *frameworkTestProvider) Configure(ctx context.Context, req provider.Conf
436438
}
437439
}
438440

441+
// DataSources overrides the provider's DataSources function so that we can append test-specific data sources to the list of data sources on the provider.
442+
// This makes the data source(s) usable only in the context of acctests, and isn't available to users
443+
func (p *frameworkTestProvider) DataSources(ctx context.Context) []func() datasource.DataSource {
444+
ds := p.FrameworkProvider.DataSources(ctx)
445+
ds = append(ds, fwprovider.NewGoogleProviderConfigPluginFrameworkDataSource) // google_provider_config_plugin_framework
446+
return ds
447+
}
448+
439449
func configureApiClient(ctx context.Context, p *fwprovider.FrameworkProvider, diags *fwDiags.Diagnostics) {
440450
var data fwmodels.ProviderModel
441451
var d fwDiags.Diagnostics
@@ -453,6 +463,11 @@ func configureApiClient(ctx context.Context, p *fwprovider.FrameworkProvider, di
453463
// GetSDKProvider gets the SDK provider with an overwritten configure function to be called by MuxedProviders
454464
func GetSDKProvider(testName string) *schema.Provider {
455465
prov := tpgprovider.Provider()
466+
467+
// Append a test-specific data source to the list of data sources on the provider
468+
// This makes the data source(s) usable only in the context of acctests, and isn't available to users
469+
prov.DataSourcesMap["google_provider_config_sdk"] = tpgprovider.DataSourceGoogleProviderConfigSdk()
470+
456471
if IsVcrEnabled() {
457472
old := prov.ConfigureContextFunc
458473
prov.ConfigureContextFunc = func(ctx context.Context, d *schema.ResourceData) (interface{}, diag.Diagnostics) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
package fwprovider
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/hashicorp/terraform-plugin-framework/datasource"
8+
"github.com/hashicorp/terraform-plugin-framework/datasource/schema"
9+
"github.com/hashicorp/terraform-plugin-framework/diag"
10+
"github.com/hashicorp/terraform-plugin-framework/types"
11+
"github.com/hashicorp/terraform-provider-google/google/fwmodels"
12+
"github.com/hashicorp/terraform-provider-google/google/fwresource"
13+
"github.com/hashicorp/terraform-provider-google/google/fwtransport"
14+
)
15+
16+
// Ensure the data source satisfies the expected interfaces.
17+
var (
18+
_ datasource.DataSource = &GoogleProviderConfigPluginFrameworkDataSource{}
19+
_ datasource.DataSourceWithConfigure = &GoogleProviderConfigPluginFrameworkDataSource{}
20+
_ fwresource.LocationDescriber = &GoogleProviderConfigPluginFrameworkModel{}
21+
)
22+
23+
func NewGoogleProviderConfigPluginFrameworkDataSource() datasource.DataSource {
24+
return &GoogleProviderConfigPluginFrameworkDataSource{}
25+
}
26+
27+
type GoogleProviderConfigPluginFrameworkDataSource struct {
28+
providerConfig *fwtransport.FrameworkProviderConfig
29+
}
30+
31+
type GoogleProviderConfigPluginFrameworkModel struct {
32+
// Currently this reflects the FrameworkProviderConfig struct and ProviderModel in google/fwmodels/provider_model.go
33+
// which means it uses the plugin-framework type system where values can be explicitly Null or Unknown.
34+
//
35+
// As part of future muxing fixes/refactoring we'll change this struct to reflect structs used in the SDK code, and will move to
36+
// using the SDK type system.
37+
Credentials types.String `tfsdk:"credentials"`
38+
AccessToken types.String `tfsdk:"access_token"`
39+
ImpersonateServiceAccount types.String `tfsdk:"impersonate_service_account"`
40+
ImpersonateServiceAccountDelegates types.List `tfsdk:"impersonate_service_account_delegates"`
41+
Project types.String `tfsdk:"project"`
42+
BillingProject types.String `tfsdk:"billing_project"`
43+
Region types.String `tfsdk:"region"`
44+
Zone types.String `tfsdk:"zone"`
45+
Scopes types.List `tfsdk:"scopes"`
46+
// omit Batching
47+
UserProjectOverride types.Bool `tfsdk:"user_project_override"`
48+
RequestTimeout types.String `tfsdk:"request_timeout"`
49+
RequestReason types.String `tfsdk:"request_reason"`
50+
UniverseDomain types.String `tfsdk:"universe_domain"`
51+
DefaultLabels types.Map `tfsdk:"default_labels"`
52+
AddTerraformAttributionLabel types.Bool `tfsdk:"add_terraform_attribution_label"`
53+
TerraformAttributionLabelAdditionStrategy types.String `tfsdk:"terraform_attribution_label_addition_strategy"`
54+
}
55+
56+
func (m *GoogleProviderConfigPluginFrameworkModel) GetLocationDescription(providerConfig *fwtransport.FrameworkProviderConfig) fwresource.LocationDescription {
57+
return fwresource.LocationDescription{
58+
RegionSchemaField: types.StringValue("region"),
59+
ZoneSchemaField: types.StringValue("zone"),
60+
ProviderRegion: providerConfig.Region,
61+
ProviderZone: providerConfig.Zone,
62+
}
63+
}
64+
65+
func (d *GoogleProviderConfigPluginFrameworkDataSource) Metadata(ctx context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
66+
resp.TypeName = req.ProviderTypeName + "_provider_config_plugin_framework"
67+
}
68+
69+
func (d *GoogleProviderConfigPluginFrameworkDataSource) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) {
70+
71+
resp.Schema = schema.Schema{
72+
73+
Description: "Use this data source to access the configuration of the Google Cloud provider. This data source is implemented with the SDK.",
74+
MarkdownDescription: "Use this data source to access the configuration of the Google Cloud provider. This data source is implemented with the SDK.",
75+
Attributes: map[string]schema.Attribute{
76+
// Start of user inputs
77+
"access_token": schema.StringAttribute{
78+
Description: "The access_token argument used to configure the provider",
79+
MarkdownDescription: "The access_token argument used to configure the provider",
80+
Computed: true,
81+
Sensitive: true,
82+
},
83+
"credentials": schema.StringAttribute{
84+
Description: "The credentials argument used to configure the provider",
85+
MarkdownDescription: "The credentials argument used to configure the provider",
86+
Computed: true,
87+
Sensitive: true,
88+
},
89+
"impersonate_service_account": schema.StringAttribute{
90+
Description: "The impersonate_service_account argument used to configure the provider",
91+
MarkdownDescription: "The impersonate_service_account argument used to configure the provider.",
92+
Computed: true,
93+
},
94+
"impersonate_service_account_delegates": schema.ListAttribute{
95+
ElementType: types.StringType,
96+
Description: "The impersonate_service_account_delegates argument used to configure the provider",
97+
MarkdownDescription: "The impersonate_service_account_delegates argument used to configure the provider.",
98+
Computed: true,
99+
},
100+
"project": schema.StringAttribute{
101+
Description: "The project argument used to configure the provider",
102+
MarkdownDescription: "The project argument used to configure the provider.",
103+
Computed: true,
104+
},
105+
"region": schema.StringAttribute{
106+
Description: "The region argument used to configure the provider.",
107+
MarkdownDescription: "The region argument used to configure the provider.",
108+
Computed: true,
109+
},
110+
"billing_project": schema.StringAttribute{
111+
Description: "The billing_project argument used to configure the provider.",
112+
MarkdownDescription: "The billing_project argument used to configure the provider.",
113+
Computed: true,
114+
},
115+
"zone": schema.StringAttribute{
116+
Description: "The zone argument used to configure the provider.",
117+
MarkdownDescription: "The zone argument used to configure the provider.",
118+
Computed: true,
119+
},
120+
"universe_domain": schema.StringAttribute{
121+
Description: "The universe_domain argument used to configure the provider.",
122+
MarkdownDescription: "The universe_domain argument used to configure the provider.",
123+
Computed: true,
124+
},
125+
"scopes": schema.ListAttribute{
126+
ElementType: types.StringType,
127+
Description: "The scopes argument used to configure the provider.",
128+
MarkdownDescription: "The scopes argument used to configure the provider.",
129+
Computed: true,
130+
},
131+
"user_project_override": schema.BoolAttribute{
132+
Description: "The user_project_override argument used to configure the provider.",
133+
MarkdownDescription: "The user_project_override argument used to configure the provider.",
134+
Computed: true,
135+
},
136+
"request_reason": schema.StringAttribute{
137+
Description: "The request_reason argument used to configure the provider.",
138+
MarkdownDescription: "The request_reason argument used to configure the provider.",
139+
Computed: true,
140+
},
141+
"request_timeout": schema.StringAttribute{
142+
Description: "The request_timeout argument used to configure the provider.",
143+
MarkdownDescription: "The request_timeout argument used to configure the provider.",
144+
Computed: true,
145+
},
146+
"default_labels": schema.MapAttribute{
147+
ElementType: types.StringType,
148+
Description: "The default_labels argument used to configure the provider.",
149+
MarkdownDescription: "The default_labels argument used to configure the provider.",
150+
Computed: true,
151+
},
152+
"add_terraform_attribution_label": schema.BoolAttribute{
153+
Description: "The add_terraform_attribution_label argument used to configure the provider.",
154+
MarkdownDescription: "The add_terraform_attribution_label argument used to configure the provider.",
155+
Computed: true,
156+
},
157+
"terraform_attribution_label_addition_strategy": schema.StringAttribute{
158+
Description: "The terraform_attribution_label_addition_strategy argument used to configure the provider.",
159+
MarkdownDescription: "The terraform_attribution_label_addition_strategy argument used to configure the provider.",
160+
Computed: true,
161+
},
162+
// End of user inputs
163+
164+
// Note - this data source excludes the default and custom endpoints for individual services
165+
},
166+
}
167+
}
168+
169+
func (d *GoogleProviderConfigPluginFrameworkDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
170+
// Prevent panic if the provider has not been configured.
171+
if req.ProviderData == nil {
172+
return
173+
}
174+
175+
p, ok := req.ProviderData.(*fwtransport.FrameworkProviderConfig)
176+
if !ok {
177+
resp.Diagnostics.AddError(
178+
"Unexpected Data Source Configure Type",
179+
fmt.Sprintf("Expected *fwtransport.FrameworkProviderConfig, got: %T. Please report this issue to the provider developers.", req.ProviderData),
180+
)
181+
return
182+
}
183+
184+
// Required for accessing project, region, zone and tokenSource
185+
d.providerConfig = p
186+
}
187+
188+
func (d *GoogleProviderConfigPluginFrameworkDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) {
189+
var data GoogleProviderConfigPluginFrameworkModel
190+
var metaData *fwmodels.ProviderMetaModel
191+
192+
// Read Provider meta into the meta model
193+
resp.Diagnostics.Append(req.ProviderMeta.Get(ctx, &metaData)...)
194+
if resp.Diagnostics.HasError() {
195+
return
196+
}
197+
198+
// Read Terraform configuration data into the model
199+
resp.Diagnostics.Append(req.Config.Get(ctx, &data)...)
200+
if resp.Diagnostics.HasError() {
201+
return
202+
}
203+
204+
// Copy all values from the provider config into this data source
205+
206+
data.Credentials = d.providerConfig.Credentials
207+
// TODO(SarahFrench) - access_token
208+
// TODO(SarahFrench) - impersonate_service_account
209+
// TODO(SarahFrench) - impersonate_service_account_delegates
210+
data.Project = d.providerConfig.Project
211+
data.Region = d.providerConfig.Region
212+
data.BillingProject = d.providerConfig.BillingProject
213+
data.Zone = d.providerConfig.Zone
214+
data.UniverseDomain = d.providerConfig.UniverseDomain
215+
data.Scopes = d.providerConfig.Scopes
216+
data.UserProjectOverride = d.providerConfig.UserProjectOverride
217+
// TODO(SarahFrench) - request_reason
218+
// TODO(SarahFrench) - request_timeout
219+
data.DefaultLabels = d.providerConfig.DefaultLabels
220+
// TODO(SarahFrench) - add_terraform_attribution_label
221+
// TODO(SarahFrench) - terraform_attribution_label_addition_strategy
222+
223+
// Warn users against using this data source
224+
resp.Diagnostics.Append(diag.NewWarningDiagnostic(
225+
"Data source google_provider_config_plugin_framework should not be used",
226+
"Data source google_provider_config_plugin_framework is intended to be used only in acceptance tests for the provider. Instead, please use the google_client_config data source to access provider configuration details, or open a GitHub issue requesting new features in that datasource. Please go to: https://github.com/hashicorp/terraform-provider-google/issues/new/choose",
227+
))
228+
229+
// Save data into Terraform state
230+
resp.Diagnostics.Append(resp.State.Set(ctx, &data)...)
231+
}

0 commit comments

Comments
 (0)