vmc 0.3.13.beta.2 → 0.3.13.beta.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/Rakefile +84 -2
  2. data/lib/cli.rb +2 -3
  3. data/lib/cli/commands/admin.rb +9 -6
  4. data/lib/cli/commands/apps.rb +144 -111
  5. data/lib/cli/commands/base.rb +8 -15
  6. data/lib/cli/commands/misc.rb +3 -2
  7. data/lib/cli/commands/services.rb +15 -16
  8. data/lib/cli/commands/user.rb +11 -2
  9. data/lib/cli/config.rb +5 -1
  10. data/lib/cli/core_ext.rb +331 -0
  11. data/lib/cli/frameworks.rb +10 -4
  12. data/lib/cli/runner.rb +4 -0
  13. data/lib/cli/services_helper.rb +8 -2
  14. data/lib/cli/usage.rb +4 -3
  15. data/lib/cli/version.rb +1 -1
  16. data/lib/vmc/client.rb +4 -0
  17. data/lib/vmc/const.rb +1 -0
  18. metadata +13 -46
  19. data/spec/assets/app_info.txt +0 -9
  20. data/spec/assets/app_listings.txt +0 -9
  21. data/spec/assets/bad_create_app.txt +0 -9
  22. data/spec/assets/delete_app.txt +0 -9
  23. data/spec/assets/global_service_listings.txt +0 -9
  24. data/spec/assets/good_create_app.txt +0 -9
  25. data/spec/assets/good_create_service.txt +0 -9
  26. data/spec/assets/info_authenticated.txt +0 -27
  27. data/spec/assets/info_return.txt +0 -15
  28. data/spec/assets/info_return_bad.txt +0 -16
  29. data/spec/assets/list_users.txt +0 -13
  30. data/spec/assets/login_fail.txt +0 -9
  31. data/spec/assets/login_success.txt +0 -9
  32. data/spec/assets/sample_token.txt +0 -1
  33. data/spec/assets/service_already_exists.txt +0 -9
  34. data/spec/assets/service_gateway_fail.txt +0 -9
  35. data/spec/assets/service_listings.txt +0 -9
  36. data/spec/assets/service_not_found.txt +0 -9
  37. data/spec/assets/user_info.txt +0 -9
  38. data/spec/spec_helper.rb +0 -11
  39. data/spec/unit/cli_opts_spec.rb +0 -68
  40. data/spec/unit/client_spec.rb +0 -345
data/Rakefile CHANGED
@@ -2,8 +2,7 @@ require 'rake'
2
2
  require 'spec/rake/spectask'
3
3
 
4
4
  desc "Run specs"
5
- task :spec do
6
- sh('bundle install')
5
+ task :spec => :build do
7
6
  Spec::Rake::SpecTask.new('spec') do |t|
8
7
  t.spec_opts = %w(-fs -c)
9
8
  t.spec_files = FileList['spec/**/*_spec.rb']
@@ -15,3 +14,86 @@ task :test => :spec
15
14
  desc "Synonym for spec"
16
15
  task :tests => :spec
17
16
  task :default => :spec
17
+
18
+ def tests_path
19
+ if @tests_path == nil
20
+ @tests_path = File.join(Dir.pwd, "spec/assets/tests")
21
+ end
22
+ @tests_path
23
+ end
24
+ TESTS_PATH = tests_path
25
+
26
+ BUILD_ARTIFACT = File.join(Dir.pwd, "spec/assets/.build")
27
+
28
+ TESTS_TO_BUILD = ["#{TESTS_PATH}/java_web/java_tiny_app",
29
+ # "#{TESTS_PATH}/grails/guestbook",
30
+ "#{TESTS_PATH}/lift/hello_lift",
31
+ "#{TESTS_PATH}/spring/roo-guestbook",
32
+ "#{TESTS_PATH}/spring/spring-osgi-hello",
33
+ ]
34
+
35
+ desc "Build the tests. If the git hash associated with the test assets has not changed, nothing is built. To force a build, invoke 'rake build[--force]'"
36
+ task :build, [:force] do |t, args|
37
+ sh('bundle install')
38
+ sh('git submodule update --init')
39
+ puts "\nBuilding tests"
40
+ if build_required? args.force
41
+ ENV['MAVEN_OPTS']="-XX:MaxPermSize=256M"
42
+ TESTS_TO_BUILD.each do |test|
43
+ puts "\tBuilding '#{test}'"
44
+ Dir.chdir test do
45
+ sh('mvn package -DskipTests') do |success, exit_code|
46
+ unless success
47
+ clear_build_artifact
48
+ do_mvn_clean('-q')
49
+ fail "\tFailed to build #{test} - aborting build"
50
+ end
51
+ end
52
+ end
53
+ puts "\tCompleted building '#{test}'"
54
+ end
55
+ save_git_hash
56
+ else
57
+ puts "Built artifacts in sync with test assets - no build required"
58
+ end
59
+ end
60
+
61
+ desc "Clean the build artifacts"
62
+ task :clean do
63
+ puts "\nCleaning tests"
64
+ clear_build_artifact
65
+ TESTS_TO_BUILD.each do |test|
66
+ puts "\tCleaning '#{test}'"
67
+ Dir.chdir test do
68
+ do_mvn_clean
69
+ end
70
+ puts "\tCompleted cleaning '#{test}'"
71
+ end
72
+ end
73
+
74
+ def build_required? (force_build=nil)
75
+ if File.exists?(BUILD_ARTIFACT) == false or (force_build and force_build == "--force")
76
+ return true
77
+ end
78
+ Dir.chdir(tests_path) do
79
+ saved_git_hash = IO.readlines(BUILD_ARTIFACT)[0].split[0]
80
+ git_hash = `git rev-parse --short=8 --verify HEAD`
81
+ saved_git_hash.to_s.strip != git_hash.to_s.strip
82
+ end
83
+ end
84
+
85
+ def save_git_hash
86
+ Dir.chdir(tests_path) do
87
+ git_hash = `git rev-parse --short=8 --verify HEAD`
88
+ File.open(BUILD_ARTIFACT, 'w') {|f| f.puts("#{git_hash}")}
89
+ end
90
+ end
91
+
92
+ def clear_build_artifact
93
+ puts "\tClearing build artifact #{BUILD_ARTIFACT}"
94
+ File.unlink BUILD_ARTIFACT if File.exists? BUILD_ARTIFACT
95
+ end
96
+
97
+ def do_mvn_clean options=nil
98
+ sh("mvn clean #{options}")
99
+ end
data/lib/cli.rb CHANGED
@@ -1,12 +1,11 @@
1
-
2
1
  ROOT = File.expand_path(File.dirname(__FILE__))
2
+ WINDOWS = !!(RUBY_PLATFORM =~ /mingw|mswin32|cygwin/)
3
3
 
4
- module VMC
5
4
 
5
+ module VMC
6
6
  autoload :Client, "#{ROOT}/vmc/client"
7
7
 
8
8
  module Cli
9
-
10
9
  autoload :Config, "#{ROOT}/cli/config"
11
10
  autoload :Framework, "#{ROOT}/cli/frameworks"
12
11
  autoload :Runner, "#{ROOT}/cli/runner"
@@ -22,12 +22,12 @@ module VMC::Cli::Command
22
22
  alias :users :list_users
23
23
 
24
24
  def add_user(email=nil)
25
- email = @options[:email] unless email
25
+ email ||= @options[:email]
26
+ email ||= ask("Email") unless no_prompt
26
27
  password = @options[:password]
27
- email = ask("Email: ") unless no_prompt || email
28
28
  unless no_prompt || password
29
- password = ask("Password: ") {|q| q.echo = '*'}
30
- password2 = ask("Verify Password: ") {|q| q.echo = '*'}
29
+ password = ask("Password", :echo => "*")
30
+ password2 = ask("Verify Password", :echo => "*")
31
31
  err "Passwords did not match, try again" if password != password2
32
32
  end
33
33
  err "Need a valid email" unless email
@@ -53,8 +53,11 @@ module VMC::Cli::Command
53
53
 
54
54
  if (apps && !apps.empty?)
55
55
  unless no_prompt
56
- proceed = ask("\nDeployed applications and associated services will be DELETED, continue? [yN]: ")
57
- err "Aborted" if proceed.upcase != 'Y'
56
+ proceed = ask(
57
+ "\nDeployed applications and associated services will be DELETED, continue?",
58
+ :default => false
59
+ )
60
+ err "Aborted" unless proceed
58
61
  end
59
62
  cmd = Apps.new(@options)
60
63
  apps.each { |app| cmd.delete_app(app[:name], true) }
@@ -44,6 +44,28 @@ module VMC::Cli::Command
44
44
  return display "Application '#{appname}' could not be found".red if app.nil?
45
45
  return display "Application '#{appname}' already started".yellow if app[:state] == 'STARTED'
46
46
 
47
+ if @options[:debug]
48
+ runtimes = client.runtimes_info
49
+ return display "Cannot get runtime information." unless runtimes
50
+
51
+ runtime = runtimes[app[:staging][:stack].to_sym]
52
+ return display "Unknown runtime." unless runtime
53
+
54
+ unless runtime[:debug_modes] and runtime[:debug_modes].include? @options[:debug]
55
+ modes = runtime[:debug_modes] || []
56
+
57
+ display "\nApplication '#{appname}' cannot start in '#{@options[:debug]}' mode"
58
+
59
+ if push
60
+ display "Try `vmc start' with one of the following modes: #{modes.inspect}"
61
+ else
62
+ display "Available modes: #{modes.inspect}"
63
+ end
64
+
65
+ return
66
+ end
67
+ end
68
+
47
69
  banner = 'Staging Application: '
48
70
  display banner, false
49
71
 
@@ -57,6 +79,7 @@ module VMC::Cli::Command
57
79
  end
58
80
 
59
81
  app[:state] = 'STARTED'
82
+ app[:debug] = @options[:debug]
60
83
  client.update_app(appname, app)
61
84
 
62
85
  Thread.kill(t)
@@ -79,10 +102,9 @@ module VMC::Cli::Command
79
102
  # Check for the existance of crashes
80
103
  display "\nError: Application [#{appname}] failed to start, logs information below.\n".red
81
104
  grab_crash_logs(appname, '0', true)
82
- if push
105
+ if push and !no_prompt
83
106
  display "\n"
84
- should_delete = ask 'Should I delete the application? (Y/n)? ' unless no_prompt
85
- delete_app(appname, false) unless no_prompt || should_delete.upcase == 'N'
107
+ delete_app(appname, false) if ask "Delete the application?", :default => true
86
108
  end
87
109
  failed = true
88
110
  break
@@ -130,14 +152,11 @@ module VMC::Cli::Command
130
152
  mem = current_mem = mem_quota_to_choice(app[:resources][:memory])
131
153
  memsize = normalize_mem(memsize) if memsize
132
154
 
133
- unless memsize
134
- choose do |menu|
135
- menu.layout = :one_line
136
- menu.prompt = "Update Memory Reservation? [Current:#{current_mem}] "
137
- menu.default = current_mem
138
- mem_choices.each { |choice| menu.choice(choice) { memsize = choice } }
139
- end
140
- end
155
+ memsize ||= ask(
156
+ "Update Memory Reservation?",
157
+ :default => current_mem,
158
+ :choices => mem_choices
159
+ )
141
160
 
142
161
  mem = mem_choice_to_quota(mem)
143
162
  memsize = mem_choice_to_quota(memsize)
@@ -184,11 +203,7 @@ module VMC::Cli::Command
184
203
  def delete(appname=nil)
185
204
  force = @options[:force]
186
205
  if @options[:all]
187
- should_delete = force && no_prompt ? 'Y' : 'N'
188
- unless no_prompt || force
189
- should_delete = ask 'Delete ALL Applications and Services? (y/N)? '
190
- end
191
- if should_delete.upcase == 'Y'
206
+ if no_prompt || force || ask("Delete ALL applications and services?", :default => false)
192
207
  apps = client.apps
193
208
  apps.each { |app| delete_app(app[:name], force) }
194
209
  end
@@ -206,25 +221,30 @@ module VMC::Cli::Command
206
221
  app_services.each { |service|
207
222
  del_service = force && no_prompt ? 'Y' : 'N'
208
223
  unless no_prompt || force
209
- apps_using_service = services_apps_hash[service].reject!{ |app| app == appname}
210
- if apps_using_service.size > 0
211
- del_service = ask("Provisioned service [#{service}] is being used by #{apps_using_service.entries}, would you still like to delete it? [yN]: ")
212
- else
213
- del_service = ask("Provisioned service [#{service}] detected, would you like to delete it? [yN]: ")
224
+ del_service = ask(
225
+ "Provisioned service [#{service}] detected, would you like to delete it?",
226
+ :default => false
227
+ )
228
+
229
+ if del_service
230
+ apps_using_service = services_apps_hash[service].reject!{ |app| app == appname}
231
+ if apps_using_service.size > 0
232
+ del_service = ask(
233
+ "Provisioned service [#{service}] is also used by #{apps_using_service.size == 1 ? "app" : "apps"} #{apps_using_service.entries}, are you sure you want to delete it?",
234
+ :default => false
235
+ )
236
+ end
214
237
  end
215
238
  end
216
- services_to_delete << service if del_service.upcase == 'Y'
239
+ services_to_delete << service if del_service
217
240
  }
241
+
218
242
  display "Deleting application [#{appname}]: ", false
219
243
  client.delete_app(appname)
220
244
  display 'OK'.green
221
245
 
222
- unless services_to_delete.length == 0
223
- services_to_delete.each do |s|
224
- display "Deleting service [#{s}]: ", false
225
- client.delete_service(s)
226
- display 'OK'.green
227
- end
246
+ services_to_delete.each do |s|
247
+ delete_service_banner(s)
228
248
  end
229
249
  end
230
250
 
@@ -352,10 +372,10 @@ module VMC::Cli::Command
352
372
  no_start = @options[:nostart]
353
373
 
354
374
  path = @options[:path] || '.'
355
- appname = @options[:name] unless appname
356
- url = @options[:url]
375
+ appname ||= @options[:name]
357
376
  mem, memswitch = nil, @options[:mem]
358
377
  memswitch = normalize_mem(memswitch) if memswitch
378
+ url = @options[:url]
359
379
 
360
380
  # Check app existing upfront if we have appname
361
381
  app_checked = false
@@ -375,52 +395,57 @@ module VMC::Cli::Command
375
395
  end
376
396
 
377
397
  unless no_prompt || @options[:path]
378
- proceed = ask('Would you like to deploy from the current directory? [Yn]: ')
379
- if proceed.upcase == 'N'
380
- path = ask('Please enter in the deployment path: ')
398
+ unless ask('Would you like to deploy from the current directory?', :default => true)
399
+ path = ask('Please enter in the deployment path')
381
400
  end
382
401
  end
383
402
 
384
403
  path = File.expand_path(path)
385
404
  check_deploy_directory(path)
386
405
 
387
- appname = ask("Application Name: ") unless no_prompt || appname
406
+ appname ||= ask("Application Name") unless no_prompt
388
407
  err "Application Name required." if appname.nil? || appname.empty?
389
408
 
390
- unless app_checked
391
- err "Application '#{appname}' already exists, use update or delete." if app_exists?(appname)
409
+ if !app_checked and app_exists?(appname)
410
+ err "Application '#{appname}' already exists, use update or delete."
392
411
  end
393
412
 
413
+ default_url = "#{appname}.#{VMC::Cli::Config.suggest_url}"
414
+
394
415
  unless no_prompt || url
395
- url = ask("Application Deployed URL: '#{appname}.#{VMC::Cli::Config.suggest_url}'? ")
416
+ url = ask(
417
+ "Application Deployed URL",
418
+ :default => default_url
419
+ )
396
420
 
397
- # common error case is for prompted users to answer y or Y or yes or YES to this ask() resulting in an
398
- # unintended URL of y. Special case this common error
399
- if YES_SET.member?(url)
400
- #silently revert to the stock url
401
- url = "#{appname}.#{VMC::Cli::Config.suggest_url}"
402
- end
421
+ # common error case is for prompted users to answer y or Y or yes or
422
+ # YES to this ask() resulting in an unintended URL of y. Special case
423
+ # this common error
424
+ url = nil if YES_SET.member? url
403
425
  end
404
426
 
405
- url = "#{appname}.#{VMC::Cli::Config.suggest_url}" if url.nil? || url.empty?
427
+ url ||= default_url
406
428
 
407
429
  # Detect the appropriate framework.
408
430
  framework = nil
409
431
  unless ignore_framework
410
432
  framework = VMC::Cli::Framework.detect(path)
411
- framework_correct = ask("Detected a #{framework}, is this correct? [Yn]: ") if prompt_ok && framework
412
- framework_correct ||= 'y'
413
- if prompt_ok && (framework.nil? || framework_correct.upcase == 'N')
433
+
434
+ if prompt_ok and framework
435
+ framework_correct =
436
+ ask("Detected a #{framework}, is this correct?", :default => true)
437
+ end
438
+
439
+ if prompt_ok && (framework.nil? || !framework_correct)
414
440
  display "#{"[WARNING]".yellow} Can't determine the Application Type." unless framework
415
- framework = nil if framework_correct.upcase == 'N'
416
- choose do |menu|
417
- menu.layout = :one_line
418
- menu.prompt = "Select Application Type: "
419
- menu.default = framework
420
- VMC::Cli::Framework.known_frameworks.each do |f|
421
- menu.choice(f) { framework = VMC::Cli::Framework.lookup(f) }
422
- end
423
- end
441
+ framework = VMC::Cli::Framework.lookup(
442
+ ask(
443
+ "Select Application Type",
444
+ { :indexed => true,
445
+ :choices => VMC::Cli::Framework.known_frameworks
446
+ }
447
+ )
448
+ )
424
449
  display "Selected #{framework}"
425
450
  end
426
451
  # Framework override, deprecated
@@ -430,18 +455,14 @@ module VMC::Cli::Command
430
455
  end
431
456
 
432
457
  err "Application Type undetermined for path '#{path}'" unless framework
433
- unless memswitch
434
- mem = framework.memory
435
- if prompt_ok
436
- choose do |menu|
437
- menu.layout = :one_line
438
- menu.prompt = "Memory Reservation [Default:#{mem}] "
439
- menu.default = mem
440
- mem_choices.each { |choice| menu.choice(choice) { mem = choice } }
441
- end
442
- end
443
- else
458
+
459
+ if memswitch
444
460
  mem = memswitch
461
+ elsif prompt_ok
462
+ mem = ask("Memory Reservation",
463
+ :default => framework.memory, :choices => mem_choices)
464
+ else
465
+ mem = framework.memory
445
466
  end
446
467
 
447
468
  # Set to MB number
@@ -473,8 +494,8 @@ module VMC::Cli::Command
473
494
  unless no_prompt || @options[:noservices]
474
495
  services = client.services_info
475
496
  unless services.empty?
476
- proceed = ask("Would you like to bind any services to '#{appname}'? [yN]: ")
477
- bind_services(appname, services) if proceed.upcase == 'Y'
497
+ proceed = ask("Would you like to bind any services to '#{appname}'?", :default => false)
498
+ bind_services(appname, services) if proceed
478
499
  end
479
500
  end
480
501
 
@@ -648,57 +669,54 @@ module VMC::Cli::Command
648
669
 
649
670
  def choose_existing_service(appname, user_services)
650
671
  return unless prompt_ok
651
- selected = false
652
- choose do |menu|
653
- menu.header = "The following provisioned services are available"
654
- menu.prompt = 'Please select one you wish to provision: '
655
- menu.select_by = :index_or_name
656
- user_services.each do |s|
657
- menu.choice(s[:name]) do
658
- display "Binding Service: ", false
659
- client.bind_service(s[:name], appname)
660
- display 'OK'.green
661
- selected = true
662
- end
663
- end
664
- end
665
- selected
672
+
673
+ display "The following provisioned services are available"
674
+ name = ask(
675
+ "Please select one you which to prevision",
676
+ { :indexed => true,
677
+ :choices => user_services.collect { |s| s[:name] }
678
+ }
679
+ )
680
+
681
+ bind_service_banner(name, appname, false)
682
+
683
+ true
666
684
  end
667
685
 
668
686
  def choose_new_service(appname, services)
669
687
  return unless prompt_ok
670
- choose do |menu|
671
- menu.header = "The following system services are available"
672
- menu.prompt = 'Please select one you wish to provision: '
673
- menu.select_by = :index_or_name
674
- service_choices = []
675
- services.each do |service_type, value|
676
- value.each do |vendor, version|
677
- service_choices << vendor
678
- end
679
- end
680
- service_choices.sort! {|a, b| a.to_s <=> b.to_s }
681
- service_choices.each do |vendor|
682
- menu.choice(vendor) do
683
- default_name = random_service_name(vendor)
684
- service_name = ask("Specify the name of the service [#{default_name}]: ")
685
- service_name = default_name if service_name.empty?
686
- create_service_banner(vendor, service_name)
687
- bind_service_banner(service_name, appname)
688
- end
689
- end
690
- end
688
+
689
+ display "The following system services are available"
690
+
691
+ vendor = ask(
692
+ "Please select one you wish to provision",
693
+ { :indexed => true,
694
+ :choices =>
695
+ services.values.collect { |type|
696
+ type.keys.collect(&:to_s)
697
+ }.flatten.sort!
698
+ }
699
+ )
700
+
701
+ default_name = random_service_name(vendor)
702
+ service_name = ask("Specify the name of the service",
703
+ :default => default_name)
704
+
705
+ create_service_banner(vendor, service_name)
706
+ bind_service_banner(service_name, appname)
691
707
  end
692
708
 
693
709
  def bind_services(appname, services)
694
710
  user_services = client.services
711
+
695
712
  selected_existing = false
696
713
  unless no_prompt || user_services.empty?
697
- use_existing = ask "Would you like to use an existing provisioned service [yN]? "
698
- if use_existing.upcase == 'Y'
714
+ if ask("Would you like to use an existing provisioned service?",
715
+ :default => false)
699
716
  selected_existing = choose_existing_service(appname, user_services)
700
717
  end
701
718
  end
719
+
702
720
  # Create a new service and bind it here
703
721
  unless selected_existing
704
722
  choose_new_service(appname, services)
@@ -795,9 +813,19 @@ module VMC::Cli::Command
795
813
  return display "No running instances for [#{appname}]".yellow if instances_info.empty?
796
814
 
797
815
  instances_table = table do |t|
798
- t.headings = 'Index', 'State', 'Start Time'
816
+ show_debug = instances_info.any? { |e| e[:debug_port] }
817
+
818
+ headings = ['Index', 'State', 'Start Time']
819
+ headings << 'Debug IP' if show_debug
820
+ headings << 'Debug Port' if show_debug
821
+
822
+ t.headings = headings
823
+
799
824
  instances_info.each do |entry|
800
- t << [entry[:index], entry[:state], Time.at(entry[:since]).strftime("%m/%d/%Y %I:%M%p")]
825
+ row = [entry[:index], entry[:state], Time.at(entry[:since]).strftime("%m/%d/%Y %I:%M%p")]
826
+ row << entry[:debug_ip] if show_debug
827
+ row << entry[:debug_port] if show_debug
828
+ t << row
801
829
  end
802
830
  end
803
831
  display "\n"
@@ -849,12 +877,17 @@ module VMC::Cli::Command
849
877
  case health(app)
850
878
  when 'N/A'
851
879
  # Health manager not running.
852
- err "\Application '#{appname}'s state is undetermined, not enough information available." if error_on_health
880
+ err "\nApplication '#{appname}'s state is undetermined, not enough information available." if error_on_health
853
881
  return false
854
882
  when 'RUNNING'
855
883
  return true
856
884
  else
857
- return false
885
+ if app[:meta][:debug] == "suspend"
886
+ display "\nApplication [#{appname}] has started in a mode that is waiting for you to trigger startup."
887
+ return true
888
+ else
889
+ return false
890
+ end
858
891
  end
859
892
  end
860
893