google-cloud-env 1.6.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright 2023 Google LLC
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # https://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+
17
+
18
+ module Google
19
+ module Cloud
20
+ class Env
21
+ ##
22
+ # Access to system environment variables.
23
+ #
24
+ # This is a hashlike object that controls access to environment variable
25
+ # data. It supports temporarily changing the data source (i.e. swapping
26
+ # ::ENV out for a different set of data) for mocking.
27
+ #
28
+ class Variables
29
+ ##
30
+ # Create an enviroment variables access object. This is initially
31
+ # backed by the actual environment variables (i.e. ENV).
32
+ #
33
+ def initialize
34
+ @backing_data = ::ENV
35
+ end
36
+
37
+ ##
38
+ # Fetch the given environment variable from the backing data.
39
+ #
40
+ # @param key [String]
41
+ # @return [String,nil]
42
+ #
43
+ def [] key
44
+ @backing_data[key.to_s]
45
+ end
46
+ alias get []
47
+
48
+ ##
49
+ # The backing data is a hash or hash-like object that represents the
50
+ # environment variable data. This can either be the actual environment
51
+ # variables object (i.e. ENV) or a substitute hash used for mocking.
52
+ #
53
+ # @return [Hash{String=>String}]
54
+ #
55
+ attr_accessor :backing_data
56
+
57
+ ##
58
+ # Run the given block with the backing data replaced with the given
59
+ # hash. The original backing data is restored afterward. This is used
60
+ # for debugging/testing/mocking.
61
+ #
62
+ # @param temp_backing_data [Hash{String=>String}]
63
+ #
64
+ def with_backing_data temp_backing_data
65
+ old_backing_data = @backing_data
66
+ begin
67
+ @backing_data = temp_backing_data
68
+ yield
69
+ ensure
70
+ @backing_data = old_backing_data
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -16,7 +16,11 @@
16
16
  module Google
17
17
  module Cloud
18
18
  class Env
19
- VERSION = "1.6.0".freeze
19
+ ##
20
+ # Library version
21
+ # @return [String]
22
+ #
23
+ VERSION = "2.0.0".freeze
20
24
  end
21
25
  end
22
26
  end
@@ -12,24 +12,32 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
-
16
- require "faraday"
17
15
  require "json"
18
16
 
17
+ require "google/cloud/env/compute_metadata"
18
+ require "google/cloud/env/compute_smbios"
19
+ require "google/cloud/env/file_system"
20
+ require "google/cloud/env/variables"
19
21
 
22
+ ##
23
+ # Namespace of Google products
24
+ #
20
25
  module Google
26
+ ##
27
+ # Namespace of Google Cloud products
28
+ #
21
29
  module Cloud
22
30
  ##
23
- # # Google Cloud hosting environment
31
+ # ## Google Cloud hosting environment
24
32
  #
25
33
  # This library provides access to information about the application's
26
- # hosting environment if it is running on Google Cloud Platform. You may
34
+ # hosting environment if it is running on Google Cloud Platform. You can
27
35
  # use this library to determine which Google Cloud product is hosting your
28
36
  # application (e.g. App Engine, Kubernetes Engine), information about the
29
37
  # Google Cloud project hosting the application, information about the
30
38
  # virtual machine instance, authentication information, and so forth.
31
39
  #
32
- # ## Usage
40
+ # ### Usage
33
41
  #
34
42
  # Obtain an instance of the environment info with:
35
43
  #
@@ -56,116 +64,180 @@ module Google
56
64
  # ```
57
65
  #
58
66
  class Env
59
- # @private Base (host) URL for the metadata server.
60
- METADATA_HOST = "http://169.254.169.254".freeze
67
+ ##
68
+ # Create a new instance of the environment information.
69
+ # Most clients should not need to call this directly. Obtain a singleton
70
+ # instance of the information from `Google::Cloud.env`.
71
+ #
72
+ def initialize
73
+ @variables = Variables.new
74
+ @file_system = FileSystem.new
75
+ @compute_smbios = ComputeSMBIOS.new
76
+ @compute_metadata = ComputeMetadata.new variables: @variables,
77
+ compute_smbios: @compute_smbios
78
+ end
61
79
 
62
- # @private URL path for v1 of the metadata service.
63
- METADATA_PATH_BASE = "/computeMetadata/v1".freeze
80
+ ##
81
+ # The variables access object. Use this to make direct queries for
82
+ # environment variable information, or to mock out environment variables
83
+ # for testing.
84
+ #
85
+ # @return [Google::Cloud::Env::Variables]
86
+ #
87
+ attr_reader :variables
88
+
89
+ ##
90
+ # The variables access object. Use this to make direct queries for
91
+ # information from the file system, or to mock out the file system for
92
+ # testing.
93
+ #
94
+ # @return [Google::Cloud::Env::FileSystem]
95
+ #
96
+ attr_reader :file_system
64
97
 
65
- # @private URL path for metadata server root.
66
- METADATA_ROOT_PATH = "/".freeze
98
+ ##
99
+ # The compute SMBIOS access object. Use this to make direct queries for
100
+ # compute SMBIOS information, or to mock out the SMBIOS for testing.
101
+ #
102
+ # @return [Google::Cloud::Env::ComputeSMBIOS]
103
+ #
104
+ attr_reader :compute_smbios
67
105
 
68
- # @private
69
- METADATA_FAILURE_EXCEPTIONS = [
70
- Faraday::TimeoutError,
71
- Faraday::ConnectionFailed,
72
- Errno::EHOSTDOWN,
73
- Errno::ETIMEDOUT,
74
- Timeout::Error
75
- ].freeze
106
+ ##
107
+ # The compute metadata access object. Use this to make direct calls to
108
+ # compute metadata or configure how metadata server queries are done, or
109
+ # to mock out the metadata server for testing.
110
+ #
111
+ # @return [Google::Cloud::Env::ComputeMetadata]
112
+ #
113
+ attr_reader :compute_metadata
76
114
 
77
115
  ##
78
- # Create a new instance of the environment information.
79
- # Most client should not need to call this directly. Obtain a singleton
80
- # instance of the information from `Google::Cloud.env`. This constructor
81
- # is provided to allow customization of the timeout/retry settings, as
82
- # well as mocking for testing.
83
- #
84
- # @param [Hash] env Mock environment variables.
85
- # @param [String] host The hostname or IP address of the metadata server.
86
- # Optional. If not specified, uses the `GCE_METADATA_HOST`,
87
- # environment variable or falls back to `169.254.167.254`.
88
- # @param [Hash,false] metadata_cache The metadata cache. You may pass
89
- # a prepopuated cache, an empty cache (the default) or `false` to
90
- # disable the cache completely.
91
- # @param [Numeric] open_timeout Timeout for opening http connections.
92
- # Defaults to 0.1.
93
- # @param [Numeric] request_timeout Timeout for entire http requests.
94
- # Defaults to 1.0.
95
- # @param [Integer] retry_count Number of times to retry http requests.
96
- # Defaults to 1. Note that retry remains in effect even if a custom
97
- # `connection` is provided.
98
- # @param [Numeric] retry_interval Time between retries in seconds.
99
- # Defaults to 0.1.
100
- # @param [Numeric] retry_backoff_factor Multiplier applied to the retry
101
- # interval on each retry. Defaults to 1.5.
102
- # @param [Numeric] retry_max_interval Maximum time between retries in
103
- # seconds. Defaults to 0.5.
104
- # @param [Faraday::Connection] connection Faraday connection to use.
105
- # If specified, overrides the `request_timeout` and `open_timeout`
106
- # settings.
107
- #
108
- def initialize env: nil, host: nil, connection: nil, metadata_cache: nil,
109
- open_timeout: 0.1, request_timeout: 1.0,
110
- retry_count: 2, retry_interval: 0.1,
111
- retry_backoff_factor: 1.5, retry_max_interval: 0.5
112
- @disable_metadata_cache = metadata_cache == false
113
- @metadata_cache = metadata_cache || {}
114
- @env = env || ::ENV
115
- @retry_count = retry_count
116
- @retry_interval = retry_interval
117
- @retry_backoff_factor = retry_backoff_factor
118
- @retry_max_interval = retry_max_interval
119
- request_opts = { timeout: request_timeout, open_timeout: open_timeout }
120
- host ||= @env["GCE_METADATA_HOST"] || METADATA_HOST
121
- host = "http://#{host}" unless host.start_with? "http://"
122
- @connection = connection || ::Faraday.new(url: host, request: request_opts)
116
+ # Determine whether the Google Compute Engine Metadata Service is running.
117
+ #
118
+ # This method is conservative. It may block for a short period (up to
119
+ # about 1.5 seconds) while attempting to contact the server, but if this
120
+ # fails, this method will return false, even though it is possible that a
121
+ # future call could succeed. In particular, this might happen in
122
+ # environments where there is a warmup time for the Metadata Server.
123
+ # Early calls before the Server has warmed up may return false, while
124
+ # later calls return true.
125
+ #
126
+ # @return [boolean]
127
+ #
128
+ def metadata?
129
+ compute_metadata.check_existence == :confirmed
130
+ end
131
+
132
+ ##
133
+ # Assert that the Metadata Server should be present, and wait for a
134
+ # confirmed connection to ensure it is up. In general, this will run at
135
+ # most {ComputeMetadata::DEFAULT_WARMUP_TIME} seconds to wait out the
136
+ # expected maximum warmup time, but a shorter timeout can be provided.
137
+ #
138
+ # This method is useful call during application initialization to wait
139
+ # for the Metadata Server to warm up and ensure that subsequent lookups
140
+ # should succeed.
141
+ #
142
+ # @param timeout [Numeric,nil] a timeout in seconds, or nil to wait
143
+ # until we have conclusively decided one way or the other.
144
+ # @return [:confirmed] if we were able to confirm connection.
145
+ # @raise [MetadataServerNotResponding] if we were unable to confirm
146
+ # connection with the Metadata Server, either because the timeout
147
+ # expired or because the server seems to be down
148
+ #
149
+ def ensure_metadata timeout: nil
150
+ compute_metadata.ensure_existence timeout: timeout
151
+ end
152
+
153
+ ##
154
+ # Retrieve info from the Google Compute Engine Metadata Service.
155
+ # Returns `nil` if the given data is not present.
156
+ #
157
+ # @param [String] type Type of metadata to look up. Currently supported
158
+ # values are "project" and "instance".
159
+ # @param [String] entry Metadata entry path to look up.
160
+ # @param query [Hash{String => String}] Any additional query parameters
161
+ # to send with the request.
162
+ #
163
+ # @return [String] the data
164
+ # @return [nil] if there is no data for the specified type and entry
165
+ # @raise [MetadataServerNotResponding] if the Metadata Server is not
166
+ # responding. This could either be because the metadata service is
167
+ # not present in the current environment, or if it is expected to be
168
+ # present but is overloaded or has not finished initializing.
169
+ #
170
+ def lookup_metadata type, entry, query: nil
171
+ compute_metadata.lookup "#{type}/#{entry}", query: query
172
+ end
173
+
174
+ ##
175
+ # Retrieve an HTTP response from the Google Compute Engine Metadata
176
+ # Service. Returns a {ComputeMetadata::Response} with a status code,
177
+ # data, and headers. The response could be 200 for success, 404 if the
178
+ # given entry is not present, or other HTTP result code for authorization
179
+ # or other errors.
180
+ #
181
+ # @param [String] type Type of metadata to look up. Currently supported
182
+ # values are "project" and "instance".
183
+ # @param [String] entry Metadata entry path to look up.
184
+ # @param query [Hash{String => String}] Any additional query parameters
185
+ # to send with the request.
186
+ #
187
+ # @return [Google::Cloud::Env::ComputeMetadata::Response] the response
188
+ # @raise [MetadataServerNotResponding] if the Metadata Server is not
189
+ # responding. This could either be because the metadata service is
190
+ # not present in the current environment, or if it is expected to be
191
+ # present but is overloaded or has not finished initializing.
192
+ #
193
+ def lookup_metadata_response type, entry, query: nil
194
+ compute_metadata.lookup_response "#{type}/#{entry}", query: query
123
195
  end
124
196
 
125
197
  ##
126
198
  # Determine whether the application is running on a Knative-based
127
199
  # hosting platform, such as Cloud Run or Cloud Functions.
128
200
  #
129
- # @return [Boolean]
201
+ # @return [boolean]
130
202
  #
131
203
  def knative?
132
- env["K_SERVICE"] ? true : false
204
+ variables["K_SERVICE"] ? true : false
133
205
  end
134
206
 
135
207
  ##
136
208
  # Determine whether the application is running on Google App Engine.
137
209
  #
138
- # @return [Boolean]
210
+ # @return [boolean]
139
211
  #
140
212
  def app_engine?
141
- env["GAE_INSTANCE"] ? true : false
213
+ variables["GAE_INSTANCE"] ? true : false
142
214
  end
143
215
 
144
216
  ##
145
217
  # Determine whether the application is running on Google App Engine
146
218
  # Flexible Environment.
147
219
  #
148
- # @return [Boolean]
220
+ # @return [boolean]
149
221
  #
150
222
  def app_engine_flexible?
151
- app_engine? && env["GAE_ENV"] != "standard"
223
+ app_engine? && variables["GAE_ENV"] != "standard"
152
224
  end
153
225
 
154
226
  ##
155
227
  # Determine whether the application is running on Google App Engine
156
228
  # Standard Environment.
157
229
  #
158
- # @return [Boolean]
230
+ # @return [boolean]
159
231
  #
160
232
  def app_engine_standard?
161
- app_engine? && env["GAE_ENV"] == "standard"
233
+ app_engine? && variables["GAE_ENV"] == "standard"
162
234
  end
163
235
 
164
236
  ##
165
237
  # Determine whether the application is running on Google Kubernetes
166
238
  # Engine (GKE).
167
239
  #
168
- # @return [Boolean]
240
+ # @return [boolean]
169
241
  #
170
242
  def kubernetes_engine?
171
243
  kubernetes_engine_cluster_name ? true : false
@@ -175,10 +247,10 @@ module Google
175
247
  ##
176
248
  # Determine whether the application is running on Google Cloud Shell.
177
249
  #
178
- # @return [Boolean]
250
+ # @return [boolean]
179
251
  #
180
252
  def cloud_shell?
181
- env["DEVSHELL_GCLOUD_CONFIG"] ? true : false
253
+ variables["GOOGLE_CLOUD_SHELL"] ? true : false
182
254
  end
183
255
 
184
256
  ##
@@ -191,10 +263,10 @@ module Google
191
263
  # VM without using a higher level hosting product, use
192
264
  # {Env#raw_compute_engine?}.
193
265
  #
194
- # @return [Boolean]
266
+ # @return [boolean]
195
267
  #
196
268
  def compute_engine?
197
- metadata?
269
+ compute_smbios.google_compute?
198
270
  end
199
271
 
200
272
  ##
@@ -202,10 +274,10 @@ module Google
202
274
  # Engine without using a higher level hosting product such as App
203
275
  # Engine or Kubernetes Engine.
204
276
  #
205
- # @return [Boolean]
277
+ # @return [boolean]
206
278
  #
207
279
  def raw_compute_engine?
208
- !knative? && !app_engine? && !cloud_shell? && metadata? && !kubernetes_engine?
280
+ compute_engine? && !knative? && !app_engine? && !cloud_shell? && !kubernetes_engine?
209
281
  end
210
282
 
211
283
  ##
@@ -215,10 +287,12 @@ module Google
215
287
  # @return [String,nil]
216
288
  #
217
289
  def project_id
218
- env["GOOGLE_CLOUD_PROJECT"] ||
219
- env["GCLOUD_PROJECT"] ||
220
- env["DEVSHELL_PROJECT_ID"] ||
221
- lookup_metadata("project", "project-id")
290
+ variables["GOOGLE_CLOUD_PROJECT"] ||
291
+ variables["GCLOUD_PROJECT"] ||
292
+ variables["DEVSHELL_PROJECT_ID"] ||
293
+ compute_metadata.lookup("project/project-id")
294
+ rescue MetadataServerNotResponding
295
+ nil
222
296
  end
223
297
 
224
298
  ##
@@ -236,8 +310,12 @@ module Google
236
310
  # disable this for CloudShell to avoid confusion.
237
311
  return nil if cloud_shell?
238
312
 
239
- result = lookup_metadata "project", "numeric-project-id"
240
- result.nil? ? nil : result.to_i
313
+ result = begin
314
+ compute_metadata.lookup "project/numeric-project-id"
315
+ rescue MetadataServerNotResponding
316
+ nil
317
+ end
318
+ result&.to_i
241
319
  end
242
320
 
243
321
  ##
@@ -247,7 +325,9 @@ module Google
247
325
  # @return [String,nil]
248
326
  #
249
327
  def instance_name
250
- env["GAE_INSTANCE"] || lookup_metadata("instance", "name")
328
+ variables["GAE_INSTANCE"] || compute_metadata.lookup("instance/name")
329
+ rescue MetadataServerNotResponding
330
+ nil
251
331
  end
252
332
 
253
333
  ##
@@ -258,7 +338,9 @@ module Google
258
338
  # @return [String,nil]
259
339
  #
260
340
  def instance_description
261
- lookup_metadata "instance", "description"
341
+ compute_metadata.lookup "instance/description"
342
+ rescue MetadataServerNotResponding
343
+ nil
262
344
  end
263
345
 
264
346
  ##
@@ -269,8 +351,10 @@ module Google
269
351
  # @return [String,nil]
270
352
  #
271
353
  def instance_zone
272
- result = lookup_metadata "instance", "zone"
273
- result.nil? ? nil : result.split("/").last
354
+ result = compute_metadata.lookup "instance/zone"
355
+ result&.split("/")&.last
356
+ rescue MetadataServerNotResponding
357
+ nil
274
358
  end
275
359
 
276
360
  ##
@@ -280,8 +364,10 @@ module Google
280
364
  # @return [String,nil]
281
365
  #
282
366
  def instance_machine_type
283
- result = lookup_metadata "instance", "machine-type"
284
- result.nil? ? nil : result.split("/").last
367
+ result = compute_metadata.lookup "instance/machine-type"
368
+ result&.split("/")&.last
369
+ rescue MetadataServerNotResponding
370
+ nil
285
371
  end
286
372
 
287
373
  ##
@@ -292,8 +378,10 @@ module Google
292
378
  # @return [Array<String>,nil]
293
379
  #
294
380
  def instance_tags
295
- result = lookup_metadata "instance", "tags"
381
+ result = compute_metadata.lookup "instance/tags"
296
382
  result.nil? ? nil : JSON.parse(result)
383
+ rescue MetadataServerNotResponding
384
+ nil
297
385
  end
298
386
 
299
387
  ##
@@ -304,8 +392,10 @@ module Google
304
392
  # @return [Array<String>,nil]
305
393
  #
306
394
  def instance_attribute_keys
307
- result = lookup_metadata "instance", "attributes/"
308
- result.nil? ? nil : result.split
395
+ result = compute_metadata.lookup "instance/attributes/"
396
+ result&.split
397
+ rescue MetadataServerNotResponding
398
+ nil
309
399
  end
310
400
 
311
401
  ##
@@ -317,7 +407,9 @@ module Google
317
407
  # @return [String,nil]
318
408
  #
319
409
  def instance_attribute key
320
- lookup_metadata "instance", "attributes/#{key}"
410
+ compute_metadata.lookup "instance/attributes/#{key}"
411
+ rescue MetadataServerNotResponding
412
+ nil
321
413
  end
322
414
 
323
415
  ##
@@ -327,7 +419,7 @@ module Google
327
419
  # @return [String,nil]
328
420
  #
329
421
  def knative_service_id
330
- env["K_SERVICE"]
422
+ variables["K_SERVICE"]
331
423
  end
332
424
  alias knative_service_name knative_service_id
333
425
 
@@ -338,7 +430,7 @@ module Google
338
430
  # @return [String,nil]
339
431
  #
340
432
  def knative_service_revision
341
- env["K_REVISION"]
433
+ variables["K_REVISION"]
342
434
  end
343
435
 
344
436
  ##
@@ -348,7 +440,7 @@ module Google
348
440
  # @return [String,nil]
349
441
  #
350
442
  def app_engine_service_id
351
- env["GAE_SERVICE"]
443
+ variables["GAE_SERVICE"]
352
444
  end
353
445
  alias app_engine_service_name app_engine_service_id
354
446
 
@@ -359,7 +451,7 @@ module Google
359
451
  # @return [String,nil]
360
452
  #
361
453
  def app_engine_service_version
362
- env["GAE_VERSION"]
454
+ variables["GAE_VERSION"]
363
455
  end
364
456
 
365
457
  ##
@@ -369,8 +461,8 @@ module Google
369
461
  # @return [Integer,nil]
370
462
  #
371
463
  def app_engine_memory_mb
372
- result = env["GAE_MEMORY_MB"]
373
- result.nil? ? nil : result.to_i
464
+ result = variables["GAE_MEMORY_MB"]
465
+ result&.to_i
374
466
  end
375
467
 
376
468
  ##
@@ -382,6 +474,8 @@ module Google
382
474
  #
383
475
  def kubernetes_engine_cluster_name
384
476
  instance_attribute "cluster-name"
477
+ rescue MetadataServerNotResponding
478
+ nil
385
479
  end
386
480
  alias container_engine_cluster_name kubernetes_engine_cluster_name
387
481
 
@@ -398,55 +492,11 @@ module Google
398
492
  # below is set in some older versions of GKE, and the file below is
399
493
  # present in Kubernetes as of version 1.9, but it is possible that
400
494
  # alternatives will need to be found in the future.
401
- env["GKE_NAMESPACE_ID"] || ::IO.read("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
402
- rescue SystemCallError
403
- nil
495
+ variables["GKE_NAMESPACE_ID"] ||
496
+ file_system.read("/var/run/secrets/kubernetes.io/serviceaccount/namespace")
404
497
  end
405
498
  alias container_engine_namespace_id kubernetes_engine_namespace_id
406
499
 
407
- ##
408
- # Determine whether the Google Compute Engine Metadata Service is running.
409
- #
410
- # @return [Boolean]
411
- #
412
- def metadata?
413
- path = METADATA_ROOT_PATH
414
- if @disable_metadata_cache || !metadata_cache.include?(path)
415
- metadata_cache[path] = retry_or_fail_with false do
416
- resp = connection.get path do |req|
417
- req.headers = { "Metadata-Flavor" => "Google" }
418
- end
419
- resp.status == 200 && resp.headers["Metadata-Flavor"] == "Google"
420
- end
421
- end
422
- metadata_cache[path]
423
- end
424
-
425
- ##
426
- # Retrieve info from the Google Compute Engine Metadata Service.
427
- # Returns `nil` if the Metadata Service is not running or the given
428
- # data is not present.
429
- #
430
- # @param [String] type Type of metadata to look up. Currently supported
431
- # values are "project" and "instance".
432
- # @param [String] entry Metadata entry path to look up.
433
- # @return [String,nil]
434
- #
435
- def lookup_metadata type, entry
436
- return nil unless metadata?
437
-
438
- path = "#{METADATA_PATH_BASE}/#{type}/#{entry}"
439
- if @disable_metadata_cache || !metadata_cache.include?(path)
440
- metadata_cache[path] = retry_or_fail_with nil do
441
- resp = connection.get path do |req|
442
- req.headers = { "Metadata-Flavor" => "Google" }
443
- end
444
- resp.status == 200 ? resp.body.strip : nil
445
- end
446
- end
447
- metadata_cache[path]
448
- end
449
-
450
500
  ##
451
501
  # Returns the global instance of {Google::Cloud::Env}.
452
502
  #
@@ -455,29 +505,6 @@ module Google
455
505
  def self.get
456
506
  ::Google::Cloud.env
457
507
  end
458
-
459
- private
460
-
461
- attr_reader :connection
462
- attr_reader :env
463
- attr_reader :metadata_cache
464
-
465
- def retry_or_fail_with error_result
466
- retries_remaining = @retry_count
467
- retry_interval = @retry_interval
468
- begin
469
- yield
470
- rescue *METADATA_FAILURE_EXCEPTIONS
471
- retries_remaining -= 1
472
- if retries_remaining >= 0
473
- sleep retry_interval
474
- retry_interval *= @retry_backoff_factor
475
- retry_interval = @retry_max_interval if retry_interval > @retry_max_interval
476
- retry
477
- end
478
- error_result
479
- end
480
- end
481
508
  end
482
509
 
483
510
  @env = Env.new