Skip to content

Commit

Permalink
Revert "Unignore empty values in the provider configuration block i…
Browse files Browse the repository at this point in the history
…n 5.0.0 (#9014)"

This reverts commit 83df041.
  • Loading branch information
SarahFrench authored Sep 22, 2023
1 parent 83df041 commit c3daef5
Show file tree
Hide file tree
Showing 6 changed files with 182 additions and 99 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,10 @@ func TestFrameworkProvider_CredentialsValidator(t *testing.T) {
return types.StringValue(stringContents)
},
},
"configuring credentials as an empty string is not valid": {
"configuring credentials as an empty string is valid": {
ConfigValue: func(t *testing.T) types.String {
return types.StringValue("")
},
ExpectedErrorCount: 1,
},
"leaving credentials unconfigured is valid": {
ConfigValue: func(t *testing.T) types.String {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"github.com/hashicorp/terraform-plugin-framework/types"

googleoauth "golang.org/x/oauth2/google"
)
Expand All @@ -30,7 +31,7 @@ func (v credentialsValidator) MarkdownDescription(ctx context.Context) string {

// ValidateString performs the validation.
func (v credentialsValidator) ValidateString(ctx context.Context, request validator.StringRequest, response *validator.StringResponse) {
if request.ConfigValue.IsNull() || request.ConfigValue.IsUnknown() {
if request.ConfigValue.IsNull() || request.ConfigValue.IsUnknown() || request.ConfigValue.Equal(types.StringValue("")) {
return
}

Expand Down
81 changes: 81 additions & 0 deletions mmv1/third_party/terraform/fwtransport/framework_config.go.erb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"google.golang.org/grpc"

"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-log/tflog"
Expand Down Expand Up @@ -55,6 +56,15 @@ type FrameworkProviderConfig struct {
// LoadAndValidateFramework handles the bulk of configuring the provider
// it is pulled out so that we can manually call this from our testing provider as well
func (p *FrameworkProviderConfig) LoadAndValidateFramework(ctx context.Context, data *fwmodels.ProviderModel, tfVersion string, diags *diag.Diagnostics, providerversion string) {


// Make the plugin framwork code behave like the SDK by ignoring zero values. This means re-setting zero values to null.
// This is added to fix https://github.com/hashicorp/terraform-provider-google/issues/14255 in a v4.x.x release
// TODO(SarahFrench) remove as part of https://github.com/hashicorp/terraform-provider-google/issues/14447 in 5.0.0
p.HandleZeroValues(ctx, data, diags)
if diags.HasError() {
return
}

// Set defaults if needed
p.HandleDefaults(ctx, data, diags)
Expand Down Expand Up @@ -105,6 +115,77 @@ func (p *FrameworkProviderConfig) LoadAndValidateFramework(ctx context.Context,
p.RequestBatcherIam = transport_tpg.NewRequestBatcher("IAM", ctx, batchingConfig)
}

// HandleZeroValues will make the plugin framework act like the SDK; zero value, particularly empty strings, are converted to null.
// This causes the plugin framework to treat the field as unset, just like how the SDK ignores empty strings.
func (p *FrameworkProviderConfig) HandleZeroValues(ctx context.Context, data *fwmodels.ProviderModel, diags *diag.Diagnostics) {

// Change empty strings to null values
if data.AccessToken.Equal(types.StringValue("")) {
data.AccessToken = types.StringNull()
}
if data.BillingProject.Equal(types.StringValue("")) {
data.BillingProject = types.StringNull()
}
if data.Credentials.Equal(types.StringValue("")) {
data.Credentials = types.StringNull()
}
if data.ImpersonateServiceAccount.Equal(types.StringValue("")) {
data.ImpersonateServiceAccount = types.StringNull()
}
if data.Project.Equal(types.StringValue("")) {
data.Project = types.StringNull()
}
if data.Region.Equal(types.StringValue("")) {
data.Region = types.StringNull()
}
if data.RequestReason.Equal(types.StringValue("")) {
data.RequestReason = types.StringNull()
}
if data.RequestTimeout.Equal(types.StringValue("")) {
data.RequestTimeout = types.StringNull()
}
if data.Zone.Equal(types.StringValue("")) {
data.Zone = types.StringNull()
}

// Change lists that aren't null or unknown with length of zero to null lists
if !data.Scopes.IsNull() && !data.Scopes.IsUnknown() && (len(data.Scopes.Elements()) == 0) {
data.Scopes = types.ListNull(types.StringType)
}
if !data.ImpersonateServiceAccountDelegates.IsNull() && !data.ImpersonateServiceAccountDelegates.IsUnknown() && (len(data.ImpersonateServiceAccountDelegates.Elements()) == 0) {
data.ImpersonateServiceAccountDelegates = types.ListNull(types.StringType)
}

// Batching implementation will change in future, but this code will be removed in 5.0.0 so may be unaffected
if !data.Batching.IsNull() && !data.Batching.IsUnknown() && (len(data.Batching.Elements()) > 0) {
var pbConfigs []fwmodels.ProviderBatching
d := data.Batching.ElementsAs(ctx, &pbConfigs, true)
diags.Append(d...)
if diags.HasError() {
return
}
if pbConfigs[0].SendAfter.Equal(types.StringValue("")) {
pbConfigs[0].SendAfter = types.StringNull() // Convert empty string to null
}
b, _ := types.ObjectValue(
map[string]attr.Type{
"enable_batching": types.BoolType,
"send_after": types.StringType,
},
map[string]attr.Value{
"enable_batching": pbConfigs[0].EnableBatching,
"send_after": pbConfigs[0].SendAfter,
},
)
newBatching, d := types.ListValue(types.ObjectType{}.WithAttributeTypes(fwmodels.ProviderBatchingAttributes), []attr.Value{b})
diags.Append(d...)
if diags.HasError() {
return
}
data.Batching = newBatching
}
}

// HandleDefaults will handle all the defaults necessary in the provider
func (p *FrameworkProviderConfig) HandleDefaults(ctx context.Context, data *fwmodels.ProviderModel, diags *diag.Diagnostics) {
if (data.AccessToken.IsNull() || data.AccessToken.IsUnknown()) && (data.Credentials.IsNull() || data.Credentials.IsUnknown()) {
Expand Down
Loading

0 comments on commit c3daef5

Please sign in to comment.