balepc-zombie_passenger_killer 0.2.1.patched
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +7 -0
- data/Gemfile.lock +26 -0
- data/Rakefile +21 -0
- data/Readme.md +66 -0
- data/bin/zombie_passenger_killer +39 -0
- data/lib/zombie_passenger_killer/reaper.rb +91 -0
- data/lib/zombie_passenger_killer/version.rb +3 -0
- data/lib/zombie_passenger_killer.rb +4 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/zombie_passenger_killer_spec.rb +178 -0
- data/zombie_passenger_killer.gemspec +12 -0
- metadata +78 -0
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
zombie_passenger_killer (0.2.1)
|
|
5
|
+
|
|
6
|
+
GEM
|
|
7
|
+
remote: http://rubygems.org/
|
|
8
|
+
specs:
|
|
9
|
+
diff-lcs (1.1.3)
|
|
10
|
+
rake (0.9.2)
|
|
11
|
+
rspec (2.6.0)
|
|
12
|
+
rspec-core (~> 2.6.0)
|
|
13
|
+
rspec-expectations (~> 2.6.0)
|
|
14
|
+
rspec-mocks (~> 2.6.0)
|
|
15
|
+
rspec-core (2.6.4)
|
|
16
|
+
rspec-expectations (2.6.0)
|
|
17
|
+
diff-lcs (~> 1.1.2)
|
|
18
|
+
rspec-mocks (2.6.0)
|
|
19
|
+
|
|
20
|
+
PLATFORMS
|
|
21
|
+
ruby
|
|
22
|
+
|
|
23
|
+
DEPENDENCIES
|
|
24
|
+
rake
|
|
25
|
+
rspec (~> 2)
|
|
26
|
+
zombie_passenger_killer!
|
data/Rakefile
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'bundler/gem_tasks'
|
|
2
|
+
|
|
3
|
+
task :default do
|
|
4
|
+
sh "rspec spec/"
|
|
5
|
+
end
|
|
6
|
+
|
|
7
|
+
rule /^version:bump:.*/ do |t|
|
|
8
|
+
sh "git status | grep 'nothing to commit'" # ensure we are not dirty
|
|
9
|
+
index = ['major', 'minor','patch'].index(t.name.split(':').last)
|
|
10
|
+
file = 'lib/zombie_passenger_killer/version.rb'
|
|
11
|
+
|
|
12
|
+
version_file = File.read(file)
|
|
13
|
+
old_version, *version_parts = version_file.match(/(\d+)\.(\d+)\.(\d+)/).to_a
|
|
14
|
+
version_parts[index] = version_parts[index].to_i + 1
|
|
15
|
+
version_parts[2] = 0 if index < 2 # remove patch for minor
|
|
16
|
+
version_parts[1] = 0 if index < 1 # remove minor for major
|
|
17
|
+
new_version = version_parts * '.'
|
|
18
|
+
File.open(file,'w'){|f| f.write(version_file.sub(old_version, new_version)) }
|
|
19
|
+
|
|
20
|
+
sh "bundle && git add #{file} Gemfile.lock && git commit -m 'bump version to #{new_version}'"
|
|
21
|
+
end
|
data/Readme.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
Guaranteed zombie passengers death.
|
|
4
|
+
|
|
5
|
+
- passenger process no longer listed in passenger-status ? => Death
|
|
6
|
+
- high CPU load over long period (Optional) ? => Death
|
|
7
|
+
|
|
8
|
+
strace of killed zombies is printed, so debugging is easier.
|
|
9
|
+
|
|
10
|
+
(god/bluepill are not suited to monitor passenger apps because of ever-changing pids)
|
|
11
|
+
|
|
12
|
+
Add passenger-status to `/etc/sudoers` or run with sudo.
|
|
13
|
+
|
|
14
|
+
Install
|
|
15
|
+
=======
|
|
16
|
+
sudo gem install zombie_passenger_killer
|
|
17
|
+
|
|
18
|
+
Usage
|
|
19
|
+
=====
|
|
20
|
+
|
|
21
|
+
zombie_passenger_killer [options]
|
|
22
|
+
|
|
23
|
+
Options:
|
|
24
|
+
-m, --max [SIZE] Max high CPU entries in history before killing (default: off)
|
|
25
|
+
--history [SIZE] History size (default: 5)
|
|
26
|
+
-c, --cpu [PERCENT] Mark as high CPU when above PERCENT (default: 70)
|
|
27
|
+
-g, --grace [SECONDS] Wait SECONDS before hard-killing (-9) a process (default: 5)
|
|
28
|
+
-i, --interval [SECONDS] Check every SECONDS (default: 10)
|
|
29
|
+
-p, --pattern [PATTERN] Find processes with this pattern (default: ' Rack: ')
|
|
30
|
+
-r, --rvm-sudo Use `rvmsudo` to see passenger-status
|
|
31
|
+
-h, --help Show this
|
|
32
|
+
-v, --version Show Version
|
|
33
|
+
-t, --time Show time in output
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
### Bluepill script
|
|
37
|
+
|
|
38
|
+
app.process("zombie_passenger_killer") do |process|
|
|
39
|
+
process.start_command = "zombie_passenger_killer --max 5 --history 10 --cpu 30 --interval 10"
|
|
40
|
+
process.stdout = process.stderr = "/var/log/autorotate/zombie_passenger_killer.log"
|
|
41
|
+
process.pid_file = "/var/run/zombie_passenger_killer.pid"
|
|
42
|
+
process.daemonize = true
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
### Monit script
|
|
46
|
+
|
|
47
|
+
check process zombie_killer
|
|
48
|
+
with pidfile "/var/run/zombie_passenger_killer.pid"
|
|
49
|
+
start program = "/bin/bash -c 'export PATH=$PATH:/usr/local/bin HOME=/home;zombie_passenger_killer --max 5 --history 10 --cpu 30 --interval 10 &>/var/log/zombie_passenger_killer.log & &>/dev/null;echo $! > /var/run/zombie_passenger_killer.pid'"
|
|
50
|
+
stop program = "/bin/bash -c 'PIDF=/var/run/zombie_passenger_killer.pid;/bin/kill `cat $PIDF` && rm -f $PIDF'"
|
|
51
|
+
group zombie_killer
|
|
52
|
+
|
|
53
|
+
### God script
|
|
54
|
+
|
|
55
|
+
# TODO
|
|
56
|
+
|
|
57
|
+
Author
|
|
58
|
+
======
|
|
59
|
+
|
|
60
|
+
###Contributors
|
|
61
|
+
- [Roman Heinrich](https://github.com/mindreframer)
|
|
62
|
+
- [Kevin Mullin](https://github.com/kmullin)
|
|
63
|
+
|
|
64
|
+
[Michael Grosser](http://grosser.it)<br/>
|
|
65
|
+
michael@grosser.it<br/>
|
|
66
|
+
Hereby placed under public domain, do what you want, just do not hold me accountable...
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
require 'optparse'
|
|
3
|
+
|
|
4
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
|
|
5
|
+
require 'zombie_passenger_killer'
|
|
6
|
+
|
|
7
|
+
options = {}
|
|
8
|
+
version = ZombiePassengerKiller::VERSION
|
|
9
|
+
OptionParser.new do |opts|
|
|
10
|
+
opts.banner = <<BANNER
|
|
11
|
+
Guaranteed zombie passengers death
|
|
12
|
+
|
|
13
|
+
Usage:
|
|
14
|
+
zombie_passenger_killer [options]
|
|
15
|
+
|
|
16
|
+
Options:
|
|
17
|
+
BANNER
|
|
18
|
+
opts.on("-m", "--max [SIZE]", Integer, "Max high CPU entries in history before killing (default: off)") {|i| options[:max]=i }
|
|
19
|
+
opts.on("--history [SIZE]", Integer, "History size (default: 5)") {|i| options[:history]=i }
|
|
20
|
+
opts.on("-c", "--cpu [PERCENT]", Integer, "Mark as high CPU when above PERCENT (default: 70)") {|i| options[:cpu]=i }
|
|
21
|
+
opts.on("-g", "--grace [SECONDS]", Integer, "Wait SECONDS before hard-killing (-9) a process (default: 5)") {|i| options[:grace]=i }
|
|
22
|
+
opts.on("-i", "--interval [SECONDS]", Integer, "Check every SECONDS (default: 10)") {|i| options[:interval]=i }
|
|
23
|
+
opts.on("-p", "--pattern [PATTERN]", String, "Find processes with this pattern (default: ' Rack: ')") {|i| options[:pattern]=i }
|
|
24
|
+
opts.on("-n", "--no-daemon","Do not start daemon. Check once and exit") {|i| options[:no_daemon]=i }
|
|
25
|
+
opts.on("-r", "--rvm-sudo","Use `rvmsudo` to see passenger-status") {|i| options[:rvm_sudo]=i }
|
|
26
|
+
opts.on("-h", "--help","Show this") { puts opts; exit }
|
|
27
|
+
opts.on("-v", "--version","Show Version"){ puts version; exit }
|
|
28
|
+
opts.on("-t", "--timing","Show timing on output") { options[:show_times]=true }
|
|
29
|
+
end.parse!
|
|
30
|
+
|
|
31
|
+
$stdout.sync = true
|
|
32
|
+
puts "PID: #{$$} Version: #{version} Started at #{Time.now}"
|
|
33
|
+
|
|
34
|
+
$0 = File.basename(__FILE__) + '-' + version
|
|
35
|
+
unless options[:no_daemon].nil?
|
|
36
|
+
ZombiePassengerKiller::Reaper.new(options).hunt_zombies
|
|
37
|
+
else
|
|
38
|
+
ZombiePassengerKiller::Reaper.new(options).lurk
|
|
39
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
module ZombiePassengerKiller
|
|
2
|
+
class Reaper
|
|
3
|
+
|
|
4
|
+
attr_accessor :out # overwriteable for tests
|
|
5
|
+
|
|
6
|
+
def initialize(options)
|
|
7
|
+
@history = {}
|
|
8
|
+
@history_entries = options[:history] || 5
|
|
9
|
+
@max_high_cpu = options[:max]
|
|
10
|
+
@high_cpu = options[:cpu] || 70
|
|
11
|
+
@grace_time = options[:grace] || 5
|
|
12
|
+
@pattern = options[:pattern] || ' Rack: '
|
|
13
|
+
@show_times = options[:show_times] || false
|
|
14
|
+
@interval = options[:interval] || 10
|
|
15
|
+
@strace_time = 5
|
|
16
|
+
@out = STDOUT
|
|
17
|
+
@rvm_sudo = options[:rvm_sudo] || false
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def lurk
|
|
21
|
+
loop do
|
|
22
|
+
hunt_zombies
|
|
23
|
+
sleep @interval
|
|
24
|
+
end
|
|
25
|
+
rescue Interrupt
|
|
26
|
+
log "Exiting..."
|
|
27
|
+
raise $!
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def store_current_cpu(processes)
|
|
31
|
+
keys_to_remove = @history.keys - processes.map{|x| x[:pid] }
|
|
32
|
+
keys_to_remove.each{|k| !@history.delete k }
|
|
33
|
+
|
|
34
|
+
processes.each do |process|
|
|
35
|
+
@history[process[:pid]] ||= []
|
|
36
|
+
@history[process[:pid]] << process[:cpu]
|
|
37
|
+
@history[process[:pid]] = @history[process[:pid]].last(@history_entries)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def get_strace(pid, time)
|
|
42
|
+
Process.getpgid(pid) rescue return 'No such process'
|
|
43
|
+
`( strace -p #{pid} 2>&1 ) & sleep #{time} ; kill $! 2>&1`
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def hunt_zombies
|
|
47
|
+
active_pids_in_passenger_status = passenger_pids
|
|
48
|
+
active_processes_in_processlist = process_status
|
|
49
|
+
zombies = active_processes_in_processlist.map{|x| x[:pid] } - active_pids_in_passenger_status rescue Array.new
|
|
50
|
+
|
|
51
|
+
# kill processes with high CPU if user wants it
|
|
52
|
+
high_load = if @max_high_cpu
|
|
53
|
+
store_current_cpu active_processes_in_processlist
|
|
54
|
+
active_pids_in_passenger_status.select do |pid|
|
|
55
|
+
@history[pid].count{|x| x > @high_cpu } >= @max_high_cpu
|
|
56
|
+
end
|
|
57
|
+
else
|
|
58
|
+
[]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
(high_load + zombies).each do |pid|
|
|
62
|
+
kill_zombie pid
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# return array of pids reported from passenger-status command, nil if passenger-status doesn't run
|
|
67
|
+
def passenger_pids
|
|
68
|
+
pids = %x(#{'rvmsudo ' if @rvm_sudo}passenger-status|grep PID).split("\n").map { |x| x.strip.match(/PID: \d*/).to_s.split[1].to_i }
|
|
69
|
+
pids if $?.exitstatus.zero?
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def process_status
|
|
73
|
+
%x(ps -eo pid,pcpu,args|grep -v grep|grep '#{@pattern}').split("\n").map do |line|
|
|
74
|
+
values = line.strip.split[0..1]
|
|
75
|
+
{:pid => values.first.to_i, :cpu => values.last.to_f}
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def kill_zombie(pid)
|
|
80
|
+
log "Killing passenger process #{pid}"
|
|
81
|
+
log get_strace(pid, @strace_time)
|
|
82
|
+
Process.kill('TERM', pid) rescue nil
|
|
83
|
+
sleep @grace_time # wait for it to die
|
|
84
|
+
Process.kill('KILL', pid) rescue nil
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def log(msg)
|
|
88
|
+
@out.puts "#{@show_times ? "** [#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}] #$$: " : ''}#{msg}"
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
require File.expand_path('spec/spec_helper')
|
|
2
|
+
|
|
3
|
+
describe ZombiePassengerKiller do
|
|
4
|
+
let(:killer){
|
|
5
|
+
ZombiePassengerKiller::Reaper.new(@options || {}).tap do |k|
|
|
6
|
+
k.stub!(:passenger_pids).and_return([111])
|
|
7
|
+
k.out = StringIO.new
|
|
8
|
+
end
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
def output
|
|
12
|
+
killer.out.rewind
|
|
13
|
+
killer.out.read
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "has a VERSION" do
|
|
17
|
+
ZombiePassengerKiller::VERSION.should =~ /^\d+\.\d+\.\d+$/
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "#hunt_zombies" do
|
|
21
|
+
it "does not kill anything by default" do
|
|
22
|
+
killer.should_not_receive(:kill_zombie)
|
|
23
|
+
killer.hunt_zombies
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "finds the right zombies" do
|
|
27
|
+
killer.stub!(:passenger_pids).and_return([123])
|
|
28
|
+
killer.stub!(:process_status).and_return([{:pid => 124, :cpu => 0}])
|
|
29
|
+
killer.should_receive(:kill_zombie).with(124)
|
|
30
|
+
killer.hunt_zombies
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "kills zombies with high cpu over max" do
|
|
34
|
+
@options = {:max => 1}
|
|
35
|
+
killer.stub!(:process_status).and_return([{:pid => 111, :cpu => 100}])
|
|
36
|
+
killer.should_receive(:kill_zombie).with(111)
|
|
37
|
+
killer.hunt_zombies
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "does not kills zombies with high cpu under max" do
|
|
41
|
+
@options = {:max => 2}
|
|
42
|
+
killer.stub!(:process_status).and_return([{:pid => 111, :cpu => 100}])
|
|
43
|
+
killer.should_not_receive(:kill_zombie).with(111)
|
|
44
|
+
killer.hunt_zombies
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "ignores high cpu levels in old history" do
|
|
48
|
+
@options = {:max => 2, :history => 2}
|
|
49
|
+
killer.should_not_receive(:kill_zombie).with(111)
|
|
50
|
+
killer.stub!(:process_status).and_return([{:pid => 111, :cpu => 100}])
|
|
51
|
+
killer.hunt_zombies
|
|
52
|
+
killer.stub!(:process_status).and_return([{:pid => 111, :cpu => 0}])
|
|
53
|
+
killer.hunt_zombies
|
|
54
|
+
killer.stub!(:process_status).and_return([{:pid => 111, :cpu => 100}])
|
|
55
|
+
killer.hunt_zombies
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "kills on high cpu levels in recent history" do
|
|
59
|
+
@options = {:max => 2, :history => 2}
|
|
60
|
+
killer.stub!(:process_status).and_return([{:pid => 111, :cpu => 100}])
|
|
61
|
+
killer.hunt_zombies
|
|
62
|
+
killer.should_receive(:kill_zombie).with(111)
|
|
63
|
+
killer.hunt_zombies
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe "#kill_zombies" do
|
|
68
|
+
before do
|
|
69
|
+
killer.instance_eval{
|
|
70
|
+
@grace_time = 0.1
|
|
71
|
+
@strace_time = 0.1
|
|
72
|
+
}
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def pid_of(marker)
|
|
76
|
+
processes = `ps -ef | grep '#{marker}' | grep -v grep`
|
|
77
|
+
processes.strip.split("\n").last.split(/\s+/)[1].to_i
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
def start_bogus_process(options={})
|
|
81
|
+
marker = "TEST---#{rand(999999999999)}"
|
|
82
|
+
Thread.new do
|
|
83
|
+
`ruby -e 'at_exit{ puts "proper exit"; #{'sleep 10' if options[:hang]}}; sleep 10; puts "#{marker}"' 2>&1`
|
|
84
|
+
end
|
|
85
|
+
sleep 1 # give process time to spin up
|
|
86
|
+
pid_of(marker)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def process_alive?(pid)
|
|
90
|
+
Process.getpgid(pid)
|
|
91
|
+
rescue Errno::ESRCH
|
|
92
|
+
false
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "kills normal processes" do
|
|
96
|
+
pid = start_bogus_process
|
|
97
|
+
lambda{
|
|
98
|
+
killer.kill_zombie(pid)
|
|
99
|
+
sleep 0.1
|
|
100
|
+
}.should change{ process_alive?(pid) }
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
it "kills hanging processes" do
|
|
104
|
+
pid = start_bogus_process :hang => true
|
|
105
|
+
lambda{
|
|
106
|
+
killer.kill_zombie(pid)
|
|
107
|
+
sleep 0.1
|
|
108
|
+
}.should change{ process_alive?(pid) }
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "prints an strace of the process" do
|
|
112
|
+
pid = start_bogus_process
|
|
113
|
+
killer.kill_zombie(pid)
|
|
114
|
+
output.should include('attach:')
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
it "does not take a strace of a dead process" do
|
|
118
|
+
killer.kill_zombie(111)
|
|
119
|
+
output.should_not include('attach:')
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "does not fail with an unknown pid" do
|
|
123
|
+
killer.kill_zombie(111)
|
|
124
|
+
output.should include('No such process')
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
describe "#log" do
|
|
129
|
+
it "logs simple when :show_times is not given" do
|
|
130
|
+
killer.log "X"
|
|
131
|
+
output.should == "X\n"
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
it "logs simple when :show_times is not given" do
|
|
135
|
+
@options = {:show_times => true}
|
|
136
|
+
killer.log "X"
|
|
137
|
+
output.should include(Time.now.year.to_s)
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
describe "#lurk" do
|
|
142
|
+
it "sleeps after checking" do
|
|
143
|
+
killer.should_receive(:hunt_zombies)
|
|
144
|
+
killer.should_receive(:sleep).with(10).and_raise "LOOP-BREAKER"
|
|
145
|
+
lambda{
|
|
146
|
+
killer.lurk
|
|
147
|
+
}.should raise_error "LOOP-BREAKER"
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it "calls sleep with the given interval" do
|
|
151
|
+
@options = {:interval => 5}
|
|
152
|
+
killer.stub(:hunt_zombies)
|
|
153
|
+
killer.should_receive(:sleep).with(5).and_raise "LOOP-BREAKER"
|
|
154
|
+
lambda{
|
|
155
|
+
killer.lurk
|
|
156
|
+
}.should raise_error "LOOP-BREAKER"
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
it "prints Exiting on Interrupt" do
|
|
160
|
+
killer.stub(:hunt_zombies)
|
|
161
|
+
killer.should_receive(:sleep).and_raise Interrupt.new
|
|
162
|
+
lambda{
|
|
163
|
+
killer.lurk
|
|
164
|
+
}.should raise_error Interrupt
|
|
165
|
+
output.should include("Exiting")
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
describe "cli" do
|
|
170
|
+
it "prints its version" do
|
|
171
|
+
`./bin/zombie_passenger_killer -v`.should =~ /^\d+\.\d+\.\d+$/m
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
it "prints help" do
|
|
175
|
+
`./bin/zombie_passenger_killer -h`.should include('Usage')
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
|
2
|
+
require 'zombie_passenger_killer/version'
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new "balepc-zombie_passenger_killer", ZombiePassengerKiller::VERSION do |s|
|
|
5
|
+
s.summary = "Guaranteed zombie passengers death"
|
|
6
|
+
s.authors = ["Michael Grosser"]
|
|
7
|
+
s.email = "michael@grosser.it"
|
|
8
|
+
s.homepage = "http://github.com/grosser/zombie_passenger_killer"
|
|
9
|
+
s.files = `git ls-files`.split("\n")
|
|
10
|
+
s.executables = ["zombie_passenger_killer"]
|
|
11
|
+
s.license = "MIT"
|
|
12
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: balepc-zombie_passenger_killer
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
hash: -1513943312
|
|
5
|
+
prerelease: 6
|
|
6
|
+
segments:
|
|
7
|
+
- 0
|
|
8
|
+
- 2
|
|
9
|
+
- 1
|
|
10
|
+
- patched
|
|
11
|
+
version: 0.2.1.patched
|
|
12
|
+
platform: ruby
|
|
13
|
+
authors:
|
|
14
|
+
- Michael Grosser
|
|
15
|
+
autorequire:
|
|
16
|
+
bindir: bin
|
|
17
|
+
cert_chain: []
|
|
18
|
+
|
|
19
|
+
date: 2012-03-14 00:00:00 Z
|
|
20
|
+
dependencies: []
|
|
21
|
+
|
|
22
|
+
description:
|
|
23
|
+
email: michael@grosser.it
|
|
24
|
+
executables:
|
|
25
|
+
- zombie_passenger_killer
|
|
26
|
+
extensions: []
|
|
27
|
+
|
|
28
|
+
extra_rdoc_files: []
|
|
29
|
+
|
|
30
|
+
files:
|
|
31
|
+
- Gemfile
|
|
32
|
+
- Gemfile.lock
|
|
33
|
+
- Rakefile
|
|
34
|
+
- Readme.md
|
|
35
|
+
- bin/zombie_passenger_killer
|
|
36
|
+
- lib/zombie_passenger_killer.rb
|
|
37
|
+
- lib/zombie_passenger_killer/reaper.rb
|
|
38
|
+
- lib/zombie_passenger_killer/version.rb
|
|
39
|
+
- spec/spec_helper.rb
|
|
40
|
+
- spec/zombie_passenger_killer_spec.rb
|
|
41
|
+
- zombie_passenger_killer.gemspec
|
|
42
|
+
homepage: http://github.com/grosser/zombie_passenger_killer
|
|
43
|
+
licenses:
|
|
44
|
+
- MIT
|
|
45
|
+
post_install_message:
|
|
46
|
+
rdoc_options: []
|
|
47
|
+
|
|
48
|
+
require_paths:
|
|
49
|
+
- lib
|
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
51
|
+
none: false
|
|
52
|
+
requirements:
|
|
53
|
+
- - ">="
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
hash: 3
|
|
56
|
+
segments:
|
|
57
|
+
- 0
|
|
58
|
+
version: "0"
|
|
59
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
60
|
+
none: false
|
|
61
|
+
requirements:
|
|
62
|
+
- - ">"
|
|
63
|
+
- !ruby/object:Gem::Version
|
|
64
|
+
hash: 25
|
|
65
|
+
segments:
|
|
66
|
+
- 1
|
|
67
|
+
- 3
|
|
68
|
+
- 1
|
|
69
|
+
version: 1.3.1
|
|
70
|
+
requirements: []
|
|
71
|
+
|
|
72
|
+
rubyforge_project:
|
|
73
|
+
rubygems_version: 1.8.17
|
|
74
|
+
signing_key:
|
|
75
|
+
specification_version: 3
|
|
76
|
+
summary: Guaranteed zombie passengers death
|
|
77
|
+
test_files: []
|
|
78
|
+
|