vmc 0.4.0.beta.12 → 0.4.0.beta.13
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.
- data/vmc-ng/bin/vmc +0 -3
- data/vmc-ng/lib/vmc.rb +5 -0
- data/vmc-ng/lib/vmc/cli.rb +190 -342
- data/vmc-ng/lib/vmc/cli/app.rb +363 -235
- data/vmc-ng/lib/vmc/cli/help.rb +12 -0
- data/vmc-ng/lib/vmc/cli/interactive.rb +101 -0
- data/vmc-ng/lib/vmc/cli/service.rb +116 -38
- data/vmc-ng/lib/vmc/cli/start.rb +252 -0
- data/vmc-ng/lib/vmc/cli/user.rb +53 -24
- data/vmc-ng/lib/vmc/plugin.rb +0 -5
- data/vmc-ng/lib/vmc/version.rb +1 -1
- metadata +16 -16
- data/vmc-ng/lib/vmc/cli/better_help.rb +0 -193
- data/vmc-ng/lib/vmc/cli/command.rb +0 -567
- data/vmc-ng/lib/vmc/cli/dots.rb +0 -190
data/vmc-ng/bin/vmc
CHANGED
data/vmc-ng/lib/vmc.rb
CHANGED
data/vmc-ng/lib/vmc/cli.rb
CHANGED
@@ -1,428 +1,276 @@
|
|
1
|
-
require "
|
2
|
-
|
3
|
-
VMC::Command.groups(
|
4
|
-
[:start, "Getting Started"],
|
5
|
-
[:apps, "Applications",
|
6
|
-
[:manage, "Management"],
|
7
|
-
[:info, "Information"]],
|
8
|
-
[:services, "Services",
|
9
|
-
[:manage, "Management"]],
|
10
|
-
[:admin, "Administration",
|
11
|
-
[:user, "User Management"]])
|
12
|
-
|
13
|
-
require "vmc/cli/app"
|
14
|
-
require "vmc/cli/service"
|
15
|
-
require "vmc/cli/user"
|
1
|
+
require "yaml"
|
16
2
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
subcommand "service", Service
|
21
|
-
|
22
|
-
desc "user SUBCOMMAND ...ARGS", "User management"
|
23
|
-
subcommand "user", User
|
24
|
-
|
25
|
-
desc "info", "Display information on the current target, user, etc."
|
26
|
-
group :start
|
27
|
-
flag :runtimes, :default => false
|
28
|
-
flag :services, :default => false
|
29
|
-
flag :frameworks, :default => false
|
30
|
-
def info
|
31
|
-
info =
|
32
|
-
with_progress("Getting target information") do
|
33
|
-
client.info
|
34
|
-
end
|
3
|
+
require "mothership"
|
4
|
+
require "mothership/pretty"
|
5
|
+
require "mothership/progress"
|
35
6
|
|
36
|
-
|
7
|
+
require "cfoundry"
|
37
8
|
|
38
|
-
|
39
|
-
|
9
|
+
require "vmc/constants"
|
10
|
+
require "vmc/errors"
|
40
11
|
|
41
|
-
|
42
|
-
|
43
|
-
f["runtimes"].each do |r|
|
44
|
-
runtimes[r["name"]] = r
|
45
|
-
end
|
46
|
-
end
|
12
|
+
require "vmc/cli/help"
|
13
|
+
require "vmc/cli/interactive"
|
47
14
|
|
48
|
-
runtimes = runtimes.values.sort_by { |x| x["name"] }
|
49
15
|
|
50
|
-
|
51
|
-
runtimes.each do |r|
|
52
|
-
puts r["name"]
|
53
|
-
end
|
54
|
-
return
|
55
|
-
end
|
16
|
+
$vmc_asked_auth = false
|
56
17
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
return
|
65
|
-
end
|
66
|
-
|
67
|
-
if input(:services)
|
68
|
-
raise NotAuthorized unless authorized
|
69
|
-
|
70
|
-
services = client.system_services
|
71
|
-
|
72
|
-
if simple_output?
|
73
|
-
services.each do |name, _|
|
74
|
-
puts name
|
75
|
-
end
|
18
|
+
module VMC
|
19
|
+
class CLI < Mothership
|
20
|
+
include VMC::Interactive
|
21
|
+
include Mothership::Pretty
|
22
|
+
include Mothership::Progress
|
76
23
|
|
77
|
-
|
78
|
-
|
24
|
+
option :help, :alias => "-h", :type => :boolean,
|
25
|
+
:desc => "Show command usage & instructions"
|
79
26
|
|
80
|
-
|
81
|
-
|
82
|
-
puts "#{c(name, :name)}:"
|
83
|
-
puts " versions: #{meta[:versions].join ", "}"
|
84
|
-
puts " description: #{meta[:description]}"
|
85
|
-
puts " type: #{meta[:type]}"
|
86
|
-
end
|
27
|
+
option :proxy, :alias => "-u", :value => :email,
|
28
|
+
:desc => "Act as another user (admin only)"
|
87
29
|
|
88
|
-
|
89
|
-
|
30
|
+
option :version, :alias => "-v", :type => :boolean,
|
31
|
+
:desc => "Print version number"
|
90
32
|
|
91
|
-
|
92
|
-
|
33
|
+
option(:force, :alias => "-f", :type => :boolean,
|
34
|
+
:desc => "Skip interaction when possible") {
|
35
|
+
option(:script)
|
36
|
+
}
|
93
37
|
|
94
|
-
|
38
|
+
option(:quiet, :alias => "-q", :type => :boolean,
|
39
|
+
:desc => "Simplify output format") {
|
40
|
+
option(:script)
|
41
|
+
}
|
95
42
|
|
96
|
-
|
97
|
-
|
98
|
-
|
43
|
+
option(:script, :alias => "-s", :type => :boolean,
|
44
|
+
:desc => "Shortcut for --quiet and --force") {
|
45
|
+
!$stdout.tty?
|
46
|
+
}
|
99
47
|
|
100
|
-
|
101
|
-
|
48
|
+
option(:color, :type => :boolean, :default => true,
|
49
|
+
:desc => "Use colorful output") {
|
50
|
+
!option(:quiet)
|
51
|
+
}
|
102
52
|
|
103
|
-
|
53
|
+
option :trace, :alias => "-t", :type => :boolean,
|
54
|
+
:desc => "Show API requests and responses"
|
104
55
|
|
105
|
-
puts info["description"]
|
106
|
-
puts ""
|
107
|
-
puts "target: #{b(client.target)}"
|
108
|
-
puts " version: #{info["version"]}"
|
109
|
-
puts " support: #{info["support"]}"
|
110
56
|
|
111
|
-
|
112
|
-
|
113
|
-
puts "
|
114
|
-
|
115
|
-
|
116
|
-
limits = info["limits"]
|
117
|
-
info["usage"].each do |k, v|
|
118
|
-
m = limits[k]
|
119
|
-
if k == "memory"
|
120
|
-
puts " #{k}: #{usage(v * 1024 * 1024, m * 1024 * 1024)}"
|
121
|
-
else
|
122
|
-
puts " #{k}: #{b(v)} of #{b(m)} limit"
|
123
|
-
end
|
124
|
-
end
|
57
|
+
def default_action
|
58
|
+
if option(:version)
|
59
|
+
puts "vmc #{VERSION}"
|
60
|
+
else
|
61
|
+
super
|
125
62
|
end
|
126
63
|
end
|
127
64
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
65
|
+
def execute(cmd, argv)
|
66
|
+
if option(:help)
|
67
|
+
invoke :help, :command => cmd.name.to_s
|
68
|
+
else
|
69
|
+
super
|
70
|
+
end
|
71
|
+
rescue Interrupt
|
72
|
+
exit_status 130
|
73
|
+
rescue Mothership::Error
|
74
|
+
raise
|
75
|
+
rescue UserError => e
|
76
|
+
err e.message
|
77
|
+
rescue CFoundry::Denied => e
|
78
|
+
if !$vmc_asked_auth && e.error_code == 200
|
79
|
+
$vmc_asked_auth = true
|
135
80
|
|
136
|
-
|
137
|
-
|
138
|
-
with_progress("Setting target to #{display}") do
|
139
|
-
unless force?
|
140
|
-
# check that the target is valid
|
141
|
-
CFoundry::Client.new(target).info
|
142
|
-
end
|
81
|
+
puts ""
|
82
|
+
puts c("Not authenticated! Try logging in:", :warning)
|
143
83
|
|
144
|
-
|
145
|
-
|
146
|
-
end
|
84
|
+
invoke :login
|
85
|
+
@client = nil
|
147
86
|
|
148
|
-
|
149
|
-
group :start
|
150
|
-
flag(:email) {
|
151
|
-
ask("Email")
|
152
|
-
}
|
153
|
-
flag(:password)
|
154
|
-
# TODO: implement new authentication scheme
|
155
|
-
def login(email = nil)
|
156
|
-
unless simple_output?
|
157
|
-
display_target
|
158
|
-
puts ""
|
87
|
+
retry
|
159
88
|
end
|
160
89
|
|
161
|
-
|
162
|
-
|
90
|
+
err "Denied: #{e.description}"
|
91
|
+
rescue Exception => e
|
92
|
+
msg = e.class.name
|
93
|
+
msg << ": #{e}" unless e.to_s.empty?
|
94
|
+
err msg
|
163
95
|
|
164
|
-
|
165
|
-
failed = false
|
166
|
-
until authenticated
|
167
|
-
unless force?
|
168
|
-
if failed || !password
|
169
|
-
password = ask("Password", :echo => "*", :forget => true)
|
170
|
-
end
|
171
|
-
end
|
96
|
+
ensure_config_dir
|
172
97
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
98
|
+
File.open(File.expand_path(VMC::CRASH_FILE), "w") do |f|
|
99
|
+
f.puts "Time of crash:"
|
100
|
+
f.puts " #{Time.now}"
|
101
|
+
f.puts ""
|
102
|
+
f.puts msg
|
103
|
+
f.puts ""
|
179
104
|
|
180
|
-
|
181
|
-
|
182
|
-
|
105
|
+
vmc_dir = File.expand_path("../../../..", __FILE__) + "/"
|
106
|
+
e.backtrace.each do |loc|
|
107
|
+
if loc =~ /\/gems\//
|
108
|
+
f.puts loc.sub(/.*\/gems\//, "")
|
109
|
+
else
|
110
|
+
f.puts loc.sub(vmc_dir, "")
|
183
111
|
end
|
184
112
|
end
|
185
113
|
end
|
186
|
-
ensure
|
187
|
-
$exit_status = 1 if not authenticated
|
188
114
|
end
|
189
115
|
|
190
|
-
|
191
|
-
|
192
|
-
def logout
|
193
|
-
with_progress("Logging out") do
|
194
|
-
remove_token
|
195
|
-
end
|
116
|
+
def quiet?
|
117
|
+
option(:quiet)
|
196
118
|
end
|
197
119
|
|
198
|
-
|
199
|
-
|
200
|
-
flag(:email) {
|
201
|
-
ask("Email")
|
202
|
-
}
|
203
|
-
flag(:password) {
|
204
|
-
ask("Password", :echo => "*", :forget => true)
|
205
|
-
}
|
206
|
-
flag(:verify_password) {
|
207
|
-
ask("Confirm Password", :echo => "*", :forget => true)
|
208
|
-
}
|
209
|
-
flag(:no_login, :type => :boolean)
|
210
|
-
def register(email = nil)
|
211
|
-
unless simple_output?
|
212
|
-
puts "Target: #{c(client_target, :name)}"
|
213
|
-
puts ""
|
214
|
-
end
|
215
|
-
|
216
|
-
email ||= input(:email)
|
217
|
-
password ||= input(:password)
|
218
|
-
|
219
|
-
if !force? && password != input(:verify_password)
|
220
|
-
fail "Passwords do not match."
|
221
|
-
end
|
222
|
-
|
223
|
-
with_progress("Creating user") do
|
224
|
-
client.register(email, password)
|
225
|
-
end
|
226
|
-
|
227
|
-
unless input(:skip_login)
|
228
|
-
with_progress("Logging in") do
|
229
|
-
save_token(client.login(email, password))
|
230
|
-
end
|
231
|
-
end
|
120
|
+
def force?
|
121
|
+
option(:force)
|
232
122
|
end
|
233
123
|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
flag :runtime, :desc => "Filter by runtime regexp"
|
238
|
-
flag :framework, :desc => "Filter by framework regexp"
|
239
|
-
flag :url, :desc => "Filter by url regexp"
|
240
|
-
def apps
|
241
|
-
apps =
|
242
|
-
with_progress("Getting applications") do
|
243
|
-
client.apps
|
244
|
-
end
|
124
|
+
def color_enabled?
|
125
|
+
option(:color)
|
126
|
+
end
|
245
127
|
|
246
|
-
|
247
|
-
|
248
|
-
puts
|
249
|
-
|
128
|
+
def err(msg, exit_status = 1)
|
129
|
+
if quiet?
|
130
|
+
$stderr.puts(msg)
|
131
|
+
else
|
132
|
+
puts c(msg, :error)
|
250
133
|
end
|
251
134
|
|
252
|
-
|
253
|
-
display_app(a) if app_matches(a)
|
254
|
-
end
|
135
|
+
exit_status 1
|
255
136
|
end
|
256
137
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
flag :app, :desc => "Filter by bound application regexp"
|
261
|
-
flag :type, :desc => "Filter by service type regexp"
|
262
|
-
flag :vendor, :desc => "Filter by service vendor regexp"
|
263
|
-
flag :tier, :desc => "Filter by service tier regexp"
|
264
|
-
def services
|
265
|
-
services =
|
266
|
-
with_progress("Getting services") do
|
267
|
-
client.services
|
268
|
-
end
|
269
|
-
|
270
|
-
puts "" unless simple_output?
|
271
|
-
|
272
|
-
if services.empty? and !simple_output?
|
273
|
-
puts "No services."
|
274
|
-
end
|
138
|
+
def fail(msg)
|
139
|
+
raise UserError, msg
|
140
|
+
end
|
275
141
|
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
apps.none? { |a| a.services.include? s.name }
|
280
|
-
end
|
142
|
+
def sane_target_url(url)
|
143
|
+
unless url =~ /^https?:\/\//
|
144
|
+
url = "http://#{url}"
|
281
145
|
end
|
282
146
|
|
283
|
-
|
284
|
-
display_service(s) if service_matches(s)
|
285
|
-
end
|
147
|
+
url.gsub(/\/$/, "")
|
286
148
|
end
|
287
149
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
users =
|
292
|
-
with_progress("Getting users") do
|
293
|
-
client.users
|
294
|
-
end
|
150
|
+
def target_file
|
151
|
+
one_of(VMC::TARGET_FILE, VMC::OLD_TARGET_FILE)
|
152
|
+
end
|
295
153
|
|
296
|
-
|
297
|
-
|
298
|
-
end
|
154
|
+
def tokens_file
|
155
|
+
one_of(VMC::TOKENS_FILE, VMC::OLD_TOKENS_FILE)
|
299
156
|
end
|
300
157
|
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
if options[:version]
|
306
|
-
puts "vmc #{VERSION}"
|
307
|
-
return
|
158
|
+
def one_of(*paths)
|
159
|
+
paths.each do |p|
|
160
|
+
exp = File.expand_path(p)
|
161
|
+
return exp if File.exist? exp
|
308
162
|
end
|
309
163
|
|
310
|
-
|
311
|
-
|
312
|
-
else
|
313
|
-
unless input(:all)
|
314
|
-
puts "Showing basic command set. Pass --all to list all commands."
|
315
|
-
puts ""
|
316
|
-
end
|
164
|
+
paths.first
|
165
|
+
end
|
317
166
|
|
318
|
-
|
319
|
-
|
167
|
+
def client_target
|
168
|
+
File.read(target_file).chomp
|
320
169
|
end
|
321
170
|
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
user_colors.each do |n, c|
|
326
|
-
puts "#{n}: #{c(c.to_s, n)}"
|
327
|
-
end
|
171
|
+
def ensure_config_dir
|
172
|
+
config = File.expand_path(VMC::CONFIG_DIR)
|
173
|
+
Dir.mkdir(config) unless File.exist? config
|
328
174
|
end
|
329
175
|
|
330
|
-
|
176
|
+
def set_target(url)
|
177
|
+
ensure_config_dir
|
331
178
|
|
332
|
-
|
333
|
-
|
334
|
-
return false if a.name !~ /#{name}/
|
179
|
+
File.open(File.expand_path(VMC::TARGET_FILE), "w") do |f|
|
180
|
+
f.write(sane_target_url(url))
|
335
181
|
end
|
336
182
|
|
337
|
-
|
338
|
-
|
339
|
-
end
|
183
|
+
@client = nil
|
184
|
+
end
|
340
185
|
|
341
|
-
|
342
|
-
|
343
|
-
|
186
|
+
def tokens
|
187
|
+
new_toks = File.expand_path(VMC::TOKENS_FILE)
|
188
|
+
old_toks = File.expand_path(VMC::OLD_TOKENS_FILE)
|
344
189
|
|
345
|
-
if
|
346
|
-
|
190
|
+
if File.exist? new_toks
|
191
|
+
YAML.load_file(new_toks)
|
192
|
+
elsif File.exist? old_toks
|
193
|
+
JSON.load(File.read(old_toks))
|
194
|
+
else
|
195
|
+
{}
|
347
196
|
end
|
197
|
+
end
|
348
198
|
|
349
|
-
|
199
|
+
def client_token
|
200
|
+
tokens[client_target]
|
350
201
|
end
|
351
202
|
|
352
|
-
|
203
|
+
def save_tokens(ts)
|
204
|
+
ensure_config_dir
|
353
205
|
|
354
|
-
|
355
|
-
|
356
|
-
puts a.name
|
357
|
-
return
|
206
|
+
File.open(File.expand_path(VMC::TOKENS_FILE), "w") do |io|
|
207
|
+
YAML.dump(ts, io)
|
358
208
|
end
|
209
|
+
end
|
359
210
|
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
puts " platform: #{b(a.framework)} on #{b(a.runtime)}"
|
367
|
-
|
368
|
-
print " usage: #{b(human_size(a.memory * 1024 * 1024, 0))}"
|
369
|
-
print " #{c(IS_UTF8 ? "\xc3\x97" : "x", :dim)} #{b(a.total_instances)}"
|
370
|
-
print " instance#{a.total_instances == 1 ? "" : "s"}"
|
371
|
-
puts ""
|
372
|
-
|
373
|
-
unless a.urls.empty?
|
374
|
-
puts " urls: #{a.urls.collect { |u| b(u) }.join(", ")}"
|
375
|
-
end
|
211
|
+
def save_token(token)
|
212
|
+
ts = tokens
|
213
|
+
ts[client_target] = token
|
214
|
+
save_tokens(ts)
|
215
|
+
end
|
376
216
|
|
377
|
-
|
378
|
-
|
379
|
-
|
217
|
+
def remove_token
|
218
|
+
ts = tokens
|
219
|
+
ts.delete client_target
|
220
|
+
save_tokens(ts)
|
380
221
|
end
|
381
222
|
|
382
|
-
def
|
383
|
-
|
384
|
-
return false if s.name !~ /#{name}/
|
385
|
-
end
|
223
|
+
def client
|
224
|
+
return @client if @client
|
386
225
|
|
387
|
-
|
388
|
-
|
389
|
-
|
226
|
+
@client = CFoundry::Client.new(client_target, client_token)
|
227
|
+
@client.proxy = option(:proxy)
|
228
|
+
@client.trace = option(:trace)
|
229
|
+
@client
|
230
|
+
end
|
390
231
|
|
391
|
-
|
392
|
-
|
393
|
-
|
232
|
+
def usage(used, limit)
|
233
|
+
"#{b(human_size(used))} of #{b(human_size(limit, 0))}"
|
234
|
+
end
|
394
235
|
|
395
|
-
|
396
|
-
|
397
|
-
|
236
|
+
def percentage(num, low = 50, mid = 70)
|
237
|
+
color =
|
238
|
+
if num <= low
|
239
|
+
:good
|
240
|
+
elsif num <= mid
|
241
|
+
:warning
|
242
|
+
else
|
243
|
+
:bad
|
244
|
+
end
|
398
245
|
|
399
|
-
|
246
|
+
c(format("%.1f\%", num), color)
|
400
247
|
end
|
401
248
|
|
402
|
-
def
|
403
|
-
if
|
404
|
-
|
405
|
-
|
406
|
-
|
249
|
+
def megabytes(str)
|
250
|
+
if str =~ /T$/i
|
251
|
+
str.to_i * 1024 * 1024
|
252
|
+
elsif str =~ /G$/i
|
253
|
+
str.to_i * 1024
|
254
|
+
elsif str =~ /M$/i
|
255
|
+
str.to_i
|
256
|
+
elsif str =~ /K$/i
|
257
|
+
str.to_i / 1024
|
258
|
+
else # assume megabytes
|
259
|
+
str.to_i
|
407
260
|
end
|
408
261
|
end
|
409
262
|
|
410
|
-
def
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
263
|
+
def human_size(num, precision = 1)
|
264
|
+
sizes = ["G", "M", "K"]
|
265
|
+
sizes.each.with_index do |suf, i|
|
266
|
+
pow = sizes.size - i
|
267
|
+
unit = 1024 ** pow
|
268
|
+
if num >= unit
|
269
|
+
return format("%.#{precision}f%s", num / unit, suf)
|
270
|
+
end
|
417
271
|
end
|
418
|
-
end
|
419
272
|
|
420
|
-
|
421
|
-
if simple_output?
|
422
|
-
puts client.target
|
423
|
-
else
|
424
|
-
puts "Target: #{c(client.target, :name)}"
|
425
|
-
end
|
273
|
+
format("%.#{precision}fB", num)
|
426
274
|
end
|
427
275
|
end
|
428
276
|
end
|