right_aws_api 0.1.0

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 (37) hide show
  1. checksums.yaml +7 -0
  2. data/HISTORY +2 -0
  3. data/LICENSE +19 -0
  4. data/README.md +164 -0
  5. data/Rakefile +38 -0
  6. data/lib/cloud/aws/as/manager.rb +118 -0
  7. data/lib/cloud/aws/base/helpers/utils.rb +328 -0
  8. data/lib/cloud/aws/base/manager.rb +186 -0
  9. data/lib/cloud/aws/base/parsers/response_error.rb +117 -0
  10. data/lib/cloud/aws/base/routines/request_signer.rb +80 -0
  11. data/lib/cloud/aws/cf/manager.rb +171 -0
  12. data/lib/cloud/aws/cf/routines/request_signer.rb +70 -0
  13. data/lib/cloud/aws/cf/wrappers/default.rb +213 -0
  14. data/lib/cloud/aws/cfm/manager.rb +90 -0
  15. data/lib/cloud/aws/cw/manager.rb +113 -0
  16. data/lib/cloud/aws/eb/manager.rb +87 -0
  17. data/lib/cloud/aws/ec/manager.rb +91 -0
  18. data/lib/cloud/aws/ec2/manager.rb +222 -0
  19. data/lib/cloud/aws/elb/manager.rb +120 -0
  20. data/lib/cloud/aws/emr/manager.rb +86 -0
  21. data/lib/cloud/aws/iam/manager.rb +100 -0
  22. data/lib/cloud/aws/rds/manager.rb +110 -0
  23. data/lib/cloud/aws/route53/manager.rb +177 -0
  24. data/lib/cloud/aws/route53/routines/request_signer.rb +70 -0
  25. data/lib/cloud/aws/route53/wrappers/default.rb +132 -0
  26. data/lib/cloud/aws/s3/manager.rb +373 -0
  27. data/lib/cloud/aws/s3/parsers/response_error.rb +76 -0
  28. data/lib/cloud/aws/s3/routines/request_signer.rb +243 -0
  29. data/lib/cloud/aws/s3/wrappers/default.rb +315 -0
  30. data/lib/cloud/aws/sdb/manager.rb +150 -0
  31. data/lib/cloud/aws/sns/manager.rb +96 -0
  32. data/lib/cloud/aws/sqs/manager.rb +335 -0
  33. data/lib/right_aws_api.rb +45 -0
  34. data/lib/right_aws_api_version.rb +40 -0
  35. data/right_aws_api.gemspec +55 -0
  36. data/spec/describe_calls.rb +92 -0
  37. metadata +118 -0
@@ -0,0 +1,70 @@
1
+ #--
2
+ # Copyright (c) 2013 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
+ #++
23
+
24
+ module RightScale
25
+ module CloudApi
26
+ module AWS
27
+ module Route53
28
+
29
+ # Route 53 request signer
30
+ class RequestSigner < CloudApi::Routine
31
+
32
+ # Route53 RequestSigner Error
33
+ class Error < CloudApi::Error
34
+ end
35
+
36
+ # Authenticates a Route53 request
37
+ #
38
+ # @return [void]
39
+ #
40
+ # @example
41
+ # # no example
42
+ #
43
+ def process
44
+ # Fix body
45
+ unless @data[:request][:body]._blank?
46
+ # Make sure 'content-type' is set if we have a body
47
+ @data[:request][:headers].set_if_blank('content-type', 'application/xml' )
48
+ # Fix body if it is a Hash instance
49
+ if @data[:request][:body].is_a?(Hash)
50
+ @data[:request][:body] = Utils::contentify_body(@data[:request][:body], @data[:request][:headers]['content-type'])
51
+ end
52
+ # Calculate 'content-md5' when possible (some API calls wanna have it set)
53
+ if @data[:request][:body].is_a?(String)
54
+ @data[:request][:headers]['content-md5'] = Base64::encode64(Digest::MD5::digest(@data[:request][:body])).strip
55
+ end
56
+ end
57
+ # Set date
58
+ @data[:request][:headers].set_if_blank('date', Time::now.utc.httpdate)
59
+ # Sign a request
60
+ signature = Utils::AWS::sign(@data[:credentials][:aws_secret_access_key], Utils::dearrayify(@data[:request][:headers]['date']))
61
+ @data[:request][:headers]['x-amzn-authorization'] = "AWS3-HTTPS AWSAccessKeyId=#{@data[:credentials][:aws_access_key_id]},Algorithm=HmacSHA1,Signature=#{signature}"
62
+ # Set path
63
+ @data[:request][:path] = Utils::join_urn(@data[:connection][:uri].path, @data[:options][:api_version], @data[:request][:relative_path], @data[:request][:params])
64
+ end
65
+
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,132 @@
1
+ #--
2
+ # Copyright (c) 2013 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
+ #++
23
+
24
+ module RightScale
25
+ module CloudApi
26
+ module AWS
27
+ module Route53
28
+
29
+ # Route 53 wrapper namespace
30
+ module Wrapper
31
+
32
+ # Default wrapper
33
+ module DEFAULT
34
+
35
+ # Defines QUERY API like methods for the service
36
+ #
37
+ # @return [void]
38
+ #
39
+ # @example
40
+ # # no example
41
+ #
42
+ def self.extended(base)
43
+
44
+ #-----------------
45
+ # Hosted Zones
46
+ #-----------------
47
+
48
+
49
+ base.query_api_pattern 'ListHostedZones', :get, 'hostedzone'
50
+
51
+
52
+ base.query_api_pattern 'GetHostedZone', :get, 'hostedzone/{:HostedZoneId}'
53
+
54
+
55
+ base.query_api_pattern 'CreateHostedZones', :post, 'hostedzone',
56
+ :body => {
57
+ 'CreateHostedZoneRequest' => {
58
+ 'Name' => :Name,
59
+ 'CallerReference' => :CallerReference,
60
+ 'HostedZoneConfig{!remove-if-blank}' => {
61
+ 'Comment' => :Comment
62
+ }
63
+ }
64
+ },
65
+ :defaults => {
66
+ :Comment => Utils::NONE
67
+ }
68
+
69
+
70
+ base.query_api_pattern 'DeleteHostedZone', :delete, 'hostedzone/{:HostedZoneId}'
71
+
72
+
73
+ #----------------------
74
+ # Resource Record Sets
75
+ #----------------------
76
+
77
+
78
+ base.query_api_pattern 'ListResourceRecordSets', :get, 'hostedzone/{:HostedZoneId}/rrset'
79
+
80
+
81
+ base.query_api_pattern 'GetChange', :get, 'change/{:ChangeId}'
82
+
83
+
84
+ base.query_api_pattern 'ChangeResourceRecordSets', :post, 'hostedzone/{:HostedZoneId}/rrset',
85
+ :body => {
86
+ 'ChangeResourceRecordSetsRequest' => {
87
+ '@xmlns' => 'https://route53.amazonaws.com/doc/2011-05-05/',
88
+ 'ChangeBatch' => {
89
+ 'Comment' => :Comment,
90
+ 'Changes' => {
91
+ 'Change[{:Change}]' => {
92
+ 'Action' => :Action,
93
+ 'ResourceRecordSet' => {
94
+ 'Name' => :Name,
95
+ 'Type' => :Type,
96
+ 'AliasTarget{!remove-if-blank}' => {
97
+ 'HostedZoneId' => :HostedZoneId,
98
+ 'DNSName' => :DNSName
99
+ },
100
+ 'SetIdentifier' => :SetIdentifier,
101
+ 'Weight' => :Weight,
102
+ 'TTL' => :TTL,
103
+ 'ResourceRecords{!remove-if-blank}' => {
104
+ 'ResourceRecord{!remove-if-blank}' => {
105
+ 'Value' => :ResourceRecord
106
+ }
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+ }
113
+ },
114
+ :defaults => {
115
+ :Comment => Utils::NONE,
116
+ :TTL => Utils::NONE,
117
+ :DNSName => Utils::NONE,
118
+ :HostedZoneId => Utils::NONE,
119
+ :SetIdentifier => Utils::NONE,
120
+ :Weight => Utils::NONE,
121
+ :ResourceRecord => Utils::NONE
122
+ }
123
+
124
+
125
+ end
126
+
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,373 @@
1
+ #--
2
+ # Copyright (c) 2013 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
+ #++
23
+
24
+ require "cloud/aws/base/helpers/utils"
25
+ require "cloud/aws/s3/parsers/response_error"
26
+ require "cloud/aws/s3/wrappers/default"
27
+ require "cloud/aws/s3/routines/request_signer"
28
+
29
+ module RightScale
30
+ module CloudApi
31
+ module AWS
32
+
33
+ # Simple Storage Service namespace
34
+ #
35
+ # @api public
36
+ #
37
+ module S3
38
+
39
+ # Amazon Simple Storage Service (S3) compatible manager (thread safe).
40
+ #
41
+ # @example
42
+ # require "right_aws_api"
43
+ #
44
+ # s3 = RightScale::CloudApi::AWS::S3::Manager.new(key, secret, 'https://s3.amazonaws.com')
45
+ #
46
+ # @example
47
+ # # -- Using HTTP verb methods --
48
+ #
49
+ # # List all buckets
50
+ # s3.get
51
+ #
52
+ # # List bucket objects
53
+ # s3.get('devs-us-east')
54
+ #
55
+ # # Get bucket ACL
56
+ # s3.get('devs-us-east', :params => {'acl' => nil} )
57
+ #
58
+ # # Put bucket ACL
59
+ # s3.put('devs-us-east',
60
+ # :params => {'acl' => nil},
61
+ # :body => access_control_policy_xml,
62
+ # :headers => { 'content-type' => 'application/xml' }
63
+ # )
64
+ #
65
+ # # Get bucket Versions
66
+ # s3.get('devs-us-east', :params => {'version' => nil} )
67
+ #
68
+ # # Get object
69
+ # s3.get('devs-us-east/boot1.jpg')
70
+ # # Do not parse response if Amazon reports back XML or JSON content-type
71
+ # s3.get('devs-us-east/boot1.xml', :options => { :raw_response => true})
72
+ #
73
+ # # Get object, force set content-type
74
+ # s3.get('kd-kd-kd-1/boot1.jpg', :params => { 'response-content-type' => 'image/jpeg'})
75
+ #
76
+ # # Put object
77
+ # # Do not forget to provide a proper 'content-type' header because the default
78
+ # # one is set to 'application/octet-stream'
79
+ # s3.put('devs-us-east/boot1.jpg',
80
+ # :body => 'This is my object DATA. WooHoo!!!',
81
+ # :headers => {'content-type' => 'text/plain'})
82
+ #
83
+ #
84
+ # @example
85
+ # # A simple example of a multi-thread file download:
86
+ # threads = []
87
+ # file_size = 3257230
88
+ # chunks = 3
89
+ # chunk_size = file_size / chunks
90
+ # chunks.times do |i|
91
+ # from_byte = i * chunk_size
92
+ # to_byte = from_byte + chunk_size - 1
93
+ # to_byte += file_size % chunks if i + 1 == chunks
94
+ # threads << Thread::new {
95
+ # Thread.current[:my_file] = s3.get('devs-us-east/xxx/boot.jpg', {:headers => {'Range' => "bytes=#{from_byte}-#{to_byte}"}})
96
+ # }
97
+ # end
98
+ # file_body = ''
99
+ # threads.each do |thread|
100
+ # thread.join
101
+ # file_body << thread[:my_file]
102
+ # end
103
+ # file_body.size #=> 3257230
104
+ #
105
+ #
106
+ # @example
107
+ # # Download into IO object
108
+ # File.open('/tmp/boot.jpg','w') do |file|
109
+ # s3.get('devs-us-east/kd/boot.jpg') do |chunk|
110
+ # file.write(chunk)
111
+ # end
112
+ # end
113
+ #
114
+ #
115
+ # @example
116
+ # # -- Using helper methods --
117
+ #
118
+ # # List all buckets
119
+ # s3.ListAllMyBuckets
120
+ #
121
+ # # List bucket objects
122
+ # s3.ListObjects('Bucket' => 'devs-us-east')
123
+ #
124
+ # # Get bucket ACL
125
+ # s3.GetBucketAcl('Bucket' => 'devs-us-east')
126
+ #
127
+ # # Get bucket Versions
128
+ # s3.GetBucketVersions('Bucket' => 'devs-us-east')
129
+ #
130
+ # # Get object
131
+ # s3.GetObject('Bucket' => 'devs-us-east', 'Object' => 'boot1.jpg')
132
+ #
133
+ # # Get object, force set content-type
134
+ # s3.GetObject('Bucket' => 'devs-us-east', 'Object' => 'boot1.jpg',
135
+ # :params => { 'response-content-type' => 'image/jpeg'})
136
+ #
137
+ # # Put object
138
+ # # P.S. 'content-type' is 'application/octet-stream' by default
139
+ # s3.PutObject('Bucket' => 'devs-us-east',
140
+ # 'Object' => 'boot1.jpg',
141
+ # :body => file_content,
142
+ # :headers => {'content-type' => 'image/jpeg'})
143
+ #
144
+ # @example
145
+ #
146
+ # # List all buckets
147
+ # s3.ListAllMyBuckets #=>
148
+ # {"ListAllMyBucketsResult"=>
149
+ # {"Buckets"=>
150
+ # {"Bucket"=>
151
+ # [{"Name"=>"CI_right_test",
152
+ # "CreationDate"=>"2011-05-25T20:46:28.000Z"},
153
+ # {"Name"=>"CR_right_test",
154
+ # "CreationDate"=>"2011-06-08T20:46:32.000Z"},
155
+ # {"Name"=>"DarrylTest",
156
+ # "CreationDate"=>"2011-06-03T03:43:08.000Z"},
157
+ # {"Name"=>"RightScalePeter",
158
+ # "CreationDate"=>"2008-10-28T03:59:20.000Z"}]},
159
+ # "Owner"=>
160
+ # {"DisplayName"=>"fghsfg",
161
+ # "ID"=>"16144ab2929314cc309ffe736daa2b264357476c7fea6efb2c3347ac3ab2792a"},
162
+ # "@xmlns"=>"http://s3.amazonaws.com/doc/2006-03-01/"}}
163
+ #
164
+ # # List bucket objects
165
+ # s3.ListObjects('Bucket' => 'devs-us-east', 'max-keys' => 3, 'prefix' => 'kd') #=>
166
+ # {"ListBucketResult"=>
167
+ # {"MaxKeys"=>"3",
168
+ # "IsTruncated"=>"false",
169
+ # "Name"=>"devs-us-east",
170
+ # "Marker"=>nil,
171
+ # "Contents"=>
172
+ # {"LastModified"=>"2010-08-26T12:23:30.000Z",
173
+ # "StorageClass"=>"STANDARD",
174
+ # "ETag"=>"\"3c9a2717e34efedb6d6ac007b2acb8df\"",
175
+ # "Owner"=>
176
+ # {"DisplayName"=>"thve",
177
+ # "ID"=>
178
+ # "16144ab2929314cc309ffe736daa2b264357476c7fea6efb2c3347ac3ab2792a"},
179
+ # "Size"=>"3257230",
180
+ # "Key"=>"kd/boot.jpg"},
181
+ # "@xmlns"=>"http://s3.amazonaws.com/doc/2006-03-01/",
182
+ # "Prefix"=>"kd"}}
183
+ #
184
+ #
185
+ # @example
186
+ # # Get
187
+ # s3.GetBucketCors('Bucket' => 'my-bucket' ) #=>
188
+ # {"CORSConfiguration"=>
189
+ # {"@xmlns"=>"http://s3.amazonaws.com/doc/2006-03-01/",
190
+ # "CORSRule"=>
191
+ # [{"AllowedOrigin"=>"http://www.example.com",
192
+ # "AllowedMethod"=>["PUT", "POST"],
193
+ # "MaxAgeSeconds"=>"2000",
194
+ # "ExposeHeader"=>"x-amz-server-side-encryption"},
195
+ # {"AllowedOrigin"=>"*", "AllowedMethod"=>"GET", "MaxAgeSeconds"=>"2001"}]}}
196
+ #
197
+ #
198
+ # @example
199
+ # # Put
200
+ # cors_rules = [
201
+ # {'AllowedOrigin' => 'http://www.example.com',
202
+ # 'AllowedMethod' => ['PUT', 'POST'],
203
+ # 'MaxAgeSeconds' => 3000,
204
+ # 'ExposeHeader' => 'x-amz-server-side-encryption' },
205
+ # {'AllowedOrigin' => '*',
206
+ # 'AllowedMethod' => 'GET',
207
+ # 'MaxAgeSeconds' => 3000 } ]
208
+ # s3.PutBucketCors('Bucket' => 'kd-ver-test', 'CORSRule' => cors_rules ) #=> ''
209
+ #
210
+ # # .. or
211
+ # body = "<CORSConfiguration><CORSRule><AllowedOrigin>http://www.example.com</AllowedOrigin>"+
212
+ # "<AllowedMethod>PUT</AllowedMethod><AllowedMethod>POST</AllowedMethod>"+
213
+ # "<MaxAgeSeconds>3000</MaxAgeSeconds>..</CORSConfiguration>"
214
+ # s3.PutBucketCors('Bucket' => 'my-bucket', :body => body ) #=> ''
215
+ #
216
+ #
217
+ # @example
218
+ # # Delete
219
+ # s3.DeleteBucketCors('Bucket' => 'my-bucket' ) #=> ''
220
+ #
221
+ #
222
+ # @example
223
+ # # Bucket Tagging
224
+ # # Get
225
+ # s3.GetBucketTagging('Bucket' => 'my-bucket' ) #=>
226
+ # {"Tagging"=> {
227
+ # "TagSet"=> {
228
+ # "Tag"=>[
229
+ # {"Key"=>"Project",
230
+ # "Value"=>"Project One"},
231
+ # {"Key"=>"User",
232
+ # "Value"=>"jsmith"}]}}}
233
+ #
234
+ #
235
+ # @example
236
+ # # Delete
237
+ # s3.DeleteBucketTagging('Bucket' => 'my-bucket' ) #=> ''
238
+ #
239
+ #
240
+ # @example
241
+ # # Put
242
+ # tagging_rules = [
243
+ # {"Key"=>"Project",
244
+ # "Value"=>"Project One"},
245
+ # {"Key"=>"User",
246
+ # "Value"=>"jsmith"} ]
247
+ # s3.PutBucketTagging('Bucket' => 'my-bucket', 'TagSet' => tagging_rules ) #=> ''
248
+ #
249
+ #
250
+ # @example
251
+ # # Bucket Lifecycle
252
+ # # Get
253
+ # s3.GetBucketLifecycle('Bucket' => 'my-bucket' ) #=>
254
+ # {"LifecycleConfiguration"=> {
255
+ # "Rule"=>[{
256
+ # "ID" => "30-day-log-deletion-rule",
257
+ # "Prefix" => "logs",
258
+ # "Status" => "Enabled",
259
+ # "Expiration" => { "Days" => 30 }}]}}
260
+ #
261
+ #
262
+ # @example
263
+ # # Delete
264
+ # s3.DeleteBucketLifecycle('Bucket' => 'my-bucket' ) #=> ''
265
+ #
266
+ #
267
+ # @example
268
+ # # Put
269
+ # lifecycle_rules = [
270
+ # { "ID" => "30-day-log-deletion-rule",
271
+ # "Prefix" => "logs",
272
+ # "Status" => "Enabled",
273
+ # "Expiration" => {"Days" => 30}},
274
+ # {"ID" => "delete-documents-rule",
275
+ # "Prefix" => "documents",
276
+ # "Status" => "Enabled",
277
+ # "Expiration" => { "Days" => 365 }}]
278
+ # s3.PutBucketLifecycle('Bucket' => 'my-bucket', 'Rule' => lifecycle_rules ) #=> ''
279
+ #
280
+ #
281
+ # @example
282
+ # # Get a link to ListAllMyBuckets action
283
+ # s3.ListAllMyBuckets(:options=>{:cloud=>{:link=>true}}) #=>
284
+ # {"verb" => "get",
285
+ # "link" => "https://s3.amazonaws.com/?AWSAccessKeyId=0K4QH...G2&Expires=1426111071&Signature=vLMH...3D",
286
+ # "headers"=> {"host"=>["s3.amazonaws.com"]}}
287
+ #
288
+ # # If you need to get a bunch of links you can use with_options helper method:
289
+ # opts = {:headers => {'expires' => Time.now + 3600}}
290
+ # s3.with_options(:cloud=>{:link => true}) do
291
+ # pp s3.GetObject({'Bucket'=>'my-bucket', 'Object'=>'kd/kd0.test', 'versionId'=>"00eYZeb291o4"}, opts)
292
+ # pp s3.GetObject({'Bucket'=>'my-bucket', 'Object'=>'kd/kd1.test', 'versionId'=>"fafaf1obp1W4"}, opts)
293
+ # pp s3.GetObject({'Bucket'=>'my-bucket', 'Object'=>'kd/kd2.test', 'versionId'=>"00asdTebp1W4"}, opts)
294
+ # pp s3.GetObject({'Bucket'=>'my-bucket', 'Object'=>'kd/kd3.test', 'versionId'=>"0lkjreobp1W4"}, opts)
295
+ # end
296
+ #
297
+ #
298
+ # @see ApiManager
299
+ # @see Wrapper::DEFAULT.extended Wrapper::DEFAULT.extended (click [View source])
300
+ # @see http://docs.aws.amazon.com/AmazonS3/latest/API/APIRest.html
301
+ #
302
+ class Manager < CloudApi::Manager
303
+ end
304
+
305
+
306
+ # Amazon Simple Storage Service (S3) compatible manager (thread unsafe).
307
+ #
308
+ # @see Manager
309
+ #
310
+ class ApiManager < CloudApi::ApiManager
311
+
312
+ # S3 Error
313
+ class Error < CloudApi::Error
314
+ end
315
+
316
+ include Mixin::QueryApiPatterns
317
+
318
+ set_routine CloudApi::RetryManager
319
+ set_routine CloudApi::RequestInitializer
320
+ set_routine AWS::S3::RequestSigner
321
+ set_routine CloudApi::RequestGenerator
322
+ set_routine CloudApi::ConnectionProxy
323
+ set_routine CloudApi::ResponseAnalyzer
324
+ set_routine CloudApi::ResponseParser
325
+ set_routine CloudApi::ResultWrapper
326
+
327
+ set :response_error_parser => Parser::AWS::S3::ResponseError
328
+
329
+
330
+ # Constructor
331
+ #
332
+ # @param [String] aws_access_key_id
333
+ # @param [String] aws_secret_access_key
334
+ # @param [String] endpoint
335
+ # @param [Hash] options
336
+ #
337
+ # @example
338
+ # # see Manager class
339
+ #
340
+ # @see Manager
341
+ #
342
+ def initialize(aws_access_key_id, aws_secret_access_key, endpoint, options={})
343
+ credentials = { :aws_access_key_id => aws_access_key_id,
344
+ :aws_secret_access_key => aws_secret_access_key }
345
+ super(credentials, endpoint, options)
346
+ end
347
+
348
+
349
+ # Makes an API call to AWS::S3 compatible cloud
350
+ #
351
+ # @param [String,Symbol] verb 'get' | 'put' | etc
352
+ # @param [Objects] args
353
+ #
354
+ # @return [Object]
355
+ #
356
+ # @example
357
+ # api(verb, opts={})
358
+ # api(verb, 'bucket', opts={})
359
+ # # Where opts may have next keys: :options, :headers, :params, :body
360
+ # api(verb, 'bucket/object', opts={})
361
+ #
362
+ def api(verb, *args, &block)
363
+ relative_path = args.first.is_a?(String) ? args.shift : ''
364
+ opts = args.shift || {}
365
+ raise Error::new("Opts must be Hash not #{opts.class.name}") unless opts.is_a?(Hash)
366
+ process_api_request(verb, relative_path, opts, &block)
367
+ end
368
+
369
+ end
370
+ end
371
+ end
372
+ end
373
+ end