1
0
Fork 0
mirror of https://github.com/puma/puma.git synced 2022-11-09 13:48:40 -05:00
puma--puma/lib/puma/control_cli.rb

263 lines
6.4 KiB
Ruby
Raw Normal View History

require 'optparse'
require 'puma/state_file'
require 'puma/const'
require 'puma/detect'
2011-12-07 16:42:53 -05:00
require 'puma/configuration'
require 'uri'
require 'socket'
module Puma
class ControlCLI
COMMANDS = %w{halt restart phased-restart start stats status stop reload-worker-directory gc gc-stats}
2012-09-02 08:56:05 -04:00
def initialize(argv, stdout=STDOUT, stderr=STDERR)
@state = nil
@quiet = false
@pidfile = nil
@pid = nil
@control_url = nil
@control_auth_token = nil
@config_file = nil
@command = nil
@argv = argv.dup
@stdout = stdout
@stderr = stderr
@cli_options = {}
2012-10-16 01:24:22 -04:00
opts = OptionParser.new do |o|
o.banner = "Usage: pumactl (-p PID | -P pidfile | -S status_file | -C url -T token | -F config.rb) (#{COMMANDS.join("|")})"
2012-10-16 01:24:22 -04:00
o.on "-S", "--state PATH", "Where the state file to use is" do |arg|
@state = arg
2012-09-02 08:56:05 -04:00
end
2012-10-16 01:24:22 -04:00
o.on "-Q", "--quiet", "Not display messages" do |arg|
@quiet = true
2012-09-02 08:56:05 -04:00
end
2012-10-16 01:24:22 -04:00
o.on "-P", "--pidfile PATH", "Pid file" do |arg|
@pidfile = arg
2012-09-02 08:56:05 -04:00
end
2012-10-16 01:24:22 -04:00
2012-10-16 01:41:23 -04:00
o.on "-p", "--pid PID", "Pid" do |arg|
@pid = arg.to_i
2012-10-16 01:41:23 -04:00
end
2012-10-16 01:24:22 -04:00
o.on "-C", "--control-url URL", "The bind url to use for the control server" do |arg|
@control_url = arg
end
2012-10-16 01:24:22 -04:00
o.on "-T", "--control-token TOKEN", "The token to use as authentication for the control server" do |arg|
@control_auth_token = arg
2012-09-02 08:56:05 -04:00
end
2012-10-16 01:24:22 -04:00
o.on "-F", "--config-file PATH", "Puma config script" do |arg|
@config_file = arg
end
2012-10-16 01:24:22 -04:00
o.on_tail("-H", "--help", "Show this message") do
2012-10-16 01:37:28 -04:00
@stdout.puts o
2012-09-02 08:56:05 -04:00
exit
end
2012-10-16 01:24:22 -04:00
o.on_tail("-V", "--version", "Show version") do
2012-09-02 08:56:05 -04:00
puts Const::PUMA_VERSION
exit
end
2012-10-16 01:24:22 -04:00
end
2012-10-16 01:37:28 -04:00
opts.order!(argv) { |a| opts.terminate a }
@command = argv.shift
unless @config_file == '-'
if @config_file.nil? and File.exist?('config/puma.rb')
@config_file = 'config/puma.rb'
end
if @config_file
config = Puma::Configuration.new({ config_files: [@config_file] }, {})
config.load
@state ||= config.options[:state]
@control_url ||= config.options[:control_url]
@control_auth_token ||= config.options[:control_auth_token]
@pidfile ||= config.options[:pidfile]
end
end
2012-09-02 08:56:05 -04:00
# check present of command
unless @command
2012-09-02 08:56:05 -04:00
raise "Available commands: #{COMMANDS.join(", ")}"
2012-10-16 01:24:22 -04:00
end
unless COMMANDS.include? @command
raise "Invalid command: #{@command}"
end
2012-10-16 01:24:22 -04:00
2012-09-02 08:56:05 -04:00
rescue => e
@stdout.puts e.message
@stdout.puts e.backtrace
2012-09-02 08:56:05 -04:00
exit 1
end
2012-10-16 01:24:22 -04:00
def message(msg)
@stdout.puts msg unless @quiet
end
2012-09-02 08:56:05 -04:00
def prepare_configuration
if @state
unless File.exist? @state
raise "State file not found: #{@state}"
2012-10-16 01:24:22 -04:00
end
sf = Puma::StateFile.new
sf.load @state
2012-10-16 01:24:22 -04:00
@control_url = sf.control_url
@control_auth_token = sf.control_auth_token
@pid = sf.pid
elsif @pidfile
2012-09-02 08:56:05 -04:00
# get pid from pid_file
@pid = File.open(@pidfile).gets.to_i
end
end
2012-09-02 08:56:05 -04:00
def send_request
uri = URI.parse @control_url
2012-09-02 08:56:05 -04:00
# create server object by scheme
@server = case uri.scheme
2012-10-16 01:41:23 -04:00
when "tcp"
TCPSocket.new uri.host, uri.port
when "unix"
UNIXSocket.new "#{uri.host}#{uri.path}"
else
raise "Invalid scheme: #{uri.scheme}"
end
2012-10-16 01:24:22 -04:00
if @command == "status"
2012-10-16 01:24:22 -04:00
message "Puma is started"
else
url = "/#{@command}"
2012-10-16 01:24:22 -04:00
if @control_auth_token
url = url + "?token=#{@control_auth_token}"
2012-09-02 08:56:05 -04:00
end
2012-10-16 01:24:22 -04:00
2012-09-02 08:56:05 -04:00
@server << "GET #{url} HTTP/1.0\r\n\r\n"
2012-10-16 01:24:22 -04:00
2013-06-01 16:55:17 -04:00
unless data = @server.read
raise "Server closed connection before responding"
2013-06-01 17:24:33 -04:00
end
2013-06-01 16:55:17 -04:00
response = data.split("\r\n")
if response.empty?
raise "Server sent empty response"
end
2012-10-16 01:24:22 -04:00
(@http,@code,@message) = response.first.split(" ",3)
2012-10-16 01:24:22 -04:00
2012-09-02 08:56:05 -04:00
if @code == "403"
raise "Unauthorized access to server (wrong auth token)"
elsif @code == "404"
raise "Command error: #{response.last}"
2012-09-02 08:56:05 -04:00
elsif @code != "200"
raise "Bad response from server: #{@code}"
end
2012-10-16 01:24:22 -04:00
message "Command #{@command} sent success"
message response.last if @command == "stats" || @command == "gc-stats"
end
2012-09-02 08:56:05 -04:00
@server.close
end
2012-09-02 08:56:05 -04:00
def send_signal
unless @pid
2012-10-16 01:41:23 -04:00
raise "Neither pid nor control url available"
end
begin
2012-10-16 01:24:22 -04:00
case @command
when "restart"
Process.kill "SIGUSR2", @pid
2012-10-16 01:24:22 -04:00
when "halt"
Process.kill "QUIT", @pid
2012-10-16 01:24:22 -04:00
when "stop"
Process.kill "SIGTERM", @pid
2012-10-16 01:41:23 -04:00
when "stats"
puts "Stats not available via pid only"
return
2012-10-16 01:24:22 -04:00
when "reload-worker-directory"
puts "reload-worker-directory not available via pid only"
return
2014-02-25 08:52:20 -05:00
when "phased-restart"
Process.kill "SIGUSR1", @pid
else
message "Puma is started"
return
end
rescue SystemCallError
if @command == "restart"
start
else
raise "No pid '#{@pid}' found"
end
end
2012-10-16 01:24:22 -04:00
message "Command #{@command} sent success"
end
2012-09-02 08:56:05 -04:00
def run
start if @command == "start"
2012-10-16 01:37:28 -04:00
2012-09-02 08:56:05 -04:00
prepare_configuration
if Puma.windows?
2012-09-02 08:56:05 -04:00
send_request
else
@control_url ? send_request : send_signal
end
2012-09-02 08:56:05 -04:00
rescue => e
message e.message
message e.backtrace
2012-09-02 08:56:05 -04:00
exit 1
end
private
def start
require 'puma/cli'
run_args = []
run_args += ["-S", @state] if @state
run_args += ["-q"] if @quiet
run_args += ["--pidfile", @pidfile] if @pidfile
run_args += ["--control", @control_url] if @control_url
run_args += ["--control-token", @control_auth_token] if @control_auth_token
run_args += ["-C", @config_file] if @config_file
events = Puma::Events.new @stdout, @stderr
# replace $0 because puma use it to generate restart command
2015-11-06 14:00:49 -05:00
puma_cmd = $0.gsub(/pumactl$/, 'puma')
$0 = puma_cmd if File.exist?(puma_cmd)
cli = Puma::CLI.new run_args, events
cli.run
end
end
end