# Phusion Passenger - http://www.modrails.com/ # Copyright (c) 2008, 2009 Phusion # # "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui. # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. require 'rexml/document' require 'fileutils' require 'socket' require 'phusion_passenger/admin_tools' require 'phusion_passenger/message_channel' module PhusionPassenger module AdminTools class ControlProcess class Instance attr_accessor :pid, :socket_name, :socket_type, :sessions, :uptime INT_PROPERTIES = [:pid, :sessions] end attr_accessor :path attr_accessor :pid def self.list(clean_stale = true) results = [] Dir["#{AdminTools.tmpdir}/passenger.*"].each do |dir| next if dir !~ /passenger.(\d+)\Z/ begin results << ControlProcess.new(dir) rescue ArgumentError # Stale Passenger temp folder. Clean it up if instructed. if clean_stale puts "*** Cleaning stale folder #{dir}" FileUtils.chmod_R(0700, dir) rescue nil FileUtils.rm_rf(dir) end end end return results end def self.for_pid(pid) return list(false).find { |c| c.pid == pid } end def initialize(path) @path = path if File.exist?("#{path}/control_process.pid") data = File.read("#{path}/control_process.pid").strip if data.empty? raise ArgumentError, "'#{path}' is not a valid control process directory." else @pid = data.to_i end else path =~ /passenger.(\d+)\Z/ @pid = $1.to_i end if !AdminTools.process_is_alive?(@pid) raise ArgumentError, "There is no control process with PID #{@pid}." end end def status connect do |channel| channel.write("status") return channel.read_scalar end end def backtraces connect do |channel| channel.write("backtraces") return channel.read_scalar end end def xml connect do |channel| channel.write("status_xml") return channel.read_scalar end end def domains doc = REXML::Document.new(xml) domains = [] doc.elements.each("info/domains/domain") do |domain| instances = [] d = { :name => domain.elements["name"].text, :instances => instances } domain.elements.each("instances/instance") do |instance| i = Instance.new instance.elements.each do |element| if i.respond_to?("#{element.name}=") if Instance::INT_PROPERTIES.include?(element.name.to_sym) value = element.text.to_i else value = element.text end i.send("#{element.name}=", value) end end instances << i end domains << d end return domains end def instances return domains.map do |domain| domain[:instances] end.flatten end private def connect channel = MessageChannel.new(UNIXSocket.new("#{path}/info/status.socket")) begin yield channel ensure channel.close end end end end # module AdminTools end # module PhusionPassenger