cf 0.1.5 → 0.6.0.rc1

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.
Files changed (140) hide show
  1. data/LICENSE +1277 -30
  2. data/Rakefile +12 -1
  3. data/bin/cf +0 -3
  4. data/lib/cf.rb +6 -0
  5. data/lib/cf/cli.rb +389 -190
  6. data/lib/cf/cli/app/app.rb +45 -0
  7. data/lib/cf/cli/app/apps.rb +99 -0
  8. data/lib/cf/cli/app/base.rb +90 -0
  9. data/lib/cf/cli/app/crashes.rb +42 -0
  10. data/lib/cf/cli/app/delete.rb +95 -0
  11. data/lib/cf/cli/app/deprecated.rb +11 -0
  12. data/lib/cf/cli/app/env.rb +78 -0
  13. data/lib/cf/cli/app/files.rb +137 -0
  14. data/lib/cf/cli/app/health.rb +26 -0
  15. data/lib/cf/cli/app/instances.rb +53 -0
  16. data/lib/cf/cli/app/logs.rb +76 -0
  17. data/lib/cf/cli/app/push.rb +105 -0
  18. data/lib/cf/cli/app/push/create.rb +149 -0
  19. data/lib/cf/cli/app/push/interactions.rb +94 -0
  20. data/lib/cf/cli/app/push/sync.rb +64 -0
  21. data/lib/cf/cli/app/rename.rb +35 -0
  22. data/lib/cf/cli/app/restart.rb +20 -0
  23. data/lib/cf/cli/app/scale.rb +69 -0
  24. data/lib/cf/cli/app/start.rb +143 -0
  25. data/lib/cf/cli/app/stats.rb +67 -0
  26. data/lib/cf/cli/app/stop.rb +27 -0
  27. data/lib/cf/cli/domain/base.rb +8 -0
  28. data/lib/cf/cli/domain/domains.rb +40 -0
  29. data/lib/cf/cli/domain/map.rb +55 -0
  30. data/lib/cf/cli/domain/unmap.rb +56 -0
  31. data/lib/cf/cli/help.rb +15 -0
  32. data/lib/cf/cli/interactive.rb +105 -0
  33. data/lib/cf/cli/organization/base.rb +12 -0
  34. data/lib/cf/cli/organization/create.rb +32 -0
  35. data/lib/cf/cli/organization/delete.rb +73 -0
  36. data/lib/cf/cli/organization/org.rb +45 -0
  37. data/lib/cf/cli/organization/orgs.rb +35 -0
  38. data/lib/cf/cli/organization/rename.rb +36 -0
  39. data/lib/cf/cli/route/base.rb +8 -0
  40. data/lib/cf/cli/route/map.rb +70 -0
  41. data/lib/cf/cli/route/routes.rb +26 -0
  42. data/lib/cf/cli/route/unmap.rb +62 -0
  43. data/lib/cf/cli/service/base.rb +8 -0
  44. data/lib/cf/cli/service/bind.rb +44 -0
  45. data/lib/cf/cli/service/create.rb +107 -0
  46. data/lib/cf/cli/service/delete.rb +82 -0
  47. data/lib/cf/cli/service/rename.rb +35 -0
  48. data/lib/cf/cli/service/service.rb +40 -0
  49. data/lib/cf/cli/service/services.rb +99 -0
  50. data/lib/cf/cli/service/unbind.rb +38 -0
  51. data/lib/cf/cli/space/base.rb +19 -0
  52. data/lib/cf/cli/space/create.rb +63 -0
  53. data/lib/cf/cli/space/delete.rb +95 -0
  54. data/lib/cf/cli/space/rename.rb +39 -0
  55. data/lib/cf/cli/space/space.rb +64 -0
  56. data/lib/cf/cli/space/spaces.rb +55 -0
  57. data/lib/cf/cli/space/switch.rb +16 -0
  58. data/lib/cf/cli/start/base.rb +93 -0
  59. data/lib/cf/cli/start/colors.rb +13 -0
  60. data/lib/cf/cli/start/info.rb +124 -0
  61. data/lib/cf/cli/start/login.rb +94 -0
  62. data/lib/cf/cli/start/logout.rb +17 -0
  63. data/lib/cf/cli/start/target.rb +69 -0
  64. data/lib/cf/cli/start/target_interactions.rb +37 -0
  65. data/lib/cf/cli/start/targets.rb +16 -0
  66. data/lib/cf/cli/user/base.rb +29 -0
  67. data/lib/cf/cli/user/create.rb +39 -0
  68. data/lib/cf/cli/user/passwd.rb +43 -0
  69. data/lib/cf/cli/user/register.rb +42 -0
  70. data/lib/cf/cli/user/users.rb +32 -0
  71. data/lib/cf/constants.rb +10 -7
  72. data/lib/cf/detect.rb +113 -48
  73. data/lib/cf/errors.rb +17 -0
  74. data/lib/cf/plugin.rb +28 -12
  75. data/lib/cf/spacing.rb +89 -0
  76. data/lib/cf/spec_helper.rb +1 -0
  77. data/lib/cf/test_support.rb +6 -0
  78. data/lib/cf/version.rb +1 -1
  79. data/spec/assets/hello-sinatra/Gemfile +3 -0
  80. data/spec/assets/hello-sinatra/Gemfile.lock +17 -0
  81. data/spec/assets/hello-sinatra/config.ru +3 -0
  82. data/spec/assets/hello-sinatra/fat-cat-makes-app-larger.png +0 -0
  83. data/spec/assets/hello-sinatra/main.rb +6 -0
  84. data/spec/assets/specker_runner/specker_runner_input.rb +6 -0
  85. data/spec/assets/specker_runner/specker_runner_pause.rb +5 -0
  86. data/spec/cf/cli/app/base_spec.rb +17 -0
  87. data/spec/cf/cli/app/delete_spec.rb +188 -0
  88. data/spec/cf/cli/app/instances_spec.rb +65 -0
  89. data/spec/cf/cli/app/push/create_spec.rb +661 -0
  90. data/spec/cf/cli/app/push_spec.rb +369 -0
  91. data/spec/cf/cli/app/rename_spec.rb +104 -0
  92. data/spec/cf/cli/app/scale_spec.rb +75 -0
  93. data/spec/cf/cli/app/start_spec.rb +208 -0
  94. data/spec/cf/cli/app/stats_spec.rb +68 -0
  95. data/spec/cf/cli/domain/map_spec.rb +130 -0
  96. data/spec/cf/cli/domain/unmap_spec.rb +69 -0
  97. data/spec/cf/cli/organization/orgs_spec.rb +108 -0
  98. data/spec/cf/cli/organization/rename_spec.rb +113 -0
  99. data/spec/cf/cli/route/map_spec.rb +121 -0
  100. data/spec/cf/cli/route/unmap_spec.rb +155 -0
  101. data/spec/cf/cli/service/bind_spec.rb +25 -0
  102. data/spec/cf/cli/service/delete_spec.rb +22 -0
  103. data/spec/cf/cli/service/rename_spec.rb +105 -0
  104. data/spec/cf/cli/service/service_spec.rb +23 -0
  105. data/spec/cf/cli/service/unbind_spec.rb +25 -0
  106. data/spec/cf/cli/space/create_spec.rb +93 -0
  107. data/spec/cf/cli/space/rename_spec.rb +102 -0
  108. data/spec/cf/cli/space/spaces_spec.rb +104 -0
  109. data/spec/cf/cli/space/switch_space_spec.rb +55 -0
  110. data/spec/cf/cli/start/info_spec.rb +160 -0
  111. data/spec/cf/cli/start/login_spec.rb +142 -0
  112. data/spec/cf/cli/start/logout_spec.rb +50 -0
  113. data/spec/cf/cli/start/target_spec.rb +123 -0
  114. data/spec/cf/cli/user/create_spec.rb +54 -0
  115. data/spec/cf/cli/user/passwd_spec.rb +102 -0
  116. data/spec/cf/cli/user/register_spec.rb +140 -0
  117. data/spec/cf/cli_spec.rb +442 -0
  118. data/spec/cf/detect_spec.rb +54 -0
  119. data/spec/console_app_specker/console_app_specker_matchers_spec.rb +173 -0
  120. data/spec/console_app_specker/specker_runner_spec.rb +167 -0
  121. data/spec/features/account_lifecycle_spec.rb +85 -0
  122. data/spec/features/login_spec.rb +66 -0
  123. data/spec/features/push_flow_spec.rb +125 -0
  124. data/spec/features/switching_targets_spec.rb +32 -0
  125. data/spec/spec_helper.rb +72 -0
  126. data/spec/support/command_helper.rb +81 -0
  127. data/spec/support/config_helper.rb +15 -0
  128. data/spec/support/console_app_specker_matchers.rb +86 -0
  129. data/spec/support/fake_home_dir.rb +55 -0
  130. data/spec/support/interact_helper.rb +29 -0
  131. data/spec/support/shared_examples/errors.rb +40 -0
  132. data/spec/support/shared_examples/input.rb +14 -0
  133. data/spec/support/specker_runner.rb +80 -0
  134. data/spec/support/tracking_expector.rb +71 -0
  135. metadata +427 -66
  136. data/lib/cf/cli/app.rb +0 -595
  137. data/lib/cf/cli/command.rb +0 -444
  138. data/lib/cf/cli/dots.rb +0 -133
  139. data/lib/cf/cli/service.rb +0 -112
  140. data/lib/cf/cli/user.rb +0 -71
@@ -0,0 +1,45 @@
1
+ require "cf/cli/app/base"
2
+
3
+ module CF::App
4
+ class Apps < Base
5
+ IS_UTF8 = !!(ENV["LC_ALL"] || ENV["LC_CTYPE"] || ENV["LANG"] || "")["UTF-8"].freeze
6
+
7
+ desc "Show app information"
8
+ group :apps
9
+ input :app, :desc => "App to show", :argument => :required,
10
+ :from_given => by_name(:app)
11
+ def app
12
+ app = input[:app]
13
+
14
+ if quiet?
15
+ line app.name
16
+ else
17
+ display_app(app)
18
+ end
19
+ end
20
+
21
+ def display_app(a)
22
+ status = app_status(a)
23
+
24
+ line "#{c(a.name, :name)}: #{status}"
25
+
26
+ indented do
27
+ line "platform: #{b(a.framework.name)} on #{b(a.runtime.name)}"
28
+
29
+ start_line "usage: #{b(human_mb(a.memory))}"
30
+ print " #{d(IS_UTF8 ? "\xc3\x97" : "x")} #{b(a.total_instances)}"
31
+ print " instance#{a.total_instances == 1 ? "" : "s"}"
32
+
33
+ line
34
+
35
+ unless a.urls.empty?
36
+ line "urls: #{a.urls.collect { |u| b(u) }.join(", ")}"
37
+ end
38
+
39
+ unless a.services.empty?
40
+ line "services: #{a.services.collect { |s| b(s.name) }.join(", ")}"
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,99 @@
1
+ require "cf/cli/app/base"
2
+
3
+ module CF::App
4
+ class Apps < Base
5
+ desc "List your applications"
6
+ group :apps
7
+ input :space, :desc => "Show apps in given space",
8
+ :default => proc { client.current_space },
9
+ :from_given => by_name(:space)
10
+ input :name, :desc => "Filter by name regexp"
11
+ input :runtime, :desc => "Filter by runtime regexp"
12
+ input :framework, :desc => "Filter by framework regexp"
13
+ input :url, :desc => "Filter by url regexp"
14
+ input :full, :desc => "Verbose output format", :default => false
15
+ def apps
16
+ if space = input[:space]
17
+ begin
18
+ space.summarize!
19
+ rescue CFoundry::APIError
20
+ end
21
+
22
+ apps =
23
+ with_progress("Getting applications in #{c(space.name, :name)}") do
24
+ space.apps
25
+ end
26
+ else
27
+ apps =
28
+ with_progress("Getting applications") do
29
+ client.apps(:depth => 2)
30
+ end
31
+ end
32
+
33
+ line unless quiet?
34
+
35
+ if apps.empty? and !quiet?
36
+ line "No applications."
37
+ return
38
+ end
39
+
40
+ apps.reject! do |a|
41
+ !app_matches?(a, input)
42
+ end
43
+
44
+ apps = apps.sort_by(&:name)
45
+
46
+ if input[:full]
47
+ spaced(apps) do |a|
48
+ invoke :app, :app => a
49
+ end
50
+ elsif quiet?
51
+ apps.each do |a|
52
+ line a.name
53
+ end
54
+ else
55
+ display_apps_table(apps)
56
+ end
57
+ end
58
+
59
+ def display_apps_table(apps)
60
+ table(
61
+ ["name", "status", "usage", "plan", "runtime", "url"],
62
+ apps.collect { |a|
63
+ [ c(a.name, :name),
64
+ app_status(a),
65
+ "#{a.total_instances} x #{human_mb(a.memory)}",
66
+ a.production ? "prod" : "dev",
67
+ a.runtime.name,
68
+ if a.urls.empty?
69
+ d("none")
70
+ elsif a.urls.size == 1
71
+ a.url
72
+ else
73
+ "#{a.url}, ..."
74
+ end
75
+ ]
76
+ })
77
+ end
78
+
79
+ def app_matches?(a, options)
80
+ if name = options[:name]
81
+ return false if a.name !~ /#{name}/
82
+ end
83
+
84
+ if runtime = options[:runtime]
85
+ return false if a.runtime.name !~ /#{runtime}/
86
+ end
87
+
88
+ if framework = options[:framework]
89
+ return false if a.framework.name !~ /#{framework}/
90
+ end
91
+
92
+ if url = options[:url]
93
+ return false if a.urls.none? { |u| u =~ /#{url}/ }
94
+ end
95
+
96
+ true
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,90 @@
1
+ require "cf/cli"
2
+
3
+ module CF
4
+ module App
5
+ class Base < CLI
6
+ # choose the right color for app/instance state
7
+ def state_color(s)
8
+ case s
9
+ when "STARTING"
10
+ :neutral
11
+ when "STARTED", "RUNNING"
12
+ :good
13
+ when "DOWN"
14
+ :bad
15
+ when "FLAPPING"
16
+ :error
17
+ when "N/A"
18
+ :unknown
19
+ else
20
+ :warning
21
+ end
22
+ end
23
+
24
+ def app_status(a)
25
+ health = a.health
26
+
27
+ if a.debug_mode == "suspend" && health == "0%"
28
+ c("suspended", :neutral)
29
+ else
30
+ c(health.downcase, state_color(health))
31
+ end
32
+ end
33
+
34
+ def memory_choices(exclude = 0)
35
+ info = client.info
36
+
37
+ usage = info[:usage]
38
+ limit = info[:limits][:memory]
39
+
40
+ ceiling =
41
+ if usage
42
+ used = usage[:memory]
43
+ limit - used + exclude
44
+ else
45
+ limit
46
+ end
47
+
48
+ mem = 64
49
+ choices = []
50
+ until mem > ceiling
51
+ choices << human_mb(mem)
52
+ mem *= 2
53
+ end
54
+
55
+ choices
56
+ end
57
+
58
+ def human_mb(num)
59
+ human_size(num * 1024 * 1024, 0)
60
+ end
61
+
62
+ def human_size(num, precision = 1)
63
+ sizes = %w(G M K)
64
+ sizes.each.with_index do |suf, i|
65
+ pow = sizes.size - i
66
+ unit = 1024.0 ** pow
67
+ if num >= unit
68
+ return format("%.#{precision}f%s", num / unit, suf)
69
+ end
70
+ end
71
+
72
+ format("%.#{precision}fB", num)
73
+ end
74
+
75
+ def megabytes(str)
76
+ if str =~ /T$/i
77
+ str.to_i * 1024 * 1024
78
+ elsif str =~ /G$/i
79
+ str.to_i * 1024
80
+ elsif str =~ /M$/i
81
+ str.to_i
82
+ elsif str =~ /K$/i
83
+ str.to_i / 1024
84
+ else # assume megabytes
85
+ str.to_i
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,42 @@
1
+ require "cf/cli/app/base"
2
+
3
+ module CF::App
4
+ class Crashes < Base
5
+ desc "List an app's crashed instances"
6
+ group :apps, :info, :hidden => true
7
+ input :apps, :desc => "Applications whose crashed instances to list",
8
+ :argument => :splat, :singular => :app, :from_given => by_name(:app)
9
+ def crashes
10
+ apps = input[:apps]
11
+ fail "No applications given." if apps.empty?
12
+
13
+ spaced(apps) do |app|
14
+ instances =
15
+ with_progress("Getting crashed instances for #{c(app.name, :name)}") do
16
+ app.crashes
17
+ end
18
+
19
+ line unless quiet?
20
+
21
+ spaced(instances) do |i|
22
+ if quiet?
23
+ line i.id
24
+ else
25
+ display_crashed_instance(i)
26
+ end
27
+ end
28
+ end
29
+ end
30
+
31
+ def display_crashed_instance(i)
32
+ start_line "instance #{c("\##{i.id}", :instance)}: "
33
+ puts "#{b(c("crashed", :error))} "
34
+
35
+ indented do
36
+ if s = i.since
37
+ line "since: #{c(s.strftime("%F %r"), :neutral)}"
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,95 @@
1
+ require "set"
2
+
3
+ require "cf/cli/app/base"
4
+
5
+ module CF::App
6
+ class Delete < Base
7
+ desc "Delete an application"
8
+ group :apps, :manage
9
+ input :apps, :desc => "Applications to delete", :argument => :splat,
10
+ :singular => :app, :from_given => by_name(:app)
11
+ input :routes, :desc => "Delete associated routes", :default => false
12
+ input :delete_orphaned, :desc => "Delete orphaned services",
13
+ :aliases => "-o", :default => proc { force? ? false : interact },
14
+ :forget => true
15
+ input :all, :desc => "Delete all applications", :default => false
16
+ input :really, :type => :boolean, :forget => true, :hidden => true,
17
+ :default => proc { force? || interact }
18
+ def delete
19
+ apps = client.apps
20
+
21
+ if input[:all]
22
+ return unless input[:really, "ALL APPS", :bad]
23
+
24
+ to_delete = apps
25
+ others = []
26
+ else
27
+ to_delete = input[:apps]
28
+ others = apps - to_delete
29
+ end
30
+
31
+ all_services = apps.collect(&:services).flatten
32
+ deleted_app_services = []
33
+
34
+ spaced(to_delete) do |app|
35
+ really = input[:all] || input[:really, app.name, :name]
36
+ next unless really
37
+
38
+ deleted_app_services += app.services
39
+
40
+ with_progress("Deleting #{c(app.name, :name)}") do
41
+ app.routes.collect(&:delete!) if input[:routes]
42
+ app.delete!
43
+ end
44
+ end
45
+
46
+ delete_orphaned_services(
47
+ find_orphaned_services(deleted_app_services, all_services))
48
+
49
+ to_delete
50
+ end
51
+
52
+ def find_orphaned_services(deleted, all)
53
+ orphaned = []
54
+
55
+ leftover = all.dup
56
+ deleted.each do |svc|
57
+ leftover.slice!(leftover.index(svc))
58
+ orphaned << svc unless leftover.include?(svc)
59
+ end
60
+
61
+ # clear out the relationships as the apps are now deleted
62
+ orphaned.each(&:invalidate!)
63
+ end
64
+
65
+ def delete_orphaned_services(orphans)
66
+ return if orphans.empty?
67
+
68
+ line unless quiet? || force?
69
+
70
+ orphans.select { |o| input[:delete_orphaned, o] }.each do |service|
71
+ # TODO: splat
72
+ invoke :delete_service, :service => service, :really => true
73
+ end
74
+ end
75
+
76
+ private
77
+
78
+ def ask_apps
79
+ apps = client.apps
80
+ fail "No applications." if apps.empty?
81
+
82
+ [ask("Delete which application?", :choices => apps.sort_by(&:name),
83
+ :display => proc(&:name))]
84
+ end
85
+
86
+ def ask_really(name, color)
87
+ ask("Really delete #{c(name, color)}?", :default => false)
88
+ end
89
+
90
+ def ask_delete_orphaned(service)
91
+ ask("Delete orphaned service #{c(service.name, :name)}?",
92
+ :default => false)
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,11 @@
1
+ require "cf/cli/app/base"
2
+
3
+ module CF::App
4
+ class Deprecated < Base
5
+ desc "DEPRECATED. Use 'push' instead."
6
+ input :app, :argument => :optional
7
+ def update
8
+ fail "The 'update' command is no longer needed; use 'push' instead."
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,78 @@
1
+ require "cf/cli/app/base"
2
+
3
+ module CF::App
4
+ class Env < Base
5
+ VALID_ENV_VAR = /^[a-zA-Za-z_][[:alnum:]_]*$/
6
+
7
+ desc "Show all environment variables set for an app"
8
+ group :apps, :info, :hidden => true
9
+ input :app, :desc => "Application to inspect the environment of",
10
+ :argument => true, :from_given => by_name(:app)
11
+ def env
12
+ app = input[:app]
13
+
14
+ vars =
15
+ with_progress("Getting env for #{c(app.name, :name)}") do |s|
16
+ app.env
17
+ end
18
+
19
+ line unless quiet?
20
+
21
+ vars.each do |name, val|
22
+ line "#{c(name, :name)}: #{val}"
23
+ end
24
+ end
25
+
26
+ desc "Set an environment variable"
27
+ group :apps, :info, :hidden => true
28
+ input :app, :desc => "Application to set the variable for",
29
+ :argument => true, :from_given => by_name(:app)
30
+ input :name, :desc => "Variable name", :argument => true
31
+ input :value, :desc => "Variable value", :argument => :optional
32
+ input :restart, :desc => "Restart app after updating?", :default => true
33
+ def set_env
34
+ app = input[:app]
35
+ name = input[:name]
36
+
37
+ if value = input[:value]
38
+ name = input[:name]
39
+ elsif name["="]
40
+ name, value = name.split("=")
41
+ end
42
+
43
+ unless name =~ VALID_ENV_VAR
44
+ fail "Invalid variable name; must match #{VALID_ENV_VAR.inspect}"
45
+ end
46
+
47
+ with_progress("Updating #{c(app.name, :name)}") do
48
+ app.env[name] = value
49
+ app.update!
50
+ end
51
+
52
+ if app.started? && input[:restart]
53
+ invoke :restart, :app => app
54
+ end
55
+ end
56
+
57
+
58
+ desc "Remove an environment variable"
59
+ group :apps, :info, :hidden => true
60
+ input :app, :desc => "Application to set the variable for",
61
+ :argument => true, :from_given => by_name(:app)
62
+ input :name, :desc => "Variable name", :argument => true
63
+ input :restart, :desc => "Restart app after updating?", :default => true
64
+ def unset_env
65
+ app = input[:app]
66
+ name = input[:name]
67
+
68
+ with_progress("Updating #{c(app.name, :name)}") do
69
+ app.env.delete(name)
70
+ app.update!
71
+ end
72
+
73
+ if app.started? && input[:restart]
74
+ invoke :restart, :app => app
75
+ end
76
+ end
77
+ end
78
+ end