vzcdn 0.1.7 → 0.1.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +4 -0
- data/bin/ec +2 -1
- data/bin/vzcdn +2 -1
- data/lib/args.rb +142 -183
- data/lib/clui_config.rb +33 -18
- data/lib/command.rb +66 -45
- data/lib/common.rb +16 -2
- data/lib/config_handler.rb +0 -1
- data/lib/proxy_credentials.rb +30 -0
- data/lib/route.rb +6 -3
- data/lib/vzcdn.rb +6 -5
- data/lib/vzcdn/version.rb +1 -1
- data/lib/zone.rb +138 -81
- data/lib/zone_add.rb +36 -0
- 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: 5defb8c0d907a56ce79b0d129ca104687c4e1db1
|
4
|
+
data.tar.gz: 122ceba67885edbdacba2d6178b1cc3a2889afef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 432815ea229141614d538475134234d79412b2e1d402b0a0de6b393aa744fafd8ce5c008996591b3815dcae8b3e119232b86c042928e0865a33bba5d1817552f
|
7
|
+
data.tar.gz: 24e95955bbeff970bead4b7061f8d38952a36abe86f273cb3922a2fb6c6a809a458c545958c7e9948bb42b65143de2191522267cf38f2a7077a1e67ce6364ed3
|
data/README.md
CHANGED
@@ -4,6 +4,10 @@ Commandline UI for Edgecast API
|
|
4
4
|
|
5
5
|
##RELEASE NOTES
|
6
6
|
|
7
|
+
2014/04/22 0.1.8
|
8
|
+
* Create zone support
|
9
|
+
* Add record support
|
10
|
+
|
7
11
|
2014/04/17 0.1.7
|
8
12
|
* Default action - print
|
9
13
|
* Presentation changes for zone display ( <object> to "...", array elements to [num] etc)
|
data/bin/ec
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
require 'vzcdn'
|
4
4
|
|
5
|
+
# $debug = true
|
6
|
+
|
5
7
|
def add_prefix(prefix, text)
|
6
8
|
result = ""
|
7
9
|
text.each_line { |line|
|
@@ -18,7 +20,6 @@ end
|
|
18
20
|
|
19
21
|
begin
|
20
22
|
VzcdnApp.new("vzcdn", "vzcdn").run(ARGV)
|
21
|
-
|
22
23
|
exit 0
|
23
24
|
rescue Exception => e
|
24
25
|
if e.class != SystemExit
|
data/bin/vzcdn
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
require 'vzcdn'
|
4
4
|
|
5
|
+
# $debug = true
|
6
|
+
|
5
7
|
def add_prefix(prefix, text)
|
6
8
|
result = ""
|
7
9
|
text.each_line { |line|
|
@@ -18,7 +20,6 @@ end
|
|
18
20
|
|
19
21
|
begin
|
20
22
|
VzcdnApp.new("vzcdn", "vzcdn").run(ARGV)
|
21
|
-
|
22
23
|
exit 0
|
23
24
|
rescue Exception => e
|
24
25
|
if e.class != SystemExit
|
data/lib/args.rb
CHANGED
@@ -1,37 +1,85 @@
|
|
1
1
|
require_relative 'route'
|
2
2
|
|
3
|
-
class
|
4
|
-
attr_accessor :
|
5
|
-
attr_reader :value
|
3
|
+
class Cell
|
4
|
+
attr_accessor :required, :repeatable, :value, :default
|
6
5
|
|
7
|
-
def initialize(
|
8
|
-
@
|
6
|
+
def initialize(object, hash = { })
|
7
|
+
@obj = object
|
9
8
|
hash.each {|k,v| instance_variable_set("@#{k}",v)}
|
10
9
|
if @repeatable
|
11
|
-
@
|
10
|
+
@value = [ ]
|
12
11
|
end
|
13
12
|
end
|
14
13
|
|
15
14
|
def full?
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
@full
|
16
|
+
end
|
17
|
+
|
18
|
+
def command
|
19
|
+
@obj.class <= Command ? @obj : nil
|
20
|
+
end
|
21
|
+
|
22
|
+
# return nil on success, error message on failure
|
23
|
+
def set(value, target)
|
24
|
+
case
|
25
|
+
when @obj.class == Arg
|
26
|
+
error = @obj.validate?(value, target)
|
27
|
+
if error
|
28
|
+
if @repeatable
|
29
|
+
@full = true
|
30
|
+
end
|
31
|
+
return error
|
32
|
+
end
|
33
|
+
if @obj.validator.class == Hash
|
34
|
+
value = @obj.validator[value]
|
35
|
+
end
|
36
|
+
if @repeatable
|
37
|
+
@value << value
|
38
|
+
else
|
39
|
+
@value = value
|
40
|
+
@full = true
|
41
|
+
end
|
42
|
+
when @obj.class <= Command
|
43
|
+
if value == @obj.name
|
44
|
+
@value = @obj
|
45
|
+
@full = true
|
46
|
+
else
|
47
|
+
return "incorrect command name"
|
48
|
+
end
|
20
49
|
end
|
50
|
+
nil
|
21
51
|
end
|
22
52
|
|
23
|
-
def
|
24
|
-
if @
|
25
|
-
@
|
26
|
-
@value << value
|
27
|
-
else
|
28
|
-
@value = value
|
53
|
+
def missing_value
|
54
|
+
if @value.nil? && @default
|
55
|
+
set(@default, nil)
|
29
56
|
end
|
57
|
+
return false unless @required
|
58
|
+
@value.nil?
|
30
59
|
end
|
31
60
|
|
32
|
-
|
33
|
-
|
61
|
+
def name
|
62
|
+
@obj.name
|
63
|
+
end
|
64
|
+
|
65
|
+
def desc
|
66
|
+
@obj.desc
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
34
70
|
|
71
|
+
class Arg
|
72
|
+
attr_reader :name, :desc, :validator
|
73
|
+
|
74
|
+
def initialize(name, desc, validator)
|
75
|
+
@name = name
|
76
|
+
@desc = desc
|
77
|
+
@validator = validator
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
# return nil on success
|
82
|
+
# error message on failure
|
35
83
|
def validate?(value, obj)
|
36
84
|
vclass = @validator.class
|
37
85
|
if vclass == Regexp
|
@@ -39,10 +87,10 @@ class Arg
|
|
39
87
|
on_error = "Invalid Format for " + @name
|
40
88
|
elsif vclass == Array
|
41
89
|
test = @validator.include? value
|
42
|
-
on_error = "Invalid choice for
|
90
|
+
on_error = "Invalid choice for #{@name}, must be one of #{@validator}"
|
43
91
|
elsif vclass == Hash
|
44
92
|
test = @validator.has_key? value
|
45
|
-
on_error = "Invalid choice for
|
93
|
+
on_error = "Invalid choice for #{@name}, must be one of #{@validator.keys}"
|
46
94
|
elsif vclass == String
|
47
95
|
result = {}
|
48
96
|
Route.new.send("get_available_" + @validator).each { |hash|
|
@@ -55,13 +103,12 @@ class Arg
|
|
55
103
|
test = false
|
56
104
|
end
|
57
105
|
elsif vclass == Symbol
|
58
|
-
|
106
|
+
if obj
|
107
|
+
on_error, test = obj.send(@validator, value)
|
108
|
+
end
|
59
109
|
else
|
60
110
|
test = false
|
61
|
-
on_error = "unknown type of validator
|
62
|
-
end
|
63
|
-
if not test && @repeatable
|
64
|
-
@full = true
|
111
|
+
on_error = "unknown type of validator:#{@validator}, class=#{@validator.class}"
|
65
112
|
end
|
66
113
|
if test
|
67
114
|
nil
|
@@ -72,162 +119,103 @@ class Arg
|
|
72
119
|
end
|
73
120
|
|
74
121
|
class Flow
|
75
|
-
|
76
|
-
|
77
|
-
def initialize(*args)
|
78
|
-
@root = nil
|
79
|
-
add(*args)
|
80
|
-
end
|
81
|
-
|
82
|
-
def iargs(node, args)
|
83
|
-
if node.nil?
|
84
|
-
return args
|
85
|
-
end
|
86
|
-
if (node.class == Arg)
|
87
|
-
if node.value
|
88
|
-
new_args = args.clone
|
89
|
-
new_args[node.name] = node.value
|
90
|
-
args = new_args
|
91
|
-
end
|
92
|
-
iargs(node.next_node, args)
|
93
|
-
elsif node.is_a? Command
|
94
|
-
args["command"] = node
|
95
|
-
return args
|
96
|
-
end
|
97
|
-
end
|
122
|
+
attr_accessor :usage_string
|
98
123
|
|
99
|
-
def
|
100
|
-
|
124
|
+
def initialize
|
125
|
+
@cells = [ ]
|
101
126
|
end
|
102
127
|
|
103
|
-
def
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
end
|
108
|
-
response
|
128
|
+
def add(*cells)
|
129
|
+
cells.each { |cell|
|
130
|
+
@cells << cell
|
131
|
+
}
|
109
132
|
end
|
110
133
|
|
111
|
-
def
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
error = validate_and_set(value, node)
|
120
|
-
if error && node.repeatable
|
121
|
-
return isetvalue(value, node.next_node)
|
134
|
+
def parse(args, obj = nil)
|
135
|
+
@target = obj
|
136
|
+
rest = [ ]
|
137
|
+
args.each_with_index { |arg, index|
|
138
|
+
name, value = Util.parse_line(arg)
|
139
|
+
if value.nil?
|
140
|
+
value = name
|
141
|
+
error, finished = setvalue(value)
|
122
142
|
else
|
123
|
-
|
143
|
+
error, finished = set(name, value)
|
124
144
|
end
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
return nil, nil
|
129
|
-
else
|
130
|
-
return "incorrect command name", nil
|
145
|
+
if error
|
146
|
+
result = add_errline(result, error)
|
147
|
+
finished = :finished
|
131
148
|
end
|
149
|
+
if finished
|
150
|
+
rest = args[index..-1]
|
151
|
+
break
|
152
|
+
end
|
153
|
+
}
|
154
|
+
missing = missing_args
|
155
|
+
unless missing.empty?
|
156
|
+
result = add_errline(result, "missing args: #{missing}")
|
132
157
|
end
|
158
|
+
# dputs "parse for class #{obj.class} result=#{result}, rest=#{rest}"
|
159
|
+
return result, rest
|
133
160
|
end
|
134
161
|
|
135
162
|
def setvalue(value)
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
def iset(name, value, node)
|
140
|
-
if node.nil?
|
141
|
-
return "could not find argument with name #{name}", :finished
|
142
|
-
end
|
143
|
-
if (node.class == Arg )
|
144
|
-
if (node.name == name)
|
145
|
-
error = validate_and_set(value, node)
|
146
|
-
return error, nil
|
163
|
+
@cells.each { |cell|
|
164
|
+
if cell.full?
|
165
|
+
next
|
147
166
|
else
|
148
|
-
|
167
|
+
error = cell.set(value, @target)
|
168
|
+
if error && cell.repeatable
|
169
|
+
next
|
170
|
+
end
|
171
|
+
return error, nil
|
149
172
|
end
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
# return true for success
|
154
|
-
# false for unable to find arg name
|
155
|
-
# String for invalid arg
|
156
|
-
def set(name, value)
|
157
|
-
iset(name, value, @root)
|
158
|
-
end
|
159
|
-
|
160
|
-
def iadd(arg, node)
|
161
|
-
if node.next_node.nil?
|
162
|
-
node.next_node = arg
|
163
|
-
else
|
164
|
-
iadd(arg, node.next_node)
|
165
|
-
end
|
173
|
+
}
|
174
|
+
return nil, :finished
|
166
175
|
end
|
167
176
|
|
168
|
-
def
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
iadd(arg, @root)
|
177
|
+
def missing_args
|
178
|
+
missing = [ ]
|
179
|
+
@cells.each { |cell|
|
180
|
+
if cell.missing_value
|
181
|
+
missing << cell.name
|
182
|
+
end
|
175
183
|
}
|
176
|
-
|
184
|
+
missing
|
177
185
|
end
|
178
186
|
|
179
|
-
def
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
187
|
+
def set(name, value)
|
188
|
+
@cells.each { |cell|
|
189
|
+
if cell.name == name
|
190
|
+
return cell.set(value, @target), nil
|
191
|
+
end
|
184
192
|
}
|
185
|
-
|
186
|
-
end
|
187
|
-
|
188
|
-
def print_flow(node)
|
189
|
-
if node.nil?
|
190
|
-
return
|
191
|
-
end
|
192
|
-
result = node.name + " - " + node.desc
|
193
|
-
if (node.value)
|
194
|
-
result += ":" + node.value
|
195
|
-
end
|
196
|
-
puts result
|
197
|
-
print_flow(node.next_node)
|
193
|
+
return "argument named #{name} not found", nil
|
198
194
|
end
|
199
195
|
|
200
|
-
def
|
201
|
-
|
202
|
-
|
203
|
-
names << (node.class == Arg ? "<#{node.name}>" : node.name)
|
204
|
-
desc << node.desc
|
205
|
-
iusage node.next_node, names, desc
|
196
|
+
def command
|
197
|
+
if @cells[-1]
|
198
|
+
@cells[-1].command
|
206
199
|
end
|
207
|
-
return names, desc
|
208
200
|
end
|
209
201
|
|
210
|
-
def
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
if (node.required) && (node.value.nil?)
|
218
|
-
missing << node.name
|
219
|
-
end
|
220
|
-
ivalidate node.next_node, missing
|
221
|
-
elsif node.is_a? Command
|
222
|
-
if node.required? && (not node.full?)
|
223
|
-
missing << node.name
|
224
|
-
end
|
225
|
-
end
|
226
|
-
missing
|
202
|
+
def arghash
|
203
|
+
result = { }
|
204
|
+
@cells.each { |cell|
|
205
|
+
result[cell.name] = cell.value
|
206
|
+
}
|
207
|
+
result["command"] = command
|
208
|
+
result
|
227
209
|
end
|
228
210
|
|
229
|
-
def
|
230
|
-
|
211
|
+
def usage
|
212
|
+
names = [ ]
|
213
|
+
desc = [ ]
|
214
|
+
@cells.each { |cell|
|
215
|
+
names << cell.name
|
216
|
+
desc << cell.desc
|
217
|
+
}
|
218
|
+
return names, desc
|
231
219
|
end
|
232
220
|
|
233
221
|
def add_errline(str, error)
|
@@ -237,33 +225,4 @@ class Flow
|
|
237
225
|
error
|
238
226
|
end
|
239
227
|
end
|
240
|
-
|
241
|
-
def parse(args, obj = nil)
|
242
|
-
result = nil
|
243
|
-
rest = [ ]
|
244
|
-
@target = obj
|
245
|
-
args.each_with_index { |arg, index|
|
246
|
-
name, value = Util.parse_line(arg)
|
247
|
-
if value.nil?
|
248
|
-
value = name
|
249
|
-
error, finished = setvalue(value)
|
250
|
-
else
|
251
|
-
error, finished = set(name, value)
|
252
|
-
end
|
253
|
-
|
254
|
-
if error
|
255
|
-
result = add_errline(result, error)
|
256
|
-
finished = :finished
|
257
|
-
end
|
258
|
-
if finished
|
259
|
-
rest = args[index...args.length]
|
260
|
-
break
|
261
|
-
end
|
262
|
-
}
|
263
|
-
missing = validate
|
264
|
-
if ! missing.empty?
|
265
|
-
result = add_errline(result, "missing args:" + missing.to_s)
|
266
|
-
end
|
267
|
-
return result, rest
|
268
|
-
end
|
269
228
|
end
|
data/lib/clui_config.rb
CHANGED
@@ -6,11 +6,13 @@ class ConfigInit < Command
|
|
6
6
|
|
7
7
|
include ConfigReader
|
8
8
|
|
9
|
+
def create_args
|
10
|
+
add_arg("acct-num", "EdgeCast account number", /[[:alnum:]]+/)
|
11
|
+
add_arg("token", "Web Services REST API Token (see my.edgecase.com)", /.*/)
|
12
|
+
end
|
13
|
+
|
9
14
|
def create_flows
|
10
|
-
|
11
|
-
flow.add(Arg.new("acct-num", desc: "EdgeCast account number", required: true, validator: /[[:alnum:]]+/))
|
12
|
-
flow.add(Arg.new("token", desc: "Web Services REST API Token (see my.edgecase.com)", required: true, validator: /.*/))
|
13
|
-
add_flow(flow)
|
15
|
+
add_flow_from_usage("<acct-num> <token>")
|
14
16
|
end
|
15
17
|
|
16
18
|
def execute(args, ignore)
|
@@ -29,10 +31,12 @@ class ConfigInit < Command
|
|
29
31
|
end
|
30
32
|
|
31
33
|
class ConfigGet < Command
|
34
|
+
def create_args
|
35
|
+
add_arg("param", "name of configuration parameter", /[-a-zA-Z]+/)
|
36
|
+
end
|
37
|
+
|
32
38
|
def create_flows
|
33
|
-
|
34
|
-
flow.add(Arg.new("param", desc: "name of configuration parameter", required: true, validator: /[-a-zA-Z]+/))
|
35
|
-
add_flow(flow)
|
39
|
+
add_flow_from_usage("<param>")
|
36
40
|
end
|
37
41
|
|
38
42
|
def execute(args, ignore)
|
@@ -42,10 +46,12 @@ class ConfigGet < Command
|
|
42
46
|
end
|
43
47
|
|
44
48
|
class ConfigDelete < Command
|
49
|
+
def create_args
|
50
|
+
add_arg("param", "name of configuration parameter", /[-a-zA-Z]+/)
|
51
|
+
end
|
52
|
+
|
45
53
|
def create_flows
|
46
|
-
|
47
|
-
flow.add(Arg.new("param", desc: "name of configuration parameter", required: true, validator: /[-a-zA-Z]+/))
|
48
|
-
add_flow(flow)
|
54
|
+
add_flow_from_usage("<param>")
|
49
55
|
end
|
50
56
|
|
51
57
|
def execute(args, ignore)
|
@@ -55,11 +61,13 @@ class ConfigDelete < Command
|
|
55
61
|
end
|
56
62
|
|
57
63
|
class ConfigSet < Command
|
64
|
+
def create_args
|
65
|
+
add_arg("param", "name of configuration parameter", /[-a-zA-Z]+/)
|
66
|
+
add_arg("value", "value of configuration parameter", /.*/)
|
67
|
+
end
|
68
|
+
|
58
69
|
def create_flows
|
59
|
-
|
60
|
-
flow.add(Arg.new("param", desc: "name of configuration parameter", required: true, validator: /[-a-zA-Z]+/))
|
61
|
-
flow.add(Arg.new("value", desc: "value of configuration parameter", required: true, validator: /.*/))
|
62
|
-
add_flow(flow)
|
70
|
+
add_flow_from_usage("<param> <value>")
|
63
71
|
end
|
64
72
|
|
65
73
|
def execute(args, ignore)
|
@@ -69,11 +77,18 @@ class ConfigSet < Command
|
|
69
77
|
end
|
70
78
|
|
71
79
|
class ConfigCommand < Command
|
80
|
+
def create_args
|
81
|
+
add_cmd(ConfigInit, "init", "initialize in current directory")
|
82
|
+
add_cmd(ConfigGet, "get", "print configuration parameter's value")
|
83
|
+
add_cmd(ConfigDelete, "delete", "delete configuration parameter")
|
84
|
+
add_cmd(ConfigSet, "set", "set (or reset) a configuration parameter to specified value")
|
85
|
+
end
|
86
|
+
|
72
87
|
def create_flows
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
88
|
+
add_flow_from_usage("init")
|
89
|
+
add_flow_from_usage("get")
|
90
|
+
add_flow_from_usage("delete")
|
91
|
+
add_flow_from_usage("set")
|
77
92
|
end
|
78
93
|
|
79
94
|
def execute(args, subargs)
|
data/lib/command.rb
CHANGED
@@ -12,36 +12,15 @@ class Command
|
|
12
12
|
@name = name
|
13
13
|
@desc = description
|
14
14
|
@options = [{ short_name: 'h', long_name: 'help', method: :show_help_option, takes_value: false }]
|
15
|
-
init
|
16
15
|
@flows = [ ]
|
17
|
-
@
|
16
|
+
@cellhash = { }
|
17
|
+
@subcommands = [ ]
|
18
|
+
@input = { }
|
19
|
+
|
20
|
+
init
|
18
21
|
add_options
|
19
22
|
create_args
|
20
23
|
create_flows
|
21
|
-
@args = nil
|
22
|
-
@full = false
|
23
|
-
@required = true
|
24
|
-
end
|
25
|
-
|
26
|
-
# TODO: make Flow keep track of next_node and fullness
|
27
|
-
def next_node
|
28
|
-
nil
|
29
|
-
end
|
30
|
-
|
31
|
-
def full?
|
32
|
-
return @full
|
33
|
-
end
|
34
|
-
|
35
|
-
def setfull
|
36
|
-
@full = true
|
37
|
-
end
|
38
|
-
|
39
|
-
def required?
|
40
|
-
@required
|
41
|
-
end
|
42
|
-
|
43
|
-
def required=(value)
|
44
|
-
@required = value
|
45
24
|
end
|
46
25
|
|
47
26
|
def init
|
@@ -53,7 +32,13 @@ class Command
|
|
53
32
|
def create_args
|
54
33
|
end
|
55
34
|
|
35
|
+
# default is to have one flow with no arguments
|
56
36
|
def create_flows
|
37
|
+
add_flow(Flow.new)
|
38
|
+
end
|
39
|
+
|
40
|
+
def add_input(name, value)
|
41
|
+
@input[name] = value
|
57
42
|
end
|
58
43
|
|
59
44
|
def add_option(option)
|
@@ -67,33 +52,69 @@ class Command
|
|
67
52
|
|
68
53
|
def show_help
|
69
54
|
puts "#{@name} - #{@desc}"
|
55
|
+
puts "Usage:"
|
70
56
|
@flows.each { |flow|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
if
|
81
|
-
|
82
|
-
|
57
|
+
puts " #{@name} #{flow.usage_string}"
|
58
|
+
}
|
59
|
+
puts "Where:"
|
60
|
+
@cellhash.each { |name,arg|
|
61
|
+
if arg.class == Arg
|
62
|
+
choice = ""
|
63
|
+
if arg.validator.class == String
|
64
|
+
error, ignore = arg.validate?("asdf", nil)
|
65
|
+
end
|
66
|
+
if arg.validator.class == Array
|
67
|
+
choice = " - value from #{arg.validator}"
|
68
|
+
elsif arg.validator.class == Hash
|
69
|
+
choice = " - value from #{arg.validator.keys}"
|
83
70
|
end
|
71
|
+
|
72
|
+
puts " #{arg.name} : #{arg.desc}#{choice}"
|
84
73
|
end
|
85
74
|
}
|
86
75
|
end
|
87
76
|
|
88
|
-
def add_arg(name,
|
89
|
-
|
77
|
+
def add_arg(name, desc, validator)
|
78
|
+
name = name.to_s
|
79
|
+
arg = Arg.new(name, desc, validator)
|
80
|
+
@cellhash[name] = arg
|
90
81
|
end
|
91
82
|
|
92
|
-
def
|
83
|
+
def add_cmd(cmd_class, name, desc)
|
84
|
+
name = name.to_s
|
85
|
+
cmd = cmd_class.new(name, desc)
|
86
|
+
@cellhash[name] = cmd
|
87
|
+
@subcommands << name
|
88
|
+
end
|
89
|
+
|
90
|
+
def command_name?(str)
|
91
|
+
@subcommands.include?(str.to_s)
|
92
|
+
end
|
93
|
+
|
94
|
+
def add_flow_from_usage(usage)
|
93
95
|
flow = Flow.new
|
94
|
-
|
95
|
-
|
96
|
-
|
96
|
+
flow.usage_string = usage
|
97
|
+
line = usage
|
98
|
+
re = /\A
|
99
|
+
( # matches one arg spec
|
100
|
+
(?<optional> \[)? # turn on 'optional' if we see an open square bracket
|
101
|
+
<?(?<argname> [[:alnum:]-]+)>? # argname is inside optional angle brackets and consists of alphanumerics and dashes
|
102
|
+
(=\'(?<default>[^\']+)\')? # default value has form ='value'
|
103
|
+
(?<repeatable> \s*\.\.\.)? # three dots turn on 'repeatable'
|
104
|
+
\]? # matching close square bracket
|
105
|
+
) # end of arg spec
|
106
|
+
\s* /x # skips white space
|
107
|
+
index = 0
|
108
|
+
while(m = re.match(line))
|
109
|
+
argname = m[:argname]
|
110
|
+
required = m[:optional].nil?
|
111
|
+
repeatable = (not m[:repeatable].nil?)
|
112
|
+
default = m[:default]
|
113
|
+
index = m.end(0)
|
114
|
+
line = line[index..-1]
|
115
|
+
cell = Cell.new(@cellhash[argname], required: required, repeatable: repeatable, default: default)
|
116
|
+
flow.add(cell)
|
117
|
+
end
|
97
118
|
add_flow(flow)
|
98
119
|
end
|
99
120
|
|
@@ -115,7 +136,7 @@ class Command
|
|
115
136
|
@flows.each { |flow|
|
116
137
|
error, rest = flow.parse args, self
|
117
138
|
if error.nil?
|
118
|
-
execute(flow.
|
139
|
+
execute(flow.arghash, rest)
|
119
140
|
return
|
120
141
|
end
|
121
142
|
}
|
data/lib/common.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'rest_client'
|
2
2
|
require 'json'
|
3
3
|
require 'config_reader'
|
4
|
+
require_relative 'proxy_credentials'
|
4
5
|
|
5
6
|
class CommonRestUtils
|
6
7
|
include ConfigReader
|
@@ -19,12 +20,25 @@ class CommonRestUtils
|
|
19
20
|
when :post
|
20
21
|
RestClient.post(url, json_body, @headers)
|
21
22
|
when :delete
|
22
|
-
RestClient.(url, @headers)
|
23
|
+
RestClient.delete(url, @headers)
|
23
24
|
else
|
24
25
|
"unsupported http method:" + http_method
|
25
26
|
end
|
26
27
|
rescue Exception => e
|
27
|
-
puts "
|
28
|
+
puts "Problem executing REST command to server " + param("rest_base_url")
|
29
|
+
puts e.message
|
30
|
+
puts "#{e.response}"
|
31
|
+
proxy_auth_req = (e.message =~ /\A407 /)
|
32
|
+
if e.message =~ /\A407 /
|
33
|
+
ProxyCredentials.proxy_credentials param("proxy")
|
34
|
+
if @proxy_retries && @proxy_retries > 3
|
35
|
+
raise e.message + " too many retries"
|
36
|
+
else
|
37
|
+
@proxy_retries = @proxy_retries ? @proxy_retries + 1 : 1
|
38
|
+
return callMethod(url_suffix, http_method, body)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
exit
|
28
42
|
if $debug
|
29
43
|
puts "full URL is:" + url
|
30
44
|
if (body)
|
data/lib/config_handler.rb
CHANGED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'rubygems/user_interaction'
|
3
|
+
|
4
|
+
class ProxyCredentials
|
5
|
+
include Gem::UserInteraction
|
6
|
+
def self.proxy_credentials(proxy)
|
7
|
+
new.get_credentials(proxy)
|
8
|
+
end
|
9
|
+
|
10
|
+
def get_credentials(proxy)
|
11
|
+
puts "need credentials for proxy #{proxy}"
|
12
|
+
uri = URI(proxy)
|
13
|
+
proxy_host = uri.hostname
|
14
|
+
proxy_port = uri.port
|
15
|
+
proxy_user = ask("username:")
|
16
|
+
proxy_password = ask_for_password("password:")
|
17
|
+
|
18
|
+
uri = URI("http://blogsearch.google.com/ping/RPC2")
|
19
|
+
req = Net::HTTP::Get.new(uri)
|
20
|
+
net = Net::HTTP.new(uri.hostname, uri.port, proxy_host, proxy_port, proxy_user, proxy_password)
|
21
|
+
puts "created net"
|
22
|
+
net.read_timeout = 20
|
23
|
+
net.open_timeout = 20
|
24
|
+
|
25
|
+
net.start { |http|
|
26
|
+
response = http.request(req)
|
27
|
+
puts "response code from internet web service is #{response.code}, message is #{response.message}"
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
data/lib/route.rb
CHANGED
@@ -110,6 +110,7 @@ class Route
|
|
110
110
|
return nil if zonelist.nil?
|
111
111
|
zonelist.each { |zone|
|
112
112
|
translate_value(:zone_status, zone, "Status")
|
113
|
+
translate_value(:zone_type, zone, "ZoneType")
|
113
114
|
}
|
114
115
|
end
|
115
116
|
|
@@ -136,16 +137,18 @@ class Route
|
|
136
137
|
end
|
137
138
|
|
138
139
|
def delete_zone(id)
|
139
|
-
suffix = customer_suffix("dns/routezone
|
140
|
+
suffix = customer_suffix("dns/routezone/#{id}")
|
140
141
|
@common.callMethod(suffix, :delete)
|
141
142
|
end
|
142
143
|
|
143
|
-
def add_zone()
|
144
|
+
def add_zone(zone)
|
145
|
+
suffix = customer_suffix("dns/routezone")
|
146
|
+
@common.callMethod(suffix, :post, zone)
|
144
147
|
end
|
145
148
|
|
146
149
|
def update_zone(zone)
|
147
150
|
suffix = customer_suffix("dns/routezone")
|
148
|
-
@common.callMethod(suffix, :put, zone)
|
151
|
+
@common.callMethod(suffix, :put, zone)
|
149
152
|
end
|
150
153
|
|
151
154
|
def xlate_name(symbol, name)
|
data/lib/vzcdn.rb
CHANGED
@@ -14,7 +14,8 @@ class VzcdnApp < Command
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def print_version
|
17
|
-
puts "vzcdn
|
17
|
+
puts "vzcdn Version:" + Vzcdn::VERSION
|
18
|
+
exit
|
18
19
|
end
|
19
20
|
|
20
21
|
def set_debug
|
@@ -22,13 +23,13 @@ class VzcdnApp < Command
|
|
22
23
|
end
|
23
24
|
|
24
25
|
def create_args
|
25
|
-
|
26
|
-
|
26
|
+
add_cmd(Zone, "zone", "dns zone command")
|
27
|
+
add_cmd(ConfigCommand, "config", "configuration control")
|
27
28
|
end
|
28
29
|
|
29
30
|
def create_flows
|
30
|
-
|
31
|
-
|
31
|
+
add_flow_from_usage("zone")
|
32
|
+
add_flow_from_usage("config")
|
32
33
|
end
|
33
34
|
|
34
35
|
def execute(args, subargs)
|
data/lib/vzcdn/version.rb
CHANGED
data/lib/zone.rb
CHANGED
@@ -3,26 +3,38 @@ require_relative 'util'
|
|
3
3
|
require_relative 'print'
|
4
4
|
require_relative 'command'
|
5
5
|
require_relative 'args'
|
6
|
+
require_relative 'zone_add'
|
6
7
|
|
7
8
|
class ZoneList < Command
|
8
|
-
def execute
|
9
|
-
|
9
|
+
def execute(args, rest)
|
10
|
+
zones = Route.do.get_all_zones
|
11
|
+
Route.do.translate_zonelist(zones)
|
12
|
+
StructurePrint.new('~').structure_print(zones, "zonelist")
|
10
13
|
end
|
11
14
|
end
|
12
15
|
|
13
16
|
class ZonePull < Command
|
14
|
-
def execute
|
17
|
+
def execute(args, rest)
|
18
|
+
zone = @input["zone"]
|
15
19
|
zone.pull
|
16
20
|
end
|
17
21
|
end
|
18
22
|
|
19
|
-
class
|
20
|
-
|
23
|
+
class ZonePush < Command
|
24
|
+
def execute(args, rest)
|
25
|
+
zone = @input["zone"]
|
26
|
+
zone.push
|
27
|
+
end
|
28
|
+
end
|
21
29
|
|
22
|
-
|
23
|
-
|
30
|
+
class ZoneDelete < Command
|
31
|
+
def execute(args, rest)
|
32
|
+
zone = @input["zone"]
|
33
|
+
zone.delete
|
24
34
|
end
|
35
|
+
end
|
25
36
|
|
37
|
+
class ZonePrint < Command
|
26
38
|
def add_options
|
27
39
|
add_option({ short_name: 'j', long_name: 'json', method: :set_format, takes_value: false})
|
28
40
|
# add_option({ short_name: 'f', long_name: 'force-online', method: :force_online, takes_value: false})
|
@@ -32,18 +44,43 @@ class ZonePrint < Command
|
|
32
44
|
@format = :json
|
33
45
|
end
|
34
46
|
|
35
|
-
def execute(args,
|
47
|
+
def execute(args, rest)
|
48
|
+
struct = @input["struct"]
|
49
|
+
level = @input["level"]
|
50
|
+
sep_char = @input["sep_char"]
|
36
51
|
if @format == :json
|
37
|
-
puts JSON.pretty_generate(
|
52
|
+
puts JSON.pretty_generate(struct)
|
38
53
|
else
|
39
|
-
StructurePrint.new(
|
54
|
+
StructurePrint.new(sep_char).structure_print(struct, level)
|
40
55
|
end
|
41
56
|
end
|
42
57
|
end
|
43
58
|
|
44
|
-
class
|
45
|
-
def
|
46
|
-
zone
|
59
|
+
class ZoneCreate < Command
|
60
|
+
def create_args
|
61
|
+
add_arg("name", "name of zone", /[[:alnum:]\.-]+/)
|
62
|
+
add_arg("comment", "zone comment", /.*/)
|
63
|
+
add_arg("status", "zone status", 'zone_statuses')
|
64
|
+
add_arg("type", "zone type", 'zone_types')
|
65
|
+
end
|
66
|
+
|
67
|
+
def create_flows
|
68
|
+
add_flow_from_usage("<name> <status> [comment] [type='Primary']")
|
69
|
+
end
|
70
|
+
|
71
|
+
def execute(arghash, rest)
|
72
|
+
name = arghash["name"]
|
73
|
+
if name[-1] != '.'
|
74
|
+
name = name + '.'
|
75
|
+
end
|
76
|
+
status = arghash["status"]
|
77
|
+
comment = arghash["comment"]
|
78
|
+
comment = "" if comment.nil?
|
79
|
+
type = arghash["type"]
|
80
|
+
puts "name = #{name}, comment=#{comment}, status=#{status}, type=#{type}"
|
81
|
+
zone = { "Comment" => comment, "DomainName" => name, "Status" => status, "ZoneType" => type, "Records" => {"A" => [] } }
|
82
|
+
puts "creating zone on server"
|
83
|
+
Route.do.add_zone(zone)
|
47
84
|
end
|
48
85
|
end
|
49
86
|
|
@@ -51,28 +88,31 @@ class Zone < Command
|
|
51
88
|
include ConfigReader
|
52
89
|
|
53
90
|
def create_args
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
add_arg(
|
62
|
-
add_arg(
|
91
|
+
add_cmd(ZoneList, "list", "list all owned zones")
|
92
|
+
add_cmd(ZonePull, "pull", "retrieve local copy of zone data")
|
93
|
+
add_cmd(ZonePush, "push", "push local changes to server")
|
94
|
+
add_cmd(ZonePrint, "print", "print zone data. ~~~~ online, ---- local copy")
|
95
|
+
add_cmd(ZoneAdd, "add", "add record/group/healthcheck")
|
96
|
+
add_cmd(ZoneCreate, "create", "create new zone")
|
97
|
+
add_cmd(ZoneDelete, "delete", "delete zone")
|
98
|
+
add_arg("zname", "name or id of zone", :alnum_not_command)
|
99
|
+
add_arg("drill-down-param", "names of fields, or indexes of items, for drilling down", :alnum_not_command)
|
63
100
|
end
|
64
101
|
|
65
102
|
def create_flows
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
103
|
+
add_flow_from_usage("list")
|
104
|
+
add_flow_from_usage("create")
|
105
|
+
add_flow_from_usage("<zname> pull")
|
106
|
+
add_flow_from_usage("<zname> push")
|
107
|
+
add_flow_from_usage("<zname> delete")
|
108
|
+
add_flow_from_usage("<zname> [<drill-down-param>...] add")
|
109
|
+
add_flow_from_usage("<zname> [<drill-down-param>...] [print]")
|
70
110
|
end
|
71
111
|
|
72
|
-
def
|
112
|
+
def alnum_not_command(value)
|
73
113
|
test = value =~ /[[:alnum:]]+/
|
74
114
|
if test
|
75
|
-
if
|
115
|
+
if command_name? value
|
76
116
|
return "name of command", false
|
77
117
|
else
|
78
118
|
return nil, true
|
@@ -81,36 +121,77 @@ class Zone < Command
|
|
81
121
|
return "invalid argument", false
|
82
122
|
end
|
83
123
|
|
84
|
-
def execute(args,
|
124
|
+
def execute(args, rest)
|
85
125
|
@zname = args["zname"]
|
86
126
|
command = args["command"]
|
87
127
|
ddparams = args["drill-down-param"]
|
88
128
|
if ddparams
|
89
|
-
@zname = ddparams.shift
|
90
129
|
zone = get_zone
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
command.
|
96
|
-
command.level = @level
|
97
|
-
command.sep_char = @sep_char
|
130
|
+
struct, level = drill_down(zone, ddparams, "zone")
|
131
|
+
command.add_input("struct", struct)
|
132
|
+
command.add_input("level", level)
|
133
|
+
command.add_input("sep_char", @sep_char)
|
134
|
+
command.add_input("toplevel", zone)
|
98
135
|
end
|
99
|
-
if command
|
100
|
-
command.
|
101
|
-
|
102
|
-
command.execute self
|
136
|
+
if command
|
137
|
+
command.add_input("zone", self)
|
138
|
+
command.run(rest)
|
103
139
|
else
|
104
140
|
raise "error"
|
105
141
|
end
|
106
142
|
end
|
107
143
|
|
108
|
-
def
|
109
|
-
|
110
|
-
|
111
|
-
|
144
|
+
def push
|
145
|
+
puts "pushing zone to server"
|
146
|
+
zone = get_zone
|
147
|
+
Route.do.untranslate_zone(zone)
|
148
|
+
if $debug
|
149
|
+
File.open("untranslated.zone","w").write(JSON.pretty_generate zone)
|
150
|
+
end
|
151
|
+
Route.do.update_zone(zone)
|
152
|
+
end
|
153
|
+
|
154
|
+
def local_filename(zone)
|
155
|
+
file_name = zone["DomainName"].sub(/\.\Z/, '')
|
156
|
+
file_name = file_name + '.' + zone["ZoneId"].to_s
|
157
|
+
end
|
158
|
+
|
159
|
+
def write_zone_file(zone, hide_dup = false)
|
160
|
+
basename = local_filename(zone)
|
161
|
+
if hide_dup
|
162
|
+
file_name = config_file("zones", basename)
|
163
|
+
File.delete(file_name) if File.exists?(file_name)
|
164
|
+
File.open(file_name, "w").write(JSON.pretty_generate zone)
|
165
|
+
end
|
166
|
+
file_name = user_file("zones", basename)
|
167
|
+
File.delete(file_name) if File.exists?(file_name)
|
168
|
+
File.open(file_name, "w").write(JSON.pretty_generate zone)
|
169
|
+
file_name
|
170
|
+
end
|
171
|
+
|
172
|
+
def pull
|
173
|
+
zone = get_zone(true)
|
174
|
+
file_name = write_zone_file(zone, true)
|
175
|
+
puts "'#{file_name}' saved locally"
|
176
|
+
end
|
177
|
+
|
178
|
+
def delete_local_zone_files(id)
|
179
|
+
files = Dir.glob(File.join("#{config_dir}", "zones", "*.#{id}"))
|
180
|
+
files.each { |file| File.delete(file) }
|
181
|
+
files = Dir.glob(File.join("zones", "*.#{id}"))
|
182
|
+
files.each { |file| File.delete(file) }
|
112
183
|
end
|
113
184
|
|
185
|
+
def delete
|
186
|
+
id, name = id_and_name
|
187
|
+
if (id.nil?)
|
188
|
+
zone = get_zone(true)
|
189
|
+
id = zone["ZoneId"]
|
190
|
+
end
|
191
|
+
puts "deleting zone with id #{id}"
|
192
|
+
delete_local_zone_files(id)
|
193
|
+
Route.do.delete_zone(id)
|
194
|
+
end
|
114
195
|
|
115
196
|
def id_and_name
|
116
197
|
id = name = nil
|
@@ -147,6 +228,18 @@ class Zone < Command
|
|
147
228
|
dputs "getting zone with id=#{id} and name=#{name}"
|
148
229
|
@sep_char = "~"
|
149
230
|
zone = Route.do.get_zone(id, name)
|
231
|
+
if zone['Records'].nil?
|
232
|
+
zone['Records'] = {
|
233
|
+
"A"=> [ ],
|
234
|
+
"AAAA"=> [ ],
|
235
|
+
"CNAME"=> [ ],
|
236
|
+
"MX"=> [ ],
|
237
|
+
"NS"=> [ ],
|
238
|
+
"SPF"=> [ ],
|
239
|
+
"SRV"=> [ ],
|
240
|
+
"TXT"=> [ ]
|
241
|
+
}
|
242
|
+
end
|
150
243
|
if zone.nil?
|
151
244
|
raise "zone doesn't exist or is empty"
|
152
245
|
end
|
@@ -159,24 +252,6 @@ class Zone < Command
|
|
159
252
|
zone
|
160
253
|
end
|
161
254
|
|
162
|
-
def push
|
163
|
-
puts "in zone.push"
|
164
|
-
zone = get_zone
|
165
|
-
Route.do.untranslate_zone(zone)
|
166
|
-
File.open("untranslated.zone","w").write(JSON.pretty_generate zone)
|
167
|
-
Route.do.update_zone(zone)
|
168
|
-
end
|
169
|
-
|
170
|
-
def pull
|
171
|
-
zone = get_zone(true)
|
172
|
-
file_name = zone["DomainName"].sub(/\.\Z/, '')
|
173
|
-
file_name = file_name + '.' + zone["ZoneId"].to_s
|
174
|
-
file_name = user_file("zones", file_name)
|
175
|
-
File.delete(file_name) if File.exists?(file_name)
|
176
|
-
File.open(file_name, "w").write(JSON.pretty_generate zone)
|
177
|
-
puts "'#{file_name}' saved locally"
|
178
|
-
end
|
179
|
-
|
180
255
|
# let user lowercase and abbreviate key; abbreviation must match one key
|
181
256
|
def match_key(abbrev, struct)
|
182
257
|
abbrev = abbrev.downcase
|
@@ -244,22 +319,4 @@ class Zone < Command
|
|
244
319
|
def force_online
|
245
320
|
@force_online = true
|
246
321
|
end
|
247
|
-
|
248
|
-
|
249
|
-
def add(args)
|
250
|
-
if @zname
|
251
|
-
puts "unimplemented"
|
252
|
-
else
|
253
|
-
@zone = {
|
254
|
-
:Comment => "",
|
255
|
-
:DomainName => @zname,
|
256
|
-
:FailoverGroups => [ ],
|
257
|
-
:LoadBalancingGroups => [ ],
|
258
|
-
:Records => null,
|
259
|
-
:Status => 1,
|
260
|
-
:ZoneType => 1
|
261
|
-
}
|
262
|
-
|
263
|
-
end
|
264
|
-
end
|
265
322
|
end
|
data/lib/zone_add.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
class ZoneAdd < Command
|
2
|
+
def create_args
|
3
|
+
# for level zone.Records.?
|
4
|
+
add_arg('name', 'Name of the node to which this record pertains', /[[:alnum:]]+/)
|
5
|
+
add_arg('rdata', 'Additional resource record data, such as IP Address', /.*/)
|
6
|
+
add_arg('ttl', 'Time to live, in seconds', /\d+/)
|
7
|
+
end
|
8
|
+
|
9
|
+
def create_flows
|
10
|
+
add_flow_from_usage("<name> <rdata> <ttl>")
|
11
|
+
end
|
12
|
+
|
13
|
+
def handle_level(level)
|
14
|
+
levels = level.split('.')
|
15
|
+
if levels.length == 3 && levels[1] == 'Records'
|
16
|
+
rtype = levels[2]
|
17
|
+
struct = @input["struct"]
|
18
|
+
struct << @record
|
19
|
+
StructurePrint.new("-").structure_print(struct, level)
|
20
|
+
else
|
21
|
+
raise "Illegal or unimplemented add location"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def execute(arghash, rest)
|
26
|
+
struct = @input["struct"]
|
27
|
+
level = @input["level"]
|
28
|
+
@zone_struct = @input["toplevel"]
|
29
|
+
zone = @input["zone"]
|
30
|
+
|
31
|
+
@record = { "Name" => arghash["name"], "Rdata" => arghash["rdata"], "TTL" => arghash["ttl"].to_i }
|
32
|
+
handle_level(level)
|
33
|
+
zone.write_zone_file(@zone_struct)
|
34
|
+
|
35
|
+
end
|
36
|
+
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.1.
|
4
|
+
version: 0.1.8
|
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-04-
|
13
|
+
date: 2014-04-22 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rest-client
|
@@ -83,6 +83,7 @@ files:
|
|
83
83
|
- lib/method.rb
|
84
84
|
- lib/mkbind.sh
|
85
85
|
- lib/print.rb
|
86
|
+
- lib/proxy_credentials.rb
|
86
87
|
- lib/realTimeStats.rb
|
87
88
|
- lib/reporting.rb
|
88
89
|
- lib/route.rb
|
@@ -94,6 +95,7 @@ files:
|
|
94
95
|
- lib/vzcdn.rb
|
95
96
|
- lib/vzcdn/version.rb
|
96
97
|
- lib/zone.rb
|
98
|
+
- lib/zone_add.rb
|
97
99
|
- pkg/vzcdn-0.0.1.gem
|
98
100
|
- test/test_all.rb
|
99
101
|
- test/test_clui.rb
|