zillabyte-cli 0.1.0 → 0.1.1

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: 54c7334eca6bc7a0ee7d5b20093411539b51b891
4
- data.tar.gz: 6239db222616513ebc77fbfadf8c3484d215800a
3
+ metadata.gz: 284b1b673fa8e9159a4f9f5ac108ffdf2f158fe0
4
+ data.tar.gz: a8d5398aa5b99320f6d050c797c952b977b10dc1
5
5
  SHA512:
6
- metadata.gz: 1a3382cdff1fa803334611716c351f8bd27ce899b43180713331ef6f8e37279b38accbf100126ad9cd0b48b3df3217c9dc8ffbc420725950d61d716e35773da0
7
- data.tar.gz: e0a1dceff8dd68bf110c403979b42224d06ebb07415e58f7eb5446c5a1a4bf3ba5936d0d059ace0bacd105ad4cc9602218f882975f8327eb92528df29f66e49f
6
+ metadata.gz: 5786156d1bb899860e7a8c9468b1e0a4ac5dcb4f7d4afe7b59bf4174b455eaefe2d3764db9bfc7c056f972cb7e1bec8c570bf48fc378ab5d5d2b049a7dbbc2f2
7
+ data.tar.gz: f56ec56c826a691b1b911264e38358ec66efe9ee77e0560e09690f95bf93605a99d5f58262d8254e33d8ecc981c8e4c7c8ab30edc248966786a9780f88bc6c71
@@ -1,5 +1,5 @@
1
1
  module Zillabyte
2
2
  module CLI
3
- VERSION = "0.1.0"
3
+ VERSION = "0.1.1"
4
4
  end
5
5
  end
@@ -42,24 +42,7 @@ class Zillabyte::API::Apps < Zillabyte::API::Flows
42
42
 
43
43
  end
44
44
 
45
- # POST /apps/id/kill
46
- def kill(id, options = {})
47
45
 
48
- options = {
49
- # TODO
50
- }.merge(options)
51
-
52
- res = @api.request(
53
- :expects => 200,
54
- :method => :post,
55
- :path => "/apps/#{id}/kill",
56
- :body => options.to_json
57
- )
58
-
59
- res.body
60
-
61
- end
62
-
63
46
  def list_cycles(id, options={})
64
47
  res = @api.request(
65
48
  :expects => 200,
@@ -110,6 +93,10 @@ class Zillabyte::API::Apps < Zillabyte::API::Flows
110
93
  # Get the meta info
111
94
  options[:local_flag] = 1
112
95
  hash = Zillabyte::API::Flows.get_rich_meta_info_from_script(dir, session, options)
96
+ if hash["flow_type"] == "component"
97
+ session.error("To push up a component please use git. The \"zillabyte push\" command is only supported for apps.") if session
98
+ end
99
+
113
100
  if hash.nil?
114
101
  session.error("unable to extract app meta information", type) if session
115
102
  end
@@ -94,22 +94,4 @@ class Zillabyte::API::Components < Zillabyte::API::Flows
94
94
  res.body
95
95
  end
96
96
 
97
- # POST /components/id/kill
98
- def kill(id, options = {})
99
-
100
- options = {
101
- # TODO
102
- }.merge(options)
103
-
104
- res = @api.request(
105
- :expects => 200,
106
- :method => :post,
107
- :path => "/components/#{id}/kill",
108
- :body => options.to_json
109
- )
110
-
111
- res.body
112
-
113
- end
114
-
115
97
  end
@@ -14,6 +14,78 @@ class Zillabyte::API::Flows < Zillabyte::API::Base
14
14
  res.body
15
15
  end
16
16
 
17
+ # POST /flows/id/kill
18
+ def create_kill(id, options = {})
19
+
20
+ options = {
21
+ # TODO
22
+ }.merge(options)
23
+
24
+ res = @api.request(
25
+ :expects => 200,
26
+ :method => :post,
27
+ :path => "/flows/#{id}/kill",
28
+ :body => options.to_json
29
+ )
30
+
31
+ res.body
32
+
33
+ end
34
+
35
+ # GET /flows/id/kill
36
+ def poll_kill(id, options = {})
37
+
38
+ options = {
39
+ # TODO
40
+ }.merge(options)
41
+
42
+ res = @api.request(
43
+ :expects => 200,
44
+ :method => :get,
45
+ :path => "/flows/#{id}/kill",
46
+ :body => options.to_json
47
+ )
48
+
49
+ res.body
50
+
51
+ end
52
+
53
+ # POST /flows/id/delete
54
+ def create_delete(id, options = {})
55
+
56
+ options = {
57
+ # TODO
58
+ }.merge(options)
59
+
60
+ res = @api.request(
61
+ :expects => 200,
62
+ :method => :post,
63
+ :path => "/flows/#{id}/delete",
64
+ :body => options.to_json
65
+ )
66
+
67
+ res.body
68
+
69
+ end
70
+
71
+ # GET /flows/id/delete
72
+ def poll_delete(id, options = {})
73
+
74
+ options = {
75
+ # TODO
76
+ }.merge(options)
77
+
78
+ res = @api.request(
79
+ :expects => 200,
80
+ :method => :get,
81
+ :path => "/flows/#{id}/delete",
82
+ :body => options.to_json
83
+ )
84
+
85
+ res.body
86
+
87
+ end
88
+
17
89
  # GET /flows/id/download
18
90
  def pull_to_directory(id, dir, session = nil, options = {})
19
91
 
@@ -12,6 +12,7 @@ class Zillabyte::Auth
12
12
  def login(email, auth_token)
13
13
  if valid_credentials?(email, auth_token)
14
14
  write_credentials(email, auth_token)
15
+ display "Authentication complete."
15
16
  end
16
17
  end
17
18
 
@@ -113,7 +114,6 @@ class Zillabyte::Auth
113
114
  display error.message
114
115
  exit 1
115
116
  end
116
- display "Authentication complete"
117
117
  end
118
118
 
119
119
  def delete_credentials
@@ -198,8 +198,44 @@ class Zillabyte::Auth
198
198
  if not valid_credentials?(email, auth_token)
199
199
  raise Zillabyte::Auth::InvalidCredentialsException
200
200
  else
201
+
201
202
  # Success...
202
203
  write_credentials(email, auth_token)
204
+
205
+ # Maybe add ssh keys while we're at it...
206
+ possible_keys = [
207
+ "~/.ssh/id_rsa.pub",
208
+ "~/.ssh/id_dsa.pub"
209
+ ]
210
+
211
+ key_added = false
212
+ possible_keys.each do |keypath|
213
+ if File.exists?(File.expand_path(keypath))
214
+
215
+ display "Register SSH key #{keypath}? (y/N)", false
216
+ break if (ask() || "").strip.downcase[0] != "y"
217
+
218
+ api = Zillabyte::API.new(:api_key => auth_token, :session => self)
219
+ begin
220
+ key = File.binread(File.expand_path(keypath))
221
+ rescue => e
222
+ error(e.message, type)
223
+ break
224
+ end
225
+ message = api.keys.add("default", key)
226
+ display("SSH keys added. Use 'zillabyte keys' to manage.")
227
+ key_added = true
228
+ break
229
+
230
+ end
231
+ end
232
+
233
+ unless key_added
234
+ display "Please run zillabyte keys:add to add your ssh keys."
235
+ end
236
+
237
+ display "Authentication complete."
238
+
203
239
  end
204
240
  end
205
241
  rescue Zillabyte::Auth::InvalidCredentialsException => e
@@ -15,7 +15,7 @@ require 'net/http'
15
15
  class Zillabyte::Command::Apps < Zillabyte::Command::Flows
16
16
 
17
17
  MAX_POLL_SECONDS = 60 * 15
18
- POLL_SLEEP = 0.5
18
+ POLL_SLEEP = 2.0
19
19
 
20
20
  # apps
21
21
  #
@@ -279,11 +279,15 @@ class Zillabyte::Command::Apps < Zillabyte::Command::Flows
279
279
  def init
280
280
 
281
281
  name = options[:name] || shift_argument
282
+ error("name required") if name.nil?
283
+
282
284
  lang = options[:lang] || options[:language] || "ruby"
283
- dir = options[:dir] || options[:directory] || File.join(Dir.pwd, name)
285
+ dir = options[:dir] || options[:directory] || Dir.pwd
286
+ remote = options[:remote] || "zillabyte"
287
+
284
288
  dir = File.expand_path(dir) unless dir.nil?
285
289
  type = options[:output_type]
286
-
290
+
287
291
  languages = ["ruby","python", "js"]
288
292
 
289
293
  error("Unsupported language #{lang}. Zillabyte currently supports #{languages.join(', ')}.", type) if not languages.include? lang
@@ -303,6 +307,8 @@ class Zillabyte::Command::Apps < Zillabyte::Command::Flows
303
307
 
304
308
  end
305
309
 
310
+ # Add the git remote...
311
+ add_git_remote(name, remote)
306
312
 
307
313
  end
308
314
 
@@ -380,7 +386,7 @@ class Zillabyte::Command::Apps < Zillabyte::Command::Flows
380
386
  options.delete :is_name
381
387
 
382
388
  start = Time.now.utc
383
- display "Next cycle request sent. If your app was RETIRED this may take a few minutes. Check 'zillabyte logs' for progress." if type.nil?
389
+ display "Next cycle request sent. If your app was RETIRED this may take a few minutes. Please wait or check 'zillabyte logs' for progress." if type.nil?
384
390
 
385
391
  while(Time.now.utc < start + MAX_POLL_SECONDS) do
386
392
 
@@ -439,24 +445,7 @@ class Zillabyte::Command::Apps < Zillabyte::Command::Flows
439
445
  # --output_type OUTPUT_TYPE # specify an output type i.e. json
440
446
  #
441
447
  def kill
442
- id = options[:id] || shift_argument
443
- type = options[:output_type]
444
-
445
- if id.nil?
446
- id = read_name_from_conf(options)
447
- options[:is_name] = true
448
- elsif !(id =~ /^\d*$/)
449
- options[:is_name] = true
450
- end
451
-
452
- display "Killing app ##{id}...please wait..." if type.nil?
453
- api.apps.kill(id, options)
454
-
455
- if type == "json"
456
- display "{}"
457
- else
458
- display "App ##{id} killed"
459
- end
448
+ super
460
449
  end
461
450
 
462
451
 
@@ -15,7 +15,58 @@ class Zillabyte::Command::Components < Zillabyte::Command::Flows
15
15
  def index
16
16
  self.list
17
17
  end
18
+
19
+
20
+
21
+
18
22
 
23
+ # components:init [NAME]
24
+ #
25
+ # initializes a new component
26
+ #
27
+ # --lang LANG # which language to use [ruby, python]. default 'ruby'.
28
+ # --dir DIR # target directory of the app.
29
+ # --remote REMOTE # the git remote name. default 'zillabyte'
30
+ #
31
+ #Examples:
32
+ #
33
+ # $ zillabyte components:init domain_extractor --lang ruby
34
+ #
35
+ def init
36
+
37
+ name = options[:name] || shift_argument
38
+ error("name required") if name.nil?
39
+
40
+ lang = options[:lang] || options[:language] || "ruby"
41
+ dir = options[:dir] || options[:directory] || Dir.pwd
42
+ remote = options[:remote] || "zillabyte"
43
+
44
+ dir = File.expand_path(dir) unless dir.nil?
45
+ type = options[:output_type]
46
+
47
+ languages = ["ruby","python", "js"]
48
+
49
+ error("Unsupported language #{lang}. Zillabyte currently supports #{languages.join(', ')}.", type) if not languages.include? lang
50
+
51
+ display "initializing empty #{lang} component in #{dir}" if type.nil?
52
+ erb_binding = binding
53
+ FileUtils.mkdir_p dir
54
+
55
+ Dir[File.join(File.expand_path("../templates/components/#{lang}", __FILE__), "*")].each do |source_file|
56
+
57
+ next if File.directory?(source_file)
58
+ erb = ERB.new(File.read(source_file))
59
+ erb.filename = source_file
60
+
61
+ dest_file = File.join(dir, File.basename(source_file).gsub(/\.erb$/, ""))
62
+ File.open(dest_file, 'w') {|file| file.write(erb.result(erb_binding))}
63
+
64
+ end
65
+
66
+ # Add the git remote...
67
+ add_git_remote(name, remote)
68
+
69
+ end
19
70
 
20
71
 
21
72
  # components
@@ -25,7 +76,7 @@ class Zillabyte::Command::Components < Zillabyte::Command::Flows
25
76
  def list
26
77
  type = options[:output_type]
27
78
 
28
- headings = ["id", "name", "state", "inputs", "outputs"]
79
+ headings = ["id", "name", "state", "inputs", "outputs", "scope"]
29
80
  rows = api.component.list.map do |row|
30
81
  if headings.size == 0
31
82
  headings = row.keys
@@ -90,24 +141,7 @@ class Zillabyte::Command::Components < Zillabyte::Command::Flows
90
141
  # --output_type OUTPUT_TYPE # specify an output type i.e. json
91
142
  #
92
143
  def kill
93
- id = options[:id] || shift_argument
94
- type = options[:output_type]
95
-
96
- if id.nil?
97
- id = read_name_from_conf(options)
98
- options[:is_name] = true
99
- elsif !(id =~ /^\d*$/)
100
- options[:is_name] = true
101
- end
102
-
103
- display "Killing component ##{id}...please wait..." if type.nil?
104
- api.components.kill(id, options)
105
-
106
- if type == "json"
107
- display "{}"
108
- else
109
- display "Component ##{id} killed"
110
- end
144
+ super
111
145
  end
112
146
 
113
147
  # components:info [DIR]
@@ -130,7 +164,7 @@ class Zillabyte::Command::Components < Zillabyte::Command::Flows
130
164
  # --config CONFIG_FILE # use the given config file
131
165
  # --input INPUT_FILE # uses a CSV for component input
132
166
  # --output OUTPUT_FILE # write output to a CSV
133
- # --directory DIR # app directory
167
+ # --directory DIR # component directory
134
168
  #
135
169
  def test
136
170
  super
@@ -150,6 +184,7 @@ class Zillabyte::Command::Components < Zillabyte::Command::Flows
150
184
  # components:errors ID
151
185
  #
152
186
  # show recent errors generated by the componeny rpc
187
+ #
153
188
  # --output_type OUTPUT_TYPE # specify an output type i.e. json
154
189
  #
155
190
  def errors
@@ -169,13 +204,32 @@ class Zillabyte::Command::Components < Zillabyte::Command::Flows
169
204
  super
170
205
  end
171
206
 
172
- # components:rpc [ID] [QUERY_1_INPUT_1,QUERY_1_INPUT_2,...] [QUERY_2_INPUT_1,QUERY_2_INPUT_2,...], ...
207
+
208
+ # components:rpc [ID] [INPUT_1] [INPUT_2] ...
173
209
  #
174
- # runs a component as an rpc
210
+ # Submits a single query to the rpc. The input parameters MUST be
211
+ # listed in the same order as that given in the component inputs.
212
+ # TO SUBMIT MULTIPLE queries, use the --file switch to specify a
213
+ # csv file containing the queries without listing any inputs on
214
+ # the command line. Each line of the file should correspond to a
215
+ # unique query.
216
+ #
217
+ # --async # run the command asynchronously
218
+ # --input_file INTPUT_FILE # input csv file containing parameters for multiple queries
219
+ # --output_file OUTPUT_FILE # output csv file containing query parameters and run ids
220
+ #
221
+ # Examples:
222
+ #
223
+ # Single query:
224
+ # $ zillabyte components:rpc 'web_screenshot' 'google.com'
225
+ #
226
+ # Multiple queries:
227
+ # $ zillabyte components:rpc 'web_screenshot' --file 'url_list.csv'
175
228
  #
176
- # --output_type OUTPUT_TYPE # specify an output type i.e. json
177
229
  def rpc
230
+
178
231
  component_id = options[:id] || shift_argument
232
+ async = options[:async] || false
179
233
 
180
234
  if component_id.nil?
181
235
  component_id = read_name_from_conf(options)
@@ -185,31 +239,91 @@ class Zillabyte::Command::Components < Zillabyte::Command::Flows
185
239
  end
186
240
 
187
241
  type = options[:output_type]
242
+ file = options[:input_file]
243
+ out_file = options[:output_file]
188
244
 
189
245
  component_args = []
190
- while(true) do
191
- next_arg = shift_argument
192
- break if next_arg.nil?
193
- component_args << next_arg.split(",")
246
+ if file
247
+ CSV.foreach(file) {|line| component_args << line}
248
+ else
249
+ args = []
250
+ while(true) do
251
+ next_arg = shift_argument
252
+ break if next_arg.nil?
253
+ args << next_arg
254
+ end
255
+ component_args << args if !args.empty?
194
256
  end
195
257
 
196
- res = api.components.rpc(component_id, {:rpc_inputs => component_args})
258
+ opts = {:rpc_inputs => component_args} if component_args.size != 0
259
+ res = api.components.rpc(component_id, opts)
260
+
261
+ input_par_for_id = {}
197
262
  if res['error']
198
263
  error("error: #{res['error_message']}", type)
199
264
  else
200
265
  if type.nil?
201
- display "Request submitted to component ##{res['id']}. The run ids are (query: run_id):"
202
- res["execute_ids"].each do |pars, id|
203
- display "\t #{pars}: #{id}"
266
+ display "Request submitted to component ##{res['id']}."
267
+ end
268
+
269
+ if res["execute_ids"]
270
+ input_par_for_id = res["execute_ids"].invert
271
+ if out_file
272
+ CSV.open(out_file, "w") {|csv| res["execute_ids"].to_a.each {|elem| csv << elem}}
273
+ end
274
+ end
275
+ end
276
+
277
+ if async
278
+ # Async -- return right away..
279
+ display "The run ids are (query: run_id):"
280
+ res["execute_ids"].each do |pars, id|
281
+ display "\t #{pars}: #{id}"
282
+ end
283
+ display "Please use \"zillabyte components:results [run id]\" to check on the status of your query and to retrieve your results.\nYou may also wish to check \"zillabyte logs\" for errors."
284
+ else
285
+ # Sync -- poll until it's done...
286
+ if res["execute_ids"]
287
+ run_ids = res["execute_ids"].values
288
+ while true
289
+ res = api.components.get_rpc_results(component_id, {:execute_ids => run_ids})
290
+ if res['error']
291
+ error("error: #{res['error_message']}", type)
292
+ else
293
+ if res["results"].detect{|id, res| ["running", "waiting"].member?(res["status"].downcase)}
294
+ # poll again
295
+ sleep(2)
296
+ else
297
+ if type.nil?
298
+ # All results are done (or rather, not 'running). Display them
299
+ res["results"].each do |id, hash|
300
+ display "Query #{input_par_for_id[id]}:"
301
+ if hash["data"].size == 0
302
+ display "\t NO OUTPUT"
303
+ else
304
+ display "\t #{hash["data"].to_json()}"
305
+ end
306
+ end
307
+ end
308
+ break
309
+ end
310
+ end
204
311
  end
205
- display "Please use \"zillabyte components:results [run id]\" to check on the status of your query and to retrieve your results.\nYou may also wish to check \"zillabyte logs\" for errors."
206
312
  end
207
313
  end
208
314
  end
315
+ alias_command "rpc", "components:rpc"
209
316
 
210
- # components:results [ID] [RUN_ID]
317
+
318
+
319
+ # components:results [ID] [RUN_ID_1] [RUN_ID_2] ...
211
320
  #
212
- # gets the result of an rpc request if it is done running, otherwise gets current run status
321
+ # Gets the result of rpc requests corresponding to RUN_ID if it is
322
+ # done running, otherwise gets current run status. A list of RUN_IDs
323
+ # may also be specified in an input csv file like that generated by
324
+ # components:rpc with the --output_file flag.
325
+ #
326
+ # --input_file INTPUT_FILE # input csv file containing query parameters and run ids (this can be generated automatically by components:rpc using the --output_file flag)
213
327
  #
214
328
  def results
215
329
  component_id = options[:id] || shift_argument
@@ -222,12 +336,19 @@ class Zillabyte::Command::Components < Zillabyte::Command::Flows
222
336
  end
223
337
 
224
338
  type = options[:output_type]
339
+ file = options[:input_file]
225
340
 
226
341
  run_ids = []
227
- while(true) do
228
- next_arg = shift_argument
229
- break if next_arg.nil?
230
- run_ids << next_arg
342
+ if file
343
+ CSV.foreach(file) do |line|
344
+ run_ids << line[1]
345
+ end
346
+ else
347
+ while(true) do
348
+ next_arg = shift_argument
349
+ break if next_arg.nil?
350
+ run_ids << next_arg
351
+ end
231
352
  end
232
353
 
233
354
  res = api.components.get_rpc_results(component_id, {:execute_ids => run_ids})
@@ -237,9 +358,16 @@ class Zillabyte::Command::Components < Zillabyte::Command::Flows
237
358
  if type.nil?
238
359
  res["results"].each do |id, hash|
239
360
  display "#{id}: #{hash["status"]}"
240
- display "\t #{hash["data"]}" if hash["status"] == "complete"
361
+ if hash["status"] == "complete"
362
+ if hash["data"].size == 0
363
+ display "\t NO OUTPUT"
364
+ else
365
+ display "\t #{hash["data"]}"
366
+ end
367
+ end
241
368
  end
242
369
  end
243
370
  end
244
371
  end
372
+
245
373
  end