diff --git a/samples/snippets/snippets_test.py b/samples/snippets/snippets_test.py index 6d9cfc317..4f98884b5 100644 --- a/samples/snippets/snippets_test.py +++ b/samples/snippets/snippets_test.py @@ -59,9 +59,12 @@ import storage_get_autoclass import storage_get_bucket_labels import storage_get_bucket_metadata +import storage_get_soft_deleted_bucket import storage_get_metadata import storage_get_service_account import storage_list_buckets +import storage_list_soft_deleted_buckets +import storage_restore_soft_deleted_bucket import storage_list_file_archived_generations import storage_list_files import storage_list_files_with_prefix @@ -131,6 +134,19 @@ def test_bucket(): bucket.delete(force=True) +@pytest.fixture(scope="module") +def test_soft_deleted_bucket(): + """Yields a soft-deleted bucket.""" + bucket = None + while bucket is None or bucket.exists(): + bucket_name = f"storage-snippets-test-{uuid.uuid4()}" + bucket = storage.Client().bucket(bucket_name) + bucket.create() + # [Assumption] Bucket is created with default policy , ie soft delete on. + bucket.delete() + yield bucket + + @pytest.fixture(scope="function") def test_public_bucket(): # The new projects don't allow to make a bucket available to public, so @@ -195,6 +211,12 @@ def test_list_buckets(test_bucket, capsys): assert test_bucket.name in out +def test_list_soft_deleted_buckets(test_soft_deleted_bucket, capsys): + storage_list_soft_deleted_buckets.list_soft_deleted_buckets() + out, _ = capsys.readouterr() + assert test_soft_deleted_bucket.name in out + + def test_list_blobs(test_blob, capsys): storage_list_files.list_blobs(test_blob.bucket.name) out, _ = capsys.readouterr() @@ -207,6 +229,18 @@ def test_bucket_metadata(test_bucket, capsys): assert test_bucket.name in out +def test_get_soft_deleted_bucket(test_soft_deleted_bucket, capsys): + storage_get_soft_deleted_bucket.get_soft_deleted_bucket(test_soft_deleted_bucket.name, test_soft_deleted_bucket.generation) + out, _ = capsys.readouterr() + assert test_soft_deleted_bucket.name in out + + +def test_restore_soft_deleted_bucket(test_soft_deleted_bucket, capsys): + storage_restore_soft_deleted_bucket.restore_bucket(test_soft_deleted_bucket.name, test_soft_deleted_bucket.generation) + out, _ = capsys.readouterr() + assert test_soft_deleted_bucket.name in out + + def test_list_blobs_with_prefix(test_blob, capsys): storage_list_files_with_prefix.list_blobs_with_prefix( test_blob.bucket.name, prefix="storage_snippets" diff --git a/samples/snippets/storage_get_soft_deleted_bucket.py b/samples/snippets/storage_get_soft_deleted_bucket.py new file mode 100644 index 000000000..2b7955046 --- /dev/null +++ b/samples/snippets/storage_get_soft_deleted_bucket.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the 'License'); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import sys + +# [START storage_get_soft_deleted_bucket] + +from google.cloud import storage + + +def get_soft_deleted_bucket(bucket_name, generation): + """Prints out a soft-deleted bucket's metadata. + + Args: + bucket_name: str + The name of the bucket to get. + + generation: + The generation of the bucket. + + """ + storage_client = storage.Client() + bucket = storage_client.get_bucket(bucket_name, soft_deleted=True, generation=generation) + + print(f"ID: {bucket.id}") + print(f"Name: {bucket.name}") + print(f"Soft Delete time: {bucket.soft_delete_time}") + print(f"Hard Delete Time : {bucket.hard_delete_time}") + + +# [END storage_get_soft_deleted_bucket] + +if __name__ == "__main__": + get_soft_deleted_bucket(bucket_name=sys.argv[1], generation=sys.argv[2]) diff --git a/samples/snippets/storage_list_soft_deleted_buckets.py b/samples/snippets/storage_list_soft_deleted_buckets.py new file mode 100644 index 000000000..16abd90f0 --- /dev/null +++ b/samples/snippets/storage_list_soft_deleted_buckets.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the 'License'); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# [START storage_list_soft_deleted_buckets] + +from google.cloud import storage + + +def list_soft_deleted_buckets(): + """Lists all soft-deleted buckets.""" + + storage_client = storage.Client() + buckets = storage_client.list_buckets(soft_deleted=True) + + for bucket in buckets: + print(bucket.name) + + +# [END storage_list_soft_deleted_buckets] + + +if __name__ == "__main__": + list_soft_deleted_buckets() diff --git a/samples/snippets/storage_restore_soft_deleted_bucket.py b/samples/snippets/storage_restore_soft_deleted_bucket.py new file mode 100644 index 000000000..fb6291997 --- /dev/null +++ b/samples/snippets/storage_restore_soft_deleted_bucket.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the 'License'); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import sys + +# [START storage_restore_soft_deleted_bucket] + +from google.cloud import storage + + +def restore_bucket(bucket_name, bucket_generation): + storage_client = storage.Client() + bucket = storage_client.restore_bucket(bucket_name=bucket_name, generation=bucket_generation) + print(f"Soft-deleted bucket {bucket.name} with ID: {bucket.id} was restored.") + print(f"Bucket Generation: {bucket.generation}") + + +# [END storage_restore_soft_deleted_bucket] + +if __name__ == "__main__": + if len(sys.argv) != 3: + print("Wrong inputs!! Usage of script - \"python storage_restore_soft_deleted_bucket.py \" ") + sys.exit(1) + restore_bucket(bucket_name=sys.argv[1], bucket_generation=sys.argv[2])