route53 0.1.8 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.markdown CHANGED
@@ -6,7 +6,7 @@ This interface can either be used as a command line tool or as a library from wi
6
6
  Costs & Impact
7
7
  --------------
8
8
 
9
- At the time of this writing Amazon charges $1/zone/month. This includes zones that have been created and deleted and then recreated. The creator of this gem is not responsible for costs incurred while using this interface or unexpected oepration or bugs which may incur a cost for the user. The creator is also not responsible for any downtime incurred or disruption in service from the usage of this tool. DNS can be a tricky thing, be careful and always make sure you have a backup of your zone prior to mucking around with it. (route53 -l example.com.)
9
+ At the time of this writing Amazon charges $1/zone/month. This includes zones that have been created and deleted and then recreated outside of the normal 12 hour grace period. The creator of this gem is not responsible for costs incurred while using this interface or unexpected oepration or bugs which may incur a cost for the user. The creator is also not responsible for any downtime incurred or disruption in service from the usage of this tool. DNS can be a tricky thing, be careful and always make sure you have a backup of your zone prior to mucking around with it. (route53 -l example.com.)
10
10
 
11
11
  Latest Version
12
12
  --------------
@@ -43,10 +43,10 @@ The first time you run the gem in command line mode you'll be prompted to setup.
43
43
  Please answer the following prompts.
44
44
  Amazon Access Key: []
45
45
  Amazon Secret Key: []
46
- Amazon Route 53 API Version: [2010-10-01]
47
- Amazon Route 53 Endpoint: [https://route53.amazonaws.com/]
48
- Default TTL: [3600]
49
- Save the configuration file to "~/.route53"?: [Y]
46
+ Amazon Route 53 API Version: [2011-05-05]
47
+ Amazon Route 53 Endpoint: [https://route53.amazonaws.com/]
48
+ Default TTL: [3600]
49
+ Save the configuration file to "~/.route53"?: [Y]
50
50
 
51
51
  Command Line Options
52
52
  --------------------
@@ -66,15 +66,19 @@ Command Line Options
66
66
  --name [NAME] Specify a name for a record
67
67
  --type [TYPE] Specify a type for a record
68
68
  --ttl [TTL] Specify a TTL for a record
69
+ --weight [WEIGHT] Specify a Weight for a record
70
+ --ident [IDENTIFIER] Specify a unique identifier for a record
69
71
  --values [VALUE1],[VALUE2],[VALUE3]
70
72
  Specify one or multiple values for a record
73
+ --zone-apex-id [ZONE_APEX_ID]
74
+ Specify a zone apex if for the record
71
75
  -m, --comment [COMMENT] Provide a comment for this operation
72
76
  --no-wait Do not wait for actions to finish syncing.
73
77
  -s, --setup Run the setup ptogram to create your configuration file.
74
78
  -f, --file [CONFIGFILE] Specify a configuration file to use
75
79
  --access [ACCESSKEY] Specify an access key on the command line.
76
80
  --secret [SECRETKEY] Specify a secret key on the command line. WARNING: Not a good idea
77
-
81
+ --no-upgrade Do not automatically upgrade the route53 api spec for this version.
78
82
 
79
83
  Command Line Usage
80
84
  ------------------
@@ -100,9 +104,20 @@ Once route53 is installed, started and has been setup you're ready to start. You
100
104
  #If updating values for a record, make sure to includ all other values. Otherwise they will be dropped
101
105
  route53 --zone example.com. -g --ttl 600
102
106
 
107
+ #Creating a record that corresponds to an Amazon ELB (zone apex support)
108
+ route53 --zone example.com. -c --name example. --zone-apex-id Z3DZXE0XXXXXXX --type A --values my-load-balancer-XXXXXXX.us-east-1.elb.amazonaws.com
109
+
110
+ #Creating weighted record sets
111
+ route53 example.com. -c --name www.example.com. --weight 15 --ident "75 percent of traffic to pool1" --type CNAME --values pool1.example.com.
112
+ route53 example.com. -c --name www.example.com. --weight 5 --ident "25 percent of traffic to pool2" --type CNAME --values pool2.example.com.
113
+
114
+ #Creating a wildcard domain
115
+ route53 example.com. -c --name *.example.com --type CNAME --values pool1.example.com.
116
+
103
117
  #Deleting a zone - First remove all records except the NS and SOA record. Then delete the zone.
104
118
  route53 --zone example.com. -r
105
119
  route53 -d example.com.
120
+
106
121
 
107
122
  Library Usage
108
123
  -------------
data/lib/route53.rb CHANGED
@@ -19,7 +19,7 @@ module Route53
19
19
  attr_reader :endpoint
20
20
  attr_reader :verbose
21
21
 
22
- def initialize(accesskey,secret,api='2010-10-01',endpoint='https://route53.amazonaws.com/',verbose=false)
22
+ def initialize(accesskey,secret,api='2011-05-05',endpoint='https://route53.amazonaws.com/',verbose=false)
23
23
  @accesskey = accesskey
24
24
  @secret = secret
25
25
  @api = api
@@ -165,14 +165,23 @@ module Route53
165
165
  #puts "Name:"+record.search("Name").first.innerText if @conn.verbose
166
166
  #puts "Type:"+record.search("Type").first.innerText if @conn.verbose
167
167
  #puts "TTL:"+record.search("TTL").first.innerText if @conn.verbose
168
- record.search("Value").each do |val|
169
- #puts "Val:"+val.innerText if @conn.verbose
170
- end
168
+ #record.search("Value").each do |val|
169
+ # #puts "Val:"+val.innerText if @conn.verbose
170
+ #end
171
+ zone_apex_records = record.search("HostedZoneId")
172
+ values = record.search("Value").map { |val| val.innerText }
173
+ values << record.search("DNSName").first.innerText unless zone_apex_records.empty?
174
+ weight_records = record.search("Weight")
175
+ ident_records = record.search("SetIdentifier")
171
176
  dom_records.push(DNSRecord.new(record.search("Name").first.innerText,
172
177
  record.search("Type").first.innerText,
173
- record.search("TTL").first.innerText,
174
- record.search("Value").map { |val| val.innerText },
175
- self))
178
+ (record.search("TTL").first.innerText if zone_apex_records.empty?),
179
+ values,
180
+ self,
181
+ (zone_apex_records.first.innerText unless zone_apex_records.empty?),
182
+ (weight_records.first.innerText unless weight_records.empty?),
183
+ (ident_records.first.innerText unless ident_records.empty?)
184
+ ))
176
185
  end
177
186
 
178
187
  truncated = (zone_file.search("IsTruncated").first.innerText == "true")
@@ -230,7 +239,7 @@ module Route53
230
239
 
231
240
 
232
241
  def initialize(resp,conn)
233
- @raw_data = resp
242
+ @raw_data = unescape(resp)
234
243
  if error?
235
244
  $stderr.puts "ERROR: Amazon returned an error for the request."
236
245
  $stderr.puts "ERROR: RAW_XML: "+@raw_data
@@ -291,6 +300,10 @@ module Route53
291
300
  def to_s
292
301
  return @raw_data
293
302
  end
303
+
304
+ def unescape(string)
305
+ string.gsub(/\\0(\d{2})/) { $1.oct.chr }
306
+ end
294
307
  end
295
308
 
296
309
  class DNSRecord
@@ -298,16 +311,22 @@ module Route53
298
311
  attr_reader :type
299
312
  attr_reader :ttl
300
313
  attr_reader :values
314
+ attr_reader :weight
315
+ attr_reader :ident
316
+ attr_reader :zone_apex
301
317
 
302
- def initialize(name,type,ttl,values,zone)
318
+ def initialize(name,type,ttl,values,zone,zone_apex=nil,weight=nil,ident=nil)
303
319
  @name = name
304
320
  unless @name.end_with?(".")
305
321
  @name += "."
306
322
  end
307
- @type = type
308
- @ttl = ttl.upcase
323
+ @type = type.upcase
324
+ @ttl = ttl
309
325
  @values = values
310
326
  @zone = zone
327
+ @zone_apex = zone_apex
328
+ @weight = weight
329
+ @ident = ident
311
330
  end
312
331
 
313
332
  def gen_change_xml(xml,action)
@@ -316,14 +335,23 @@ module Route53
316
335
  change.ResourceRecordSet { |record|
317
336
  record.Name(@name)
318
337
  record.Type(@type)
319
- record.TTL(@ttl)
320
- record.ResourceRecords { |resources|
321
- @values.each { |val|
322
- resources.ResourceRecord { |record|
323
- record.Value(val)
338
+ record.SetIdentifier(@ident) if @ident
339
+ record.Weight(@weight) if @weight
340
+ record.TTL(@ttl) unless @zone_apex
341
+ if @zone_apex
342
+ record.AliasTarget { |targets|
343
+ targets.HostedZoneId(@zone_apex)
344
+ targets.DNSName(@values.first)
345
+ }
346
+ else
347
+ record.ResourceRecords { |resources|
348
+ @values.each { |val|
349
+ resources.ResourceRecord { |record|
350
+ record.Value(val)
351
+ }
324
352
  }
325
353
  }
326
- }
354
+ end
327
355
  }
328
356
  }
329
357
  end
@@ -337,12 +365,13 @@ module Route53
337
365
  end
338
366
 
339
367
  #Need to modify to a param hash
340
- def update(name,type,ttl,values,comment=nil)
368
+ def update(name,type,ttl,values,comment=nil, zone_apex = nil)
341
369
  prev = self.clone
342
370
  @name = name unless name.nil?
343
371
  @type = type unless type.nil?
344
372
  @ttl = ttl unless ttl.nil?
345
373
  @values = values unless values.nil?
374
+ @zone_apex = zone_apex unless zone_apex.nil?
346
375
  @zone.perform_actions([
347
376
  {:action => "DELETE", :record => prev},
348
377
  {:action => "CREATE", :record => self},
@@ -351,20 +380,28 @@ module Route53
351
380
 
352
381
  #Returns the raw array so the developer can update large batches manually
353
382
  #Need to modify to a param hash
354
- def update_dirty(name,type,ttl,values)
383
+ def update_dirty(name,type,ttl,values,zone_apex = nil)
355
384
  prev = self.clone
356
385
  @name = name unless name.nil?
357
386
  @type = type unless type.nil?
358
387
  @ttl = ttl unless ttl.nil?
359
388
  @values = values unless values.nil?
389
+ @zone_apex = zone_apex unless zone_apex.nil?
360
390
  return [{:action => "DELETE", :record => prev},
361
391
  {:action => "CREATE", :record => self}]
362
392
  end
363
393
 
364
394
  def to_s
365
- return "#{@name} #{@type} #{@ttl} #{@values.join(",")}"
395
+ if @weight
396
+ "#{@name} #{@type} #{@ttl} '#{@ident}' #{@weight} #{@values.join(",")}"
397
+ elsif @zone_apex
398
+ "#{@name} #{@type} #{@zone_apex} #{@values.join(",")}"
399
+ else
400
+ "#{@name} #{@type} #{@ttl} #{@values.join(",")}"
401
+ end
366
402
  end
367
403
  end
404
+
368
405
  end
369
406
 
370
407
  $messages = { "InvalidClientTokenId" => "You may have a missing or incorrect secret or access key. Please double check your configuration files and amazon account",
@@ -373,7 +410,7 @@ end
373
410
  "Other" => "It looks like you've run into an unhandled error. Please send a detailed bug report with the entire input and output from the program to support@50projects.com or to https://github.com/pcorliss/ruby_route_53/issues and we'll do out best to help you.",
374
411
  "SignatureDoesNotMatch" => "It looks like your secret key is incorrect or no longer valid. Please check your amazon account information for the proper key.",
375
412
  "HostedZoneNotEmpty" => "You'll need to first delete the contents of this zone. You can do so using the '--remove' option as part of the command line interface.",
376
- "InvalidChangeBatch" => "You may have tried to delete a NS or SOA record. This error is safe to ignore if you're just trying to delete all records as part of a zone prior to deleting the zone. Otherwise please file a bug by sending a detailed bug report with the entire input and output from the program to support@50projects.com or to https://github.com/pcorliss/ruby_route_53/issues and we'll do out best to help you.",
413
+ "InvalidChangeBatch" => "You may have tried to delete a NS or SOA record. This error is safe to ignore if you're just trying to delete all records as part of a zone prior to deleting the zone. Or you may have tried to create a record that already exists. Otherwise please file a bug by sending a detailed bug report with the entire input and output from the program to support@50projects.com or to https://github.com/pcorliss/ruby_route_53/issues and we'll do out best to help you.",
377
414
  "ValidationError" => "Check over your input again to make sure the record to be created is valid. The error message should give you some hints on what went wrong. If you're still having problems please file a bug by sending a detailed bug report with the entire input and output from the program to support@50projects.com or to https://github.com/pcorliss/ruby_route_53/issues and we'll do out best to help you."}
378
415
 
379
416
 
data/lib/route53/cli.rb CHANGED
@@ -35,7 +35,8 @@ module Route53
35
35
  puts "\nFinished at #{DateTime.now}" if @options.verbose
36
36
 
37
37
  else
38
- #puts "Usage Message"
38
+ puts "ERROR: Invalid Options passed. Please run with --help"
39
+ exit 1
39
40
  end
40
41
 
41
42
  end
@@ -57,13 +58,17 @@ module Route53
57
58
  opts.on('-z', '--zone [ZONE]', String, "Specify a zone to perform an operation on. Either in 'example.com.' or '/hostedzone/XXX' format") { |zone| @options.zone = zone }
58
59
 
59
60
  opts.on('-c', '--create', "Create a new record") { @options.create_record = true }
61
+
60
62
  opts.on('-r', '--remove', String, "Remove a record") { |record| @options.remove_record = true }
61
63
  opts.on('-g', '--change', String, "Change a record") { |record| @options.change_record = true }
62
64
 
63
65
  opts.on('--name [NAME]', String, "Specify a name for a record") { |name| @options.name = name }
64
66
  opts.on('--type [TYPE]', String, "Specify a type for a record") { |dnstype| @options.dnstype = dnstype }
65
67
  opts.on('--ttl [TTL]', String, "Specify a TTL for a record") { |ttl| @options.ttl = ttl }
68
+ opts.on('--weight [WEIGHT]', String, "Specify a Weight for a record") { |weight| @options.weight = weight }
69
+ opts.on('--ident [IDENTIFIER]', String, "Specify a unique identifier for a record") { |ident| @options.ident = ident }
66
70
  opts.on('--values [VALUE1],[VALUE2],[VALUE3]', Array, "Specify one or multiple values for a record") { |value| @options.values = value }
71
+ opts.on('--zone-apex-id [ZONE_APEX_ID]', String, "Specify a zone apex if for the record") { |zone_apex| @options.zone_apex = zone_apex }
67
72
 
68
73
  opts.on('-m', '--comment [COMMENT]', String, "Provide a comment for this operation") { |comment| @options.comment = comment }
69
74
 
@@ -74,10 +79,12 @@ module Route53
74
79
  opts.on('--access [ACCESSKEY]',String,"Specify an access key on the command line.") { |access| @options.access = access }
75
80
  opts.on('--secret [SECRETKEY]',String,"Specify a secret key on the command line. WARNING: Not a good idea") { |secret| @options.secret = secret }
76
81
 
82
+ opts.on('--no-upgrade',"Do not automatically upgrade the route53 api spec for this version.") { @options.no_upgrade = true }
83
+
77
84
  opts.parse!(@arguments) rescue return false
78
85
 
79
86
  process_options
80
- true
87
+ true
81
88
  end
82
89
 
83
90
  # Performs post-parse processing on options
@@ -180,7 +187,7 @@ module Route53
180
187
  puts "Zone Deleted." unless resp.error?
181
188
  end
182
189
  else
183
- $stderr.puts "ERROR: Couldn't Find Record for @options.zone."
190
+ $stderr.puts "ERROR: Couldn't Find Record for #{@options.zone}."
184
191
  end
185
192
  else
186
193
  required_options("delete zone",["--zone"])
@@ -197,7 +204,7 @@ module Route53
197
204
  zones.each do |z|
198
205
  puts "Creating Record"
199
206
  @options.ttl = @config['default_ttl'] if @options.ttl.nil?
200
- if @options.dnstype == 'TXT'
207
+ if @options.dnstype.upcase == 'TXT'
201
208
  @options.values = @options.values.map do |val|
202
209
  unless val.start_with?('"') && val.end_with?('"')
203
210
  val = '"' + val unless val.start_with? '"'
@@ -206,7 +213,7 @@ module Route53
206
213
  val
207
214
  end
208
215
  end
209
- record = Route53::DNSRecord.new(@options.name,@options.dnstype,@options.ttl,@options.values,z)
216
+ record = Route53::DNSRecord.new(@options.name,@options.dnstype,@options.ttl,@options.values,z,@options.zone_apex,@options.weight,@options.ident)
210
217
  puts "Creating Record #{record}"
211
218
  resps.push(record.create)
212
219
  end
@@ -215,7 +222,7 @@ module Route53
215
222
  puts "Record Created." unless resp.error?
216
223
  end
217
224
  else
218
- $stderr.puts "ERROR: Couldn't Find Record for @options.zone."
225
+ $stderr.puts "ERROR: Couldn't Find Record for #{@options.zone}."
219
226
  end
220
227
  else
221
228
  #$stderr.puts "ERROR: The following arguments are required for a create record operation."
@@ -243,11 +250,11 @@ module Route53
243
250
  puts "Record Deleted." unless resp.error?
244
251
  end
245
252
  else
246
- $stderr.puts "ERROR: Couldn't Find Record for @options.zone of type "+(@options.dnstype.nil? ? "ANY" : @options.dnstype)+"."
253
+ $stderr.puts "ERROR: Couldn't Find Record for #{@options.zone} of type "+(@options.dnstype.nil? ? "ANY" : @options.dnstype)+"."
247
254
  end
248
255
  end
249
256
  else
250
- $stderr.puts "ERROR: Couldn't Find Record for @options.zone."
257
+ $stderr.puts "ERROR: Couldn't Find Record for #{@options.zone}."
251
258
  end
252
259
  else
253
260
  #$stderr.puts "ERROR: The following arguments are required for a record removal operation."
@@ -263,7 +270,7 @@ module Route53
263
270
  if zones.size > 0
264
271
  zones.each do |z|
265
272
  records = z.get_records(@options.dnstype.nil? ? "ANY" : @options.dnstype)
266
- records = records.select { |rec| rec.name == @options.name } if @options.name
273
+ records = records.select { |rec| puts "Rec: #{rec.name}"; rec.name == @options.name } if @options.name
267
274
  if records.size > 0
268
275
  if records.size > 1
269
276
  records = record_picker(records,false)
@@ -275,11 +282,11 @@ module Route53
275
282
  puts "Record Modified." unless resp.error?
276
283
  end
277
284
  else
278
- $stderr.puts "ERROR: Couldn't Find Record for @options.zone of type "+(@options.dnstype.nil? ? "ANY" : @options.dnstype)+"."
285
+ $stderr.puts "ERROR: Couldn't Find Record for #{@options.name} of type "+(@options.dnstype.nil? ? "ANY" : @options.dnstype)+"."
279
286
  end
280
287
  end
281
288
  else
282
- $stderr.puts "ERROR: Couldn't Find Record for @options.zone."
289
+ $stderr.puts "ERROR: Couldn't Find Record for #{@options.name}."
283
290
  end
284
291
  else
285
292
  #$stderr.puts "ERROR: The following arguments are required for a record change operation."
@@ -304,7 +311,7 @@ module Route53
304
311
  new_config = Hash.new
305
312
  new_config['access_key'] = get_input(String,"Amazon Access Key")
306
313
  new_config['secret_key'] = get_input(String,"Amazon Secret Key")
307
- new_config['api'] = get_input(String,"Amazon Route 53 API Version","2010-10-01")
314
+ new_config['api'] = get_input(String,"Amazon Route 53 API Version","2011-05-05")
308
315
  new_config['endpoint'] = get_input(String,"Amazon Route 53 Endpoint","https://route53.amazonaws.com/")
309
316
  new_config['default_ttl'] = get_input(String,"Default TTL","3600")
310
317
  if get_input(true.class,"Save the configuration file to \"~/.route53\"?","Y")
@@ -406,6 +413,14 @@ module Route53
406
413
  unless @config
407
414
  @config = Hash.new
408
415
  end
416
+ if @config['api'] != '2011-05-05' && !@options.no_upgrade
417
+ puts "Note: Automatically setting your configuration file to the amazon route 53 api spec this program was written for. You can avoid this by passing --no-upgrade"
418
+ @config['api'] = '2011-05-05'
419
+ File.open(@options.file,'w') do |out|
420
+ YAML.dump(@config,out)
421
+ end
422
+ File.chmod(0600,@options.file)
423
+ end
409
424
  end
410
425
 
411
426
  def user_home
@@ -1,3 +1,3 @@
1
1
  module Route53
2
- VERSION = "0.1.8"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
8
- - 8
9
- version: 0.1.8
7
+ - 2
8
+ - 0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Philip Corliss
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-02-02 00:00:00 -06:00
17
+ date: 2011-05-30 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency