simple_aws 0.0.1a → 0.0.1b

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/README.md +115 -38
  2. data/lib/aws/auto_scaling.rb +24 -0
  3. data/lib/aws/call_types/action_param.rb +10 -35
  4. data/lib/aws/cloud_formation.rb +25 -0
  5. data/lib/aws/cloud_watch.rb +25 -0
  6. data/lib/aws/core/connection.rb +2 -1
  7. data/lib/aws/core/request.rb +16 -7
  8. data/lib/aws/core/util.rb +2 -0
  9. data/lib/aws/ec2.rb +2 -0
  10. data/lib/aws/elasti_cache.rb +25 -0
  11. data/lib/aws/elastic_beanstalk.rb +25 -0
  12. data/lib/aws/elb.rb +2 -0
  13. data/lib/aws/iam.rb +2 -0
  14. data/lib/aws/import_export.rb +28 -0
  15. data/lib/aws/map_reduce.rb +24 -0
  16. data/lib/aws/mechanical_turk.rb +57 -0
  17. data/lib/aws/rds.rb +24 -0
  18. data/lib/aws/ses.rb +29 -0
  19. data/lib/aws/signing/version2.rb +49 -0
  20. data/lib/aws/signing/version3.rb +38 -0
  21. data/lib/aws/sns.rb +25 -0
  22. data/lib/aws/sqs.rb +56 -0
  23. data/samples/sqs.rb +35 -0
  24. data/samples/turk.rb +14 -0
  25. data/simple_aws.gemspec +1 -1
  26. data/test/aws/auto_scaling_test.rb +36 -0
  27. data/test/aws/call_types/action_param_test.rb +6 -13
  28. data/test/aws/cloud_formation_test.rb +36 -0
  29. data/test/aws/cloud_watch_test.rb +36 -0
  30. data/test/aws/core/connection_test.rb +12 -0
  31. data/test/aws/core/request_test.rb +15 -3
  32. data/test/aws/ec2_test.rb +1 -1
  33. data/test/aws/elasti_cache_test.rb +36 -0
  34. data/test/aws/elastic_beanstalk_test.rb +36 -0
  35. data/test/aws/elb_test.rb +1 -1
  36. data/test/aws/iam_test.rb +1 -1
  37. data/test/aws/import_export_test.rb +42 -0
  38. data/test/aws/map_reduce_test.rb +36 -0
  39. data/test/aws/mechanical_turk_test.rb +44 -0
  40. data/test/aws/rds_test.rb +36 -0
  41. data/test/aws/ses.rb +42 -0
  42. data/test/aws/signing/version2_test.rb +37 -0
  43. data/test/aws/signing/version3.rb +40 -0
  44. data/test/aws/sns_test.rb +36 -0
  45. data/test/aws/sqs.rb +54 -0
  46. metadata +50 -6
@@ -0,0 +1,49 @@
1
+ require 'uri'
2
+ require 'openssl'
3
+
4
+ module AWS
5
+ module Signing
6
+ ##
7
+ # Implementation of "Signature Version 2" signing
8
+ ##
9
+ module Version2
10
+
11
+ ##
12
+ # Build and sign the final request, as per the rules here:
13
+ # http://docs.amazonwebservices.com/AWSEC2/latest/UserGuide/index.html?using-query-api.html
14
+ ##
15
+ def finish_and_sign_request(request)
16
+ request.params.merge!({
17
+ "AWSAccessKeyId" => self.access_key,
18
+ "SignatureMethod" => "HmacSHA256",
19
+ "SignatureVersion" => "2",
20
+ "Timestamp" => Time.now.utc.strftime("%Y-%m-%dT%H:%M:%SZ"),
21
+ "Version" => self.version
22
+ })
23
+
24
+ request.params["Signature"] = Base64.encode64(sign_request(request)).chomp
25
+
26
+ request
27
+ end
28
+
29
+ def sign_request(request)
30
+ signing_params = request.params.clone
31
+
32
+ list = signing_params.map {|k, v| [k, Util.uri_escape(v.to_s)] }
33
+ list.sort! do |a, b|
34
+ if a[0] == "AWSAccessKeyId"
35
+ -1
36
+ else
37
+ a[0] <=> b[0]
38
+ end
39
+ end
40
+
41
+ plain_host = URI.parse(request.host).host
42
+
43
+ to_sign = "POST\n#{plain_host}\n#{request.path}\n#{list.map {|p| p.join("=") }.join("&")}"
44
+ OpenSSL::HMAC.digest("sha256", self.secret_key, to_sign)
45
+ end
46
+
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,38 @@
1
+ require 'openssl'
2
+
3
+ module AWS
4
+ module Signing
5
+ ##
6
+ # Implementation of "Signature Version 3" signing, the X-Amzn-Authorization header
7
+ ##
8
+ module Version3
9
+
10
+ ##
11
+ # Build and sign the final request, as per the rules here:
12
+ # http://docs.amazonwebservices.com/ses/latest/DeveloperGuide/QueryInterface.Authentication.html
13
+ ##
14
+ def finish_and_sign_request(request)
15
+ timestamp = Time.now.utc
16
+ request.params.merge!({
17
+ "AWSAccessKeyId" => self.access_key,
18
+ "Timestamp" => timestamp.strftime("%Y-%m-%dT%H:%M:%SZ"),
19
+ "Version" => self.version
20
+ })
21
+
22
+ request.headers["Date"] = timestamp.httpdate
23
+
24
+ request.headers["X-Amzn-Authorization"] =
25
+ "AWS3-HTTPS AWSAccessKeyId=#{self.access_key}, " +
26
+ "Algorithm=HmacSHA256, " +
27
+ "Signature=#{Base64.encode64(build_signature_for(timestamp)).chomp}"
28
+
29
+ request
30
+ end
31
+
32
+ def build_signature_for(timestamp)
33
+ OpenSSL::HMAC.digest("sha256", self.secret_key, timestamp.httpdate)
34
+ end
35
+
36
+ end
37
+ end
38
+ end
data/lib/aws/sns.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'aws/api'
2
+ require 'aws/call_types/action_param'
3
+ require 'aws/signing/version2'
4
+
5
+ module AWS
6
+
7
+ ##
8
+ # Amazon's Simple Notification Service
9
+ #
10
+ # http://docs.amazonwebservices.com/sns/latest/api/Welcome.html
11
+ #
12
+ # All requests are POST and always through HTTPS. Use the third parameter to
13
+ # #initialize if you need to talk to a region other than us-east-1.
14
+ ##
15
+ class SNS < API
16
+ endpoint "sns"
17
+ use_https true
18
+ version "2010-03-31"
19
+ default_region "us-east-1"
20
+
21
+ include CallTypes::ActionParam
22
+ include Signing::Version2
23
+ end
24
+
25
+ end
data/lib/aws/sqs.rb ADDED
@@ -0,0 +1,56 @@
1
+ require 'aws/api'
2
+ require 'aws/call_types/action_param'
3
+ require 'aws/signing/version2'
4
+
5
+ module AWS
6
+
7
+ ##
8
+ # Amazon's Simple Queue Service
9
+ #
10
+ # http://docs.amazonwebservices.com/AWSSimpleQueueService/latest/APIReference/Welcome.html
11
+ #
12
+ # All requests are POST and always through HTTPS. Use the third parameter to
13
+ # #initialize if you need to talk to a region other than us-east-1.
14
+ #
15
+ # For the requests that act on a queue directly, like SendMessage, pass in the QueueURL
16
+ # as the first parameter to the call:
17
+ #
18
+ # sqs.send_message queue_url, params
19
+ #
20
+ # In accordance with the AWS documentation, SimpleAWS does not try to reconstruct
21
+ # queue urls, use ListQueues or GetQueueUrl to get the correct queue url when needed.
22
+ ##
23
+ class SQS < API
24
+ endpoint "sqs"
25
+ use_https true
26
+ version "2011-10-01"
27
+ default_region "us-east-1"
28
+
29
+ include CallTypes::ActionParam
30
+ include Signing::Version2
31
+
32
+ # Special handling here, we need to look for a QueueURL as the first
33
+ # parameter and update the request URI accordingly
34
+ def method_missing(name, *args)
35
+ if args.first.is_a?(String)
36
+ request_uri = args.first
37
+ params = args.last
38
+ else
39
+ request_uri = self.uri
40
+ params = args.first
41
+ end
42
+
43
+ uri = URI.parse(request_uri)
44
+
45
+ request = AWS::Request.new :post, "#{uri.scheme}://#{uri.host}", uri.path
46
+ request.params["Action"] = AWS::Util.camelcase(name.to_s)
47
+
48
+ if params.is_a?(Hash)
49
+ insert_params_from request, params
50
+ end
51
+
52
+ send_request request
53
+ end
54
+ end
55
+
56
+ end
data/samples/sqs.rb ADDED
@@ -0,0 +1,35 @@
1
+ $: << File.expand_path("../../lib", __FILE__)
2
+
3
+ require 'aws/sqs'
4
+
5
+ ##
6
+ # Expects your Amazon keys to be in the environment, something like
7
+ #
8
+ # export AWS_KEY="KEY"
9
+ # export AWS_SECRET="SECRET"
10
+ ##
11
+
12
+ sqs = AWS::SQS.new ENV["AWS_KEY"], ENV["AWS_SECRET"]
13
+
14
+ queue_name = "SimpleAWSTest"
15
+
16
+ puts "Creating queue #{queue_name}"
17
+ response = sqs.create_queue "QueueName" => queue_name
18
+ queue_url = response.queue_url
19
+
20
+ puts "Sending message to #{queue_url}"
21
+ sent = sqs.send_message queue_url, "MessageBody" => "This is a new message in the queue"
22
+
23
+ puts ""
24
+ p sent
25
+ puts ""
26
+
27
+ puts "Receiving message from #{queue_url}"
28
+ received = sqs.receive_message queue_url
29
+
30
+ puts ""
31
+ p received
32
+ puts ""
33
+
34
+ puts "Deleting queue #{queue_url}"
35
+ p sqs.delete_queue queue_url
data/samples/turk.rb ADDED
@@ -0,0 +1,14 @@
1
+ $: << File.expand_path("../../lib", __FILE__)
2
+
3
+ require 'aws/mechanical_turk'
4
+
5
+ ##
6
+ # Expects your Amazon keys to be in the environment, something like
7
+ #
8
+ # export AWS_KEY="KEY"
9
+ # export AWS_SECRET="SECRET"
10
+ ##
11
+
12
+ turk = AWS::MechanicalTurk.new ENV["AWS_KEY"], ENV["AWS_SECRET"], true
13
+
14
+ p turk.SearchHITs
data/simple_aws.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = "simple_aws"
3
- s.version = "0.0.1a"
3
+ s.version = "0.0.1b"
4
4
  s.platform = Gem::Platform::RUBY
5
5
  s.authors = ["Jason Roelofs"]
6
6
  s.email = ["jameskilton@gmail.com"]
@@ -0,0 +1,36 @@
1
+ require 'test_helper'
2
+ require 'aws/auto_scaling'
3
+
4
+ describe AWS::AutoScaling do
5
+
6
+ before do
7
+ @api = AWS::AutoScaling.new "key", "secret"
8
+ end
9
+
10
+ it "points to the endpoint" do
11
+ @api.uri.must_equal "https://autoscaling.amazonaws.com"
12
+ end
13
+
14
+ it "works with the current version" do
15
+ @api.version.must_equal "2011-01-01"
16
+ end
17
+
18
+ describe "API calls" do
19
+
20
+ it "builds and signs calls with ActionParam rules" do
21
+ AWS::Connection.any_instance.expects(:call).with do |request|
22
+ params = request.params
23
+ params.wont_be_nil
24
+
25
+ params["Action"].must_equal "ExecutePolicy"
26
+ params["Signature"].wont_be_nil
27
+
28
+ true
29
+ end
30
+
31
+ obj = AWS::AutoScaling.new "key", "secret"
32
+ obj.execute_policy
33
+ end
34
+
35
+ end
36
+ end
@@ -10,25 +10,18 @@ describe AWS::CallTypes::ActionParam do
10
10
  use_https true
11
11
 
12
12
  include AWS::CallTypes::ActionParam
13
+
14
+ #noop
15
+ def finish_and_sign_request(request)
16
+ request
17
+ end
13
18
  end
14
19
 
15
- it "builds and signs AWS requests on methods it doesn't know about" do
20
+ it "takes an unknown method call and turns it into a request" do
16
21
  AWS::Connection.any_instance.expects(:call).with do |request|
17
- request.method.must_equal :post
18
- request.uri.must_equal "https://aptest.amazonaws.com/"
19
-
20
22
  params = request.params
21
- params.wont_be_nil
22
-
23
23
  params["Action"].must_equal "DescribeInstances"
24
- params["Version"].must_equal "2011-01-01"
25
- params["AWSAccessKeyId"].must_equal "key"
26
- params["SignatureMethod"].must_equal "HmacSHA256"
27
- params["SignatureVersion"].must_equal "2"
28
-
29
- params["Signature"].wont_be_nil
30
24
 
31
- Time.parse(params["Timestamp"]).wont_be_nil
32
25
  true
33
26
  end.returns
34
27
 
@@ -0,0 +1,36 @@
1
+ require 'test_helper'
2
+ require 'aws/cloud_formation'
3
+
4
+ describe AWS::CloudFormation do
5
+
6
+ before do
7
+ @api = AWS::CloudFormation.new "key", "secret"
8
+ end
9
+
10
+ it "points to endpoint, default to us-east-1" do
11
+ @api.uri.must_equal "https://cloudformation.us-east-1.amazonaws.com"
12
+ end
13
+
14
+ it "works with the current version" do
15
+ @api.version.must_equal "2010-05-15"
16
+ end
17
+
18
+ describe "API calls" do
19
+
20
+ it "builds and signs calls with ActionParam rules" do
21
+ AWS::Connection.any_instance.expects(:call).with do |request|
22
+ params = request.params
23
+ params.wont_be_nil
24
+
25
+ params["Action"].must_equal "DescribeStacks"
26
+ params["Signature"].wont_be_nil
27
+
28
+ true
29
+ end
30
+
31
+ obj = AWS::CloudFormation.new "key", "secret"
32
+ obj.describe_stacks
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ require 'test_helper'
2
+ require 'aws/cloud_watch'
3
+
4
+ describe AWS::CloudWatch do
5
+
6
+ before do
7
+ @api = AWS::CloudWatch.new "key", "secret"
8
+ end
9
+
10
+ it "points to endpoint, default to us-east-1" do
11
+ @api.uri.must_equal "https://monitoring.us-east-1.amazonaws.com"
12
+ end
13
+
14
+ it "works with the current version" do
15
+ @api.version.must_equal "2010-08-01"
16
+ end
17
+
18
+ describe "API calls" do
19
+
20
+ it "builds and signs calls with ActionParam rules" do
21
+ AWS::Connection.any_instance.expects(:call).with do |request|
22
+ params = request.params
23
+ params.wont_be_nil
24
+
25
+ params["Action"].must_equal "ListMetrics"
26
+ params["Signature"].wont_be_nil
27
+
28
+ true
29
+ end
30
+
31
+ obj = AWS::CloudWatch.new "key", "secret"
32
+ obj.list_metrics
33
+ end
34
+
35
+ end
36
+ end
@@ -44,5 +44,17 @@ describe AWS::Connection do
44
44
  @connection.call request
45
45
  end
46
46
 
47
+ it "adds any headers from the Request object" do
48
+ request = AWS::Request.new(:get, "host.com", "/")
49
+ request.headers["Header"] = "Awesome"
50
+
51
+ AWS::HTTP.expects(:get).with {|uri, options|
52
+ options[:query].wont_be_nil
53
+ options[:headers].must_equal "Header" => "Awesome"
54
+ }.returns(@http_response)
55
+
56
+ @connection.call request
57
+ end
58
+
47
59
  end
48
60
  end
@@ -26,6 +26,18 @@ describe AWS::Request do
26
26
  @request.params.must_equal "Param1" => "Value1", "Param2" => "Value2"
27
27
  end
28
28
 
29
+ it "ensures path is never an empty string" do
30
+ @request.path = ""
31
+ @request.path.must_equal "/"
32
+ end
33
+
34
+ describe "headers" do
35
+ it "allows setting raw request headers" do
36
+ @request.headers["Date"] = "This is a header"
37
+ @request.headers["Date"].must_equal "This is a header"
38
+ end
39
+ end
40
+
29
41
  describe "hashes" do
30
42
  it "converts hash params to AWS param names" do
31
43
  @request.params["Filter"] = [
@@ -62,12 +74,12 @@ describe AWS::Request do
62
74
  })
63
75
  end
64
76
 
65
- it "wraps a singular hash into a single element array" do
77
+ it "handles a singular hash properly" do
66
78
  @request.params["Filter"] = {"Name" => "filter1", "Value" => "value1"}
67
79
 
68
80
  @request.params.must_equal({
69
- "Filter.1.Name" => "filter1",
70
- "Filter.1.Value" => "value1"
81
+ "Filter.Name" => "filter1",
82
+ "Filter.Value" => "value1"
71
83
  })
72
84
  end
73
85
  end
data/test/aws/ec2_test.rb CHANGED
@@ -7,7 +7,7 @@ describe AWS::EC2 do
7
7
  @api = AWS::EC2.new "key", "secret"
8
8
  end
9
9
 
10
- it "points to ec2" do
10
+ it "points to the endpoint" do
11
11
  @api.uri.must_equal "https://ec2.amazonaws.com"
12
12
  end
13
13
 
@@ -0,0 +1,36 @@
1
+ require 'test_helper'
2
+ require 'aws/elasti_cache'
3
+
4
+ describe AWS::ElastiCache do
5
+
6
+ before do
7
+ @api = AWS::ElastiCache.new "key", "secret"
8
+ end
9
+
10
+ it "points to the endpoint, default to us-east-1" do
11
+ @api.uri.must_equal "https://elasticache.us-east-1.amazonaws.com"
12
+ end
13
+
14
+ it "works with the current version" do
15
+ @api.version.must_equal "2011-07-15"
16
+ end
17
+
18
+ describe "API calls" do
19
+
20
+ it "builds and signs calls with ActionParam rules" do
21
+ AWS::Connection.any_instance.expects(:call).with do |request|
22
+ params = request.params
23
+ params.wont_be_nil
24
+
25
+ params["Action"].must_equal "DescribeEvents"
26
+ params["Signature"].wont_be_nil
27
+
28
+ true
29
+ end
30
+
31
+ obj = AWS::ElastiCache.new "key", "secret"
32
+ obj.describe_events
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ require 'test_helper'
2
+ require 'aws/elastic_beanstalk'
3
+
4
+ describe AWS::ElasticBeanstalk do
5
+
6
+ before do
7
+ @api = AWS::ElasticBeanstalk.new "key", "secret"
8
+ end
9
+
10
+ it "points to endpoint, default to us-east-1" do
11
+ @api.uri.must_equal "https://elasticbeanstalk.us-east-1.amazonaws.com"
12
+ end
13
+
14
+ it "works with the current version" do
15
+ @api.version.must_equal "2010-12-01"
16
+ end
17
+
18
+ describe "API calls" do
19
+
20
+ it "builds and signs calls with ActionParam rules" do
21
+ AWS::Connection.any_instance.expects(:call).with do |request|
22
+ params = request.params
23
+ params.wont_be_nil
24
+
25
+ params["Action"].must_equal "DescribeApplications"
26
+ params["Signature"].wont_be_nil
27
+
28
+ true
29
+ end
30
+
31
+ obj = AWS::ElasticBeanstalk.new "key", "secret"
32
+ obj.describe_applications
33
+ end
34
+
35
+ end
36
+ end
data/test/aws/elb_test.rb CHANGED
@@ -7,7 +7,7 @@ describe AWS::ELB do
7
7
  @api = AWS::ELB.new "key", "secret"
8
8
  end
9
9
 
10
- it "points to elb" do
10
+ it "points to the endpoint" do
11
11
  @api.uri.must_equal "https://elasticloadbalancing.amazonaws.com"
12
12
  end
13
13
 
data/test/aws/iam_test.rb CHANGED
@@ -7,7 +7,7 @@ describe AWS::IAM do
7
7
  @api = AWS::IAM.new "key", "secret"
8
8
  end
9
9
 
10
- it "points to iam" do
10
+ it "points to the endpoint" do
11
11
  @api.uri.must_equal "https://iam.amazonaws.com"
12
12
  end
13
13
 
@@ -0,0 +1,42 @@
1
+ require 'test_helper'
2
+ require 'aws/import_export'
3
+
4
+ describe AWS::ImportExport do
5
+
6
+ before do
7
+ @api = AWS::ImportExport.new "key", "secret"
8
+ end
9
+
10
+ it "does not support region selection" do
11
+ lambda {
12
+ AWS::ImportExport.new "key", "secret", "us-east-1"
13
+ }.must_raise ArgumentError
14
+ end
15
+
16
+ it "points to endpoint" do
17
+ @api.uri.must_equal "https://importexport.amazonaws.com"
18
+ end
19
+
20
+ it "works with the current version" do
21
+ @api.version.must_equal "2010-06-03"
22
+ end
23
+
24
+ describe "API calls" do
25
+
26
+ it "builds and signs calls with ActionParam rules" do
27
+ AWS::Connection.any_instance.expects(:call).with do |request|
28
+ params = request.params
29
+ params.wont_be_nil
30
+
31
+ params["Action"].must_equal "ListJobs"
32
+ params["Signature"].wont_be_nil
33
+
34
+ true
35
+ end
36
+
37
+ obj = AWS::ImportExport.new "key", "secret"
38
+ obj.list_jobs
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,36 @@
1
+ require 'test_helper'
2
+ require 'aws/map_reduce'
3
+
4
+ describe AWS::MapReduce do
5
+
6
+ before do
7
+ @api = AWS::MapReduce.new "key", "secret"
8
+ end
9
+
10
+ it "points to the endpoint" do
11
+ @api.uri.must_equal "https://elasticmapreduce.amazonaws.com"
12
+ end
13
+
14
+ it "works with the current version" do
15
+ @api.version.must_equal "2009-03-31"
16
+ end
17
+
18
+ describe "API calls" do
19
+
20
+ it "builds and signs calls with ActionParam rules" do
21
+ AWS::Connection.any_instance.expects(:call).with do |request|
22
+ params = request.params
23
+ params.wont_be_nil
24
+
25
+ params["Action"].must_equal "GetGroup"
26
+ params["Signature"].wont_be_nil
27
+
28
+ true
29
+ end
30
+
31
+ obj = AWS::MapReduce.new "key", "secret"
32
+ obj.get_group
33
+ end
34
+
35
+ end
36
+ end
@@ -0,0 +1,44 @@
1
+ require 'test_helper'
2
+ require 'aws/mechanical_turk'
3
+
4
+ describe AWS::MechanicalTurk do
5
+
6
+ before do
7
+ @api = AWS::MechanicalTurk.new "key", "secret"
8
+ end
9
+
10
+ it "points to the endpoint" do
11
+ @api.uri.must_equal "https://mechanicalturk.amazonaws.com"
12
+ end
13
+
14
+ it "works with the current version" do
15
+ @api.version.must_equal "2011-10-01"
16
+ end
17
+
18
+ it "can be told to work in sandbox mode" do
19
+ api = AWS::MechanicalTurk.new "key", "secret", true
20
+ api.uri.must_equal "https://mechanicalturk.sandbox.amazonaws.com"
21
+ end
22
+
23
+ describe "API calls" do
24
+
25
+ it "builds and signs calls with Operation and Service" do
26
+ AWS::Connection.any_instance.expects(:call).with do |request|
27
+ params = request.params
28
+ params.wont_be_nil
29
+
30
+ params["Operation"].must_equal "SearchHITs"
31
+ params["Service"].must_equal "AWSMechanicalTurkRequester"
32
+ params["AWSAccessKeyId"].must_equal "key"
33
+ params["Version"].must_equal "2011-10-01"
34
+ params["Signature"].wont_be_nil
35
+
36
+ true
37
+ end
38
+
39
+ obj = AWS::MechanicalTurk.new "key", "secret"
40
+ obj.SearchHITs
41
+ end
42
+
43
+ end
44
+ end