sunshine 1.0.0.pre

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 (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