ubalo 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/bin/ubalo +106 -104
  2. data/lib/ubalo.rb +30 -25
  3. metadata +8 -8
data/bin/ubalo CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  require 'gli'
4
4
  require 'yaml'
5
+ require 'fileutils'
5
6
 
6
7
  require 'highline'
7
- require 'highline/import'
8
8
  hl = HighLine.new
9
9
 
10
10
  require 'ubalo'
@@ -44,11 +44,14 @@ def ubalo
44
44
  end
45
45
 
46
46
  program_desc 'Command-line access to ubalo.com.'
47
- version "0.0.6"
47
+ version "0.0.7"
48
48
 
49
49
  desc "Change the connect url"
50
50
  flag 'connect-url'
51
51
 
52
+ desc "Enable debug mode"
53
+ switch :debug
54
+
52
55
  desc 'Display authentication information'
53
56
  command :whoami do |c|
54
57
  c.action do |global_options,options,args|
@@ -106,120 +109,120 @@ command :tasks do |c|
106
109
  end
107
110
  end
108
111
 
109
- desc 'Add an ssh key (defaults to ~/.ssh/id_rsa.pub)'
110
- arg_name '<file containing ssh key>'
111
- command :add_key do |c|
112
- c.action do |global_options,options,args|
112
+ def process_download response, destination_path=nil
113
+ name = response.fetch('name')
114
+ fullname = response.fetch('fullname')
115
+ files = response.fetch('files')
116
+ destination_path ||= name
113
117
 
114
- public_key_file, = *args
118
+ if Dir.exist?(destination_path)
119
+ raise "directory #{destination_path.inspect} already exists"
120
+ end
115
121
 
116
- public_key_file ||= '~/.ssh/id_rsa.pub'
117
- public_key_file = File.expand_path(public_key_file)
122
+ FileUtils.mkdir(destination_path)
123
+ FileUtils.mkdir(File.join(destination_path, ".ubalo"))
118
124
 
119
- puts ubalo.upload_key(File.read(public_key_file))
125
+ File.open(File.join(destination_path, ".ubalo", "name"), "w") do |f|
126
+ f.puts name
120
127
  end
121
- end
122
128
 
123
- desc 'Clear all ssh keys'
124
- command :clear_keys do |c|
125
- c.action do |global_options,options,args|
126
- puts ubalo.clear_keys
129
+ files.each do |filename,content|
130
+ File.open(File.join(destination_path, filename), "w") do |f|
131
+ f.puts content
132
+ end
127
133
  end
134
+
135
+ [fullname, destination_path]
128
136
  end
129
137
 
130
- desc 'Modify a pod'
138
+ desc 'Download a pod to your computer'
131
139
  arg_name '<pod name>'
132
- command :edit do |c|
140
+ command :get do |c|
133
141
  c.action do |global_options,options,args|
134
142
  pod_name = args.shift
135
143
  unless pod_name
136
144
  raise "please specify a pod"
137
145
  end
146
+ destination_path = args.shift
138
147
 
139
- ubalo.ssh(pod_name)
148
+ $stderr.print "Fetching code for #{pod_name}..."
149
+ response = ubalo.download(pod_name)
150
+
151
+ fullname, destination_path = process_download(response)
152
+ $stderr.puts " done."
153
+ $stderr.puts "Retrieved #{fullname} into #{destination_path}/."
140
154
  end
141
155
  end
142
156
 
143
- desc 'Show the code in a pod'
157
+ desc 'Create a new pod'
144
158
  arg_name '<pod name>'
145
- command :cat do |c|
146
- c.action do |global_options,options,args|
147
- pod_name = args.shift
148
- unless pod_name
149
- raise "please specify a pod"
150
- end
159
+ command :create do |c|
151
160
 
152
- puts ubalo.cat_code(pod_name)
153
- end
154
- end
161
+ c.desc "Pod name"
162
+ c.flag :name
163
+ c.desc "Pod type"
164
+ c.flag :type
155
165
 
156
- desc 'Set the code in a pod'
157
- arg_name '<pod_name> <code_file>'
158
- command :code do |c|
159
166
  c.action do |global_options,options,args|
160
- pod_name = args.first
161
- unless pod_name
162
- raise "please specify a pod"
167
+ if options.name
168
+ pod_name = options.name
169
+ else
170
+ pod_name = hl.ask("New pod name: ")
171
+ if pod_name.empty?
172
+ raise "No pod name given"
173
+ end
163
174
  end
175
+ destination_path = pod_name
164
176
 
165
- file_name = args.last
166
- if file_name
167
- code = File.read(file_name)
168
- elsif $stdin.tty?
169
- raise "please give the new code as a filename or on stdin"
177
+ if Dir.exist?(pod_name)
178
+ raise "directory #{destination_path} already exists, giving up."
179
+ end
180
+
181
+ templates = ubalo.available_templates
182
+ if options.type
183
+ pod_type = options.type
184
+ unless templates.include? pod_type
185
+ raise "Invalid pod type"
186
+ end
170
187
  else
171
- code = $stdin.read
188
+ pod_type = hl.choose do |menu|
189
+ menu.prompt = "New pod type: "
190
+ menu.choices(*templates.keys)
191
+ end
172
192
  end
173
193
 
174
- puts ubalo.upload_code(pod_name, code)
194
+ $stderr.print "Creating a new #{pod_type} pod called #{pod_name}..."
195
+ response = ubalo.create_pod(pod_name, templates[pod_type])
196
+
197
+ fullname, destination_path = process_download(response)
198
+
199
+ $stderr.puts " done."
200
+ $stderr.puts "Created #{fullname} and placed in #{destination_path}/."
175
201
  end
176
202
  end
177
203
 
178
- desc 'Show the files in a pod environ'
204
+ desc 'Run a pod'
179
205
  arg_name '<pod name>'
180
- command :ls do |c|
181
- c.desc 'list in long format'
182
- c.switch :l
183
-
184
- c.desc 'list in human-readable form'
185
- c.switch :h
206
+ command :run do |c|
186
207
 
187
208
  c.action do |global_options,options,args|
188
- opts = ""
189
- opts << " -l" if options.l
190
- opts << " -h" if options.h
191
-
192
- pod_name = args.last
209
+ pod_name = args.shift
193
210
  unless pod_name
194
211
  raise "please specify a pod"
195
212
  end
196
- puts ubalo.ls(pod_name, opts)
197
- end
198
- end
199
213
 
200
- desc 'Copy files into and out of a pod environ'
201
- arg_name '<pod name>'
202
- command :cp do |c|
203
- c.desc 'copy recursively'
204
- c.switch :r
205
-
206
- c.action do |global_options,options,args|
207
- opts = ""
208
- opts << " -r" if options.r
209
-
210
- environ = nil
211
- scp_args = args.join(" ").gsub(/[\w-]+(?=:)/) do |pod_name|
212
- ssh_path, environ = ubalo.ssh_path(pod_name)
213
- "#{ssh_path}"
214
- end
214
+ $stderr.print "Running #{pod_name}..."
215
+ response = ubalo.submit_task(pod_name, args.join(" "))
216
+ task_label = response['label']
215
217
 
216
- ubalo.scp(environ, opts, scp_args)
218
+ result = ubalo.check_task(task_label, true)
219
+ ubalo.show_result(result)
217
220
  end
218
221
  end
219
222
 
220
- desc 'Snap a pod'
223
+ desc 'Submit a pod for running in the background'
221
224
  arg_name '<pod name>'
222
- command :run do |c|
225
+ command :submit do |c|
223
226
 
224
227
  c.action do |global_options,options,args|
225
228
  pod_name = args.shift
@@ -227,54 +230,49 @@ command :run do |c|
227
230
  raise "please specify a pod"
228
231
  end
229
232
 
230
- $stderr.print "Running #{pod_name}..."
231
- response = ubalo.submit_task(pod_name, args.join(" "))
232
- task_id = response['id']
233
+ $stderr.print "Submitting #{pod_name}..."
234
+ result = ubalo.submit_task(pod_name, args.join(" "))
235
+ $stderr.puts " submitted."
233
236
 
234
- result = ubalo.check_task(task_id, true)
235
237
  ubalo.show_result(result)
238
+
236
239
  end
237
240
  end
238
241
 
239
242
  desc 'Check or get the result of a task'
240
- arg_name '<task id>'
243
+ arg_name '<task label>'
241
244
  command :check do |c|
242
- c.desc 'explicitly show the complete result'
243
- c.switch [:verbose, :v]
244
-
245
- c.desc 'wait for the result if the task is pending'
246
- c.switch [:wait, :w]
247
-
248
- c.desc 'outputs as json to stdout; stdout > stderr'
249
- c.switch [:json, :j]
250
-
251
245
  c.action do |global_options,options,args|
252
- task_id = args.first
253
- unless task_id
246
+ task_label = args.first
247
+ unless task_label
254
248
  raise "please specify a task"
255
249
  end
256
250
 
257
- result = ubalo.check_task(task_id, true)
251
+ $stderr.print "Checking task #{task_label}..."
252
+
253
+ result = ubalo.check_task(task_label, true)
258
254
  ubalo.show_result(result, options.verbose, options.json)
259
255
  end
260
256
  end
261
257
 
262
- desc 'Sign into Ubalo'
263
- command :signin do |c|
258
+ desc 'Enter username and password for access'
259
+ command :login do |c|
264
260
  c.action do |global_options,options,args|
265
- puts "Please enter your Ubalo username/email and password to unlock command-line access."
261
+ puts "Please enter your Ubalo details for command-line access."
266
262
  login = hl.ask(" login: "){|q| q.echo = true}
267
263
  password = hl.ask(" password: "){|q| q.echo = false}
268
264
 
269
- ubalo.token = ubalo.get_api_token(login, password)
265
+ response = ubalo.get_api_token(login, password)
266
+ ubalo.token = response['api_token']
267
+ username = response['username']
268
+
270
269
  Ubalo.write_config("connect-url" => ubalo.base_url, ubalo.base_url => {'token' => ubalo.token})
271
- puts "Access details saved to ~/.ubalorc."
272
- puts ubalo.whoami
270
+ puts "Success! Ready to use as #{username}."
273
271
  end
274
272
  end
275
273
 
276
- desc 'Sign out of Ubalo'
277
- command :signout do |c|
274
+ desc 'Remove saved username and password'
275
+ command :logout do |c|
278
276
  c.action do |global_options,options,args|
279
277
  Ubalo.write_config(ubalo.base_url => nil)
280
278
  puts "Access details deleted."
@@ -285,23 +283,26 @@ pre do |global,command,options,args|
285
283
  config = Ubalo.config
286
284
  connect_url = global['connect-url'] || config['connect-url']
287
285
 
288
- # When signing in, don't use the token:
289
- unless command && command.name == :signin
286
+ # When logging in, don't use the token:
287
+ unless command && command.name == :login
290
288
  if host_config = config[connect_url]
291
289
  token = host_config['token']
292
290
  end
293
291
  end
294
292
 
295
- unless token or (command && command.name == :signin)
296
- raise "No credentials found. Please run 'ubalo signin'."
293
+ unless token or (command && command.name == :login)
294
+ raise "No credentials found. Please run 'ubalo login'."
297
295
  end
298
296
 
299
- @ubalo ||= Ubalo.signin(token, connect_url)
297
+ @ubalo ||= Ubalo.login(token, connect_url)
298
+
299
+ @debug = global.debug
300
300
 
301
301
  true
302
302
  end
303
303
 
304
304
  on_error do |exception|
305
+ puts
305
306
  case exception
306
307
  when RestClient::BadRequest
307
308
  $stderr.puts exception.inspect.sub('400 Bad Request', 'Error')
@@ -310,6 +311,7 @@ on_error do |exception|
310
311
  # Normal exit, preserving the correct exit code.
311
312
  exit exception.message
312
313
  else
314
+ raise if @debug
313
315
  true
314
316
  end
315
317
  end
data/lib/ubalo.rb CHANGED
@@ -47,7 +47,7 @@ end
47
47
  class Ubalo
48
48
  class << self
49
49
  def format_task task
50
- "#{task['id'].to_s[0,6]} #{task['state'].lfit(8)} #{task['pod_name'].lfit(25)} #{task['arg'].to_s.lfit(40)}"
50
+ "#{task['label']} #{task['state'].lfit(8)} #{task['pod_name'].lfit(25)} #{task['arg'].to_s.lfit(40)}"
51
51
  end
52
52
 
53
53
  def format_pod pod, with_username
@@ -63,7 +63,7 @@ class Ubalo
63
63
  attr_reader :base_url
64
64
  attr_accessor :token
65
65
 
66
- def self.signin token, base_url=nil
66
+ def self.login token, base_url=nil
67
67
  new(token, base_url)
68
68
  end
69
69
 
@@ -78,35 +78,32 @@ class Ubalo
78
78
  params.merge!({:auth_token => token})
79
79
  end
80
80
  response = RestClient.get url, :params => params
81
- response
81
+ parse(response)
82
82
  end
83
83
 
84
84
  def post(action, params={})
85
85
  url = "#{base_url}/#{action}"
86
- RestClient.post url, {:auth_token => token}.merge(params)
87
- end
88
-
89
- def username
90
- username, role = whoami
91
- username
86
+ response = RestClient.post url, {:auth_token => token}.merge(params)
87
+ parse(response)
92
88
  end
93
89
 
94
90
  def whoami
95
- get(:whoami)
91
+ response = get(:whoami)
92
+ "You are #{response['username']}, with role #{response['role']}. You have #{response['pod_count']} pods."
96
93
  end
97
94
 
98
95
  def tasks state, count
99
- parse(get(:tasks, :count => count, :state => state))
96
+ get(:tasks, :count => count, :state => state)
100
97
  end
101
98
 
102
99
  def submit_task(pod_name, arg)
103
- parse(post(:submit_task, {:pod_name => pod_name, :arg => arg}))
100
+ post(:submit_task, {:pod_name => pod_name, :arg => arg})
104
101
  end
105
102
 
106
- def check_task(id, blocking=false)
103
+ def check_task(label, blocking=false)
107
104
  if blocking
108
105
  60.times do
109
- h = check_task_once(id)
106
+ h = check_task_once(label)
110
107
  if %w{complete failed}.include?(h['state'])
111
108
  $stderr.puts " done."
112
109
  return h
@@ -118,7 +115,7 @@ class Ubalo
118
115
  $stderr.puts
119
116
  raise "timed-out waiting for task"
120
117
  else
121
- check_task_once(id)
118
+ check_task_once(label)
122
119
  end
123
120
  end
124
121
 
@@ -130,8 +127,8 @@ class Ubalo
130
127
  post(:clear_keys)
131
128
  end
132
129
 
133
- def cat_code(name)
134
- get(:cat_code, :pod_name => name)
130
+ def download(name)
131
+ get(:download, :pod_name => name)
135
132
  end
136
133
 
137
134
  def upload_code(name, code)
@@ -139,12 +136,12 @@ class Ubalo
139
136
  end
140
137
 
141
138
  def ssh_path(name)
142
- h = parse(get(:ssh_path, :pod_name => name))
139
+ h = get(:ssh_path, :pod_name => name)
143
140
  [h['ssh_path'], h['environ'], h['environ_fullname']]
144
141
  end
145
142
 
146
143
  def pods
147
- parse(get(:pods))
144
+ get(:pods)
148
145
  end
149
146
 
150
147
  def ssh(pod_name)
@@ -173,8 +170,8 @@ class Ubalo
173
170
  if json
174
171
  puts outputs
175
172
  else
176
- puts " id: #{result['id']}"
177
- puts " name: #{result['pod_name']}"
173
+ puts " label: #{result['label']}"
174
+ puts " pod: #{result['pod_name']}"
178
175
  puts " arg: #{result['arg']}"
179
176
  puts " state: #{result['state']}"
180
177
  puts "status: #{result['status']}" if result['status']
@@ -187,19 +184,27 @@ class Ubalo
187
184
  puts result['stderr'].indent
188
185
  end
189
186
  if outputs
190
- puts "outputs:"
187
+ puts "output:"
191
188
  puts outputs.indent
192
189
  end
193
190
  end
194
191
  end
195
192
 
196
193
  def get_api_token login, password
197
- parse(post(:get_api_token, :user => {:login => login, :password => password}))['api_token']
194
+ post(:get_api_token, :user => {:login => login, :password => password})
195
+ end
196
+
197
+ def available_templates
198
+ get(:available_templates)['templates']
199
+ end
200
+
201
+ def create_pod name, type
202
+ post(:create_pod, template: type, pod_name: name)
198
203
  end
199
204
 
200
205
  private
201
- def check_task_once id
202
- parse(get(:check_task, :id => id))
206
+ def check_task_once label
207
+ get(:check_task, :label => label)
203
208
  end
204
209
 
205
210
  def parse(result)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ubalo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-12-01 00:00:00.000000000Z
12
+ date: 2011-12-02 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: gli
16
- requirement: &2153089760 !ruby/object:Gem::Requirement
16
+ requirement: &2161042040 !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,10 @@ dependencies:
21
21
  version: '0'
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *2153089760
24
+ version_requirements: *2161042040
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: highline
27
- requirement: &2153089320 !ruby/object:Gem::Requirement
27
+ requirement: &2161041600 !ruby/object:Gem::Requirement
28
28
  none: false
29
29
  requirements:
30
30
  - - ! '>='
@@ -32,10 +32,10 @@ dependencies:
32
32
  version: '0'
33
33
  type: :runtime
34
34
  prerelease: false
35
- version_requirements: *2153089320
35
+ version_requirements: *2161041600
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rest-client
38
- requirement: &2153088800 !ruby/object:Gem::Requirement
38
+ requirement: &2161041080 !ruby/object:Gem::Requirement
39
39
  none: false
40
40
  requirements:
41
41
  - - ~>
@@ -43,7 +43,7 @@ dependencies:
43
43
  version: 1.6.3
44
44
  type: :runtime
45
45
  prerelease: false
46
- version_requirements: *2153088800
46
+ version_requirements: *2161041080
47
47
  description: CLI and API client for Ubalo
48
48
  email: dev@ubalo.com
49
49
  executables: