bluepill 0.0.68 → 0.0.69

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -2
  3. data/bin/bluepill +19 -20
  4. data/bin/sample_forking_server +26 -13
  5. data/bluepill.gemspec +12 -18
  6. data/lib/bluepill.rb +12 -12
  7. data/lib/bluepill/application.rb +64 -71
  8. data/lib/bluepill/application/client.rb +0 -2
  9. data/lib/bluepill/application/server.rb +1 -3
  10. data/lib/bluepill/condition_watch.rb +12 -7
  11. data/lib/bluepill/controller.rb +37 -42
  12. data/lib/bluepill/dsl.rb +1 -2
  13. data/lib/bluepill/dsl/app_proxy.rb +3 -4
  14. data/lib/bluepill/dsl/process_factory.rb +40 -44
  15. data/lib/bluepill/dsl/process_proxy.rb +4 -5
  16. data/lib/bluepill/group.rb +15 -21
  17. data/lib/bluepill/logger.rb +4 -4
  18. data/lib/bluepill/process.rb +107 -109
  19. data/lib/bluepill/process_conditions.rb +1 -3
  20. data/lib/bluepill/process_conditions/always_true.rb +2 -3
  21. data/lib/bluepill/process_conditions/cpu_usage.rb +0 -1
  22. data/lib/bluepill/process_conditions/file_time.rb +5 -6
  23. data/lib/bluepill/process_conditions/http.rb +11 -9
  24. data/lib/bluepill/process_conditions/mem_usage.rb +6 -7
  25. data/lib/bluepill/process_conditions/process_condition.rb +4 -5
  26. data/lib/bluepill/process_conditions/running_time.rb +1 -2
  27. data/lib/bluepill/process_conditions/zombie_process.rb +1 -2
  28. data/lib/bluepill/process_journal.rb +18 -21
  29. data/lib/bluepill/process_statistics.rb +2 -4
  30. data/lib/bluepill/socket.rb +13 -16
  31. data/lib/bluepill/system.rb +57 -63
  32. data/lib/bluepill/trigger.rb +9 -11
  33. data/lib/bluepill/triggers/flapping.rb +12 -16
  34. data/lib/bluepill/util/rotational_array.rb +1 -2
  35. data/lib/bluepill/version.rb +1 -2
  36. metadata +4 -28
  37. data/.gitignore +0 -12
  38. data/.rspec +0 -1
  39. data/.travis.yml +0 -17
  40. data/Gemfile +0 -27
  41. data/Rakefile +0 -38
  42. data/examples/example.rb +0 -87
  43. data/examples/new_example.rb +0 -89
  44. data/examples/new_runit_example.rb +0 -29
  45. data/examples/runit_example.rb +0 -26
  46. data/local-bluepill +0 -130
  47. data/spec/lib/bluepill/application_spec.rb +0 -51
  48. data/spec/lib/bluepill/logger_spec.rb +0 -3
  49. data/spec/lib/bluepill/process_spec.rb +0 -135
  50. data/spec/lib/bluepill/process_statistics_spec.rb +0 -24
  51. data/spec/lib/bluepill/system_spec.rb +0 -45
  52. data/spec/spec_helper.rb +0 -26
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  module ProcessConditions
4
3
  def self.[](name)
@@ -7,8 +6,7 @@ module Bluepill
7
6
  end
8
7
  end
9
8
 
10
- require "bluepill/process_conditions/process_condition"
9
+ require 'bluepill/process_conditions/process_condition'
11
10
  Dir["#{File.dirname(__FILE__)}/process_conditions/*.rb"].each do |pc|
12
11
  require pc
13
12
  end
14
-
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  module ProcessConditions
4
3
  class AlwaysTrue < ProcessCondition
@@ -6,11 +5,11 @@ module Bluepill
6
5
  @below = options[:below]
7
6
  end
8
7
 
9
- def run(pid, include_children)
8
+ def run(_pid, _include_children)
10
9
  1
11
10
  end
12
11
 
13
- def check(value)
12
+ def check(_value)
14
13
  true
15
14
  end
16
15
  end
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  module ProcessConditions
4
3
  class CpuUsage < ProcessCondition
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  module ProcessConditions
4
3
  class FileTime < ProcessCondition
@@ -7,19 +6,19 @@ module Bluepill
7
6
  @filename = options[:filename]
8
7
  end
9
8
 
10
- def run(pid, include_children)
11
- if File.exists?(@filename)
12
- Time.now()-File::mtime(@filename)
9
+ def run(_pid, _include_children)
10
+ if File.exist?(@filename)
11
+ Time.now - File.mtime(@filename)
13
12
  else
14
13
  nil
15
14
  end
16
15
  rescue
17
- $!
16
+ $ERROR_INFO
18
17
  end
19
18
 
20
19
  def check(value)
21
20
  return false if value.nil?
22
- return value < @below
21
+ value < @below
23
22
  end
24
23
  end
25
24
  end
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require 'net/http'
3
2
  require 'uri'
4
3
 
@@ -8,8 +7,10 @@ module Bluepill
8
7
  def initialize(options = {})
9
8
  @uri = URI.parse(options[:url])
10
9
  @kind = case options[:kind]
11
- when Fixnum then Net::HTTPResponse::CODE_TO_OBJ[options[:kind].to_s]
12
- when String, Symbol then Net.const_get("HTTP#{options[:kind].to_s.camelize}")
10
+ when Fixnum
11
+ Net::HTTPResponse::CODE_TO_OBJ[options[:kind].to_s]
12
+ when String, Symbol
13
+ Net.const_get("HTTP#{options[:kind].to_s.camelize}")
13
14
  else
14
15
  Net::HTTPSuccess
15
16
  end
@@ -18,11 +19,11 @@ module Bluepill
18
19
  @read_timeout = (options[:read_timeout] || options[:timeout] || 5).to_i
19
20
  end
20
21
 
21
- def run(pid, include_children)
22
+ def run(_pid, _include_children)
22
23
  session = Net::HTTP.new(@uri.host, @uri.port)
23
24
  if @uri.scheme == 'https'
24
25
  require 'net/https'
25
- session.use_ssl=true
26
+ session.use_ssl = true
26
27
  session.verify_mode = OpenSSL::SSL::VERIFY_NONE
27
28
  end
28
29
  session.open_timeout = @open_timeout
@@ -33,22 +34,23 @@ module Bluepill
33
34
  end
34
35
  end
35
36
  rescue
36
- $!
37
+ $ERROR_INFO
37
38
  end
38
39
 
39
40
  def check(value)
40
- return false unless value.kind_of?(@kind)
41
+ return false unless value.is_a?(@kind)
41
42
  return true unless @pattern
42
43
  return false unless value.class.body_permitted?
43
44
  @pattern === value.body
44
45
  end
45
46
 
46
47
  private
48
+
47
49
  def hide_net_http_bug
48
50
  yield
49
51
  rescue NoMethodError => e
50
- if e.to_s =~ /#{Regexp.escape(%q|undefined method `closed?' for nil:NilClass|)}/
51
- raise Errno::ECONNREFUSED, "Connection refused attempting to contact #{@uri.scheme}://#{@uri.host}:#{@uri.port}"
52
+ if e.to_s =~ /#{Regexp.escape("undefined method `closed?' for nil:NilClass")}/
53
+ raise(Errno::ECONNREFUSED.new("Connection refused attempting to contact #{@uri.scheme}://#{@uri.host}:#{@uri.port}"))
52
54
  else
53
55
  raise
54
56
  end
@@ -1,11 +1,10 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  module ProcessConditions
4
3
  class MemUsage < ProcessCondition
5
- MB = 1024 ** 2
6
- FORMAT_STR = "%d%s"
7
- MB_LABEL = "MB"
8
- KB_LABEL = "KB"
4
+ MB = 1024**2
5
+ FORMAT_STR = '%d%s'
6
+ MB_LABEL = 'MB'
7
+ KB_LABEL = 'KB'
9
8
 
10
9
  def initialize(options = {})
11
10
  @below = options[:below]
@@ -22,9 +21,9 @@ module Bluepill
22
21
 
23
22
  def format_value(value)
24
23
  if value.kilobytes >= MB
25
- FORMAT_STR % [(value / 1024).round, MB_LABEL]
24
+ format(FORMAT_STR, (value / 1024).round, MB_LABEL)
26
25
  else
27
- FORMAT_STR % [value, KB_LABEL]
26
+ format(FORMAT_STR, value, KB_LABEL)
28
27
  end
29
28
  end
30
29
  end
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  module ProcessConditions
4
3
  class ProcessCondition
@@ -6,12 +5,12 @@ module Bluepill
6
5
  @options = options
7
6
  end
8
7
 
9
- def run(pid, include_children)
10
- raise "Implement in subclass!"
8
+ def run(_pid, _include_children)
9
+ fail 'Implement in subclass!'
11
10
  end
12
11
 
13
- def check(value)
14
- raise "Implement in subclass!"
12
+ def check(_value)
13
+ fail 'Implement in subclass!'
15
14
  end
16
15
 
17
16
  def format_value(value)
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  module ProcessConditions
4
3
  class RunningTime < ProcessCondition
@@ -6,7 +5,7 @@ module Bluepill
6
5
  @below = options[:below]
7
6
  end
8
7
 
9
- def run(pid, include_children)
8
+ def run(pid, _include_children)
10
9
  System.running_time(pid)
11
10
  end
12
11
 
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  module ProcessConditions
4
3
  # Process must have cache_actual_pid set to false to function correctly:
@@ -7,7 +6,7 @@ module Bluepill
7
6
  # process.cache_actual_pid = false
8
7
 
9
8
  class ZombieProcess < ProcessCondition
10
- def run(pid, include_children)
9
+ def run(pid, _include_children)
11
10
  System.command(pid)
12
11
  end
13
12
 
@@ -2,7 +2,7 @@ require 'bluepill/system'
2
2
 
3
3
  module Bluepill
4
4
  module ProcessJournal
5
- extend self
5
+ module_function
6
6
 
7
7
  class << self
8
8
  attr_reader :logger
@@ -13,8 +13,8 @@ module Bluepill
13
13
  end
14
14
 
15
15
  def base_dir=(base_dir)
16
- @journal_base_dir ||= File.join(base_dir, "journals")
17
- FileUtils.mkdir_p(@journal_base_dir) unless File.exists?(@journal_base_dir)
16
+ @journal_base_dir ||= File.join(base_dir, 'journals')
17
+ FileUtils.mkdir_p(@journal_base_dir) unless File.exist?(@journal_base_dir)
18
18
  FileUtils.chmod(0777, @journal_base_dir)
19
19
  end
20
20
  end
@@ -39,7 +39,7 @@ module Bluepill
39
39
  times += 1
40
40
  logger.debug("Waiting for lock #{name}")
41
41
  sleep 1
42
- unless times >= 10
42
+ if times < 10
43
43
  retry
44
44
  else
45
45
  logger.info("Timeout waiting for lock #{name}")
@@ -65,7 +65,7 @@ module Bluepill
65
65
 
66
66
  def pid_journal(filename)
67
67
  logger.debug("pid journal file: #{filename}")
68
- result = File.open(filename, 'r').readlines.map(&:to_i).reject {|pid| skip_pid?(pid)}
68
+ result = File.open(filename, 'r').readlines.map(&:to_i).reject { |pid| skip_pid?(pid) }
69
69
  logger.debug("pid journal = #{result.join(' ')}")
70
70
  result
71
71
  rescue Errno::ENOENT
@@ -74,7 +74,7 @@ module Bluepill
74
74
 
75
75
  def pgid_journal(filename)
76
76
  logger.debug("pgid journal file: #{filename}")
77
- result = File.open(filename, 'r').readlines.map(&:to_i).reject {|pgid| skip_pgid?(pgid)}
77
+ result = File.open(filename, 'r').readlines.map(&:to_i).reject { |pgid| skip_pgid?(pgid) }
78
78
  logger.debug("pgid journal = #{result.join(' ')}")
79
79
  result
80
80
  rescue Errno::ENOENT
@@ -82,18 +82,15 @@ module Bluepill
82
82
  end
83
83
 
84
84
  def clear_atomic_fs_lock(name)
85
- if File.directory?(name)
86
- Dir.rmdir(name)
87
- logger.debug("Cleared lock #{name}")
88
- end
85
+ return unless File.directory?(name)
86
+ Dir.rmdir(name)
87
+ logger.debug("Cleared lock #{name}")
89
88
  end
90
89
 
91
90
  def kill_all_from_all_journals
92
- Dir[".bluepill_pids_journal.*"].map { |x|
93
- x.sub(/^\.bluepill_pids_journal\./,"")
94
- }.reject { |y|
95
- y =~ /\.lock$/
96
- }.each do |journal_name|
91
+ pids = Dir['.bluepill_pids_journal.*'].map { |p| p.sub(/^\.bluepill_pids_journal\./, '') }
92
+ pids.reject! { |p| p =~ /\.lock$/ }
93
+ pids.each do |journal_name|
97
94
  kill_all_from_journal(journal_name)
98
95
  end
99
96
  end
@@ -177,13 +174,13 @@ module Bluepill
177
174
 
178
175
  filename = pgid_journal_filename(journal_name)
179
176
  acquire_atomic_fs_lock(filename) do
180
- unless pgid_journal(filename).include?(pgid)
177
+ if pgid_journal(filename).include?(pgid)
178
+ logger.debug("Skipping duplicate pgid #{pgid} already in journal #{journal_name}")
179
+ else
181
180
  logger.debug("Saving pgid #{pgid} to process journal #{journal_name}")
182
181
  File.open(filename, 'a+', 0600) { |f| f.puts(pgid) }
183
182
  logger.info("Saved pgid #{pgid} to journal #{journal_name}")
184
183
  logger.debug("Journal now = #{File.open(filename, 'r').read}")
185
- else
186
- logger.debug("Skipping duplicate pgid #{pgid} already in journal #{journal_name}")
187
184
  end
188
185
  end
189
186
  end
@@ -200,13 +197,13 @@ module Bluepill
200
197
 
201
198
  filename = pid_journal_filename(journal_name)
202
199
  acquire_atomic_fs_lock(filename) do
203
- unless pid_journal(filename).include?(pid)
200
+ if pid_journal(filename).include?(pid)
201
+ logger.debug("Skipping duplicate pid #{pid} already in journal #{journal_name}")
202
+ else
204
203
  logger.debug("Saving pid #{pid} to process journal #{journal_name}")
205
204
  File.open(filename, 'a+', 0600) { |f| f.puts(pid) }
206
205
  logger.info("Saved pid #{pid} to journal #{journal_name}")
207
206
  logger.debug("Journal now = #{File.open(filename, 'r').read}")
208
- else
209
- logger.debug("Skipping duplicate pid #{pid} already in journal #{journal_name}")
210
207
  end
211
208
  end
212
209
  end
@@ -1,7 +1,6 @@
1
- # -*- encoding: utf-8 -*-
2
1
  module Bluepill
3
2
  class ProcessStatistics
4
- STRFTIME = "%m/%d/%Y %H:%I:%S".freeze
3
+ STRFTIME = '%m/%d/%Y %H:%I:%S'.freeze
5
4
  EVENTS_TO_PERSIST = 10
6
5
 
7
6
  attr_reader :events
@@ -17,11 +16,10 @@ module Bluepill
17
16
 
18
17
  def to_s
19
18
  str = events.reverse.map do |(event, reason, time)|
20
- " #{event} at #{time.strftime(STRFTIME)} - #{reason || "unspecified"}"
19
+ " #{event} at #{time.strftime(STRFTIME)} - #{reason || 'unspecified'}"
21
20
  end.join("\n")
22
21
 
23
22
  "event history:\n#{str}"
24
23
  end
25
24
  end
26
25
  end
27
-
@@ -1,4 +1,3 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require 'socket'
3
2
 
4
3
  module Bluepill
@@ -6,7 +5,7 @@ module Bluepill
6
5
  TIMEOUT = 60 # Used for client commands
7
6
  MAX_ATTEMPTS = 5
8
7
 
9
- extend self
8
+ module_function
10
9
 
11
10
  def client(base_dir, name, &block)
12
11
  UNIXSocket.open(socket_path(base_dir, name), &block)
@@ -25,7 +24,7 @@ module Bluepill
25
24
  break
26
25
  rescue EOFError, Timeout::Error
27
26
  if current_attempt == MAX_ATTEMPTS - 1
28
- abort("Socket Timeout: Server may not be responding")
27
+ abort('Socket Timeout: Server may not be responding')
29
28
  end
30
29
  puts "Retry #{current_attempt + 1} of #{MAX_ATTEMPTS}"
31
30
  end
@@ -35,24 +34,22 @@ module Bluepill
35
34
 
36
35
  def server(base_dir, name)
37
36
  socket_path = self.socket_path(base_dir, name)
37
+ UNIXServer.open(socket_path)
38
+ rescue Errno::EADDRINUSE
38
39
  begin
39
- UNIXServer.open(socket_path)
40
- rescue Errno::EADDRINUSE
41
- # if sock file has been created. test to see if there is a server
42
- begin
43
- UNIXSocket.open(socket_path)
44
- rescue Errno::ECONNREFUSED
45
- File.delete(socket_path)
46
- return UNIXServer.open(socket_path)
47
- else
48
- logger.err("Server is already running!")
49
- exit(7)
50
- end
40
+ # if sock file has been created, test to see if there is a server
41
+ UNIXSocket.open(socket_path)
42
+ rescue Errno::ECONNREFUSED
43
+ File.delete(socket_path)
44
+ return UNIXServer.open(socket_path)
45
+ else
46
+ logger.err('Server is already running!')
47
+ exit(7)
51
48
  end
52
49
  end
53
50
 
54
51
  def socket_path(base_dir, name)
55
- File.join(base_dir, 'socks', name + ".sock")
52
+ File.join(base_dir, 'socks', name + '.sock')
56
53
  end
57
54
  end
58
55
  end
@@ -1,13 +1,13 @@
1
- # -*- encoding: utf-8 -*-
2
1
  require 'etc'
3
- require "shellwords"
2
+ require 'shellwords'
4
3
 
5
4
  module Bluepill
6
5
  # This class represents the system that bluepill is running on.. It's mainly used to memoize
7
6
  # results of running ps auxx etc so that every watch in the every process will not result in a fork
8
7
  module System
9
- APPEND_MODE = "a"
10
- extend self
8
+ APPEND_MODE = 'a'
9
+
10
+ module_function
11
11
 
12
12
  # The position of each field in ps output
13
13
  IDX_MAP = {
@@ -16,27 +16,25 @@ module Bluepill
16
16
  :pcpu => 2,
17
17
  :rss => 3,
18
18
  :etime => 4,
19
- :command => 5
19
+ :command => 5,
20
20
  }
21
21
 
22
22
  def pid_alive?(pid)
23
- begin
24
- ::Process.kill(0, pid)
25
- true
26
- rescue Errno::EPERM # no permission, but it is definitely alive
27
- true
28
- rescue Errno::ESRCH
29
- false
30
- end
23
+ ::Process.kill(0, pid)
24
+ true
25
+ rescue Errno::EPERM # no permission, but it is definitely alive
26
+ true
27
+ rescue Errno::ESRCH
28
+ false
31
29
  end
32
30
 
33
31
  def cpu_usage(pid, include_children)
34
32
  ps = ps_axu
35
33
  return unless ps[pid]
36
34
  cpu_used = ps[pid][IDX_MAP[:pcpu]].to_f
37
- get_children(pid).each { |child_pid|
35
+ get_children(pid).each do |child_pid|
38
36
  cpu_used += ps[child_pid][IDX_MAP[:pcpu]].to_f if ps[child_pid]
39
- } if include_children
37
+ end if include_children
40
38
  cpu_used
41
39
  end
42
40
 
@@ -44,9 +42,9 @@ module Bluepill
44
42
  ps = ps_axu
45
43
  return unless ps[pid]
46
44
  mem_used = ps[pid][IDX_MAP[:rss]].to_f
47
- get_children(pid).each { |child_pid|
45
+ get_children(pid).each do |child_pid|
48
46
  mem_used += ps[child_pid][IDX_MAP[:rss]].to_f if ps[child_pid]
49
- } if include_children
47
+ end if include_children
50
48
  mem_used
51
49
  end
52
50
 
@@ -63,11 +61,11 @@ module Bluepill
63
61
  end
64
62
 
65
63
  def get_children(parent_pid)
66
- child_pids = Array.new
67
- ps_axu.each_pair do |pid, chunks|
64
+ child_pids = []
65
+ ps_axu.each_pair do |_pid, chunks|
68
66
  child_pids << chunks[IDX_MAP[:pid]].to_i if chunks[IDX_MAP[:ppid]].to_i == parent_pid.to_i
69
67
  end
70
- grand_children = child_pids.map{|pid| get_children(pid)}.flatten
68
+ grand_children = child_pids.map { |pid| get_children(pid) }.flatten
71
69
  child_pids.concat grand_children
72
70
  end
73
71
 
@@ -75,8 +73,9 @@ module Bluepill
75
73
  def daemonize(cmd, options = {})
76
74
  rd, wr = IO.pipe
77
75
 
78
- if child = Daemonize.safefork
79
- # we do not wanna create zombies, so detach ourselves from the child exit status
76
+ child = Daemonize.safefork
77
+ if child
78
+ # we don't want to create zombies, so detach ourselves from the child exit status
80
79
  ::Process.detach(child)
81
80
 
82
81
  # parent
@@ -86,7 +85,6 @@ module Bluepill
86
85
  rd.close
87
86
 
88
87
  return daemon_id if daemon_id > 0
89
-
90
88
  else
91
89
  # child
92
90
  rd.close
@@ -98,7 +96,7 @@ module Bluepill
98
96
 
99
97
  to_daemonize = lambda do
100
98
  # Setting end PWD env emulates bash behavior when dealing with symlinks
101
- Dir.chdir(ENV["PWD"] = options[:working_dir].to_s) if options[:working_dir]
99
+ Dir.chdir(ENV['PWD'] = options[:working_dir].to_s) if options[:working_dir]
102
100
  options[:environment].each { |key, value| ENV[key.to_s] = value.to_s } if options[:environment]
103
101
 
104
102
  redirect_io(*options.values_at(:stdin, :stdout, :stderr))
@@ -109,12 +107,12 @@ module Bluepill
109
107
 
110
108
  daemon_id = Daemonize.call_as_daemon(to_daemonize, nil, cmd)
111
109
 
112
- File.open(options[:pid_file], "w") {|f| f.write(daemon_id)}
110
+ File.open(options[:pid_file], 'w') { |f| f.write(daemon_id) }
113
111
 
114
112
  wr.write daemon_id
115
113
  wr.close
116
114
 
117
- ::Process::exit!(true)
115
+ ::Process.exit!(true)
118
116
  end
119
117
  end
120
118
 
@@ -122,7 +120,7 @@ module Bluepill
122
120
  tries = 0
123
121
 
124
122
  begin
125
- File.unlink(filename) if filename && File.exists?(filename)
123
+ File.unlink(filename) if filename && File.exist?(filename)
126
124
  rescue IOError, Errno::ENOENT
127
125
  rescue Errno::EACCES
128
126
  retry if (tries += 1) < 3
@@ -134,7 +132,8 @@ module Bluepill
134
132
  def execute_blocking(cmd, options = {})
135
133
  rd, wr = IO.pipe
136
134
 
137
- if child = Daemonize.safefork
135
+ child = Daemonize.safefork
136
+ if child
138
137
  # parent
139
138
  wr.close
140
139
 
@@ -152,12 +151,12 @@ module Bluepill
152
151
  cmd_out_read, cmd_out_write = IO.pipe
153
152
  cmd_err_read, cmd_err_write = IO.pipe
154
153
 
155
- pid = fork {
154
+ pid = fork do
156
155
  begin
157
156
  # grandchild
158
157
  drop_privileges(options[:uid], options[:gid], options[:supplementary_groups])
159
158
 
160
- Dir.chdir(ENV["PWD"] = options[:working_dir].to_s) if options[:working_dir]
159
+ Dir.chdir(ENV['PWD'] = options[:working_dir].to_s) if options[:working_dir]
161
160
  options[:environment].each { |key, value| ENV[key.to_s] = value.to_s } if options[:environment]
162
161
 
163
162
  # close unused fds so ancestors wont hang. This line is the only reason we are not
@@ -166,7 +165,7 @@ module Bluepill
166
165
  wr.close
167
166
 
168
167
  # we do not care about stdin of cmd
169
- STDIN.reopen("/dev/null")
168
+ STDIN.reopen('/dev/null')
170
169
 
171
170
  # point stdout of cmd to somewhere we can read
172
171
  cmd_out_read.close
@@ -180,12 +179,12 @@ module Bluepill
180
179
 
181
180
  # finally, replace grandchild with cmd
182
181
  ::Kernel.exec(*Shellwords.shellwords(cmd))
183
- rescue Exception => e
184
- (cmd_err_write.closed? ? STDERR : cmd_err_write).puts "Exception in grandchild: #{e.to_s}."
182
+ rescue => e
183
+ (cmd_err_write.closed? ? STDERR : cmd_err_write).puts "Exception in grandchild: #{e}."
185
184
  (cmd_err_write.closed? ? STDERR : cmd_err_write).puts e.backtrace
186
185
  exit 1
187
186
  end
188
- }
187
+ end
189
188
 
190
189
  # we do not use these ends of the pipes in the child
191
190
  cmd_out_write.close
@@ -198,7 +197,7 @@ module Bluepill
198
197
  result = {
199
198
  :stdout => cmd_out_read.read,
200
199
  :stderr => cmd_err_read.read,
201
- :exit_code => $?.exitstatus
200
+ :exit_code => $CHILD_STATUS.exitstatus,
202
201
  }
203
202
 
204
203
  # We're done with these ends of the pipes as well
@@ -214,7 +213,7 @@ module Bluepill
214
213
  end
215
214
 
216
215
  def store
217
- @store ||= Hash.new
216
+ @store ||= {}
218
217
  end
219
218
 
220
219
  def reset_data
@@ -229,7 +228,7 @@ module Bluepill
229
228
 
230
229
  lines.inject(Hash.new) do |mem, line|
231
230
  chunks = line.split(/\s+/)
232
- chunks.delete_if {|c| c.strip.empty? }
231
+ chunks.delete_if { |c| c.strip.empty? }
233
232
  pid = chunks[IDX_MAP[:pid]].strip.to_i
234
233
  command = chunks.slice!(IDX_MAP[:command], chunks.length).join ' '
235
234
  chunks[IDX_MAP[:command]] = command
@@ -242,11 +241,11 @@ module Bluepill
242
241
  def parse_elapsed_time(str)
243
242
  # [[dd-]hh:]mm:ss
244
243
  if str =~ /(?:(?:(\d+)-)?(\d\d):)?(\d\d):(\d\d)/
245
- days = ($1 || 0).to_i
246
- hours = ($2 || 0).to_i
247
- mins = $3.to_i
248
- secs = $4.to_i
249
- ((days*24 + hours)*60 + mins)*60 + secs
244
+ days = (Regexp.last_match[1] || 0).to_i
245
+ hours = (Regexp.last_match[2] || 0).to_i
246
+ mins = Regexp.last_match[3].to_i
247
+ secs = Regexp.last_match[4].to_i
248
+ ((days * 24 + hours) * 60 + mins) * 60 + secs
250
249
  else
251
250
  0
252
251
  end
@@ -255,33 +254,28 @@ module Bluepill
255
254
  # be sure to call this from a fork otherwise it will modify the attributes
256
255
  # of the bluepill daemon
257
256
  def drop_privileges(uid, gid, supplementary_groups)
258
- if ::Process::Sys.geteuid == 0
259
- uid_num = Etc.getpwnam(uid).uid if uid
260
- gid_num = Etc.getgrnam(gid).gid if gid
261
-
262
- supplementary_groups ||= []
263
-
264
- group_nums = supplementary_groups.map do |group|
265
- Etc.getgrnam(group).gid
266
- end
267
-
268
- ::Process.groups = [gid_num] if gid
269
- ::Process.groups |= group_nums unless group_nums.empty?
270
- ::Process::Sys.setgid(gid_num) if gid
271
- ::Process::Sys.setuid(uid_num) if uid
272
- ENV['HOME'] = Etc.getpwuid(uid_num).try(:dir) || ENV['HOME'] if uid
257
+ return unless ::Process::Sys.geteuid.zero?
258
+ uid_num = Etc.getpwnam(uid).uid if uid
259
+ gid_num = Etc.getgrnam(gid).gid if gid
260
+ supplementary_groups ||= []
261
+ group_nums = supplementary_groups.map do |group|
262
+ Etc.getgrnam(group).gid
273
263
  end
264
+ ::Process.groups = [gid_num] if gid
265
+ ::Process.groups |= group_nums unless group_nums.empty?
266
+ ::Process::Sys.setgid(gid_num) if gid
267
+ ::Process::Sys.setuid(uid_num) if uid
268
+ ENV['HOME'] = Etc.getpwuid(uid_num).try(:dir) || ENV['HOME'] if uid
274
269
  end
275
270
 
276
271
  def can_write_pid_file(pid_file, logger)
277
272
  FileUtils.touch(pid_file)
278
273
  File.unlink(pid_file)
279
- return true
280
-
281
- rescue Exception => e
282
- logger.warning "%s - %s" % [e.class.name, e.message]
283
- e.backtrace.each {|l| logger.warning l}
284
- return false
274
+ true
275
+ rescue => e
276
+ logger.warning(format('%s - %s', e.class.name, e.message))
277
+ e.backtrace.each { |l| logger.warning l }
278
+ false
285
279
  end
286
280
 
287
281
  def redirect_io(io_in, io_out, io_err)