right_aws 1.9.0 → 1.10.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.
- data/History.txt +25 -0
- data/README.txt +5 -3
- data/Rakefile +15 -6
- data/lib/acf/right_acf_interface.rb +1 -1
- data/lib/awsbase/right_awsbase.rb +89 -9
- data/lib/ec2/right_ec2.rb +105 -21
- data/lib/right_aws.rb +1 -1
- data/lib/s3/right_s3_interface.rb +32 -42
- data/lib/sdb/active_sdb.rb +178 -21
- data/lib/sdb/right_sdb_interface.rb +222 -27
- data/lib/sqs/right_sqs_gen2_interface.rb +14 -20
- data/lib/sqs/right_sqs_interface.rb +4 -11
- data/test/acf/test_right_acf.rb +1 -1
- data/test/ec2/test_right_ec2.rb +32 -0
- data/test/s3/test_right_s3.rb +2 -2
- data/test/sdb/test_active_sdb.rb +50 -7
- data/test/sdb/test_right_sdb.rb +59 -10
- metadata +6 -6
@@ -38,7 +38,6 @@ module RightAws
|
|
38
38
|
class SqsGen2Interface < RightAwsBase
|
39
39
|
include RightAwsBaseInterface
|
40
40
|
|
41
|
-
SIGNATURE_VERSION = "1"
|
42
41
|
API_VERSION = "2008-01-01"
|
43
42
|
DEFAULT_HOST = "queue.amazonaws.com"
|
44
43
|
DEFAULT_PORT = 443
|
@@ -99,18 +98,15 @@ module RightAws
|
|
99
98
|
# fields required in all requests, and then the headers passed in as
|
100
99
|
# params. We sort the header fields alphabetically and then generate the
|
101
100
|
# signature before URL escaping the resulting query and sending it.
|
102
|
-
|
101
|
+
service = param[:queue_url] ? URI(param[:queue_url]).path : '/'
|
103
102
|
param.each{ |key, value| param.delete(key) if (value.nil? || key.is_a?(Symbol)) }
|
104
|
-
|
103
|
+
service_hash = { "Action" => action,
|
105
104
|
"Expires" => (Time.now + REQUEST_TTL).utc.strftime("%Y-%m-%dT%H:%M:%SZ"),
|
106
105
|
"AWSAccessKeyId" => @aws_access_key_id,
|
107
|
-
"Version" => API_VERSION
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
request_hash['Signature'] = AwsUtils::sign(@aws_secret_access_key, request_data)
|
112
|
-
request_params = request_hash.to_a.collect{|key,val| key.to_s + "=" + val.to_s }.join("&")
|
113
|
-
request = Net::HTTP::Get.new(AwsUtils.URLencode("#{queue_uri}?#{request_params}"))
|
106
|
+
"Version" => API_VERSION }
|
107
|
+
service_hash.update(param)
|
108
|
+
service_params = signed_service_params(@aws_secret_access_key, service_hash, :get, @params[:server], service)
|
109
|
+
request = Net::HTTP::Get.new("#{AwsUtils.URLencode(service)}?#{service_params}")
|
114
110
|
# prepare output hash
|
115
111
|
{ :request => request,
|
116
112
|
:server => @params[:server],
|
@@ -119,22 +115,20 @@ module RightAws
|
|
119
115
|
end
|
120
116
|
|
121
117
|
def generate_post_request(action, param={}) # :nodoc:
|
122
|
-
|
118
|
+
service = param[:queue_url] ? URI(param[:queue_url]).path : '/'
|
123
119
|
message = param[:message] # extract message body if nesessary
|
124
120
|
param.each{ |key, value| param.delete(key) if (value.nil? || key.is_a?(Symbol)) }
|
125
|
-
|
121
|
+
service_hash = { "Action" => action,
|
126
122
|
"Expires" => (Time.now + REQUEST_TTL).utc.strftime("%Y-%m-%dT%H:%M:%SZ"),
|
127
123
|
"AWSAccessKeyId" => @aws_access_key_id,
|
128
124
|
"MessageBody" => message,
|
129
|
-
"Version" => API_VERSION
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
request_body = request_hash.to_a.collect{|key,val| CGI.escape(key.to_s) + "=" + CGI.escape(val.to_s) }.join("&")
|
135
|
-
request = Net::HTTP::Post.new(AwsUtils.URLencode(queue_uri))
|
125
|
+
"Version" => API_VERSION }
|
126
|
+
service_hash.update(param)
|
127
|
+
#
|
128
|
+
service_params = signed_service_params(@aws_secret_access_key, service_hash, :post, @params[:server], service)
|
129
|
+
request = Net::HTTP::Post.new(AwsUtils::URLencode(service))
|
136
130
|
request['Content-Type'] = 'application/x-www-form-urlencoded'
|
137
|
-
request.body =
|
131
|
+
request.body = service_params
|
138
132
|
# prepare output hash
|
139
133
|
{ :request => request,
|
140
134
|
:server => @params[:server],
|
@@ -78,24 +78,17 @@ module RightAws
|
|
78
78
|
def generate_request(action, params={}) # :nodoc:
|
79
79
|
# Sometimes we need to use queue uri (delete queue etc)
|
80
80
|
# In that case we will use Symbol key: 'param[:queue_url]'
|
81
|
-
|
81
|
+
service = params[:queue_url] ? URI(params[:queue_url]).path : '/'
|
82
82
|
# remove unset(=optional) and symbolyc keys
|
83
83
|
params.each{ |key, value| params.delete(key) if (value.nil? || key.is_a?(Symbol)) }
|
84
84
|
# prepare output hash
|
85
85
|
service_hash = { "Action" => action,
|
86
86
|
"Expires" => (Time.now + REQUEST_TTL).utc.strftime("%Y-%m-%dT%H:%M:%SZ"),
|
87
87
|
"AWSAccessKeyId" => @aws_access_key_id,
|
88
|
-
"Version" => API_VERSION
|
89
|
-
"SignatureVersion" => signature_version }
|
88
|
+
"Version" => API_VERSION }
|
90
89
|
service_hash.update(params)
|
91
|
-
|
92
|
-
|
93
|
-
when '0' : service_hash["Action"] + service_hash["Expires"]
|
94
|
-
when '1' : service_hash.sort{|a,b| (a[0].to_s.downcase)<=>(b[0].to_s.downcase)}.to_s
|
95
|
-
end
|
96
|
-
service_hash['Signature'] = AwsUtils::sign(@aws_secret_access_key, string_to_sign)
|
97
|
-
request_params = service_hash.to_a.collect{|key,val| key.to_s + "=" + CGI::escape(val.to_s) }.join("&")
|
98
|
-
request = Net::HTTP::Get.new("#{queue_uri}?#{request_params}")
|
90
|
+
service_params = signed_service_params(@aws_secret_access_key, service_hash, :get, @params[:server], service)
|
91
|
+
request = Net::HTTP::Get.new("#{AwsUtils::URLencode(service)}?#{service_params}")
|
99
92
|
# prepare output hash
|
100
93
|
{ :request => request,
|
101
94
|
:server => @params[:server],
|
data/test/acf/test_right_acf.rb
CHANGED
data/test/ec2/test_right_ec2.rb
CHANGED
@@ -72,5 +72,37 @@ class TestEc2 < Test::Unit::TestCase
|
|
72
72
|
# check that the request has correct signature version
|
73
73
|
assert ec2.last_request.path.include?('SignatureVersion=0')
|
74
74
|
end
|
75
|
+
|
76
|
+
def test_11_regions
|
77
|
+
regions = nil
|
78
|
+
assert_nothing_raised do
|
79
|
+
regions = @ec2.describe_regions
|
80
|
+
end
|
81
|
+
# check we got more that 0 regions
|
82
|
+
assert regions.size > 0
|
83
|
+
# check an access to regions
|
84
|
+
regions.each do |region|
|
85
|
+
regional_ec2 = Rightscale::Ec2.new(TestCredentials.aws_access_key_id, TestCredentials.aws_secret_access_key, :region => region)
|
86
|
+
# do we have a correct endpoint server?
|
87
|
+
assert_equal "#{region}.ec2.amazonaws.com", regional_ec2.params[:server]
|
88
|
+
# get a list of images from every region
|
89
|
+
images = nil
|
90
|
+
assert_nothing_raised do
|
91
|
+
images = regional_ec2.describe_regions
|
92
|
+
end
|
93
|
+
# every region must have images
|
94
|
+
assert images.size > 0
|
95
|
+
end
|
96
|
+
end
|
75
97
|
|
98
|
+
def test_12_endpoint_url
|
99
|
+
ec2 = Rightscale::Ec2.new(TestCredentials.aws_access_key_id, TestCredentials.aws_secret_access_key, :endpoint_url => 'a://b.c:0/d/', :region => 'z')
|
100
|
+
# :endpoint_url has a priority hence :region should be ommitted
|
101
|
+
assert_equal 'a', ec2.params[:protocol]
|
102
|
+
assert_equal 'b.c', ec2.params[:server]
|
103
|
+
assert_equal '/d/', ec2.params[:service]
|
104
|
+
assert_equal 0, ec2.params[:port]
|
105
|
+
assert_nil ec2.params[:region]
|
106
|
+
end
|
107
|
+
|
76
108
|
end
|
data/test/s3/test_right_s3.rb
CHANGED
@@ -6,8 +6,8 @@ class TestS3 < Test::Unit::TestCase
|
|
6
6
|
|
7
7
|
def setup
|
8
8
|
@s3 = Rightscale::S3Interface.new(TestCredentials.aws_access_key_id, TestCredentials.aws_secret_access_key)
|
9
|
-
@bucket = '
|
10
|
-
@bucket2 = '
|
9
|
+
@bucket = 'right_s3_awesome_test_bucket_000A1'
|
10
|
+
@bucket2 = 'right_s3_awesome_test_bucket_000A2'
|
11
11
|
@key1 = 'test/woohoo1/'
|
12
12
|
@key2 = 'test1/key/woohoo2'
|
13
13
|
@key3 = 'test2/A%B@C_D&E?F+G=H"I'
|
data/test/sdb/test_active_sdb.rb
CHANGED
@@ -107,6 +107,10 @@ class TestSdb < Test::Unit::TestCase
|
|
107
107
|
assert_raise(RightAws::ActiveSdb::ActiveSdbError) do
|
108
108
|
Client.find(ids)
|
109
109
|
end
|
110
|
+
# find one record by unknown id
|
111
|
+
assert_raise(RightAws::ActiveSdb::ActiveSdbError) do
|
112
|
+
Client.find('dummy_id')
|
113
|
+
end
|
110
114
|
end
|
111
115
|
|
112
116
|
def test_05_find_first
|
@@ -144,7 +148,7 @@ class TestSdb < Test::Unit::TestCase
|
|
144
148
|
assert_equal ['Bush'], Client.find_by_post('president', :order => 'name', :auto_load => true)['name']
|
145
149
|
assert_equal ['Putin'], Client.find_by_post('president', :order => 'name desc', :auto_load => true)['name']
|
146
150
|
end
|
147
|
-
|
151
|
+
|
148
152
|
def test_08_reload
|
149
153
|
putin = Client.find_by_name('Putin')
|
150
154
|
# attributes must be empty until reload (except 'id' field)
|
@@ -163,9 +167,44 @@ class TestSdb < Test::Unit::TestCase
|
|
163
167
|
assert_equal ['2008'], putin['expiration']
|
164
168
|
assert_equal ['president'], putin['post']
|
165
169
|
end
|
170
|
+
|
171
|
+
def test_09_select
|
172
|
+
# select all records
|
173
|
+
assert_equal 7, Client.select(:all).size
|
174
|
+
# LIMIT
|
175
|
+
# 1 record
|
176
|
+
assert Client.select(:first).is_a?(Client)
|
177
|
+
# select 2 recs
|
178
|
+
assert_equal 2, Client.select(:all, :limit => 2).size
|
179
|
+
# ORDER
|
180
|
+
# select all recs ordered by 'expration' (must find only recs where 'expration' attribute presents)
|
181
|
+
result = Client.select(:all, :order => 'expiration')
|
182
|
+
assert_equal 3, result.size
|
183
|
+
assert_equal ['2008', '2009', '2012'], result.map{ |c| c['expiration'] }.flatten
|
184
|
+
# desc order
|
185
|
+
result = Client.select(:all, :order => 'expiration desc')
|
186
|
+
assert_equal ['2012', '2009', '2008'], result.map{ |c| c['expiration'] }.flatten
|
187
|
+
# CONDITIONS
|
188
|
+
result = Client.select(:all, :conditions => ["expiration >= ?", 2009], :order => 'name')
|
189
|
+
assert_equal ['Bush', 'Medvedev'], result.map{ |c| c['name'] }.flatten
|
190
|
+
result = Client.select(:all, :conditions => "hobby='flowers' AND gender='female'", :order => 'name')
|
191
|
+
assert_equal ['Mary', 'Sandy'], result.map{ |c| c['name'] }.flatten
|
192
|
+
# SELECT
|
193
|
+
result = Client.select(:all, :select => 'hobby', :conditions => "gender IS NOT NULL", :order => 'name')
|
194
|
+
hobbies = result.map{|c| c['hobby']}
|
195
|
+
# must return all recs
|
196
|
+
assert_equal 6, result.size
|
197
|
+
# but anly 3 of them have this field set
|
198
|
+
assert_equal 3, hobbies.compact.size
|
199
|
+
end
|
200
|
+
|
201
|
+
def test_10_select_by
|
202
|
+
assert_equal 2, Client.select_all_by_hobby('flowers').size
|
203
|
+
assert_equal 2, Client.select_all_by_hobby_and_country('flowers', 'Russia').size
|
204
|
+
assert_equal ['Putin'], Client.select_by_post_and_expiration('president','2008')['name']
|
205
|
+
end
|
166
206
|
|
167
|
-
|
168
|
-
def test_09_save_and_put
|
207
|
+
def test_11_save_and_put
|
169
208
|
putin = Client.find_by_name('Putin')
|
170
209
|
putin.reload
|
171
210
|
putin['hobby'] = 'ski'
|
@@ -194,7 +233,7 @@ class TestSdb < Test::Unit::TestCase
|
|
194
233
|
assert ['dogs', 'ski'], new_putin['hobby'].sort
|
195
234
|
end
|
196
235
|
|
197
|
-
def
|
236
|
+
def test_12_save_and_put_attributes
|
198
237
|
putin = Client.find_by_name('Putin')
|
199
238
|
putin.reload
|
200
239
|
# SAVE method (replace values)
|
@@ -220,12 +259,16 @@ class TestSdb < Test::Unit::TestCase
|
|
220
259
|
assert ['english', 'german', 'russian'], new_putin['language'].sort
|
221
260
|
end
|
222
261
|
|
223
|
-
def
|
262
|
+
def test_13_delete
|
224
263
|
putin = Client.find_by_name('Putin')
|
225
264
|
putin.reload
|
226
265
|
# --- delete_values
|
266
|
+
# remove an unknown attribute
|
267
|
+
# should return an empty hash
|
268
|
+
assert_equal( {}, putin.delete_values('undefined_attribute' => 'ohoho'))
|
227
269
|
# remove 2 languages
|
228
|
-
|
270
|
+
lang_hash = {'language' => ['english', 'german']}
|
271
|
+
assert_equal lang_hash, putin.delete_values(lang_hash)
|
229
272
|
wait SDB_DELAY, 'test 11: after put_attributes'
|
230
273
|
# now Putin must know only russian lang
|
231
274
|
new_putin = Client.find_by_name('Putin')
|
@@ -245,7 +288,7 @@ class TestSdb < Test::Unit::TestCase
|
|
245
288
|
assert_nil Client.find_by_name('Putin')
|
246
289
|
end
|
247
290
|
|
248
|
-
def
|
291
|
+
def test_14_delete_domain
|
249
292
|
assert Client.delete_domain
|
250
293
|
wait SDB_DELAY, 'test 12: after delete domain'
|
251
294
|
assert_raise(Rightscale::AwsError) do
|
data/test/sdb/test_right_sdb.rb
CHANGED
@@ -134,22 +134,40 @@ class TestSdb < Test::Unit::TestCase
|
|
134
134
|
# check that the request has correct signature version
|
135
135
|
assert sdb.last_request.path.include?('SignatureVersion=0')
|
136
136
|
end
|
137
|
-
|
138
|
-
def
|
137
|
+
|
138
|
+
def test_10_signature_version_1
|
139
|
+
sdb = Rightscale::SdbInterface.new(TestCredentials.aws_access_key_id, TestCredentials.aws_secret_access_key, :signature_version => '1')
|
140
|
+
domains = nil
|
141
|
+
assert_nothing_thrown "Failed to use signature V1" do
|
142
|
+
domains = sdb.list_domains
|
143
|
+
end
|
144
|
+
assert domains
|
145
|
+
end
|
146
|
+
|
147
|
+
def test_11_signature_version_1
|
148
|
+
sdb = Rightscale::SdbInterface.new(TestCredentials.aws_access_key_id, TestCredentials.aws_secret_access_key, :signature_version => '2')
|
149
|
+
domains = nil
|
150
|
+
assert_nothing_thrown "Failed to use signature V2" do
|
151
|
+
domains = sdb.list_domains
|
152
|
+
end
|
153
|
+
assert domains
|
154
|
+
end
|
155
|
+
|
156
|
+
def test_12_array_of_attrs
|
139
157
|
item = 'multiples'
|
140
158
|
assert_nothing_thrown "Failed to put multiple attrs" do
|
141
159
|
@sdb.put_attributes(@domain, item, {:one=>1, :two=>2, :three=>3})
|
142
160
|
end
|
143
161
|
end
|
144
162
|
|
145
|
-
def
|
163
|
+
def test_13_zero_len_attrs
|
146
164
|
item = 'zeroes'
|
147
165
|
assert_nothing_thrown "Failed to put zero-length attributes" do
|
148
166
|
@sdb.put_attributes(@domain, item, {:one=>"", :two=>"", :three=>""})
|
149
167
|
end
|
150
168
|
end
|
151
169
|
|
152
|
-
def
|
170
|
+
def test_14_nil_attrs
|
153
171
|
item = 'nils'
|
154
172
|
res = nil
|
155
173
|
assert_nothing_thrown do
|
@@ -163,7 +181,7 @@ class TestSdb < Test::Unit::TestCase
|
|
163
181
|
assert_not_nil(res[:attributes]['three'][0])
|
164
182
|
end
|
165
183
|
|
166
|
-
def
|
184
|
+
def test_15_url_escape
|
167
185
|
item = 'urlescapes'
|
168
186
|
content = {:a=>"one & two & three",
|
169
187
|
:b=>"one ? two / three"}
|
@@ -174,7 +192,7 @@ class TestSdb < Test::Unit::TestCase
|
|
174
192
|
assert_equal(content[:b], res[:attributes]['b'][0])
|
175
193
|
end
|
176
194
|
|
177
|
-
def
|
195
|
+
def test_16_put_attrs_by_post
|
178
196
|
item = 'reqgirth'
|
179
197
|
i = 0
|
180
198
|
sa = ""
|
@@ -184,15 +202,46 @@ class TestSdb < Test::Unit::TestCase
|
|
184
202
|
end
|
185
203
|
@sdb.put_attributes(@domain, item, {:a => sa, :b => sa, :c => sa, :d => sa, :e => sa})
|
186
204
|
end
|
187
|
-
|
205
|
+
|
206
|
+
def test_20_query_with_atributes
|
207
|
+
response = @sdb.query_with_attributes(@domain)
|
208
|
+
# convers response to a hash representation
|
209
|
+
items = {};
|
210
|
+
response[:items].each{ |item| items.merge!(item) }
|
211
|
+
# check we have receied all 5 items each full of attributes
|
212
|
+
assert_equal 5, items.keys.size
|
213
|
+
assert items['toys'].size > 0
|
214
|
+
assert items['nils'].size > 0
|
215
|
+
assert items['urlescapes'].size > 0
|
216
|
+
assert items['multiples'].size > 0
|
217
|
+
assert items['reqgirth'].size > 0
|
218
|
+
# fetch only Jon's attributes from all items
|
219
|
+
response = @sdb.query_with_attributes(@domain,['Jon'])
|
220
|
+
items = {};
|
221
|
+
response[:items].each{ |item| items.merge!(item) }
|
222
|
+
# check we have receied all 5 items
|
223
|
+
# check we have receied all 5 items, but only 'toys' has attributes
|
224
|
+
puts items.inspect
|
225
|
+
assert_equal 2, items['toys']['Jon'].size
|
226
|
+
assert_equal 0, items['nils'].size
|
227
|
+
assert_equal 0, items['urlescapes'].size
|
228
|
+
assert_equal 0, items['multiples'].size
|
229
|
+
assert_equal 0, items['reqgirth'].size
|
230
|
+
# kust Jurgen's attriburs
|
231
|
+
response = @sdb.query_with_attributes(@domain,['Jurgen'], "['Jurgen'='piglet']")
|
232
|
+
items = {};
|
233
|
+
response[:items].each{ |item| items.merge!(item) }
|
234
|
+
# check we have receied an only item
|
235
|
+
assert_equal 1, items.keys.size
|
236
|
+
assert_equal ["chickabiddy", "kitten", "piglet", "puppy"], items['toys']['Jurgen'].sort
|
237
|
+
end
|
238
|
+
|
188
239
|
# Keep this test last, because it deletes the domain...
|
189
|
-
def
|
240
|
+
def test_21_delete_domain
|
190
241
|
assert @sdb.delete_domain(@domain), 'delete_domain fail'
|
191
242
|
wait SDB_DELAY, 'after domain deletion'
|
192
243
|
# check that domain does not exist
|
193
244
|
assert !@sdb.list_domains[:domains].include?(@domain)
|
194
245
|
end
|
195
246
|
|
196
|
-
|
197
|
-
|
198
247
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: right_aws
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- RightScale, Inc.
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date:
|
12
|
+
date: 2009-02-24 00:00:00 -08:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -20,10 +20,10 @@ dependencies:
|
|
20
20
|
requirements:
|
21
21
|
- - ">="
|
22
22
|
- !ruby/object:Gem::Version
|
23
|
-
version: 1.2.
|
23
|
+
version: 1.2.4
|
24
24
|
version:
|
25
25
|
description: "== DESCRIPTION: The RightScale AWS gems have been designed to provide a robust, fast, and secure interface to Amazon EC2, EBS, S3, SQS, SDB, and CloudFront. These gems have been used in production by RightScale since late 2006 and are being maintained to track enhancements made by Amazon. The RightScale AWS gems comprise: - RightAws::Ec2 -- interface to Amazon EC2 (Elastic Compute Cloud) and the associated EBS (Elastic Block Store) - RightAws::S3 and RightAws::S3Interface -- interface to Amazon S3 (Simple Storage Service) - RightAws::Sqs and RightAws::SqsInterface -- interface to first-generation Amazon SQS (Simple Queue Service) (API version 2007-05-01) - RightAws::SqsGen2 and RightAws::SqsGen2Interface -- interface to second-generation Amazon SQS (Simple Queue Service) (API version 2008-01-01) - RightAws::SdbInterface and RightAws::ActiveSdb -- interface to Amazon SDB (SimpleDB) - RightAws::AcfInterface -- interface to Amazon CloudFront, a content distribution service == FEATURES:"
|
26
|
-
email:
|
26
|
+
email: rubygems@rightscale.com
|
27
27
|
executables: []
|
28
28
|
|
29
29
|
extensions: []
|
@@ -89,10 +89,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
89
89
|
version:
|
90
90
|
requirements: []
|
91
91
|
|
92
|
-
rubyforge_project:
|
92
|
+
rubyforge_project: rightscale
|
93
93
|
rubygems_version: 1.3.1
|
94
94
|
signing_key:
|
95
95
|
specification_version: 2
|
96
|
-
summary: Interface classes for the Amazon EC2, SQS, and
|
96
|
+
summary: Interface classes for the Amazon EC2/EBS, SQS, S3, SDB, and ACF Web Services
|
97
97
|
test_files:
|
98
98
|
- test/ts_right_aws.rb
|