right_aws 1.8.0 → 1.8.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 +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
|