bluepill 0.0.51 → 0.0.52

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,8 +1,10 @@
1
1
  *.sw?
2
2
  .DS_Store
3
- coverage
4
- rdoc
5
- pkg/*
3
+ coverage/
4
+ .yardoc/
5
+ doc/
6
+ pkg/
6
7
  *.gem
7
- .bundle
8
+ .bundle/
8
9
  Gemfile.lock
10
+ .idea
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ -r ./spec/spec_helper.rb -c -f progress
data/Gemfile CHANGED
@@ -2,3 +2,9 @@ source :rubygems
2
2
 
3
3
  # Specify your gem's dependencies in bluepill.gemspec
4
4
  gemspec
5
+
6
+ # YARD helper for ruby 1.8 (already embedded into ruby 1.9)
7
+ gem "ripper", :platforms => :ruby_18, :group => :development
8
+
9
+ # Code coverage tool that works on Ruby 1.9
10
+ gem "simplecov", ">= 0.4.0", :platforms => :ruby_19, :group => :test
data/README.md CHANGED
@@ -119,6 +119,23 @@ If you want to run the process as someone other than root:
119
119
  end
120
120
  ```
121
121
 
122
+ If you want to include one or more supplementary groups:
123
+
124
+ ```ruby
125
+ Bluepill.application("app_name") do |app|
126
+ app.process("process_name") do |process|
127
+ process.start_command = "/usr/bin/some_start_command"
128
+ process.pid_file = "/tmp/some_pid_file.pid"
129
+ process.uid = "deploy"
130
+ process.gid = "deploy"
131
+ process.supplementary_groups = ['rvm']
132
+
133
+ process.checks :cpu_usage, :every => 10.seconds, :below => 5, :times => 3
134
+ process.checks :mem_usage, :every => 10.seconds, :below => 100.megabytes, :times => [3,5]
135
+ end
136
+ end
137
+ ```
138
+
122
139
  You can also set an app-wide uid/gid:
123
140
 
124
141
  ```ruby
@@ -164,6 +181,35 @@ You can also have an app-wide working directory:
164
181
 
165
182
  Note: We also set the PWD in the environment to the working dir you specify. This is useful for when the working dir is a symlink. Unicorn in particular will cd into the environment variable in PWD when it re-execs to deal with a change in the symlink.
166
183
 
184
+ By default, bluepill will send a SIGTERM to your process when stopping.
185
+ To change the stop command:
186
+
187
+ ```ruby
188
+ Bluepill.application("app_name") do |app|
189
+ app.process("process_name") do |process|
190
+ process.start_command = "/usr/bin/some_start_command"
191
+ process.pid_file = "/tmp/some_pid_file.pid"
192
+ process.stop_command = "/user/bin/some_stop_command"
193
+ end
194
+ end
195
+ ```
196
+
197
+ If you'd like to send a signal or signals to your process to stop it:
198
+
199
+ ```ruby
200
+ Bluepill.application("app_name") do |app|
201
+ app.process("process_name") do |process|
202
+ process.start_command = "/usr/bin/some_start_command"
203
+ process.pid_file = "/tmp/some_pid_file.pid"
204
+ process.stop_signals = [:quit, 30.seconds, :term, 5.seconds, :kill]
205
+ end
206
+ end
207
+ ```
208
+
209
+ We added a line that will send a SIGQUIT, wait 30 seconds and check to
210
+ see if the process is still up, send a SIGTERM, wait 5 seconds and check
211
+ to see if the process is still up, and finally send a SIGKILL.
212
+
167
213
  And lastly, to monitor child processes:
168
214
 
169
215
  ```ruby
data/Rakefile CHANGED
@@ -7,3 +7,32 @@ rescue LoadError
7
7
  $stderr.puts "Bundler not installed. You should install it with: gem install bundler"
8
8
  end
9
9
 
10
+ $LOAD_PATH << File.expand_path('./lib', File.dirname(__FILE__))
11
+ require 'bluepill/version'
12
+
13
+ begin
14
+ require 'rspec/core/rake_task'
15
+
16
+ RSpec::Core::RakeTask.new
17
+
18
+ if RUBY_VERSION >= '1.9'
19
+ RSpec::Core::RakeTask.new(:cov) do |t|
20
+ ENV['ENABLE_SIMPLECOV'] = '1'
21
+ t.ruby_opts = '-w'
22
+ t.rcov_opts = %q[-Ilib --exclude "spec/*,gems/*"]
23
+ end
24
+ end
25
+ rescue LoadError
26
+ $stderr.puts "RSpec not available. Install it with: gem install rspec-core rspec-expectations rr faker"
27
+ end
28
+
29
+ begin
30
+ require 'yard'
31
+ YARD::Rake::YardocTask.new do |yard|
32
+ yard.options << "--title='bluepill #{Bluepill::VERSION}'"
33
+
34
+ end
35
+ rescue LoadError
36
+ $stderr.puts "Please install YARD with: gem install yard"
37
+ end
38
+
data/bin/bluepill CHANGED
@@ -2,11 +2,20 @@
2
2
  require 'optparse'
3
3
  require 'bluepill'
4
4
 
5
+ begin
6
+ require 'rbconfig'
7
+ rescue LoadError
8
+ end
9
+
10
+ RbConfig = Config unless Object.const_defined?(:RbConfig)
11
+
5
12
  # Default options
6
13
  options = {
7
14
  :log_file => "/var/log/bluepill.log",
8
- :base_dir => "/var/bluepill",
9
- :privileged => true
15
+ :base_dir => "/var/run/bluepill",
16
+ :privileged => true,
17
+ :timeout => 10,
18
+ :attempts => 1
10
19
  }
11
20
 
12
21
  OptionParser.new do |opts|
@@ -32,6 +41,10 @@ OptionParser.new do |opts|
32
41
  options[:timeout] = timeout
33
42
  end
34
43
 
44
+ opts.on('--attempts Count', Integer, "Attempts for commands sent to the daemon, in seconds. Defaults to 1.") do |attempts|
45
+ options[:attempts] = attempts
46
+ end
47
+
35
48
  help = proc do
36
49
  puts opts
37
50
  puts
@@ -95,8 +108,7 @@ if options[:command] == "load"
95
108
  if File.exists?(file)
96
109
  # Restart the ruby interpreter for the config file so that anything loaded here
97
110
  # does not stay in memory for the daemon
98
- require 'rbconfig'
99
- ruby = File.join(Config::CONFIG['bindir'], Config::CONFIG['ruby_install_name'])
111
+ ruby = File.join(RbConfig::CONFIG['bindir'], RbConfig::CONFIG['ruby_install_name'])
100
112
  load_path = File.expand_path("#{File.dirname(__FILE__)}/../lib")
101
113
  file_path = File.expand_path(file)
102
114
 
@@ -109,3 +121,4 @@ else
109
121
  target = ARGV.shift
110
122
  controller.handle_command(options[:application], options[:command], target)
111
123
  end
124
+
data/bluepill.gemspec CHANGED
@@ -15,11 +15,17 @@ Gem::Specification.new do |s|
15
15
  s.description = %q{Bluepill keeps your daemons up while taking up as little resources as possible. After all you probably want the resources of your server to be used by whatever daemons you are running rather than the thing that's supposed to make sure they are brought back up, should they die or misbehave.}
16
16
 
17
17
  s.add_dependency 'daemons', '~> 1.1.0'
18
- s.add_dependency 'state_machine', '~> 0.9.4'
18
+ s.add_dependency 'state_machine', '~> 1.1.0'
19
19
  s.add_dependency 'activesupport', '>= 3.0.0'
20
20
  s.add_dependency 'i18n', '>= 0.5.0'
21
21
 
22
22
  s.add_development_dependency 'bundler', '>= 1.0.10'
23
+ s.add_development_dependency 'rake', '!= 0.9.0'
24
+ s.add_development_dependency 'rspec-core', '~> 2.0'
25
+ s.add_development_dependency 'rspec-expectations', '~> 2.0'
26
+ s.add_development_dependency 'rr', '~> 1.0'
27
+ s.add_development_dependency 'faker', '~> 0.9'
28
+ s.add_development_dependency 'yard', '~> 0.7'
23
29
 
24
30
  s.files = `git ls-files`.split("\n")
25
31
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
@@ -27,3 +33,4 @@ Gem::Specification.new do |s|
27
33
  s.require_paths = ["lib"]
28
34
  s.extra_rdoc_files = ["LICENSE", "README.md"]
29
35
  end
36
+
@@ -14,7 +14,7 @@ module Bluepill
14
14
 
15
15
  @foreground = options[:foreground]
16
16
  self.log_file = options[:log_file]
17
- self.base_dir = options[:base_dir] || '/var/bluepill'
17
+ self.base_dir = options[:base_dir] || '/var/run/bluepill'
18
18
  self.pid_file = File.join(self.base_dir, 'pids', self.name + ".pid")
19
19
  self.pids_dir = File.join(self.base_dir, 'pids', self.name)
20
20
 
@@ -74,6 +74,41 @@ module Bluepill
74
74
  else
75
75
  @@pid_files[pid_key] = 0
76
76
  end
77
+
78
+ #validate stop_signals array
79
+ stop_grace_time = process.attributes[:stop_grace_time]
80
+ stop_signals = process.attributes[:stop_signals]
81
+
82
+ unless stop_signals.nil?
83
+ #Start with the more helpful error messages before the 'odd number' message.
84
+ delay_sum = 0
85
+ stop_signals.each_with_index do |s_or_d, i|
86
+ if i % 2 == 0
87
+ signal = s_or_d
88
+ unless signal.is_a? Symbol
89
+ $stderr.puts "Config Error: Invalid stop_signals! Expected a symbol (signal) at position #{i} instead of '#{signal}'."
90
+ exit(6)
91
+ end
92
+ else
93
+ delay = s_or_d
94
+ unless delay.is_a? Fixnum
95
+ $stderr.puts "Config Error: Invalid stop_signals! Expected a number (delay) at position #{i} instead of '#{delay}'."
96
+ exit(6)
97
+ end
98
+ delay_sum += delay
99
+ end
100
+ end
101
+
102
+ unless stop_signals.size % 2 == 1
103
+ $stderr.puts "Config Error: Invalid stop_signals! Expected an odd number of elements."
104
+ exit(6)
105
+ end
106
+
107
+ if stop_grace_time.nil? || stop_grace_time <= delay_sum
108
+ $stderr.puts "Config Error: Stop_grace_time should be greater than the sum of stop_signals delays!"
109
+ exit(6)
110
+ end
111
+ end
77
112
  end
78
113
 
79
114
  def validate_child_process!(child)
@@ -35,7 +35,11 @@ module Bluepill
35
35
  :child_process_factory,
36
36
 
37
37
  :pid_command,
38
- :auto_start
38
+ :auto_start,
39
+
40
+ :supplementary_groups,
41
+
42
+ :stop_signals
39
43
  ]
40
44
 
41
45
  attr_accessor :name, :watches, :triggers, :logger, :skip_ticks_until, :process_running
@@ -87,6 +91,7 @@ module Bluepill
87
91
  end
88
92
 
89
93
  before_transition any => any, :do => :notify_triggers
94
+ before_transition :stopping => any, :do => :clean_threads
90
95
 
91
96
  after_transition any => :starting, :do => :start_process
92
97
  after_transition any => :stopping, :do => :stop_process
@@ -101,6 +106,7 @@ module Bluepill
101
106
  @watches = []
102
107
  @triggers = []
103
108
  @children = []
109
+ @threads = []
104
110
  @statistics = ProcessStatistics.new
105
111
  @actual_pid = options[:actual_pid]
106
112
  self.logger = options[:logger]
@@ -134,6 +140,9 @@ module Bluepill
134
140
  # clear the memoization per tick
135
141
  @process_running = nil
136
142
 
143
+ # Deal with thread cleanup here since the stopping state isn't used
144
+ clean_threads if self.unmonitored?
145
+
137
146
  # run state machine transitions
138
147
  super
139
148
 
@@ -288,6 +297,30 @@ module Bluepill
288
297
  end
289
298
  end
290
299
 
300
+ elsif stop_signals
301
+ # issue stop signals with configurable delay between each
302
+ logger.warning "Sending stop signals to #{actual_pid}"
303
+ @threads << Thread.new(self, stop_signals.clone) do |process, stop_signals|
304
+ signal = stop_signals.shift
305
+ logger.info "Sending signal #{signal} to #{process.actual_pid}"
306
+ process.signal_process(signal.upcase) # send first signal
307
+
308
+ until stop_signals.empty?
309
+ # we already checked to make sure stop_signals had an odd number of items
310
+ delay = stop_signals.shift
311
+ signal = stop_signals.shift
312
+
313
+ logger.debug "Sleeping for #{delay} seconds"
314
+ sleep delay
315
+ #break unless signal_process(0) #break unless the process can be reached
316
+ unless process.signal_process(0)
317
+ logger.debug "Process has terminated."
318
+ break
319
+ end
320
+ logger.info "Sending signal #{signal} to #{process.actual_pid}"
321
+ process.signal_process(signal.upcase)
322
+ end
323
+ end
291
324
  else
292
325
  logger.warning "Executing default stop command. Sending TERM signal to #{actual_pid}"
293
326
  signal_process("TERM")
@@ -320,6 +353,11 @@ module Bluepill
320
353
  end
321
354
  end
322
355
 
356
+ def clean_threads
357
+ @threads.each { |t| t.kill }
358
+ @threads.clear
359
+ end
360
+
323
361
  def daemonize?
324
362
  !!self.daemonize
325
363
  end
@@ -422,7 +460,8 @@ module Bluepill
422
460
  :logger => self.logger,
423
461
  :stdin => self.stdin,
424
462
  :stdout => self.stdout,
425
- :stderr => self.stderr
463
+ :stderr => self.stderr,
464
+ :supplementary_groups => self.supplementary_groups
426
465
  }
427
466
  end
428
467
 
@@ -1,19 +1,22 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  module Bluepill
3
3
  class ProcessStatistics
4
- STRFTIME = "%m/%d/%Y %H:%I:%S"
4
+ STRFTIME = "%m/%d/%Y %H:%I:%S".freeze
5
+ EVENTS_TO_PERSIST = 10
6
+
7
+ attr_reader :events
5
8
 
6
9
  # possibly persist this data.
7
10
  def initialize
8
- @events = Util::RotationalArray.new(10)
11
+ @events = Util::RotationalArray.new(EVENTS_TO_PERSIST)
9
12
  end
10
13
 
11
14
  def record_event(event, reason)
12
- @events.push([event, reason, Time.now])
15
+ events.push([event, reason, Time.now])
13
16
  end
14
17
 
15
18
  def to_s
16
- str = @events.reverse.map do |(event, reason, time)|
19
+ str = events.reverse.map do |(event, reason, time)|
17
20
  " #{event} at #{time.strftime(STRFTIME)} - #{reason || "unspecified"}"
18
21
  end.join("\n")
19
22
 
@@ -21,3 +24,4 @@ module Bluepill
21
24
  end
22
25
  end
23
26
  end
27
+
@@ -4,22 +4,33 @@ require 'socket'
4
4
  module Bluepill
5
5
  module Socket
6
6
  TIMEOUT = 60 # Used for client commands
7
+ MAX_ATTEMPTS = 5
7
8
 
8
9
  extend self
9
10
 
10
- def client(base_dir, name, &b)
11
- UNIXSocket.open(socket_path(base_dir, name), &b)
11
+ def client(base_dir, name, &block)
12
+ UNIXSocket.open(socket_path(base_dir, name), &block)
12
13
  end
13
14
 
14
15
  def client_command(base_dir, name, command)
15
- client(base_dir, name) do |socket|
16
- Timeout.timeout(TIMEOUT) do
17
- socket.puts command
18
- Marshal.load(socket)
16
+ res = nil
17
+ MAX_ATTEMPTS.times do |current_attempt|
18
+ begin
19
+ client(base_dir, name) do |socket|
20
+ Timeout.timeout(TIMEOUT) do
21
+ socket.puts command
22
+ res = Marshal.load(socket.read)
23
+ end
24
+ end
25
+ break
26
+ rescue EOFError, Timeout::Error
27
+ if current_attempt == MAX_ATTEMPTS - 1
28
+ abort("Socket Timeout: Server may not be responding")
29
+ end
30
+ puts "Retry #{current_attempt + 1} of #{MAX_ATTEMPTS}"
19
31
  end
20
32
  end
21
- rescue EOFError, Timeout::Error
22
- abort("Socket Timeout: Server may not be responding")
33
+ res
23
34
  end
24
35
 
25
36
  def server(base_dir, name)
@@ -62,7 +62,7 @@ module Bluepill
62
62
  # child
63
63
  rd.close
64
64
 
65
- drop_privileges(options[:uid], options[:gid])
65
+ drop_privileges(options[:uid], options[:gid], options[:supplementary_groups])
66
66
 
67
67
  # if we cannot write the pid file as the provided user, err out
68
68
  exit unless can_write_pid_file(options[:pid_file], options[:logger])
@@ -113,7 +113,7 @@ module Bluepill
113
113
 
114
114
  pid = fork {
115
115
  # grandchild
116
- drop_privileges(options[:uid], options[:gid])
116
+ drop_privileges(options[:uid], options[:gid], options[:supplementary_groups])
117
117
 
118
118
  Dir.chdir(ENV["PWD"] = options[:working_dir]) if options[:working_dir]
119
119
  options[:environment].each { |key, value| ENV[key.to_s] = value.to_s } if options[:environment]
@@ -192,14 +192,22 @@ module Bluepill
192
192
 
193
193
  # be sure to call this from a fork otherwise it will modify the attributes
194
194
  # of the bluepill daemon
195
- def drop_privileges(uid, gid)
195
+ def drop_privileges(uid, gid, supplementary_groups)
196
196
  if ::Process::Sys.geteuid == 0
197
197
  uid_num = Etc.getpwnam(uid).uid if uid
198
198
  gid_num = Etc.getgrnam(gid).gid if gid
199
199
 
200
+ supplementary_groups ||= []
201
+
202
+ group_nums = supplementary_groups.map do |group|
203
+ Etc.getgrnam(group).gid
204
+ end
205
+
200
206
  ::Process.groups = [gid_num] if gid
207
+ ::Process.groups |= group_nums unless group_nums.empty?
201
208
  ::Process::Sys.setgid(gid_num) if gid
202
209
  ::Process::Sys.setuid(uid_num) if uid
210
+ ENV['HOME'] = Etc.getpwuid(uid_num).try(:dir) || ENV['HOME'] if uid
203
211
  end
204
212
  end
205
213
 
@@ -1,4 +1,4 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  module Bluepill
3
- VERSION = "0.0.51".freeze
3
+ VERSION = "0.0.52".freeze
4
4
  end
@@ -0,0 +1,3 @@
1
+ describe Bluepill::Logger do
2
+
3
+ end
@@ -0,0 +1,24 @@
1
+ describe Bluepill::ProcessStatistics do
2
+ before(:each) do
3
+ @stats = Bluepill::ProcessStatistics.new
4
+ end
5
+
6
+ it "should record events" do
7
+ @stats.record_event('some event', 'some reason')
8
+ @stats.record_event('another event', 'another reason')
9
+ @stats.events.should have(2).events
10
+ end
11
+
12
+ it "should record #EVENTS_TO_PERSIST events" do
13
+ (2 * Bluepill::ProcessStatistics::EVENTS_TO_PERSIST).times do
14
+ @stats.record_event('some event', 'some reason')
15
+ end
16
+ @stats.events.should have(Bluepill::ProcessStatistics::EVENTS_TO_PERSIST).events
17
+ end
18
+
19
+ it "should return event history" do
20
+ @stats.record_event('some event', 'some reason')
21
+ @stats.to_s.should match(/some reason/)
22
+ @stats.to_s.should match(/event history/)
23
+ end
24
+ end
@@ -0,0 +1,36 @@
1
+ describe Bluepill::System do
2
+ describe :pid_alive? do
3
+ it "should be true if process responds to zero signal" do
4
+ mock(::Process).kill(0, 555)
5
+ Bluepill::System.should be_pid_alive(555)
6
+ end
7
+
8
+ it "should be false if process throws exception on zero signal" do
9
+ mock(::Process).kill(0, 555) { raise Errno::ESRCH.new }
10
+ Bluepill::System.should_not be_pid_alive(555)
11
+ end
12
+ end
13
+
14
+ describe :store do
15
+ it "should be Hash" do
16
+ Bluepill::System.store.should be_kind_of(Hash)
17
+ end
18
+
19
+ it "should return same Hash or every call" do
20
+ Bluepill::System.store.should be_equal(Bluepill::System.store)
21
+ end
22
+
23
+ it "should store assigned pairs" do
24
+ Bluepill::System.store[:somekey] = 10
25
+ Bluepill::System.store[:somekey].should be_eql(10)
26
+ end
27
+ end
28
+
29
+ describe :reset_data do
30
+ it 'should clear the #store' do
31
+ Bluepill::System.store[:anotherkey] = Faker::Lorem.sentence
32
+ Bluepill::System.reset_data
33
+ Bluepill::System.store.should be_empty
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,19 @@
1
+ if RUBY_VERSION >= '1.9'
2
+ if ENV['ENABLE_SIMPLECOV']
3
+ require 'simplecov'
4
+ SimpleCov.start
5
+ end
6
+ else
7
+ require 'rubygems'
8
+ end
9
+
10
+ require 'faker'
11
+ require 'rspec/core'
12
+
13
+ $LOAD_PATH.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
14
+
15
+ RSpec.configure do |conf|
16
+ conf.mock_with :rr
17
+ end
18
+
19
+ require 'bluepill'
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bluepill
3
3
  version: !ruby/object:Gem::Version
4
- hash: 121
5
- prerelease:
4
+ hash: 119
5
+ prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 0
9
- - 51
10
- version: 0.0.51
9
+ - 52
10
+ version: 0.0.52
11
11
  platform: ruby
12
12
  authors:
13
13
  - Arya Asemanfar
@@ -17,7 +17,7 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2011-06-01 00:00:00 +04:00
20
+ date: 2011-12-13 00:00:00 +04:00
21
21
  default_executable:
22
22
  dependencies:
23
23
  - !ruby/object:Gem::Dependency
@@ -44,12 +44,12 @@ dependencies:
44
44
  requirements:
45
45
  - - ~>
46
46
  - !ruby/object:Gem::Version
47
- hash: 51
47
+ hash: 19
48
48
  segments:
49
+ - 1
50
+ - 1
49
51
  - 0
50
- - 9
51
- - 4
52
- version: 0.9.4
52
+ version: 1.1.0
53
53
  type: :runtime
54
54
  version_requirements: *id002
55
55
  - !ruby/object:Gem::Dependency
@@ -100,6 +100,97 @@ dependencies:
100
100
  version: 1.0.10
101
101
  type: :development
102
102
  version_requirements: *id005
103
+ - !ruby/object:Gem::Dependency
104
+ name: rake
105
+ prerelease: false
106
+ requirement: &id006 !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - "!="
110
+ - !ruby/object:Gem::Version
111
+ hash: 59
112
+ segments:
113
+ - 0
114
+ - 9
115
+ - 0
116
+ version: 0.9.0
117
+ type: :development
118
+ version_requirements: *id006
119
+ - !ruby/object:Gem::Dependency
120
+ name: rspec-core
121
+ prerelease: false
122
+ requirement: &id007 !ruby/object:Gem::Requirement
123
+ none: false
124
+ requirements:
125
+ - - ~>
126
+ - !ruby/object:Gem::Version
127
+ hash: 3
128
+ segments:
129
+ - 2
130
+ - 0
131
+ version: "2.0"
132
+ type: :development
133
+ version_requirements: *id007
134
+ - !ruby/object:Gem::Dependency
135
+ name: rspec-expectations
136
+ prerelease: false
137
+ requirement: &id008 !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ~>
141
+ - !ruby/object:Gem::Version
142
+ hash: 3
143
+ segments:
144
+ - 2
145
+ - 0
146
+ version: "2.0"
147
+ type: :development
148
+ version_requirements: *id008
149
+ - !ruby/object:Gem::Dependency
150
+ name: rr
151
+ prerelease: false
152
+ requirement: &id009 !ruby/object:Gem::Requirement
153
+ none: false
154
+ requirements:
155
+ - - ~>
156
+ - !ruby/object:Gem::Version
157
+ hash: 15
158
+ segments:
159
+ - 1
160
+ - 0
161
+ version: "1.0"
162
+ type: :development
163
+ version_requirements: *id009
164
+ - !ruby/object:Gem::Dependency
165
+ name: faker
166
+ prerelease: false
167
+ requirement: &id010 !ruby/object:Gem::Requirement
168
+ none: false
169
+ requirements:
170
+ - - ~>
171
+ - !ruby/object:Gem::Version
172
+ hash: 25
173
+ segments:
174
+ - 0
175
+ - 9
176
+ version: "0.9"
177
+ type: :development
178
+ version_requirements: *id010
179
+ - !ruby/object:Gem::Dependency
180
+ name: yard
181
+ prerelease: false
182
+ requirement: &id011 !ruby/object:Gem::Requirement
183
+ none: false
184
+ requirements:
185
+ - - ~>
186
+ - !ruby/object:Gem::Version
187
+ hash: 5
188
+ segments:
189
+ - 0
190
+ - 7
191
+ version: "0.7"
192
+ type: :development
193
+ version_requirements: *id011
103
194
  description: Bluepill keeps your daemons up while taking up as little resources as possible. After all you probably want the resources of your server to be used by whatever daemons you are running rather than the thing that's supposed to make sure they are brought back up, should they die or misbehave.
104
195
  email:
105
196
  - entombedvirus@gmail.com
@@ -114,6 +205,7 @@ extra_rdoc_files:
114
205
  - README.md
115
206
  files:
116
207
  - .gitignore
208
+ - .rspec
117
209
  - DESIGN.md
118
210
  - Gemfile
119
211
  - LICENSE
@@ -153,6 +245,10 @@ files:
153
245
  - lib/bluepill/triggers/flapping.rb
154
246
  - lib/bluepill/util/rotational_array.rb
155
247
  - lib/bluepill/version.rb
248
+ - spec/lib/bluepill/logger_spec.rb
249
+ - spec/lib/bluepill/process_statistics_spec.rb
250
+ - spec/lib/bluepill/system_spec.rb
251
+ - spec/spec_helper.rb
156
252
  has_rdoc: true
157
253
  homepage: http://github.com/arya/bluepill
158
254
  licenses: []
@@ -183,9 +279,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
183
279
  requirements: []
184
280
 
185
281
  rubyforge_project:
186
- rubygems_version: 1.5.2
282
+ rubygems_version: 1.3.7
187
283
  signing_key:
188
284
  specification_version: 3
189
285
  summary: A process monitor written in Ruby with stability and minimalism in mind.
190
- test_files: []
191
-
286
+ test_files:
287
+ - spec/lib/bluepill/logger_spec.rb
288
+ - spec/lib/bluepill/process_statistics_spec.rb
289
+ - spec/lib/bluepill/system_spec.rb
290
+ - spec/spec_helper.rb