Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions google-cloud-storage/.yardopts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
-
OVERVIEW.md
AUTHENTICATION.md
EMULATOR.md
LOGGING.md
CONTRIBUTING.md
TROUBLESHOOTING.md
Expand Down
47 changes: 47 additions & 0 deletions google-cloud-storage/EMULATOR.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Google Cloud Storage Emulator

To develop and test your application locally, you can point the client at a
Cloud Storage emulator instead of the live service.

Set the `STORAGE_EMULATOR_HOST` environment variable to the host and port where
the emulator is running. You can set it in the shell that runs your Ruby code,
or in the code itself:

```ruby
require "google/cloud/storage"

# Make Storage use the emulator
ENV["STORAGE_EMULATOR_HOST"] = "localhost:4443"

storage = Google::Cloud::Storage.new

bucket = storage.create_bucket "my-bucket"
file = bucket.create_file StringIO.new("Hello world!"), "hello-world.txt"
file.name #=> "hello-world.txt"
```

You can also pass the `emulator_host` argument, or set `emulator_host` in the
configuration:

```ruby
require "google/cloud/storage"

storage = Google::Cloud::Storage.new emulator_host: "localhost:4443"

# Or, for every client:
Google::Cloud::Storage.configure do |config|
config.emulator_host = "localhost:4443"
end
```

When an emulator host is set, the client:

* Uses `http://` if the host has no scheme. Include the scheme, such as
`https://localhost:4443`, if the emulator serves HTTPS.
* Connects anonymously instead of looking up Application Default Credentials.
Credentials passed with the `credentials` argument are still used.
* Doesn't require a project ID.
* Ignores the `endpoint` option.

`Google::Cloud::Storage.anonymous` also uses the emulator host from the
environment variable or the configuration.
3 changes: 2 additions & 1 deletion google-cloud-storage/OVERVIEW.md
Original file line number Diff line number Diff line change
Expand Up @@ -616,5 +616,6 @@ for a list of error conditions.

## Additional information

Google Cloud Storage can be configured to use logging. To learn more, see the
Google Cloud Storage can be configured to use an emulator or to enable logging.
To learn more, see the [Emulator guide](EMULATOR.md) and
[Logging guide](LOGGING.md).
2 changes: 1 addition & 1 deletion google-cloud-storage/google-cloud-storage.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Gem::Specification.new do |gem|
gem.license = "Apache-2.0"

gem.files = `git ls-files -- lib/*`.split("\n") +
["OVERVIEW.md", "AUTHENTICATION.md", "LOGGING.md", "CONTRIBUTING.md", "TROUBLESHOOTING.md", "CHANGELOG.md", "CODE_OF_CONDUCT.md", "LICENSE", ".yardopts"]
["OVERVIEW.md", "AUTHENTICATION.md", "EMULATOR.md", "LOGGING.md", "CONTRIBUTING.md", "TROUBLESHOOTING.md", "CHANGELOG.md", "CODE_OF_CONDUCT.md", "LICENSE", ".yardopts"]
gem.require_paths = ["lib"]

gem.required_ruby_version = ">= 3.2"
Expand Down
22 changes: 18 additions & 4 deletions google-cloud-storage/lib/google-cloud-storage.rb
Comment thread
SalvatoreT marked this conversation as resolved.
Resolved
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ module Cloud
# @param [Integer] upload_chunk_size The chunk size of storage upload, in bytes.
# The default value is 100 MB, i.e. 104_857_600 bytes. To disable chunking and upload
# the complete file regardless of size, pass 0 as the chunk size.
# @param [String] emulator_host Host of a Storage emulator, such as `localhost:9000`. Optional.
# If nil, uses the `emulator_host` config, which defaults to the `STORAGE_EMULATOR_HOST`
# environment variable. See {Google::Cloud::Storage.new}.
#
# @return [Google::Cloud::Storage::Project]
#
Expand All @@ -77,7 +80,8 @@ module Cloud
# readonly_storage = gcloud.storage scope: readonly_scope
#
def storage scope: nil, retries: nil, timeout: nil, open_timeout: nil, read_timeout: nil, send_timeout: nil,
max_elapsed_time: nil, base_interval: nil, max_interval: nil, multiplier: nil, upload_chunk_size: nil
max_elapsed_time: nil, base_interval: nil, max_interval: nil, multiplier: nil, upload_chunk_size: nil,
emulator_host: nil
Google::Cloud.storage @project, @keyfile, scope: scope,
retries: retries || @retries,
timeout: timeout || @timeout,
Expand All @@ -88,7 +92,8 @@ def storage scope: nil, retries: nil, timeout: nil, open_timeout: nil, read_time
base_interval: base_interval,
max_interval: max_interval,
multiplier: multiplier,
upload_chunk_size: upload_chunk_size
upload_chunk_size: upload_chunk_size,
emulator_host: emulator_host
end

##
Expand Down Expand Up @@ -127,6 +132,9 @@ def storage scope: nil, retries: nil, timeout: nil, open_timeout: nil, read_time
# @param [Integer] upload_chunk_size The chunk size of storage upload, in bytes.
# The default value is 100 MB, i.e. 104_857_600 bytes. To disable chunking and upload
# the complete file regardless of size, pass 0 as the chunk size.
# @param [String] emulator_host Host of a Storage emulator, such as `localhost:9000`. Optional.
# If nil, uses the `emulator_host` config, which defaults to the `STORAGE_EMULATOR_HOST`
# environment variable. See {Google::Cloud::Storage.new}.
#
# @return [Google::Cloud::Storage::Project]
#
Expand All @@ -142,7 +150,7 @@ def storage scope: nil, retries: nil, timeout: nil, open_timeout: nil, read_time
def self.storage project_id = nil, credentials = nil, scope: nil,
retries: nil, timeout: nil, open_timeout: nil, read_timeout: nil, send_timeout: nil,
max_elapsed_time: nil, base_interval: nil, max_interval: nil, multiplier: nil,
upload_chunk_size: nil
upload_chunk_size: nil, emulator_host: nil
require "google/cloud/storage"
Google::Cloud::Storage.new project_id: project_id,
credentials: credentials,
Expand All @@ -156,7 +164,8 @@ def self.storage project_id = nil, credentials = nil, scope: nil,
base_interval: base_interval,
max_interval: max_interval,
multiplier: multiplier,
upload_chunk_size: upload_chunk_size
upload_chunk_size: upload_chunk_size,
emulator_host: emulator_host
end
end
end
Expand All @@ -172,6 +181,10 @@ def self.storage project_id = nil, credentials = nil, scope: nil,
"STORAGE_KEYFILE", "STORAGE_KEYFILE_JSON"
)
end
default_emulator = Google::Cloud::Config.deferred do
Comment thread
SalvatoreT marked this conversation as resolved.
Resolved
emulator_host = ENV["STORAGE_EMULATOR_HOST"]
emulator_host unless emulator_host.to_s.strip.empty?
end

config.add_field! :project_id, default_project, match: String, allow_nil: true
config.add_alias! :project, :project_id
Expand All @@ -192,5 +205,6 @@ def self.storage project_id = nil, credentials = nil, scope: nil,
config.add_field! :send_timeout, nil, match: Integer
config.add_field! :upload_chunk_size, nil, match: Integer
config.add_field! :endpoint, nil, match: String, allow_nil: true
config.add_field! :emulator_host, default_emulator, match: String, allow_nil: true
config.add_field! :universe_domain, nil, match: String, allow_nil: true
end
41 changes: 36 additions & 5 deletions google-cloud-storage/lib/google/cloud/storage.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ module Storage
# @param [Integer] send_timeout How long, in seconds, before receiving response from server times out. Optional.
# @param [String] endpoint Override of the endpoint host name. Optional.
# If the param is nil, uses the default endpoint.
# @param [String] emulator_host Host of a Storage emulator, such as `localhost:9000` or
# `http://localhost:9000`. `http://` is used when no scheme is given. Optional.
# If the param is nil, uses the value of the `emulator_host` config, which defaults to the
# `STORAGE_EMULATOR_HOST` environment variable. When set, the client sends requests to the
# emulator instead of `endpoint`, connects anonymously unless `credentials` is given, and
# does not require a project ID.
# @param universe_domain [String] Override of the universe domain. Optional.
# If unset or nil, uses the default unvierse domain
# @param [Integer] upload_chunk_size The chunk size of storage upload, in bytes.
Expand Down Expand Up @@ -97,28 +103,37 @@ def self.new project_id: nil, credentials: nil, scope: nil, retries: nil,
timeout: nil, open_timeout: nil, read_timeout: nil,
send_timeout: nil, endpoint: nil, project: nil, keyfile: nil,
max_elapsed_time: nil, base_interval: nil, max_interval: nil,
multiplier: nil, upload_chunk_size: nil, universe_domain: nil
multiplier: nil, upload_chunk_size: nil, universe_domain: nil,
emulator_host: nil
scope ||= configure.scope
retries ||= configure.retries
timeout ||= configure.timeout
open_timeout ||= configure.open_timeout || timeout
read_timeout ||= configure.read_timeout || timeout
send_timeout ||= configure.send_timeout || timeout
endpoint ||= configure.endpoint
credentials ||= keyfile || default_credentials(scope: scope)
max_elapsed_time ||= configure.max_elapsed_time
base_interval ||= configure.base_interval
max_interval ||= configure.max_interval
multiplier ||= configure.multiplier
upload_chunk_size ||= configure.upload_chunk_size
universe_domain ||= configure.universe_domain
emulator_host ||= configure.emulator_host

unless credentials.is_a? Google::Auth::Credentials
emulator_url = emulator_root_url emulator_host
if emulator_url
endpoint = emulator_url
credentials ||= keyfile
else
credentials ||= keyfile || default_credentials(scope: scope)
end

if credentials && !credentials.is_a?(Google::Auth::Credentials)
credentials = Storage::Credentials.new credentials, scope: scope
end

project_id = resolve_project_id(project_id || project, credentials)
raise ArgumentError, "project_id is missing" if project_id.empty?
raise ArgumentError, "project_id is missing" if project_id.empty? && !emulator_url

Storage::Project.new(
Storage::Service.new(
Expand Down Expand Up @@ -151,7 +166,8 @@ def self.new project_id: nil, credentials: nil, scope: nil, retries: nil,
# @param [Integer] read_timeout How long, in seconds, before requests time out. Optional.
# @param [Integer] send_timeout How long, in seconds, before receiving response from server times out. Optional.
# @param [String] endpoint Override of the endpoint host name. Optional.
# If the param is nil, uses the default endpoint.
# If the param is nil, uses the default endpoint. Ignored when the `emulator_host` config
# (or the `STORAGE_EMULATOR_HOST` environment variable) is set.
# @param universe_domain [String] Override of the universe domain. Optional.
# If unset or nil, uses the default unvierse domain
# @param [Integer] upload_chunk_size The chunk size of storage upload, in bytes.
Expand Down Expand Up @@ -179,6 +195,7 @@ def self.anonymous retries: nil, timeout: nil, open_timeout: nil,
open_timeout ||= timeout
read_timeout ||= timeout
send_timeout ||= timeout
endpoint = emulator_root_url(configure.emulator_host) || endpoint
Storage::Project.new(
Storage::Service.new(
nil, nil, retries: retries, timeout: timeout, open_timeout: open_timeout,
Expand All @@ -203,6 +220,9 @@ def self.anonymous retries: nil, timeout: nil, open_timeout: nil,
# parameter `keyfile` is considered deprecated, but may also be used.)
# * `endpoint` - (String) Override of the endpoint host name, or `nil`
# to use the default endpoint.
# * `emulator_host` - (String) Host of a Storage emulator, such as
# `localhost:9000`, or `nil` to connect to the live service. Defaults to
# `ENV["STORAGE_EMULATOR_HOST"]`.
# * `scope` - (String, Array<String>) The OAuth 2.0 scopes controlling
# the set of resources and operations that the connection can access.
# * `retries` - (Integer) Number of times to retry requests on server
Expand Down Expand Up @@ -255,6 +275,17 @@ def self.default_credentials scope: nil
Google::Cloud.configure.credentials ||
Storage::Credentials.default(scope: scope)
end

##
# @private Root URL for an emulator host, or nil if the host is blank.
# The API client appends paths such as `storage/v1/` directly to the
# root URL, so it must end with a slash.
def self.emulator_root_url emulator_host
url = emulator_host.to_s.strip
return nil if url.empty?
url = "http://#{url}" unless url.include? "://"
url.end_with?("/") ? url : "#{url}/"
end
end
end
end
Loading
Loading