Skip to content

Commit 378dfa6

Browse files
authored
Add support for default configuration modes (#2624)
1 parent 9e917e3 commit 378dfa6

31 files changed

+873
-14
lines changed

build_tools/aws-sdk-code-generator/lib/aws-sdk-code-generator/plugin_list.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ def default_plugins
5858
'Aws::Plugins::ClientMetricsPlugin' => "#{core_plugins}/client_metrics_plugin.rb",
5959
'Aws::Plugins::ClientMetricsSendPlugin' => "#{core_plugins}/client_metrics_send_plugin.rb",
6060
'Aws::Plugins::TransferEncoding' => "#{core_plugins}/transfer_encoding.rb",
61-
'Aws::Plugins::HttpChecksum' => "#{core_plugins}/http_checksum.rb"
61+
'Aws::Plugins::HttpChecksum' => "#{core_plugins}/http_checksum.rb",
62+
'Aws::Plugins::DefaultsMode' => "#{core_plugins}/defaults_mode.rb"
6263
}
6364
end
6465

build_tools/aws-sdk-code-generator/templates/client_class.mustache

+4-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ module {{module_name}}
4545
# seconds to wait when opening a HTTP session before raising a
4646
# `Timeout::Error`.
4747
#
48-
# @option options [Integer] :http_read_timeout (60) The default
48+
# @option options [Float] :http_read_timeout (60) The default
4949
# number of seconds to wait for response data. This value can
5050
# safely be set per-request on the session.
5151
#
@@ -61,6 +61,9 @@ module {{module_name}}
6161
# disables this behaviour. This value can safely be set per
6262
# request on the session.
6363
#
64+
# @option options [Float] :ssl_timeout (nil) Sets the SSL timeout
65+
# in seconds.
66+
#
6467
# @option options [Boolean] :http_wire_trace (false) When `true`,
6568
# HTTP debug output will be sent to the `:logger`.
6669
#

build_tools/custom_service.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ def build
4343
'Aws::Plugins::RegionalEndpoint',
4444
'Aws::Plugins::EndpointDiscovery',
4545
'Aws::Plugins::EndpointPattern',
46-
'Aws::Plugins::CredentialsConfiguration'
46+
'Aws::Plugins::CredentialsConfiguration',
47+
'Aws::Plugins::DefaultsMode'
4748
]
4849
)
4950
end

build_tools/services.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class ServiceEnumerator
1010
MANIFEST_PATH = File.expand_path('../../services.json', __FILE__)
1111

1212
# Minimum `aws-sdk-core` version for new gem builds
13-
MINIMUM_CORE_VERSION = "3.122.0"
13+
MINIMUM_CORE_VERSION = "3.125.0"
1414

1515
EVENTSTREAM_PLUGIN = "Aws::Plugins::EventStreamConfiguration"
1616

gems/aws-sdk-core/CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
Unreleased Changes
22
------------------
33

4+
* Feature - Add `:defaults_mode` configuration - that determines how certain default configuration options are resolved in the SDK.
5+
46
3.124.0 (2021-11-30)
57
------------------
68

gems/aws-sdk-core/lib/aws-defaults.rb

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# frozen_string_literal: true
2+
3+
require_relative 'aws-defaults/default_configuration'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
# frozen_string_literal: true
2+
3+
require_relative 'defaults_mode_config_resolver'
4+
5+
module Aws
6+
7+
# A defaults mode determines how certain default configuration options are resolved in the SDK.
8+
#
9+
# *Note*: For any mode other than `'legacy'` the vended default values might change as best practices may
10+
# evolve. As a result, it is encouraged to perform testing when upgrading the SDK if you are using a mode other than
11+
# `'legacy'`. While the `'legacy'` defaults mode is specific to Ruby,
12+
# other modes are standardized across all of the AWS SDKs.
13+
#
14+
# The defaults mode can be configured:
15+
#
16+
# * Directly on a client via `:defaults_mode`
17+
#
18+
# * On a configuration profile via the "defaults_mode" profile file property.
19+
#
20+
# * Globally via the "AWS_DEFAULTS_MODE" environment variable.
21+
#
22+
#
23+
# @code_generation START - documentation
24+
# The following `:default_mode` values are supported:
25+
#
26+
# * `'standard'` -
27+
# The STANDARD mode provides the latest recommended default values
28+
# that should be safe to run in most scenarios
29+
#
30+
# Note that the default values vended from this mode might change as
31+
# best practices may evolve. As a result, it is encouraged to perform
32+
# tests when upgrading the SDK
33+
#
34+
# * `'in-region'` -
35+
# The IN\_REGION mode builds on the standard mode and includes
36+
# optimization tailored for applications which call AWS services from
37+
# within the same AWS region
38+
#
39+
# Note that the default values vended from this mode might change as
40+
# best practices may evolve. As a result, it is encouraged to perform
41+
# tests when upgrading the SDK
42+
#
43+
# * `'cross-region'` -
44+
# The CROSS\_REGION mode builds on the standard mode and includes
45+
# optimization tailored for applications which call AWS services in a
46+
# different region
47+
#
48+
# Note that the default values vended from this mode might change as
49+
# best practices may evolve. As a result, it is encouraged to perform
50+
# tests when upgrading the SDK
51+
#
52+
# * `'mobile'` -
53+
# The MOBILE mode builds on the standard mode and includes
54+
# optimization tailored for mobile applications
55+
#
56+
# Note that the default values vended from this mode might change as
57+
# best practices may evolve. As a result, it is encouraged to perform
58+
# tests when upgrading the SDK
59+
#
60+
# * `'auto'` -
61+
# The AUTO mode is an experimental mode that builds on the standard
62+
# mode. The SDK will attempt to discover the execution environment to
63+
# determine the appropriate settings automatically.
64+
#
65+
# Note that the auto detection is heuristics-based and does not
66+
# guarantee 100% accuracy. STANDARD mode will be used if the execution
67+
# environment cannot be determined. The auto detection might query
68+
# [EC2 Instance Metadata service][1], which might introduce latency.
69+
# Therefore we recommend choosing an explicit defaults\_mode instead
70+
# if startup latency is critical to your application
71+
#
72+
# * `'legacy'` -
73+
# The LEGACY mode provides default settings that vary per SDK and were
74+
# used prior to establishment of defaults\_mode
75+
#
76+
# Based on the provided mode, the SDK will vend sensible default values
77+
# tailored to the mode for the following settings:
78+
#
79+
# * `:retry_mode` -
80+
# A retry mode specifies how the SDK attempts retries. See [Retry
81+
# Mode][2]
82+
#
83+
# * `:sts_regional_endpoints` -
84+
# Specifies how the SDK determines the AWS service endpoint that it
85+
# uses to talk to the AWS Security Token Service (AWS STS). See
86+
# [Setting STS Regional endpoints][3]
87+
#
88+
# * `:s3_us_east_1_regional_endpoint` -
89+
# Specifies how the SDK determines the AWS service endpoint that it
90+
# uses to talk to the Amazon S3 for the us-east-1 region
91+
#
92+
# * `:http_open_timeout` -
93+
# The amount of time after making an initial connection attempt on a
94+
# socket, where if the client does not receive a completion of the
95+
# connect handshake, the client gives up and fails the operation
96+
#
97+
# * `:ssl_timeout` -
98+
# The maximum amount of time that a TLS handshake is allowed to take
99+
# from the time the CLIENT HELLO message is sent to ethe time the
100+
# client and server have fully negotiated ciphers and exchanged keys
101+
#
102+
# All options above can be configured by users, and the overridden value will take precedence.
103+
#
104+
# [1]: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html
105+
# [2]: https://docs.aws.amazon.com/sdkref/latest/guide/setting-global-retry_mode.html
106+
# [3]: https://docs.aws.amazon.com/sdkref/latest/guide/setting-global-sts_regional_endpoints.html
107+
#
108+
# @code_generation END - documentation
109+
module DefaultsModeConfiguration
110+
# @api private
111+
# @code_generation START - configuration
112+
SDK_DEFAULT_CONFIGURATION =
113+
{
114+
"version" => 1,
115+
"base" => {
116+
"retryMode" => "standard",
117+
"stsRegionalEndpoints" => "regional",
118+
"s3UsEast1RegionalEndpoints" => "regional",
119+
"connectTimeoutInMillis" => 1100,
120+
"tlsNegotiationTimeoutInMillis" => 1100
121+
},
122+
"modes" => {
123+
"standard" => {
124+
"connectTimeoutInMillis" => {
125+
"override" => 3100
126+
},
127+
"tlsNegotiationTimeoutInMillis" => {
128+
"override" => 3100
129+
}
130+
},
131+
"in-region" => {
132+
},
133+
"cross-region" => {
134+
"connectTimeoutInMillis" => {
135+
"override" => 3100
136+
},
137+
"tlsNegotiationTimeoutInMillis" => {
138+
"override" => 3100
139+
}
140+
},
141+
"mobile" => {
142+
"connectTimeoutInMillis" => {
143+
"override" => 30000
144+
},
145+
"tlsNegotiationTimeoutInMillis" => {
146+
"override" => 30000
147+
}
148+
}
149+
}
150+
}
151+
# @code_generation END - configuration
152+
end
153+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
# frozen_string_literal: true
2+
3+
module Aws
4+
#@api private
5+
class DefaultsModeConfigResolver
6+
7+
@@application_region = nil
8+
@@application_region_mutex = Mutex.new
9+
@@imds_client = EC2Metadata.new(retries: 0, http_open_timeout: 0.01)
10+
11+
# mappings from Ruby SDK configuration names to the
12+
# sdk defaults option names and (optional) scale modifiers
13+
CFG_OPTIONS = {
14+
retry_mode: { name: "retryMode" },
15+
sts_regional_endpoints: { name: "stsRegionalEndpoints" },
16+
s3_us_east_1_regional_endpoint: { name: "s3UsEast1RegionalEndpoints" },
17+
http_open_timeout: { name: "connectTimeoutInMillis", scale: 0.001 },
18+
http_read_timeout: { name: "timeToFirstByteTimeoutInMillis", scale: 0.001 },
19+
ssl_timeout: { name: "tlsNegotiationTimeoutInMillis", scale: 0.001 }
20+
}.freeze
21+
22+
def initialize(sdk_defaults, cfg)
23+
@sdk_defaults = sdk_defaults
24+
@cfg = cfg
25+
@resolved_mode = nil
26+
@mutex = Mutex.new
27+
end
28+
29+
# option_name should be the symbolized ruby name to resolve
30+
# returns the ruby appropriate value or nil if none are resolved
31+
def resolve(option_name)
32+
return unless (std_option = CFG_OPTIONS[option_name])
33+
mode = resolved_mode.downcase
34+
35+
return nil if mode == 'legacy'
36+
37+
value = resolve_for_mode(std_option[:name], mode)
38+
value = value * std_option[:scale] if value && std_option[:scale]
39+
40+
value
41+
end
42+
43+
private
44+
def resolved_mode
45+
@mutex.synchronize do
46+
return @resolved_mode unless @resolved_mode.nil?
47+
48+
@resolved_mode = @cfg.defaults_mode == 'auto' ? resolve_auto_mode : @cfg.defaults_mode
49+
end
50+
end
51+
52+
def resolve_auto_mode
53+
return "mobile" if env_mobile?
54+
55+
region = application_current_region
56+
57+
if region
58+
@cfg.region == region ? "in-region": "cross-region"
59+
else
60+
# We don't seem to be mobile, and we couldn't determine whether we're running within an AWS region. Fall back to standard.
61+
'standard'
62+
end
63+
end
64+
65+
def application_current_region
66+
resolved_region = @@application_region_mutex.synchronize do
67+
return @@application_region unless @@application_region.nil?
68+
69+
region = nil
70+
if ENV['AWS_EXECUTION_ENV']
71+
region = ENV['AWS_REGION'] || ENV['AWS_DEFAULT_REGION']
72+
end
73+
74+
if region.nil? && ENV['AWS_EC2_METADATA_DISABLED']&.downcase != "true"
75+
begin
76+
region = @@imds_client.get('/latest/meta-data/placement/region')
77+
rescue
78+
# unable to get region, leave it unset
79+
end
80+
end
81+
82+
# required so that we cache the unknown/nil result
83+
@@application_region = region || :unknown
84+
end
85+
resolved_region == :unknown ? nil : resolved_region
86+
end
87+
88+
def resolve_for_mode(name, mode)
89+
base_value = @sdk_defaults['base'][name]
90+
mode_value = @sdk_defaults['modes'].fetch(mode, {})[name]
91+
92+
if mode_value.nil?
93+
return base_value
94+
end
95+
96+
return mode_value['override'] unless mode_value['override'].nil?
97+
return base_value + mode_value['add'] unless mode_value['add'].nil?
98+
return base_value * mode_value['multiply'] unless mode_value['multiply'].nil?
99+
return base_value
100+
end
101+
102+
def env_mobile?
103+
false
104+
end
105+
106+
end
107+
end

gems/aws-sdk-core/lib/aws-sdk-core.rb

+3
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@
8888
require_relative 'aws-sdk-core/arn_parser'
8989
require_relative 'aws-sdk-core/ec2_metadata'
9090

91+
# defaults
92+
require_relative 'aws-defaults'
93+
9194
# plugins
9295
# loaded through building STS or SSO ..
9396

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# frozen_string_literal: true
2+
3+
module Aws
4+
# @api private
5+
module Plugins
6+
# @api private
7+
class DefaultsMode < Seahorse::Client::Plugin
8+
9+
option(:defaults_mode,
10+
default: 'legacy',
11+
doc_type: String,
12+
docstring: <<-DOCS
13+
See {Aws::DefaultsModeConfiguration} for a list of the
14+
accepted modes and the configuration defaults that are included.
15+
DOCS
16+
) do |cfg|
17+
resolve_defaults_mode(cfg)
18+
end
19+
20+
option(:defaults_mode_config_resolver,
21+
doc_type: 'Aws::DefaultsModeConfigResolver') do |cfg|
22+
Aws::DefaultsModeConfigResolver.new(
23+
Aws::DefaultsModeConfiguration::SDK_DEFAULT_CONFIGURATION, cfg)
24+
end
25+
26+
class << self
27+
private
28+
29+
def resolve_defaults_mode(cfg)
30+
value = ENV['AWS_DEFAULTS_MODE']
31+
value ||= Aws.shared_config.defaults_mode(
32+
profile: cfg.profile
33+
)
34+
value&.downcase || "legacy"
35+
end
36+
end
37+
38+
end
39+
end
40+
end

gems/aws-sdk-core/lib/aws-sdk-core/plugins/retry_errors.rb

+9-3
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,15 @@ class RetryErrors < Seahorse::Client::Plugin
163163
option(:clock_skew) { Retries::ClockSkew.new }
164164

165165
def self.resolve_retry_mode(cfg)
166-
value = ENV['AWS_RETRY_MODE'] ||
167-
Aws.shared_config.retry_mode(profile: cfg.profile) ||
168-
'legacy'
166+
default_mode_value =
167+
if cfg.respond_to?(:defaults_mode_config_resolver)
168+
cfg.defaults_mode_config_resolver.resolve(:retry_mode)
169+
end
170+
171+
value = ENV['AWS_RETRY_MODE'] ||
172+
Aws.shared_config.retry_mode(profile: cfg.profile) ||
173+
default_mode_value ||
174+
'legacy'
169175
# Raise if provided value is not one of the retry modes
170176
if value != 'legacy' && value != 'standard' && value != 'adaptive'
171177
raise ArgumentError,

0 commit comments

Comments
 (0)