diff --git a/internal/provider/resource_self_signed_cert.go b/internal/provider/resource_self_signed_cert.go index 7c975c0c4..70171eb02 100644 --- a/internal/provider/resource_self_signed_cert.go +++ b/internal/provider/resource_self_signed_cert.go @@ -16,6 +16,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/tfsdk" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-log/tflog" + "github.com/hashicorp/terraform-provider-tls/internal/provider/attribute_plan_modifier" ) @@ -235,6 +236,7 @@ func (r *selfSignedCertResource) GetSchema(_ context.Context) (tfsdk.Schema, dia "organization": { Type: types.StringType, Optional: true, + Computed: true, PlanModifiers: []tfsdk.AttributePlanModifier{ resource.RequiresReplace(), }, @@ -243,16 +245,18 @@ func (r *selfSignedCertResource) GetSchema(_ context.Context) (tfsdk.Schema, dia "common_name": { Type: types.StringType, Optional: true, + Computed: true, PlanModifiers: []tfsdk.AttributePlanModifier{ - resource.RequiresReplace(), + attribute_plan_modifier.RequiresReplaceNullEmpty(), }, Description: "Distinguished name: `CN`", }, "organizational_unit": { Type: types.StringType, Optional: true, + Computed: true, PlanModifiers: []tfsdk.AttributePlanModifier{ - resource.RequiresReplace(), + attribute_plan_modifier.RequiresReplaceNullEmpty(), }, Description: "Distinguished name: `OU`", }, @@ -261,48 +265,54 @@ func (r *selfSignedCertResource) GetSchema(_ context.Context) (tfsdk.Schema, dia ElemType: types.StringType, }, Optional: true, + Computed: true, PlanModifiers: []tfsdk.AttributePlanModifier{ - resource.RequiresReplace(), + attribute_plan_modifier.RequiresReplaceNullEmpty(), }, Description: "Distinguished name: `STREET`", }, "locality": { Type: types.StringType, Optional: true, + Computed: true, PlanModifiers: []tfsdk.AttributePlanModifier{ - resource.RequiresReplace(), + attribute_plan_modifier.RequiresReplaceNullEmpty(), }, Description: "Distinguished name: `L`", }, "province": { Type: types.StringType, Optional: true, + Computed: true, PlanModifiers: []tfsdk.AttributePlanModifier{ - resource.RequiresReplace(), + attribute_plan_modifier.RequiresReplaceNullEmpty(), }, Description: "Distinguished name: `ST`", }, "country": { Type: types.StringType, Optional: true, + Computed: true, PlanModifiers: []tfsdk.AttributePlanModifier{ - resource.RequiresReplace(), + attribute_plan_modifier.RequiresReplaceNullEmpty(), }, Description: "Distinguished name: `C`", }, "postal_code": { Type: types.StringType, Optional: true, + Computed: true, PlanModifiers: []tfsdk.AttributePlanModifier{ - resource.RequiresReplace(), + attribute_plan_modifier.RequiresReplaceNullEmpty(), }, Description: "Distinguished name: `PC`", }, "serial_number": { Type: types.StringType, Optional: true, + Computed: true, PlanModifiers: []tfsdk.AttributePlanModifier{ - resource.RequiresReplace(), + attribute_plan_modifier.RequiresReplaceNullEmpty(), }, Description: "Distinguished name: `SERIALNUMBER`", }, diff --git a/internal/provider/resource_self_signed_cert_test.go b/internal/provider/resource_self_signed_cert_test.go index 721307bdf..035f1366f 100644 --- a/internal/provider/resource_self_signed_cert_test.go +++ b/internal/provider/resource_self_signed_cert_test.go @@ -11,6 +11,7 @@ import ( "time" r "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-tls/internal/provider/fixtures" tu "github.com/hashicorp/terraform-provider-tls/internal/provider/testutils" @@ -192,6 +193,51 @@ func TestAccResourceSelfSignedCert_UpgradeFromVersion3_4_0(t *testing.T) { }) } +func TestAccResourceSelfSignedCert_UpgradeFromVersion3_4_0_Preserve_Empty_Strings(t *testing.T) { + var id1, id2 string + + config := `resource "tls_private_key" "example" { + algorithm = "ECDSA" +} + +resource "tls_self_signed_cert" "example" { + private_key_pem = tls_private_key.example.private_key_pem + is_ca_certificate = true + + subject { + organization = "Example" + } + + # 3 Years + validity_period_hours = 24 * 365 * 3 + + allowed_uses = [ + "cert_signing", + "crl_signing", + ] +}` + + r.Test(t, r.TestCase{ + Steps: []r.TestStep{ + { + ExternalProviders: providerVersion340(), + Config: config, + Check: r.ComposeTestCheckFunc( + testExtractResourceAttr("tls_self_signed_cert.example", "id", &id1), + ), + }, + { + ProtoV5ProviderFactories: protoV5ProviderFactories(), + Config: config, + Check: r.ComposeTestCheckFunc( + testExtractResourceAttr("tls_self_signed_cert.example", "id", &id2), + testCheckAttributeValuesEqual(&id1, &id2), + ), + }, + }, + }) +} + func TestResourceSelfSignedCert_DetectExpiringAndExpired(t *testing.T) { oldNow := overridableTimeFunc r.UnitTest(t, r.TestCase{ @@ -753,3 +799,13 @@ func TestResourceSelfSignedCert_NoSubject(t *testing.T) { }, }) } + +func testCheckAttributeValuesEqual(i *string, j *string) r.TestCheckFunc { + return func(s *terraform.State) error { + if testStringValue(i) != testStringValue(j) { + return fmt.Errorf("attribute values are different, got %s and %s", testStringValue(i), testStringValue(j)) + } + + return nil + } +}