kerryb-right_aws 1.7.6 → 1.10.1
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.
- data/History.txt +78 -1
- data/Manifest.txt +3 -1
- data/README.txt +28 -8
- data/Rakefile +23 -7
- data/lib/acf/right_acf_interface.rb +379 -0
- data/lib/awsbase/right_awsbase.rb +150 -12
- data/lib/ec2/right_ec2.rb +595 -77
- data/lib/right_aws.rb +3 -3
- data/lib/s3/right_s3_interface.rb +3 -3
- data/lib/sdb/active_sdb.rb +267 -32
- data/lib/sdb/right_sdb_interface.rb +272 -48
- data/lib/sqs/right_sqs.rb +8 -0
- data/lib/sqs/right_sqs_gen2.rb +8 -0
- data/lib/sqs/right_sqs_gen2_interface.rb +17 -22
- data/lib/sqs/right_sqs_interface.rb +7 -13
- data/test/acf/test_helper.rb +2 -0
- data/test/acf/test_right_acf.rb +146 -0
- data/test/ec2/test_right_ec2.rb +32 -0
- data/test/s3/test_right_s3.rb +41 -10
- data/test/sdb/test_active_sdb.rb +59 -9
- data/test/sdb/test_helper.rb +1 -0
- data/test/sdb/test_right_sdb.rb +106 -6
- data/test/ts_right_aws.rb +1 -0
- metadata +30 -21
- data/lib/awsbase/file_fix.rb +0 -33
@@ -24,11 +24,73 @@
|
|
24
24
|
# Test
|
25
25
|
module RightAws
|
26
26
|
require 'md5'
|
27
|
+
require 'pp'
|
27
28
|
|
28
29
|
class AwsUtils #:nodoc:
|
29
|
-
@@
|
30
|
+
@@digest1 = OpenSSL::Digest::Digest.new("sha1")
|
31
|
+
@@digest256 = nil
|
32
|
+
if OpenSSL::OPENSSL_VERSION_NUMBER > 0x00908000
|
33
|
+
@@digest256 = OpenSSL::Digest::Digest.new("sha256") rescue nil # Some installation may not support sha256
|
34
|
+
end
|
35
|
+
|
30
36
|
def self.sign(aws_secret_access_key, auth_string)
|
31
|
-
Base64.encode64(OpenSSL::HMAC.digest(@@
|
37
|
+
Base64.encode64(OpenSSL::HMAC.digest(@@digest1, aws_secret_access_key, auth_string)).strip
|
38
|
+
end
|
39
|
+
|
40
|
+
# Escape a string accordingly Amazon rulles
|
41
|
+
# http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?REST_RESTAuth.html
|
42
|
+
def self.amz_escape(param)
|
43
|
+
param.to_s.gsub(/([^a-zA-Z0-9._~-]+)/n) do
|
44
|
+
'%' + $1.unpack('H2' * $1.size).join('%').upcase
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Set a timestamp and a signature version
|
49
|
+
def self.fix_service_params(service_hash, signature)
|
50
|
+
# Removed hardcoded UTC timezone
|
51
|
+
service_hash["Timestamp"] ||= Time.now.strftime("%Y-%m-%dT%H:%M:%S.000Z") unless service_hash["Expires"]
|
52
|
+
service_hash["SignatureVersion"] = signature
|
53
|
+
service_hash
|
54
|
+
end
|
55
|
+
|
56
|
+
# Signature Version 0
|
57
|
+
# A deprecated guy (should work till septemper 2009)
|
58
|
+
def self.sign_request_v0(aws_secret_access_key, service_hash)
|
59
|
+
fix_service_params(service_hash, '0')
|
60
|
+
string_to_sign = "#{service_hash['Action']}#{service_hash['Timestamp'] || service_hash['Expires']}"
|
61
|
+
service_hash['Signature'] = AwsUtils::sign(aws_secret_access_key, string_to_sign)
|
62
|
+
service_hash.to_a.collect{|key,val| "#{amz_escape(key)}=#{amz_escape(val.to_s)}" }.join("&")
|
63
|
+
end
|
64
|
+
|
65
|
+
# Signature Version 1
|
66
|
+
# Another deprecated guy (should work till septemper 2009)
|
67
|
+
def self.sign_request_v1(aws_secret_access_key, service_hash)
|
68
|
+
fix_service_params(service_hash, '1')
|
69
|
+
string_to_sign = service_hash.sort{|a,b| (a[0].to_s.downcase)<=>(b[0].to_s.downcase)}.to_s
|
70
|
+
service_hash['Signature'] = AwsUtils::sign(aws_secret_access_key, string_to_sign)
|
71
|
+
service_hash.to_a.collect{|key,val| "#{amz_escape(key)}=#{amz_escape(val.to_s)}" }.join("&")
|
72
|
+
end
|
73
|
+
|
74
|
+
# Signature Version 2
|
75
|
+
# EC2, SQS and SDB requests must be signed by this guy.
|
76
|
+
# See: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?REST_RESTAuth.html
|
77
|
+
# http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1928
|
78
|
+
def self.sign_request_v2(aws_secret_access_key, service_hash, http_verb, host, uri)
|
79
|
+
fix_service_params(service_hash, '2')
|
80
|
+
# select a signing method (make an old openssl working with sha1)
|
81
|
+
# make 'HmacSHA256' to be a default one
|
82
|
+
service_hash['SignatureMethod'] = 'HmacSHA256' unless ['HmacSHA256', 'HmacSHA1'].include?(service_hash['SignatureMethod'])
|
83
|
+
service_hash['SignatureMethod'] = 'HmacSHA1' unless @@digest256
|
84
|
+
# select a digest
|
85
|
+
digest = (service_hash['SignatureMethod'] == 'HmacSHA256' ? @@digest256 : @@digest1)
|
86
|
+
# form string to sign
|
87
|
+
canonical_string = service_hash.keys.sort.map do |key|
|
88
|
+
"#{amz_escape(key)}=#{amz_escape(service_hash[key])}"
|
89
|
+
end.join('&')
|
90
|
+
string_to_sign = "#{http_verb.to_s.upcase}\n#{host.downcase}\n#{uri}\n#{canonical_string}"
|
91
|
+
# sign the string
|
92
|
+
signature = amz_escape(Base64.encode64(OpenSSL::HMAC.digest(digest, aws_secret_access_key, string_to_sign)).strip)
|
93
|
+
"#{canonical_string}&Signature=#{signature}"
|
32
94
|
end
|
33
95
|
|
34
96
|
# From Amazon's SQS Dev Guide, a brief description of how to escape:
|
@@ -44,6 +106,23 @@ module RightAws
|
|
44
106
|
e = URI.escape(raw)
|
45
107
|
e.gsub(/\+/, "%2b")
|
46
108
|
end
|
109
|
+
|
110
|
+
def self.allow_only(allowed_keys, params)
|
111
|
+
bogus_args = []
|
112
|
+
params.keys.each {|p| bogus_args.push(p) unless allowed_keys.include?(p) }
|
113
|
+
raise AwsError.new("The following arguments were given but are not legal for the function call #{caller_method}: #{bogus_args.inspect}") if bogus_args.length > 0
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.mandatory_arguments(required_args, params)
|
117
|
+
rargs = required_args.dup
|
118
|
+
params.keys.each {|p| rargs.delete(p)}
|
119
|
+
raise AwsError.new("The following mandatory arguments were not provided to #{caller_method}: #{rargs.inspect}") if rargs.length > 0
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.caller_method
|
123
|
+
caller[1]=~/`(.*?)'/
|
124
|
+
$1
|
125
|
+
end
|
47
126
|
|
48
127
|
end
|
49
128
|
|
@@ -93,7 +172,7 @@ module RightAws
|
|
93
172
|
end
|
94
173
|
|
95
174
|
module RightAwsBaseInterface
|
96
|
-
DEFAULT_SIGNATURE_VERSION = '
|
175
|
+
DEFAULT_SIGNATURE_VERSION = '2'
|
97
176
|
|
98
177
|
@@caching = false
|
99
178
|
def self.caching
|
@@ -102,7 +181,7 @@ module RightAws
|
|
102
181
|
def self.caching=(caching)
|
103
182
|
@@caching = caching
|
104
183
|
end
|
105
|
-
|
184
|
+
|
106
185
|
# Current aws_access_key_id
|
107
186
|
attr_reader :aws_access_key_id
|
108
187
|
# Last HTTP request object
|
@@ -130,10 +209,20 @@ module RightAws
|
|
130
209
|
if aws_access_key_id.blank? || aws_secret_access_key.blank?
|
131
210
|
@aws_access_key_id = aws_access_key_id
|
132
211
|
@aws_secret_access_key = aws_secret_access_key
|
133
|
-
|
134
|
-
@params[:
|
135
|
-
|
136
|
-
|
212
|
+
# if the endpoint was explicitly defined - then use it
|
213
|
+
if @params[:endpoint_url]
|
214
|
+
@params[:server] = URI.parse(@params[:endpoint_url]).host
|
215
|
+
@params[:port] = URI.parse(@params[:endpoint_url]).port
|
216
|
+
@params[:service] = URI.parse(@params[:endpoint_url]).path
|
217
|
+
@params[:protocol] = URI.parse(@params[:endpoint_url]).scheme
|
218
|
+
@params[:region] = nil
|
219
|
+
else
|
220
|
+
@params[:server] ||= service_info[:default_host]
|
221
|
+
@params[:server] = "#{@params[:region]}.#{@params[:server]}" if @params[:region]
|
222
|
+
@params[:port] ||= service_info[:default_port]
|
223
|
+
@params[:service] ||= service_info[:default_service]
|
224
|
+
@params[:protocol] ||= service_info[:default_protocol]
|
225
|
+
end
|
137
226
|
@params[:multi_thread] ||= defined?(AWS_DAEMON)
|
138
227
|
@logger = @params[:logger]
|
139
228
|
@logger = RAILS_DEFAULT_LOGGER if !@logger && defined?(RAILS_DEFAULT_LOGGER)
|
@@ -144,6 +233,15 @@ module RightAws
|
|
144
233
|
@signature_version = (params[:signature_version] || DEFAULT_SIGNATURE_VERSION).to_s
|
145
234
|
end
|
146
235
|
|
236
|
+
def signed_service_params(aws_secret_access_key, service_hash, http_verb=nil, host=nil, service=nil )
|
237
|
+
case signature_version.to_s
|
238
|
+
when '0' then AwsUtils::sign_request_v0(aws_secret_access_key, service_hash)
|
239
|
+
when '1' then AwsUtils::sign_request_v1(aws_secret_access_key, service_hash)
|
240
|
+
when '2' then AwsUtils::sign_request_v2(aws_secret_access_key, service_hash, http_verb, host, service)
|
241
|
+
else raise AwsError.new("Unknown signature version (#{signature_version.to_s}) requested")
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
147
245
|
# Returns +true+ if the describe_xxx responses are being cached
|
148
246
|
def caching?
|
149
247
|
@params.key?(:cache) ? @params[:cache] : @@caching
|
@@ -157,10 +255,13 @@ module RightAws
|
|
157
255
|
def cache_hits?(function, response, do_raise=:raise)
|
158
256
|
result = false
|
159
257
|
if caching?
|
160
|
-
function
|
258
|
+
function = function.to_sym
|
259
|
+
# get rid of requestId (this bad boy was added for API 2008-08-08+ and it is uniq for every response)
|
260
|
+
response = response.sub(%r{<requestId>.+?</requestId>}, '')
|
161
261
|
response_md5 = MD5.md5(response).to_s
|
162
|
-
#
|
262
|
+
# check for changes
|
163
263
|
unless @cache[function] && @cache[function][:response_md5] == response_md5
|
264
|
+
# well, the response is new, reset cache data
|
164
265
|
update_cache(function, {:response_md5 => response_md5,
|
165
266
|
:timestamp => Time.now,
|
166
267
|
:hits => 0,
|
@@ -264,6 +365,27 @@ module RightAws
|
|
264
365
|
raise
|
265
366
|
end
|
266
367
|
|
368
|
+
def request_cache_or_info(method, link, parser_class, benchblock, use_cache=true) #:nodoc:
|
369
|
+
# We do not want to break the logic of parsing hence will use a dummy parser to process all the standard
|
370
|
+
# steps (errors checking etc). The dummy parser does nothig - just returns back the params it received.
|
371
|
+
# If the caching is enabled and hit then throw AwsNoChange.
|
372
|
+
# P.S. caching works for the whole images list only! (when the list param is blank)
|
373
|
+
# check cache
|
374
|
+
response, params = request_info(link, RightDummyParser.new)
|
375
|
+
cache_hits?(method.to_sym, response.body) if use_cache
|
376
|
+
parser = parser_class.new(:logger => @logger)
|
377
|
+
benchblock.xml.add!{ parser.parse(response, params) }
|
378
|
+
result = block_given? ? yield(parser) : parser.result
|
379
|
+
# update parsed data
|
380
|
+
update_cache(method.to_sym, :parsed => result) if use_cache
|
381
|
+
result
|
382
|
+
end
|
383
|
+
|
384
|
+
# Returns Amazons request ID for the latest request
|
385
|
+
def last_request_id
|
386
|
+
@last_response && @last_response.body.to_s[%r{<requestId>(.+?)</requestId>}] && $1
|
387
|
+
end
|
388
|
+
|
267
389
|
end
|
268
390
|
|
269
391
|
|
@@ -550,8 +672,9 @@ module RightAws
|
|
550
672
|
@xmlpath += @xmlpath.empty? ? name : "/#{name}"
|
551
673
|
end
|
552
674
|
def tag_end(name)
|
553
|
-
@xmlpath
|
554
|
-
|
675
|
+
if @xmlpath =~ /^(.*?)\/?#{name}$/
|
676
|
+
@xmlpath = $1
|
677
|
+
end
|
555
678
|
tagend(name)
|
556
679
|
end
|
557
680
|
def text(text)
|
@@ -656,5 +779,20 @@ module RightAws
|
|
656
779
|
end
|
657
780
|
end
|
658
781
|
|
782
|
+
# Dummy parser - does nothing
|
783
|
+
# Returns the original params back
|
784
|
+
class RightDummyParser # :nodoc:
|
785
|
+
attr_accessor :result
|
786
|
+
def parse(response, params={})
|
787
|
+
@result = [response, params]
|
788
|
+
end
|
789
|
+
end
|
790
|
+
|
791
|
+
class RightHttp2xxParser < RightAWSParser # :nodoc:
|
792
|
+
def parse(response)
|
793
|
+
@result = response.is_a?(Net::HTTPSuccess)
|
794
|
+
end
|
795
|
+
end
|
796
|
+
|
659
797
|
end
|
660
798
|
|