diff --git a/.changelog/365.txt b/.changelog/365.txt new file mode 100644 index 00000000..15d518cc --- /dev/null +++ b/.changelog/365.txt @@ -0,0 +1,3 @@ +```release-note:bug +`resource/davinci_variable`: Fix "Value Conversion Error" when defining variables with unknown values. +``` diff --git a/internal/service/davinci/resource_variable.go b/internal/service/davinci/resource_variable.go index 3a5ef02a..eddbe3df 100644 --- a/internal/service/davinci/resource_variable.go +++ b/internal/service/davinci/resource_variable.go @@ -20,6 +20,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/pingidentity/terraform-provider-davinci/internal/framework" stringvalidatorinternal "github.com/pingidentity/terraform-provider-davinci/internal/framework/stringvalidator" "github.com/pingidentity/terraform-provider-davinci/internal/sdk" @@ -278,26 +279,30 @@ func (p *VariableResource) ModifyPlan(ctx context.Context, req resource.ModifyPl return } - var varValuePlan *string + var varValuePlan basetypes.StringValue resp.Diagnostics.Append(resp.Plan.GetAttribute(ctx, path.Root("value"), &varValuePlan)...) if resp.Diagnostics.HasError() { return } - var varEmptyValuePlan *bool + var varEmptyValuePlan basetypes.BoolValue resp.Diagnostics.Append(resp.Plan.GetAttribute(ctx, path.Root("empty_value"), &varEmptyValuePlan)...) if resp.Diagnostics.HasError() { return } - if varEmptyValuePlan != nil && *varEmptyValuePlan { + if !varEmptyValuePlan.IsNull() && !varEmptyValuePlan.IsUnknown() { resp.Plan.SetAttribute(ctx, path.Root("value_service"), types.StringNull()) } else { - if varValuePlan != nil { - resp.Plan.SetAttribute(ctx, path.Root("value_service"), types.StringValue(*varValuePlan)) + if !varValuePlan.IsNull() && !varValuePlan.IsUnknown() { + resp.Plan.SetAttribute(ctx, path.Root("value_service"), varValuePlan) } } + + if varEmptyValuePlan.IsUnknown() || varValuePlan.IsUnknown() { + resp.Plan.SetAttribute(ctx, path.Root("value_service"), types.StringUnknown()) + } } func (r *VariableResource) Configure(ctx context.Context, req resource.ConfigureRequest, resp *resource.ConfigureResponse) { diff --git a/internal/service/davinci/resource_variable_test.go b/internal/service/davinci/resource_variable_test.go index cf0c618d..c219a865 100644 --- a/internal/service/davinci/resource_variable_test.go +++ b/internal/service/davinci/resource_variable_test.go @@ -615,6 +615,50 @@ func testAccResourceVariable_Values(t *testing.T, context, variableName string) }) } +func TestAccResourceVariable_UnknownValue(t *testing.T) { + + resourceBase := "davinci_variable" + resourceName := acctest.ResourceNameGen() + resourceFullName := fmt.Sprintf("%s.%s", resourceBase, resourceName) + + name := resourceName + + withBootstrapConfig := false + + step1 := resource.TestStep{ + Config: testAccResourceVariable_UnknownValue1_Hcl(resourceName, name, withBootstrapConfig), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceFullName, "value", "testVariable##SK##company"), + resource.TestCheckNoResourceAttr(resourceFullName, "empty_value"), + resource.TestCheckResourceAttr(resourceFullName, "value_service", "testVariable##SK##company"), + ), + } + + step2 := resource.TestStep{ + Config: testAccResourceVariable_UnknownValue2_Hcl(resourceName, name, withBootstrapConfig), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceFullName, "value", "testVariable3##SK##company"), + resource.TestCheckNoResourceAttr(resourceFullName, "empty_value"), + resource.TestCheckResourceAttr(resourceFullName, "value_service", "testVariable3##SK##company"), + ), + } + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheckClient(t) + acctest.PreCheckNewEnvironment(t) + }, + ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories, + ExternalProviders: acctest.ExternalProviders, + ErrorCheck: acctest.ErrorCheck(t), + CheckDestroy: davinci.Variable_CheckDestroy(), + Steps: []resource.TestStep{ + step1, + step2, + }, + }) +} + func TestAccResourceVariable_BadParameters(t *testing.T) { resourceBase := "davinci_variable" @@ -845,6 +889,49 @@ resource "davinci_variable" "%[1]s-flow" { return hcl } +func testAccResourceVariable_UnknownValue1_Hcl(resourceName, name string, withBootstrapConfig bool) (hcl string) { + hcl = fmt.Sprintf(` +resource "davinci_variable" "%[1]s" { + environment_id = pingone_environment.%[1]s.id + + name = "testVariable2" + context = "company" + description = "testVariable2 description" + type = "string" + value = davinci_variable.%[1]s-company.id +} + +%s`, resourceName, testAccResourceVariable_StaticValue_Hcl(resourceName, name, withBootstrapConfig, "myVal123")) + + return +} + +func testAccResourceVariable_UnknownValue2_Hcl(resourceName, name string, withBootstrapConfig bool) (hcl string) { + hcl = fmt.Sprintf(` +resource "davinci_variable" "%[1]s" { + environment_id = pingone_environment.%[1]s.id + + name = "testVariable2" + context = "company" + description = "testVariable2 description" + type = "string" + value = davinci_variable.%[1]s-test.id +} + +resource "davinci_variable" "%[1]s-test" { + environment_id = pingone_environment.%[1]s.id + + name = "testVariable3" + context = "company" + description = "testVariable3 description" + type = "string" +} + +%s`, resourceName, testAccResourceVariable_StaticValue_Hcl(resourceName, name, withBootstrapConfig, "myVal123")) + + return +} + func testAccResourceVariable_EmptyValue_Hcl(resourceName, name string, withBootstrapConfig bool) (hcl string) { mainFlowJson, err := acctest.ReadFlowJsonFile("flows/full-basic-vars.json") if err != nil {