vzcdn 0.1.7 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 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