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 +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
|