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 +4 -4
- data/README.md +5 -0
- data/lib/args.rb +1 -1
- data/lib/bind2zone.sh +44 -0
- data/lib/cloptions.rb +15 -0
- data/lib/command.rb +24 -1
- data/lib/diff.rb +70 -66
- data/lib/mkbind.sh +10 -2
- data/lib/print.rb +87 -46
- data/lib/route.rb +1 -0
- data/lib/vzcdn/version.rb +1 -1
- data/lib/zone.rb +57 -6
- data/lib/zone_add.rb +2 -2
- data/lib/zone_diff.rb +57 -0
- data/lib/zone_hc.rb +5 -5
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 02c4b114ae9aa0f8eb6b7a62d71ad699ce670de7
|
4
|
+
data.tar.gz: 43df82ae708930fc0f98995b066339aa9ff7866a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 = (
|
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
|
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
|
-
|
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
|
11
|
-
if
|
12
|
-
|
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
|
-
|
11
|
+
@@term_width, h = Util.detect_terminal_size
|
12
|
+
@@term_width
|
26
13
|
end
|
27
|
-
output
|
28
14
|
end
|
29
15
|
|
30
|
-
def
|
31
|
-
|
32
|
-
|
33
|
-
|
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
|
37
|
-
if old
|
38
|
-
|
39
|
-
return
|
28
|
+
def self.diff(old, old_name, new, new_name)
|
29
|
+
if old == new
|
30
|
+
return true
|
40
31
|
end
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
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
|
-
|
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
|
-
|
49
|
-
|
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
|
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(
|
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
|
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
|
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
|
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
|
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)
|
188
|
-
print_table_normally(maxwidth
|
182
|
+
if (width_needed <= term_width)
|
183
|
+
print_table_normally(maxwidth)
|
189
184
|
else
|
190
|
-
print_staggered(maxwidth, term_width
|
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,
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
231
|
-
|
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
|
-
|
255
|
+
istructure_print(struct, level)
|
256
|
+
@table.print_table if @table
|
236
257
|
end
|
237
258
|
|
238
|
-
def
|
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
|
-
|
253
|
-
value =
|
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 = "[
|
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 = "
|
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
|
-
|
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
data/lib/vzcdn/version.rb
CHANGED
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:
|
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: :
|
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
|
-
@
|
91
|
+
@header = false
|
84
92
|
end
|
85
93
|
|
86
|
-
def
|
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
|
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
|
-
|
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' =>
|
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' =>
|
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.
|
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-
|
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
|