fog-google 1.10.0 → 1.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -3
- data/CHANGELOG.md +20 -0
- data/README.md +37 -0
- data/fog-google.gemspec +2 -2
- data/lib/fog/compute/google.rb +0 -4
- data/lib/fog/compute/google/models/server.rb +3 -3
- data/lib/fog/compute/google/requests/set_server_metadata.rb +1 -1
- data/lib/fog/google/requests/pubsub/pull_subscription.rb +5 -1
- data/lib/fog/google/shared.rb +7 -2
- data/lib/fog/google/version.rb +1 -1
- data/lib/fog/storage/google_json.rb +4 -0
- data/lib/fog/storage/google_json/mock.rb +6 -0
- data/lib/fog/storage/google_json/real.rb +106 -3
- data/lib/fog/storage/google_json/utils.rb +1 -1
- data/lib/fog/storage/google_xml/requests/get_bucket.rb +0 -1
- data/lib/fog/storage/google_xml/requests/head_object.rb +7 -6
- data/tasks/changelog.rake +8 -1
- data/test/helpers/integration_test_helper.rb +15 -1
- data/test/integration/monitoring/test_timeseries.rb +11 -25
- data/test/integration/pubsub/test_pubsub_models.rb +3 -3
- data/test/integration/pubsub/test_pubsub_requests.rb +2 -2
- data/test/integration/sql/test_certs.rb +0 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e41bc807cc19b9984780ffcc9c253bac3ec3d13d
|
4
|
+
data.tar.gz: 69df7076d8eda3dfb5e22b1afcdb2ef97ee16e43
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: af8cff6ac06cab566a31db97eb6b2065c53a74be8a77e133b4816f132a9b8079d7ff01e0031a393120bc3c98e8d680371ebfb07c72c5ddabded8f96d6f4d8b54
|
7
|
+
data.tar.gz: f81555df397158c969d85dd2b3215842e46f2e2217371e54fae1125fef349b76ea8d02c8218ebe3dc9ba04c6965e9c93ba96db2f501d070dfaf060a772badc07
|
data/.rubocop.yml
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# Fog custom enforced styles
|
2
|
-
|
2
|
+
Layout/LineLength:
|
3
3
|
Enabled: false
|
4
4
|
|
5
5
|
Style/ConditionalAssignment:
|
@@ -94,7 +94,7 @@ Naming/PredicateName:
|
|
94
94
|
- is_
|
95
95
|
- has_
|
96
96
|
- have_
|
97
|
-
|
97
|
+
ForbiddenPrefixes:
|
98
98
|
- is_
|
99
99
|
Exclude:
|
100
100
|
- spec/**/*
|
@@ -246,7 +246,7 @@ Style/WhenThen:
|
|
246
246
|
Lint/EachWithObjectArgument:
|
247
247
|
Description: Check for immutable argument given to each_with_object.
|
248
248
|
Enabled: true
|
249
|
-
Lint/
|
249
|
+
Lint/SuppressedException:
|
250
250
|
Description: Don't suppress exception.
|
251
251
|
StyleGuide: https://github.com/bbatsov/ruby-style-guide#dont-hide-exceptions
|
252
252
|
Enabled: false
|
data/CHANGELOG.md
CHANGED
@@ -6,6 +6,26 @@ This project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html
|
|
6
6
|
|
7
7
|
## Next
|
8
8
|
|
9
|
+
## 1.11.0
|
10
|
+
|
11
|
+
### User-facing
|
12
|
+
|
13
|
+
#### Added
|
14
|
+
|
15
|
+
- \#503 - Add fallback URL signing mechanism via IAM SignBlob API [temikus]
|
16
|
+
|
17
|
+
#### Fixed
|
18
|
+
|
19
|
+
- \#498 Add `:idempotent` flag to Fog::Storage::GoogleXML::Real#head_object, fixing
|
20
|
+
`Excon::Error::Socket: end of file reached (EOFError)` in certain scenarios, see \#416 [temikus]
|
21
|
+
- \#500 Set default options automatically if missing in `Pubsub#pull_subscription`
|
22
|
+
|
23
|
+
### Development changes
|
24
|
+
|
25
|
+
#### Fixed
|
26
|
+
|
27
|
+
- \#501 DRY'ed up the retry methods in monitoring tests [temikus]
|
28
|
+
- \#500 Cleanup unneeded constants in Server model, fix flaky PubSub tests [temikus]
|
9
29
|
|
10
30
|
## 1.10.0
|
11
31
|
|
data/README.md
CHANGED
@@ -108,6 +108,43 @@ defined:
|
|
108
108
|
=> [ <Fog::Compute::Google::Server ... ]
|
109
109
|
```
|
110
110
|
|
111
|
+
#### CarrierWave integration
|
112
|
+
|
113
|
+
It is common to integrate Fog with Carrierwave. Here's a minimal config that's commonly put in `config/initializers/carrierwave.rb`:
|
114
|
+
|
115
|
+
```
|
116
|
+
CarrierWave.configure do |config|
|
117
|
+
config.fog_provider = 'fog/google'
|
118
|
+
config.fog_credentials = {
|
119
|
+
provider: 'Google',
|
120
|
+
google_project: Rails.application.secrets.google_cloud_storage_project_name,
|
121
|
+
google_json_key_string: Rails.application.secrets.google_cloud_storage_credential_content
|
122
|
+
# can optionally use google_json_key_location if using an actual file;
|
123
|
+
}
|
124
|
+
config.fog_directory = Rails.application.secrets.google_cloud_storage_bucket_name
|
125
|
+
end
|
126
|
+
```
|
127
|
+
|
128
|
+
This needs a corresponding secret in `config/secrets.yml`, e.g.:
|
129
|
+
|
130
|
+
```
|
131
|
+
development:
|
132
|
+
google_cloud_storage_project_name: your-project-name
|
133
|
+
google_cloud_storage_credential_content: '{
|
134
|
+
"type": "service_account",
|
135
|
+
"project_id": "your-project-name",
|
136
|
+
"private_key_id": "REDACTED",
|
137
|
+
"private_key": "-----BEGIN PRIVATE KEY-----REDACTED-----END PRIVATE KEY-----\n",
|
138
|
+
"client_email": "REDACTED@your-project-name.iam.gserviceaccount.com",
|
139
|
+
"client_id": "REDACTED",
|
140
|
+
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
141
|
+
"token_uri": "https://accounts.google.com/o/oauth2/token",
|
142
|
+
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
143
|
+
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/REDACTED%40your-project-name.iam.gserviceaccount.com"
|
144
|
+
}'
|
145
|
+
google_cloud_storage_bucket_name: your-bucket-name
|
146
|
+
```
|
147
|
+
|
111
148
|
#### SSH-ing into instances
|
112
149
|
|
113
150
|
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`
|
data/fog-google.gemspec
CHANGED
@@ -25,9 +25,9 @@ Gem::Specification.new do |spec|
|
|
25
25
|
spec.add_dependency "fog-json", "~> 1.2"
|
26
26
|
spec.add_dependency "fog-xml", "~> 0.1.0"
|
27
27
|
|
28
|
-
# Hard Requirement as of 1.0
|
29
28
|
spec.add_dependency "google-api-client", ">= 0.32", "< 0.34"
|
30
|
-
|
29
|
+
spec.add_dependency "google-cloud-env", "~> 1.2"
|
30
|
+
|
31
31
|
# Debugger
|
32
32
|
spec.add_development_dependency "pry"
|
33
33
|
|
data/lib/fog/compute/google.rb
CHANGED
@@ -27,10 +27,6 @@ module Fog
|
|
27
27
|
https://www.googleapis.com/auth/ndev.cloudman
|
28
28
|
https://www.googleapis.com/auth/cloud-platform).freeze
|
29
29
|
GOOGLE_COMPUTE_DEFAULT_NETWORK = "default".freeze
|
30
|
-
# TODO: Do we need those constants?
|
31
|
-
RUNNING = "RUNNING".freeze
|
32
|
-
PROVISIONING = "PROVISIONING".freeze
|
33
|
-
STAGING = "STAGING".freeze
|
34
30
|
|
35
31
|
request_path "fog/compute/google/requests"
|
36
32
|
request :add_backend_service_backends
|
@@ -447,7 +447,7 @@ module Fog
|
|
447
447
|
#
|
448
448
|
# @return [TrueClass or FalseClass]
|
449
449
|
def provisioning?
|
450
|
-
status == PROVISIONING
|
450
|
+
status == "PROVISIONING"
|
451
451
|
end
|
452
452
|
|
453
453
|
# Check if instance is staging. On staging vs. provisioning difference:
|
@@ -455,7 +455,7 @@ module Fog
|
|
455
455
|
#
|
456
456
|
# @return [TrueClass or FalseClass]
|
457
457
|
def staging?
|
458
|
-
status == STAGING
|
458
|
+
status == "STAGING"
|
459
459
|
end
|
460
460
|
|
461
461
|
# Check if instance is stopped.
|
@@ -469,7 +469,7 @@ module Fog
|
|
469
469
|
#
|
470
470
|
# @return [TrueClass or FalseClass]
|
471
471
|
def ready?
|
472
|
-
status == RUNNING
|
472
|
+
status == "RUNNING"
|
473
473
|
end
|
474
474
|
|
475
475
|
def zone_name
|
@@ -21,7 +21,7 @@ module Fog
|
|
21
21
|
# fingerprint = instance.metadata['fingerprint']
|
22
22
|
# @param [Hash] metadata A new metadata object
|
23
23
|
# Should have the following structure:
|
24
|
-
# {
|
24
|
+
# {'foo' => 'bar', 'baz'=>'foo'}
|
25
25
|
#
|
26
26
|
# @returns [::Google::Apis::ComputeV1::Operation] set operation
|
27
27
|
def set_server_metadata(instance, zone, fingerprint, metadata_items = [])
|
@@ -16,7 +16,11 @@ module Fog
|
|
16
16
|
# @option options [Number] :max_messages maximum number of messages to
|
17
17
|
# retrieve (defaults to 10)
|
18
18
|
# @see https://cloud.google.com/pubsub/reference/rest/v1/projects.subscriptions/pull
|
19
|
-
def pull_subscription(subscription, options = {
|
19
|
+
def pull_subscription(subscription, options = {})
|
20
|
+
defaults = { :return_immediately => true,
|
21
|
+
:max_messages => 10 }
|
22
|
+
options = defaults.merge(options)
|
23
|
+
|
20
24
|
pull_request = ::Google::Apis::PubsubV1::PullRequest.new(
|
21
25
|
:return_immediately => options[:return_immediately],
|
22
26
|
:max_messages => options[:max_messages]
|
data/lib/fog/google/shared.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require "google-cloud-env"
|
2
|
+
|
1
3
|
module Fog
|
2
4
|
module Google
|
3
5
|
module Shared
|
@@ -14,6 +16,9 @@ module Fog
|
|
14
16
|
@project = project
|
15
17
|
@api_version = api_version
|
16
18
|
@api_url = base_url + api_version + "/projects/"
|
19
|
+
# google-cloud-env allows us to figure out which GCP runtime we're running in and query metadata
|
20
|
+
# e.g. whether we're running in GCE/GKE/AppEngine or what region the instance is running in
|
21
|
+
@google_cloud_env = ::Google::Cloud::Env.get
|
17
22
|
end
|
18
23
|
|
19
24
|
##
|
@@ -33,14 +38,14 @@ module Fog
|
|
33
38
|
def initialize_google_client(options)
|
34
39
|
# NOTE: loaded here to avoid requiring this as a core Fog dependency
|
35
40
|
begin
|
36
|
-
#
|
37
|
-
# of funky things, like this nonsense.
|
41
|
+
# TODO: google-api-client is in gemspec now, re-assess if this initialization logic is still needed
|
38
42
|
require "google/apis/monitoring_#{Fog::Google::Monitoring::GOOGLE_MONITORING_API_VERSION}"
|
39
43
|
require "google/apis/compute_#{Fog::Compute::Google::GOOGLE_COMPUTE_API_VERSION}"
|
40
44
|
require "google/apis/dns_#{Fog::DNS::Google::GOOGLE_DNS_API_VERSION}"
|
41
45
|
require "google/apis/pubsub_#{Fog::Google::Pubsub::GOOGLE_PUBSUB_API_VERSION}"
|
42
46
|
require "google/apis/sqladmin_#{Fog::Google::SQL::GOOGLE_SQL_API_VERSION}"
|
43
47
|
require "google/apis/storage_#{Fog::Storage::GoogleJSON::GOOGLE_STORAGE_JSON_API_VERSION}"
|
48
|
+
require "google/apis/iamcredentials_#{Fog::Storage::GoogleJSON::GOOGLE_STORAGE_JSON_IAM_API_VERSION}"
|
44
49
|
require "googleauth"
|
45
50
|
rescue LoadError => error
|
46
51
|
Fog::Errors::Error.new("Please install the google-api-client (>= 0.9) gem before using this provider")
|
data/lib/fog/google/version.rb
CHANGED
@@ -27,6 +27,10 @@ module Fog
|
|
27
27
|
GOOGLE_STORAGE_JSON_BASE_URL = "https://www.googleapis.com/storage/".freeze
|
28
28
|
GOOGLE_STORAGE_BUCKET_BASE_URL = "https://storage.googleapis.com/".freeze
|
29
29
|
|
30
|
+
# Version of IAM API used for blob signing, see Fog::Storage::GoogleJSON::Real#iam_signer
|
31
|
+
GOOGLE_STORAGE_JSON_IAM_API_VERSION = "v1".freeze
|
32
|
+
GOOGLE_STORAGE_JSON_IAM_API_SCOPE_URLS = %w(https://www.googleapis.com/auth/devstorage.full_control).freeze
|
33
|
+
|
30
34
|
# TODO: Come up with a way to only request a subset of permissions.
|
31
35
|
# https://cloud.google.com/storage/docs/json_api/v1/how-tos/authorizing
|
32
36
|
GOOGLE_STORAGE_JSON_API_SCOPE_URLS = %w(https://www.googleapis.com/auth/devstorage.full_control).freeze
|
@@ -10,11 +10,17 @@ module Fog
|
|
10
10
|
def initialize(options = {})
|
11
11
|
shared_initialize(options[:google_project], GOOGLE_STORAGE_JSON_API_VERSION, GOOGLE_STORAGE_JSON_BASE_URL)
|
12
12
|
@client = MockClient.new('test')
|
13
|
+
@storage_json = MockClient.new('test')
|
14
|
+
@iam_service = MockClient.new('test')
|
13
15
|
end
|
14
16
|
|
15
17
|
def signature(_params)
|
16
18
|
"foo"
|
17
19
|
end
|
20
|
+
|
21
|
+
def google_access_id
|
22
|
+
"my-account@project.iam.gserviceaccount"
|
23
|
+
end
|
18
24
|
end
|
19
25
|
end
|
20
26
|
end
|
@@ -13,7 +13,14 @@ module Fog
|
|
13
13
|
options[:google_api_scope_url] = GOOGLE_STORAGE_JSON_API_SCOPE_URLS.join(" ")
|
14
14
|
@host = options[:host] || "storage.googleapis.com"
|
15
15
|
|
16
|
+
# TODO(temikus): Do we even need this client?
|
16
17
|
@client = initialize_google_client(options)
|
18
|
+
# IAM client used for SignBlob API
|
19
|
+
@iam_service = ::Google::Apis::IamcredentialsV1::IAMCredentialsService.new
|
20
|
+
apply_client_options(@iam_service, {
|
21
|
+
google_api_scope_url: GOOGLE_STORAGE_JSON_IAM_API_SCOPE_URLS.join(" ")
|
22
|
+
})
|
23
|
+
|
17
24
|
@storage_json = ::Google::Apis::StorageV1::StorageService.new
|
18
25
|
apply_client_options(@storage_json, options)
|
19
26
|
|
@@ -56,12 +63,108 @@ DATA
|
|
56
63
|
canonical_resource.chop!
|
57
64
|
string_to_sign << canonical_resource.to_s
|
58
65
|
|
59
|
-
|
60
|
-
|
61
|
-
|
66
|
+
# TODO(temikus): make signer configurable or add ability to supply your own via lambda
|
67
|
+
if !@storage_json.authorization.signing_key.nil?
|
68
|
+
signed_string = default_signer(string_to_sign)
|
69
|
+
else
|
70
|
+
# If client doesn't contain signing key attempt to auth via IAM SignBlob API
|
71
|
+
signed_string = iam_signer(string_to_sign)
|
72
|
+
end
|
62
73
|
|
63
74
|
Base64.encode64(signed_string).chomp!
|
64
75
|
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def google_access_id
|
80
|
+
@google_access_id ||= get_google_access_id
|
81
|
+
end
|
82
|
+
|
83
|
+
##
|
84
|
+
# Fetches the google service account name
|
85
|
+
#
|
86
|
+
# @return [String] Service account name, typically needed for GoogleAccessId, e.g.
|
87
|
+
# my-account@project.iam.gserviceaccount
|
88
|
+
# @raises [Fog::Errors::Error] If authorisation is incorrect or inapplicable for current action
|
89
|
+
def get_google_access_id
|
90
|
+
if @storage_json.authorization.is_a?(::Google::Auth::UserRefreshCredentials)
|
91
|
+
raise Fog::Errors::Error.new("User / Application Default Credentials are not supported for storage"\
|
92
|
+
"url signing, please use a service account or metadata authentication.")
|
93
|
+
end
|
94
|
+
|
95
|
+
if !@storage_json.authorization.issuer.nil?
|
96
|
+
return @storage_json.authorization.issuer
|
97
|
+
else
|
98
|
+
get_access_id_from_metadata
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
##
|
103
|
+
# Attempts to fetch the google service account name from metadata using Google::Cloud::Env
|
104
|
+
#
|
105
|
+
# @return [String] Service account name, typically needed for GoogleAccessId, e.g.
|
106
|
+
# my-account@project.iam.gserviceaccount
|
107
|
+
# @raises [Fog::Errors::Error] If Metadata service is not available or returns an invalid response
|
108
|
+
def get_access_id_from_metadata
|
109
|
+
if @google_cloud_env.metadata?
|
110
|
+
access_id = @google_cloud_env.lookup_metadata("instance", "service-accounts/default/email")
|
111
|
+
else
|
112
|
+
raise Fog::Errors::Error.new("Metadata service not available, unable to retrieve service account info.")
|
113
|
+
end
|
114
|
+
|
115
|
+
if access_id.nil?
|
116
|
+
raise Fog::Errors::Error.new("Metadata service found but didn't return data." \
|
117
|
+
"Please file a bug: https://github.com/fog/fog-google")
|
118
|
+
end
|
119
|
+
|
120
|
+
return access_id
|
121
|
+
end
|
122
|
+
|
123
|
+
##
|
124
|
+
# Default url signer using service account keys
|
125
|
+
#
|
126
|
+
# @param [String] string_to_sign Special collection of headers and options for V2 storage signing, e.g.:
|
127
|
+
#
|
128
|
+
# StringToSign = HTTP_Verb + "\n" +
|
129
|
+
# Content_MD5 + "\n" +
|
130
|
+
# Content_Type + "\n" +
|
131
|
+
# Expires + "\n" +
|
132
|
+
# Canonicalized_Extension_Headers +
|
133
|
+
# Canonicalized_Resource
|
134
|
+
#
|
135
|
+
# See https://cloud.google.com/storage/docs/access-control/signed-urls-v2
|
136
|
+
# @return [String] Signature binary blob
|
137
|
+
def default_signer(string_to_sign)
|
138
|
+
key = OpenSSL::PKey::RSA.new(@storage_json.authorization.signing_key)
|
139
|
+
digest = OpenSSL::Digest::SHA256.new
|
140
|
+
return key.sign(digest, string_to_sign)
|
141
|
+
end
|
142
|
+
|
143
|
+
##
|
144
|
+
# Fallback URL signer using the IAM SignServiceAccountBlob API, see
|
145
|
+
# Google::Apis::IamcredentialsV1::IAMCredentialsService#sign_service_account_blob
|
146
|
+
#
|
147
|
+
# @param [String] string_to_sign Special collection of headers and options for V2 storage signing, e.g.:
|
148
|
+
#
|
149
|
+
# StringToSign = HTTP_Verb + "\n" +
|
150
|
+
# Content_MD5 + "\n" +
|
151
|
+
# Content_Type + "\n" +
|
152
|
+
# Expires + "\n" +
|
153
|
+
# Canonicalized_Extension_Headers +
|
154
|
+
# Canonicalized_Resource
|
155
|
+
#
|
156
|
+
# See https://cloud.google.com/storage/docs/access-control/signed-urls-v2
|
157
|
+
# @return [String] Signature binary blob
|
158
|
+
def iam_signer(string_to_sign)
|
159
|
+
request = {
|
160
|
+
"payload": string_to_sign
|
161
|
+
}
|
162
|
+
|
163
|
+
resource = "projects/-/serviceAccounts/#{google_access_id}"
|
164
|
+
response = @iam_service.sign_service_account_blob resource, request, {}
|
165
|
+
|
166
|
+
return response.signed_blob
|
167
|
+
end
|
65
168
|
end
|
66
169
|
end
|
67
170
|
end
|
@@ -27,7 +27,7 @@ module Fog
|
|
27
27
|
query = filtered.map { |k, v| [k.to_s, Fog::Google.escape(v)].join("=") }
|
28
28
|
end
|
29
29
|
|
30
|
-
query << "GoogleAccessId=#{
|
30
|
+
query << "GoogleAccessId=#{google_access_id}"
|
31
31
|
query << "Signature=#{CGI.escape(signature(params))}"
|
32
32
|
query << "Expires=#{params[:headers]['Date']}"
|
33
33
|
"#{params[:host]}/#{params[:path]}?#{query.join('&')}"
|
@@ -33,12 +33,13 @@ module Fog
|
|
33
33
|
headers["If-Modified-Since"] = Fog::Time.at(options["If-Modified-Since"].to_i).to_date_header if options["If-Modified-Since"]
|
34
34
|
headers["If-Unmodified-Since"] = Fog::Time.at(options["If-Unmodified-Since"].to_i).to_date_header if options["If-Modified-Since"]
|
35
35
|
headers.merge!(options)
|
36
|
-
request(:expects
|
37
|
-
:headers
|
38
|
-
:host
|
39
|
-
:
|
40
|
-
:
|
41
|
-
:
|
36
|
+
request(:expects => [200, 206],
|
37
|
+
:headers => headers,
|
38
|
+
:host => "#{bucket_name}.#{@host}",
|
39
|
+
:idempotent => true,
|
40
|
+
:method => "HEAD",
|
41
|
+
:path => Fog::Google.escape(object_name),
|
42
|
+
:query => query)
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
data/tasks/changelog.rake
CHANGED
@@ -20,11 +20,18 @@ end
|
|
20
20
|
|
21
21
|
# Extracts all changes that have been made after the latest pushed tag
|
22
22
|
def changes_since_last_tag
|
23
|
-
`git --no-pager log $(git describe --tags --abbrev=0)..HEAD --
|
23
|
+
`git --no-pager log $(git describe --tags --abbrev=0)..HEAD --grep="Merge" --pretty=format:"%t - %s%n%b%n"`
|
24
|
+
end
|
25
|
+
|
26
|
+
# Extracts all github users contributed since last tag
|
27
|
+
def users_since_last_tag
|
28
|
+
`git --no-pager log $(git describe --tags --abbrev=0)..HEAD --grep="Merge" --pretty=format:"%s" | cut -d' ' -f 6 | cut -d/ -f1 | uniq`
|
24
29
|
end
|
25
30
|
|
26
31
|
namespace :changelog do
|
27
32
|
task :generate do
|
28
33
|
insert_after_line("CHANGELOG.md", changes_since_last_tag, /^## Next/)
|
34
|
+
printf("Users contributed since last release:\n")
|
35
|
+
printf(users_since_last_tag)
|
29
36
|
end
|
30
37
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require "helpers/test_helper"
|
2
2
|
require "helpers/test_collection"
|
3
|
+
require "retriable"
|
3
4
|
|
4
5
|
# Use :test credentials in ~/.fog for live integration testing
|
5
6
|
# XXX not sure if this will work on Travis CI or not
|
@@ -22,7 +23,7 @@ TEST_IMAGE_FAMILY = "debian-9".freeze
|
|
22
23
|
|
23
24
|
# XXX This depends on a public image in gs://fog-test-bucket; there may be a better way to do this
|
24
25
|
# The image was created like so: https://cloud.google.com/compute/docs/images#export_an_image_to_google_cloud_storage
|
25
|
-
TEST_RAW_DISK_SOURCE = "
|
26
|
+
TEST_RAW_DISK_SOURCE = "https://storage.googleapis.com/fog-testing-bucket/fog-test-raw-disk-source.image.tar.gz".freeze
|
26
27
|
|
27
28
|
TEST_SQL_TIER = "db-n1-standard-1".freeze
|
28
29
|
TEST_SQL_REGION = TEST_REGION
|
@@ -87,8 +88,21 @@ wLjafhPTSAIS0jijglJ7uzaSbFUW11fw1/EIqIFNe0R0Xf9lsyPxFA==
|
|
87
88
|
-----END RSA PRIVATE KEY-----
|
88
89
|
KEY
|
89
90
|
|
91
|
+
# Retry module config - standard retriable gem settings
|
92
|
+
# see: https://github.com/kamui/retriable
|
93
|
+
RETRIABLE_TRIES = 3
|
94
|
+
RETRIABLE_BASE_INTERVAL = 50
|
95
|
+
|
90
96
|
class FogIntegrationTest < MiniTest::Test
|
91
97
|
def namespaced_name
|
92
98
|
"#{self.class}_#{name}"
|
93
99
|
end
|
100
|
+
|
101
|
+
def retry_on(klass)
|
102
|
+
Retriable.retriable(on: klass,
|
103
|
+
tries: RETRIABLE_TRIES,
|
104
|
+
base_interval: RETRIABLE_BASE_INTERVAL) do
|
105
|
+
yield
|
106
|
+
end
|
107
|
+
end
|
94
108
|
end
|
@@ -1,12 +1,11 @@
|
|
1
1
|
require "helpers/integration_test_helper"
|
2
|
-
require "retriable"
|
3
2
|
|
4
3
|
class TestMetricDescriptors < FogIntegrationTest
|
5
|
-
#
|
6
|
-
# metric propagation (sometimes 80+ seconds) and client
|
7
|
-
# Google::Apis::ClientError: badRequest if the metric
|
8
|
-
|
9
|
-
|
4
|
+
# This module has a decent amount of retry wrappers as the Stackdriver API
|
5
|
+
# can be quite slow with metric propagation (sometimes 80+ seconds) and client
|
6
|
+
# returning errors, e.g. Google::Apis::ClientError: badRequest if the metric
|
7
|
+
# hasn't yet been created instead of a 404.
|
8
|
+
|
10
9
|
TEST_METRIC_PREFIX = "custom.googleapis.com/fog-google-test/timeseries".freeze
|
11
10
|
LABEL_DESCRIPTORS = [
|
12
11
|
{
|
@@ -51,10 +50,7 @@ class TestMetricDescriptors < FogIntegrationTest
|
|
51
50
|
assert_empty(resp.to_h)
|
52
51
|
|
53
52
|
# Wait for metric to be created
|
54
|
-
|
55
|
-
Retriable.retriable(on: Google::Apis::ClientError,
|
56
|
-
tries: RETRIABLE_TRIES,
|
57
|
-
base_interval: RETRIABLE_BASE_INTERVAL) do
|
53
|
+
retry_on(Google::Apis::ClientError) do
|
58
54
|
@client.list_timeseries(
|
59
55
|
:filter => "metric.type = \"#{metric_type}\"",
|
60
56
|
:interval => {
|
@@ -67,9 +63,7 @@ class TestMetricDescriptors < FogIntegrationTest
|
|
67
63
|
).time_series
|
68
64
|
end
|
69
65
|
|
70
|
-
series =
|
71
|
-
tries: RETRIABLE_TRIES,
|
72
|
-
base_interval: RETRIABLE_BASE_INTERVAL) do
|
66
|
+
series = retry_on(Google::Apis::ClientError) do
|
73
67
|
@client.timeseries_collection.all(
|
74
68
|
:filter => "metric.type = \"#{metric_type}\"",
|
75
69
|
:interval => {
|
@@ -115,9 +109,7 @@ class TestMetricDescriptors < FogIntegrationTest
|
|
115
109
|
_some_timeseries(start_time, metric_type, labels)
|
116
110
|
end
|
117
111
|
|
118
|
-
|
119
|
-
tries: RETRIABLE_TRIES,
|
120
|
-
base_interval: RETRIABLE_BASE_INTERVAL) do
|
112
|
+
retry_on(Google::Apis::ServerError) do
|
121
113
|
@client.create_timeseries(:timeseries => timeseries)
|
122
114
|
end
|
123
115
|
interval = {
|
@@ -132,9 +124,7 @@ class TestMetricDescriptors < FogIntegrationTest
|
|
132
124
|
# Wait for metric to be created
|
133
125
|
# Retriable is used instead of wait_for due to API client returning Google::Apis::ClientError: badRequest if the
|
134
126
|
# metric hasn't yet been created
|
135
|
-
|
136
|
-
tries: RETRIABLE_TRIES,
|
137
|
-
base_interval: RETRIABLE_BASE_INTERVAL) do
|
127
|
+
retry_on(Google::Apis::ClientError) do
|
138
128
|
@client.list_timeseries(
|
139
129
|
:filter => "metric.type = \"#{metric_type}\"",
|
140
130
|
:interval => interval
|
@@ -142,9 +132,7 @@ class TestMetricDescriptors < FogIntegrationTest
|
|
142
132
|
end
|
143
133
|
|
144
134
|
# Test page size
|
145
|
-
resp =
|
146
|
-
tries: RETRIABLE_TRIES,
|
147
|
-
base_interval: RETRIABLE_BASE_INTERVAL) do
|
135
|
+
resp = retry_on(Google::Apis::ClientError) do
|
148
136
|
@client.list_timeseries(
|
149
137
|
:filter => "metric.type = \"#{metric_type}\"",
|
150
138
|
:interval => interval,
|
@@ -170,9 +158,7 @@ class TestMetricDescriptors < FogIntegrationTest
|
|
170
158
|
"expected different timeseries when using page_token")
|
171
159
|
|
172
160
|
# Test filter
|
173
|
-
series =
|
174
|
-
tries: RETRIABLE_TRIES,
|
175
|
-
base_interval: RETRIABLE_BASE_INTERVAL) do
|
161
|
+
series = retry_on(Google::Apis::ClientError) do
|
176
162
|
@client.timeseries_collection.all(
|
177
163
|
:filter => %[
|
178
164
|
metric.type = "#{metric_type}" AND
|
@@ -102,7 +102,7 @@ class TestPubsubModels < PubSubShared
|
|
102
102
|
:topic => some_topic_name)
|
103
103
|
@client.topics.get(some_topic_name).publish(["data" => message_bytes])
|
104
104
|
|
105
|
-
result = subscription.pull
|
105
|
+
result = subscription.pull(:return_immediately => false)
|
106
106
|
assert_operator(result.length, :>, 0)
|
107
107
|
|
108
108
|
contained = result.any? { |received| received.message[:data] == message_bytes }
|
@@ -115,7 +115,7 @@ class TestPubsubModels < PubSubShared
|
|
115
115
|
:topic => some_topic_name)
|
116
116
|
@client.topics.get(some_topic_name).publish(["data" => Base64.strict_encode64("some message")])
|
117
117
|
|
118
|
-
result = subscription.pull
|
118
|
+
result = subscription.pull(:return_immediately => false)
|
119
119
|
assert_operator(result.length, :>, 0)
|
120
120
|
|
121
121
|
subscription.acknowledge([result[0].ack_id])
|
@@ -127,7 +127,7 @@ class TestPubsubModels < PubSubShared
|
|
127
127
|
:topic => some_topic_name)
|
128
128
|
@client.topics.get(some_topic_name).publish(["data" => Base64.strict_encode64("some message")])
|
129
129
|
|
130
|
-
result = subscription.pull
|
130
|
+
result = subscription.pull(:return_immediately => false)
|
131
131
|
assert_operator(result.length, :>, 0)
|
132
132
|
|
133
133
|
result[0].acknowledge
|
@@ -86,7 +86,7 @@ class TestPubsubRequests < PubSubShared
|
|
86
86
|
@client.create_subscription(subscription_name, some_topic_name)
|
87
87
|
@client.publish_topic(some_topic_name, [:data => message_bytes])
|
88
88
|
|
89
|
-
result = @client.pull_subscription(subscription_name)
|
89
|
+
result = @client.pull_subscription(subscription_name, {:return_immediately => false})
|
90
90
|
|
91
91
|
contained = result.received_messages.any? { |received| received.message.data == message_bytes }
|
92
92
|
assert_equal(true, contained, "sent messsage not contained within pulled responses")
|
@@ -96,7 +96,7 @@ class TestPubsubRequests < PubSubShared
|
|
96
96
|
subscription_name = new_subscription_name
|
97
97
|
@client.create_subscription(subscription_name, some_topic_name)
|
98
98
|
@client.publish_topic(some_topic_name, [:data => Base64.strict_encode64("some message")])
|
99
|
-
pull_result = @client.pull_subscription(subscription_name)
|
99
|
+
pull_result = @client.pull_subscription(subscription_name, {:return_immediately => false})
|
100
100
|
assert_operator(pull_result.received_messages.length, :>, 0)
|
101
101
|
|
102
102
|
@client.acknowledge_subscription(subscription_name,
|
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.
|
4
|
+
version: 1.11.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: 2020-
|
12
|
+
date: 2020-08-13 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fog-core
|
@@ -73,6 +73,20 @@ dependencies:
|
|
73
73
|
- - "<"
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0.34'
|
76
|
+
- !ruby/object:Gem::Dependency
|
77
|
+
name: google-cloud-env
|
78
|
+
requirement: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.2'
|
83
|
+
type: :runtime
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '1.2'
|
76
90
|
- !ruby/object:Gem::Dependency
|
77
91
|
name: pry
|
78
92
|
requirement: !ruby/object:Gem::Requirement
|