root/trunk/projects/mongrel_cluster/lib/mongrel_cluster/init.rb

Revision 918, 11.1 kB (checked in by wayneeseguin, 9 months ago)

New logger API is: Mongrel.log(:log_level,"message") or Mongrel.log("message") so examples:
Mongrel.log(:error, "uh oh...") # :error level logging
Mongrel.log("hi mom!") # Defaults to :info level logging
Updated Mongrel codebase for use with this API.

Line 
1 require 'gem_plugin'
2 require 'mongrel'
3 require 'yaml'
4
5 module Cluster
6   module ExecBase
7     include Mongrel::Command::Base
8      
9     STATUS_OK = 0
10     STATUS_ERROR = 2
11    
12     def validate
13       valid_exists?(@config_file, "Configuration file does not exist. Run mongrel_rails cluster::configure.")
14       @valid
15     end
16    
17     def read_options
18       @options = {
19         "environment" => ENV['RAILS_ENV'] || "development",
20         "port" => 3000,
21         "pid_file" => "tmp/pids/mongrel.pid",
22         "log_file" => "log/mongrel.log",
23         "servers" => 2
24       }
25       conf = YAML.load_file(@config_file)
26       @options.merge! conf if conf
27        
28       process_pid_file @options["pid_file"]
29       process_log_file @options["log_file"]
30
31       start_port = end_port = @only
32       start_port ||=  @options["port"].to_i
33       end_port ||=  start_port + @options["servers"] - 1
34       @ports = (start_port..end_port).to_a
35     end
36
37     def process_pid_file(pid_file)
38       @pid_file_ext = File.extname(pid_file)
39       @pid_file_base = File.basename(pid_file, @pid_file_ext)
40       @pid_file_dir = File.dirname(pid_file)
41     end
42
43     def process_log_file(log_file)
44       @log_file_ext = File.extname(log_file)
45       @log_file_base = File.basename(log_file, @log_file_ext)
46       @log_file_dir = File.dirname(log_file)
47     end
48    
49     def port_pid_file(port)
50       pid_file = [@pid_file_base, port].join(".") + @pid_file_ext     
51       File.join(@pid_file_dir, pid_file)
52     end
53      
54     def port_log_file(port)
55       log_file = [@log_file_base, port].join(".") +  @log_file_ext     
56       File.join(@log_file_dir, log_file)
57     end
58      
59     def start
60       read_options
61      
62       argv = [ "mongrel_rails" ]
63       argv << "start"
64       argv << "-d"
65       argv << "-e #{@options['environment']}" if @options['environment']
66       argv << "-a #{@options['address']}"  if @options['address']
67       argv << "-c #{@options['cwd']}" if @options['cwd']
68       argv << "-o #{@options['timeout']}" if @options['timeout']
69       argv << "-t #{@options['throttle']}" if @options['throttle']
70       argv << "-m #{@options['mime_map']}" if @options['mime_map']
71       argv << "-r #{@options['docroot']}" if @options['docroot']
72       argv << "-n #{@options['num_procs']}" if @options['num_procs']
73       argv << "-B" if @options['debug']
74       argv << "-S #{@options['config_script']}" if @options['config_script']
75       argv << "--user #{@options['user']}" if @options['user']
76       argv << "--group #{@options['group']}" if @options['group']
77       argv << "--prefix #{@options['prefix']}" if @options['prefix']
78       cmd = argv.join " "
79      
80       @ports.each do |port|             
81         if @clean && pid_file_exists?(port) && !check_process(port)
82           pid_file = port_pid_file(port)       
83           Mongrel.log("missing process: removing #{pid_file}")
84           chdir_cwd do
85             File.unlink(pid_file)
86           end
87         end
88        
89         if pid_file_exists?(port) && check_process(port)
90           Mongrel.log("already started port #{port}")
91           next
92         end
93
94         exec_cmd = cmd + " -p #{port} -P #{port_pid_file(port)}"
95         exec_cmd += " -l #{port_log_file(port)}"
96         Mongrel.log("starting port #{port}")
97         log_verbose exec_cmd
98         output = `#{exec_cmd}`
99         Mongrel.log(:error, output) unless $?.success?
100       end
101     end
102      
103     def stop
104       read_options
105    
106       argv = [ "mongrel_rails" ]
107       argv << "stop"
108       argv << "-c #{@options["cwd"]}" if @options["cwd"]
109       argv << "-f" if @force
110       cmd = argv.join " "
111
112       @ports.each do |port|
113         pid = check_process(port)       
114         if @clean && pid && !pid_file_exists?(port)       
115           Mongrel.log("missing pid_file: killing mongrel_rails port #{port}, pid #{pid}")
116           Process.kill("KILL", pid.to_i) 
117         end
118        
119         if !check_process(port)
120           Mongrel.log("already stopped port #{port}")
121           next       
122         end
123
124         exec_cmd = cmd + " -P #{port_pid_file(port)}"
125         Mongrel.log("stopping port #{port}")
126         log_verbose exec_cmd
127         output = `#{exec_cmd}`
128         Mongrel.log(:error, output) unless $?.success?
129        
130       end
131     end
132  
133     def status
134       read_options
135      
136       status = STATUS_OK
137      
138       @ports.each do |port|
139         pid = check_process(port)       
140         unless pid_file_exists?(port)       
141           Mongrel.log(:error, "missing pid_file: #{port_pid_file(port)}")
142           status = STATUS_ERROR
143         else
144           Mongrel.log("found pid_file: #{port_pid_file(port)}")
145         end   
146         if pid
147           Mongrel.log("found mongrel_rails: port #{port}, pid #{pid}")
148         else
149           Mongrel.log(:error, "missing mongrel_rails: port #{port}")
150           status = STATUS_ERROR
151         end
152         Mongrel.log("")
153       end
154
155       status
156     end
157
158     def pid_file_exists?(port)   
159       pid_file = port_pid_file(port)
160       exists = false
161       chdir_cwd do     
162         exists = File.exists?(pid_file) 
163       end
164       exists
165     end
166
167     def check_process(port)
168       if pid_file_exists?(port)
169         pid = read_pid(port)
170         ps_output = `ps -o #{cmd_name}= -p #{pid}`
171         pid = ps_output =~ /mongrel_rails/ ? pid : nil
172       else
173         pid = find_pid(port)
174       end
175       pid
176     end
177    
178     def cmd_name
179       RUBY_PLATFORM =~ /solaris|aix/i ? "args" : "command"
180     end
181        
182     def cmd_flags
183       RUBY_PLATFORM =~ /solaris|aix/i ? "-eo" : "-ewwo"
184     end
185    
186     def chdir_cwd
187       pwd = Dir.pwd
188       Dir.chdir(@options["cwd"]) if @options["cwd"]     
189       yield
190       Dir.chdir(pwd) if @options["cwd"]
191     end
192
193     def read_pid(port)
194       pid_file = port_pid_file(port)
195       pid = 0
196       chdir_cwd do     
197         pid = File.read(pid_file)
198       end
199       pid
200     end
201  
202     def find_pid(port)
203       ps_cmd = "ps #{cmd_flags} pid,#{cmd_name}"
204       ps_output = `#{ps_cmd}`
205       ps_output.each do |line|
206         if line =~ /-P #{Regexp.escape(port_pid_file(port))} /
207           pid = line.split[0]
208           return pid
209         end
210       end
211       nil
212     end
213    
214     def log_verbose(message)
215       Mongrel.log(message) if @verbose
216     end
217
218   end
219
220   class Start < GemPlugin::Plugin "/commands"
221     include ExecBase
222    
223     def configure
224       options [
225         ['-C', '--config PATH', "Path to cluster configuration file", :@config_file, "config/mongrel_cluster.yml"],
226         ['-v', '--verbose', "Print all called commands and output.", :@verbose, false],
227         ['', '--clean', "Remove pid_file if needed before starting", :@clean, false],
228         ['', '--only PORT', "Port number of cluster member", :@only, nil]
229       ]
230     end
231
232     def run
233       start     
234     end
235   end
236  
237   class Stop < GemPlugin::Plugin "/commands"
238     include ExecBase
239
240     def configure
241       options [
242        ['-C', '--config PATH', "Path to cluster configuration file", :@config_file, "config/mongrel_cluster.yml"],
243        ['-f', '--force', "Force the shutdown.", :@force, false],
244        ['-v', '--verbose', "Print all called commands and output.", :@verbose, false],
245        ['', '--clean', "Remove orphaned process if needed before stopping", :@clean, false],
246        ['', '--only PORT', "Port number of cluster member", :@only, nil]
247       ]
248     end
249    
250     def run
251       stop
252     end 
253   end
254  
255   class Restart < GemPlugin::Plugin "/commands"
256     include ExecBase
257
258     def configure
259       options [
260         ['-C', '--config PATH', "Path to cluster configuration file", :@config_file, "config/mongrel_cluster.yml"],
261         ['-f', '--force', "Force the shutdown.", :@force, false],
262         ['-v', '--verbose', "Print all called commands and output.", :@verbose, false],
263         ['', '--clean', "Call stop and start with --clean", :@clean, false],       
264         ['', '--only PORT', "Port number of cluster member", :@only, nil]       
265       ]
266     end
267    
268     def run
269       stop
270       start
271     end
272    
273   end
274  
275   class Configure < GemPlugin::Plugin "/commands"
276     include ExecBase
277    
278     def configure
279       options [
280         ["-e", "--environment ENV", "Rails environment to run as", :@environment, nil],
281         ['-p', '--port PORT', "Starting port to bind to", :@port, 3000],
282         ['-a', '--address ADDR', "Address to bind to", :@address, nil],
283         ['-l', '--log FILE', "Where to write log messages", :@log_file, "log/mongrel.log"],
284         ['-P', '--pid FILE', "Where to write the PID", :@pid_file, "tmp/pids/mongrel.pid"],
285         ['-c', '--chdir PATH', "Change to dir before starting (will be expanded)", :@cwd, nil],
286         ['-o', '--timeout TIME', "Time to wait (in seconds) before killing a stalled thread", :@timeout, nil],
287         ['-t', '--throttle TIME', "Time to pause (in hundredths of a second) between accepting clients", :@throttle, nil],
288         ['-m', '--mime PATH', "A YAML file that lists additional MIME types", :@mime_map, nil],
289         ['-r', '--root PATH', "Set the document root (default 'public')", :@docroot, nil],
290         ['-n', '--num-procs INT', "Number of processor threads to use", :@num_procs, nil],
291         ['-B', '--debug', "Enable debugging mode", :@debug, nil],
292         ['-S', '--script PATH', "Load the given file as an extra config script.", :@config_script, nil],
293         ['-N', '--num-servers INT', "Number of Mongrel servers", :@servers, 2],
294         ['-C', '--config PATH', "Path to cluster configuration file", :@config_file, "config/mongrel_cluster.yml"],
295         ['', '--user USER', "User to run as", :@user, nil],
296         ['', '--group GROUP', "Group to run as", :@group, nil],
297         ['', '--prefix PREFIX', "Rails prefix to use", :@prefix, nil]
298       ]
299     end
300
301     def validate
302       @servers = @servers.to_i
303      
304       valid?(@servers > 0, "Must give a valid number of servers")
305       valid_dir? File.dirname(@config_file), "Path to config file not valid: #{@config_file}"
306      
307       @valid
308     end
309
310     def run
311       @options = {
312         "port" => @port,
313         "servers" => @servers,
314         "pid_file" => @pid_file
315       }
316      
317       @options["log_file"] = @log_file if @log_file
318       @options["debug"] = @debug if @debug
319       @options["num_procs"] = @num_procs if @num_procs
320       @options["docroot"] = @docroot if @docroot
321       @options["address"] = @address if @address
322       @options["timeout"] = @timeout if @timeout
323       @options["throttle"] = @throttle if @throttle
324       @options["environment"] = @environment if @environment
325       @options["mime_map"] = @mime_map if @mime_map
326       @options["config_script"] = @config_script if @config_script
327       @options["cwd"] = @cwd if @cwd
328       @options["user"] = @user if @user
329       @options["group"] = @group if @group
330       @options["prefix"] = @prefix if @prefix
331      
332       Mongrel.log("Writing configuration file to #{@config_file}.")
333       File.open(@config_file,"w") {|f| f.write(@options.to_yaml)}
334     end 
335   end
336
337   class Status < GemPlugin::Plugin "/commands"
338     include ExecBase
339
340     def configure
341       options [
342         ['-C', '--config PATH', "Path to cluster configuration file", :@config_file, "config/mongrel_cluster.yml"],
343         ['-v', '--verbose', "Print all called commands and output.", :@verbose, false],
344         ['', '--only PORT', "Port number of cluster member", :@only, nil]       
345       ]
346     end
347    
348     def run
349       status
350     end
351
352   end
353 end
354
Note: See TracBrowser for help on using the browser.