daemons 1.1.9 → 1.2.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.
- checksums.yaml +7 -0
- data/LICENSE +1 -1
- data/README.md +206 -0
- data/Releases +17 -0
- data/examples/call/call.rb +13 -16
- data/examples/call/call_monitor.rb +13 -17
- data/examples/daemonize/daemonize.rb +4 -8
- data/examples/run/ctrl_crash.rb +0 -1
- data/examples/run/ctrl_custom_logfiles.rb +18 -0
- data/examples/run/ctrl_exec.rb +0 -1
- data/examples/run/ctrl_exit.rb +0 -1
- data/examples/run/ctrl_keep_pid_files.rb +1 -3
- data/examples/run/ctrl_monitor.rb +0 -1
- data/examples/run/ctrl_monitor_multiple.rb +17 -0
- data/examples/run/ctrl_multiple.rb +0 -1
- data/examples/run/ctrl_ontop.rb +0 -1
- data/examples/run/ctrl_optionparser.rb +4 -6
- data/examples/run/ctrl_proc.rb +8 -9
- data/examples/run/ctrl_proc_multiple.rb +4 -6
- data/examples/run/ctrl_proc_rand.rb +2 -4
- data/examples/run/ctrl_proc_simple.rb +0 -1
- data/examples/run/myserver.rb +0 -1
- data/examples/run/myserver_crashing.rb +5 -5
- data/examples/run/myserver_exiting.rb +2 -2
- data/examples/run/myserver_hanging.rb +4 -5
- data/examples/run/myserver_slowstop.rb +5 -6
- data/lib/daemons.rb +66 -68
- data/lib/daemons/application.rb +171 -188
- data/lib/daemons/application_group.rb +99 -92
- data/lib/daemons/change_privilege.rb +3 -3
- data/lib/daemons/cmdline.rb +43 -54
- data/lib/daemons/controller.rb +36 -53
- data/lib/daemons/daemonize.rb +54 -64
- data/lib/daemons/etc_extension.rb +3 -2
- data/lib/daemons/exceptions.rb +10 -11
- data/lib/daemons/monitor.rb +60 -62
- data/lib/daemons/pid.rb +24 -56
- data/lib/daemons/pidfile.rb +38 -40
- data/lib/daemons/pidmem.rb +5 -9
- data/lib/daemons/version.rb +3 -0
- metadata +45 -45
- data/README +0 -214
- data/Rakefile +0 -90
- data/TODO +0 -2
- data/setup.rb +0 -1360
@@ -1,65 +1,63 @@
|
|
1
1
|
|
2
2
|
module Daemons
|
3
3
|
class ApplicationGroup
|
4
|
-
|
5
4
|
attr_reader :app_name
|
6
5
|
attr_reader :script
|
7
|
-
|
6
|
+
|
8
7
|
attr_reader :monitor
|
9
|
-
|
10
|
-
#attr_reader :controller
|
11
|
-
|
8
|
+
|
9
|
+
# attr_reader :controller
|
10
|
+
|
12
11
|
attr_reader :options
|
13
|
-
|
12
|
+
|
14
13
|
attr_reader :applications
|
15
|
-
|
14
|
+
|
16
15
|
attr_accessor :controller_argv
|
17
16
|
attr_accessor :app_argv
|
18
|
-
|
17
|
+
|
19
18
|
attr_accessor :dir_mode
|
20
19
|
attr_accessor :dir
|
21
|
-
|
20
|
+
|
22
21
|
# true if the application is supposed to run in multiple instances
|
23
22
|
attr_reader :multiple
|
24
|
-
|
25
|
-
|
23
|
+
|
26
24
|
def initialize(app_name, options = {})
|
27
25
|
@app_name = app_name
|
28
26
|
@options = options
|
29
|
-
|
27
|
+
|
30
28
|
if options[:script]
|
31
29
|
@script = File.expand_path(options[:script])
|
32
30
|
end
|
33
|
-
|
34
|
-
|
31
|
+
|
32
|
+
# @controller = controller
|
35
33
|
@monitor = nil
|
36
|
-
|
37
|
-
#options = controller.options
|
38
|
-
|
34
|
+
|
35
|
+
# options = controller.options
|
36
|
+
|
39
37
|
@multiple = options[:multiple] || false
|
40
|
-
|
38
|
+
|
41
39
|
@dir_mode = options[:dir_mode] || :script
|
42
40
|
@dir = options[:dir] || ''
|
43
|
-
|
41
|
+
|
44
42
|
@keep_pid_files = options[:keep_pid_files] || false
|
45
43
|
@no_pidfiles = options[:no_pidfiles] || false
|
46
|
-
|
47
|
-
|
44
|
+
|
45
|
+
# @applications = find_applications(pidfile_dir())
|
48
46
|
@applications = []
|
49
47
|
end
|
50
|
-
|
48
|
+
|
51
49
|
# Setup the application group.
|
52
50
|
# Currently this functions calls <tt>find_applications</tt> which finds
|
53
51
|
# all running instances of the application and populates the application array.
|
54
52
|
#
|
55
53
|
def setup
|
56
|
-
@applications = find_applications(pidfile_dir
|
54
|
+
@applications = find_applications(pidfile_dir)
|
57
55
|
end
|
58
|
-
|
56
|
+
|
59
57
|
def pidfile_dir
|
60
58
|
PidFile.dir(@dir_mode, @dir, script)
|
61
|
-
end
|
62
|
-
|
59
|
+
end
|
60
|
+
|
63
61
|
def find_applications(dir)
|
64
62
|
if @no_pidfiles
|
65
63
|
return find_applications_by_app_name(app_name)
|
@@ -67,128 +65,137 @@ module Daemons
|
|
67
65
|
return find_applications_by_pidfiles(dir)
|
68
66
|
end
|
69
67
|
end
|
70
|
-
|
68
|
+
|
71
69
|
# TODO: identifiy the monitor process
|
72
70
|
def find_applications_by_app_name(app_name)
|
73
71
|
pids = []
|
74
|
-
|
72
|
+
|
75
73
|
begin
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
74
|
+
x = `ps auxw | grep -v grep | awk '{print $2, $11, $12}' | grep #{app_name}`
|
75
|
+
if x && x.chomp!
|
76
|
+
processes = x.split(/\n/).compact
|
77
|
+
processes = processes.delete_if do |p|
|
78
|
+
pid, name, add = p.split(/\s/)
|
79
|
+
# We want to make sure that the first part of the process name matches
|
80
|
+
# so that app_name matches app_name_22
|
81
|
+
|
82
|
+
app_name != name[0..(app_name.length - 1)] and not add.include?(app_name)
|
83
|
+
end
|
84
|
+
pids = processes.map { |p| p.split(/\s/)[0].to_i }
|
85
85
|
end
|
86
|
-
|
86
|
+
rescue ::Exception
|
87
87
|
end
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
return pids.map {|f|
|
88
|
+
|
89
|
+
pids.map do |f|
|
92
90
|
app = Application.new(self, {}, PidMem.existing(f))
|
93
91
|
setup_app(app)
|
94
92
|
app
|
95
|
-
|
93
|
+
end
|
96
94
|
end
|
97
|
-
|
95
|
+
|
98
96
|
def find_applications_by_pidfiles(dir)
|
99
|
-
pid_files = PidFile.find_files(dir, app_name, ! @keep_pid_files)
|
100
|
-
|
101
|
-
#pp pid_files
|
102
|
-
|
103
97
|
@monitor = Monitor.find(dir, app_name + '_monitor')
|
104
|
-
|
105
|
-
pid_files.
|
106
|
-
|
107
|
-
return pid_files.map {|f|
|
98
|
+
|
99
|
+
pid_files = PidFile.find_files(dir, app_name, ! @keep_pid_files)
|
100
|
+
pid_files.map do |f|
|
108
101
|
app = Application.new(self, {}, PidFile.existing(f))
|
109
102
|
setup_app(app)
|
110
103
|
app
|
111
|
-
|
104
|
+
end
|
112
105
|
end
|
113
|
-
|
106
|
+
|
114
107
|
def new_application(add_options = {})
|
115
|
-
if @applications.size > 0
|
108
|
+
if @applications.size > 0 && !@multiple
|
116
109
|
if options[:force]
|
117
|
-
@applications.delete_if
|
110
|
+
@applications.delete_if do |a|
|
118
111
|
unless a.running?
|
119
112
|
a.zap
|
120
113
|
true
|
121
114
|
end
|
122
|
-
|
115
|
+
end
|
123
116
|
end
|
124
|
-
|
125
|
-
|
117
|
+
|
118
|
+
fail RuntimeException.new('there is already one or more instance(s) of the program running') unless @applications.empty?
|
126
119
|
end
|
127
|
-
|
120
|
+
|
128
121
|
app = Application.new(self, add_options)
|
129
|
-
|
122
|
+
|
130
123
|
setup_app(app)
|
131
|
-
|
124
|
+
|
132
125
|
@applications << app
|
133
|
-
|
134
|
-
|
126
|
+
|
127
|
+
app
|
135
128
|
end
|
136
|
-
|
129
|
+
|
137
130
|
def setup_app(app)
|
138
131
|
app.controller_argv = @controller_argv
|
139
132
|
app.app_argv = @app_argv
|
133
|
+
if @options[:show_status_callback]
|
134
|
+
app.show_status_callback = @options[:show_status_callback]
|
135
|
+
end
|
140
136
|
end
|
141
137
|
private :setup_app
|
142
|
-
|
138
|
+
|
143
139
|
def create_monitor(an_app)
|
144
|
-
|
145
|
-
|
140
|
+
if @monitor && options[:monitor]
|
141
|
+
@monitor.stop
|
142
|
+
@monitor = nil
|
143
|
+
end
|
144
|
+
|
146
145
|
if options[:monitor]
|
147
146
|
@monitor = Monitor.new(an_app)
|
148
|
-
|
149
|
-
@monitor.start(@applications)
|
147
|
+
@monitor.start(self)
|
150
148
|
end
|
151
149
|
end
|
152
|
-
|
150
|
+
|
153
151
|
def start_all
|
154
152
|
@monitor.stop if @monitor
|
155
153
|
@monitor = nil
|
156
|
-
|
157
|
-
@applications.each
|
158
|
-
fork
|
159
|
-
a.start
|
160
|
-
|
161
|
-
|
154
|
+
|
155
|
+
@applications.each do |a|
|
156
|
+
fork do
|
157
|
+
a.start
|
158
|
+
end
|
159
|
+
end
|
162
160
|
end
|
163
|
-
|
161
|
+
|
164
162
|
def stop_all(no_wait = false)
|
165
|
-
|
166
|
-
|
163
|
+
if @monitor
|
164
|
+
@monitor.stop
|
165
|
+
@monitor = nil
|
166
|
+
setup
|
167
|
+
end
|
168
|
+
|
167
169
|
threads = []
|
168
|
-
|
169
|
-
@applications.each
|
170
|
+
|
171
|
+
@applications.each do |a|
|
170
172
|
threads << Thread.new do
|
171
173
|
a.stop(no_wait)
|
172
174
|
end
|
173
|
-
|
174
|
-
|
175
|
-
threads.each {|t| t.join}
|
175
|
+
end
|
176
|
+
|
177
|
+
threads.each { |t| t.join }
|
176
178
|
end
|
177
|
-
|
179
|
+
|
178
180
|
def reload_all
|
179
|
-
@applications.each {|a| a.reload}
|
181
|
+
@applications.each { |a| a.reload }
|
180
182
|
end
|
181
183
|
|
182
184
|
def zap_all
|
183
185
|
@monitor.stop if @monitor
|
184
|
-
|
185
|
-
@applications.each {|a| a.zap}
|
186
|
+
|
187
|
+
@applications.each { |a| a.zap }
|
186
188
|
end
|
187
|
-
|
189
|
+
|
188
190
|
def show_status
|
189
|
-
@applications.each {|a| a.show_status}
|
191
|
+
@applications.each { |a| a.show_status }
|
192
|
+
end
|
193
|
+
|
194
|
+
# Check whether at least one of the applications in the group is running. If yes, return true.
|
195
|
+
def running?
|
196
|
+
@applications.each { |a| return true if a.running? }
|
197
|
+
return false
|
190
198
|
end
|
191
199
|
|
192
200
|
end
|
193
|
-
|
194
201
|
end
|
@@ -1,9 +1,9 @@
|
|
1
1
|
require 'daemons/etc_extension'
|
2
2
|
|
3
3
|
class CurrentProcess
|
4
|
-
def self.change_privilege(user, group=user)
|
4
|
+
def self.change_privilege(user, group = user)
|
5
5
|
puts "Changing process privilege to #{user}:#{group}"
|
6
|
-
|
6
|
+
|
7
7
|
uid, gid = Process.euid, Process.egid
|
8
8
|
target_uid = Etc.getpwnam(user).uid
|
9
9
|
target_gid = Etc.getgrnam(group).gid
|
@@ -16,4 +16,4 @@ class CurrentProcess
|
|
16
16
|
rescue Errno::EPERM => e
|
17
17
|
raise "Couldn't change user and group to #{user}:#{group}: #{e}"
|
18
18
|
end
|
19
|
-
end
|
19
|
+
end
|
data/lib/daemons/cmdline.rb
CHANGED
@@ -1,56 +1,52 @@
|
|
1
|
-
|
2
1
|
module Daemons
|
3
|
-
|
4
2
|
class Optparse
|
5
|
-
|
6
3
|
attr_reader :usage
|
7
4
|
|
8
5
|
def initialize(controller)
|
9
6
|
@controller = controller
|
10
7
|
@options = {}
|
11
|
-
|
8
|
+
|
12
9
|
@opts = OptionParser.new do |opts|
|
13
|
-
opts.banner =
|
14
|
-
|
10
|
+
opts.banner = ''
|
11
|
+
|
15
12
|
# opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
|
16
13
|
# @options[:verbose] = v
|
17
14
|
# end
|
18
|
-
|
19
|
-
opts.on(
|
15
|
+
|
16
|
+
opts.on('-t', '--ontop', 'Stay on top (does not daemonize)') do |t|
|
20
17
|
@options[:ontop] = t
|
21
18
|
end
|
22
|
-
|
23
|
-
opts.on(
|
19
|
+
|
20
|
+
opts.on('-f', '--force', 'Force operation') do |t|
|
24
21
|
@options[:force] = t
|
25
22
|
end
|
26
|
-
|
27
|
-
opts.on(
|
23
|
+
|
24
|
+
opts.on('-n', '--no_wait', 'Do not wait for processes to stop') do |t|
|
28
25
|
@options[:no_wait] = t
|
29
26
|
end
|
30
|
-
|
31
|
-
#opts.separator ""
|
32
|
-
#opts.separator "Specific options:"
|
33
27
|
|
34
|
-
|
35
|
-
opts.separator ""
|
36
|
-
|
28
|
+
# opts.separator ""
|
29
|
+
# opts.separator "Specific options:"
|
30
|
+
|
31
|
+
opts.separator ''
|
32
|
+
opts.separator 'Common options:'
|
37
33
|
|
38
34
|
# No argument, shows at tail. This will print an options summary
|
39
|
-
opts.on_tail(
|
40
|
-
#puts opts
|
41
|
-
|
42
|
-
controller.print_usage
|
43
|
-
|
35
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
36
|
+
# puts opts
|
37
|
+
# @usage =
|
38
|
+
controller.print_usage
|
39
|
+
|
44
40
|
exit
|
45
41
|
end
|
46
42
|
|
47
43
|
# Switch to print the version.
|
48
|
-
opts.on_tail(
|
44
|
+
opts.on_tail('--version', 'Show version') do
|
49
45
|
puts "daemons version #{Daemons::VERSION}"
|
50
46
|
exit
|
51
47
|
end
|
52
|
-
end
|
53
|
-
|
48
|
+
end
|
49
|
+
|
54
50
|
begin
|
55
51
|
@usage = @opts.to_s
|
56
52
|
rescue ::Exception # work around a bug in ruby 1.9
|
@@ -65,57 +61,50 @@ module Daemons
|
|
65
61
|
END
|
66
62
|
end
|
67
63
|
end
|
68
|
-
|
69
|
-
|
64
|
+
|
70
65
|
#
|
71
66
|
# Return a hash describing the options.
|
72
67
|
#
|
73
68
|
def parse(args)
|
74
69
|
# The options specified on the command line will be collected in *options*.
|
75
70
|
# We set default values here.
|
76
|
-
#options = {}
|
77
|
-
|
78
|
-
|
79
|
-
##pp args
|
71
|
+
# options = {}
|
72
|
+
|
73
|
+
# #pp args
|
80
74
|
@opts.parse(args)
|
81
|
-
|
82
|
-
return @options
|
83
|
-
end
|
84
75
|
|
76
|
+
@options
|
77
|
+
end
|
85
78
|
end
|
86
|
-
|
87
|
-
|
79
|
+
|
88
80
|
class Controller
|
89
|
-
|
90
81
|
def print_usage
|
91
82
|
puts "Usage: #{@app_name} <command> <options> -- <application options>"
|
92
83
|
puts
|
93
|
-
puts
|
94
|
-
puts
|
95
|
-
puts
|
96
|
-
puts
|
97
|
-
puts
|
98
|
-
puts
|
99
|
-
puts
|
100
|
-
puts
|
84
|
+
puts '* where <command> is one of:'
|
85
|
+
puts ' start start an instance of the application'
|
86
|
+
puts ' stop stop all instances of the application'
|
87
|
+
puts ' restart stop all instances and restart them afterwards'
|
88
|
+
puts ' reload send a SIGHUP to all instances of the application'
|
89
|
+
puts ' run start the application and stay on top'
|
90
|
+
puts ' zap set the application to a stopped state'
|
91
|
+
puts ' status show status (PID) of application instances'
|
101
92
|
puts
|
102
|
-
puts
|
103
|
-
|
93
|
+
puts '* and where <options> may contain several of the following:'
|
94
|
+
|
104
95
|
puts @optparse.usage
|
105
96
|
end
|
106
|
-
|
97
|
+
|
107
98
|
def catch_exceptions(&block)
|
108
99
|
begin
|
109
100
|
block.call
|
110
101
|
rescue CmdException, OptionParser::ParseError => e
|
111
|
-
puts "ERROR: #{e
|
102
|
+
puts "ERROR: #{e}"
|
112
103
|
puts
|
113
|
-
print_usage
|
104
|
+
print_usage
|
114
105
|
rescue RuntimeException => e
|
115
|
-
puts "ERROR: #{e
|
106
|
+
puts "ERROR: #{e}"
|
116
107
|
end
|
117
108
|
end
|
118
|
-
|
119
109
|
end
|
120
|
-
|
121
110
|
end
|