fog-google 1.8.2 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f5891afe294dbc055e5e3f3ff46a2dab00692cb3
4
- data.tar.gz: f81a710b9e7774d9ece9c8b49d02c9fe54a37fac
3
+ metadata.gz: 870ce94387132895473e52fcee3adc9cbce052c5
4
+ data.tar.gz: aa4f7954f7c441b6bcb4f4d32c49e8ab8ff78ac5
5
5
  SHA512:
6
- metadata.gz: 47b3b0b0a4687ec054180bda94aa7e45a65d3e65a6c7145a574d4f3f9fbbc433da67b60e61de5ceff72664fd5839f20ccc5694ae61daae606885d3e259b4c714
7
- data.tar.gz: 44ed811c6cc6246667aed5742d2b43ca312cf2864b19a8c477d1592ca9b11066d421e0ee4be21e2db9356098e794ac2800357946f75052313a8c4af0aad82788
6
+ metadata.gz: 6426e7e238fe7592575516799ea209c4019d2807519efb91830a694fda2ccf733432e9c28b6ae91f3311b28dd80a97015663d1a9fa0552bc67f15095c4f2fd86
7
+ data.tar.gz: f19bbc71aa3bba9bb6e859cb82767e64c501a5638e962a159fa6a6baa3bed9a25bd3ed69de084773dece607021eb139777fcdf30cbe0d2d137c712de888849f3
@@ -15,10 +15,8 @@
15
15
  # START GOOGLE CONFIG
16
16
  my_google_credentials:
17
17
  google_project: my-project-id
18
- google_client_email: xxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx@developer.gserviceaccount.com
19
18
  google_json_key_location: /path/to/my-project-xxxxxxxxxxxx.json
20
- # You can also provide service account credentials with `google_json_key_string` or
21
- # with `google_key_location` and `google_key_string` for P12 private keys.
19
+ # You can also provide service account credentials with `google_json_key_string`
22
20
  # If so, uncomment the two following lines.
23
21
  # HMAC credentials follow a similar format:
24
22
  #google_storage_access_key_id: GOOGXXXXXXXXXXXXXXXX
@@ -6,6 +6,35 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
6
6
 
7
7
  ## Next
8
8
 
9
+ ## 1.9.0
10
+
11
+ ### User-facing
12
+
13
+ #### Added
14
+
15
+ - \#442 Add support for Application Default credentials [mavin]
16
+ - This change allows the use of Application Default Credentials so that end
17
+ users can authenticate without a service account for development, testing,
18
+ and one-off interactions by using `:google_application_default`client
19
+ option. See README for more details.
20
+
21
+ ### Fixed
22
+
23
+ - \#444 Remove deprecated `google_client_email` option from client parameters
24
+ [temikus]
25
+ - \#446 Updating service parameters to avoid "unrecognised parameter" warnings
26
+ when initializing Fog client with application default auth [temikus]
27
+
28
+ ### Development changes
29
+
30
+ #### Fixed
31
+
32
+ - \#441 Update CI pipeline to Concourse V4 [temikus]
33
+ - \#444 Rework client authentication workflow [temikus]
34
+ - Separate different auth streams into private helper methods
35
+ - Add a fallback auth option - Google Application Default credentials
36
+ - Minor fixes and performance optimizations
37
+
9
38
  ## 1.8.2
10
39
 
11
40
  ### User-facing
@@ -94,7 +94,6 @@ make sure you have a `:test` credential in `~/.fog`, something like:
94
94
  ```
95
95
  test:
96
96
  google_project: my-project
97
- google_client_email: xxxxxxxxxxxxx-xxxxxxxxxxxxx@developer.gserviceaccount.com
98
97
  google_json_key_location: /path/to/my-project-xxxxxxxxxxxxx.json
99
98
  ```
100
99
 
data/README.md CHANGED
@@ -94,6 +94,20 @@ cat .fog.example >> ~/.fog # appends the sample configuration
94
94
  vim ~/.fog # edit file with yout config
95
95
  ```
96
96
 
97
+ As of `1.9.0` fog-google supports Google [application default credentials (ADC)](https://cloud.google.com/docs/authentication/production)
98
+ The auth method uses [Google::Auth.get_application_default](https://www.rubydoc.info/gems/googleauth/0.6.7/Google%2FAuth.get_application_default)
99
+ under the hood.
100
+
101
+ Example workflow for a GCE instance with [service account scopes](https://cloud.google.com/compute/docs/access/create-enable-service-accounts-for-instances)
102
+ defined:
103
+
104
+ ```
105
+ > connection = Fog::Compute::Google.new(:google_project => "my-project", :google_application_default => true)
106
+ => #<Fog::Compute::Google::Real:32157700...
107
+ > connection.servers
108
+ => [ <Fog::Compute::Google::Server ... ]
109
+ ```
110
+
97
111
  #### SSH-ing into instances
98
112
 
99
113
  If you want to be able to bootstrap SSH-able instances, (using `servers.bootstrap`,) be sure you have a key in `~/.ssh/id_rsa` and `~/.ssh/id_rsa.pub`
@@ -9,8 +9,6 @@ PR when the test completes.
9
9
 
10
10
  In order to run the fog-google Concourse Pipeline you must have an existing
11
11
  [Concourse](http://concourse.ci) environment.
12
- See [Deploying Concourse on Google Compute Engine](https://github.com/cloudfoundry-incubator/bosh-google-cpi-release/blob/master/docs/concourse/README.md)
13
- for instructions.
14
12
 
15
13
  To deploy the pipeline:
16
14
 
@@ -28,13 +26,13 @@ file. See [Credentials Requirements](#credentials-requirements) for specific ins
28
26
  * Set the fog-google pipeline:
29
27
 
30
28
  ```
31
- fly -t fog-ci set-pipeline -p fog-google -c pipeline.yml -l credentials.yml
29
+ fly -t fog-ci set-pipeline -p pr-integration -c pipeline.yml -l credentials.yml
32
30
  ```
33
31
 
34
32
  * Unpause the fog-google pipeline:
35
33
 
36
34
  ```
37
- fly -t fog-ci unpause-pipeline -p fog-google
35
+ fly -t fog-ci unpause-pipeline -p pr-integration
38
36
  ```
39
37
 
40
38
  ## Credentials Requirements
@@ -42,18 +40,19 @@ fly -t fog-ci unpause-pipeline -p fog-google
42
40
  Several external pieces of authentication are needed for credentials.yml
43
41
 
44
42
  1. A JSON Service Account File for a service account with at least Editor access to the project.
45
- * To get a Service Account File, see [here](https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount)
43
+ * To get a Service Account File, see [here](https://developers.google.com/identity/protocols/OAuth2ServiceAccount#creatinganaccount)
46
44
  and create using the Project/Editor role.
47
45
 
48
46
  1. A [Github Access Token](https://github.com/blog/1509-personal-api-tokens) with at least
49
47
  `repo:status` access and a private key with push access to the `fog/fog-google` repositoy.
50
48
 
49
+ 1. A [Codecov.io](https://codecov.io/) token for tracking test coverage.
50
+
51
51
  These items are equivalent to your login credentials for their resources.
52
52
 
53
53
  ## Login Gotchas
54
54
 
55
- * If your Concourse deployment is using a self-signed certificate, use `--insecure` to
56
- trust the provided certificate.
55
+ * Our concourse pipeline is using GitHub auth, providing access to manipulate the pipeline to the members of the [fog-google team](https://github.com/orgs/fog/teams/fog-google), managed through the OAuth application managed by [fog-google bot](https://github.com/fog-google-bot).
57
56
 
58
57
  * If logging into a specific team, ie `fog-google`, use `--team-name fog-google` to specify that.
59
58
 
@@ -3,8 +3,6 @@
3
3
  codecov_token:
4
4
  # Google Cloud Platform project to run under
5
5
  google_project:
6
- # Google Compute Engine Service Account email
7
- google_client_email:
8
6
  # Google Compute Engine Service Account JSON
9
7
  google_json_key_data: |
10
8
  {
@@ -16,7 +16,6 @@ jobs:
16
16
  codecov_token: {{codecov_token}}
17
17
  google_project: {{google_project}}
18
18
  google_json_key_data: {{google_json_key_data}}
19
- google_client_email: {{google_client_email}}
20
19
  on_failure:
21
20
  put: pull-request
22
21
  params:
@@ -40,7 +39,6 @@ jobs:
40
39
  codecov_token: {{codecov_token}}
41
40
  google_project: {{google_project}}
42
41
  google_json_key_data: {{google_json_key_data}}
43
- google_client_email: {{google_client_email}}
44
42
  on_failure:
45
43
  put: pull-request
46
44
  params:
@@ -64,7 +62,6 @@ jobs:
64
62
  codecov_token: {{codecov_token}}
65
63
  google_project: {{google_project}}
66
64
  google_json_key_data: {{google_json_key_data}}
67
- google_client_email: {{google_client_email}}
68
65
  on_failure:
69
66
  put: pull-request
70
67
  params:
@@ -88,7 +85,6 @@ jobs:
88
85
  codecov_token: {{codecov_token}}
89
86
  google_project: {{google_project}}
90
87
  google_json_key_data: {{google_json_key_data}}
91
- google_client_email: {{google_client_email}}
92
88
  on_failure:
93
89
  put: pull-request
94
90
  params:
@@ -112,7 +108,6 @@ jobs:
112
108
  codecov_token: {{codecov_token}}
113
109
  google_project: {{google_project}}
114
110
  google_json_key_data: {{google_json_key_data}}
115
- google_client_email: {{google_client_email}}
116
111
  on_failure:
117
112
  put: pull-request
118
113
  params:
@@ -136,7 +131,6 @@ jobs:
136
131
  codecov_token: {{codecov_token}}
137
132
  google_project: {{google_project}}
138
133
  google_json_key_data: {{google_json_key_data}}
139
- google_client_email: {{google_client_email}}
140
134
  on_failure:
141
135
  put: pull-request
142
136
  params:
@@ -160,7 +154,6 @@ jobs:
160
154
  codecov_token: {{codecov_token}}
161
155
  google_project: {{google_project}}
162
156
  google_json_key_data: {{google_json_key_data}}
163
- google_client_email: {{google_client_email}}
164
157
  on_failure:
165
158
  put: pull-request
166
159
  params:
@@ -184,7 +177,6 @@ jobs:
184
177
  codecov_token: {{codecov_token}}
185
178
  google_project: {{google_project}}
186
179
  google_json_key_data: {{google_json_key_data}}
187
- google_client_email: {{google_client_email}}
188
180
  on_failure:
189
181
  put: pull-request
190
182
  params:
@@ -208,7 +200,6 @@ jobs:
208
200
  codecov_token: {{codecov_token}}
209
201
  google_project: {{google_project}}
210
202
  google_json_key_data: {{google_json_key_data}}
211
- google_client_email: {{google_client_email}}
212
203
  on_failure:
213
204
  put: pull-request
214
205
  params:
@@ -13,7 +13,6 @@ source ci/tasks/utils.sh
13
13
  popd > /dev/null
14
14
 
15
15
  check_param google_project
16
- check_param google_client_email
17
16
  check_param google_json_key_data
18
17
  check_param rake_task
19
18
  check_param codecov_token
@@ -23,7 +22,6 @@ echo $google_json_key_data > `pwd`/service_account_key.json
23
22
  cat >~/.fog <<EOL
24
23
  test:
25
24
  google_project: ${google_project}
26
- google_client_email: ${google_client_email}
27
25
  google_json_key_location: `pwd`/service_account_key.json
28
26
  EOL
29
27
 
@@ -10,7 +10,7 @@ run:
10
10
  path: src/fog-google/ci/tasks/run-int.sh
11
11
  params:
12
12
  rake_task: replace-me
13
+ codecov_token: replace-me
13
14
  google_project: replace-me
14
- google_client_email: replace-me
15
15
  google_json_key_data: |
16
16
  replace-me
@@ -10,7 +10,6 @@ module Fog
10
10
  :app_version,
11
11
  :google_auth,
12
12
  :google_client,
13
- :google_client_email,
14
13
  :google_client_options,
15
14
  :google_extra_global_projects,
16
15
  :google_key_location,
@@ -8,9 +8,9 @@ module Fog
8
8
  recognizes(
9
9
  :app_name,
10
10
  :app_version,
11
+ :google_application_default,
11
12
  :google_auth,
12
13
  :google_client,
13
- :google_client_email,
14
14
  :google_client_options,
15
15
  :google_key_location,
16
16
  :google_key_string,
@@ -8,8 +8,9 @@ module Fog
8
8
  recognizes(
9
9
  :app_name,
10
10
  :app_version,
11
+ :google_application_default,
12
+ :google_auth,
11
13
  :google_client,
12
- :google_client_email,
13
14
  :google_client_options,
14
15
  :google_key_location,
15
16
  :google_key_string,
@@ -8,9 +8,9 @@ module Fog
8
8
  recognizes(
9
9
  :app_name,
10
10
  :app_version,
11
+ :google_application_default,
11
12
  :google_auth,
12
13
  :google_client,
13
- :google_client_email,
14
14
  :google_client_options,
15
15
  :google_json_key_location,
16
16
  :google_json_key_string,
@@ -20,16 +20,13 @@ module Fog
20
20
  # Initializes the Google API Client
21
21
  #
22
22
  # @param [Hash] options Google API options
23
+ # @option options [Bool] :google_application_default Explicitly use application default credentials
23
24
  # @option options [Google::Auth|Signet] :google_auth Manually created authorization to use
24
- # @option options [String] :google_client_email A @developer.gserviceaccount.com email address to use
25
- # @option options [String] :google_key_location The location of a pkcs12 key file
26
- # @option options [String] :google_key_string The content of the pkcs12 key file
27
25
  # @option options [String] :google_json_key_location The location of a JSON key file
28
26
  # @option options [String] :google_json_key_string The content of the JSON key file
29
27
  # @option options [String] :google_api_scope_url The access scope URLs
30
28
  # @option options [String] :app_name The app name to set in the user agent
31
29
  # @option options [String] :app_version The app version to set in the user agent
32
- # @option options [Google::APIClient] :google_client Existing Google API Client
33
30
  # @option options [Hash] :google_client_options A hash to send additional options to Google API Client
34
31
  # @return [Google::APIClient] Google API Client
35
32
  # @raises [ArgumentError] If there is any missing argument
@@ -50,25 +47,7 @@ module Fog
50
47
  raise error
51
48
  end
52
49
 
53
- # Users can no longer provide their own clients due to rewrite of auth
54
- # in https://github.com/google/google-api-ruby-client/ version 0.9.
55
- if options[:google_client]
56
- raise ArgumentError.new("Deprecated argument no longer works: google_client")
57
- end
58
-
59
- # They can also no longer use pkcs12 files, because Google's new auth
60
- # library doesn't support them either.
61
- if options[:google_key_location]
62
- raise ArgumentError.new("Deprecated argument no longer works: google_key_location")
63
- end
64
- if options[:google_key_string]
65
- raise ArgumentError.new("Deprecated argument no longer works: google_key_string")
66
- end
67
-
68
- # Validate required arguments
69
- unless options[:google_api_scope_url]
70
- raise ArgumentError.new("Missing required arguments: google_api_scope_url")
71
- end
50
+ validate_client_options(options)
72
51
 
73
52
  application_name = "fog"
74
53
  unless options[:app_name].nil?
@@ -78,41 +57,21 @@ module Fog
78
57
  ::Google::Apis::ClientOptions.default.application_name = application_name
79
58
  ::Google::Apis::ClientOptions.default.application_version = Fog::Google::VERSION
80
59
 
81
- auth = nil
82
- if options[:google_json_key_location] || options[:google_json_key_string]
83
- if options[:google_json_key_location]
84
- json_key_location = File.expand_path(options[:google_json_key_location])
85
- json_key = File.open(json_key_location, "r", &:read)
86
- else
87
- json_key = options[:google_json_key_string]
88
- end
89
-
90
- json_key_hash = Fog::JSON.decode(json_key)
91
- unless json_key_hash.key?("client_email") || json_key_hash.key?("private_key")
92
- raise ArgumentError.new("Invalid Google JSON key")
93
- end
94
-
95
- options[:google_client_email] = json_key_hash["client_email"]
96
- unless options[:google_client_email]
97
- raise ArgumentError.new("Missing required arguments: google_client_email")
98
- end
60
+ if ENV["DEBUG"]
61
+ ::Google::Apis.logger = ::Logger.new(::STDERR)
62
+ ::Google::Apis.logger.level = ::Logger::DEBUG
63
+ end
99
64
 
100
- if ENV["DEBUG"]
101
- ::Google::Apis.logger = ::Logger.new(::STDERR)
102
- ::Google::Apis.logger.level = ::Logger::DEBUG
103
- end
65
+ auth = nil
104
66
 
105
- auth = ::Google::Auth::ServiceAccountCredentials.make_creds(
106
- :json_key_io => StringIO.new(json_key_hash.to_json),
107
- :scope => options[:google_api_scope_url]
108
- )
67
+ if options[:google_json_key_location] || options[:google_json_key_string]
68
+ auth = process_key_auth(options)
109
69
  elsif options[:google_auth]
110
70
  auth = options[:google_auth]
71
+ elsif options[:google_application_default]
72
+ auth = process_application_default_auth(options)
111
73
  else
112
- raise ArgumentError.new(
113
- "Missing required arguments: google_json_key_location, "\
114
- "google_json_key_string or google_auth"
115
- )
74
+ auth = process_fallback_auth(options)
116
75
  end
117
76
 
118
77
  ::Google::Apis::RequestOptions.default.authorization = auth
@@ -188,6 +147,102 @@ module Fog
188
147
 
189
148
  response
190
149
  end
150
+
151
+ private
152
+
153
+ # Helper method to process application default authentication
154
+ #
155
+ # @param [Hash] options - client options hash
156
+ # @return [Google::Auth::DefaultCredentials] - google auth object
157
+ def process_application_default_auth(options)
158
+ ::Google::Auth.get_application_default(options[:google_api_scope_url])
159
+ end
160
+
161
+ # Helper method to process fallback authentication
162
+ # Current fallback is application default authentication
163
+ #
164
+ # @param [Hash] options - client options hash
165
+ # @return [Google::Auth::DefaultCredentials] - google auth object
166
+ def process_fallback_auth(options)
167
+ Fog::Logger.warning(
168
+ "Didn't detect any client auth settings, " \
169
+ "trying to fall back to application default credentials..."
170
+ )
171
+ begin
172
+ return process_application_default_auth(options)
173
+ rescue
174
+ raise Fog::Errors::Error.new(
175
+ "Fallback auth failed, could not configure authentication for Fog client.\n" \
176
+ "Check your auth options, must be one of:\n" \
177
+ "- :google_json_key_location,\n" \
178
+ "- :google_json_key_string,\n" \
179
+ "- :google_auth,\n" \
180
+ "- :google_application_default,\n" \
181
+ "If credentials are valid - please, file a bug to fog-google." \
182
+ )
183
+ end
184
+ end
185
+
186
+ # Helper method to process key authentication
187
+ #
188
+ # @param [Hash] options - client options hash
189
+ # @return [Google::Auth::ServiceAccountCredentials] - google auth object
190
+ def process_key_auth(options)
191
+ if options[:google_json_key_location]
192
+ json_key = File.read(File.expand_path(options[:google_json_key_location]))
193
+ elsif options[:google_json_key_string]
194
+ json_key = options[:google_json_key_string]
195
+ end
196
+
197
+ validate_json_credentials(json_key)
198
+
199
+ ::Google::Auth::ServiceAccountCredentials.make_creds(
200
+ :json_key_io => StringIO.new(json_key),
201
+ :scope => options[:google_api_scope_url]
202
+ )
203
+ end
204
+
205
+ # Helper method to sort out deprecated and missing auth options
206
+ #
207
+ # @param [Hash] options - client options hash
208
+ def validate_client_options(options)
209
+ # Users can no longer provide their own clients due to rewrite of auth
210
+ # in https://github.com/google/google-api-ruby-client/ version 0.9.
211
+ if options[:google_client]
212
+ raise ArgumentError.new("Deprecated argument no longer works: google_client")
213
+ end
214
+
215
+ # They can also no longer use pkcs12 files, because Google's new auth
216
+ # library doesn't support them either.
217
+ if options[:google_key_location]
218
+ raise ArgumentError.new("Deprecated auth method no longer works: google_key_location")
219
+ end
220
+ if options[:google_key_string]
221
+ raise ArgumentError.new("Deprecated auth method no longer works: google_key_string")
222
+ end
223
+
224
+ # Google client email option is no longer needed
225
+ if options[:google_client_email]
226
+ Fog::Logger.deprecation("Argument no longer needed for auth: google_client_email")
227
+ end
228
+
229
+ # Validate required arguments
230
+ unless options[:google_api_scope_url]
231
+ raise ArgumentError.new("Missing required arguments: google_api_scope_url")
232
+ end
233
+ end
234
+
235
+ # Helper method to checks whether the necessary fields are present in
236
+ # JSON key credentials
237
+ #
238
+ # @param [String] json_key - Google json auth key string
239
+ def validate_json_credentials(json_key)
240
+ json_key_hash = Fog::JSON.decode(json_key)
241
+
242
+ unless json_key_hash.key?("client_email") || json_key_hash.key?("private_key")
243
+ raise ArgumentError.new("Invalid Google JSON key")
244
+ end
245
+ end
191
246
  end
192
247
  end
193
248
  end
@@ -8,9 +8,9 @@ module Fog
8
8
  recognizes(
9
9
  :app_name,
10
10
  :app_version,
11
+ :google_application_default,
11
12
  :google_auth,
12
13
  :google_client,
13
- :google_client_email,
14
14
  :google_client_options,
15
15
  :google_key_location,
16
16
  :google_key_string,
@@ -1,5 +1,5 @@
1
1
  module Fog
2
2
  module Google
3
- VERSION = "1.8.2".freeze
3
+ VERSION = "1.9.0".freeze
4
4
  end
5
5
  end
@@ -9,9 +9,9 @@ module Fog
9
9
  recognizes(
10
10
  :app_name,
11
11
  :app_version,
12
+ :google_application_default,
12
13
  :google_auth,
13
14
  :google_client,
14
- :google_client_email,
15
15
  :google_client_options,
16
16
  :google_key_location,
17
17
  :google_key_string,
@@ -27,13 +27,6 @@ class TestAuthentication < FogIntegrationTest
27
27
  assert_raises(ArgumentError) { Fog::Compute::Google.new(:google_project => nil) }
28
28
  end
29
29
 
30
- def test_raises_argument_error_when_google_client_email_is_missing
31
- assert_raises(ArgumentError) do
32
- Fog::Compute::Google.new(:google_client_email => nil,
33
- :google_json_key_location => nil)
34
- end # JSON key overrides google_client_email
35
- end
36
-
37
30
  def test_raises_argument_error_when_google_keys_are_given
38
31
  assert_raises(ArgumentError) do
39
32
  Fog::Compute::Google.new(:google_key_location => nil,
@@ -4,7 +4,6 @@ class UnitTestJsonRequests < MiniTest::Test
4
4
  def setup
5
5
  Fog.mock!
6
6
  @client = Fog::Storage.new(provider: "google",
7
- google_client_email: "",
8
7
  google_project: "",
9
8
  google_json_key_location: "")
10
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fog-google
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.2
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nat Welch
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2019-01-23 00:00:00.000000000 Z
12
+ date: 2019-03-22 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: fog-core
@@ -758,7 +758,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
758
758
  version: '0'
759
759
  requirements: []
760
760
  rubyforge_project:
761
- rubygems_version: 2.6.14
761
+ rubygems_version: 2.6.14.3
762
762
  signing_key:
763
763
  specification_version: 4
764
764
  summary: Module for the 'fog' gem to support Google.