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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1ab3dde228779094870d79d8794f4b40128a7910
4
- data.tar.gz: 819e89b69b19dee444471a32227cf9652576b6a7
3
+ metadata.gz: 5defb8c0d907a56ce79b0d129ca104687c4e1db1
4
+ data.tar.gz: 122ceba67885edbdacba2d6178b1cc3a2889afef
5
5
  SHA512:
6
- metadata.gz: b0e14f296d6df37b7c8b0fe6c32516da978fbd00adcf3a9160df96829b558d655b386052a82fb5236deb00d8e3ffa320b1ff5cd3677b2ad03679a5a99721e79e
7
- data.tar.gz: 09a23650f5a1cef68ae69868ab83ecd9d461df13676be3ad1b790ceb598ed8e652185008a0ad9704cd163a2abc66369b09e6187c3f5aca203bf4f75ba433909f
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
@@ -1,37 +1,85 @@
1
1
  require_relative 'route'
2
2
 
3
- class Arg
4
- attr_accessor :desc, :required, :default, :validator, :name, :next_node, :repeatable
5
- attr_reader :value
3
+ class Cell
4
+ attr_accessor :required, :repeatable, :value, :default
6
5
 
7
- def initialize(name, hash={ })
8
- @name = name
6
+ def initialize(object, hash = { })
7
+ @obj = object
9
8
  hash.each {|k,v| instance_variable_set("@#{k}",v)}
10
9
  if @repeatable
11
- @full = false
10
+ @value = [ ]
12
11
  end
13
12
  end
14
13
 
15
14
  def full?
16
- if @repeatable
17
- @full
18
- else
19
- ! @value.nil?
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 value=(value)
24
- if @repeatable
25
- @value = [ ] if @value.nil?
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
- # return true on success
33
- # error message on failure
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 " + @name + ", must be one of " + @validator.to_s
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 " + @name + ", must be one of " + @validator.keys.to_s
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
- on_error, test = obj.send(@validator, value)
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:" + @validator.to_s + ", class=" + @validator.class.to_s
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
- attr_reader :root, :command
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 args
100
- iargs(@root, {})
124
+ def initialize
125
+ @cells = [ ]
101
126
  end
102
127
 
103
- def validate_and_set(value, node)
104
- response = node.validate?(value, @target)
105
- if response.nil?
106
- node.value = value
107
- end
108
- response
128
+ def add(*cells)
129
+ cells.each { |cell|
130
+ @cells << cell
131
+ }
109
132
  end
110
133
 
111
- def isetvalue(value, node)
112
- if node.nil?
113
- return nil, :finished
114
- end
115
- if node.full?
116
- return isetvalue(value, node.next_node)
117
- end
118
- if node.class == Arg
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
- return error, nil
143
+ error, finished = set(name, value)
124
144
  end
125
- elsif node.is_a? Command
126
- if value == node.name.to_s
127
- node.setfull
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
- isetvalue(value, @root)
137
- end
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
- return iset(name, value, node.next_node)
167
+ error = cell.set(value, @target)
168
+ if error && cell.repeatable
169
+ next
170
+ end
171
+ return error, nil
149
172
  end
150
- end
151
- end
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 add(*args)
169
- return if args.length == 0
170
- if @root.nil?
171
- @root = args.shift
172
- end
173
- args.each { |arg|
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
- self
184
+ missing
177
185
  end
178
186
 
179
- def to_s
180
- result = ""
181
- args = iargs(@root, {})
182
- args.each { |name, value|
183
- result = result + "\n#{name}:#{value}"
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
- result
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 iusage(node, names, desc)
201
- return names, desc if node.nil?
202
- if node.class == Arg || node.is_a?(Command)
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 usage
211
- names, desc = iusage root, [ ], [ ]
212
- end
213
-
214
- def ivalidate(node, missing)
215
- return missing if node.nil?
216
- if node.class == Arg
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 validate
230
- ivalidate root, [ ]
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
@@ -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
- flow = Flow.new
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
- flow = Flow.new
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
- flow = Flow.new
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
- flow = Flow.new
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
- add_flow(Flow.new.add(ConfigInit.new(:init, "initialize in current directory")))
74
- add_flow(Flow.new.add(ConfigGet.new(:get, "print configuration parameter's value")))
75
- add_flow(Flow.new.add(ConfigDelete.new(:delete, "delete configuration parameter")))
76
- add_flow(Flow.new.add(ConfigSet.new(:set, "set (or reset) a configuration parameter to specified value")))
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)
@@ -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
- @arghash = { }
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
- names, desc = flow.usage
72
- if (names.length > 0)
73
- puts "usage:" + @name.to_s + " " + "#{[names].join(" ")}"
74
- where_clause = ""
75
- names.zip(desc).each { |name, description|
76
- if name =~ /\A<.*>\B/
77
- where_clause = where_clause + "\n #{name}: #{description}"
78
- end
79
- }
80
- if where_clause.length > 0
81
- puts "where:#{where_clause}"
82
- puts ""
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, arg)
89
- @arghash[name] = arg
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 add_flow_from_args(*keys)
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
- keys.each { |key|
95
- flow.add(@arghash[key])
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.args, rest)
139
+ execute(flow.arghash, rest)
119
140
  return
120
141
  end
121
142
  }
@@ -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 "Unable to connect to REST server " + param("rest_base_url")
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)
@@ -83,5 +83,4 @@ class ConfigHandler
83
83
  def delete(name)
84
84
  set(name, nil)
85
85
  end
86
-
87
86
  end
@@ -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
@@ -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/" + id)
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)
@@ -14,7 +14,8 @@ class VzcdnApp < Command
14
14
  end
15
15
 
16
16
  def print_version
17
- puts "vzcdn version:" + Vzcdn::VERSION
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
- add_arg(:zone, Zone.new("zone", "zone"))
26
- add_arg(:config, ConfigCommand.new("config", "config description"))
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
- add_flow_from_args(:zone)
31
- add_flow_from_args(:config)
31
+ add_flow_from_usage("zone")
32
+ add_flow_from_usage("config")
32
33
  end
33
34
 
34
35
  def execute(args, subargs)
@@ -1,3 +1,3 @@
1
1
  module Vzcdn
2
- VERSION = "0.1.7"
2
+ VERSION = "0.1.8"
3
3
  end
@@ -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 zone
9
- zone.list
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 zone
17
+ def execute(args, rest)
18
+ zone = @input["zone"]
15
19
  zone.pull
16
20
  end
17
21
  end
18
22
 
19
- class ZonePrint < Command
20
- attr_writer :struct, :level, :sep_char
23
+ class ZonePush < Command
24
+ def execute(args, rest)
25
+ zone = @input["zone"]
26
+ zone.push
27
+ end
28
+ end
21
29
 
22
- def create_flows
23
- add_flow(Flow.new)
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, subargs)
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(@struct)
52
+ puts JSON.pretty_generate(struct)
38
53
  else
39
- StructurePrint.new(@sep_char).structure_print(@struct, @level)
54
+ StructurePrint.new(sep_char).structure_print(struct, level)
40
55
  end
41
56
  end
42
57
  end
43
58
 
44
- class ZonePush < Command
45
- def execute zone
46
- zone.push
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
- add_arg(:list, ZoneList.new("list", "list all owned zones"))
55
- add_arg(:pull, ZonePull.new(:pull, "retrieve local copy of zone data"))
56
- add_arg(:push, ZonePush.new(:push, "push local changes to server"))
57
- arg = ZonePrint.new(:print, "print zone data. ~~~~ online, ---- local copy")
58
- arg.required = false
59
- add_arg(:print, arg)
60
- add_arg(:zname, Arg.new("zname", desc: "name or id of zone to pull", required: true, validator: /[[:alnum:]]+/))
61
- add_arg(:zname2, Arg.new("zname", desc: "name or id of zone to pull", required: true, validator: /[[:alnum:]]+/))
62
- add_arg(:drill_down, Arg.new("drill-down-param", desc: "drill down the zone structure", required: true, repeatable: true, validator: :ddverify ))
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
- add_flow_from_args(:list)
67
- add_flow_from_args(:zname, :pull)
68
- add_flow_from_args(:zname2, :push)
69
- add_flow_from_args(:drill_down, :print)
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 ddverify(value)
112
+ def alnum_not_command(value)
73
113
  test = value =~ /[[:alnum:]]+/
74
114
  if test
75
- if @arghash[value.to_sym].is_a? Command
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, subargs)
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
- @struct, @level = drill_down(zone, ddparams, "zone")
92
- if command.nil?
93
- command = @arghash[:print]
94
- end
95
- command.struct = @struct
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.class == ZonePrint
100
- command.run subargs
101
- elsif command
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 list
109
- zones = Route.do.get_all_zones
110
- Route.do.translate_zonelist(zones)
111
- StructurePrint.new('~').structure_print(zones, "zonelist")
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
@@ -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.7
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-17 00:00:00.000000000 Z
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