appoxy-aws 1.11.13

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,166 @@
1
+ = RightScale Amazon Web Services Ruby Gems
2
+
3
+ Published by RightScale, Inc. under the MIT License.
4
+ For information about RightScale, see http://www.rightscale.com
5
+
6
+ == DESCRIPTION:
7
+
8
+ The RightScale AWS gems have been designed to provide a robust, fast, and secure interface to Amazon EC2, EBS, S3, SQS, SDB, and CloudFront.
9
+ These gems have been used in production by RightScale since late 2006 and are being maintained to track enhancements made by Amazon.
10
+ The RightScale AWS gems comprise:
11
+
12
+ - RightAws::Ec2 -- interface to Amazon EC2 (Elastic Compute Cloud) and the
13
+ associated EBS (Elastic Block Store)
14
+ - RightAws::S3 and RightAws::S3Interface -- interface to Amazon S3 (Simple Storage Service)
15
+ - RightAws::Sqs and RightAws::SqsInterface -- interface to first-generation Amazon SQS (Simple Queue Service) (API version 2007-05-01)
16
+ - RightAws::SqsGen2 and RightAws::SqsGen2Interface -- interface to second-generation Amazon SQS (Simple Queue Service) (API version 2008-01-01)
17
+ - RightAws::SdbInterface and RightAws::ActiveSdb -- interface to Amazon SDB (SimpleDB)
18
+ - RightAws::AcfInterface -- interface to Amazon CloudFront, a content distribution service
19
+
20
+ == FEATURES:
21
+
22
+ - Full programmmatic access to EC2, EBS, S3, SQS, SDB, and CloudFront.
23
+ - Complete error handling: all operations check for errors and report complete
24
+ error information by raising an AwsError.
25
+ - Persistent HTTP connections with robust network-level retry layer using
26
+ RightHttpConnection). This includes socket timeouts and retries.
27
+ - Robust HTTP-level retry layer. Certain (user-adjustable) HTTP errors returned
28
+ by Amazon's services are classified as temporary errors.
29
+ These errors are automaticallly retried using exponentially increasing intervals.
30
+ The number of retries is user-configurable.
31
+ - Fast REXML-based parsing of responses (as fast as a pure Ruby solution allows).
32
+ - Uses libxml (if available) for faster response parsing.
33
+ - Support for large S3 list operations. Buckets and key subfolders containing
34
+ many (> 1000) keys are listed in entirety. Operations based on list (like
35
+ bucket clear) work on arbitrary numbers of keys.
36
+ - Support for streaming GETs from S3, and streaming PUTs to S3 if the data source is a file.
37
+ - Support for single-threaded usage, multithreaded usage, as well as usage with multiple
38
+ AWS accounts.
39
+ - Support for both first- and second-generation SQS (API versions 2007-05-01
40
+ and 2008-01-01). These versions of SQS are not compatible.
41
+ - Support for signature versions 0, 1 and 2 on all services.
42
+ - Interoperability with any cloud running Eucalyptus (http://eucalyptus.cs.ucsb.edu)
43
+ - Test suite (requires AWS account to do "live" testing).
44
+
45
+ == THREADING:
46
+
47
+ All RightScale AWS interfaces offer two threading options:
48
+ 1. Use a single persistent HTTP connection per process.
49
+ 2. Use a persistent HTTP connection per Ruby thread.
50
+
51
+ Either way, it doesn't matter how many (for example) RightAws::S3 objects you create,
52
+ they all use the same per-program or per-thread
53
+ connection. The purpose of sharing the connection is to keep a single
54
+ persistent HTTP connection open to avoid paying connection
55
+ overhead on every request. However, if you have multiple concurrent
56
+ threads, you may want or need an HTTP connection per thread to enable
57
+ concurrent requests to AWS. The way this plays out in practice is:
58
+ 1. If you have a non-multithreaded Ruby program, use the non-multithreaded setting.
59
+ 2. If you have a multi-threaded Ruby program, use the multithreaded setting to enable
60
+ concurrent requests to S3 (or SQS, or SDB, or EC2).
61
+ 3. For running under Mongrel/Rails, use the non-multithreaded setting even though
62
+ mongrel is multithreaded. This is because only one Rails handler is invoked at
63
+ time (i.e. it acts like a single-threaded program)
64
+
65
+ Note that due to limitations in the I/O of the Ruby interpreter you
66
+ may not get the degree of parallelism you may expect with the multi-threaded setting.
67
+
68
+ By default, EC2/S3/SQS/SDB/ACF interface instances are created in single-threaded mode. Set
69
+ "params[:multi_thread]" to "true" in the initialization arguments to use
70
+ multithreaded mode.
71
+
72
+ == GETTING STARTED:
73
+
74
+ * For EC2 read RightAws::Ec2 and consult the Amazon EC2 API documentation at
75
+ http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=87
76
+ * For S3 read RightAws::S3 and consult the Amazon S3 API documentation at
77
+ http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=48
78
+ * For first generation SQS read RightAws::Sqs and consult the Amazon SQS API documentation at
79
+ http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=31
80
+ * For second generation SQS read RightAws::SqsGen2, RightAws::SqsGen2Interface, and consult the Amazon SQS API documentation at
81
+ http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1214&categoryID=31
82
+
83
+ Amazon's Migration Guide for moving from first to second generation SQS is
84
+ avalable at:
85
+ http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1148
86
+ * For SDB read RightAws::SdbInterface, RightAws::ActiveSdb, and consult the Amazon SDB API documentation at
87
+ http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=141
88
+ * For CloudFront (ACF) read RightAws::AcfInterface and consult the Amazon CloudFront API documentation at
89
+ http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=213
90
+
91
+ == KNOWN ISSUES:
92
+
93
+ - 7/08: A user has reported that uploads of large files on Windows may be broken on some
94
+ Win platforms due to a buggy File.lstat.size. Use the following monkey-patch at your own risk,
95
+ as it has been proven to break Rails 2.0 on Windows:
96
+
97
+ require 'win32/file'
98
+ class File
99
+ def lstat
100
+ self.stat
101
+ end
102
+ end
103
+
104
+
105
+ - Attempting to use the Gibberish plugin (used by the Beast forum app)
106
+ will break right_aws as well as lots of other code. Gibberish
107
+ changes the semantics of core Ruby (specifically, the String class) and thus presents a reliability
108
+ problem for most Ruby programs.
109
+
110
+ - 2/11/08: If you use RightAws in conjunction with attachment_fu, the
111
+ right_aws gem must be included (using the require statement) AFTER
112
+ attachment_fu. If right_aws is loaded before attachment_fu, you'll
113
+ encounter errors similar to:
114
+
115
+ s3.amazonaws.com temporarily unavailable: (wrong number of arguments (5 for 4))
116
+
117
+ or
118
+
119
+ 'incompatible Net::HTTP monkey-patch'
120
+
121
+ This is due to a conflict between the right_http_connection gem and another
122
+ gem required by attachment_fu. It may be possible to require right_aws (and
123
+ thus right_http_connection) in the .after_initialize method of the config object in
124
+ environment.rb (check the docs for Rails::Configuration.after_initialize).
125
+
126
+ - 8/07: Amazon has changed the semantics of the SQS service. A
127
+ new queue may not be created within 60 seconds of the destruction of any
128
+ older queue with the same name. Certain methods of RightAws::Sqs and
129
+ RightAws::SqsInterface will fail with the message:
130
+ "AWS.SimpleQueueService.QueueDeletedRecently: You must wait 60 seconds after deleting a queue before you can create another with the same name."
131
+
132
+ == REQUIREMENTS:
133
+
134
+ RightAws requires REXML and the right_http_connection gem.
135
+ If libxml and its Ruby bindings (distributed in the libxml-ruby gem) are
136
+ present, RightAws can be configured to use them:
137
+ RightAws::RightAWSParser.xml_lib = 'libxml'
138
+ Any error with the libxml installation will result in RightAws failing-safe to
139
+ REXML parsing.
140
+
141
+ == INSTALL:
142
+
143
+ sudo gem install right_aws
144
+
145
+ == LICENSE:
146
+
147
+ Copyright (c) 2007-2009 RightScale, Inc.
148
+
149
+ Permission is hereby granted, free of charge, to any person obtaining
150
+ a copy of this software and associated documentation files (the
151
+ 'Software'), to deal in the Software without restriction, including
152
+ without limitation the rights to use, copy, modify, merge, publish,
153
+ distribute, sublicense, and/or sell copies of the Software, and to
154
+ permit persons to whom the Software is furnished to do so, subject to
155
+ the following conditions:
156
+
157
+ The above copyright notice and this permission notice shall be
158
+ included in all copies or substantial portions of the Software.
159
+
160
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
161
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
162
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
163
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
164
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
165
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
166
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,2 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../../lib/right_aws'
@@ -0,0 +1,146 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+
3
+ class TestAcf < Test::Unit::TestCase
4
+
5
+ RIGHT_OBJECT_TEXT = 'Right test message'
6
+
7
+ STDOUT.sync = true
8
+
9
+ def setup
10
+ @acf= Rightscale::AcfInterface.new(TestCredentials.aws_access_key_id, TestCredentials.aws_secret_access_key)
11
+ @s3 = Rightscale::S3.new(TestCredentials.aws_access_key_id, TestCredentials.aws_secret_access_key)
12
+ @bucket_name = "right-acf-awesome-test-bucket-0001"
13
+ @bucket_domain = "#{@bucket_name}.s3.amazonaws.com"
14
+ end
15
+
16
+ def test_01_list_distributions_part1
17
+ distributions = nil
18
+ assert_nothing_raised(Rightscale::AwsError) do
19
+ distributions = @acf.list_distributions
20
+ end
21
+ assert distributions.is_a?(Array)
22
+ end
23
+
24
+ def test_02_try_to_create_for_bad_bucket
25
+ # a bucket does not exist
26
+ assert_raise(Rightscale::AwsError) do
27
+ @acf.create_distribution("right-cloudfront-awesome-test-bucket-not-exist", "Mustn't to be born", true)
28
+ end
29
+ # a bucket is not a domain naming complied guy
30
+ bucket_name = 'right_cloudfront_awesome_test_bucket_BAD'
31
+ @s3.bucket(bucket_name, :create)
32
+ assert_raise(Rightscale::AwsError) do
33
+ @acf.create_distribution(bucket_name, "Mustn't to be born", true)
34
+ end
35
+ end
36
+
37
+ def test_03_create
38
+ comment = 'WooHoo!!!'
39
+ # create a test bucket
40
+ @s3.bucket(@bucket_name, :create)
41
+ # create a distribution
42
+ distribution = @acf.create_distribution(@bucket_domain, comment, true)
43
+ assert_equal comment, distribution[:comment]
44
+ assert distribution[:cnames].size == 0
45
+ assert distribution[:enabled]
46
+ end
47
+
48
+ def test_04_list_distributions_part2
49
+ distributions = @acf.list_distributions
50
+ assert distributions.size > 0
51
+ end
52
+
53
+ def get_test_distribution
54
+ @acf.list_distributions.select{ |d| d[:origin] == @bucket_domain }.first
55
+ end
56
+
57
+ def test_05_get_distribution
58
+ old = get_test_distribution
59
+ assert_nothing_raised do
60
+ @acf.get_distribution(old[:aws_id])
61
+ end
62
+ end
63
+
64
+ def test_06_get_and_set_config
65
+ config = nil
66
+ old = get_test_distribution
67
+ assert_nothing_raised do
68
+ config = @acf.get_distribution_config(old[:aws_id])
69
+ end
70
+ # change a config
71
+ config[:enabled] = false
72
+ config[:cnames] << 'x1.myawesomesite.com'
73
+ config[:cnames] << 'x2.myawesomesite.com'
74
+ # set config
75
+ set_config_result = nil
76
+ assert_nothing_raised do
77
+ set_config_result = @acf.set_distribution_config(old[:aws_id], config)
78
+ end
79
+ assert set_config_result
80
+ # reget the config and check
81
+ new_config = nil
82
+ assert_nothing_raised do
83
+ new_config = @acf.get_distribution_config(old[:aws_id])
84
+ end
85
+ assert !new_config[:enabled]
86
+ assert_equal new_config[:cnames].sort, ['x1.myawesomesite.com', 'x2.myawesomesite.com']
87
+ assert_not_equal config[:e_tag], new_config[:e_tag]
88
+
89
+ # try to update the old config again (must fail because ETAG has changed)
90
+ assert_raise(Rightscale::AwsError) do
91
+ @acf.set_distribution_config(old[:aws_id], config)
92
+ end
93
+ end
94
+
95
+ def test_07_caching
96
+ # enable caching
97
+ @acf.params[:cache] = true
98
+ # list distributions
99
+ @acf.list_distributions
100
+ # list the distributions again - cache should hit
101
+ assert_raise(Rightscale::AwsNoChange) do
102
+ @acf.list_distributions
103
+ end
104
+ # disable caching
105
+ @acf.params[:cache] = true
106
+ end
107
+
108
+ def test_08_delete_distribution
109
+ # we need ETAG so use get_distribution
110
+ distribution = @acf.get_distribution(get_test_distribution[:aws_id])
111
+ # try to delete a distribution
112
+ # should fail because
113
+ if distribution[:status] == 'InProgress'
114
+ # should fail because the distribution is not deployed yet
115
+ assert_raise(Rightscale::AwsError) do
116
+ @acf.delete_distribution(distribution[:aws_id], distribution[:e_tag])
117
+ end
118
+ # wait for a deployed state
119
+ print "waiting up to 5 min while the distribution is being deployed: "
120
+ 100.times do
121
+ print '.'
122
+ distribution = @acf.get_distribution(distribution[:aws_id])
123
+ if distribution[:status] == 'Deployed'
124
+ print ' done'
125
+ break
126
+ end
127
+ sleep 3
128
+ end
129
+ puts
130
+ end
131
+
132
+ # only disabled and deployed distribution can be deleted
133
+ assert_equal 'Deployed', distribution[:status]
134
+ assert !distribution[:enabled]
135
+
136
+ # delete the distribution
137
+ assert_nothing_raised do
138
+ @acf.delete_distribution(distribution[:aws_id], distribution[:e_tag])
139
+ end
140
+ end
141
+
142
+ def test_09_drop_bucket
143
+ assert @s3.bucket(@bucket_name).delete
144
+ end
145
+
146
+ end
@@ -0,0 +1,2 @@
1
+ require 'test/unit'
2
+ require File.dirname(__FILE__) + '/../../lib/right_aws'
@@ -0,0 +1,108 @@
1
+ require File.dirname(__FILE__) + '/test_helper.rb'
2
+ require 'pp'
3
+
4
+ class TestEc2 < Test::Unit::TestCase
5
+
6
+ # Some of RightEc2 instance methods concerning instance launching and image registration
7
+ # are not tested here due to their potentially risk.
8
+
9
+ def setup
10
+ @ec2 = Rightscale::Ec2.new(TestCredentials.aws_access_key_id,
11
+ TestCredentials.aws_secret_access_key)
12
+ @key = 'right_ec2_awesome_test_key'
13
+ @group = 'right_ec2_awesome_test_security_group'
14
+ end
15
+
16
+ def test_01_create_describe_key_pairs
17
+ new_key = @ec2.create_key_pair(@key)
18
+ assert new_key[:aws_material][/BEGIN RSA PRIVATE KEY/], "New key material is absent"
19
+ keys = @ec2.describe_key_pairs
20
+ assert keys.map{|key| key[:aws_key_name] }.include?(@key), "#{@key} must exist"
21
+ end
22
+
23
+ def test_02_create_security_group
24
+ assert @ec2.create_security_group(@group,'My awesone test group'), 'Create_security_group fail'
25
+ group = @ec2.describe_security_groups([@group])[0]
26
+ assert_equal @group, group[:aws_group_name], 'Group must be created but does not exist'
27
+ end
28
+
29
+ def test_03_perms_add
30
+ assert @ec2.authorize_security_group_named_ingress(@group, TestCredentials.account_number, 'default')
31
+ assert @ec2.authorize_security_group_IP_ingress(@group, 80,80,'udp','192.168.1.0/8')
32
+ end
33
+
34
+ def test_04_check_new_perms_exist
35
+ assert_equal 2, @ec2.describe_security_groups([@group])[0][:aws_perms].size
36
+ end
37
+
38
+ def test_05_perms_remove
39
+ assert @ec2.revoke_security_group_IP_ingress(@group, 80,80,'udp','192.168.1.0/8')
40
+ assert @ec2.revoke_security_group_named_ingress(@group,
41
+ TestCredentials.account_number, 'default')
42
+ end
43
+
44
+ def test_06_describe_images
45
+ images = @ec2.describe_images
46
+ assert images.size>0, 'Amazon must have at least some public images'
47
+ # unknown image
48
+ assert_raise(Rightscale::AwsError){ @ec2.describe_images(['ami-ABCDEFGH'])}
49
+ end
50
+
51
+ def test_07_describe_instanses
52
+ assert @ec2.describe_instances
53
+ # unknown image
54
+ assert_raise(Rightscale::AwsError){ @ec2.describe_instances(['i-ABCDEFGH'])}
55
+ end
56
+
57
+ def test_08_delete_security_group
58
+ assert @ec2.delete_security_group(@group), 'Delete_security_group fail'
59
+ end
60
+
61
+ def test_09_delete_key_pair
62
+ assert @ec2.delete_key_pair(@key), 'Delete_key_pair fail'
63
+ ## Hmmm... Amazon does not through the exception any more. It now just returns a 'true' if the key does not exist any more...
64
+ ## # key must be deleted already
65
+ ## assert_raise(Rightscale::AwsError) { @ec2.delete_key_pair(@key) }
66
+ end
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
+
76
+ def test_11_regions
77
+ regions = nil
78
+ assert_nothing_raised do
79
+ regions = @ec2.describe_regions
80
+ end
81
+ # check we got more that 0 regions
82
+ assert regions.size > 0
83
+ # check an access to regions
84
+ regions.each do |region|
85
+ regional_ec2 = Rightscale::Ec2.new(TestCredentials.aws_access_key_id, TestCredentials.aws_secret_access_key, :region => region)
86
+ # do we have a correct endpoint server?
87
+ assert_equal "#{region}.ec2.amazonaws.com", regional_ec2.params[:server]
88
+ # get a list of images from every region
89
+ images = nil
90
+ assert_nothing_raised do
91
+ images = regional_ec2.describe_regions
92
+ end
93
+ # every region must have images
94
+ assert images.size > 0
95
+ end
96
+ end
97
+
98
+ def test_12_endpoint_url
99
+ ec2 = Rightscale::Ec2.new(TestCredentials.aws_access_key_id, TestCredentials.aws_secret_access_key, :endpoint_url => 'a://b.c:0/d/', :region => 'z')
100
+ # :endpoint_url has a priority hence :region should be ommitted
101
+ assert_equal 'a', ec2.params[:protocol]
102
+ assert_equal 'b.c', ec2.params[:server]
103
+ assert_equal '/d/', ec2.params[:service]
104
+ assert_equal 0, ec2.params[:port]
105
+ assert_nil ec2.params[:region]
106
+ end
107
+
108
+ end
@@ -0,0 +1,87 @@
1
+ =begin
2
+ Copyright (c) 2007 RightScale, Inc.
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining
5
+ a copy of this software and associated documentation files (the
6
+ 'Software'), to deal in the Software without restriction, including
7
+ without limitation the rights to use, copy, modify, merge, publish,
8
+ distribute, sublicense, and/or sell copies of the Software, and to
9
+ permit persons to whom the Software is furnished to do so, subject to
10
+ the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ =end
23
+
24
+ # Stub extension/redefinition of RightHttpConnection for testing purposes.
25
+ require 'net/http'
26
+ require 'rubygems'
27
+ require 'right_http_connection'
28
+
29
+ module Net
30
+ class HTTPResponse
31
+ alias_method :real_body, :body
32
+ def setmsg(msg)
33
+ @mymsg = msg
34
+ end
35
+
36
+ def body
37
+ # defined?() helps us to get rid of a bunch of 'warnings'
38
+ (defined?(@mymsg) && @mymsg) ? @mymsg : real_body
39
+ end
40
+ end
41
+ end
42
+
43
+ module Rightscale
44
+
45
+ class HttpConnection
46
+ @@response_stack = []
47
+
48
+ alias_method :real_request, :request
49
+
50
+ def request(request_params, &block)
51
+ if(@@response_stack.length == 0)
52
+ return real_request(request_params, &block)
53
+ end
54
+
55
+ if(block)
56
+ # Do something special
57
+ else
58
+ next_response = HttpConnection::pop()
59
+ classname = Net::HTTPResponse::CODE_TO_OBJ["#{next_response[:code]}"]
60
+ response = classname.new("1.1", next_response[:code], next_response[:msg])
61
+ if(next_response[:msg])
62
+ response.setmsg(next_response[:msg])
63
+ end
64
+ response
65
+ end
66
+ end
67
+
68
+ def self.reset
69
+ @@response_stack = []
70
+ end
71
+
72
+ def self.push(code, msg=nil)
73
+ response = {:code => code, :msg => msg}
74
+ @@response_stack << response
75
+ end
76
+
77
+ def self.pop
78
+ @@response_stack.pop
79
+ end
80
+
81
+ def self.length
82
+ @@response_stack.length
83
+ end
84
+
85
+ end
86
+
87
+ end