diff --git a/samples/snippets/README.md b/samples/snippets/README.md new file mode 100644 index 000000000..3d7e3664f --- /dev/null +++ b/samples/snippets/README.md @@ -0,0 +1,10 @@ + +For requester_pays_test.py, we need to use a different Storage bucket. + +The test looks for an environment variable `REQUESTER_PAYS_TEST_BUCKET`. + +Also, the service account for the test needs to have `Billing Project +Manager` role in order to make changes on buckets with requester pays +enabled. + +We added that role to the test service account. diff --git a/samples/snippets/acl_test.py b/samples/snippets/acl_test.py new file mode 100644 index 000000000..fd2088ad6 --- /dev/null +++ b/samples/snippets/acl_test.py @@ -0,0 +1,172 @@ +# Copyright 2016 Google, Inc. +# +# 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 os +import uuid + +import backoff +from google.cloud import storage +from googleapiclient.errors import HttpError +import pytest + +import storage_add_bucket_default_owner +import storage_add_bucket_owner +import storage_add_file_owner +import storage_print_bucket_acl +import storage_print_bucket_acl_for_user +import storage_print_file_acl +import storage_print_file_acl_for_user +import storage_remove_bucket_default_owner +import storage_remove_bucket_owner +import storage_remove_file_owner + +# Typically we'd use a @example.com address, but GCS requires a real Google +# account. Retrieve a service account email with storage admin permissions. +TEST_EMAIL = ( + "py38-storage-test" + "@python-docs-samples-tests.iam.gserviceaccount.com" +) + + +@pytest.fixture(scope="module") +def test_bucket(): + """Yields a bucket that is deleted after the test completes.""" + + # The new projects have uniform bucket-level access and our tests don't + # pass with those buckets. We need to use the old main project for now. + original_value = os.environ['GOOGLE_CLOUD_PROJECT'] + os.environ['GOOGLE_CLOUD_PROJECT'] = os.environ['MAIN_GOOGLE_CLOUD_PROJECT'] + bucket = None + while bucket is None or bucket.exists(): + bucket_name = "acl-test-{}".format(uuid.uuid4()) + bucket = storage.Client().bucket(bucket_name) + bucket.create() + yield bucket + bucket.delete(force=True) + # Set the value back. + os.environ['GOOGLE_CLOUD_PROJECT'] = original_value + + +@pytest.fixture +def test_blob(test_bucket): + """Yields a blob that is deleted after the test completes.""" + bucket = test_bucket + blob = bucket.blob("storage_acl_test_sigil-{}".format(uuid.uuid4())) + blob.upload_from_string("Hello, is it me you're looking for?") + yield blob + + +def test_print_bucket_acl(test_bucket, capsys): + storage_print_bucket_acl.print_bucket_acl(test_bucket.name) + out, _ = capsys.readouterr() + assert out + + +def test_print_bucket_acl_for_user(test_bucket, capsys): + test_bucket.acl.user(TEST_EMAIL).grant_owner() + test_bucket.acl.save() + + storage_print_bucket_acl_for_user.print_bucket_acl_for_user( + test_bucket.name, TEST_EMAIL + ) + + out, _ = capsys.readouterr() + assert "OWNER" in out + + +@backoff.on_exception(backoff.expo, HttpError, max_time=60) +def test_add_bucket_owner(test_bucket): + storage_add_bucket_owner.add_bucket_owner(test_bucket.name, TEST_EMAIL) + + test_bucket.acl.reload() + assert "OWNER" in test_bucket.acl.user(TEST_EMAIL).get_roles() + + +@backoff.on_exception(backoff.expo, HttpError, max_time=60) +def test_remove_bucket_owner(test_bucket): + test_bucket.acl.user(TEST_EMAIL).grant_owner() + test_bucket.acl.save() + + storage_remove_bucket_owner.remove_bucket_owner( + test_bucket.name, TEST_EMAIL) + + test_bucket.acl.reload() + assert "OWNER" not in test_bucket.acl.user(TEST_EMAIL).get_roles() + + +@backoff.on_exception(backoff.expo, HttpError, max_time=60) +def test_add_bucket_default_owner(test_bucket): + storage_add_bucket_default_owner.add_bucket_default_owner( + test_bucket.name, TEST_EMAIL + ) + + test_bucket.default_object_acl.reload() + roles = test_bucket.default_object_acl.user(TEST_EMAIL).get_roles() + assert "OWNER" in roles + + +@backoff.on_exception(backoff.expo, HttpError, max_time=60) +def test_remove_bucket_default_owner(test_bucket): + test_bucket.acl.user(TEST_EMAIL).grant_owner() + test_bucket.acl.save() + + storage_remove_bucket_default_owner.remove_bucket_default_owner( + test_bucket.name, TEST_EMAIL + ) + + test_bucket.default_object_acl.reload() + roles = test_bucket.default_object_acl.user(TEST_EMAIL).get_roles() + assert "OWNER" not in roles + + +def test_print_blob_acl(test_blob, capsys): + storage_print_file_acl.print_blob_acl( + test_blob.bucket.name, test_blob.name) + out, _ = capsys.readouterr() + assert out + + +@backoff.on_exception(backoff.expo, HttpError, max_time=60) +def test_print_blob_acl_for_user(test_blob, capsys): + test_blob.acl.user(TEST_EMAIL).grant_owner() + test_blob.acl.save() + + storage_print_file_acl_for_user.print_blob_acl_for_user( + test_blob.bucket.name, test_blob.name, TEST_EMAIL + ) + + out, _ = capsys.readouterr() + assert "OWNER" in out + + +@backoff.on_exception(backoff.expo, HttpError, max_time=60) +def test_add_blob_owner(test_blob): + storage_add_file_owner.add_blob_owner( + test_blob.bucket.name, test_blob.name, TEST_EMAIL) + + test_blob.acl.reload() + assert "OWNER" in test_blob.acl.user(TEST_EMAIL).get_roles() + + +@backoff.on_exception(backoff.expo, HttpError, max_time=60) +def test_remove_blob_owner(test_blob): + test_blob.acl.user(TEST_EMAIL).grant_owner() + test_blob.acl.save() + + storage_remove_file_owner.remove_blob_owner( + test_blob.bucket.name, test_blob.name, TEST_EMAIL + ) + + test_blob.acl.reload() + assert "OWNER" not in test_blob.acl.user(TEST_EMAIL).get_roles() diff --git a/samples/snippets/bucket_lock_test.py b/samples/snippets/bucket_lock_test.py new file mode 100644 index 000000000..67d4ec685 --- /dev/null +++ b/samples/snippets/bucket_lock_test.py @@ -0,0 +1,176 @@ +# Copyright 2018 Google Inc. All Rights Reserved. +# +# 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 time +import uuid + +from google.cloud import storage +import pytest + +import storage_disable_default_event_based_hold +import storage_enable_default_event_based_hold +import storage_get_default_event_based_hold +import storage_get_retention_policy +import storage_lock_retention_policy +import storage_release_event_based_hold +import storage_release_temporary_hold +import storage_remove_retention_policy +import storage_set_event_based_hold +import storage_set_retention_policy +import storage_set_temporary_hold + + +BLOB_NAME = "storage_snippets_test_sigil" +BLOB_CONTENT = "Hello, is it me you're looking for?" +# Retention policy for 5 seconds +RETENTION_POLICY = 5 + + +@pytest.fixture +def bucket(): + """Yields a bucket that is deleted after the test completes.""" + bucket = None + while bucket is None or bucket.exists(): + bucket_name = "bucket-lock-{}".format(uuid.uuid4()) + bucket = storage.Client().bucket(bucket_name) + bucket.create() + yield bucket + bucket.delete(force=True) + + +def test_retention_policy_no_lock(bucket, capsys): + storage_set_retention_policy.set_retention_policy( + bucket.name, RETENTION_POLICY + ) + bucket.reload() + + assert bucket.retention_period is RETENTION_POLICY + assert bucket.retention_policy_effective_time is not None + assert bucket.retention_policy_locked is None + + storage_get_retention_policy.get_retention_policy(bucket.name) + out, _ = capsys.readouterr() + assert "Retention Policy for {}".format(bucket.name) in out + assert "Retention Period: 5" in out + assert "Effective Time: " in out + assert "Retention Policy is locked" not in out + + blob = bucket.blob(BLOB_NAME) + blob.upload_from_string(BLOB_CONTENT) + + assert blob.retention_expiration_time is not None + + storage_remove_retention_policy.remove_retention_policy(bucket.name) + bucket.reload() + assert bucket.retention_period is None + + time.sleep(RETENTION_POLICY) + + +def test_retention_policy_lock(bucket, capsys): + storage_set_retention_policy.set_retention_policy( + bucket.name, RETENTION_POLICY + ) + bucket.reload() + assert bucket.retention_policy_locked is None + + storage_lock_retention_policy.lock_retention_policy(bucket.name) + bucket.reload() + assert bucket.retention_policy_locked is True + + storage_get_retention_policy.get_retention_policy(bucket.name) + out, _ = capsys.readouterr() + assert "Retention Policy is locked" in out + + +def test_enable_disable_bucket_default_event_based_hold(bucket, capsys): + storage_get_default_event_based_hold.get_default_event_based_hold( + bucket.name + ) + out, _ = capsys.readouterr() + assert ( + "Default event-based hold is not enabled for {}".format(bucket.name) + in out + ) + assert ( + "Default event-based hold is enabled for {}".format(bucket.name) + not in out + ) + + storage_enable_default_event_based_hold.enable_default_event_based_hold( + bucket.name + ) + bucket.reload() + + assert bucket.default_event_based_hold is True + + storage_get_default_event_based_hold.get_default_event_based_hold( + bucket.name + ) + out, _ = capsys.readouterr() + assert ( + "Default event-based hold is enabled for {}".format(bucket.name) in out + ) + + # Changes to the bucket will be readable immediately after writing, + # but configuration changes may take time to propagate. + time.sleep(10) + + blob = bucket.blob(BLOB_NAME) + blob.upload_from_string(BLOB_CONTENT) + assert blob.event_based_hold is True + + storage_release_event_based_hold.release_event_based_hold( + bucket.name, blob.name + ) + blob.reload() + assert blob.event_based_hold is False + + storage_disable_default_event_based_hold.disable_default_event_based_hold( + bucket.name + ) + bucket.reload() + assert bucket.default_event_based_hold is False + + +def test_enable_disable_temporary_hold(bucket): + blob = bucket.blob(BLOB_NAME) + blob.upload_from_string(BLOB_CONTENT) + assert blob.temporary_hold is None + + storage_set_temporary_hold.set_temporary_hold(bucket.name, blob.name) + blob.reload() + assert blob.temporary_hold is True + + storage_release_temporary_hold.release_temporary_hold( + bucket.name, blob.name + ) + blob.reload() + assert blob.temporary_hold is False + + +def test_enable_disable_event_based_hold(bucket): + blob = bucket.blob(BLOB_NAME) + blob.upload_from_string(BLOB_CONTENT) + assert blob.event_based_hold is None + + storage_set_event_based_hold.set_event_based_hold(bucket.name, blob.name) + blob.reload() + assert blob.event_based_hold is True + + storage_release_event_based_hold.release_event_based_hold( + bucket.name, blob.name + ) + blob.reload() + assert blob.event_based_hold is False diff --git a/samples/snippets/conftest.py b/samples/snippets/conftest.py new file mode 100644 index 000000000..b0db57561 --- /dev/null +++ b/samples/snippets/conftest.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# Copyright 2021 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 os +import time +import uuid + +from google.cloud import storage +import pytest + + +@pytest.fixture(scope="function") +def bucket(): + """Yields a bucket that is deleted after the test completes.""" + # The new projects enforces uniform bucket level access, so + # we need to use the old main project for now. + original_value = os.environ['GOOGLE_CLOUD_PROJECT'] + os.environ['GOOGLE_CLOUD_PROJECT'] = os.environ['MAIN_GOOGLE_CLOUD_PROJECT'] + bucket = None + while bucket is None or bucket.exists(): + bucket_name = f"uniform-bucket-level-access-{uuid.uuid4().hex}" + bucket = storage.Client().bucket(bucket_name) + bucket.create() + yield bucket + time.sleep(3) + bucket.delete(force=True) + # Set the value back. + os.environ['GOOGLE_CLOUD_PROJECT'] = original_value diff --git a/samples/snippets/encryption_test.py b/samples/snippets/encryption_test.py new file mode 100644 index 000000000..6c2377e0f --- /dev/null +++ b/samples/snippets/encryption_test.py @@ -0,0 +1,125 @@ +# Copyright 2016 Google, Inc. +# +# 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 base64 +import os +import tempfile +import uuid + +from google.api_core.exceptions import NotFound +from google.cloud import storage +from google.cloud.storage import Blob +import pytest + +import storage_download_encrypted_file +import storage_generate_encryption_key +import storage_object_csek_to_cmek +import storage_rotate_encryption_key +import storage_upload_encrypted_file + +BUCKET = os.environ["CLOUD_STORAGE_BUCKET"] +KMS_KEY = os.environ["CLOUD_KMS_KEY"] + +TEST_ENCRYPTION_KEY = "brtJUWneL92g5q0N2gyDSnlPSYAiIVZ/cWgjyZNeMy0=" +TEST_ENCRYPTION_KEY_DECODED = base64.b64decode(TEST_ENCRYPTION_KEY) + +TEST_ENCRYPTION_KEY_2 = "o4OD7SWCaPjfeEGhAY+YCgMdY9UW+OJ8mvfWD9lNtO4=" +TEST_ENCRYPTION_KEY_2_DECODED = base64.b64decode(TEST_ENCRYPTION_KEY_2) + + +def test_generate_encryption_key(capsys): + storage_generate_encryption_key.generate_encryption_key() + out, _ = capsys.readouterr() + encoded_key = out.split(":", 1).pop().strip() + key = base64.b64decode(encoded_key) + assert len(key) == 32, "Returned key should be 32 bytes" + + +def test_upload_encrypted_blob(): + with tempfile.NamedTemporaryFile() as source_file: + source_file.write(b"test") + + storage_upload_encrypted_file.upload_encrypted_blob( + BUCKET, + source_file.name, + "test_encrypted_upload_blob", + TEST_ENCRYPTION_KEY, + ) + + +@pytest.fixture(scope="module") +def test_blob(): + """Provides a pre-existing blob in the test bucket.""" + bucket = storage.Client().bucket(BUCKET) + blob_name = "test_blob_{}".format(uuid.uuid4().hex) + blob = Blob( + blob_name, + bucket, + encryption_key=TEST_ENCRYPTION_KEY_DECODED, + ) + content = "Hello, is it me you're looking for?" + blob.upload_from_string(content) + + yield blob.name, content + + # To delete an encrypted blob, you have to provide the same key + # used for the blob. When you provide a wrong key, you'll get + # NotFound. + try: + # Clean up for the case that the rotation didn't occur. + blob.delete() + except NotFound as e: + # For the case that the rotation succeeded. + print("Ignoring 404, detail: {}".format(e)) + blob = Blob( + blob_name, + bucket, + encryption_key=TEST_ENCRYPTION_KEY_2_DECODED + ) + blob.delete() + + +def test_download_blob(test_blob): + test_blob_name, test_blob_content = test_blob + with tempfile.NamedTemporaryFile() as dest_file: + storage_download_encrypted_file.download_encrypted_blob( + BUCKET, test_blob_name, dest_file.name, TEST_ENCRYPTION_KEY + ) + + downloaded_content = dest_file.read().decode("utf-8") + assert downloaded_content == test_blob_content + + +def test_rotate_encryption_key(test_blob): + test_blob_name, test_blob_content = test_blob + storage_rotate_encryption_key.rotate_encryption_key( + BUCKET, test_blob_name, TEST_ENCRYPTION_KEY, TEST_ENCRYPTION_KEY_2 + ) + + with tempfile.NamedTemporaryFile() as dest_file: + storage_download_encrypted_file.download_encrypted_blob( + BUCKET, test_blob_name, dest_file.name, TEST_ENCRYPTION_KEY_2 + ) + + downloaded_content = dest_file.read().decode("utf-8") + assert downloaded_content == test_blob_content + + +def test_object_csek_to_cmek(test_blob): + test_blob_name, test_blob_content = test_blob + cmek_blob = storage_object_csek_to_cmek.object_csek_to_cmek( + BUCKET, test_blob_name, TEST_ENCRYPTION_KEY_2, KMS_KEY + ) + + assert cmek_blob.download_as_string(), test_blob_content diff --git a/samples/snippets/hmac_samples_test.py b/samples/snippets/hmac_samples_test.py new file mode 100644 index 000000000..60eba2401 --- /dev/null +++ b/samples/snippets/hmac_samples_test.py @@ -0,0 +1,121 @@ +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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. +""" +Tests for hmac.py. Requires GOOGLE_CLOUD_PROJECT (valid project) and +HMAC_KEY_TEST_SERVICE_ACCOUNT (valid service account email) env variables to be +set in order to run. +""" + + +import os + +import google.api_core.exceptions +from google.cloud import storage +import pytest + +import storage_activate_hmac_key +import storage_create_hmac_key +import storage_deactivate_hmac_key +import storage_delete_hmac_key +import storage_get_hmac_key +import storage_list_hmac_keys + +# We are reaching maximum number of HMAC keys on the service account. +# We change the service account based on the value of +# RUN_TESTS_SESSION in noxfile_config.py. +# The reason we can not use multiple project is that our new projects +# are enforced to have +# 'constraints/iam.disableServiceAccountKeyCreation' policy. + +PROJECT_ID = os.environ["MAIN_GOOGLE_CLOUD_PROJECT"] +SERVICE_ACCOUNT_EMAIL = os.environ["HMAC_KEY_TEST_SERVICE_ACCOUNT"] +STORAGE_CLIENT = storage.Client(project=PROJECT_ID) + + +@pytest.fixture(scope="module") +def new_hmac_key(): + """ + Fixture to create a new HMAC key, and to guarantee all keys are deleted at + the end of the module. + + NOTE: Due to the module scope, test order in this file is significant + """ + hmac_key, secret = STORAGE_CLIENT.create_hmac_key( + service_account_email=SERVICE_ACCOUNT_EMAIL, project_id=PROJECT_ID + ) + yield hmac_key + # Re-fetch the key metadata in case state has changed during the test. + hmac_key = STORAGE_CLIENT.get_hmac_key_metadata( + hmac_key.access_id, project_id=PROJECT_ID + ) + if hmac_key.state == "DELETED": + return + if not hmac_key.state == "INACTIVE": + hmac_key.state = "INACTIVE" + hmac_key.update() + hmac_key.delete() + + +def test_list_keys(capsys, new_hmac_key): + hmac_keys = storage_list_hmac_keys.list_keys(PROJECT_ID) + assert "HMAC Keys:" in capsys.readouterr().out + assert hmac_keys.num_results >= 1 + + +def test_create_key(capsys): + hmac_key = storage_create_hmac_key.create_key( + PROJECT_ID, SERVICE_ACCOUNT_EMAIL + ) + hmac_key.state = "INACTIVE" + hmac_key.update() + hmac_key.delete() + assert "Key ID:" in capsys.readouterr().out + assert hmac_key.access_id + + +def test_get_key(capsys, new_hmac_key): + hmac_key = storage_get_hmac_key.get_key(new_hmac_key.access_id, PROJECT_ID) + assert "HMAC key metadata" in capsys.readouterr().out + assert hmac_key.access_id == new_hmac_key.access_id + + +def test_activate_key(capsys, new_hmac_key): + new_hmac_key.state = "INACTIVE" + new_hmac_key.update() + hmac_key = storage_activate_hmac_key.activate_key( + new_hmac_key.access_id, PROJECT_ID + ) + assert "State: ACTIVE" in capsys.readouterr().out + assert hmac_key.state == "ACTIVE" + + +def test_deactivate_key(capsys, new_hmac_key): + hmac_key = storage_deactivate_hmac_key.deactivate_key( + new_hmac_key.access_id, PROJECT_ID + ) + assert "State: INACTIVE" in capsys.readouterr().out + assert hmac_key.state == "INACTIVE" + + +def test_delete_key(capsys, new_hmac_key): + # Due to reuse of the HMAC key for each test function, the previous + # test has deactivated the key already. + try: + new_hmac_key.state = "INACTIVE" + new_hmac_key.update() + except google.api_core.exceptions.BadRequest: + pass + + storage_delete_hmac_key.delete_key(new_hmac_key.access_id, PROJECT_ID) + assert "The key is deleted" in capsys.readouterr().out diff --git a/samples/snippets/iam_test.py b/samples/snippets/iam_test.py new file mode 100644 index 000000000..eb7638de5 --- /dev/null +++ b/samples/snippets/iam_test.py @@ -0,0 +1,146 @@ +# Copyright 2017 Google, Inc. +# +# 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 os +import re +import time +import uuid + +from google.cloud import storage +import pytest + +import storage_add_bucket_conditional_iam_binding +import storage_add_bucket_iam_member +import storage_remove_bucket_conditional_iam_binding +import storage_remove_bucket_iam_member +import storage_set_bucket_public_iam +import storage_view_bucket_iam_members + +MEMBER = "group:dpebot@google.com" +ROLE = "roles/storage.legacyBucketReader" + +CONDITION_TITLE = "match-prefix" +CONDITION_DESCRIPTION = "Applies to objects matching a prefix" +CONDITION_EXPRESSION = ( + 'resource.name.startsWith("projects/_/buckets/bucket-name/objects/prefix-a-")' +) + + +@pytest.fixture(scope="module") +def bucket(): + bucket = None + while bucket is None or bucket.exists(): + storage_client = storage.Client() + bucket_name = "test-iam-{}".format(uuid.uuid4()) + bucket = storage_client.bucket(bucket_name) + bucket.iam_configuration.uniform_bucket_level_access_enabled = True + storage_client.create_bucket(bucket) + yield bucket + time.sleep(3) + bucket.delete(force=True) + + +@pytest.fixture(scope="function") +def public_bucket(): + # The new projects don't allow to make a bucket available to public, so + # we need to use the old main project for now. + original_value = os.environ['GOOGLE_CLOUD_PROJECT'] + os.environ['GOOGLE_CLOUD_PROJECT'] = os.environ['MAIN_GOOGLE_CLOUD_PROJECT'] + bucket = None + while bucket is None or bucket.exists(): + storage_client = storage.Client() + bucket_name = "test-iam-{}".format(uuid.uuid4()) + bucket = storage_client.bucket(bucket_name) + bucket.iam_configuration.uniform_bucket_level_access_enabled = True + storage_client.create_bucket(bucket) + yield bucket + time.sleep(3) + bucket.delete(force=True) + # Set the value back. + os.environ['GOOGLE_CLOUD_PROJECT'] = original_value + + +def test_view_bucket_iam_members(capsys, bucket): + storage_view_bucket_iam_members.view_bucket_iam_members(bucket.name) + assert re.match("Role: .*, Members: .*", capsys.readouterr().out) + + +def test_add_bucket_iam_member(bucket): + storage_add_bucket_iam_member.add_bucket_iam_member(bucket.name, ROLE, MEMBER) + policy = bucket.get_iam_policy(requested_policy_version=3) + assert any( + binding["role"] == ROLE and MEMBER in binding["members"] + for binding in policy.bindings + ) + + +def test_add_bucket_conditional_iam_binding(bucket): + storage_add_bucket_conditional_iam_binding.add_bucket_conditional_iam_binding( + bucket.name, + ROLE, + CONDITION_TITLE, + CONDITION_DESCRIPTION, + CONDITION_EXPRESSION, + {MEMBER}, + ) + policy = bucket.get_iam_policy(requested_policy_version=3) + assert any( + binding["role"] == ROLE + and binding["members"] == {MEMBER} + and binding["condition"] + == { + "title": CONDITION_TITLE, + "description": CONDITION_DESCRIPTION, + "expression": CONDITION_EXPRESSION, + } + for binding in policy.bindings + ) + + +def test_remove_bucket_iam_member(public_bucket): + storage_remove_bucket_iam_member.remove_bucket_iam_member( + public_bucket.name, ROLE, MEMBER) + + policy = public_bucket.get_iam_policy(requested_policy_version=3) + assert not any( + binding["role"] == ROLE and MEMBER in binding["members"] + for binding in policy.bindings + ) + + +def test_remove_bucket_conditional_iam_binding(bucket): + storage_remove_bucket_conditional_iam_binding.remove_bucket_conditional_iam_binding( + bucket.name, ROLE, CONDITION_TITLE, CONDITION_DESCRIPTION, CONDITION_EXPRESSION + ) + + policy = bucket.get_iam_policy(requested_policy_version=3) + condition = { + "title": CONDITION_TITLE, + "description": CONDITION_DESCRIPTION, + "expression": CONDITION_EXPRESSION, + } + assert not any( + (binding["role"] == ROLE and binding.get("condition") == condition) + for binding in policy.bindings + ) + + +def test_set_bucket_public_iam(public_bucket): + storage_set_bucket_public_iam.set_bucket_public_iam(public_bucket.name) + policy = public_bucket.get_iam_policy(requested_policy_version=3) + assert any( + binding["role"] == "roles/storage.objectViewer" + and "allUsers" in binding["members"] + for binding in policy.bindings + ) diff --git a/samples/snippets/notification_polling.py b/samples/snippets/notification_polling.py new file mode 100644 index 000000000..3182db6da --- /dev/null +++ b/samples/snippets/notification_polling.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python + +# Copyright 2017 Google Inc. All rights reserved. +# +# 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. + +"""This application demonstrates how to poll for GCS notifications from a +Cloud Pub/Sub subscription, parse the incoming message, and acknowledge the +successful processing of the message. + +This application will work with any subscription configured for pull rather +than push notifications. If you do not already have notifications configured, +you may consult the docs at +https://cloud.google.com/storage/docs/reporting-changes or follow the steps +below: + +1. First, follow the common setup steps for these snippets, specically + configuring auth and installing dependencies. See the README's "Setup" + section. + +2. Activate the Google Cloud Pub/Sub API, if you have not already done so. + https://console.cloud.google.com/flows/enableapi?apiid=pubsub + +3. Create a Google Cloud Storage bucket: + $ gsutil mb gs://testbucket + +4. Create a Cloud Pub/Sub topic and publish bucket notifications there: + $ gsutil notification create -f json -t testtopic gs://testbucket + +5. Create a subscription for your new topic: + $ gcloud beta pubsub subscriptions create testsubscription --topic=testtopic + +6. Run this program: + $ python notification_polling.py my-project-id testsubscription + +7. While the program is running, upload and delete some files in the testbucket + bucket (you could use the console or gsutil) and watch as changes scroll by + in the app. +""" + +import argparse +import json +import time + +from google.cloud import pubsub_v1 + + +def summarize(message): + data = message.data.decode("utf-8") + attributes = message.attributes + + event_type = attributes["eventType"] + bucket_id = attributes["bucketId"] + object_id = attributes["objectId"] + generation = attributes["objectGeneration"] + description = ( + "\tEvent type: {event_type}\n" + "\tBucket ID: {bucket_id}\n" + "\tObject ID: {object_id}\n" + "\tGeneration: {generation}\n" + ).format( + event_type=event_type, + bucket_id=bucket_id, + object_id=object_id, + generation=generation, + ) + + if "overwroteGeneration" in attributes: + description += "\tOverwrote generation: %s\n" % ( + attributes["overwroteGeneration"] + ) + if "overwrittenByGeneration" in attributes: + description += "\tOverwritten by generation: %s\n" % ( + attributes["overwrittenByGeneration"] + ) + + payload_format = attributes["payloadFormat"] + if payload_format == "JSON_API_V1": + object_metadata = json.loads(data) + size = object_metadata["size"] + content_type = object_metadata["contentType"] + metageneration = object_metadata["metageneration"] + description += ( + "\tContent type: {content_type}\n" + "\tSize: {object_size}\n" + "\tMetageneration: {metageneration}\n" + ).format( + content_type=content_type, + object_size=size, + metageneration=metageneration, + ) + return description + + +def poll_notifications(project, subscription_name): + """Polls a Cloud Pub/Sub subscription for new GCS events for display.""" + subscriber = pubsub_v1.SubscriberClient() + subscription_path = subscriber.subscription_path( + project, subscription_name + ) + + def callback(message): + print("Received message:\n{}".format(summarize(message))) + message.ack() + + subscriber.subscribe(subscription_path, callback=callback) + + # The subscriber is non-blocking, so we must keep the main thread from + # exiting to allow it to process messages in the background. + print("Listening for messages on {}".format(subscription_path)) + while True: + time.sleep(60) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + parser.add_argument( + "project", help="The ID of the project that owns the subscription" + ) + parser.add_argument( + "subscription", help="The ID of the Pub/Sub subscription" + ) + args = parser.parse_args() + poll_notifications(args.project, args.subscription) diff --git a/samples/snippets/notification_polling_test.py b/samples/snippets/notification_polling_test.py new file mode 100644 index 000000000..dfb241b84 --- /dev/null +++ b/samples/snippets/notification_polling_test.py @@ -0,0 +1,55 @@ +# Copyright 2017 Google Inc. All rights reserved. +# +# 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. + + +from google.cloud.pubsub_v1.subscriber.message import Message +import mock + +from notification_polling import summarize + + +MESSAGE_ID = 12345 + + +def test_parse_json_message(): + attributes = { + "eventType": "OBJECT_FINALIZE", + "bucketId": "mybucket", + "objectId": "myobject", + "objectGeneration": 1234567, + "resource": "projects/_/buckets/mybucket/objects/myobject#1234567", + "notificationConfig": ( + "projects/_/buckets/mybucket/" "notificationConfigs/5" + ), + "payloadFormat": "JSON_API_V1", + } + data = ( + b"{" + b' "size": 12345,' + b' "contentType": "text/html",' + b' "metageneration": 1' + b"}" + ) + message = Message( + mock.Mock(data=data, attributes=attributes, publish_time=mock.Mock(seconds=0.0, nanos=0.0)), MESSAGE_ID, delivery_attempt=0, request_queue=mock.Mock() + ) + assert summarize(message) == ( + "\tEvent type: OBJECT_FINALIZE\n" + "\tBucket ID: mybucket\n" + "\tObject ID: myobject\n" + "\tGeneration: 1234567\n" + "\tContent type: text/html\n" + "\tSize: 12345\n" + "\tMetageneration: 1\n" + ) diff --git a/samples/snippets/noxfile.py b/samples/snippets/noxfile.py new file mode 100644 index 000000000..93a9122cc --- /dev/null +++ b/samples/snippets/noxfile.py @@ -0,0 +1,270 @@ +# Copyright 2019 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. + +from __future__ import print_function + +import os +from pathlib import Path +import sys +from typing import Callable, Dict, List, Optional + +import nox + + +# WARNING - WARNING - WARNING - WARNING - WARNING +# WARNING - WARNING - WARNING - WARNING - WARNING +# DO NOT EDIT THIS FILE EVER! +# WARNING - WARNING - WARNING - WARNING - WARNING +# WARNING - WARNING - WARNING - WARNING - WARNING + +BLACK_VERSION = "black==19.10b0" + +# Copy `noxfile_config.py` to your directory and modify it instead. + +# `TEST_CONFIG` dict is a configuration hook that allows users to +# modify the test configurations. The values here should be in sync +# with `noxfile_config.py`. Users will copy `noxfile_config.py` into +# their directory and modify it. + +TEST_CONFIG = { + # You can opt out from the test for specific Python versions. + "ignored_versions": [], + # Old samples are opted out of enforcing Python type hints + # All new samples should feature them + "enforce_type_hints": False, + # An envvar key for determining the project id to use. Change it + # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a + # build specific Cloud project. You can also use your own string + # to use your own Cloud project. + "gcloud_project_env": "GOOGLE_CLOUD_PROJECT", + # 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT', + # If you need to use a specific version of pip, + # change pip_version_override to the string representation + # of the version number, for example, "20.2.4" + "pip_version_override": None, + # A dictionary you want to inject into your test. Don't put any + # secrets here. These values will override predefined values. + "envs": {}, +} + + +try: + # Ensure we can import noxfile_config in the project's directory. + sys.path.append(".") + from noxfile_config import TEST_CONFIG_OVERRIDE +except ImportError as e: + print("No user noxfile_config found: detail: {}".format(e)) + TEST_CONFIG_OVERRIDE = {} + +# Update the TEST_CONFIG with the user supplied values. +TEST_CONFIG.update(TEST_CONFIG_OVERRIDE) + + +def get_pytest_env_vars() -> Dict[str, str]: + """Returns a dict for pytest invocation.""" + ret = {} + + # Override the GCLOUD_PROJECT and the alias. + env_key = TEST_CONFIG["gcloud_project_env"] + # This should error out if not set. + ret["GOOGLE_CLOUD_PROJECT"] = os.environ[env_key] + + # Apply user supplied envs. + ret.update(TEST_CONFIG["envs"]) + return ret + + +# DO NOT EDIT - automatically generated. +# All versions used to test samples. +ALL_VERSIONS = ["3.6", "3.7", "3.8", "3.9", "3.10"] + +# Any default versions that should be ignored. +IGNORED_VERSIONS = TEST_CONFIG["ignored_versions"] + +TESTED_VERSIONS = sorted([v for v in ALL_VERSIONS if v not in IGNORED_VERSIONS]) + +INSTALL_LIBRARY_FROM_SOURCE = os.environ.get("INSTALL_LIBRARY_FROM_SOURCE", False) in ( + "True", + "true", +) + +# Error if a python version is missing +nox.options.error_on_missing_interpreters = True + +# +# Style Checks +# + + +def _determine_local_import_names(start_dir: str) -> List[str]: + """Determines all import names that should be considered "local". + + This is used when running the linter to insure that import order is + properly checked. + """ + file_ext_pairs = [os.path.splitext(path) for path in os.listdir(start_dir)] + return [ + basename + for basename, extension in file_ext_pairs + if extension == ".py" + or os.path.isdir(os.path.join(start_dir, basename)) + and basename not in ("__pycache__") + ] + + +# Linting with flake8. +# +# We ignore the following rules: +# E203: whitespace before ‘:’ +# E266: too many leading ‘#’ for block comment +# E501: line too long +# I202: Additional newline in a section of imports +# +# We also need to specify the rules which are ignored by default: +# ['E226', 'W504', 'E126', 'E123', 'W503', 'E24', 'E704', 'E121'] +FLAKE8_COMMON_ARGS = [ + "--show-source", + "--builtin=gettext", + "--max-complexity=20", + "--import-order-style=google", + "--exclude=.nox,.cache,env,lib,generated_pb2,*_pb2.py,*_pb2_grpc.py", + "--ignore=E121,E123,E126,E203,E226,E24,E266,E501,E704,W503,W504,I202", + "--max-line-length=88", +] + + +@nox.session +def lint(session: nox.sessions.Session) -> None: + if not TEST_CONFIG["enforce_type_hints"]: + session.install("flake8", "flake8-import-order") + else: + session.install("flake8", "flake8-import-order", "flake8-annotations") + + local_names = _determine_local_import_names(".") + args = FLAKE8_COMMON_ARGS + [ + "--application-import-names", + ",".join(local_names), + ".", + ] + session.run("flake8", *args) + + +# +# Black +# + + +@nox.session +def blacken(session: nox.sessions.Session) -> None: + session.install(BLACK_VERSION) + python_files = [path for path in os.listdir(".") if path.endswith(".py")] + + session.run("black", *python_files) + + +# +# Sample Tests +# + + +PYTEST_COMMON_ARGS = ["--junitxml=sponge_log.xml"] + + +def _session_tests( + session: nox.sessions.Session, post_install: Callable = None +) -> None: + if TEST_CONFIG["pip_version_override"]: + pip_version = TEST_CONFIG["pip_version_override"] + session.install(f"pip=={pip_version}") + """Runs py.test for a particular project.""" + if os.path.exists("requirements.txt"): + if os.path.exists("constraints.txt"): + session.install("-r", "requirements.txt", "-c", "constraints.txt") + else: + session.install("-r", "requirements.txt") + + if os.path.exists("requirements-test.txt"): + if os.path.exists("constraints-test.txt"): + session.install("-r", "requirements-test.txt", "-c", "constraints-test.txt") + else: + session.install("-r", "requirements-test.txt") + + if INSTALL_LIBRARY_FROM_SOURCE: + session.install("-e", _get_repo_root()) + + if post_install: + post_install(session) + + session.run( + "pytest", + *(PYTEST_COMMON_ARGS + session.posargs), + # Pytest will return 5 when no tests are collected. This can happen + # on travis where slow and flaky tests are excluded. + # See http://doc.pytest.org/en/latest/_modules/_pytest/main.html + success_codes=[0, 5], + env=get_pytest_env_vars(), + ) + + +@nox.session(python=ALL_VERSIONS) +def py(session: nox.sessions.Session) -> None: + """Runs py.test for a sample using the specified version of Python.""" + if session.python in TESTED_VERSIONS: + _session_tests(session) + else: + session.skip( + "SKIPPED: {} tests are disabled for this sample.".format(session.python) + ) + + +# +# Readmegen +# + + +def _get_repo_root() -> Optional[str]: + """ Returns the root folder of the project. """ + # Get root of this repository. Assume we don't have directories nested deeper than 10 items. + p = Path(os.getcwd()) + for i in range(10): + if p is None: + break + if Path(p / ".git").exists(): + return str(p) + # .git is not available in repos cloned via Cloud Build + # setup.py is always in the library's root, so use that instead + # https://github.com/googleapis/synthtool/issues/792 + if Path(p / "setup.py").exists(): + return str(p) + p = p.parent + raise Exception("Unable to detect repository root.") + + +GENERATED_READMES = sorted([x for x in Path(".").rglob("*.rst.in")]) + + +@nox.session +@nox.parametrize("path", GENERATED_READMES) +def readmegen(session: nox.sessions.Session, path: str) -> None: + """(Re-)generates the readme for a sample.""" + session.install("jinja2", "pyyaml") + dir_ = os.path.dirname(path) + + if os.path.exists(os.path.join(dir_, "requirements.txt")): + session.install("-r", os.path.join(dir_, "requirements.txt")) + + in_file = os.path.join(dir_, "README.rst.in") + session.run( + "python", _get_repo_root() + "/scripts/readme-gen/readme_gen.py", in_file + ) diff --git a/samples/snippets/noxfile_config.py b/samples/snippets/noxfile_config.py new file mode 100644 index 000000000..463da97de --- /dev/null +++ b/samples/snippets/noxfile_config.py @@ -0,0 +1,96 @@ +# Copyright 2020 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. + +# Default TEST_CONFIG_OVERRIDE for python repos. + +# You can copy this file into your directory, then it will be imported from +# the noxfile.py. + +# The source of truth: +# https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/noxfile_config.py + +import os + + +# We are reaching maximum number of HMAC keys on the service account. +# We change the service account based on the value of +# RUN_TESTS_SESSION. The reason we can not use multiple project is +# that our new projects are enforced to have +# 'constraints/iam.disableServiceAccountKeyCreation' policy. +def get_service_account_email(): + session = os.environ.get('RUN_TESTS_SESSION') + if session == 'py-3.6': + return ('py36-storage-test@' + 'python-docs-samples-tests.iam.gserviceaccount.com') + if session == 'py-3.7': + return ('py37-storage-test@' + 'python-docs-samples-tests.iam.gserviceaccount.com') + if session == 'py-3.8': + return ('py38-storage-test@' + 'python-docs-samples-tests.iam.gserviceaccount.com') + if session == 'py-3.9': + return ('py39-storage-test@' + 'python-docs-samples-tests.iam.gserviceaccount.com') + if session == 'py-3.10': + return ('py310-storage-test@' + 'python-docs-samples-tests.iam.gserviceaccount.com') + return os.environ['HMAC_KEY_TEST_SERVICE_ACCOUNT'] + + +# We change the value of CLOUD_KMS_KEY based on the value of +# RUN_TESTS_SESSION. +def get_cloud_kms_key(): + session = os.environ.get('RUN_TESTS_SESSION') + if session == 'py-3.6': + return ('projects/python-docs-samples-tests-py36/locations/us/' + 'keyRings/gcs-kms-key-ring/cryptoKeys/gcs-kms-key') + if session == 'py-3.7': + return ('projects/python-docs-samples-tests-py37/locations/us/' + 'keyRings/gcs-kms-key-ring/cryptoKeys/gcs-kms-key') + if session == 'py-3.8': + return ('projects/python-docs-samples-tests-py38/locations/us/' + 'keyRings/gcs-kms-key-ring/cryptoKeys/gcs-kms-key') + if session == 'py-3.9': + return ('projects/python-docs-samples-tests-py39/locations/us/' + 'keyRings/gcs-kms-key-ring/cryptoKeys/gcs-kms-key') + if session == 'py-3.10': + return ('projects/python-docs-samples-tests-310/locations/us/' + 'keyRings/gcs-kms-key-ring/cryptoKeys/gcs-kms-key') + return os.environ['CLOUD_KMS_KEY'] + + +TEST_CONFIG_OVERRIDE = { + # You can opt out from the test for specific Python versions. + 'ignored_versions': ["2.7"], + + # An envvar key for determining the project id to use. Change it + # to 'BUILD_SPECIFIC_GCLOUD_PROJECT' if you want to opt in using a + # build specific Cloud project. You can also use your own string + # to use your own Cloud project. + # 'gcloud_project_env': 'GOOGLE_CLOUD_PROJECT', + 'gcloud_project_env': 'BUILD_SPECIFIC_GCLOUD_PROJECT', + + # A dictionary you want to inject into your test. Don't put any + # secrets here. These values will override predefined values. + 'envs': { + 'HMAC_KEY_TEST_SERVICE_ACCOUNT': get_service_account_email(), + 'CLOUD_KMS_KEY': get_cloud_kms_key(), + # Some tests can not use multiple projects because of several reasons: + # 1. The new projects is enforced to have the + # 'constraints/iam.disableServiceAccountKeyCreation' policy. + # 2. The new projects buckets need to have universal permission model. + # For those tests, we'll use the original project. + 'MAIN_GOOGLE_CLOUD_PROJECT': 'python-docs-samples-tests' + }, +} diff --git a/samples/snippets/public_access_prevention_test.py b/samples/snippets/public_access_prevention_test.py new file mode 100644 index 000000000..40d3924b2 --- /dev/null +++ b/samples/snippets/public_access_prevention_test.py @@ -0,0 +1,50 @@ +# Copyright 2021 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 pytest + +import storage_get_public_access_prevention +import storage_set_public_access_prevention_enforced +import storage_set_public_access_prevention_inherited +import storage_set_public_access_prevention_unspecified + + +@pytest.mark.skip(reason="Inconsistent due to unspecified->inherited change") +def test_get_public_access_prevention(bucket, capsys): + short_name = storage_get_public_access_prevention + short_name.get_public_access_prevention(bucket.name) + out, _ = capsys.readouterr() + assert f"Public access prevention is inherited for {bucket.name}." in out + + +def test_set_public_access_prevention_enforced(bucket, capsys): + short_name = storage_set_public_access_prevention_enforced + short_name.set_public_access_prevention_enforced(bucket.name) + out, _ = capsys.readouterr() + assert f"Public access prevention is set to enforced for {bucket.name}." in out + + +@pytest.mark.skip(reason="Inconsistent due to unspecified->inherited change") +def test_set_public_access_prevention_unspecified(bucket, capsys): + short_name = storage_set_public_access_prevention_unspecified + short_name.set_public_access_prevention_unspecified(bucket.name) + out, _ = capsys.readouterr() + assert f"Public access prevention is 'unspecified' for {bucket.name}." in out + + +def test_set_public_access_prevention_inherited(bucket, capsys): + short_name = storage_set_public_access_prevention_inherited + short_name.set_public_access_prevention_inherited(bucket.name) + out, _ = capsys.readouterr() + assert f"Public access prevention is 'inherited' for {bucket.name}." in out diff --git a/samples/snippets/quickstart.py b/samples/snippets/quickstart.py new file mode 100644 index 000000000..578e50753 --- /dev/null +++ b/samples/snippets/quickstart.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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. + + +def run_quickstart(): + # [START storage_quickstart] + # Imports the Google Cloud client library + from google.cloud import storage + + # Instantiates a client + storage_client = storage.Client() + + # The name for the new bucket + bucket_name = "my-new-bucket" + + # Creates the new bucket + bucket = storage_client.create_bucket(bucket_name) + + print("Bucket {} created.".format(bucket.name)) + # [END storage_quickstart] + + +if __name__ == "__main__": + run_quickstart() diff --git a/samples/snippets/quickstart_test.py b/samples/snippets/quickstart_test.py new file mode 100644 index 000000000..f6e06ad93 --- /dev/null +++ b/samples/snippets/quickstart_test.py @@ -0,0 +1,28 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# 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 mock + +import quickstart + + +@mock.patch("google.cloud.storage.client.Client.create_bucket") +def test_quickstart(create_bucket_mock, capsys): + # Unlike other quickstart tests, this one mocks out the creation + # because buckets are expensive, globally-namespaced object. + create_bucket_mock.return_value = mock.sentinel.bucket + + quickstart.run_quickstart() + + create_bucket_mock.assert_called_with("my-new-bucket") diff --git a/samples/snippets/requester_pays_test.py b/samples/snippets/requester_pays_test.py new file mode 100644 index 000000000..9f85c6bdb --- /dev/null +++ b/samples/snippets/requester_pays_test.py @@ -0,0 +1,65 @@ +# Copyright 2017 Google, Inc. +# +# 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 os +import tempfile + +from google.cloud import storage +import pytest + +import storage_disable_requester_pays +import storage_download_file_requester_pays +import storage_enable_requester_pays +import storage_get_requester_pays_status + + +# We use a different bucket from other tests. +BUCKET = os.environ["REQUESTER_PAYS_TEST_BUCKET"] +PROJECT = os.environ["GOOGLE_CLOUD_PROJECT"] + + +def test_enable_requester_pays(capsys): + storage_enable_requester_pays.enable_requester_pays(BUCKET) + out, _ = capsys.readouterr() + assert "Requester Pays has been enabled for {}".format(BUCKET) in out + + +def test_disable_requester_pays(capsys): + storage_disable_requester_pays.disable_requester_pays(BUCKET) + out, _ = capsys.readouterr() + assert "Requester Pays has been disabled for {}".format(BUCKET) in out + + +def test_get_requester_pays_status(capsys): + storage_get_requester_pays_status.get_requester_pays_status(BUCKET) + out, _ = capsys.readouterr() + assert "Requester Pays is disabled for {}".format(BUCKET) in out + + +@pytest.fixture +def test_blob(): + """Provides a pre-existing blob in the test bucket.""" + bucket = storage.Client().bucket(BUCKET) + blob = bucket.blob("storage_snippets_test_sigil") + blob.upload_from_string("Hello, is it me you're looking for?") + return blob + + +def test_download_file_requester_pays(test_blob, capsys): + with tempfile.NamedTemporaryFile() as dest_file: + storage_download_file_requester_pays.download_file_requester_pays( + BUCKET, PROJECT, test_blob.name, dest_file.name + ) + + assert dest_file.read() diff --git a/samples/snippets/requirements-test.txt b/samples/snippets/requirements-test.txt new file mode 100644 index 000000000..2b550f467 --- /dev/null +++ b/samples/snippets/requirements-test.txt @@ -0,0 +1,3 @@ +pytest==6.2.4 +mock==4.0.3 +backoff==1.11.1 \ No newline at end of file diff --git a/samples/snippets/requirements.txt b/samples/snippets/requirements.txt new file mode 100644 index 000000000..76ac6ee7c --- /dev/null +++ b/samples/snippets/requirements.txt @@ -0,0 +1,3 @@ +google-cloud-pubsub==2.8.0 +google-cloud-storage==1.42.3 +google-api-python-client==2.25.0 diff --git a/samples/snippets/snippets_test.py b/samples/snippets/snippets_test.py new file mode 100644 index 000000000..dd8e6aeaf --- /dev/null +++ b/samples/snippets/snippets_test.py @@ -0,0 +1,511 @@ +# Copyright 2016 Google, Inc. +# +# 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 os +import tempfile +import time +import uuid + +from google.cloud import storage +import google.cloud.exceptions +import pytest +import requests + +import storage_add_bucket_label +import storage_bucket_delete_default_kms_key +import storage_change_default_storage_class +import storage_change_file_storage_class +import storage_compose_file +import storage_configure_retries +import storage_copy_file +import storage_copy_file_archived_generation +import storage_cors_configuration +import storage_create_bucket_class_location +import storage_define_bucket_website_configuration +import storage_delete_file +import storage_delete_file_archived_generation +import storage_disable_bucket_lifecycle_management +import storage_disable_versioning +import storage_download_file +import storage_download_public_file +import storage_enable_bucket_lifecycle_management +import storage_enable_versioning +import storage_generate_signed_post_policy_v4 +import storage_generate_signed_url_v2 +import storage_generate_signed_url_v4 +import storage_generate_upload_signed_url_v4 +import storage_get_bucket_labels +import storage_get_bucket_metadata +import storage_get_metadata +import storage_get_service_account +import storage_list_buckets +import storage_list_file_archived_generations +import storage_list_files +import storage_list_files_with_prefix +import storage_make_public +import storage_move_file +import storage_object_get_kms_key +import storage_remove_bucket_label +import storage_remove_cors_configuration +import storage_rename_file +import storage_set_bucket_default_kms_key +import storage_set_metadata +import storage_upload_file +import storage_upload_with_kms_key + +KMS_KEY = os.environ["CLOUD_KMS_KEY"] + + +def test_enable_default_kms_key(test_bucket): + storage_set_bucket_default_kms_key.enable_default_kms_key( + bucket_name=test_bucket.name, kms_key_name=KMS_KEY + ) + time.sleep(2) # Let change propagate as needed + bucket = storage.Client().get_bucket(test_bucket.name) + assert bucket.default_kms_key_name.startswith(KMS_KEY) + bucket.default_kms_key_name = None + bucket.patch() + + +def test_get_bucket_labels(test_bucket): + storage_get_bucket_labels.get_bucket_labels(test_bucket.name) + + +def test_add_bucket_label(test_bucket, capsys): + storage_add_bucket_label.add_bucket_label(test_bucket.name) + out, _ = capsys.readouterr() + assert "example" in out + + +def test_remove_bucket_label(test_bucket, capsys): + storage_add_bucket_label.add_bucket_label(test_bucket.name) + storage_remove_bucket_label.remove_bucket_label(test_bucket.name) + out, _ = capsys.readouterr() + assert "Removed labels" in out + + +@pytest.fixture(scope="module") +def test_bucket(): + """Yields a bucket that is deleted after the test completes.""" + bucket = None + while bucket is None or bucket.exists(): + bucket_name = "storage-snippets-test-{}".format(uuid.uuid4()) + bucket = storage.Client().bucket(bucket_name) + bucket.create() + yield bucket + bucket.delete(force=True) + + +@pytest.fixture(scope="function") +def test_public_bucket(): + # The new projects don't allow to make a bucket available to public, so + # for some tests we need to use the old main project for now. + original_value = os.environ['GOOGLE_CLOUD_PROJECT'] + os.environ['GOOGLE_CLOUD_PROJECT'] = os.environ['MAIN_GOOGLE_CLOUD_PROJECT'] + bucket = None + while bucket is None or bucket.exists(): + storage_client = storage.Client() + bucket_name = "storage-snippets-test-{}".format(uuid.uuid4()) + bucket = storage_client.bucket(bucket_name) + storage_client.create_bucket(bucket) + yield bucket + bucket.delete(force=True) + # Set the value back. + os.environ['GOOGLE_CLOUD_PROJECT'] = original_value + + +@pytest.fixture +def test_blob(test_bucket): + """Yields a blob that is deleted after the test completes.""" + bucket = test_bucket + blob = bucket.blob("storage_snippets_test_sigil-{}".format(uuid.uuid4())) + blob.upload_from_string("Hello, is it me you're looking for?") + yield blob + + +@pytest.fixture(scope="function") +def test_public_blob(test_public_bucket): + """Yields a blob that is deleted after the test completes.""" + bucket = test_public_bucket + blob = bucket.blob("storage_snippets_test_sigil-{}".format(uuid.uuid4())) + blob.upload_from_string("Hello, is it me you're looking for?") + yield blob + + +@pytest.fixture +def test_bucket_create(): + """Yields a bucket object that is deleted after the test completes.""" + bucket = None + while bucket is None or bucket.exists(): + bucket_name = "storage-snippets-test-{}".format(uuid.uuid4()) + bucket = storage.Client().bucket(bucket_name) + yield bucket + bucket.delete(force=True) + + +def test_list_buckets(test_bucket, capsys): + storage_list_buckets.list_buckets() + out, _ = capsys.readouterr() + assert test_bucket.name in out + + +def test_list_blobs(test_blob, capsys): + storage_list_files.list_blobs(test_blob.bucket.name) + out, _ = capsys.readouterr() + assert test_blob.name in out + + +def test_bucket_metadata(test_bucket, capsys): + storage_get_bucket_metadata.bucket_metadata(test_bucket.name) + out, _ = capsys.readouterr() + assert test_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" + ) + out, _ = capsys.readouterr() + assert test_blob.name in out + + +def test_upload_blob(test_bucket): + with tempfile.NamedTemporaryFile() as source_file: + source_file.write(b"test") + + storage_upload_file.upload_blob( + test_bucket.name, source_file.name, "test_upload_blob" + ) + + +def test_upload_blob_with_kms(test_bucket): + with tempfile.NamedTemporaryFile() as source_file: + source_file.write(b"test") + storage_upload_with_kms_key.upload_blob_with_kms( + test_bucket.name, source_file.name, "test_upload_blob_encrypted", KMS_KEY + ) + bucket = storage.Client().bucket(test_bucket.name) + kms_blob = bucket.get_blob("test_upload_blob_encrypted") + assert kms_blob.kms_key_name.startswith(KMS_KEY) + + +def test_download_blob(test_blob): + with tempfile.NamedTemporaryFile() as dest_file: + storage_download_file.download_blob( + test_blob.bucket.name, test_blob.name, dest_file.name + ) + + assert dest_file.read() + + +def test_blob_metadata(test_blob, capsys): + storage_get_metadata.blob_metadata(test_blob.bucket.name, test_blob.name) + out, _ = capsys.readouterr() + assert test_blob.name in out + + +def test_set_blob_metadata(test_blob, capsys): + storage_set_metadata.set_blob_metadata(test_blob.bucket.name, test_blob.name) + out, _ = capsys.readouterr() + assert test_blob.name in out + + +def test_delete_blob(test_blob): + storage_delete_file.delete_blob(test_blob.bucket.name, test_blob.name) + + +def test_make_blob_public(test_public_blob): + storage_make_public.make_blob_public( + test_public_blob.bucket.name, test_public_blob.name) + + r = requests.get(test_public_blob.public_url) + assert r.text == "Hello, is it me you're looking for?" + + +def test_generate_signed_url(test_blob, capsys): + url = storage_generate_signed_url_v2.generate_signed_url( + test_blob.bucket.name, test_blob.name + ) + + r = requests.get(url) + assert r.text == "Hello, is it me you're looking for?" + + +def test_generate_download_signed_url_v4(test_blob, capsys): + url = storage_generate_signed_url_v4.generate_download_signed_url_v4( + test_blob.bucket.name, test_blob.name + ) + + r = requests.get(url) + assert r.text == "Hello, is it me you're looking for?" + + +def test_generate_upload_signed_url_v4(test_bucket, capsys): + blob_name = "storage_snippets_test_upload" + content = b"Uploaded via v4 signed url" + url = storage_generate_upload_signed_url_v4.generate_upload_signed_url_v4( + test_bucket.name, blob_name + ) + + requests.put( + url, data=content, headers={"content-type": "application/octet-stream"}, + ) + + bucket = storage.Client().bucket(test_bucket.name) + blob = bucket.blob(blob_name) + assert blob.download_as_string() == content + + +def test_generate_signed_policy_v4(test_bucket, capsys): + blob_name = "storage_snippets_test_form" + short_name = storage_generate_signed_post_policy_v4 + form = short_name.generate_signed_post_policy_v4(test_bucket.name, blob_name) + assert "name='key' value='{}'".format(blob_name) in form + assert "name='x-goog-signature'" in form + assert "name='x-goog-date'" in form + assert "name='x-goog-credential'" in form + assert "name='x-goog-algorithm' value='GOOG4-RSA-SHA256'" in form + assert "name='policy'" in form + assert "name='x-goog-meta-test' value='data'" in form + assert "type='file' name='file'/>" in form + + +def test_rename_blob(test_blob): + bucket = storage.Client().bucket(test_blob.bucket.name) + + try: + bucket.delete_blob("test_rename_blob") + except google.cloud.exceptions.exceptions.NotFound: + print("test_rename_blob not found in bucket {}".format(bucket.name)) + + storage_rename_file.rename_blob(bucket.name, test_blob.name, "test_rename_blob") + + assert bucket.get_blob("test_rename_blob") is not None + assert bucket.get_blob(test_blob.name) is None + + +def test_move_blob(test_bucket_create, test_blob): + bucket = test_blob.bucket + storage.Client().create_bucket(test_bucket_create) + + try: + test_bucket_create.delete_blob("test_move_blob") + except google.cloud.exceptions.NotFound: + print("test_move_blob not found in bucket {}".format(test_bucket_create.name)) + + storage_move_file.move_blob( + bucket.name, test_blob.name, test_bucket_create.name, "test_move_blob" + ) + + assert test_bucket_create.get_blob("test_move_blob") is not None + assert bucket.get_blob(test_blob.name) is None + + +def test_copy_blob(test_blob): + bucket = storage.Client().bucket(test_blob.bucket.name) + + try: + bucket.delete_blob("test_copy_blob") + except google.cloud.exceptions.NotFound: + pass + + storage_copy_file.copy_blob( + bucket.name, test_blob.name, bucket.name, "test_copy_blob" + ) + + assert bucket.get_blob("test_copy_blob") is not None + assert bucket.get_blob(test_blob.name) is not None + + +def test_versioning(test_bucket, capsys): + bucket = storage_enable_versioning.enable_versioning(test_bucket) + out, _ = capsys.readouterr() + assert "Versioning was enabled for bucket" in out + assert bucket.versioning_enabled is True + + bucket = storage_disable_versioning.disable_versioning(test_bucket) + out, _ = capsys.readouterr() + assert "Versioning was disabled for bucket" in out + assert bucket.versioning_enabled is False + + +def test_bucket_lifecycle_management(test_bucket, capsys): + bucket = storage_enable_bucket_lifecycle_management.enable_bucket_lifecycle_management( + test_bucket + ) + out, _ = capsys.readouterr() + assert "[]" in out + assert "Lifecycle management is enable" in out + assert len(list(bucket.lifecycle_rules)) > 0 + + bucket = storage_disable_bucket_lifecycle_management.disable_bucket_lifecycle_management( + test_bucket + ) + out, _ = capsys.readouterr() + assert "[]" in out + assert len(list(bucket.lifecycle_rules)) == 0 + + +def test_create_bucket_class_location(test_bucket_create): + bucket = storage_create_bucket_class_location.create_bucket_class_location( + test_bucket_create.name + ) + + assert bucket.location == "US" + assert bucket.storage_class == "COLDLINE" + + +def test_bucket_delete_default_kms_key(test_bucket, capsys): + test_bucket.default_kms_key_name = KMS_KEY + test_bucket.patch() + + assert test_bucket.default_kms_key_name == KMS_KEY + + bucket = storage_bucket_delete_default_kms_key.bucket_delete_default_kms_key( + test_bucket.name + ) + + out, _ = capsys.readouterr() + assert bucket.default_kms_key_name is None + assert bucket.name in out + + +def test_get_service_account(capsys): + storage_get_service_account.get_service_account() + + out, _ = capsys.readouterr() + + assert "@gs-project-accounts.iam.gserviceaccount.com" in out + + +def test_download_public_file(test_public_blob): + storage_make_public.make_blob_public( + test_public_blob.bucket.name, test_public_blob.name) + with tempfile.NamedTemporaryFile() as dest_file: + storage_download_public_file.download_public_file( + test_public_blob.bucket.name, test_public_blob.name, dest_file.name + ) + + assert dest_file.read() == b"Hello, is it me you're looking for?" + + +def test_define_bucket_website_configuration(test_bucket): + bucket = storage_define_bucket_website_configuration.define_bucket_website_configuration( + test_bucket.name, "index.html", "404.html" + ) + + website_val = {"mainPageSuffix": "index.html", "notFoundPage": "404.html"} + + assert bucket._properties["website"] == website_val + + +def test_object_get_kms_key(test_bucket): + with tempfile.NamedTemporaryFile() as source_file: + storage_upload_with_kms_key.upload_blob_with_kms( + test_bucket.name, source_file.name, "test_upload_blob_encrypted", KMS_KEY + ) + kms_key = storage_object_get_kms_key.object_get_kms_key( + test_bucket.name, "test_upload_blob_encrypted" + ) + + assert kms_key.startswith(KMS_KEY) + + +def test_storage_compose_file(test_bucket): + source_files = ["test_upload_blob_1", "test_upload_blob_2"] + for source in source_files: + blob = test_bucket.blob(source) + blob.upload_from_string(source) + + with tempfile.NamedTemporaryFile() as dest_file: + destination = storage_compose_file.compose_file( + test_bucket.name, source_files[0], source_files[1], dest_file.name + ) + composed = destination.download_as_string() + + assert composed.decode("utf-8") == source_files[0] + source_files[1] + + +def test_cors_configuration(test_bucket, capsys): + bucket = storage_cors_configuration.cors_configuration(test_bucket) + out, _ = capsys.readouterr() + assert "Set CORS policies for bucket" in out + assert len(bucket.cors) > 0 + + bucket = storage_remove_cors_configuration.remove_cors_configuration(test_bucket) + out, _ = capsys.readouterr() + assert "Remove CORS policies for bucket" in out + assert len(bucket.cors) == 0 + + +def test_delete_blobs_archived_generation(test_blob, capsys): + storage_delete_file_archived_generation.delete_file_archived_generation( + test_blob.bucket.name, test_blob.name, test_blob.generation + ) + out, _ = capsys.readouterr() + assert "blob " + test_blob.name + " was deleted" in out + blob = test_blob.bucket.get_blob(test_blob.name, generation=test_blob.generation) + assert blob is None + + +def test_change_default_storage_class(test_bucket, capsys): + bucket = storage_change_default_storage_class.change_default_storage_class( + test_bucket + ) + out, _ = capsys.readouterr() + assert "Default storage class for bucket" in out + assert bucket.storage_class == 'COLDLINE' + + +def test_change_file_storage_class(test_blob, capsys): + blob = storage_change_file_storage_class.change_file_storage_class( + test_blob.bucket.name, test_blob.name + ) + out, _ = capsys.readouterr() + assert "Blob {} in bucket {}". format(blob.name, blob.bucket.name) in out + assert blob.storage_class == 'NEARLINE' + + +def test_copy_file_archived_generation(test_blob): + bucket = storage.Client().bucket(test_blob.bucket.name) + + try: + bucket.delete_blob("test_copy_blob") + except google.cloud.exceptions.NotFound: + pass + + storage_copy_file_archived_generation.copy_file_archived_generation( + bucket.name, test_blob.name, bucket.name, "test_copy_blob", test_blob.generation + ) + + assert bucket.get_blob("test_copy_blob") is not None + assert bucket.get_blob(test_blob.name) is not None + + +def test_list_blobs_archived_generation(test_blob, capsys): + storage_list_file_archived_generations.list_file_archived_generations( + test_blob.bucket.name + ) + out, _ = capsys.readouterr() + assert str(test_blob.generation) in out + + +def test_storage_configure_retries(test_blob, capsys): + storage_configure_retries.configure_retries(test_blob.bucket.name, test_blob.name) + + # This simply checks if the retry configurations were set and printed as intended. + out, _ = capsys.readouterr() + assert "The following library method is customized to be retried" in out + assert "_should_retry" in out + assert "initial=1.5, maximum=45.0, multiplier=1.2, deadline=500.0" in out diff --git a/samples/snippets/storage_activate_hmac_key.py b/samples/snippets/storage_activate_hmac_key.py new file mode 100644 index 000000000..e77cd8066 --- /dev/null +++ b/samples/snippets/storage_activate_hmac_key.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_activate_hmac_key] +from google.cloud import storage + + +def activate_key(access_id, project_id): + """ + Activate the HMAC key with the given access ID. + """ + # project_id = "Your Google Cloud project ID" + # access_id = "ID of an inactive HMAC key" + + storage_client = storage.Client(project=project_id) + + hmac_key = storage_client.get_hmac_key_metadata( + access_id, project_id=project_id + ) + hmac_key.state = "ACTIVE" + hmac_key.update() + + print("The HMAC key metadata is:") + print("Service Account Email: {}".format(hmac_key.service_account_email)) + print("Key ID: {}".format(hmac_key.id)) + print("Access ID: {}".format(hmac_key.access_id)) + print("Project ID: {}".format(hmac_key.project)) + print("State: {}".format(hmac_key.state)) + print("Created At: {}".format(hmac_key.time_created)) + print("Updated At: {}".format(hmac_key.updated)) + print("Etag: {}".format(hmac_key.etag)) + return hmac_key + + +# [END storage_activate_hmac_key] + +if __name__ == "__main__": + activate_key(access_id=sys.argv[1], project_id=sys.argv[2]) diff --git a/samples/snippets/storage_add_bucket_conditional_iam_binding.py b/samples/snippets/storage_add_bucket_conditional_iam_binding.py new file mode 100644 index 000000000..ddc0fc028 --- /dev/null +++ b/samples/snippets/storage_add_bucket_conditional_iam_binding.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC. All Rights Reserved +# +# 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_add_bucket_conditional_iam_binding] +from google.cloud import storage + + +def add_bucket_conditional_iam_binding( + bucket_name, role, title, description, expression, members +): + """Add a conditional IAM binding to a bucket's IAM policy.""" + # bucket_name = "your-bucket-name" + # role = "IAM role, e.g. roles/storage.objectViewer" + # members = {"IAM identity, e.g. user: name@example.com}" + # title = "Condition title." + # description = "Condition description." + # expression = "Condition expression." + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + + policy = bucket.get_iam_policy(requested_policy_version=3) + + # Set the policy's version to 3 to use condition in bindings. + policy.version = 3 + + policy.bindings.append( + { + "role": role, + "members": members, + "condition": { + "title": title, + "description": description, + "expression": expression, + }, + } + ) + + bucket.set_iam_policy(policy) + + print("Added the following member(s) with role {} to {}:".format(role, bucket_name)) + + for member in members: + print(" {}".format(member)) + + print("with condition:") + print(" Title: {}".format(title)) + print(" Description: {}".format(description)) + print(" Expression: {}".format(expression)) + + +# [END storage_add_bucket_conditional_iam_binding] + + +if __name__ == "__main__": + add_bucket_conditional_iam_binding( + bucket_name=sys.argv[1], + role=sys.argv[2], + title=sys.argv[3], + description=sys.argv[4], + expression=sys.argv[5], + members=set(sys.argv[6::]), + ) diff --git a/samples/snippets/storage_add_bucket_default_owner.py b/samples/snippets/storage_add_bucket_default_owner.py new file mode 100644 index 000000000..932b1328f --- /dev/null +++ b/samples/snippets/storage_add_bucket_default_owner.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python + +# Copyright 2019 Google, Inc. +# +# 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_add_bucket_default_owner] +from google.cloud import storage + + +def add_bucket_default_owner(bucket_name, user_email): + """Adds a user as an owner in the given bucket's default object access + control list.""" + # bucket_name = "your-bucket-name" + # user_email = "name@example.com" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + + # Reload fetches the current ACL from Cloud Storage. + bucket.acl.reload() + + # You can also use `group`, `domain`, `all_authenticated` and `all` to + # grant access to different types of entities. You can also use + # `grant_read` or `grant_write` to grant different roles. + bucket.default_object_acl.user(user_email).grant_owner() + bucket.default_object_acl.save() + + print( + "Added user {} as an owner in the default acl on bucket {}.".format( + user_email, bucket_name + ) + ) + + +# [END storage_add_bucket_default_owner] + +if __name__ == "__main__": + add_bucket_default_owner(bucket_name=sys.argv[1], user_email=sys.argv[2]) diff --git a/samples/snippets/storage_add_bucket_iam_member.py b/samples/snippets/storage_add_bucket_iam_member.py new file mode 100644 index 000000000..727f18483 --- /dev/null +++ b/samples/snippets/storage_add_bucket_iam_member.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_add_bucket_iam_member] +from google.cloud import storage + + +def add_bucket_iam_member(bucket_name, role, member): + """Add a new member to an IAM Policy""" + # bucket_name = "your-bucket-name" + # role = "IAM role, e.g., roles/storage.objectViewer" + # member = "IAM identity, e.g., user: name@example.com" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + + policy = bucket.get_iam_policy(requested_policy_version=3) + + policy.bindings.append({"role": role, "members": {member}}) + + bucket.set_iam_policy(policy) + + print("Added {} with role {} to {}.".format(member, role, bucket_name)) + + +# [END storage_add_bucket_iam_member] + + +if __name__ == "__main__": + add_bucket_iam_member(bucket_name=sys.argv[1], role=sys.argv[2], member=sys.argv[3]) diff --git a/samples/snippets/storage_add_bucket_label.py b/samples/snippets/storage_add_bucket_label.py new file mode 100644 index 000000000..8ae8fe1f4 --- /dev/null +++ b/samples/snippets/storage_add_bucket_label.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_add_bucket_label] +import pprint +# [END storage_add_bucket_label] +import sys +# [START storage_add_bucket_label] + +from google.cloud import storage + + +def add_bucket_label(bucket_name): + """Add a label to a bucket.""" + # bucket_name = "your-bucket-name" + + storage_client = storage.Client() + + bucket = storage_client.get_bucket(bucket_name) + labels = bucket.labels + labels["example"] = "label" + bucket.labels = labels + bucket.patch() + + print("Updated labels on {}.".format(bucket.name)) + pprint.pprint(bucket.labels) + + +# [END storage_add_bucket_label] + +if __name__ == "__main__": + add_bucket_label(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_add_bucket_owner.py b/samples/snippets/storage_add_bucket_owner.py new file mode 100644 index 000000000..acdb60dc5 --- /dev/null +++ b/samples/snippets/storage_add_bucket_owner.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python + +# Copyright 2019 Google, Inc. +# +# 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_add_bucket_owner] +from google.cloud import storage + + +def add_bucket_owner(bucket_name, user_email): + """Adds a user as an owner on the given bucket.""" + # bucket_name = "your-bucket-name" + # user_email = "name@example.com" + + storage_client = storage.Client() + + bucket = storage_client.bucket(bucket_name) + + # Reload fetches the current ACL from Cloud Storage. + bucket.acl.reload() + + # You can also use `group()`, `domain()`, `all_authenticated()` and `all()` + # to grant access to different types of entities. + # You can also use `grant_read()` or `grant_write()` to grant different + # roles. + bucket.acl.user(user_email).grant_owner() + bucket.acl.save() + + print( + "Added user {} as an owner on bucket {}.".format( + user_email, bucket_name + ) + ) + + +# [END storage_add_bucket_owner] + +if __name__ == "__main__": + add_bucket_owner(bucket_name=sys.argv[1], user_email=sys.argv[2]) diff --git a/samples/snippets/storage_add_file_owner.py b/samples/snippets/storage_add_file_owner.py new file mode 100644 index 000000000..9e9342590 --- /dev/null +++ b/samples/snippets/storage_add_file_owner.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +# Copyright 2019 Google, Inc. +# +# 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_add_file_owner] +from google.cloud import storage + + +def add_blob_owner(bucket_name, blob_name, user_email): + """Adds a user as an owner on the given blob.""" + # bucket_name = "your-bucket-name" + # blob_name = "your-object-name" + # user_email = "name@example.com" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + blob = bucket.blob(blob_name) + + # Reload fetches the current ACL from Cloud Storage. + blob.acl.reload() + + # You can also use `group`, `domain`, `all_authenticated` and `all` to + # grant access to different types of entities. You can also use + # `grant_read` or `grant_write` to grant different roles. + blob.acl.user(user_email).grant_owner() + blob.acl.save() + + print( + "Added user {} as an owner on blob {} in bucket {}.".format( + user_email, blob_name, bucket_name + ) + ) + + +# [END storage_add_file_owner] + +if __name__ == "__main__": + add_blob_owner( + bucket_name=sys.argv[1], blob_name=sys.argv[2], user_email=sys.argv[3], + ) diff --git a/samples/snippets/storage_bucket_delete_default_kms_key.py b/samples/snippets/storage_bucket_delete_default_kms_key.py new file mode 100644 index 000000000..3df23767d --- /dev/null +++ b/samples/snippets/storage_bucket_delete_default_kms_key.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC. All Rights Reserved. +# +# 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_bucket_delete_default_kms_key] +from google.cloud import storage + + +def bucket_delete_default_kms_key(bucket_name): + """Delete a default KMS key of bucket""" + # bucket_name = "your-bucket-name" + + storage_client = storage.Client() + + bucket = storage_client.get_bucket(bucket_name) + bucket.default_kms_key_name = None + bucket.patch() + + print("Default KMS key was removed from {}".format(bucket.name)) + return bucket + + +# [END storage_bucket_delete_default_kms_key] + +if __name__ == "__main__": + bucket_delete_default_kms_key(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_change_default_storage_class.py b/samples/snippets/storage_change_default_storage_class.py new file mode 100644 index 000000000..8a72719ba --- /dev/null +++ b/samples/snippets/storage_change_default_storage_class.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC. All Rights Reserved. +# +# 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_change_default_storage_class] +from google.cloud import storage +from google.cloud.storage import constants + + +def change_default_storage_class(bucket_name): + """Change the default storage class of the bucket""" + # bucket_name = "your-bucket-name" + + storage_client = storage.Client() + + bucket = storage_client.get_bucket(bucket_name) + bucket.storage_class = constants.COLDLINE_STORAGE_CLASS + bucket.patch() + + print("Default storage class for bucket {} has been set to {}".format(bucket_name, bucket.storage_class)) + return bucket + + +# [END storage_change_default_storage_class] + +if __name__ == "__main__": + change_default_storage_class(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_change_file_storage_class.py b/samples/snippets/storage_change_file_storage_class.py new file mode 100644 index 000000000..d5dda56a7 --- /dev/null +++ b/samples/snippets/storage_change_file_storage_class.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC. All Rights Reserved. +# +# 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_change_file_storage_class] +from google.cloud import storage + + +def change_file_storage_class(bucket_name, blob_name): + """Change the default storage class of the blob""" + # bucket_name = "your-bucket-name" + # blob_name = "your-object-name" + + storage_client = storage.Client() + + bucket = storage_client.get_bucket(bucket_name) + blob = bucket.get_blob(blob_name) + blob.update_storage_class("NEARLINE") + + print( + "Blob {} in bucket {} had its storage class set to {}".format( + blob_name, + bucket_name, + blob.storage_class + ) + ) + return blob +# [END storage_change_file_storage_class] + + +if __name__ == "__main__": + change_file_storage_class(bucket_name=sys.argv[1], blob_name=sys.argv[2]) diff --git a/samples/snippets/storage_compose_file.py b/samples/snippets/storage_compose_file.py new file mode 100644 index 000000000..2c1443f22 --- /dev/null +++ b/samples/snippets/storage_compose_file.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC. All Rights Reserved. +# +# 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_compose_file] +from google.cloud import storage + + +def compose_file(bucket_name, first_blob_name, second_blob_name, destination_blob_name): + """Concatenate source blobs into destination blob.""" + # bucket_name = "your-bucket-name" + # first_blob_name = "first-object-name" + # second_blob_name = "second-blob-name" + # destination_blob_name = "destination-object-name" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + destination = bucket.blob(destination_blob_name) + destination.content_type = "text/plain" + + # sources is a list of Blob instances, up to the max of 32 instances per request + sources = [bucket.get_blob(first_blob_name), bucket.get_blob(second_blob_name)] + destination.compose(sources) + + print( + "New composite object {} in the bucket {} was created by combining {} and {}".format( + destination_blob_name, bucket_name, first_blob_name, second_blob_name + ) + ) + return destination + + +# [END storage_compose_file] + +if __name__ == "__main__": + compose_file( + bucket_name=sys.argv[1], + first_blob_name=sys.argv[2], + second_blob_name=sys.argv[3], + destination_blob_name=sys.argv[4], + ) diff --git a/samples/snippets/storage_configure_retries.py b/samples/snippets/storage_configure_retries.py new file mode 100644 index 000000000..9543111b3 --- /dev/null +++ b/samples/snippets/storage_configure_retries.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +# Copyright 2021 Google LLC. All Rights Reserved. +# +# 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 + +"""Sample that configures retries on an operation call. +This sample is used on this page: + https://cloud.google.com/storage/docs/retry-strategy +For more information, see README.md. +""" + +# [START storage_configure_retries] +from google.cloud import storage +from google.cloud.storage.retry import DEFAULT_RETRY + + +def configure_retries(bucket_name, blob_name): + """Configures retries with customizations.""" + # The ID of your GCS bucket + # bucket_name = "your-bucket-name" + # The ID of your GCS object + # blob_name = "your-object-name" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + blob = bucket.blob(blob_name) + + # Customize retry with a deadline of 500 seconds (default=120 seconds). + modified_retry = DEFAULT_RETRY.with_deadline(500.0) + # Customize retry with an initial wait time of 1.5 (default=1.0). + # Customize retry with a wait time multiplier per iteration of 1.2 (default=2.0). + # Customize retry with a maximum wait time of 45.0 (default=60.0). + modified_retry = modified_retry.with_delay(initial=1.5, multiplier=1.2, maximum=45.0) + + # blob.delete() uses DEFAULT_RETRY_IF_GENERATION_SPECIFIED by default. + # Override with modified_retry so the function retries even if the generation + # number is not specified. + print( + f"The following library method is customized to be retried according to the following configurations: {modified_retry}" + ) + + blob.delete(retry=modified_retry) + print("Blob {} deleted with a customized retry strategy.".format(blob_name)) + + +# [END storage_configure_retries] + + +if __name__ == "__main__": + configure_retries(bucket_name=sys.argv[1], blob_name=sys.argv[2]) diff --git a/samples/snippets/storage_copy_file.py b/samples/snippets/storage_copy_file.py new file mode 100644 index 000000000..5d36aa94b --- /dev/null +++ b/samples/snippets/storage_copy_file.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_copy_file] +from google.cloud import storage + + +def copy_blob( + bucket_name, blob_name, destination_bucket_name, destination_blob_name +): + """Copies a blob from one bucket to another with a new name.""" + # bucket_name = "your-bucket-name" + # blob_name = "your-object-name" + # destination_bucket_name = "destination-bucket-name" + # destination_blob_name = "destination-object-name" + + storage_client = storage.Client() + + source_bucket = storage_client.bucket(bucket_name) + source_blob = source_bucket.blob(blob_name) + destination_bucket = storage_client.bucket(destination_bucket_name) + + blob_copy = source_bucket.copy_blob( + source_blob, destination_bucket, destination_blob_name + ) + + print( + "Blob {} in bucket {} copied to blob {} in bucket {}.".format( + source_blob.name, + source_bucket.name, + blob_copy.name, + destination_bucket.name, + ) + ) + + +# [END storage_copy_file] + +if __name__ == "__main__": + copy_blob( + bucket_name=sys.argv[1], + blob_name=sys.argv[2], + destination_bucket_name=sys.argv[3], + destination_blob_name=sys.argv[4], + ) diff --git a/samples/snippets/storage_copy_file_archived_generation.py b/samples/snippets/storage_copy_file_archived_generation.py new file mode 100644 index 000000000..988ebcbeb --- /dev/null +++ b/samples/snippets/storage_copy_file_archived_generation.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC. All Rights Reserved. +# +# 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_copy_file_archived_generation] +from google.cloud import storage + + +def copy_file_archived_generation( + bucket_name, blob_name, destination_bucket_name, destination_blob_name, generation +): + """Copies a blob from one bucket to another with a new name with the same generation.""" + # bucket_name = "your-bucket-name" + # blob_name = "your-object-name" + # destination_bucket_name = "destination-bucket-name" + # destination_blob_name = "destination-object-name" + # generation = 1579287380533984 + + storage_client = storage.Client() + + source_bucket = storage_client.bucket(bucket_name) + source_blob = source_bucket.blob(blob_name) + destination_bucket = storage_client.bucket(destination_bucket_name) + + blob_copy = source_bucket.copy_blob( + source_blob, destination_bucket, destination_blob_name, source_generation=generation + ) + + print( + "Generation {} of the blob {} in bucket {} copied to blob {} in bucket {}.".format( + source_blob.generation, + source_blob.name, + source_bucket.name, + blob_copy.name, + destination_bucket.name, + ) + ) + + +# [END storage_copy_file_archived_generation] + +if __name__ == "__main__": + copy_file_archived_generation( + bucket_name=sys.argv[1], + blob_name=sys.argv[2], + destination_bucket_name=sys.argv[3], + destination_blob_name=sys.argv[4], + generation=sys.argv[5] + ) diff --git a/samples/snippets/storage_cors_configuration.py b/samples/snippets/storage_cors_configuration.py new file mode 100644 index 000000000..3d2595a9d --- /dev/null +++ b/samples/snippets/storage_cors_configuration.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC. All Rights Reserved. +# +# 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_cors_configuration] +from google.cloud import storage + + +def cors_configuration(bucket_name): + """Set a bucket's CORS policies configuration.""" + # bucket_name = "your-bucket-name" + + storage_client = storage.Client() + bucket = storage_client.get_bucket(bucket_name) + bucket.cors = [ + { + "origin": ["*"], + "responseHeader": [ + "Content-Type", + "x-goog-resumable"], + "method": ['PUT', 'POST'], + "maxAgeSeconds": 3600 + } + ] + bucket.patch() + + print("Set CORS policies for bucket {} is {}".format(bucket.name, bucket.cors)) + return bucket + + +# [END storage_cors_configuration] + +if __name__ == "__main__": + cors_configuration(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_create_bucket.py b/samples/snippets/storage_create_bucket.py new file mode 100644 index 000000000..aaee9e234 --- /dev/null +++ b/samples/snippets/storage_create_bucket.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_create_bucket] +from google.cloud import storage + + +def create_bucket(bucket_name): + """Creates a new bucket.""" + # bucket_name = "your-new-bucket-name" + + storage_client = storage.Client() + + bucket = storage_client.create_bucket(bucket_name) + + print("Bucket {} created".format(bucket.name)) + + +# [END storage_create_bucket] + +if __name__ == "__main__": + create_bucket(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_create_bucket_class_location.py b/samples/snippets/storage_create_bucket_class_location.py new file mode 100644 index 000000000..64c2652d7 --- /dev/null +++ b/samples/snippets/storage_create_bucket_class_location.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC. All Rights Reserved. +# +# 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_create_bucket_class_location] +from google.cloud import storage + + +def create_bucket_class_location(bucket_name): + """Create a new bucket in specific location with storage class""" + # bucket_name = "your-new-bucket-name" + + storage_client = storage.Client() + + bucket = storage_client.bucket(bucket_name) + bucket.storage_class = "COLDLINE" + new_bucket = storage_client.create_bucket(bucket, location="us") + + print( + "Created bucket {} in {} with storage class {}".format( + new_bucket.name, new_bucket.location, new_bucket.storage_class + ) + ) + return new_bucket + + +# [END storage_create_bucket_class_location] + +if __name__ == "__main__": + create_bucket_class_location(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_create_hmac_key.py b/samples/snippets/storage_create_hmac_key.py new file mode 100644 index 000000000..27a418c39 --- /dev/null +++ b/samples/snippets/storage_create_hmac_key.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_create_hmac_key] +from google.cloud import storage + + +def create_key(project_id, service_account_email): + """ + Create a new HMAC key using the given project and service account. + """ + # project_id = 'Your Google Cloud project ID' + # service_account_email = 'Service account used to generate the HMAC key' + + storage_client = storage.Client(project=project_id) + + hmac_key, secret = storage_client.create_hmac_key( + service_account_email=service_account_email, project_id=project_id + ) + + print("The base64 encoded secret is {}".format(secret)) + print("Do not miss that secret, there is no API to recover it.") + print("The HMAC key metadata is:") + print("Service Account Email: {}".format(hmac_key.service_account_email)) + print("Key ID: {}".format(hmac_key.id)) + print("Access ID: {}".format(hmac_key.access_id)) + print("Project ID: {}".format(hmac_key.project)) + print("State: {}".format(hmac_key.state)) + print("Created At: {}".format(hmac_key.time_created)) + print("Updated At: {}".format(hmac_key.updated)) + print("Etag: {}".format(hmac_key.etag)) + return hmac_key + + +# [END storage_create_hmac_key] + +if __name__ == "__main__": + create_key(project_id=sys.argv[1], service_account_email=sys.argv[2]) diff --git a/samples/snippets/storage_deactivate_hmac_key.py b/samples/snippets/storage_deactivate_hmac_key.py new file mode 100644 index 000000000..389efb998 --- /dev/null +++ b/samples/snippets/storage_deactivate_hmac_key.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_deactivate_hmac_key] +from google.cloud import storage + + +def deactivate_key(access_id, project_id): + """ + Deactivate the HMAC key with the given access ID. + """ + # project_id = "Your Google Cloud project ID" + # access_id = "ID of an active HMAC key" + + storage_client = storage.Client(project=project_id) + + hmac_key = storage_client.get_hmac_key_metadata( + access_id, project_id=project_id + ) + hmac_key.state = "INACTIVE" + hmac_key.update() + + print("The HMAC key is now inactive.") + print("The HMAC key metadata is:") + print("Service Account Email: {}".format(hmac_key.service_account_email)) + print("Key ID: {}".format(hmac_key.id)) + print("Access ID: {}".format(hmac_key.access_id)) + print("Project ID: {}".format(hmac_key.project)) + print("State: {}".format(hmac_key.state)) + print("Created At: {}".format(hmac_key.time_created)) + print("Updated At: {}".format(hmac_key.updated)) + print("Etag: {}".format(hmac_key.etag)) + return hmac_key + + +# [END storage_deactivate_hmac_key] + +if __name__ == "__main__": + deactivate_key(access_id=sys.argv[1], project_id=sys.argv[2]) diff --git a/samples/snippets/storage_define_bucket_website_configuration.py b/samples/snippets/storage_define_bucket_website_configuration.py new file mode 100644 index 000000000..ce6c7e66c --- /dev/null +++ b/samples/snippets/storage_define_bucket_website_configuration.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC. All Rights Reserved. +# +# 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_define_bucket_website_configuration] +from google.cloud import storage + + +def define_bucket_website_configuration(bucket_name, main_page_suffix, not_found_page): + """Configure website-related properties of bucket""" + # bucket_name = "your-bucket-name" + # main_page_suffix = "index.html" + # not_found_page = "404.html" + + storage_client = storage.Client() + + bucket = storage_client.get_bucket(bucket_name) + bucket.configure_website(main_page_suffix, not_found_page) + bucket.patch() + + print( + "Static website bucket {} is set up to use {} as the index page and {} as the 404 page".format( + bucket.name, main_page_suffix, not_found_page + ) + ) + return bucket + + +# [END storage_define_bucket_website_configuration] + +if __name__ == "__main__": + define_bucket_website_configuration( + bucket_name=sys.argv[1], + main_page_suffix=sys.argv[2], + not_found_page=sys.argv[3], + ) diff --git a/samples/snippets/storage_delete_bucket.py b/samples/snippets/storage_delete_bucket.py new file mode 100644 index 000000000..b3e264c74 --- /dev/null +++ b/samples/snippets/storage_delete_bucket.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_delete_bucket] +from google.cloud import storage + + +def delete_bucket(bucket_name): + """Deletes a bucket. The bucket must be empty.""" + # bucket_name = "your-bucket-name" + + storage_client = storage.Client() + + bucket = storage_client.get_bucket(bucket_name) + bucket.delete() + + print("Bucket {} deleted".format(bucket.name)) + + +# [END storage_delete_bucket] + +if __name__ == "__main__": + delete_bucket(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_delete_file.py b/samples/snippets/storage_delete_file.py new file mode 100644 index 000000000..1105f3725 --- /dev/null +++ b/samples/snippets/storage_delete_file.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_delete_file] +from google.cloud import storage + + +def delete_blob(bucket_name, blob_name): + """Deletes a blob from the bucket.""" + # bucket_name = "your-bucket-name" + # blob_name = "your-object-name" + + storage_client = storage.Client() + + bucket = storage_client.bucket(bucket_name) + blob = bucket.blob(blob_name) + blob.delete() + + print("Blob {} deleted.".format(blob_name)) + + +# [END storage_delete_file] + +if __name__ == "__main__": + delete_blob(bucket_name=sys.argv[1], blob_name=sys.argv[2]) diff --git a/samples/snippets/storage_delete_file_archived_generation.py b/samples/snippets/storage_delete_file_archived_generation.py new file mode 100644 index 000000000..4e4909001 --- /dev/null +++ b/samples/snippets/storage_delete_file_archived_generation.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC. All Rights Reserved. +# +# 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_delete_file_archived_generation] +from google.cloud import storage + + +def delete_file_archived_generation(bucket_name, blob_name, generation): + """Delete a blob in the bucket with the given generation.""" + # bucket_name = "your-bucket-name" + # blob_name = "your-object-name" + # generation = 1579287380533984 + + storage_client = storage.Client() + + bucket = storage_client.get_bucket(bucket_name) + bucket.delete_blob(blob_name, generation=generation) + print( + "Generation {} of blob {} was deleted from {}".format( + generation, blob_name, bucket_name + ) + ) + + +# [END storage_delete_file_archived_generation] + + +if __name__ == "__main__": + delete_file_archived_generation( + bucket_name=sys.argv[1], + blob_name=sys.argv[2], + generation=sys.argv[3] + ) diff --git a/samples/snippets/storage_delete_hmac_key.py b/samples/snippets/storage_delete_hmac_key.py new file mode 100644 index 000000000..403dc193b --- /dev/null +++ b/samples/snippets/storage_delete_hmac_key.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_delete_hmac_key] +from google.cloud import storage + + +def delete_key(access_id, project_id): + """ + Delete the HMAC key with the given access ID. Key must have state INACTIVE + in order to succeed. + """ + # project_id = "Your Google Cloud project ID" + # access_id = "ID of an HMAC key (must be in INACTIVE state)" + + storage_client = storage.Client(project=project_id) + + hmac_key = storage_client.get_hmac_key_metadata( + access_id, project_id=project_id + ) + hmac_key.delete() + + print( + "The key is deleted, though it may still appear in list_hmac_keys()" + " results." + ) + + +# [END storage_delete_hmac_key] + +if __name__ == "__main__": + delete_key(access_id=sys.argv[1], project_id=sys.argv[2]) diff --git a/samples/snippets/storage_disable_bucket_lifecycle_management.py b/samples/snippets/storage_disable_bucket_lifecycle_management.py new file mode 100644 index 000000000..9ef6971fb --- /dev/null +++ b/samples/snippets/storage_disable_bucket_lifecycle_management.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# Copyright 2020 Google Inc. All Rights Reserved. +# +# 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_disable_bucket_lifecycle_management] +from google.cloud import storage + + +def disable_bucket_lifecycle_management(bucket_name): + """Disable lifecycle management for a bucket""" + # bucket_name = "my-bucket" + + storage_client = storage.Client() + + bucket = storage_client.get_bucket(bucket_name) + bucket.clear_lifecyle_rules() + bucket.patch() + rules = bucket.lifecycle_rules + + print("Lifecycle management is disable for bucket {} and the rules are {}".format(bucket_name, list(rules))) + return bucket + + +# [END storage_disable_bucket_lifecycle_management] + +if __name__ == "__main__": + disable_bucket_lifecycle_management(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_disable_default_event_based_hold.py b/samples/snippets/storage_disable_default_event_based_hold.py new file mode 100644 index 000000000..dff3ed3c1 --- /dev/null +++ b/samples/snippets/storage_disable_default_event_based_hold.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_disable_default_event_based_hold] +from google.cloud import storage + + +def disable_default_event_based_hold(bucket_name): + """Disables the default event based hold on a given bucket""" + # bucket_name = "my-bucket" + + storage_client = storage.Client() + + bucket = storage_client.get_bucket(bucket_name) + bucket.default_event_based_hold = False + bucket.patch() + + print("Default event based hold was disabled for {}".format(bucket_name)) + + +# [END storage_disable_default_event_based_hold] + + +if __name__ == "__main__": + disable_default_event_based_hold(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_disable_requester_pays.py b/samples/snippets/storage_disable_requester_pays.py new file mode 100644 index 000000000..c49cc28ea --- /dev/null +++ b/samples/snippets/storage_disable_requester_pays.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +# Copyright 2019 Google, Inc. +# +# 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_disable_requester_pays] +from google.cloud import storage + + +def disable_requester_pays(bucket_name): + """Disable a bucket's requesterpays metadata""" + # bucket_name = "my-bucket" + + storage_client = storage.Client() + + bucket = storage_client.get_bucket(bucket_name) + bucket.requester_pays = False + bucket.patch() + + print("Requester Pays has been disabled for {}".format(bucket_name)) + + +# [END storage_disable_requester_pays] + + +if __name__ == "__main__": + disable_requester_pays(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_disable_uniform_bucket_level_access.py b/samples/snippets/storage_disable_uniform_bucket_level_access.py new file mode 100644 index 000000000..4f4691611 --- /dev/null +++ b/samples/snippets/storage_disable_uniform_bucket_level_access.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_disable_uniform_bucket_level_access] +from google.cloud import storage + + +def disable_uniform_bucket_level_access(bucket_name): + """Disable uniform bucket-level access for a bucket""" + # bucket_name = "my-bucket" + + storage_client = storage.Client() + bucket = storage_client.get_bucket(bucket_name) + + bucket.iam_configuration.uniform_bucket_level_access_enabled = False + bucket.patch() + + print( + "Uniform bucket-level access was disabled for {}.".format(bucket.name) + ) + + +# [END storage_disable_uniform_bucket_level_access] + +if __name__ == "__main__": + disable_uniform_bucket_level_access(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_disable_versioning.py b/samples/snippets/storage_disable_versioning.py new file mode 100644 index 000000000..98832ba68 --- /dev/null +++ b/samples/snippets/storage_disable_versioning.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +# Copyright 2020 Google Inc. All Rights Reserved. +# +# 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_disable_versioning] +from google.cloud import storage + + +def disable_versioning(bucket_name): + """Disable versioning for this bucket.""" + # bucket_name = "my-bucket" + + storage_client = storage.Client() + + bucket = storage_client.get_bucket(bucket_name) + bucket.versioning_enabled = False + bucket.patch() + + print("Versioning was disabled for bucket {}".format(bucket)) + return bucket + + +# [END storage_disable_versioning] + +if __name__ == "__main__": + disable_versioning(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_download_encrypted_file.py b/samples/snippets/storage_download_encrypted_file.py new file mode 100644 index 000000000..ac7071fbe --- /dev/null +++ b/samples/snippets/storage_download_encrypted_file.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python + +# Copyright 2019 Google, Inc. +# +# 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_download_encrypted_file] +import base64 +# [END storage_download_encrypted_file] +import sys +# [START storage_download_encrypted_file] + +from google.cloud import storage + + +def download_encrypted_blob( + bucket_name, + source_blob_name, + destination_file_name, + base64_encryption_key, +): + """Downloads a previously-encrypted blob from Google Cloud Storage. + + The encryption key provided must be the same key provided when uploading + the blob. + """ + # bucket_name = "your-bucket-name" + # source_blob_name = "storage-object-name" + # destination_file_name = "local/path/to/file" + # base64_encryption_key = "base64-encoded-encryption-key" + + storage_client = storage.Client() + + bucket = storage_client.bucket(bucket_name) + + # Encryption key must be an AES256 key represented as a bytestring with + # 32 bytes. Since it's passed in as a base64 encoded string, it needs + # to be decoded. + encryption_key = base64.b64decode(base64_encryption_key) + blob = bucket.blob(source_blob_name, encryption_key=encryption_key) + + blob.download_to_filename(destination_file_name) + + print( + "Blob {} downloaded to {}.".format( + source_blob_name, destination_file_name + ) + ) + + +# [END storage_download_encrypted_file] + +if __name__ == "__main__": + download_encrypted_blob( + bucket_name=sys.argv[1], + source_blob_name=sys.argv[2], + destination_file_name=sys.argv[3], + base64_encryption_key=sys.argv[4], + ) diff --git a/samples/snippets/storage_download_file.py b/samples/snippets/storage_download_file.py new file mode 100644 index 000000000..f8a1c93c8 --- /dev/null +++ b/samples/snippets/storage_download_file.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_download_file] +from google.cloud import storage + + +def download_blob(bucket_name, source_blob_name, destination_file_name): + """Downloads a blob from the bucket.""" + # The ID of your GCS bucket + # bucket_name = "your-bucket-name" + + # The ID of your GCS object + # source_blob_name = "storage-object-name" + + # The path to which the file should be downloaded + # destination_file_name = "local/path/to/file" + + storage_client = storage.Client() + + bucket = storage_client.bucket(bucket_name) + + # Construct a client side representation of a blob. + # Note `Bucket.blob` differs from `Bucket.get_blob` as it doesn't retrieve + # any content from Google Cloud Storage. As we don't need additional data, + # using `Bucket.blob` is preferred here. + blob = bucket.blob(source_blob_name) + blob.download_to_filename(destination_file_name) + + print( + "Downloaded storage object {} from bucket {} to local file {}.".format( + source_blob_name, bucket_name, destination_file_name + ) + ) + + +# [END storage_download_file] + +if __name__ == "__main__": + download_blob( + bucket_name=sys.argv[1], + source_blob_name=sys.argv[2], + destination_file_name=sys.argv[3], + ) diff --git a/samples/snippets/storage_download_file_requester_pays.py b/samples/snippets/storage_download_file_requester_pays.py new file mode 100644 index 000000000..babbafda7 --- /dev/null +++ b/samples/snippets/storage_download_file_requester_pays.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +# Copyright 2019 Google, Inc. +# +# 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_download_file_requester_pays] +from google.cloud import storage + + +def download_file_requester_pays( + bucket_name, project_id, source_blob_name, destination_file_name +): + """Download file using specified project as the requester""" + # bucket_name = "your-bucket-name" + # project_id = "your-project-id" + # source_blob_name = "source-blob-name" + # destination_file_name = "local-destination-file-name" + + storage_client = storage.Client() + + bucket = storage_client.bucket(bucket_name, user_project=project_id) + blob = bucket.blob(source_blob_name) + blob.download_to_filename(destination_file_name) + + print( + "Blob {} downloaded to {} using a requester-pays request.".format( + source_blob_name, destination_file_name + ) + ) + + +# [END storage_download_file_requester_pays] + +if __name__ == "__main__": + download_file_requester_pays( + bucket_name=sys.argv[1], + project_id=sys.argv[2], + source_blob_name=sys.argv[3], + destination_file_name=sys.argv[4], + ) diff --git a/samples/snippets/storage_download_public_file.py b/samples/snippets/storage_download_public_file.py new file mode 100644 index 000000000..8fbb68405 --- /dev/null +++ b/samples/snippets/storage_download_public_file.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC. All Rights Reserved. +# +# 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_download_public_file] +from google.cloud import storage + + +def download_public_file(bucket_name, source_blob_name, destination_file_name): + """Downloads a public blob from the bucket.""" + # bucket_name = "your-bucket-name" + # source_blob_name = "storage-object-name" + # destination_file_name = "local/path/to/file" + + storage_client = storage.Client.create_anonymous_client() + + bucket = storage_client.bucket(bucket_name) + blob = bucket.blob(source_blob_name) + blob.download_to_filename(destination_file_name) + + print( + "Downloaded public blob {} from bucket {} to {}.".format( + source_blob_name, bucket.name, destination_file_name + ) + ) + + +# [END storage_download_public_file] + +if __name__ == "__main__": + download_public_file( + bucket_name=sys.argv[1], + source_blob_name=sys.argv[2], + destination_file_name=sys.argv[3], + ) diff --git a/samples/snippets/storage_enable_bucket_lifecycle_management.py b/samples/snippets/storage_enable_bucket_lifecycle_management.py new file mode 100644 index 000000000..61c7d7b20 --- /dev/null +++ b/samples/snippets/storage_enable_bucket_lifecycle_management.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# Copyright 2020 Google Inc. All Rights Reserved. +# +# 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_enable_bucket_lifecycle_management] +from google.cloud import storage + + +def enable_bucket_lifecycle_management(bucket_name): + """Enable lifecycle management for a bucket""" + # bucket_name = "my-bucket" + + storage_client = storage.Client() + + bucket = storage_client.get_bucket(bucket_name) + rules = bucket.lifecycle_rules + + print("Lifecycle management rules for bucket {} are {}".format(bucket_name, list(rules))) + bucket.add_lifecycle_delete_rule(age=2) + bucket.patch() + + rules = bucket.lifecycle_rules + print("Lifecycle management is enable for bucket {} and the rules are {}".format(bucket_name, list(rules))) + + return bucket + + +# [END storage_enable_bucket_lifecycle_management] + +if __name__ == "__main__": + enable_bucket_lifecycle_management(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_enable_default_event_based_hold.py b/samples/snippets/storage_enable_default_event_based_hold.py new file mode 100644 index 000000000..a535390c9 --- /dev/null +++ b/samples/snippets/storage_enable_default_event_based_hold.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_enable_default_event_based_hold] +from google.cloud import storage + + +def enable_default_event_based_hold(bucket_name): + """Enables the default event based hold on a given bucket""" + # bucket_name = "my-bucket" + + storage_client = storage.Client() + + bucket = storage_client.bucket(bucket_name) + bucket.default_event_based_hold = True + bucket.patch() + + print("Default event based hold was enabled for {}".format(bucket_name)) + + +# [END storage_enable_default_event_based_hold] + + +if __name__ == "__main__": + enable_default_event_based_hold(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_enable_requester_pays.py b/samples/snippets/storage_enable_requester_pays.py new file mode 100644 index 000000000..9787008dd --- /dev/null +++ b/samples/snippets/storage_enable_requester_pays.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +# Copyright 2019 Google, Inc. +# +# 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_enable_requester_pays] +from google.cloud import storage + + +def enable_requester_pays(bucket_name): + """Enable a bucket's requesterpays metadata""" + # bucket_name = "my-bucket" + + storage_client = storage.Client() + + bucket = storage_client.get_bucket(bucket_name) + bucket.requester_pays = True + bucket.patch() + + print("Requester Pays has been enabled for {}".format(bucket_name)) + + +# [END storage_enable_requester_pays] + +if __name__ == "__main__": + enable_requester_pays(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_enable_uniform_bucket_level_access.py b/samples/snippets/storage_enable_uniform_bucket_level_access.py new file mode 100644 index 000000000..c689bb735 --- /dev/null +++ b/samples/snippets/storage_enable_uniform_bucket_level_access.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_enable_uniform_bucket_level_access] +from google.cloud import storage + + +def enable_uniform_bucket_level_access(bucket_name): + """Enable uniform bucket-level access for a bucket""" + # bucket_name = "my-bucket" + + storage_client = storage.Client() + bucket = storage_client.get_bucket(bucket_name) + + bucket.iam_configuration.uniform_bucket_level_access_enabled = True + bucket.patch() + + print( + "Uniform bucket-level access was enabled for {}.".format(bucket.name) + ) + + +# [END storage_enable_uniform_bucket_level_access] + +if __name__ == "__main__": + enable_uniform_bucket_level_access(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_enable_versioning.py b/samples/snippets/storage_enable_versioning.py new file mode 100644 index 000000000..89693e426 --- /dev/null +++ b/samples/snippets/storage_enable_versioning.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +# Copyright 2020 Google Inc. All Rights Reserved. +# +# 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_enable_versioning] +from google.cloud import storage + + +def enable_versioning(bucket_name): + """Enable versioning for this bucket.""" + # bucket_name = "my-bucket" + + storage_client = storage.Client() + + bucket = storage_client.get_bucket(bucket_name) + bucket.versioning_enabled = True + bucket.patch() + + print("Versioning was enabled for bucket {}".format(bucket.name)) + return bucket + + +# [END storage_enable_versioning] + +if __name__ == "__main__": + enable_versioning(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_generate_encryption_key.py b/samples/snippets/storage_generate_encryption_key.py new file mode 100644 index 000000000..a973418a6 --- /dev/null +++ b/samples/snippets/storage_generate_encryption_key.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +# Copyright 2019 Google, Inc. +# +# 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_generate_encryption_key] +import base64 +import os + + +def generate_encryption_key(): + """Generates a 256 bit (32 byte) AES encryption key and prints the + base64 representation. + + This is included for demonstration purposes. You should generate your own + key. Please remember that encryption keys should be handled with a + comprehensive security policy. + """ + key = os.urandom(32) + encoded_key = base64.b64encode(key).decode("utf-8") + + print("Base 64 encoded encryption key: {}".format(encoded_key)) + + +# [END storage_generate_encryption_key] + +if __name__ == "__main__": + generate_encryption_key() diff --git a/samples/snippets/storage_generate_signed_post_policy_v4.py b/samples/snippets/storage_generate_signed_post_policy_v4.py new file mode 100644 index 000000000..8217714e2 --- /dev/null +++ b/samples/snippets/storage_generate_signed_post_policy_v4.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python + +# Copyright 2020 Google Inc. All Rights Reserved. +# +# 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_generate_signed_post_policy_v4] +import datetime +# [END storage_generate_signed_post_policy_v4] +import sys +# [START storage_generate_signed_post_policy_v4] + +from google.cloud import storage + + +def generate_signed_post_policy_v4(bucket_name, blob_name): + """Generates a v4 POST Policy and prints an HTML form.""" + # bucket_name = 'your-bucket-name' + # blob_name = 'your-object-name' + + storage_client = storage.Client() + + policy = storage_client.generate_signed_post_policy_v4( + bucket_name, + blob_name, + expiration=datetime.timedelta(minutes=10), + fields={ + 'x-goog-meta-test': 'data' + } + ) + + # Create an HTML form with the provided policy + header = "
\n" + form = header.format(policy["url"]) + + # Include all fields returned in the HTML form as they're required + for key, value in policy["fields"].items(): + form += " \n".format(key, value) + + form += "
\n" + form += "
\n" + form += "
" + + print(form) + + return form + + +# [END storage_generate_signed_post_policy_v4] + +if __name__ == "__main__": + generate_signed_post_policy_v4( + bucket_name=sys.argv[1], blob_name=sys.argv[2] + ) diff --git a/samples/snippets/storage_generate_signed_url_v2.py b/samples/snippets/storage_generate_signed_url_v2.py new file mode 100644 index 000000000..abea3dd54 --- /dev/null +++ b/samples/snippets/storage_generate_signed_url_v2.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_generate_signed_url_v2] +import datetime +# [END storage_generate_signed_url_v2] +import sys +# [START storage_generate_signed_url_v2] + +from google.cloud import storage + + +def generate_signed_url(bucket_name, blob_name): + """Generates a v2 signed URL for downloading a blob. + + Note that this method requires a service account key file. You can not use + this if you are using Application Default Credentials from Google Compute + Engine or from the Google Cloud SDK. + """ + # bucket_name = 'your-bucket-name' + # blob_name = 'your-object-name' + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + blob = bucket.blob(blob_name) + + url = blob.generate_signed_url( + # This URL is valid for 1 hour + expiration=datetime.timedelta(hours=1), + # Allow GET requests using this URL. + method="GET", + ) + + print("The signed url for {} is {}".format(blob.name, url)) + return url + + +# [END storage_generate_signed_url_v2] + +if __name__ == "__main__": + generate_signed_url(bucket_name=sys.argv[1], blob_name=sys.argv[2]) diff --git a/samples/snippets/storage_generate_signed_url_v4.py b/samples/snippets/storage_generate_signed_url_v4.py new file mode 100644 index 000000000..2a45b23e9 --- /dev/null +++ b/samples/snippets/storage_generate_signed_url_v4.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_generate_signed_url_v4] +import datetime +# [END storage_generate_signed_url_v4] +import sys +# [START storage_generate_signed_url_v4] + +from google.cloud import storage + + +def generate_download_signed_url_v4(bucket_name, blob_name): + """Generates a v4 signed URL for downloading a blob. + + Note that this method requires a service account key file. You can not use + this if you are using Application Default Credentials from Google Compute + Engine or from the Google Cloud SDK. + """ + # bucket_name = 'your-bucket-name' + # blob_name = 'your-object-name' + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + blob = bucket.blob(blob_name) + + url = blob.generate_signed_url( + version="v4", + # This URL is valid for 15 minutes + expiration=datetime.timedelta(minutes=15), + # Allow GET requests using this URL. + method="GET", + ) + + print("Generated GET signed URL:") + print(url) + print("You can use this URL with any user agent, for example:") + print("curl '{}'".format(url)) + return url + + +# [END storage_generate_signed_url_v4] + +if __name__ == "__main__": + generate_download_signed_url_v4( + bucket_name=sys.argv[1], blob_name=sys.argv[2] + ) diff --git a/samples/snippets/storage_generate_upload_signed_url_v4.py b/samples/snippets/storage_generate_upload_signed_url_v4.py new file mode 100644 index 000000000..dc1da8864 --- /dev/null +++ b/samples/snippets/storage_generate_upload_signed_url_v4.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_generate_upload_signed_url_v4] +import datetime +# [END storage_generate_upload_signed_url_v4] +import sys +# [START storage_generate_upload_signed_url_v4] + +from google.cloud import storage + + +def generate_upload_signed_url_v4(bucket_name, blob_name): + """Generates a v4 signed URL for uploading a blob using HTTP PUT. + + Note that this method requires a service account key file. You can not use + this if you are using Application Default Credentials from Google Compute + Engine or from the Google Cloud SDK. + """ + # bucket_name = 'your-bucket-name' + # blob_name = 'your-object-name' + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + blob = bucket.blob(blob_name) + + url = blob.generate_signed_url( + version="v4", + # This URL is valid for 15 minutes + expiration=datetime.timedelta(minutes=15), + # Allow PUT requests using this URL. + method="PUT", + content_type="application/octet-stream", + ) + + print("Generated PUT signed URL:") + print(url) + print("You can use this URL with any user agent, for example:") + print( + "curl -X PUT -H 'Content-Type: application/octet-stream' " + "--upload-file my-file '{}'".format(url) + ) + return url + + +# [END storage_generate_upload_signed_url_v4] + + +if __name__ == "__main__": + generate_upload_signed_url_v4( + bucket_name=sys.argv[1], blob_name=sys.argv[2] + ) diff --git a/samples/snippets/storage_get_bucket_labels.py b/samples/snippets/storage_get_bucket_labels.py new file mode 100644 index 000000000..b3bcd6208 --- /dev/null +++ b/samples/snippets/storage_get_bucket_labels.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_get_bucket_labels] +import pprint +# [END storage_get_bucket_labels] +import sys +# [START storage_get_bucket_labels] + +from google.cloud import storage + + +def get_bucket_labels(bucket_name): + """Prints out a bucket's labels.""" + # bucket_name = 'your-bucket-name' + storage_client = storage.Client() + + bucket = storage_client.get_bucket(bucket_name) + + labels = bucket.labels + pprint.pprint(labels) + + +# [END storage_get_bucket_labels] + +if __name__ == "__main__": + get_bucket_labels(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_get_bucket_metadata.py b/samples/snippets/storage_get_bucket_metadata.py new file mode 100644 index 000000000..87cd5eddc --- /dev/null +++ b/samples/snippets/storage_get_bucket_metadata.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_bucket_metadata] + +from google.cloud import storage + + +def bucket_metadata(bucket_name): + """Prints out a bucket's metadata.""" + # bucket_name = 'your-bucket-name' + + storage_client = storage.Client() + bucket = storage_client.get_bucket(bucket_name) + + print(f"ID: {bucket.id}") + print(f"Name: {bucket.name}") + print(f"Storage Class: {bucket.storage_class}") + print(f"Location: {bucket.location}") + print(f"Location Type: {bucket.location_type}") + print(f"Cors: {bucket.cors}") + print(f"Default Event Based Hold: {bucket.default_event_based_hold}") + print(f"Default KMS Key Name: {bucket.default_kms_key_name}") + print(f"Metageneration: {bucket.metageneration}") + print( + f"Public Access Prevention: {bucket.iam_configuration.public_access_prevention}" + ) + print(f"Retention Effective Time: {bucket.retention_policy_effective_time}") + print(f"Retention Period: {bucket.retention_period}") + print(f"Retention Policy Locked: {bucket.retention_policy_locked}") + print(f"Requester Pays: {bucket.requester_pays}") + print(f"Self Link: {bucket.self_link}") + print(f"Time Created: {bucket.time_created}") + print(f"Versioning Enabled: {bucket.versioning_enabled}") + print(f"Labels: {bucket.labels}") + + +# [END storage_get_bucket_metadata] + +if __name__ == "__main__": + bucket_metadata(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_get_default_event_based_hold.py b/samples/snippets/storage_get_default_event_based_hold.py new file mode 100644 index 000000000..4cf13914d --- /dev/null +++ b/samples/snippets/storage_get_default_event_based_hold.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_default_event_based_hold] +from google.cloud import storage + + +def get_default_event_based_hold(bucket_name): + """Gets the default event based hold on a given bucket""" + # bucket_name = "my-bucket" + + storage_client = storage.Client() + + bucket = storage_client.get_bucket(bucket_name) + + if bucket.default_event_based_hold: + print("Default event-based hold is enabled for {}".format(bucket_name)) + else: + print( + "Default event-based hold is not enabled for {}".format( + bucket_name + ) + ) + + +# [END storage_get_default_event_based_hold] + + +if __name__ == "__main__": + get_default_event_based_hold(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_get_hmac_key.py b/samples/snippets/storage_get_hmac_key.py new file mode 100644 index 000000000..4dc52240d --- /dev/null +++ b/samples/snippets/storage_get_hmac_key.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_hmac_key] +from google.cloud import storage + + +def get_key(access_id, project_id): + """ + Retrieve the HMACKeyMetadata with the given access id. + """ + # project_id = "Your Google Cloud project ID" + # access_id = "ID of an HMAC key" + + storage_client = storage.Client(project=project_id) + + hmac_key = storage_client.get_hmac_key_metadata( + access_id, project_id=project_id + ) + + print("The HMAC key metadata is:") + print("Service Account Email: {}".format(hmac_key.service_account_email)) + print("Key ID: {}".format(hmac_key.id)) + print("Access ID: {}".format(hmac_key.access_id)) + print("Project ID: {}".format(hmac_key.project)) + print("State: {}".format(hmac_key.state)) + print("Created At: {}".format(hmac_key.time_created)) + print("Updated At: {}".format(hmac_key.updated)) + print("Etag: {}".format(hmac_key.etag)) + return hmac_key + + +# [END storage_get_hmac_key] + +if __name__ == "__main__": + get_key(access_id=sys.argv[1], project_id=sys.argv[2]) diff --git a/samples/snippets/storage_get_metadata.py b/samples/snippets/storage_get_metadata.py new file mode 100644 index 000000000..c5ef0b4cc --- /dev/null +++ b/samples/snippets/storage_get_metadata.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_metadata] +from google.cloud import storage + + +def blob_metadata(bucket_name, blob_name): + """Prints out a blob's metadata.""" + # bucket_name = 'your-bucket-name' + # blob_name = 'your-object-name' + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + + # Retrieve a blob, and its metadata, from Google Cloud Storage. + # Note that `get_blob` differs from `Bucket.blob`, which does not + # make an HTTP request. + blob = bucket.get_blob(blob_name) + + print("Blob: {}".format(blob.name)) + print("Bucket: {}".format(blob.bucket.name)) + print("Storage class: {}".format(blob.storage_class)) + print("ID: {}".format(blob.id)) + print("Size: {} bytes".format(blob.size)) + print("Updated: {}".format(blob.updated)) + print("Generation: {}".format(blob.generation)) + print("Metageneration: {}".format(blob.metageneration)) + print("Etag: {}".format(blob.etag)) + print("Owner: {}".format(blob.owner)) + print("Component count: {}".format(blob.component_count)) + print("Crc32c: {}".format(blob.crc32c)) + print("md5_hash: {}".format(blob.md5_hash)) + print("Cache-control: {}".format(blob.cache_control)) + print("Content-type: {}".format(blob.content_type)) + print("Content-disposition: {}".format(blob.content_disposition)) + print("Content-encoding: {}".format(blob.content_encoding)) + print("Content-language: {}".format(blob.content_language)) + print("Metadata: {}".format(blob.metadata)) + print("Custom Time: {}".format(blob.custom_time)) + print("Temporary hold: ", "enabled" if blob.temporary_hold else "disabled") + print( + "Event based hold: ", + "enabled" if blob.event_based_hold else "disabled", + ) + if blob.retention_expiration_time: + print( + "retentionExpirationTime: {}".format( + blob.retention_expiration_time + ) + ) + + +# [END storage_get_metadata] + +if __name__ == "__main__": + blob_metadata(bucket_name=sys.argv[1], blob_name=sys.argv[2]) diff --git a/samples/snippets/storage_get_public_access_prevention.py b/samples/snippets/storage_get_public_access_prevention.py new file mode 100644 index 000000000..275b84e35 --- /dev/null +++ b/samples/snippets/storage_get_public_access_prevention.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +# Copyright 2021 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_public_access_prevention] +from google.cloud import storage + + +def get_public_access_prevention(bucket_name): + """Gets the public access prevention setting (either 'inherited' or 'enforced') for a bucket.""" + # The ID of your GCS bucket + # bucket_name = "my-bucket" + + storage_client = storage.Client() + bucket = storage_client.get_bucket(bucket_name) + iam_configuration = bucket.iam_configuration + + print( + f"Public access prevention is {iam_configuration.public_access_prevention} for {bucket.name}." + ) + + +# [END storage_get_public_access_prevention] + +if __name__ == "__main__": + get_public_access_prevention(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_get_requester_pays_status.py b/samples/snippets/storage_get_requester_pays_status.py new file mode 100644 index 000000000..2014d654c --- /dev/null +++ b/samples/snippets/storage_get_requester_pays_status.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +# Copyright 2019 Google, Inc. +# +# 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_requester_pays_status] +from google.cloud import storage + + +def get_requester_pays_status(bucket_name): + """Get a bucket's requester pays metadata""" + # bucket_name = "my-bucket" + storage_client = storage.Client() + + bucket = storage_client.get_bucket(bucket_name) + requester_pays_status = bucket.requester_pays + + if requester_pays_status: + print("Requester Pays is enabled for {}".format(bucket_name)) + else: + print("Requester Pays is disabled for {}".format(bucket_name)) + + +# [END storage_get_requester_pays_status] + +if __name__ == "__main__": + get_requester_pays_status(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_get_retention_policy.py b/samples/snippets/storage_get_retention_policy.py new file mode 100644 index 000000000..f2ca26d26 --- /dev/null +++ b/samples/snippets/storage_get_retention_policy.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_retention_policy] +from google.cloud import storage + + +def get_retention_policy(bucket_name): + """Gets the retention policy on a given bucket""" + # bucket_name = "my-bucket" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + bucket.reload() + + print("Retention Policy for {}".format(bucket_name)) + print("Retention Period: {}".format(bucket.retention_period)) + if bucket.retention_policy_locked: + print("Retention Policy is locked") + + if bucket.retention_policy_effective_time: + print( + "Effective Time: {}".format(bucket.retention_policy_effective_time) + ) + + +# [END storage_get_retention_policy] + + +if __name__ == "__main__": + get_retention_policy(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_get_service_account.py b/samples/snippets/storage_get_service_account.py new file mode 100644 index 000000000..58ababb91 --- /dev/null +++ b/samples/snippets/storage_get_service_account.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC. All Rights Reserved. +# +# 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_get_service_account] +from google.cloud import storage + + +def get_service_account(): + """Get the service account email""" + storage_client = storage.Client() + + email = storage_client.get_service_account_email() + print( + "The GCS service account for project {} is: {} ".format( + storage_client.project, email + ) + ) + + +# [END storage_get_service_account] + +if __name__ == "__main__": + get_service_account() diff --git a/samples/snippets/storage_get_uniform_bucket_level_access.py b/samples/snippets/storage_get_uniform_bucket_level_access.py new file mode 100644 index 000000000..eddb8bc1a --- /dev/null +++ b/samples/snippets/storage_get_uniform_bucket_level_access.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_uniform_bucket_level_access] +from google.cloud import storage + + +def get_uniform_bucket_level_access(bucket_name): + """Get uniform bucket-level access for a bucket""" + # bucket_name = "my-bucket" + + storage_client = storage.Client() + bucket = storage_client.get_bucket(bucket_name) + iam_configuration = bucket.iam_configuration + + if iam_configuration.uniform_bucket_level_access_enabled: + print( + "Uniform bucket-level access is enabled for {}.".format( + bucket.name + ) + ) + print( + "Bucket will be locked on {}.".format( + iam_configuration.uniform_bucket_level_locked_time + ) + ) + else: + print( + "Uniform bucket-level access is disabled for {}.".format( + bucket.name + ) + ) + + +# [END storage_get_uniform_bucket_level_access] + +if __name__ == "__main__": + get_uniform_bucket_level_access(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_list_buckets.py b/samples/snippets/storage_list_buckets.py new file mode 100644 index 000000000..f5897e47a --- /dev/null +++ b/samples/snippets/storage_list_buckets.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_buckets] +from google.cloud import storage + + +def list_buckets(): + """Lists all buckets.""" + + storage_client = storage.Client() + buckets = storage_client.list_buckets() + + for bucket in buckets: + print(bucket.name) + + +# [END storage_list_buckets] + + +if __name__ == "__main__": + list_buckets() diff --git a/samples/snippets/storage_list_file_archived_generations.py b/samples/snippets/storage_list_file_archived_generations.py new file mode 100644 index 000000000..dc2f5eaf5 --- /dev/null +++ b/samples/snippets/storage_list_file_archived_generations.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC. All Rights Reserved. +# +# 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_list_file_archived_generations] +from google.cloud import storage + + +def list_file_archived_generations(bucket_name): + """Lists all the blobs in the bucket with generation.""" + # bucket_name = "your-bucket-name" + + storage_client = storage.Client() + + blobs = storage_client.list_blobs(bucket_name, versions=True) + + for blob in blobs: + print("{},{}".format(blob.name, blob.generation)) + + +# [END storage_list_file_archived_generations] + + +if __name__ == "__main__": + list_file_archived_generations(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_list_files.py b/samples/snippets/storage_list_files.py new file mode 100644 index 000000000..c6a80d9fa --- /dev/null +++ b/samples/snippets/storage_list_files.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_list_files] +from google.cloud import storage + + +def list_blobs(bucket_name): + """Lists all the blobs in the bucket.""" + # bucket_name = "your-bucket-name" + + storage_client = storage.Client() + + # Note: Client.list_blobs requires at least package version 1.17.0. + blobs = storage_client.list_blobs(bucket_name) + + for blob in blobs: + print(blob.name) + + +# [END storage_list_files] + + +if __name__ == "__main__": + list_blobs(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_list_files_with_prefix.py b/samples/snippets/storage_list_files_with_prefix.py new file mode 100644 index 000000000..f79413fb6 --- /dev/null +++ b/samples/snippets/storage_list_files_with_prefix.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_list_files_with_prefix] +from google.cloud import storage + + +def list_blobs_with_prefix(bucket_name, prefix, delimiter=None): + """Lists all the blobs in the bucket that begin with the prefix. + + This can be used to list all blobs in a "folder", e.g. "public/". + + The delimiter argument can be used to restrict the results to only the + "files" in the given "folder". Without the delimiter, the entire tree under + the prefix is returned. For example, given these blobs: + + a/1.txt + a/b/2.txt + + If you specify prefix ='a/', without a delimiter, you'll get back: + + a/1.txt + a/b/2.txt + + However, if you specify prefix='a/' and delimiter='/', you'll get back + only the file directly under 'a/': + + a/1.txt + + As part of the response, you'll also get back a blobs.prefixes entity + that lists the "subfolders" under `a/`: + + a/b/ + """ + + storage_client = storage.Client() + + # Note: Client.list_blobs requires at least package version 1.17.0. + blobs = storage_client.list_blobs(bucket_name, prefix=prefix, delimiter=delimiter) + + print("Blobs:") + for blob in blobs: + print(blob.name) + + if delimiter: + print("Prefixes:") + for prefix in blobs.prefixes: + print(prefix) + + +# [END storage_list_files_with_prefix] + +if __name__ == "__main__": + list_blobs_with_prefix( + bucket_name=sys.argv[1], prefix=sys.argv[2], delimiter=sys.argv[3] + ) diff --git a/samples/snippets/storage_list_hmac_keys.py b/samples/snippets/storage_list_hmac_keys.py new file mode 100644 index 000000000..8e5c53b58 --- /dev/null +++ b/samples/snippets/storage_list_hmac_keys.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_list_hmac_keys] +from google.cloud import storage + + +def list_keys(project_id): + """ + List all HMAC keys associated with the project. + """ + # project_id = "Your Google Cloud project ID" + + storage_client = storage.Client(project=project_id) + hmac_keys = storage_client.list_hmac_keys(project_id=project_id) + print("HMAC Keys:") + for hmac_key in hmac_keys: + print( + "Service Account Email: {}".format(hmac_key.service_account_email) + ) + print("Access ID: {}".format(hmac_key.access_id)) + return hmac_keys + + +# [END storage_list_hmac_keys] + +if __name__ == "__main__": + list_keys(project_id=sys.argv[1]) diff --git a/samples/snippets/storage_lock_retention_policy.py b/samples/snippets/storage_lock_retention_policy.py new file mode 100644 index 000000000..d59572f5d --- /dev/null +++ b/samples/snippets/storage_lock_retention_policy.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_lock_retention_policy] +from google.cloud import storage + + +def lock_retention_policy(bucket_name): + """Locks the retention policy on a given bucket""" + # bucket_name = "my-bucket" + + storage_client = storage.Client() + # get_bucket gets the current metageneration value for the bucket, + # required by lock_retention_policy. + bucket = storage_client.get_bucket(bucket_name) + + # Warning: Once a retention policy is locked it cannot be unlocked + # and retention period can only be increased. + bucket.lock_retention_policy() + + print("Retention policy for {} is now locked".format(bucket_name)) + print( + "Retention policy effective as of {}".format( + bucket.retention_policy_effective_time + ) + ) + + +# [END storage_lock_retention_policy] + + +if __name__ == "__main__": + lock_retention_policy(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_make_public.py b/samples/snippets/storage_make_public.py new file mode 100644 index 000000000..79ae40d12 --- /dev/null +++ b/samples/snippets/storage_make_public.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_make_public] +from google.cloud import storage + + +def make_blob_public(bucket_name, blob_name): + """Makes a blob publicly accessible.""" + # bucket_name = "your-bucket-name" + # blob_name = "your-object-name" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + blob = bucket.blob(blob_name) + + blob.make_public() + + print( + "Blob {} is publicly accessible at {}".format( + blob.name, blob.public_url + ) + ) + + +# [END storage_make_public] + +if __name__ == "__main__": + make_blob_public(bucket_name=sys.argv[1], blob_name=sys.argv[2]) diff --git a/samples/snippets/storage_move_file.py b/samples/snippets/storage_move_file.py new file mode 100644 index 000000000..a881a38ba --- /dev/null +++ b/samples/snippets/storage_move_file.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python + +# Copyright 2019 Google LLC. All Rights Reserved. +# +# 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_move_file] +from google.cloud import storage + + +def move_blob(bucket_name, blob_name, destination_bucket_name, destination_blob_name): + """Moves a blob from one bucket to another with a new name.""" + # The ID of your GCS bucket + # bucket_name = "your-bucket-name" + # The ID of your GCS object + # blob_name = "your-object-name" + # The ID of the bucket to move the object to + # destination_bucket_name = "destination-bucket-name" + # The ID of your new GCS object (optional) + # destination_blob_name = "destination-object-name" + + storage_client = storage.Client() + + source_bucket = storage_client.bucket(bucket_name) + source_blob = source_bucket.blob(blob_name) + destination_bucket = storage_client.bucket(destination_bucket_name) + + blob_copy = source_bucket.copy_blob( + source_blob, destination_bucket, destination_blob_name + ) + source_bucket.delete_blob(blob_name) + + print( + "Blob {} in bucket {} moved to blob {} in bucket {}.".format( + source_blob.name, + source_bucket.name, + blob_copy.name, + destination_bucket.name, + ) + ) + + +# [END storage_move_file] + +if __name__ == "__main__": + move_blob( + bucket_name=sys.argv[1], + blob_name=sys.argv[2], + destination_bucket_name=sys.argv[3], + destination_blob_name=sys.argv[4], + ) diff --git a/samples/snippets/storage_object_csek_to_cmek.py b/samples/snippets/storage_object_csek_to_cmek.py new file mode 100644 index 000000000..9d4d710bf --- /dev/null +++ b/samples/snippets/storage_object_csek_to_cmek.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC. All Rights Reserved. +# +# 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 base64 +import sys + +# [START storage_object_csek_to_cmek] +from google.cloud import storage + + +def object_csek_to_cmek(bucket_name, blob_name, encryption_key, kms_key_name): + """Change a blob's customer-supplied encryption key to KMS key""" + # bucket_name = "your-bucket-name" + # blob_name = "your-object-name" + # encryption_key = "TIbv/fjexq+VmtXzAlc63J4z5kFmWJ6NdAPQulQBT7g=" + # kms_key_name = "projects/PROJ/locations/LOC/keyRings/RING/cryptoKey/KEY" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + + current_encryption_key = base64.b64decode(encryption_key) + source_blob = bucket.blob(blob_name, encryption_key=current_encryption_key) + + destination_blob = bucket.blob(blob_name, kms_key_name=kms_key_name) + token, rewritten, total = destination_blob.rewrite(source_blob) + + while token is not None: + token, rewritten, total = destination_blob.rewrite(source_blob, token=token) + + print( + "Blob {} in bucket {} is now managed by the KMS key {} instead of a customer-supplied encryption key".format( + blob_name, bucket_name, kms_key_name + ) + ) + return destination_blob + + +# [END storage_object_csek_to_cmek] + +if __name__ == "__main__": + object_csek_to_cmek( + bucket_name=sys.argv[1], + blob_name=sys.argv[2], + encryption_key=sys.argv[3], + kms_key_name=sys.argv[4], + ) diff --git a/samples/snippets/storage_object_get_kms_key.py b/samples/snippets/storage_object_get_kms_key.py new file mode 100644 index 000000000..dddfc9151 --- /dev/null +++ b/samples/snippets/storage_object_get_kms_key.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC. All Rights Reserved. +# +# 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_object_get_kms_key] +from google.cloud import storage + + +def object_get_kms_key(bucket_name, blob_name): + """Retrieve the KMS key of a blob""" + # bucket_name = "your-bucket-name" + # blob_name = "your-object-name" + + storage_client = storage.Client() + + bucket = storage_client.bucket(bucket_name) + blob = bucket.get_blob(blob_name) + + kms_key = blob.kms_key_name + + print("The KMS key of a blob is {}".format(blob.kms_key_name)) + return kms_key + + +# [END storage_object_get_kms_key] + +if __name__ == "__main__": + object_get_kms_key(bucket_name=sys.argv[1], blob_name=sys.argv[2]) diff --git a/samples/snippets/storage_print_bucket_acl.py b/samples/snippets/storage_print_bucket_acl.py new file mode 100644 index 000000000..0804f7a9a --- /dev/null +++ b/samples/snippets/storage_print_bucket_acl.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +# Copyright 2019 Google, Inc. +# +# 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_print_bucket_acl] +from google.cloud import storage + + +def print_bucket_acl(bucket_name): + """Prints out a bucket's access control list.""" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + + for entry in bucket.acl: + print("{}: {}".format(entry["role"], entry["entity"])) + + +# [END storage_print_bucket_acl] + +if __name__ == "__main__": + print_bucket_acl(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_print_bucket_acl_for_user.py b/samples/snippets/storage_print_bucket_acl_for_user.py new file mode 100644 index 000000000..fa786d03a --- /dev/null +++ b/samples/snippets/storage_print_bucket_acl_for_user.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# Copyright 2019 Google, Inc. +# +# 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_print_bucket_acl_for_user] +from google.cloud import storage + + +def print_bucket_acl_for_user(bucket_name, user_email): + """Prints out a bucket's access control list for a given user.""" + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + + # Reload fetches the current ACL from Cloud Storage. + bucket.acl.reload() + + # You can also use `group`, `domain`, `all_authenticated` and `all` to + # get the roles for different types of entities. + roles = bucket.acl.user(user_email).get_roles() + + print(roles) + + +# [END storage_print_bucket_acl_for_user] + +if __name__ == "__main__": + print_bucket_acl_for_user(bucket_name=sys.argv[1], user_email=sys.argv[2]) diff --git a/samples/snippets/storage_print_file_acl.py b/samples/snippets/storage_print_file_acl.py new file mode 100644 index 000000000..f34a5283b --- /dev/null +++ b/samples/snippets/storage_print_file_acl.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python + +# Copyright 2019 Google, Inc. +# +# 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_print_file_acl] +from google.cloud import storage + + +def print_blob_acl(bucket_name, blob_name): + """Prints out a blob's access control list.""" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + blob = bucket.blob(blob_name) + + for entry in blob.acl: + print("{}: {}".format(entry["role"], entry["entity"])) + + +# [END storage_print_file_acl] + +if __name__ == "__main__": + print_blob_acl(bucket_name=sys.argv[1], blob_name=sys.argv[2]) diff --git a/samples/snippets/storage_print_file_acl_for_user.py b/samples/snippets/storage_print_file_acl_for_user.py new file mode 100644 index 000000000..e399b9160 --- /dev/null +++ b/samples/snippets/storage_print_file_acl_for_user.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# Copyright 2019 Google, Inc. +# +# 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_print_file_acl_for_user] +from google.cloud import storage + + +def print_blob_acl_for_user(bucket_name, blob_name, user_email): + """Prints out a blob's access control list for a given user.""" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + blob = bucket.blob(blob_name) + + # Reload fetches the current ACL from Cloud Storage. + blob.acl.reload() + + # You can also use `group`, `domain`, `all_authenticated` and `all` to + # get the roles for different types of entities. + roles = blob.acl.user(user_email).get_roles() + + print(roles) + + +# [END storage_print_file_acl_for_user] + +if __name__ == "__main__": + print_blob_acl_for_user( + bucket_name=sys.argv[1], blob_name=sys.argv[2], user_email=sys.argv[3], + ) diff --git a/samples/snippets/storage_release_event_based_hold.py b/samples/snippets/storage_release_event_based_hold.py new file mode 100644 index 000000000..8c3c11b6f --- /dev/null +++ b/samples/snippets/storage_release_event_based_hold.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_release_event_based_hold] +from google.cloud import storage + + +def release_event_based_hold(bucket_name, blob_name): + """Releases the event based hold on a given blob""" + + # bucket_name = "my-bucket" + # blob_name = "my-blob" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + blob = bucket.blob(blob_name) + + blob.event_based_hold = False + blob.patch() + + print("Event based hold was released for {}".format(blob_name)) + + +# [END storage_release_event_based_hold] + + +if __name__ == "__main__": + release_event_based_hold(bucket_name=sys.argv[1], blob_name=sys.argv[2]) diff --git a/samples/snippets/storage_release_temporary_hold.py b/samples/snippets/storage_release_temporary_hold.py new file mode 100644 index 000000000..02a6ca96c --- /dev/null +++ b/samples/snippets/storage_release_temporary_hold.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_release_temporary_hold] +from google.cloud import storage + + +def release_temporary_hold(bucket_name, blob_name): + """Releases the temporary hold on a given blob""" + + # bucket_name = "my-bucket" + # blob_name = "my-blob" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + blob = bucket.blob(blob_name) + + blob.temporary_hold = False + blob.patch() + + print("Temporary hold was release for #{blob_name}") + + +# [END storage_release_temporary_hold] + + +if __name__ == "__main__": + release_temporary_hold(bucket_name=sys.argv[1], blob_name=sys.argv[2]) diff --git a/samples/snippets/storage_remove_bucket_conditional_iam_binding.py b/samples/snippets/storage_remove_bucket_conditional_iam_binding.py new file mode 100644 index 000000000..242544d8e --- /dev/null +++ b/samples/snippets/storage_remove_bucket_conditional_iam_binding.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC. All Rights Reserved +# +# 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_remove_bucket_conditional_iam_binding] +from google.cloud import storage + + +def remove_bucket_conditional_iam_binding( + bucket_name, role, title, description, expression +): + """Remove a conditional IAM binding from a bucket's IAM policy.""" + # bucket_name = "your-bucket-name" + # role = "IAM role, e.g. roles/storage.objectViewer" + # title = "Condition title." + # description = "Condition description." + # expression = "Condition expression." + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + + policy = bucket.get_iam_policy(requested_policy_version=3) + + # Set the policy's version to 3 to use condition in bindings. + policy.version = 3 + + condition = { + "title": title, + "description": description, + "expression": expression, + } + policy.bindings = [ + binding + for binding in policy.bindings + if not (binding["role"] == role and binding.get("condition") == condition) + ] + + bucket.set_iam_policy(policy) + + print("Conditional Binding was removed.") + + +# [END storage_remove_bucket_conditional_iam_binding] + + +if __name__ == "__main__": + remove_bucket_conditional_iam_binding( + bucket_name=sys.argv[1], + role=sys.argv[2], + title=sys.argv[3], + description=sys.argv[4], + expression=sys.argv[5], + ) diff --git a/samples/snippets/storage_remove_bucket_default_owner.py b/samples/snippets/storage_remove_bucket_default_owner.py new file mode 100644 index 000000000..beaf6be84 --- /dev/null +++ b/samples/snippets/storage_remove_bucket_default_owner.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python + +# Copyright 2019 Google, Inc. +# +# 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_remove_bucket_default_owner] +from google.cloud import storage + + +def remove_bucket_default_owner(bucket_name, user_email): + """Removes a user from the access control list of the given bucket's + default object access control list.""" + # bucket_name = "your-bucket-name" + # user_email = "name@example.com" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + + # Reload fetches the current ACL from Cloud Storage. + bucket.acl.reload() + + # You can also use `group`, `domain`, `all_authenticated` and `all` to + # remove access for different types of entities. + bucket.default_object_acl.user(user_email).revoke_read() + bucket.default_object_acl.user(user_email).revoke_write() + bucket.default_object_acl.user(user_email).revoke_owner() + bucket.default_object_acl.save() + + print( + "Removed user {} from the default acl of bucket {}.".format( + user_email, bucket_name + ) + ) + + +# [END storage_remove_bucket_default_owner] + +if __name__ == "__main__": + remove_bucket_default_owner( + bucket_name=sys.argv[1], user_email=sys.argv[2] + ) diff --git a/samples/snippets/storage_remove_bucket_iam_member.py b/samples/snippets/storage_remove_bucket_iam_member.py new file mode 100644 index 000000000..ef75a1a15 --- /dev/null +++ b/samples/snippets/storage_remove_bucket_iam_member.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_remove_bucket_iam_member] +from google.cloud import storage + + +def remove_bucket_iam_member(bucket_name, role, member): + """Remove member from bucket IAM Policy""" + # bucket_name = "your-bucket-name" + # role = "IAM role, e.g. roles/storage.objectViewer" + # member = "IAM identity, e.g. user: name@example.com" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + + policy = bucket.get_iam_policy(requested_policy_version=3) + + for binding in policy.bindings: + print(binding) + if binding["role"] == role and binding.get("condition") is None: + binding["members"].discard(member) + + bucket.set_iam_policy(policy) + + print("Removed {} with role {} from {}.".format(member, role, bucket_name)) + + +# [END storage_remove_bucket_iam_member] + +if __name__ == "__main__": + remove_bucket_iam_member( + bucket_name=sys.argv[1], role=sys.argv[2], member=sys.argv[3] + ) diff --git a/samples/snippets/storage_remove_bucket_label.py b/samples/snippets/storage_remove_bucket_label.py new file mode 100644 index 000000000..58bbfef2d --- /dev/null +++ b/samples/snippets/storage_remove_bucket_label.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_remove_bucket_label] +import pprint +# [END storage_remove_bucket_label] +import sys +# [START storage_remove_bucket_label] + +from google.cloud import storage + + +def remove_bucket_label(bucket_name): + """Remove a label from a bucket.""" + # bucket_name = "your-bucket-name" + + storage_client = storage.Client() + bucket = storage_client.get_bucket(bucket_name) + + labels = bucket.labels + + if "example" in labels: + del labels["example"] + + bucket.labels = labels + bucket.patch() + + print("Removed labels on {}.".format(bucket.name)) + pprint.pprint(bucket.labels) + + +# [END storage_remove_bucket_label] + +if __name__ == "__main__": + remove_bucket_label(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_remove_bucket_owner.py b/samples/snippets/storage_remove_bucket_owner.py new file mode 100644 index 000000000..f54e7a7cc --- /dev/null +++ b/samples/snippets/storage_remove_bucket_owner.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +# Copyright 2019 Google, Inc. +# +# 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_remove_bucket_owner] +from google.cloud import storage + + +def remove_bucket_owner(bucket_name, user_email): + """Removes a user from the access control list of the given bucket.""" + # bucket_name = "your-bucket-name" + # user_email = "name@example.com" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + + # Reload fetches the current ACL from Cloud Storage. + bucket.acl.reload() + + # You can also use `group`, `domain`, `all_authenticated` and `all` to + # remove access for different types of entities. + bucket.acl.user(user_email).revoke_read() + bucket.acl.user(user_email).revoke_write() + bucket.acl.user(user_email).revoke_owner() + bucket.acl.save() + + print("Removed user {} from bucket {}.".format(user_email, bucket_name)) + + +# [END storage_remove_bucket_owner] + +if __name__ == "__main__": + remove_bucket_owner(bucket_name=sys.argv[1], user_email=sys.argv[2]) diff --git a/samples/snippets/storage_remove_cors_configuration.py b/samples/snippets/storage_remove_cors_configuration.py new file mode 100644 index 000000000..48ee74338 --- /dev/null +++ b/samples/snippets/storage_remove_cors_configuration.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC. All Rights Reserved. +# +# 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_remove_cors_configuration] +from google.cloud import storage + + +def remove_cors_configuration(bucket_name): + """Remove a bucket's CORS policies configuration.""" + # bucket_name = "your-bucket-name" + + storage_client = storage.Client() + bucket = storage_client.get_bucket(bucket_name) + bucket.cors = [] + bucket.patch() + + print("Remove CORS policies for bucket {}.".format(bucket.name)) + return bucket + + +# [END storage_remove_cors_configuration] + +if __name__ == "__main__": + remove_cors_configuration(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_remove_file_owner.py b/samples/snippets/storage_remove_file_owner.py new file mode 100644 index 000000000..9db83cce0 --- /dev/null +++ b/samples/snippets/storage_remove_file_owner.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +# Copyright 2019 Google, Inc. +# +# 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_remove_file_owner] +from google.cloud import storage + + +def remove_blob_owner(bucket_name, blob_name, user_email): + """Removes a user from the access control list of the given blob in the + given bucket.""" + # bucket_name = "your-bucket-name" + # blob_name = "your-object-name" + # user_email = "name@example.com" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + blob = bucket.blob(blob_name) + + # You can also use `group`, `domain`, `all_authenticated` and `all` to + # remove access for different types of entities. + blob.acl.user(user_email).revoke_read() + blob.acl.user(user_email).revoke_write() + blob.acl.user(user_email).revoke_owner() + blob.acl.save() + + print( + "Removed user {} from blob {} in bucket {}.".format( + user_email, blob_name, bucket_name + ) + ) + + +# [END storage_remove_file_owner] + +if __name__ == "__main__": + remove_blob_owner( + bucket_name=sys.argv[1], blob_name=sys.argv[2], user_email=sys.argv[3], + ) diff --git a/samples/snippets/storage_remove_retention_policy.py b/samples/snippets/storage_remove_retention_policy.py new file mode 100644 index 000000000..cb8ee548c --- /dev/null +++ b/samples/snippets/storage_remove_retention_policy.py @@ -0,0 +1,47 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_remove_retention_policy] +from google.cloud import storage + + +def remove_retention_policy(bucket_name): + """Removes the retention policy on a given bucket""" + # bucket_name = "my-bucket" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + bucket.reload() + + if bucket.retention_policy_locked: + print( + "Unable to remove retention period as retention policy is locked." + ) + return + + bucket.retention_period = None + bucket.patch() + + print("Removed bucket {} retention policy".format(bucket.name)) + + +# [END storage_remove_retention_policy] + + +if __name__ == "__main__": + remove_retention_policy(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_rename_file.py b/samples/snippets/storage_rename_file.py new file mode 100644 index 000000000..b47e18621 --- /dev/null +++ b/samples/snippets/storage_rename_file.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python + +# Copyright 2021 Google LLC. All Rights Reserved. +# +# 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_rename_file] +from google.cloud import storage + + +def rename_blob(bucket_name, blob_name, new_name): + """Renames a blob.""" + # The ID of your GCS bucket + # bucket_name = "your-bucket-name" + # The ID of the GCS object to rename + # blob_name = "your-object-name" + # The new ID of the GCS object + # new_name = "new-object-name" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + blob = bucket.blob(blob_name) + + new_blob = bucket.rename_blob(blob, new_name) + + print("Blob {} has been renamed to {}".format(blob.name, new_blob.name)) + + +# [END storage_rename_file] + +if __name__ == "__main__": + rename_blob(bucket_name=sys.argv[1], blob_name=sys.argv[2], new_name=sys.argv[3]) diff --git a/samples/snippets/storage_rotate_encryption_key.py b/samples/snippets/storage_rotate_encryption_key.py new file mode 100644 index 000000000..663ee4796 --- /dev/null +++ b/samples/snippets/storage_rotate_encryption_key.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python + +# Copyright 2019 Google, Inc. +# +# 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_rotate_encryption_key] +import base64 +# [END storage_rotate_encryption_key] +import sys +# [START storage_rotate_encryption_key] + +from google.cloud import storage + + +def rotate_encryption_key( + bucket_name, blob_name, base64_encryption_key, base64_new_encryption_key +): + """Performs a key rotation by re-writing an encrypted blob with a new + encryption key.""" + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + current_encryption_key = base64.b64decode(base64_encryption_key) + new_encryption_key = base64.b64decode(base64_new_encryption_key) + + # Both source_blob and destination_blob refer to the same storage object, + # but destination_blob has the new encryption key. + source_blob = bucket.blob( + blob_name, encryption_key=current_encryption_key + ) + destination_blob = bucket.blob( + blob_name, encryption_key=new_encryption_key + ) + + token = None + + while True: + token, bytes_rewritten, total_bytes = destination_blob.rewrite( + source_blob, token=token + ) + if token is None: + break + + print("Key rotation complete for Blob {}".format(blob_name)) + + +# [END storage_rotate_encryption_key] + +if __name__ == "__main__": + rotate_encryption_key( + bucket_name=sys.argv[1], + blob_name=sys.argv[2], + base64_encryption_key=sys.argv[3], + base64_new_encryption_key=sys.argv[4], + ) diff --git a/samples/snippets/storage_set_bucket_default_kms_key.py b/samples/snippets/storage_set_bucket_default_kms_key.py new file mode 100644 index 000000000..7ba4718b2 --- /dev/null +++ b/samples/snippets/storage_set_bucket_default_kms_key.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_set_bucket_default_kms_key] +from google.cloud import storage + + +def enable_default_kms_key(bucket_name, kms_key_name): + """Sets a bucket's default KMS key.""" + # bucket_name = "your-bucket-name" + # kms_key_name = "projects/PROJ/locations/LOC/keyRings/RING/cryptoKey/KEY" + + storage_client = storage.Client() + bucket = storage_client.get_bucket(bucket_name) + bucket.default_kms_key_name = kms_key_name + bucket.patch() + + print( + "Set default KMS key for bucket {} to {}.".format( + bucket.name, bucket.default_kms_key_name + ) + ) + + +# [END storage_set_bucket_default_kms_key] + +if __name__ == "__main__": + enable_default_kms_key(bucket_name=sys.argv[1], kms_key_name=sys.argv[2]) diff --git a/samples/snippets/storage_set_bucket_public_iam.py b/samples/snippets/storage_set_bucket_public_iam.py new file mode 100644 index 000000000..c43b3eee5 --- /dev/null +++ b/samples/snippets/storage_set_bucket_public_iam.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC. All Rights Reserved. +# +# 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_set_bucket_public_iam] +from google.cloud import storage + + +def set_bucket_public_iam(bucket_name): + """Set a public IAM Policy to bucket""" + # bucket_name = "your-bucket-name" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + + policy = bucket.get_iam_policy(requested_policy_version=3) + policy.bindings.append( + {"role": "roles/storage.objectViewer", "members": {"allUsers"}} + ) + + bucket.set_iam_policy(policy) + + print("Bucket {} is now publicly readable".format(bucket.name)) + + +# [END storage_set_bucket_public_iam] + +if __name__ == "__main__": + set_bucket_public_iam( + bucket_name=sys.argv[1], + ) diff --git a/samples/snippets/storage_set_event_based_hold.py b/samples/snippets/storage_set_event_based_hold.py new file mode 100644 index 000000000..52a89b88e --- /dev/null +++ b/samples/snippets/storage_set_event_based_hold.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_set_event_based_hold] +from google.cloud import storage + + +def set_event_based_hold(bucket_name, blob_name): + """Sets a event based hold on a given blob""" + # bucket_name = "my-bucket" + # blob_name = "my-blob" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + blob = bucket.blob(blob_name) + + blob.event_based_hold = True + blob.patch() + + print("Event based hold was set for {}".format(blob_name)) + + +# [END storage_set_event_based_hold] + + +if __name__ == "__main__": + set_event_based_hold(bucket_name=sys.argv[1], blob_name=sys.argv[2]) diff --git a/samples/snippets/storage_set_metadata.py b/samples/snippets/storage_set_metadata.py new file mode 100644 index 000000000..07529ac68 --- /dev/null +++ b/samples/snippets/storage_set_metadata.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python + +# Copyright 2020 Google Inc. All Rights Reserved. +# +# 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_set_metadata] +from google.cloud import storage + + +def set_blob_metadata(bucket_name, blob_name): + """Set a blob's metadata.""" + # bucket_name = 'your-bucket-name' + # blob_name = 'your-object-name' + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + blob = bucket.get_blob(blob_name) + metadata = {'color': 'Red', 'name': 'Test'} + blob.metadata = metadata + blob.patch() + + print("The metadata for the blob {} is {}".format(blob.name, blob.metadata)) + + +# [END storage_set_metadata] + +if __name__ == "__main__": + set_blob_metadata(bucket_name=sys.argv[1], blob_name=sys.argv[2]) diff --git a/samples/snippets/storage_set_public_access_prevention_enforced.py b/samples/snippets/storage_set_public_access_prevention_enforced.py new file mode 100644 index 000000000..59ce5ce56 --- /dev/null +++ b/samples/snippets/storage_set_public_access_prevention_enforced.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +# Copyright 2021 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_set_public_access_prevention_enforced] +from google.cloud import storage +from google.cloud.storage.constants import PUBLIC_ACCESS_PREVENTION_ENFORCED + + +def set_public_access_prevention_enforced(bucket_name): + """Enforce public access prevention for a bucket.""" + # The ID of your GCS bucket + # bucket_name = "my-bucket" + + storage_client = storage.Client() + bucket = storage_client.get_bucket(bucket_name) + + bucket.iam_configuration.public_access_prevention = ( + PUBLIC_ACCESS_PREVENTION_ENFORCED + ) + bucket.patch() + + print(f"Public access prevention is set to enforced for {bucket.name}.") + + +# [END storage_set_public_access_prevention_enforced] + +if __name__ == "__main__": + set_public_access_prevention_enforced(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_set_public_access_prevention_inherited.py b/samples/snippets/storage_set_public_access_prevention_inherited.py new file mode 100644 index 000000000..97e218f9d --- /dev/null +++ b/samples/snippets/storage_set_public_access_prevention_inherited.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python + +# Copyright 2021 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 + +"""Sample that sets public access prevention to inherited. +This sample is used on this page: + https://cloud.google.com/storage/docs/using-public-access-prevention +For more information, see README.md. +""" + +# [START storage_set_public_access_prevention_inherited] + +from google.cloud import storage +from google.cloud.storage.constants import PUBLIC_ACCESS_PREVENTION_INHERITED + + +def set_public_access_prevention_inherited(bucket_name): + """Sets the public access prevention status to inherited, so that the bucket inherits its setting from its parent project.""" + # The ID of your GCS bucket + # bucket_name = "my-bucket" + + storage_client = storage.Client() + bucket = storage_client.get_bucket(bucket_name) + + bucket.iam_configuration.public_access_prevention = ( + PUBLIC_ACCESS_PREVENTION_INHERITED + ) + bucket.patch() + + print(f"Public access prevention is 'inherited' for {bucket.name}.") + + +# [END storage_set_public_access_prevention_inherited] + +if __name__ == "__main__": + set_public_access_prevention_inherited(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_set_public_access_prevention_unspecified.py b/samples/snippets/storage_set_public_access_prevention_unspecified.py new file mode 100644 index 000000000..ae2c4701c --- /dev/null +++ b/samples/snippets/storage_set_public_access_prevention_unspecified.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +# Copyright 2021 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_set_public_access_prevention_unspecified] +from google.cloud import storage +from google.cloud.storage.constants import PUBLIC_ACCESS_PREVENTION_UNSPECIFIED + + +def set_public_access_prevention_unspecified(bucket_name): + """Sets the public access prevention status to unspecified, so that the bucket inherits its setting from its parent project.""" + # The ID of your GCS bucket + # bucket_name = "my-bucket" + + storage_client = storage.Client() + bucket = storage_client.get_bucket(bucket_name) + + bucket.iam_configuration.public_access_prevention = ( + PUBLIC_ACCESS_PREVENTION_UNSPECIFIED + ) + bucket.patch() + + print(f"Public access prevention is 'unspecified' for {bucket.name}.") + + +# [END storage_set_public_access_prevention_unspecified] + +if __name__ == "__main__": + set_public_access_prevention_unspecified(bucket_name=sys.argv[1]) diff --git a/samples/snippets/storage_set_retention_policy.py b/samples/snippets/storage_set_retention_policy.py new file mode 100644 index 000000000..2b3602491 --- /dev/null +++ b/samples/snippets/storage_set_retention_policy.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_set_retention_policy] +from google.cloud import storage + + +def set_retention_policy(bucket_name, retention_period): + """Defines a retention policy on a given bucket""" + # bucket_name = "my-bucket" + # retention_period = 10 + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + + bucket.retention_period = retention_period + bucket.patch() + + print( + "Bucket {} retention period set for {} seconds".format( + bucket.name, bucket.retention_period + ) + ) + + +# [END storage_set_retention_policy] + + +if __name__ == "__main__": + set_retention_policy(bucket_name=sys.argv[1], retention_period=sys.argv[2]) diff --git a/samples/snippets/storage_set_temporary_hold.py b/samples/snippets/storage_set_temporary_hold.py new file mode 100644 index 000000000..edeb3c578 --- /dev/null +++ b/samples/snippets/storage_set_temporary_hold.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_set_temporary_hold] +from google.cloud import storage + + +def set_temporary_hold(bucket_name, blob_name): + """Sets a temporary hold on a given blob""" + # bucket_name = "my-bucket" + # blob_name = "my-blob" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + blob = bucket.blob(blob_name) + + blob.temporary_hold = True + blob.patch() + + print("Temporary hold was set for #{blob_name}") + + +# [END storage_set_temporary_hold] + + +if __name__ == "__main__": + set_temporary_hold(bucket_name=sys.argv[1], blob_name=sys.argv[2]) diff --git a/samples/snippets/storage_upload_encrypted_file.py b/samples/snippets/storage_upload_encrypted_file.py new file mode 100644 index 000000000..e7d02c67b --- /dev/null +++ b/samples/snippets/storage_upload_encrypted_file.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python + +# Copyright 2019 Google, Inc. +# +# 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_upload_encrypted_file] +import base64 +# [END storage_upload_encrypted_file] +import sys +# [START storage_upload_encrypted_file] + +from google.cloud import storage + + +def upload_encrypted_blob( + bucket_name, + source_file_name, + destination_blob_name, + base64_encryption_key, +): + """Uploads a file to a Google Cloud Storage bucket using a custom + encryption key. + + The file will be encrypted by Google Cloud Storage and only + retrievable using the provided encryption key. + """ + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + + # Encryption key must be an AES256 key represented as a bytestring with + # 32 bytes. Since it's passed in as a base64 encoded string, it needs + # to be decoded. + encryption_key = base64.b64decode(base64_encryption_key) + blob = bucket.blob( + destination_blob_name, encryption_key=encryption_key + ) + + blob.upload_from_filename(source_file_name) + + print( + "File {} uploaded to {}.".format( + source_file_name, destination_blob_name + ) + ) + + +# [END storage_upload_encrypted_file] + +if __name__ == "__main__": + upload_encrypted_blob( + bucket_name=sys.argv[1], + source_file_name=sys.argv[2], + destination_blob_name=sys.argv[3], + base64_encryption_key=sys.argv[4], + ) diff --git a/samples/snippets/storage_upload_file.py b/samples/snippets/storage_upload_file.py new file mode 100644 index 000000000..fb02c3632 --- /dev/null +++ b/samples/snippets/storage_upload_file.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_upload_file] +from google.cloud import storage + + +def upload_blob(bucket_name, source_file_name, destination_blob_name): + """Uploads a file to the bucket.""" + # The ID of your GCS bucket + # bucket_name = "your-bucket-name" + # The path to your file to upload + # source_file_name = "local/path/to/file" + # The ID of your GCS object + # destination_blob_name = "storage-object-name" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + blob = bucket.blob(destination_blob_name) + + blob.upload_from_filename(source_file_name) + + print( + "File {} uploaded to {}.".format( + source_file_name, destination_blob_name + ) + ) + + +# [END storage_upload_file] + +if __name__ == "__main__": + upload_blob( + bucket_name=sys.argv[1], + source_file_name=sys.argv[2], + destination_blob_name=sys.argv[3], + ) diff --git a/samples/snippets/storage_upload_with_kms_key.py b/samples/snippets/storage_upload_with_kms_key.py new file mode 100644 index 000000000..e83c10aea --- /dev/null +++ b/samples/snippets/storage_upload_with_kms_key.py @@ -0,0 +1,52 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_upload_with_kms_key] +from google.cloud import storage + + +def upload_blob_with_kms( + bucket_name, source_file_name, destination_blob_name, kms_key_name +): + """Uploads a file to the bucket, encrypting it with the given KMS key.""" + # bucket_name = "your-bucket-name" + # source_file_name = "local/path/to/file" + # destination_blob_name = "storage-object-name" + # kms_key_name = "projects/PROJ/locations/LOC/keyRings/RING/cryptoKey/KEY" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + blob = bucket.blob(destination_blob_name, kms_key_name=kms_key_name) + blob.upload_from_filename(source_file_name) + + print( + "File {} uploaded to {} with encryption key {}.".format( + source_file_name, destination_blob_name, kms_key_name + ) + ) + + +# [END storage_upload_with_kms_key] + +if __name__ == "__main__": + upload_blob_with_kms( + bucket_name=sys.argv[1], + source_file_name=sys.argv[2], + destination_blob_name=sys.argv[3], + kms_key_name=sys.argv[4], + ) diff --git a/samples/snippets/storage_view_bucket_iam_members.py b/samples/snippets/storage_view_bucket_iam_members.py new file mode 100644 index 000000000..5272f0ddb --- /dev/null +++ b/samples/snippets/storage_view_bucket_iam_members.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python + +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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_view_bucket_iam_members] +from google.cloud import storage + + +def view_bucket_iam_members(bucket_name): + """View IAM Policy for a bucket""" + # bucket_name = "your-bucket-name" + + storage_client = storage.Client() + bucket = storage_client.bucket(bucket_name) + + policy = bucket.get_iam_policy(requested_policy_version=3) + + for binding in policy.bindings: + print("Role: {}, Members: {}".format(binding["role"], binding["members"])) + + +# [END storage_view_bucket_iam_members] + + +if __name__ == "__main__": + view_bucket_iam_members(bucket_name=sys.argv[1]) diff --git a/samples/snippets/uniform_bucket_level_access_test.py b/samples/snippets/uniform_bucket_level_access_test.py new file mode 100644 index 000000000..b43fa016f --- /dev/null +++ b/samples/snippets/uniform_bucket_level_access_test.py @@ -0,0 +1,52 @@ +# Copyright 2019 Google Inc. All Rights Reserved. +# +# 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 storage_disable_uniform_bucket_level_access +import storage_enable_uniform_bucket_level_access +import storage_get_uniform_bucket_level_access + + +def test_get_uniform_bucket_level_access(bucket, capsys): + storage_get_uniform_bucket_level_access.get_uniform_bucket_level_access( + bucket.name + ) + out, _ = capsys.readouterr() + assert ( + "Uniform bucket-level access is disabled for {}.".format(bucket.name) + in out + ) + + +def test_enable_uniform_bucket_level_access(bucket, capsys): + short_name = storage_enable_uniform_bucket_level_access + short_name.enable_uniform_bucket_level_access( + bucket.name + ) + out, _ = capsys.readouterr() + assert ( + "Uniform bucket-level access was enabled for {}.".format(bucket.name) + in out + ) + + +def test_disable_uniform_bucket_level_access(bucket, capsys): + short_name = storage_disable_uniform_bucket_level_access + short_name.disable_uniform_bucket_level_access( + bucket.name + ) + out, _ = capsys.readouterr() + assert ( + "Uniform bucket-level access was disabled for {}.".format(bucket.name) + in out + )