vmc 0.4.0.beta.93 → 0.4.0.beta.94
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/Rakefile +21 -30
- data/vmc-ng/lib/vmc.rb +4 -3
- data/vmc-ng/lib/vmc/cli.rb +10 -9
- data/vmc-ng/lib/vmc/cli/app/app.rb +45 -0
- data/vmc-ng/lib/vmc/cli/app/apps.rb +97 -0
- data/vmc-ng/lib/vmc/cli/app/base.rb +82 -0
- data/vmc-ng/lib/vmc/cli/app/crashes.rb +41 -0
- data/vmc-ng/lib/vmc/cli/app/delete.rb +90 -0
- data/vmc-ng/lib/vmc/cli/app/deprecated.rb +11 -0
- data/vmc-ng/lib/vmc/cli/app/env.rb +86 -0
- data/vmc-ng/lib/vmc/cli/app/files.rb +85 -0
- data/vmc-ng/lib/vmc/cli/app/health.rb +27 -0
- data/vmc-ng/lib/vmc/cli/app/instances.rb +49 -0
- data/vmc-ng/lib/vmc/cli/app/logs.rb +80 -0
- data/vmc-ng/lib/vmc/cli/app/push.rb +336 -0
- data/vmc-ng/lib/vmc/cli/app/rename.rb +31 -0
- data/vmc-ng/lib/vmc/cli/app/restart.rb +23 -0
- data/vmc-ng/lib/vmc/cli/app/routes.rb +97 -0
- data/vmc-ng/lib/vmc/cli/app/scale.rb +67 -0
- data/vmc-ng/lib/vmc/cli/app/start.rb +96 -0
- data/vmc-ng/lib/vmc/cli/app/stats.rb +68 -0
- data/vmc-ng/lib/vmc/cli/app/stop.rb +29 -0
- data/vmc-ng/lib/vmc/cli/domain/add_domain.rb +27 -0
- data/vmc-ng/lib/vmc/cli/domain/base.rb +12 -0
- data/vmc-ng/lib/vmc/cli/domain/create_domain.rb +31 -0
- data/vmc-ng/lib/vmc/cli/domain/delete_domain.rb +51 -0
- data/vmc-ng/lib/vmc/cli/domain/domains.rb +43 -0
- data/vmc-ng/lib/vmc/cli/domain/remove_domain.rb +26 -0
- data/vmc-ng/lib/vmc/cli/help.rb +0 -1
- data/vmc-ng/lib/vmc/cli/interactive.rb +4 -0
- data/vmc-ng/lib/vmc/cli/route/base.rb +12 -0
- data/vmc-ng/lib/vmc/cli/route/create_route.rb +42 -0
- data/vmc-ng/lib/vmc/cli/route/delete_route.rb +42 -0
- data/vmc-ng/lib/vmc/cli/route/routes.rb +26 -0
- data/vmc-ng/lib/vmc/detect.rb +2 -2
- data/vmc-ng/lib/vmc/spec_helper.rb +1 -0
- data/vmc-ng/lib/vmc/version.rb +1 -1
- data/vmc-ng/spec/cli/app/push_spec.rb +34 -0
- data/vmc-ng/spec/cli/app/rename_spec.rb +108 -0
- data/vmc-ng/spec/cli/route/delete_route_spec.rb +160 -0
- data/vmc-ng/spec/detect_spec.rb +54 -0
- data/vmc-ng/spec/factories/app_factory.rb +9 -0
- data/vmc-ng/spec/factories/client_factory.rb +16 -0
- data/vmc-ng/spec/factories/domain_factory.rb +9 -0
- data/vmc-ng/spec/factories/factory.rb +3 -0
- data/vmc-ng/spec/factories/framework_factory.rb +9 -0
- data/vmc-ng/spec/factories/route_factory.rb +10 -0
- data/vmc-ng/spec/spec_helper.rb +17 -0
- data/vmc-ng/spec/support/interact_helpers.rb +23 -0
- metadata +135 -62
- data/vmc-ng/lib/vmc/cli/app.rb +0 -1333
- data/vmc-ng/lib/vmc/cli/domain.rb +0 -164
- data/vmc-ng/lib/vmc/cli/route.rb +0 -106
- data/vmc-ng/lib/vmc/spec_helpers.rb +0 -431
- data/vmc-ng/lib/vmc/spec_helpers/eventlog.rb +0 -277
- data/vmc-ng/lib/vmc/spec_helpers/patches.rb +0 -94
- data/vmc-ng/spec/Rakefile +0 -13
- data/vmc-ng/spec/app/app_spec.rb +0 -19
- data/vmc-ng/spec/app/apps_spec.rb +0 -79
- data/vmc-ng/spec/app/push_spec.rb +0 -74
- data/vmc-ng/spec/assets/hello-sinatra/Gemfile +0 -2
- data/vmc-ng/spec/assets/hello-sinatra/main.rb +0 -5
- data/vmc-ng/spec/assets/hello-sinatra/manifest.yml +0 -9
- data/vmc-ng/spec/helpers.rb +0 -7
- data/vmc-ng/spec/start/target_spec.rb +0 -60
data/vmc-ng/lib/vmc/cli/app.rb
DELETED
@@ -1,1333 +0,0 @@
|
|
1
|
-
require "set"
|
2
|
-
|
3
|
-
require "vmc/cli"
|
4
|
-
require "vmc/detect"
|
5
|
-
|
6
|
-
module VMC
|
7
|
-
class App < CLI
|
8
|
-
desc "List your applications"
|
9
|
-
group :apps
|
10
|
-
input :space, :from_given => by_name("space"),
|
11
|
-
:default => proc { client.current_space },
|
12
|
-
:desc => "Show apps in given space"
|
13
|
-
input :name, :desc => "Filter by name regexp"
|
14
|
-
input :runtime, :desc => "Filter by runtime regexp"
|
15
|
-
input :framework, :desc => "Filter by framework regexp"
|
16
|
-
input :url, :desc => "Filter by url regexp"
|
17
|
-
input :full, :type => :boolean, :default => false,
|
18
|
-
:desc => "Verbose output format"
|
19
|
-
def apps
|
20
|
-
if space = input[:space]
|
21
|
-
space.summarize! rescue CFoundry::APIError
|
22
|
-
|
23
|
-
apps =
|
24
|
-
with_progress("Getting applications in #{c(space.name, :name)}") do
|
25
|
-
space.apps
|
26
|
-
end
|
27
|
-
else
|
28
|
-
apps =
|
29
|
-
with_progress("Getting applications") do
|
30
|
-
client.apps(:depth => 2)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
line unless quiet?
|
35
|
-
|
36
|
-
if apps.empty? and !quiet?
|
37
|
-
line "No applications."
|
38
|
-
return
|
39
|
-
end
|
40
|
-
|
41
|
-
apps.reject! do |a|
|
42
|
-
!app_matches(a, input)
|
43
|
-
end
|
44
|
-
|
45
|
-
apps = apps.sort_by(&:name)
|
46
|
-
|
47
|
-
if input[:full]
|
48
|
-
spaced(apps) do |a|
|
49
|
-
display_app(a)
|
50
|
-
end
|
51
|
-
elsif quiet?
|
52
|
-
apps.each do |a|
|
53
|
-
line a.name
|
54
|
-
end
|
55
|
-
else
|
56
|
-
table(
|
57
|
-
["name", "status", "usage", v2? && "plan", "runtime", "url"],
|
58
|
-
apps.collect { |a|
|
59
|
-
[ c(a.name, :name),
|
60
|
-
app_status(a),
|
61
|
-
"#{a.total_instances} x #{human_mb(a.memory)}",
|
62
|
-
v2? && (a.production ? "prod" : "dev"),
|
63
|
-
a.runtime.name,
|
64
|
-
if a.urls.empty?
|
65
|
-
d("none")
|
66
|
-
elsif a.urls.size == 1
|
67
|
-
a.url
|
68
|
-
else
|
69
|
-
"#{a.url}, ..."
|
70
|
-
end
|
71
|
-
]
|
72
|
-
})
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
|
77
|
-
desc "Show app information"
|
78
|
-
group :apps
|
79
|
-
input :app, :argument => :required, :from_given => by_name("app"),
|
80
|
-
:desc => "App to show"
|
81
|
-
def app
|
82
|
-
app = input[:app]
|
83
|
-
|
84
|
-
if quiet?
|
85
|
-
line app.name
|
86
|
-
else
|
87
|
-
display_app(app)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
desc "Push an application, syncing changes if it exists"
|
92
|
-
group :apps, :manage
|
93
|
-
input(:name, :argument => true, :desc => "Application name") {
|
94
|
-
ask("Name")
|
95
|
-
}
|
96
|
-
input :path, :default => ".",
|
97
|
-
:desc => "Path containing the application"
|
98
|
-
input(:url, :desc => "URL bound to app") { |name|
|
99
|
-
choices = url_choices(name)
|
100
|
-
|
101
|
-
options = {
|
102
|
-
:choices => choices + ["none"],
|
103
|
-
:allow_other => true
|
104
|
-
}
|
105
|
-
|
106
|
-
options[:default] = choices.first if choices.size == 1
|
107
|
-
|
108
|
-
url = ask "URL", options
|
109
|
-
|
110
|
-
unless url == "none"
|
111
|
-
url
|
112
|
-
end
|
113
|
-
}
|
114
|
-
input(:memory, :desc => "Memory limit") { |default|
|
115
|
-
ask("Memory Limit",
|
116
|
-
:choices => memory_choices,
|
117
|
-
:allow_other => true,
|
118
|
-
:default => default || "64M")
|
119
|
-
}
|
120
|
-
input(:instances, :type => :integer,
|
121
|
-
:desc => "Number of instances to run") {
|
122
|
-
ask("Instances", :default => 1)
|
123
|
-
}
|
124
|
-
input(:framework, :from_given => find_by_name("framework"),
|
125
|
-
:desc => "Framework to use") { |all, choices, default, other|
|
126
|
-
ask_with_other("Framework", all, choices, default, other)
|
127
|
-
}
|
128
|
-
input(:runtime, :from_given => find_by_name("runtime"),
|
129
|
-
:desc => "Runtime to use") { |all, choices, default, other|
|
130
|
-
ask_with_other("Runtime", all, choices, default, other)
|
131
|
-
}
|
132
|
-
input(:command, :desc => "Startup command for standalone app") {
|
133
|
-
ask("Startup command")
|
134
|
-
}
|
135
|
-
input :plan, :default => "D100",
|
136
|
-
:desc => "Application plan (e.g. D100, P200)"
|
137
|
-
input :start, :type => :boolean, :default => true,
|
138
|
-
:desc => "Start app after pushing?"
|
139
|
-
input :restart, :type => :boolean, :default => true,
|
140
|
-
:desc => "Restart app after updating?"
|
141
|
-
input(:create_services, :type => :boolean,
|
142
|
-
:desc => "Interactively create services?") {
|
143
|
-
line unless quiet?
|
144
|
-
ask "Create services for application?", :default => false
|
145
|
-
}
|
146
|
-
input(:bind_services, :type => :boolean,
|
147
|
-
:desc => "Interactively bind services?") {
|
148
|
-
ask "Bind other services to application?", :default => false
|
149
|
-
}
|
150
|
-
def push
|
151
|
-
name = input[:name]
|
152
|
-
path = File.expand_path(input[:path])
|
153
|
-
|
154
|
-
if app = client.app_by_name(name)
|
155
|
-
sync_app(app, path)
|
156
|
-
else
|
157
|
-
create_app(name, path)
|
158
|
-
end
|
159
|
-
end
|
160
|
-
|
161
|
-
|
162
|
-
desc "Start an application"
|
163
|
-
group :apps, :manage
|
164
|
-
input :apps, :argument => :splat, :singular => :app,
|
165
|
-
:desc => "Applications to start",
|
166
|
-
:from_given => by_name("app")
|
167
|
-
input :debug_mode, :aliases => "-d",
|
168
|
-
:desc => "Debug mode to start in"
|
169
|
-
input :all, :type => :boolean, :default => false,
|
170
|
-
:desc => "Start all applications"
|
171
|
-
def start
|
172
|
-
apps = input[:all] ? client.apps : input[:apps]
|
173
|
-
fail "No applications given." if apps.empty?
|
174
|
-
|
175
|
-
spaced(apps) do |app|
|
176
|
-
app = filter(:start_app, app)
|
177
|
-
|
178
|
-
switch_mode(app, input[:debug_mode])
|
179
|
-
|
180
|
-
with_progress("Starting #{c(app.name, :name)}") do |s|
|
181
|
-
if app.started?
|
182
|
-
s.skip do
|
183
|
-
err "Already started."
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
app.start!
|
188
|
-
end
|
189
|
-
|
190
|
-
check_application(app)
|
191
|
-
|
192
|
-
if app.debug_mode && !quiet?
|
193
|
-
line
|
194
|
-
invoke :instances, :app => app
|
195
|
-
end
|
196
|
-
end
|
197
|
-
end
|
198
|
-
|
199
|
-
|
200
|
-
desc "Stop an application"
|
201
|
-
group :apps, :manage
|
202
|
-
input :apps, :argument => :splat, :singular => :app,
|
203
|
-
:desc => "Applications to start",
|
204
|
-
:from_given => by_name("app")
|
205
|
-
input :all, :type => :boolean, :default => false,
|
206
|
-
:desc => "Stop all applications"
|
207
|
-
def stop
|
208
|
-
apps = input[:all] ? client.apps : input[:apps]
|
209
|
-
fail "No applications given." if apps.empty?
|
210
|
-
|
211
|
-
apps.each do |app|
|
212
|
-
with_progress("Stopping #{c(app.name, :name)}") do |s|
|
213
|
-
if app.stopped?
|
214
|
-
s.skip do
|
215
|
-
err "Application is not running."
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
app.stop!
|
220
|
-
end
|
221
|
-
end
|
222
|
-
end
|
223
|
-
|
224
|
-
|
225
|
-
desc "Stop and start an application"
|
226
|
-
group :apps, :manage
|
227
|
-
input :apps, :argument => :splat, :singular => :app,
|
228
|
-
:desc => "Applications to start",
|
229
|
-
:from_given => by_name("app")
|
230
|
-
input :debug_mode, :aliases => "-d",
|
231
|
-
:desc => "Debug mode to start in"
|
232
|
-
input :all, :type => :boolean, :default => false,
|
233
|
-
:desc => "Restart all applications"
|
234
|
-
def restart
|
235
|
-
invoke :stop, :all => input[:all], :apps => input[:apps]
|
236
|
-
|
237
|
-
line unless quiet?
|
238
|
-
|
239
|
-
invoke :start, :all => input[:all], :apps => input[:apps],
|
240
|
-
:debug_mode => input[:debug_mode]
|
241
|
-
end
|
242
|
-
|
243
|
-
|
244
|
-
desc "Delete an application"
|
245
|
-
group :apps, :manage
|
246
|
-
input(:apps, :argument => :splat, :singular => :app,
|
247
|
-
:desc => "Applications to delete",
|
248
|
-
:from_given => by_name("app")) {
|
249
|
-
apps = client.apps
|
250
|
-
fail "No applications." if apps.empty?
|
251
|
-
|
252
|
-
[ask("Delete which application?", :choices => apps.sort_by(&:name),
|
253
|
-
:display => proc(&:name))]
|
254
|
-
}
|
255
|
-
input(:really, :type => :boolean, :forget => true,
|
256
|
-
:default => proc { force? || interact }) { |name, color|
|
257
|
-
ask("Really delete #{c(name, color)}?", :default => false)
|
258
|
-
}
|
259
|
-
input :routes, :type => :boolean, :default => false,
|
260
|
-
:desc => "Delete associated routes"
|
261
|
-
input :orphaned, :aliases => "-o", :type => :boolean,
|
262
|
-
:desc => "Delete orphaned instances"
|
263
|
-
input :all, :type => :boolean, :default => false,
|
264
|
-
:desc => "Delete all applications"
|
265
|
-
def delete
|
266
|
-
apps = client.apps
|
267
|
-
|
268
|
-
if input[:all]
|
269
|
-
return unless input[:really, "ALL APPS", :bad]
|
270
|
-
|
271
|
-
to_delete = apps
|
272
|
-
others = []
|
273
|
-
else
|
274
|
-
to_delete = input[:apps]
|
275
|
-
others = apps - to_delete
|
276
|
-
end
|
277
|
-
|
278
|
-
orphaned = find_orphaned_services(to_delete, others)
|
279
|
-
|
280
|
-
deleted = []
|
281
|
-
spaced(to_delete) do |app|
|
282
|
-
really = input[:all] || input[:really, app.name, :name]
|
283
|
-
next unless really
|
284
|
-
|
285
|
-
deleted << app
|
286
|
-
|
287
|
-
with_progress("Deleting #{c(app.name, :name)}") do
|
288
|
-
app.routes.collect(&:delete!) if input[:routes]
|
289
|
-
app.delete!
|
290
|
-
end
|
291
|
-
end
|
292
|
-
|
293
|
-
delete_orphaned_services(orphaned, input[:orphaned])
|
294
|
-
|
295
|
-
to_delete
|
296
|
-
end
|
297
|
-
|
298
|
-
|
299
|
-
desc "List an app's instances"
|
300
|
-
group :apps, :info, :hidden => true
|
301
|
-
input :apps, :argument => :splat, :singular => :app,
|
302
|
-
:desc => "Applications whose instances to list",
|
303
|
-
:from_given => by_name("app")
|
304
|
-
def instances
|
305
|
-
apps = input[:apps]
|
306
|
-
fail "No applications given." if apps.empty?
|
307
|
-
|
308
|
-
spaced(apps) do |app|
|
309
|
-
instances =
|
310
|
-
with_progress("Getting instances for #{c(app.name, :name)}") do
|
311
|
-
app.instances
|
312
|
-
end
|
313
|
-
|
314
|
-
spaced(instances) do |i|
|
315
|
-
if quiet?
|
316
|
-
line i.id
|
317
|
-
else
|
318
|
-
display_instance(i)
|
319
|
-
end
|
320
|
-
end
|
321
|
-
end
|
322
|
-
end
|
323
|
-
|
324
|
-
|
325
|
-
desc "List an app's crashed instances"
|
326
|
-
group :apps, :info, :hidden => true
|
327
|
-
input :apps, :argument => :splat, :singular => :app,
|
328
|
-
:desc => "Applications whose crashed instances to list",
|
329
|
-
:from_given => by_name("app")
|
330
|
-
def crashes
|
331
|
-
apps = input[:apps]
|
332
|
-
fail "No applications given." if apps.empty?
|
333
|
-
|
334
|
-
spaced(apps) do |app|
|
335
|
-
instances =
|
336
|
-
with_progress("Getting crashed instances for #{c(app.name, :name)}") do
|
337
|
-
app.crashes
|
338
|
-
end
|
339
|
-
|
340
|
-
spaced(instances) do |i|
|
341
|
-
if quiet?
|
342
|
-
line i.id
|
343
|
-
else
|
344
|
-
display_crashed_instance(i)
|
345
|
-
end
|
346
|
-
end
|
347
|
-
end
|
348
|
-
end
|
349
|
-
|
350
|
-
|
351
|
-
desc "Update the instances/memory limit for an application"
|
352
|
-
group :apps, :info, :hidden => true
|
353
|
-
input :app, :argument => true, :desc => "Application to update",
|
354
|
-
:from_given => by_name("app")
|
355
|
-
input(:instances, :type => :numeric,
|
356
|
-
:desc => "Number of instances to run") { |default|
|
357
|
-
ask("Instances", :default => default)
|
358
|
-
}
|
359
|
-
input(:memory, :desc => "Memory limit") { |default|
|
360
|
-
ask("Memory Limit", :choices => memory_choices(default),
|
361
|
-
:allow_other => true,
|
362
|
-
:default => human_mb(default))
|
363
|
-
}
|
364
|
-
input :plan, :default => "D100",
|
365
|
-
:desc => "Application plan (e.g. D100, P200)"
|
366
|
-
input :restart, :type => :boolean, :default => true,
|
367
|
-
:desc => "Restart app after updating?"
|
368
|
-
def scale
|
369
|
-
app = input[:app]
|
370
|
-
|
371
|
-
if input.given?(:instances)
|
372
|
-
instances = input[:instances, app.total_instances]
|
373
|
-
end
|
374
|
-
|
375
|
-
if input.given?(:memory)
|
376
|
-
memory = input[:memory, app.memory]
|
377
|
-
end
|
378
|
-
|
379
|
-
if input.given?(:plan)
|
380
|
-
fail "Plans not supported on target cloud." unless v2?
|
381
|
-
|
382
|
-
plan_name = input[:plan]
|
383
|
-
production = !!(plan_name =~ /^p/i)
|
384
|
-
end
|
385
|
-
|
386
|
-
unless instances || memory || plan_name
|
387
|
-
instances = input[:instances, app.total_instances]
|
388
|
-
memory = input[:memory, app.memory]
|
389
|
-
end
|
390
|
-
|
391
|
-
memory = megabytes(memory) if memory
|
392
|
-
|
393
|
-
instances_changed = instances && instances != app.total_instances
|
394
|
-
memory_changed = memory && memory != app.memory
|
395
|
-
plan_changed = plan_name && production != app.production
|
396
|
-
|
397
|
-
unless memory_changed || instances_changed || plan_changed
|
398
|
-
fail "No changes!"
|
399
|
-
end
|
400
|
-
|
401
|
-
with_progress("Scaling #{c(app.name, :name)}") do
|
402
|
-
app.total_instances = instances if instances_changed
|
403
|
-
app.memory = memory if memory_changed
|
404
|
-
app.production = production if plan_changed
|
405
|
-
app.update!
|
406
|
-
end
|
407
|
-
|
408
|
-
if memory_changed && app.started? && input[:restart]
|
409
|
-
invoke :restart, :app => app
|
410
|
-
end
|
411
|
-
end
|
412
|
-
|
413
|
-
|
414
|
-
desc "Print out an app's logs"
|
415
|
-
group :apps, :info, :hidden => true
|
416
|
-
input :app, :argument => true,
|
417
|
-
:desc => "Application to get the logs of",
|
418
|
-
:from_given => by_name("app")
|
419
|
-
input :instance, :default => "0",
|
420
|
-
:desc => "Instance of application to get the logs of"
|
421
|
-
input :all, :type => :boolean, :default => false,
|
422
|
-
:desc => "Get logs for every instance"
|
423
|
-
def logs
|
424
|
-
app = input[:app]
|
425
|
-
|
426
|
-
instances =
|
427
|
-
if input[:all] || input[:instance] == "all"
|
428
|
-
app.instances
|
429
|
-
else
|
430
|
-
app.instances.select { |i| i.id == input[:instance] }
|
431
|
-
end
|
432
|
-
|
433
|
-
if instances.empty?
|
434
|
-
if input[:all]
|
435
|
-
fail "No instances found."
|
436
|
-
else
|
437
|
-
fail "Instance #{app.name} \##{input[:instance]} not found."
|
438
|
-
end
|
439
|
-
end
|
440
|
-
|
441
|
-
spaced(instances) do |i|
|
442
|
-
show_instance_logs(app, i)
|
443
|
-
end
|
444
|
-
end
|
445
|
-
|
446
|
-
|
447
|
-
desc "Print out the logs for an app's crashed instances"
|
448
|
-
group :apps, :info, :hidden => true
|
449
|
-
input :app, :argument => true,
|
450
|
-
:desc => "Application to get the logs of",
|
451
|
-
:from_given => by_name("app")
|
452
|
-
def crashlogs
|
453
|
-
app = input[:app]
|
454
|
-
|
455
|
-
crashes = app.crashes
|
456
|
-
|
457
|
-
fail "No crashed instances found." if crashes.empty?
|
458
|
-
|
459
|
-
spaced(crashes) do |i|
|
460
|
-
show_instance_logs(app, i)
|
461
|
-
end
|
462
|
-
end
|
463
|
-
|
464
|
-
|
465
|
-
desc "Print out an app's file contents"
|
466
|
-
group :apps, :info, :hidden => true
|
467
|
-
input :app, :argument => true,
|
468
|
-
:desc => "Application to inspect the files of",
|
469
|
-
:from_given => by_name("app")
|
470
|
-
input :path, :argument => true, :default => "/",
|
471
|
-
:desc => "Path of file to read"
|
472
|
-
def file
|
473
|
-
app = input[:app]
|
474
|
-
path = input[:path]
|
475
|
-
|
476
|
-
file =
|
477
|
-
with_progress("Getting file contents") do
|
478
|
-
app.file(*path.split("/"))
|
479
|
-
end
|
480
|
-
|
481
|
-
if quiet?
|
482
|
-
print file
|
483
|
-
else
|
484
|
-
line
|
485
|
-
|
486
|
-
file.split("\n").each do |l|
|
487
|
-
line l
|
488
|
-
end
|
489
|
-
end
|
490
|
-
rescue CFoundry::NotFound
|
491
|
-
fail "Invalid path #{b(path)} for app #{b(app.name)}"
|
492
|
-
rescue CFoundry::FileError => e
|
493
|
-
fail e.description
|
494
|
-
end
|
495
|
-
|
496
|
-
desc "Examine an app's files"
|
497
|
-
group :apps, :info, :hidden => true
|
498
|
-
input :app, :argument => true,
|
499
|
-
:desc => "Application to inspect the files of",
|
500
|
-
:from_given => by_name("app")
|
501
|
-
input :path, :argument => :optional, :default => "/",
|
502
|
-
:desc => "Path of directory to list"
|
503
|
-
def files
|
504
|
-
app = input[:app]
|
505
|
-
path = input[:path]
|
506
|
-
|
507
|
-
if quiet?
|
508
|
-
files =
|
509
|
-
with_progress("Getting file listing") do
|
510
|
-
app.files(*path.split("/"))
|
511
|
-
end
|
512
|
-
|
513
|
-
files.each do |file|
|
514
|
-
line file.join("/")
|
515
|
-
end
|
516
|
-
else
|
517
|
-
invoke :file, :app => app, :path => path
|
518
|
-
end
|
519
|
-
rescue CFoundry::NotFound
|
520
|
-
fail "Invalid path #{b(path)} for app #{b(app.name)}"
|
521
|
-
rescue CFoundry::FileError => e
|
522
|
-
fail e.description
|
523
|
-
end
|
524
|
-
|
525
|
-
desc "Stream an app's file contents"
|
526
|
-
group :apps, :info, :hidden => true
|
527
|
-
input :app, :argument => true,
|
528
|
-
:desc => "Application to inspect the file of",
|
529
|
-
:from_given => by_name("app")
|
530
|
-
input :path, :argument => true, :default => "/",
|
531
|
-
:desc => "Path of file to stream"
|
532
|
-
def tail
|
533
|
-
app = input[:app]
|
534
|
-
path = input[:path]
|
535
|
-
|
536
|
-
app.stream_file(*path.split("/")) do |contents|
|
537
|
-
print contents
|
538
|
-
end
|
539
|
-
rescue CFoundry::NotFound
|
540
|
-
fail "Invalid path #{b(path)} for app #{b(app.name)}"
|
541
|
-
rescue CFoundry::FileError => e
|
542
|
-
fail e.description
|
543
|
-
end
|
544
|
-
|
545
|
-
|
546
|
-
desc "Get application health"
|
547
|
-
group :apps, :info, :hidden => true
|
548
|
-
input :apps, :argument => :splat, :singular => :app,
|
549
|
-
:desc => "Applications to start",
|
550
|
-
:from_given => by_name("app")
|
551
|
-
def health
|
552
|
-
apps = input[:apps]
|
553
|
-
fail "No applications given." if apps.empty?
|
554
|
-
|
555
|
-
health =
|
556
|
-
with_progress("Getting health status") do
|
557
|
-
apps.collect { |a| [a, app_status(a)] }
|
558
|
-
end
|
559
|
-
|
560
|
-
line unless quiet?
|
561
|
-
|
562
|
-
spaced(health) do |app, status|
|
563
|
-
start_line "#{c(app.name, :name)}: " unless quiet?
|
564
|
-
puts status
|
565
|
-
end
|
566
|
-
end
|
567
|
-
|
568
|
-
|
569
|
-
desc "Display application instance status"
|
570
|
-
group :apps, :info, :hidden => true
|
571
|
-
input :app, :argument => true,
|
572
|
-
:desc => "Application to get the stats for",
|
573
|
-
:from_given => by_name("app")
|
574
|
-
def stats
|
575
|
-
app = input[:app]
|
576
|
-
|
577
|
-
stats =
|
578
|
-
with_progress("Getting stats for #{c(app.name, :name)}") do |s|
|
579
|
-
begin
|
580
|
-
app.stats
|
581
|
-
rescue CFoundry::StatsError
|
582
|
-
s.fail do
|
583
|
-
err "Application #{b(app.name)} is not running."
|
584
|
-
return
|
585
|
-
end
|
586
|
-
end
|
587
|
-
end
|
588
|
-
|
589
|
-
line unless quiet?
|
590
|
-
|
591
|
-
table(
|
592
|
-
%w{instance cpu memory disk},
|
593
|
-
stats.sort_by { |idx, _| idx.to_i }.collect { |idx, info|
|
594
|
-
idx = c("\##{idx}", :instance)
|
595
|
-
|
596
|
-
if info[:state] == "DOWN"
|
597
|
-
[idx, c("down", :bad)]
|
598
|
-
else
|
599
|
-
stats = info[:stats]
|
600
|
-
usage = stats[:usage]
|
601
|
-
|
602
|
-
if usage
|
603
|
-
[ idx,
|
604
|
-
"#{percentage(usage[:cpu])} of #{b(stats[:cores])} cores",
|
605
|
-
"#{usage(usage[:mem] * 1024, stats[:mem_quota])}",
|
606
|
-
"#{usage(usage[:disk], stats[:disk_quota])}"
|
607
|
-
]
|
608
|
-
else
|
609
|
-
[idx, c("n/a", :neutral)]
|
610
|
-
end
|
611
|
-
end
|
612
|
-
})
|
613
|
-
end
|
614
|
-
|
615
|
-
|
616
|
-
desc "Add a URL mapping for an app"
|
617
|
-
group :apps, :info, :hidden => true
|
618
|
-
input :app, :argument => true,
|
619
|
-
:desc => "Application to add the URL to",
|
620
|
-
:from_given => by_name("app")
|
621
|
-
input :url, :argument => true,
|
622
|
-
:desc => "URL to map to the application"
|
623
|
-
def map
|
624
|
-
app = input[:app]
|
625
|
-
|
626
|
-
simple = input[:url].sub(/^https?:\/\/(.*)\/?/i, '\1')
|
627
|
-
|
628
|
-
if v2?
|
629
|
-
host, domain_name = simple.split(".", 2)
|
630
|
-
|
631
|
-
domain =
|
632
|
-
client.current_space.domain_by_name(domain_name, :depth => 0)
|
633
|
-
|
634
|
-
fail "Invalid domain '#{domain_name}'" unless domain
|
635
|
-
|
636
|
-
route = client.routes_by_host(host, :depth => 0).find do |r|
|
637
|
-
r.domain == domain
|
638
|
-
end
|
639
|
-
|
640
|
-
unless route
|
641
|
-
route = client.route
|
642
|
-
|
643
|
-
with_progress("Creating route #{c(simple, :name)}") do
|
644
|
-
route.host = host
|
645
|
-
route.domain = domain
|
646
|
-
route.space = app.space
|
647
|
-
route.create!
|
648
|
-
end
|
649
|
-
end
|
650
|
-
|
651
|
-
with_progress("Binding #{c(simple, :name)} to #{c(app.name, :name)}") do
|
652
|
-
app.add_route(route)
|
653
|
-
end
|
654
|
-
else
|
655
|
-
with_progress("Updating #{c(app.name, :name)}") do
|
656
|
-
app.urls << simple
|
657
|
-
app.update!
|
658
|
-
end
|
659
|
-
end
|
660
|
-
end
|
661
|
-
|
662
|
-
|
663
|
-
desc "Remove a URL mapping from an app"
|
664
|
-
group :apps, :info, :hidden => true
|
665
|
-
input :app, :argument => true,
|
666
|
-
:desc => "Application to remove the URL from",
|
667
|
-
:from_given => by_name("app")
|
668
|
-
input(:url, :argument => true, :desc => "URL to unmap") { |choices|
|
669
|
-
ask("Which URL?", :choices => choices)
|
670
|
-
}
|
671
|
-
def unmap
|
672
|
-
app = input[:app]
|
673
|
-
url = input[:url, app.urls]
|
674
|
-
|
675
|
-
simple = url.sub(/^https?:\/\/(.*)\/?/i, '\1')
|
676
|
-
|
677
|
-
if v2?
|
678
|
-
host, domain_name = simple.split(".", 2)
|
679
|
-
|
680
|
-
domain =
|
681
|
-
client.current_space.domain_by_name(domain_name, :depth => 0)
|
682
|
-
|
683
|
-
fail "Invalid domain '#{domain_name}'" unless domain
|
684
|
-
|
685
|
-
route = app.routes_by_host(host, :depth => 0).find do |r|
|
686
|
-
r.domain == domain
|
687
|
-
end
|
688
|
-
|
689
|
-
fail "Invalid route '#{simple}'" unless route
|
690
|
-
|
691
|
-
with_progress("Removing route #{c(simple, :name)}") do
|
692
|
-
app.remove_route(route)
|
693
|
-
end
|
694
|
-
else
|
695
|
-
with_progress("Updating #{c(app.name, :name)}") do |s|
|
696
|
-
unless app.urls.delete(simple)
|
697
|
-
s.fail do
|
698
|
-
err "URL #{url} is not mapped to this application."
|
699
|
-
return
|
700
|
-
end
|
701
|
-
end
|
702
|
-
|
703
|
-
app.update!
|
704
|
-
end
|
705
|
-
end
|
706
|
-
end
|
707
|
-
|
708
|
-
|
709
|
-
desc "Show all environment variables set for an app"
|
710
|
-
group :apps, :info, :hidden => true
|
711
|
-
input :app, :argument => true,
|
712
|
-
:desc => "Application to inspect the environment of",
|
713
|
-
:from_given => by_name("app")
|
714
|
-
def env
|
715
|
-
app = input[:app]
|
716
|
-
|
717
|
-
vars =
|
718
|
-
with_progress("Getting env for #{c(app.name, :name)}") do |s|
|
719
|
-
app.env
|
720
|
-
end
|
721
|
-
|
722
|
-
line unless quiet?
|
723
|
-
|
724
|
-
vars.each do |name, val|
|
725
|
-
line "#{c(name, :name)}: #{val}"
|
726
|
-
end
|
727
|
-
end
|
728
|
-
|
729
|
-
|
730
|
-
VALID_ENV_VAR = /^[a-zA-Za-z_][[:alnum:]_]*$/
|
731
|
-
|
732
|
-
desc "Set an environment variable"
|
733
|
-
group :apps, :info, :hidden => true
|
734
|
-
input :app, :argument => true,
|
735
|
-
:desc => "Application to set the variable for",
|
736
|
-
:from_given => by_name("app")
|
737
|
-
input :name, :argument => true,
|
738
|
-
:desc => "Environment variable name"
|
739
|
-
input :value, :argument => :optional,
|
740
|
-
:desc => "Environment variable value"
|
741
|
-
input :restart, :type => :boolean, :default => true,
|
742
|
-
:desc => "Restart app after updating?"
|
743
|
-
def set_env
|
744
|
-
app = input[:app]
|
745
|
-
name = input[:name]
|
746
|
-
|
747
|
-
if value = input[:value]
|
748
|
-
name = input[:name]
|
749
|
-
elsif name["="]
|
750
|
-
name, value = name.split("=")
|
751
|
-
end
|
752
|
-
|
753
|
-
unless name =~ VALID_ENV_VAR
|
754
|
-
fail "Invalid variable name; must match #{VALID_ENV_VAR.inspect}"
|
755
|
-
end
|
756
|
-
|
757
|
-
with_progress("Updating #{c(app.name, :name)}") do
|
758
|
-
app.env[name] = value
|
759
|
-
app.update!
|
760
|
-
end
|
761
|
-
|
762
|
-
if app.started? && input[:restart]
|
763
|
-
invoke :restart, :app => app
|
764
|
-
end
|
765
|
-
end
|
766
|
-
|
767
|
-
|
768
|
-
desc "Remove an environment variable"
|
769
|
-
group :apps, :info, :hidden => true
|
770
|
-
input :app, :argument => true,
|
771
|
-
:desc => "Application to set the variable for",
|
772
|
-
:from_given => by_name("app")
|
773
|
-
input :name, :argument => true,
|
774
|
-
:desc => "Environment variable name"
|
775
|
-
input :restart, :type => :boolean, :default => true,
|
776
|
-
:desc => "Restart app after updating?"
|
777
|
-
def unset_env
|
778
|
-
app = input[:app]
|
779
|
-
name = input[:name]
|
780
|
-
|
781
|
-
with_progress("Updating #{c(app.name, :name)}") do
|
782
|
-
app.env.delete(name)
|
783
|
-
app.update!
|
784
|
-
end
|
785
|
-
|
786
|
-
if app.started? && input[:restart]
|
787
|
-
invoke :restart, :app => app
|
788
|
-
end
|
789
|
-
end
|
790
|
-
|
791
|
-
|
792
|
-
desc "DEPRECATED. Use 'push' instead."
|
793
|
-
input :app, :argument => :optional
|
794
|
-
def update
|
795
|
-
fail "The 'update' command is no longer needed; use 'push' instead."
|
796
|
-
end
|
797
|
-
|
798
|
-
private
|
799
|
-
|
800
|
-
def app_matches(a, options)
|
801
|
-
if name = options[:name]
|
802
|
-
return false if a.name !~ /#{name}/
|
803
|
-
end
|
804
|
-
|
805
|
-
if runtime = options[:runtime]
|
806
|
-
return false if a.runtime.name !~ /#{runtime}/
|
807
|
-
end
|
808
|
-
|
809
|
-
if framework = options[:framework]
|
810
|
-
return false if a.framework.name !~ /#{framework}/
|
811
|
-
end
|
812
|
-
|
813
|
-
if url = options[:url]
|
814
|
-
return false if a.urls.none? { |u| u =~ /#{url}/ }
|
815
|
-
end
|
816
|
-
|
817
|
-
true
|
818
|
-
end
|
819
|
-
|
820
|
-
IS_UTF8 = !!(ENV["LC_ALL"] || ENV["LC_CTYPE"] || ENV["LANG"] || "")["UTF-8"]
|
821
|
-
|
822
|
-
def display_app(a)
|
823
|
-
status = app_status(a)
|
824
|
-
|
825
|
-
line "#{c(a.name, :name)}: #{status}"
|
826
|
-
|
827
|
-
indented do
|
828
|
-
line "platform: #{b(a.framework.name)} on #{b(a.runtime.name)}"
|
829
|
-
|
830
|
-
start_line "usage: #{b(human_mb(a.memory))}"
|
831
|
-
print " #{d(IS_UTF8 ? "\xc3\x97" : "x")} #{b(a.total_instances)}"
|
832
|
-
print " instance#{a.total_instances == 1 ? "" : "s"}"
|
833
|
-
|
834
|
-
line
|
835
|
-
|
836
|
-
unless a.urls.empty?
|
837
|
-
line "urls: #{a.urls.collect { |u| b(u) }.join(", ")}"
|
838
|
-
end
|
839
|
-
|
840
|
-
unless a.services.empty?
|
841
|
-
line "services: #{a.services.collect { |s| b(s.name) }.join(", ")}"
|
842
|
-
end
|
843
|
-
end
|
844
|
-
end
|
845
|
-
|
846
|
-
def sync_app(app, path)
|
847
|
-
upload_app(app, path)
|
848
|
-
|
849
|
-
diff = {}
|
850
|
-
|
851
|
-
if input.given?(:memory)
|
852
|
-
mem = megabytes(input[:memory])
|
853
|
-
|
854
|
-
if mem != app.memory
|
855
|
-
diff[:memory] = [app.memory, mem]
|
856
|
-
app.memory = mem
|
857
|
-
end
|
858
|
-
end
|
859
|
-
|
860
|
-
if input.given?(:instances)
|
861
|
-
instances = input[:instances]
|
862
|
-
|
863
|
-
if instances != app.total_instances
|
864
|
-
diff[:instances] = [app.total_instances, instances]
|
865
|
-
app.total_instances = instances
|
866
|
-
end
|
867
|
-
end
|
868
|
-
|
869
|
-
if input.given?(:framework)
|
870
|
-
all_frameworks = client.frameworks
|
871
|
-
|
872
|
-
framework = input[:framework, all_frameworks, all_frameworks]
|
873
|
-
|
874
|
-
if framework != app.framework
|
875
|
-
diff[:framework] = [app.framework.name, framework.name]
|
876
|
-
app.framework = framework
|
877
|
-
end
|
878
|
-
end
|
879
|
-
|
880
|
-
if input.given?(:runtime)
|
881
|
-
all_runtimes = client.runtimes
|
882
|
-
|
883
|
-
runtime = input[:runtime, all_runtimes, all_runtimes]
|
884
|
-
|
885
|
-
if runtime != app.runtime
|
886
|
-
diff[:runtime] = [app.runtime.name, runtime.name]
|
887
|
-
app.runtime = runtime
|
888
|
-
end
|
889
|
-
end
|
890
|
-
|
891
|
-
if input.given?(:command) && input[:command] != app.command
|
892
|
-
command = input[:command]
|
893
|
-
|
894
|
-
if command != app.command
|
895
|
-
diff[:command] = [app.command, command]
|
896
|
-
app.command = command
|
897
|
-
end
|
898
|
-
end
|
899
|
-
|
900
|
-
if input.given?(:plan) && v2?
|
901
|
-
production = !!(input[:plan] =~ /^p/i)
|
902
|
-
|
903
|
-
if production != app.production
|
904
|
-
diff[:production] = [bool(app.production), bool(production)]
|
905
|
-
app.production = production
|
906
|
-
end
|
907
|
-
end
|
908
|
-
|
909
|
-
unless diff.empty?
|
910
|
-
line "Changes:"
|
911
|
-
|
912
|
-
indented do
|
913
|
-
diff.each do |name, change|
|
914
|
-
old, new = change
|
915
|
-
line "#{c(name, :name)}: #{old} #{c("->", :dim)} #{new}"
|
916
|
-
end
|
917
|
-
end
|
918
|
-
|
919
|
-
with_progress("Updating #{c(app.name, :name)}") do
|
920
|
-
app.update!
|
921
|
-
end
|
922
|
-
end
|
923
|
-
|
924
|
-
if input[:restart] && app.started?
|
925
|
-
invoke :restart, :app => app
|
926
|
-
end
|
927
|
-
end
|
928
|
-
|
929
|
-
def create_app(name, path)
|
930
|
-
app = client.app
|
931
|
-
app.name = name
|
932
|
-
app.space = client.current_space if client.current_space
|
933
|
-
app.total_instances = input[:instances]
|
934
|
-
app.production = !!(input[:plan] =~ /^p/i) if v2?
|
935
|
-
|
936
|
-
detector = Detector.new(client, path)
|
937
|
-
all_frameworks = detector.all_frameworks
|
938
|
-
all_runtimes = detector.all_runtimes
|
939
|
-
|
940
|
-
if detected_framework = detector.detect_framework
|
941
|
-
framework = input[
|
942
|
-
:framework,
|
943
|
-
all_frameworks,
|
944
|
-
[detected_framework],
|
945
|
-
detected_framework,
|
946
|
-
:other
|
947
|
-
]
|
948
|
-
else
|
949
|
-
framework = input[:framework, all_frameworks, all_frameworks]
|
950
|
-
end
|
951
|
-
|
952
|
-
|
953
|
-
if framework.name == "standalone"
|
954
|
-
detected_runtimes = detector.detect_runtimes
|
955
|
-
else
|
956
|
-
detected_runtimes = detector.runtimes(framework)
|
957
|
-
end
|
958
|
-
|
959
|
-
if detected_runtimes.size == 1
|
960
|
-
default_runtime = detected_runtimes.first
|
961
|
-
end
|
962
|
-
|
963
|
-
if detected_runtimes.empty?
|
964
|
-
runtime = input[:runtime, all_runtimes, all_runtimes]
|
965
|
-
else
|
966
|
-
runtime = input[
|
967
|
-
:runtime,
|
968
|
-
all_runtimes,
|
969
|
-
detected_runtimes,
|
970
|
-
default_runtime,
|
971
|
-
:other
|
972
|
-
]
|
973
|
-
end
|
974
|
-
|
975
|
-
|
976
|
-
fail "Invalid framework '#{input[:framework]}'" unless framework
|
977
|
-
fail "Invalid runtime '#{input[:runtime]}'" unless runtime
|
978
|
-
|
979
|
-
app.framework = framework
|
980
|
-
app.runtime = runtime
|
981
|
-
|
982
|
-
app.command = input[:command] if framework.name == "standalone"
|
983
|
-
|
984
|
-
default_memory = detector.suggested_memory(framework) || 64
|
985
|
-
app.memory = megabytes(input[:memory, human_mb(default_memory)])
|
986
|
-
|
987
|
-
app = filter(:create_app, app)
|
988
|
-
|
989
|
-
with_progress("Creating #{c(app.name, :name)}") do
|
990
|
-
app.create!
|
991
|
-
end
|
992
|
-
|
993
|
-
line unless quiet?
|
994
|
-
|
995
|
-
url = input[:url, name]
|
996
|
-
|
997
|
-
mapped_url = false
|
998
|
-
until !url || mapped_url
|
999
|
-
begin
|
1000
|
-
invoke :map, :app => app, :url => url
|
1001
|
-
mapped_url = true
|
1002
|
-
rescue CFoundry::RouteHostTaken, CFoundry::UriAlreadyTaken => e
|
1003
|
-
line c(e.description, :bad)
|
1004
|
-
line
|
1005
|
-
|
1006
|
-
input.forget(:url)
|
1007
|
-
url = input[:url, name]
|
1008
|
-
|
1009
|
-
# version bumps on v1 even though mapping fails
|
1010
|
-
app.invalidate! unless v2?
|
1011
|
-
end
|
1012
|
-
end
|
1013
|
-
|
1014
|
-
bindings = []
|
1015
|
-
|
1016
|
-
if input[:create_services] && !force?
|
1017
|
-
while true
|
1018
|
-
invoke :create_service, { :app => app }, :plan => :interact
|
1019
|
-
break unless ask "Create another service?", :default => false
|
1020
|
-
end
|
1021
|
-
end
|
1022
|
-
|
1023
|
-
if input[:bind_services] && !force?
|
1024
|
-
instances = client.service_instances
|
1025
|
-
|
1026
|
-
while true
|
1027
|
-
invoke :bind_service, :app => app
|
1028
|
-
|
1029
|
-
break if (instances - app.services).empty?
|
1030
|
-
|
1031
|
-
break unless ask("Bind another service?", :default => false)
|
1032
|
-
end
|
1033
|
-
end
|
1034
|
-
|
1035
|
-
app = filter(:push_app, app)
|
1036
|
-
|
1037
|
-
begin
|
1038
|
-
upload_app(app, path)
|
1039
|
-
rescue
|
1040
|
-
err "Upload failed. Try again with 'vmc push'."
|
1041
|
-
raise
|
1042
|
-
end
|
1043
|
-
|
1044
|
-
invoke :start, :app => app if input[:start]
|
1045
|
-
end
|
1046
|
-
|
1047
|
-
def upload_app(app, path)
|
1048
|
-
with_progress("Uploading #{c(app.name, :name)}") do
|
1049
|
-
app.upload(path)
|
1050
|
-
end
|
1051
|
-
end
|
1052
|
-
|
1053
|
-
# set app debug mode, ensuring it's valid, and shutting it down
|
1054
|
-
def switch_mode(app, mode)
|
1055
|
-
mode = nil if mode == "none"
|
1056
|
-
mode = "run" if mode == "debug_mode" # no value given
|
1057
|
-
|
1058
|
-
return false if app.debug_mode == mode
|
1059
|
-
|
1060
|
-
if mode.nil?
|
1061
|
-
with_progress("Removing debug mode") do
|
1062
|
-
app.debug_mode = nil
|
1063
|
-
app.stop! if app.started?
|
1064
|
-
end
|
1065
|
-
|
1066
|
-
return true
|
1067
|
-
end
|
1068
|
-
|
1069
|
-
with_progress("Switching mode to #{c(mode, :name)}") do |s|
|
1070
|
-
runtime = client.runtimes.find { |r| r.name == app.runtime.name }
|
1071
|
-
modes = runtime.debug_modes
|
1072
|
-
|
1073
|
-
if modes.include?(mode)
|
1074
|
-
app.debug_mode = mode
|
1075
|
-
app.stop! if app.started?
|
1076
|
-
else
|
1077
|
-
fail "Unknown mode '#{mode}'; available: #{modes.join ", "}"
|
1078
|
-
end
|
1079
|
-
end
|
1080
|
-
end
|
1081
|
-
|
1082
|
-
APP_CHECK_LIMIT = 60
|
1083
|
-
|
1084
|
-
def check_application(app)
|
1085
|
-
with_progress("Checking #{c(app.name, :name)}") do |s|
|
1086
|
-
if app.debug_mode == "suspend"
|
1087
|
-
s.skip do
|
1088
|
-
line "Application is in suspended debugging mode."
|
1089
|
-
line "It will wait for you to attach to it before starting."
|
1090
|
-
end
|
1091
|
-
end
|
1092
|
-
|
1093
|
-
seconds = 0
|
1094
|
-
until app.healthy?
|
1095
|
-
sleep 1
|
1096
|
-
seconds += 1
|
1097
|
-
if seconds == APP_CHECK_LIMIT
|
1098
|
-
s.give_up do
|
1099
|
-
err "Application failed to start."
|
1100
|
-
# TODO: print logs
|
1101
|
-
end
|
1102
|
-
end
|
1103
|
-
end
|
1104
|
-
end
|
1105
|
-
end
|
1106
|
-
|
1107
|
-
# choose the right color for app/instance state
|
1108
|
-
def state_color(s)
|
1109
|
-
case s
|
1110
|
-
when "STARTING"
|
1111
|
-
:neutral
|
1112
|
-
when "STARTED", "RUNNING"
|
1113
|
-
:good
|
1114
|
-
when "DOWN"
|
1115
|
-
:bad
|
1116
|
-
when "FLAPPING"
|
1117
|
-
:error
|
1118
|
-
when "N/A"
|
1119
|
-
:unknown
|
1120
|
-
else
|
1121
|
-
:warning
|
1122
|
-
end
|
1123
|
-
end
|
1124
|
-
|
1125
|
-
def app_status(a)
|
1126
|
-
health = a.health
|
1127
|
-
|
1128
|
-
if a.debug_mode == "suspend" && health == "0%"
|
1129
|
-
c("suspended", :neutral)
|
1130
|
-
else
|
1131
|
-
c(health.downcase, state_color(health))
|
1132
|
-
end
|
1133
|
-
end
|
1134
|
-
|
1135
|
-
def display_instance(i)
|
1136
|
-
start_line "instance #{c("\##{i.id}", :instance)}: "
|
1137
|
-
puts "#{b(c(i.state.downcase, state_color(i.state)))} "
|
1138
|
-
|
1139
|
-
indented do
|
1140
|
-
if s = i.since
|
1141
|
-
line "started: #{c(s.strftime("%F %r"), :neutral)}"
|
1142
|
-
end
|
1143
|
-
|
1144
|
-
if d = i.debugger
|
1145
|
-
line "debugger: port #{b(d[:port])} at #{b(d[:ip])}"
|
1146
|
-
end
|
1147
|
-
|
1148
|
-
if c = i.console
|
1149
|
-
line "console: port #{b(c[:port])} at #{b(c[:ip])}"
|
1150
|
-
end
|
1151
|
-
end
|
1152
|
-
end
|
1153
|
-
|
1154
|
-
def display_crashed_instance(i)
|
1155
|
-
start_line "instance #{c("\##{i.id}", :instance)}: "
|
1156
|
-
puts "#{b(c("crashed", :error))} "
|
1157
|
-
|
1158
|
-
indented do
|
1159
|
-
if s = i.since
|
1160
|
-
line "since: #{c(s.strftime("%F %r"), :neutral)}"
|
1161
|
-
end
|
1162
|
-
end
|
1163
|
-
end
|
1164
|
-
|
1165
|
-
def show_instance_logs(app, i)
|
1166
|
-
return unless i.id
|
1167
|
-
|
1168
|
-
logs =
|
1169
|
-
with_progress(
|
1170
|
-
"Getting logs for #{c(app.name, :name)} " +
|
1171
|
-
c("\##{i.id}", :instance)) do
|
1172
|
-
i.files("logs")
|
1173
|
-
end
|
1174
|
-
|
1175
|
-
line unless quiet?
|
1176
|
-
|
1177
|
-
spaced(logs) do |log|
|
1178
|
-
begin
|
1179
|
-
body =
|
1180
|
-
with_progress("Reading " + b(log.join("/"))) do |s|
|
1181
|
-
i.file(*log)
|
1182
|
-
end
|
1183
|
-
|
1184
|
-
lines body
|
1185
|
-
line unless body.empty?
|
1186
|
-
rescue CFoundry::NotFound
|
1187
|
-
end
|
1188
|
-
end
|
1189
|
-
end
|
1190
|
-
|
1191
|
-
def find_orphaned_services(apps, others = [])
|
1192
|
-
orphaned = Set.new
|
1193
|
-
|
1194
|
-
apps.each do |a|
|
1195
|
-
a.services.each do |i|
|
1196
|
-
if others.none? { |x| x.binds?(i) }
|
1197
|
-
orphaned << i
|
1198
|
-
end
|
1199
|
-
end
|
1200
|
-
end
|
1201
|
-
|
1202
|
-
orphaned.each(&:invalidate!)
|
1203
|
-
end
|
1204
|
-
|
1205
|
-
def delete_orphaned_services(instances, orphaned)
|
1206
|
-
return if instances.empty?
|
1207
|
-
|
1208
|
-
line unless quiet? || force?
|
1209
|
-
|
1210
|
-
instances.select { |i|
|
1211
|
-
orphaned ||
|
1212
|
-
ask("Delete orphaned service instance #{c(i.name, :name)}?",
|
1213
|
-
:default => false)
|
1214
|
-
}.each do |instance|
|
1215
|
-
# TODO: splat
|
1216
|
-
invoke :delete_service, :instance => instance, :really => true
|
1217
|
-
end
|
1218
|
-
end
|
1219
|
-
|
1220
|
-
def ask_with_other(message, all, choices, default, other)
|
1221
|
-
choices = choices.sort_by(&:name)
|
1222
|
-
choices << other if other
|
1223
|
-
|
1224
|
-
opts = {
|
1225
|
-
:choices => choices,
|
1226
|
-
:display => proc { |x|
|
1227
|
-
if other && x == other
|
1228
|
-
"other"
|
1229
|
-
else
|
1230
|
-
x.name
|
1231
|
-
end
|
1232
|
-
}
|
1233
|
-
}
|
1234
|
-
|
1235
|
-
opts[:default] = default if default
|
1236
|
-
|
1237
|
-
res = ask(message, opts)
|
1238
|
-
|
1239
|
-
if other && res == other
|
1240
|
-
opts[:choices] = all
|
1241
|
-
res = ask(message, opts)
|
1242
|
-
end
|
1243
|
-
|
1244
|
-
res
|
1245
|
-
end
|
1246
|
-
def usage(used, limit)
|
1247
|
-
"#{b(human_size(used))} of #{b(human_size(limit, 0))}"
|
1248
|
-
end
|
1249
|
-
|
1250
|
-
def percentage(num, low = 50, mid = 70)
|
1251
|
-
color =
|
1252
|
-
if num <= low
|
1253
|
-
:good
|
1254
|
-
elsif num <= mid
|
1255
|
-
:warning
|
1256
|
-
else
|
1257
|
-
:bad
|
1258
|
-
end
|
1259
|
-
|
1260
|
-
c(format("%.1f\%", num), color)
|
1261
|
-
end
|
1262
|
-
|
1263
|
-
def megabytes(str)
|
1264
|
-
if str =~ /T$/i
|
1265
|
-
str.to_i * 1024 * 1024
|
1266
|
-
elsif str =~ /G$/i
|
1267
|
-
str.to_i * 1024
|
1268
|
-
elsif str =~ /M$/i
|
1269
|
-
str.to_i
|
1270
|
-
elsif str =~ /K$/i
|
1271
|
-
str.to_i / 1024
|
1272
|
-
else # assume megabytes
|
1273
|
-
str.to_i
|
1274
|
-
end
|
1275
|
-
end
|
1276
|
-
|
1277
|
-
def human_size(num, precision = 1)
|
1278
|
-
sizes = ["G", "M", "K"]
|
1279
|
-
sizes.each.with_index do |suf, i|
|
1280
|
-
pow = sizes.size - i
|
1281
|
-
unit = 1024 ** pow
|
1282
|
-
if num >= unit
|
1283
|
-
return format("%.#{precision}f%s", num / unit, suf)
|
1284
|
-
end
|
1285
|
-
end
|
1286
|
-
|
1287
|
-
format("%.#{precision}fB", num)
|
1288
|
-
end
|
1289
|
-
|
1290
|
-
def human_mb(num)
|
1291
|
-
human_size(num * 1024 * 1024, 0)
|
1292
|
-
end
|
1293
|
-
|
1294
|
-
def target_base
|
1295
|
-
client.target.sub(/^https?:\/\/([^\.]+\.)?(.+)\/?/, '\2')
|
1296
|
-
end
|
1297
|
-
|
1298
|
-
def url_choices(name)
|
1299
|
-
if v2?
|
1300
|
-
client.current_space.domains.sort_by(&:name).collect do |d|
|
1301
|
-
# TODO: check availability
|
1302
|
-
"#{name}.#{d.name}"
|
1303
|
-
end
|
1304
|
-
else
|
1305
|
-
["#{name}.#{target_base}"]
|
1306
|
-
end
|
1307
|
-
end
|
1308
|
-
|
1309
|
-
def memory_choices(exclude = 0)
|
1310
|
-
info = client.info
|
1311
|
-
used = info[:usage][:memory]
|
1312
|
-
limit = info[:limits][:memory]
|
1313
|
-
available = limit - used + exclude
|
1314
|
-
|
1315
|
-
mem = 64
|
1316
|
-
choices = []
|
1317
|
-
until mem > available
|
1318
|
-
choices << human_mb(mem)
|
1319
|
-
mem *= 2
|
1320
|
-
end
|
1321
|
-
|
1322
|
-
choices
|
1323
|
-
end
|
1324
|
-
|
1325
|
-
def bool(b)
|
1326
|
-
if b
|
1327
|
-
c("true", :yes)
|
1328
|
-
else
|
1329
|
-
c("false", :no)
|
1330
|
-
end
|
1331
|
-
end
|
1332
|
-
end
|
1333
|
-
end
|