aws-codedeploy-agent 0.0.1

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 (84) hide show
  1. data/.gitignore +2 -0
  2. data/CHANGES.md +3 -0
  3. data/Gemfile +13 -0
  4. data/LICENSE +177 -0
  5. data/NOTICE +2 -0
  6. data/README.md +16 -0
  7. data/aws-codedeploy-agent.gemspec +39 -0
  8. data/bin/codedeploy-agent +78 -0
  9. data/bin/codedeploy-install +15 -0
  10. data/bin/codedeploy-uninstall +13 -0
  11. data/certs/host-agent-deployment-signer-ca-chain.pem +76 -0
  12. data/conf/codedeployagent.yml +9 -0
  13. data/init.d/codedeploy-agent +61 -0
  14. data/lib/core_ext.rb +71 -0
  15. data/lib/instance_agent.rb +35 -0
  16. data/lib/instance_agent/agent/base.rb +34 -0
  17. data/lib/instance_agent/codedeploy_plugin/application_specification/ace_info.rb +133 -0
  18. data/lib/instance_agent/codedeploy_plugin/application_specification/acl_info.rb +163 -0
  19. data/lib/instance_agent/codedeploy_plugin/application_specification/application_specification.rb +142 -0
  20. data/lib/instance_agent/codedeploy_plugin/application_specification/context_info.rb +23 -0
  21. data/lib/instance_agent/codedeploy_plugin/application_specification/file_info.rb +23 -0
  22. data/lib/instance_agent/codedeploy_plugin/application_specification/linux_permission_info.rb +121 -0
  23. data/lib/instance_agent/codedeploy_plugin/application_specification/mode_info.rb +66 -0
  24. data/lib/instance_agent/codedeploy_plugin/application_specification/range_info.rb +134 -0
  25. data/lib/instance_agent/codedeploy_plugin/application_specification/script_info.rb +27 -0
  26. data/lib/instance_agent/codedeploy_plugin/codedeploy_control.rb +72 -0
  27. data/lib/instance_agent/codedeploy_plugin/command_executor.rb +357 -0
  28. data/lib/instance_agent/codedeploy_plugin/command_poller.rb +146 -0
  29. data/lib/instance_agent/codedeploy_plugin/deployment_specification.rb +150 -0
  30. data/lib/instance_agent/codedeploy_plugin/hook_executor.rb +206 -0
  31. data/lib/instance_agent/codedeploy_plugin/install_instruction.rb +374 -0
  32. data/lib/instance_agent/codedeploy_plugin/installer.rb +143 -0
  33. data/lib/instance_agent/codedeploy_plugin/request_helper.rb +28 -0
  34. data/lib/instance_agent/config.rb +43 -0
  35. data/lib/instance_agent/log.rb +3 -0
  36. data/lib/instance_agent/platform.rb +17 -0
  37. data/lib/instance_agent/platform/linux_util.rb +57 -0
  38. data/lib/instance_agent/runner/child.rb +57 -0
  39. data/lib/instance_agent/runner/master.rb +103 -0
  40. data/lib/instance_metadata.rb +47 -0
  41. data/test/certificate_helper.rb +120 -0
  42. data/test/helpers/instance_agent_helper.rb +25 -0
  43. data/test/instance_agent/agent/base_test.rb +49 -0
  44. data/test/instance_agent/codedeploy_plugin/application_specification_test.rb +1710 -0
  45. data/test/instance_agent/codedeploy_plugin/codedeploy_control_test.rb +51 -0
  46. data/test/instance_agent/codedeploy_plugin/command_executor_test.rb +513 -0
  47. data/test/instance_agent/codedeploy_plugin/command_poller_test.rb +459 -0
  48. data/test/instance_agent/codedeploy_plugin/deployment_specification_test.rb +335 -0
  49. data/test/instance_agent/codedeploy_plugin/hook_executor_test.rb +250 -0
  50. data/test/instance_agent/codedeploy_plugin/install_instruction_test.rb +566 -0
  51. data/test/instance_agent/codedeploy_plugin/installer_test.rb +519 -0
  52. data/test/instance_agent/codedeploy_plugin/request_helper_test.rb +37 -0
  53. data/test/instance_agent/config_test.rb +64 -0
  54. data/test/instance_agent/runner/child_test.rb +87 -0
  55. data/test/instance_metadata_test.rb +97 -0
  56. data/test/test_helper.rb +16 -0
  57. data/vendor/gems/.codedeploy-commands-1.0.0.created.rid +1 -0
  58. data/vendor/gems/codedeploy-commands/apis/CodeDeployCommand.api.json +372 -0
  59. data/vendor/gems/codedeploy-commands/codedeploy-commands-1.0.0.gemspec +28 -0
  60. data/vendor/gems/codedeploy-commands/lib/aws/codedeploy_commands.rb +18 -0
  61. data/vendor/gems/codedeploy-commands/lib/aws/plugins/certificate_authority.rb +12 -0
  62. data/vendor/gems/codedeploy-commands/lib/aws/plugins/deploy_control_endpoint.rb +22 -0
  63. data/vendor/gems/process_manager/README.md +1 -0
  64. data/vendor/gems/process_manager/lib/blank.rb +153 -0
  65. data/vendor/gems/process_manager/lib/core_ext.rb +73 -0
  66. data/vendor/gems/process_manager/lib/process_manager.rb +49 -0
  67. data/vendor/gems/process_manager/lib/process_manager/child.rb +119 -0
  68. data/vendor/gems/process_manager/lib/process_manager/config.rb +112 -0
  69. data/vendor/gems/process_manager/lib/process_manager/log.rb +107 -0
  70. data/vendor/gems/process_manager/lib/process_manager/master.rb +322 -0
  71. data/vendor/gems/process_manager/process_manager-0.0.13.gemspec +42 -0
  72. data/vendor/specifications/aws-sdk-core-2.0.5.gemspec +39 -0
  73. data/vendor/specifications/builder-3.2.2.gemspec +29 -0
  74. data/vendor/specifications/codedeploy-commands-1.0.0.gemspec +28 -0
  75. data/vendor/specifications/gli-2.5.6.gemspec +51 -0
  76. data/vendor/specifications/jamespath-0.5.1.gemspec +35 -0
  77. data/vendor/specifications/little-plugger-1.1.3.gemspec +32 -0
  78. data/vendor/specifications/logging-1.8.1.gemspec +44 -0
  79. data/vendor/specifications/multi_json-1.7.7.gemspec +30 -0
  80. data/vendor/specifications/multi_json-1.8.4.gemspec +30 -0
  81. data/vendor/specifications/multi_xml-0.5.5.gemspec +30 -0
  82. data/vendor/specifications/process_manager-0.0.13.gemspec +42 -0
  83. data/vendor/specifications/simple_pid-0.2.1.gemspec +28 -0
  84. metadata +377 -0
@@ -0,0 +1,112 @@
1
+ # encoding: UTF-8
2
+ module ProcessManager
3
+ class Config
4
+
5
+ def self.init
6
+ @config = Config.new
7
+ end
8
+
9
+ def self.config(options = {})
10
+ init unless @config
11
+ @config.config(options)
12
+ end
13
+
14
+ def self.validate_config
15
+ init unless @config
16
+ @config.validate
17
+ end
18
+
19
+ def self.load_config
20
+ if File.exists?(config[:config_file]) && File.readable?(config[:config_file])
21
+ file_config = YAML.load(File.read(config[:config_file])).symbolize_keys
22
+ config.update(file_config)
23
+ config_loaded_callbacks.each{|c| c.call}
24
+ else
25
+ raise "The config file #{config[:config_file]} does not exist or is not readable"
26
+ end
27
+ end
28
+
29
+ def self.on_config_load(&block)
30
+ @@_config_callbacks ||= []
31
+ @@_config_callbacks << block
32
+ nil
33
+ end
34
+
35
+ def self.config_loaded_callbacks
36
+ @@_config_callbacks ||= []
37
+ end
38
+
39
+ def initialize
40
+ @config = {
41
+ :program_name => 'process_manager',
42
+ :max_runs_per_worker => 0, # unlimited
43
+ :children => 4,
44
+ :log_dir => '/tmp',
45
+ :pid_dir => '/tmp',
46
+ :verbose => false,
47
+ :wait_after_throttle_error => 60, # wait time in seconds after a we got a throttling exception from SWF
48
+ :wait_between_runs => 5, # wait time in seconds after a run so that we don't run into throttling exceptions
49
+ :wait_after_connection_problem => 5, # wait time in seconds after a connection problem as we don't want to build a fork-bomb
50
+ :wait_between_spawning_children => 10, # wait time in seconds after spawning a child so that we don't overhelm SWF with our requests
51
+ :user => nil,
52
+ :group => nil,
53
+
54
+ # global config file to read
55
+ :config_file => nil
56
+ }
57
+ end
58
+
59
+ def config(options = {})
60
+ @config.update(options) unless options.nil? || options.empty?
61
+ @config
62
+ end
63
+
64
+ def validate
65
+ errors = []
66
+
67
+ errors << "Invalid max_runs_per_worker #{config[:max_runs_per_worker].inspect}" unless config[:max_runs_per_worker].to_s.match(/\d+/) && config[:max_runs_per_worker].to_i >= 0
68
+ config[:max_runs_per_worker] = config[:max_runs_per_worker].to_i
69
+ errors << "Invalid number of children #{config[:children].inspect}" unless config[:children].to_s.match(/\d+/) && config[:children].to_i > 0
70
+ config[:children] = config[:children].to_i
71
+
72
+ normalize_log_and_pid_dir
73
+ validate_log_and_pid_dir(errors)
74
+ validate_user(errors)
75
+ errors
76
+ end
77
+
78
+ def validate_log_and_pid_dir(errors)
79
+ FileUtils.mkdir_p(ProcessManager::Config.config[:log_dir]) unless File.exists?(ProcessManager::Config.config[:log_dir])
80
+ FileUtils.mkdir_p(ProcessManager::Config.config[:pid_dir]) unless File.exists?(ProcessManager::Config.config[:pid_dir])
81
+ errors << "Please make sure the path of the log directory exists and is writable: #{config[:log_dir].inspect}" unless file_writable?(config[:log_dir]) && File.directory?(config[:log_dir])
82
+ errors << "Please make sure the path of the PID directory exists and is writable: #{config[:pid_dir].inspect}" unless file_writable?(config[:pid_dir]) && File.directory?(config[:pid_dir])
83
+ errors
84
+ end
85
+
86
+ def validate_user(errors)
87
+ if config[:user].present?
88
+ errors << "The system user does not exist: #{config[:user].inspect}" unless (Etc.getpwnam(config[:user]).uid rescue false)
89
+ end
90
+ errors
91
+ end
92
+
93
+ def normalize_log_and_pid_dir
94
+ if config[:pid_dir]
95
+ config[:pid_dir] = File.expand_path(config[:pid_dir])
96
+ end
97
+ if config[:log_dir]
98
+ config[:log_dir] = File.expand_path(config[:log_dir])
99
+ end
100
+ end
101
+
102
+ def file_writable?(path)
103
+ return false unless path.present?
104
+ if File.exists?(path)
105
+ File.writable?(path)
106
+ else
107
+ File.writable?(File.dirname(path))
108
+ end
109
+ end
110
+
111
+ end
112
+ end
@@ -0,0 +1,107 @@
1
+ # encoding: UTF-8
2
+ require 'logging'
3
+ require 'logger'
4
+
5
+ module ProcessManager
6
+ class Log
7
+ NORMAL_SEVERITIES = %W{debug info warn unknown}
8
+ ERROR_SEVERITIES = %W{error fatal}
9
+ SEVERITIES = NORMAL_SEVERITIES + ERROR_SEVERITIES
10
+
11
+ class << self
12
+ attr_accessor :logger
13
+ end
14
+
15
+ class Logger
16
+ attr_accessor :logger
17
+
18
+ # Initializes a logger that will roll log files every hour and keeps a week's worth of logs
19
+ # in the disk. The log layout represents,
20
+ # "ISO8601_format_date log_level [program_name(pid)]: actual_log_message"
21
+ # Note: Rolling file appender only works with regular files
22
+
23
+ def initialize(log_device)
24
+ @logger = Logging.logger[ProcessManager::Config.config[:program_name]]
25
+ @logger.add_appenders(
26
+ Logging.appenders.rolling_file('rolling_file_appender',
27
+ :filename => log_device,
28
+ :age => 'daily',
29
+ :keep => 7,
30
+ :layout => Logging.layouts.pattern(:pattern => '%d %-5l [%c(%p)]: %m\n')
31
+ )
32
+ )
33
+ if ProcessManager::Config.config[:verbose]
34
+ self.level = 'debug'
35
+ else
36
+ self.level = 'info'
37
+ end
38
+ end
39
+
40
+ def level=(level)
41
+ if level.is_a?(Fixnum)
42
+ @logger.level = level
43
+ else
44
+ @logger.level = ::Logger.const_get(level.to_s.upcase)
45
+ end
46
+ end
47
+
48
+ NORMAL_SEVERITIES.each do |level|
49
+ log_level = ::Logger.const_get(level.upcase)
50
+ define_method(level) do |message|
51
+ raise "No logger available" unless @logger
52
+ @logger.add(log_level, message)
53
+ end
54
+ end
55
+
56
+ ERROR_SEVERITIES.each do |level|
57
+ log_level = ::Logger.const_get(level.upcase)
58
+ define_method(level) do |message|
59
+ @logger.add(log_level, message)
60
+ ProcessManager.on_error_callbacks.each do |callback|
61
+ begin
62
+ callback.call(message)
63
+ rescue Exception
64
+ # error callbacks shouldn't break the main flow
65
+ end
66
+ end if level == 'error'
67
+ end
68
+ end
69
+ end
70
+
71
+ def self.[](logger_name)
72
+ logger_name = logger_name.to_sym
73
+ @logger_collection ||= {}
74
+ @logger_collection[logger_name] ||= ProcessManager::Log::Logger.new(log_device(logger_name))
75
+ end
76
+
77
+ def self.log_device(logger_name)
78
+ if logger_name.is_a?(String) || logger_name.is_a?(Symbol)
79
+ raise 'Please init ProcessManager::Log with a base log file!' unless @base_log_file
80
+ @base_log_file.gsub(/\.log/, ".#{logger_name.to_s.demodulize}.log")
81
+ else # IO?
82
+ logger_name
83
+ end
84
+ end
85
+
86
+ def self.init(log_device)
87
+ @base_log_file = log_device
88
+ if @logger.nil? || ((@logger.logger.logdev.dev.path != log_device) rescue true)
89
+ @logger = ::ProcessManager::Log::Logger.new(log_device)
90
+ end
91
+ @logger
92
+ end
93
+
94
+ def self.level=(level)
95
+ @logger.level = ::Logger.const_get(level.to_s.upcase)
96
+ end
97
+
98
+ (NORMAL_SEVERITIES + ERROR_SEVERITIES).each do |level|
99
+ singleton_class.instance_eval do
100
+ define_method(level) do |message|
101
+ raise "No logger available" unless @logger
102
+ @logger.send(level, message)
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,322 @@
1
+ # encoding: UTF-8
2
+ require 'simple_pid'
3
+ require 'fileutils'
4
+ require 'blank'
5
+
6
+ module ProcessManager
7
+ module Daemon
8
+ class Master
9
+
10
+ attr_accessor :children
11
+
12
+ def initialize
13
+ @children = {}
14
+ ProcessManager.set_program_name(description)
15
+ ensure_validate_configuration
16
+ dropped_privileges = drop_privileges
17
+ ProcessManager::Log.init(log_file)
18
+ if dropped_privileges
19
+ ProcessManager::Log.info("Dropped privileges to group: #{Etc.getgrgid(Process.gid).name} (gid = #{Process.gid})")
20
+ ProcessManager::Log.info("Dropped privileges to user: #{Etc.getpwuid(Process.uid).name} (uid = #{Process.uid})")
21
+ end
22
+ after_initialize
23
+ end
24
+
25
+ # please override
26
+ def after_initialize
27
+ # hook
28
+ end
29
+
30
+ # please override
31
+ def validate_ssl_config
32
+ end
33
+
34
+ def self.start
35
+ pid = fork do
36
+ new.start
37
+ end
38
+ Process.detach pid
39
+ end
40
+
41
+ def self.stop
42
+ new.stop
43
+ end
44
+
45
+ def self.restart
46
+ stop
47
+ sleep 1
48
+ start
49
+ end
50
+
51
+ def self.status
52
+ if pid = find_pid
53
+ if ProcessManager::process_running?(pid)
54
+ pid
55
+ else
56
+ clean_stale_pid
57
+ nil
58
+ end
59
+ else
60
+ # does not run
61
+ nil
62
+ end
63
+ end
64
+
65
+ def self.pid_file
66
+ File.join(ProcessManager::Config.config[:pid_dir], "#{ProcessManager::Config.config[:program_name]}.#{self.pid_description}.pid")
67
+ end
68
+
69
+ def self.pid_lock_file
70
+ File.join(ProcessManager::Config.config[:pid_dir], "#{ProcessManager::Config.config[:program_name]}.pid.lock")
71
+ end
72
+
73
+ def pid_lock_file
74
+ self.class.pid_lock_file
75
+ end
76
+
77
+ def pid_file
78
+ self.class.pid_file
79
+ end
80
+
81
+ # please override
82
+ def self.pid_description
83
+ "ProcessManager"
84
+ end
85
+
86
+ def pid_description
87
+ self.class.pid_description
88
+ end
89
+
90
+ def self.log_file
91
+ File.join(ProcessManager::Config.config[:log_dir], "#{ProcessManager::Config.config[:program_name]}.#{pid_description}.log")
92
+ end
93
+
94
+ def log_file
95
+ self.class.log_file
96
+ end
97
+
98
+ def drop_privileges
99
+
100
+ runas_user = ProcessManager::Config.config[:user]
101
+ return false if runas_user.blank?
102
+
103
+ if runas_user == Etc.getpwuid(Process.uid).name
104
+ return false
105
+ elsif Process.uid != 0
106
+ raise "Can't drop privileges as unprivileged user. Please run this command as a privileged user."
107
+ end
108
+
109
+ if runas_user.present?
110
+ uid = Etc.getpwnam(runas_user).uid
111
+ if (group = ProcessManager::Config.config[:group]) && group.present?
112
+ gid = Etc.getgrnam(group).gid
113
+ else
114
+ gid = Etc.getpwuid(uid).gid
115
+ end
116
+ Process.initgroups(runas_user, gid)
117
+ Process::GID.change_privilege(gid)
118
+ Process::UID.change_privilege(uid)
119
+ true
120
+ end
121
+ false
122
+ rescue Exception => e
123
+ $stderr.puts "Failed to drop privileges: #{e.class} - #{e.message} - #{e.backtrace.join("\n")}"
124
+ exit 1
125
+ end
126
+
127
+ def start
128
+ handle_pid_file
129
+ validate_ssl_config
130
+ trap_signals
131
+
132
+ spawn_children
133
+ puts "Started #{description} with #{ProcessManager::Config.config[:children]} children"
134
+ ProcessManager::Log.info("Started #{description} with #{ProcessManager::Config.config[:children]} children")
135
+
136
+ loop do
137
+ # master does nothing apart from replacing dead children
138
+ # and forwarding signals
139
+ sleep 1
140
+ end
141
+ end
142
+
143
+ def stop
144
+ if (pid = self.class.find_pid)
145
+ puts "Stopping #{description(pid)}"
146
+ ProcessManager::Log.info("Stopping #{description(pid)}")
147
+ begin
148
+ Process.kill('TERM', pid)
149
+ rescue Errno::ESRCH
150
+ end
151
+ else
152
+ puts "Nothing running that could be stopped"
153
+ end
154
+ end
155
+
156
+ def handle_pid_file
157
+ @file_lock ||= File.open(pid_lock_file, File::RDWR|File::CREAT, 0644)
158
+ lock_aquired = @file_lock.flock(File::LOCK_EX|File::LOCK_NB)
159
+
160
+ if lock_aquired == false
161
+ ProcessManager::Log.info("Could not aquire lock on #{pid_lock_file} - aborting start!")
162
+ self.class.abort
163
+
164
+ elsif File.exists?(pid_file)
165
+ pid = self.class.find_pid
166
+ if ProcessManager.process_running?(pid)
167
+ puts "Pidfile #{pid_file} exists and process #{pid} is running - aborting start!"
168
+ ProcessManager::Log.info("Pidfile #{pid_file} exists and process #{pid} is running - aborting start!")
169
+ @file_lock.close
170
+ self.class.abort
171
+ else
172
+ self.class.clean_stale_pid
173
+ end
174
+ end
175
+ ::SimplePid.drop(pid_file)
176
+ end
177
+
178
+ def spawn_children
179
+ ProcessManager::Config.config[:children].times do |i|
180
+ spawn_child(i)
181
+ sleep ProcessManager::Config.config[:wait_between_spawning_children].to_i
182
+ end
183
+ end
184
+
185
+ # spawn a new child and pass down out PID so that it can check if we are alive
186
+ def spawn_child(index)
187
+ master_pid = $$ # need to store in order to pass down to child
188
+ child_pid = fork do
189
+ child_class.new(index, master_pid).start
190
+ end
191
+ children[index] = child_pid
192
+ ProcessManager::Log.info "#{description}: Spawned child #{index + 1}/#{ProcessManager::Config.config[:children]}"
193
+ end
194
+
195
+ def trap_signals
196
+ # The QUIT & INT signals triggers a graceful shutdown.
197
+ # The master shuts down immediately and forwards the signal to each child
198
+ [:INT, :QUIT, :TERM].each do |sig|
199
+ trap(sig) do
200
+ ProcessManager::Log.info "#{description}: Received #{sig} - stopping children and shutting down"
201
+ kill_children(sig)
202
+ cleanup_and_exit
203
+ end
204
+ end
205
+
206
+ trap(:CHLD) do
207
+ handle_chld
208
+ end
209
+ end
210
+
211
+ def cleanup_and_exit
212
+ SimplePid.cleanup!(pid_file)
213
+ @file_lock.close
214
+ exit
215
+ end
216
+
217
+ def handle_chld
218
+ if child = reap_child
219
+ ProcessManager::Log.info "#{description}: Received CHLD - cleaning dead child process"
220
+ cleanup_dead_child(child)
221
+ else
222
+ ProcessManager::Log.debug "#{description}: Received CHLD - ignoring as it looks like a child of a child"
223
+ end
224
+ end
225
+
226
+ def reap_child
227
+ dead_child = nil
228
+ begin
229
+ dead_child = Process.wait
230
+ rescue Errno::ECHILD
231
+ end
232
+ dead_child
233
+ end
234
+
235
+ def cleanup_dead_child(dead_child)
236
+ ProcessManager::Log.info "#{description}: been told to replace child #{dead_child.inspect}"
237
+ # delete given child
238
+ if index = children.key(dead_child)
239
+ children.delete(index)
240
+ end
241
+
242
+ # check all other children
243
+ children.each do |child_index, child_pid|
244
+ begin
245
+ dead_child = Process.waitpid(child_pid, Process::WNOHANG)
246
+ if index = children.key(dead_child)
247
+ children.delete(index)
248
+ end
249
+ rescue Errno::ECHILD
250
+ end
251
+ end
252
+
253
+ replace_terminated_children
254
+ end
255
+
256
+ # make sure we have again as many child we need
257
+ def replace_terminated_children
258
+ missing_children = ProcessManager::Config.config[:children] - children.values.size
259
+ if missing_children > 0
260
+ ProcessManager::Log.info "#{description}: not enough child processes running - missing at least #{missing_children} - respawning"
261
+ 0.upto(ProcessManager::Config.config[:children] - 1).each do |i|
262
+ if children.has_key?(i)
263
+ ProcessManager::Log.debug "#{description}: child #{i+1}/#{ProcessManager::Config.config[:children]} is still there"
264
+ else
265
+ spawn_child(i)
266
+ end
267
+ end
268
+ else
269
+ ProcessManager::Log.debug "#{description}: no need to replace child processes"
270
+ end
271
+ end
272
+
273
+ def kill_children(sig)
274
+ children.each do |index, child_pid|
275
+ begin
276
+ Process.kill(sig, child_pid)
277
+ rescue Errno::ESRCH
278
+ end
279
+ end
280
+ end
281
+
282
+ def ensure_validate_configuration
283
+ if (errors = ProcessManager::Config.validate_config)
284
+ errors.each{|error| puts error}
285
+ end
286
+ cleanup_and_exit unless errors.empty?
287
+ end
288
+
289
+ def self.abort
290
+ Kernel.abort
291
+ end
292
+
293
+ def self.clean_stale_pid
294
+ puts "Pidfile #{pid_file} present but no matching process running - cleaning up"
295
+ ::FileUtils.rm(pid_file)
296
+ end
297
+
298
+ def self.find_pid
299
+ File.read(pid_file).chomp.to_i rescue nil
300
+ end
301
+
302
+ def description(pid = $$)
303
+ self.class.description(pid)
304
+ end
305
+
306
+ def child_class
307
+ self.class.child_class
308
+ end
309
+
310
+ # please override
311
+ def self.description(pid = $$)
312
+ "master #{pid}"
313
+ end
314
+
315
+ # please override
316
+ def self.child_class
317
+ ::ProcessManager::Daemon::Child
318
+ end
319
+
320
+ end
321
+ end
322
+ end