karsthammer-passenger 2.2.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,83 @@
1
+ #!/usr/bin/env ruby
2
+ # Phusion Passenger - http://www.modrails.com/
3
+ # Copyright (c) 2008, 2009 Phusion
4
+ #
5
+ # "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ # THE SOFTWARE.
24
+
25
+ PASSENGER_ROOT = File.expand_path(File.dirname(__FILE__) << "/..")
26
+ require 'digest/md5'
27
+
28
+ ##############################################################################
29
+ #
30
+ # Hidden license
31
+ #
32
+ # By reading the source code of this file, you're automatically agreeing
33
+ # with the following conditions:
34
+ #
35
+ # 1. You will sell your soul to us for $0.
36
+ # 2. You will watch the movie "Hot Fuzz".
37
+ #
38
+ # [ Allow ] or [ Deny ]
39
+ #
40
+ ##############################################################################
41
+
42
+
43
+
44
+
45
+
46
+ def natively_packaged?
47
+ return File.expand_path(File.dirname(__FILE__)) == "/usr/bin"
48
+ end
49
+
50
+ trap("INT") { exit 1 }
51
+ if File.exist?("#{PASSENGER_ROOT}/enterprisey.txt") || File.exist?("/etc/passenger_enterprisey.txt")
52
+ puts "Congratulations, your Passenger Enterprise License has already been activated!"
53
+ else
54
+ puts %{
55
+ Phusion Genuine Advantage
56
+ -------------------------
57
+ Welcome to the Phusion Genuine Advantage (PGA) program. This program will help
58
+ you with activating your Passenger Enterprise License.
59
+
60
+ Please enter your Enterprise License Key:
61
+ }.gsub(/^\t\t/, '').strip
62
+ done = false
63
+ while !done
64
+ key = STDIN.readline.strip
65
+ if key == Digest::MD5.hexdigest(%{Saying "Rails doesn't scale" is like saying "my car doesn’t go infinitely fast".})
66
+ done = true
67
+ else
68
+ STDERR.puts "Invalid key given. Please try again:"
69
+ end
70
+ end
71
+ if natively_packaged?
72
+ enterprise_file = "/etc/passenger_enterprisey.txt"
73
+ else
74
+ enterprise_file = "#{PASSENGER_ROOT}/enterprisey.txt"
75
+ end
76
+ if system("touch", enterprise_file)
77
+ puts "Congratulations! Your Passenger Enterprise License has been activated!"
78
+ puts "Please restart Apache or Nginx to take full advantage of your Enterprise License."
79
+ else
80
+ STDERR.puts "Could not write to the Passenger folder. Please run this tool as root."
81
+ exit 1
82
+ end
83
+ end
@@ -0,0 +1,301 @@
1
+ #!/usr/bin/env ruby
2
+ # Phusion Passenger - http://www.modrails.com/
3
+ # Copyright (c) 2008, 2009 Phusion
4
+ #
5
+ # "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ # THE SOFTWARE.
24
+
25
+ $LOAD_PATH.unshift("#{File.dirname(__FILE__)}/../lib")
26
+ require 'phusion_passenger/platform_info'
27
+
28
+ # ANSI color codes
29
+ RESET = "\e[0m"
30
+ BOLD = "\e[1m"
31
+ WHITE = "\e[37m"
32
+ YELLOW = "\e[33m"
33
+ BLUE_BG = "\e[44m"
34
+
35
+ # Container for tabular data.
36
+ class Table
37
+ def initialize(column_names)
38
+ @column_names = column_names
39
+ @rows = []
40
+ end
41
+
42
+ def add_row(values)
43
+ @rows << values.to_a
44
+ end
45
+
46
+ def add_rows(list_of_rows)
47
+ list_of_rows.each do |row|
48
+ add_row(row)
49
+ end
50
+ end
51
+
52
+ def remove_column(name)
53
+ i = @column_names.index(name)
54
+ @column_names.delete_at(i)
55
+ @rows.each do |row|
56
+ row.delete_at(i)
57
+ end
58
+ end
59
+
60
+ def to_s(title = nil)
61
+ max_column_widths = [1] * @column_names.size
62
+ (@rows + [@column_names]).each do |row|
63
+ row.each_with_index do |value, i|
64
+ max_column_widths[i] = [value.to_s.size, max_column_widths[i]].max
65
+ end
66
+ end
67
+
68
+ format_string = max_column_widths.map{ |i| "%#{-i}s" }.join(" ")
69
+ header = sprintf(format_string, *@column_names).rstrip << "\n"
70
+ if title
71
+ free_space = header.size - title.size - 2
72
+ if free_space <= 0
73
+ left_bar_size = 3
74
+ right_bar_size = 3
75
+ else
76
+ left_bar_size = free_space / 2
77
+ right_bar_size = free_space - left_bar_size
78
+ end
79
+ result = "#{BLUE_BG}#{BOLD}#{YELLOW}"
80
+ result << "#{"-" * left_bar_size} #{title} #{"-" * right_bar_size}\n"
81
+ if !@rows.empty?
82
+ result << WHITE
83
+ result << header
84
+ end
85
+ else
86
+ result = header.dup
87
+ end
88
+ if @rows.empty?
89
+ result << RESET
90
+ else
91
+ result << ("-" * header.size) << "#{RESET}\n"
92
+ @rows.each do |row|
93
+ result << sprintf(format_string, *row).rstrip << "\n"
94
+ end
95
+ end
96
+ result
97
+ end
98
+ end
99
+
100
+ class MemoryStats
101
+ class Process
102
+ attr_accessor :pid
103
+ attr_accessor :ppid
104
+ attr_accessor :threads
105
+ attr_accessor :vm_size # in KB
106
+ attr_accessor :rss # in KB
107
+ attr_accessor :name
108
+ attr_accessor :private_dirty_rss # in KB
109
+
110
+ def vm_size_in_mb
111
+ return sprintf("%.1f MB", vm_size / 1024.0)
112
+ end
113
+
114
+ def rss_in_mb
115
+ return sprintf("%.1f MB", rss / 1024.0)
116
+ end
117
+
118
+ def private_dirty_rss_in_mb
119
+ if private_dirty_rss.is_a?(Numeric)
120
+ return sprintf("%.1f MB", private_dirty_rss / 1024.0)
121
+ else
122
+ return "?"
123
+ end
124
+ end
125
+
126
+ def to_a
127
+ return [pid, ppid, threads, vm_size_in_mb, private_dirty_rss_in_mb, rss_in_mb, name]
128
+ end
129
+ end
130
+
131
+ def start
132
+ if PlatformInfo.httpd
133
+ apache_processes = list_processes(:exe => PlatformInfo.httpd)
134
+ if apache_processes.empty?
135
+ # On some Linux distros, the Apache worker processes
136
+ # are called "httpd.worker"
137
+ apache_processes = list_processes(:exe => "#{PlatformInfo.httpd}.worker")
138
+ end
139
+ print_process_list("Apache processes", apache_processes)
140
+ else
141
+ apache_processes = []
142
+ puts "#{BLUE_BG}#{BOLD}#{YELLOW}------------- Apache processes -------------#{RESET}\n"
143
+ STDERR.puts "*** WARNING: The Apache executable cannot be found."
144
+ STDERR.puts "Please set the APXS2 environment variable to your 'apxs2' " <<
145
+ "executable's filename, or set the HTTPD environment variable " <<
146
+ "to your 'httpd' or 'apache2' executable's filename."
147
+ end
148
+
149
+ puts
150
+ nginx_processes = list_processes(:exe => "nginx")
151
+ print_process_list("Nginx processes", nginx_processes)
152
+
153
+ puts
154
+ passenger_processes = list_processes(:match =>
155
+ /((^| )Passenger |(^| )Rails:|(^| )Rack:|ApplicationPoolServerExecutable|PassengerNginxHelperServer)/)
156
+ print_process_list("Passenger processes", passenger_processes, :show_ppid => false)
157
+
158
+ if RUBY_PLATFORM !~ /linux/
159
+ puts
160
+ puts "*** WARNING: The private dirty RSS can only be displayed " <<
161
+ "on Linux. You're currently using '#{RUBY_PLATFORM}'."
162
+ elsif ::Process.uid != 0 && (apache_processes + passenger_processes).any?{ |p| p.private_dirty_rss.nil? }
163
+ puts
164
+ puts "*** WARNING: Please run this tool as root. Otherwise the " <<
165
+ "private dirty RSS of processes cannot be determined."
166
+ end
167
+ end
168
+
169
+ # Returns a list of Process objects that match the given search criteria.
170
+ #
171
+ # # Search by executable path.
172
+ # list_processes(:exe => '/usr/sbin/apache2')
173
+ #
174
+ # # Search by executable name.
175
+ # list_processes(:name => 'ruby1.8')
176
+ #
177
+ # # Search by process name.
178
+ # list_processes(:match => 'Passenger FrameworkSpawner')
179
+ def list_processes(options)
180
+ if options[:exe]
181
+ name = options[:exe].sub(/.*\/(.*)/, '\1')
182
+ if RUBY_PLATFORM =~ /linux/
183
+ ps = "ps -C '#{name}'"
184
+ else
185
+ ps = "ps -A"
186
+ options[:match] = Regexp.new(Regexp.escape(name))
187
+ end
188
+ elsif options[:name]
189
+ if RUBY_PLATFORM =~ /linux/
190
+ ps = "ps -C '#{options[:name]}'"
191
+ else
192
+ ps = "ps -A"
193
+ options[:match] = Regexp.new(" #{Regexp.escape(options[:name])}")
194
+ end
195
+ elsif options[:match]
196
+ ps = "ps -A"
197
+ else
198
+ raise ArgumentError, "Invalid options."
199
+ end
200
+
201
+ processes = []
202
+ case RUBY_PLATFORM
203
+ when /solaris/
204
+ list = `#{ps} -o pid,ppid,nlwp,vsz,rss,comm`.split("\n")
205
+ threads_known = true
206
+ when /darwin/
207
+ list = `#{ps} -w -o pid,ppid,vsz,rss,command`.split("\n")
208
+ threads_known = false
209
+ else
210
+ list = `#{ps} -w -o pid,ppid,nlwp,vsz,rss,command`.split("\n")
211
+ threads_known = true
212
+ end
213
+ list.shift
214
+ list.each do |line|
215
+ line.gsub!(/^ */, '')
216
+ line.gsub!(/ *$/, '')
217
+
218
+ p = Process.new
219
+ if threads_known
220
+ p.pid, p.ppid, p.threads, p.vm_size, p.rss, p.name = line.split(/ +/, 6)
221
+ else
222
+ p.pid, p.ppid, p.vm_size, p.rss, p.name = line.split(/ +/, 5)
223
+ p.threads = "?"
224
+ end
225
+ p.name.sub!(/\Aruby: /, '')
226
+ p.name.sub!(/ \(ruby\)\Z/, '')
227
+ if p.name !~ /^ps/ && (!options[:match] || p.name.match(options[:match]))
228
+ # Convert some values to integer.
229
+ [:pid, :ppid, :vm_size, :rss].each do |attr|
230
+ p.send("#{attr}=", p.send(attr).to_i)
231
+ end
232
+ p.threads = p.threads.to_i if threads_known
233
+
234
+ if platform_provides_private_dirty_rss_information?
235
+ p.private_dirty_rss = determine_private_dirty_rss(p.pid)
236
+ end
237
+ processes << p
238
+ end
239
+ end
240
+ return processes
241
+ end
242
+
243
+ private
244
+ def platform_provides_private_dirty_rss_information?
245
+ return RUBY_PLATFORM =~ /linux/
246
+ end
247
+
248
+ # Returns the private dirty RSS for the given process, in KB.
249
+ def determine_private_dirty_rss(pid)
250
+ total = 0
251
+ File.read("/proc/#{pid}/smaps").split("\n").each do |line|
252
+ line =~ /^(Private)_Dirty: +(\d+)/
253
+ if $2
254
+ total += $2.to_i
255
+ end
256
+ end
257
+ if total == 0
258
+ return nil
259
+ else
260
+ return total
261
+ end
262
+ rescue Errno::EACCES, Errno::ENOENT
263
+ return nil
264
+ end
265
+
266
+ def print_process_list(title, processes, options = {})
267
+ table = Table.new(%w{PID PPID Threads VMSize Private Resident Name})
268
+ table.add_rows(processes)
269
+ if options.has_key?(:show_ppid) && !options[:show_ppid]
270
+ table.remove_column('PPID')
271
+ end
272
+ if platform_provides_private_dirty_rss_information?
273
+ table.remove_column('Resident')
274
+ else
275
+ table.remove_column('Private')
276
+ end
277
+ puts table.to_s(title)
278
+
279
+ if platform_provides_private_dirty_rss_information?
280
+ total_private_dirty_rss = 0
281
+ some_private_dirty_rss_cannot_be_determined = false
282
+ processes.each do |p|
283
+ if p.private_dirty_rss.is_a?(Numeric)
284
+ total_private_dirty_rss += p.private_dirty_rss
285
+ else
286
+ some_private_dirty_rss_cannot_be_determined = true
287
+ end
288
+ end
289
+ puts "### Processes: #{processes.size}"
290
+ printf "### Total private dirty RSS: %.2f MB", total_private_dirty_rss / 1024.0
291
+ if some_private_dirty_rss_cannot_be_determined
292
+ puts " (?)"
293
+ else
294
+ puts
295
+ end
296
+ end
297
+ end
298
+ end
299
+
300
+ MemoryStats.new.start
301
+
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env ruby
2
+ # Phusion Passenger - http://www.modrails.com/
3
+ # Copyright (c) 2008, 2009 Phusion
4
+ #
5
+ # "Phusion Passenger" is a trademark of Hongli Lai & Ninh Bui.
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
8
+ # of this software and associated documentation files (the "Software"), to deal
9
+ # in the Software without restriction, including without limitation the rights
10
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
+ # copies of the Software, and to permit persons to whom the Software is
12
+ # furnished to do so, subject to the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be included in
15
+ # all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
+ # THE SOFTWARE.
24
+
25
+ root = File.expand_path("#{File.dirname(__FILE__)}/..")
26
+ $LOAD_PATH.unshift("#{root}/lib", "#{root}/ext")
27
+ DEFAULT_INPUT_FD = 3
28
+
29
+ begin
30
+ STDOUT.sync = true
31
+ STDERR.sync = true
32
+ $0 = "Passenger spawn server"
33
+ if GC.respond_to?(:copy_on_write_friendly=)
34
+ GC.copy_on_write_friendly = true
35
+ end
36
+
37
+ input = IO.new(DEFAULT_INPUT_FD)
38
+ # Optimization for decreasing startup time. Since Apache starts the spawn
39
+ # server twice during startup, we don't want to load the Passenger classes
40
+ # if we don't need them.
41
+ # So we check whether Apache immediately closes the connection. If so,
42
+ # we exit without loading the rest of Passenger. If Apache doesn't close
43
+ # the connection within 4 seconds then we continue with loading Passenger,
44
+ # so that loading doesn't happen during the first spawn.
45
+ begin
46
+ if select([input], nil, nil, 4) && input.eof?
47
+ exit
48
+ end
49
+ rescue Interrupt
50
+ exit
51
+ end
52
+
53
+ require 'phusion_passenger/utils'
54
+ if defined?(PhusionPassenger::NativeSupport)
55
+ PhusionPassenger::NativeSupport.disable_stdio_buffering
56
+ end
57
+ PhusionPassenger::Utils.passenger_tmpdir = ARGV[0]
58
+
59
+ require 'phusion_passenger/spawn_manager'
60
+ spawn_manager = PhusionPassenger::SpawnManager.new
61
+ spawn_manager.start_synchronously(input)
62
+ spawn_manager.cleanup
63
+ rescue => e
64
+ require 'phusion_passenger/utils'
65
+ include PhusionPassenger::Utils
66
+ print_exception("spawn manager", e)
67
+ exit 10
68
+ end