ubalo 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/ubalo +106 -104
- data/lib/ubalo.rb +30 -25
- 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.
|
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
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
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
|
-
|
118
|
+
if Dir.exist?(destination_path)
|
119
|
+
raise "directory #{destination_path.inspect} already exists"
|
120
|
+
end
|
115
121
|
|
116
|
-
|
117
|
-
|
122
|
+
FileUtils.mkdir(destination_path)
|
123
|
+
FileUtils.mkdir(File.join(destination_path, ".ubalo"))
|
118
124
|
|
119
|
-
|
125
|
+
File.open(File.join(destination_path, ".ubalo", "name"), "w") do |f|
|
126
|
+
f.puts name
|
120
127
|
end
|
121
|
-
end
|
122
128
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
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 '
|
138
|
+
desc 'Download a pod to your computer'
|
131
139
|
arg_name '<pod name>'
|
132
|
-
command :
|
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
|
-
|
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 '
|
157
|
+
desc 'Create a new pod'
|
144
158
|
arg_name '<pod name>'
|
145
|
-
command :
|
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
|
-
|
153
|
-
|
154
|
-
|
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
|
-
|
161
|
-
|
162
|
-
|
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
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
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
|
-
|
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
|
-
|
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 '
|
204
|
+
desc 'Run a pod'
|
179
205
|
arg_name '<pod name>'
|
180
|
-
command :
|
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
|
-
|
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
|
-
|
201
|
-
|
202
|
-
|
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.
|
218
|
+
result = ubalo.check_task(task_label, true)
|
219
|
+
ubalo.show_result(result)
|
217
220
|
end
|
218
221
|
end
|
219
222
|
|
220
|
-
desc '
|
223
|
+
desc 'Submit a pod for running in the background'
|
221
224
|
arg_name '<pod name>'
|
222
|
-
command :
|
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 "
|
231
|
-
|
232
|
-
|
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
|
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
|
-
|
253
|
-
unless
|
246
|
+
task_label = args.first
|
247
|
+
unless task_label
|
254
248
|
raise "please specify a task"
|
255
249
|
end
|
256
250
|
|
257
|
-
|
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 '
|
263
|
-
command :
|
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
|
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
|
-
|
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 "
|
272
|
-
puts ubalo.whoami
|
270
|
+
puts "Success! Ready to use as #{username}."
|
273
271
|
end
|
274
272
|
end
|
275
273
|
|
276
|
-
desc '
|
277
|
-
command :
|
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
|
289
|
-
unless command && command.name == :
|
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 == :
|
296
|
-
raise "No credentials found. Please run 'ubalo
|
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.
|
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['
|
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.
|
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
|
-
|
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
|
-
|
96
|
+
get(:tasks, :count => count, :state => state)
|
100
97
|
end
|
101
98
|
|
102
99
|
def submit_task(pod_name, arg)
|
103
|
-
|
100
|
+
post(:submit_task, {:pod_name => pod_name, :arg => arg})
|
104
101
|
end
|
105
102
|
|
106
|
-
def check_task(
|
103
|
+
def check_task(label, blocking=false)
|
107
104
|
if blocking
|
108
105
|
60.times do
|
109
|
-
h = check_task_once(
|
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(
|
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
|
134
|
-
get(:
|
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 =
|
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
|
-
|
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 "
|
177
|
-
puts "
|
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 "
|
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
|
-
|
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
|
202
|
-
|
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.
|
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-
|
12
|
+
date: 2011-12-02 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: gli
|
16
|
-
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: *
|
24
|
+
version_requirements: *2161042040
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: highline
|
27
|
-
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: *
|
35
|
+
version_requirements: *2161041600
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rest-client
|
38
|
-
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: *
|
46
|
+
version_requirements: *2161041080
|
47
47
|
description: CLI and API client for Ubalo
|
48
48
|
email: dev@ubalo.com
|
49
49
|
executables:
|