right_aws 1.8.0 → 1.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +21 -2
- data/lib/awsbase/right_awsbase.rb +18 -0
- data/lib/ec2/right_ec2.rb +6 -6
- data/lib/right_aws.rb +1 -1
- data/lib/s3/right_s3.rb +38 -0
- data/lib/s3/right_s3_interface.rb +197 -1
- data/lib/sdb/active_sdb.rb +102 -24
- data/lib/sdb/right_sdb_interface.rb +57 -28
- data/lib/sqs/right_sqs.rb +8 -0
- data/lib/sqs/right_sqs_gen2.rb +8 -0
- data/test/s3/test_right_s3.rb +40 -9
- data/test/sdb/test_active_sdb.rb +9 -2
- data/test/sdb/test_helper.rb +1 -0
- data/test/sdb/test_right_sdb.rb +55 -4
- metadata +2 -2
data/History.txt
CHANGED
@@ -174,7 +174,7 @@ Initial release.
|
|
174
174
|
|
175
175
|
- Removed the 1.7.2 monkey-patch of the Ruby File class on Windows. This patch broke Rails 2.0.
|
176
176
|
The patch is now included in the README for anyone to use at their own risk.
|
177
|
-
|
177
|
+
|
178
178
|
== 1.8.0
|
179
179
|
|
180
180
|
Release Notes:
|
@@ -184,4 +184,23 @@ Initial release.
|
|
184
184
|
and delete EBS volumes, attach and detach them from instances, snapshot
|
185
185
|
volumes, and list the available volumes and snapshots.
|
186
186
|
|
187
|
-
Bug fixes include correction of RightAws::S3 copy's failure to url-encode
|
187
|
+
Bug fixes include correction of RightAws::S3 copy's failure to url-encode
|
188
|
+
the source key.
|
189
|
+
|
190
|
+
== 1.8.1
|
191
|
+
|
192
|
+
Release Notes:
|
193
|
+
|
194
|
+
RightScale::SdbInterface & ::ActiveSdb have several enhancements, including:
|
195
|
+
- RightAws::SdbInterface#last_query_expression added for debug puposes
|
196
|
+
- RightAws::ActiveSdb::Base#query :order and :auto_load options added to support query
|
197
|
+
result sorting and attributes auto loading
|
198
|
+
- RightAws::ActiveSdb::Base#find_all_by_ and find_by_ helpers improved to support
|
199
|
+
:order, :auto_load, :limit and :next_token options
|
200
|
+
- RightAws::SdbInterface#delete_attributes bug fixed
|
201
|
+
- SdbInterface allows specification of a string value to use for
|
202
|
+
representing Ruby nil in SDB.
|
203
|
+
- Sdb tests fixed and improved
|
204
|
+
|
205
|
+
The ::S3 interface now has support for S3's server access logging.
|
206
|
+
Amazon considers server access logging to be a beta or provisional feature.
|
@@ -24,6 +24,7 @@
|
|
24
24
|
# Test
|
25
25
|
module RightAws
|
26
26
|
require 'md5'
|
27
|
+
require 'pp'
|
27
28
|
|
28
29
|
class AwsUtils #:nodoc:
|
29
30
|
@@digest = OpenSSL::Digest::Digest.new("sha1")
|
@@ -44,6 +45,23 @@ module RightAws
|
|
44
45
|
e = URI.escape(raw)
|
45
46
|
e.gsub(/\+/, "%2b")
|
46
47
|
end
|
48
|
+
|
49
|
+
def self.allow_only(allowed_keys, params)
|
50
|
+
bogus_args = []
|
51
|
+
params.keys.each {|p| bogus_args.push(p) unless allowed_keys.include?(p) }
|
52
|
+
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
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.mandatory_arguments(required_args, params)
|
56
|
+
rargs = required_args.dup
|
57
|
+
params.keys.each {|p| rargs.delete(p)}
|
58
|
+
raise AwsError.new("The following mandatory arguments were not provided to #{caller_method}: #{rargs.inspect}") if rargs.length > 0
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.caller_method
|
62
|
+
caller[1]=~/`(.*?)'/
|
63
|
+
$1
|
64
|
+
end
|
47
65
|
|
48
66
|
end
|
49
67
|
|
data/lib/ec2/right_ec2.rb
CHANGED
@@ -863,7 +863,7 @@ module RightAws
|
|
863
863
|
#-----------------------------------------------------------------
|
864
864
|
# EBS: Volumes
|
865
865
|
#-----------------------------------------------------------------
|
866
|
-
|
866
|
+
|
867
867
|
# Describe all EBS volumes.
|
868
868
|
#
|
869
869
|
# ec2.describe_volumes #=>
|
@@ -891,7 +891,7 @@ module RightAws
|
|
891
891
|
rescue Exception
|
892
892
|
on_exception
|
893
893
|
end
|
894
|
-
|
894
|
+
|
895
895
|
# Create new EBS volume based on previously created snapshot.
|
896
896
|
# +Size+ in Gigabytes.
|
897
897
|
#
|
@@ -1380,7 +1380,7 @@ module RightAws
|
|
1380
1380
|
#-----------------------------------------------------------------
|
1381
1381
|
# PARSERS: EBS - Volumes
|
1382
1382
|
#-----------------------------------------------------------------
|
1383
|
-
|
1383
|
+
|
1384
1384
|
class QEc2CreateVolumeParser < RightAWSParser #:nodoc:
|
1385
1385
|
def tagend(name)
|
1386
1386
|
case name
|
@@ -1396,7 +1396,7 @@ module RightAws
|
|
1396
1396
|
@result = {}
|
1397
1397
|
end
|
1398
1398
|
end
|
1399
|
-
|
1399
|
+
|
1400
1400
|
class QEc2AttachAndDetachVolumeParser < RightAWSParser #:nodoc:
|
1401
1401
|
def tagend(name)
|
1402
1402
|
case name
|
@@ -1411,13 +1411,13 @@ module RightAws
|
|
1411
1411
|
@result = {}
|
1412
1412
|
end
|
1413
1413
|
end
|
1414
|
-
|
1414
|
+
|
1415
1415
|
class QEc2DescribeVolumesParser < RightAWSParser #:nodoc:
|
1416
1416
|
def tagstart(name, attributes)
|
1417
1417
|
case name
|
1418
1418
|
when 'item'
|
1419
1419
|
case @xmlpath
|
1420
|
-
|
1420
|
+
when 'DescribeVolumesResponse/volumeSet' then @volume = {}
|
1421
1421
|
end
|
1422
1422
|
end
|
1423
1423
|
end
|
data/lib/right_aws.rb
CHANGED
data/lib/s3/right_s3.rb
CHANGED
@@ -53,6 +53,14 @@ module RightAws
|
|
53
53
|
# Create a new handle to an S3 account. All handles share the same per process or per thread
|
54
54
|
# HTTP connection to Amazon S3. Each handle is for a specific account.
|
55
55
|
# The +params+ are passed through as-is to RightAws::S3Interface.new
|
56
|
+
#
|
57
|
+
# Params is a hash:
|
58
|
+
#
|
59
|
+
# {:server => 's3.amazonaws.com' # Amazon service host: 's3.amazonaws.com'(default)
|
60
|
+
# :port => 443 # Amazon service port: 80 or 443(default)
|
61
|
+
# :protocol => 'https' # Amazon service protocol: 'http' or 'https'(default)
|
62
|
+
# :multi_thread => true|false # Multi-threaded (connection per each thread): true or false(default)
|
63
|
+
# :logger => Logger Object} # Logger instance: logs to STDOUT if omitted }
|
56
64
|
def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
|
57
65
|
@interface = S3Interface.new(aws_access_key_id, aws_secret_access_key, params)
|
58
66
|
end
|
@@ -161,6 +169,36 @@ module RightAws
|
|
161
169
|
def location
|
162
170
|
@location ||= @s3.interface.bucket_location(@name)
|
163
171
|
end
|
172
|
+
|
173
|
+
# Retrieves the logging configuration for a bucket.
|
174
|
+
# Returns a hash of {:enabled, :targetbucket, :targetprefix}
|
175
|
+
#
|
176
|
+
# bucket.logging_info()
|
177
|
+
# => {:enabled=>true, :targetbucket=>"mylogbucket", :targetprefix=>"loggylogs/"}
|
178
|
+
def logging_info
|
179
|
+
@s3.interface.get_logging_parse(:bucket => @name)
|
180
|
+
end
|
181
|
+
|
182
|
+
# Enables S3 server access logging on a bucket. The target bucket must have been properly configured to receive server
|
183
|
+
# access logs.
|
184
|
+
# Params:
|
185
|
+
# :targetbucket - either the target bucket object or the name of the target bucket
|
186
|
+
# :targetprefix - the prefix under which all logs should be stored
|
187
|
+
#
|
188
|
+
# bucket.enable_logging(:targetbucket=>"mylogbucket", :targetprefix=>"loggylogs/")
|
189
|
+
# => true
|
190
|
+
def enable_logging(params)
|
191
|
+
AwsUtils.mandatory_arguments([:targetbucket, :targetprefix], params)
|
192
|
+
AwsUtils.allow_only([:targetbucket, :targetprefix], params)
|
193
|
+
xmldoc = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><BucketLoggingStatus xmlns=\"http://doc.s3.amazonaws.com/2006-03-01\"><LoggingEnabled><TargetBucket>#{params[:targetbucket]}</TargetBucket><TargetPrefix>#{params[:targetprefix]}</TargetPrefix></LoggingEnabled></BucketLoggingStatus>"
|
194
|
+
@s3.interface.put_logging(:bucket => @name, :xmldoc => xmldoc)
|
195
|
+
end
|
196
|
+
|
197
|
+
# Disables S3 server access logging on a bucket. Takes no arguments.
|
198
|
+
def disable_logging
|
199
|
+
xmldoc = "<?xml version=\"1.0\" encoding=\"UTF-8\"?><BucketLoggingStatus xmlns=\"http://doc.s3.amazonaws.com/2006-03-01\"></BucketLoggingStatus>"
|
200
|
+
@s3.interface.put_logging(:bucket => @name, :xmldoc => xmldoc)
|
201
|
+
end
|
164
202
|
|
165
203
|
# Retrieve a group of keys from Amazon.
|
166
204
|
# +options+ is a hash: { 'prefix'=>'', 'marker'=>'', 'max-keys'=>5, 'delimiter'=>'' }).
|
@@ -95,7 +95,7 @@ module RightAws
|
|
95
95
|
out_string << '?acl' if path[/[&?]acl($|&|=)/]
|
96
96
|
out_string << '?torrent' if path[/[&?]torrent($|&|=)/]
|
97
97
|
out_string << '?location' if path[/[&?]location($|&|=)/]
|
98
|
-
|
98
|
+
out_string << '?logging' if path[/[&?]logging($|&|=)/] # this one is beta, no support for now
|
99
99
|
out_string
|
100
100
|
end
|
101
101
|
|
@@ -211,6 +211,37 @@ module RightAws
|
|
211
211
|
on_exception
|
212
212
|
end
|
213
213
|
|
214
|
+
# Retrieves the logging configuration for a bucket.
|
215
|
+
# Returns a hash of {:enabled, :targetbucket, :targetprefix}
|
216
|
+
#
|
217
|
+
# s3.interface.get_logging_parse(:bucket => "asset_bucket")
|
218
|
+
# => {:enabled=>true, :targetbucket=>"mylogbucket", :targetprefix=>"loggylogs/"}
|
219
|
+
#
|
220
|
+
#
|
221
|
+
def get_logging_parse(params)
|
222
|
+
AwsUtils.mandatory_arguments([:bucket], params)
|
223
|
+
AwsUtils.allow_only([:bucket, :headers], params)
|
224
|
+
params[:headers] = {} unless params[:headers]
|
225
|
+
req_hash = generate_rest_request('GET', params[:headers].merge(:url=>"#{params[:bucket]}?logging"))
|
226
|
+
request_info(req_hash, S3LoggingParser.new)
|
227
|
+
rescue
|
228
|
+
on_exception
|
229
|
+
end
|
230
|
+
|
231
|
+
# Sets logging configuration for a bucket from the XML configuration document.
|
232
|
+
# params:
|
233
|
+
# :bucket
|
234
|
+
# :xmldoc
|
235
|
+
def put_logging(params)
|
236
|
+
AwsUtils.mandatory_arguments([:bucket,:xmldoc], params)
|
237
|
+
AwsUtils.allow_only([:bucket,:xmldoc, :headers], params)
|
238
|
+
params[:headers] = {} unless params[:headers]
|
239
|
+
req_hash = generate_rest_request('PUT', params[:headers].merge(:url=>"#{params[:bucket]}?logging", :data => params[:xmldoc]))
|
240
|
+
request_info(req_hash, S3TrueParser.new)
|
241
|
+
rescue
|
242
|
+
on_exception
|
243
|
+
end
|
244
|
+
|
214
245
|
# Deletes new bucket. Bucket must be empty! Returns +true+ or an exception.
|
215
246
|
#
|
216
247
|
# s3.delete_bucket('my_awesome_bucket') #=> true
|
@@ -349,6 +380,7 @@ module RightAws
|
|
349
380
|
# a text mode IO object is passed to PUT, it will be converted to binary
|
350
381
|
# mode.
|
351
382
|
#
|
383
|
+
|
352
384
|
def put(bucket, key, data=nil, headers={})
|
353
385
|
# On Windows, if someone opens a file in text mode, we must reset it so
|
354
386
|
# to binary mode for streaming to work properly
|
@@ -364,6 +396,86 @@ module RightAws
|
|
364
396
|
rescue
|
365
397
|
on_exception
|
366
398
|
end
|
399
|
+
|
400
|
+
|
401
|
+
|
402
|
+
# New experimental API for uploading objects, introduced in RightAws 1.8.1.
|
403
|
+
# store_object is similar in function to the older function put, but returns the full response metadata. It also allows for optional verification
|
404
|
+
# of object md5 checksums on upload. Parameters are passed as hash entries and are checked for completeness as well as for spurious arguments.
|
405
|
+
# The hash of the response headers contains useful information like the Amazon request ID and the object ETag (MD5 checksum).
|
406
|
+
#
|
407
|
+
# If the optional :md5 argument is provided, store_object verifies that the given md5 matches the md5 returned by S3. The :verified_md5 field in the response hash is
|
408
|
+
# set true or false depending on the outcome of this check. If no :md5 argument is given, :verified_md5 will be false in the response.
|
409
|
+
#
|
410
|
+
# The optional argument of :headers allows the caller to specify arbitrary request header values.
|
411
|
+
#
|
412
|
+
# s3.store_object(:bucket => "foobucket", :key => "foo", :md5 => "a507841b1bc8115094b00bbe8c1b2954", :data => "polemonium" )
|
413
|
+
# => {"x-amz-id-2"=>"SVsnS2nfDaR+ixyJUlRKM8GndRyEMS16+oZRieamuL61pPxPaTuWrWtlYaEhYrI/",
|
414
|
+
# "etag"=>"\"a507841b1bc8115094b00bbe8c1b2954\"",
|
415
|
+
# "date"=>"Mon, 29 Sep 2008 18:57:46 GMT",
|
416
|
+
# :verified_md5=>true,
|
417
|
+
# "x-amz-request-id"=>"63916465939995BA",
|
418
|
+
# "server"=>"AmazonS3",
|
419
|
+
# "content-length"=>"0"}
|
420
|
+
#
|
421
|
+
# s3.store_object(:bucket => "foobucket", :key => "foo", :data => "polemonium" )
|
422
|
+
# => {"x-amz-id-2"=>"MAt9PLjgLX9UYJ5tV2fI/5dBZdpFjlzRVpWgBDpvZpl+V+gJFcBMW2L+LBstYpbR",
|
423
|
+
# "etag"=>"\"a507841b1bc8115094b00bbe8c1b2954\"",
|
424
|
+
# "date"=>"Mon, 29 Sep 2008 18:58:56 GMT",
|
425
|
+
# :verified_md5=>false,
|
426
|
+
# "x-amz-request-id"=>"3B25A996BC2CDD3B",
|
427
|
+
# "server"=>"AmazonS3",
|
428
|
+
# "content-length"=>"0"}
|
429
|
+
|
430
|
+
def store_object(params)
|
431
|
+
AwsUtils.allow_only([:bucket, :key, :data, :headers, :md5], params)
|
432
|
+
AwsUtils.mandatory_arguments([:bucket, :key, :data], params)
|
433
|
+
params[:headers] = {} unless params[:headers]
|
434
|
+
|
435
|
+
params[:data].binmode if(params[:data].respond_to?(:binmode)) # On Windows, if someone opens a file in text mode, we must reset it to binary mode for streaming to work properly
|
436
|
+
if (params[:data].respond_to?(:lstat) && params[:data].lstat.size >= USE_100_CONTINUE_PUT_SIZE) ||
|
437
|
+
(params[:data].respond_to?(:size) && params[:data].size >= USE_100_CONTINUE_PUT_SIZE)
|
438
|
+
params[:headers]['expect'] = '100-continue'
|
439
|
+
end
|
440
|
+
|
441
|
+
req_hash = generate_rest_request('PUT', params[:headers].merge(:url=>"#{params[:bucket]}/#{CGI::escape params[:key]}", :data=>params[:data]))
|
442
|
+
resp = request_info(req_hash, S3HttpResponseHeadParser.new)
|
443
|
+
if(params[:md5])
|
444
|
+
resp[:verified_md5] = (resp['etag'].gsub(/\"/, '') == params[:md5]) ? true : false
|
445
|
+
else
|
446
|
+
resp[:verified_md5] = false
|
447
|
+
end
|
448
|
+
resp
|
449
|
+
rescue
|
450
|
+
on_exception
|
451
|
+
end
|
452
|
+
|
453
|
+
# Identical in function to store_object, but requires verification that the returned ETag is identical to the checksum passed in by the user as the 'md5' argument.
|
454
|
+
# If the check passes, returns the response metadata with the "verified_md5" field set true. Raises an exception if the checksums conflict.
|
455
|
+
# This call is implemented as a wrapper around put_object and the user may gain different semantics by creating a custom wrapper.
|
456
|
+
#
|
457
|
+
# s3.store_object_and_verify(:bucket => "foobucket", :key => "foo", :md5 => "a507841b1bc8115094b00bbe8c1b2954", :data => "polemonium" )
|
458
|
+
# => {"x-amz-id-2"=>"IZN3XsH4FlBU0+XYkFTfHwaiF1tNzrm6dIW2EM/cthKvl71nldfVC0oVQyydzWpb",
|
459
|
+
# "etag"=>"\"a507841b1bc8115094b00bbe8c1b2954\"",
|
460
|
+
# "date"=>"Mon, 29 Sep 2008 18:38:32 GMT",
|
461
|
+
# :verified_md5=>true,
|
462
|
+
# "x-amz-request-id"=>"E8D7EA4FE00F5DF7",
|
463
|
+
# "server"=>"AmazonS3",
|
464
|
+
# "content-length"=>"0"}
|
465
|
+
#
|
466
|
+
# s3.store_object_and_verify(:bucket => "foobucket", :key => "foo", :md5 => "a507841b1bc8115094b00bbe8c1b2953", :data => "polemonium" )
|
467
|
+
# RightAws::AwsError: Uploaded object failed MD5 checksum verification: {"x-amz-id-2"=>"HTxVtd2bf7UHHDn+WzEH43MkEjFZ26xuYvUzbstkV6nrWvECRWQWFSx91z/bl03n",
|
468
|
+
# "etag"=>"\"a507841b1bc8115094b00bbe8c1b2954\"",
|
469
|
+
# "date"=>"Mon, 29 Sep 2008 18:38:41 GMT",
|
470
|
+
# :verified_md5=>false,
|
471
|
+
# "x-amz-request-id"=>"0D7ADE09F42606F2",
|
472
|
+
# "server"=>"AmazonS3",
|
473
|
+
# "content-length"=>"0"}
|
474
|
+
def store_object_and_verify(params)
|
475
|
+
AwsUtils.mandatory_arguments([:md5], params)
|
476
|
+
r = put_object(params)
|
477
|
+
r[:verified_md5] ? (return r) : (raise AwsError.new("Uploaded object failed MD5 checksum verification: #{r.inspect}"))
|
478
|
+
end
|
367
479
|
|
368
480
|
# Retrieves object data from Amazon. Returns a +hash+ or an exception.
|
369
481
|
#
|
@@ -398,6 +510,68 @@ module RightAws
|
|
398
510
|
rescue
|
399
511
|
on_exception
|
400
512
|
end
|
513
|
+
|
514
|
+
# New experimental API for retrieving objects, introduced in RightAws 1.8.1.
|
515
|
+
# retrieve_object is similar in function to the older function get. It allows for optional verification
|
516
|
+
# of object md5 checksums on retrieval. Parameters are passed as hash entries and are checked for completeness as well as for spurious arguments.
|
517
|
+
#
|
518
|
+
# If the optional :md5 argument is provided, retrieve_object verifies that the given md5 matches the md5 returned by S3. The :verified_md5 field in the response hash is
|
519
|
+
# set true or false depending on the outcome of this check. If no :md5 argument is given, :verified_md5 will be false in the response.
|
520
|
+
#
|
521
|
+
# The optional argument of :headers allows the caller to specify arbitrary request header values.
|
522
|
+
# Mandatory arguments:
|
523
|
+
# :bucket - the bucket in which the object is stored
|
524
|
+
# :key - the object address (or path) within the bucket
|
525
|
+
# Optional arguments:
|
526
|
+
# :headers - hash of additional HTTP headers to include with the request
|
527
|
+
# :md5 - MD5 checksum against which to verify the retrieved object
|
528
|
+
#
|
529
|
+
# s3.retrieve_object(:bucket => "foobucket", :key => "foo")
|
530
|
+
# => {:verified_md5=>false,
|
531
|
+
# :headers=>{"last-modified"=>"Mon, 29 Sep 2008 18:58:56 GMT",
|
532
|
+
# "x-amz-id-2"=>"2Aj3TDz6HP5109qly//18uHZ2a1TNHGLns9hyAtq2ved7wmzEXDOPGRHOYEa3Qnp",
|
533
|
+
# "content-type"=>"",
|
534
|
+
# "etag"=>"\"a507841b1bc8115094b00bbe8c1b2954\"",
|
535
|
+
# "date"=>"Tue, 30 Sep 2008 00:52:44 GMT",
|
536
|
+
# "x-amz-request-id"=>"EE4855DE27A2688C",
|
537
|
+
# "server"=>"AmazonS3",
|
538
|
+
# "content-length"=>"10"},
|
539
|
+
# :object=>"polemonium"}
|
540
|
+
#
|
541
|
+
# s3.retrieve_object(:bucket => "foobucket", :key => "foo", :md5=>'a507841b1bc8115094b00bbe8c1b2954')
|
542
|
+
# => {:verified_md5=>true,
|
543
|
+
# :headers=>{"last-modified"=>"Mon, 29 Sep 2008 18:58:56 GMT",
|
544
|
+
# "x-amz-id-2"=>"mLWQcI+VuKVIdpTaPXEo84g0cz+vzmRLbj79TS8eFPfw19cGFOPxuLy4uGYVCvdH",
|
545
|
+
# "content-type"=>"", "etag"=>"\"a507841b1bc8115094b00bbe8c1b2954\"",
|
546
|
+
# "date"=>"Tue, 30 Sep 2008 00:53:08 GMT",
|
547
|
+
# "x-amz-request-id"=>"6E7F317356580599",
|
548
|
+
# "server"=>"AmazonS3",
|
549
|
+
# "content-length"=>"10"},
|
550
|
+
# :object=>"polemonium"}
|
551
|
+
def retrieve_object(params, &block)
|
552
|
+
AwsUtils.mandatory_arguments([:bucket, :key], params)
|
553
|
+
AwsUtils.allow_only([:bucket, :key, :headers, :md5], params)
|
554
|
+
params[:headers] = {} unless params[:headers]
|
555
|
+
req_hash = generate_rest_request('GET', params[:headers].merge(:url=>"#{params[:bucket]}/#{CGI::escape params[:key]}"))
|
556
|
+
resp = request_info(req_hash, S3HttpResponseBodyParser.new, &block)
|
557
|
+
resp[:verified_md5] = false
|
558
|
+
if(params[:md5] && (resp[:headers]['etag'].gsub(/\"/,'') == params[:md5]))
|
559
|
+
resp[:verified_md5] = true
|
560
|
+
end
|
561
|
+
resp
|
562
|
+
rescue
|
563
|
+
on_exception
|
564
|
+
end
|
565
|
+
|
566
|
+
# Identical in function to retrieve_object, but requires verification that the returned ETag is identical to the checksum passed in by the user as the 'md5' argument.
|
567
|
+
# If the check passes, returns the response metadata with the "verified_md5" field set true. Raises an exception if the checksums conflict.
|
568
|
+
# This call is implemented as a wrapper around retrieve_object and the user may gain different semantics by creating a custom wrapper.
|
569
|
+
def retrieve_object_and_verify(params, &block)
|
570
|
+
AwsUtils.mandatory_arguments([:md5], params)
|
571
|
+
resp = get_object(params, block)
|
572
|
+
return resp if resp[:verified_md5]
|
573
|
+
raise AwsError.new("Retrieved object failed MD5 checksum verification: #{resp.inspect}")
|
574
|
+
end
|
401
575
|
|
402
576
|
# Retrieves object metadata. Returns a +hash+ of http_response_headers.
|
403
577
|
#
|
@@ -932,6 +1106,28 @@ module RightAws
|
|
932
1106
|
end
|
933
1107
|
end
|
934
1108
|
end
|
1109
|
+
|
1110
|
+
class S3LoggingParser < RightAWSParser # :nodoc:
|
1111
|
+
def reset
|
1112
|
+
@result = {:enabled => false, :targetbucket => '', :targetprefix => ''}
|
1113
|
+
@current_grantee = {}
|
1114
|
+
end
|
1115
|
+
def tagend(name)
|
1116
|
+
case name
|
1117
|
+
# service info
|
1118
|
+
when 'TargetBucket'
|
1119
|
+
if @xmlpath == 'BucketLoggingStatus/LoggingEnabled'
|
1120
|
+
@result[:targetbucket] = @text
|
1121
|
+
@result[:enabled] = true
|
1122
|
+
end
|
1123
|
+
when 'TargetPrefix'
|
1124
|
+
if @xmlpath == 'BucketLoggingStatus/LoggingEnabled'
|
1125
|
+
@result[:targetprefix] = @text
|
1126
|
+
@result[:enabled] = true
|
1127
|
+
end
|
1128
|
+
end
|
1129
|
+
end
|
1130
|
+
end
|
935
1131
|
|
936
1132
|
class S3CopyParser < RightAWSParser # :nodoc:
|
937
1133
|
def reset
|
data/lib/sdb/active_sdb.rb
CHANGED
@@ -101,6 +101,15 @@ module RightAws
|
|
101
101
|
# Create a new handle to an Sdb account. All handles share the same per process or per thread
|
102
102
|
# HTTP connection to Amazon Sdb. Each handle is for a specific account.
|
103
103
|
# The +params+ are passed through as-is to RightAws::SdbInterface.new
|
104
|
+
# Params:
|
105
|
+
# { :server => 'sdb.amazonaws.com' # Amazon service host: 'sdb.amazonaws.com'(default)
|
106
|
+
# :port => 443 # Amazon service port: 80 or 443(default)
|
107
|
+
# :protocol => 'https' # Amazon service protocol: 'http' or 'https'(default)
|
108
|
+
# :signature_version => '0' # The signature version : '0' or '1'(default)
|
109
|
+
# :multi_thread => true|false # Multi-threaded (connection per each thread): true or false(default)
|
110
|
+
# :logger => Logger Object # Logger instance: logs to STDOUT if omitted
|
111
|
+
# :nil_representation => 'mynil'} # interpret Ruby nil as this string value; i.e. use this string in SDB to represent Ruby nils (default is the string 'nil')
|
112
|
+
|
104
113
|
def establish_connection(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
|
105
114
|
@connection = RightAws::SdbInterface.new(aws_access_key_id, aws_secret_access_key, params)
|
106
115
|
end
|
@@ -259,9 +268,10 @@ module RightAws
|
|
259
268
|
# Client.find_by_name('Matias Rust')
|
260
269
|
# Client.find_by_name_and_city('Putin','Moscow')
|
261
270
|
# Client.find_by_name_and_city_and_post('Medvedev','Moscow','president')
|
262
|
-
#
|
271
|
+
#
|
263
272
|
# Client.find_all_by_author('G.Bush jr')
|
264
273
|
# Client.find_all_by_age_and_gender_and_ethnicity('34','male','russian')
|
274
|
+
# Client.find_all_by_gender_and_country('male', 'Russia', :auto_load => true, :order => 'name desc')
|
265
275
|
#
|
266
276
|
# Returned records have to be +reloaded+ to access their attributes.
|
267
277
|
#
|
@@ -276,37 +286,100 @@ module RightAws
|
|
276
286
|
# Client.find(:all, :limit => 10, :next_token => Client.next_token)
|
277
287
|
# end while Client.next_token
|
278
288
|
#
|
289
|
+
# Sort oder:
|
290
|
+
# Client.find(:all, :order => 'gender')
|
291
|
+
# Client.find(:all, :order => 'name desc')
|
292
|
+
#
|
293
|
+
# Attributes auto load (be carefull - this may take lot of time for a huge bunch of records):
|
294
|
+
# Client.find(:first) #=> #<Client:0xb77d0d40 @attributes={"id"=>"2937601a-e45d-11dc-a75f-001bfc466dd7"}, @new_record=false>
|
295
|
+
# Client.find(:first, :auto_load => true) #=> #<Client:0xb77d0d40 @attributes={"id"=>"2937601a-e45d-11dc-a75f-001bfc466dd7", "name"=>["Cat"], "toys"=>["Jons socks", "clew", "mice"]}, @new_record=false>
|
296
|
+
#
|
279
297
|
def find(*args)
|
280
298
|
options = args.last.is_a?(Hash) ? args.pop : {}
|
281
299
|
case args.first
|
282
|
-
when :all
|
283
|
-
when :first
|
284
|
-
else
|
300
|
+
when :all then find_every options
|
301
|
+
when :first then find_initial options
|
302
|
+
else find_from_ids args, options
|
285
303
|
end
|
286
304
|
end
|
287
305
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
306
|
+
protected
|
307
|
+
|
308
|
+
# Returns an array of query attributes.
|
309
|
+
# Query_expression must be a well formated SDB query string:
|
310
|
+
# query_attributes("['title' starts-with 'O\\'Reily'] intersection ['year' = '2007']") #=> ["title", "year"]
|
311
|
+
def query_attributes(query_expression)
|
312
|
+
attrs = []
|
313
|
+
array = query_expression.scan(/['"](.*?[^\\])['"]/).flatten
|
314
|
+
until array.empty? do
|
315
|
+
attrs << array.shift # skip it's value
|
316
|
+
array.shift #
|
317
|
+
end
|
318
|
+
attrs
|
319
|
+
end
|
320
|
+
|
321
|
+
# Returns an array of [attribute_name, 'asc'|'desc']
|
322
|
+
def sort_options(sort_string)
|
323
|
+
sort_string[/['"]?(\w+)['"]? *(asc|desc)?/i]
|
324
|
+
[$1, ($2 || 'asc')]
|
325
|
+
end
|
326
|
+
|
327
|
+
# Perform a query request.
|
328
|
+
#
|
329
|
+
# Options
|
330
|
+
# :query_expression nil | string | array
|
331
|
+
# :max_number_of_items nil | integer
|
332
|
+
# :next_token nil | string
|
333
|
+
# :sort_option nil | string "name desc|asc"
|
334
|
+
#
|
335
|
+
def query(options) # :nodoc:
|
336
|
+
@next_token = options[:next_token]
|
337
|
+
query_expression = options[:query_expression]
|
338
|
+
query_expression = connection.query_expression_from_array(query_expression) if query_expression.is_a?(Array)
|
339
|
+
# add sort_options to the query_expression
|
340
|
+
if options[:sort_option]
|
341
|
+
sort_by, sort_order = sort_options(options[:sort_option])
|
342
|
+
sort_query_expression = "['#{sort_by}' starts-with '']"
|
343
|
+
sort_by_expression = " sort '#{sort_by}' #{sort_order}"
|
344
|
+
# make query_expression to be a string (it may be null)
|
345
|
+
query_expression = query_expression.to_s
|
346
|
+
# quote from Amazon:
|
347
|
+
# The sort attribute must be present in at least one of the predicates of the query expression.
|
348
|
+
if query_expression.blank?
|
349
|
+
query_expression = sort_query_expression
|
350
|
+
elsif !query_attributes(query_expression).include?(sort_by)
|
351
|
+
query_expression += " intersection #{sort_query_expression}"
|
352
|
+
end
|
353
|
+
query_expression += sort_by_expression
|
354
|
+
end
|
292
355
|
# request items
|
293
|
-
query_result = self.connection.query(domain, query_expression, max_number_of_items, @next_token)
|
356
|
+
query_result = self.connection.query(domain, query_expression, options[:max_number_of_items], @next_token)
|
294
357
|
@next_token = query_result[:next_token]
|
295
358
|
items = query_result[:items].map do |name|
|
296
359
|
new_item = self.new('id' => name)
|
297
360
|
new_item.mark_as_old
|
361
|
+
new_item.reload if options[:auto_load]
|
298
362
|
new_item
|
299
363
|
end
|
300
364
|
items
|
301
365
|
end
|
302
366
|
|
367
|
+
def reload_all_records(*list) # :nodoc:
|
368
|
+
list.flatten.each { |record| record.reload }
|
369
|
+
end
|
370
|
+
|
303
371
|
def find_every(options) # :nodoc:
|
304
|
-
query(
|
372
|
+
records = query( :query_expression => options[:conditions],
|
373
|
+
:max_number_of_items => options[:limit],
|
374
|
+
:next_token => options[:next_token],
|
375
|
+
:sort_option => options[:sort] || options[:order] )
|
376
|
+
options[:auto_load] ? reload_all_records(records) : records
|
305
377
|
end
|
306
378
|
|
307
379
|
def find_initial(options) # :nodoc:
|
308
380
|
options[:limit] = 1
|
309
|
-
find_every(options)
|
381
|
+
record = find_every(options).first
|
382
|
+
options[:auto_load] ? reload_all_records(record).first : record
|
310
383
|
end
|
311
384
|
|
312
385
|
def find_from_ids(args, options) # :nodoc:
|
@@ -326,7 +399,7 @@ module RightAws
|
|
326
399
|
result = find_every(options)
|
327
400
|
# if one record was requested then return it
|
328
401
|
unless bunch_of_records_requested
|
329
|
-
result.first
|
402
|
+
options[:auto_load] ? reload_all_records(result.first).first : result.first
|
330
403
|
else
|
331
404
|
# if a bunch of records was requested then return check that we found all of them
|
332
405
|
# and return as an array
|
@@ -334,35 +407,40 @@ module RightAws
|
|
334
407
|
id_list = args.map{|i| "'#{i}'"}.join(',')
|
335
408
|
raise ActiveSdbError.new("Couldn't find all #{name} with IDs (#{id_list}) (found #{result.size} results, but was looking for #{args.size})")
|
336
409
|
else
|
337
|
-
result
|
410
|
+
options[:auto_load] ? reload_all_records(result) : result
|
338
411
|
end
|
339
412
|
end
|
340
413
|
end
|
341
414
|
|
342
415
|
# find_by helpers
|
343
|
-
def find_all_by_(format_str, args,
|
416
|
+
def find_all_by_(format_str, args, options) # :nodoc:
|
344
417
|
fields = format_str.to_s.sub(/^find_(all_)?by_/,'').split('_and_')
|
345
418
|
conditions = fields.map { |field| "['#{field}'=?]" }.join(' intersection ')
|
346
|
-
|
419
|
+
options[:conditions] = [conditions, *args]
|
420
|
+
find(:all, options)
|
347
421
|
end
|
348
422
|
|
349
|
-
def find_by_(format_str, args) # :nodoc:
|
350
|
-
|
423
|
+
def find_by_(format_str, args, options) # :nodoc:
|
424
|
+
options[:limit] = 1
|
425
|
+
find_all_by_(format_str, args, options).first
|
351
426
|
end
|
352
427
|
|
353
428
|
def method_missing(method, *args) # :nodoc:
|
354
|
-
if
|
355
|
-
|
356
|
-
|
429
|
+
if method.to_s[/^(find_all_by_|find_by_)/]
|
430
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
431
|
+
if method.to_s[/^find_all_by_/]
|
432
|
+
find_all_by_(method, args, options)
|
433
|
+
else
|
434
|
+
find_by_(method, args, options)
|
435
|
+
end
|
436
|
+
else
|
437
|
+
super(method, *args)
|
357
438
|
end
|
358
439
|
end
|
359
|
-
|
360
440
|
end
|
361
441
|
|
362
442
|
def self.generate_id # :nodoc:
|
363
|
-
|
364
|
-
result = UUID.timestamp_create().to_s
|
365
|
-
result
|
443
|
+
UUID.timestamp_create().to_s
|
366
444
|
end
|
367
445
|
|
368
446
|
public
|
@@ -33,11 +33,14 @@ module RightAws
|
|
33
33
|
DEFAULT_PORT = 443
|
34
34
|
DEFAULT_PROTOCOL = 'https'
|
35
35
|
API_VERSION = '2007-11-07'
|
36
|
+
DEFAULT_NIL_REPRESENTATION = 'nil'
|
36
37
|
|
37
38
|
@@bench = AwsBenchmarkingBlock.new
|
38
39
|
def self.bench_xml; @@bench.xml; end
|
39
40
|
def self.bench_sdb; @@bench.service; end
|
40
41
|
|
42
|
+
attr_reader :last_query_expression
|
43
|
+
|
41
44
|
# Creates new RightSdb instance.
|
42
45
|
#
|
43
46
|
# Params:
|
@@ -46,7 +49,8 @@ module RightAws
|
|
46
49
|
# :protocol => 'https' # Amazon service protocol: 'http' or 'https'(default)
|
47
50
|
# :signature_version => '0' # The signature version : '0' or '1'(default)
|
48
51
|
# :multi_thread => true|false # Multi-threaded (connection per each thread): true or false(default)
|
49
|
-
# :logger => Logger Object
|
52
|
+
# :logger => Logger Object # Logger instance: logs to STDOUT if omitted
|
53
|
+
# :nil_representation => 'mynil'} # interpret Ruby nil as this string value; i.e. use this string in SDB to represent Ruby nils (default is the string 'nil')
|
50
54
|
#
|
51
55
|
# Example:
|
52
56
|
#
|
@@ -55,6 +59,8 @@ module RightAws
|
|
55
59
|
# see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/
|
56
60
|
#
|
57
61
|
def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
|
62
|
+
@nil_rep = params[:nil_representation] ? params[:nil_representation] : DEFAULT_NIL_REPRESENTATION
|
63
|
+
params.delete(:nil_representation)
|
58
64
|
init({ :name => 'SDB',
|
59
65
|
:default_host => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).host : DEFAULT_HOST,
|
60
66
|
:default_port => ENV['SDB_URL'] ? URI.parse(ENV['SDB_URL']).port : DEFAULT_PORT,
|
@@ -69,8 +75,8 @@ module RightAws
|
|
69
75
|
#-----------------------------------------------------------------
|
70
76
|
def generate_request(action, params={}) #:nodoc:
|
71
77
|
# remove empty params from request
|
72
|
-
params.delete_if {|key,value| value.
|
73
|
-
params_string = params.to_a.collect{|key,val| key + "=#{CGI::escape(val.to_s)}" }.join("&")
|
78
|
+
params.delete_if {|key,value| value.nil? }
|
79
|
+
#params_string = params.to_a.collect{|key,val| key + "=#{CGI::escape(val.to_s)}" }.join("&")
|
74
80
|
# prepare service data
|
75
81
|
service_hash = {"Action" => action,
|
76
82
|
"AWSAccessKeyId" => @aws_access_key_id,
|
@@ -80,20 +86,20 @@ module RightAws
|
|
80
86
|
service_hash.update(params)
|
81
87
|
# prepare string to sight
|
82
88
|
string_to_sign = case signature_version
|
83
|
-
when '0'
|
84
|
-
when '1'
|
89
|
+
when '0' then service_hash["Action"] + service_hash["Timestamp"]
|
90
|
+
when '1' then service_hash.sort{|a,b| (a[0].to_s.downcase)<=>(b[0].to_s.downcase)}.to_s
|
85
91
|
end
|
86
92
|
service_hash.update('Signature' => AwsUtils::sign(@aws_secret_access_key, string_to_sign))
|
87
93
|
service_string = service_hash.to_a.collect{|key,val| key + "=#{CGI::escape(val.to_s)}" }.join("&")
|
88
94
|
#
|
89
95
|
# use POST method if the length of the query string is too large
|
90
96
|
# see http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/MakingRESTRequests.html
|
91
|
-
if
|
92
|
-
request = Net::HTTP::Post.new("
|
93
|
-
request.body =
|
97
|
+
if service_string.size > 2000
|
98
|
+
request = Net::HTTP::Post.new("/")
|
99
|
+
request.body = service_string
|
94
100
|
else
|
95
|
-
params_string = "&#{params_string}" unless params_string.blank?
|
96
|
-
request = Net::HTTP::Get.new("/?#{service_string}
|
101
|
+
#params_string = "&#{params_string}" unless params_string.blank?
|
102
|
+
request = Net::HTTP::Get.new("/?#{service_string}")
|
97
103
|
end
|
98
104
|
# prepare output hash
|
99
105
|
{ :request => request,
|
@@ -116,18 +122,20 @@ module RightAws
|
|
116
122
|
result = {}
|
117
123
|
if attributes
|
118
124
|
idx = 0
|
125
|
+
skip_values = attributes.is_a?(Array)
|
119
126
|
attributes.each do |attribute, values|
|
120
127
|
# set replacement attribute
|
121
128
|
result["Attribute.#{idx}.Replace"] = 'true' if replace
|
122
129
|
# pack Name/Value
|
123
|
-
unless values.
|
124
|
-
values.
|
130
|
+
unless values.nil?
|
131
|
+
Array(values).each do |value|
|
125
132
|
result["Attribute.#{idx}.Name"] = attribute
|
126
|
-
result["Attribute.#{idx}.Value"] = value
|
133
|
+
result["Attribute.#{idx}.Value"] = ruby_to_sdb(value) unless skip_values
|
127
134
|
idx += 1
|
128
135
|
end
|
129
136
|
else
|
130
137
|
result["Attribute.#{idx}.Name"] = attribute
|
138
|
+
result["Attribute.#{idx}.Value"] = ruby_to_sdb(nil) unless skip_values
|
131
139
|
idx += 1
|
132
140
|
end
|
133
141
|
end
|
@@ -144,6 +152,18 @@ module RightAws
|
|
144
152
|
%Q{'#{value.to_s.gsub(/(['\\])/){ "\\#{$1}" }}'} if value
|
145
153
|
end
|
146
154
|
|
155
|
+
# Convert a Ruby language value to a SDB value by replacing Ruby nil with the user's chosen string representation of nil.
|
156
|
+
# Non-nil values are unaffected by this filter.
|
157
|
+
def ruby_to_sdb(value)
|
158
|
+
value.nil? ? @nil_rep : value
|
159
|
+
end
|
160
|
+
|
161
|
+
# Convert a SDB value to a Ruby language value by replacing the user's chosen string representation of nil with Ruby nil.
|
162
|
+
# Values are unaffected by this filter unless they match the nil representation exactly.
|
163
|
+
def sdb_to_ruby(value)
|
164
|
+
value.eql?(@nil_rep) ? nil : value
|
165
|
+
end
|
166
|
+
|
147
167
|
# Create query expression from an array.
|
148
168
|
# (similar to ActiveRecord::Base#find using :conditions => ['query', param1, .., paramN])
|
149
169
|
#
|
@@ -324,7 +344,11 @@ module RightAws
|
|
324
344
|
link = generate_request("GetAttributes", 'DomainName' => domain_name,
|
325
345
|
'ItemName' => item_name,
|
326
346
|
'AttributeName' => attribute_name )
|
327
|
-
request_info(link, QSdbGetAttributesParser.new)
|
347
|
+
res = request_info(link, QSdbGetAttributesParser.new)
|
348
|
+
res[:attributes].each_value do |values|
|
349
|
+
values.collect! { |e| sdb_to_ruby(e) }
|
350
|
+
end
|
351
|
+
res
|
328
352
|
rescue Exception
|
329
353
|
on_exception
|
330
354
|
end
|
@@ -385,10 +409,15 @@ module RightAws
|
|
385
409
|
# query = [ "['cat'=?] union ['dog'=?]", "clew", "Jon's boot" ]
|
386
410
|
# sdb.query('family', query)
|
387
411
|
#
|
412
|
+
# query = [ "['cat'=?] union ['dog'=?] sort 'cat' desc", "clew", "Jon's boot" ]
|
413
|
+
# sdb.query('family', query)
|
414
|
+
#
|
388
415
|
# see: http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/SDB_API_Query.html
|
416
|
+
# http://docs.amazonwebservices.com/AmazonSimpleDB/2007-11-07/DeveloperGuide/index.html?SortingData.html
|
389
417
|
#
|
390
418
|
def query(domain_name, query_expression = nil, max_number_of_items = nil, next_token = nil)
|
391
419
|
query_expression = query_expression_from_array(query_expression) if query_expression.is_a?(Array)
|
420
|
+
@last_query_expression = query_expression
|
392
421
|
#
|
393
422
|
request_params = { 'DomainName' => domain_name,
|
394
423
|
'QueryExpression' => query_expression,
|
@@ -420,10 +449,10 @@ module RightAws
|
|
420
449
|
end
|
421
450
|
def tagend(name)
|
422
451
|
case name
|
423
|
-
when 'NextToken'
|
424
|
-
when 'DomainName'
|
425
|
-
when 'BoxUsage'
|
426
|
-
when 'RequestId'
|
452
|
+
when 'NextToken' then @result[:next_token] = @text
|
453
|
+
when 'DomainName' then @result[:domains] << @text
|
454
|
+
when 'BoxUsage' then @result[:box_usage] = @text
|
455
|
+
when 'RequestId' then @result[:request_id] = @text
|
427
456
|
end
|
428
457
|
end
|
429
458
|
end
|
@@ -434,8 +463,8 @@ module RightAws
|
|
434
463
|
end
|
435
464
|
def tagend(name)
|
436
465
|
case name
|
437
|
-
when 'BoxUsage'
|
438
|
-
when 'RequestId'
|
466
|
+
when 'BoxUsage' then @result[:box_usage] = @text
|
467
|
+
when 'RequestId' then @result[:request_id] = @text
|
439
468
|
end
|
440
469
|
end
|
441
470
|
end
|
@@ -447,10 +476,10 @@ module RightAws
|
|
447
476
|
end
|
448
477
|
def tagend(name)
|
449
478
|
case name
|
450
|
-
when 'Name'
|
451
|
-
when 'Value'
|
452
|
-
when 'BoxUsage'
|
453
|
-
when 'RequestId'
|
479
|
+
when 'Name' then @last_attribute_name = @text
|
480
|
+
when 'Value' then (@result[:attributes][@last_attribute_name] ||= []) << @text
|
481
|
+
when 'BoxUsage' then @result[:box_usage] = @text
|
482
|
+
when 'RequestId' then @result[:request_id] = @text
|
454
483
|
end
|
455
484
|
end
|
456
485
|
end
|
@@ -461,10 +490,10 @@ module RightAws
|
|
461
490
|
end
|
462
491
|
def tagend(name)
|
463
492
|
case name
|
464
|
-
when 'ItemName'
|
465
|
-
when 'BoxUsage'
|
466
|
-
when 'RequestId'
|
467
|
-
when 'NextToken'
|
493
|
+
when 'ItemName' then @result[:items] << @text
|
494
|
+
when 'BoxUsage' then @result[:box_usage] = @text
|
495
|
+
when 'RequestId' then @result[:request_id] = @text
|
496
|
+
when 'NextToken' then @result[:next_token] = @text
|
468
497
|
end
|
469
498
|
end
|
470
499
|
end
|
data/lib/sqs/right_sqs.rb
CHANGED
@@ -54,6 +54,14 @@ module RightAws
|
|
54
54
|
# ...
|
55
55
|
# grantee2 = queue.grantees('another_cool_guy@email.address')
|
56
56
|
# grantee2.revoke('SENDMESSAGE')
|
57
|
+
#
|
58
|
+
# Params is a hash:
|
59
|
+
#
|
60
|
+
# {:server => 'queue.amazonaws.com' # Amazon service host: 'queue.amazonaws.com' (default)
|
61
|
+
# :port => 443 # Amazon service port: 80 or 443 (default)
|
62
|
+
# :multi_thread => true|false # Multi-threaded (connection per each thread): true or false (default)
|
63
|
+
# :signature_version => '0' # The signature version : '0' or '1'(default)
|
64
|
+
# :logger => Logger Object} # Logger instance: logs to STDOUT if omitted }
|
57
65
|
#
|
58
66
|
class Sqs
|
59
67
|
attr_reader :interface
|
data/lib/sqs/right_sqs_gen2.rb
CHANGED
@@ -55,6 +55,14 @@ module RightAws
|
|
55
55
|
# ...
|
56
56
|
#
|
57
57
|
# NB: Second-generation SQS has eliminated the entire access grant mechanism present in Gen 1.
|
58
|
+
#
|
59
|
+
# Params is a hash:
|
60
|
+
#
|
61
|
+
# {:server => 'queue.amazonaws.com' # Amazon service host: 'queue.amazonaws.com' (default)
|
62
|
+
# :port => 443 # Amazon service port: 80 or 443 (default)
|
63
|
+
# :multi_thread => true|false # Multi-threaded (connection per each thread): true or false (default)
|
64
|
+
# :signature_version => '0' # The signature version : '0' or '1'(default)
|
65
|
+
# :logger => Logger Object} # Logger instance: logs to STDOUT if omitted }
|
58
66
|
class SqsGen2
|
59
67
|
attr_reader :interface
|
60
68
|
|
data/test/s3/test_right_s3.rb
CHANGED
@@ -7,6 +7,7 @@ class TestS3 < Test::Unit::TestCase
|
|
7
7
|
def setup
|
8
8
|
@s3 = Rightscale::S3Interface.new(TestCredentials.aws_access_key_id, TestCredentials.aws_secret_access_key)
|
9
9
|
@bucket = 'right_s3_awesome_test_bucket_00001'
|
10
|
+
@bucket2 = 'right_s3_awesome_test_bucket_00002'
|
10
11
|
@key1 = 'test/woohoo1/'
|
11
12
|
@key2 = 'test1/key/woohoo2'
|
12
13
|
@key3 = 'test2/A%B@C_D&E?F+G=H"I'
|
@@ -72,9 +73,9 @@ class TestS3 < Test::Unit::TestCase
|
|
72
73
|
def test_08_keys
|
73
74
|
keys = @s3.list_bucket(@bucket).map{|b| b[:key]}
|
74
75
|
assert_equal keys.size, 3, "There should be 3 keys"
|
75
|
-
assert(keys.include?
|
76
|
-
assert(keys.include?
|
77
|
-
assert(keys.include?
|
76
|
+
assert(keys.include?(@key1))
|
77
|
+
assert(keys.include?(@key2))
|
78
|
+
assert(keys.include?(@key3))
|
78
79
|
end
|
79
80
|
|
80
81
|
def test_09_copy_key
|
@@ -120,18 +121,26 @@ class TestS3 < Test::Unit::TestCase
|
|
120
121
|
keys = @s3.list_bucket(@bucket).map{|b| b[:key]}
|
121
122
|
assert(!keys.include?(@key2))
|
122
123
|
end
|
123
|
-
|
124
|
-
|
124
|
+
def test_12_retrieve_object
|
125
|
+
assert_raise(Rightscale::AwsError) { @s3.retrieve_object(:bucket => @bucket, :key => 'undefined/key') }
|
126
|
+
data1 = @s3.retrieve_object(:bucket => @bucket, :key => @key1_new_name)
|
127
|
+
assert_equal RIGHT_OBJECT_TEXT, data1[:object], "Object text must be equal to '#{RIGHT_OBJECT_TEXT}'"
|
128
|
+
assert_equal 'Woohoo1!', data1[:headers]['x-amz-meta-family'], "x-amz-meta-family header must be equal to 'Woohoo1!'"
|
129
|
+
end
|
130
|
+
def test_13_delete_folder
|
125
131
|
assert_equal 1, @s3.delete_folder(@bucket, 'test').size, "Only one key(#{@key1}) must be deleted!"
|
126
132
|
end
|
127
|
-
|
128
|
-
def
|
133
|
+
|
134
|
+
def test_14_delete_bucket
|
129
135
|
assert_raise(Rightscale::AwsError) { @s3.delete_bucket(@bucket) }
|
130
136
|
assert @s3.clear_bucket(@bucket), 'Clear_bucket fail'
|
131
137
|
assert_equal 0, @s3.list_bucket(@bucket).size, 'Bucket must be empty'
|
132
138
|
assert @s3.delete_bucket(@bucket)
|
133
139
|
assert !@s3.list_all_my_buckets.map{|bucket| bucket[:name]}.include?(@bucket), "#{@bucket} must not exist"
|
134
140
|
end
|
141
|
+
|
142
|
+
|
143
|
+
|
135
144
|
|
136
145
|
#---------------------------
|
137
146
|
# Rightscale::S3 classes
|
@@ -312,10 +321,10 @@ class TestS3 < Test::Unit::TestCase
|
|
312
321
|
assert grantee.apply
|
313
322
|
assert !grantee.exists?
|
314
323
|
# Check multiple perms assignment
|
315
|
-
assert grantee.grant
|
324
|
+
assert grantee.grant('FULL_CONTROL', 'READ', 'WRITE')
|
316
325
|
assert_equal ['FULL_CONTROL','READ','WRITE'].sort, grantee.perms.sort
|
317
326
|
# Check multiple perms removal
|
318
|
-
assert grantee.revoke
|
327
|
+
assert grantee.revoke('FULL_CONTROL', 'WRITE')
|
319
328
|
assert_equal ['READ'], grantee.perms
|
320
329
|
# check 'Drop' method
|
321
330
|
assert grantee.drop
|
@@ -384,5 +393,27 @@ class TestS3 < Test::Unit::TestCase
|
|
384
393
|
RightAws::S3Interface.amazon_problems= nil
|
385
394
|
assert_nil(RightAws::S3Interface.amazon_problems)
|
386
395
|
end
|
396
|
+
|
397
|
+
def test_37_access_logging
|
398
|
+
bucket = Rightscale::S3::Bucket.create(@s, @bucket, false)
|
399
|
+
targetbucket = Rightscale::S3::Bucket.create(@s, @bucket2, true)
|
400
|
+
# Take 'AllUsers' grantee
|
401
|
+
grantee = Rightscale::S3::Grantee.new(targetbucket,'http://acs.amazonaws.com/groups/s3/LogDelivery')
|
402
|
+
|
403
|
+
assert grantee.grant(['READ_ACP', 'WRITE'])
|
404
|
+
|
405
|
+
assert bucket.enable_logging(:targetbucket => targetbucket, :targetprefix => "loggylogs/")
|
406
|
+
|
407
|
+
assert_equal(bucket.logging_info, {:enabled => true, :targetbucket => @bucket2, :targetprefix => "loggylogs/"})
|
408
|
+
|
409
|
+
assert bucket.disable_logging
|
410
|
+
|
411
|
+
# check 'Drop' method
|
412
|
+
assert grantee.drop
|
413
|
+
|
414
|
+
# Delete bucket
|
415
|
+
bucket.delete(true)
|
416
|
+
targetbucket.delete(true)
|
417
|
+
end
|
387
418
|
|
388
419
|
end
|
data/test/sdb/test_active_sdb.rb
CHANGED
@@ -127,6 +127,11 @@ class TestSdb < Test::Unit::TestCase
|
|
127
127
|
assert_equal 2, Client.find_all_by_post_and_country('president','Russia').size
|
128
128
|
# find all women in USA that love flowers
|
129
129
|
assert_equal 2, Client.find_all_by_gender_and_country_and_hobby('female','Russia','flowers').size
|
130
|
+
# order and auto_load:
|
131
|
+
clients = Client.find_all_by_post('president', :order => 'name', :auto_load => true)
|
132
|
+
assert_equal [['Bush'], ['Medvedev'], ['Putin']], clients.map{|c| c['name']}
|
133
|
+
clients = Client.find_all_by_post('president', :order => 'name desc', :auto_load => true)
|
134
|
+
assert_equal [['Putin'], ['Medvedev'], ['Bush']], clients.map{|c| c['name']}
|
130
135
|
end
|
131
136
|
|
132
137
|
def test_07_find_by_helpers
|
@@ -135,7 +140,9 @@ class TestSdb < Test::Unit::TestCase
|
|
135
140
|
# find any russian president
|
136
141
|
assert Client.find_by_post_and_country('president','Russia')
|
137
142
|
# find Mary in Russia that loves flowers
|
138
|
-
|
143
|
+
# order and auto_load:
|
144
|
+
assert_equal ['Bush'], Client.find_by_post('president', :order => 'name', :auto_load => true)['name']
|
145
|
+
assert_equal ['Putin'], Client.find_by_post('president', :order => 'name desc', :auto_load => true)['name']
|
139
146
|
end
|
140
147
|
|
141
148
|
def test_08_reload
|
@@ -226,7 +233,7 @@ class TestSdb < Test::Unit::TestCase
|
|
226
233
|
assert ['russian'], new_putin['language'].sort
|
227
234
|
# --- delete_attributes
|
228
235
|
putin.delete_attributes('language', 'hobby')
|
229
|
-
wait SDB_DELAY, 'test 11: after
|
236
|
+
wait SDB_DELAY, 'test 11: after delete_attributes'
|
230
237
|
# trash hoddy and langs
|
231
238
|
new_putin = Client.find_by_name('Putin')
|
232
239
|
new_putin.reload
|
data/test/sdb/test_helper.rb
CHANGED
data/test/sdb/test_right_sdb.rb
CHANGED
@@ -97,15 +97,15 @@ class TestSdb < Test::Unit::TestCase
|
|
97
97
|
end
|
98
98
|
|
99
99
|
def test_07_delete_item
|
100
|
-
@sdb.put_attributes @domain, @item, {'
|
100
|
+
@sdb.put_attributes @domain, @item, {'Volodya' => ['girls','vodka']}
|
101
101
|
wait SDB_DELAY, 'after adding attributes'
|
102
102
|
# get attributes ('girls' and 'vodka' must be there)
|
103
|
-
values = @sdb.get_attributes(@domain, @item)[:attributes]['
|
103
|
+
values = @sdb.get_attributes(@domain, @item)[:attributes]['Volodya'].to_a.sort
|
104
104
|
assert_equal values, ['girls', 'vodka']
|
105
105
|
# delete an item
|
106
106
|
@sdb.delete_attributes @domain, @item
|
107
107
|
# get attributes (values must be empty)
|
108
|
-
values = @sdb.get_attributes(@domain, @item)[:attributes]['
|
108
|
+
values = @sdb.get_attributes(@domain, @item)[:attributes]['Volodya']
|
109
109
|
assert_equal values, nil
|
110
110
|
end
|
111
111
|
|
@@ -121,6 +121,7 @@ class TestSdb < Test::Unit::TestCase
|
|
121
121
|
def test_09_signature_version_0
|
122
122
|
sdb = Rightscale::SdbInterface.new(TestCredentials.aws_access_key_id, TestCredentials.aws_secret_access_key, :signature_version => '0')
|
123
123
|
item = 'toys'
|
124
|
+
# TODO: need to change the below test. I think Juergen's intention was to include some umlauts in the values
|
124
125
|
# put attributes
|
125
126
|
# mhhh... Not sure how to translate this: hölzchehn klötzchen grÃŒnspan buÃe... Lets assume this is:
|
126
127
|
attributes = { 'Jurgen' => %w{kitten puppy chickabiddy piglet} }
|
@@ -134,8 +135,58 @@ class TestSdb < Test::Unit::TestCase
|
|
134
135
|
assert sdb.last_request.path.include?('SignatureVersion=0')
|
135
136
|
end
|
136
137
|
|
138
|
+
def test_10_array_of_attrs
|
139
|
+
item = 'multiples'
|
140
|
+
assert_nothing_thrown "Failed to put multiple attrs" do
|
141
|
+
@sdb.put_attributes(@domain, item, {:one=>1, :two=>2, :three=>3})
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_11_zero_len_attrs
|
146
|
+
item = 'zeroes'
|
147
|
+
assert_nothing_thrown "Failed to put zero-length attributes" do
|
148
|
+
@sdb.put_attributes(@domain, item, {:one=>"", :two=>"", :three=>""})
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def test_12_nil_attrs
|
153
|
+
item = 'nils'
|
154
|
+
res = nil
|
155
|
+
assert_nothing_thrown do
|
156
|
+
@sdb.put_attributes(@domain, item, {:one=>nil, :two=>nil, :three=>'chunder'})
|
157
|
+
end
|
158
|
+
assert_nothing_thrown do
|
159
|
+
res = @sdb.get_attributes(@domain, item)
|
160
|
+
end
|
161
|
+
assert_nil(res[:attributes]['one'][0])
|
162
|
+
assert_nil(res[:attributes]['two'][0])
|
163
|
+
assert_not_nil(res[:attributes]['three'][0])
|
164
|
+
end
|
165
|
+
|
166
|
+
def test_13_url_escape
|
167
|
+
item = 'urlescapes'
|
168
|
+
content = {:a=>"one & two & three",
|
169
|
+
:b=>"one ? two / three"}
|
170
|
+
@sdb.put_attributes(@domain, item, content)
|
171
|
+
|
172
|
+
res = @sdb.get_attributes(@domain, item)
|
173
|
+
assert_equal(content[:a], res[:attributes]['a'][0])
|
174
|
+
assert_equal(content[:b], res[:attributes]['b'][0])
|
175
|
+
end
|
176
|
+
|
177
|
+
def test_14_put_attrs_by_post
|
178
|
+
item = 'reqgirth'
|
179
|
+
i = 0
|
180
|
+
sa = ""
|
181
|
+
while(i < 64) do
|
182
|
+
sa += "aaaaaaaa"
|
183
|
+
i += 1
|
184
|
+
end
|
185
|
+
@sdb.put_attributes(@domain, item, {:a => sa, :b => sa, :c => sa, :d => sa, :e => sa})
|
186
|
+
end
|
187
|
+
|
137
188
|
# Keep this test last, because it deletes the domain...
|
138
|
-
def
|
189
|
+
def test_20_delete_domain
|
139
190
|
assert @sdb.delete_domain(@domain), 'delete_domain fail'
|
140
191
|
wait SDB_DELAY, 'after domain deletion'
|
141
192
|
# check that domain does not exist
|
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.8.
|
4
|
+
version: 1.8.1
|
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: 2008-
|
12
|
+
date: 2008-10-07 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|