aws-sdk-core 3.46.0 → 3.94.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 +5 -5
- data/VERSION +1 -1
- data/lib/aws-sdk-core.rb +7 -0
- data/lib/aws-sdk-core/arn.rb +77 -0
- data/lib/aws-sdk-core/arn_parser.rb +38 -0
- data/lib/aws-sdk-core/assume_role_web_identity_credentials.rb +102 -0
- data/lib/aws-sdk-core/async_client_stubs.rb +80 -0
- data/lib/aws-sdk-core/binary.rb +3 -0
- data/lib/aws-sdk-core/binary/decode_handler.rb +9 -1
- data/lib/aws-sdk-core/binary/encode_handler.rb +32 -0
- data/lib/aws-sdk-core/binary/event_builder.rb +122 -0
- data/lib/aws-sdk-core/binary/event_parser.rb +48 -18
- data/lib/aws-sdk-core/binary/event_stream_decoder.rb +5 -2
- data/lib/aws-sdk-core/binary/event_stream_encoder.rb +53 -0
- data/lib/aws-sdk-core/client_side_monitoring/publisher.rb +9 -1
- data/lib/aws-sdk-core/client_stubs.rb +10 -9
- data/lib/aws-sdk-core/credential_provider.rb +0 -31
- data/lib/aws-sdk-core/credential_provider_chain.rb +79 -39
- data/lib/aws-sdk-core/deprecations.rb +16 -10
- data/lib/aws-sdk-core/ecs_credentials.rb +12 -8
- data/lib/aws-sdk-core/endpoint_cache.rb +14 -11
- data/lib/aws-sdk-core/errors.rb +94 -6
- data/lib/aws-sdk-core/event_emitter.rb +42 -0
- data/lib/aws-sdk-core/instance_profile_credentials.rb +120 -38
- data/lib/aws-sdk-core/json.rb +13 -14
- data/lib/aws-sdk-core/json/error_handler.rb +19 -2
- data/lib/aws-sdk-core/json/handler.rb +19 -1
- data/lib/aws-sdk-core/log/formatter.rb +7 -1
- data/lib/aws-sdk-core/log/param_filter.rb +3 -3
- data/lib/aws-sdk-core/pageable_response.rb +34 -20
- data/lib/aws-sdk-core/param_validator.rb +11 -5
- data/lib/aws-sdk-core/plugins/client_metrics_plugin.rb +26 -1
- data/lib/aws-sdk-core/plugins/endpoint_discovery.rb +1 -1
- data/lib/aws-sdk-core/plugins/event_stream_configuration.rb +14 -0
- data/lib/aws-sdk-core/plugins/invocation_id.rb +33 -0
- data/lib/aws-sdk-core/plugins/regional_endpoint.rb +8 -1
- data/lib/aws-sdk-core/plugins/retries/client_rate_limiter.rb +137 -0
- data/lib/aws-sdk-core/plugins/retries/clock_skew.rb +98 -0
- data/lib/aws-sdk-core/plugins/retries/error_inspector.rb +142 -0
- data/lib/aws-sdk-core/plugins/retries/retry_quota.rb +57 -0
- data/lib/aws-sdk-core/plugins/retry_errors.rb +290 -106
- data/lib/aws-sdk-core/plugins/signature_v4.rb +13 -2
- data/lib/aws-sdk-core/plugins/stub_responses.rb +20 -7
- data/lib/aws-sdk-core/plugins/transfer_encoding.rb +51 -0
- data/lib/aws-sdk-core/plugins/user_agent.rb +4 -8
- data/lib/aws-sdk-core/process_credentials.rb +9 -3
- data/lib/aws-sdk-core/shared_config.rb +95 -125
- data/lib/aws-sdk-core/structure.rb +1 -2
- data/lib/aws-sdk-core/stubbing/protocols/rest.rb +19 -0
- data/lib/aws-sdk-core/stubbing/stub_data.rb +13 -4
- data/lib/aws-sdk-core/util.rb +4 -0
- data/lib/aws-sdk-core/waiters/waiter.rb +2 -2
- data/lib/aws-sdk-core/xml/error_handler.rb +26 -3
- data/lib/aws-sdk-sts.rb +7 -4
- data/lib/aws-sdk-sts/client.rb +1109 -459
- data/lib/aws-sdk-sts/client_api.rb +67 -0
- data/lib/aws-sdk-sts/customizations.rb +2 -0
- data/lib/aws-sdk-sts/errors.rb +150 -0
- data/lib/aws-sdk-sts/plugins/sts_regional_endpoints.rb +32 -0
- data/lib/aws-sdk-sts/presigner.rb +67 -0
- data/lib/aws-sdk-sts/resource.rb +1 -0
- data/lib/aws-sdk-sts/types.rb +736 -176
- data/lib/seahorse.rb +9 -0
- data/lib/seahorse/client/async_base.rb +50 -0
- data/lib/seahorse/client/async_response.rb +62 -0
- data/lib/seahorse/client/base.rb +4 -2
- data/lib/seahorse/client/configuration.rb +4 -2
- data/lib/seahorse/client/events.rb +1 -1
- data/lib/seahorse/client/h2/connection.rb +246 -0
- data/lib/seahorse/client/h2/handler.rb +151 -0
- data/lib/seahorse/client/handler_list_entry.rb +2 -2
- data/lib/seahorse/client/http/async_response.rb +42 -0
- data/lib/seahorse/client/http/response.rb +13 -8
- data/lib/seahorse/client/logging/formatter.rb +4 -2
- data/lib/seahorse/client/net_http/connection_pool.rb +19 -20
- data/lib/seahorse/client/net_http/handler.rb +7 -1
- data/lib/seahorse/client/net_http/patches.rb +7 -1
- data/lib/seahorse/client/networking_error.rb +28 -0
- data/lib/seahorse/client/plugin.rb +5 -4
- data/lib/seahorse/client/plugins/content_length.rb +5 -2
- data/lib/seahorse/client/plugins/h2.rb +64 -0
- data/lib/seahorse/client/response.rb +3 -5
- data/lib/seahorse/model/api.rb +4 -0
- data/lib/seahorse/model/operation.rb +4 -0
- data/lib/seahorse/model/shapes.rb +2 -2
- metadata +43 -10
@@ -35,33 +35,39 @@ module Aws
|
|
35
35
|
# @api private
|
36
36
|
module Deprecations
|
37
37
|
|
38
|
-
# @param [Symbol]
|
38
|
+
# @param [Symbol] method The name of the deprecated method.
|
39
39
|
#
|
40
40
|
# @option options [String] :message The warning message to issue
|
41
41
|
# when the deprecated method is called.
|
42
42
|
#
|
43
|
-
# @option options [
|
44
|
-
# method that should be used.
|
43
|
+
# @option options [String] :use The name of a method that should be used.
|
45
44
|
#
|
46
|
-
|
45
|
+
# @option options [String] :version The version that will remove the
|
46
|
+
# deprecated method.
|
47
|
+
#
|
48
|
+
def deprecated(method, options = {})
|
47
49
|
|
48
50
|
deprecation_msg = options[:message] || begin
|
49
|
-
msg = "DEPRECATION WARNING
|
50
|
-
msg << "of
|
51
|
-
msg << "
|
51
|
+
msg = "#################### DEPRECATION WARNING ####################\n"
|
52
|
+
msg << "Called deprecated method `#{method}` of #{self}."
|
53
|
+
msg << " Use `#{options[:use]}` instead.\n" if options[:use]
|
54
|
+
if options[:version]
|
55
|
+
msg << "Method `#{method}` will be removed in #{options[:version]}."
|
56
|
+
end
|
57
|
+
msg << "\n#############################################################"
|
52
58
|
msg
|
53
59
|
end
|
54
60
|
|
55
|
-
alias_method(:"deprecated_#{
|
61
|
+
alias_method(:"deprecated_#{method}", method)
|
56
62
|
|
57
63
|
warned = false # we only want to issue this warning once
|
58
64
|
|
59
|
-
define_method(
|
65
|
+
define_method(method) do |*args, &block|
|
60
66
|
unless warned
|
61
67
|
warned = true
|
62
68
|
warn(deprecation_msg + "\n" + caller.join("\n"))
|
63
69
|
end
|
64
|
-
send("deprecated_#{
|
70
|
+
send("deprecated_#{method}", *args, &block)
|
65
71
|
end
|
66
72
|
end
|
67
73
|
|
@@ -78,14 +78,18 @@ module Aws
|
|
78
78
|
# Retry loading credentials up to 3 times is the instance metadata
|
79
79
|
# service is responding but is returning invalid JSON documents
|
80
80
|
# in response to the GET profile credentials call.
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
81
|
+
begin
|
82
|
+
retry_errors([JSON::ParserError, StandardError], max_retries: 3) do
|
83
|
+
c = JSON.parse(get_credentials.to_s)
|
84
|
+
@credentials = Credentials.new(
|
85
|
+
c['AccessKeyId'],
|
86
|
+
c['SecretAccessKey'],
|
87
|
+
c['Token']
|
88
|
+
)
|
89
|
+
@expiration = c['Expiration'] ? Time.iso8601(c['Expiration']) : nil
|
90
|
+
end
|
91
|
+
rescue JSON::ParserError
|
92
|
+
raise Aws::Errors::MetadataParserError.new
|
89
93
|
end
|
90
94
|
end
|
91
95
|
|
@@ -47,8 +47,8 @@ module Aws
|
|
47
47
|
@mutex.synchronize do
|
48
48
|
# delete the least recent used endpoint when cache is full
|
49
49
|
unless @entries.size < @max_entries
|
50
|
-
old_key,
|
51
|
-
|
50
|
+
old_key, = @entries.shift
|
51
|
+
delete_polling_thread(old_key)
|
52
52
|
end
|
53
53
|
# delete old value if exists
|
54
54
|
@entries.delete(key)
|
@@ -60,10 +60,12 @@ module Aws
|
|
60
60
|
# @param [String] key
|
61
61
|
# @return [Boolean]
|
62
62
|
def key?(key)
|
63
|
-
|
64
|
-
|
63
|
+
@mutex.synchronize do
|
64
|
+
if @entries.key?(key) && (@entries[key].nil? || @entries[key].expired?)
|
65
|
+
@entries.delete(key)
|
66
|
+
end
|
67
|
+
@entries.key?(key)
|
65
68
|
end
|
66
|
-
@entries.key?(key)
|
67
69
|
end
|
68
70
|
|
69
71
|
# checking whether an polling thread exist for the key
|
@@ -84,7 +86,7 @@ module Aws
|
|
84
86
|
# kill the old polling thread and remove it from pool
|
85
87
|
# @param [String] key
|
86
88
|
def delete_polling_thread(key)
|
87
|
-
Thread.kill(@pool[key]) if
|
89
|
+
Thread.kill(@pool[key]) if threads_key?(key)
|
88
90
|
@pool.delete(key)
|
89
91
|
end
|
90
92
|
|
@@ -109,7 +111,7 @@ module Aws
|
|
109
111
|
if _endpoint_operation_identifier(ctx)
|
110
112
|
parts << ctx.operation_name
|
111
113
|
ctx.operation.input.shape.members.inject(parts) do |p, (name, ref)|
|
112
|
-
p << ctx.params[name] if ref[
|
114
|
+
p << ctx.params[name] if ref['endpointdiscoveryid']
|
113
115
|
p
|
114
116
|
end
|
115
117
|
end
|
@@ -141,7 +143,7 @@ module Aws
|
|
141
143
|
# build identifier params when available
|
142
144
|
params[:operation] = ctx.operation.name
|
143
145
|
ctx.operation.input.shape.members.inject(params) do |p, (name, ref)|
|
144
|
-
if ref[
|
146
|
+
if ref['endpointdiscoveryid']
|
145
147
|
p[:identifiers] ||= {}
|
146
148
|
p[:identifiers][ref.location_name] = ctx.params[name]
|
147
149
|
end
|
@@ -153,19 +155,20 @@ module Aws
|
|
153
155
|
endpoint_operation_name = ctx.config.api.endpoint_operation
|
154
156
|
ctx.client.send(endpoint_operation_name, params)
|
155
157
|
rescue Aws::Errors::ServiceError
|
156
|
-
nil
|
158
|
+
nil
|
157
159
|
end
|
158
160
|
end
|
159
161
|
|
160
162
|
def _endpoint_operation_identifier(ctx)
|
161
163
|
return @require_identifier unless @require_identifier.nil?
|
164
|
+
|
162
165
|
operation_name = ctx.config.api.endpoint_operation
|
163
166
|
operation = ctx.config.api.operation(operation_name)
|
164
167
|
@require_identifier = operation.input.shape.members.any?
|
165
168
|
end
|
166
169
|
|
167
170
|
class Endpoint
|
168
|
-
|
171
|
+
|
169
172
|
# default endpoint cache time, 1 minute
|
170
173
|
CACHE_PERIOD = 1
|
171
174
|
|
@@ -175,7 +178,7 @@ module Aws
|
|
175
178
|
@created_time = Time.now
|
176
179
|
end
|
177
180
|
|
178
|
-
# [String] valid URI address (with path)
|
181
|
+
# [String] valid URI address (with path)
|
179
182
|
attr_reader :address
|
180
183
|
|
181
184
|
def expired?
|
data/lib/aws-sdk-core/errors.rb
CHANGED
@@ -1,5 +1,3 @@
|
|
1
|
-
require 'thread'
|
2
|
-
|
3
1
|
module Aws
|
4
2
|
module Errors
|
5
3
|
|
@@ -13,9 +11,12 @@ module Aws
|
|
13
11
|
|
14
12
|
# @param [Seahorse::Client::RequestContext] context
|
15
13
|
# @param [String] message
|
16
|
-
|
14
|
+
# @param [Aws::Structure] data
|
15
|
+
def initialize(context, message, data = Aws::EmptyStructure.new)
|
17
16
|
@code = self.class.code
|
17
|
+
@message = message if message && !message.empty?
|
18
18
|
@context = context
|
19
|
+
@data = data
|
19
20
|
super(message)
|
20
21
|
end
|
21
22
|
|
@@ -26,12 +27,43 @@ module Aws
|
|
26
27
|
# that triggered the remote service to return this error.
|
27
28
|
attr_reader :context
|
28
29
|
|
30
|
+
# @return [Aws::Structure]
|
31
|
+
attr_reader :data
|
32
|
+
|
29
33
|
class << self
|
30
34
|
|
31
35
|
# @return [String]
|
32
36
|
attr_accessor :code
|
33
37
|
|
34
38
|
end
|
39
|
+
|
40
|
+
# @api private undocumented
|
41
|
+
def retryable?
|
42
|
+
false
|
43
|
+
end
|
44
|
+
|
45
|
+
# @api private undocumented
|
46
|
+
def throttling?
|
47
|
+
false
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Raised when InstanceProfileCredentialsProvider or
|
52
|
+
# EcsCredentialsProvider fails to parse the metadata response after retries
|
53
|
+
class MetadataParserError < RuntimeError
|
54
|
+
def initialize(*args)
|
55
|
+
msg = "Failed to parse metadata service response."
|
56
|
+
super(msg)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Raised when a `streaming` operation has `requiresLength` trait
|
61
|
+
# enabled but request payload size/length cannot be calculated
|
62
|
+
class MissingContentLength < RuntimeError
|
63
|
+
def initialize(*args)
|
64
|
+
msg = 'Required `Content-Length` value missing for the request.'
|
65
|
+
super(msg)
|
66
|
+
end
|
35
67
|
end
|
36
68
|
|
37
69
|
# Rasied when endpoint discovery failed for operations
|
@@ -58,10 +90,18 @@ module Aws
|
|
58
90
|
|
59
91
|
end
|
60
92
|
|
93
|
+
# Raised when attempting to #signal an event before
|
94
|
+
# making an async request
|
95
|
+
class SignalEventError < RuntimeError; end
|
96
|
+
|
61
97
|
# Raised when EventStream Parser failed to parse
|
62
98
|
# a raw event message
|
63
99
|
class EventStreamParserError < RuntimeError; end
|
64
100
|
|
101
|
+
# Raise when EventStream Builder failed to build
|
102
|
+
# an event message with parameters provided
|
103
|
+
class EventStreamBuilderError < RuntimeError; end
|
104
|
+
|
65
105
|
# Error event in an event stream which has event_type :error
|
66
106
|
# error code and error message can be retrieved when available.
|
67
107
|
#
|
@@ -93,6 +133,29 @@ module Aws
|
|
93
133
|
|
94
134
|
end
|
95
135
|
|
136
|
+
# Raised when ARN string input doesn't follow the standard:
|
137
|
+
# https://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html#genref-arns
|
138
|
+
class InvalidARNError < RuntimeError; end
|
139
|
+
|
140
|
+
# Raised when the region from the ARN string is different from the :region
|
141
|
+
# configured on the service client.
|
142
|
+
class InvalidARNRegionError < RuntimeError
|
143
|
+
def initialize(*args)
|
144
|
+
msg = 'ARN region is different from the configured client region.'
|
145
|
+
super(msg)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# Raised when the partition of the ARN region is different than the
|
150
|
+
# partition of the :region configured on the service client.
|
151
|
+
class InvalidARNPartitionError < RuntimeError
|
152
|
+
def initialize(*args)
|
153
|
+
msg = 'ARN region partition is different from the configured '\
|
154
|
+
'client region partition.'
|
155
|
+
super(msg)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
96
159
|
# Various plugins perform client-side checksums of responses.
|
97
160
|
# This error indicates a checksum failed.
|
98
161
|
class ChecksumError < RuntimeError; end
|
@@ -126,6 +189,18 @@ module Aws
|
|
126
189
|
end
|
127
190
|
end
|
128
191
|
|
192
|
+
# Raised when :web_identity_token_file parameter is not
|
193
|
+
# provided or the file doesn't exist when initializing
|
194
|
+
# AssumeRoleWebIdentityCredentials credential provider
|
195
|
+
class MissingWebIdentityTokenFile < RuntimeError
|
196
|
+
def initialize(*args)
|
197
|
+
msg = 'Missing :web_identity_token_file parameter or'\
|
198
|
+
' invalid file path provided for'\
|
199
|
+
' Aws::AssumeRoleWebIdentityCredentials provider'
|
200
|
+
super(msg)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
129
204
|
# Raised when a credentials provider process returns a JSON
|
130
205
|
# payload with either invalid version number or malformed contents
|
131
206
|
class InvalidProcessCredentialsPayload < RuntimeError; end
|
@@ -157,8 +232,8 @@ This is typically the result of an invalid `:region` option or a
|
|
157
232
|
poorly formatted `:endpoint` option.
|
158
233
|
|
159
234
|
* Avoid configuring the `:endpoint` option directly. Endpoints are constructed
|
160
|
-
from the `:region`. The `:endpoint` option is reserved for
|
161
|
-
non-standard test endpoints.
|
235
|
+
from the `:region`. The `:endpoint` option is reserved for certain services
|
236
|
+
or for connecting to non-standard test endpoints.
|
162
237
|
|
163
238
|
* Not every service is available in every region.
|
164
239
|
|
@@ -190,6 +265,15 @@ Known AWS regions include (not specific to this service):
|
|
190
265
|
|
191
266
|
end
|
192
267
|
|
268
|
+
# Raised when attempting to retry a request
|
269
|
+
# and no capacity is available to retry (See adaptive retry_mode)
|
270
|
+
class RetryCapacityNotAvailableError < RuntimeError
|
271
|
+
def initialize(*args)
|
272
|
+
msg = 'Insufficient client side capacity available to retry request.'
|
273
|
+
super(msg)
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
193
277
|
# This module is mixed into another module, providing dynamic
|
194
278
|
# error classes. Error classes all inherit from {ServiceError}.
|
195
279
|
#
|
@@ -223,7 +307,11 @@ Known AWS regions include (not specific to this service):
|
|
223
307
|
def error_class(error_code)
|
224
308
|
constant = error_class_constant(error_code)
|
225
309
|
if error_const_set?(constant)
|
226
|
-
|
310
|
+
# modeled error class exist
|
311
|
+
# set code attribute
|
312
|
+
err_class = const_get(constant)
|
313
|
+
err_class.code = constant.to_s
|
314
|
+
err_class
|
227
315
|
else
|
228
316
|
set_error_constant(constant)
|
229
317
|
end
|
@@ -3,8 +3,19 @@ module Aws
|
|
3
3
|
|
4
4
|
def initialize
|
5
5
|
@listeners = {}
|
6
|
+
@validate_event = true
|
7
|
+
@status = :sleep
|
8
|
+
@signal_queue = Queue.new
|
6
9
|
end
|
7
10
|
|
11
|
+
attr_accessor :stream
|
12
|
+
|
13
|
+
attr_accessor :encoder
|
14
|
+
|
15
|
+
attr_accessor :validate_event
|
16
|
+
|
17
|
+
attr_accessor :signal_queue
|
18
|
+
|
8
19
|
def on(type, callback)
|
9
20
|
(@listeners[type] ||= []) << callback
|
10
21
|
end
|
@@ -16,5 +27,36 @@ module Aws
|
|
16
27
|
end
|
17
28
|
end
|
18
29
|
|
30
|
+
def emit(type, params)
|
31
|
+
unless @stream
|
32
|
+
raise Aws::Errors::SignalEventError.new(
|
33
|
+
"Singaling events before making async request"\
|
34
|
+
" is not allowed."
|
35
|
+
)
|
36
|
+
end
|
37
|
+
if @validate_event && type != :end_stream
|
38
|
+
Aws::ParamValidator.validate!(
|
39
|
+
@encoder.rules.shape.member(type), params)
|
40
|
+
end
|
41
|
+
_ready_for_events?
|
42
|
+
@stream.data(
|
43
|
+
@encoder.encode(type, params),
|
44
|
+
end_stream: type == :end_stream
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def _ready_for_events?
|
51
|
+
return true if @status == :ready
|
52
|
+
|
53
|
+
# blocked until once initial 200 response is received
|
54
|
+
# signal will be available in @signal_queue
|
55
|
+
# and this check will no longer be blocked
|
56
|
+
@signal_queue.pop
|
57
|
+
@status = :ready
|
58
|
+
true
|
59
|
+
end
|
60
|
+
|
19
61
|
end
|
20
62
|
end
|
@@ -11,6 +11,12 @@ module Aws
|
|
11
11
|
# @api private
|
12
12
|
class Non200Response < RuntimeError; end
|
13
13
|
|
14
|
+
# @api private
|
15
|
+
class TokenRetrivalError < RuntimeError; end
|
16
|
+
|
17
|
+
# @api private
|
18
|
+
class TokenExpiredError < RuntimeError; end
|
19
|
+
|
14
20
|
# These are the errors we trap when attempting to talk to the
|
15
21
|
# instance metadata service. Any of these imply the service
|
16
22
|
# is not present, no responding or some other non-recoverable
|
@@ -23,16 +29,24 @@ module Aws
|
|
23
29
|
Errno::ENETUNREACH,
|
24
30
|
SocketError,
|
25
31
|
Timeout::Error,
|
26
|
-
Non200Response
|
27
|
-
]
|
32
|
+
Non200Response
|
33
|
+
].freeze
|
34
|
+
|
35
|
+
# Path base for GET request for profile and credentials
|
36
|
+
# @api private
|
37
|
+
METADATA_PATH_BASE = '/latest/meta-data/iam/security-credentials/'.freeze
|
38
|
+
|
39
|
+
# Path for PUT request for token
|
40
|
+
# @api private
|
41
|
+
METADATA_TOKEN_PATH = '/latest/api/token'.freeze
|
28
42
|
|
29
43
|
# @param [Hash] options
|
30
|
-
# @option options [Integer] :retries (
|
44
|
+
# @option options [Integer] :retries (1) Number of times to retry
|
31
45
|
# when retrieving credentials.
|
32
46
|
# @option options [String] :ip_address ('169.254.169.254')
|
33
47
|
# @option options [Integer] :port (80)
|
34
|
-
# @option options [Float] :http_open_timeout (
|
35
|
-
# @option options [Float] :http_read_timeout (
|
48
|
+
# @option options [Float] :http_open_timeout (1)
|
49
|
+
# @option options [Float] :http_read_timeout (1)
|
36
50
|
# @option options [Numeric, Proc] :delay By default, failures are retried
|
37
51
|
# with exponential back-off, i.e. `sleep(1.2 ** num_failures)`. You can
|
38
52
|
# pass a number of seconds to sleep between failed attempts, or
|
@@ -40,19 +54,25 @@ module Aws
|
|
40
54
|
# @option options [IO] :http_debug_output (nil) HTTP wire
|
41
55
|
# traces are sent to this object. You can specify something
|
42
56
|
# like $stdout.
|
43
|
-
|
44
|
-
|
57
|
+
# @option options [Integer] :token_ttl Time-to-Live in seconds for EC2
|
58
|
+
# Metadata Token used for fetching Metadata Profile Credentials, defaults
|
59
|
+
# to 21600 seconds
|
60
|
+
def initialize(options = {})
|
61
|
+
@retries = options[:retries] || 1
|
45
62
|
@ip_address = options[:ip_address] || '169.254.169.254'
|
46
63
|
@port = options[:port] || 80
|
47
|
-
@http_open_timeout = options[:http_open_timeout] ||
|
48
|
-
@http_read_timeout = options[:http_read_timeout] ||
|
64
|
+
@http_open_timeout = options[:http_open_timeout] || 1
|
65
|
+
@http_read_timeout = options[:http_read_timeout] || 1
|
49
66
|
@http_debug_output = options[:http_debug_output]
|
50
67
|
@backoff = backoff(options[:backoff])
|
68
|
+
@token_ttl = options[:token_ttl] || 21_600
|
69
|
+
@token = nil
|
51
70
|
super
|
52
71
|
end
|
53
72
|
|
54
|
-
# @return [Integer]
|
55
|
-
#
|
73
|
+
# @return [Integer] Number of times to retry when retrieving credentials
|
74
|
+
# from the instance metadata service. Defaults to 0 when resolving from
|
75
|
+
# the default credential chain ({Aws::CredentialProviderChain}).
|
56
76
|
attr_reader :retries
|
57
77
|
|
58
78
|
private
|
@@ -60,8 +80,8 @@ module Aws
|
|
60
80
|
def backoff(backoff)
|
61
81
|
case backoff
|
62
82
|
when Proc then backoff
|
63
|
-
when Numeric then
|
64
|
-
else
|
83
|
+
when Numeric then ->(_) { sleep(backoff) }
|
84
|
+
else ->(num_failures) { Kernel.sleep(1.2**num_failures) }
|
65
85
|
end
|
66
86
|
end
|
67
87
|
|
@@ -69,14 +89,18 @@ module Aws
|
|
69
89
|
# Retry loading credentials up to 3 times is the instance metadata
|
70
90
|
# service is responding but is returning invalid JSON documents
|
71
91
|
# in response to the GET profile credentials call.
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
92
|
+
begin
|
93
|
+
retry_errors([JSON::ParserError, StandardError], max_retries: 3) do
|
94
|
+
c = JSON.parse(get_credentials.to_s)
|
95
|
+
@credentials = Credentials.new(
|
96
|
+
c['AccessKeyId'],
|
97
|
+
c['SecretAccessKey'],
|
98
|
+
c['Token']
|
99
|
+
)
|
100
|
+
@expiration = c['Expiration'] ? Time.iso8601(c['Expiration']) : nil
|
101
|
+
end
|
102
|
+
rescue JSON::ParserError
|
103
|
+
raise Aws::Errors::MetadataParserError
|
80
104
|
end
|
81
105
|
end
|
82
106
|
|
@@ -89,9 +113,27 @@ module Aws
|
|
89
113
|
begin
|
90
114
|
retry_errors(NETWORK_ERRORS, max_retries: @retries) do
|
91
115
|
open_connection do |conn|
|
92
|
-
|
93
|
-
|
94
|
-
|
116
|
+
# attempt to fetch token to start secure flow first
|
117
|
+
# and rescue to failover
|
118
|
+
begin
|
119
|
+
retry_errors(NETWORK_ERRORS, max_retries: @retries) do
|
120
|
+
unless token_set?
|
121
|
+
token_value, ttl = http_put(
|
122
|
+
conn, METADATA_TOKEN_PATH, @token_ttl
|
123
|
+
)
|
124
|
+
@token = Token.new(token_value, ttl) if token_value && ttl
|
125
|
+
end
|
126
|
+
end
|
127
|
+
rescue *NETWORK_ERRORS
|
128
|
+
# token attempt failed, reset token
|
129
|
+
# fallback to non-token mode
|
130
|
+
@token = nil
|
131
|
+
end
|
132
|
+
|
133
|
+
token = @token.value if token_set?
|
134
|
+
metadata = http_get(conn, METADATA_PATH_BASE, token)
|
135
|
+
profile_name = metadata.lines.first.strip
|
136
|
+
http_get(conn, METADATA_PATH_BASE + profile_name, token)
|
95
137
|
end
|
96
138
|
end
|
97
139
|
rescue
|
@@ -100,9 +142,12 @@ module Aws
|
|
100
142
|
end
|
101
143
|
end
|
102
144
|
|
145
|
+
def token_set?
|
146
|
+
@token && !@token.expired?
|
147
|
+
end
|
148
|
+
|
103
149
|
def _metadata_disabled?
|
104
|
-
|
105
|
-
!flag.nil? && flag.downcase == "true"
|
150
|
+
ENV.fetch('AWS_EC2_METADATA_DISABLED', 'false').downcase == 'true'
|
106
151
|
end
|
107
152
|
|
108
153
|
def open_connection
|
@@ -114,30 +159,67 @@ module Aws
|
|
114
159
|
yield(http).tap { http.finish }
|
115
160
|
end
|
116
161
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
162
|
+
# GET request fetch profile and credentials
|
163
|
+
def http_get(connection, path, token = nil)
|
164
|
+
headers = { 'User-Agent' => "aws-sdk-ruby3/#{CORE_GEM_VERSION}" }
|
165
|
+
headers['x-aws-ec2-metadata-token'] = token if token
|
166
|
+
response = connection.request(Net::HTTP::Get.new(path, headers))
|
167
|
+
raise Non200Response unless response.code.to_i == 200
|
168
|
+
|
169
|
+
response.body
|
170
|
+
end
|
171
|
+
|
172
|
+
# PUT request fetch token with ttl
|
173
|
+
def http_put(connection, path, ttl)
|
174
|
+
headers = {
|
175
|
+
'User-Agent' => "aws-sdk-ruby3/#{CORE_GEM_VERSION}",
|
176
|
+
'x-aws-ec2-metadata-token-ttl-seconds' => ttl.to_s
|
177
|
+
}
|
178
|
+
response = connection.request(Net::HTTP::Put.new(path, headers))
|
179
|
+
case response.code.to_i
|
180
|
+
when 200
|
181
|
+
[
|
182
|
+
response.body,
|
183
|
+
response.header['x-aws-ec2-metadata-token-ttl-seconds'].to_i
|
184
|
+
]
|
185
|
+
when 400
|
186
|
+
raise TokenRetrivalError
|
187
|
+
when 401
|
188
|
+
raise TokenExpiredError
|
121
189
|
else
|
122
190
|
raise Non200Response
|
123
191
|
end
|
124
192
|
end
|
125
193
|
|
126
|
-
def retry_errors(error_classes, options = {}, &
|
194
|
+
def retry_errors(error_classes, options = {}, &_block)
|
127
195
|
max_retries = options[:max_retries]
|
128
196
|
retries = 0
|
129
197
|
begin
|
130
198
|
yield
|
131
199
|
rescue *error_classes
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
raise
|
138
|
-
end
|
200
|
+
raise unless retries < max_retries
|
201
|
+
|
202
|
+
@backoff.call(retries)
|
203
|
+
retries += 1
|
204
|
+
retry
|
139
205
|
end
|
140
206
|
end
|
141
207
|
|
208
|
+
# @api private
|
209
|
+
# Token used to fetch IMDS profile and credentials
|
210
|
+
class Token
|
211
|
+
def initialize(value, ttl)
|
212
|
+
@ttl = ttl
|
213
|
+
@value = value
|
214
|
+
@created_time = Time.now
|
215
|
+
end
|
216
|
+
|
217
|
+
# [String] token value
|
218
|
+
attr_reader :value
|
219
|
+
|
220
|
+
def expired?
|
221
|
+
Time.now - @created_time > @ttl
|
222
|
+
end
|
223
|
+
end
|
142
224
|
end
|
143
225
|
end
|