diff --git a/.changelog/11903.txt b/.changelog/11903.txt new file mode 100644 index 00000000000..ffb56a5f718 --- /dev/null +++ b/.changelog/11903.txt @@ -0,0 +1,3 @@ +```release-note:note +provider: refactored how the provider configuration is handled internally +``` \ No newline at end of file diff --git a/google/acctest/framework_test_utils.go b/google/acctest/framework_test_utils.go deleted file mode 100644 index 3bd578ab48e..00000000000 --- a/google/acctest/framework_test_utils.go +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 -package acctest - -import ( - "context" - "log" - "testing" - - "github.com/hashicorp/terraform-plugin-framework/diag" -) - -func GetFwTestProvider(t *testing.T) *frameworkTestProvider { - configsLock.RLock() - fwProvider, ok := fwProviders[t.Name()] - configsLock.RUnlock() - if ok { - return fwProvider - } - - var diags diag.Diagnostics - p := NewFrameworkTestProvider(t.Name()) - configureApiClient(context.Background(), &p.FrameworkProvider, &diags) - if diags.HasError() { - log.Fatalf("%d errors when configuring test provider client: first is %s", diags.ErrorsCount(), diags.Errors()[0].Detail()) - } - - return p -} diff --git a/google/acctest/provider_test_utils.go b/google/acctest/provider_test_utils.go index 58b4d07baae..421c37ce025 100644 --- a/google/acctest/provider_test_utils.go +++ b/google/acctest/provider_test_utils.go @@ -22,7 +22,6 @@ var testAccProvider *schema.Provider func init() { configs = make(map[string]*transport_tpg.Config) - fwProviders = make(map[string]*frameworkTestProvider) sources = make(map[string]VcrSource) testAccProvider = provider.Provider() TestAccProviders = map[string]*schema.Provider{ diff --git a/google/acctest/test_utils.go b/google/acctest/test_utils.go index 239443dfb0c..dd15b7c9f46 100644 --- a/google/acctest/test_utils.go +++ b/google/acctest/test_utils.go @@ -82,9 +82,13 @@ func CheckDataSourceStateMatchesResourceStateWithIgnores(dataSourceName, resourc func MuxedProviders(testName string) (func() tfprotov5.ProviderServer, error) { ctx := context.Background() + // primary is the SDKv2 implementation of the provider + // If tests are run in VCR mode, the provider will use a cached config specific to the test name + primary := GetSDKProvider(testName) + providers := []func() tfprotov5.ProviderServer{ - providerserver.NewProtocol5(NewFrameworkTestProvider(testName)), // framework provider - GetSDKProvider(testName).GRPCProvider, // sdk provider + primary.GRPCProvider, // sdk provider + providerserver.NewProtocol5(NewFrameworkTestProvider(testName, primary)), // framework provider } muxServer, err := tf5muxserver.NewMuxServer(ctx, providers...) diff --git a/google/acctest/vcr_utils.go b/google/acctest/vcr_utils.go index 17687bc118c..89d06422cac 100644 --- a/google/acctest/vcr_utils.go +++ b/google/acctest/vcr_utils.go @@ -23,7 +23,6 @@ import ( "testing" "time" - "github.com/hashicorp/terraform-provider-google/google/fwmodels" "github.com/hashicorp/terraform-provider-google/google/fwprovider" tpgprovider "github.com/hashicorp/terraform-provider-google/google/provider" "github.com/hashicorp/terraform-provider-google/google/tpgresource" @@ -32,12 +31,9 @@ import ( "github.com/dnaeon/go-vcr/cassette" "github.com/dnaeon/go-vcr/recorder" - "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/datasource" - fwDiags "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/provider" - "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-go/tfprotov5" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -55,7 +51,6 @@ var configsLock = sync.RWMutex{} var sourcesLock = sync.RWMutex{} var configs map[string]*transport_tpg.Config -var fwProviders map[string]*frameworkTestProvider var sources map[string]VcrSource @@ -205,39 +200,6 @@ func closeRecorder(t *testing.T) { delete(sources, t.Name()) sourcesLock.Unlock() } - - configsLock.RLock() - fwProvider, fwOk := fwProviders[t.Name()] - configsLock.RUnlock() - if fwOk { - // We did not cache the config if it does not use VCR - if !t.Failed() && IsVcrEnabled() { - // If a test succeeds, write new seed/yaml to files - err := fwProvider.Client.Transport.(*recorder.Recorder).Stop() - if err != nil { - t.Error(err) - } - envPath := os.Getenv("VCR_PATH") - - sourcesLock.RLock() - vcrSource, ok := sources[t.Name()] - sourcesLock.RUnlock() - if ok { - err = writeSeedToFile(vcrSource.seed, vcrSeedFile(envPath, t.Name())) - if err != nil { - t.Error(err) - } - } - } - // Clean up test config - configsLock.Lock() - delete(fwProviders, t.Name()) - configsLock.Unlock() - - sourcesLock.Lock() - delete(sources, t.Name()) - sourcesLock.Unlock() - } } func isReleaseDiffEnabled() bool { @@ -321,6 +283,11 @@ func reformConfigWithProvider(config, provider string) string { return string(resourceHeader.ReplaceAll(configBytes, providerReplacementBytes)) } +// HandleVCRConfiguration configures the recorder (github.com/dnaeon/go-vcr/recorder) used in the VCR test +// This includes: +// - Setting the recording/replaying mode +// - Determining the path to the file API interactions will be recorded to/read from +// - Determining the logic used to match requests against recorded HTTP interactions (see rec.SetMatcher) func HandleVCRConfiguration(ctx context.Context, testName string, rndTripper http.RoundTripper, pollInterval time.Duration) (time.Duration, http.RoundTripper, fwDiags.Diagnostics) { var diags fwDiags.Diagnostics var vcrMode recorder.Mode @@ -404,18 +371,18 @@ func NewVcrMatcherFunc(ctx context.Context) func(r *http.Request, i cassette.Req // test versions of the provider that will call the same configure function, only append the VCR // configuration to it. -func NewFrameworkTestProvider(testName string) *frameworkTestProvider { +func NewFrameworkTestProvider(testName string, primary *schema.Provider) *frameworkTestProvider { return &frameworkTestProvider{ FrameworkProvider: fwprovider.FrameworkProvider{ Version: "test", + Primary: primary, }, TestName: testName, } } -// frameworkTestProvider is a test version of the plugin-framework version of the provider -// that embeds FrameworkProvider whose configure function we can use -// the Configure function is overwritten in the framework_provider_test file +// frameworkTestProvider is a test version of the plugin-framework version of the provider. +// This facilitates overwriting the Configure function that's used during acceptance tests. type frameworkTestProvider struct { fwprovider.FrameworkProvider TestName string @@ -423,26 +390,13 @@ type frameworkTestProvider struct { // Configure is here to overwrite the FrameworkProvider configure function for VCR testing func (p *frameworkTestProvider) Configure(ctx context.Context, req provider.ConfigureRequest, resp *provider.ConfigureResponse) { - p.FrameworkProvider.Configure(ctx, req, resp) - if IsVcrEnabled() { - if resp.Diagnostics.HasError() { - return - } - - var diags fwDiags.Diagnostics - p.PollInterval, p.Client.Transport, diags = HandleVCRConfiguration(ctx, p.TestName, p.Client.Transport, p.PollInterval) - if diags.HasError() { - resp.Diagnostics.Append(diags...) - return - } - configsLock.Lock() - fwProviders[p.TestName] = p - configsLock.Unlock() - return - } else { - tflog.Debug(ctx, "VCR_PATH or VCR_MODE not set, skipping VCR") - } + // When creating the frameworkTestProvider struct we took in a pointer to the the SDK provider. + // That SDK provider was configured using `GetSDKProvider` and `getCachedConfig`, so this framework provider will also + // use a cached client for the correct test name. + // No extra logic is required here, but in future when the SDK provider is removed this function will + // need to be updated with logic similar to that in `GetSDKProvider`. + p.FrameworkProvider.Configure(ctx, req, resp) } // 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. @@ -453,21 +407,9 @@ func (p *frameworkTestProvider) DataSources(ctx context.Context) []func() dataso return ds } -func configureApiClient(ctx context.Context, p *fwprovider.FrameworkProvider, diags *fwDiags.Diagnostics) { - var data fwmodels.ProviderModel - var d fwDiags.Diagnostics - - // Set defaults if needed - the only attribute without a default is ImpersonateServiceAccountDelegates - // this is a bit of a hack, but we'll just initialize it here so that it's been initialized at least - data.ImpersonateServiceAccountDelegates, d = types.ListValue(types.StringType, []attr.Value{}) - diags.Append(d...) - if diags.HasError() { - return - } - p.LoadAndValidateFramework(ctx, &data, "test", diags, p.Version) -} - -// GetSDKProvider gets the SDK provider with an overwritten configure function to be called by MuxedProviders +// GetSDKProvider gets the SDK provider for use in acceptance tests +// If VCR is in use, the configure function is overwritten. +// See usage in MuxedProviders func GetSDKProvider(testName string) *schema.Provider { prov := tpgprovider.Provider() diff --git a/google/fwprovider/data_source_provider_config_plugin_framework.go b/google/fwprovider/data_source_provider_config_plugin_framework.go index ff499b7f43a..121ae06f17d 100644 --- a/google/fwprovider/data_source_provider_config_plugin_framework.go +++ b/google/fwprovider/data_source_provider_config_plugin_framework.go @@ -6,13 +6,14 @@ import ( "context" "fmt" + "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/datasource/schema" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-provider-google/google/fwmodels" "github.com/hashicorp/terraform-provider-google/google/fwresource" - "github.com/hashicorp/terraform-provider-google/google/fwtransport" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) // Ensure the data source satisfies the expected interfaces. @@ -27,15 +28,17 @@ func NewGoogleProviderConfigPluginFrameworkDataSource() datasource.DataSource { } type GoogleProviderConfigPluginFrameworkDataSource struct { - providerConfig *fwtransport.FrameworkProviderConfig + providerConfig *transport_tpg.Config } +// GoogleProviderConfigPluginFrameworkModel describes the data source and matches the schema. Its fields match those in a Config struct (google/transport/config.go) but uses a different type system. +// - In the original Config struct old SDK/Go primitives types are used, e.g. `string` +// - Here in the GoogleProviderConfigPluginFrameworkModel struct we need to use the terraform-plugin-framework/types type system, e.g. `types.String` +// - This is needed because the PF type system is 'baked into' how we define schemas. The schema will expect a nullable type. +// - See terraform-plugin-framework/datasource/schema#StringAttribute's CustomType: https://pkg.go.dev/github.com/hashicorp/terraform-plugin-framework@v1.7.0/datasource/schema#StringAttribute +// - Due to the different type systems of Config versus GoogleProviderConfigPluginFrameworkModel struct, we need to convert from primitive types to terraform-plugin-framework/types when we populate +// GoogleProviderConfigPluginFrameworkModel structs with data in this data source's Read method. type GoogleProviderConfigPluginFrameworkModel struct { - // Currently this reflects the FrameworkProviderConfig struct and ProviderModel in google/fwmodels/provider_model.go - // which means it uses the plugin-framework type system where values can be explicitly Null or Unknown. - // - // As part of future muxing fixes/refactoring we'll change this struct to reflect structs used in the SDK code, and will move to - // using the SDK type system. Credentials types.String `tfsdk:"credentials"` AccessToken types.String `tfsdk:"access_token"` ImpersonateServiceAccount types.String `tfsdk:"impersonate_service_account"` @@ -55,12 +58,12 @@ type GoogleProviderConfigPluginFrameworkModel struct { TerraformAttributionLabelAdditionStrategy types.String `tfsdk:"terraform_attribution_label_addition_strategy"` } -func (m *GoogleProviderConfigPluginFrameworkModel) GetLocationDescription(providerConfig *fwtransport.FrameworkProviderConfig) fwresource.LocationDescription { +func (m *GoogleProviderConfigPluginFrameworkModel) GetLocationDescription(providerConfig *transport_tpg.Config) fwresource.LocationDescription { return fwresource.LocationDescription{ RegionSchemaField: types.StringValue("region"), ZoneSchemaField: types.StringValue("zone"), - ProviderRegion: providerConfig.Region, - ProviderZone: providerConfig.Zone, + ProviderRegion: types.StringValue(providerConfig.Region), + ProviderZone: types.StringValue(providerConfig.Zone), } } @@ -174,11 +177,11 @@ func (d *GoogleProviderConfigPluginFrameworkDataSource) Configure(ctx context.Co return } - p, ok := req.ProviderData.(*fwtransport.FrameworkProviderConfig) + p, ok := req.ProviderData.(*transport_tpg.Config) if !ok { resp.Diagnostics.AddError( "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected *fwtransport.FrameworkProviderConfig, got: %T. Please report this issue to the provider developers.", req.ProviderData), + fmt.Sprintf("Expected *transport_tpg.Config, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return } @@ -204,23 +207,54 @@ func (d *GoogleProviderConfigPluginFrameworkDataSource) Read(ctx context.Context } // Copy all values from the provider config into this data source + // - The 'meta' from the provider configuration process uses Go primitive types (e.g. `string`) but this data source needs to use the plugin-framework type system due to being PF-implemented + // - As a result we have to make conversions between type systems in the value assignments below + data.Credentials = types.StringValue(d.providerConfig.Credentials) + data.AccessToken = types.StringValue(d.providerConfig.AccessToken) + data.ImpersonateServiceAccount = types.StringValue(d.providerConfig.ImpersonateServiceAccount) - data.Credentials = d.providerConfig.Credentials - data.AccessToken = d.providerConfig.AccessToken - data.ImpersonateServiceAccount = d.providerConfig.ImpersonateServiceAccount - data.ImpersonateServiceAccountDelegates = d.providerConfig.ImpersonateServiceAccountDelegates - data.Project = d.providerConfig.Project - data.Region = d.providerConfig.Region - data.BillingProject = d.providerConfig.BillingProject - data.Zone = d.providerConfig.Zone - data.UniverseDomain = d.providerConfig.UniverseDomain - data.Scopes = d.providerConfig.Scopes - data.UserProjectOverride = d.providerConfig.UserProjectOverride - data.RequestReason = d.providerConfig.RequestReason - data.RequestTimeout = d.providerConfig.RequestTimeout - data.DefaultLabels = d.providerConfig.DefaultLabels - data.AddTerraformAttributionLabel = d.providerConfig.AddTerraformAttributionLabel - data.TerraformAttributionLabelAdditionStrategy = d.providerConfig.TerraformAttributionLabelAdditionStrategy + delegateAttrs := make([]attr.Value, len(d.providerConfig.ImpersonateServiceAccountDelegates)) + for i, delegate := range d.providerConfig.ImpersonateServiceAccountDelegates { + delegateAttrs[i] = types.StringValue(delegate) + } + delegates, di := types.ListValue(types.StringType, delegateAttrs) + if di.HasError() { + resp.Diagnostics.Append(di...) + } + data.ImpersonateServiceAccountDelegates = delegates + + data.Project = types.StringValue(d.providerConfig.Project) + data.Region = types.StringValue(d.providerConfig.Region) + data.BillingProject = types.StringValue(d.providerConfig.BillingProject) + data.Zone = types.StringValue(d.providerConfig.Zone) + data.UniverseDomain = types.StringValue(d.providerConfig.UniverseDomain) + + scopeAttrs := make([]attr.Value, len(d.providerConfig.Scopes)) + for i, scope := range d.providerConfig.Scopes { + scopeAttrs[i] = types.StringValue(scope) + } + scopes, di := types.ListValue(types.StringType, scopeAttrs) + if di.HasError() { + resp.Diagnostics.Append(di...) + } + data.Scopes = scopes + + data.UserProjectOverride = types.BoolValue(d.providerConfig.UserProjectOverride) + data.RequestReason = types.StringValue(d.providerConfig.RequestReason) + data.RequestTimeout = types.StringValue(d.providerConfig.RequestTimeout.String()) + + lbs := make(map[string]attr.Value, len(d.providerConfig.DefaultLabels)) + for k, v := range d.providerConfig.DefaultLabels { + lbs[k] = types.StringValue(v) + } + labels, di := types.MapValueFrom(ctx, types.StringType, lbs) + if di.HasError() { + resp.Diagnostics.Append(di...) + } + data.DefaultLabels = labels + + data.AddTerraformAttributionLabel = types.BoolValue(d.providerConfig.AddTerraformAttributionLabel) + data.TerraformAttributionLabelAdditionStrategy = types.StringValue(d.providerConfig.TerraformAttributionLabelAdditionStrategy) // Warn users against using this data source resp.Diagnostics.Append(diag.NewWarningDiagnostic( diff --git a/google/fwprovider/framework_provider.go b/google/fwprovider/framework_provider.go index cbe1ff7f3f4..37f0d914906 100644 --- a/google/fwprovider/framework_provider.go +++ b/google/fwprovider/framework_provider.go @@ -5,6 +5,8 @@ package fwprovider import ( "context" + sdk_schema "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/datasource" "github.com/hashicorp/terraform-plugin-framework/function" @@ -18,7 +20,6 @@ import ( "github.com/hashicorp/terraform-provider-google/google/functions" "github.com/hashicorp/terraform-provider-google/google/fwmodels" - "github.com/hashicorp/terraform-provider-google/google/fwtransport" "github.com/hashicorp/terraform-provider-google/google/services/resourcemanager" "github.com/hashicorp/terraform-provider-google/version" @@ -33,16 +34,17 @@ var ( ) // New is a helper function to simplify provider server and testing implementation. -func New() provider.ProviderWithMetaSchema { +func New(primary *sdk_schema.Provider) provider.ProviderWithMetaSchema { return &FrameworkProvider{ Version: version.ProviderVersion, + Primary: primary, } } // FrameworkProvider is the provider implementation. type FrameworkProvider struct { - fwtransport.FrameworkProviderConfig Version string + Primary *sdk_schema.Provider } // Metadata returns @@ -65,6 +67,9 @@ func (p *FrameworkProvider) MetaSchema(_ context.Context, _ provider.MetaSchemaR } // Schema defines the provider-level schema for configuration data. +// See: https://developer.hashicorp.com/terraform/plugin/framework/migrating/mux +// "The schema and configuration handling must exactly match between all underlying providers of the mux server" +// This schema matches the schema implemented with SDKv2 in google/provider/provider.go func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest, resp *provider.SchemaResponse) { resp.Schema = schema.Schema{ Attributes: map[string]schema.Attribute{ @@ -130,6 +135,10 @@ func (p *FrameworkProvider) Schema(_ context.Context, _ provider.SchemaRequest, }, "request_timeout": schema.StringAttribute{ Optional: true, + Validators: []validator.String{ + NonEmptyStringValidator(), + NonNegativeDurationValidator(), + }, }, "request_reason": schema.StringAttribute{ Optional: true, @@ -1011,15 +1020,18 @@ func (p *FrameworkProvider) Configure(ctx context.Context, req provider.Configur } // Configuration values are now available. - p.LoadAndValidateFramework(ctx, &data, req.TerraformVersion, &resp.Diagnostics, p.Version) - if resp.Diagnostics.HasError() { - return - } + // However we don't use them; for the plugin-framework implementation of the provider + // we take the configuration values from the SDK implementation of the provider. This avoids duplicated logic and inconsistencies in implementation. + // The trade off is that we don't benefit from the new type system that differentiates Null and Unknown values, which is especially useful for strings. + // This makes it necessary to write code that stops empty strings (etc) being passed from the Config struct to PF-implemented resources/datasources. + // E.g. GetProjectFramework treats Null and "" the same way : https://github.com/hashicorp/terraform-provider-google/blob/74c815ee4ad059453e06b84448af244d80490ec1/google/fwresource/field_helpers.go#L21-L36 + // See also, new approaches to handle this: https://github.com/GoogleCloudPlatform/magic-modules/pull/11925 // This is how we make provider configuration info (configured clients, default project, etc) available to resources and data sources // implemented using the plugin-framework. The resources' Configure functions receive this data in the ConfigureRequest argument. - resp.DataSourceData = &p.FrameworkProviderConfig - resp.ResourceData = &p.FrameworkProviderConfig + meta := p.Primary.Meta().(*transport_tpg.Config) + resp.DataSourceData = meta + resp.ResourceData = meta } // DataSources defines the data sources implemented in the provider. diff --git a/google/fwprovider/framework_provider_access_token_test.go b/google/fwprovider/framework_provider_access_token_test.go index 04200767b21..e1f955b4d5e 100644 --- a/google/fwprovider/framework_provider_access_token_test.go +++ b/google/fwprovider/framework_provider_access_token_test.go @@ -184,7 +184,7 @@ credentials = "%s" Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "access_token", accessToken), // not set as ENV not used - resource.TestCheckNoResourceAttr("data.google_provider_config_plugin_framework.default", "credentials"), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "credentials", ""), ), }, { @@ -197,7 +197,7 @@ credentials = "%s" Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("data.google_provider_config_sdk.default", "credentials", credentials), // not set, as ENV not used - resource.TestCheckNoResourceAttr("data.google_provider_config_sdk.default", "access_token"), + resource.TestCheckResourceAttr("data.google_provider_config_sdk.default", "access_token", ""), ), ExpectError: regexp.MustCompile("JSON credentials are not valid"), }, diff --git a/google/fwprovider/framework_provider_add_terraform_attribution_label_test.go b/google/fwprovider/framework_provider_add_terraform_attribution_label_test.go index 5996a24e97c..97629d7f9ff 100644 --- a/google/fwprovider/framework_provider_add_terraform_attribution_label_test.go +++ b/google/fwprovider/framework_provider_add_terraform_attribution_label_test.go @@ -15,8 +15,8 @@ import ( func TestAccFwProvider_add_terraform_attribution_label(t *testing.T) { testCases := map[string]func(t *testing.T){ // Configuring the provider using inputs - "when add_terraform_attribution_label is set in the config, the value is set in the provider meta data": testAccFwProvider_add_terraform_attribution_label_configUsed, - "when add_terraform_attribution_label is unset in the config, the default value 'true' is NOT set on the provider meta data": testAccFwProvider_add_terraform_attribution_label_defaultValue, + "when add_terraform_attribution_label is set in the config, the value is set in the provider meta data": testAccFwProvider_add_terraform_attribution_label_configUsed, + "when add_terraform_attribution_label is unset in the config, the default value 'true' is set on the provider meta data": testAccFwProvider_add_terraform_attribution_label_defaultValue, } for name, tc := range testCases { @@ -73,7 +73,7 @@ func testAccFwProvider_add_terraform_attribution_label_defaultValue(t *testing.T { Config: testAccFwProvider_add_terraform_attribution_label_inEnvsOnly(context), Check: resource.ComposeTestCheckFunc( - resource.TestCheckNoResourceAttr("data.google_provider_config_plugin_framework.default", "add_terraform_attribution_label"), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "add_terraform_attribution_label", "true"), ), }, }, diff --git a/google/fwprovider/framework_provider_billing_project_test.go b/google/fwprovider/framework_provider_billing_project_test.go index 189bbe10fb8..f2e4c946cda 100644 --- a/google/fwprovider/framework_provider_billing_project_test.go +++ b/google/fwprovider/framework_provider_billing_project_test.go @@ -102,7 +102,7 @@ func testAccFwProvider_billing_project_precedenceOrderEnvironmentVariables(t *te }, Config: testAccFwProvider_billing_project_inEnvsOnly(context), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckNoResourceAttr("data.google_provider_config_plugin_framework.default", "billing_project"), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "billing_project", ""), ), }, }, diff --git a/google/fwprovider/framework_provider_internal_test.go b/google/fwprovider/framework_provider_internal_test.go index 0de5c495451..d843aa5bc0a 100644 --- a/google/fwprovider/framework_provider_internal_test.go +++ b/google/fwprovider/framework_provider_internal_test.go @@ -7,8 +7,11 @@ import ( "github.com/hashicorp/terraform-plugin-framework/provider" "github.com/hashicorp/terraform-provider-google/google/fwprovider" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" ) func TestFrameworkProvider_impl(t *testing.T) { - var _ provider.ProviderWithMetaSchema = fwprovider.New() + primary := &schema.Provider{} + var _ provider.ProviderWithMetaSchema = fwprovider.New(primary) } diff --git a/google/fwprovider/framework_provider_project_test.go b/google/fwprovider/framework_provider_project_test.go index e7e4e04f859..1ce1bc1358c 100644 --- a/google/fwprovider/framework_provider_project_test.go +++ b/google/fwprovider/framework_provider_project_test.go @@ -89,9 +89,7 @@ func testAccFwProvider_project_precedenceOrderEnvironmentVariables(t *testing.T) }, Config: testAccFwProvider_projectInEnvsOnly(), Check: resource.ComposeTestCheckFunc( - // Differing behavior between SDK and PF; the attribute is NOT found here. - // This reflects the different type systems used in the SDKv2 and the plugin-framework - resource.TestCheckNoResourceAttr("data.google_provider_config_plugin_framework.default", "project"), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "project", ""), ), }, { diff --git a/google/fwprovider/framework_provider_request_reason_test.go b/google/fwprovider/framework_provider_request_reason_test.go index e0e096a446e..a31d253c37b 100644 --- a/google/fwprovider/framework_provider_request_reason_test.go +++ b/google/fwprovider/framework_provider_request_reason_test.go @@ -20,7 +20,7 @@ func TestAccFwProvider_request_reason(t *testing.T) { // Schema-level validation // TODO: https://github.com/hashicorp/terraform-provider-google/issues/19643 - "when request_reason is set to an empty string in the config the value is not ignored, and there isn't any validation about this that raises an error": testAccFwProvider_request_reason_emptyStringValidation, + "when request_reason is set to an empty string in the config the value IS ignored, allowing environment values to be used": testAccFwProvider_request_reason_emptyStringValidation, // Usage // We cannot test the impact of this field in an acc test, as it sets the X-Goog-Request-Reason value for audit logging purposes in GCP @@ -118,7 +118,7 @@ func testAccFwProvider_request_reason_emptyStringValidation(t *testing.T) { Check: resource.ComposeAggregateTestCheckFunc( // Currently the PF provider uses empty strings, instead of providing validation feedback to users // See: https://github.com/hashicorp/terraform-provider-google/issues/19643 - resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "request_reason", emptyString), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "request_reason", envReason), ), }, }, diff --git a/google/fwprovider/framework_provider_request_timeout_test.go b/google/fwprovider/framework_provider_request_timeout_test.go index dbdb1438b81..84ca57abd61 100644 --- a/google/fwprovider/framework_provider_request_timeout_test.go +++ b/google/fwprovider/framework_provider_request_timeout_test.go @@ -16,8 +16,8 @@ import ( func TestAccFwProvider_request_timeout(t *testing.T) { testCases := map[string]func(t *testing.T){ // Configuring the provider using inputs - "a default value of 120s is used when there are no user inputs": testAccFwProvider_request_timeout_providerDefault, - "request_timeout can be set in config in different formats, are NOT normalized to full-length format": testAccFwProvider_request_timeout_setInConfig, + "a default value of 0s is used when there are no user inputs": testAccFwProvider_request_timeout_providerDefault, + "request_timeout can be set in config in different formats, are normalized to full-length format": testAccFwProvider_request_timeout_setInConfig, //no ENVs to test // Schema-level validation @@ -42,7 +42,7 @@ func TestAccFwProvider_request_timeout(t *testing.T) { func testAccFwProvider_request_timeout_providerDefault(t *testing.T) { acctest.SkipIfVcr(t) // Test doesn't interact with API - defaultValue := "120s" + defaultValue := "0s" acctest.VcrTest(t, resource.TestCase{ // No PreCheck for checking ENVs @@ -64,9 +64,8 @@ func testAccFwProvider_request_timeout_setInConfig(t *testing.T) { providerTimeout1 := "3m0s" providerTimeout2 := "3m" - // In the SDK version of the test expectedValue = "3m0s" only - expectedValue1 := "3m0s" - expectedValue2 := "3m" + // All inputs are normalised to this + expectedValue := "3m0s" context1 := map[string]interface{}{ "request_timeout": providerTimeout1, @@ -82,13 +81,13 @@ func testAccFwProvider_request_timeout_setInConfig(t *testing.T) { { Config: testAccFwProvider_request_timeout_inProviderBlock(context1), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "request_timeout", expectedValue1), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "request_timeout", expectedValue), ), }, { Config: testAccFwProvider_request_timeout_inProviderBlock(context2), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "request_timeout", expectedValue2), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "request_timeout", expectedValue), ), }, }, diff --git a/google/fwprovider/framework_provider_terraform_attribution_label_addition_strategy_test.go b/google/fwprovider/framework_provider_terraform_attribution_label_addition_strategy_test.go index 266d5e2b034..26df6388d01 100644 --- a/google/fwprovider/framework_provider_terraform_attribution_label_addition_strategy_test.go +++ b/google/fwprovider/framework_provider_terraform_attribution_label_addition_strategy_test.go @@ -15,8 +15,8 @@ import ( func TestAccFwProvider_terraform_attribution_label_addition_strategy(t *testing.T) { testCases := map[string]func(t *testing.T){ // Configuring the provider using inputs - "config sets terraform_attribution_label_addition_strategy values": testAccFwProvider_terraform_attribution_label_addition_strategy_configUsed, - "when terraform_attribution_label_addition_strategy is unset in the config, the default value'CREATION_ONLY' is NOT set in the provider meta data": testAccFwProvider_terraform_attribution_label_addition_strategy_defaultValue, + "config sets terraform_attribution_label_addition_strategy values": testAccFwProvider_terraform_attribution_label_addition_strategy_configUsed, + "when terraform_attribution_label_addition_strategy is unset in the config, the default value 'CREATION_ONLY' is set in the provider meta data": testAccFwProvider_terraform_attribution_label_addition_strategy_defaultValue, } for name, tc := range testCases { @@ -73,7 +73,7 @@ func testAccFwProvider_terraform_attribution_label_addition_strategy_defaultValu { Config: testAccFwProvider_terraform_attribution_label_addition_strategy_inEnvsOnly(context), Check: resource.ComposeTestCheckFunc( - resource.TestCheckNoResourceAttr("data.google_provider_config_plugin_framework.default", "terraform_attribution_label_addition_strategy"), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "terraform_attribution_label_addition_strategy", "CREATION_ONLY"), ), }, }, diff --git a/google/fwprovider/framework_provider_test.go b/google/fwprovider/framework_provider_test.go index 1ac18e88bc7..b3f654576c4 100644 --- a/google/fwprovider/framework_provider_test.go +++ b/google/fwprovider/framework_provider_test.go @@ -13,14 +13,11 @@ import ( "github.com/hashicorp/terraform-provider-google/google/acctest" "github.com/hashicorp/terraform-provider-google/google/fwresource" - "github.com/hashicorp/terraform-provider-google/google/fwtransport" "github.com/hashicorp/terraform-provider-google/google/tpgresource" transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) func TestAccFrameworkProviderMeta_setModuleName(t *testing.T) { - // TODO: https://github.com/hashicorp/terraform-provider-google/issues/14158 - acctest.SkipIfVcr(t) t.Parallel() moduleName := "my-module" @@ -65,47 +62,23 @@ func TestAccFrameworkProviderBasePath_setInvalidBasePath(t *testing.T) { } func TestAccFrameworkProviderBasePath_setBasePath(t *testing.T) { - // TODO: https://github.com/hashicorp/terraform-provider-google/issues/14158 - acctest.SkipIfVcr(t) t.Parallel() acctest.VcrTest(t, resource.TestCase{ - PreCheck: func() { acctest.AccTestPreCheck(t) }, - CheckDestroy: testAccCheckDNSManagedZoneDestroyProducerFramework(t), + PreCheck: func() { acctest.AccTestPreCheck(t) }, + CheckDestroy: testAccCheckDNSManagedZoneDestroyProducerFramework(t), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), Steps: []resource.TestStep{ { - ExternalProviders: map[string]resource.ExternalProvider{ - "google": { - VersionConstraint: "4.58.0", - Source: "hashicorp/google", - }, - }, Config: testAccFrameworkProviderBasePath_setBasePath("https://www.googleapis.com/dns/v1beta2/", acctest.RandString(t, 10)), }, { - ExternalProviders: map[string]resource.ExternalProvider{ - "google": { - VersionConstraint: "4.58.0", - Source: "hashicorp/google", - }, - }, ResourceName: "google_dns_managed_zone.foo", ImportState: true, ImportStateVerify: true, }, { - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - Config: testAccFrameworkProviderBasePath_setBasePath("https://www.googleapis.com/dns/v1beta2/", acctest.RandString(t, 10)), - }, - { - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - ResourceName: "google_dns_managed_zone.foo", - ImportState: true, - ImportStateVerify: true, - }, - { - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t), - Config: testAccFrameworkProviderBasePath_setBasePathstep3("https://www.googleapis.com/dns/v1beta2/", acctest.RandString(t, 10)), + Config: testAccFrameworkProviderBasePath_setBasePathstep3("https://www.googleapis.com/dns/v1beta2/", acctest.RandString(t, 10)), }, }, }) @@ -222,21 +195,28 @@ func testAccCheckDNSManagedZoneDestroyProducerFramework(t *testing.T) func(s *te continue } - p := acctest.GetFwTestProvider(t) + config := acctest.GoogleProviderConfig(t) - url, err := fwresource.ReplaceVarsForFrameworkTest(&p.FrameworkProvider.FrameworkProviderConfig, rs, "{{DNSBasePath}}projects/{{project}}/managedZones/{{name}}") + url, err := fwresource.ReplaceVarsForFrameworkTest(config, rs, "{{DNSBasePath}}projects/{{project}}/managedZones/{{name}}") if err != nil { return err } billingProject := "" - if !p.BillingProject.IsNull() && p.BillingProject.String() != "" { - billingProject = p.BillingProject.String() + if config.BillingProject != "" { + billingProject = config.BillingProject } - _, diags := fwtransport.SendFrameworkRequest(&p.FrameworkProvider.FrameworkProviderConfig, "GET", billingProject, url, p.UserAgent, nil) - if !diags.HasError() { + _, err = transport_tpg.SendRequest(transport_tpg.SendRequestOptions{ + Config: config, + Method: "GET", + Project: billingProject, + RawURL: url, + UserAgent: config.UserAgent, + }) + + if err == nil { return fmt.Errorf("DNSManagedZone still exists at %s", url) } } diff --git a/google/fwprovider/framework_provider_user_project_override_test.go b/google/fwprovider/framework_provider_user_project_override_test.go index 8a6add00588..bb37525b00e 100644 --- a/google/fwprovider/framework_provider_user_project_override_test.go +++ b/google/fwprovider/framework_provider_user_project_override_test.go @@ -88,7 +88,7 @@ func testAccFwProvider_user_project_override_precedenceOrderEnvironmentVariables }, Config: testAccFwProvider_user_project_overrideInEnvsOnly(context), Check: resource.ComposeAggregateTestCheckFunc( - resource.TestCheckNoResourceAttr("data.google_provider_config_plugin_framework.default", "user_project_override"), + resource.TestCheckResourceAttr("data.google_provider_config_plugin_framework.default", "user_project_override", "false"), ), }, { diff --git a/google/fwprovider/framework_validators_test.go b/google/fwprovider/framework_validators_test.go index b2dc7b7aa3b..ce387d6f2ac 100644 --- a/google/fwprovider/framework_validators_test.go +++ b/google/fwprovider/framework_validators_test.go @@ -67,3 +67,55 @@ func TestFrameworkProvider_CredentialsValidator(t *testing.T) { }) } } + +func TestFrameworkProvider_NonNegativeDurationValidator(t *testing.T) { + cases := map[string]struct { + ConfigValue types.String + ExpectedWarningCount int + ExpectedErrorCount int + }{ + "3m is a valid, non-negative duration": { + ConfigValue: types.StringValue("3m"), + }, + "3m0s is a valid, non-negative duration": { + ConfigValue: types.StringValue("3m0s"), + }, + "0s is a valid, non-negative duration": { + ConfigValue: types.StringValue("0s"), + }, + "-0s not valid, as it is a negative duration": { + ConfigValue: types.StringValue("-0s"), + ExpectedErrorCount: 1, + }, + "empty strings are not valid, non-negative durations": { + ConfigValue: types.StringValue(""), + ExpectedErrorCount: 1, + }, + } + + for tn, tc := range cases { + t.Run(tn, func(t *testing.T) { + // Arrange + req := validator.StringRequest{ + ConfigValue: tc.ConfigValue, + } + + resp := validator.StringResponse{ + Diagnostics: diag.Diagnostics{}, + } + + cv := fwprovider.NonNegativeDurationValidator() + + // Act + cv.ValidateString(context.Background(), req, &resp) + + // Assert + if resp.Diagnostics.WarningsCount() > tc.ExpectedWarningCount { + t.Errorf("Expected %d warnings, got %d", tc.ExpectedWarningCount, resp.Diagnostics.WarningsCount()) + } + if resp.Diagnostics.ErrorsCount() > tc.ExpectedErrorCount { + t.Errorf("Expected %d errors, got %d", tc.ExpectedErrorCount, resp.Diagnostics.ErrorsCount()) + } + }) + } +} diff --git a/google/fwresource/field_helpers.go b/google/fwresource/field_helpers.go index 78e015085a7..cec64fdf5e5 100644 --- a/google/fwresource/field_helpers.go +++ b/google/fwresource/field_helpers.go @@ -11,8 +11,8 @@ import ( "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-testing/terraform" - "github.com/hashicorp/terraform-provider-google/google/fwtransport" "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) // GetProject reads the "project" field from the given resource and falls @@ -71,7 +71,7 @@ func ParseProjectFieldValueFramework(resourceType, fieldValue, projectSchemaFiel // This function isn't a test of transport.go; instead, it is used as an alternative // to ReplaceVars inside tests. -func ReplaceVarsForFrameworkTest(prov *fwtransport.FrameworkProviderConfig, rs *terraform.ResourceState, linkTmpl string) (string, error) { +func ReplaceVarsForFrameworkTest(prov *transport_tpg.Config, rs *terraform.ResourceState, linkTmpl string) (string, error) { re := regexp.MustCompile("{{([[:word:]]+)}}") var project, region, zone string diff --git a/google/fwresource/framework_location.go b/google/fwresource/framework_location.go index 893511a9df6..cb349e1ac3a 100644 --- a/google/fwresource/framework_location.go +++ b/google/fwresource/framework_location.go @@ -7,12 +7,12 @@ import ( "fmt" "github.com/hashicorp/terraform-plugin-framework/types" - "github.com/hashicorp/terraform-provider-google/google/fwtransport" "github.com/hashicorp/terraform-provider-google/google/tpgresource" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) type LocationDescriber interface { - GetLocationDescription(providerConfig *fwtransport.FrameworkProviderConfig) LocationDescription + GetLocationDescription(providerConfig *transport_tpg.Config) LocationDescription } type LocationDescription struct { diff --git a/google/provider/provider.go b/google/provider/provider.go index 40837b77341..4ceeccd0795 100644 --- a/google/provider/provider.go +++ b/google/provider/provider.go @@ -31,6 +31,9 @@ func Provider() *schema.Provider { } provider := &schema.Provider{ + // See: https://developer.hashicorp.com/terraform/plugin/framework/migrating/mux + // "The schema and configuration handling must exactly match between all underlying providers of the mux server" + // This schema matches the schema implemented with the plugin-framework in google/fwprovider/framework_provider.go Schema: map[string]*schema.Schema{ "credentials": { Type: schema.TypeString, diff --git a/google/provider/provider_request_timeout_test.go b/google/provider/provider_request_timeout_test.go index f10edc8f5da..9e403e57676 100644 --- a/google/provider/provider_request_timeout_test.go +++ b/google/provider/provider_request_timeout_test.go @@ -64,6 +64,8 @@ func testAccSdkProvider_request_timeout_setInConfig(t *testing.T) { providerTimeout1 := "3m0s" providerTimeout2 := "3m" + + // All inputs are normalised to this expectedValue := "3m0s" context1 := map[string]interface{}{ diff --git a/google/services/resourcemanager/data_source_google_client_config.go b/google/services/resourcemanager/data_source_google_client_config.go index 2149f6a4959..c77408b9903 100644 --- a/google/services/resourcemanager/data_source_google_client_config.go +++ b/google/services/resourcemanager/data_source_google_client_config.go @@ -11,7 +11,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-provider-google/google/fwmodels" "github.com/hashicorp/terraform-provider-google/google/fwresource" - "github.com/hashicorp/terraform-provider-google/google/fwtransport" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) // Ensure the data source satisfies the expected interfaces. @@ -26,7 +26,7 @@ func NewGoogleClientConfigDataSource() datasource.DataSource { } type GoogleClientConfigDataSource struct { - providerConfig *fwtransport.FrameworkProviderConfig + providerConfig *transport_tpg.Config } type GoogleClientConfigModel struct { @@ -40,14 +40,14 @@ type GoogleClientConfigModel struct { DefaultLabels types.Map `tfsdk:"default_labels"` } -func (m *GoogleClientConfigModel) GetLocationDescription(providerConfig *fwtransport.FrameworkProviderConfig) fwresource.LocationDescription { +func (m *GoogleClientConfigModel) GetLocationDescription(providerConfig *transport_tpg.Config) fwresource.LocationDescription { return fwresource.LocationDescription{ RegionSchemaField: types.StringValue("region"), ZoneSchemaField: types.StringValue("zone"), ResourceRegion: m.Region, ResourceZone: m.Zone, - ProviderRegion: providerConfig.Region, - ProviderZone: providerConfig.Zone, + ProviderRegion: types.StringValue(providerConfig.Region), + ProviderZone: types.StringValue(providerConfig.Zone), } } @@ -104,11 +104,11 @@ func (d *GoogleClientConfigDataSource) Configure(ctx context.Context, req dataso return } - p, ok := req.ProviderData.(*fwtransport.FrameworkProviderConfig) + p, ok := req.ProviderData.(*transport_tpg.Config) if !ok { resp.Diagnostics.AddError( "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected *fwtransport.FrameworkProviderConfig, got: %T. Please report this issue to the provider developers.", req.ProviderData), + fmt.Sprintf("Expected *transport_tpg.Config, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return } @@ -137,11 +137,25 @@ func (d *GoogleClientConfigDataSource) Read(ctx context.Context, req datasource. region, _ := locationInfo.GetRegion() zone, _ := locationInfo.GetZone() - data.Id = types.StringValue(fmt.Sprintf("projects/%s/regions/%s/zones/%s", d.providerConfig.Project.String(), region.String(), zone.String())) - data.Project = d.providerConfig.Project + data.Id = types.StringValue(fmt.Sprintf("projects/%s/regions/%s/zones/%s", d.providerConfig.Project, region.String(), zone.String())) + data.Project = types.StringValue(d.providerConfig.Project) data.Region = region data.Zone = zone - data.DefaultLabels = d.providerConfig.DefaultLabels + + // Convert default labels from SDK type system to plugin-framework data type + m := map[string]*string{} + for k, v := range d.providerConfig.DefaultLabels { + // m[k] = types.StringValue(v) + val := v + m[k] = &val + } + dls, diags := types.MapValueFrom(ctx, types.StringType, m) + resp.Diagnostics.Append(diags...) + if resp.Diagnostics.HasError() { + return + } + + data.DefaultLabels = dls token, err := d.providerConfig.TokenSource.Token() if err != nil { diff --git a/google/services/resourcemanager/data_source_google_client_openid_userinfo.go b/google/services/resourcemanager/data_source_google_client_openid_userinfo.go index 9ab4a5b7d73..d1f8e624aec 100644 --- a/google/services/resourcemanager/data_source_google_client_openid_userinfo.go +++ b/google/services/resourcemanager/data_source_google_client_openid_userinfo.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-provider-google/google/fwmodels" "github.com/hashicorp/terraform-provider-google/google/fwtransport" + transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport" ) // Ensure the data source satisfies the expected interfaces. @@ -25,7 +26,7 @@ func NewGoogleClientOpenIDUserinfoDataSource() datasource.DataSource { } type GoogleClientOpenIDUserinfoDataSource struct { - providerConfig *fwtransport.FrameworkProviderConfig + providerConfig *transport_tpg.Config } type GoogleClientOpenIDUserinfoModel struct { @@ -70,11 +71,11 @@ func (d *GoogleClientOpenIDUserinfoDataSource) Configure(ctx context.Context, re return } - p, ok := req.ProviderData.(*fwtransport.FrameworkProviderConfig) + p, ok := req.ProviderData.(*transport_tpg.Config) if !ok { resp.Diagnostics.AddError( "Unexpected Data Source Configure Type", - fmt.Sprintf("Expected *fwtransport.FrameworkProviderConfig, got: %T. Please report this issue to the provider developers.", req.ProviderData), + fmt.Sprintf("Expected *transport_tpg.Config, got: %T. Please report this issue to the provider developers.", req.ProviderData), ) return } @@ -101,8 +102,11 @@ func (d *GoogleClientOpenIDUserinfoDataSource) Read(ctx context.Context, req dat } userAgent := fwtransport.GenerateFrameworkUserAgentString(metaData, d.providerConfig.UserAgent) - email := fwtransport.GetCurrentUserEmailFramework(d.providerConfig, userAgent, &diags) - + email, err := transport_tpg.GetCurrentUserEmail(d.providerConfig, userAgent) + if err != nil { + diags.AddError("error retrieving userinfo for your provider credentials", err.Error()) + return + } data.Email = types.StringValue(email) data.Id = types.StringValue(email) diff --git a/google/transport/config.go b/google/transport/config.go index 8c0329fd8cf..9dba6e3ddc4 100644 --- a/google/transport/config.go +++ b/google/transport/config.go @@ -186,7 +186,7 @@ type Config struct { UserAgent string gRPCLoggingOptions []option.ClientOption - tokenSource oauth2.TokenSource + TokenSource oauth2.TokenSource AccessApprovalBasePath string AccessContextManagerBasePath string @@ -1410,7 +1410,7 @@ func (c *Config) LoadAndValidate(ctx context.Context) error { return err } - c.tokenSource = tokenSource + c.TokenSource = tokenSource cleanCtx := context.WithValue(ctx, oauth2.HTTPClient, cleanhttp.DefaultClient()) @@ -2036,7 +2036,7 @@ func (c *Config) NewCloudIdentityClient(userAgent string) *cloudidentity.Service func (c *Config) BigTableClientFactory(userAgent string) *BigtableClientFactory { bigtableClientFactory := &BigtableClientFactory{ UserAgent: userAgent, - TokenSource: c.tokenSource, + TokenSource: c.TokenSource, gRPCLoggingOptions: c.gRPCLoggingOptions, BillingProject: c.BillingProject, UserProjectOverride: c.UserProjectOverride, diff --git a/main.go b/main.go index fd0d9ce0d6d..f90ea3f0761 100644 --- a/main.go +++ b/main.go @@ -22,10 +22,12 @@ func main() { flag.BoolVar(&debug, "debug", false, "set to true to run the provider with support for debuggers like delve") flag.Parse() - // concat with sdkv2 provider + // primary is the SDKv2 implementation of the provider + primary := provider.Provider() + providers := []func() tfprotov5.ProviderServer{ - providerserver.NewProtocol5(fwprovider.New()), // framework provider - provider.Provider().GRPCProvider, // sdk provider + primary.GRPCProvider, // sdk provider + providerserver.NewProtocol5(fwprovider.New(primary)), // framework provider } // use the muxer