| 1 |
# Copyright (c) 2005 Zed A. Shaw |
|---|
| 2 |
# You can redistribute it and/or modify it under the same terms as Ruby. |
|---|
| 3 |
# |
|---|
| 4 |
# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html |
|---|
| 5 |
# for more information. |
|---|
| 6 |
|
|---|
| 7 |
require 'yaml' |
|---|
| 8 |
require 'etc' |
|---|
| 9 |
|
|---|
| 10 |
$LOAD_PATH.unshift "#{File.dirname(__FILE__)}/../lib" |
|---|
| 11 |
require 'mongrel' |
|---|
| 12 |
require 'mongrel/rails' |
|---|
| 13 |
|
|---|
| 14 |
Mongrel::Gems.require 'gem_plugin' |
|---|
| 15 |
|
|---|
| 16 |
# require 'ruby-debug' |
|---|
| 17 |
# Debugger.start |
|---|
| 18 |
|
|---|
| 19 |
module Mongrel |
|---|
| 20 |
class Start < GemPlugin::Plugin "/commands" |
|---|
| 21 |
include Mongrel::Command::Base |
|---|
| 22 |
|
|---|
| 23 |
def configure |
|---|
| 24 |
options [ |
|---|
| 25 |
["-e", "--environment ENV", "Rails environment to run as", :@environment, ENV['RAILS_ENV'] || "development"], |
|---|
| 26 |
["-d", "--daemonize", "Run daemonized in the background", :@daemon, false], |
|---|
| 27 |
['-p', '--port PORT', "Which port to bind to", :@port, 3000], |
|---|
| 28 |
['-a', '--address ADDR', "Address to bind to", :@address, "0.0.0.0"], |
|---|
| 29 |
['-l', '--log FILE', "Where to write log messages", :@log_file, "log/mongrel.log"], |
|---|
| 30 |
['-P', '--pid FILE', "Where to write the PID", :@pid_file, "log/mongrel.pid"], |
|---|
| 31 |
['-n', '--num-procs INT', "Number of processors active before clients denied", :@num_processors, 1024], |
|---|
| 32 |
['-o', '--timeout TIME', "Time to wait (in seconds) before killing a stalled thread", :@timeout, 60], |
|---|
| 33 |
['-t', '--throttle TIME', "Time to pause (in hundredths of a second) between accepting clients", :@throttle, 0], |
|---|
| 34 |
['-m', '--mime PATH', "A YAML file that lists additional MIME types", :@mime_map, nil], |
|---|
| 35 |
['-c', '--chdir PATH', "Change to dir before starting (will be expanded)", :@cwd, Dir.pwd], |
|---|
| 36 |
['-r', '--root PATH', "Set the document root (default 'public')", :@docroot, "public"], |
|---|
| 37 |
['-B', '--debug', "Enable debugging mode", :@debug, false], |
|---|
| 38 |
['-C', '--config PATH', "Use a config file", :@config_file, nil], |
|---|
| 39 |
['-S', '--script PATH', "Load the given file as an extra config script", :@config_script, nil], |
|---|
| 40 |
['-G', '--generate PATH', "Generate a config file for use with -C", :@generate, nil], |
|---|
| 41 |
['', '--user USER', "User to run as", :@user, nil], |
|---|
| 42 |
['', '--group GROUP', "Group to run as", :@group, nil], |
|---|
| 43 |
['', '--prefix PATH', "URL prefix for Rails app", :@prefix, nil] |
|---|
| 44 |
] |
|---|
| 45 |
end |
|---|
| 46 |
|
|---|
| 47 |
def validate |
|---|
| 48 |
if @config_file |
|---|
| 49 |
valid_exists?(@config_file, "Config file not there: #@config_file") |
|---|
| 50 |
return false unless @valid |
|---|
| 51 |
@config_file = File.expand_path(@config_file) |
|---|
| 52 |
load_config |
|---|
| 53 |
return false unless @valid |
|---|
| 54 |
end |
|---|
| 55 |
|
|---|
| 56 |
@cwd = File.expand_path(@cwd) |
|---|
| 57 |
valid_dir? @cwd, "Invalid path to change to during daemon mode: #@cwd" |
|---|
| 58 |
|
|---|
| 59 |
# Change there to start, then we'll have to come back after daemonize |
|---|
| 60 |
Dir.chdir(@cwd) |
|---|
| 61 |
|
|---|
| 62 |
valid?(@prefix[0] == ?/ && @prefix[-1] != ?/, "Prefix must begin with / and not end in /") if @prefix |
|---|
| 63 |
valid_dir? File.dirname(@log_file), "Path to log file not valid: #@log_file" |
|---|
| 64 |
valid_dir? File.dirname(@pid_file), "Path to pid file not valid: #@pid_file" |
|---|
| 65 |
valid_dir? @docroot, "Path to docroot not valid: #@docroot" |
|---|
| 66 |
valid_exists? @mime_map, "MIME mapping file does not exist: #@mime_map" if @mime_map |
|---|
| 67 |
valid_exists? @config_file, "Config file not there: #@config_file" if @config_file |
|---|
| 68 |
valid_dir? File.dirname(@generate), "Problem accessing directory to #@generate" if @generate |
|---|
| 69 |
valid_user? @user if @user |
|---|
| 70 |
valid_group? @group if @group |
|---|
| 71 |
|
|---|
| 72 |
return @valid |
|---|
| 73 |
end |
|---|
| 74 |
|
|---|
| 75 |
def run |
|---|
| 76 |
if @generate |
|---|
| 77 |
@generate = File.expand_path(@generate) |
|---|
| 78 |
Mongrel.log(:error, "** Writing config to \"#@generate\".") |
|---|
| 79 |
open(@generate, "w") {|f| f.write(settings.to_yaml) } |
|---|
| 80 |
Mongrel.log(:error, "** Finished. Run \"mongrel_rails start -C #@generate\" to use the config file.") |
|---|
| 81 |
exit 0 |
|---|
| 82 |
end |
|---|
| 83 |
|
|---|
| 84 |
config = Mongrel::Rails::RailsConfigurator.new(settings) do |
|---|
| 85 |
if defaults[:daemon] |
|---|
| 86 |
if File.exist? defaults[:pid_file] |
|---|
| 87 |
Mongrel.log(:error, "!!! PID file #{defaults[:pid_file]} already exists. Mongrel could be running already. Check your #{defaults[:log_file]} for errors.") |
|---|
| 88 |
Mongrel.log(:error, "!!! Exiting with error. You must stop mongrel and clear the .pid before I'll attempt a start.") |
|---|
| 89 |
exit 1 |
|---|
| 90 |
end |
|---|
| 91 |
|
|---|
| 92 |
daemonize |
|---|
| 93 |
write_pid_file |
|---|
| 94 |
Mongrel.log("Daemonized, any open files are closed. Look at #{defaults[:pid_file]} and #{defaults[:log_file]} for info.") |
|---|
| 95 |
Mongrel.log("Settings loaded from #{@config_file} (they override command line).") if @config_file |
|---|
| 96 |
end |
|---|
| 97 |
|
|---|
| 98 |
Mongrel.log("Starting Mongrel listening at #{defaults[:host]}:#{defaults[:port]}, further information can be found in log/mongrel-#{defaults[:host]}-#{defaults[:port]}.log") |
|---|
| 99 |
|
|---|
| 100 |
listener do |
|---|
| 101 |
mime = {} |
|---|
| 102 |
if defaults[:mime_map] |
|---|
| 103 |
Mongrel.log("Loading additional MIME types from #{defaults[:mime_map]}") |
|---|
| 104 |
mime = load_mime_map(defaults[:mime_map], mime) |
|---|
| 105 |
end |
|---|
| 106 |
|
|---|
| 107 |
if defaults[:debug] |
|---|
| 108 |
Mongrel.log("Installing debugging prefixed filters. Look in log/mongrel_debug for the files.") |
|---|
| 109 |
debug "/" |
|---|
| 110 |
end |
|---|
| 111 |
|
|---|
| 112 |
Mongrel.log("Starting Rails with #{defaults[:environment]} environment...") |
|---|
| 113 |
Mongrel.log("Mounting Rails at #{defaults[:prefix]}...") if defaults[:prefix] |
|---|
| 114 |
uri defaults[:prefix] || "/", :handler => rails(:mime => mime, :prefix => defaults[:prefix]) |
|---|
| 115 |
Mongrel.log("Rails loaded.") |
|---|
| 116 |
|
|---|
| 117 |
Mongrel.log("Loading any Rails specific GemPlugins" ) |
|---|
| 118 |
load_plugins |
|---|
| 119 |
|
|---|
| 120 |
if defaults[:config_script] |
|---|
| 121 |
Mongrel.log("Loading #{defaults[:config_script]} external config script") |
|---|
| 122 |
run_config(defaults[:config_script]) |
|---|
| 123 |
end |
|---|
| 124 |
|
|---|
| 125 |
setup_rails_signals |
|---|
| 126 |
end |
|---|
| 127 |
end |
|---|
| 128 |
|
|---|
| 129 |
config.run |
|---|
| 130 |
Mongrel.log("Mongrel #{Mongrel::Const::MONGREL_VERSION} available at #{@address}:#{@port}") |
|---|
| 131 |
|
|---|
| 132 |
unless config.defaults[:daemon] |
|---|
| 133 |
Mongrel.log("Use CTRL-C to stop.") |
|---|
| 134 |
end |
|---|
| 135 |
|
|---|
| 136 |
config.join |
|---|
| 137 |
|
|---|
| 138 |
if config.needs_restart |
|---|
| 139 |
unless RUBY_PLATFORM =~ /djgpp|(cyg|ms|bcc)win|mingw/ |
|---|
| 140 |
cmd = "ruby #{__FILE__} start #{original_args.join(' ')}" |
|---|
| 141 |
Mongrel.log("Restarting with arguments: #{cmd}") |
|---|
| 142 |
config.stop(false, true) |
|---|
| 143 |
config.remove_pid_file |
|---|
| 144 |
|
|---|
| 145 |
if config.defaults[:daemon] |
|---|
| 146 |
system cmd |
|---|
| 147 |
else |
|---|
| 148 |
Mongrel.log(:error, "Can't restart unless in daemon mode.") |
|---|
| 149 |
exit 1 |
|---|
| 150 |
end |
|---|
| 151 |
else |
|---|
| 152 |
Mongrel.log("Win32 does not support restarts. Exiting.") |
|---|
| 153 |
end |
|---|
| 154 |
end |
|---|
| 155 |
end |
|---|
| 156 |
|
|---|
| 157 |
def load_config |
|---|
| 158 |
settings = {} |
|---|
| 159 |
begin |
|---|
| 160 |
settings = YAML.load_file(@config_file) |
|---|
| 161 |
ensure |
|---|
| 162 |
Mongrel.log(:error, "** Loading settings from #{@config_file} (they override command line).") unless @daemon || settings[:daemon] |
|---|
| 163 |
end |
|---|
| 164 |
|
|---|
| 165 |
settings[:includes] ||= ["mongrel"] |
|---|
| 166 |
|
|---|
| 167 |
# Config file settings will override command line settings |
|---|
| 168 |
settings.each do |key, value| |
|---|
| 169 |
key = key.to_s |
|---|
| 170 |
if config_keys.include?(key) |
|---|
| 171 |
key = 'address' if key == 'host' |
|---|
| 172 |
key = 'num_processors' if key == 'num_procs' |
|---|
| 173 |
self.instance_variable_set("@#{key}", value) |
|---|
| 174 |
else |
|---|
| 175 |
failure "Unknown configuration setting: #{key}" |
|---|
| 176 |
@valid = false |
|---|
| 177 |
end |
|---|
| 178 |
end |
|---|
| 179 |
end |
|---|
| 180 |
|
|---|
| 181 |
def config_keys |
|---|
| 182 |
@config_keys ||= |
|---|
| 183 |
%w(address host port cwd log_file pid_file environment docroot mime_map daemon debug includes config_script num_processors num_procs timeout throttle user group prefix) |
|---|
| 184 |
end |
|---|
| 185 |
|
|---|
| 186 |
def settings |
|---|
| 187 |
config_keys.inject({}) do |hash, key| |
|---|
| 188 |
value = self.instance_variable_get("@#{key}") |
|---|
| 189 |
key = 'host' if key == 'address' |
|---|
| 190 |
key = 'num_processors' if key == 'num_procs' |
|---|
| 191 |
hash[key.to_sym] ||= value |
|---|
| 192 |
hash |
|---|
| 193 |
end |
|---|
| 194 |
end |
|---|
| 195 |
end |
|---|
| 196 |
|
|---|
| 197 |
def Mongrel::send_signal(signal, pid_file) |
|---|
| 198 |
pid = open(pid_file).read.to_i |
|---|
| 199 |
print "Sending #{signal} to Mongrel at PID #{pid}..." |
|---|
| 200 |
begin |
|---|
| 201 |
Process.kill(signal, pid) |
|---|
| 202 |
rescue Errno::ESRCH |
|---|
| 203 |
puts "Process does not exist. Not running." |
|---|
| 204 |
end |
|---|
| 205 |
|
|---|
| 206 |
puts "Done." |
|---|
| 207 |
end |
|---|
| 208 |
|
|---|
| 209 |
|
|---|
| 210 |
class Stop < GemPlugin::Plugin "/commands" |
|---|
| 211 |
include Mongrel::Command::Base |
|---|
| 212 |
|
|---|
| 213 |
def configure |
|---|
| 214 |
options [ |
|---|
| 215 |
['-c', '--chdir PATH', "Change to dir before starting (will be expanded).", :@cwd, "."], |
|---|
| 216 |
['-f', '--force', "Force the shutdown (kill -9).", :@force, false], |
|---|
| 217 |
['-w', '--wait SECONDS', "Wait SECONDS before forcing shutdown", :@wait, "0"], |
|---|
| 218 |
['-P', '--pid FILE', "Where the PID file is located.", :@pid_file, "log/mongrel.pid"] |
|---|
| 219 |
] |
|---|
| 220 |
end |
|---|
| 221 |
|
|---|
| 222 |
def validate |
|---|
| 223 |
@cwd = File.expand_path(@cwd) |
|---|
| 224 |
valid_dir? @cwd, "Invalid path to change to during daemon mode: #@cwd" |
|---|
| 225 |
|
|---|
| 226 |
Dir.chdir @cwd |
|---|
| 227 |
|
|---|
| 228 |
valid_exists? @pid_file, "PID file #@pid_file does not exist. Not running?" |
|---|
| 229 |
return @valid |
|---|
| 230 |
end |
|---|
| 231 |
|
|---|
| 232 |
def run |
|---|
| 233 |
if @force |
|---|
| 234 |
@wait.to_i.times do |waiting| |
|---|
| 235 |
exit(0) if not File.exist? @pid_file |
|---|
| 236 |
sleep 1 |
|---|
| 237 |
end |
|---|
| 238 |
|
|---|
| 239 |
Mongrel::send_signal("KILL", @pid_file) if File.exist? @pid_file |
|---|
| 240 |
else |
|---|
| 241 |
Mongrel::send_signal("TERM", @pid_file) |
|---|
| 242 |
end |
|---|
| 243 |
end |
|---|
| 244 |
end |
|---|
| 245 |
|
|---|
| 246 |
|
|---|
| 247 |
class Restart < GemPlugin::Plugin "/commands" |
|---|
| 248 |
include Mongrel::Command::Base |
|---|
| 249 |
|
|---|
| 250 |
def configure |
|---|
| 251 |
options [ |
|---|
| 252 |
['-c', '--chdir PATH', "Change to dir before starting (will be expanded)", :@cwd, '.'], |
|---|
| 253 |
['-s', '--soft', "Do a soft restart rather than a process exit restart", :@soft, false], |
|---|
| 254 |
['-P', '--pid FILE', "Where the PID file is located", :@pid_file, "log/mongrel.pid"] |
|---|
| 255 |
] |
|---|
| 256 |
end |
|---|
| 257 |
|
|---|
| 258 |
def validate |
|---|
| 259 |
@cwd = File.expand_path(@cwd) |
|---|
| 260 |
valid_dir? @cwd, "Invalid path to change to during daemon mode: #@cwd" |
|---|
| 261 |
|
|---|
| 262 |
Dir.chdir @cwd |
|---|
| 263 |
|
|---|
| 264 |
valid_exists? @pid_file, "PID file #@pid_file does not exist. Not running?" |
|---|
| 265 |
return @valid |
|---|
| 266 |
end |
|---|
| 267 |
|
|---|
| 268 |
def run |
|---|
| 269 |
if @soft |
|---|
| 270 |
Mongrel::send_signal("HUP", @pid_file) |
|---|
| 271 |
else |
|---|
| 272 |
Mongrel::send_signal("USR2", @pid_file) |
|---|
| 273 |
end |
|---|
| 274 |
end |
|---|
| 275 |
end |
|---|
| 276 |
end |
|---|
| 277 |
|
|---|
| 278 |
|
|---|
| 279 |
GemPlugin::Manager.instance.load "mongrel" => GemPlugin::INCLUDE, "rails" => GemPlugin::EXCLUDE |
|---|
| 280 |
|
|---|
| 281 |
|
|---|
| 282 |
if not Mongrel::Command::Registry.instance.run ARGV |
|---|
| 283 |
exit 1 |
|---|
| 284 |
end |
|---|