diff --git a/internal/provider/resource_password.go b/internal/provider/resource_password.go index c14a8f71..aa82c7de 100644 --- a/internal/provider/resource_password.go +++ b/internal/provider/resource_password.go @@ -11,10 +11,14 @@ import ( ) // resourcePassword and resourceString both use the same set of CustomizeDiffFunc(s) in order to handle the deprecation -// of the `number` attribute and the simultaneous addition of the `numeric` attribute. customDiffIfValue handles +// of the `number` attribute and the simultaneous addition of the `numeric` attribute. planDefaultIfAllNull handles // ensuring that both `number` and `numeric` default to `true` when they are both absent from config. -// customDiffIfValueChange handles keeping number and numeric in-sync when either one has been changed. +// planSyncIfChange handles keeping number and numeric in-sync when either one has been changed. func resourcePassword() *schema.Resource { + customizeDiffFuncs := planDefaultIfAllNull(true, "number", "numeric") + customizeDiffFuncs = append(customizeDiffFuncs, planSyncIfChange("number", "numeric")) + customizeDiffFuncs = append(customizeDiffFuncs, planSyncIfChange("numeric", "number")) + return &schema.Resource{ Description: "Identical to [random_string](string.html) with the exception that the result is " + "treated as sensitive and, thus, _not_ displayed in console output. Read more about sensitive " + @@ -42,10 +46,7 @@ func resourcePassword() *schema.Resource { }, }, CustomizeDiff: customdiff.All( - customDiffIfValue("number"), - customDiffIfValue("numeric"), - customDiffIfValueChange("number", "numeric"), - customDiffIfValueChange("numeric", "number"), + customizeDiffFuncs..., ), } } diff --git a/internal/provider/resource_string.go b/internal/provider/resource_string.go index b0962133..5749aeb0 100644 --- a/internal/provider/resource_string.go +++ b/internal/provider/resource_string.go @@ -9,10 +9,14 @@ import ( ) // resourceString and resourcePassword both use the same set of CustomizeDiffFunc(s) in order to handle the deprecation -// of the `number` attribute and the simultaneous addition of the `numeric` attribute. customDiffIfValue handles +// of the `number` attribute and the simultaneous addition of the `numeric` attribute. planDefaultIfAllNull handles // ensuring that both `number` and `numeric` default to `true` when they are both absent from config. -// customDiffIfValueChange handles keeping number and numeric in-sync when either one has been changed. +// planSyncIfChange handles keeping number and numeric in-sync when either one has been changed. func resourceString() *schema.Resource { + customizeDiffFuncs := planDefaultIfAllNull(true, "number", "numeric") + customizeDiffFuncs = append(customizeDiffFuncs, planSyncIfChange("number", "numeric")) + customizeDiffFuncs = append(customizeDiffFuncs, planSyncIfChange("numeric", "number")) + return &schema.Resource{ Description: "The resource `random_string` generates a random permutation of alphanumeric " + "characters and optionally special characters.\n" + @@ -41,10 +45,7 @@ func resourceString() *schema.Resource { }, }, CustomizeDiff: customdiff.All( - customDiffIfValue("number"), - customDiffIfValue("numeric"), - customDiffIfValueChange("number", "numeric"), - customDiffIfValueChange("numeric", "number"), + customizeDiffFuncs..., ), } } diff --git a/internal/provider/string.go b/internal/provider/string.go index 072b25a7..3e2eb863 100644 --- a/internal/provider/string.go +++ b/internal/provider/string.go @@ -6,6 +6,7 @@ package provider import ( "context" "crypto/rand" + "errors" "fmt" "math/big" "sort" @@ -340,36 +341,53 @@ func resourceStateUpgradeAddNumeric(resourceName string) func(_ context.Context, } } -// customDiffIfValue handles ensuring that both `number` and `numeric` attributes default to `true` when neither are set +// planDefaultIfAllNull handles ensuring that both `number` and `numeric` attributes default to `true` when neither are set // in the config and, they had been previously set to `false`. This behaviour mimics setting `Default: true` on the // attributes. Usage of `Default` is avoided as `Default` cannot be used with CustomizeDiffFunc(s) which are required in -// order to keep `number` and `numeric` in-sync (see customDiffIfValueChange). -func customDiffIfValue(key string) func(context.Context, *schema.ResourceDiff, interface{}) error { - return customdiff.IfValue( - key, - func(ctx context.Context, value, meta interface{}) bool { - return !value.(bool) - }, - func(_ context.Context, d *schema.ResourceDiff, _ interface{}) error { - vm := d.GetRawConfig().AsValueMap() - if vm["number"].IsNull() && vm["numeric"].IsNull() { - err := d.SetNew("number", true) - if err != nil { - return err +// order to keep `number` and `numeric` in-sync (see planSyncIfChange). +func planDefaultIfAllNull(defaultVal interface{}, keys ...string) []schema.CustomizeDiffFunc { + var result []schema.CustomizeDiffFunc + + for _, key := range keys { + result = append(result, customdiff.IfValue( + key, + func(ctx context.Context, value, meta interface{}) bool { + return !value.(bool) + }, + func(_ context.Context, d *schema.ResourceDiff, _ interface{}) error { + vm := d.GetRawConfig().AsValueMap() + + number, ok := vm["number"] + if !ok { + return errors.New("number is absent from raw config") } - err = d.SetNew("numeric", true) - if err != nil { - return err + + numeric, ok := vm["numeric"] + if !ok { + return errors.New("numeric is absent from raw config") } - } - return nil - }, - ) + + if number.IsNull() && numeric.IsNull() { + err := d.SetNew("number", defaultVal) + if err != nil { + return err + } + err = d.SetNew("numeric", defaultVal) + if err != nil { + return err + } + } + return nil + }, + )) + } + + return result } -// customDiffIfValueChange handles keeping `number` and `numeric` in-sync. If either is changed the value of both is +// planSyncIfChange handles keeping `number` and `numeric` in-sync. If either is changed the value of both is // set to the new value of the attribute that has changed. -func customDiffIfValueChange(key, keyToSync string) func(context.Context, *schema.ResourceDiff, interface{}) error { +func planSyncIfChange(key, keyToSync string) func(context.Context, *schema.ResourceDiff, interface{}) error { return customdiff.IfValueChange( key, func(ctx context.Context, oldValue, newValue, meta interface{}) bool {