vmc 0.5.0.beta.12 → 0.5.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
@@ -63,7 +63,7 @@ module VMC
63
63
  end
64
64
 
65
65
  def check_target
66
- unless File.exists? target_file
66
+ unless client && client.target
67
67
  fail "Please select a target with 'vmc target'."
68
68
  end
69
69
  end
@@ -96,14 +96,8 @@ module VMC
96
96
  end
97
97
  end
98
98
 
99
- def execute(cmd, argv, global = {})
100
- if input[:help]
101
- invoke :help, :command => cmd.name.to_s
102
- else
103
- @command = cmd
104
- precondition
105
- super
106
- end
99
+ def wrap_errors
100
+ yield
107
101
  rescue CFoundry::Timeout => e
108
102
  err(e.message)
109
103
  rescue Interrupt
@@ -122,6 +116,8 @@ module VMC
122
116
  line
123
117
  line c("Not authenticated! Try logging in:", :warning)
124
118
 
119
+ # TODO: there's no color here; global flags not being passed
120
+ # through (mothership bug?)
125
121
  invoke :login
126
122
 
127
123
  retry
@@ -132,18 +128,52 @@ module VMC
132
128
  err "Denied: #{e.description}"
133
129
 
134
130
  rescue Exception => e
135
- ensure_config_dir
136
-
137
131
  log_error(e)
138
132
 
139
133
  msg = e.class.name
140
134
  msg << ": #{e}" unless e.to_s.empty?
141
135
  msg << "\nFor more information, see #{VMC::CRASH_FILE}"
142
136
  err msg
137
+
143
138
  raise if debug?
144
139
  end
145
140
 
141
+ def execute(cmd, argv, global = {})
142
+ if input[:help]
143
+ invoke :help, :command => cmd.name.to_s
144
+ else
145
+ wrap_errors do
146
+ @command = cmd
147
+ precondition
148
+
149
+ save_token_if_it_changes do
150
+ super
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+ def save_token_if_it_changes
157
+ return yield unless client && client.token
158
+
159
+ before_token = client.token
160
+
161
+ yield
162
+
163
+ after_token = client.token
164
+
165
+ return unless after_token
166
+
167
+ if before_token != after_token
168
+ info = target_info
169
+ info[:token] = after_token.auth_header
170
+ save_target_info(info)
171
+ end
172
+ end
173
+
146
174
  def log_error(e)
175
+ ensure_config_dir
176
+
147
177
  msg = e.class.name
148
178
  msg << ": #{e}" unless e.to_s.empty?
149
179
 
@@ -277,8 +307,9 @@ module VMC
277
307
  end
278
308
 
279
309
  def client_target
280
- check_target
281
- File.read(target_file).chomp
310
+ if File.exists?(target_file)
311
+ File.read(target_file).chomp
312
+ end
282
313
  end
283
314
 
284
315
  def ensure_config_dir
@@ -300,13 +331,14 @@ module VMC
300
331
  new_toks = File.expand_path(VMC::TOKENS_FILE)
301
332
  old_toks = File.expand_path(VMC::OLD_TOKENS_FILE)
302
333
 
303
- info = if File.exist? new_toks
304
- YAML.load_file(new_toks)
305
- elsif File.exist? old_toks
306
- MultiJson.load(File.read(old_toks))
307
- else
308
- {}
309
- end
334
+ info =
335
+ if File.exist? new_toks
336
+ YAML.load_file(new_toks)
337
+ elsif File.exist? old_toks
338
+ MultiJson.load(File.read(old_toks))
339
+ end
340
+
341
+ info ||= {}
310
342
 
311
343
  normalize_targets_info(info)
312
344
  end
@@ -314,7 +346,7 @@ module VMC
314
346
  def normalize_targets_info(info_by_url)
315
347
  info_by_url.reduce({}) do |hash, pair|
316
348
  key, value = pair
317
- hash[key] = value.is_a?(String) ? {:token => value } : value
349
+ hash[key] = value.is_a?(String) ? { :token => value } : value
318
350
  hash
319
351
  end
320
352
  end
@@ -358,6 +390,7 @@ module VMC
358
390
 
359
391
  def client(target = client_target)
360
392
  return @@client if defined?(@@client) && @@client
393
+ return unless target
361
394
 
362
395
  info = target_info(target)
363
396
  token = info[:token] && CFoundry::AuthToken.from_hash(info)
@@ -392,6 +425,11 @@ module VMC
392
425
  end
393
426
 
394
427
  @@client
428
+ rescue CFoundry::InvalidTarget
429
+ end
430
+
431
+ def fail_unknown(display, name)
432
+ fail("Unknown #{display} '#{name}'.")
395
433
  end
396
434
 
397
435
  class << self
@@ -411,14 +449,14 @@ module VMC
411
449
  choices ||= instance_exec(&blk) if block_given?
412
450
 
413
451
  choices.find { |c| c.name == name } ||
414
- fail("Unknown #{display} '#{name}'.")
452
+ fail_unknown(display, name)
415
453
  }
416
454
  end
417
455
 
418
456
  def by_name(what, display = what)
419
457
  proc { |name, *_|
420
458
  client.send(:"#{what}_by_name", name) ||
421
- fail("Unknown #{display} '#{name}'.")
459
+ fail_unknown(display, name)
422
460
  }
423
461
  end
424
462
 
@@ -428,7 +466,7 @@ module VMC
428
466
  choices ||= instance_exec(&blk) if block_given?
429
467
 
430
468
  choices.find { |c| c.name.upcase == name.upcase } ||
431
- fail("Unknown #{display} '#{name}'.")
469
+ fail_unknown(display, name)
432
470
  }
433
471
  end
434
472
  end
@@ -12,7 +12,16 @@ module VMC::App
12
12
  group :apps, :manage
13
13
  input :name, :desc => "Application name", :argument => :optional
14
14
  input :path, :desc => "Path containing the bits", :default => "."
15
- input :url, :desc => "URL to bind to app"
15
+ input :host, :desc => "Subdomain for the app's URL"
16
+ input :domain, :desc => "Domain for the app",
17
+ :from_given => proc { |given, app|
18
+ if !v2? || given == "none"
19
+ given
20
+ else
21
+ app.space.domain_by_name(given) ||
22
+ fail_unknown("domain", given)
23
+ end
24
+ }
16
25
  input :memory, :desc => "Memory limit"
17
26
  input :instances, :desc => "Number of instances to run", :type => :integer
18
27
  input :framework, :desc => "Framework to use", :from_given => by_name(:framework)
@@ -50,7 +59,7 @@ module VMC::App
50
59
  def setup_new_app(path)
51
60
  self.path = path
52
61
  app = create_app(get_inputs)
53
- map_url(app)
62
+ map_route(app)
54
63
  create_services(app)
55
64
  bind_services(app)
56
65
  upload_app(app, path)
@@ -80,5 +89,17 @@ module VMC::App
80
89
  err "Upload failed. Try again with 'vmc push'."
81
90
  raise
82
91
  end
92
+
93
+ def wrap_message_format_errors
94
+ yield
95
+ rescue CFoundry::MessageParseError => e
96
+ md = e.description.match /Field: ([^,]+)/
97
+ field = md[1]
98
+
99
+ case field
100
+ when "buildpack"
101
+ fail "Buildpack must be a public git repository URI."
102
+ end
103
+ end
83
104
  end
84
105
  end
@@ -59,21 +59,25 @@ module VMC::App
59
59
  app = filter(:create_app, app)
60
60
 
61
61
  with_progress("Creating #{c(app.name, :name)}") do
62
- app.create!
62
+ wrap_message_format_errors do
63
+ app.create!
64
+ end
63
65
  end
64
66
 
65
67
  app
66
68
  end
67
69
 
68
- def map_url(app)
70
+ def map_route(app)
69
71
  line unless quiet?
70
72
 
71
- url = input[:url, app.name]
73
+ host = input[:host, app.name] if v2?
74
+ domain = input[:domain, app]
72
75
 
73
76
  mapped_url = false
74
- until url == "none" || !url || mapped_url
77
+ until domain == "none" || !domain || mapped_url
75
78
  begin
76
- invoke :map, :app => app, :url => url
79
+ host = "" if host == "none"
80
+ invoke :map, :app => app, :host => host, :domain => domain
77
81
  mapped_url = true
78
82
  rescue CFoundry::RouteHostTaken, CFoundry::UriAlreadyTaken => e
79
83
  raise if force?
@@ -81,8 +85,11 @@ module VMC::App
81
85
  line c(e.description, :bad)
82
86
  line
83
87
 
84
- input.forget(:url)
85
- url = input[:url, app.name]
88
+ input.forget(:host) if v2?
89
+ input.forget(:domain)
90
+
91
+ host = input[:host, app.name] if v2?
92
+ domain = input[:domain, app]
86
93
 
87
94
  # version bumps on v1 even though mapping fails
88
95
  app.invalidate! unless v2?
@@ -4,17 +4,24 @@ module VMC::App
4
4
  ask("Name")
5
5
  end
6
6
 
7
- def ask_url(name)
8
- choices = url_choices(name)
7
+ def ask_host(name)
8
+ ask "Subdomain", :choices => [name, "none"],
9
+ :default => name,
10
+ :allow_other => true
11
+ end
12
+
13
+ def ask_domain(app)
14
+ choices = v2? ? app.space.domains : ["#{app.name}.#{target_base}"]
9
15
 
10
16
  options = {
11
17
  :choices => choices + ["none"],
18
+ :display => proc { |d| d.is_a?(String) ? d : d.name },
12
19
  :allow_other => true
13
20
  }
14
21
 
15
22
  options[:default] = choices.first if choices.size == 1
16
23
 
17
- ask "URL", options
24
+ ask "Domain", options
18
25
  end
19
26
 
20
27
  def ask_memory(default)
@@ -25,7 +25,9 @@ module VMC::App
25
25
  def commit_changes(app)
26
26
  if app.changed?
27
27
  with_progress("Updating #{c(app.name, :name)}") do
28
- app.update!
28
+ wrap_message_format_errors do
29
+ app.update!
30
+ end
29
31
  end
30
32
  end
31
33
 
@@ -42,7 +44,7 @@ module VMC::App
42
44
  human_mb(val)
43
45
  when :framework, :runtime
44
46
  val.name
45
- when :command
47
+ when :command, :buildpack
46
48
  "'#{val}'"
47
49
  when :production
48
50
  bool(val)
@@ -36,7 +36,7 @@ module VMC::App
36
36
 
37
37
  if usage
38
38
  [ idx,
39
- "#{percentage(usage[:cpu])} of #{b(stats[:cores])} cores",
39
+ "#{percentage(usage[:cpu])}",
40
40
  "#{usage(usage[:mem], stats[:mem_quota])}",
41
41
  "#{usage(usage[:disk], stats[:disk_quota])}"
42
42
  ]
@@ -6,29 +6,33 @@ module VMC::Route
6
6
 
7
7
  desc "Add a URL mapping"
8
8
  group :apps, :info, :hidden => true
9
- input :url, :desc => "URL to map", :argument => true
10
- input :app, :desc => "Application to add the URL to", :argument => :optional,
11
- :from_given => by_name(:app)
12
- input :space, :desc => "Space to add the URL to",
13
- :from_given => by_name(:space)
9
+ input :app, :desc => "Application to add the URL to",
10
+ :argument => :optional, :from_given => by_name(:app)
11
+ input :host, :desc => "Host name for the route",
12
+ :argument => :optional, :default => ""
13
+ input :domain, :desc => "Domain to add the route to",
14
+ :argument => true,
15
+ :from_given => proc { |name, space|
16
+ if v2?
17
+ space.domain_by_name(name) ||
18
+ fail_unknown("domain", name)
19
+ else
20
+ name
21
+ end
22
+ }
14
23
  def map
15
- if input.has?(:space)
16
- space = input[:space]
17
- else
18
- app = input[:app]
19
- space = app.space if v2?
20
- end
24
+ app = input[:app]
25
+ space = app.space if v2?
21
26
 
22
- url = input[:url].sub(/^https?:\/\/(.*)\/?/i, '\1')
27
+ host = input[:host]
28
+ domain = input[:domain, space]
23
29
 
24
30
  if v2?
25
- host, domain_name = url.split(".", 2)
26
- domain = find_domain(space, domain_name)
27
31
  route = find_or_create_route(domain, host, space)
28
32
  bind_route(route, app) if app
29
33
  else
30
34
  with_progress("Updating #{c(app.name, :name)}") do
31
- app.urls << url
35
+ app.urls << domain
32
36
  app.update!
33
37
  end
34
38
  end
@@ -56,7 +60,9 @@ module VMC::Route
56
60
  route.domain = domain
57
61
  route.space = space
58
62
 
59
- with_progress("Creating route #{c(route.name, :name)}") { route.create! }
63
+ with_progress("Creating route #{c(route.name, :name)}") do
64
+ route.create!
65
+ end
60
66
 
61
67
  route
62
68
  end
@@ -69,7 +69,7 @@ module VMC::Service
69
69
  service.type = offering.type
70
70
  service.vendor = offering.label
71
71
  service.version = offering.version
72
- service.tier = "free"
72
+ service.tier = v1_service_tier(offering)
73
73
  end
74
74
 
75
75
  with_progress("Creating service #{c(service.name, :name)}") do
@@ -102,10 +102,25 @@ module VMC::Service
102
102
  ask "Name?", :default => "#{offering.label}-#{random}"
103
103
  end
104
104
 
105
- def ask_plan(plans)
106
- ask "Which plan?", :choices => plans.sort_by(&:name),
107
- :display => proc { |p| "#{p.name}: #{p.description}" },
105
+ def ask_plan(plans, default_plan = nil)
106
+ ask "Which plan?",
107
+ :choices => plans.sort_by(&:name),
108
+ :indexed => true,
109
+ :display => proc { |p| "#{p.name}: #{p.description || 'No description'}" },
110
+ :default => default_plan,
108
111
  :complete => proc(&:name)
109
112
  end
113
+
114
+ def v1_service_tier(service)
115
+ plans = service.service_plans
116
+ fail "No service plans" if plans.empty?
117
+ if plans.length == 1
118
+ plan = plans[0]
119
+ else
120
+ plan = ask_plan(plans, service.default_service_plan)
121
+ end
122
+ plan.name
123
+ end
124
+
110
125
  end
111
126
  end
@@ -2,6 +2,10 @@ require "vmc/cli/start/base"
2
2
 
3
3
  module VMC::Start
4
4
  class Info < Base
5
+ def precondition
6
+ check_target
7
+ end
8
+
5
9
  desc "Display information on the current target, user, etc."
6
10
  group :start
7
11
  input :runtimes, :desc => "List supported runtimes", :alias => "-r",
@@ -3,6 +3,10 @@ require "vmc/cli/start/target_interactions"
3
3
 
4
4
  module VMC::Start
5
5
  class Login < Base
6
+ def precondition
7
+ check_target
8
+ end
9
+
6
10
  desc "Authenticate with the target"
7
11
  group :start
8
12
  input :username, :value => :email, :desc => "Account email",
@@ -2,6 +2,10 @@ require "vmc/cli/start/base"
2
2
 
3
3
  module VMC::Start
4
4
  class Logout < Base
5
+ def precondition
6
+ check_target
7
+ end
8
+
5
9
  desc "Log out from the target"
6
10
  group :start
7
11
  def logout