hackerdude-aws 2.3.25

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,187 @@
1
+ # Appoxy AWS Library
2
+
3
+ A Ruby gem for all Amazon Web Services.
4
+
5
+ Brought to you by: [![Appoxy](http://www.simpledeployr.com/images/global/appoxy-small.png)](http://www.appoxy.com)
6
+
7
+ ## Discussion Group
8
+
9
+ http://groups.google.com/group/ruby-aws
10
+
11
+ ## Issue Tracker
12
+
13
+ http://appoxy.lighthouseapp.com/projects/38441-aws/overview
14
+
15
+ ## Documentation
16
+
17
+ http://rdoc.info/projects/appoxy/aws
18
+
19
+ ## Appoxy Amazon Web Services Ruby Gems
20
+
21
+ Published by Appoxy LLC, under the MIT License. Special thanks to RightScale from which this project is forked.
22
+
23
+ ## INSTALL:
24
+
25
+ THEN (you should have http://gemcutter.org in your sources and it MUST be above rubyforge.org):
26
+
27
+ gem install aws
28
+
29
+
30
+ ## DESCRIPTION:
31
+
32
+ The RightScale AWS gems have been designed to provide a robust, fast, and secure interface to Amazon EC2, EBS, S3, SQS, SDB, and CloudFront.
33
+ These gems have been used in production by RightScale since late 2006 and are being maintained to track enhancements made by Amazon.
34
+ The RightScale AWS gems comprise:
35
+
36
+ - Aws::Ec2 -- interface to Amazon EC2 (Elastic Compute Cloud) and the associated EBS (Elastic Block Store)
37
+ - Aws::S3 and Aws::S3Interface -- interface to Amazon S3 (Simple Storage Service)
38
+ - Aws::Sqs and Aws::SqsInterface -- interface to Amazon SQS (Simple Queue Service)
39
+ - Aws::SdbInterface and Aws::ActiveSdb -- interface to Amazon SDB (SimpleDB)
40
+ - Aws::AcfInterface -- interface to Amazon CloudFront, a content distribution service
41
+ - Aws::ElbInterface -- interface to Amazon Load Balancing service
42
+ - Aws::MonInterface -- interface to Amazon CloudWatch monitoring service
43
+
44
+
45
+ ## FEATURES:
46
+
47
+ - Full programmmatic access to EC2, EBS, S3, SQS, SDB, ELB, and CloudFront.
48
+ - Complete error handling: all operations check for errors and report complete
49
+ error information by raising an AwsError.
50
+ - Persistent HTTP connections with robust network-level retry layer using
51
+ RightHttpConnection). This includes socket timeouts and retries.
52
+ - Robust HTTP-level retry layer. Certain (user-adjustable) HTTP errors returned
53
+ by Amazon's services are classified as temporary errors.
54
+ These errors are automaticallly retried using exponentially increasing intervals.
55
+ The number of retries is user-configurable.
56
+ - Fast REXML-based parsing of responses (as fast as a pure Ruby solution allows).
57
+ - Uses libxml (if available) for faster response parsing.
58
+ - Support for large S3 list operations. Buckets and key subfolders containing
59
+ many (> 1000) keys are listed in entirety. Operations based on list (like
60
+ bucket clear) work on arbitrary numbers of keys.
61
+ - Support for streaming GETs from S3, and streaming PUTs to S3 if the data source is a file.
62
+ - Support for single-threaded usage, multithreaded usage, as well as usage with multiple
63
+ AWS accounts.
64
+ - Support for both first- and second-generation SQS (API versions 2007-05-01
65
+ and 2008-01-01). These versions of SQS are not compatible.
66
+ - Support for signature versions 0, 1 and 2 on all services.
67
+ - Interoperability with any cloud running Eucalyptus (http://eucalyptus.cs.ucsb.edu)
68
+ - Test suite (requires AWS account to do "live" testing).
69
+
70
+ ## THREADING:
71
+
72
+ All AWS interfaces offer three threading options:
73
+ 1. Use a single persistent HTTP connection per process. :single
74
+ 2. Use a persistent HTTP connection per Ruby thread. :per_thread
75
+ 3. Open a new connection for each request. :per_request
76
+
77
+ Either way, it doesn't matter how many (for example) Aws::S3 objects you create,
78
+ they all use the same per-program or per-thread
79
+ connection. The purpose of sharing the connection is to keep a single
80
+ persistent HTTP connection open to avoid paying connection
81
+ overhead on every request. However, if you have multiple concurrent
82
+ threads, you may want or need an HTTP connection per thread to enable
83
+ concurrent requests to AWS. The way this plays out in practice is:
84
+ 1. If you have a non-multithreaded Ruby program, use the non-multithreaded setting.
85
+ 2. If you have a multi-threaded Ruby program, use the multithreaded setting to enable
86
+ concurrent requests to S3 (or SQS, or SDB, or EC2).
87
+ 3. For running under Mongrel/Rails, use the non-multithreaded setting even though
88
+ mongrel is multithreaded. This is because only one Rails handler is invoked at
89
+ time (i.e. it acts like a single-threaded program)
90
+
91
+ Note that due to limitations in the I/O of the Ruby interpreter you
92
+ may not get the degree of parallelism you may expect with the multi-threaded setting.
93
+
94
+ By default, EC2/S3/SQS/SDB/ACF interface instances are created in single-threaded mode. Set
95
+ params[:connection_mode] to :per_thread in the initialization arguments to use
96
+ multithreaded mode.
97
+
98
+ ## GETTING STARTED:
99
+
100
+ * For EC2 read Aws::Ec2 and consult the Amazon EC2 API documentation at
101
+ http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=87
102
+ * For S3 read Aws::S3 and consult the Amazon S3 API documentation at
103
+ http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=48
104
+ * For SQS read Aws::Sqs and consult the Amazon SQS API documentation at
105
+ http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=31
106
+
107
+ Amazon's Migration Guide for moving from first to second generation SQS is
108
+ avalable at:
109
+ http://developer.amazonwebservices.com/connect/entry.jspa?externalID=1148
110
+ * For SDB read Aws::SdbInterface, Aws::ActiveSdb, and consult the Amazon SDB API documentation at
111
+ http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=141
112
+ * For CloudFront (ACF) read Aws::AcfInterface and consult the Amazon CloudFront API documentation at
113
+ http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=213
114
+
115
+ ## KNOWN ISSUES:
116
+
117
+ - 7/08: A user has reported that uploads of large files on Windows may be broken on some
118
+ Win platforms due to a buggy File.lstat.size. Use the following monkey-patch at your own risk,
119
+ as it has been proven to break Rails 2.0 on Windows:
120
+
121
+ require 'win32/file'
122
+ class File
123
+ def lstat
124
+ self.stat
125
+ end
126
+ end
127
+
128
+
129
+ - Attempting to use the Gibberish plugin (used by the Beast forum app)
130
+ will break right_aws as well as lots of other code. Gibberish
131
+ changes the semantics of core Ruby (specifically, the String class) and thus presents a reliability
132
+ problem for most Ruby programs.
133
+
134
+ - 2/11/08: If you use Aws in conjunction with attachment_fu, the
135
+ right_aws gem must be included (using the require statement) AFTER
136
+ attachment_fu. If right_aws is loaded before attachment_fu, you'll
137
+ encounter errors similar to:
138
+
139
+ s3.amazonaws.com temporarily unavailable: (wrong number of arguments (5 for 4))
140
+
141
+ or
142
+
143
+ 'incompatible Net::HTTP monkey-patch'
144
+
145
+ This is due to a conflict between the right_http_connection gem and another
146
+ gem required by attachment_fu. It may be possible to require right_aws (and
147
+ thus right_http_connection) in the .after_initialize method of the config object in
148
+ environment.rb (check the docs for Rails::Configuration.after_initialize).
149
+
150
+ - 8/07: Amazon has changed the semantics of the SQS service. A
151
+ new queue may not be created within 60 seconds of the destruction of any
152
+ older queue with the same name. Certain methods of Aws::Sqs and
153
+ Aws::SqsInterface will fail with the message:
154
+ "AWS.SimpleQueueService.QueueDeletedRecently: You must wait 60 seconds after deleting a queue before you can create another with the same name."
155
+
156
+ ## REQUIREMENTS:
157
+
158
+ Aws requires REXML and the right_http_connection gem.
159
+ If libxml and its Ruby bindings (distributed in the libxml-ruby gem) are
160
+ present, Aws can be configured to use them:
161
+ Aws::AwsParser.xml_lib = 'libxml'
162
+ Any error with the libxml installation will result in Aws failing-safe to
163
+ REXML parsing.
164
+
165
+
166
+ == LICENSE:
167
+
168
+ Copyright (c) 2007-2009 RightScale, Inc.
169
+
170
+ Permission is hereby granted, free of charge, to any person obtaining
171
+ a copy of this software and associated documentation files (the
172
+ 'Software'), to deal in the Software without restriction, including
173
+ without limitation the rights to use, copy, modify, merge, publish,
174
+ distribute, sublicense, and/or sell copies of the Software, and to
175
+ permit persons to whom the Software is furnished to do so, subject to
176
+ the following conditions:
177
+
178
+ The above copyright notice and this permission notice shall be
179
+ included in all copies or substantial portions of the Software.
180
+
181
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
182
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
183
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
184
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
185
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
186
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
187
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,383 @@
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
+
24
+ module Aws
25
+
26
+ # = Aws::AcfInterface -- RightScale Amazon's CloudFront interface
27
+ # The AcfInterface class provides a complete interface to Amazon's
28
+ # CloudFront service.
29
+ #
30
+ # For explanations of the semantics of each call, please refer to
31
+ # Amazon's documentation at
32
+ # http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=211
33
+ #
34
+ # Example:
35
+ #
36
+ # acf = Aws::AcfInterface.new('1E3GDYEOGFJPIT7XXXXXX','hgTHt68JY07JKUY08ftHYtERkjgtfERn57XXXXXX')
37
+ #
38
+ # list = acf.list_distributions #=>
39
+ # [{:status => "Deployed",
40
+ # :domain_name => "d74zzrxmpmygb.6hops.net",
41
+ # :aws_id => "E4U91HCJHGXVC",
42
+ # :origin => "my-bucket.s3.amazonaws.com",
43
+ # :cnames => ["x1.my-awesome-site.net", "x1.my-awesome-site.net"]
44
+ # :comment => "My comments",
45
+ # :last_modified_time => Wed Sep 10 17:00:04 UTC 2008 }, ..., {...} ]
46
+ #
47
+ # distibution = list.first
48
+ #
49
+ # info = acf.get_distribution(distibution[:aws_id]) #=>
50
+ # {:enabled => true,
51
+ # :caller_reference => "200809102100536497863003",
52
+ # :e_tag => "E39OHHU1ON65SI",
53
+ # :status => "Deployed",
54
+ # :domain_name => "d3dxv71tbbt6cd.6hops.net",
55
+ # :cnames => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
56
+ # :aws_id => "E2REJM3VUN5RSI",
57
+ # :comment => "Woo-Hoo!",
58
+ # :origin => "my-bucket.s3.amazonaws.com",
59
+ # :last_modified_time => Wed Sep 10 17:00:54 UTC 2008 }
60
+ #
61
+ # config = acf.get_distribution_config(distibution[:aws_id]) #=>
62
+ # {:enabled => true,
63
+ # :caller_reference => "200809102100536497863003",
64
+ # :e_tag => "E39OHHU1ON65SI",
65
+ # :cnames => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
66
+ # :comment => "Woo-Hoo!",
67
+ # :origin => "my-bucket.s3.amazonaws.com"}
68
+ #
69
+ # config[:comment] = 'Olah-lah!'
70
+ # config[:enabled] = false
71
+ # config[:cnames] << "web3.my-awesome-site.net"
72
+ #
73
+ # acf.set_distribution_config(distibution[:aws_id], config) #=> true
74
+ #
75
+ class AcfInterface < AwsBase
76
+
77
+ include AwsBaseInterface
78
+
79
+ API_VERSION = "2010-08-01"
80
+ DEFAULT_HOST = 'cloudfront.amazonaws.com'
81
+ DEFAULT_PORT = 443
82
+ DEFAULT_PROTOCOL = 'https'
83
+ DEFAULT_PATH = '/'
84
+
85
+ @@bench = AwsBenchmarkingBlock.new
86
+ def self.bench_xml
87
+ @@bench.xml
88
+ end
89
+ def self.bench_service
90
+ @@bench.service
91
+ end
92
+
93
+ # Create a new handle to a CloudFront account. All handles share the same per process or per thread
94
+ # HTTP connection to CloudFront. Each handle is for a specific account. The params have the
95
+ # following options:
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.logger else STDOUT
101
+ # * <tt>:cache</tt>: true/false: caching for list_distributions method, default: false.
102
+ #
103
+ # acf = Aws::AcfInterface.new('1E3GDYEOGFJPIT7XXXXXX','hgTHt68JY07JKUY08ftHYtERkjgtfERn57XXXXXX',
104
+ # {:multi_thread => true, :logger => Logger.new('/tmp/x.log')}) #=> #<Aws::AcfInterface::0xb7b3c30c>
105
+ #
106
+ 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 },
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, body=nil, headers={}) # :nodoc:
123
+ headers['content-type'] ||= 'text/xml' if body
124
+ headers['date'] = Time.now.httpdate
125
+ # Auth
126
+ signature = AwsUtils::sign(@aws_secret_access_key, headers['date'])
127
+ headers['Authorization'] = "AWS #{@aws_access_key_id}:#{signature}"
128
+ # Request
129
+ path = "#{@params[:default_service]}/#{API_VERSION}/#{path}"
130
+ request = "Net::HTTP::#{method.capitalize}".constantize.new(path)
131
+ request.body = body if body
132
+ # Set request headers
133
+ headers.each { |key, value| request[key.to_s] = value }
134
+ # prepare output hash
135
+ { :request => request,
136
+ :server => @params[:server],
137
+ :port => @params[:port],
138
+ :protocol => @params[:protocol] }
139
+ end
140
+
141
+ # Sends request to Amazon and parses the response.
142
+ # Raises AwsError if any banana happened.
143
+ def request_info(request, parser, &block) # :nodoc:
144
+ thread = @params[:multi_thread] ? Thread.current : Thread.main
145
+ thread[:acf_connection] ||= Rightscale::HttpConnection.new(:exception => Aws::AwsError, :logger => @logger)
146
+ request_info_impl(thread[:acf_connection], @@bench, request, parser, &block)
147
+ end
148
+
149
+ #-----------------------------------------------------------------
150
+ # Helpers:
151
+ #-----------------------------------------------------------------
152
+
153
+ def self.escape(text) # :nodoc:
154
+ REXML::Text::normalize(text)
155
+ end
156
+
157
+ def self.unescape(text) # :nodoc:
158
+ REXML::Text::unnormalize(text)
159
+ end
160
+
161
+ def xmlns # :nodoc:
162
+ %Q{"http://#{@params[:server]}/doc/#{API_VERSION}/"}
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
+ #-----------------------------------------------------------------
178
+ # API Calls:
179
+ #-----------------------------------------------------------------
180
+
181
+ # List distributions.
182
+ # Returns an array of distributions or Aws::AwsError exception.
183
+ #
184
+ # acf.list_distributions #=>
185
+ # [{:status => "Deployed",
186
+ # :domain_name => "d74zzrxmpmygb.6hops.net",
187
+ # :aws_id => "E4U91HCJHGXVC",
188
+ # :cnames => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
189
+ # :origin => "my-bucket.s3.amazonaws.com",
190
+ # :comment => "My comments",
191
+ # :last_modified_time => Wed Sep 10 17:00:04 UTC 2008 }, ..., {...} ]
192
+ #
193
+ def list_distributions
194
+ request_hash = generate_request('GET', 'distribution')
195
+ request_cache_or_info :list_distributions, request_hash, AcfDistributionListParser, @@bench
196
+ end
197
+
198
+ # Create a new distribution.
199
+ # Returns the just created distribution or Aws::AwsError exception.
200
+ #
201
+ # acf.create_distribution('bucket-for-k-dzreyev.s3.amazonaws.com', 'Woo-Hoo!', true, ['web1.my-awesome-site.net'] ) #=>
202
+ # {:comment => "Woo-Hoo!",
203
+ # :enabled => true,
204
+ # :location => "https://cloudfront.amazonaws.com/2008-06-30/distribution/E2REJM3VUN5RSI",
205
+ # :status => "InProgress",
206
+ # :aws_id => "E2REJM3VUN5RSI",
207
+ # :domain_name => "d3dxv71tbbt6cd.6hops.net",
208
+ # :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,
211
+ # :caller_reference => "200809102100536497863003"}
212
+ #
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))
233
+ end
234
+
235
+ # Get a distribution's information.
236
+ # Returns a distribution's information or Aws::AwsError exception.
237
+ #
238
+ # acf.get_distribution('E2REJM3VUN5RSI') #=>
239
+ # {:enabled => true,
240
+ # :caller_reference => "200809102100536497863003",
241
+ # :e_tag => "E39OHHU1ON65SI",
242
+ # :status => "Deployed",
243
+ # :domain_name => "d3dxv71tbbt6cd.6hops.net",
244
+ # :cnames => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
245
+ # :aws_id => "E2REJM3VUN5RSI",
246
+ # :comment => "Woo-Hoo!",
247
+ # :origin => "my-bucket.s3.amazonaws.com",
248
+ # :last_modified_time => Wed Sep 10 17:00:54 UTC 2008 }
249
+ #
250
+ def get_distribution(aws_id)
251
+ request_hash = generate_request('GET', "distribution/#{aws_id}")
252
+ merge_headers(request_info(request_hash, AcfDistributionParser.new))
253
+ end
254
+
255
+ # Get a distribution's configuration.
256
+ # Returns a distribution's configuration or Aws::AwsError exception.
257
+ #
258
+ # acf.get_distribution_config('E2REJM3VUN5RSI') #=>
259
+ # {:enabled => true,
260
+ # :caller_reference => "200809102100536497863003",
261
+ # :e_tag => "E39OHHU1ON65SI",
262
+ # :cnames => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
263
+ # :comment => "Woo-Hoo!",
264
+ # :origin => "my-bucket.s3.amazonaws.com"}
265
+ #
266
+ 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))
269
+ end
270
+
271
+ # Set a distribution's configuration
272
+ # (the :origin and the :caller_reference cannot be changed).
273
+ # Returns +true+ on success or Aws::AwsError exception.
274
+ #
275
+ # config = acf.get_distribution_config('E2REJM3VUN5RSI') #=>
276
+ # {:enabled => true,
277
+ # :caller_reference => "200809102100536497863003",
278
+ # :e_tag => "E39OHHU1ON65SI",
279
+ # :cnames => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
280
+ # :comment => "Woo-Hoo!",
281
+ # :origin => "my-bucket.s3.amazonaws.com",
282
+ # :default_root_object =>
283
+ # }
284
+ # config[:comment] = 'Olah-lah!'
285
+ # config[:enabled] = false
286
+ # acf.set_distribution_config('E2REJM3VUN5RSI', config) #=> true
287
+ #
288
+ def set_distribution_config(aws_id, config)
289
+ # join CNAMES
290
+ cnames_str = ''
291
+ unless config[:cnames].blank?
292
+ config[:cnames].to_a.each { |cname| cnames_str += "\n <CNAME>#{cname}</CNAME>" }
293
+ end
294
+ root_ob = config[:default_root_object] ? "<DefaultRootObject>#{config[:default_root_object]}</DefaultRootObject>" : ""
295
+ # format request's XML body
296
+ body = <<-EOXML
297
+ <?xml version="1.0" encoding="UTF-8"?>
298
+ <DistributionConfig xmlns=#{xmlns}>
299
+ <Origin>#{config[:origin]}</Origin>
300
+ <CallerReference>#{config[:caller_reference]}</CallerReference>
301
+ #{cnames_str.lstrip}
302
+ <Comment>#{AcfInterface::escape(config[:comment].to_s)}</Comment>
303
+ <Enabled>#{config[:enabled]}</Enabled>
304
+ #{root_ob}
305
+ </DistributionConfig>
306
+ EOXML
307
+ request_hash = generate_request('PUT', "distribution/#{aws_id}/config", body.strip,
308
+ 'If-Match' => config[:e_tag])
309
+ request_info(request_hash, RightHttp2xxParser.new)
310
+ end
311
+
312
+ # Delete a distribution. The enabled distribution cannot be deleted.
313
+ # Returns +true+ on success or Aws::AwsError exception.
314
+ #
315
+ # acf.delete_distribution('E2REJM3VUN5RSI', 'E39OHHU1ON65SI') #=> true
316
+ #
317
+ def delete_distribution(aws_id, e_tag)
318
+ request_hash = generate_request('DELETE', "distribution/#{aws_id}", nil,
319
+ 'If-Match' => e_tag)
320
+ request_info(request_hash, RightHttp2xxParser.new)
321
+ end
322
+
323
+ #-----------------------------------------------------------------
324
+ # PARSERS:
325
+ #-----------------------------------------------------------------
326
+
327
+ class AcfDistributionListParser < AwsParser # :nodoc:
328
+ def reset
329
+ @result = []
330
+ end
331
+ def tagstart(name, attributes)
332
+ @distribution = { :cnames => [] } if name == 'DistributionSummary'
333
+ end
334
+ def tagend(name)
335
+ case name
336
+ when 'Id' then @distribution[:aws_id] = @text
337
+ when 'Status' then @distribution[:status] = @text
338
+ when 'LastModifiedTime' then @distribution[:last_modified_time] = Time.parse(@text)
339
+ when 'DomainName' then @distribution[:domain_name] = @text
340
+ when 'Origin' then @distribution[:origin] = @text
341
+ when 'Comment' then @distribution[:comment] = AcfInterface::unescape(@text)
342
+ when 'CNAME' then @distribution[:cnames] << @text
343
+ when 'DistributionSummary' then @result << @distribution
344
+ end
345
+ end
346
+ end
347
+
348
+ class AcfDistributionParser < AwsParser # :nodoc:
349
+ def reset
350
+ @result = { :cnames => [] }
351
+ end
352
+ def tagend(name)
353
+ case name
354
+ when 'Id' then @result[:aws_id] = @text
355
+ when 'Status' then @result[:status] = @text
356
+ when 'LastModifiedTime' then @result[:last_modified_time] = Time.parse(@text)
357
+ when 'DomainName' then @result[:domain_name] = @text
358
+ when 'Origin' then @result[:origin] = @text
359
+ when 'CallerReference' then @result[:caller_reference] = @text
360
+ when 'Comment' then @result[:comment] = AcfInterface::unescape(@text)
361
+ when 'Enabled' then @result[:enabled] = @text == 'true' ? true : false
362
+ when 'CNAME' then @result[:cnames] << @text
363
+ end
364
+ end
365
+ end
366
+
367
+ class AcfDistributionConfigParser < AwsParser # :nodoc:
368
+ def reset
369
+ @result = { :cnames => [] }
370
+ end
371
+ def tagend(name)
372
+ case name
373
+ when 'Origin' then @result[:origin] = @text
374
+ when 'CallerReference' then @result[:caller_reference] = @text
375
+ when 'Comment' then @result[:comment] = AcfInterface::unescape(@text)
376
+ when 'Enabled' then @result[:enabled] = @text == 'true' ? true : false
377
+ when 'CNAME' then @result[:cnames] << @text
378
+ end
379
+ end
380
+ end
381
+
382
+ end
383
+ end