aws-sdk-core 2.0.3 → 2.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/apis/CognitoIdentity.api.json +16 -4
- data/apis/EC2.paginators.json +3 -0
- data/apis/ElastiCache.api.json +164 -15
- data/apis/IAM.api.json +326 -1
- data/apis/IAM.resources.json +2 -29
- data/apis/Route53Domains.api.json +56 -0
- data/apis/S3.api.json +1 -1
- data/endpoints.json +62 -76
- data/lib/aws-sdk-core.rb +4 -14
- data/lib/aws-sdk-core/api/documenter.rb +1 -1
- data/lib/aws-sdk-core/api/service_customizations.rb +1 -0
- data/lib/aws-sdk-core/assume_role_credentials.rb +46 -0
- data/lib/aws-sdk-core/autoscaling.rb +3 -3
- data/lib/aws-sdk-core/cloudformation.rb +3 -3
- data/lib/aws-sdk-core/cloudfront.rb +4 -4
- data/lib/aws-sdk-core/cloudsearch.rb +3 -3
- data/lib/aws-sdk-core/cloudsearchdomain.rb +2 -2
- data/lib/aws-sdk-core/cloudtrail.rb +3 -3
- data/lib/aws-sdk-core/cloudwatch.rb +3 -3
- data/lib/aws-sdk-core/cloudwatchlogs.rb +3 -3
- data/lib/aws-sdk-core/cognitoidentity.rb +2 -2
- data/lib/aws-sdk-core/cognitosync.rb +2 -2
- data/lib/aws-sdk-core/datapipeline.rb +3 -3
- data/lib/aws-sdk-core/directconnect.rb +3 -3
- data/lib/aws-sdk-core/dynamodb.rb +4 -4
- data/lib/aws-sdk-core/ec2.rb +5 -5
- data/lib/aws-sdk-core/elasticache.rb +3 -3
- data/lib/aws-sdk-core/elasticbeanstalk.rb +3 -3
- data/lib/aws-sdk-core/elasticloadbalancing.rb +3 -3
- data/lib/aws-sdk-core/elastictranscoder.rb +4 -4
- data/lib/aws-sdk-core/emr.rb +3 -3
- data/lib/aws-sdk-core/endpoint_provider.rb +16 -78
- data/lib/aws-sdk-core/glacier.rb +5 -5
- data/lib/aws-sdk-core/iam.rb +4 -4
- data/lib/aws-sdk-core/importexport.rb +3 -3
- data/lib/aws-sdk-core/instance_profile_credentials.rb +13 -45
- data/lib/aws-sdk-core/kinesis.rb +3 -3
- data/lib/aws-sdk-core/opsworks.rb +4 -4
- data/lib/aws-sdk-core/pageable_response.rb +18 -0
- data/lib/aws-sdk-core/plugins/regional_endpoint.rb +1 -5
- data/lib/aws-sdk-core/plugins/request_signer.rb +3 -9
- data/lib/aws-sdk-core/plugins/s3_region_detection.rb +157 -0
- data/lib/aws-sdk-core/plugins/stub_responses.rb +13 -1
- data/lib/aws-sdk-core/rds.rb +4 -4
- data/lib/aws-sdk-core/redshift.rb +4 -4
- data/lib/aws-sdk-core/refreshing_credentials.rb +73 -0
- data/lib/aws-sdk-core/route53.rb +3 -3
- data/lib/aws-sdk-core/route53domains.rb +2 -2
- data/lib/aws-sdk-core/s3.rb +24 -5
- data/lib/aws-sdk-core/s3/bucket_region_cache.rb +75 -0
- data/lib/aws-sdk-core/ses.rb +4 -4
- data/lib/aws-sdk-core/signers/v4.rb +1 -1
- data/lib/aws-sdk-core/simpledb.rb +3 -3
- data/lib/aws-sdk-core/sns.rb +4 -4
- data/lib/aws-sdk-core/sqs.rb +4 -4
- data/lib/aws-sdk-core/storagegateway.rb +3 -3
- data/lib/aws-sdk-core/sts.rb +2 -2
- data/lib/aws-sdk-core/support.rb +3 -3
- data/lib/aws-sdk-core/swf.rb +3 -3
- data/lib/aws-sdk-core/version.rb +1 -1
- metadata +6 -2
@@ -0,0 +1,157 @@
|
|
1
|
+
module Aws
|
2
|
+
module Plugins
|
3
|
+
# This plugin is an implementation detail and may be modified.
|
4
|
+
# @api private
|
5
|
+
class S3RegionDetection < Seahorse::Client::Plugin
|
6
|
+
|
7
|
+
# Intentionally not documented - this should go away when all
|
8
|
+
# services support signature version 4 in every region.
|
9
|
+
option(:signature_version) do |cfg|
|
10
|
+
if S3.sigv2_region?(cfg.region)
|
11
|
+
's3'
|
12
|
+
else
|
13
|
+
'v4'
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Handler < Seahorse::Client::Handler
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def new_hostname(context, region)
|
22
|
+
bucket = context.params[:bucket]
|
23
|
+
if region == 'us-east-1'
|
24
|
+
"#{bucket}.s3-external-1.amazonaws.com"
|
25
|
+
else
|
26
|
+
"#{bucket}.s3.#{region}.amazonaws.com"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
class CachedBucketRegionHandler < Handler
|
33
|
+
|
34
|
+
def call(context)
|
35
|
+
if bucket = context.params[:bucket]
|
36
|
+
use_regional_endpoint_when_known(context, bucket)
|
37
|
+
end
|
38
|
+
@handler.call(context)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def use_regional_endpoint_when_known(context, bucket)
|
44
|
+
cached_region = S3::BUCKET_REGIONS[bucket]
|
45
|
+
if cached_region && cached_region != context.config.region
|
46
|
+
context.http_request.endpoint.host = new_hostname(context, cached_region)
|
47
|
+
context[:sigv4_region] = cached_region
|
48
|
+
context[:signature_version] =
|
49
|
+
S3.sigv2_region?(cached_region) ? 's3' : 'v4'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
class DetectRegionHandler < Handler
|
56
|
+
|
57
|
+
def call(context)
|
58
|
+
response = @handler.call(context)
|
59
|
+
handle_region_errors(response)
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def handle_region_errors(response)
|
65
|
+
if requires_sigv4?(response)
|
66
|
+
detect_region_and_retry(response)
|
67
|
+
elsif wrong_sigv4_region?(response)
|
68
|
+
extract_body_region_and_retry(response.context)
|
69
|
+
elsif moved_permanently?(response) and dns_style?(response.context)
|
70
|
+
# region detection not supported for 301 moved permanently
|
71
|
+
# when using path style
|
72
|
+
detect_region_and_retry(response) else
|
73
|
+
response
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def requires_sigv4?(resp)
|
78
|
+
resp.context.http_response.status_code == 400 &&
|
79
|
+
resp.context.http_response.body_contents.include?('Please use AWS4-HMAC-SHA256') &&
|
80
|
+
resp.context.http_response.body.respond_to?(:truncate)
|
81
|
+
end
|
82
|
+
|
83
|
+
def wrong_sigv4_region?(resp)
|
84
|
+
resp.context.http_response.status_code == 400 &&
|
85
|
+
resp.context.http_response.body_contents.match(/<Region>.+?<\/Region>/)
|
86
|
+
end
|
87
|
+
|
88
|
+
def moved_permanently?(resp)
|
89
|
+
resp.context.http_response.status_code == 301
|
90
|
+
end
|
91
|
+
|
92
|
+
def extract_body_region_and_retry(context)
|
93
|
+
actual_region = region_from_body(context)
|
94
|
+
updgrade_to_v4(context, actual_region)
|
95
|
+
log_warning(context, actual_region)
|
96
|
+
@handler.call(context)
|
97
|
+
end
|
98
|
+
|
99
|
+
def region_from_body(context)
|
100
|
+
context.http_response.body_contents.match(/<Region>(.+?)<\/Region>/)[1]
|
101
|
+
end
|
102
|
+
|
103
|
+
def detect_region_and_retry(resp)
|
104
|
+
context = resp.context
|
105
|
+
updgrade_to_v4(context, 'us-east-1')
|
106
|
+
resp = @handler.call(context)
|
107
|
+
actual_region = region_from_location_header(context)
|
108
|
+
updgrade_to_v4(context, actual_region)
|
109
|
+
log_warning(context, actual_region)
|
110
|
+
@handler.call(context)
|
111
|
+
end
|
112
|
+
|
113
|
+
def updgrade_to_v4(context, region)
|
114
|
+
bucket = context.params[:bucket]
|
115
|
+
context.http_response.body.truncate(0)
|
116
|
+
context.http_request.headers.delete('authorization')
|
117
|
+
context.http_request.headers.delete('x-amz-security-token')
|
118
|
+
context.http_request.endpoint.host = new_hostname(context, region)
|
119
|
+
signer = Signers::V4.new(context.config.credentials, 's3', region)
|
120
|
+
signer.sign(context.http_request)
|
121
|
+
end
|
122
|
+
|
123
|
+
def dns_style?(context)
|
124
|
+
bucket = context.params[:bucket]
|
125
|
+
context.http_request.endpoint.host.match(/^#{Regexp.escape(bucket)}\.s3/)
|
126
|
+
end
|
127
|
+
|
128
|
+
def region_from_location_header(context)
|
129
|
+
location = context.http_response.headers['location']
|
130
|
+
location.match(/s3\.(.+?)\.amazonaws\.com/)[1]
|
131
|
+
end
|
132
|
+
|
133
|
+
def log_warning(context, actual_region)
|
134
|
+
S3::BUCKET_REGIONS[context.params[:bucket]] = actual_region
|
135
|
+
msg = "S3 client configured for #{context.config.region.inspect} " +
|
136
|
+
"but the bucket #{context.params[:bucket].inspect} is in " +
|
137
|
+
"#{actual_region.inspect}; Please configure the proper region " +
|
138
|
+
"to avoid multiple unecessary redirects and signing attempts"
|
139
|
+
if logger = context.config.logger
|
140
|
+
logger.warn(msg)
|
141
|
+
else
|
142
|
+
warn(msg)
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
# BEFORE the request is signed
|
150
|
+
handle(CachedBucketRegionHandler, step: :sign, priority: 60)
|
151
|
+
|
152
|
+
# AFTER the request is signed
|
153
|
+
handle(DetectRegionHandler, step: :sign, priority: 40)
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
@@ -14,13 +14,25 @@ module Aws
|
|
14
14
|
|
15
15
|
option(:stub_responses, false)
|
16
16
|
|
17
|
+
option(:region) do |config|
|
18
|
+
'stubbed-region' if config.stub_responses
|
19
|
+
end
|
20
|
+
|
21
|
+
option(:credentials) do |config|
|
22
|
+
if config.stub_responses
|
23
|
+
Credentials.new('stubbed-akid', 'stubbed-secret')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
17
27
|
def add_handlers(handlers, config)
|
18
28
|
handlers.add(Handler, step: :send) if config.stub_responses
|
19
29
|
end
|
20
30
|
|
21
31
|
def after_initialize(client)
|
22
32
|
# disable retries when stubbing responses
|
23
|
-
|
33
|
+
if client.config.stub_responses
|
34
|
+
client.handlers.remove(RetryErrors::Handler)
|
35
|
+
end
|
24
36
|
end
|
25
37
|
|
26
38
|
class Handler < Seahorse::Client::Handler
|
data/lib/aws-sdk-core/rds.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Aws.add_service(:RDS, {
|
2
|
-
api: File.join(Aws::
|
3
|
-
docs: File.join(Aws::
|
4
|
-
paginators: File.join(Aws::
|
5
|
-
waiters: File.join(Aws::
|
2
|
+
api: File.join(Aws::API_DIR, 'RDS.api.json'),
|
3
|
+
docs: File.join(Aws::API_DIR, 'RDS.docs.json'),
|
4
|
+
paginators: File.join(Aws::API_DIR, 'RDS.paginators.json'),
|
5
|
+
waiters: File.join(Aws::API_DIR, 'RDS.waiters.json'),
|
6
6
|
})
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Aws.add_service(:Redshift, {
|
2
|
-
api: File.join(Aws::
|
3
|
-
docs: File.join(Aws::
|
4
|
-
paginators: File.join(Aws::
|
5
|
-
waiters: File.join(Aws::
|
2
|
+
api: File.join(Aws::API_DIR, 'Redshift.api.json'),
|
3
|
+
docs: File.join(Aws::API_DIR, 'Redshift.docs.json'),
|
4
|
+
paginators: File.join(Aws::API_DIR, 'Redshift.paginators.json'),
|
5
|
+
waiters: File.join(Aws::API_DIR, 'Redshift.waiters.json'),
|
6
6
|
})
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
|
5
|
+
# Base class used credential classes that can be refreshed. This
|
6
|
+
# provides basic refresh logic in a thread-safe manor. Classes mixing in
|
7
|
+
# this module are expected to implement a #refresh method that populates
|
8
|
+
# the following instance variables:
|
9
|
+
#
|
10
|
+
# * `@access_key_id`
|
11
|
+
# * `@secret_access_key`
|
12
|
+
# * `@session_token`
|
13
|
+
# * `@expiration`
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
module RefreshingCredentials
|
17
|
+
|
18
|
+
def initialize(options = {})
|
19
|
+
@mutex = Mutex.new
|
20
|
+
refresh
|
21
|
+
end
|
22
|
+
|
23
|
+
# @return [String,nil]
|
24
|
+
def access_key_id
|
25
|
+
refresh_if_near_expiration
|
26
|
+
@access_key_id
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [String,nil]
|
30
|
+
def secret_access_key
|
31
|
+
refresh_if_near_expiration
|
32
|
+
@secret_access_key
|
33
|
+
end
|
34
|
+
|
35
|
+
# @return [String,nil]
|
36
|
+
def session_token
|
37
|
+
refresh_if_near_expiration
|
38
|
+
@session_token
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [Time,nil]
|
42
|
+
def expiration
|
43
|
+
refresh_if_near_expiration
|
44
|
+
@expiration
|
45
|
+
end
|
46
|
+
|
47
|
+
# Refresh credentials.
|
48
|
+
# @return [void]
|
49
|
+
def refresh!
|
50
|
+
@mutex.synchronize { refresh }
|
51
|
+
end
|
52
|
+
|
53
|
+
private
|
54
|
+
|
55
|
+
# Refreshes instance metadata credentials if they are within
|
56
|
+
# 5 minutes of expiration.
|
57
|
+
def refresh_if_near_expiration
|
58
|
+
if near_expiration?
|
59
|
+
@mutex.synchronize do
|
60
|
+
refresh if near_expiration?
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def near_expiration?
|
66
|
+
if @expiration
|
67
|
+
# are we within 5 minutes of expiration?
|
68
|
+
(Time.now.to_i + 5 * 60) > @expiration.to_i
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
data/lib/aws-sdk-core/route53.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
Aws.add_service(:Route53, {
|
2
|
-
api: File.join(Aws::
|
3
|
-
docs: File.join(Aws::
|
4
|
-
paginators: File.join(Aws::
|
2
|
+
api: File.join(Aws::API_DIR, 'Route53.api.json'),
|
3
|
+
docs: File.join(Aws::API_DIR, 'Route53.docs.json'),
|
4
|
+
paginators: File.join(Aws::API_DIR, 'Route53.paginators.json'),
|
5
5
|
})
|
@@ -1,4 +1,4 @@
|
|
1
1
|
Aws.add_service(:Route53Domains, {
|
2
|
-
api: File.join(Aws::
|
3
|
-
docs: File.join(Aws::
|
2
|
+
api: File.join(Aws::API_DIR, 'Route53Domains.api.json'),
|
3
|
+
docs: File.join(Aws::API_DIR, 'Route53Domains.docs.json'),
|
4
4
|
})
|
data/lib/aws-sdk-core/s3.rb
CHANGED
@@ -1,13 +1,32 @@
|
|
1
1
|
Aws.add_service(:S3, {
|
2
|
-
api: File.join(Aws::
|
3
|
-
docs: File.join(Aws::
|
4
|
-
paginators: File.join(Aws::
|
5
|
-
resources: File.join(Aws::
|
6
|
-
waiters: File.join(Aws::
|
2
|
+
api: File.join(Aws::API_DIR, 'S3.api.json'),
|
3
|
+
docs: File.join(Aws::API_DIR, 'S3.docs.json'),
|
4
|
+
paginators: File.join(Aws::API_DIR, 'S3.paginators.json'),
|
5
|
+
resources: File.join(Aws::API_DIR, 'S3.resources.json'),
|
6
|
+
waiters: File.join(Aws::API_DIR, 'S3.waiters.json'),
|
7
7
|
})
|
8
8
|
|
9
9
|
module Aws
|
10
10
|
module S3
|
11
|
+
|
11
12
|
autoload :Presigner, 'aws-sdk-core/s3/presigner'
|
13
|
+
autoload :BucketRegionCache, 'aws-sdk-core/s3/bucket_region_cache'
|
14
|
+
|
15
|
+
# A cache of discovered bucket regions. You can call `#bucket_added`
|
16
|
+
# on this to be notified when you must configure the proper region
|
17
|
+
# to access a bucket.
|
18
|
+
#
|
19
|
+
# This cache is considered an implementation detail.
|
20
|
+
#
|
21
|
+
# @api private
|
22
|
+
BUCKET_REGIONS = BucketRegionCache.new
|
23
|
+
|
24
|
+
# @param [String] region
|
25
|
+
# @return [Boolean]
|
26
|
+
# @api private
|
27
|
+
def self.sigv2_region?(region)
|
28
|
+
Client.api.metadata('sigv2Regions').include?(region)
|
29
|
+
end
|
30
|
+
|
12
31
|
end
|
13
32
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module Aws
|
4
|
+
module S3
|
5
|
+
class BucketRegionCache
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@regions = {}
|
9
|
+
@listeners = []
|
10
|
+
@mutex = Mutex.new
|
11
|
+
end
|
12
|
+
|
13
|
+
# Registers a block as a callback. This listener is called when a
|
14
|
+
# new bucket/region pair is added to the cache.
|
15
|
+
#
|
16
|
+
# S3::BUCKET_REGIONS.bucket_added do |bucket_name, region_name|
|
17
|
+
# # ...
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# This happens when a request is made against the classic endpoint,
|
21
|
+
# "s3.amazonaws.com" and an error is returned requiring the request
|
22
|
+
# to be resent with Signature Version 4. At this point, multiple
|
23
|
+
# requests are made to discover the bucket region so that a v4
|
24
|
+
# signature can be generated.
|
25
|
+
#
|
26
|
+
# An application can register listeners here to avoid these extra
|
27
|
+
# requests in the future. By constructing an {S3::Client} with
|
28
|
+
# the proper region, a proper signature can be generated and redirects
|
29
|
+
# avoided.
|
30
|
+
# @return [void]
|
31
|
+
def bucket_added(&block)
|
32
|
+
if block
|
33
|
+
@mutex.synchronize { @listeners << block }
|
34
|
+
else
|
35
|
+
raise ArgumentError, 'missing required block'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# @param [String] bucket_name
|
40
|
+
# @return [String,nil] Returns the cached region for the named bucket.
|
41
|
+
# Returns `nil` if the bucket is not in the cache.
|
42
|
+
# @api private
|
43
|
+
def [](bucket_name)
|
44
|
+
@mutex.synchronize { @regions[bucket_name] }
|
45
|
+
end
|
46
|
+
|
47
|
+
# Caches a bucket's region. Calling this method will trigger each
|
48
|
+
# of the {#bucket_added} listener callbacks.
|
49
|
+
# @param [String] bucket_name
|
50
|
+
# @param [String] region_name
|
51
|
+
# @return [void]
|
52
|
+
# @api private
|
53
|
+
def []=(bucket_name, region_name)
|
54
|
+
@mutex.synchronize do
|
55
|
+
@regions[bucket_name] = region_name
|
56
|
+
@listeners.each { |block| block.call(bucket_name, region_name) }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# @api private
|
61
|
+
def clear
|
62
|
+
@mutex.synchronize { @regions = {} }
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [Hash] Returns a hash of cached bucket names and region names.
|
66
|
+
def to_hash
|
67
|
+
@mutex.synchronize do
|
68
|
+
@regions.dup
|
69
|
+
end
|
70
|
+
end
|
71
|
+
alias to_h to_hash
|
72
|
+
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/aws-sdk-core/ses.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Aws.add_service(:SES, {
|
2
|
-
api: File.join(Aws::
|
3
|
-
docs: File.join(Aws::
|
4
|
-
paginators: File.join(Aws::
|
5
|
-
waiters: File.join(Aws::
|
2
|
+
api: File.join(Aws::API_DIR, 'SES.api.json'),
|
3
|
+
docs: File.join(Aws::API_DIR, 'SES.docs.json'),
|
4
|
+
paginators: File.join(Aws::API_DIR, 'SES.paginators.json'),
|
5
|
+
waiters: File.join(Aws::API_DIR, 'SES.waiters.json'),
|
6
6
|
})
|
@@ -1,5 +1,5 @@
|
|
1
1
|
Aws.add_service(:SimpleDB, {
|
2
|
-
api: File.join(Aws::
|
3
|
-
docs: File.join(Aws::
|
4
|
-
paginators: File.join(Aws::
|
2
|
+
api: File.join(Aws::API_DIR, 'SimpleDB.api.json'),
|
3
|
+
docs: File.join(Aws::API_DIR, 'SimpleDB.docs.json'),
|
4
|
+
paginators: File.join(Aws::API_DIR, 'SimpleDB.paginators.json'),
|
5
5
|
})
|
data/lib/aws-sdk-core/sns.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Aws.add_service(:SNS, {
|
2
|
-
api: File.join(Aws::
|
3
|
-
docs: File.join(Aws::
|
4
|
-
paginators: File.join(Aws::
|
5
|
-
resources: File.join(Aws::
|
2
|
+
api: File.join(Aws::API_DIR, 'SNS.api.json'),
|
3
|
+
docs: File.join(Aws::API_DIR, 'SNS.docs.json'),
|
4
|
+
paginators: File.join(Aws::API_DIR, 'SNS.paginators.json'),
|
5
|
+
resources: File.join(Aws::API_DIR, 'SNS.resources.json'),
|
6
6
|
})
|