revans_right_aws 2.0.1

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 (52) hide show
  1. data/.gemtest +0 -0
  2. data/History.txt +284 -0
  3. data/Manifest.txt +50 -0
  4. data/README.txt +167 -0
  5. data/Rakefile +110 -0
  6. data/lib/acf/right_acf_interface.rb +485 -0
  7. data/lib/acf/right_acf_origin_access_identities.rb +230 -0
  8. data/lib/acf/right_acf_streaming_interface.rb +236 -0
  9. data/lib/acw/right_acw_interface.rb +249 -0
  10. data/lib/as/right_as_interface.rb +699 -0
  11. data/lib/awsbase/benchmark_fix.rb +39 -0
  12. data/lib/awsbase/right_awsbase.rb +978 -0
  13. data/lib/awsbase/support.rb +115 -0
  14. data/lib/ec2/right_ec2.rb +395 -0
  15. data/lib/ec2/right_ec2_ebs.rb +452 -0
  16. data/lib/ec2/right_ec2_images.rb +373 -0
  17. data/lib/ec2/right_ec2_instances.rb +755 -0
  18. data/lib/ec2/right_ec2_monitoring.rb +70 -0
  19. data/lib/ec2/right_ec2_reserved_instances.rb +170 -0
  20. data/lib/ec2/right_ec2_security_groups.rb +277 -0
  21. data/lib/ec2/right_ec2_spot_instances.rb +399 -0
  22. data/lib/ec2/right_ec2_vpc.rb +571 -0
  23. data/lib/elb/right_elb_interface.rb +496 -0
  24. data/lib/rds/right_rds_interface.rb +998 -0
  25. data/lib/right_aws.rb +83 -0
  26. data/lib/s3/right_s3.rb +1126 -0
  27. data/lib/s3/right_s3_interface.rb +1199 -0
  28. data/lib/sdb/active_sdb.rb +1122 -0
  29. data/lib/sdb/right_sdb_interface.rb +721 -0
  30. data/lib/sqs/right_sqs.rb +388 -0
  31. data/lib/sqs/right_sqs_gen2.rb +343 -0
  32. data/lib/sqs/right_sqs_gen2_interface.rb +524 -0
  33. data/lib/sqs/right_sqs_interface.rb +594 -0
  34. data/test/acf/test_helper.rb +2 -0
  35. data/test/acf/test_right_acf.rb +138 -0
  36. data/test/ec2/test_helper.rb +2 -0
  37. data/test/ec2/test_right_ec2.rb +108 -0
  38. data/test/http_connection.rb +87 -0
  39. data/test/rds/test_helper.rb +2 -0
  40. data/test/rds/test_right_rds.rb +120 -0
  41. data/test/s3/test_helper.rb +2 -0
  42. data/test/s3/test_right_s3.rb +421 -0
  43. data/test/s3/test_right_s3_stubbed.rb +97 -0
  44. data/test/sdb/test_active_sdb.rb +357 -0
  45. data/test/sdb/test_helper.rb +3 -0
  46. data/test/sdb/test_right_sdb.rb +253 -0
  47. data/test/sqs/test_helper.rb +2 -0
  48. data/test/sqs/test_right_sqs.rb +291 -0
  49. data/test/sqs/test_right_sqs_gen2.rb +264 -0
  50. data/test/test_credentials.rb +37 -0
  51. data/test/ts_right_aws.rb +14 -0
  52. metadata +169 -0
@@ -0,0 +1,110 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require "rake/testtask"
6
+ require 'rcov/rcovtask'
7
+ $: << File.dirname(__FILE__)
8
+ require 'lib/right_aws.rb'
9
+
10
+ testglobs = ["test/ts_right_aws.rb"]
11
+
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
15
+ # these gems to run tests, etc.
16
+ class Hoe
17
+ def extra_deps
18
+ @extra_deps.reject do |x|
19
+ Array(x).first == 'hoe'
20
+ end
21
+ end
22
+ end
23
+
24
+ Hoe.new('revans_right_aws', RightAws::VERSION::STRING) do |p|
25
+ p.rubyforge_name = 'revans_rightaws'
26
+ p.author = 'RightScale, Inc.'
27
+ p.email = 'support@rightscale.com'
28
+ p.summary = 'Interface classes for the Amazon EC2, SQS, and S3 Web Services'
29
+ p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
30
+ p.url = p.paragraphs_of('README.txt', 0).first.split(/\n/)[1..-1]
31
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
32
+ p.remote_rdoc_dir = "/right_aws_gem_doc"
33
+ p.extra_deps = [['right_http_connection','>= 1.2.1']]
34
+ p.test_globs = testglobs
35
+ end
36
+
37
+ desc "Analyze code coverage of the unit tests."
38
+ Rcov::RcovTask.new do |t|
39
+ t.test_files = FileList[testglobs]
40
+ #t.verbose = true # uncomment to see the executed command
41
+ end
42
+
43
+ desc "Test just the SQS interface"
44
+ task :testsqs do
45
+ require 'test/test_credentials'
46
+ require 'test/http_connection'
47
+ TestCredentials.get_credentials
48
+ require 'test/sqs/test_right_sqs.rb'
49
+ end
50
+
51
+ desc "Test just the second generation SQS interface"
52
+ task :testsqs2 do
53
+ require 'test/test_credentials'
54
+ require 'test/http_connection'
55
+ TestCredentials.get_credentials
56
+ require 'test/sqs/test_right_sqs_gen2.rb'
57
+ end
58
+
59
+ desc "Test just the S3 interface"
60
+ task :tests3 do
61
+ require 'test/test_credentials'
62
+ require 'test/http_connection'
63
+ TestCredentials.get_credentials
64
+ require 'test/s3/test_right_s3.rb'
65
+ end
66
+
67
+ desc "Test just the S3 interface using local stubs"
68
+ task :tests3local do
69
+ require 'test/test_credentials'
70
+ require 'test/http_connection'
71
+ TestCredentials.get_credentials
72
+ require 'test/s3/test_right_s3_stubbed.rb'
73
+ end
74
+
75
+ desc "Test just the EC2 interface"
76
+ task :testec2 do
77
+ require 'test/test_credentials'
78
+ TestCredentials.get_credentials
79
+ require 'test/ec2/test_right_ec2.rb'
80
+ end
81
+
82
+ desc "Test just the SDB interface"
83
+ task :testsdb do
84
+ require 'test/test_credentials'
85
+ TestCredentials.get_credentials
86
+ require 'test/sdb/test_right_sdb.rb'
87
+ end
88
+
89
+ desc "Test active SDB interface"
90
+ task :testactivesdb do
91
+ require 'test/test_credentials'
92
+ TestCredentials.get_credentials
93
+ require 'test/sdb/test_active_sdb.rb'
94
+ end
95
+
96
+ desc "Test CloudFront interface"
97
+ task :testacf do
98
+ require 'test/test_credentials'
99
+ TestCredentials.get_credentials
100
+ require 'test/acf/test_right_acf.rb'
101
+ end
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
+
110
+ # vim: syntax=Ruby
@@ -0,0 +1,485 @@
1
+ #
2
+ # Copyright (c) 2008 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
18
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ #
23
+ module RightAws
24
+
25
+ # = RightAws::AcfInterface -- RightScale Amazon's CloudFront interface
26
+ # The AcfInterface class provides a complete interface to Amazon's
27
+ # CloudFront service.
28
+ #
29
+ # For explanations of the semantics of each call, please refer to
30
+ # Amazon's documentation at
31
+ # http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=211
32
+ #
33
+ # Example:
34
+ #
35
+ # acf = RightAws::AcfInterface.new('1E3GDYEOGFJPIT7XXXXXX','hgTHt68JY07JKUY08ftHYtERkjgtfERn57XXXXXX')
36
+ #
37
+ # list = acf.list_distributions #=>
38
+ # [{:status => "Deployed",
39
+ # :domain_name => "d74zzrxmpmygb.6hops.net",
40
+ # :aws_id => "E4U91HCJHGXVC",
41
+ # :origin => "my-bucket.s3.amazonaws.com",
42
+ # :cnames => ["x1.my-awesome-site.net", "x1.my-awesome-site.net"]
43
+ # :comment => "My comments",
44
+ # :last_modified_time => "2008-09-10T17:00:04.000Z" }, ..., {...} ]
45
+ #
46
+ # distibution = list.first
47
+ #
48
+ # info = acf.get_distribution(distibution[:aws_id]) #=>
49
+ # {:enabled => true,
50
+ # :caller_reference => "200809102100536497863003",
51
+ # :e_tag => "E39OHHU1ON65SI",
52
+ # :status => "Deployed",
53
+ # :domain_name => "d3dxv71tbbt6cd.6hops.net",
54
+ # :cnames => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
55
+ # :aws_id => "E2REJM3VUN5RSI",
56
+ # :comment => "Woo-Hoo!",
57
+ # :origin => "my-bucket.s3.amazonaws.com",
58
+ # :last_modified_time => "2008-09-10T17:00:54.000Z" }
59
+ #
60
+ # config = acf.get_distribution_config(distibution[:aws_id]) #=>
61
+ # {:enabled => true,
62
+ # :caller_reference => "200809102100536497863003",
63
+ # :e_tag => "E39OHHU1ON65SI",
64
+ # :cnames => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
65
+ # :comment => "Woo-Hoo!",
66
+ # :origin => "my-bucket.s3.amazonaws.com"}
67
+ #
68
+ # config[:comment] = 'Olah-lah!'
69
+ # config[:enabled] = false
70
+ # config[:cnames] << "web3.my-awesome-site.net"
71
+ #
72
+ # acf.set_distribution_config(distibution[:aws_id], config) #=> true
73
+ #
74
+ class AcfInterface < RightAwsBase
75
+
76
+ include RightAwsBaseInterface
77
+
78
+ API_VERSION = "2010-03-01"
79
+ DEFAULT_HOST = 'cloudfront.amazonaws.com'
80
+ DEFAULT_PORT = 443
81
+ DEFAULT_PROTOCOL = 'https'
82
+ DEFAULT_PATH = '/'
83
+
84
+ @@bench = AwsBenchmarkingBlock.new
85
+ def self.bench_xml
86
+ @@bench.xml
87
+ end
88
+ def self.bench_service
89
+ @@bench.service
90
+ end
91
+
92
+ # Create a new handle to a CloudFront account. All handles share the same per process or per thread
93
+ # HTTP connection to CloudFront. Each handle is for a specific account. The params have the
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
+ # * <tt>:server</tt>: CloudFront service host, default: DEFAULT_HOST
97
+ # * <tt>:port</tt>: CloudFront service port, default: DEFAULT_PORT
98
+ # * <tt>:protocol</tt>: 'http' or 'https', default: DEFAULT_PROTOCOL
99
+ # * <tt>:multi_thread</tt>: true=HTTP connection per thread, false=per process
100
+ # * <tt>:logger</tt>: for log messages, default: RAILS_DEFAULT_LOGGER else STDOUT
101
+ #
102
+ # acf = RightAws::AcfInterface.new('1E3GDYEOGFJPIT7XXXXXX','hgTHt68JY07JKUY08ftHYtERkjgtfERn57XXXXXX',
103
+ # {:logger => Logger.new('/tmp/x.log')}) #=> #<RightAws::AcfInterface::0xb7b3c30c>
104
+ #
105
+ def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
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
+ aws_access_key_id || ENV['AWS_ACCESS_KEY_ID'],
113
+ aws_secret_access_key || ENV['AWS_SECRET_ACCESS_KEY'],
114
+ params)
115
+ end
116
+
117
+ #-----------------------------------------------------------------
118
+ # Requests
119
+ #-----------------------------------------------------------------
120
+
121
+ # Generates request hash for REST API.
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
129
+ headers['content-type'] ||= 'text/xml' if body
130
+ headers['date'] = Time.now.httpdate
131
+ # Auth
132
+ signature = AwsUtils::sign(@aws_secret_access_key, headers['date'])
133
+ headers['Authorization'] = "AWS #{@aws_access_key_id}:#{signature}"
134
+ # Request
135
+ path = "#{@params[:service]}#{@params[:api_version]}/#{path}"
136
+ request = "Net::HTTP::#{method.capitalize}".constantize.new(path)
137
+ request.body = body if body
138
+ # Set request headers
139
+ headers.each { |key, value| request[key.to_s] = value }
140
+ # prepare output hash
141
+ { :request => request,
142
+ :server => @params[:server],
143
+ :port => @params[:port],
144
+ :protocol => @params[:protocol] }
145
+ end
146
+
147
+ # Sends request to Amazon and parses the response.
148
+ # Raises AwsError if any banana happened.
149
+ def request_info(request, parser, &block) # :nodoc:
150
+ request_info_impl(:acf_connection, @@bench, request, parser, &block)
151
+ end
152
+
153
+ #-----------------------------------------------------------------
154
+ # Helpers:
155
+ #-----------------------------------------------------------------
156
+
157
+ def self.escape(text) # :nodoc:
158
+ REXML::Text::normalize(text)
159
+ end
160
+
161
+ def self.unescape(text) # :nodoc:
162
+ REXML::Text::unnormalize(text)
163
+ end
164
+
165
+ def generate_call_reference # :nodoc:
166
+ result = Time.now.strftime('%Y%m%d%H%M%S')
167
+ 10.times{ result << rand(10).to_s }
168
+ result
169
+ end
170
+
171
+ def merge_headers(hash) # :nodoc:
172
+ hash[:location] = @last_response['Location'] if @last_response['Location']
173
+ hash[:e_tag] = @last_response['ETag'] if @last_response['ETag']
174
+ hash
175
+ end
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
+
228
+ #-----------------------------------------------------------------
229
+ # API Calls:
230
+ #-----------------------------------------------------------------
231
+
232
+ # List all distributions.
233
+ # Returns an array of distributions or RightAws::AwsError exception.
234
+ #
235
+ # acf.list_distributions #=>
236
+ # [{:status => "Deployed",
237
+ # :domain_name => "d74zzrxmpmygb.6hops.net",
238
+ # :aws_id => "E4U91HCJHGXVC",
239
+ # :cnames => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
240
+ # :origin => "my-bucket.s3.amazonaws.com",
241
+ # :comment => "My comments",
242
+ # :last_modified_time => Wed Sep 10 17:00:04 UTC 2008 }, ..., {...} ]
243
+ #
244
+ def list_distributions
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
294
+ end
295
+
296
+ # Create a new distribution.
297
+ # Returns the just created distribution or RightAws::AwsError exception.
298
+ #
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" } ) #=>
301
+ # {:comment => "Woo-Hoo!",
302
+ # :enabled => true,
303
+ # :location => "https://cloudfront.amazonaws.com/2008-06-30/distribution/E2REJM3VUN5RSI",
304
+ # :status => "InProgress",
305
+ # :aws_id => "E2REJM3VUN5RSI",
306
+ # :domain_name => "d3dxv71tbbt6cd.6hops.net",
307
+ # :origin => "my-bucket.s3.amazonaws.com",
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",
312
+ # :caller_reference => "200809102100536497863003"}
313
+ #
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)
328
+ end
329
+
330
+ # Get a distribution's information.
331
+ # Returns a distribution's information or RightAws::AwsError exception.
332
+ #
333
+ # acf.get_distribution('E2REJM3VUN5RSI') #=>
334
+ # {:enabled => true,
335
+ # :caller_reference => "200809102100536497863003",
336
+ # :e_tag => "E39OHHU1ON65SI",
337
+ # :status => "Deployed",
338
+ # :domain_name => "d3dxv71tbbt6cd.6hops.net",
339
+ # :cnames => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
340
+ # :aws_id => "E2REJM3VUN5RSI",
341
+ # :comment => "Woo-Hoo!",
342
+ # :origin => "my-bucket.s3.amazonaws.com",
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"}
363
+ #
364
+ def get_distribution(aws_id)
365
+ link = generate_request('GET', "distribution/#{aws_id}")
366
+ merge_headers(request_info(link, AcfDistributionListParser.new(:logger => @logger))[:distributions].first)
367
+ end
368
+
369
+ # Get a distribution's configuration.
370
+ # Returns a distribution's configuration or RightAws::AwsError exception.
371
+ #
372
+ # acf.get_distribution_config('E2REJM3VUN5RSI') #=>
373
+ # {:enabled => true,
374
+ # :caller_reference => "200809102100536497863003",
375
+ # :e_tag => "E39OHHU1ON65SI",
376
+ # :cnames => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
377
+ # :comment => "Woo-Hoo!",
378
+ # :origin => "my-bucket.s3.amazonaws.com"}
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
+ #
389
+ def get_distribution_config(aws_id)
390
+ link = generate_request('GET', "distribution/#{aws_id}/config")
391
+ merge_headers(request_info(link, AcfDistributionListParser.new(:logger => @logger))[:distributions].first)
392
+ end
393
+
394
+ # Set a distribution's configuration
395
+ # (the :origin and the :caller_reference cannot be changed).
396
+ # Returns +true+ on success or RightAws::AwsError exception.
397
+ #
398
+ # config = acf.get_distribution_config('E2REJM3VUN5RSI') #=>
399
+ # {:enabled => true,
400
+ # :caller_reference => "200809102100536497863003",
401
+ # :e_tag => "E39OHHU1ON65SI",
402
+ # :cnames => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
403
+ # :comment => "Woo-Hoo!",
404
+ # :origin => "my-bucket.s3.amazonaws.com"}
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
+ #
414
+ # acf.set_distribution_config('E2REJM3VUN5RSI', config) #=> true
415
+ #
416
+ def set_distribution_config(aws_id, config)
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))
420
+ end
421
+
422
+ # Delete a distribution. The enabled distribution cannot be deleted.
423
+ # Returns +true+ on success or RightAws::AwsError exception.
424
+ #
425
+ # acf.delete_distribution('E2REJM3VUN5RSI', 'E39OHHU1ON65SI') #=> true
426
+ #
427
+ def delete_distribution(aws_id, e_tag)
428
+ link = generate_request('DELETE', "distribution/#{aws_id}", {}, nil,
429
+ 'If-Match' => e_tag)
430
+ request_info(link, RightHttp2xxParser.new(:logger => @logger))
431
+ end
432
+
433
+ #-----------------------------------------------------------------
434
+ # PARSERS:
435
+ #-----------------------------------------------------------------
436
+
437
+ class AcfDistributionListParser < RightAWSParser # :nodoc:
438
+ def reset
439
+ @result = { :distributions => [] }
440
+ end
441
+ def tagstart(name, attributes)
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 = { }
449
+ end
450
+ end
451
+ def tagend(name)
452
+ case name
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
469
+ end
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
481
+ end
482
+ end
483
+ end
484
+ end
485
+ end