Skip to content

Commit 239c36e

Browse files
fix(secretmanager): specify the project ID and secret name in the secretmanager (#15397) (hashicorp#11015)
[upstream:9222c7bd6e479d7c1b7baa12ad5e2dc579705883] Signed-off-by: Modular Magician <magic-modules@google.com>
1 parent 056474d commit 239c36e

8 files changed

+179
-27
lines changed

.changelog/15397.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
```release-note:enhancement
2+
secretmanager: added project and short name support for secret on `ephemeral_google_secret_manager_secret_version`
3+
```
4+
5+
```release-note:enhancement
6+
secretmanager: added project and short name support for secret on `google_secret_manager_secret_version`
7+
```

google-beta/services/secretmanager/ephemeral_google_secret_manager_secret_version.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"context"
2121
"encoding/base64"
2222
"fmt"
23+
"strings"
2324

2425
"github.com/hashicorp/terraform-plugin-framework/ephemeral"
2526
"github.com/hashicorp/terraform-plugin-framework/ephemeral/schema"
@@ -142,12 +143,20 @@ func (p *googleEphemeralSecretManagerSecretVersion) Open(ctx context.Context, re
142143
}
143144

144145
var url string
146+
versionID := "latest"
145147
if version != "" {
146-
url = fmt.Sprintf("%s%s/versions/%s", config.SecretManagerBasePath, secret, version)
147-
} else {
148-
url = fmt.Sprintf("%s%s/versions/latest", config.SecretManagerBasePath, secret)
148+
versionID = version
149149
}
150150

151+
// The secret can be given as a full resource name or just the secret id.
152+
fullSecretName := secret
153+
if !strings.Contains(secret, "/") {
154+
// If no slash is present, assume it's a secret id and construct the full resource name.
155+
fullSecretName = fmt.Sprintf("projects/%s/secrets/%s", project, secret)
156+
}
157+
158+
url = fmt.Sprintf("%s%s/versions/%s", config.SecretManagerBasePath, fullSecretName, versionID)
159+
151160
versionResp, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
152161
Config: config,
153162
Method: "GET",

google-beta/services/secretmanager/ephemeral_google_secret_manager_secret_version_test.go

Lines changed: 50 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ func TestAccEphemeralSecretManagerSecretVersion_basic(t *testing.T) {
4040
Config: testAccEphemeralSecretManagerSecretVersion_basic(secret, secretData),
4141
Check: resource.ComposeTestCheckFunc(
4242
resource.TestCheckResourceAttr("data.google_secret_manager_secret_version.default", "secret_data", secretData),
43+
resource.TestCheckResourceAttr("data.google_secret_manager_secret_version.from_secret_id", "secret_data", secretData),
4344
),
4445
},
4546
},
@@ -62,6 +63,8 @@ func TestAccEphemeralSecretManagerSecretVersion_base64(t *testing.T) {
6263
Check: resource.ComposeTestCheckFunc(
6364
resource.TestCheckResourceAttr("data.google_secret_manager_secret_version.default", "is_secret_data_base64", "true"),
6465
resource.TestCheckResourceAttr("data.google_secret_manager_secret_version.default", "secret_data", base64.StdEncoding.EncodeToString([]byte(secretData))),
66+
resource.TestCheckResourceAttr("data.google_secret_manager_secret_version.from_secret_id", "is_secret_data_base64", "true"),
67+
resource.TestCheckResourceAttr("data.google_secret_manager_secret_version.from_secret_id", "secret_data", base64.StdEncoding.EncodeToString([]byte(secretData))),
6568
),
6669
},
6770
},
@@ -84,20 +87,36 @@ resource "google_secret_manager_secret_version" "version" {
8487
}
8588
8689
ephemeral "google_secret_manager_secret_version" "ephemeral" {
87-
secret = google_secret_manager_secret_version.version.secret
90+
secret = google_secret_manager_secret.secret.id
8891
version = google_secret_manager_secret_version.version.version
8992
}
9093
9194
resource "google_secret_manager_secret_version" "version_two_based_on_ephemeral" {
92-
secret = google_secret_manager_secret_version.version.secret
93-
secret_data_wo = ephemeral.google_secret_manager_secret_version.ephemeral.secret_data
95+
secret = google_secret_manager_secret_version.version.secret
96+
secret_data_wo = ephemeral.google_secret_manager_secret_version.ephemeral.secret_data
9497
secret_data_wo_version = "1"
9598
}
9699
97100
data "google_secret_manager_secret_version" "default" {
98101
secret = google_secret_manager_secret_version.version_two_based_on_ephemeral.secret
99102
version = google_secret_manager_secret_version.version_two_based_on_ephemeral.version
100103
}
104+
105+
ephemeral "google_secret_manager_secret_version" "ephemeral_from_secret_id" {
106+
secret = google_secret_manager_secret.secret.secret_id
107+
version = google_secret_manager_secret_version.version.version
108+
}
109+
110+
resource "google_secret_manager_secret_version" "version_from_secret_id_ephemeral" {
111+
secret = google_secret_manager_secret_version.version.secret
112+
secret_data_wo = ephemeral.google_secret_manager_secret_version.ephemeral_from_secret_id.secret_data
113+
secret_data_wo_version = "2"
114+
}
115+
116+
data "google_secret_manager_secret_version" "from_secret_id" {
117+
secret = google_secret_manager_secret_version.version_from_secret_id_ephemeral.secret
118+
version = google_secret_manager_secret_version.version_from_secret_id_ephemeral.version
119+
}
101120
`, secret, secretData)
102121
}
103122

@@ -112,28 +131,47 @@ resource "google_secret_manager_secret" "secret" {
112131
}
113132
114133
resource "google_secret_manager_secret_version" "version" {
115-
secret = google_secret_manager_secret.secret.id
116-
secret_data = base64encode("%s")
117-
is_secret_data_base64 = true
134+
secret = google_secret_manager_secret.secret.id
135+
secret_data = base64encode("%s")
136+
is_secret_data_base64 = true
118137
}
119138
120139
ephemeral "google_secret_manager_secret_version" "ephemeral" {
121-
secret = google_secret_manager_secret_version.version.secret
122-
version = google_secret_manager_secret_version.version.version
140+
secret = google_secret_manager_secret.secret.id
141+
version = google_secret_manager_secret_version.version.version
123142
is_secret_data_base64 = true
124143
}
125144
126145
resource "google_secret_manager_secret_version" "version_two_based_on_ephemeral" {
127-
secret = google_secret_manager_secret_version.version.secret
128-
secret_data_wo = ephemeral.google_secret_manager_secret_version.ephemeral.secret_data
146+
secret = google_secret_manager_secret_version.version.secret
147+
secret_data_wo = ephemeral.google_secret_manager_secret_version.ephemeral.secret_data
129148
secret_data_wo_version = "1"
130149
is_secret_data_base64 = true
131150
}
132151
133152
data "google_secret_manager_secret_version" "default" {
134-
secret = google_secret_manager_secret_version.version_two_based_on_ephemeral.secret
135-
version = google_secret_manager_secret_version.version_two_based_on_ephemeral.version
153+
secret = google_secret_manager_secret_version.version_two_based_on_ephemeral.secret
154+
version = google_secret_manager_secret_version.version_two_based_on_ephemeral.version
155+
is_secret_data_base64 = true
156+
}
157+
158+
ephemeral "google_secret_manager_secret_version" "ephemeral_from_secret_id" {
159+
secret = google_secret_manager_secret.secret.secret_id
160+
version = google_secret_manager_secret_version.version.version
161+
is_secret_data_base64 = true
162+
}
163+
164+
resource "google_secret_manager_secret_version" "version_from_secret_id_ephemeral" {
165+
secret = google_secret_manager_secret_version.version.secret
166+
secret_data_wo = ephemeral.google_secret_manager_secret_version.ephemeral_from_secret_id.secret_data
167+
secret_data_wo_version = "2"
136168
is_secret_data_base64 = true
137169
}
170+
171+
data "google_secret_manager_secret_version" "from_secret_id" {
172+
secret = google_secret_manager_secret_version.version_from_secret_id_ephemeral.secret
173+
version = google_secret_manager_secret_version.version_from_secret_id_ephemeral.version
174+
is_secret_data_base64 = true
175+
}
138176
`, secret, secretData)
139177
}

google-beta/services/secretmanager/resource_secret_manager_secret_version.go

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,14 @@ func ResourceSecretManagerSecretVersion() *schema.Resource {
175175
Description: `The current state of the SecretVersion.`,
176176
Default: true,
177177
},
178+
"project": {
179+
Type: schema.TypeString,
180+
Computed: true,
181+
Optional: true,
182+
ForceNew: true,
183+
Description: `The ID of the project in which the resource belongs. If it is not provided,
184+
the provider project is used`,
185+
},
178186
"create_time": {
179187
Type: schema.TypeString,
180188
Computed: true,
@@ -253,6 +261,39 @@ func resourceSecretManagerSecretVersionCreate(d *schema.ResourceData, meta inter
253261
}
254262

255263
headers := make(http.Header)
264+
secret := d.Get("secret").(string)
265+
secretRegex := regexp.MustCompile("^(?:projects/([^/]+)/secrets/)?([^/]+)$")
266+
267+
parts := secretRegex.FindStringSubmatch(secret)
268+
if len(parts) != 2 && len(parts) != 3 {
269+
return fmt.Errorf("secret does not fit any of the expected formats `projects/{{project}}/secrets/{{secret}}` or `{{secret}}`. Got: %s", secret)
270+
}
271+
272+
// Add project ID to secret if only its name is provided
273+
if parts[1] == "" {
274+
project, err := tpgresource.GetProject(d, config)
275+
if err != nil {
276+
return fmt.Errorf("error fetching project for DomainTrust: %s", err)
277+
}
278+
279+
if err = d.Set("project", project); err != nil {
280+
return fmt.Errorf("error updating the project in state: %s", err)
281+
}
282+
283+
if err = d.Set("secret", fmt.Sprintf("projects/%s/secrets/%s", project, parts[2])); err != nil {
284+
return fmt.Errorf("error updating the secret with its project ID: %s", err)
285+
}
286+
287+
// Override the url after updating the secret
288+
url, err = tpgresource.ReplaceVars(d, config, "{{SecretManagerBasePath}}{{secret}}:addVersion")
289+
if err != nil {
290+
return err
291+
}
292+
} else if configProject, hasConfigProject := d.GetOk("project"); hasConfigProject {
293+
if configProject != parts[1] {
294+
return fmt.Errorf("project %s was supplied on the secret and %s supplied on the config, values conflict", parts[1], configProject)
295+
}
296+
}
256297
res, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
257298
Config: config,
258299
Method: "POST",

google-beta/services/secretmanager/resource_secret_manager_secret_version_generated_meta.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ fields:
1717
- field: 'is_secret_data_base64'
1818
provider_only: true
1919
- api_field: 'name'
20+
- field: 'project'
21+
provider_only: true
2022
- field: 'secret'
2123
provider_only: true
2224
- api_field: 'payload.data'

google-beta/services/secretmanager/resource_secret_manager_secret_version_generated_test.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func TestAccSecretManagerSecretVersion_secretVersionBasicExample(t *testing.T) {
6969
ResourceName: "google_secret_manager_secret_version.secret-version-basic",
7070
ImportState: true,
7171
ImportStateVerify: true,
72-
ImportStateVerifyIgnore: []string{"secret"},
72+
ImportStateVerifyIgnore: []string{"project", "secret"},
7373
},
7474
},
7575
})
@@ -117,7 +117,7 @@ func TestAccSecretManagerSecretVersion_secretVersionBasicWriteOnlyExample(t *tes
117117
ResourceName: "google_secret_manager_secret_version.secret-version-basic-write-only",
118118
ImportState: true,
119119
ImportStateVerify: true,
120-
ImportStateVerifyIgnore: []string{"secret"},
120+
ImportStateVerifyIgnore: []string{"project", "secret"},
121121
},
122122
},
123123
})
@@ -165,7 +165,7 @@ func TestAccSecretManagerSecretVersion_secretVersionDeletionPolicyAbandonExample
165165
ResourceName: "google_secret_manager_secret_version.secret-version-deletion-policy",
166166
ImportState: true,
167167
ImportStateVerify: true,
168-
ImportStateVerifyIgnore: []string{"deletion_policy", "secret"},
168+
ImportStateVerifyIgnore: []string{"deletion_policy", "project", "secret"},
169169
},
170170
},
171171
})
@@ -213,7 +213,7 @@ func TestAccSecretManagerSecretVersion_secretVersionDeletionPolicyDisableExample
213213
ResourceName: "google_secret_manager_secret_version.secret-version-deletion-policy",
214214
ImportState: true,
215215
ImportStateVerify: true,
216-
ImportStateVerifyIgnore: []string{"deletion_policy", "secret"},
216+
ImportStateVerifyIgnore: []string{"deletion_policy", "project", "secret"},
217217
},
218218
},
219219
})
@@ -262,7 +262,7 @@ func TestAccSecretManagerSecretVersion_secretVersionWithBase64StringSecretDataEx
262262
ResourceName: "google_secret_manager_secret_version.secret-version-base64",
263263
ImportState: true,
264264
ImportStateVerify: true,
265-
ImportStateVerifyIgnore: []string{"is_secret_data_base64", "secret"},
265+
ImportStateVerifyIgnore: []string{"is_secret_data_base64", "project", "secret"},
266266
},
267267
},
268268
})
@@ -311,7 +311,7 @@ func TestAccSecretManagerSecretVersion_secretVersionWithBase64StringSecretDataWr
311311
ResourceName: "google_secret_manager_secret_version.secret-version-base64-write-only",
312312
ImportState: true,
313313
ImportStateVerify: true,
314-
ImportStateVerifyIgnore: []string{"is_secret_data_base64", "secret"},
314+
ImportStateVerifyIgnore: []string{"is_secret_data_base64", "project", "secret"},
315315
},
316316
},
317317
})

google-beta/services/secretmanager/resource_secret_manager_secret_version_test.go

Lines changed: 56 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ func TestAccSecretManagerSecretVersion_update(t *testing.T) {
4242
ResourceName: "google_secret_manager_secret_version.secret-version-basic",
4343
ImportState: true,
4444
ImportStateVerify: true,
45-
ImportStateVerifyIgnore: []string{"secret_data", "secret_data_wo_version"},
45+
ImportStateVerifyIgnore: []string{"secret_data", "secret_data_wo_version", "project"},
4646
},
4747
{
4848
Config: testAccSecretManagerSecretVersion_disable(context),
@@ -53,16 +53,41 @@ func TestAccSecretManagerSecretVersion_update(t *testing.T) {
5353
ImportStateVerify: true,
5454
// at this point the secret data is disabled and so reading the data on import will
5555
// give an empty string
56-
ImportStateVerifyIgnore: []string{"secret_data", "secret_data_wo_version"},
56+
ImportStateVerifyIgnore: []string{"secret_data", "secret_data_wo_version", "project"},
5757
},
5858
{
59-
Config: testAccSecretManagerSecretVersion_basic(context),
59+
Config: testAccSecretManagerSecretVersion_byName(context),
60+
},
61+
{
62+
ResourceName: "google_secret_manager_secret_version.secret-version-basic",
63+
ImportState: true,
64+
ImportStateVerify: true,
65+
ImportStateVerifyIgnore: []string{"secret_data", "secret_data_wo_version", "project"},
66+
},
67+
},
68+
})
69+
}
70+
71+
func TestAccSecretManagerSecretVersion_byName(t *testing.T) {
72+
t.Parallel()
73+
74+
context := map[string]interface{}{
75+
"random_suffix": acctest.RandString(t, 10),
76+
}
77+
78+
acctest.VcrTest(t, resource.TestCase{
79+
PreCheck: func() { acctest.AccTestPreCheck(t) },
80+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
81+
CheckDestroy: testAccCheckSecretManagerSecretVersionDestroyProducer(t),
82+
Steps: []resource.TestStep{
83+
{
84+
Config: testAccSecretManagerSecretVersion_byName(context),
6085
},
6186
{
6287
ResourceName: "google_secret_manager_secret_version.secret-version-basic",
6388
ImportState: true,
6489
ImportStateVerify: true,
65-
ImportStateVerifyIgnore: []string{"secret_data", "secret_data_wo_version"},
90+
ImportStateVerifyIgnore: []string{"secret_data", "secret_data_wo_version", "project", "secret"},
6691
},
6792
},
6893
})
@@ -86,7 +111,7 @@ resource "google_secret_manager_secret_version" "secret-version-basic" {
86111
secret = google_secret_manager_secret.secret-basic.name
87112
88113
secret_data = "my-tf-test-secret%{random_suffix}"
89-
enabled = true
114+
enabled = true
90115
}
91116
`, context)
92117
}
@@ -109,7 +134,32 @@ resource "google_secret_manager_secret_version" "secret-version-basic" {
109134
secret = google_secret_manager_secret.secret-basic.name
110135
111136
secret_data = "my-tf-test-secret%{random_suffix}"
112-
enabled = false
137+
enabled = false
138+
}
139+
`, context)
140+
}
141+
142+
func testAccSecretManagerSecretVersion_byName(context map[string]interface{}) string {
143+
return acctest.Nprintf(`
144+
resource "google_secret_manager_secret" "secret-basic" {
145+
secret_id = "tf-test-secret-version-%{random_suffix}"
146+
147+
labels = {
148+
label = "my-label"
149+
}
150+
151+
replication {
152+
auto {}
153+
}
154+
}
155+
156+
resource "google_secret_manager_secret_version" "secret-version-basic" {
157+
secret = "tf-test-secret-version-%{random_suffix}"
158+
159+
secret_data = "my-tf-test-secret%{random_suffix}"
160+
enabled = true
161+
162+
depends_on = [google_secret_manager_secret.secret-basic]
113163
}
114164
`, context)
115165
}

website/docs/r/secret_manager_secret_version.html.markdown

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,11 @@ The following arguments are supported:
236236
(Optional)
237237
Triggers update of secret data write-only. For more info see [updating write-only attributes](/docs/providers/google/guides/using_write_only_attributes.html#updating-write-only-attributes)
238238

239+
* `project` -
240+
(Optional)
241+
The ID of the project in which the resource belongs. If it is not provided,
242+
the provider project is used
243+
239244
* `deletion_policy` - (Optional) The deletion policy for the secret version. Setting `ABANDON` allows the resource
240245
to be abandoned rather than deleted. Setting `DISABLE` allows the resource to be
241246
disabled rather than deleted. Default is `DELETE`. Possible values are:

0 commit comments

Comments
 (0)