aws-sdk-core 3.36.0 → 3.37.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: '083dd2b29c24dd42e393906e157ed16992abd9ce'
4
- data.tar.gz: d7aec8220a6df968102325ffc645801d67e7183b
3
+ metadata.gz: 3a0ca80cd27bbc952ef138198462d128f8586206
4
+ data.tar.gz: f45b8a21bbefd877679e6f9eb61b5d20e53377a7
5
5
  SHA512:
6
- metadata.gz: 85b1ce5dc4e283f2407e9718e298b82773505cdb13b53e9734e176c05e130e691d7329d89e8e51c9c81cbb2dd6e3c3a443ac5bd2bb31422424d5952ff2650dac
7
- data.tar.gz: 5c9cdcfdf9029fd8c0177859097fde46d0c48f8bcfc03361ff5261be6cf9ca0bc6ce71ad4bf8f6ac69d4e5017d09ebc5a0e5bba9ca97c8d6b7d7c1441962ba01
6
+ metadata.gz: 417e4adb9bd6a423160f6ce7a2fed489d77f46bf685535588a38145832d07dee582f674c501f622207129496502fcaebf36cac2a76fd0a73244827c0f6e6ad86
7
+ data.tar.gz: f2299177e51157ec28c44d7a5eed130c3a3bb3b50ca1f717291907b34b05c221442cd786a7101ab83f5f9cb2db174f8e7dee0ba28a07d85dba6cef3711c63464
data/VERSION CHANGED
@@ -1 +1 @@
1
- 3.36.0
1
+ 3.37.0
@@ -64,9 +64,14 @@ require_relative 'aws-sdk-core/xml'
64
64
  require_relative 'aws-sdk-core/json'
65
65
 
66
66
  # event stream
67
+
67
68
  require_relative 'aws-sdk-core/binary'
68
69
  require_relative 'aws-sdk-core/event_emitter'
69
70
 
71
+ # endpoint discovery
72
+
73
+ require_relative 'aws-sdk-core/endpoint_cache'
74
+
70
75
  # client metrics
71
76
 
72
77
  require_relative 'aws-sdk-core/client_side_monitoring/request_metrics'
@@ -0,0 +1,188 @@
1
+ module Aws
2
+ # @api private
3
+ # a LRU cache caching endpoints data
4
+ class EndpointCache
5
+
6
+ # default cache entries limit
7
+ MAX_ENTRIES = 1000
8
+
9
+ # default max threads pool size
10
+ MAX_THREADS = 10
11
+
12
+ def initialize(options = {})
13
+ @max_entries = options[:max_entries] || MAX_ENTRIES
14
+ @entries = {} # store endpoints
15
+ @max_threads = options[:max_threads] || MAX_THREADS
16
+ @pool = {} # store polling threads
17
+ @mutex = Mutex.new
18
+ @require_identifier = nil # whether endpoint operation support identifier
19
+ end
20
+
21
+ # @return [Integer] Max size limit of cache
22
+ attr_reader :max_entries
23
+
24
+ # @return [Integer] Max count of polling threads
25
+ attr_reader :max_threads
26
+
27
+ # return [Hash] Polling threads pool
28
+ attr_reader :pool
29
+
30
+ # @param [String] key
31
+ # @return [Endpoint]
32
+ def [](key)
33
+ @mutex.synchronize do
34
+ # fetching an existing endpoint delete it and then append it
35
+ endpoint = @entries[key]
36
+ if endpoint
37
+ @entries.delete(key)
38
+ @entries[key] = endpoint
39
+ end
40
+ endpoint
41
+ end
42
+ end
43
+
44
+ # @param [String] key
45
+ # @param [Hash] value
46
+ def []=(key, value)
47
+ @mutex.synchronize do
48
+ # delete the least recent used endpoint when cache is full
49
+ unless @entries.size < @max_entries
50
+ old_key, _ = @entries.shift
51
+ self.delete_polling_thread(old_key)
52
+ end
53
+ # delete old value if exists
54
+ @entries.delete(key)
55
+ @entries[key] = Endpoint.new(value.to_hash)
56
+ end
57
+ end
58
+
59
+ # checking whether an unexpired endpoint key exists in cache
60
+ # @param [String] key
61
+ # @return [Boolean]
62
+ def key?(key)
63
+ if @entries.key?(key) && (@entries[key].nil? || @entries[key].expired?)
64
+ self.delete(key)
65
+ end
66
+ @entries.key?(key)
67
+ end
68
+
69
+ # checking whether an polling thread exist for the key
70
+ # @param [String] key
71
+ # @return [Boolean]
72
+ def threads_key?(key)
73
+ @pool.key?(key)
74
+ end
75
+
76
+ # remove entry only
77
+ # @param [String] key
78
+ def delete(key)
79
+ @mutex.synchronize do
80
+ @entries.delete(key)
81
+ end
82
+ end
83
+
84
+ # kill the old polling thread and remove it from pool
85
+ # @param [String] key
86
+ def delete_polling_thread(key)
87
+ Thread.kill(@pool[key]) if self.threads_key?(key)
88
+ @pool.delete(key)
89
+ end
90
+
91
+ # update cache with requests (using service endpoint operation)
92
+ # to fetch endpoint list (with identifiers when available)
93
+ # @param [String] key
94
+ # @param [RequestContext] ctx
95
+ def update(key, ctx)
96
+ resp = _request_endpoint(ctx)
97
+ if resp && resp.endpoints
98
+ resp.endpoints.each { |e| self[key] = e }
99
+ end
100
+ end
101
+
102
+ # extract the key to be used in the cache from request context
103
+ # @param [RequestContext] ctx
104
+ # @return [String]
105
+ def extract_key(ctx)
106
+ parts = []
107
+ # fetching from cred provider directly gives warnings
108
+ parts << ctx.config.credentials.credentials.access_key_id
109
+ if _endpoint_operation_identifier(ctx)
110
+ parts << ctx.operation_name
111
+ ctx.operation.input.shape.members.inject(parts) do |p, (name, ref)|
112
+ p << ctx.params[name] if ref["endpointdiscoveryid"]
113
+ p
114
+ end
115
+ end
116
+ parts.join('_')
117
+ end
118
+
119
+ # update polling threads pool
120
+ # param [String] key
121
+ # param [Thread] thread
122
+ def update_polling_pool(key, thread)
123
+ unless @pool.size < @max_threads
124
+ _, thread = @pool.shift
125
+ Thread.kill(thread)
126
+ end
127
+ @pool[key] = thread
128
+ end
129
+
130
+ # kill all polling threads
131
+ def stop_polling!
132
+ @pool.each { |_, t| Thread.kill(t) }
133
+ @pool = {}
134
+ end
135
+
136
+ private
137
+
138
+ def _request_endpoint(ctx)
139
+ params = {}
140
+ if _endpoint_operation_identifier(ctx)
141
+ # build identifier params when available
142
+ params[:operation] = ctx.operation.name
143
+ ctx.operation.input.shape.members.inject(params) do |p, (name, ref)|
144
+ if ref["endpointdiscoveryid"]
145
+ p[:identifiers] ||= {}
146
+ p[:identifiers][ref.location_name] = ctx.params[name]
147
+ end
148
+ p
149
+ end
150
+ end
151
+
152
+ begin
153
+ endpoint_operation_name = ctx.config.api.endpoint_operation
154
+ ctx.client.send(endpoint_operation_name, params)
155
+ rescue Aws::Errors::ServiceError
156
+ nil
157
+ end
158
+ end
159
+
160
+ def _endpoint_operation_identifier(ctx)
161
+ return @require_identifier unless @require_identifier.nil?
162
+ operation_name = ctx.config.api.endpoint_operation
163
+ operation = ctx.config.api.operation(operation_name)
164
+ @require_identifier = operation.input.shape.members.any?
165
+ end
166
+
167
+ class Endpoint
168
+
169
+ # default endpoint cache time, 1 minute
170
+ CACHE_PERIOD = 1
171
+
172
+ def initialize(options)
173
+ @address = options.fetch(:address)
174
+ @cache_period = options[:cache_period_in_minutes] || CACHE_PERIOD
175
+ @created_time = Time.now
176
+ end
177
+
178
+ # [String] valid URI address (with path)
179
+ attr_reader :address
180
+
181
+ def expired?
182
+ Time.now - @created_time > @cache_period * 60
183
+ end
184
+
185
+ end
186
+
187
+ end
188
+ end
@@ -34,6 +34,16 @@ module Aws
34
34
  end
35
35
  end
36
36
 
37
+ # Rasied when endpoint discovery failed for operations
38
+ # that requires endpoints from endpoint discovery
39
+ class EndpointDiscoveryError < RuntimeError
40
+ def initialize(*args)
41
+ msg = 'Endpoint discovery failed for the operation or discovered endpoint is not working, '\
42
+ 'request will keep failing until endpoint discovery succeeds or :endpoint option is provided.'
43
+ super(msg)
44
+ end
45
+ end
46
+
37
47
  # Raised when EventStream Parser failed to parse
38
48
  # a raw event message
39
49
  class EventStreamParserError < RuntimeError; end
@@ -0,0 +1,160 @@
1
+ module Aws
2
+ module Plugins
3
+ # @api private
4
+ class EndpointDiscovery < Seahorse::Client::Plugin
5
+
6
+ option(:endpoint_discovery,
7
+ default: false,
8
+ doc_type: 'Boolean',
9
+ docstring: <<-DOCS) do |cfg|
10
+ When set to `true`, endpoint discovery will be enabled for operations when available. Defaults to `false`.
11
+ DOCS
12
+ resolve_endpoint_discovery(cfg)
13
+ end
14
+
15
+ option(:endpoint_cache_max_entries,
16
+ default: 1000,
17
+ doc_type: Integer,
18
+ docstring: <<-DOCS
19
+ Used for the maximum size limit of the LRU cache storing endpoints data
20
+ for endpoint discovery enabled operations. Defaults to 1000.
21
+ DOCS
22
+ )
23
+
24
+ option(:endpoint_cache_max_threads,
25
+ default: 10,
26
+ doc_type: Integer,
27
+ docstring: <<-DOCS
28
+ Used for the maximum threads in use for polling endpoints to be cached, defaults to 10.
29
+ DOCS
30
+ )
31
+
32
+ option(:endpoint_cache_poll_interval,
33
+ default: 60,
34
+ doc_type: Integer,
35
+ docstring: <<-DOCS
36
+ When :endpoint_discovery and :active_endpoint_cache is enabled,
37
+ Use this option to config the time interval in seconds for making
38
+ requests fetching endpoints information. Defaults to 60 sec.
39
+ DOCS
40
+ )
41
+
42
+ option(:endpoint_cache) do |cfg|
43
+ Aws::EndpointCache.new(
44
+ max_entries: cfg.endpoint_cache_max_entries,
45
+ max_threads: cfg.endpoint_cache_max_threads
46
+ )
47
+ end
48
+
49
+ option(:active_endpoint_cache,
50
+ default: false,
51
+ doc_type: 'Boolean',
52
+ docstring: <<-DOCS
53
+ When set to `true`, a thread polling for endpoints will be running in
54
+ the background every 60 secs (default). Defaults to `false`.
55
+ DOCS
56
+ )
57
+
58
+ def add_handlers(handlers, config)
59
+ handlers.add(Handler, priority: 90) if config.regional_endpoint
60
+ end
61
+
62
+ class Handler < Seahorse::Client::Handler
63
+
64
+ def call(context)
65
+ if context.operation.endpoint_operation
66
+ context.http_request.headers['x-amz-api-version'] = context.config.api.version
67
+ _apply_endpoint_discovery_user_agent(context)
68
+ elsif discovery_cfg = context.operation.endpoint_discovery
69
+ endpoint = _discover_endpoint(
70
+ context,
71
+ Aws::Util.str_2_bool(discovery_cfg["required"])
72
+ )
73
+ context.http_request.endpoint = _valid_uri(endpoint.address) if endpoint
74
+ if endpoint || context.config.endpoint_discovery
75
+ _apply_endpoint_discovery_user_agent(context)
76
+ end
77
+ end
78
+ @handler.call(context)
79
+ end
80
+
81
+ private
82
+
83
+ def _valid_uri(address)
84
+ # returned address can be missing scheme
85
+ if address.start_with?('http')
86
+ URI.parse(address)
87
+ else
88
+ URI.parse("https://" + address)
89
+ end
90
+ end
91
+
92
+ def _apply_endpoint_discovery_user_agent(ctx)
93
+ if ctx.config.user_agent_suffix.nil?
94
+ ctx.config.user_agent_suffix = "endpoint-discovery"
95
+ elsif !ctx.config.user_agent_suffix.include? "endpoint-discovery"
96
+ ctx.config.user_agent_suffix += "endpoint-discovery"
97
+ end
98
+ end
99
+
100
+ def _discover_endpoint(ctx, required)
101
+ cache = ctx.config.endpoint_cache
102
+ key = cache.extract_key(ctx)
103
+
104
+ if required
105
+ # required for the operation
106
+ unless cache.key?(key)
107
+ cache.update(key, ctx)
108
+ end
109
+ endpoint = cache[key]
110
+ # hard fail if endpoint is not discovered
111
+ raise Aws::Errors::EndpointDiscoveryError.new unless endpoint
112
+ endpoint
113
+ elsif ctx.config.endpoint_discovery
114
+ # not required for the operation
115
+ # but enabled
116
+ if cache.key?(key)
117
+ cache[key]
118
+ elsif ctx.config.active_endpoint_cache
119
+ # enabled active cache pull
120
+ interval = ctx.config.endpoint_cache_poll_interval
121
+ if key.include?('_')
122
+ # identifier related, kill the previous polling thread by key
123
+ # because endpoint req params might be changed
124
+ cache.delete_polling_thread(key)
125
+ end
126
+
127
+ # start a thread for polling endpoints when non-exist
128
+ unless cache.threads_key?(key)
129
+ thread = Thread.new do
130
+ while !cache.key?(key) do
131
+ cache.update(key, ctx)
132
+ sleep(interval)
133
+ end
134
+ end
135
+ cache.update_polling_pool(key, thread)
136
+ end
137
+
138
+ cache[key]
139
+ else
140
+ # disabled active cache pull
141
+ # attempt, buit fail soft
142
+ cache.update(key, ctx)
143
+ cache[key]
144
+ end
145
+ end
146
+ end
147
+
148
+ end
149
+
150
+ private
151
+
152
+ def self.resolve_endpoint_discovery(cfg)
153
+ env = ENV['AWS_ENABLE_ENDPOINT_DISCOVERY']
154
+ shared_cfg = Aws.shared_config.endpoint_discovery(profile: cfg.profile)
155
+ Aws::Util.str_2_bool(env) || Aws::Util.str_2_bool(shared_cfg)
156
+ end
157
+
158
+ end
159
+ end
160
+ end
@@ -26,6 +26,8 @@ a default `:region` is search for in the following locations:
26
26
  resolve_region(cfg)
27
27
  end
28
28
 
29
+ option(:regional_endpoint, false)
30
+
29
31
  option(:endpoint, doc_type: String, docstring: <<-DOCS) do |cfg|
30
32
  The client endpoint is normally constructed from the `:region`
31
33
  option. You should only configure an `:endpoint` when connecting
@@ -120,12 +120,32 @@ A delay randomiser function used by the default backoff function. Some predefine
120
120
  (500..599).include?(@http_status_code)
121
121
  end
122
122
 
123
+ def endpoint_discovery?(context)
124
+ return false unless context.operation.endpoint_discovery
125
+
126
+ if @http_status_code == 421 ||
127
+ extract_name(@error) == 'InvalidEndpointException'
128
+ @error = Errors::EndpointDiscoveryError.new
129
+ end
130
+
131
+ # When endpoint discovery error occurs
132
+ # evict the endpoint from cache
133
+ if @error.is_a?(Errors::EndpointDiscoveryError)
134
+ key = context.config.endpoint_cache.extract_key(context)
135
+ context.config.endpoint_cache.delete(key)
136
+ true
137
+ else
138
+ false
139
+ end
140
+ end
141
+
123
142
  def retryable?(context)
124
143
  (expired_credentials? and refreshable_credentials?(context)) or
125
144
  throttling_error? or
126
145
  checksum? or
127
146
  networking? or
128
- server?
147
+ server? or
148
+ endpoint_discovery?(context)
129
149
  end
130
150
 
131
151
  private
@@ -136,6 +136,13 @@ module Aws
136
136
  end
137
137
  end
138
138
 
139
+ def endpoint_discovery(opts = {})
140
+ p = opts[:profile] || @profile_name
141
+ if @config_enabled && @parsed_config
142
+ @parsed_config.fetch(p, {})["endpoint_discovery_enabled"]
143
+ end
144
+ end
145
+
139
146
  def credentials_process(profile)
140
147
  validate_profile_exists(profile)
141
148
  @parsed_config[profile]['credential_process']
@@ -52,6 +52,15 @@ module Aws
52
52
  end
53
53
  end
54
54
 
55
+ def str_2_bool(str)
56
+ case str.to_s
57
+ when "true" then true
58
+ when "false" then false
59
+ else
60
+ nil
61
+ end
62
+ end
63
+
55
64
  end
56
65
  end
57
66
  end
@@ -40,6 +40,6 @@ require_relative 'aws-sdk-sts/customizations'
40
40
  # @service
41
41
  module Aws::STS
42
42
 
43
- GEM_VERSION = '3.36.0'
43
+ GEM_VERSION = '3.37.0'
44
44
 
45
45
  end
@@ -15,6 +15,7 @@ require 'aws-sdk-core/plugins/helpful_socket_errors.rb'
15
15
  require 'aws-sdk-core/plugins/retry_errors.rb'
16
16
  require 'aws-sdk-core/plugins/global_configuration.rb'
17
17
  require 'aws-sdk-core/plugins/regional_endpoint.rb'
18
+ require 'aws-sdk-core/plugins/endpoint_discovery.rb'
18
19
  require 'aws-sdk-core/plugins/response_paging.rb'
19
20
  require 'aws-sdk-core/plugins/stub_responses.rb'
20
21
  require 'aws-sdk-core/plugins/idempotency_token.rb'
@@ -45,6 +46,7 @@ module Aws::STS
45
46
  add_plugin(Aws::Plugins::RetryErrors)
46
47
  add_plugin(Aws::Plugins::GlobalConfiguration)
47
48
  add_plugin(Aws::Plugins::RegionalEndpoint)
49
+ add_plugin(Aws::Plugins::EndpointDiscovery)
48
50
  add_plugin(Aws::Plugins::ResponsePaging)
49
51
  add_plugin(Aws::Plugins::StubResponses)
50
52
  add_plugin(Aws::Plugins::IdempotencyToken)
@@ -98,6 +100,10 @@ module Aws::STS
98
100
  #
99
101
  # @option options [String] :access_key_id
100
102
  #
103
+ # @option options [Boolean] :active_endpoint_cache (false)
104
+ # When set to `true`, a thread polling for endpoints will be running in
105
+ # the background every 60 secs (default). Defaults to `false`.
106
+ #
101
107
  # @option options [Boolean] :client_side_monitoring (false)
102
108
  # When `true`, client-side metrics will be collected for all API requests from
103
109
  # this client.
@@ -123,6 +129,21 @@ module Aws::STS
123
129
  # option. You should only configure an `:endpoint` when connecting
124
130
  # to test endpoints. This should be avalid HTTP(S) URI.
125
131
  #
132
+ # @option options [Integer] :endpoint_cache_max_entries (1000)
133
+ # Used for the maximum size limit of the LRU cache storing endpoints data
134
+ # for endpoint discovery enabled operations. Defaults to 1000.
135
+ #
136
+ # @option options [Integer] :endpoint_cache_max_threads (10)
137
+ # Used for the maximum threads in use for polling endpoints to be cached, defaults to 10.
138
+ #
139
+ # @option options [Integer] :endpoint_cache_poll_interval (60)
140
+ # When :endpoint_discovery and :active_endpoint_cache is enabled,
141
+ # Use this option to config the time interval in seconds for making
142
+ # requests fetching endpoints information. Defaults to 60 sec.
143
+ #
144
+ # @option options [Boolean] :endpoint_discovery (false)
145
+ # When set to `true`, endpoint discovery will be enabled for operations when available. Defaults to `false`.
146
+ #
126
147
  # @option options [Aws::Log::Formatter] :log_formatter (Aws::Log::Formatter.default)
127
148
  # The log formatter.
128
149
  #
@@ -1508,7 +1529,7 @@ module Aws::STS
1508
1529
  params: params,
1509
1530
  config: config)
1510
1531
  context[:gem_name] = 'aws-sdk-core'
1511
- context[:gem_version] = '3.36.0'
1532
+ context[:gem_version] = '3.37.0'
1512
1533
  Seahorse::Client::Request.new(handlers, context)
1513
1534
  end
1514
1535
 
@@ -197,7 +197,13 @@ module Seahorse
197
197
 
198
198
  def value_at(opt_name)
199
199
  value = @struct[opt_name]
200
- value.is_a?(Defaults) ? resolve_defaults(opt_name, value) : value
200
+ if value.is_a?(Defaults)
201
+ # this config value is used by endpoint discovery
202
+ @struct[:regional_endpoint] = true if opt_name == :endpoint
203
+ resolve_defaults(opt_name, value)
204
+ else
205
+ value
206
+ end
201
207
  end
202
208
 
203
209
  def resolve_defaults(opt_name, defaults)
@@ -6,6 +6,7 @@ module Seahorse
6
6
  @metadata = {}
7
7
  @operations = {}
8
8
  @authorizers = {}
9
+ @endpoint_operation = nil
9
10
  end
10
11
 
11
12
  # @return [String, nil]
@@ -14,6 +15,9 @@ module Seahorse
14
15
  # @return [Hash]
15
16
  attr_accessor :metadata
16
17
 
18
+ # @return [Symbol|nil]
19
+ attr_accessor :endpoint_operation
20
+
17
21
  def operations(&block)
18
22
  if block_given?
19
23
  @operations.each(&block)
@@ -22,6 +22,12 @@ module Seahorse
22
22
  # @return [Boolean]
23
23
  attr_accessor :deprecated
24
24
 
25
+ # @return [Boolean]
26
+ attr_accessor :endpoint_operation
27
+
28
+ # @return [Hash]
29
+ attr_accessor :endpoint_discovery
30
+
25
31
  # @return [String, nil]
26
32
  attr_accessor :documentation
27
33
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aws-sdk-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.36.0
4
+ version: 3.37.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Amazon Web Services
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-30 00:00:00.000000000 Z
11
+ date: 2018-11-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: jmespath
@@ -90,6 +90,7 @@ files:
90
90
  - lib/aws-sdk-core/deprecations.rb
91
91
  - lib/aws-sdk-core/eager_loader.rb
92
92
  - lib/aws-sdk-core/ecs_credentials.rb
93
+ - lib/aws-sdk-core/endpoint_cache.rb
93
94
  - lib/aws-sdk-core/errors.rb
94
95
  - lib/aws-sdk-core/event_emitter.rb
95
96
  - lib/aws-sdk-core/ini_parser.rb
@@ -116,6 +117,7 @@ files:
116
117
  - lib/aws-sdk-core/plugins/client_metrics_plugin.rb
117
118
  - lib/aws-sdk-core/plugins/client_metrics_send_plugin.rb
118
119
  - lib/aws-sdk-core/plugins/credentials_configuration.rb
120
+ - lib/aws-sdk-core/plugins/endpoint_discovery.rb
119
121
  - lib/aws-sdk-core/plugins/event_stream_configuration.rb
120
122
  - lib/aws-sdk-core/plugins/global_configuration.rb
121
123
  - lib/aws-sdk-core/plugins/helpful_socket_errors.rb