Skip to content

Commit 3739a60

Browse files
authored
Add RequiresReplace attribute for secret_name in hvs secret resource (#1157)
* Add replacable attribute for secret_name in hvs secret resource * add changelog * Add unit tests * fix goimport * Add destroy * update changelog Please enter the commit message for your changes. Lines starting
1 parent 7204cba commit 3739a60

File tree

3 files changed

+72
-7
lines changed

3 files changed

+72
-7
lines changed

.changelog/1157.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:bug
2+
Fix a bug where updating an HVS secret name or app name would not recreate the resource as expected
3+
```

internal/provider/vaultsecrets/resource_vault_secrets_secret.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ func (r *resourceVaultsecretsSecret) Schema(_ context.Context, _ resource.Schema
6464
"must contain only ASCII letters, numbers, and hyphens; must not start or end with a hyphen",
6565
),
6666
},
67+
PlanModifiers: []planmodifier.String{
68+
stringplanmodifier.RequiresReplace(),
69+
},
6770
},
6871
"secret_name": schema.StringAttribute{
6972
Description: "The name of the secret",
@@ -76,6 +79,9 @@ func (r *resourceVaultsecretsSecret) Schema(_ context.Context, _ resource.Schema
7679
"must contain only ASCII letters, numbers, and underscores; must not start with a number",
7780
),
7881
},
82+
PlanModifiers: []planmodifier.String{
83+
stringplanmodifier.RequiresReplace(),
84+
},
7985
},
8086
"secret_value": schema.StringAttribute{
8187
Description: "The value of the secret",

internal/provider/vaultsecrets/resource_vault_secrets_secret_test.go

Lines changed: 63 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,57 @@ import (
77
"fmt"
88
"testing"
99

10+
"github.com/hashicorp/hcp-sdk-go/clients/cloud-vault-secrets/stable/2023-11-28/client/secret_service"
11+
"github.com/hashicorp/terraform-plugin-testing/terraform"
12+
"github.com/hashicorp/terraform-provider-hcp/internal/clients"
13+
1014
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
1115
"github.com/hashicorp/terraform-provider-hcp/internal/provider/acctest"
1216
)
1317

1418
func TestAccVaultSecretsResourceSecret(t *testing.T) {
1519
testAppName1 := generateRandomSlug()
1620
testAppName2 := generateRandomSlug()
21+
secretName1 := "acc_tests_secret_1"
22+
secretName2 := "acc_tests_secret_2"
1723
resource.Test(t, resource.TestCase{
1824
ProtoV6ProviderFactories: acctest.ProtoV6ProviderFactories,
1925
Steps: []resource.TestStep{
20-
26+
// Create secretName1 in testAppName1
2127
{
2228
PreConfig: func() {
2329
createTestApp(t, testAppName1)
2430
},
2531
Config: fmt.Sprintf(`
2632
resource "hcp_vault_secrets_secret" "example" {
2733
app_name = %q
28-
secret_name = "test_secret"
34+
secret_name = %q
35+
secret_value = "super secret"
36+
}`, testAppName1, secretName1),
37+
Check: resource.ComposeTestCheckFunc(
38+
resource.TestCheckResourceAttr("hcp_vault_secrets_secret.example", "app_name", testAppName1),
39+
resource.TestCheckResourceAttr("hcp_vault_secrets_secret.example", "secret_name", secretName1),
40+
resource.TestCheckResourceAttr("hcp_vault_secrets_secret.example", "secret_value", "super secret"),
41+
),
42+
},
43+
// Changing secret name should cause recreation.
44+
// Validate that secretName2 is created and secretName1 is destroyed.
45+
{
46+
Config: fmt.Sprintf(`
47+
resource "hcp_vault_secrets_secret" "example" {
48+
app_name = %q
49+
secret_name = %q
2950
secret_value = "super secret"
30-
}`, testAppName1),
51+
}`, testAppName1, secretName2),
3152
Check: resource.ComposeTestCheckFunc(
3253
resource.TestCheckResourceAttr("hcp_vault_secrets_secret.example", "app_name", testAppName1),
33-
resource.TestCheckResourceAttr("hcp_vault_secrets_secret.example", "secret_name", "test_secret"),
54+
resource.TestCheckResourceAttr("hcp_vault_secrets_secret.example", "secret_name", secretName2),
3455
resource.TestCheckResourceAttr("hcp_vault_secrets_secret.example", "secret_value", "super secret"),
56+
testAccCheckSecretExists(t, testAppName1, secretName1),
3557
),
3658
},
59+
// Changing app name should also cause secret recreation.
60+
// Validate secretName2 is created in testAppName2 and is destroyed in testAppName1
3761
{
3862
Config: fmt.Sprintf(`
3963
resource "hcp_project" "example" {
@@ -48,17 +72,49 @@ func TestAccVaultSecretsResourceSecret(t *testing.T) {
4872
4973
resource "hcp_vault_secrets_secret" "example" {
5074
app_name = hcp_vault_secrets_app.example.app_name
51-
secret_name = "test_secret"
75+
secret_name = %q
5276
secret_value = "super secret"
5377
project_id = hcp_project.example.resource_id
54-
}`, testAppName2),
78+
}`, testAppName2, secretName2),
5579
Check: resource.ComposeTestCheckFunc(
5680
resource.TestCheckResourceAttr("hcp_vault_secrets_secret.example", "app_name", testAppName2),
57-
resource.TestCheckResourceAttr("hcp_vault_secrets_secret.example", "secret_name", "test_secret"),
81+
resource.TestCheckResourceAttr("hcp_vault_secrets_secret.example", "secret_name", secretName2),
5882
resource.TestCheckResourceAttr("hcp_vault_secrets_secret.example", "secret_value", "super secret"),
5983
resource.TestCheckResourceAttrSet("hcp_vault_secrets_secret.example", "project_id"),
84+
testAccCheckSecretExists(t, testAppName1, secretName2),
6085
),
6186
},
6287
},
88+
CheckDestroy: func(s *terraform.State) error {
89+
deleteTestApp(t, testAppName1)
90+
return nil
91+
},
6392
})
6493
}
94+
95+
func testAccCheckSecretExists(t *testing.T, appName string, secretName string) resource.TestCheckFunc {
96+
return func(_ *terraform.State) error {
97+
if secretExists(t, appName, secretName) {
98+
return fmt.Errorf("test secret %s was not destroyed", secretName)
99+
}
100+
return nil
101+
}
102+
}
103+
104+
func secretExists(t *testing.T, appName string, secretName string) bool {
105+
t.Helper()
106+
107+
client := acctest.HCPClients(t)
108+
109+
response, err := client.VaultSecrets.GetAppSecret(
110+
secret_service.NewGetAppSecretParamsWithContext(ctx).
111+
WithOrganizationID(client.Config.OrganizationID).
112+
WithProjectID(client.Config.ProjectID).
113+
WithAppName(appName).
114+
WithSecretName(secretName), nil)
115+
if err != nil && !clients.IsResponseCodeNotFound(err) {
116+
t.Fatal(err)
117+
}
118+
119+
return !clients.IsResponseCodeNotFound(err) && response != nil && response.Payload != nil && response.Payload.Secret != nil
120+
}

0 commit comments

Comments
 (0)