right_aws 2.0.0 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/History.txt +22 -1
  2. data/Manifest.txt +11 -1
  3. data/README.txt +0 -4
  4. data/Rakefile +19 -25
  5. data/lib/acf/right_acf_interface.rb +199 -135
  6. data/lib/acf/right_acf_invalidations.rb +144 -0
  7. data/lib/acf/right_acf_origin_access_identities.rb +4 -4
  8. data/lib/acf/right_acf_streaming_interface.rb +19 -26
  9. data/lib/acw/right_acw_interface.rb +1 -2
  10. data/lib/as/right_as_interface.rb +6 -7
  11. data/lib/awsbase/right_awsbase.rb +287 -91
  12. data/lib/awsbase/support.rb +2 -82
  13. data/lib/awsbase/version.rb +9 -0
  14. data/lib/ec2/right_ec2.rb +101 -38
  15. data/lib/ec2/right_ec2_ebs.rb +71 -58
  16. data/lib/ec2/right_ec2_images.rb +82 -42
  17. data/lib/ec2/right_ec2_instances.rb +74 -44
  18. data/lib/ec2/right_ec2_placement_groups.rb +108 -0
  19. data/lib/ec2/right_ec2_reserved_instances.rb +50 -46
  20. data/lib/ec2/right_ec2_security_groups.rb +148 -32
  21. data/lib/ec2/right_ec2_spot_instances.rb +53 -27
  22. data/lib/ec2/right_ec2_tags.rb +139 -0
  23. data/lib/ec2/right_ec2_vpc.rb +151 -139
  24. data/lib/ec2/right_ec2_windows_mobility.rb +84 -0
  25. data/lib/elb/right_elb_interface.rb +93 -18
  26. data/lib/iam/right_iam_access_keys.rb +71 -0
  27. data/lib/iam/right_iam_groups.rb +195 -0
  28. data/lib/iam/right_iam_interface.rb +341 -0
  29. data/lib/iam/right_iam_mfa_devices.rb +67 -0
  30. data/lib/iam/right_iam_users.rb +251 -0
  31. data/lib/rds/right_rds_interface.rb +513 -202
  32. data/lib/right_aws.rb +12 -12
  33. data/lib/route_53/right_route_53_interface.rb +630 -0
  34. data/lib/s3/right_s3.rb +9 -12
  35. data/lib/s3/right_s3_interface.rb +10 -11
  36. data/lib/sdb/active_sdb.rb +18 -33
  37. data/lib/sdb/right_sdb_interface.rb +36 -4
  38. data/lib/sqs/right_sqs.rb +1 -2
  39. data/lib/sqs/right_sqs_gen2.rb +0 -1
  40. data/lib/sqs/right_sqs_gen2_interface.rb +4 -5
  41. data/lib/sqs/right_sqs_interface.rb +6 -7
  42. data/right_aws.gemspec +91 -0
  43. data/test/awsbase/test_helper.rb +2 -0
  44. data/test/awsbase/test_right_awsbase.rb +12 -0
  45. data/test/s3/test_right_s3.rb +1 -1
  46. data/test/sdb/test_active_sdb.rb +1 -1
  47. data/test/sdb/test_batch_put_attributes.rb +54 -0
  48. data/test/sqs/test_right_sqs.rb +0 -6
  49. data/test/sqs/test_right_sqs_gen2.rb +1 -1
  50. metadata +109 -58
@@ -35,8 +35,9 @@ require 'rubygems'
35
35
  require 'right_http_connection'
36
36
 
37
37
  $:.unshift(File.dirname(__FILE__))
38
- require 'awsbase/benchmark_fix'
38
+ require 'awsbase/version'
39
39
  require 'awsbase/support'
40
+ require 'awsbase/benchmark_fix'
40
41
  require 'awsbase/right_awsbase'
41
42
  require 'ec2/right_ec2'
42
43
  require 'ec2/right_ec2_images'
@@ -47,6 +48,9 @@ require 'ec2/right_ec2_ebs'
47
48
  require 'ec2/right_ec2_reserved_instances'
48
49
  require 'ec2/right_ec2_vpc'
49
50
  require 'ec2/right_ec2_monitoring'
51
+ require 'ec2/right_ec2_placement_groups'
52
+ require 'ec2/right_ec2_windows_mobility'
53
+ require 'ec2/right_ec2_tags'
50
54
  require 'elb/right_elb_interface'
51
55
  require 'acw/right_acw_interface'
52
56
  require 'as/right_as_interface'
@@ -60,18 +64,14 @@ require 'sdb/right_sdb_interface'
60
64
  require 'acf/right_acf_interface'
61
65
  require 'acf/right_acf_streaming_interface'
62
66
  require 'acf/right_acf_origin_access_identities'
67
+ require 'acf/right_acf_invalidations'
63
68
  require 'rds/right_rds_interface'
64
-
65
-
66
- module RightAws #:nodoc:
67
- module VERSION #:nodoc:
68
- MAJOR = 2 unless defined?(MAJOR)
69
- MINOR = 0 unless defined?(MINOR)
70
- TINY = 0 unless defined?(TINY)
71
-
72
- STRING = [MAJOR, MINOR, TINY].join('.') unless defined?(STRING)
73
- end
74
- end
69
+ require 'iam/right_iam_interface'
70
+ require 'iam/right_iam_groups'
71
+ require 'iam/right_iam_users'
72
+ require 'iam/right_iam_access_keys'
73
+ require 'iam/right_iam_mfa_devices'
74
+ require 'route_53/right_route_53_interface'
75
75
 
76
76
  #-
77
77
 
@@ -0,0 +1,630 @@
1
+ # Copyright (c) 2007-2011 RightScale Inc
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining
4
+ # a copy of this software and associated documentation files (the
5
+ # "Software"), to deal in the Software without restriction, including
6
+ # without limitation the rights to use, copy, modify, merge, publish,
7
+ # distribute, sublicense, and/or sell copies of the Software, and to
8
+ # permit persons to whom the Software is furnished to do so, subject to
9
+ # the following conditions:
10
+ #
11
+ # The above copyright notice and this permission notice shall be
12
+ # included in all copies or substantial portions of the Software.
13
+ #
14
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
+ #
22
+
23
+ module RightAws
24
+
25
+ # = RightAws::Route53Interface -- Amazon Route 53 web service interface.
26
+ #
27
+ # The RightAws::Route53Interface class provides a complete interface to Amazon Route 53: a web
28
+ # service that enables you to manage your DNS service.
29
+ #
30
+ # For explanations of the semantics of each call, please refer to Amazon's documentation at
31
+ # http://aws.amazon.com/documentation/route53/
32
+ #
33
+ # Examples:
34
+ #
35
+ # # Create Route53 handler
36
+ # r53 = RightAws::Route53Interface.new(AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY)
37
+ #
38
+ # #------------------------
39
+ # # Create Hosted Zone
40
+ # #------------------------
41
+ #
42
+ # hosted_zone_config = {
43
+ # :name => 'my-awesome-site.com.',
44
+ # :config => {
45
+ # :comment => 'My test site!'
46
+ # }
47
+ # }
48
+ # r53.create_hosted_zone(hosted_zone_config) #=>
49
+ # {:name_servers=>
50
+ # ["ns-1115.awsdns-11.org",
51
+ # "ns-696.awsdns-23.net",
52
+ # "ns-1963.awsdns-53.co.uk",
53
+ # "ns-362.awsdns-45.com"],
54
+ # :aws_id=>"/hostedzone/Z1K6NCF0EB26FB",
55
+ # :caller_reference=>"1295424990-710392-gqMuw-KcY8F-LFlrB-SQhp9",
56
+ # :config=>{:comment=>"My test site!"},
57
+ # :change_info=>
58
+ # {:status=>"PENDING",
59
+ # :aws_id=>"/change/C23QGMT8XTCAJY",
60
+ # :submitted_at=>"2011-01-19T08:16:31.046Z"},
61
+ # :name=>"my-awesome-site.com."}
62
+ #
63
+ # # List Hosted Zones
64
+ # r53.list_hosted_zones #=> []
65
+ # [{:aws_id=>"/hostedzone/Z1K6NCF0EB26FB",
66
+ # :caller_reference=>"1295424990-710392-gqMuw-KcY8F-LFlrB-SQhp9",
67
+ # :config=>{:comment=>"My test site!"},
68
+ # :name=>"my-awesome-site.com."}]
69
+ #
70
+ # #--------------------------------
71
+ # # Manage DNS Records and Changes
72
+ # #--------------------------------
73
+ #
74
+ # # Create DNS Records
75
+ # resource_record_sets = [ { :name => 'www1.my-awesome-site.com.',
76
+ # :type => 'NS',
77
+ # :ttl => 600,
78
+ # :resource_records => 'www.mysite.com' },
79
+ # { :name => 'www2.my-awesome-site.com.',
80
+ # :type => 'A',
81
+ # :ttl => 600,
82
+ # :resource_records => ['10.0.0.1'] } ]
83
+ # r53.create_resource_record_sets("/hostedzone/Z1K6NCF0EB26FB", resource_record_sets, 'my first set of records') #=>
84
+ # { :status=>"PENDING",
85
+ # :aws_id=>"/change/C2C6IGNRTKA0AY",
86
+ # :submitted_at=>"2011-01-19T08:29:26.160Z" }
87
+ #
88
+ # # Delete DNS records
89
+ # r53.delete_resource_record_sets("/hostedzone/Z1K6NCF0EB26FB", resource_record_sets, 'I dont need them any more') #=>
90
+ # { :status=>"PENDING",
91
+ # :aws_id=>"/change/C1CYJ10EZBFLO7",
92
+ # :submitted_at=>"2011-01-19T08:26:41.220Z" }
93
+ #
94
+ # # Create or delete DNS records (:action key must be provided):
95
+ # resource_record_sets = [ { :action => :create,
96
+ # :name => 'www1.my-awesome-site.com.',
97
+ # :type => 'NS',
98
+ # :ttl => 600,
99
+ # :resource_records => 'www.mysite.com' },
100
+ # { :action => :delete,
101
+ # :name => 'www2.my-awesome-site.com.',
102
+ # :type => 'A',
103
+ # :ttl => 600,
104
+ # :resource_records => ['10.0.0.1'] } ]
105
+ # r53.change_resource_record_sets("/hostedzone/Z1K6NCF0EB26FB", resource_record_sets, 'do change records')
106
+ # { :status=>"PENDING",
107
+ # :aws_id=>"/change/C2PWXVECN794LK",
108
+ # :submitted_at=>"2011-01-19T08:31:33.301Z" }
109
+ #
110
+ # # List DNS Records
111
+ # r53.list_resource_record_sets("/hostedzone/Z1K6NCF0EB26FB") #=>
112
+ # [{:type=>"NS",
113
+ # :ttl=>172800,
114
+ # :resource_records=>
115
+ # ["ns-1115.awsdns-11.org.",
116
+ # "ns-696.awsdns-23.net.",
117
+ # "ns-1963.awsdns-53.co.uk.",
118
+ # "ns-362.awsdns-45.com."],
119
+ # :name=>"my-awesome-site.com."},
120
+ # {:type=>"SOA",
121
+ # :ttl=>900,
122
+ # :resource_records=>
123
+ # ["ns-1115.awsdns-11.org. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"],
124
+ # :name=>"my-awesome-site.com."},
125
+ # {:type=>"NS",
126
+ # :ttl=>600,
127
+ # :resource_records=>["www.mysite.com"],
128
+ # :name=>"www1.my-awesome-site.com."}]
129
+ #
130
+ # # Get Change info
131
+ # r53.get_change("/change/C2C6IGNRTKA0AY")
132
+ # {:status=>"INSYNC",
133
+ # :aws_id=>"/change/C2C6IGNRTKA0AY",
134
+ # :submitted_at=>"2011-01-19T08:29:26.160Z"}
135
+ #
136
+ # #------------------------
137
+ # # Delete Hosted Zone
138
+ # #------------------------
139
+ #
140
+ # # Get a list of DNS records I have created (the first 2 records were added by Amazon and cannot be deleted)
141
+ # resource_record_sets = r53.list_resource_record_sets("/hostedzone/Z1K6NCF0EB26FB")
142
+ # resource_record_sets.shift
143
+ # resource_record_sets.shift
144
+ #
145
+ # # Delete them all
146
+ # delete_resource_record_sets("/hostedzone/Z1K6NCF0EB26FB", resource_record_sets, 'kill all records I have created') #=>
147
+ # { :status=>"PENDING",
148
+ # :aws_id=>"/change/C6NCO8Z50MHXV",
149
+ # :submitted_at=>"2011-01-19T08:46:37.307Z" }
150
+ #
151
+ # # Delete Hosted Zone
152
+ # r53.delete_hosted_zone("/hostedzone/Z1K6NCF0EB26FB") #=>
153
+ # { :status=>"PENDING",
154
+ # :aws_id=>"/change/C3OJ31D4V5P2LU",
155
+ # :submitted_at=>"2011-01-19T08:46:37.530Z" }
156
+ #
157
+ class Route53Interface < RightAwsBase
158
+
159
+ include RightAwsBaseInterface
160
+
161
+ API_VERSION = "2010-10-01"
162
+ DEFAULT_HOST = "route53.amazonaws.com"
163
+ DEFAULT_PATH = '/'
164
+ DEFAULT_PROTOCOL = 'https'
165
+ DEFAULT_PORT = 443
166
+
167
+ @@bench = AwsBenchmarkingBlock.new
168
+ def self.bench_xml
169
+ @@bench.xml
170
+ end
171
+ def self.bench_service
172
+ @@bench.service
173
+ end
174
+
175
+ # Create a new handle to an Route53 account. All handles share the same per process or per thread
176
+ # HTTP connection to Amazon Route53. Each handle is for a specific account. The params have the
177
+ # following options:
178
+ # * <tt>:endpoint_url</tt> a fully qualified url to Amazon API endpoint (this overwrites: :server, :port, :service, :protocol).
179
+ # * <tt>:server</tt>: Route53 service host, default: DEFAULT_HOST
180
+ # * <tt>:port</tt>: Route53 service port, default: DEFAULT_PORT
181
+ # * <tt>:protocol</tt>: 'http' or 'https', default: DEFAULT_PROTOCOL
182
+ # * <tt>:logger</tt>: for log messages, default: RAILS_DEFAULT_LOGGER else STDOUT
183
+ # * <tt>:signature_version</tt>: The signature version : '0','1' or '2'(default)
184
+ #
185
+ def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
186
+ init({ :name => 'ROUTE_53',
187
+ :default_host => ENV['ROUTE_53_URL'] ? URI.parse(ENV['ROUTE_53_URL']).host : DEFAULT_HOST,
188
+ :default_port => ENV['ROUTE_53_URL'] ? URI.parse(ENV['ROUTE_53_URL']).port : DEFAULT_PORT,
189
+ :default_service => ENV['ROUTE_53_URL'] ? URI.parse(ENV['ROUTE_53_URL']).path : DEFAULT_PATH,
190
+ :default_protocol => ENV['ROUTE_53_URL'] ? URI.parse(ENV['ROUTE_53_URL']).scheme : DEFAULT_PROTOCOL,
191
+ :default_api_version => ENV['ROUTE_53_API_VERSION'] || API_VERSION },
192
+ aws_access_key_id || ENV['AWS_ACCESS_KEY_ID'] ,
193
+ aws_secret_access_key|| ENV['AWS_SECRET_ACCESS_KEY'],
194
+ params)
195
+ end
196
+
197
+ #-----------------------------------------------------------------
198
+ # Requests
199
+ #-----------------------------------------------------------------
200
+
201
+ # Generates request hash for REST API.
202
+ def generate_request(method, path, params={}, body=nil, headers={}) # :nodoc:
203
+ # Params
204
+ params.delete_if{ |key, val| val.right_blank? }
205
+ unless params.right_blank?
206
+ path += "?" + params.to_a.collect{ |key,val| "#{AwsUtils::amz_escape(key)}=#{AwsUtils::amz_escape(val.to_s)}" }.join("&")
207
+ end
208
+ # Headers
209
+ headers['content-type'] ||= 'text/xml' if body
210
+ headers['date'] = Time.now.httpdate
211
+ # Auth
212
+ signature = AwsUtils::sign(@aws_secret_access_key, headers['date'])
213
+ headers['X-Amzn-Authorization'] = "AWS3-HTTPS AWSAccessKeyId=#{@aws_access_key_id},Algorithm=HmacSHA1,Signature=#{signature}"
214
+ # Request
215
+ path = "#{@params[:service]}#{@params[:api_version]}/#{path}"
216
+ request = "Net::HTTP::#{method.capitalize}".right_constantize.new(path)
217
+ request.body = body if body
218
+ # Set request headers
219
+ headers.each { |key, value| request[key.to_s] = value }
220
+ # prepare output hash
221
+ { :request => request,
222
+ :server => @params[:server],
223
+ :port => @params[:port],
224
+ :protocol => @params[:protocol] }
225
+ end
226
+
227
+ # Sends request to Amazon and parses the response.
228
+ # Raises AwsError if any banana happened.
229
+ def request_info(request, parser, &block) # :nodoc:
230
+ request_info_impl(:acf_connection, @@bench, request, parser, &block)
231
+ end
232
+
233
+ def incrementally_list_hosted_zones(path, parser, params={}, &block) # :nodoc:
234
+ opts = {}
235
+ opts['MaxItems'] = params[:max_items] if params[:max_items]
236
+ opts['Marker'] = params[:marker] if params[:marker]
237
+ last_response = nil
238
+ loop do
239
+ link = generate_request('GET', path, opts)
240
+ last_response = request_info(link, parser.new(:logger => @logger))
241
+ opts['Marker'] = last_response[:next_marker]
242
+ break unless block && block.call(last_response) && !last_response[:next_marker].right_blank?
243
+ end
244
+ last_response
245
+ end
246
+
247
+ def incrementally_list_resource_records(path, parser, params={}, &block) # :nodoc:
248
+ opts = {}
249
+ opts[:maxitems] = params.delete(:max_items) if params[:max_items]
250
+ last_response = nil
251
+ loop do
252
+ link = generate_request('GET', path, opts)
253
+ last_response = request_info(link, parser.new(:logger => @logger))
254
+ opts[:maxitems] = last_response[:max_items]
255
+ opts[:name] = last_response[:next_record_name]
256
+ opts[:type] = last_response[:next_record_type]
257
+ break unless block && block.call(last_response) && last_response[:is_truncated]
258
+ end
259
+ last_response
260
+ end
261
+
262
+ def expand_hosted_zone_id(aws_id) # :nodoc:
263
+ aws_id[%r{^/hostedzone/}] ? aws_id : "/hostedzone/#{aws_id}"
264
+ end
265
+
266
+ def expand_change_id(aws_id) # :nodoc:
267
+ aws_id[%r{^/change/}] ? aws_id : "/change/#{aws_id}"
268
+ end
269
+
270
+ def hosted_zone_config_to_xml(config) # :nodoc:
271
+ config[:caller_reference] ||= AwsUtils::generate_call_reference
272
+ hosted_zone_config = ''
273
+ unless config[:config].right_blank?
274
+ hosted_zone_config = " <HostedZoneConfig>\n" +
275
+ " <Comment>#{AwsUtils::xml_escape config[:config][:comment]}</Comment>\n" +
276
+ " </HostedZoneConfig>\n"
277
+ end
278
+ # XML
279
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
280
+ "<CreateHostedZoneRequest xmlns=\"https://#{@params[:server]}/doc/#{API_VERSION}/\">\n" +
281
+ " <Name>#{config[:name]}</Name>\n" +
282
+ " <CallerReference>#{config[:caller_reference]}</CallerReference>\n" +
283
+ hosted_zone_config +
284
+ "</CreateHostedZoneRequest>\n"
285
+ end
286
+
287
+ def resource_record_sets_to_xml(resource_record_changes, comment) # :nodoc:
288
+ # Comment
289
+ xml_comment = comment.right_blank? ? '' : " <Comment>#{AwsUtils::xml_escape(comment)}</Comment>\n"
290
+ # Changes
291
+ xml_changes = ''
292
+ resource_record_changes.each do |change|
293
+ xml_resource_records = Array(change[:resource_records]).map{|record| " <ResourceRecord><Value>#{AwsUtils::xml_escape(record)}</Value></ResourceRecord>\n" }.join('')
294
+ xml_changes += " <Change>\n" +
295
+ " <Action>#{AwsUtils::xml_escape(change[:action].to_s.upcase)}</Action>\n" +
296
+ " <ResourceRecordSet>\n" +
297
+ " <Name>#{AwsUtils::xml_escape(change[:name])}</Name>\n" +
298
+ " <Type>#{AwsUtils::xml_escape(change[:type].to_s.upcase)}</Type>\n" +
299
+ " <TTL>#{AwsUtils::xml_escape(change[:ttl].to_s)}</TTL>\n" +
300
+ " <ResourceRecords>\n" +
301
+ xml_resource_records +
302
+ " </ResourceRecords>\n" +
303
+ " </ResourceRecordSet>\n" +
304
+ " </Change>\n"
305
+ end
306
+ # XML
307
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
308
+ "<ChangeResourceRecordSetsRequest xmlns=\"https://#{@params[:server]}/doc/#{API_VERSION}/\">\n" +
309
+ " <ChangeBatch>\n" +
310
+ xml_comment +
311
+ " <Changes>\n" +
312
+ xml_changes +
313
+ " </Changes>\n" +
314
+ " </ChangeBatch>\n" +
315
+ "</ChangeResourceRecordSetsRequest>\n"
316
+ end
317
+
318
+
319
+ #-----------------------------------------------------------------
320
+ # Hosted Zones
321
+ #-----------------------------------------------------------------
322
+
323
+ # List your hosted zones.
324
+ #
325
+ # r53.list_hosted_zones #=>
326
+ # [{:config=>{:comment=>"KD1, description"},
327
+ # :aws_id=>"/hostedzone/Z2P714ENJN23PN",
328
+ # :caller_reference=>"1295424990-710392-gqMuw-KcY8F-LFlrB-SQhp9",
329
+ # :name=>"patch-island.com."},
330
+ # {:config=>{:comment=>"My awesome site!"},
331
+ # :aws_id=>"/hostedzone/ZWEC7PPVACGQ4",
332
+ # :caller_reference=>"1295422234-657482-hfkeo-JFKid-Ldfle-Sdrty",
333
+ # :name=>"mysite.patch-island.com."}, ...]
334
+ #
335
+ # PS: http://docs.amazonwebservices.com/Route53/latest/APIReference/API_ListHostedZones.html
336
+ #
337
+ def list_hosted_zones
338
+ result = []
339
+ incrementally_list_hosted_zones('hostedzone', ListHostedZonesParser) do |response|
340
+ result += response[:items]
341
+ true
342
+ end
343
+ result
344
+ end
345
+
346
+ # Create new hosted zone
347
+ #
348
+ # config = {
349
+ # :name => 'mysite.patch-island.com.',
350
+ # :config => {
351
+ # :comment => 'My awesome site!'
352
+ # }
353
+ # }
354
+ # r53.create_hosted_zone(config) #=>
355
+ # {:config=>{:comment=>"My awesome site!"},
356
+ # :change_info=>
357
+ # {:status=>"PENDING",
358
+ # :aws_id=>"/change/C2NOTVGL7IOFFF",
359
+ # :submitted_at=>"2011-01-18T15:34:18.086Z"},
360
+ # :aws_id=>"/hostedzone/ZWEC7PPVACGQ4",
361
+ # :caller_reference=>"1295365357-227168-NfZ4P-VGHWi-Yq0p7-nuN6q",
362
+ # :name_servers=>
363
+ # ["ns-794.awsdns-35.net",
364
+ # "ns-459.awsdns-57.com",
365
+ # "ns-1537.awsdns-00.co.uk",
366
+ # "ns-1165.awsdns-17.org"],
367
+ # :name=>"mysite.patch-island.com."}
368
+ #
369
+ # PS: http://docs.amazonwebservices.com/Route53/latest/APIReference/index.html?API_CreateHostedZone.html
370
+ #
371
+ def create_hosted_zone(config)
372
+ config[:caller_reference] ||= AwsUtils::generate_unique_token
373
+ link = generate_request('POST', 'hostedzone', {}, hosted_zone_config_to_xml(config))
374
+ request_info(link, GetHostedZoneParser.new(:logger => @logger))
375
+ end
376
+
377
+ # Get your hosted zone.
378
+ #
379
+ # r53.get_hosted_zone("ZWEC7PPVACGQ4") #=>
380
+ # {:config=>{:comment=>"My awesome site!"},
381
+ # :aws_id=>"/hostedzone/ZWEC7PPVACGQ4",
382
+ # :caller_reference=>"1295422234-657482-hfkeo-JFKid-Ldfle-Sdrty",
383
+ # :name_servers=>
384
+ # ["ns-794.awsdns-35.net",
385
+ # "ns-459.awsdns-57.com",
386
+ # "ns-1537.awsdns-00.co.uk",
387
+ # "ns-1165.awsdns-17.org"],
388
+ # :name=>"mysite.patch-island.com."}
389
+ #
390
+ # PS: http://docs.amazonwebservices.com/Route53/latest/APIReference/API_GetHostedZone.html
391
+ #
392
+ def get_hosted_zone(hosted_zone_aws_id)
393
+ link = generate_request('GET', expand_hosted_zone_id(hosted_zone_aws_id))
394
+ request_info(link, GetHostedZoneParser.new(:logger => @logger))
395
+ end
396
+
397
+ # Delete hosted zone.
398
+ #
399
+ # r53.delete_hosted_zone("/hostedzone/Z2P714ENJN23PN") #=>
400
+ # {:status=>"PENDING",
401
+ # :submitted_at=>"2011-01-18T15:45:45.060Z",
402
+ # :aws_id=>"/change/C1PN1SDWZKPTAC"}
403
+ #
404
+ # PS: http://docs.amazonwebservices.com/Route53/latest/APIReference/API_DeleteHostedZone.html
405
+ #
406
+ def delete_hosted_zone(hosted_zone_aws_id)
407
+ link = generate_request('DELETE', expand_hosted_zone_id(hosted_zone_aws_id))
408
+ request_info(link, GetChangeParser.new(:logger => @logger))
409
+ end
410
+
411
+ #-----------------------------------------------------------------
412
+ # Resource Records Set
413
+ #-----------------------------------------------------------------
414
+
415
+ # List your resource record sets.
416
+ # Options: :type, :name, :max_items
417
+ #
418
+ # r53.list_resource_record_sets("/hostedzone/ZWEC7PPVACGQ4") #=>
419
+ # {:items=>
420
+ # [{:type=>"NS",
421
+ # :ttl=>172800,
422
+ # :name=>"mysite.patch-island.com.",
423
+ # :resource_records=>
424
+ # ["ns-459.awsdns-57.com.",
425
+ # "ns-794.awsdns-35.net.",
426
+ # "ns-1165.awsdns-17.org.",
427
+ # "ns-1537.awsdns-00.co.uk."]},
428
+ # {:type=>"SOA",
429
+ # :ttl=>900,
430
+ # :name=>"mysite.patch-island.com.",
431
+ # :resource_records=>
432
+ # ["ns-794.awsdns-35.net. awsdns-hostmaster.amazon.com. 1 7200 900 1209600 86400"]},
433
+ # {:type=>"NS",
434
+ # :ttl=>600,
435
+ # :resource_records=>["xxx.mysite.com"],
436
+ # :name=>"m1.mysite.patch-island.com."}],
437
+ # :is_truncated=>false,
438
+ # :max_items=>100}
439
+ #
440
+ # PS: http://docs.amazonwebservices.com/Route53/latest/APIReference/API_ListResourceRecordSets.html
441
+ #
442
+ def list_resource_record_sets(hosted_zone_aws_id, options={})
443
+ options = options.dup
444
+ result = []
445
+ incrementally_list_resource_records("#{expand_hosted_zone_id(hosted_zone_aws_id)}/rrset", ListResourceRecordSetsParser, options) do |response|
446
+ result += response[:items]
447
+ true
448
+ end
449
+ result
450
+ end
451
+
452
+ # Create or delete DNS records.
453
+ #
454
+ # resource_record_sets = { :action => :create,
455
+ # :name => 'm3.mysite.patch-island.com',
456
+ # :type => 'NS',
457
+ # :ttl => 600,
458
+ # :resource_records => 'xxx.mysite.com' },
459
+ # { :action => :delete,
460
+ # :name => 'm2.mysite.patch-island.com',
461
+ # :type => 'A',
462
+ # :ttl => 600,
463
+ # :resource_records => ['10.0.0.1'] }
464
+ # r53.change_resource_record_sets("/hostedzone/Z1K6NCF0EB26FB", resource_record_sets, 'KD: Comment#1') #=>
465
+ # {:status=>"PENDING",
466
+ # :submitted_at=>"2011-01-18T20:21:56.828Z",
467
+ # :aws_id=>"/change/C394PNLM1B2P08"}
468
+ #
469
+ # PS: resource_record_sets must have an :action key set (== :create or :delete)
470
+ # PPS: http://docs.amazonwebservices.com/Route53/latest/APIReference/API_ChangeResourceRecordSets.html
471
+ #
472
+ def change_resource_record_sets(hosted_zone_aws_id, resource_record_sets, comment = '')
473
+ link = generate_request('POST', "#{expand_hosted_zone_id(hosted_zone_aws_id)}/rrset", {}, resource_record_sets_to_xml(resource_record_sets, comment))
474
+ request_info(link, GetChangeParser.new(:logger => @logger))
475
+ end
476
+
477
+ # Create DNS records.
478
+ #
479
+ # resource_record_sets = { :name => 'm3.mysite.patch-island.com',
480
+ # :type => 'NS',
481
+ # :ttl => 600,
482
+ # :resource_records => 'xxx.mysite.com' },
483
+ # { :name => 'm2.mysite.patch-island.com',
484
+ # :type => 'A',
485
+ # :ttl => 600,
486
+ # :resource_records => ['10.0.0.1'] }
487
+ # r53.create_resource_record_sets("/hostedzone/Z1K6NCF0EB26FB", resource_record_sets, 'KD: Comment#1') #=>
488
+ # {:status=>"PENDING",
489
+ # :submitted_at=>"2011-01-18T20:21:56.828Z",
490
+ # :aws_id=>"/change/C394PNLM1B2P08"}
491
+ #
492
+ # PS: http://docs.amazonwebservices.com/Route53/latest/APIReference/API_ChangeResourceRecordSets.html
493
+ #
494
+ def create_resource_record_sets(hosted_zone_aws_id, resource_record_sets, comment = '')
495
+ resource_record_sets.each{|rrs| rrs[:action] = :create}
496
+ change_resource_record_sets(hosted_zone_aws_id, resource_record_sets, comment)
497
+ end
498
+
499
+ # Delete DNS records.
500
+ #
501
+ # resource_record_sets = { :name => 'm3.mysite.patch-island.com',
502
+ # :type => 'NS',
503
+ # :ttl => 600,
504
+ # :resource_records => 'xxx.mysite.com' },
505
+ # { :name => 'm2.mysite.patch-island.com',
506
+ # :type => 'A',
507
+ # :ttl => 600,
508
+ # :resource_records => ['10.0.0.1'] }
509
+ # r53.create_resource_record_sets("/hostedzone/Z1K6NCF0EB26FB", resource_record_sets, 'KD: Comment#1') #=>
510
+ # {:status=>"PENDING",
511
+ # :submitted_at=>"2011-01-18T20:21:56.828Z",
512
+ # :aws_id=>"/change/C394PNLM1B2P08"}
513
+ #
514
+ # PS: http://docs.amazonwebservices.com/Route53/latest/APIReference/API_ChangeResourceRecordSets.html
515
+ #
516
+ def delete_resource_record_sets(hosted_zone_aws_id, resource_record_sets, comment = '')
517
+ resource_record_sets.each{|rrs| rrs[:action] = :delete}
518
+ change_resource_record_sets(hosted_zone_aws_id, resource_record_sets, comment)
519
+ end
520
+
521
+
522
+ # Get the current state of a change request.
523
+ #
524
+ # r53.get_change("/change/C1PN1SDWZKPTAC") #=>
525
+ # {:status=>"INSYNC",
526
+ # :aws_id=>"/change/C1PN1SDWZKPTAC",
527
+ # :submitted_at=>"2011-01-18T15:45:45.060Z"}
528
+ #
529
+ # PS: http://docs.amazonwebservices.com/Route53/latest/APIReference/API_GetChange.html
530
+ #
531
+ def get_change(change_aws_id)
532
+ link = generate_request('GET', expand_change_id(change_aws_id))
533
+ request_info(link, GetChangeParser.new(:logger => @logger))
534
+ end
535
+
536
+ #-----------------------------------------------------------------
537
+ # Hosted Zones
538
+ #-----------------------------------------------------------------
539
+
540
+ class ListHostedZonesParser < RightAWSParser # :nodoc:
541
+ def reset
542
+ @result = { :items => [] }
543
+ end
544
+ def tagstart(name, attributes)
545
+ case name
546
+ when 'HostedZone' then @item = { :config => {} }
547
+ end
548
+ end
549
+ def tagend(name)
550
+ case name
551
+ when 'IsTruncated' then @result[:is_truncated] = @text == 'true'
552
+ when 'NextMarker' then @result[:next_marker] = @text
553
+ when 'MaxItems' then @result[:max_items] = @text.to_i
554
+ when 'Id' then @item[:aws_id] = @text
555
+ when 'Name' then @item[:name] = @text
556
+ when 'CallerReference' then @item[:caller_reference] = @text
557
+ when 'HostedZone' then @result[:items] << @item
558
+ else
559
+ case full_tag_name
560
+ when %r{/Config/Comment$} then @item[:config][:comment] = @text
561
+ end
562
+ end
563
+ end
564
+ end
565
+
566
+ class GetHostedZoneParser < RightAWSParser # :nodoc:
567
+ def reset
568
+ @result = {}
569
+ end
570
+ def tagend(name)
571
+ case full_tag_name
572
+ when %r{/HostedZone/Id} then @result[:aws_id] = @text
573
+ when %r{/HostedZone/Name} then @result[:name] = @text
574
+ when %r{/HostedZone/CallerReference} then @result[:caller_reference] = @text
575
+ when %r{/Config/Comment$} then (@result[:config] ||= {})[:comment] = AwsUtils::xml_unescape(@text)
576
+ when %r{/ChangeInfo/Id$} then (@result[:change_info] ||= {})[:aws_id] = @text
577
+ when %r{/ChangeInfo/Status$} then (@result[:change_info] ||= {})[:status] = @text
578
+ when %r{/ChangeInfo/SubmittedAt$} then (@result[:change_info] ||= {})[:submitted_at] = @text
579
+ when %r{/DelegationSet/NameServers/NameServer$} then (@result[:name_servers] ||= []) << @text
580
+ end
581
+ end
582
+ end
583
+
584
+ #-----------------------------------------------------------------
585
+ # Resource Records Set
586
+ #-----------------------------------------------------------------
587
+
588
+ class ListResourceRecordSetsParser < RightAWSParser # :nodoc:
589
+ def reset
590
+ @result = { :items => [] }
591
+ end
592
+ def tagstart(name, attributes)
593
+ case name
594
+ when 'ResourceRecordSet' then @item = {}
595
+ end
596
+ end
597
+ def tagend(name)
598
+ case name
599
+ when 'IsTruncated' then @result[:is_truncated] = @text == 'true'
600
+ when 'NextRecordName' then @result[:next_record_name] = @text
601
+ when 'NextRecordType' then @result[:next_record_type] = @text
602
+ when 'MaxItems' then @result[:max_items] = @text.to_i
603
+ when 'Type' then @item[:type] = @text
604
+ when 'Name' then @item[:name] = @text
605
+ when 'TTL' then @item[:ttl] = @text.to_i
606
+ when 'ResourceRecordSet' then @result[:items] << @item
607
+ else
608
+ case full_tag_name
609
+ when %r{/ResourceRecord/Value} then (@item[:resource_records] ||= []) << @text
610
+ end
611
+ end
612
+ end
613
+ end
614
+
615
+ class GetChangeParser < RightAWSParser # :nodoc:
616
+ def reset
617
+ @result = { }
618
+ end
619
+ def tagend(name)
620
+ case name
621
+ when 'Id' then @result[:aws_id] = @text
622
+ when 'Status' then @result[:status] = @text
623
+ when 'SubmittedAt' then @result[:submitted_at] = @text
624
+ end
625
+ end
626
+ end
627
+
628
+ end
629
+
630
+ end