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/lib/vmc/cli/app.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
require "vmc/cli
|
1
|
+
require "vmc/cli"
|
2
2
|
require "vmc/detect"
|
3
3
|
|
4
4
|
module VMC
|
5
|
-
class App <
|
5
|
+
class App < CLI
|
6
6
|
MEM_CHOICES = ["64M", "128M", "256M", "512M"]
|
7
7
|
|
8
8
|
# TODO: don't hardcode; bring in from remote
|
@@ -33,14 +33,40 @@ module VMC
|
|
33
33
|
}
|
34
34
|
|
35
35
|
|
36
|
-
desc "
|
36
|
+
desc "List your applications"
|
37
|
+
group :apps
|
38
|
+
input :name, :desc => "Filter by name regexp"
|
39
|
+
input :runtime, :desc => "Filter by runtime regexp"
|
40
|
+
input :framework, :desc => "Filter by framework regexp"
|
41
|
+
input :url, :desc => "Filter by url regexp"
|
42
|
+
def apps(input)
|
43
|
+
apps =
|
44
|
+
with_progress("Getting applications") do
|
45
|
+
client.apps
|
46
|
+
end
|
47
|
+
|
48
|
+
if apps.empty? and !quiet?
|
49
|
+
puts ""
|
50
|
+
puts "No applications."
|
51
|
+
return
|
52
|
+
end
|
53
|
+
|
54
|
+
apps.each.with_index do |a, num|
|
55
|
+
display_app(a) if app_matches(a, input)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
desc "Push an application, syncing changes if it exists"
|
37
61
|
group :apps, :manage
|
38
|
-
|
39
|
-
|
40
|
-
|
62
|
+
input(:name, :argument => true, :desc => "Application name") {
|
63
|
+
ask("Name")
|
64
|
+
}
|
65
|
+
input :path, :desc => "Path containing the application"
|
66
|
+
input(:url, :desc => "URL bound to app") { |default|
|
41
67
|
ask("URL", :default => default)
|
42
68
|
}
|
43
|
-
|
69
|
+
input(:memory, :desc => "Memory limit") { |framework, runtime|
|
44
70
|
ask("Memory Limit",
|
45
71
|
:choices => MEM_CHOICES,
|
46
72
|
:default =>
|
@@ -48,33 +74,38 @@ module VMC
|
|
48
74
|
MEM_DEFAULTS_FRAMEWORK[framework] ||
|
49
75
|
"64M")
|
50
76
|
}
|
51
|
-
|
77
|
+
input(:instances, :type => :integer,
|
78
|
+
:desc => "Number of instances to run") {
|
52
79
|
ask("Instances", :default => 1)
|
53
80
|
}
|
54
|
-
|
81
|
+
input(:framework, :desc => "Framework to use") { |choices, default|
|
55
82
|
opts = {:choices => choices}
|
56
83
|
opts[:default] = default if default
|
57
84
|
|
58
85
|
ask("Framework", opts)
|
59
86
|
}
|
60
|
-
|
87
|
+
input(:runtime, :desc => "Runtime to run it with") { |choices|
|
61
88
|
ask("Runtime", :choices => choices)
|
62
89
|
}
|
63
|
-
|
90
|
+
input(:command, :desc => "Startup command for standalone app") {
|
64
91
|
ask("Startup command")
|
65
92
|
}
|
66
|
-
|
67
|
-
|
68
|
-
|
93
|
+
input :start, :type => :boolean, :default => true,
|
94
|
+
:desc => "Start app after pushing?"
|
95
|
+
input :restart, :type => :boolean, :default => true,
|
96
|
+
:desc => "Restart app after updating?"
|
97
|
+
input(:create_services, :type => :boolean,
|
98
|
+
:desc => "Interactively create services?") {
|
69
99
|
ask "Create services for application?", :default => false
|
70
100
|
}
|
71
|
-
|
101
|
+
input(:bind_services, :type => :boolean,
|
102
|
+
:desc => "Interactively bind services?") {
|
72
103
|
ask "Bind other services to application?", :default => false
|
73
104
|
}
|
74
|
-
def push(
|
75
|
-
path = File.expand_path(input
|
105
|
+
def push(input)
|
106
|
+
path = File.expand_path(input[:path] || ".")
|
76
107
|
|
77
|
-
name = input
|
108
|
+
name = input[:name] if input[:name]
|
78
109
|
|
79
110
|
detector = Detector.new(client, path)
|
80
111
|
frameworks = detector.all_frameworks
|
@@ -84,47 +115,47 @@ module VMC
|
|
84
115
|
|
85
116
|
if app.exists?
|
86
117
|
upload_app(app, path)
|
87
|
-
restart
|
118
|
+
invoke :restart, :name => app.name if input[:restart]
|
88
119
|
return
|
89
120
|
end
|
90
121
|
|
91
|
-
app.total_instances = input
|
122
|
+
app.total_instances = input[:instances]
|
92
123
|
|
93
124
|
if detected.empty?
|
94
|
-
framework = input
|
125
|
+
framework = input[:framework, frameworks.keys.sort, nil]
|
95
126
|
else
|
96
|
-
framework = input
|
127
|
+
framework = input[:framework, detected.keys.sort + ["other"], default]
|
97
128
|
if framework == "other"
|
98
|
-
forget(:framework)
|
99
|
-
framework = input
|
129
|
+
input.forget(:framework)
|
130
|
+
framework = input[:framework, frameworks.keys.sort, nil]
|
100
131
|
end
|
101
132
|
end
|
102
133
|
|
103
134
|
framework_runtimes =
|
104
135
|
frameworks[framework]["runtimes"].collect { |k| k["name"] }
|
105
136
|
|
106
|
-
runtime = input
|
137
|
+
runtime = input[:runtime, framework_runtimes.sort]
|
107
138
|
|
108
139
|
app.framework = framework
|
109
140
|
app.runtime = runtime
|
110
141
|
|
111
142
|
if framework == "standalone"
|
112
|
-
app.command = input
|
143
|
+
app.command = input[:command]
|
113
144
|
|
114
|
-
if (url = input
|
145
|
+
if (url = input[:url, "none"]) != "none"
|
115
146
|
app.urls = [url]
|
116
147
|
else
|
117
148
|
app.urls = []
|
118
149
|
end
|
119
150
|
else
|
120
151
|
domain = client.target.sub(/^https?:\/\/api\.(.+)\/?/, '\1')
|
121
|
-
app.urls = [input
|
152
|
+
app.urls = [input[:url, "#{name}.#{domain}"]]
|
122
153
|
end
|
123
154
|
|
124
|
-
app.memory = megabytes(input
|
155
|
+
app.memory = megabytes(input[:memory, framework, runtime])
|
125
156
|
|
126
157
|
bindings = []
|
127
|
-
if input
|
158
|
+
if input[:create_services] && !force?
|
128
159
|
services = client.system_services
|
129
160
|
|
130
161
|
while true
|
@@ -157,7 +188,7 @@ module VMC
|
|
157
188
|
end
|
158
189
|
end
|
159
190
|
|
160
|
-
if input
|
191
|
+
if input[:bind_services] && !force?
|
161
192
|
services = client.services.collect(&:name)
|
162
193
|
|
163
194
|
while true
|
@@ -188,18 +219,18 @@ module VMC
|
|
188
219
|
raise
|
189
220
|
end
|
190
221
|
|
191
|
-
start
|
222
|
+
invoke :start, :name => app.name if input[:start]
|
192
223
|
end
|
193
224
|
|
194
|
-
desc "start APPS...", "Start an application"
|
195
|
-
group :apps, :manage
|
196
|
-
flag :name
|
197
|
-
flag :debug_mode, :aliases => "-d"
|
198
|
-
def start(*names)
|
199
|
-
if name = passed_value(:name)
|
200
|
-
names = [name]
|
201
|
-
end
|
202
225
|
|
226
|
+
desc "Start an application"
|
227
|
+
group :apps, :manage
|
228
|
+
input :names, :argument => :splat, :singular => :name,
|
229
|
+
:desc => "Applications to start"
|
230
|
+
input :debug_mode, :aliases => "-d",
|
231
|
+
:desc => "Debug mode to start in"
|
232
|
+
def start(input)
|
233
|
+
names = input[:names]
|
203
234
|
fail "No applications given." if names.empty?
|
204
235
|
|
205
236
|
names.each do |name|
|
@@ -209,7 +240,7 @@ module VMC
|
|
209
240
|
|
210
241
|
app = filter(:start_app, app)
|
211
242
|
|
212
|
-
switch_mode(app, input
|
243
|
+
switch_mode(app, input[:debug_mode])
|
213
244
|
|
214
245
|
with_progress("Starting #{c(name, :name)}") do |s|
|
215
246
|
if app.started?
|
@@ -223,21 +254,20 @@ module VMC
|
|
223
254
|
|
224
255
|
check_application(app)
|
225
256
|
|
226
|
-
if app.debug_mode && !
|
257
|
+
if app.debug_mode && !quiet?
|
227
258
|
puts ""
|
228
259
|
instances(name)
|
229
260
|
end
|
230
261
|
end
|
231
262
|
end
|
232
263
|
|
233
|
-
desc "stop APPS...", "Stop an application"
|
234
|
-
group :apps, :manage
|
235
|
-
flag :name
|
236
|
-
def stop(*names)
|
237
|
-
if name = passed_value(:name)
|
238
|
-
names = [name]
|
239
|
-
end
|
240
264
|
|
265
|
+
desc "Stop an application"
|
266
|
+
group :apps, :manage
|
267
|
+
input :names, :argument => :splat, :singular => :name,
|
268
|
+
:desc => "Applications to stop"
|
269
|
+
def stop(input)
|
270
|
+
names = input[:names]
|
241
271
|
fail "No applications given." if names.empty?
|
242
272
|
|
243
273
|
names.each do |name|
|
@@ -261,30 +291,36 @@ module VMC
|
|
261
291
|
end
|
262
292
|
end
|
263
293
|
|
264
|
-
|
294
|
+
|
295
|
+
desc "Stop and start an application"
|
265
296
|
group :apps, :manage
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
297
|
+
input :names, :argument => :splat, :singular => :name,
|
298
|
+
:desc => "Applications to stop"
|
299
|
+
input :debug_mode, :aliases => "-d",
|
300
|
+
:desc => "Debug mode to start in"
|
301
|
+
def restart(input)
|
302
|
+
invoke :stop, :names => input[:names]
|
303
|
+
invoke :start, :names => input[:names],
|
304
|
+
:debug_mode => input[:debug_mode]
|
271
305
|
end
|
272
306
|
|
273
|
-
|
307
|
+
|
308
|
+
desc "Delete an application"
|
274
309
|
group :apps, :manage
|
275
|
-
|
276
|
-
flag(:really) { |name, color|
|
310
|
+
input(:really, :type => :boolean) { |name, color|
|
277
311
|
force? || ask("Really delete #{c(name, color)}?", :default => false)
|
278
312
|
}
|
279
|
-
|
280
|
-
|
313
|
+
input(:names, :argument => :splat, :singular => :name,
|
314
|
+
:desc => "Applications to delete") { |names|
|
315
|
+
[ask("Delete which application?", :choices => names)]
|
281
316
|
}
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
317
|
+
input :orphaned, :aliases => "-o", :type => :boolean,
|
318
|
+
:desc => "Delete orphaned instances"
|
319
|
+
input :all, :default => false,
|
320
|
+
:desc => "Delete all applications"
|
321
|
+
def delete(input)
|
322
|
+
if input[:all]
|
323
|
+
return unless input[:really, "ALL APPS", :bad]
|
288
324
|
|
289
325
|
apps = client.apps
|
290
326
|
|
@@ -296,18 +332,15 @@ module VMC
|
|
296
332
|
end
|
297
333
|
end
|
298
334
|
|
299
|
-
delete_orphaned_services(orphaned)
|
335
|
+
delete_orphaned_services(orphaned, input[:orphaned])
|
300
336
|
|
301
337
|
return
|
302
338
|
end
|
303
339
|
|
304
340
|
apps = client.apps
|
341
|
+
fail "No applications." if apps.empty?
|
305
342
|
|
306
|
-
|
307
|
-
fail "No applications." if apps.empty?
|
308
|
-
|
309
|
-
names = [input(:name, apps.collect(&:name).sort)]
|
310
|
-
end
|
343
|
+
names = input[:names, apps.collect(&:name).sort]
|
311
344
|
|
312
345
|
to_delete = names.collect do |n|
|
313
346
|
if app = apps.find { |a| a.name == n }
|
@@ -317,31 +350,32 @@ module VMC
|
|
317
350
|
end
|
318
351
|
end
|
319
352
|
|
320
|
-
|
321
|
-
|
353
|
+
deleted = []
|
322
354
|
to_delete.each do |app|
|
323
|
-
really = input
|
324
|
-
|
325
|
-
forget(:really)
|
326
|
-
|
355
|
+
really = input[:really, app.name, :name]
|
327
356
|
next unless really
|
328
357
|
|
358
|
+
deleted << app
|
359
|
+
|
329
360
|
with_progress("Deleting #{c(app.name, :name)}") do
|
330
361
|
app.delete!
|
331
362
|
end
|
332
363
|
end
|
333
364
|
|
334
|
-
|
365
|
+
unless deleted.empty?
|
366
|
+
delete_orphaned_services(
|
367
|
+
find_orphaned_services(deleted),
|
368
|
+
input[:orphaned])
|
369
|
+
end
|
335
370
|
end
|
336
371
|
|
337
|
-
desc "instances APPS...", "List an app's instances"
|
338
|
-
group :apps, :info, :hidden => true
|
339
|
-
flag :name
|
340
|
-
def instances(*names)
|
341
|
-
if name = passed_value(:name)
|
342
|
-
names = [name]
|
343
|
-
end
|
344
372
|
|
373
|
+
desc "List an app's instances"
|
374
|
+
group :apps, :info, :hidden => true
|
375
|
+
input :names, :argument => :splat, :singular => :name,
|
376
|
+
:desc => "Applications to list instances of"
|
377
|
+
def instances(input)
|
378
|
+
names = input[:names]
|
345
379
|
fail "No applications given." if names.empty?
|
346
380
|
|
347
381
|
names.each do |name|
|
@@ -351,7 +385,7 @@ module VMC
|
|
351
385
|
end
|
352
386
|
|
353
387
|
instances.each do |i|
|
354
|
-
if
|
388
|
+
if quiet?
|
355
389
|
puts i.index
|
356
390
|
else
|
357
391
|
puts ""
|
@@ -361,29 +395,30 @@ module VMC
|
|
361
395
|
end
|
362
396
|
end
|
363
397
|
|
364
|
-
|
398
|
+
|
399
|
+
desc "Update the instances/memory limit for an application"
|
365
400
|
group :apps, :info, :hidden => true
|
366
|
-
|
367
|
-
|
401
|
+
input :name, :argument => true, :desc => "Application to update"
|
402
|
+
input(:instances, :type => :numeric,
|
403
|
+
:desc => "Number of instances to run") { |default|
|
368
404
|
ask("Instances", :default => default)
|
369
405
|
}
|
370
|
-
|
371
|
-
ask("Memory Limit",
|
372
|
-
:default => human_size(default * 1024 * 1024, 0)
|
373
|
-
:choices => MEM_CHOICES)
|
406
|
+
input(:memory, :desc => "Memory limit") { |default|
|
407
|
+
ask("Memory Limit", :choices => MEM_CHOICES,
|
408
|
+
:default => human_size(default * 1024 * 1024, 0))
|
374
409
|
}
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
410
|
+
input :restart, :default => true,
|
411
|
+
:desc => "Restart app after updating?"
|
412
|
+
def scale(input)
|
413
|
+
name = input[:name]
|
379
414
|
app = client.app(name)
|
380
415
|
|
381
|
-
instances =
|
382
|
-
memory =
|
416
|
+
instances = input.given(:instances)
|
417
|
+
memory = input.given(:memory)
|
383
418
|
|
384
419
|
unless instances || memory
|
385
|
-
instances = input
|
386
|
-
memory = input
|
420
|
+
instances = input[:instances, app.total_instances]
|
421
|
+
memory = input[:memory, app.memory]
|
387
422
|
end
|
388
423
|
|
389
424
|
megs = megabytes(memory)
|
@@ -399,36 +434,38 @@ module VMC
|
|
399
434
|
app.update!
|
400
435
|
end
|
401
436
|
|
402
|
-
if memory_changed && app.started? && input
|
403
|
-
|
404
|
-
app.restart!
|
405
|
-
end
|
437
|
+
if memory_changed && app.started? && input[:restart]
|
438
|
+
invoke :restart, :name => name
|
406
439
|
end
|
407
440
|
end
|
408
441
|
|
409
|
-
|
442
|
+
|
443
|
+
desc "Print out an app's logs"
|
410
444
|
group :apps, :info, :hidden => true
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
445
|
+
input :name, :argument => true,
|
446
|
+
:desc => "Application to get the logs of"
|
447
|
+
input :instance, :type => :numeric, :default => 0,
|
448
|
+
:desc => "Instance of application to get the logs of"
|
449
|
+
input :all, :default => false,
|
450
|
+
:desc => "Get logs for every instance"
|
451
|
+
def logs(input)
|
452
|
+
name = input[:name]
|
416
453
|
|
417
454
|
app = client.app(name)
|
418
455
|
fail "Unknown application '#{name}'" unless app.exists?
|
419
456
|
|
420
457
|
instances =
|
421
|
-
if input
|
458
|
+
if input[:all]
|
422
459
|
app.instances
|
423
460
|
else
|
424
|
-
app.instances.select { |i| i.index == input
|
461
|
+
app.instances.select { |i| i.index == input[:instance] }
|
425
462
|
end
|
426
463
|
|
427
464
|
if instances.empty?
|
428
|
-
if input
|
465
|
+
if input[:all]
|
429
466
|
fail "No instances found."
|
430
467
|
else
|
431
|
-
fail "Instance #{name} \##{input
|
468
|
+
fail "Instance #{name} \##{input[:instance]} not found."
|
432
469
|
end
|
433
470
|
end
|
434
471
|
|
@@ -441,7 +478,7 @@ module VMC
|
|
441
478
|
i.files("logs")
|
442
479
|
end
|
443
480
|
|
444
|
-
puts "" unless
|
481
|
+
puts "" unless quiet?
|
445
482
|
|
446
483
|
logs.each do |log|
|
447
484
|
body =
|
@@ -455,56 +492,57 @@ module VMC
|
|
455
492
|
end
|
456
493
|
end
|
457
494
|
|
458
|
-
desc "file APP [PATH]", "Print out an app's file contents"
|
459
|
-
group :apps, :info, :hidden => true
|
460
|
-
flag :name
|
461
|
-
def file(name = nil, path = "/")
|
462
|
-
name ||= input(:name)
|
463
495
|
|
496
|
+
desc "Print out an app's file contents"
|
497
|
+
group :apps, :info, :hidden => true
|
498
|
+
input :name, :argument => true,
|
499
|
+
:desc => "Application to inspect the files of"
|
500
|
+
input :path, :argument => true, :default => "/",
|
501
|
+
:desc => "Path of file to read"
|
502
|
+
def file(input)
|
464
503
|
file =
|
465
504
|
with_progress("Getting file contents") do
|
466
|
-
client.app(name).file(*path.split("/"))
|
505
|
+
client.app(input[:name]).file(*input[:path].split("/"))
|
467
506
|
end
|
468
507
|
|
469
|
-
puts "" unless
|
508
|
+
puts "" unless quiet?
|
470
509
|
|
471
510
|
print file
|
472
511
|
end
|
473
512
|
|
474
|
-
desc "
|
513
|
+
desc "Examine an app's files"
|
475
514
|
group :apps, :info, :hidden => true
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
515
|
+
input :name, :argument => true,
|
516
|
+
:desc => "Application to inspect the files of"
|
517
|
+
input :path, :argument => true, :default => "/",
|
518
|
+
:desc => "Path of directory to list"
|
519
|
+
def files(input)
|
480
520
|
files =
|
481
521
|
with_progress("Getting file listing") do
|
482
|
-
client.app(name).files(*path.split("/"))
|
522
|
+
client.app(input[:name]).files(*input[:path].split("/"))
|
483
523
|
end
|
484
524
|
|
485
|
-
puts "" unless
|
525
|
+
puts "" unless quiet?
|
486
526
|
files.each do |file|
|
487
527
|
puts file.join("/")
|
488
528
|
end
|
489
529
|
end
|
490
530
|
|
491
|
-
desc "health ...APPS", "Get application health"
|
492
|
-
group :apps, :info, :hidden => true
|
493
|
-
flag :name
|
494
|
-
def health(*names)
|
495
|
-
if name = passed_value(:name)
|
496
|
-
names = [name]
|
497
|
-
end
|
498
531
|
|
532
|
+
desc "Get application health"
|
533
|
+
group :apps, :info, :hidden => true
|
534
|
+
input :names, :argument => :splat, :singular => :name,
|
535
|
+
:desc => "Application to check the status of"
|
536
|
+
def health(input)
|
499
537
|
apps =
|
500
538
|
with_progress("Getting application health") do
|
501
|
-
names.collect do |n|
|
539
|
+
input[:names].collect do |n|
|
502
540
|
[n, app_status(client.app(n))]
|
503
541
|
end
|
504
542
|
end
|
505
543
|
|
506
544
|
apps.each do |name, status|
|
507
|
-
unless
|
545
|
+
unless quiet?
|
508
546
|
puts ""
|
509
547
|
print "#{c(name, :name)}: "
|
510
548
|
end
|
@@ -513,15 +551,15 @@ module VMC
|
|
513
551
|
end
|
514
552
|
end
|
515
553
|
|
516
|
-
desc "stats APP", "Display application instance status"
|
517
|
-
group :apps, :info, :hidden => true
|
518
|
-
flag :name
|
519
|
-
def stats(name = nil)
|
520
|
-
name ||= input(:name)
|
521
554
|
|
555
|
+
desc "Display application instance status"
|
556
|
+
group :apps, :info, :hidden => true
|
557
|
+
input :name, :argument => true,
|
558
|
+
:desc => "Application to get the stats for"
|
559
|
+
def stats(input)
|
522
560
|
stats =
|
523
|
-
with_progress("Getting stats") do
|
524
|
-
client.app(name).stats
|
561
|
+
with_progress("Getting stats for #{c(input[:name], :name)}") do
|
562
|
+
client.app(input[:name]).stats
|
525
563
|
end
|
526
564
|
|
527
565
|
stats.sort_by { |k, _| k }.each do |idx, info|
|
@@ -542,128 +580,218 @@ module VMC
|
|
542
580
|
end
|
543
581
|
end
|
544
582
|
|
545
|
-
|
546
|
-
|
547
|
-
|
583
|
+
|
584
|
+
desc "Add a URL mapping for an app"
|
585
|
+
group :apps, :info, :hidden => true
|
586
|
+
input :name, :argument => true,
|
587
|
+
:desc => "Application to add the URL to"
|
588
|
+
input :url, :argument => true,
|
589
|
+
:desc => "URL to route"
|
590
|
+
def map(input)
|
591
|
+
name = input[:name]
|
592
|
+
simple = input[:url].sub(/^https?:\/\/(.*)\/?/i, '\1')
|
593
|
+
|
594
|
+
with_progress("Updating #{c(name, :name)}") do
|
595
|
+
app = client.app(name)
|
596
|
+
app.urls << simple
|
597
|
+
app.update!
|
598
|
+
end
|
548
599
|
end
|
549
600
|
|
550
|
-
class URL < Command
|
551
|
-
desc "map APP URL", "Add a URL mapping for an app"
|
552
|
-
group :apps, :info, :hidden => true
|
553
|
-
def map(name, url)
|
554
|
-
simple = url.sub(/^https?:\/\/(.*)\/?/i, '\1')
|
555
601
|
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
602
|
+
desc "Remove a URL mapping from an app"
|
603
|
+
group :apps, :info, :hidden => true
|
604
|
+
input :name, :argument => true,
|
605
|
+
:desc => "Application to remove the URL from"
|
606
|
+
input(:url, :argument => true, :desc => "URL to unmap") { |choices|
|
607
|
+
ask("Which URL?", :choices => choices)
|
608
|
+
}
|
609
|
+
def unmap(input)
|
610
|
+
name = input[:name]
|
611
|
+
app = client.app(name)
|
612
|
+
|
613
|
+
url = input[:url, app.urls]
|
614
|
+
|
615
|
+
simple = url.sub(/^https?:\/\/(.*)\/?/i, '\1')
|
616
|
+
|
617
|
+
fail "Unknown application '#{name}'" unless app.exists?
|
618
|
+
|
619
|
+
with_progress("Updating #{c(name, :name)}") do |s|
|
620
|
+
unless app.urls.delete(simple)
|
621
|
+
s.fail do
|
622
|
+
err "URL #{url} is not mapped to this application."
|
623
|
+
return
|
624
|
+
end
|
560
625
|
end
|
626
|
+
|
627
|
+
app.update!
|
561
628
|
end
|
629
|
+
end
|
562
630
|
|
563
|
-
desc "unmap APP URL", "Remove a URL mapping from an app"
|
564
|
-
group :apps, :info, :hidden => true
|
565
|
-
def unmap(name, url)
|
566
|
-
simple = url.sub(/^https?:\/\/(.*)\/?/i, '\1')
|
567
631
|
|
568
|
-
|
569
|
-
|
632
|
+
desc "Show all environment variables set for an app"
|
633
|
+
group :apps, :info, :hidden => true
|
634
|
+
input :name, :argument => true,
|
635
|
+
:desc => "Application to inspect the environment of"
|
636
|
+
def env(input)
|
637
|
+
appname = input[:name]
|
570
638
|
|
571
|
-
|
572
|
-
|
639
|
+
vars =
|
640
|
+
with_progress("Getting env for #{c(input[:name], :name)}") do |s|
|
641
|
+
app = client.app(appname)
|
642
|
+
|
643
|
+
unless app.exists?
|
573
644
|
s.fail do
|
574
|
-
err "
|
645
|
+
err "Unknown application '#{appname}'"
|
575
646
|
return
|
576
647
|
end
|
577
648
|
end
|
578
649
|
|
579
|
-
app.
|
650
|
+
app.env
|
580
651
|
end
|
652
|
+
|
653
|
+
puts "" unless quiet?
|
654
|
+
|
655
|
+
vars.each do |pair|
|
656
|
+
name, val = pair.split("=", 2)
|
657
|
+
puts "#{c(name, :name)}: #{val}"
|
581
658
|
end
|
582
659
|
end
|
583
660
|
|
584
|
-
desc "url SUBCOMMAND ...ARGS", "Manage application URL bindings"
|
585
|
-
subcommand "url", URL
|
586
661
|
|
587
|
-
|
588
|
-
VALID_NAME = /^[a-zA-Za-z_][[:alnum:]_]*$/
|
662
|
+
VALID_ENV_VAR = /^[a-zA-Za-z_][[:alnum:]_]*$/
|
589
663
|
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
664
|
+
desc "Set an environment variable"
|
665
|
+
group :apps, :info, :hidden => true
|
666
|
+
input :name, :argument => true,
|
667
|
+
:desc => "Application to set the variable for"
|
668
|
+
input :var, :argument => true,
|
669
|
+
:desc => "Environment variable name"
|
670
|
+
input :value, :argument => :optional,
|
671
|
+
:desc => "Environment variable value"
|
672
|
+
input :restart, :default => true,
|
673
|
+
:desc => "Restart app after updating?"
|
674
|
+
def set_env(input)
|
675
|
+
appname = input[:name]
|
676
|
+
name = input[:var]
|
600
677
|
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
end
|
678
|
+
if value = input[:value]
|
679
|
+
name = input[:var]
|
680
|
+
elsif name["="]
|
681
|
+
name, value = name.split("=")
|
682
|
+
end
|
607
683
|
|
608
|
-
|
609
|
-
|
610
|
-
app.restart!
|
611
|
-
end
|
612
|
-
end
|
684
|
+
unless name =~ VALID_ENV_VAR
|
685
|
+
fail "Invalid variable name; must match #{VALID_ENV_VAR.inspect}"
|
613
686
|
end
|
614
687
|
|
615
|
-
|
616
|
-
|
617
|
-
flag :restart, :default => true
|
618
|
-
def unset(appname, name)
|
619
|
-
app = client.app(appname)
|
620
|
-
fail "Unknown application '#{appname}'" unless app.exists?
|
688
|
+
app = client.app(appname)
|
689
|
+
fail "Unknown application '#{appname}'" unless app.exists?
|
621
690
|
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
627
|
-
|
691
|
+
with_progress("Updating #{c(app.name, :name)}") do
|
692
|
+
app.update!("env" =>
|
693
|
+
app.env.reject { |v|
|
694
|
+
v.start_with?("#{name}=")
|
695
|
+
}.push("#{name}=#{value}"))
|
696
|
+
end
|
628
697
|
|
629
|
-
|
630
|
-
|
631
|
-
app.restart!
|
632
|
-
end
|
633
|
-
end
|
698
|
+
if app.started? && input[:restart]
|
699
|
+
invoke :restart, :name => app.name
|
634
700
|
end
|
701
|
+
end
|
635
702
|
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
vars =
|
640
|
-
with_progress("Getting variables") do |s|
|
641
|
-
app = client.app(appname)
|
703
|
+
alias_command :set_env, :env_set
|
704
|
+
alias_command :set_env, :add_env
|
705
|
+
alias_command :set_env, :env_add
|
642
706
|
|
643
|
-
unless app.exists?
|
644
|
-
s.fail do
|
645
|
-
err "Unknown application '#{appname}'"
|
646
|
-
return
|
647
|
-
end
|
648
|
-
end
|
649
707
|
|
650
|
-
|
651
|
-
|
708
|
+
desc "Remove an environment variable"
|
709
|
+
group :apps, :info, :hidden => true
|
710
|
+
input :name, :argument => true,
|
711
|
+
:desc => "Application to remove the variable from"
|
712
|
+
input :var, :argument => true,
|
713
|
+
:desc => "Environment variable name"
|
714
|
+
input :restart, :default => true,
|
715
|
+
:desc => "Restart app after updating?"
|
716
|
+
def delete_env(input)
|
717
|
+
appname = input[:name]
|
718
|
+
name = input[:var]
|
652
719
|
|
653
|
-
|
720
|
+
app = client.app(appname)
|
721
|
+
fail "Unknown application '#{appname}'" unless app.exists?
|
654
722
|
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
723
|
+
with_progress("Updating #{c(app.name, :name)}") do
|
724
|
+
app.update!("env" =>
|
725
|
+
app.env.reject { |v|
|
726
|
+
v.start_with?("#{name}=")
|
727
|
+
})
|
728
|
+
end
|
729
|
+
|
730
|
+
if app.started? && input[:restart]
|
731
|
+
invoke :restart, :name => app.name
|
659
732
|
end
|
660
733
|
end
|
661
734
|
|
662
|
-
|
663
|
-
|
735
|
+
alias_command :delete_env, :env_del
|
736
|
+
|
737
|
+
|
738
|
+
desc "DEPRECATED. Use 'push' instead."
|
739
|
+
def update(input)
|
740
|
+
fail "The 'update' command is no longer needed; use 'push' instead."
|
741
|
+
end
|
664
742
|
|
665
743
|
private
|
666
744
|
|
745
|
+
def app_matches(a, options)
|
746
|
+
if name = options[:name]
|
747
|
+
return false if a.name !~ /#{name}/
|
748
|
+
end
|
749
|
+
|
750
|
+
if runtime = options[:runtime]
|
751
|
+
return false if a.runtime !~ /#{runtime}/
|
752
|
+
end
|
753
|
+
|
754
|
+
if framework = options[:framework]
|
755
|
+
return false if a.framework !~ /#{framework}/
|
756
|
+
end
|
757
|
+
|
758
|
+
if url = options[:url]
|
759
|
+
return false if a.urls.none? { |u| u =~ /#{url}/ }
|
760
|
+
end
|
761
|
+
|
762
|
+
true
|
763
|
+
end
|
764
|
+
|
765
|
+
IS_UTF8 = !!(ENV["LC_ALL"] || ENV["LC_CTYPE"] || ENV["LANG"])["UTF-8"]
|
766
|
+
|
767
|
+
def display_app(a)
|
768
|
+
if quiet?
|
769
|
+
puts a.name
|
770
|
+
return
|
771
|
+
end
|
772
|
+
|
773
|
+
puts ""
|
774
|
+
|
775
|
+
status = app_status(a)
|
776
|
+
|
777
|
+
puts "#{c(a.name, :name)}: #{status}"
|
778
|
+
|
779
|
+
puts " platform: #{b(a.framework)} on #{b(a.runtime)}"
|
780
|
+
|
781
|
+
print " usage: #{b(human_size(a.memory * 1024 * 1024, 0))}"
|
782
|
+
print " #{c(IS_UTF8 ? "\xc3\x97" : "x", :dim)} #{b(a.total_instances)}"
|
783
|
+
print " instance#{a.total_instances == 1 ? "" : "s"}"
|
784
|
+
puts ""
|
785
|
+
|
786
|
+
unless a.urls.empty?
|
787
|
+
puts " urls: #{a.urls.collect { |u| b(u) }.join(", ")}"
|
788
|
+
end
|
789
|
+
|
790
|
+
unless a.services.empty?
|
791
|
+
puts " services: #{a.services.collect { |s| b(s) }.join(", ")}"
|
792
|
+
end
|
793
|
+
end
|
794
|
+
|
667
795
|
def upload_app(app, path)
|
668
796
|
with_progress("Uploading #{c(app.name, :name)}") do
|
669
797
|
app.upload(path)
|
@@ -780,13 +908,13 @@ module VMC
|
|
780
908
|
orphaned
|
781
909
|
end
|
782
910
|
|
783
|
-
def delete_orphaned_services(names)
|
911
|
+
def delete_orphaned_services(names, orphaned)
|
784
912
|
return if names.empty?
|
785
913
|
|
786
|
-
puts "" unless
|
914
|
+
puts "" unless quiet?
|
787
915
|
|
788
916
|
names.select { |s|
|
789
|
-
|
917
|
+
orphaned ||
|
790
918
|
ask("Delete orphaned service #{c(s, :name)}?", :default => false)
|
791
919
|
}.each do |s|
|
792
920
|
with_progress("Deleting service #{c(s, :name)}") do
|