right_aws 1.10.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. data/History.txt +53 -15
  2. data/Manifest.txt +16 -0
  3. data/README.txt +10 -9
  4. data/Rakefile +13 -15
  5. data/lib/acf/right_acf_interface.rb +224 -118
  6. data/lib/acf/right_acf_origin_access_identities.rb +230 -0
  7. data/lib/acf/right_acf_streaming_interface.rb +236 -0
  8. data/lib/acw/right_acw_interface.rb +249 -0
  9. data/lib/as/right_as_interface.rb +699 -0
  10. data/lib/awsbase/right_awsbase.rb +232 -51
  11. data/lib/awsbase/support.rb +4 -0
  12. data/lib/ec2/right_ec2.rb +33 -1375
  13. data/lib/ec2/right_ec2_ebs.rb +452 -0
  14. data/lib/ec2/right_ec2_images.rb +373 -0
  15. data/lib/ec2/right_ec2_instances.rb +755 -0
  16. data/lib/ec2/right_ec2_monitoring.rb +70 -0
  17. data/lib/ec2/right_ec2_reserved_instances.rb +170 -0
  18. data/lib/ec2/right_ec2_security_groups.rb +280 -0
  19. data/lib/ec2/right_ec2_spot_instances.rb +399 -0
  20. data/lib/ec2/right_ec2_vpc.rb +571 -0
  21. data/lib/elb/right_elb_interface.rb +496 -0
  22. data/lib/rds/right_rds_interface.rb +998 -0
  23. data/lib/right_aws.rb +18 -4
  24. data/lib/s3/right_s3.rb +39 -7
  25. data/lib/s3/right_s3_interface.rb +77 -53
  26. data/lib/sdb/active_sdb.rb +203 -11
  27. data/lib/sdb/right_sdb_interface.rb +68 -45
  28. data/lib/sqs/right_sqs_gen2.rb +73 -16
  29. data/lib/sqs/right_sqs_gen2_interface.rb +131 -51
  30. data/lib/sqs/right_sqs_interface.rb +2 -4
  31. data/test/acf/test_right_acf.rb +10 -18
  32. data/test/rds/test_helper.rb +2 -0
  33. data/test/rds/test_right_rds.rb +120 -0
  34. data/test/s3/test_right_s3.rb +10 -8
  35. data/test/s3/test_right_s3_stubbed.rb +6 -4
  36. data/test/sdb/test_active_sdb.rb +70 -12
  37. data/test/sdb/test_right_sdb.rb +13 -7
  38. data/test/sqs/test_right_sqs_gen2.rb +104 -49
  39. metadata +103 -14
@@ -223,24 +223,62 @@ the source key.
223
223
  === 1.10.0
224
224
 
225
225
  Release Notes:
226
-
227
- The big new features are SDB's SQL-like query and query_with_attributes
228
- support as well as signature v2 support for all services. There are also
229
- numerous bug fixes, many of them reported and patched by users and
230
- customers.
231
-
232
226
  - AwsBase: signature v2 support added
233
- - AwsBase: fix the regex matching for xmlpath which didn't work in Ruby
234
- 1.8.7 (thanks to a customer report)
235
227
  - Ec2: describe_availability_zones improved to support regions
236
- - Ec2: Disabled retries when EC2 returns "ServiceUnavailable: Request limit
237
- exceeded"
238
- - Ec2: Use POST for large queries; this avoids truncation of large user data
239
- when launching instances (thanks to Bob for the report)
240
228
  - CloudFront: docs fixes
241
229
  - SDB: added: SQL-like query, select and query_with_attributes support
242
230
  - SDB: fixed no method error when searching for id that doesn't exist
243
- (thanks to multiple users for reporting this)
244
- - S3: Fixed overzealous URL-encoding when generating URLs for S3 keys
245
- (thanks to a bug report on the RubyForge forum)
246
231
 
232
+ === 1.11.0
233
+
234
+ Release Notes:
235
+ - Full Amazon RDS instances support added with RightAws::RdsInterface
236
+ - Boot from EBS support added
237
+ - VPC support added
238
+ - Latest EC2 API 2009-10-31 support added
239
+ - Some of bugs fixed
240
+
241
+ === 2.0.0
242
+
243
+ Release Notes:
244
+ - Added:
245
+ - Ruby 1.9 support
246
+ - Ec2:
247
+ - SpotInstances support
248
+ - m2.xlarge instances
249
+ - GetPasswordData API call (see get_password_data_v2)
250
+ - SecurityGroups support for Eucalyptus clouds
251
+ - EBS:
252
+ - :delete_on_termination field for volumes
253
+ - SimpleDB:
254
+ - BatchPutAttributes support
255
+ - ActiveSDB:
256
+ - Dynamic attribute accessors
257
+ - "Columns" support
258
+ - Simple Type Casting support
259
+ - ELB:
260
+ - API '2009-11-25' support (stickiness policies)
261
+ - ACF:
262
+ - API '2010-03-01' support (origin access policy and streaming distributions)
263
+ - Bunch of small issues were fixed
264
+ - Time objects were replaced by Strings (as Amazon returns them) to make the gem more consistent:
265
+ - :last_modified_time in:
266
+ RightAws::AcfInterface#incrementally_list_distributions,
267
+ RightAws::AcfInterface#create_distribution_by_config,
268
+ RightAws::AcfInterface#get_distribution,
269
+ RightAws::AcfInterface#get_distribution_config
270
+ - :timestamp in:
271
+ RightAws::AcwInterface#get_metric_statistics
272
+ - :aws_created_at in:
273
+ RightAws::Ec2#create_volume,
274
+ RightAws::Ec2#describe_volumes
275
+ - :aws_attached_at in:
276
+ RightAws::Ec2#attach_volume,
277
+ RightAws::Ec2#detach_volume,
278
+ RightAws::Ec2#describe_volumes
279
+ - :aws_started_at in:
280
+ RightAws::Ec2#describe_snapshots,
281
+ RightAws::Ec2#create_snapshot,
282
+ RightAws::Ec2#try_create_snapshot
283
+ - :created_time in:
284
+ RightAws::ElbInterface#describe_load_balancers
@@ -6,8 +6,19 @@ lib/awsbase/benchmark_fix.rb
6
6
  lib/awsbase/right_awsbase.rb
7
7
  lib/awsbase/support.rb
8
8
  lib/ec2/right_ec2.rb
9
+ lib/ec2/right_ec2_images.rb
10
+ lib/ec2/right_ec2_instances.rb
11
+ lib/ec2/right_ec2_security_groups.rb
12
+ lib/ec2/right_ec2_spot_instances.rb
13
+ lib/ec2/right_ec2_ebs.rb
14
+ lib/ec2/right_ec2_reserved_instances.rb
15
+ lib/ec2/right_ec2_vpc.rb
16
+ lib/ec2/right_ec2_monitoring.rb
9
17
  lib/right_aws.rb
10
18
  lib/s3/right_s3.rb
19
+ lib/acw/right_acw_interface.rb
20
+ lib/elb/right_elb_interface.rb
21
+ lib/as/right_as_interface.rb
11
22
  lib/s3/right_s3_interface.rb
12
23
  lib/sdb/active_sdb.rb
13
24
  lib/sdb/right_sdb_interface.rb
@@ -16,6 +27,9 @@ lib/sqs/right_sqs_gen2.rb
16
27
  lib/sqs/right_sqs_gen2_interface.rb
17
28
  lib/sqs/right_sqs_interface.rb
18
29
  lib/acf/right_acf_interface.rb
30
+ lib/acf/right_acf_streaming_interface.rb
31
+ lib/acf/right_acf_origin_access_identities.rb
32
+ lib/rds/right_rds_interface.rb
19
33
  test/ec2/test_helper.rb
20
34
  test/ec2/test_right_ec2.rb
21
35
  test/http_connection.rb
@@ -32,3 +46,5 @@ test/test_credentials.rb
32
46
  test/ts_right_aws.rb
33
47
  test/acf/test_helper.rb
34
48
  test/acf/test_right_acf.rb
49
+ test/rds/test_helper.rb
50
+ test/rds/test_right_rds.rb
data/README.txt CHANGED
@@ -9,17 +9,20 @@ The RightScale AWS gems have been designed to provide a robust, fast, and secure
9
9
  These gems have been used in production by RightScale since late 2006 and are being maintained to track enhancements made by Amazon.
10
10
  The RightScale AWS gems comprise:
11
11
 
12
- - RightAws::Ec2 -- interface to Amazon EC2 (Elastic Compute Cloud) and the
13
- associated EBS (Elastic Block Store)
12
+ - RightAws::Ec2 -- interface to Amazon EC2 (Elastic Compute Cloud), VPC (Virtual Private Cloud) and the associated EBS (Elastic Block Store)
14
13
  - 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)
14
+ - RightAws::Sqs and RightAws::SqsInterface -- interface to first-generation Amazon SQS (Simple Queue Service)
15
+ - RightAws::SqsGen2 and RightAws::SqsGen2Interface -- interface to second-generation Amazon SQS (Simple Queue Service)
17
16
  - RightAws::SdbInterface and RightAws::ActiveSdb -- interface to Amazon SDB (SimpleDB)
18
17
  - RightAws::AcfInterface -- interface to Amazon CloudFront, a content distribution service
18
+ - RightAws::AsInterface -- interface to Amazon Auto Scaling
19
+ - RightAws::AcwInterface -- interface to Amazon Cloud Watch
20
+ - RightAws::ElbInterface -- interface to Amazon Elastic Load Balancer
21
+ - RightAws::RdsInterface -- interface to Amazon RDS instances
19
22
 
20
23
  == FEATURES:
21
24
 
22
- - Full programmmatic access to EC2, EBS, S3, SQS, SDB, and CloudFront.
25
+ - Full programmmatic access to EC2, EBS, S3, SQS, SDB, CloudFront, AS, ACW, ELB and RDS.
23
26
  - Complete error handling: all operations check for errors and report complete
24
27
  error information by raising an AwsError.
25
28
  - Persistent HTTP connections with robust network-level retry layer using
@@ -38,7 +41,7 @@ The RightScale AWS gems comprise:
38
41
  AWS accounts.
39
42
  - Support for both first- and second-generation SQS (API versions 2007-05-01
40
43
  and 2008-01-01). These versions of SQS are not compatible.
41
- - Support for signature versions 0, 1 and 2 on all services.
44
+ - Support for signature versions 0 and 1 on SQS, SDB, and EC2.
42
45
  - Interoperability with any cloud running Eucalyptus (http://eucalyptus.cs.ucsb.edu)
43
46
  - Test suite (requires AWS account to do "live" testing).
44
47
 
@@ -119,9 +122,7 @@ multithreaded mode.
119
122
  'incompatible Net::HTTP monkey-patch'
120
123
 
121
124
  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
+ gem required by attachment_fu.
125
126
 
126
127
  - 8/07: Amazon has changed the semantics of the SQS service. A
127
128
  new queue may not be created within 60 seconds of the destruction of any
data/Rakefile CHANGED
@@ -10,36 +10,27 @@ require 'lib/right_aws.rb'
10
10
  testglobs = ["test/ts_right_aws.rb"]
11
11
 
12
12
 
13
- # Suppress Hoe's self-inclusion as a dependency for our Gem. This also keeps
14
- # Rake & rubyforge out of the dependency list. Users must manually install
13
+ # Suppress Hoe's self-inclusion as a dependency for our Gem. This also keeps
14
+ # Rake & rubyforge out of the dependency list. Users must manually install
15
15
  # these gems to run tests, etc.
16
- # TRB 2/24/09: also do this for the extra_dev_deps array present in newer hoes.
17
- # Older versions of RubyGems will try to install developer-dependencies as
18
- # required runtime dependencies. It would be great to take advantage of the extra dev deps, but not
19
- # at the cost of requiring many additional dependencies if the user is running an older RubyGems.
20
16
  class Hoe
21
17
  def extra_deps
22
18
  @extra_deps.reject do |x|
23
19
  Array(x).first == 'hoe'
24
20
  end
25
21
  end
26
- def extra_dev_deps
27
- @extra_dev_deps.reject do |x|
28
- Array(x).first == 'hoe'
29
- end
30
- end
31
22
  end
32
23
 
33
24
  Hoe.new('right_aws', RightAws::VERSION::STRING) do |p|
34
- p.rubyforge_name = 'rightscale'
25
+ p.rubyforge_name = 'rightaws'
35
26
  p.author = 'RightScale, Inc.'
36
- p.email = 'rubygems@rightscale.com'
37
- p.summary = 'Interface classes for the Amazon EC2/EBS, SQS, S3, SDB, and ACF Web Services'
27
+ p.email = 'support@rightscale.com'
28
+ p.summary = 'Interface classes for the Amazon EC2, SQS, and S3 Web Services'
38
29
  p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
39
30
  p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
40
31
  p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
41
32
  p.remote_rdoc_dir = "/right_aws_gem_doc"
42
- p.extra_deps = [['right_http_connection','>= 1.2.4']]
33
+ p.extra_deps = [['right_http_connection','>= 1.2.1']]
43
34
  p.test_globs = testglobs
44
35
  end
45
36
 
@@ -109,4 +100,11 @@ task :testacf do
109
100
  require 'test/acf/test_right_acf.rb'
110
101
  end
111
102
 
103
+ desc "Test RDS interface"
104
+ task :testrds do
105
+ require 'test/test_credentials'
106
+ TestCredentials.get_credentials
107
+ require 'test/rds/test_right_rds.rb'
108
+ end
109
+
112
110
  # vim: syntax=Ruby
@@ -20,7 +20,6 @@
20
20
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
21
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  #
23
-
24
23
  module RightAws
25
24
 
26
25
  # = RightAws::AcfInterface -- RightScale Amazon's CloudFront interface
@@ -42,7 +41,7 @@ module RightAws
42
41
  # :origin => "my-bucket.s3.amazonaws.com",
43
42
  # :cnames => ["x1.my-awesome-site.net", "x1.my-awesome-site.net"]
44
43
  # :comment => "My comments",
45
- # :last_modified_time => Wed Sep 10 17:00:04 UTC 2008 }, ..., {...} ]
44
+ # :last_modified_time => "2008-09-10T17:00:04.000Z" }, ..., {...} ]
46
45
  #
47
46
  # distibution = list.first
48
47
  #
@@ -56,7 +55,7 @@ module RightAws
56
55
  # :aws_id => "E2REJM3VUN5RSI",
57
56
  # :comment => "Woo-Hoo!",
58
57
  # :origin => "my-bucket.s3.amazonaws.com",
59
- # :last_modified_time => Wed Sep 10 17:00:54 UTC 2008 }
58
+ # :last_modified_time => "2008-09-10T17:00:54.000Z" }
60
59
  #
61
60
  # config = acf.get_distribution_config(distibution[:aws_id]) #=>
62
61
  # {:enabled => true,
@@ -76,7 +75,7 @@ module RightAws
76
75
 
77
76
  include RightAwsBaseInterface
78
77
 
79
- API_VERSION = "2008-06-30"
78
+ API_VERSION = "2010-03-01"
80
79
  DEFAULT_HOST = 'cloudfront.amazonaws.com'
81
80
  DEFAULT_PORT = 443
82
81
  DEFAULT_PROTOCOL = 'https'
@@ -93,22 +92,23 @@ module RightAws
93
92
  # Create a new handle to a CloudFront account. All handles share the same per process or per thread
94
93
  # HTTP connection to CloudFront. Each handle is for a specific account. The params have the
95
94
  # following options:
95
+ # * <tt>:endpoint_url</tt> a fully qualified url to Amazon API endpoint (this overwrites: :server, :port, :service, :protocol). Example: 'https://cloudfront.amazonaws.com'
96
96
  # * <tt>:server</tt>: CloudFront service host, default: DEFAULT_HOST
97
97
  # * <tt>:port</tt>: CloudFront service port, default: DEFAULT_PORT
98
98
  # * <tt>:protocol</tt>: 'http' or 'https', default: DEFAULT_PROTOCOL
99
99
  # * <tt>:multi_thread</tt>: true=HTTP connection per thread, false=per process
100
100
  # * <tt>:logger</tt>: for log messages, default: RAILS_DEFAULT_LOGGER else STDOUT
101
- # * <tt>:cache</tt>: true/false: caching for list_distributions method, default: false.
102
101
  #
103
102
  # acf = RightAws::AcfInterface.new('1E3GDYEOGFJPIT7XXXXXX','hgTHt68JY07JKUY08ftHYtERkjgtfERn57XXXXXX',
104
- # {:multi_thread => true, :logger => Logger.new('/tmp/x.log')}) #=> #<RightAws::AcfInterface::0xb7b3c30c>
103
+ # {:logger => Logger.new('/tmp/x.log')}) #=> #<RightAws::AcfInterface::0xb7b3c30c>
105
104
  #
106
105
  def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
107
- init({ :name => 'ACF',
108
- :default_host => ENV['ACF_URL'] ? URI.parse(ENV['ACF_URL']).host : DEFAULT_HOST,
109
- :default_port => ENV['ACF_URL'] ? URI.parse(ENV['ACF_URL']).port : DEFAULT_PORT,
110
- :default_service => ENV['ACF_URL'] ? URI.parse(ENV['ACF_URL']).path : DEFAULT_PATH,
111
- :default_protocol => ENV['ACF_URL'] ? URI.parse(ENV['ACF_URL']).scheme : DEFAULT_PROTOCOL },
106
+ init({ :name => 'ACF',
107
+ :default_host => ENV['ACF_URL'] ? URI.parse(ENV['ACF_URL']).host : DEFAULT_HOST,
108
+ :default_port => ENV['ACF_URL'] ? URI.parse(ENV['ACF_URL']).port : DEFAULT_PORT,
109
+ :default_service => ENV['ACF_URL'] ? URI.parse(ENV['ACF_URL']).path : DEFAULT_PATH,
110
+ :default_protocol => ENV['ACF_URL'] ? URI.parse(ENV['ACF_URL']).scheme : DEFAULT_PROTOCOL,
111
+ :default_api_version => ENV['ACF_API_VERSION'] || API_VERSION },
112
112
  aws_access_key_id || ENV['AWS_ACCESS_KEY_ID'],
113
113
  aws_secret_access_key || ENV['AWS_SECRET_ACCESS_KEY'],
114
114
  params)
@@ -119,14 +119,20 @@ module RightAws
119
119
  #-----------------------------------------------------------------
120
120
 
121
121
  # Generates request hash for REST API.
122
- def generate_request(method, path, body=nil, headers={}) # :nodoc:
122
+ def generate_request(method, path, params={}, body=nil, headers={}) # :nodoc:
123
+ # Params
124
+ params.delete_if{ |key, val| val.blank? }
125
+ unless params.blank?
126
+ path += "?" + params.to_a.collect{ |key,val| "#{AwsUtils::amz_escape(key)}=#{AwsUtils::amz_escape(val.to_s)}" }.join("&")
127
+ end
128
+ # Headers
123
129
  headers['content-type'] ||= 'text/xml' if body
124
130
  headers['date'] = Time.now.httpdate
125
131
  # Auth
126
132
  signature = AwsUtils::sign(@aws_secret_access_key, headers['date'])
127
133
  headers['Authorization'] = "AWS #{@aws_access_key_id}:#{signature}"
128
134
  # Request
129
- path = "#{@params[:default_service]}/#{API_VERSION}/#{path}"
135
+ path = "#{@params[:service]}#{@params[:api_version]}/#{path}"
130
136
  request = "Net::HTTP::#{method.capitalize}".constantize.new(path)
131
137
  request.body = body if body
132
138
  # Set request headers
@@ -141,9 +147,7 @@ module RightAws
141
147
  # Sends request to Amazon and parses the response.
142
148
  # Raises AwsError if any banana happened.
143
149
  def request_info(request, parser, &block) # :nodoc:
144
- thread = @params[:multi_thread] ? Thread.current : Thread.main
145
- thread[:acf_connection] ||= Rightscale::HttpConnection.new(:exception => RightAws::AwsError, :logger => @logger)
146
- request_info_impl(thread[:acf_connection], @@bench, request, parser, &block)
150
+ request_info_impl(:acf_connection, @@bench, request, parser, &block)
147
151
  end
148
152
 
149
153
  #-----------------------------------------------------------------
@@ -158,10 +162,6 @@ module RightAws
158
162
  REXML::Text::unnormalize(text)
159
163
  end
160
164
 
161
- def xmlns # :nodoc:
162
- %Q{"http://#{@params[:server]}/doc/#{API_VERSION}/"}
163
- end
164
-
165
165
  def generate_call_reference # :nodoc:
166
166
  result = Time.now.strftime('%Y%m%d%H%M%S')
167
167
  10.times{ result << rand(10).to_s }
@@ -174,11 +174,62 @@ module RightAws
174
174
  hash
175
175
  end
176
176
 
177
+ def distribution_config_to_xml(config, xml_wrapper='DistributionConfig') # :nodoc:
178
+ cnames = ''
179
+ logging = ''
180
+ origin_access_identity = ''
181
+ trusted_signers = ''
182
+ # CNAMES
183
+ unless config[:cnames].blank?
184
+ Array(config[:cnames]).each { |cname| cnames += " <CNAME>#{cname}</CNAME>\n" }
185
+ end
186
+ # Logging
187
+ unless config[:logging].blank?
188
+ logging = " <Logging>\n" +
189
+ " <Bucket>#{config[:logging][:bucket]}</Bucket>\n" +
190
+ " <Prefix>#{config[:logging][:prefix]}</Prefix>\n" +
191
+ " </Logging>\n"
192
+ end
193
+ # Origin Access Identity
194
+ unless config[:origin_access_identity].blank?
195
+ origin_access_identity = config[:origin_access_identity]
196
+ unless origin_access_identity[%r{^origin-access-identity}]
197
+ origin_access_identity = "origin-access-identity/cloudfront/#{origin_access_identity}"
198
+ end
199
+ origin_access_identity = " <OriginAccessIdentity>#{origin_access_identity}</OriginAccessIdentity>\n"
200
+ end
201
+ # Trusted Signers
202
+ unless config[:trusted_signers].blank?
203
+ trusted_signers = " <TrustedSigners>\n"
204
+ Array(config[:trusted_signers]).each do |trusted_signer|
205
+ trusted_signers += if trusted_signer.to_s[/self/i]
206
+ " <Self/>\n"
207
+ else
208
+ " <AwsAccountNumber>#{trusted_signer}</AwsAccountNumber>\n"
209
+ end
210
+ end
211
+ trusted_signers += " </TrustedSigners>\n"
212
+ end
213
+
214
+ # XML
215
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
216
+ "<#{xml_wrapper} xmlns=\"http://#{@params[:server]}/doc/#{API_VERSION}/\">\n" +
217
+ " <Origin>#{config[:origin]}</Origin>\n" +
218
+ " <CallerReference>#{config[:caller_reference]}</CallerReference>\n" +
219
+ " <Comment>#{AcfInterface::escape(config[:comment].to_s)}</Comment>\n" +
220
+ " <Enabled>#{config[:enabled]}</Enabled>\n" +
221
+ cnames +
222
+ logging +
223
+ origin_access_identity +
224
+ trusted_signers +
225
+ "</#{xml_wrapper}>"
226
+ end
227
+
177
228
  #-----------------------------------------------------------------
178
229
  # API Calls:
179
230
  #-----------------------------------------------------------------
180
231
 
181
- # List distributions.
232
+ # List all distributions.
182
233
  # Returns an array of distributions or RightAws::AwsError exception.
183
234
  #
184
235
  # acf.list_distributions #=>
@@ -191,14 +242,62 @@ module RightAws
191
242
  # :last_modified_time => Wed Sep 10 17:00:04 UTC 2008 }, ..., {...} ]
192
243
  #
193
244
  def list_distributions
194
- request_hash = generate_request('GET', 'distribution')
195
- request_cache_or_info :list_distributions, request_hash, AcfDistributionListParser, @@bench
245
+ result = []
246
+ incrementally_list_distributions do |response|
247
+ result += response[:distributions]
248
+ true
249
+ end
250
+ result
251
+ end
252
+
253
+ # Incrementally list distributions.
254
+ #
255
+ # Optional params: +:marker+ and +:max_items+.
256
+ #
257
+ # # get first distribution
258
+ # incrementally_list_distributions(:max_items => 1) #=>
259
+ # {:distributions=>
260
+ # [{:status=>"Deployed",
261
+ # :aws_id=>"E2Q0AOOMFNPSYL",
262
+ # :origin=>"my-bucket.s3.amazonaws.com",
263
+ # :domain_name=>"d1s5gmdtmafnre.6hops.net",
264
+ # :comment=>"ONE LINE OF COMMENT",
265
+ # :last_modified_time=>"2008-10-22T19:31:23.000Z",
266
+ # :enabled=>true,
267
+ # :cnames=>[]}],
268
+ # :is_truncated=>true,
269
+ # :max_items=>1,
270
+ # :marker=>"",
271
+ # :next_marker=>"E2Q0AOOMFNPSYL"}
272
+ #
273
+ # # get max 100 distributions (the list will be restricted by a default MaxItems value ==100 )
274
+ # incrementally_list_distributions
275
+ #
276
+ # # list distributions by 10
277
+ # incrementally_list_distributions(:max_items => 10) do |response|
278
+ # puts response.inspect # a list of 10 distributions
279
+ # true # return false if the listing should be broken otherwise use true
280
+ # end
281
+ #
282
+ def incrementally_list_distributions(params={}, &block)
283
+ opts = {}
284
+ opts['MaxItems'] = params[:max_items] if params[:max_items]
285
+ opts['Marker'] = params[:marker] if params[:marker]
286
+ last_response = nil
287
+ loop do
288
+ link = generate_request('GET', 'distribution', opts)
289
+ last_response = request_info(link, AcfDistributionListParser.new(:logger => @logger))
290
+ opts['Marker'] = last_response[:next_marker]
291
+ break unless block && block.call(last_response) && !last_response[:next_marker].blank?
292
+ end
293
+ last_response
196
294
  end
197
295
 
198
296
  # Create a new distribution.
199
297
  # Returns the just created distribution or RightAws::AwsError exception.
200
298
  #
201
- # acf.create_distribution('bucket-for-k-dzreyev.s3.amazonaws.com', 'Woo-Hoo!', true, ['web1.my-awesome-site.net'] ) #=>
299
+ # acf.create_distribution('my-bucket.s3.amazonaws.com', 'Woo-Hoo!', true, ['web1.my-awesome-site.net'], nil,
300
+ # { :prefix=>"log/", :bucket=>"my-logs.s3.amazonaws.com" } ) #=>
202
301
  # {:comment => "Woo-Hoo!",
203
302
  # :enabled => true,
204
303
  # :location => "https://cloudfront.amazonaws.com/2008-06-30/distribution/E2REJM3VUN5RSI",
@@ -206,30 +305,26 @@ module RightAws
206
305
  # :aws_id => "E2REJM3VUN5RSI",
207
306
  # :domain_name => "d3dxv71tbbt6cd.6hops.net",
208
307
  # :origin => "my-bucket.s3.amazonaws.com",
209
- # :cnames => ["web1.my-awesome-site.net"]
210
- # :last_modified_time => Wed Sep 10 17:00:54 UTC 2008,
308
+ # :cnames => ["web1.my-awesome-site.net"],
309
+ # :logging => { :prefix => "log/",
310
+ # :bucket => "my-logs.s3.amazonaws.com"},
311
+ # :last_modified_time => "2008-10-22T19:31:23.000Z",
211
312
  # :caller_reference => "200809102100536497863003"}
212
313
  #
213
- def create_distribution(origin, comment='', enabled=true, cnames=[], caller_reference=nil)
214
- # join CNAMES
215
- cnames_str = ''
216
- unless cnames.blank?
217
- cnames.to_a.each { |cname| cnames_str += "\n <CNAME>#{cname}</CNAME>" }
218
- end
219
- # reference
220
- caller_reference ||= generate_call_reference
221
- body = <<-EOXML
222
- <?xml version="1.0" encoding="UTF-8"?>
223
- <DistributionConfig xmlns=#{xmlns}>
224
- <Origin>#{origin}</Origin>
225
- <CallerReference>#{caller_reference}</CallerReference>
226
- #{cnames_str.lstrip}
227
- <Comment>#{AcfInterface::escape(comment.to_s)}</Comment>
228
- <Enabled>#{enabled}</Enabled>
229
- </DistributionConfig>
230
- EOXML
231
- request_hash = generate_request('POST', 'distribution', body.strip)
232
- merge_headers(request_info(request_hash, AcfDistributionParser.new))
314
+ def create_distribution(origin, comment='', enabled=true, cnames=[], caller_reference=nil, logging={})
315
+ config = { :origin => origin,
316
+ :comment => comment,
317
+ :enabled => enabled,
318
+ :cnames => Array(cnames),
319
+ :caller_reference => caller_reference }
320
+ config[:logging] = logging unless logging.blank?
321
+ create_distribution_by_config(config)
322
+ end
323
+
324
+ def create_distribution_by_config(config)
325
+ config[:caller_reference] ||= generate_call_reference
326
+ link = generate_request('POST', 'distribution', {}, distribution_config_to_xml(config))
327
+ merge_headers(request_info(link, AcfDistributionListParser.new(:logger => @logger))[:distributions].first)
233
328
  end
234
329
 
235
330
  # Get a distribution's information.
@@ -245,11 +340,30 @@ module RightAws
245
340
  # :aws_id => "E2REJM3VUN5RSI",
246
341
  # :comment => "Woo-Hoo!",
247
342
  # :origin => "my-bucket.s3.amazonaws.com",
248
- # :last_modified_time => Wed Sep 10 17:00:54 UTC 2008 }
343
+ # :last_modified_time => "2008-09-10T17:00:54.000Z" }
344
+ #
345
+ # acf.get_distribution('E2FNSBHNVVF11E') #=>
346
+ # {:e_tag=>"E1Q2DJEPTQOLJD",
347
+ # :status=>"InProgress",
348
+ # :last_modified_time=>"2010-04-17T17:24:25.000Z",
349
+ # :cnames=>["web1.my-awesome-site.net", "web2.my-awesome-site.net"],
350
+ # :aws_id=>"E2FNSBHNVVF11E",
351
+ # :logging=>{:prefix=>"xlog/", :bucket=>"my-bucket.s3.amazonaws.com"},
352
+ # :enabled=>true,
353
+ # :active_trusted_signers=>
354
+ # [{:aws_account_number=>"120288270000",
355
+ # :key_pair_ids=>["APKAJTD5OHNDX0000000", "APKAIK74BJWCL0000000"]},
356
+ # {:aws_account_number=>"self"},
357
+ # {:aws_account_number=>"648772220000"}],
358
+ # :caller_reference=>"201004171154450740700072",
359
+ # :domain_name=>"d1f6lpevremt5m.cloudfront.net",
360
+ # :origin_access_identity=>"origin-access-identity/cloudfront/E3JPJZ80ZBX24G",
361
+ # :trusted_signers=>["self", "648772220000", "120288270000"],
362
+ # :origin=>"my-bucket.s3.amazonaws.com"}
249
363
  #
250
364
  def get_distribution(aws_id)
251
- request_hash = generate_request('GET', "distribution/#{aws_id}")
252
- merge_headers(request_info(request_hash, AcfDistributionParser.new))
365
+ link = generate_request('GET', "distribution/#{aws_id}")
366
+ merge_headers(request_info(link, AcfDistributionListParser.new(:logger => @logger))[:distributions].first)
253
367
  end
254
368
 
255
369
  # Get a distribution's configuration.
@@ -263,9 +377,18 @@ module RightAws
263
377
  # :comment => "Woo-Hoo!",
264
378
  # :origin => "my-bucket.s3.amazonaws.com"}
265
379
  #
380
+ # acf.get_distribution_config('E2FNSBHNVVF11E') #=>
381
+ # {:e_tag=>"E1Q2DJEPTQOLJD",
382
+ # :logging=>{:prefix=>"xlog/", :bucket=>"my-bucket.s3.amazonaws.com"},
383
+ # :enabled=>true,
384
+ # :caller_reference=>"201004171154450740700072",
385
+ # :origin_access_identity=>"origin-access-identity/cloudfront/E3JPJZ80ZBX24G",
386
+ # :trusted_signers=>["self", "648772220000", "120288270000"],
387
+ # :origin=>"my-bucket.s3.amazonaws.com"}
388
+ #
266
389
  def get_distribution_config(aws_id)
267
- request_hash = generate_request('GET', "distribution/#{aws_id}/config")
268
- merge_headers(request_info(request_hash, AcfDistributionConfigParser.new))
390
+ link = generate_request('GET', "distribution/#{aws_id}/config")
391
+ merge_headers(request_info(link, AcfDistributionListParser.new(:logger => @logger))[:distributions].first)
269
392
  end
270
393
 
271
394
  # Set a distribution's configuration
@@ -279,30 +402,21 @@ module RightAws
279
402
  # :cnames => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
280
403
  # :comment => "Woo-Hoo!",
281
404
  # :origin => "my-bucket.s3.amazonaws.com"}
282
- # config[:comment] = 'Olah-lah!'
283
- # config[:enabled] = false
405
+ #
406
+ # config[:comment] = 'Olah-lah!'
407
+ # config[:enabled] = false
408
+ # config[:origin_access_identity] = "origin-access-identity/cloudfront/E3JPJZ80ZBX24G"
409
+ # # or just
410
+ # # config[:origin_access_identity] = "E3JPJZ80ZBX24G"
411
+ # config[:trusted_signers] = ['self', '648772220000', '120288270000']
412
+ # config[:logging] = { :bucket => 'my-bucket.s3.amazonaws.com', :prefix => 'xlog/' }
413
+ #
284
414
  # acf.set_distribution_config('E2REJM3VUN5RSI', config) #=> true
285
415
  #
286
416
  def set_distribution_config(aws_id, config)
287
- # join CNAMES
288
- cnames_str = ''
289
- unless config[:cnames].blank?
290
- config[:cnames].to_a.each { |cname| cnames_str += "\n <CNAME>#{cname}</CNAME>" }
291
- end
292
- # format request's XML body
293
- body = <<-EOXML
294
- <?xml version="1.0" encoding="UTF-8"?>
295
- <DistributionConfig xmlns=#{xmlns}>
296
- <Origin>#{config[:origin]}</Origin>
297
- <CallerReference>#{config[:caller_reference]}</CallerReference>
298
- #{cnames_str.lstrip}
299
- <Comment>#{AcfInterface::escape(config[:comment].to_s)}</Comment>
300
- <Enabled>#{config[:enabled]}</Enabled>
301
- </DistributionConfig>
302
- EOXML
303
- request_hash = generate_request('PUT', "distribution/#{aws_id}/config", body.strip,
304
- 'If-Match' => config[:e_tag])
305
- request_info(request_hash, RightHttp2xxParser.new)
417
+ link = generate_request('PUT', "distribution/#{aws_id}/config", {}, distribution_config_to_xml(config),
418
+ 'If-Match' => config[:e_tag])
419
+ request_info(link, RightHttp2xxParser.new(:logger => @logger))
306
420
  end
307
421
 
308
422
  # Delete a distribution. The enabled distribution cannot be deleted.
@@ -311,9 +425,9 @@ module RightAws
311
425
  # acf.delete_distribution('E2REJM3VUN5RSI', 'E39OHHU1ON65SI') #=> true
312
426
  #
313
427
  def delete_distribution(aws_id, e_tag)
314
- request_hash = generate_request('DELETE', "distribution/#{aws_id}", nil,
315
- 'If-Match' => e_tag)
316
- request_info(request_hash, RightHttp2xxParser.new)
428
+ link = generate_request('DELETE', "distribution/#{aws_id}", {}, nil,
429
+ 'If-Match' => e_tag)
430
+ request_info(link, RightHttp2xxParser.new(:logger => @logger))
317
431
  end
318
432
 
319
433
  #-----------------------------------------------------------------
@@ -322,58 +436,50 @@ module RightAws
322
436
 
323
437
  class AcfDistributionListParser < RightAWSParser # :nodoc:
324
438
  def reset
325
- @result = []
439
+ @result = { :distributions => [] }
326
440
  end
327
441
  def tagstart(name, attributes)
328
- @distribution = { :cnames => [] } if name == 'DistributionSummary'
329
- end
330
- def tagend(name)
331
- case name
332
- when 'Id' then @distribution[:aws_id] = @text
333
- when 'Status' then @distribution[:status] = @text
334
- when 'LastModifiedTime' then @distribution[:last_modified_time] = Time.parse(@text)
335
- when 'DomainName' then @distribution[:domain_name] = @text
336
- when 'Origin' then @distribution[:origin] = @text
337
- when 'Comment' then @distribution[:comment] = AcfInterface::unescape(@text)
338
- when 'CNAME' then @distribution[:cnames] << @text
339
- when 'DistributionSummary' then @result << @distribution
442
+ case full_tag_name
443
+ when %r{/Signer$}
444
+ @active_signer = {}
445
+ when %r{(Streaming)?DistributionSummary$},
446
+ %r{^(Streaming)?Distribution$},
447
+ %r{^(Streaming)?DistributionConfig$}
448
+ @distribution = { }
340
449
  end
341
450
  end
342
- end
343
-
344
- class AcfDistributionParser < RightAWSParser # :nodoc:
345
- def reset
346
- @result = { :cnames => [] }
347
- end
348
451
  def tagend(name)
349
452
  case name
350
- when 'Id' then @result[:aws_id] = @text
351
- when 'Status' then @result[:status] = @text
352
- when 'LastModifiedTime' then @result[:last_modified_time] = Time.parse(@text)
353
- when 'DomainName' then @result[:domain_name] = @text
354
- when 'Origin' then @result[:origin] = @text
355
- when 'CallerReference' then @result[:caller_reference] = @text
356
- when 'Comment' then @result[:comment] = AcfInterface::unescape(@text)
357
- when 'Enabled' then @result[:enabled] = @text == 'true' ? true : false
358
- when 'CNAME' then @result[:cnames] << @text
453
+ when 'Marker' then @result[:marker] = @text
454
+ when 'NextMarker' then @result[:next_marker] = @text
455
+ when 'MaxItems' then @result[:max_items] = @text.to_i
456
+ when 'IsTruncated' then @result[:is_truncated] = (@text == 'true')
457
+ when 'Id' then @distribution[:aws_id] = @text
458
+ when 'Status' then @distribution[:status] = @text
459
+ when 'LastModifiedTime' then @distribution[:last_modified_time] = @text
460
+ when 'DomainName' then @distribution[:domain_name] = @text
461
+ when 'Origin' then @distribution[:origin] = @text
462
+ when 'Comment' then @distribution[:comment] = AcfInterface::unescape(@text)
463
+ when 'CallerReference' then @distribution[:caller_reference] = @text
464
+ when 'CNAME' then (@distribution[:cnames] ||= []) << @text
465
+ when 'Enabled' then @distribution[:enabled] = (@text == 'true')
466
+ when 'Bucket' then (@distribution[:logging] ||= {})[:bucket] = @text
467
+ when 'Prefix' then (@distribution[:logging] ||= {})[:prefix] = @text
468
+ when 'OriginAccessIdentity' then @distribution[:origin_access_identity] = @text
359
469
  end
360
- end
361
- end
362
-
363
- class AcfDistributionConfigParser < RightAWSParser # :nodoc:
364
- def reset
365
- @result = { :cnames => [] }
366
- end
367
- def tagend(name)
368
- case name
369
- when 'Origin' then @result[:origin] = @text
370
- when 'CallerReference' then @result[:caller_reference] = @text
371
- when 'Comment' then @result[:comment] = AcfInterface::unescape(@text)
372
- when 'Enabled' then @result[:enabled] = @text == 'true' ? true : false
373
- when 'CNAME' then @result[:cnames] << @text
470
+ case full_tag_name
471
+ when %r{/TrustedSigners/Self$} then (@distribution[:trusted_signers] ||= []) << 'self'
472
+ when %r{/TrustedSigners/AwsAccountNumber$} then (@distribution[:trusted_signers] ||= []) << @text
473
+ when %r{/Signer/Self$} then @active_signer[:aws_account_number] = 'self'
474
+ when %r{/Signer/AwsAccountNumber$} then @active_signer[:aws_account_number] = @text
475
+ when %r{/Signer/KeyPairId$} then (@active_signer[:key_pair_ids] ||= []) << @text
476
+ when %r{/Signer$} then (@distribution[:active_trusted_signers] ||= []) << @active_signer
477
+ when %r{(Streaming)?DistributionSummary$},
478
+ %r{^(Streaming)?Distribution$},
479
+ %r{^(Streaming)?DistributionConfig$}
480
+ @result[:distributions] << @distribution
374
481
  end
375
482
  end
376
483
  end
377
-
378
484
  end
379
485
  end