sunshine 1.0.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/History.txt +237 -0
  2. data/Manifest.txt +70 -0
  3. data/README.txt +277 -0
  4. data/Rakefile +46 -0
  5. data/bin/sunshine +5 -0
  6. data/examples/deploy.rb +61 -0
  7. data/examples/deploy_tasks.rake +112 -0
  8. data/examples/standalone_deploy.rb +31 -0
  9. data/lib/commands/add.rb +96 -0
  10. data/lib/commands/default.rb +169 -0
  11. data/lib/commands/list.rb +322 -0
  12. data/lib/commands/restart.rb +62 -0
  13. data/lib/commands/rm.rb +83 -0
  14. data/lib/commands/run.rb +151 -0
  15. data/lib/commands/start.rb +72 -0
  16. data/lib/commands/stop.rb +61 -0
  17. data/lib/sunshine/app.rb +876 -0
  18. data/lib/sunshine/binder.rb +70 -0
  19. data/lib/sunshine/crontab.rb +143 -0
  20. data/lib/sunshine/daemon.rb +380 -0
  21. data/lib/sunshine/daemons/ar_sendmail.rb +28 -0
  22. data/lib/sunshine/daemons/delayed_job.rb +30 -0
  23. data/lib/sunshine/daemons/nginx.rb +104 -0
  24. data/lib/sunshine/daemons/rainbows.rb +35 -0
  25. data/lib/sunshine/daemons/server.rb +66 -0
  26. data/lib/sunshine/daemons/unicorn.rb +26 -0
  27. data/lib/sunshine/dependencies.rb +103 -0
  28. data/lib/sunshine/dependency_lib.rb +200 -0
  29. data/lib/sunshine/exceptions.rb +54 -0
  30. data/lib/sunshine/healthcheck.rb +83 -0
  31. data/lib/sunshine/output.rb +131 -0
  32. data/lib/sunshine/package_managers/apt.rb +48 -0
  33. data/lib/sunshine/package_managers/dependency.rb +349 -0
  34. data/lib/sunshine/package_managers/gem.rb +54 -0
  35. data/lib/sunshine/package_managers/yum.rb +62 -0
  36. data/lib/sunshine/remote_shell.rb +241 -0
  37. data/lib/sunshine/repo.rb +128 -0
  38. data/lib/sunshine/repos/git_repo.rb +122 -0
  39. data/lib/sunshine/repos/rsync_repo.rb +29 -0
  40. data/lib/sunshine/repos/svn_repo.rb +78 -0
  41. data/lib/sunshine/server_app.rb +554 -0
  42. data/lib/sunshine/shell.rb +384 -0
  43. data/lib/sunshine.rb +391 -0
  44. data/templates/logrotate/logrotate.conf.erb +11 -0
  45. data/templates/nginx/nginx.conf.erb +109 -0
  46. data/templates/nginx/nginx_optimize.conf +23 -0
  47. data/templates/nginx/nginx_proxy.conf +13 -0
  48. data/templates/rainbows/rainbows.conf.erb +18 -0
  49. data/templates/tasks/sunshine.rake +114 -0
  50. data/templates/unicorn/unicorn.conf.erb +6 -0
  51. data/test/fixtures/app_configs/test_app.yml +11 -0
  52. data/test/fixtures/sunshine_test/test_upload +0 -0
  53. data/test/mocks/mock_object.rb +179 -0
  54. data/test/mocks/mock_open4.rb +117 -0
  55. data/test/test_helper.rb +188 -0
  56. data/test/unit/test_app.rb +489 -0
  57. data/test/unit/test_binder.rb +20 -0
  58. data/test/unit/test_crontab.rb +128 -0
  59. data/test/unit/test_git_repo.rb +26 -0
  60. data/test/unit/test_healthcheck.rb +70 -0
  61. data/test/unit/test_nginx.rb +107 -0
  62. data/test/unit/test_rainbows.rb +26 -0
  63. data/test/unit/test_remote_shell.rb +102 -0
  64. data/test/unit/test_repo.rb +42 -0
  65. data/test/unit/test_server.rb +324 -0
  66. data/test/unit/test_server_app.rb +425 -0
  67. data/test/unit/test_shell.rb +97 -0
  68. data/test/unit/test_sunshine.rb +157 -0
  69. data/test/unit/test_svn_repo.rb +55 -0
  70. data/test/unit/test_unicorn.rb +22 -0
  71. metadata +217 -0
@@ -0,0 +1,104 @@
1
+ module Sunshine
2
+
3
+ ##
4
+ # Simple server wrapper for nginx setup and control.
5
+
6
+ class Nginx < Server
7
+
8
+ def initialize app, options={}
9
+ super
10
+
11
+ @sudo ||= @port < 1024
12
+
13
+ @dep_name = use_passenger? ? 'passenger-nginx' : 'nginx'
14
+ end
15
+
16
+
17
+ def start_cmd
18
+ "#{@bin} -c #{self.config_file_path}"
19
+ end
20
+
21
+
22
+ def stop_cmd
23
+ cmd = "test -f #{@pid} && kill -QUIT $(cat #{@pid})"+
24
+ " || echo 'No #{@name} process to stop for #{@app.name}';"
25
+ cmd << "sleep 2 ; rm -f #{@pid};"
26
+ end
27
+
28
+
29
+ def setup
30
+ super do |server_app, binder|
31
+
32
+ binder.forward :use_passenger?
33
+
34
+ binder.set :passenger_root do
35
+ passenger_root server_app.shell
36
+ end
37
+
38
+ binder.set :nginx_conf_path do
39
+ nginx_bin = server_app.shell.call "which nginx"
40
+ File.join File.dirname(nginx_bin), '..', 'conf'
41
+ end
42
+
43
+ yield(server_app, binder) if block_given?
44
+ end
45
+ end
46
+
47
+
48
+ ##
49
+ # Check if passenger is required to run the application.
50
+ # Returns true if the server's target is a Sunshine::App
51
+
52
+ def use_passenger?
53
+ Sunshine::App === @target
54
+ end
55
+
56
+
57
+ ##
58
+ # Gets the root of the installer passenger gem.
59
+
60
+ def passenger_root shell
61
+ str = shell.call "gem list passenger -d"
62
+ version = $1 if str =~ /passenger\s\((.*)\)$/
63
+ gempath = $1 if str =~ /Installed\sat:\s(.*)$/
64
+
65
+ return unless version && gempath
66
+
67
+ File.join(gempath, "gems/passenger-#{version}")
68
+ end
69
+
70
+
71
+ ##
72
+ # Run passenger installation for nginx
73
+
74
+ def setup_passenger server_app
75
+ server_app.install_deps 'passenger'
76
+
77
+ server_app.shell.call \
78
+ 'passenger-install-nginx-module --auto --auto-download',
79
+ :sudo => true do |stream, data, inn|
80
+
81
+ if data =~ /Please specify a prefix directory \[(.*)\]:/
82
+
83
+ dir = $1
84
+ inn.puts dir
85
+
86
+ required_dirs = [
87
+ File.join(dir, 'fastcgi_temp'),
88
+ File.join(dir, 'proxy_temp')
89
+ ]
90
+
91
+ server_app.shell.call \
92
+ "mkdir -p #{required_dirs.join(" ")}", :sudo => true
93
+
94
+ error_log = File.join(dir, "logs/error.log")
95
+
96
+ server_app.shell.call \
97
+ "touch #{error_log} && chmod a+rw #{error_log}", :sudo => true
98
+
99
+ server_app.add_shell_paths File.join(dir, 'sbin')
100
+ end
101
+ end
102
+ end
103
+ end
104
+ end
@@ -0,0 +1,35 @@
1
+ module Sunshine
2
+
3
+ ##
4
+ # Simple server wrapper for Rainbows setup and control.
5
+
6
+ class Rainbows < Unicorn
7
+
8
+ attr_reader :concurrency
9
+
10
+ ##
11
+ # Assign and/or use a concurrency model. Supports all Rainbows concurrency
12
+ # models; defaults to :ThreadSpawn
13
+ # Allows options:
14
+ # :model:: :ConcurrModel - concurrency model. Defaults to ThreadSpawn
15
+ # :connections:: int - the number of worker connections to use.
16
+ # :timeout:: seconds - the keepalive timeout. zero disables keepalives.
17
+
18
+ def use_concurrency options=nil
19
+ @concurrency ||= {:model => :ThreadSpawn}
20
+ @concurrency.merge! options
21
+ end
22
+
23
+
24
+ ##
25
+ # Setup Rainbows specific bindings before building its config.
26
+
27
+ def setup
28
+ super do |server_app, binder|
29
+ binder.forward :concurrency
30
+
31
+ yield(server_app, binder) if block_given?
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,66 @@
1
+ module Sunshine
2
+
3
+ ##
4
+ # An abstract class to wrap simple server software setup and start/stop.
5
+ #
6
+ # Child classes are expected to at least provide a start and stop bash script
7
+ # by either overloading the start_cmd and stop_cmd methods, or by setting
8
+ # @start_cmd and @stop_cmd. A restart_cmd method or @restart_cmd attribute
9
+ # may also be specified if restart requires more functionality than simply
10
+ # calling start_cmd && stop_cmd.
11
+
12
+ class Server < Daemon
13
+
14
+ def self.binder_methods
15
+ [:server_name, :port].concat super
16
+ end
17
+
18
+
19
+ attr_reader :server_name, :port
20
+
21
+
22
+ # Server objects need only an App object to be instantiated.
23
+ # All Daemon init options are supported plus the following:
24
+ #
25
+ # :port:: port_num - the port to run the server on
26
+ # defaults to 80
27
+ #
28
+ # :server_name:: myserver.com - host name used by server
29
+ # defaults to nil
30
+ #
31
+ # By default, servers also assign the option :role => :web.
32
+
33
+ def initialize app, options={}
34
+ options[:role] ||= :web
35
+
36
+ super app, options
37
+
38
+ @port = options[:port] || 80
39
+ @server_name = options[:server_name]
40
+ end
41
+
42
+
43
+ private
44
+
45
+ def config_binding shell
46
+ binder = super
47
+
48
+ binder.set :server_name, (@server_name || shell.host)
49
+
50
+ binder
51
+ end
52
+
53
+
54
+ def register_after_user_script
55
+ super
56
+
57
+ @app.after_user_script do |app|
58
+ next unless @port
59
+
60
+ each_server_app do |sa|
61
+ sa.info[:ports][@pid] = @port
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,26 @@
1
+ module Sunshine
2
+
3
+ ##
4
+ # Simple server wrapper for Unicorn setup and control.
5
+
6
+ class Unicorn < Server
7
+
8
+ def initialize app, options={}
9
+ super
10
+ @timeout = options[:timeout] || 3.0
11
+ end
12
+
13
+
14
+ def start_cmd
15
+ "cd #{@app.current_path} && #{@bin} -D -E"+
16
+ " #{@app.deploy_env} -p #{@port} -c #{self.config_file_path};"
17
+ end
18
+
19
+
20
+ def stop_cmd
21
+ "test -f #{@pid} && kill -QUIT $(cat #{@pid})"+
22
+ " || echo 'No #{@name} process to stop for #{@app.name}';"+
23
+ "sleep 2; rm -f #{@pid};"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,103 @@
1
+ ##
2
+ # Defines Sunshine deploy server dependencies.
3
+
4
+ #class Sunshine::Dependencies < Settler
5
+ Sunshine.dependencies.instance_eval do
6
+
7
+ yum 'tpkg'
8
+
9
+ apt 'svn', :pkg => 'subversion'
10
+ yum 'svn', :pkg => 'subversion'
11
+
12
+ apt 'git', :pkg => 'git-core'
13
+ yum 'git', :pkg => 'git-core'
14
+
15
+ apt 'nginx'
16
+ yum 'nginx'
17
+
18
+ apt 'logrotate'
19
+ yum 'logrotate'
20
+
21
+ apt 'ruby', :pkg => 'ruby-full'
22
+ yum 'ruby'
23
+
24
+ apt 'ruby-devel', :pkg => 'ruby-dev'
25
+ yum 'ruby-devel'
26
+
27
+ apt 'irb'
28
+ yum 'irb', :pkg => 'ruby-irb'
29
+
30
+ apt 'rubygems', :version => '1.3.5' do
31
+ requires 'ruby', 'ruby-devel'
32
+ end
33
+ yum 'rubygems', :version => '1.3.5' do
34
+ requires 'ruby', 'ruby-devel'
35
+ end
36
+
37
+ apt 'logrotate'
38
+ yum 'logrotate'
39
+
40
+ apt 'curl-devel', :pkg => 'libcurl-dev'
41
+ yum 'curl-devel'
42
+
43
+ apt 'libxml2-devel', :pkg => 'libxml2-dev'
44
+ yum 'libxml2-devel'
45
+
46
+ apt 'libxslt-devel', :pkg => 'libxslt-dev'
47
+ yum 'libxslt-devel'
48
+
49
+ apt 'sqlite', :pkg => 'sqlite3'
50
+ yum 'sqlite'
51
+
52
+ apt 'sqlite-devel', :pkg => 'libsqlite3-dev'
53
+ yum 'sqlite-devel'
54
+
55
+
56
+ # Define gems used by Sunshine
57
+
58
+ gem 'bundler', :version => ">=0.9"
59
+
60
+ gem 'isolate', :version => ">=1.3.0"
61
+
62
+ gem 'rake', :version => ">=0.8"
63
+
64
+ gem 'passenger-nginx', :pkg => 'passenger' do
65
+ install do |shell, sudo|
66
+
67
+ shell.call "gem install passenger --no-ri --no-rdoc", :sudo => sudo
68
+
69
+ shell.call 'passenger-install-nginx-module --auto --auto-download',
70
+ :sudo => true do |stream, data, inn|
71
+
72
+ if data =~ /Please specify a prefix directory \[(.*)\]:/
73
+
74
+ dir = $1
75
+ inn.puts dir
76
+
77
+ required_dirs = [
78
+ File.join(dir, 'fastcgi_temp'),
79
+ File.join(dir, 'proxy_temp')
80
+ ]
81
+
82
+ shell.call "mkdir -p #{required_dirs.join(" ")}", :sudo => true
83
+
84
+ err_log = File.join(dir, "logs/error.log")
85
+ shell.call "touch #{err_log} && chmod a+rw #{err_log}", :sudo => true
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ gem 'geminstaller', :version => ">=0.5"
92
+
93
+ gem 'unicorn', :version => ">=0.9"
94
+
95
+ gem 'rainbows', :version => ">=0.90.2"
96
+
97
+ gem 'ar_mailer', :version => ">=1.5.0"
98
+
99
+ gem 'haml'
100
+
101
+ gem 'daemons'
102
+
103
+ end
@@ -0,0 +1,200 @@
1
+ module Sunshine
2
+
3
+ ##
4
+ # DependencyLib is a simple class for building and handling depenedencies.
5
+ # A dependency tree can be defined by inheriting the DependencyLib class, and
6
+ # dependencies can be defined through dependency instantiation methods:
7
+ #
8
+ # dependency_lib.instance_eval do
9
+ #
10
+ # yum 'ruby', :pkg => 'ruby-devel'
11
+ #
12
+ # yum 'rubygems', :requires => 'ruby'
13
+ #
14
+ # gem 'rdoc', :requires => 'rubygems'
15
+ #
16
+ # gem 'ri', :requires => 'rubygems'
17
+ #
18
+ # end
19
+ #
20
+ # Calling the install for rdoc will then check and install all of its parent
21
+ # dependencies as well:
22
+ #
23
+ # dependency_lib.install 'rdoc', 'ri'
24
+ #
25
+ # Dependencies may also be generic and/or have custom bash scripts
26
+ # for installs, uninstalls, and presence checks:
27
+ #
28
+ # dependency 'custom' do
29
+ # requires 'yum', 'ruby'
30
+ # install 'sudo yum install custom'
31
+ # uninstall 'sudo yum remove custom'
32
+ # check 'yum list installed custom'
33
+ # end
34
+ #
35
+ # See the Dependency class for more information.
36
+
37
+ class DependencyLib
38
+
39
+ class MissingDependency < Exception; end
40
+
41
+ ##
42
+ # Array of all dependency classes. Appended to automatically when
43
+ # DependencyLib::Dependency is inherited.
44
+
45
+ def self.dependency_types
46
+ @dependency_types ||= []
47
+ end
48
+
49
+
50
+ attr_reader :dependencies
51
+
52
+ def initialize
53
+ @dependencies = Hash.new
54
+ end
55
+
56
+
57
+ ##
58
+ # Returns a dependency hash by type:
59
+ # DependencyLib['name'] #=> {:yum => <Yum...>, :apt => <Apt...>, ...}
60
+
61
+ def [](key)
62
+ @dependencies[key]
63
+ end
64
+
65
+
66
+ ##
67
+ # Add a dependency to the dependencies hash.
68
+
69
+ def add dep
70
+ (@dependencies[dep.name] ||= []).unshift dep
71
+ end
72
+
73
+
74
+ ##
75
+ # Checks for the existance of a dependency by name
76
+
77
+ def exist? key
78
+ @dependencies.has_key? key
79
+ end
80
+
81
+
82
+ ##
83
+ # Get a dependency object by name. Supports passing :type => :pkg_manager
84
+ # if dependencies with the same name but different package managers exist:
85
+ # dependencies.get 'daemon', :type => Gem
86
+ # #=> <Gem @name="daemon"...>
87
+ #
88
+ # For an 'nginx' dependency defined for both apt and yum, where the yum
89
+ # dependency object was added to the tree last. Returns nil if
90
+ # no matching dependency type is found:
91
+ # dependencies.get 'nginx'
92
+ # #=> <Yum @name="nginx"...>
93
+ #
94
+ # dependencies.get 'nginx', :type => Apt
95
+ # #=> <Apt @name="nginx"...>
96
+ #
97
+ # Use the :prefer option if a certain dependency type is prefered but
98
+ # will fall back to whatever first dependency is available:
99
+ # dependencies.yum 'my_dep'
100
+ # dependencies.get 'my_dep', :prefer => Apt
101
+ # #=> <Yum @name="my_dep"...>
102
+ #
103
+ # Both the :type and the :prefer options support passing arrays to search
104
+ # from best to least acceptable candidate:
105
+ # dependencies.yum 'my_dep'
106
+ # dependencies.apt 'my_dep'
107
+ # dependencies.get 'my_dep', :type => [Tpkg, Yum]
108
+ # #=> <Yum @name="my_dep"...>
109
+
110
+ def get name, options={}
111
+ return unless exist? name
112
+
113
+ deps = @dependencies[name]
114
+ dep_types = [*(options[:type] || options[:prefer])].compact
115
+
116
+ return deps.first if dep_types.empty?
117
+
118
+ dep_types.each do |dep_type|
119
+ deps.each do |dep|
120
+ return dep if dep_type === dep
121
+ end
122
+ end
123
+
124
+ return deps.first unless options[:type]
125
+ end
126
+
127
+
128
+ ##
129
+ # Install one or more dependencies:
130
+ #
131
+ # dependencies.install 'dep1', 'dep2', options_hash
132
+ #
133
+ # See DependencyLib#get and Dependency#install! for supported options.
134
+ #
135
+ # Note: If a Dependency object is passed and the :type option is set,
136
+ # DependencyLib will attempt to find and install a dependency of class :type
137
+ # with the same name as the passed Dependency object:
138
+ # my_dep = dependencies.yum "my_dep_yum_only"
139
+ # dependencies.install my_dep, :type => Apt
140
+ # #=> "No dependency 'my_dep' [Sunshine::Apt]"
141
+
142
+ def install(*deps)
143
+ send_each(:install!, *deps)
144
+ end
145
+
146
+
147
+ ##
148
+ # Uninstall one or more dependencies:
149
+ #
150
+ # dependencies.uninstall 'dep1', 'dep2', options_hash
151
+ #
152
+ # See DependencyLib#get and Dependency#uninstall! for supported options.
153
+
154
+ def uninstall(*deps)
155
+ send_each(:uninstall!, *deps)
156
+ end
157
+
158
+
159
+ ##
160
+ # Get and call method on each dependency passed
161
+
162
+ def send_each(method, *deps)
163
+ options = Hash === deps.last ? deps.delete_at(-1).dup : {}
164
+
165
+ #if options[:call].respond_to? :pkg_manager
166
+ # options[:prefer] ||= options[:call].pkg_manager
167
+ #end
168
+
169
+ deps.each do |dep_name|
170
+ dep = if Dependency === dep_name
171
+ if options[:type] && !(options[:type] === dep_name)
172
+ get(dep_name.name, options)
173
+ else
174
+ dep_name
175
+ end
176
+ else
177
+ get(dep_name, options)
178
+ end
179
+
180
+ raise MissingDependency,
181
+ "No dependency '#{dep_name}' [#{options[:type] || "any"}]" if !dep
182
+
183
+ # Remove :type so dependencies of other types than dep can be installed
184
+ options.delete(:type)
185
+
186
+ dep.send method, options
187
+ end
188
+ end
189
+
190
+
191
+ ##
192
+ # Define if sudo should be used
193
+
194
+ def self.sudo= value
195
+ dependency_types.each do |dep_class|
196
+ dep_class.sudo = value
197
+ end
198
+ end
199
+ end
200
+ end
@@ -0,0 +1,54 @@
1
+ module Sunshine
2
+
3
+ ##
4
+ # A standard sunshine exception
5
+ class Exception < StandardError
6
+ def initialize input=nil, message=nil
7
+ if ::Exception === input
8
+ message = [message, input.message].compact.join(": ")
9
+ super(message)
10
+ self.set_backtrace(input.backtrace)
11
+ else
12
+ super(input)
13
+ end
14
+ end
15
+ end
16
+
17
+
18
+ ##
19
+ # An error occurred when attempting to run a command on the local system
20
+ class CmdError < Exception; end
21
+
22
+
23
+ ##
24
+ # An ssh call returned a non-zero exit code
25
+ class SSHCmdError < CmdError
26
+ attr_reader :shell
27
+ def initialize message=nil, shell=nil
28
+ @shell = shell
29
+ super(message)
30
+ end
31
+ end
32
+
33
+
34
+ ##
35
+ # Something went wrong with a deploy-specific item.
36
+ class DeployError < Exception; end
37
+
38
+
39
+ ##
40
+ # The error is serious enough that deploy cannot proceed.
41
+ # Sunshine will attempt to revert to a previous deploy if available.
42
+ class CriticalDeployError < DeployError; end
43
+
44
+
45
+ ##
46
+ # The error is so serious that all no more action can be taken.
47
+ # Sunshine will attempt to close any ssh connections and stop the deploy.
48
+ class FatalDeployError < DeployError; end
49
+
50
+ ##
51
+ # A dependency could not be installed.
52
+ class DependencyError < FatalDeployError; end
53
+
54
+ end
@@ -0,0 +1,83 @@
1
+ module Sunshine
2
+
3
+ ##
4
+ # Healthcheck objects handle enabling and disabling health checking for
5
+ # load balancers by touching health.enabled and health.disabled files on
6
+ # an app's shell.
7
+
8
+ class Healthcheck
9
+
10
+ ENABLED_FILE = "health.enabled"
11
+ DISABLED_FILE = "health.disabled"
12
+
13
+ attr_accessor :shell, :enabled_file, :disabled_file
14
+
15
+ def initialize path, shell
16
+ @shell = shell
17
+ @enabled_file = File.join path, ENABLED_FILE
18
+ @disabled_file = File.join path, DISABLED_FILE
19
+ end
20
+
21
+
22
+ ##
23
+ # Disables healthcheck - status: :disabled
24
+
25
+ def disable
26
+ @shell.call "touch #{@disabled_file} && rm -f #{@enabled_file}"
27
+ end
28
+
29
+
30
+ ##
31
+ # Check if healthcheck is disabled.
32
+
33
+ def disabled?
34
+ @shell.file? @disabled_file
35
+ end
36
+
37
+
38
+ ##
39
+ # Check if healthcheck is down.
40
+
41
+ def down?
42
+ !@shell.file?(@disabled_file) && !@shell.file?(@enabled_file)
43
+ end
44
+
45
+
46
+ ##
47
+ # Enables healthcheck which should set status to :ok
48
+
49
+ def enable
50
+ @shell.call "rm -f #{@disabled_file} && touch #{@enabled_file}"
51
+ end
52
+
53
+
54
+ ##
55
+ # Check if healthcheck is enabled.
56
+
57
+ def enabled?
58
+ @shell.file? @enabled_file
59
+ end
60
+
61
+
62
+ ##
63
+ # Remove the healthcheck file - status: :down
64
+
65
+ def remove
66
+ @shell.call "rm -f #{@disabled_file} #{@enabled_file}"
67
+ end
68
+
69
+
70
+ ##
71
+ # Get the health status from the shell.
72
+ # Returns one of three states:
73
+ # :enabled: everything is great
74
+ # :disabled: healthcheck was explicitely turned off
75
+ # :down: um, something is wrong
76
+
77
+ def status
78
+ return :disabled if disabled?
79
+ return :enabled if enabled?
80
+ :down
81
+ end
82
+ end
83
+ end