jdc 0.1.2 → 0.2.0

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 (151) hide show
  1. data/LICENSE +1277 -24
  2. data/Rakefile +13 -0
  3. data/bin/jdc +12 -2
  4. data/lib/admin/README.md +15 -0
  5. data/lib/admin/curl.rb +60 -0
  6. data/lib/admin/guid.rb +89 -0
  7. data/lib/admin/plugin.rb +6 -0
  8. data/lib/admin/service_auth_token.rb +94 -0
  9. data/lib/admin/service_broker/add.rb +47 -0
  10. data/lib/admin/service_broker/service_brokers.rb +24 -0
  11. data/lib/admin/set_quota.rb +44 -0
  12. data/lib/console/README.md +8 -0
  13. data/lib/console/console.rb +187 -0
  14. data/lib/console/plugin.rb +33 -0
  15. data/lib/jdc/cli/app/app.rb +43 -0
  16. data/lib/jdc/cli/app/apps.rb +87 -0
  17. data/lib/jdc/cli/app/base.rb +72 -0
  18. data/lib/jdc/cli/app/delete.rb +95 -0
  19. data/lib/jdc/cli/app/deprecated.rb +11 -0
  20. data/lib/jdc/cli/app/env.rb +78 -0
  21. data/lib/jdc/cli/app/events.rb +45 -0
  22. data/lib/jdc/cli/app/files.rb +137 -0
  23. data/lib/jdc/cli/app/health.rb +26 -0
  24. data/lib/jdc/cli/app/instances.rb +53 -0
  25. data/lib/jdc/cli/app/logs.rb +76 -0
  26. data/lib/jdc/cli/app/push/create.rb +108 -0
  27. data/lib/jdc/cli/app/push/interactions.rb +86 -0
  28. data/lib/jdc/cli/app/push/sync.rb +57 -0
  29. data/lib/jdc/cli/app/push.rb +103 -0
  30. data/lib/jdc/cli/app/rename.rb +35 -0
  31. data/lib/jdc/cli/app/restart.rb +31 -0
  32. data/lib/jdc/cli/app/scale.rb +63 -0
  33. data/lib/jdc/cli/app/start.rb +161 -0
  34. data/lib/jdc/cli/app/stats.rb +67 -0
  35. data/lib/jdc/cli/app/stop.rb +27 -0
  36. data/lib/jdc/cli/domain/base.rb +9 -0
  37. data/lib/jdc/cli/domain/domains.rb +40 -0
  38. data/lib/jdc/cli/domain/map.rb +55 -0
  39. data/lib/jdc/cli/domain/unmap.rb +56 -0
  40. data/lib/jdc/cli/help.rb +15 -0
  41. data/lib/jdc/cli/interactive.rb +105 -0
  42. data/lib/jdc/cli/login_requirements.rb +15 -0
  43. data/lib/jdc/cli/organization/base.rb +14 -0
  44. data/lib/jdc/cli/organization/create.rb +37 -0
  45. data/lib/jdc/cli/organization/delete.rb +63 -0
  46. data/lib/jdc/cli/organization/org.rb +45 -0
  47. data/lib/jdc/cli/organization/orgs.rb +30 -0
  48. data/lib/jdc/cli/organization/rename.rb +37 -0
  49. data/lib/jdc/cli/populators/base.rb +16 -0
  50. data/lib/jdc/cli/populators/organization.rb +32 -0
  51. data/lib/jdc/cli/populators/populator_methods.rb +64 -0
  52. data/lib/jdc/cli/populators/space.rb +33 -0
  53. data/lib/jdc/cli/populators/target.rb +13 -0
  54. data/lib/jdc/cli/route/base.rb +9 -0
  55. data/lib/jdc/cli/route/delete.rb +28 -0
  56. data/lib/jdc/cli/route/map.rb +68 -0
  57. data/lib/jdc/cli/route/routes.rb +26 -0
  58. data/lib/jdc/cli/route/unmap.rb +56 -0
  59. data/lib/jdc/cli/service/base.rb +9 -0
  60. data/lib/jdc/cli/service/bind.rb +44 -0
  61. data/lib/jdc/cli/service/create.rb +159 -0
  62. data/lib/jdc/cli/service/delete.rb +83 -0
  63. data/lib/jdc/cli/service/rename.rb +36 -0
  64. data/lib/jdc/cli/service/service.rb +42 -0
  65. data/lib/jdc/cli/service/service_instance_helper.rb +99 -0
  66. data/lib/jdc/cli/service/services.rb +111 -0
  67. data/lib/jdc/cli/service/unbind.rb +37 -0
  68. data/lib/jdc/cli/space/base.rb +29 -0
  69. data/lib/jdc/cli/space/create.rb +67 -0
  70. data/lib/jdc/cli/space/delete.rb +56 -0
  71. data/lib/jdc/cli/space/rename.rb +38 -0
  72. data/lib/jdc/cli/space/space.rb +66 -0
  73. data/lib/jdc/cli/space/spaces.rb +57 -0
  74. data/lib/jdc/cli/space/switch.rb +19 -0
  75. data/lib/jdc/cli/start/base.rb +41 -0
  76. data/lib/jdc/cli/start/colors.rb +13 -0
  77. data/lib/jdc/cli/start/target.rb +50 -0
  78. data/lib/jdc/cli/start/target_prettifier.rb +17 -0
  79. data/lib/jdc/cli/start/targets.rb +16 -0
  80. data/lib/jdc/cli/user/base.rb +30 -0
  81. data/lib/jdc/cli/user/create.rb +52 -0
  82. data/lib/jdc/cli/user/passwd.rb +37 -0
  83. data/lib/jdc/cli/user/register.rb +43 -0
  84. data/lib/jdc/cli/user/users.rb +32 -0
  85. data/lib/jdc/cli.rb +544 -0
  86. data/lib/jdc/constants.rb +11 -0
  87. data/lib/jdc/errors.rb +19 -0
  88. data/lib/jdc/object_extensions.rb +15 -0
  89. data/lib/jdc/plugin.rb +56 -0
  90. data/lib/jdc/spacing.rb +89 -0
  91. data/lib/jdc/spec_helper.rb +1 -0
  92. data/lib/jdc/test_support.rb +6 -0
  93. data/lib/jdc/version.rb +3 -0
  94. data/lib/jdc.rb +15 -2
  95. data/lib/manifests/errors.rb +35 -0
  96. data/lib/manifests/loader/builder.rb +39 -0
  97. data/lib/manifests/loader/normalizer.rb +145 -0
  98. data/lib/manifests/loader/resolver.rb +79 -0
  99. data/lib/manifests/loader.rb +31 -0
  100. data/lib/manifests/manifests.rb +344 -0
  101. data/lib/manifests/plugin.rb +140 -0
  102. data/lib/micro/README.md +9 -0
  103. data/lib/micro/errors.rb +4 -0
  104. data/lib/{jdc → micro}/micro.rb +15 -15
  105. data/lib/micro/plugin.rb +197 -0
  106. data/lib/micro/switcher/base.rb +79 -0
  107. data/lib/{jdc/micro → micro}/switcher/darwin.rb +5 -3
  108. data/lib/{jdc/micro → micro}/switcher/dummy.rb +1 -1
  109. data/lib/micro/switcher/linux.rb +16 -0
  110. data/lib/{jdc/micro → micro}/switcher/windows.rb +5 -5
  111. data/lib/{jdc/micro → micro}/vmrun.rb +26 -19
  112. data/lib/tasks/gem_release.rake +42 -0
  113. data/lib/tunnel/README.md +29 -0
  114. data/{config → lib/tunnel/config}/clients.yml +2 -2
  115. data/lib/tunnel/helper-app/Gemfile +10 -0
  116. data/lib/tunnel/helper-app/Gemfile.lock +48 -0
  117. data/{caldecott_helper → lib/tunnel/helper-app}/server.rb +5 -5
  118. data/lib/tunnel/plugin.rb +183 -0
  119. data/lib/tunnel/tunnel.rb +295 -0
  120. metadata +319 -89
  121. data/README.md +0 -102
  122. data/config/micro/paths.yml +0 -22
  123. data/config/micro/refresh_ip.rb +0 -20
  124. data/lib/cli/commands/admin.rb +0 -58
  125. data/lib/cli/commands/apps.rb +0 -1129
  126. data/lib/cli/commands/base.rb +0 -228
  127. data/lib/cli/commands/manifest.rb +0 -56
  128. data/lib/cli/commands/micro.rb +0 -115
  129. data/lib/cli/commands/misc.rb +0 -126
  130. data/lib/cli/commands/services.rb +0 -178
  131. data/lib/cli/commands/user.rb +0 -14
  132. data/lib/cli/config.rb +0 -173
  133. data/lib/cli/console_helper.rb +0 -170
  134. data/lib/cli/core_ext.rb +0 -122
  135. data/lib/cli/errors.rb +0 -19
  136. data/lib/cli/frameworks.rb +0 -265
  137. data/lib/cli/manifest_helper.rb +0 -302
  138. data/lib/cli/runner.rb +0 -505
  139. data/lib/cli/services_helper.rb +0 -84
  140. data/lib/cli/tunnel_helper.rb +0 -332
  141. data/lib/cli/usage.rb +0 -86
  142. data/lib/cli/version.rb +0 -7
  143. data/lib/cli/zip_util.rb +0 -77
  144. data/lib/cli.rb +0 -53
  145. data/lib/jdc/client.rb +0 -457
  146. data/lib/jdc/const.rb +0 -25
  147. data/lib/jdc/micro/switcher/base.rb +0 -97
  148. data/lib/jdc/micro/switcher/linux.rb +0 -16
  149. data/lib/jdc/signature/version.rb +0 -27
  150. data/lib/jdc/signer.rb +0 -13
  151. data/lib/jdc/timer.rb +0 -12
@@ -0,0 +1,87 @@
1
+ require "jdc/cli/app/base"
2
+
3
+ module JDC::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 :url, :desc => "Filter by url regexp"
12
+ input :full, :desc => "Verbose output format", :default => false
13
+ def apps
14
+ if space = input[:space]
15
+ begin
16
+ space.summarize!
17
+ rescue JFoundry::APIError
18
+ end
19
+
20
+ apps =
21
+ with_progress("Getting applications in #{c(space.name, :name)}") do
22
+ space.apps
23
+ end
24
+ else
25
+ apps =
26
+ with_progress("Getting applications") do
27
+ client.apps(:depth => 2)
28
+ end
29
+ end
30
+
31
+ line unless quiet?
32
+
33
+ if apps.empty? and !quiet?
34
+ line "No applications."
35
+ return
36
+ end
37
+
38
+ apps.reject! do |a|
39
+ !app_matches?(a, input)
40
+ end
41
+
42
+ apps = apps.sort_by(&:name)
43
+
44
+ if input[:full]
45
+ spaced(apps) do |a|
46
+ invoke :app, :app => a
47
+ end
48
+ elsif quiet?
49
+ apps.each do |a|
50
+ line a.name
51
+ end
52
+ else
53
+ display_apps_table(apps)
54
+ end
55
+ end
56
+
57
+ def display_apps_table(apps)
58
+ table(
59
+ ["name", "status", "usage", "url"],
60
+ apps.collect { |a|
61
+ [ c(a.name, :name),
62
+ app_status(a),
63
+ "#{a.total_instances} x #{human_mb(a.memory)}",
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
+
75
+ def app_matches?(a, options)
76
+ if name = options[:name]
77
+ return false if a.name !~ /#{name}/
78
+ end
79
+
80
+ if url = options[:url]
81
+ return false if a.urls.none? { |u| u =~ /#{url}/ }
82
+ end
83
+
84
+ true
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,72 @@
1
+ require "jdc/cli"
2
+
3
+ module JDC
4
+ module App
5
+ class Base < CLI
6
+ include LoginRequirements
7
+
8
+ # choose the right color for app/instance state
9
+ def state_color(s)
10
+ case s
11
+ when "STARTING"
12
+ :neutral
13
+ when "STARTED", "RUNNING"
14
+ :good
15
+ when "DOWN"
16
+ :bad
17
+ when "FLAPPING"
18
+ :error
19
+ when "N/A"
20
+ :unknown
21
+ else
22
+ :warning
23
+ end
24
+ end
25
+
26
+ def app_status(a)
27
+ health = a.health
28
+
29
+ if a.debug_mode == "suspend" && health == "0%"
30
+ c("suspended", :neutral)
31
+ else
32
+ c(health.downcase, state_color(health))
33
+ end
34
+ end
35
+
36
+ def memory_choices
37
+ [128, 256, 512, 1024].map{|n| human_mb(n)}
38
+ end
39
+
40
+ def human_mb(num)
41
+ human_size(num * 1024 * 1024, 0)
42
+ end
43
+
44
+ def human_size(num, precision = 1)
45
+ sizes = %w(G M K)
46
+ sizes.each.with_index do |suf, i|
47
+ pow = sizes.size - i
48
+ unit = 1024.0 ** pow
49
+ if num >= unit
50
+ return format("%.#{precision}f%s", num / unit, suf)
51
+ end
52
+ end
53
+
54
+ format("%.#{precision}fB", num)
55
+ end
56
+
57
+ def megabytes(str)
58
+ if str =~ /T$/i
59
+ str.to_i * 1024 * 1024
60
+ elsif str =~ /G$/i
61
+ str.to_i * 1024
62
+ elsif str =~ /M$/i
63
+ str.to_i
64
+ elsif str =~ /K$/i
65
+ str.to_i / 1024
66
+ else # assume megabytes
67
+ str.to_i
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,95 @@
1
+ require "set"
2
+
3
+ require "jdc/cli/app/base"
4
+
5
+ module JDC::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 "jdc/cli/app/base"
2
+
3
+ module JDC::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 "jdc/cli/app/base"
2
+
3
+ module JDC::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
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
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
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
@@ -0,0 +1,45 @@
1
+ require "jdc/cli/app/base"
2
+
3
+ module JDC::App
4
+ class Events < Base
5
+ desc "Display application events"
6
+ group :apps, :info
7
+ input :app, :desc => "Application to get the events for",
8
+ :argument => true, :from_given => by_name(:app)
9
+ def events
10
+ app = input[:app]
11
+
12
+ events =
13
+ with_progress("Getting events for #{c(app.name, :name)}") do
14
+ format_events(app.events)
15
+ end
16
+
17
+ line unless quiet?
18
+ table(%w{time instance\ index description exit\ status}, events)
19
+
20
+ end
21
+
22
+ private
23
+
24
+ def sort_events(events)
25
+ events.sort_by { |event| DateTime.parse(event.timestamp) }
26
+ end
27
+
28
+ def format_events(events)
29
+ sort_events(events).map do |event|
30
+ [event.timestamp,
31
+ c(event.instance_index.to_s, :warning),
32
+ event.exit_description,
33
+ format_status(event)]
34
+ end
35
+ end
36
+
37
+ def format_status(event)
38
+ if event.exit_status == 0
39
+ c("Success (#{event.exit_status})", :good)
40
+ else
41
+ c("Failure (#{event.exit_status})", :bad)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,137 @@
1
+ require "thread"
2
+ require "jdc/cli/app/base"
3
+
4
+ module JDC::App
5
+ class Files < Base
6
+ desc "Print out an app's file contents"
7
+ group :apps, :info
8
+ input :app, :desc => "Application to inspect the files of",
9
+ :argument => true, :from_given => by_name(:app)
10
+ input :path, :desc => "Path of file to read", :argument => :optional,
11
+ :default => "/"
12
+ def file
13
+ app = input[:app]
14
+ path = input[:path]
15
+
16
+ file =
17
+ with_progress("Getting file contents") do
18
+ app.file(*path.split("/"))
19
+ end
20
+
21
+ if quiet?
22
+ print file
23
+ else
24
+ line
25
+
26
+ file.split("\n").each do |l|
27
+ line l
28
+ end
29
+ end
30
+ rescue JFoundry::NotFound
31
+ fail "Invalid path #{b(path)} for app #{b(app.name)}"
32
+ rescue JFoundry::FileError => e
33
+ fail e.description
34
+ end
35
+
36
+ desc "Examine an app's files"
37
+ group :apps, :info
38
+ input :app, :desc => "Application to inspect the files of",
39
+ :argument => true, :from_given => by_name(:app)
40
+ input :path, :desc => "Path of directory to list", :argument => :optional,
41
+ :default => "/"
42
+ def files
43
+ app = input[:app]
44
+ path = input[:path]
45
+
46
+ if quiet?
47
+ files =
48
+ with_progress("Getting file listing") do
49
+ app.files(*path.split("/"))
50
+ end
51
+
52
+ files.each do |file|
53
+ line file.join("/")
54
+ end
55
+ else
56
+ invoke :file, :app => app, :path => path
57
+ end
58
+ rescue JFoundry::NotFound
59
+ fail "Invalid path #{b(path)} for app #{b(app.name)}"
60
+ rescue JFoundry::FileError => e
61
+ fail e.description
62
+ end
63
+
64
+ desc "Stream an app's file contents"
65
+ group :apps, :info
66
+ input :app, :desc => "Application to inspect the files of",
67
+ :argument => true, :from_given => by_name(:app)
68
+ input :path, :desc => "Path of file to stream", :argument => :optional
69
+ def tail
70
+ app = input[:app]
71
+
72
+ lines = Queue.new
73
+ max_len = 0
74
+
75
+ if path = input[:path]
76
+ max_len = path.size
77
+ app.instances.each do |i|
78
+ Thread.new do
79
+ stream_path(lines, i, path.split("/"))
80
+ end
81
+ end
82
+ else
83
+ app.instances.each do |i|
84
+ i.files("logs").each do |path|
85
+ len = path.join("/").size
86
+ max_len = len if len > max_len
87
+
88
+ Thread.new do
89
+ stream_path(lines, i, path)
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ while line = lines.pop
96
+ instance, path, log = line
97
+
98
+ unless log.end_with?("\n")
99
+ log += i("%") if color?
100
+ log += "\n"
101
+ end
102
+
103
+ print "\##{c(instance.id, :instance)} "
104
+ print "#{c(path.join("/").ljust(max_len), :name)} "
105
+ print log
106
+ end
107
+ rescue JFoundry::NotFound
108
+ fail "Invalid path #{b(path)} for app #{b(app.name)}"
109
+ rescue JFoundry::FileError => e
110
+ fail e.description
111
+ end
112
+
113
+ def stream_path(lines, instance, path)
114
+ if verbose?
115
+ lines << [instance, path, c("streaming...", :good) + "\n"]
116
+ end
117
+
118
+ instance.stream_file(*path) do |contents|
119
+ contents.each_line do |line|
120
+ lines << [instance, path, line]
121
+ end
122
+ end
123
+
124
+ lines << [instance, path, c("end of file", :bad) + "\n"]
125
+ rescue Timeout::Error
126
+ if verbose?
127
+ lines << [
128
+ instance,
129
+ path,
130
+ c("timed out; reconnecting...", :bad) + "\n"
131
+ ]
132
+ end
133
+
134
+ retry
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,26 @@
1
+ require "jdc/cli/app/base"
2
+
3
+ module JDC::App
4
+ class Health < Base
5
+ desc "Get application health"
6
+ group :apps, :info
7
+ input :apps, :desc => "Show the health information for one or more applications", :argument => :splat,
8
+ :singular => :app, :from_given => by_name(:app)
9
+ def health
10
+ apps = input[:apps]
11
+ fail "No applications given." if apps.empty?
12
+
13
+ health =
14
+ with_progress("Getting health status") do
15
+ apps.collect { |a| [a, app_status(a)] }
16
+ end
17
+
18
+ line unless quiet?
19
+
20
+ spaced(health) do |app, status|
21
+ start_line "#{c(app.name, :name)}: " unless quiet?
22
+ puts status
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,53 @@
1
+ require "jdc/cli/app/base"
2
+
3
+ module JDC::App
4
+ class Instances < Base
5
+ desc "List an app's instances"
6
+ group :apps, :info
7
+ input :apps, :desc => "Applications whose instances to list",
8
+ :argument => :splat, :singular => :app,
9
+ :from_given => by_name(:app)
10
+ def instances
11
+ apps = input[:apps]
12
+ fail "No applications given." if apps.empty?
13
+
14
+ spaced(apps) do |app|
15
+ instances =
16
+ with_progress("Getting instances for #{c(app.name, :name)}") do
17
+ app.instances
18
+ end
19
+
20
+ line unless quiet?
21
+
22
+ spaced(instances.sort { |a, b| a.id.to_i <=> b.id.to_i }) do |i|
23
+ if quiet?
24
+ line i.id
25
+ else
26
+ display_instance(i)
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ private
33
+
34
+ def display_instance(i)
35
+ start_line "instance #{c("\##{i.id}", :instance)}: "
36
+ puts "#{b(c(i.state.downcase, state_color(i.state)))}"
37
+
38
+ indented do
39
+ if s = i.since
40
+ line "started: #{c(s.strftime("%F %r"), :neutral)}"
41
+ end
42
+
43
+ if d = i.debugger
44
+ line "debugger: port #{b(d[:port])} at #{b(d[:ip])}"
45
+ end
46
+
47
+ if c = i.console
48
+ line "console: port #{b(c[:port])} at #{b(c[:ip])}"
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,76 @@
1
+ require "jdc/cli/app/base"
2
+
3
+ module JDC::App
4
+ class Logs < Base
5
+ desc "Print out an app's logs"
6
+ group :apps, :info
7
+ input :app, :desc => "Application to get the logs of", :argument => true,
8
+ :from_given => by_name(:app)
9
+ input :instance, :desc => "Instance of application to get the logs of",
10
+ :default => "0"
11
+ input :all, :desc => "Get logs for every instance", :default => false
12
+ def logs
13
+ app = input[:app]
14
+
15
+ instances =
16
+ if input[:all] || input[:instance] == "all"
17
+ app.instances
18
+ else
19
+ app.instances.select { |i| i.id == input[:instance] }
20
+ end
21
+
22
+ if instances.empty?
23
+ if input[:all]
24
+ fail "No instances found."
25
+ else
26
+ fail "Instance #{app.name} \##{input[:instance]} not found."
27
+ end
28
+ end
29
+
30
+ spaced(instances) do |i|
31
+ show_instance_logs(app, i)
32
+ end
33
+ end
34
+
35
+ desc "Print out the logs for an app's crashed instances"
36
+ group :apps, :info
37
+ input :app, :desc => "Application to get the logs of", :argument => true,
38
+ :from_given => by_name(:app)
39
+ def crashlogs
40
+ app = input[:app]
41
+
42
+ crashes = app.crashes
43
+
44
+ fail "No crashed instances found." if crashes.empty?
45
+
46
+ most_recent = crashes.sort_by(&:since).last
47
+ show_instance_logs(app, most_recent)
48
+ end
49
+
50
+ def show_instance_logs(app, i)
51
+ return unless i.id
52
+
53
+ logs =
54
+ with_progress(
55
+ "Getting logs for #{c(app.name, :name)} " +
56
+ c("\##{i.id}", :instance)) do
57
+ i.files("logs")
58
+ end
59
+
60
+ line unless quiet?
61
+
62
+ spaced(logs) do |log|
63
+ begin
64
+ body =
65
+ with_progress("Reading " + b(log.join("/"))) do |s|
66
+ i.file(*log)
67
+ end
68
+
69
+ lines body
70
+ line unless body.empty?
71
+ rescue JFoundry::NotFound
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end