diff --git a/google-cloud-storage/Rakefile b/google-cloud-storage/Rakefile
index 4840abdbc44a..47bcdaab6169 100644
--- a/google-cloud-storage/Rakefile
+++ b/google-cloud-storage/Rakefile
@@ -125,6 +125,40 @@ namespace :acceptance do
end
end
+task :samples do
+ Rake::Task["samples:latest"].invoke
+end
+
+namespace :samples do
+ task :latest do
+ if File.directory? "samples"
+ Dir.chdir "samples" do
+ Bundler.with_clean_env do
+ ENV["GOOGLE_CLOUD_SAMPLES_TEST"] = "not_master"
+ sh "bundle update"
+ sh "bundle exec rake test"
+ end
+ end
+ else
+ puts "The google-cloud-language gem has no samples to test."
+ end
+ end
+
+ task :master do
+ if File.directory? "samples"
+ Dir.chdir "samples" do
+ Bundler.with_clean_env do
+ ENV["GOOGLE_CLOUD_SAMPLES_TEST"] = "master"
+ sh "bundle update"
+ sh "bundle exec rake test"
+ end
+ end
+ else
+ puts "The google-cloud-language gem has no samples to test."
+ end
+ end
+end
+
desc "Run yard-doctest example tests."
task :doctest do
sh "bundle exec yard config load_plugins true && bundle exec yard doctest"
diff --git a/google-cloud-storage/samples/Gemfile b/google-cloud-storage/samples/Gemfile
new file mode 100644
index 000000000000..f98685b31aa7
--- /dev/null
+++ b/google-cloud-storage/samples/Gemfile
@@ -0,0 +1,35 @@
+# 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.
+
+# [START storage_dependencies]
+source "https://rubygems.org"
+
+# [END storage_dependencies]
+
+if ENV["GOOGLE_CLOUD_SAMPLES_TEST"] == "master"
+ gem "google-cloud-kms", group: :test, path: "../../google-cloud-kms"
+ gem "google-cloud-storage", path: "../../google-cloud-storage"
+else
+ # rubocop:disable Bundler/DuplicatedGem
+ gem "google-cloud-kms", group: :test
+ # [START storage_dependencies]
+ gem "google-cloud-storage"
+ # [END storage_dependencies]
+ # rubocop:enable Bundler/DuplicatedGem
+end
+
+group :test do
+ gem "minitest", "~> 5.13"
+ gem "rake"
+end
diff --git a/google-cloud-storage/samples/README.md b/google-cloud-storage/samples/README.md
new file mode 100644
index 000000000000..e3dccde7c54f
--- /dev/null
+++ b/google-cloud-storage/samples/README.md
@@ -0,0 +1,149 @@
+
+
+# Google Cloud Storage Ruby Samples
+
+[Cloud Storage][storage_docs] allows world-wide storage and retrieval of any
+amount of data at any time.
+
+[storage_docs]: https://cloud.google.com/storage/docs/
+
+## Run sample
+
+To run the sample, first install dependencies:
+
+ bundle install
+
+Run the sample:
+
+ bundle exec ruby buckets.rb
+ bundle exec ruby files.rb
+ bundle exec ruby acls.rb
+
+## Samples
+
+### Buckets
+
+**Usage:** `bundle exec ruby buckets.rb [command] [arguments]`
+
+```
+Usage: bundle exec ruby buckets.rb [command] [arguments]
+
+Commands:
+ list List all buckets in the authenticated project
+ enable_requester_pays Enable requester pays for a bucket
+ disable_requester_pays Disable requester pays for a bucket
+ check_requester_pays Check status of requester pays for a bucket
+ enable_default_kms_key Enable default KMS encryption for bucket
+ create Create a new bucket with default storage class and location
+ create Create a new bucket with specific storage class and location
+ list_bucket_labels List bucket labels
+ add_bucket_label Add bucket label
+ delete_bucket_label Delete bucket label
+ delete Delete bucket with the provided name
+ set_retention_policy Set a retention policy on bucket with a retention period determined in seconds
+ remove_retention_policy Remove a retention policy from a bucket if policy is not locked
+ lock_retention_policy Lock retention policy
+ get_retention_policy Get retention policy for a bucket
+ enable_default_event_based_hold Enable event-based hold for a bucket
+ disable_default_event_based_hold Disable event-based hold for a bucket
+ get_default_event_based_hold Get state of event-based hold for a bucket
+ enable_uniform_bucket_level_access Enable uniform bucket-level access for a bucket
+ disable_uniform_bucket_level_access Disable uniform bucket-level access for a bucket
+ get_uniform_bucket_level_access Get uniform bucket-level access for a bucket
+
+Environment variables:
+ GOOGLE_CLOUD_PROJECT must be set to your Google Cloud project ID
+```
+
+### Files
+
+**Usage:** `bundle exec ruby files.rb [command] [arguments]`
+
+```
+Usage: bundle exec ruby files.rb [command] [arguments]
+
+Commands:
+ list List all files in the bucket
+ upload Upload local file to a bucket
+ encrypted_upload Upload local file as an encrypted file to a bucket
+ kms_upload Upload local file and encrypt service side using a KMS key
+ download Download a file from a bucket
+ download_public_file Download a publically accessible file from a bucket
+ encrypted_download Download an encrypted file from a bucket
+ download_with_requester_pays Download a file from a requester pays enabled bucket
+ rotate_encryption_key Update encryption key of an encrypted file.
+ generate_encryption_key Generate a sample encryption key
+ delete Delete a file from a bucket
+ metadata Display metadata for a file in a bucket
+ make_public Make a file in a bucket public
+ rename Rename a file in a bucket
+ copy Copy file to other bucket
+ generate_signed_url Generate a signed url for a file
+ set_event_based_hold Set an event-based hold on a file
+ release_event_based_hold Relase an event-based hold on a file
+ set_temporary_hold Set a temporary hold on a file
+ release_temporary_hold Release a temporary hold on a file
+
+Environment variables:
+ GOOGLE_CLOUD_PROJECT must be set to your Google Cloud project ID
+```
+
+### Access Control List
+
+**Usage:** `bundle exec ruby acls.rb [command] [arguments]`
+
+```
+Usage: bundle exec ruby acls.rb [command] [arguments]
+
+Commands:
+ print_bucket_acl Print bucket Access Control List
+ print_bucket_acl_for_user Print bucket ACL for an email
+ add_bucket_owner Add a new OWNER to a bucket
+ remove_bucket_acl Remove an entity from a bucket ACL
+ add_bucket_default_owner Add a default OWNER for a bucket
+ remove_bucket_default_acl Remove an entity from default bucket ACL
+ print_file_acl Print file ACL
+ print_file_acl_for_user Print file ACL for an email
+ add_file_owner Add an OWNER to a file
+ remove_file_acl Remove an entity from a file ACL
+
+Environment variables:
+ GOOGLE_CLOUD_PROJECT must be set to your Google Cloud project ID
+```
+
+### Cloud Storage Bucket-level Identity & Access Management
+
+**Usage:** `bundle exec ruby iam.rb [command] [arguments]`
+
+```
+Usage: bundle exec ruby iam.rb [command] [arguments]
+
+Commands:
+ view_bucket_iam_members View bucket-level IAM members
+ add_bucket_iam_member Add a bucket-level IAM member
+ add_bucket_conditional_iam_binding Add a conditional bucket-level binding
+ remove_bucket_iam_member Remove a bucket-level IAM member
+ remove_bucket_conditional_iam_binding Remove a conditional bucket-level binding
+
+Environment variables:
+ GOOGLE_CLOUD_PROJECT must be set to your Google Cloud project ID
+```
+
+### Cloud Storage Service Account HMAC Key Management
+
+**Usage:** `bundle exec ruby hmac.rb [commmand] [arguments]`
+
+```
+Usage: bundle exec ruby hmac.rb [command] [arguments]
+
+Commands:
+ list_hmac_keys List all HMAC keys for a project
+ create_hmac_key Create HMAC Key
+ get_hmac_key Get HMAC Key metadata
+ activate_hmac_key Activate an HMAC Key
+ deactivate_hmac_key Deactivate an HMAC Key
+ delete_hmac_key Delete a deactivated HMAC key
+
+Environment variables:
+ GOOGLE_CLOUD_PROJECT must be set to your Google Cloud project ID
+```
diff --git a/google-cloud-storage/samples/Rakefile b/google-cloud-storage/samples/Rakefile
new file mode 100644
index 000000000000..6326eebd9945
--- /dev/null
+++ b/google-cloud-storage/samples/Rakefile
@@ -0,0 +1,6 @@
+require "rake/testtask"
+
+Rake::TestTask.new "test" do |t|
+ t.test_files = FileList["**/*_test.rb"]
+ t.warning = false
+end
diff --git a/google-cloud-storage/samples/acceptance/acls_test.rb b/google-cloud-storage/samples/acceptance/acls_test.rb
new file mode 100644
index 000000000000..e89e0b9e1bc9
--- /dev/null
+++ b/google-cloud-storage/samples/acceptance/acls_test.rb
@@ -0,0 +1,165 @@
+# 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.
+
+require_relative "helper"
+require_relative "../acls.rb"
+
+describe "ACL Snippets" do
+ parallelize_me!
+
+ let :bucket do
+ create_bucket_helper "ruby_storage_sample_#{SecureRandom.hex}"
+ end
+
+ let(:storage_client) { Google::Cloud::Storage.new }
+ let(:local_file) { File.expand_path "data/file.txt", __dir__ }
+ let(:email) { "user-test@test.com" }
+ let(:remote_file_name) { "path/file_name.txt" }
+
+ after do
+ delete_bucket_helper bucket.name
+ end
+
+ describe "print_bucket_acl" do
+ it "prints a bucket's acl" do
+ bucket.acl.add_owner email
+
+ out, _err = capture_io do
+ print_bucket_acl bucket_name: bucket.name
+ end
+
+ assert_includes out, "ACL for #{bucket.name}:"
+ assert_includes out, "OWNER #{email}"
+ end
+ end
+
+ describe "print_bucket_acl_for_user" do
+ it "prints a bucket's acl for a user" do
+ bucket.acl.add_owner email
+
+ expected_output = <<~OUTPUT
+ Permissions for #{email}:
+ OWNER
+ OUTPUT
+
+ assert_output expected_output do
+ print_bucket_acl_for_user bucket_name: bucket.name,
+ email: email
+ end
+ end
+ end
+
+ describe "add_bucket_owner" do
+ it "adds owner permissions to a user for a bucket" do
+ assert_output "Added OWNER permission for #{email} to #{bucket.name}\n" do
+ add_bucket_owner bucket_name: bucket.name,
+ email: email
+ end
+ assert_includes bucket.acl.owners, email
+ end
+ end
+
+ describe "remove_bucket_acl" do
+ it "removes a user from a bucket's acl" do
+ bucket.acl.add_owner email
+ assert_output "Removed ACL permissions for #{email} from #{bucket.name}\n" do
+ remove_bucket_acl bucket_name: bucket.name,
+ email: email
+ end
+ refute_includes bucket.acl.owners, email
+ end
+ end
+
+ describe "add_bucket_default_owner" do
+ it "adds a user as default owner for a bucket" do
+ assert_output "Added default OWNER permission for #{email} to #{bucket.name}\n" do
+ add_bucket_default_owner bucket_name: bucket.name,
+ email: email
+ end
+ assert_includes bucket.default_acl.owners, email
+ end
+ end
+
+ describe "remove_bucket_default_acl" do
+ it "adds a user as default owner for a bucket" do
+ bucket.default_acl.add_owner email
+ assert_output "Removed default ACL permissions for #{email} from #{bucket.name}\n" do
+ remove_bucket_default_acl bucket_name: bucket.name,
+ email: email
+ end
+ refute_includes bucket.default_acl.owners, email
+ end
+ end
+
+ describe "print_file_acl" do
+ it "prints the acl for a file in a bucket" do
+ bucket.create_file local_file, remote_file_name
+ owners = bucket.file(remote_file_name).acl.owners
+ readers = bucket.file(remote_file_name).acl.readers
+
+ out, _err = capture_io do
+ print_file_acl bucket_name: bucket.name,
+ file_name: remote_file_name
+ end
+
+ assert owners.all? do |owner|
+ out.includes? "OWNER #{owner}"
+ end
+
+ assert readers.all? do |reader|
+ out.includes? "READER #{reader}"
+ end
+ end
+ end
+
+ describe "print_file_acl_for_user" do
+ it "prints the permissions of a given user for a file in a bucket" do
+ bucket.create_file local_file, remote_file_name
+ bucket.file(remote_file_name).acl.add_owner email
+
+ assert_output "Permissions for #{email}:\nOWNER\n" do
+ print_file_acl_for_user bucket_name: bucket.name,
+ file_name: remote_file_name,
+ email: email
+ end
+ end
+ end
+
+ describe "add_file_owner" do
+ it "adds a user as an owner of for a file in a bucket" do
+ bucket.create_file local_file, remote_file_name
+
+ assert_output "Added OWNER permission for #{email} to #{remote_file_name}\n" do
+ add_file_owner bucket_name: bucket.name,
+ file_name: remote_file_name,
+ email: email
+ end
+ assert_includes bucket.file(remote_file_name).acl.owners, email
+ end
+ end
+
+ describe "remove_file_acl" do
+ it "removes a user from the acl for file in a bucket" do
+ bucket.create_file local_file, remote_file_name
+ bucket.file(remote_file_name).acl.add_owner email
+
+ assert_output "Removed ACL permissions for #{email} from #{remote_file_name}\n" do
+ remove_file_acl bucket_name: bucket.name,
+ file_name: remote_file_name,
+ email: email
+ end
+ refute_includes bucket.file(remote_file_name).acl.owners, email
+ end
+ end
+end
diff --git a/google-cloud-storage/samples/acceptance/buckets_test.rb b/google-cloud-storage/samples/acceptance/buckets_test.rb
new file mode 100644
index 000000000000..54a53b374276
--- /dev/null
+++ b/google-cloud-storage/samples/acceptance/buckets_test.rb
@@ -0,0 +1,355 @@
+# 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.
+
+require_relative "helper"
+require_relative "../buckets.rb"
+
+describe "Buckets Snippets" do
+ parallelize_me!
+
+ let(:storage_client) { Google::Cloud::Storage.new }
+ let(:kms_key) { get_kms_key storage_client.project }
+ let(:retention_period) { rand 1..99 }
+
+ let :bucket do
+ create_bucket_helper "ruby_storage_sample_#{SecureRandom.hex}"
+ end
+
+ let :secondary_bucket do
+ create_bucket_helper "ruby_storage_sample_#{SecureRandom.hex}_secondary"
+ end
+
+ after do
+ delete_bucket_helper bucket.name
+ delete_bucket_helper secondary_bucket.name
+ end
+
+ describe "list_buckets" do
+ it "puts the buckets for a GCP project" do
+ bucket
+ secondary_bucket
+
+ out, _err = capture_io do
+ list_buckets
+ end
+
+ assert_includes out, bucket.name
+ assert_includes out, secondary_bucket.name
+ end
+ end
+
+ describe "list_bucket_details" do
+ it "puts the details of a storage bucket" do
+ out, _err = capture_io do
+ list_bucket_details bucket_name: bucket.name
+ end
+
+ assert_includes out, bucket.name
+ end
+ end
+
+ describe "disable_requester_pays" do
+ it "disables requester_pays for a storage bucket" do
+ bucket.requester_pays = true
+
+ assert_output "Requester pays has been disabled for #{bucket.name}\n" do
+ disable_requester_pays bucket_name: bucket.name
+ end
+ bucket.refresh!
+ refute bucket.requester_pays?
+ end
+ end
+
+ describe "enable_requester_pays" do
+ it "enables requester_pays for a storage bucket" do
+ bucket.requester_pays = false
+
+ assert_output "Requester pays has been enabled for #{bucket.name}\n" do
+ enable_requester_pays bucket_name: bucket.name
+ end
+ bucket.refresh!
+ assert bucket.requester_pays?
+ end
+ end
+
+ describe "get_requester_pays_status" do
+ it "displays the status of requester_pays for a storage bucket" do
+ bucket.requester_pays = false
+
+ assert_output "Requester Pays is disabled for #{bucket.name}\n" do
+ get_requester_pays_status bucket_name: bucket.name
+ end
+
+ bucket.requester_pays = true
+ assert_output "Requester Pays is enabled for #{bucket.name}\n" do
+ get_requester_pays_status bucket_name: bucket.name
+ end
+ end
+ end
+
+ describe "disable_uniform_bucket_level_access" do
+ it "disables uniform bucket level access for a storage bucket" do
+ bucket.uniform_bucket_level_access = true
+
+ assert_output "Uniform bucket-level access was disabled for #{bucket.name}.\n" do
+ disable_uniform_bucket_level_access bucket_name: bucket.name
+ end
+
+ bucket.refresh!
+ refute bucket.uniform_bucket_level_access?
+ end
+ end
+
+ describe "enable_uniform_bucket_level_access" do
+ it "enables uniform bucket level access for a storage bucket" do
+ bucket.uniform_bucket_level_access = false
+
+ assert_output "Uniform bucket-level access was enabled for #{bucket.name}.\n" do
+ enable_uniform_bucket_level_access bucket_name: bucket.name
+ end
+
+ bucket.refresh!
+ assert bucket.uniform_bucket_level_access?
+ end
+ end
+
+ describe "get_uniform_bucket_level_access" do
+ it "displays the status of uniform bucket level access for a storage bucket" do
+ bucket.uniform_bucket_level_access = false
+
+ assert_output "Uniform bucket-level access is disabled for #{bucket.name}.\n" do
+ get_uniform_bucket_level_access bucket_name: bucket.name
+ end
+ refute bucket.uniform_bucket_level_access?
+
+ bucket.uniform_bucket_level_access = true
+
+ assert_output "Uniform bucket-level access is enabled for #{bucket.name}.\nBucket "\
+ "will be locked on #{bucket.uniform_bucket_level_access_locked_at}.\n" do
+ get_uniform_bucket_level_access bucket_name: bucket.name
+ end
+ assert bucket.uniform_bucket_level_access?
+ end
+ end
+
+ describe "enable_default_kms_key" do
+ it "sets a default kms key for a storage bucket" do
+ refute bucket.default_kms_key
+
+ assert_output "Default KMS key for #{bucket.name} was set to #{kms_key}\n" do
+ enable_default_kms_key bucket_name: bucket.name,
+ default_kms_key: kms_key
+ end
+
+ bucket.refresh!
+ assert_equal bucket.default_kms_key, kms_key
+ end
+ end
+
+ describe "create_bucket" do
+ it "creates a storage bucket" do
+ bucket_name = "ruby_storage_sample_#{SecureRandom.hex}"
+ refute storage_client.bucket bucket_name
+
+ retry_resource_exhaustion do
+ assert_output "Created bucket: #{bucket_name}\n" do
+ create_bucket bucket_name: bucket_name
+ end
+ end
+
+ refute_nil storage_client.bucket bucket_name
+ delete_bucket_helper bucket_name
+ end
+ end
+
+ describe "create_bucket_class_location" do
+ it "creates a storage bucket with a given class and location" do
+ bucket_name = "ruby_storage_sample_#{SecureRandom.hex}"
+ location = "US"
+ storage_class = "STANDARD"
+ refute storage_client.bucket bucket_name
+
+ retry_resource_exhaustion do
+ assert_output "Created bucket #{bucket_name} in #{location} with #{storage_class} class\n" do
+ create_bucket_class_location bucket_name: bucket_name,
+ location: location,
+ storage_class: storage_class
+ end
+ end
+
+ refute_nil storage_client.bucket bucket_name
+ assert_equal storage_client.bucket(bucket_name).location, location
+ assert_equal storage_client.bucket(bucket_name).storage_class, storage_class
+ delete_bucket_helper bucket_name
+ end
+ end
+
+ describe "list_bucket_labels" do
+ it "puts the labels of a given bucket" do
+ label_key = "label_key"
+ label_value = "label_value"
+ bucket.update do |b|
+ b.labels[label_key] = label_value
+ end
+
+ out, _err = capture_io do
+ list_bucket_labels bucket_name: bucket.name
+ end
+
+ assert_includes out, "#{label_key} = #{label_value}"
+ end
+ end
+
+ describe "add_bucket_label" do
+ it "adds a label to a given bucket" do
+ label_key = "label_key"
+ label_value = "label_value"
+
+ assert_output "Added label #{label_key} with value #{label_value} to #{bucket.name}\n" do
+ add_bucket_label bucket_name: bucket.name,
+ label_value: label_value,
+ label_key: label_key
+ end
+
+ bucket.refresh!
+ assert_equal bucket.labels[label_key], label_value
+ end
+ end
+
+ describe "delete_bucket_label" do
+ it "deletes a label from a given bucket" do
+ label_key = "label_key"
+ label_value = "label_value"
+ bucket.update do |b|
+ b.labels[label_key] = label_value
+ end
+
+ assert_output "Deleted label #{label_key} from #{bucket.name}\n" do
+ delete_bucket_label bucket_name: bucket.name,
+ label_key: label_key
+ end
+
+ bucket.refresh!
+ assert bucket.labels.empty?
+ end
+ end
+
+ describe "delete_bucket" do
+ it "deletes a label from a given bucket" do
+ assert_output "Deleted bucket: #{bucket.name}\n" do
+ delete_bucket bucket_name: bucket.name
+ end
+
+ refute storage_client.bucket bucket.name
+ end
+ end
+
+ describe "set_retention_policy" do
+ it "sets the retention policy for a given bucket" do
+ assert_output "Retention period for #{bucket.name} is now #{retention_period} seconds.\n" do
+ set_retention_policy bucket_name: bucket.name,
+ retention_period: retention_period
+ end
+
+ bucket.refresh!
+ assert_equal bucket.retention_period, retention_period
+ end
+ end
+
+ describe "lock_retention_policy" do
+ it "locks the retention policy for a given bucket" do
+ bucket.retention_period = retention_period
+ out, _err = capture_io do
+ lock_retention_policy bucket_name: bucket.name
+ end
+
+ assert_includes out, "Retention policy for #{bucket.name} is now locked."
+ bucket.refresh!
+ assert bucket.retention_policy_locked?
+ end
+ end
+
+ describe "remove_retention_policy" do
+ it "removes the retention policy for a given bucket" do
+ bucket.retention_period = retention_period
+ secondary_bucket.retention_period = retention_period
+ secondary_bucket.lock_retention_policy!
+
+ assert_output "Retention policy for #{bucket.name} has been removed.\n" do
+ remove_retention_policy bucket_name: bucket.name
+ end
+
+ bucket.refresh!
+ refute bucket.retention_period
+
+ assert_output "Policy is locked and retention policy can't be removed.\n" do
+ remove_retention_policy bucket_name: secondary_bucket.name
+ end
+ end
+ end
+
+ describe "get_retention_policy" do
+ it "gets the retention policy for a given bucket" do
+ bucket.retention_period = retention_period
+
+ out, _err = capture_io do
+ get_retention_policy bucket_name: bucket.name
+ end
+
+ assert_includes out, "period: #{retention_period}\n"
+ end
+ end
+
+ describe "enable_default_event_based_hold" do
+ it "gets the retention policy for a given bucket" do
+ assert_output "Default event-based hold was enabled for #{bucket.name}.\n" do
+ enable_default_event_based_hold bucket_name: bucket.name
+ end
+
+ bucket.refresh!
+ assert bucket.default_event_based_hold?
+ end
+ end
+
+ describe "disable_default_event_based_hold" do
+ it "gets the retention policy for a given bucket" do
+ bucket.update do |b|
+ b.default_event_based_hold = true
+ end
+
+ assert_output "Default event-based hold was disabled for #{bucket.name}.\n" do
+ disable_default_event_based_hold bucket_name: bucket.name
+ end
+
+ bucket.refresh!
+ refute bucket.default_event_based_hold?
+ end
+ end
+
+ describe "get_default_event_based_hold" do
+ it "gets the retention policy for a given bucket" do
+ bucket.update do |b|
+ b.default_event_based_hold = true
+ end
+
+ assert_output "Default event-based hold is enabled for #{bucket.name}.\n" do
+ get_default_event_based_hold bucket_name: bucket.name
+ end
+
+ assert_output "Default event-based hold is not enabled for #{secondary_bucket.name}.\n" do
+ get_default_event_based_hold bucket_name: secondary_bucket.name
+ end
+ end
+ end
+end
diff --git a/google-cloud-storage/samples/acceptance/data/file.txt b/google-cloud-storage/samples/acceptance/data/file.txt
new file mode 100644
index 000000000000..2409b20a4514
--- /dev/null
+++ b/google-cloud-storage/samples/acceptance/data/file.txt
@@ -0,0 +1 @@
+Content of test file.txt
diff --git a/google-cloud-storage/samples/acceptance/files_test.rb b/google-cloud-storage/samples/acceptance/files_test.rb
new file mode 100644
index 000000000000..bf29be7aee6b
--- /dev/null
+++ b/google-cloud-storage/samples/acceptance/files_test.rb
@@ -0,0 +1,479 @@
+# 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.
+
+require_relative "helper"
+require_relative "../files.rb"
+
+describe "Files Snippets" do
+ parallelize_me!
+
+ let :bucket do
+ create_bucket_helper "ruby_storage_sample_#{SecureRandom.hex}"
+ end
+
+ let :secondary_bucket do
+ create_bucket_helper "ruby_storage_sample_#{SecureRandom.hex}_secondary"
+ end
+
+ let(:storage_client) { Google::Cloud::Storage.new }
+ let(:local_file) { File.expand_path "data/file.txt", __dir__ }
+ let(:encryption_key) { OpenSSL::Cipher.new("aes-256-cfb").encrypt.random_key }
+ let(:kms_key) { get_kms_key storage_client.project }
+ let(:remote_file_name) { "path/file_name.txt" }
+ let(:downloaded_file) { "test_download_#{SecureRandom.hex}" }
+
+ after do
+ File.delete downloaded_file if File.file? downloaded_file
+ delete_bucket_helper bucket.name
+ delete_bucket_helper secondary_bucket.name
+ end
+
+ describe "list_bucket_contents" do
+ it "puts the bucket's contents" do
+ bucket.create_file local_file, "foo.txt"
+ bucket.create_file local_file, "bar.txt"
+
+ out, _err = capture_io do
+ list_bucket_contents bucket_name: bucket.name
+ end
+
+ assert_match "foo.txt", out
+ assert_match "bar.txt", out
+ end
+ end
+
+ describe "list_bucket_contents_with_prefix" do
+ it "puts the bucket's contents that begin with the prefix" do
+ ["foo/file.txt", "foo/data.txt", "bar/file.txt", "bar/data.txt"].each do |file|
+ bucket.create_file local_file, file
+ end
+
+ out, _err = capture_io do
+ list_bucket_contents_with_prefix bucket_name: bucket.name, prefix: "foo/"
+ end
+
+ assert_match "foo/file.txt", out
+ assert_match "foo/data.txt", out
+ end
+
+ it "omits the bucket's contents that don't begin with the prefix" do
+ ["foo/file.txt", "foo/data.txt", "bar/file.txt", "bar/data.txt"].each do |file|
+ bucket.create_file local_file, file
+ end
+
+ out, _err = capture_io do
+ list_bucket_contents_with_prefix bucket_name: bucket.name, prefix: "foo/"
+ end
+
+ refute_match "bar/file.txt", out
+ refute_match "bar/data.txt", out
+ end
+ end
+
+ describe "generate_encryption_key_base64" do
+ it "can generate a base64 encoded encryption key" do
+ mock_cipher = Minitest::Mock.new
+
+ def mock_cipher.encrypt
+ self
+ end
+
+ def mock_cipher.random_key
+ @key ||= OpenSSL::Cipher.new("aes-256-cfb").encrypt.random_key
+ end
+
+ encryption_key_base64 = Base64.encode64 mock_cipher.random_key
+
+ OpenSSL::Cipher.stub :new, mock_cipher do
+ assert_output "Sample encryption key: #{encryption_key_base64}" do
+ generate_encryption_key_base64
+ end
+ end
+ end
+ end
+
+ describe "upload_file" do
+ it "uploads a file to a storage bucket" do
+ assert_output "Uploaded #{remote_file_name}\n" do
+ upload_file bucket_name: bucket.name, local_file_path: local_file, storage_file_path: remote_file_name
+ end
+
+ assert_equal bucket.files.first.name, remote_file_name
+ end
+ end
+
+ describe "upload_encrypted_file" do
+ it "uploads a file to a storage bucket with an encryption key" do
+ assert_output "Uploaded #{remote_file_name} with encryption key\n" do
+ upload_encrypted_file bucket_name: bucket.name,
+ local_file_path: local_file,
+ storage_file_path: remote_file_name,
+ encryption_key: encryption_key
+ end
+
+ assert_equal bucket.files.first.name, remote_file_name
+ refute_nil bucket.files.first.encryption_key_sha256
+ end
+ end
+
+ describe "upload_with_kms_key" do
+ it "uploads a file to a storage bucket with an encryption key" do
+ assert_output(/Uploaded #{remote_file_name} and encrypted service side using #{kms_key}/) do
+ upload_with_kms_key bucket_name: bucket.name,
+ local_file_path: local_file,
+ storage_file_path: remote_file_name,
+ kms_key: kms_key
+ end
+
+ assert_equal bucket.files.first.name, remote_file_name
+ assert_match kms_key, bucket.files.first.kms_key
+ end
+ end
+
+ describe "download_file" do
+ it "downloads a file from a storage bucket" do
+ bucket.create_file local_file, remote_file_name
+
+ assert_output "Downloaded #{remote_file_name}\n" do
+ download_file bucket_name: bucket.name,
+ file_name: remote_file_name,
+ local_path: downloaded_file
+ end
+
+ assert File.file? downloaded_file
+ end
+ end
+
+ describe "download_public_file" do
+ it "downloads a file from a public storage bucket" do
+ bucket.create_file local_file, remote_file_name
+
+ assert_output "Downloaded #{remote_file_name}\n" do
+ download_file bucket_name: bucket.name,
+ file_name: remote_file_name,
+ local_path: downloaded_file
+ end
+
+ assert File.file? downloaded_file
+ end
+ end
+
+ describe "download_file_requester_pays" do
+ it "downloads a file from a bucket using requester pays" do
+ bucket.requester_pays = true
+ bucket.create_file local_file, remote_file_name
+
+ assert_output "Downloaded #{remote_file_name} using billing project #{storage_client.project}\n" do
+ download_file_requester_pays bucket_name: bucket.name,
+ file_name: remote_file_name,
+ local_path: downloaded_file
+ end
+
+ assert File.file? downloaded_file
+ end
+ end
+
+ describe "download_encrypted_file" do
+ it "downloads an encrypted file from storage bucket" do
+ bucket.create_file local_file, remote_file_name, encryption_key: encryption_key
+
+ assert_output "Downloaded encrypted #{remote_file_name}\n" do
+ download_encrypted_file bucket_name: bucket.name,
+ storage_file_path: remote_file_name,
+ local_file_path: downloaded_file,
+ encryption_key: encryption_key
+ end
+
+ assert File.file? downloaded_file
+ assert_equal File.read(local_file), File.read(downloaded_file)
+ end
+ end
+
+ describe "delete_file" do
+ it "deletes a file from storage bucket" do
+ bucket.create_file local_file, remote_file_name
+
+ assert_output "Deleted #{remote_file_name}\n" do
+ delete_file bucket_name: bucket.name,
+ file_name: remote_file_name
+ end
+
+ assert_nil bucket.file remote_file_name
+ end
+ end
+
+ describe "list_file_details" do
+ it "puts the details of a file from storage bucket" do
+ bucket.create_file local_file, remote_file_name
+
+ file = bucket.file remote_file_name
+ expected_output = <<~OUTPUT
+ Name: #{file.name}
+ Bucket: #{bucket.name}
+ Storage class: #{bucket.storage_class}
+ ID: #{file.id}
+ Size: #{file.size} bytes
+ Created: #{file.created_at}
+ Updated: #{file.updated_at}
+ Generation: #{file.generation}
+ Metageneration: #{file.metageneration}
+ Etag: #{file.etag}
+ Owners: #{file.acl.owners.join ','}
+ Crc32c: #{file.crc32c}
+ md5_hash: #{file.md5}
+ Cache-control: #{file.cache_control}
+ Content-type: #{file.content_type}
+ Content-disposition: #{file.content_disposition}
+ Content-encoding: #{file.content_encoding}
+ Content-language: #{file.content_language}
+ KmsKeyName: #{file.kms_key}
+ Event-based hold enabled?: #{file.event_based_hold?}
+ Temporary hold enaled?: #{file.temporary_hold?}
+ Retention Expiration: #{file.retention_expires_at}
+ Metadata:
+ OUTPUT
+
+ assert_output expected_output do
+ list_file_details bucket_name: bucket.name,
+ file_name: remote_file_name
+ end
+ end
+ end
+
+ describe "set_metadata" do
+ it "sets the metadata for a file in a storage bucket" do
+ bucket.create_file local_file, remote_file_name
+
+ metadata_key = "test-metadata-key"
+ metadata_value = "test-metadata-value"
+ content_type = "text/plain"
+
+ assert_output "Metadata for #{remote_file_name} has been updated.\n" do
+ set_metadata bucket_name: bucket.name,
+ file_name: remote_file_name,
+ content_type: content_type,
+ metadata_key: metadata_key,
+ metadata_value: metadata_value
+ end
+
+ assert_equal bucket.file(remote_file_name).metadata[metadata_key], metadata_value
+ end
+ end
+
+ describe "make_file_public" do
+ it "makes a file from a storage bucket publicly accessible from a url" do
+ bucket.create_file local_file, remote_file_name
+ response = Net::HTTP.get URI(bucket.file(remote_file_name).public_url)
+ refute_equal File.read(local_file), response
+
+ assert_output "#{remote_file_name} is publicly accessible at #{bucket.file(remote_file_name).public_url}\n" do
+ make_file_public bucket_name: bucket.name,
+ file_name: remote_file_name
+ end
+
+ response = Net::HTTP.get URI(bucket.file(remote_file_name).public_url)
+ assert_equal File.read(local_file), response
+ end
+ end
+
+ describe "rename_file" do
+ it "renames a file in a storage bucket" do
+ bucket.create_file local_file, remote_file_name
+
+ new_name = "path/new_name.txt"
+ assert_nil bucket.file new_name
+
+ assert_output "#{remote_file_name} has been renamed to #{new_name}\n" do
+ rename_file bucket_name: bucket.name,
+ file_name: remote_file_name,
+ new_name: new_name
+ end
+
+ assert_nil bucket.file remote_file_name
+ refute_nil bucket.file new_name
+ end
+ end
+
+ describe "copy_file" do
+ it "copies a file from one storage bucket to another" do
+ bucket.create_file local_file, remote_file_name
+ assert_nil secondary_bucket.file remote_file_name
+
+ assert_output "#{remote_file_name} in #{bucket.name} copied to #{remote_file_name} in #{secondary_bucket.name}\n" do
+ copy_file source_bucket_name: bucket.name,
+ source_file_name: remote_file_name,
+ dest_bucket_name: secondary_bucket.name,
+ dest_file_name: remote_file_name
+ end
+
+ refute_nil bucket.file remote_file_name
+ refute_nil secondary_bucket.file remote_file_name
+ end
+ end
+
+ describe "rotate_encryption_key" do
+ it "changes the encryption key used for a file in a storage bucket" do
+ bucket.create_file local_file, remote_file_name, encryption_key: encryption_key
+
+ new_encryption_key = OpenSSL::Cipher.new("aes-256-cfb").encrypt.random_key
+ file_contents = File.read local_file
+
+ assert_output "The encryption key for #{remote_file_name} in #{bucket.name} was rotated.\n" do
+ rotate_encryption_key bucket_name: bucket.name,
+ file_name: remote_file_name,
+ current_encryption_key: encryption_key,
+ new_encryption_key: new_encryption_key
+ end
+
+ bucket.file(remote_file_name).download downloaded_file, encryption_key: new_encryption_key
+ downloaded_contents = File.read downloaded_file
+ assert_equal file_contents, downloaded_contents
+ end
+ end
+
+ describe "generate_signed_url" do
+ it "generates a signed url for a file in a bucket" do
+ bucket.create_file local_file, remote_file_name
+
+ out, _err = capture_io do
+ generate_signed_url bucket_name: bucket.name,
+ file_name: remote_file_name
+ end
+
+ assert_match "The signed url for #{remote_file_name} is", out
+ signed_url = out.scan(/http.*$/).first
+ refute_nil signed_url
+
+ file_contents = Net::HTTP.get URI(signed_url)
+ assert_equal file_contents, File.read(local_file)
+ end
+ end
+
+ describe "generate_signed_get_url_v4" do
+ it "generates a v4 signed get url for a file in a bucket" do
+ bucket.create_file local_file, remote_file_name
+
+ out, _err = capture_io do
+ generate_signed_get_url_v4 bucket_name: bucket.name,
+ file_name: remote_file_name
+ end
+
+ signed_url = out.scan(/http.*$/).first
+ refute_nil signed_url
+
+ file_contents = Net::HTTP.get URI(signed_url)
+ assert_equal file_contents, File.read(local_file)
+ end
+ end
+
+ describe "generate_signed_put_url_v4" do
+ it "generates a v4 signed put url for a file in a bucket" do
+ refute bucket.file remote_file_name
+
+ out, _err = capture_io do
+ generate_signed_put_url_v4 bucket_name: bucket.name,
+ file_name: remote_file_name
+ end
+
+ signed_url = out.scan(/http.*$/).first
+ refute_nil signed_url
+
+ uri = URI.parse signed_url
+ http = Net::HTTP.new uri.host
+ request = Net::HTTP::Put.new uri.request_uri
+ request.body = File.read local_file
+ request["Content-Type"] = "text/plain"
+ request["Content-Length"] = File.size local_file
+
+ response = http.request request
+ assert_equal response.code, "200"
+
+ assert bucket.file remote_file_name
+ end
+ end
+
+ describe "set_event_based_hold" do
+ it "sets an event-based hold for a file in a bucket" do
+ bucket.create_file local_file, remote_file_name
+
+ assert_output "Event-based hold was set for #{remote_file_name}.\n" do
+ set_event_based_hold bucket_name: bucket.name,
+ file_name: remote_file_name
+ end
+
+ assert bucket.file(remote_file_name).event_based_hold?
+ bucket.file(remote_file_name).release_event_based_hold!
+ end
+ end
+
+ describe "release_event_based_hold" do
+ it "releases an event-based hold for a file in a bucket" do
+ bucket.create_file local_file, remote_file_name
+ bucket.file(remote_file_name).set_event_based_hold!
+ assert bucket.file(remote_file_name).event_based_hold?
+
+ assert_output "Event-based hold was released for #{remote_file_name}.\n" do
+ release_event_based_hold bucket_name: bucket.name,
+ file_name: remote_file_name
+ end
+
+ refute bucket.file(remote_file_name).event_based_hold?
+ end
+ end
+
+ describe "set_temporary_hold" do
+ it "sets a temporary hold for a file in a bucket" do
+ bucket.create_file local_file, remote_file_name
+ refute bucket.file(remote_file_name).temporary_hold?
+
+ assert_output "Temporary hold was set for #{remote_file_name}.\n" do
+ set_temporary_hold bucket_name: bucket.name,
+ file_name: remote_file_name
+ end
+
+ assert bucket.file(remote_file_name).temporary_hold?
+ bucket.file(remote_file_name).release_temporary_hold!
+ end
+ end
+
+ describe "release_temporary_hold" do
+ it "releases a temporary hold for a file in a bucket" do
+ bucket.create_file local_file, remote_file_name
+ bucket.file(remote_file_name).set_temporary_hold!
+ assert bucket.file(remote_file_name).temporary_hold?
+
+ assert_output "Temporary hold was released for #{remote_file_name}.\n" do
+ release_temporary_hold bucket_name: bucket.name,
+ file_name: remote_file_name
+ end
+
+ refute bucket.file(remote_file_name).temporary_hold?
+ end
+ end
+
+ describe "release_temporary_hold" do
+ it "releases a temporary hold for a file in a bucket" do
+ bucket.create_file local_file, remote_file_name
+ bucket.file(remote_file_name).set_temporary_hold!
+ assert bucket.file(remote_file_name).temporary_hold?
+
+ assert_output "Temporary hold was released for #{remote_file_name}.\n" do
+ release_temporary_hold bucket_name: bucket.name,
+ file_name: remote_file_name
+ end
+
+ refute bucket.file(remote_file_name).temporary_hold?
+ end
+ end
+end
diff --git a/google-cloud-storage/samples/acceptance/helper.rb b/google-cloud-storage/samples/acceptance/helper.rb
new file mode 100644
index 000000000000..e3a3a29904ab
--- /dev/null
+++ b/google-cloud-storage/samples/acceptance/helper.rb
@@ -0,0 +1,89 @@
+# 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.
+
+require "google/cloud/errors"
+require "google/cloud/kms"
+require "google/cloud/storage"
+require "minitest/autorun"
+require "net/http"
+require "securerandom"
+require "uri"
+
+def create_bucket_helper bucket_name
+ storage_client = Google::Cloud::Storage.new
+
+ retry_resource_exhaustion do
+ return storage_client.create_bucket bucket_name
+ end
+end
+
+def delete_bucket_helper bucket_name
+ storage_client = Google::Cloud::Storage.new
+
+ retry_resource_exhaustion do
+ bucket = storage_client.bucket bucket_name
+ return unless bucket
+
+ bucket.files.each(&:delete)
+ bucket.delete
+ end
+end
+
+def retry_resource_exhaustion
+ 5.times do
+ begin
+ yield
+ return
+ rescue Google::Cloud::ResourceExhaustedError => e
+ puts "\n#{e} Gonna try again"
+ sleep rand(3..5)
+ rescue StandardError => e
+ puts "\n#{e}"
+ return
+ end
+ end
+ raise Google::Cloud::ResourceExhaustedError, "Maybe take a break from creating and deleting buckets for a bit"
+end
+
+def get_kms_key project_id
+ kms_client = Google::Cloud::Kms.new
+
+ key_ring_id = "ruby_docs_test_ring_id"
+ location_path = kms_client.location_path project_id, "us"
+ key_ring_path = kms_client.key_ring_path project_id, "us", key_ring_id
+ begin
+ kms_client.get_key_ring key_ring_path
+ rescue Google::Gax::RetryError
+ kms_client.create_key_ring location_path, key_ring_id, {}
+ end
+
+ crypto_key_id = "ruby_docs_test_key"
+ crypto_key = {
+ purpose: :ENCRYPT_DECRYPT
+ }
+ crypto_key_path = kms_client.crypto_key_path project_id, "us", key_ring_id, crypto_key_id
+ begin
+ kms_client.get_crypto_key(crypto_key_path).name
+ rescue Google::Gax::GaxError
+ kms_client.create_crypto_key(key_ring_path, crypto_key_id, crypto_key).name
+ end
+end
+
+def delete_hmac_key_helper hmac_key
+ hmac_key.refresh!
+ return if hmac_key.deleted?
+
+ hmac_key.inactive! if hmac_key.active?
+ hmac_key.delete!
+end
diff --git a/google-cloud-storage/samples/acceptance/hmac_test.rb b/google-cloud-storage/samples/acceptance/hmac_test.rb
new file mode 100644
index 000000000000..63d0b7df4dfd
--- /dev/null
+++ b/google-cloud-storage/samples/acceptance/hmac_test.rb
@@ -0,0 +1,112 @@
+# 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.
+
+require_relative "helper"
+require_relative "../hmac.rb"
+
+describe "HMAC Snippets" do
+ parallelize_me!
+
+ let(:storage_client) { Google::Cloud::Storage.new }
+ let(:project_id) { storage_client.project }
+ let(:service_account_email) { "#{project_id}@appspot.gserviceaccount.com" }
+
+ let :hmac_key do
+ hmac_key = storage_client.create_hmac_key service_account_email
+ hmac_key
+ end
+
+ after do
+ delete_hmac_key_helper hmac_key
+ end
+
+ describe "list_hmac_keys" do
+ it "lists the hmac keys for a GCP project" do
+ access_id = hmac_key.access_id
+
+ out, _err = capture_io do
+ list_hmac_keys
+ end
+
+ assert_includes out, "Service Account Email: #{service_account_email}"
+ assert_includes out, "Access ID: #{access_id}"
+ end
+ end
+
+ describe "create_hmac_key" do
+ it "creates an hmac key" do
+ out, _err = capture_io do
+ create_hmac_key service_account_email: service_account_email
+ end
+ match = out.match(/Access ID:\s+(.*)\n/)
+ access_id = match[1]
+ # Raises error if no hmac_key found
+ delete_hmac_key_helper storage_client.hmac_key(access_id)
+
+ assert_match(/Service Account Email:\s+#{service_account_email}/, out)
+ end
+ end
+
+ describe "get_hmac_key" do
+ it "gets an hmac key from an access_id" do
+ access_id = hmac_key.access_id
+
+ out, _err = capture_io do
+ get_hmac_key access_id: access_id
+ end
+
+ assert_match(/Service Account Email:\s+#{service_account_email}/, out)
+ end
+ end
+
+ describe "activate_hmac_key" do
+ it "activates an hmac key from an access_id" do
+ hmac_key.inactive!
+
+ out, _err = capture_io do
+ activate_hmac_key access_id: hmac_key.access_id
+ end
+
+ assert_match(/Service Account Email:\s+#{service_account_email}/, out)
+ hmac_key.refresh!
+ assert hmac_key.active?
+ end
+ end
+
+ describe "deactivate_hmac_key" do
+ it "deactivates an hmac key from an access_id" do
+ out, _err = capture_io do
+ deactivate_hmac_key access_id: hmac_key.access_id
+ end
+
+ assert_match(/Service Account Email:\s+#{service_account_email}/, out)
+ hmac_key.refresh!
+ assert hmac_key.inactive?
+ end
+ end
+
+ describe "delete_hmac_key" do
+ it "deletes an hmac key from an access_id" do
+ hmac_key.inactive!
+ access_id = hmac_key.access_id
+
+ assert_output "The key is deleted, though it may still appear in Client#hmac_keys results.\n" do
+ delete_hmac_key access_id: access_id
+ end
+
+ hmac_key.refresh!
+ assert hmac_key.deleted?
+ end
+ end
+end
diff --git a/google-cloud-storage/samples/acceptance/iam_test.rb b/google-cloud-storage/samples/acceptance/iam_test.rb
new file mode 100644
index 000000000000..f2c0d08f974d
--- /dev/null
+++ b/google-cloud-storage/samples/acceptance/iam_test.rb
@@ -0,0 +1,124 @@
+# 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.
+
+require_relative "helper"
+require_relative "../iam.rb"
+
+describe "IAM Snippets" do
+ parallelize_me!
+
+ let :bucket do
+ create_bucket_helper "ruby_storage_sample_#{SecureRandom.hex}"
+ end
+
+ let(:role) { "roles/storage.admin" }
+ let(:member) { "user:test@test.com" }
+
+ after do
+ delete_bucket_helper bucket.name
+ end
+
+ describe "view_bucket_iam_members" do
+ it "puts the members for each IAM role" do
+ bucket.policy do |policy|
+ policy.add role, member
+ end
+
+ out, _err = capture_io do
+ view_bucket_iam_members bucket_name: bucket.name
+ end
+
+ assert_includes out, "Role: #{role}"
+ assert_includes out, member
+ end
+ end
+
+ describe "add_bucket_iam_member" do
+ it "adds an IAM member" do
+ assert_output "Added #{member} with role #{role} to #{bucket.name}\n" do
+ add_bucket_iam_member bucket_name: bucket.name,
+ role: role,
+ member: member
+ end
+
+ assert bucket.policy.roles.any? do |p_role, p_members|
+ p_role == role && p_members.includes?(member)
+ end
+ end
+ end
+
+ describe "remove_bucket_iam_member" do
+ it "removes an IAM member" do
+ assert_output "Removed #{member} with role #{role} from #{bucket.name}\n" do
+ remove_bucket_iam_member bucket_name: bucket.name,
+ role: role,
+ member: member
+ end
+
+ refute bucket.policy.roles.none? do |p_role, p_members|
+ p_role == role && p_members.includes?(member)
+ end
+ end
+ end
+
+ describe "add_bucket_conditional_iam_binding" do
+ it "adds conditional IAM binding to a bucket" do
+ title = "title"
+ description = "description"
+ expression = "resource.name.startsWith(\"projects/_/buckets/bucket-name/objects/prefix-a-\")"
+ bucket.uniform_bucket_level_access = true
+ assert_output "Added #{member} with role #{role} to #{bucket.name} with condition #{title} #{description} #{expression}\n" do
+ add_bucket_conditional_iam_binding bucket_name: bucket.name,
+ role: role,
+ member: member,
+ title: title,
+ description: description,
+ expression: expression
+ end
+
+ policy = bucket.policy(requested_policy_version: 3).bindings.select(&:condition).first
+ assert_equal policy.role, role
+ assert_includes policy.members, member
+ assert_equal policy.condition.title, title
+ assert_equal policy.condition.description, description
+ assert_equal policy.condition.expression, expression
+ end
+ end
+
+ describe "remove_bucket_conditional_iam_binding" do
+ it "remove conditional IAM binding to a bucket" do
+ title = "title"
+ description = "description"
+ expression = "resource.name.startsWith('projects/_/buckets/bucket-name/objects/prefix-a-')"
+ bucket.uniform_bucket_level_access = true
+ capture_io do
+ add_bucket_conditional_iam_binding bucket_name: bucket.name,
+ role: role,
+ member: member,
+ title: title,
+ description: description,
+ expression: expression
+ end
+ assert_output "Conditional Binding was removed.\n" do
+ remove_bucket_conditional_iam_binding bucket_name: bucket.name,
+ role: role,
+ title: title,
+ description: description,
+ expression: expression
+ end
+ bindings = bucket.policy(requested_policy_version: 3).bindings.select(&:condition)
+ assert_equal bindings.size, 0
+ end
+ end
+end
diff --git a/google-cloud-storage/samples/acceptance/quickstart_test.rb b/google-cloud-storage/samples/acceptance/quickstart_test.rb
new file mode 100644
index 000000000000..74c2f83e87d8
--- /dev/null
+++ b/google-cloud-storage/samples/acceptance/quickstart_test.rb
@@ -0,0 +1,33 @@
+# 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.
+
+require_relative "helper"
+require_relative "../quickstart.rb"
+
+describe "Storage Quickstart" do
+ let(:storage_client) { Google::Cloud::Storage.new }
+ let(:bucket_name) { "ruby_storage_sample_#{SecureRandom.hex}" }
+
+ after do
+ delete_bucket_helper bucket_name
+ end
+
+ it "creates a new bucket" do
+ assert_output "Bucket #{bucket_name} was created.\n" do
+ quickstart bucket_name: bucket_name
+ end
+
+ assert storage_client.bucket bucket_name
+ end
+end
diff --git a/google-cloud-storage/samples/acls.rb b/google-cloud-storage/samples/acls.rb
new file mode 100644
index 000000000000..38a9511125bc
--- /dev/null
+++ b/google-cloud-storage/samples/acls.rb
@@ -0,0 +1,260 @@
+# 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.
+
+def print_bucket_acl bucket_name:
+ # [START print_bucket_acl]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ puts "ACL for #{bucket_name}:"
+
+ bucket.acl.owners.each do |owner|
+ puts "OWNER #{owner}"
+ end
+
+ bucket.acl.writers.each do |writer|
+ puts "WRITER #{writer}"
+ end
+
+ bucket.acl.readers.each do |reader|
+ puts "READER #{reader}"
+ end
+ # [END print_bucket_acl]
+end
+
+def print_bucket_acl_for_user bucket_name:, email:
+ # [START print_bucket_acl_for_user]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # email = "Google Cloud Storage ACL Entity email"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ puts "Permissions for #{email}:"
+ puts "OWNER" if bucket.acl.owners.include? email
+ puts "WRITER" if bucket.acl.writers.include? email
+ puts "READER" if bucket.acl.readers.include? email
+ # [END print_bucket_acl_for_user]
+end
+
+def add_bucket_owner bucket_name:, email:
+ # [START add_bucket_owner]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # email = "Google Cloud Storage ACL Entity email"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.acl.add_owner email
+
+ puts "Added OWNER permission for #{email} to #{bucket_name}"
+ # [END add_bucket_owner]
+end
+
+def remove_bucket_acl bucket_name:, email:
+ # [START remove_bucket_acl]
+ # project_id = "Your Google Cloud project ID"
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # email = "Google Cloud Storage ACL Entity email"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.acl.delete email
+
+ puts "Removed ACL permissions for #{email} from #{bucket_name}"
+ # [END remove_bucket_acl]
+end
+
+def add_bucket_default_owner bucket_name:, email:
+ # [START add_bucket_default_owner]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # email = "Google Cloud Storage ACL Entity email"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.default_acl.add_owner email
+
+ puts "Added default OWNER permission for #{email} to #{bucket_name}"
+ # [END add_bucket_default_owner]
+end
+
+def remove_bucket_default_acl bucket_name:, email:
+ # [START remove_bucket_default_acl]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # email = "Google Cloud Storage ACL Entity email"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.default_acl.delete email
+
+ puts "Removed default ACL permissions for #{email} from #{bucket_name}"
+ # [END remove_bucket_default_acl]
+end
+
+def print_file_acl bucket_name:, file_name:
+ # [START print_file_acl]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of a file in the Storage bucket"
+ # email = "Google Cloud Storage ACL Entity email"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+ file = bucket.file file_name
+
+ puts "ACL for #{file_name} in #{bucket_name}:"
+
+ file.acl.owners.each do |owner|
+ puts "OWNER #{owner}"
+ end
+
+ file.acl.readers.each do |reader|
+ puts "READER #{reader}"
+ end
+ # [END print_file_acl]
+end
+
+def print_file_acl_for_user bucket_name:, file_name:, email:
+ # [START print_file_acl_for_user]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of a file in the Storage bucket"
+ # email = "Google Cloud Storage ACL Entity email"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+ file = bucket.file file_name
+
+ puts "Permissions for #{email}:"
+ puts "OWNER" if file.acl.owners.include? email
+ puts "READER" if file.acl.readers.include? email
+ # [END print_file_acl_for_user]
+end
+
+def add_file_owner bucket_name:, file_name:, email:
+ # [START add_file_owner]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of a file in the Storage bucket"
+ # email = "Google Cloud Storage ACL Entity email"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+ file = bucket.file file_name
+
+ file.acl.add_owner email
+
+ puts "Added OWNER permission for #{email} to #{file_name}"
+ # [END add_file_owner]
+end
+
+def remove_file_acl bucket_name:, file_name:, email:
+ # [START remove_file_acl]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of a file in the Storage bucket"
+ # email = "Google Cloud Storage ACL Entity email"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+ file = bucket.file file_name
+
+ file.acl.delete email
+
+ puts "Removed ACL permissions for #{email} from #{file_name}"
+ # [END remove_file_acl]
+end
+
+def run_sample arguments
+ command = arguments.shift
+
+ case command
+ when "print_bucket_acl"
+ print_bucket_acl bucket_name: arguments.shift
+ when "print_bucket_acl_for_user"
+ print_bucket_acl_for_user bucket_name: arguments.shift,
+ email: arguments.shift
+ when "add_bucket_owner"
+ add_bucket_owner bucket_name: arguments.shift,
+ email: arguments.shift
+ when "remove_bucket_acl"
+ remove_bucket_acl bucket_name: arguments.shift,
+ email: arguments.shift
+ when "add_bucket_default_owner"
+ add_bucket_default_owner bucket_name: arguments.shift,
+ email: arguments.shift
+ when "remove_bucket_default_acl"
+ remove_bucket_default_acl bucket_name: arguments.shift,
+ email: arguments.shift
+ when "print_file_acl"
+ print_file_acl bucket_name: arguments.shift,
+ file_name: arguments.shift
+ when "print_file_acl_for_user"
+ print_file_acl_for_user bucket_name: arguments.shift,
+ file_name: arguments.shift,
+ email: arguments.shift
+ when "add_file_owner"
+ add_file_owner bucket_name: arguments.shift,
+ file_name: arguments.shift,
+ email: arguments.shift
+ when "remove_file_acl"
+ remove_file_acl bucket_name: arguments.shift,
+ file_name: arguments.shift,
+ email: arguments.shift
+ else
+ puts <<~USAGE
+ Usage: bundle exec ruby acls.rb [command] [arguments]
+
+ Commands:
+ print_bucket_acl Print bucket Access Control List
+ print_bucket_acl_for_user Print bucket ACL for an email
+ add_bucket_owner Add a new OWNER to a bucket
+ remove_bucket_acl Remove an entity from a bucket ACL
+ add_bucket_default_owner Add a default OWNER for a bucket
+ remove_bucket_default_acl Remove an entity from default bucket ACL
+ print_file_acl Print file ACL
+ print_file_acl_for_user Print file ACL for an email
+ add_file_owner Add an OWNER to a file
+ remove_file_acl Remove an entity from a file ACL
+
+ Environment variables:
+ GOOGLE_CLOUD_PROJECT must be set to your Google Cloud project ID
+ USAGE
+ end
+end
+
+if $PROGRAM_NAME == __FILE__
+ run_sample ARGV
+end
diff --git a/google-cloud-storage/samples/buckets.rb b/google-cloud-storage/samples/buckets.rb
new file mode 100644
index 000000000000..7b2575b04935
--- /dev/null
+++ b/google-cloud-storage/samples/buckets.rb
@@ -0,0 +1,478 @@
+# 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.
+
+def list_buckets
+ # [START list_buckets]
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+
+ storage.buckets.each do |bucket|
+ puts bucket.name
+ end
+ # [END list_buckets]
+end
+
+def list_bucket_details bucket_name:
+ # [START storage_get_bucket_metadata]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ puts "ID: #{bucket.id}"
+ puts "Name: #{bucket.name}"
+ puts "Storage Class: #{bucket.storage_class}"
+ puts "Location: #{bucket.location}"
+ puts "Location Type: #{bucket.location_type}"
+ puts "Cors: #{bucket.cors}"
+ puts "Default Event Based Hold: #{bucket.default_event_based_hold?}"
+ puts "Default KMS Key Name: #{bucket.default_kms_key}"
+ puts "Logging Bucket: #{bucket.logging_bucket}"
+ puts "Logging Prefix: #{bucket.logging_prefix}"
+ puts "Metageneration: #{bucket.metageneration}"
+ puts "Retention Effective Time: #{bucket.retention_effective_at}"
+ puts "Retention Period: #{bucket.retention_period}"
+ puts "Retention Policy Locked: #{bucket.retention_policy_locked?}"
+ puts "Requester Pays: #{bucket.requester_pays}"
+ puts "Self Link: #{bucket.api_url}"
+ puts "Time Created: #{bucket.created_at}"
+ puts "Versioning Enabled: #{bucket.versioning?}"
+ puts "Index Page: #{bucket.website_main}"
+ puts "Not Found Page: #{bucket.website_404}"
+ puts "Labels:"
+ bucket.labels.each do |key, value|
+ puts " - #{key} = #{value}"
+ end
+ # [END storage_get_bucket_metadata]
+end
+
+def disable_requester_pays bucket_name:
+ # [START disable_requester_pays]
+ # bucket_name = "Name of your Google Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.requester_pays = false
+
+ puts "Requester pays has been disabled for #{bucket_name}"
+ # [END disable_requester_pays]
+end
+
+def enable_requester_pays bucket_name:
+ # [START enable_requester_pays]
+ # bucket_name = "Name of your Google Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.requester_pays = true
+
+ puts "Requester pays has been enabled for #{bucket_name}"
+ # [END enable_requester_pays]
+end
+
+def get_requester_pays_status bucket_name:
+ # [START get_requester_pays_status]
+ # bucket_name = "Name of your Google Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ if bucket.requester_pays
+ puts "Requester Pays is enabled for #{bucket_name}"
+ else
+ puts "Requester Pays is disabled for #{bucket_name}"
+ end
+ # [END get_requester_pays_status]
+end
+
+def disable_uniform_bucket_level_access bucket_name:
+ # [START storage_disable_uniform_bucket_level_access]
+ # bucket_name = "Name of your Google Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.uniform_bucket_level_access = false
+
+ puts "Uniform bucket-level access was disabled for #{bucket_name}."
+ # [END storage_disable_uniform_bucket_level_access]
+end
+
+def enable_uniform_bucket_level_access bucket_name:
+ # [START storage_enable_uniform_bucket_level_access]
+ # bucket_name = "Name of your Google Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.uniform_bucket_level_access = true
+
+ puts "Uniform bucket-level access was enabled for #{bucket_name}."
+ # [END storage_enable_uniform_bucket_level_access]
+end
+
+def get_uniform_bucket_level_access bucket_name:
+ # [START storage_get_uniform_bucket_level_access]
+ # bucket_name = "Name of your Google Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ if bucket.uniform_bucket_level_access?
+ puts "Uniform bucket-level access is enabled for #{bucket_name}."
+ puts "Bucket will be locked on #{bucket.uniform_bucket_level_access_locked_at}."
+ else
+ puts "Uniform bucket-level access is disabled for #{bucket_name}."
+ end
+ # [END storage_get_uniform_bucket_level_access]
+end
+
+def enable_default_kms_key bucket_name:, default_kms_key:
+ # [START storage_set_bucket_default_kms_key]
+ # bucket_name = "Name of your Google Cloud Storage bucket"
+ # default_kms_key = "KMS key resource id"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.default_kms_key = default_kms_key
+
+ puts "Default KMS key for #{bucket.name} was set to #{bucket.default_kms_key}"
+ # [END storage_set_bucket_default_kms_key]
+end
+
+def create_bucket bucket_name:
+ # [START create_bucket]
+ # bucket_name = "Name of Google Cloud Storage bucket to create"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.create_bucket bucket_name
+
+ puts "Created bucket: #{bucket.name}"
+ # [END create_bucket]
+end
+
+def create_bucket_class_location bucket_name:, location:, storage_class:
+ # [START create_bucket_class_location]
+ # bucket_name = "Name of Google Cloud Storage bucket to create"
+ # location = "Location of where to create Cloud Storage bucket"
+ # storage_class = "Storage class of Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.create_bucket bucket_name,
+ location: location,
+ storage_class: storage_class
+
+ puts "Created bucket #{bucket.name} in #{location}" +
+ " with #{storage_class} class"
+ # [END create_bucket_class_location]
+end
+
+def list_bucket_labels bucket_name:
+ # [START get_bucket_labels]
+ # bucket_name = "Name of your Google Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ puts "Labels for #{bucket_name}"
+ bucket.labels.each do |key, value|
+ puts "#{key} = #{value}"
+ end
+ # [END get_bucket_labels]
+end
+
+def add_bucket_label bucket_name:, label_key:, label_value:
+ # [START add_bucket_label]
+ # bucket_name = "Name of your Google Cloud Storage bucket"
+ # label_key = "Cloud Storage bucket Label Key"
+ # label_value = "Cloud Storage bucket Label Value"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.update do |bucket|
+ bucket.labels[label_key] = label_value
+ end
+
+ puts "Added label #{label_key} with value #{label_value} to #{bucket_name}"
+ # [END add_bucket_label]
+end
+
+def delete_bucket_label bucket_name:, label_key:
+ # [START remove_bucket_label]
+ # bucket_name = "Name of your Google Cloud Storage bucket"
+ # label_key = "Cloud Storage bucket Label Key"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.update do |bucket|
+ bucket.labels[label_key] = nil
+ end
+
+ puts "Deleted label #{label_key} from #{bucket_name}"
+ # [END remove_bucket_label]
+end
+
+def delete_bucket bucket_name:
+ # [START delete_bucket]
+ # bucket_name = "Name of your Google Cloud Storage bucket to delete"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.delete
+
+ puts "Deleted bucket: #{bucket.name}"
+ # [END delete_bucket]
+end
+
+def set_retention_policy bucket_name:, retention_period:
+ # [START storage_set_retention_policy]
+ # bucket_name = "Name of your Google Cloud Storage bucket"
+ # retention_period = "Object retention period defined in seconds"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.retention_period = retention_period
+
+ puts "Retention period for #{bucket_name} is now #{bucket.retention_period} seconds."
+ # [END storage_set_retention_policy]
+end
+
+def lock_retention_policy bucket_name:
+ # [START storage_lock_retention_policy]
+ # bucket_name = "Name of your Google Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ # Warning: Once a retention policy is locked it cannot be unlocked
+ # and retention period can only be increased.
+ # Uses Bucket#metageneration as a precondition.
+ bucket.lock_retention_policy!
+
+ puts "Retention policy for #{bucket_name} is now locked."
+ puts "Retention policy effective as of #{bucket.retention_effective_at}."
+ # [END storage_lock_retention_policy]
+end
+
+def remove_retention_policy bucket_name:
+ # [START storage_remove_retention_policy]
+ # bucket_name = "Name of your Google Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ if !bucket.retention_policy_locked?
+ bucket.retention_period = nil
+ puts "Retention policy for #{bucket_name} has been removed."
+ else
+ puts "Policy is locked and retention policy can't be removed."
+ end
+ # [END storage_remove_retention_policy]
+end
+
+def get_retention_policy bucket_name:
+ # [START storage_get_retention_policy]
+ # bucket_name = "Name of your Google Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ puts "Retention policy:"
+ puts "period: #{bucket.retention_period}"
+ puts "effective time: #{bucket.retention_effective_at}"
+ puts "policy locked: #{bucket.retention_policy_locked?}"
+ # [END storage_get_retention_policy]
+end
+
+def enable_default_event_based_hold bucket_name:
+ # [START storage_enable_default_event_based_hold]
+ # bucket_name = "Name of your Google Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.update do |b|
+ b.default_event_based_hold = true
+ end
+
+ puts "Default event-based hold was enabled for #{bucket_name}."
+ # [END storage_enable_default_event_based_hold]
+end
+
+def disable_default_event_based_hold bucket_name:
+ # [START storage_disable_default_event_based_hold]
+ # bucket_name = "Name of your Google Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.update do |b|
+ b.default_event_based_hold = false
+ end
+
+ puts "Default event-based hold was disabled for #{bucket_name}."
+ # [END storage_disable_default_event_based_hold]
+end
+
+def get_default_event_based_hold bucket_name:
+ # [START storage_get_default_event_based_hold]
+ # bucket_name = "Name of your Google Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ if bucket.default_event_based_hold?
+ puts "Default event-based hold is enabled for #{bucket_name}."
+ else
+ puts "Default event-based hold is not enabled for #{bucket_name}."
+ end
+ # [END storage_get_default_event_based_hold]
+end
+
+if $PROGRAM_NAME == __FILE__
+ case ARGV.shift
+ when "list"
+ list_buckets
+ when "metadata"
+ list_bucket_details bucket_name: ARGV.shift
+ when "create"
+ if ARGV.size == 1
+ create_bucket bucket_name: ARGV.shift
+ elsif ARGV.size == 3
+ create_bucket_class_location bucket_name: ARGV.shift,
+ location: ARGV.shift,
+ storage_class: ARGV.shift
+ end
+ when "delete"
+ delete_bucket bucket_name: ARGV.shift
+ when "enable_requester_pays"
+ enable_requester_pays bucket_name: ARGV.shift
+ when "disable_requester_pays"
+ disable_requester_pays bucket_name: ARGV.shift
+ when "enable_default_kms_key"
+ enable_default_kms_key bucket_name: ARGV.shift,
+ default_kms_key: ARGV.shift
+ when "check_requester_pays"
+ check_requester_pays bucket_name: ARGV.shift
+ when "list_bucket_labels"
+ list_bucket_labels
+ when "add_bucket_label"
+ add_bucket_label bucket_name: ARGV.shift,
+ label_key: ARGV.shift,
+ label_value: ARGV.shift
+ when "delete_bucket_label"
+ delete_bucket_label bucket_name: ARGV.shift,
+ label_key: ARGV.shift
+ when "set_retention_policy"
+ set_retention_policy bucket_name: ARGV.shift,
+ retention_period: ARGV.shift
+ when "get_retention_policy"
+ get_retention_policy bucket_name: ARGV.shift
+ when "lock_retention_policy"
+ lock_retention_policy bucket_name: ARGV.shift
+ when "enable_default_event_based_hold"
+ enable_default_event_based_hold bucket_name: ARGV.shift
+ when "disable_default_event_based_hold"
+ disable_default_event_based_hold bucket_name: ARGV.shift
+ when "get_default_event_based_hold"
+ get_default_event_based_hold bucket_name: ARGV.shift
+ when "enable_uniform_bucket_level_access"
+ enable_uniform_bucket_level_access bucket_name: ARGV.shift
+ when "disable_uniform_bucket_level_access"
+ disable_uniform_bucket_level_access bucket_name: ARGV.shift
+ when "get_uniform_bucket_level_access"
+ get_uniform_bucket_level_access bucket_name: ARGV.shift
+ else
+ puts <<~USAGE
+ Usage: bundle exec ruby buckets.rb [command] [arguments]
+
+ Commands:
+ list List all buckets in the authenticated project
+ enable_requester_pays Enable requester pays for a bucket
+ disable_requester_pays Disable requester pays for a bucket
+ check_requester_pays Check status of requester pays for a bucket
+ enable_default_kms_key Enable default KMS encryption for bucket
+ create Create a new bucket with default storage class and location
+ create Create a new bucket with specific storage class and location
+ list_bucket_labels List bucket labels
+ add_bucket_label Add bucket label
+ delete_bucket_label Delete bucket label
+ delete Delete bucket with the provided name
+ set_retention_policy Set a retention policy on bucket with a retention period determined in seconds
+ remove_retention_policy Remove a retention policy from a bucket if policy is not locked
+ lock_retention_policy Lock retention policy
+ get_retention_policy Get retention policy for a bucket
+ enable_default_event_based_hold Enable event-based hold for a bucket
+ disable_default_event_based_hold Disable event-based hold for a bucket
+ get_default_event_based_hold Get state of event-based hold for a bucket
+ enable_uniform_bucket_level_access Enable uniform bucket-level access for a bucket
+ disable_uniform_bucket_level_access Disable uniform bucket-level access for a bucket
+ get_uniform_bucket_level_access Get uniform bucket-level access for a bucket
+
+ Environment variables:
+ GOOGLE_CLOUD_PROJECT must be set to your Google Cloud project ID
+ USAGE
+ end
+end
diff --git a/google-cloud-storage/samples/files.rb b/google-cloud-storage/samples/files.rb
new file mode 100644
index 000000000000..ef52f51281a5
--- /dev/null
+++ b/google-cloud-storage/samples/files.rb
@@ -0,0 +1,593 @@
+# 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.
+
+def list_bucket_contents bucket_name:
+ # [START list_bucket_contents]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.files.each do |file|
+ puts file.name
+ end
+ # [END list_bucket_contents]
+end
+
+def list_bucket_contents_with_prefix bucket_name:, prefix:
+ # [START list_bucket_contents_with_prefix]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # prefix = "Filter results to files whose names begin with this prefix"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+ files = bucket.files prefix: prefix
+
+ files.each do |file|
+ puts file.name
+ end
+ # [END list_bucket_contents_with_prefix]
+end
+
+def generate_encryption_key_base64
+ # [START generate_encryption_key_base64]
+ require "base64"
+ require "openssl"
+
+ encryption_key = OpenSSL::Cipher.new("aes-256-cfb").encrypt.random_key
+ encoded_enc_key = Base64.encode64 encryption_key
+
+ puts "Sample encryption key: #{encoded_enc_key}"
+ # [END generate_encryption_key_base64]
+end
+
+def upload_file bucket_name:, local_file_path:, storage_file_path: nil
+ # [START upload_file]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # local_file_path = "Path to local file to upload"
+ # storage_file_path = "Path to store the file in Google Cloud Storage"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ file = bucket.create_file local_file_path, storage_file_path
+
+ puts "Uploaded #{file.name}"
+ # [END upload_file]
+end
+
+def upload_encrypted_file bucket_name:, local_file_path:, storage_file_path: nil, encryption_key:
+ # [START upload_encrypted_file]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # local_file_path = "Path to local file to upload"
+ # storage_file_path = "Path to store the file in Google Cloud Storage"
+ # encryption_key = "AES-256 encryption key"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+
+ bucket = storage.bucket bucket_name
+
+ file = bucket.create_file local_file_path, storage_file_path,
+ encryption_key: encryption_key
+
+ puts "Uploaded #{file.name} with encryption key"
+ # [END upload_encrypted_file]
+end
+
+def upload_with_kms_key bucket_name:, local_file_path:, storage_file_path: nil, kms_key:
+ # [START storage_upload_with_kms_key]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # local_file_path = "Path to local file to upload"
+ # storage_file_path = "Path to store the file in Google Cloud Storage"
+ # kms_key = "KMS key resource id"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+
+ bucket = storage.bucket bucket_name
+
+ file = bucket.create_file local_file_path, storage_file_path,
+ kms_key: kms_key
+
+ puts "Uploaded #{file.name} and encrypted service side using #{file.kms_key}"
+ # [END storage_upload_with_kms_key]
+end
+
+def download_file bucket_name:, file_name:, local_path:
+ # [START download_file]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of file in Google Cloud Storage to download locally"
+ # local_path = "Destination path for downloaded file"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+ file = bucket.file file_name
+
+ file.download local_path
+
+ puts "Downloaded #{file.name}"
+ # [END download_file]
+end
+
+def download_public_file bucket_name:, file_name:, local_path:
+ # [START download_public_file]
+ # bucket_name = "A public Google Cloud Storage bucket name"
+ # file_name = "Name of a file in the Cloud Storage bucket"
+ # local_path = "Destination path for downloaded file"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.anonymous
+ bucket = storage.bucket bucket_name, skip_lookup: true
+ file = bucket.file file_name
+
+ file.download local_path
+
+ puts "Downloaded #{file.name}"
+ # [END download_public_file]
+end
+
+def download_file_requester_pays bucket_name:, file_name:, local_path:
+ # [START download_file_requester_pays]
+ # bucket_name = "A Google Cloud Storage bucket name"
+ # file_name = "Name of file in Google Cloud Storage to download locally"
+ # local_path = "Destination path for downloaded file"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name, skip_lookup: true, user_project: true
+ file = bucket.file file_name
+
+ file.download local_path
+
+ puts "Downloaded #{file.name} using billing project #{storage.project}"
+ # [END download_file_requester_pays]
+end
+
+def download_encrypted_file(bucket_name:, storage_file_path:,
+ local_file_path:, encryption_key:)
+ # [START download_encrypted_file]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of file in Google Cloud Storage to download locally"
+ # local_path = "Destination path for downloaded file"
+ # encryption_key = "AES-256 encryption key"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+
+ bucket = storage.bucket bucket_name
+
+ file = bucket.file storage_file_path, encryption_key: encryption_key
+ file.download local_file_path, encryption_key: encryption_key
+
+ puts "Downloaded encrypted #{file.name}"
+ # [END download_encrypted_file]
+end
+
+def delete_file bucket_name:, file_name:
+ # [START delete_file]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of file in Google Cloud Storage to delete"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+ file = bucket.file file_name
+
+ file.delete
+
+ puts "Deleted #{file.name}"
+ # [END delete_file]
+end
+
+def list_file_details bucket_name:, file_name:
+ # [START list_file_details]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of file in Google Cloud Storage"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+ file = bucket.file file_name
+
+ puts "Name: #{file.name}"
+ puts "Bucket: #{bucket.name}"
+ puts "Storage class: #{bucket.storage_class}"
+ puts "ID: #{file.id}"
+ puts "Size: #{file.size} bytes"
+ puts "Created: #{file.created_at}"
+ puts "Updated: #{file.updated_at}"
+ puts "Generation: #{file.generation}"
+ puts "Metageneration: #{file.metageneration}"
+ puts "Etag: #{file.etag}"
+ puts "Owners: #{file.acl.owners.join ','}"
+ puts "Crc32c: #{file.crc32c}"
+ puts "md5_hash: #{file.md5}"
+ puts "Cache-control: #{file.cache_control}"
+ puts "Content-type: #{file.content_type}"
+ puts "Content-disposition: #{file.content_disposition}"
+ puts "Content-encoding: #{file.content_encoding}"
+ puts "Content-language: #{file.content_language}"
+ puts "KmsKeyName: #{file.kms_key}"
+ puts "Event-based hold enabled?: #{file.event_based_hold?}"
+ puts "Temporary hold enaled?: #{file.temporary_hold?}"
+ puts "Retention Expiration: #{file.retention_expires_at}"
+ puts "Metadata:"
+ file.metadata.each do |key, value|
+ puts " - #{key} = #{value}"
+ end
+ # [END list_file_details]
+end
+
+def set_metadata bucket_name:, file_name:, content_type:, metadata_key:, metadata_value:
+ # [START set_metadata]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of file in Google Cloud Storage"
+ # content_type = "file Content-Type"
+ # metadata_key = "Custom metadata key"
+ # metadata_value = "Custom metadata value"
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+ file = bucket.file file_name
+
+ file.update do |file|
+ # Fixed key file metadata
+ file.content_type = content_type
+
+ # Custom file metadata
+ file.metadata[metadata_key] = metadata_value
+ end
+
+ puts "Metadata for #{file_name} has been updated."
+ # [END set_metadata]
+end
+
+def make_file_public bucket_name:, file_name:
+ # [START make_file_public]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of file in Google Cloud Storage to make public"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+ file = bucket.file file_name
+
+ file.acl.public!
+
+ puts "#{file.name} is publicly accessible at #{file.public_url}"
+ # [END make_file_public]
+end
+
+def rename_file bucket_name:, file_name:, new_name:
+ # [START rename_file]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of file in Google Cloud Storage to rename"
+ # new_name = "File will be renamed to this new name"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+ file = bucket.file file_name
+
+ renamed_file = file.copy new_name
+
+ file.delete
+
+ puts "#{file_name} has been renamed to #{renamed_file.name}"
+ # [END rename_file]
+end
+
+def copy_file source_bucket_name:, source_file_name:, dest_bucket_name:, dest_file_name:
+ # [START copy_file]
+ # source_bucket_name = "Source bucket to copy file from"
+ # source_file_name = "Source file name"
+ # dest_bucket_name = "Destination bucket to copy file to"
+ # dest_file_name = "Destination file name"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket source_bucket_name
+ file = bucket.file source_file_name
+
+ destination_bucket = storage.bucket dest_bucket_name
+ destination_file = file.copy destination_bucket.name, dest_file_name
+
+ puts "#{file.name} in #{bucket.name} copied to " +
+ "#{destination_file.name} in #{destination_bucket.name}"
+ # [END copy_file]
+end
+
+def rotate_encryption_key bucket_name:, file_name:, current_encryption_key:, new_encryption_key:
+ # [START rotate_encryption_key]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of a file in the Cloud Storage bucket"
+ # current_encryption_key = "Encryption key currently being used"
+ # new_encryption_key = "New encryption key to use"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+ file = bucket.file file_name, encryption_key: current_encryption_key
+
+ file.rotate encryption_key: current_encryption_key,
+ new_encryption_key: new_encryption_key
+
+ puts "The encryption key for #{file.name} in #{bucket.name} was rotated."
+ # [END rotate_encryption_key]
+end
+
+def generate_signed_url bucket_name:, file_name:
+ # [START generate_signed_url]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of a file in the Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+ file = bucket.file file_name
+
+ url = file.signed_url
+
+ puts "The signed url for #{file_name} is #{url}"
+ # [END generate_signed_url]
+end
+
+def generate_signed_get_url_v4 bucket_name:, file_name:
+ # [START storage_generate_signed_url_v4]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of a file in the Google Cloud Storage bucket"
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ storage_expiry_time = 5 * 60 # 5 minutes
+
+ url = storage.signed_url bucket_name, file_name, method: "GET",
+ expires: storage_expiry_time, version: :v4
+
+ puts "Generated GET signed url:"
+ puts url
+ puts "You can use this URL with any user agent, for example:"
+ puts "curl #{url}"
+ # [END storage_generate_signed_url_v4]
+end
+
+def generate_signed_put_url_v4 bucket_name:, file_name:
+ # [START storage_generate_upload_signed_url_v4]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of a file in the Cloud Storage bucket"
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ storage_expiry_time = 5 * 60 # 5 minutes
+
+ url = storage.signed_url bucket_name, file_name, method: "PUT",
+ expires: storage_expiry_time, version: :v4,
+ headers: { "Content-Type" => "text/plain" }
+ puts "Generated PUT signed URL:"
+ puts url
+ puts "You can use this URL with any user agent, for example:"
+ puts "curl -X PUT -H 'Content-Type: text/plain' --upload-file my-file '#{url}'"
+ # [END storage_generate_upload_signed_url_v4]
+end
+
+def set_event_based_hold bucket_name:, file_name:
+ # [START storage_set_event_based_hold]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of a file in the Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+ file = bucket.file file_name
+
+ file.set_event_based_hold!
+
+ puts "Event-based hold was set for #{file_name}."
+ # [END storage_set_event_based_hold]
+end
+
+def release_event_based_hold bucket_name:, file_name:
+ # [START storage_release_event_based_hold]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of a file in the Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+ file = bucket.file file_name
+
+ file.release_event_based_hold!
+
+ puts "Event-based hold was released for #{file_name}."
+ # [END storage_release_event_based_hold]
+end
+
+def set_temporary_hold bucket_name:, file_name:
+ # [START storage_set_temporary_hold]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of a file in the Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+ file = bucket.file file_name
+
+ file.set_temporary_hold!
+
+ puts "Temporary hold was set for #{file_name}."
+ # [END storage_set_temporary_hold]
+end
+
+def release_temporary_hold bucket_name:, file_name:
+ # [START storage_release_temporary_hold]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # file_name = "Name of a file in the Cloud Storage bucket"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+ file = bucket.file file_name
+
+ file.release_temporary_hold!
+
+ puts "Temporary hold was released for #{file_name}."
+ # [END storage_release_temporary_hold]
+end
+
+def run_sample arguments
+ command = arguments.shift
+
+ case command
+ when "list"
+ list_bucket_contents bucket_name: arguments.shift
+ when "upload"
+ upload_file bucket_name: arguments.shift,
+ local_file_path: arguments.shift,
+ storage_file_path: arguments.shift
+ when "encrypted_upload"
+ upload_encrypted_file bucket_name: arguments.shift,
+ local_file_path: arguments.shift,
+ storage_file_path: arguments.shift,
+ encryption_key: Base64.decode64(arguments.shift)
+ when "kms_upload"
+ upload_with_kms_key bucket_name: arguments.shift,
+ local_file_path: arguments.shift,
+ storage_file_path: arguments.shift,
+ kms_key: arguments.shift
+ when "download"
+ download_file bucket_name: arguments.shift,
+ file_name: arguments.shift,
+ local_path: arguments.shift
+ when "download_public_file"
+ download_public_file bucket_name: arguments.shift,
+ file_name: arguments.shift,
+ local_path: arguments.shift
+ when "encrypted_download"
+ download_file bucket_name: arguments.shift,
+ file_name: arguments.shift,
+ local_path: arguments.shift,
+ encrypted_key: Base64.decode64(arguments.shift)
+ when "download_with_requester_pays"
+ download_file_requester_pays bucket_name: arguments.shift,
+ file_name: arguments.shift,
+ local_path: arguments.shift
+ when "rotate_encryption_key"
+ rotate_encryption_key bucket_name: arguments.shift,
+ file_name: arguments.shift,
+ current_encryption_key: arguments.shift,
+ new_encryption_key: arguments.shift
+ when "generate_encryption_key"
+ generate_encryption_key_base64
+ when "delete"
+ delete_file bucket_name: arguments.shift,
+ file_name: arguments.shift
+ when "metadata"
+ list_file_details bucket_name: arguments.shift,
+ file_name: arguments.shift
+ when "make_public"
+ make_file_public bucket_name: arguments.shift,
+ file_name: arguments.shift
+ when "rename"
+ rename_file bucket_name: arguments.shift,
+ file_name: arguments.shift,
+ new_name: arguments.shift
+ when "copy"
+ copy_file source_bucket_name: arguments.shift,
+ source_file_name: arguments.shift,
+ dest_bucket_name: arguments.shift,
+ dest_file_name: arguments.shift
+ when "generate_signed_url"
+ generate_signed_url bucket_name: arguments.shift,
+ file_name: arguments.shift
+ when "generate_signed_get_url_v4"
+ generate_signed_get_url_v4 bucket_name: arguments.shift,
+ file_name: arguments.shift
+ when "generate_signed_put_url_v4"
+ generate_signed_put_url_v4 bucket_name: arguments.shift,
+ file_name: arguments.shift
+ when "set_event_based_hold"
+ set_event_based_hold bucket_name: arguments.shift,
+ file_name: arguments.shift
+ when "release_event_based_hold"
+ release_event_based_hold bucket_name: arguments.shift,
+ file_name: arguments.shift
+ when "set_temporary_hold"
+ set_temporary_hold bucket_name: arguments.shift,
+ file_name: arguments.shift
+ when "release_temporary_hold"
+ release_temporary_hold bucket_name: arguments.shift,
+ file_name: arguments.shift
+ else
+ puts <<~USAGE
+ Usage: bundle exec ruby files.rb [command] [arguments]
+
+ Commands:
+ list List all files in the bucket
+ upload Upload local file to a bucket
+ encrypted_upload Upload local file as an encrypted file to a bucket
+ kms_upload Upload local file and encrypt service side using a KMS key
+ download Download a file from a bucket
+ download_public_file Download a publically accessible file from a bucket
+ encrypted_download Download an encrypted file from a bucket
+ download_with_requester_pays Download a file from a requester pays enabled bucket
+ rotate_encryption_key Update encryption key of an encrypted file.
+ generate_encryption_key Generate a sample encryption key
+ delete Delete a file from a bucket
+ metadata Display metadata for a file in a bucket
+ make_public Make a file in a bucket public
+ rename Rename a file in a bucket
+ copy Copy file to other bucket
+ generate_signed_url Generate a V2 signed url for a file
+ generate_signed_get_url_v4 Generate a V4 signed get url for a file
+ generate_signed_put_url_v4 Generate a V4 signed put url for a file
+ set_event_based_hold Set an event-based hold on a file
+ release_event_based_hold Relase an event-based hold on a file
+ set_temporary_hold Set a temporary hold on a file
+ release_temporary_hold Release a temporary hold on a file
+
+ Environment variables:
+ GOOGLE_CLOUD_PROJECT must be set to your Google Cloud project ID
+ USAGE
+ end
+end
+
+if $PROGRAM_NAME == __FILE__
+ run_sample ARGV
+end
diff --git a/google-cloud-storage/samples/hmac.rb b/google-cloud-storage/samples/hmac.rb
new file mode 100644
index 000000000000..5db8f092e7a8
--- /dev/null
+++ b/google-cloud-storage/samples/hmac.rb
@@ -0,0 +1,180 @@
+# 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.
+
+def list_hmac_keys
+ # [START storage_list_hmac_keys]
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+
+ # By default Storage#hmac_keys uses the Storage client project_id
+ hmac_keys = storage.hmac_keys
+
+ puts "HMAC Keys:"
+ hmac_keys.all do |hmac_key|
+ puts "Service Account Email: #{hmac_key.service_account_email}"
+ puts "Access ID: #{hmac_key.access_id}"
+ end
+ # [END storage_list_hmac_keys]
+end
+
+def create_hmac_key service_account_email:
+ # [START storage_create_hmac_key]
+ # service_account_email = "Service account used to associate generate HMAC key"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+
+ # By default Storage#create_hmac_key uses the Storage client project_id
+ hmac_key = storage.create_hmac_key service_account_email
+
+ puts "The base64 encoded secret is: #{hmac_key.secret}"
+ puts "Do not miss that secret, there is no API to recover it."
+ puts "\nThe HMAC key metadata is:"
+ puts "Key ID: #{hmac_key.id}"
+ puts "Service Account Email: #{hmac_key.service_account_email}"
+ puts "Access ID: #{hmac_key.access_id}"
+ puts "Project ID: #{hmac_key.project_id}"
+ puts "Active: #{hmac_key.active?}"
+ puts "Created At: #{hmac_key.created_at}"
+ puts "Updated At: #{hmac_key.updated_at}"
+ puts "Etag: #{hmac_key.etag}"
+ # [END storage_create_hmac_key]
+end
+
+def get_hmac_key access_id:
+ # [START storage_get_hmac_key]
+ # access_id = "ID of an HMAC key"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+
+ # By default Storage#hmac_keys uses the Storage client project_id
+ hmac_key = storage.hmac_key access_id
+
+ puts "The HMAC key metadata is:"
+ puts "Key ID: #{hmac_key.id}"
+ puts "Service Account Email: #{hmac_key.service_account_email}"
+ puts "Access ID: #{hmac_key.access_id}"
+ puts "Project ID: #{hmac_key.project_id}"
+ puts "Active: #{hmac_key.active?}"
+ puts "Created At: #{hmac_key.created_at}"
+ puts "Updated At: #{hmac_key.updated_at}"
+ puts "Etag: #{hmac_key.etag}"
+ # [END storage_get_hmac_key]
+end
+
+def activate_hmac_key access_id:
+ # [START storage_activate_hmac_key]
+ # access_id = "ID of an inactive HMAC key"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+
+ # By default Storage#hmac_keys uses the Storage client project_id
+ hmac_key = storage.hmac_key access_id
+
+ hmac_key.active!
+
+ puts "The HMAC key is now active."
+ puts "The HMAC key metadata is:"
+ puts "Key ID: #{hmac_key.id}"
+ puts "Service Account Email: #{hmac_key.service_account_email}"
+ puts "Access ID: #{hmac_key.access_id}"
+ puts "Project ID: #{hmac_key.project_id}"
+ puts "Active: #{hmac_key.active?}"
+ puts "Created At: #{hmac_key.created_at}"
+ puts "Updated At: #{hmac_key.updated_at}"
+ puts "Etag: #{hmac_key.etag}"
+ # [END storage_activate_hmac_key]
+end
+
+def deactivate_hmac_key access_id:
+ # [START storage_deactivate_hmac_key]
+ # access_id = "ID of an inactive HMAC key"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+
+ # By default Storage#hmac_keys uses the Storage client project_id
+ hmac_key = storage.hmac_key access_id
+
+ hmac_key.inactive!
+
+ puts "The HMAC key is now inactive."
+ puts "The HMAC key metadata is:"
+ puts "Key ID: #{hmac_key.id}"
+ puts "Service Account Email: #{hmac_key.service_account_email}"
+ puts "Access ID: #{hmac_key.access_id}"
+ puts "Project ID: #{hmac_key.project_id}"
+ puts "Active: #{hmac_key.active?}"
+ puts "Created At: #{hmac_key.created_at}"
+ puts "Updated At: #{hmac_key.updated_at}"
+ puts "Etag: #{hmac_key.etag}"
+ # [END storage_deactivate_hmac_key]
+end
+
+def delete_hmac_key access_id:
+ # [START storage_delete_hmac_key]
+ # access_id = "ID of an inactive HMAC key"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+
+ # By default Storage#hmac_keys uses the Storage client project_id
+ hmac_key = storage.hmac_key access_id
+
+ hmac_key.delete!
+
+ puts "The key is deleted, though it may still appear in Client#hmac_keys results."
+ # [END storage_delete_hmac_key]
+end
+
+if $PROGRAM_NAME == __FILE__
+ case ARGV.shift
+ when "list_hmac_keys"
+ list_hmac_keys
+ when "create_hmac_key"
+ create_hmac_key service_account_email: ARGV.shift
+ when "get_hmac_key"
+ get_hmac_key access_id: ARGV.shift
+ when "activate_hmac_key"
+ activate_hmac_key access_id: ARGV.shift
+ when "deactivate_hmac_key"
+ deactivate_hmac_key access_id: ARGV.shift
+ when "delete_hmac_key"
+ delete_hmac_key access_id: ARGV.shift
+ else
+ puts <<~USAGE
+ Usage: bundle exec ruby hmac.rb [command] [arguments]
+
+ Commands:
+ list_hmac_keys List all HMAC keys for a project
+ create_hmac_key Create HMAC Key
+ get_hmac_key Get HMAC Key metadata
+ activate_hmac_key Activate an HMAC Key
+ deactivate_hmac_key Deactivate an HMAC Key
+ delete_hmac_key Delete a deactivated HMAC key
+
+ Environment variables:
+ GOOGLE_CLOUD_PROJECT must be set to your Google Cloud project ID
+ USAGE
+ end
+end
diff --git a/google-cloud-storage/samples/iam.rb b/google-cloud-storage/samples/iam.rb
new file mode 100644
index 000000000000..efebb51d7c68
--- /dev/null
+++ b/google-cloud-storage/samples/iam.rb
@@ -0,0 +1,199 @@
+# 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.
+
+def view_bucket_iam_members bucket_name:
+ # [START view_bucket_iam_members]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ policy = bucket.policy requested_policy_version: 3
+ policy.bindings.each do |binding|
+ puts "Role: #{binding.role}"
+ puts "Members: #{binding.members}"
+
+ # if a conditional binding exists print the condition.
+ if binding.condition
+ puts "Condition Title: #{binding.condition.title}"
+ puts "Condition Description: #{binding.condition.description}"
+ puts "Condition Expression: #{binding.condition.expression}"
+ end
+ end
+ # [END view_bucket_iam_members]
+end
+
+def add_bucket_iam_member bucket_name:, role:, member:
+ # [START add_bucket_iam_member]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # role = "Bucket-level IAM role"
+ # member = "Bucket-level IAM member"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.policy requested_policy_version: 3 do |policy|
+ policy.bindings.insert role: role, members: [member]
+ end
+
+ puts "Added #{member} with role #{role} to #{bucket_name}"
+ # [END add_bucket_iam_member]
+end
+
+def remove_bucket_iam_member bucket_name:, role:, member:
+ # [START remove_bucket_iam_member]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # role = "Bucket-level IAM role"
+ # member = "Bucket-level IAM member"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.policy requested_policy_version: 3 do |policy|
+ policy.bindings.each do |binding|
+ if binding.role == role && binding.condition.nil?
+ binding.members.delete member
+ end
+ end
+ end
+
+ puts "Removed #{member} with role #{role} from #{bucket_name}"
+ # [END remove_bucket_iam_member]
+end
+
+def add_bucket_conditional_iam_binding bucket_name:, role:, member:, title:, description:, expression:
+ # [START storage_add_bucket_conditional_iam_binding]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # role = "Bucket-level IAM role"
+ # member = "Bucket-level IAM member"
+ # title = "Condition Title"
+ # description = "Condition Description"
+ # expression = "Condition Expression"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.policy requested_policy_version: 3 do |policy|
+ policy.version = 3
+ policy.bindings.insert(
+ role: role,
+ members: member,
+ condition: {
+ title: title,
+ description: description,
+ expression: expression
+ }
+ )
+ end
+
+ puts "Added #{member} with role #{role} to #{bucket_name} with condition #{title} #{description} #{expression}"
+ # [END storage_add_bucket_conditional_iam_binding]
+end
+
+def remove_bucket_conditional_iam_binding bucket_name:, role:, title:, description:, expression:
+ # [START storage_remove_bucket_conditional_iam_binding]
+ # bucket_name = "Your Google Cloud Storage bucket name"
+ # role = "Bucket-level IAM role"
+ # title = "Condition Title"
+ # description = "Condition Description"
+ # expression = "Condition Expression"
+
+ require "google/cloud/storage"
+
+ storage = Google::Cloud::Storage.new
+ bucket = storage.bucket bucket_name
+
+ bucket.policy requested_policy_version: 3 do |policy|
+ policy.version = 3
+
+ binding_to_remove = nil
+ policy.bindings.each do |b|
+ condition = {
+ title: title,
+ description: description,
+ expression: expression
+ }
+ if (b.role == role) && (b.condition &&
+ b.condition.title == title &&
+ b.condition.description == description &&
+ b.condition.expression == expression)
+ binding_to_remove = b
+ end
+ end
+ if binding_to_remove
+ policy.bindings.remove binding_to_remove
+ puts "Conditional Binding was removed."
+ else
+ puts "No matching conditional binding found."
+ end
+ end
+ # [END storage_remove_bucket_conditional_iam_binding]
+end
+
+def run_sample arguments
+ command = arguments.shift
+
+ case command
+ when "view_bucket_iam_members"
+ view_bucket_iam_members bucket_name: arguments.shift
+ when "add_bucket_iam_member"
+ add_bucket_iam_member bucket_name: arguments.shift,
+ role: arguments.shift,
+ member: arguments.shift
+ when "add_bucket_conditional_iam_binding"
+ add_bucket_conditional_iam_binding project_id: project_id,
+ bucket_name: arguments.shift,
+ role: arguments.shift,
+ member: arguments.shift,
+ title: arguments.shift,
+ description: arguments.shift,
+ expression: arguments.shift
+ when "remove_bucket_iam_member"
+ remove_bucket_iam_member bucket_name: arguments.shift,
+ role: arguments.shift,
+ member: arguments.shift
+ when "remove_bucket_conditional_iam_binding"
+ remove_bucket_conditional_iam_binding bucket_name: arguments.shift,
+ role: arguments.shift,
+ title: arguments.shift,
+ description: arguments.shift,
+ expression: arguments.shift
+ else
+ puts <<~USAGE
+ Usage: bundle exec ruby iam.rb [command] [arguments]
+
+ Commands:
+ view_bucket_iam_members View bucket-level IAM members
+ add_bucket_iam_member Add a bucket-level IAM member
+ add_bucket_conditional_iam_binding Add a conditional bucket-level binding
+ remove_bucket_iam_member Remove a bucket-level IAM member
+ remove_bucket_conditional_iam_binding Remove a conditional bucket-level binding
+
+ Environment variables:
+ GOOGLE_CLOUD_PROJECT must be set to your Google Cloud project ID
+ USAGE
+ end
+end
+
+if $PROGRAM_NAME == __FILE__
+ run_sample ARGV
+end
diff --git a/google-cloud-storage/samples/quickstart.rb b/google-cloud-storage/samples/quickstart.rb
new file mode 100644
index 000000000000..fbb3cc7ef4d6
--- /dev/null
+++ b/google-cloud-storage/samples/quickstart.rb
@@ -0,0 +1,34 @@
+# 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.
+
+def quickstart bucket_name:
+ # [START storage_quickstart]
+ # Imports the Google Cloud client library
+ require "google/cloud/storage"
+
+ # Instantiates a client
+ storage = Google::Cloud::Storage.new
+
+ # bucket_name = "The name of the bucket to be created, i.e. 'new-bucket'"
+
+ # Creates the new bucket
+ bucket = storage.create_bucket bucket_name
+
+ puts "Bucket #{bucket.name} was created."
+ # [END storage_quickstart]
+end
+
+if $PROGRAM_NAME == __FILE__
+ quickstart "quickstart_bucket"
+end