simple_aws 0.0.1a → 0.0.1b

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.
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