vzcdn 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 908fd60bab73ffcb6b51ee5800cf18bc1f342497
4
- data.tar.gz: e5977af1560fc83e7f2065c2665a70fc36faeec0
3
+ metadata.gz: 02c4b114ae9aa0f8eb6b7a62d71ad699ce670de7
4
+ data.tar.gz: 43df82ae708930fc0f98995b066339aa9ff7866a
5
5
  SHA512:
6
- metadata.gz: 1157b4228fd58982be432b0a67f1a3c73ed1cd7850a2fd6f584afd305f2b935e68a375583879c4936ec1e18940267f567235cbae7d93f6c235e6bf01874304b1
7
- data.tar.gz: f55a563fcb6999f967f4a14e3260635095275ec1191a734a23eb08c986e65e7a8978dffbc5e2de127bc5ca03870ef088036e02616e95aca68e8fdcabab93e166
6
+ metadata.gz: fca53d416484d65fd293e8d2dd894cc255b8604022da1b1b83cd2c9294f6bc81dd1f85093bcefb19d20a5a9c26a0d31751d27d92647f852ddfb5d04f274ce155
7
+ data.tar.gz: cbd0784e1a74d2240dc41d4fc7e5fef3c39cb68e86c3c9e2fdd0a2512a7b7a655d2589167f0fc4b500d92133108de948cbc13847e40d0857c82cd7bb5ee694d9
data/README.md CHANGED
@@ -4,6 +4,11 @@ Commandline UI for Edgecast API
4
4
 
5
5
  ##RELEASE NOTES
6
6
 
7
+ 2014/05/12 0.2.1
8
+ * CSV format support (ec zone <zname> print -t csv)
9
+ * Column Customization (ec zone <zname> print -c DomainName,ZoneId)
10
+ * IP address validations, 'diff' command, bind-file-to-add-zone script etc
11
+
7
12
  2014/05/02 0.2.0
8
13
  * Add/Update/Delete for groups/records/health-checks in zone.
9
14
  * Zone-list with local status
data/lib/args.rb CHANGED
@@ -88,7 +88,7 @@ class Arg
88
88
  def validate?(value, obj)
89
89
  vclass = @validator.class
90
90
  if vclass == Regexp
91
- test = (value =~ @validator)
91
+ test = value.full_match(@validator)
92
92
  on_error = "Invalid Format for " + @name
93
93
  elsif vclass == Array
94
94
  test = @validator.include? value
data/lib/bind2zone.sh ADDED
@@ -0,0 +1,44 @@
1
+ #!/bin/bash
2
+ set -o pipefail
3
+ if [ $# -ne 2 ]; then echo "Usage: $0 <bind file> <zone name>"; exit 1; fi
4
+ bindfile=$1
5
+ zonename=$2
6
+ ec zone create $zonename Active
7
+ if [ $? -eq 1 ]; then echo "Could not create zone."; exit 1; fi
8
+
9
+ tmpDir=$(mktemp -d tmpXXXXXX)
10
+ echo "tmpDir = $tmpDir"
11
+ cat $bindfile | awk -F '\t' 'BEGIN { OFS = "|"} $3 == "IN" {print $4,$1,$5,$2}' | while read line
12
+ do
13
+ name=$(echo $line | awk -F "|" '{print $2}')
14
+ args=$(echo $line | awk -F "|" '{print $1, $3, $4}')
15
+ #ec zone $zonename rec $rtype add $args
16
+ mkdir -p $tmpDir/$name
17
+ echo $args >> $tmpDir/$name/records
18
+ done
19
+
20
+ index=1
21
+ find $tmpDir -name records | while read file
22
+ do
23
+ recordCount=$(wc $file | awk '{ print $1 }')
24
+ rtype=$(cat $file | awk 'FNR == 1 {print $1}')
25
+ name=$(echo $file | awk -F "/" '{print $2}')
26
+ # echo "rtype=$rtype, name=$name, file=$file"
27
+ if [ $recordCount -eq 1 ]
28
+ then
29
+ args=$(cat $file | awk '{print $2, $3}' )
30
+ (ec zone $zonename rec $rtype add $name $args)
31
+ else
32
+ groupTtl=$(cat $file | awk 'FNR == 1 {print $3}')
33
+ (ec zone $zonename load add $name $groupTtl)
34
+ cat $file | while read line
35
+ do
36
+ rdata=$(echo $line | awk '{print $2}')
37
+ rtype=$(echo $line | awk '{print $1}')
38
+ (ec zone $zonename load $index group $rtype add 50 $rdata)
39
+ done
40
+ let "index = index + 1"
41
+ fi
42
+ done
43
+ # ec zone $zonename push
44
+ rm -rf tmpDir
data/lib/cloptions.rb CHANGED
@@ -4,6 +4,20 @@ class ClOptions
4
4
  @options = options
5
5
  end
6
6
 
7
+ def validate(value, option)
8
+ validator = option[:takes_value]
9
+ vclass = validator.class
10
+ if vclass == Regexp
11
+ if not value.full_match(validator)
12
+ raise "Invalid format for option --#{option[:long_name]}"
13
+ end
14
+ elsif vclass == Array
15
+ if not validator.include? value
16
+ raise "Invalid choice for option --#{option[:long_name]}, must be one of #{validator}"
17
+ end
18
+ end
19
+ end
20
+
7
21
  def handle_option(type, name, attached, nextarg)
8
22
  need_shift = false
9
23
  valid_option = false
@@ -14,6 +28,7 @@ class ClOptions
14
28
  if option[:takes_value]
15
29
  need_shift = attached.nil?
16
30
  if value
31
+ validate(value, option)
17
32
  @obj.send(option[:method], value)
18
33
  else
19
34
  return "value required for option"
data/lib/command.rb CHANGED
@@ -79,10 +79,33 @@ class Command
79
79
  end
80
80
  puts "Options:"
81
81
  @options.each { | o |
82
- puts " -#{o[:short_name]} or --#{o[:long_name]}" + (o[:takes_value] ? " (takes value)" : "")
82
+ puts " -#{o[:short_name]} or --#{o[:long_name]}" + option_help_string(o)
83
83
  }
84
84
  end
85
85
 
86
+ def option_help_string(option)
87
+ validator = option[:takes_value]
88
+ result = if validator
89
+ case [validator.class]
90
+ when [Array]
91
+ "one of #{validator}"
92
+ when [Regexp]
93
+ if option.has_key?(:regexp_description)
94
+ option[:regexp_description]
95
+ else
96
+ "(bug found no regexp_description)"
97
+ end
98
+ else
99
+ "(bug found unknown option validator class #{validator.class})"
100
+ end
101
+ end
102
+ if result && result.length > 0
103
+ "=<#{result}>"
104
+ else
105
+ ""
106
+ end
107
+ end
108
+
86
109
  def show_help_option
87
110
  show_help
88
111
  raise CancelExecution
data/lib/diff.rb CHANGED
@@ -1,80 +1,84 @@
1
1
  require 'json'
2
+ require_relative 'util'
2
3
 
3
4
  class Diff
4
- def initialize(old, new)
5
- @old = old
6
- @new = new
7
- @diffs = Hash.new([ ]) # entries will be "level" => [{ old: old_value, new: new_value, desc: description }, ...]
8
- end
5
+ @@term_width = nil
9
6
 
10
- def sprint_struct(struct)
11
- if (struct.class == Array)
12
- output = "[#{struct.length}]"
13
- elsif (struct.class == Hash)
14
- values = []
15
- # print top level elements of hash
16
- struct.keys.each { |key|
17
- value = struct[key]
18
- value = sprint_struct(value)
19
- values << "#{key}=#{value}"
20
- }
21
- output = values.join(", ")
22
- elsif (struct.nil?)
23
- return "null"
7
+ def self.term_width
8
+ if @@term_width
9
+ @@term_width
24
10
  else
25
- output = "#{struct}"
11
+ @@term_width, h = Util.detect_terminal_size
12
+ @@term_width
26
13
  end
27
- output
28
14
  end
29
15
 
30
- def add_diff(old, new, level)
31
- diffs = @diffs[level].clone
32
- diffs << {old: sprint_struct(old), new: sprint_struct(new)}
33
- @diffs[level] = diffs
16
+ def self.separator(fill_char, label)
17
+ term_width = Diff.term_width
18
+ filler_width = (term_width - label.length - 2) / 2
19
+ filler = ''
20
+ (1..filler_width).each { |i| filler = filler + fill_char }
21
+ line = filler + ' ' + label + ' ' + filler
22
+ if line.length < term_width
23
+ line = line + fill_char
24
+ end
25
+ line
34
26
  end
35
27
 
36
- def idiff(old, new, level)
37
- if old.class != new.class
38
- add_diff(old, new, level)
39
- return
28
+ def self.diff(old, old_name, new, new_name)
29
+ if old == new
30
+ return true
40
31
  end
41
- case [old.class]
42
- when [Array]
43
- num_to_check = [old.length, new.length].max
44
- for i in 0...num_to_check
45
- idiff(old[i], new[i], level + "[#{i+1}]")
46
- end
47
- when [Hash]
48
- old.keys.each { |key|
49
- idiff(old[key], new[key], level + ".#{key}")
50
- }
51
- else
52
- if old != new
53
- add_diff(old, new, level)
32
+ old_index = 0
33
+ new_index = 0
34
+ state = :matching
35
+ old_trigger_pulled = false
36
+ while old_index < old.length || new_index < new.length
37
+ old_line = old[old_index]
38
+ new_line = new[new_index]
39
+ case state
40
+ when :matching
41
+ if old_line == new_line
42
+ puts old_line
43
+ old_index += 1
44
+ new_index += 1
45
+ else
46
+ if old_line
47
+ state = :old
48
+ old_trigger_pulled = true
49
+ else
50
+ puts Diff.separator('>', new_name)
51
+ state = :old_eof
52
+ end
53
+ end
54
+ when :old
55
+ idx = new_line ? new[new_index..-1].find_index(old_line) : nil
56
+ if idx
57
+ idx += new_index
58
+ if idx > new_index
59
+ puts Diff.separator('>', new_name)
60
+ end
61
+ for i in new_index...idx
62
+ puts new[i]
63
+ end
64
+ puts Diff.separator('=', 'common')
65
+ new_index = idx
66
+ state = :matching
67
+ else
68
+ if old_trigger_pulled
69
+ puts Diff.separator('<', old_name)
70
+ old_trigger_pulled = false
71
+ end
72
+ puts old_line
73
+ old_index += 1
74
+ end
75
+ when :old_eof
76
+ if new_line
77
+ puts new_line
78
+ new_index += 1
79
+ end
54
80
  end
55
- end
56
- end
57
-
58
- def print_diffs
59
- @diffs.each { |level, diffs|
60
- puts "at level #{level}"
61
- diffs.each { |diff|
62
- puts " old: #{diff[:old]} | new: #{diff[:new]}"
63
- }
64
- }
65
- end
66
-
67
- def run
68
- idiff(@old, @new, "base")
69
- print_diffs
81
+ end
82
+ false
70
83
  end
71
84
  end
72
-
73
- file1 = ARGV[0]
74
- file2 = ARGV[1]
75
-
76
- old = JSON.parse(File.open(file1).read)
77
- new = JSON.parse(File.open(file2).read)
78
-
79
- diff = Diff.new(old, new)
80
- diff.run
data/lib/mkbind.sh CHANGED
@@ -45,7 +45,15 @@ while rtypes=$(ec zone $zname LoadBalancingGroups $lbgroup group | awk '{if (NR
45
45
  do
46
46
  echo ""
47
47
  echo ";-------------Load Balancing Group $lbgroup------------------"
48
- records_subcommand="ec zone $zname LoadBalancingGroups $lbgroup group xyxyxy Record"
49
- print_records
48
+ group_ttl=$(ec zone $zname LoadBalancingGroups $lbgroup print -cTTL -n)
49
+ group_name=$(ec zone $zname LoadBalancingGroups $lbgroup print -cName -n)
50
+ for rtype in $rtypes
51
+ do
52
+ rdatas=$(ec zone $zname LoadBalancingGroups $lbgroup group $rtype print -cRdata -n)
53
+ for rdata in $rdatas
54
+ do
55
+ echo "$group_name $group_ttl IN $rtype $rdata" | awk 'BEGIN {OFS="\t"} {print $1,$2,$3,$4,$5}'
56
+ done
57
+ done
50
58
  let "lbgroup = lbgroup + 1"
51
59
  done
data/lib/print.rb CHANGED
@@ -1,3 +1,4 @@
1
+ require 'csv'
1
2
  require_relative 'util'
2
3
  require_relative 'config_reader'
3
4
 
@@ -16,7 +17,7 @@ class TablePrint
16
17
  char_repeat(n, ' ')
17
18
  end
18
19
 
19
- def initialize(sep_char, *titles)
20
+ def set_titles(sep_char, titles)
20
21
  @ncols = titles.length
21
22
  @lines = [ ]
22
23
  @width = nil
@@ -24,7 +25,7 @@ class TablePrint
24
25
  @lines << titles
25
26
  end
26
27
 
27
- def append(*columns)
28
+ def append(columns)
28
29
  @lines << columns
29
30
  end
30
31
 
@@ -98,13 +99,10 @@ class TablePrint
98
99
  line
99
100
  end
100
101
 
101
- def print_table_normally(maxwidth, header)
102
+ def print_table_normally(maxwidth)
102
103
  @lines.each_with_index { |line, lineno|
103
- if lineno == 0 && ! header
104
- next
105
- end
106
104
  print_line_normally(maxwidth, line)
107
- if lineno == 0 && header
105
+ if lineno == 0
108
106
  print_line_normally(maxwidth, generate_separator_line(maxwidth))
109
107
  end
110
108
  }
@@ -114,7 +112,7 @@ class TablePrint
114
112
  char_repeat(width, @sep_char)
115
113
  end
116
114
 
117
- def print_staggered(maxwidth, term_width, header)
115
+ def print_staggered(maxwidth, term_width)
118
116
  minw = term_width
119
117
  maxwidth.each_with_index { |w, index|
120
118
  next if index == 0
@@ -124,9 +122,6 @@ class TablePrint
124
122
  @width = minw
125
123
  puts separator(term_width)
126
124
  @lines.each_with_index { |line, lineno|
127
- if lineno == 0 && ! header
128
- next
129
- end
130
125
  output = ""
131
126
  cols_left = Array.new(@ncols, true)
132
127
  while column = next_unprinted_column(cols_left)
@@ -172,7 +167,7 @@ class TablePrint
172
167
  }
173
168
  end
174
169
 
175
- def print_table(header = true)
170
+ def print_table
176
171
  return if @lines.nil?
177
172
  return if @ncols == 0
178
173
  if @ncols == 1
@@ -184,10 +179,10 @@ class TablePrint
184
179
  # will lines fit in terminal
185
180
  width_needed = maxwidth.reduce(:+) + (@ncols-1) * 2
186
181
  term_width, h = Util.detect_terminal_size
187
- if (width_needed <= term_width) || (not header)
188
- print_table_normally(maxwidth, header)
182
+ if (width_needed <= term_width)
183
+ print_table_normally(maxwidth)
189
184
  else
190
- print_staggered(maxwidth, term_width, header)
185
+ print_staggered(maxwidth, term_width)
191
186
  end
192
187
  end
193
188
 
@@ -196,65 +191,79 @@ end
196
191
  class StructurePrint
197
192
  include ConfigReader
198
193
 
199
- def initialize(sep_char)
194
+ def initialize(sep_char, header=true, format=nil, columns_to_print=nil)
200
195
  @sep_char = sep_char
196
+ @header = header
197
+ @format = format
198
+ @rownum = 0
199
+ @columns_to_print = columns_to_print
200
+
201
+ end
202
+
203
+ def indexes_from_column_names(names, struct)
204
+ result = [ ]
205
+ names.each { |name|
206
+ index = struct.keys.index name
207
+ if index.is_a? Integer
208
+ result << index
209
+ else
210
+ raise "column (#{name}) not found"
211
+ end
212
+ }
213
+ result
201
214
  end
202
215
 
203
- def get_indexes(level, key_array)
216
+ def get_indexes(level, struct)
217
+ result = (0...struct.keys.length).to_a
218
+ if @columns_to_print
219
+ if @columns_to_print == '*'
220
+ return result
221
+ end
222
+ column_names = @columns_to_print.split(',')
223
+ return indexes_from_column_names(column_names, struct)
224
+ end
204
225
  print_config_file = config_file("print.cfg")
205
226
  if File.exists? print_config_file
206
227
  level.gsub!(/\[\d*\]/, '')
207
228
  level_map = JSON.parse(File.open(print_config_file).read)
208
229
  if level_map.has_key? level
209
230
  column_names = level_map[level]
210
- result = []
211
- column_names.each { |name|
212
- index = key_array.index name
213
- result << index
214
- }
215
- return result
231
+ return indexes_from_column_names(column_names, struct)
216
232
  end
217
233
  end
218
- (0...key_array.length).to_a
234
+ result
219
235
  end
220
236
 
221
237
  def extract_printed_columns(indexes, values, index_value, add_index = false)
222
238
  print_values = []
223
- print_values << index_value.to_s if add_index
239
+ if add_index
240
+ print_values << index_value.to_s
241
+ end
224
242
  indexes.each { |index|
225
243
  print_values << values[index]
226
244
  }
227
245
  print_values
228
246
  end
229
247
 
230
- def structure_print(struct, level, header = true)
231
- istructure_print(struct, level, header)
248
+ def structure_print(struct, level)
249
+ if @header && @format.nil?
250
+ @table = TablePrint.new
251
+ end
232
252
  if $debug > 0
233
253
  puts "level = #{level}"
234
254
  end
235
- @table.print_table(header) if @table
255
+ istructure_print(struct, level)
256
+ @table.print_table if @table
236
257
  end
237
258
 
238
- def istructure_print(struct, level, header, add_index = false)
239
- if (struct.class == Array)
240
- struct.each_with_index { |elt, index|
241
- istructure_print(elt, level, header, struct.length > 1)
242
- header = false
243
- }
244
- elsif (struct.class == Hash)
245
- # print top level elements of hash
246
- indexes = get_indexes(level, struct.keys)
247
- if @table.nil?
248
- @table = TablePrint.new(@sep_char, *extract_printed_columns(indexes, struct.keys, "item", add_index))
249
- @rownum = 0
250
- end
259
+ def hash_element_array(hash)
251
260
  values = []
252
- struct.keys.each { |key|
253
- value = struct[key]
261
+ hash.keys.each { |key|
262
+ value = hash[key]
254
263
  if (value.nil?)
255
264
  value = "null"
256
265
  elsif (value.class == Array)
257
- value = "[" + value.length.to_s + "]"
266
+ value = "[#{value.length}]"
258
267
  elsif (value.class == String)
259
268
  elsif (value.class == Fixnum)
260
269
  value = value.to_s
@@ -265,12 +274,44 @@ class StructurePrint
265
274
  elsif value.class == FalseClass
266
275
  value = "false"
267
276
  else
268
- value = "<" + value.class.to_s + ">"
277
+ value = "<#{value.class}>"
269
278
  end
270
279
  values << value
271
280
  }
281
+ values
282
+ end
283
+
284
+ def print_values(values)
285
+ puts values.join("|")
286
+ end
287
+
288
+ def istructure_print(struct, level, add_index = false)
289
+ if (struct.class == Array)
290
+ struct.each_with_index { |elt, index|
291
+ istructure_print(elt, level, (struct.length > 1) && @columns_to_print.nil?)
292
+ }
293
+ elsif (struct.class == Hash)
294
+ # print top level elements of hash
295
+ if @titles.nil?
296
+ @titles = true
297
+ @indexes = get_indexes(level, struct)
298
+ titles = extract_printed_columns(@indexes, struct.keys, "item", add_index)
299
+ if @table
300
+ @table.set_titles(@sep_char, titles)
301
+ elsif @format == :csv && @header
302
+ puts titles.to_csv
303
+ end
304
+ end
305
+ values = hash_element_array(struct)
272
306
  @rownum += 1
273
- @table.append(*extract_printed_columns(indexes, values, @rownum, add_index))
307
+ values_to_print = extract_printed_columns(@indexes, values, @rownum, add_index)
308
+ if @table
309
+ @table.append(values_to_print)
310
+ elsif @format == :csv
311
+ puts values_to_print.to_csv
312
+ else
313
+ puts values_to_print.join("|")
314
+ end
274
315
  else
275
316
  puts struct.to_s
276
317
  end
data/lib/route.rb CHANGED
@@ -226,6 +226,7 @@ class Route
226
226
  end
227
227
 
228
228
  def xlate_name(symbol, name)
229
+ return nil if name.nil?
229
230
  get_available(symbol).each { |hash|
230
231
  if hash["Name"] == name
231
232
  return hash["Id"]
data/lib/vzcdn/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Vzcdn
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.1"
3
3
  end
data/lib/zone.rb CHANGED
@@ -7,6 +7,7 @@ require_relative 'zone_add'
7
7
  require_relative 'zone_update'
8
8
  require_relative 'zone_delete'
9
9
  require_relative 'zone_hc'
10
+ require_relative 'zone_diff'
10
11
 
11
12
  ZONEDIR="zones"
12
13
 
@@ -49,7 +50,7 @@ class ZonePull < Command
49
50
  end
50
51
 
51
52
  def add_options
52
- add_option({ short_name: 'f', long_name: 'file', method: :save_zone_to_file, takes_value: true})
53
+ add_option({ short_name: 'f', long_name: 'file', method: :save_zone_to_file, takes_value: /.*/, regexp_description: "file name"})
53
54
  end
54
55
 
55
56
  def execute(args, rest)
@@ -73,20 +74,35 @@ class ZoneAudit< Command
73
74
  end
74
75
 
75
76
  class ZonePrint < Command
77
+ def init
78
+ @header = true
79
+ @format = nil
80
+ end
81
+
76
82
  def add_options
77
- add_option({ short_name: 'j', long_name: 'json', method: :set_format, takes_value: false})
83
+ add_option({ short_name: 'j', long_name: 'json', method: :set_format_json, takes_value: false})
84
+ add_option({ short_name: 't', long_name: 'type', method: :set_format, takes_value: ["csv", "json"]})
78
85
  add_option({ short_name: 'n', long_name: 'no-header', method: :unset_header, takes_value: false})
86
+ add_option({ short_name: 'c', long_name: 'columns', method: :set_columns, takes_value: /[[:alpha:],]+|\*/, regexp_description: "comma separated column names, or * for all columns"})
79
87
  # add_option({ short_name: 'f', long_name: 'force-online', method: :force_online, takes_value: false})
80
88
  end
81
89
 
82
90
  def unset_header
83
- @no_header = true
91
+ @header = false
84
92
  end
85
93
 
86
- def set_format
94
+ def set_format_json
87
95
  @format = :json
88
96
  end
89
97
 
98
+ def set_format(format)
99
+ @format = format.to_sym
100
+ end
101
+
102
+ def set_columns(column_list)
103
+ @columns = column_list
104
+ end
105
+
90
106
  def execute(args, rest)
91
107
  struct = @input["struct"]
92
108
  level = @input["level"]
@@ -94,7 +110,7 @@ class ZonePrint < Command
94
110
  if @format == :json
95
111
  puts JSON.pretty_generate(struct)
96
112
  else
97
- StructurePrint.new(sep_char).structure_print(struct, level, (not @no_header))
113
+ StructurePrint.new(sep_char, @header, @format, @columns).structure_print(struct, level)
98
114
  end
99
115
  end
100
116
  end
@@ -147,6 +163,7 @@ class Zone < Command
147
163
  add_cmd(ZoneCreate, "create", "create new zone")
148
164
  add_cmd(ZoneDelete, "delete", "delete zone")
149
165
  add_cmd(ZoneSetHealthCheck, "sethc", "set health check for group member")
166
+ add_cmd(ZoneDiff, "diff", "show differences between (local, pulled, operational) versions of a zone")
150
167
  add_arg("zname", "name or id of zone", :alnum_not_command)
151
168
  add_arg("drill-down-param", "names of fields, or indexes of items, for drilling down", :alnum_not_command)
152
169
  end
@@ -158,6 +175,7 @@ class Zone < Command
158
175
  add_flow_from_usage("<zname> push")
159
176
  add_flow_from_usage("<zname> delete")
160
177
  add_flow_from_usage("<zname> audit")
178
+ add_flow_from_usage("<zname> diff")
161
179
  add_flow_from_usage("<zname> [<drill-down-param>...] add")
162
180
  add_flow_from_usage("<zname> [<drill-down-param>...] update")
163
181
  add_flow_from_usage("<zname> <drill-down-param>... delete")
@@ -213,7 +231,7 @@ class Zone < Command
213
231
  break
214
232
  elsif id && zonehash['ZoneId'].to_s == id
215
233
  name = zonehash_name
216
- puts "set_zone_file, name = #{name}, id = #{id}"
234
+ dputs "set_zone_file, name = #{name}, id = #{id}"
217
235
  break
218
236
  end
219
237
  }
@@ -322,12 +340,45 @@ class Zone < Command
322
340
  end
323
341
 
324
342
  def write_zone_to_single_file(zone, filename)
343
+ validate_zone(zone)
325
344
  File.delete(filename) if File.exists?(filename)
326
345
  File.open(filename, "w") { |file|
327
346
  file.write(JSON.pretty_generate zone)
328
347
  }
329
348
  end
330
349
 
350
+ def validate_zone(zone)
351
+ validate_records(zone["Records"])
352
+ zone["LoadBalancingGroups"].each { |group|
353
+ validate_records(group["Group"])
354
+ }
355
+ zone["FailoverGroups"].each { |group|
356
+ validate_records(group["Group"])
357
+ }
358
+ end
359
+
360
+ def validate_records(group)
361
+ group.each { |rtype, value|
362
+ re = case rtype.to_s
363
+ when "A"
364
+ /^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$/
365
+ when "AAAA"
366
+ /^(((?=.*(::))(?!.*\3.+\3))\3?|[\dA-F]{1,4}:)([\dA-F]{1,4}(\3|:\b)|\2){5}(([\dA-F]{1,4}(\3|:\b|$)|\2){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})\z/i
367
+ when "CNAME"
368
+ /[a-zA-Z]/
369
+ else
370
+ /.*/
371
+ end
372
+ value.each { |record|
373
+ if not record["Rdata"] =~ re
374
+ raise "Rdata '#{record["Rdata"]}' in wrong format for type #{rtype}"
375
+ #load orignal zone
376
+ zone = get_zone()
377
+ end
378
+ }
379
+ }
380
+ end
381
+
331
382
  def write_zone_file(zone, save_backup_ok)
332
383
  write_zone_to_single_file(zone, @zone_file)
333
384
  audit
data/lib/zone_add.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  class ZoneAdd < Command
2
2
  def create_args
3
3
  # for level zone.Records.?
4
- add_arg('name', 'Name of the node to which this record pertains', /[[:alnum:]]/)
4
+ add_arg('name', 'Name of the node to which this record pertains', /[[:alnum:]@]+/)
5
5
  add_arg('gname', 'Name of load balancing or failover group', /[[:alnum:]]+/)
6
6
  add_arg('rdata', 'Additional resource record data, such as IP Address', /.*/)
7
7
  add_arg('ttl', 'Time to live, in seconds', /\d+/)
@@ -75,7 +75,6 @@ class ZoneAdd < Command
75
75
  raise "should not happen"
76
76
  end
77
77
  struct << element
78
- StructurePrint.new("-").structure_print(struct, level)
79
78
  end
80
79
 
81
80
  def execute(arghash, rest)
@@ -85,5 +84,6 @@ class ZoneAdd < Command
85
84
  @zone_struct = @input["toplevel"]
86
85
  add_at_level(struct, level, arghash)
87
86
  zone.write_zone_file(@zone_struct, false)
87
+ StructurePrint.new("-").structure_print(struct, level)
88
88
  end
89
89
  end
data/lib/zone_diff.rb ADDED
@@ -0,0 +1,57 @@
1
+ require_relative 'diff'
2
+ require_relative 'command'
3
+
4
+ class ZoneDiff < Command
5
+ include ConfigReader
6
+
7
+ def init
8
+ @versions = ["o", "operational", "p", "pulled", "l", "local"]
9
+ end
10
+
11
+ def create_args
12
+ add_arg("version1", "one version of zone", @versions)
13
+ add_arg("version2", "one version of zone", @versions)
14
+ end
15
+
16
+ def create_flows
17
+ add_flow_from_usage("[version1='local'] [version2='pulled']")
18
+ end
19
+
20
+ def expand_version_name(version)
21
+ result = version
22
+ if (version.length == 1)
23
+ @versions.each { |version_name|
24
+ if version_name.length > 1 && version[0] == version_name[0]
25
+ result = version_name
26
+ end
27
+ }
28
+ end
29
+ result
30
+ end
31
+
32
+ def get_zone_version(version)
33
+ case version
34
+ when "operational"
35
+ zone = @zone.get_zone(true)
36
+ result = JSON.pretty_generate(zone).split("\n")
37
+ when "pulled"
38
+ filename = config_file(@zone.zone_file)
39
+ result = IO.readlines(filename).map(&:chomp)
40
+ when "local"
41
+ filename = @zone.zone_file
42
+ result = IO.readlines(filename).map(&:chomp)
43
+ end
44
+ result
45
+ end
46
+
47
+ def execute(arghash, rest)
48
+ version1 = expand_version_name(arghash["version1"])
49
+ version2 = expand_version_name(arghash["version2"])
50
+ @zone = @input['zone']
51
+ zone1 = get_zone_version(version1)
52
+ zone2 = get_zone_version(version2)
53
+ if Diff.diff(zone1, version1, zone2, version2)
54
+ puts "no difference between #{version1} and #{version2}"
55
+ end
56
+ end
57
+ end
data/lib/zone_hc.rb CHANGED
@@ -50,8 +50,8 @@ class ZoneSetHealthCheck < Command
50
50
  'IPVersion' => arghash['ip-version'],
51
51
  'PortNumber' => nil,
52
52
  'ReintegrationMethodId' => arghash['reintegration-method'],
53
- 'Status' => 0,
54
- 'StatusName' => '',
53
+ 'Status' => 4,
54
+ 'StatusName' => 'Unknown',
55
55
  'Uri' => arghash['uri']
56
56
  }
57
57
  else
@@ -66,13 +66,13 @@ class ZoneSetHealthCheck < Command
66
66
  'IPVersion' => nil,
67
67
  'PortNumber' => arghash['port'].to_i,
68
68
  'ReintegrationMethodId' => arghash['reintegration-method'],
69
- 'Status' => 0,
70
- 'StatusName' => '',
69
+ 'Status' => 4,
70
+ 'StatusName' => 'Unknown',
71
71
  'Uri' => ''
72
72
  }
73
73
  end
74
74
  struct['HealthCheck'] = hc
75
75
  StructurePrint.new("-").structure_print(struct['HealthCheck'], level+'.HealthCheck')
76
- zone.write_zone_file(@zone_struct)
76
+ zone.write_zone_file(@zone_struct, false)
77
77
  end
78
78
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vzcdn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Preston
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2014-05-02 00:00:00.000000000 Z
13
+ date: 2014-05-12 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rest-client
@@ -73,6 +73,7 @@ files:
73
73
  - bin/vzcdn
74
74
  - lib/args.rb
75
75
  - lib/argtest.rb
76
+ - lib/bind2zone.sh
76
77
  - lib/cloptions.rb
77
78
  - lib/clui_config.rb
78
79
  - lib/command.rb
@@ -98,6 +99,7 @@ files:
98
99
  - lib/zone.rb
99
100
  - lib/zone_add.rb
100
101
  - lib/zone_delete.rb
102
+ - lib/zone_diff.rb
101
103
  - lib/zone_hc.rb
102
104
  - lib/zone_update.rb
103
105
  - pkg/vzcdn-0.0.1.gem