right_aws 1.7.1 → 1.7.2

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/lib/right_aws.rb CHANGED
@@ -36,6 +36,7 @@ require 'right_http_connection'
36
36
 
37
37
  $:.unshift(File.dirname(__FILE__))
38
38
  require 'awsbase/benchmark_fix'
39
+ require 'awsbase/file_fix'
39
40
  require 'awsbase/support'
40
41
  require 'awsbase/right_awsbase'
41
42
  require 'ec2/right_ec2'
@@ -52,7 +53,7 @@ module RightAws #:nodoc:
52
53
  module VERSION #:nodoc:
53
54
  MAJOR = 1
54
55
  MINOR = 7
55
- TINY = 1
56
+ TINY = 2
56
57
 
57
58
  STRING = [MAJOR, MINOR, TINY].join('.')
58
59
  end
data/lib/s3/right_s3.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2007 RightScale Inc
2
+ # Copyright (c) 2007-2008 RightScale Inc
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -249,6 +249,40 @@ module RightAws
249
249
  key = Key.create(self, key.to_s) unless key.is_a?(Key)
250
250
  key.get(headers)
251
251
  end
252
+
253
+ # Rename object. Returns RightAws::S3::Key instance.
254
+ #
255
+ # new_key = bucket.rename_key('logs/today/1.log','logs/today/2.log') #=> #<RightAws::S3::Key:0xb7b1e240 ... >
256
+ # puts key.name #=> 'logs/today/2.log'
257
+ # key.exists? #=> true
258
+ #
259
+ def rename_key(old_key_or_name, new_name)
260
+ old_key_or_name = Key.create(self, old_key_or_name.to_s) unless old_key_or_name.is_a?(Key)
261
+ old_key_or_name.rename(new_name)
262
+ old_key_or_name
263
+ end
264
+
265
+ # Create an object copy. Returns a destination RightAws::S3::Key instance.
266
+ #
267
+ # new_key = bucket.copy_key('logs/today/1.log','logs/today/2.log') #=> #<RightAws::S3::Key:0xb7b1e240 ... >
268
+ # puts key.name #=> 'logs/today/2.log'
269
+ # key.exists? #=> true
270
+ #
271
+ def copy_key(old_key_or_name, new_key_or_name)
272
+ old_key_or_name = Key.create(self, old_key_or_name.to_s) unless old_key_or_name.is_a?(Key)
273
+ old_key_or_name.copy(new_key_or_name)
274
+ end
275
+
276
+ # Move an object to other location. Returns a destination RightAws::S3::Key instance.
277
+ #
278
+ # new_key = bucket.copy_key('logs/today/1.log','logs/today/2.log') #=> #<RightAws::S3::Key:0xb7b1e240 ... >
279
+ # puts key.name #=> 'logs/today/2.log'
280
+ # key.exists? #=> true
281
+ #
282
+ def move_key(old_key_or_name, new_key_or_name)
283
+ old_key_or_name = Key.create(self, old_key_or_name.to_s) unless old_key_or_name.is_a?(Key)
284
+ old_key_or_name.move(new_key_or_name)
285
+ end
252
286
 
253
287
  # Remove all keys from a bucket.
254
288
  # Returns +true+.
@@ -260,7 +294,7 @@ module RightAws
260
294
  end
261
295
 
262
296
  # Delete all keys where the 'folder_key' can be interpreted
263
- # as a 'folder' name.
297
+ # as a 'folder' name.
264
298
  # Returns an array of string keys that have been deleted.
265
299
  #
266
300
  # bucket.keys.map{|key| key.name}.join(', ') #=> 'test, test/2/34, test/3, test1, test1/logs'
@@ -334,7 +368,7 @@ module RightAws
334
368
  end
335
369
 
336
370
  # Create a new Key instance, but do not create the actual key.
337
- # In normal use this method should not be called directly.
371
+ # In normal use this method should not be called directly.
338
372
  # Use RightAws::S3::Key.create or bucket.key() instead.
339
373
  #
340
374
  def initialize(bucket, name, data=nil, headers={}, meta_headers={},
@@ -417,6 +451,66 @@ module RightAws
417
451
  @bucket.s3.interface.put(@bucket.name, @name, @data, meta.merge(headers))
418
452
  end
419
453
 
454
+ # Rename an object. Returns new object name.
455
+ #
456
+ # key = RightAws::S3::Key.create(bucket, 'logs/today/1.log') #=> #<RightAws::S3::Key:0xb7b1e240 ... >
457
+ # key.rename('logs/today/2.log') #=> 'logs/today/2.log'
458
+ # puts key.name #=> 'logs/today/2.log'
459
+ # key.exists? #=> true
460
+ #
461
+ def rename(new_name)
462
+ @bucket.s3.interface.rename(@bucket.name, @name, new_name)
463
+ @name = new_name
464
+ end
465
+
466
+ # Create an object copy. Returns a destination RightAws::S3::Key instance.
467
+ #
468
+ # # Key instance as destination
469
+ # key1 = RightAws::S3::Key.create(bucket, 'logs/today/1.log') #=> #<RightAws::S3::Key:0xb7b1e240 ... >
470
+ # key2 = RightAws::S3::Key.create(bucket, 'logs/today/2.log') #=> #<RightAws::S3::Key:0xb7b5e240 ... >
471
+ # key1.put('Olala!') #=> true
472
+ # key1.copy(key2) #=> #<RightAws::S3::Key:0xb7b5e240 ... >
473
+ # key1.exists? #=> true
474
+ # key2.exists? #=> true
475
+ # puts key2.data #=> 'Olala!'
476
+ #
477
+ # # String as destination
478
+ # key = RightAws::S3::Key.create(bucket, 'logs/today/777.log') #=> #<RightAws::S3::Key:0xb7b1e240 ... >
479
+ # key.put('Olala!') #=> true
480
+ # new_key = key.copy('logs/today/888.log') #=> #<RightAws::S3::Key:0xb7b5e240 ... >
481
+ # key.exists? #=> true
482
+ # new_key.exists? #=> true
483
+ #
484
+ def copy(new_key_or_name)
485
+ new_key_or_name = Key.create(@bucket, new_key_or_name.to_s) unless new_key_or_name.is_a?(Key)
486
+ @bucket.s3.interface.copy(@bucket.name, @name, new_key_or_name.bucket.name, new_key_or_name.name)
487
+ new_key_or_name
488
+ end
489
+
490
+ # Move an object to other location. Returns a destination RightAws::S3::Key instance.
491
+ #
492
+ # # Key instance as destination
493
+ # key1 = RightAws::S3::Key.create(bucket, 'logs/today/1.log') #=> #<RightAws::S3::Key:0xb7b1e240 ... >
494
+ # key2 = RightAws::S3::Key.create(bucket, 'logs/today/2.log') #=> #<RightAws::S3::Key:0xb7b5e240 ... >
495
+ # key1.put('Olala!') #=> true
496
+ # key1.move(key2) #=> #<RightAws::S3::Key:0xb7b5e240 ... >
497
+ # key1.exists? #=> false
498
+ # key2.exists? #=> true
499
+ # puts key2.data #=> 'Olala!'
500
+ #
501
+ # # String as destination
502
+ # key = RightAws::S3::Key.create(bucket, 'logs/today/777.log') #=> #<RightAws::S3::Key:0xb7b1e240 ... >
503
+ # key.put('Olala!') #=> true
504
+ # new_key = key.move('logs/today/888.log') #=> #<RightAws::S3::Key:0xb7b5e240 ... >
505
+ # key.exists? #=> false
506
+ # new_key.exists? #=> true
507
+ #
508
+ def move(new_key_or_name)
509
+ new_key_or_name = Key.create(@bucket, new_key_or_name.to_s) unless new_key_or_name.is_a?(Key)
510
+ @bucket.s3.interface.move(@bucket.name, @name, new_key_or_name.bucket.name, new_key_or_name.name)
511
+ new_key_or_name
512
+ end
513
+
420
514
  # Retrieve key info from bucket and update attributes.
421
515
  # Refresh meta-headers (by calling +head+ method) if +head+ is set.
422
516
  # Returns +true+ if the key exists in bucket and +false+ otherwise.
@@ -444,7 +538,7 @@ module RightAws
444
538
  end
445
539
  end
446
540
 
447
- # Retrieve meta-headers from S3.
541
+ # Updates headers and meta-headers from S3.
448
542
  # Returns +true+.
449
543
  #
450
544
  # key.meta_headers #=> {"family"=>"qwerty"}
@@ -455,7 +549,27 @@ module RightAws
455
549
  @headers, @meta_headers = self.class.split_meta(@bucket.s3.interface.head(@bucket, @name))
456
550
  true
457
551
  end
458
-
552
+
553
+ # Reload meta-headers only. Returns meta-headers hash.
554
+ #
555
+ # key.reload_meta #=> {"family"=>"qwerty", "name"=>"asdfg"}
556
+ #
557
+ def reload_meta
558
+ @meta_headers = self.class.split_meta(@bucket.s3.interface.head(@bucket, @name)).last
559
+ end
560
+
561
+ # Replace meta-headers by new hash at S3. Returns new meta-headers hash.
562
+ #
563
+ # key.reload_meta #=> {"family"=>"qwerty", "name"=>"asdfg"}
564
+ # key.save_meta #=> {"family"=>"oops", "race" => "troll"}
565
+ # key.reload_meta #=> {"family"=>"oops", "race" => "troll"}
566
+ #
567
+ def save_meta(meta_headers)
568
+ meta = self.class.add_meta_prefix(meta_headers)
569
+ @bucket.s3.interface.copy(@bucket.name, @name, @bucket.name, @name, :replace, meta)
570
+ @meta_headers = self.class.split_meta(meta)[1]
571
+ end
572
+
459
573
  # Check for existence of the key in the given bucket.
460
574
  # Returns +true+ or +false+.
461
575
  #
@@ -703,7 +817,7 @@ module RightAws
703
817
 
704
818
  # Apply current grantee @perms to +thing+. This method is called internally by the +grant+
705
819
  # and +revoke+ methods. In normal use this method should not
706
- # be called directly.
820
+ # be called directly.
707
821
  #
708
822
  # grantee.perms = ['FULL_CONTROL']
709
823
  # grantee.apply #=> true
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2007 RightScale Inc
2
+ # Copyright (c) 2007-2008 RightScale Inc
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -33,7 +33,8 @@ module RightAws
33
33
  DEFAULT_PORT = 443
34
34
  DEFAULT_PROTOCOL = 'https'
35
35
  REQUEST_TTL = 30
36
- DEFAULT_EXPIRES_AFTER = 1 * 24 * 60 * 60 # One day's worth of seconds
36
+ DEFAULT_EXPIRES_AFTER = 1 * 24 * 60 * 60 # One day's worth of seconds
37
+ ONE_YEAR_IN_SECONDS = 365 * 24 * 60 * 60
37
38
  AMAZON_HEADER_PREFIX = 'x-amz-'
38
39
  AMAZON_METADATA_PREFIX = 'x-amz-meta-'
39
40
 
@@ -372,12 +373,12 @@ module RightAws
372
373
  # :headers => {"last-modified" => "Wed, 23 May 2007 09:08:04 GMT",
373
374
  # "content-type" => "",
374
375
  # "etag" => "\"000000000096f4ee74bc4596443ef2a4\"",
375
- # "date" => "Wed, 23 May 2007 09:08:03 GMT",
376
- # "x-amz-id-2" => "ZZZZZZZZZZZZZZZZZZZZ1HJXZoehfrS4QxcxTdNGldR7w/FVqblP50fU8cuIMLiu",
377
- # "x-amz-meta-family" => "Woho556!",
378
- # "x-amz-request-id" => "0000000C246D770C",
379
- # "server" => "AmazonS3",
380
- # "content-length" => "7"}}
376
+ # "date" => "Wed, 23 May 2007 09:08:03 GMT",
377
+ # "x-amz-id-2" => "ZZZZZZZZZZZZZZZZZZZZ1HJXZoehfrS4QxcxTdNGldR7w/FVqblP50fU8cuIMLiu",
378
+ # "x-amz-meta-family" => "Woho556!",
379
+ # "x-amz-request-id" => "0000000C246D770C",
380
+ # "server" => "AmazonS3",
381
+ # "content-length" => "7"}}
381
382
  #
382
383
  # If a block is provided, yields incrementally to the block as
383
384
  # the response is read. For large responses, this function is ideal as
@@ -429,6 +430,54 @@ module RightAws
429
430
  on_exception
430
431
  end
431
432
 
433
+ # Copy an object.
434
+ # directive: :copy - copy meta-headers from source (default value)
435
+ # :replace - replace meta-headers by passed ones
436
+ #
437
+ # # copy a key with meta-headers
438
+ # s3.copy('b1', 'key1', 'b1', 'key1_copy') #=> {:e_tag=>"\"e8b...8d\"", :last_modified=>"2008-05-11T10:25:22.000Z"}
439
+ #
440
+ # # copy a key, overwrite meta-headers
441
+ # s3.copy('b1', 'key2', 'b1', 'key2_copy', :replace, 'x-amz-meta-family'=>'Woho555!') #=> {:e_tag=>"\"e8b...8d\"", :last_modified=>"2008-05-11T10:26:22.000Z"}
442
+ #
443
+ # see: http://docs.amazonwebservices.com/AmazonS3/2006-03-01/UsingCopyingObjects.html
444
+ # http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTObjectCOPY.html
445
+ #
446
+ def copy(src_bucket, src_key, dest_bucket, dest_key=nil, directive=:copy, headers={})
447
+ dest_key ||= src_key
448
+ headers['x-amz-metadata-directive'] = directive.to_s.upcase
449
+ headers['x-amz-copy-source'] = "#{src_bucket}/#{src_key}"
450
+ req_hash = generate_rest_request('PUT', headers.merge(:url=>"#{dest_bucket}/#{CGI::escape dest_key}"))
451
+ request_info(req_hash, S3CopyParser.new)
452
+ rescue
453
+ on_exception
454
+ end
455
+
456
+ # Move an object.
457
+ # directive: :copy - copy meta-headers from source (default value)
458
+ # :replace - replace meta-headers by passed ones
459
+ #
460
+ # # move bucket1/key1 to bucket1/key2
461
+ # s3.move('bucket1', 'key1', 'bucket1', 'key2') #=> {:e_tag=>"\"e8b...8d\"", :last_modified=>"2008-05-11T10:27:22.000Z"}
462
+ #
463
+ # # move bucket1/key1 to bucket2/key2 with new meta-headers assignment
464
+ # s3.copy('bucket1', 'key1', 'bucket2', 'key2', :replace, 'x-amz-meta-family'=>'Woho555!') #=> {:e_tag=>"\"e8b...8d\"", :last_modified=>"2008-05-11T10:28:22.000Z"}
465
+ #
466
+ def move(src_bucket, src_key, dest_bucket, dest_key=nil, directive=:copy, headers={})
467
+ copy_result = copy(src_bucket, src_key, dest_bucket, dest_key, directive, headers)
468
+ # delete an original key if it differs from a destination one
469
+ delete(src_bucket, src_key) unless src_bucket == dest_bucket && src_key == dest_key
470
+ copy_result
471
+ end
472
+
473
+ # Rename an object.
474
+ #
475
+ # # rename bucket1/key1 to bucket1/key2
476
+ # s3.rename('bucket1', 'key1', 'key2') #=> {:e_tag=>"\"e8b...8d\"", :last_modified=>"2008-05-11T10:29:22.000Z"}
477
+ #
478
+ def rename(src_bucket, src_key, dest_key, headers={})
479
+ move(src_bucket, src_key, src_bucket, dest_key, :copy, headers)
480
+ end
432
481
 
433
482
  # Retieves the ACL (access control policy) for a bucket or object. Returns a hash of headers and xml doc with ACL data. See: http://docs.amazonwebservices.com/AmazonS3/2006-03-01/RESTAccessPolicy.html.
434
483
  #
@@ -601,7 +650,7 @@ module RightAws
601
650
  end
602
651
  # expiration time
603
652
  expires ||= DEFAULT_EXPIRES_AFTER
604
- expires = Time.now.utc.since(expires) if expires.is_a?(Fixnum) && (expires<1.year)
653
+ expires = Time.now.utc + expires if expires.is_a?(Fixnum) && (expires < ONE_YEAR_IN_SECONDS)
605
654
  expires = expires.to_i
606
655
  # remove unset(==optional) and symbolyc keys
607
656
  headers.each{ |key, value| headers.delete(key) if (value.nil? || key.is_a?(Symbol)) }
@@ -669,8 +718,16 @@ module RightAws
669
718
 
670
719
  # Generates link for 'GetObject'.
671
720
  #
672
- # s3.get_link('my_awesome_bucket',key) #=> url string
721
+ # if a bucket comply with virtual hosting naming then retuns a link with the
722
+ # bucket as a part of host name:
723
+ #
724
+ # s3.get_link('my-awesome-bucket',key) #=> https://my-awesome-bucket.s3.amazonaws.com:443/asia%2Fcustomers?Signature=nh7...
725
+ #
726
+ # otherwise returns an old style link (the bucket is a part of path):
727
+ #
728
+ # s3.get_link('my_awesome_bucket',key) #=> https://s3.amazonaws.com:443/my_awesome_bucket/asia%2Fcustomers?Signature=QAO...
673
729
  #
730
+ # see http://docs.amazonwebservices.com/AmazonS3/2006-03-01/VirtualHosting.html
674
731
  def get_link(bucket, key, expires=nil, headers={})
675
732
  generate_link('GET', headers.merge(:url=>"#{bucket}/#{CGI::escape key}"), expires)
676
733
  rescue
@@ -875,6 +932,18 @@ module RightAws
875
932
  end
876
933
  end
877
934
  end
935
+
936
+ class S3CopyParser < RightAWSParser # :nodoc:
937
+ def reset
938
+ @result = {}
939
+ end
940
+ def tagend(name)
941
+ case name
942
+ when 'LastModified' : @result[:last_modified] = @text
943
+ when 'ETag' : @result[:e_tag] = @text
944
+ end
945
+ end
946
+ end
878
947
 
879
948
  #-----------------------------------------------------------------
880
949
  # PARSERS: Non XML
@@ -29,7 +29,6 @@ module RightAws
29
29
 
30
30
  include RightAwsBaseInterface
31
31
 
32
- SIGNATURE_VERSION = '1'
33
32
  DEFAULT_HOST = 'sdb.amazonaws.com'
34
33
  DEFAULT_PORT = 443
35
34
  DEFAULT_PROTOCOL = 'https'
@@ -45,6 +44,7 @@ module RightAws
45
44
  # { :server => 'sdb.amazonaws.com' # Amazon service host: 'sdb.amazonaws.com'(default)
46
45
  # :port => 443 # Amazon service port: 80 or 443(default)
47
46
  # :protocol => 'https' # Amazon service protocol: 'http' or 'https'(default)
47
+ # :signature_version => '0' # The signature version : '0' or '1'(default)
48
48
  # :multi_thread => true|false # Multi-threaded (connection per each thread): true or false(default)
49
49
  # :logger => Logger Object} # Logger instance: logs to STDOUT if omitted }
50
50
  #
@@ -76,9 +76,13 @@ module RightAws
76
76
  "AWSAccessKeyId" => @aws_access_key_id,
77
77
  "Version" => API_VERSION,
78
78
  "Timestamp" => Time.now.utc.strftime("%Y-%m-%dT%H:%M:%S.000Z"),
79
- "SignatureVersion" => SIGNATURE_VERSION }
79
+ "SignatureVersion" => signature_version }
80
+ service_hash.update(params)
80
81
  # prepare string to sight
81
- string_to_sign = service_hash.merge(params).sort{|a,b| (a[0].to_s.downcase)<=>(b[0].to_s.downcase)}.to_s
82
+ string_to_sign = case signature_version
83
+ when '0' : service_hash["Action"] + service_hash["Timestamp"]
84
+ when '1' : service_hash.sort{|a,b| (a[0].to_s.downcase)<=>(b[0].to_s.downcase)}.to_s
85
+ end
82
86
  service_hash.update('Signature' => AwsUtils::sign(@aws_secret_access_key, string_to_sign))
83
87
  service_string = service_hash.to_a.collect{|key,val| key + "=#{CGI::escape(val.to_s)}" }.join("&")
84
88
  #
data/lib/sqs/right_sqs.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c) 2007 RightScale Inc
2
+ # Copyright (c) 2007-2008 RightScale Inc
3
3
  #
4
4
  # Permission is hereby granted, free of charge, to any person obtaining
5
5
  # a copy of this software and associated documentation files (the
@@ -73,6 +73,7 @@ module RightAws
73
73
  # {:server => 'queue.amazonaws.com' # Amazon service host: 'queue.amazonaws.com' (default)
74
74
  # :port => 443 # Amazon service port: 80 or 443 (default)
75
75
  # :multi_thread => true|false # Multi-threaded (connection per each thread): true or false (default)
76
+ # :signature_version => '0' # The signature version : '0' or '1'(default)
76
77
  # :logger => Logger Object} # Logger instance: logs to STDOUT if omitted }
77
78
  #
78
79
  def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
@@ -26,7 +26,6 @@ module RightAws
26
26
  class SqsInterface < RightAwsBase
27
27
  include RightAwsBaseInterface
28
28
 
29
- SIGNATURE_VERSION = "1"
30
29
  API_VERSION = "2007-05-01"
31
30
  DEFAULT_HOST = "queue.amazonaws.com"
32
31
  DEFAULT_PORT = 443
@@ -57,6 +56,7 @@ module RightAws
57
56
  # {:server => 'queue.amazonaws.com' # Amazon service host: 'queue.amazonaws.com'(default)
58
57
  # :port => 443 # Amazon service port: 80 or 443(default)
59
58
  # :multi_thread => true|false # Multi-threaded (connection per each thread): true or false(default)
59
+ # :signature_version => '0' # The signature version : '0' or '1'(default)
60
60
  # :logger => Logger Object} # Logger instance: logs to STDOUT if omitted }
61
61
  #
62
62
  def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
@@ -75,23 +75,26 @@ module RightAws
75
75
  #-----------------------------------------------------------------
76
76
 
77
77
  # Generates a request hash for the query API
78
- def generate_request(action, param={}) # :nodoc:
78
+ def generate_request(action, params={}) # :nodoc:
79
79
  # Sometimes we need to use queue uri (delete queue etc)
80
80
  # In that case we will use Symbol key: 'param[:queue_url]'
81
- queue_uri = param[:queue_url] ? URI(param[:queue_url]).path : '/'
81
+ queue_uri = params[:queue_url] ? URI(params[:queue_url]).path : '/'
82
82
  # remove unset(=optional) and symbolyc keys
83
- param.each{ |key, value| param.delete(key) if (value.nil? || key.is_a?(Symbol)) }
83
+ params.each{ |key, value| params.delete(key) if (value.nil? || key.is_a?(Symbol)) }
84
84
  # prepare output hash
85
- request_hash = { "Action" => action,
86
- # "Expires" => Time.now.utc.since(REQUEST_TTL).strftime("%Y-%m-%dT%H:%M:%SZ"),
85
+ service_hash = { "Action" => action,
87
86
  "Expires" => (Time.now + REQUEST_TTL).utc.strftime("%Y-%m-%dT%H:%M:%SZ"),
88
87
  "AWSAccessKeyId" => @aws_access_key_id,
89
88
  "Version" => API_VERSION,
90
- "SignatureVersion" => SIGNATURE_VERSION }
91
- request_hash.update(param)
92
- request_data = request_hash.sort{|a,b| (a[0].to_s.downcase)<=>(b[0].to_s.downcase)}.to_s
93
- request_hash['Signature'] = AwsUtils::sign(@aws_secret_access_key, request_data)
94
- request_params = request_hash.to_a.collect{|key,val| key.to_s + "=" + CGI::escape(val.to_s) }.join("&")
89
+ "SignatureVersion" => signature_version }
90
+ service_hash.update(params)
91
+ # prepare string to sight
92
+ string_to_sign = case signature_version
93
+ when '0' : service_hash["Action"] + service_hash["Expires"]
94
+ when '1' : service_hash.sort{|a,b| (a[0].to_s.downcase)<=>(b[0].to_s.downcase)}.to_s
95
+ end
96
+ service_hash['Signature'] = AwsUtils::sign(@aws_secret_access_key, string_to_sign)
97
+ request_params = service_hash.to_a.collect{|key,val| key.to_s + "=" + CGI::escape(val.to_s) }.join("&")
95
98
  request = Net::HTTP::Get.new("#{queue_uri}?#{request_params}")
96
99
  # prepare output hash
97
100
  { :request => request,
@@ -65,4 +65,12 @@ class TestEc2 < Test::Unit::TestCase
65
65
  ## assert_raise(Rightscale::AwsError) { @ec2.delete_key_pair(@key) }
66
66
  end
67
67
 
68
+ def test_10_signature_version_0
69
+ ec2 = Rightscale::Ec2.new(TestCredentials.aws_access_key_id, TestCredentials.aws_secret_access_key, :signature_version => '0')
70
+ images = ec2.describe_images
71
+ assert images.size>0, 'Amazon must have at least some public images'
72
+ # check that the request has correct signature version
73
+ assert ec2.last_request.path.include?('SignatureVersion=0')
74
+ end
75
+
68
76
  end
@@ -6,10 +6,13 @@ class TestS3 < Test::Unit::TestCase
6
6
 
7
7
  def setup
8
8
  @s3 = Rightscale::S3Interface.new(TestCredentials.aws_access_key_id, TestCredentials.aws_secret_access_key)
9
- @bucket = 'right_s3_awesome_test_bucket'
9
+ @bucket = 'right_s3_awesome_test_bucket_00001'
10
10
  @key1 = 'test/woohoo1/'
11
11
  @key2 = 'test1/key/woohoo2'
12
12
  @key3 = 'test2/A%B@C_D&E?F+G=H"I'
13
+ @key1_copy = 'test/woohoo1_2'
14
+ @key1_new_name = 'test/woohoo1_3'
15
+ @key2_new_name = 'test1/key/woohoo2_new'
13
16
  @s = Rightscale::S3.new(TestCredentials.aws_access_key_id, TestCredentials.aws_secret_access_key)
14
17
  end
15
18
 
@@ -74,12 +77,55 @@ class TestS3 < Test::Unit::TestCase
74
77
  assert(keys.include? @key3)
75
78
  end
76
79
 
77
- def test_09_delete_folder
78
- assert_equal 1, @s3.delete_folder(@bucket, 'test').size, "Only one key(#{@key1}) must be deleted!"
80
+ def test_09_copy_key
81
+ #--- test COPY
82
+ # copy a key
83
+ assert @s3.copy(@bucket, @key1, @bucket, @key1_copy)
84
+ # check it was copied well
85
+ assert_equal RIGHT_OBJECT_TEXT, @s3.get_object(@bucket, @key1_copy), "copied object must have the same data"
86
+ # check meta-headers were copied
87
+ headers = @s3.head(@bucket, @key1_copy)
88
+ assert_equal 'Woohoo1!', headers['x-amz-meta-family'], "x-amz-meta-family header must be equal to 'Woohoo1!'"
89
+ #--- test REPLACE
90
+ assert @s3.copy(@bucket, @key1, @bucket, @key1_copy, :replace, 'x-amz-meta-family' => 'oooops!')
91
+ # check it was copied well
92
+ assert_equal RIGHT_OBJECT_TEXT, @s3.get_object(@bucket, @key1_copy), "copied object must have the same data"
93
+ # check meta-headers were overwrittenn
94
+ headers = @s3.head(@bucket, @key1_copy)
95
+ assert_equal 'oooops!', headers['x-amz-meta-family'], "x-amz-meta-family header must be equal to 'oooops!'"
79
96
  end
80
97
 
98
+ def test_10_move_key
99
+ # move a key
100
+ assert @s3.move(@bucket, @key1, @bucket, @key1_new_name)
101
+ # check it's data was moved correctly
102
+ assert_equal RIGHT_OBJECT_TEXT, @s3.get_object(@bucket, @key1_new_name), "moved object must have the same data"
103
+ # check meta-headers were moved
104
+ headers = @s3.head(@bucket, @key1_new_name)
105
+ assert_equal 'Woohoo1!', headers['x-amz-meta-family'], "x-amz-meta-family header must be equal to 'Woohoo1!'"
106
+ # check the original key is not exists any more
107
+ keys = @s3.list_bucket(@bucket).map{|b| b[:key]}
108
+ assert(!keys.include?(@key1))
109
+ end
81
110
 
82
- def test_10_delete_bucket
111
+ def test_11_rename_key
112
+ # rename a key
113
+ assert @s3.rename(@bucket, @key2, @key2_new_name)
114
+ # check the new key data
115
+ assert_equal RIGHT_OBJECT_TEXT, @s3.get_object(@bucket, @key2_new_name), "moved object must have the same data"
116
+ # check meta-headers
117
+ headers = @s3.head(@bucket, @key2_new_name)
118
+ assert_equal 'Woohoo2!', headers['x-amz-meta-family'], "x-amz-meta-family header must be equal to 'Woohoo2!'"
119
+ # check the original key is not exists any more
120
+ keys = @s3.list_bucket(@bucket).map{|b| b[:key]}
121
+ assert(!keys.include?(@key2))
122
+ end
123
+
124
+ def test_12_delete_folder
125
+ assert_equal 1, @s3.delete_folder(@bucket, 'test').size, "Only one key(#{@key1}) must be deleted!"
126
+ end
127
+
128
+ def test_13_delete_bucket
83
129
  assert_raise(Rightscale::AwsError) { @s3.delete_bucket(@bucket) }
84
130
  assert @s3.clear_bucket(@bucket), 'Clear_bucket fail'
85
131
  assert_equal 0, @s3.list_bucket(@bucket).size, 'Bucket must be empty'
@@ -87,7 +133,6 @@ class TestS3 < Test::Unit::TestCase
87
133
  assert !@s3.list_all_my_buckets.map{|bucket| bucket[:name]}.include?(@bucket), "#{@bucket} must not exist"
88
134
  end
89
135
 
90
-
91
136
  #---------------------------
92
137
  # Rightscale::S3 classes
93
138
  #---------------------------
@@ -145,7 +190,80 @@ class TestS3 < Test::Unit::TestCase
145
190
  assert !key2.exists?
146
191
  end
147
192
 
148
- def test_23_clear_delete
193
+ def test_23_rename_key
194
+ bucket = Rightscale::S3::Bucket.create(@s, @bucket, false)
195
+ # -- 1 -- (key based rename)
196
+ # create a key
197
+ key = bucket.key('test/copy/1')
198
+ key.put(RIGHT_OBJECT_TEXT)
199
+ original_key = key.clone
200
+ assert key.exists?, "'test/copy/1' should exist"
201
+ # rename it
202
+ key.rename('test/copy/2')
203
+ assert_equal 'test/copy/2', key.name
204
+ assert key.exists?, "'test/copy/2' should exist"
205
+ # the original key should not exist
206
+ assert !original_key.exists?, "'test/copy/1' should not exist"
207
+ # -- 2 -- (bucket based rename)
208
+ bucket.rename_key('test/copy/2', 'test/copy/3')
209
+ assert bucket.key('test/copy/3').exists?, "'test/copy/3' should exist"
210
+ assert !bucket.key('test/copy/2').exists?, "'test/copy/2' should not exist"
211
+ end
212
+
213
+ def test_24_copy_key
214
+ bucket = Rightscale::S3::Bucket.create(@s, @bucket, false)
215
+ # -- 1 -- (key based copy)
216
+ # create a key
217
+ key = bucket.key('test/copy/10')
218
+ key.put(RIGHT_OBJECT_TEXT)
219
+ # make copy
220
+ new_key = key.copy('test/copy/11')
221
+ # make sure both the keys exist and have a correct data
222
+ assert key.exists?, "'test/copy/10' should exist"
223
+ assert new_key.exists?, "'test/copy/11' should exist"
224
+ assert_equal RIGHT_OBJECT_TEXT, key.get
225
+ assert_equal RIGHT_OBJECT_TEXT, new_key.get
226
+ # -- 2 -- (bucket based copy)
227
+ bucket.copy_key('test/copy/11', 'test/copy/12')
228
+ assert bucket.key('test/copy/11').exists?, "'test/copy/11' should exist"
229
+ assert bucket.key('test/copy/12').exists?, "'test/copy/12' should exist"
230
+ assert_equal RIGHT_OBJECT_TEXT, bucket.key('test/copy/11').get
231
+ assert_equal RIGHT_OBJECT_TEXT, bucket.key('test/copy/12').get
232
+ end
233
+
234
+ def test_25_move_key
235
+ bucket = Rightscale::S3::Bucket.create(@s, @bucket, false)
236
+ # -- 1 -- (key based copy)
237
+ # create a key
238
+ key = bucket.key('test/copy/20')
239
+ key.put(RIGHT_OBJECT_TEXT)
240
+ # move
241
+ new_key = key.move('test/copy/21')
242
+ # make sure both the keys exist and have a correct data
243
+ assert !key.exists?, "'test/copy/20' should not exist"
244
+ assert new_key.exists?, "'test/copy/21' should exist"
245
+ assert_equal RIGHT_OBJECT_TEXT, new_key.get
246
+ # -- 2 -- (bucket based copy)
247
+ bucket.copy_key('test/copy/21', 'test/copy/22')
248
+ assert bucket.key('test/copy/21').exists?, "'test/copy/21' should not exist"
249
+ assert bucket.key('test/copy/22').exists?, "'test/copy/22' should exist"
250
+ assert_equal RIGHT_OBJECT_TEXT, bucket.key('test/copy/22').get
251
+ end
252
+
253
+ def test_26_save_meta
254
+ bucket = Rightscale::S3::Bucket.create(@s, @bucket, false)
255
+ # create a key
256
+ key = bucket.key('test/copy/30')
257
+ key.put(RIGHT_OBJECT_TEXT)
258
+ assert key.meta_headers.blank?
259
+ # store some meta keys
260
+ meta = {'family' => 'oops','race' => 'troll'}
261
+ assert_equal meta, key.save_meta(meta)
262
+ # reload meta
263
+ assert_equal meta, key.reload_meta
264
+ end
265
+
266
+ def test_27_clear_delete
149
267
  bucket = Rightscale::S3::Bucket.create(@s, @bucket, false)
150
268
  # add another key
151
269
  bucket.put(@key2, RIGHT_OBJECT_TEXT)