vzcdn 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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