Skip to content

Commit 3c20ea7

Browse files
committed
chore(secretmanager): Add global samples for delayed destroy
1 parent 1d1e869 commit 3c20ea7

File tree

4 files changed

+271
-0
lines changed

4 files changed

+271
-0
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2025 Google LLC
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
"""
16+
command line application and sample code for creating a new secret with
17+
delayed_destroy.
18+
"""
19+
20+
import argparse
21+
22+
from google.cloud import secretmanager
23+
24+
# [START secretmanager_create_secret_with_delayed_destroy]
25+
26+
27+
def create_secret_with_delayed_destroy(
28+
project_id: str,
29+
secret_id: str,
30+
version_destroy_ttl: int,
31+
) -> secretmanager.Secret:
32+
"""
33+
Create a new secret with the given name and version destroy ttl. A
34+
secret is a logical wrapper around a collection of secret versions.
35+
Secret versions hold the actual secret material.
36+
"""
37+
38+
# Import the Secret Manager client library.
39+
from google.cloud import secretmanager
40+
41+
# Import the Duration protobuf library.
42+
from google.protobuf.duration_pb2 import Duration
43+
44+
# Create the Secret Manager client.
45+
client = secretmanager.SecretManagerServiceClient()
46+
47+
# Build the resource name of the parent project.
48+
parent = f"projects/{project_id}"
49+
50+
# Create the secret.
51+
response = client.create_secret(
52+
request={
53+
"parent": parent,
54+
"secret_id": secret_id,
55+
"secret": {
56+
"replication": {"automatic": {}},
57+
"version_destroy_ttl": Duration(seconds=version_destroy_ttl),
58+
},
59+
}
60+
)
61+
62+
# Print the new secret name.
63+
print(f"Created secret: {response.name}")
64+
65+
return response
66+
67+
68+
# [END secretmanager_create_secret_with_delayed_destroy]
69+
70+
if __name__ == "__main__":
71+
parser = argparse.ArgumentParser(
72+
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
73+
)
74+
parser.add_argument("project_id", help="id of the GCP project")
75+
parser.add_argument("secret_id", help="id of the secret to create")
76+
parser.add_argument("version_destroy_ttl", help="version_destroy_ttl you want to add")
77+
args = parser.parse_args()
78+
79+
create_secret_with_delayed_destroy(args.project_id, args.secret_id, args.version_destroy_ttl)
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2025 Google LLC
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
16+
import argparse
17+
18+
from google.cloud import secretmanager
19+
20+
# [START secretmanager_disable_secret_with_delayed_destroy]
21+
22+
23+
def disable_secret_with_delayed_destroy(
24+
project_id: str, secret_id: str
25+
) -> secretmanager.Secret:
26+
"""
27+
Disable the version destroy ttl on the given secret version.
28+
"""
29+
30+
# Import the Secret Manager client library.
31+
from google.cloud import secretmanager
32+
33+
# Create the Secret Manager client.
34+
client = secretmanager.SecretManagerServiceClient()
35+
36+
# Build the resource name of the secret.
37+
name = client.secret_path(project_id, secret_id)
38+
39+
# Disable delayed destroy of the secret.
40+
secret = {"name": name}
41+
update_mask = {"paths": ["version_destroy_ttl"]}
42+
response = client.update_secret(request={"secret": secret, "update_mask": update_mask})
43+
44+
# Print the new secret name.
45+
print(f"Disabled delayed destroy on secret: {response.name}")
46+
# [END secretmanager_disable_secret_with_delayed_destroy]
47+
48+
return response
49+
50+
51+
if __name__ == "__main__":
52+
parser = argparse.ArgumentParser(
53+
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
54+
)
55+
parser.add_argument("project_id", help="id of the GCP project")
56+
parser.add_argument("secret_id", help="id of the secret from which to act")
57+
args = parser.parse_args()
58+
59+
disable_secret_with_delayed_destroy(
60+
args.project_id, args.secret_id
61+
)

secretmanager/snippets/snippets_test.py

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,24 @@
1212
# See the License for the specific language governing permissions and
1313

1414
import base64
15+
from datetime import timedelta
1516
import os
1617
import time
1718
from typing import Iterator, Optional, Tuple, Union
1819
import uuid
1920

2021
from google.api_core import exceptions, retry
2122
from google.cloud import secretmanager
23+
from google.protobuf.duration_pb2 import Duration
24+
2225
import pytest
2326

2427
from access_secret_version import access_secret_version
2528
from add_secret_version import add_secret_version
2629
from consume_event_notification import consume_event_notification
2730
from create_secret import create_secret
2831
from create_secret_with_annotations import create_secret_with_annotations
32+
from create_secret_with_delayed_destroy import create_secret_with_delayed_destroy
2933
from create_secret_with_labels import create_secret_with_labels
3034
from create_secret_with_user_managed_replication import create_ummr_secret
3135
from create_update_secret_label import create_update_secret_label
@@ -36,6 +40,7 @@
3640
from destroy_secret_version_with_etag import destroy_secret_version_with_etag
3741
from disable_secret_version import disable_secret_version
3842
from disable_secret_version_with_etag import disable_secret_version_with_etag
43+
from disable_secret_with_delayed_destroy import disable_secret_with_delayed_destroy
3944
from edit_secret_annotations import edit_secret_annotations
4045
from enable_secret_version import enable_secret_version
4146
from enable_secret_version_with_etag import enable_secret_version_with_etag
@@ -50,6 +55,7 @@
5055
from quickstart import quickstart
5156
from update_secret import update_secret
5257
from update_secret_with_alias import update_secret_with_alias
58+
from update_secret_with_delayed_destroy import update_secret_with_delayed_destroy
5359
from update_secret_with_etag import update_secret_with_etag
5460
from view_secret_annotations import view_secret_annotations
5561
from view_secret_labels import view_secret_labels
@@ -95,6 +101,11 @@ def annotation_value() -> str:
95101
return "annotationvalue"
96102

97103

104+
@pytest.fixture()
105+
def version_destroy_ttl() -> str:
106+
return 604800 # 7 days in seconds
107+
108+
98109
@retry.Retry()
99110
def retry_client_create_secret(
100111
client: secretmanager.SecretManagerServiceClient,
@@ -180,6 +191,33 @@ def secret(
180191
yield project_id, secret_id, secret.etag
181192

182193

194+
@pytest.fixture()
195+
def secret_with_delayed_destroy(
196+
client: secretmanager.SecretManagerServiceClient,
197+
project_id: str,
198+
secret_id: str,
199+
version_destroy_ttl: int,
200+
ttl: Optional[str],
201+
) -> Iterator[Tuple[str, str]]:
202+
print(f"creating secret {secret_id}")
203+
204+
parent = f"projects/{project_id}"
205+
time.sleep(5)
206+
retry_client_create_secret(
207+
client,
208+
request={
209+
"parent": parent,
210+
"secret_id": secret_id,
211+
"secret": {
212+
"replication": {"automatic": {}},
213+
"version_destroy_ttl": Duration(seconds=version_destroy_ttl),
214+
},
215+
},
216+
)
217+
218+
yield project_id, secret_id
219+
220+
183221
@pytest.fixture()
184222
def secret_version(
185223
client: secretmanager.SecretManagerServiceClient, secret: Tuple[str, str, str]
@@ -288,6 +326,17 @@ def test_create_secret_with_annotations(
288326
assert secret_id in secret.name
289327

290328

329+
def test_create_secret_with_delayed_destroy(
330+
client: secretmanager.SecretManagerServiceClient,
331+
project_id: str,
332+
secret_id: str,
333+
version_destroy_ttl: int,
334+
) -> None:
335+
secret = create_secret_with_delayed_destroy(project_id, secret_id, version_destroy_ttl)
336+
assert secret_id in secret.name
337+
assert timedelta(seconds=version_destroy_ttl) == secret.version_destroy_ttl
338+
339+
291340
def test_delete_secret(
292341
client: secretmanager.SecretManagerServiceClient, secret: Tuple[str, str, str]
293342
) -> None:
@@ -341,6 +390,15 @@ def test_destroy_secret_version_with_etag(
341390
assert version.destroy_time
342391

343392

393+
def test_disable_secret_with_delayed_destroy(
394+
client: secretmanager.SecretManagerServiceClient,
395+
secret_with_delayed_destroy: Tuple[str, str],
396+
) -> None:
397+
project_id, secret_id = secret_with_delayed_destroy
398+
updated_secret = disable_secret_with_delayed_destroy(project_id, secret_id)
399+
assert updated_secret.version_destroy_ttl == timedelta(0)
400+
401+
344402
def test_enable_disable_secret_version(
345403
client: secretmanager.SecretManagerServiceClient,
346404
secret_version: Tuple[str, str, str, str],
@@ -532,3 +590,10 @@ def test_update_secret_with_alias(secret_version: Tuple[str, str, str, str]) ->
532590
project_id, secret_id, version_id, _ = secret_version
533591
secret = update_secret_with_alias(project_id, secret_id)
534592
assert secret.version_aliases["test"] == 1
593+
594+
595+
def test_update_secret_with_delayed_destroy(secret_with_delayed_destroy: Tuple[str, str], version_destroy_ttl: str) -> None:
596+
project_id, secret_id = secret_with_delayed_destroy
597+
updated_version_destroy_ttl_value = 118400
598+
updated_secret = update_secret_with_delayed_destroy(project_id, secret_id, updated_version_destroy_ttl_value)
599+
assert updated_secret.version_destroy_ttl == timedelta(seconds=version_destroy_ttl)
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#!/usr/bin/env python
2+
3+
# Copyright 2025 Google LLC
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
16+
import argparse
17+
18+
from google.cloud import secretmanager
19+
20+
# [START secretmanager_update_secret_with_delayed_destroy]
21+
22+
23+
def update_secret_with_delayed_destroy(
24+
project_id: str, secret_id: str, new_version_destroy_ttl: int
25+
) -> secretmanager.UpdateSecretRequest:
26+
"""
27+
Update the version destroy ttl value on an existing secret.
28+
"""
29+
30+
# Import the Secret Manager client library.
31+
from google.cloud import secretmanager
32+
33+
# from datetime import timedelta
34+
from google.protobuf.duration_pb2 import Duration
35+
36+
# Create the Secret Manager client.
37+
client = secretmanager.SecretManagerServiceClient()
38+
39+
# Build the resource name of the secret.
40+
name = client.secret_path(project_id, secret_id)
41+
42+
# Update the version_destroy_ttl.
43+
secret = {"name": name, "version_destroy_ttl": Duration(seconds=new_version_destroy_ttl)}
44+
update_mask = {"paths": ["version_destroy_ttl"]}
45+
response = client.update_secret(
46+
request={"secret": secret, "update_mask": update_mask}
47+
)
48+
49+
# Print the new secret name.
50+
print(f"Updated secret: {response.name}")
51+
52+
return response
53+
54+
# [END secretmanager_update_secret_with_delayed_destroy]
55+
56+
57+
if __name__ == "__main__":
58+
parser = argparse.ArgumentParser(
59+
description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter
60+
)
61+
parser.add_argument("project_id", help="id of the GCP project")
62+
parser.add_argument("secret-id", help="id of the secret to act on")
63+
parser.add_argument("version_destroy_ttl", "new version destroy ttl to be added")
64+
args = parser.parse_args()
65+
66+
update_secret_with_delayed_destroy(args.project_id, args.secret_id, args.version_destroy_ttl)

0 commit comments

Comments
 (0)