oldmoe-neverblock 0.1.6 → 1.0
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/lib/never_block.rb +5 -78
- data/lib/neverblock.rb +3 -1
- data/lib/{never_block/extensions/fiber_extensions.rb → neverblock/core/fiber.rb} +20 -6
- data/lib/neverblock/core/pool.rb +72 -0
- data/lib/neverblock/core/reactor.rb +50 -0
- data/lib/neverblock/core/system/system.rb +38 -0
- data/lib/neverblock/core/system/timeout.rb +67 -0
- data/lib/{never_block/db/pooled_db_connection.rb → neverblock/io/db/connection.rb} +16 -2
- data/lib/neverblock/io/db/drivers/mysql.rb +73 -0
- data/lib/neverblock/io/db/drivers/postgres.rb +63 -0
- data/lib/neverblock/io/db/fibered_connection_pool.rb +130 -0
- data/lib/{never_block → neverblock/io}/db/fibered_mysql_connection.rb +5 -18
- data/lib/{never_block/pool/fibered_connection_pool.rb → neverblock/io/db/pool.rb} +25 -40
- data/lib/neverblock/io/file.rb +24 -0
- data/lib/neverblock/io/io.rb +219 -0
- data/lib/neverblock/io/socket.rb +75 -0
- data/lib/neverblock_io.rb +6 -0
- data/lib/system.rb +4 -0
- data/neverblock.gemspec +23 -21
- metadata +23 -20
- data/lib/active_record/connection_adapters/neverblock_mysql_adapter.rb +0 -68
- data/lib/active_record/connection_adapters/neverblock_postgresql_adapter.rb +0 -85
- data/lib/never_block/db/fibered_db_connection.rb +0 -72
- data/lib/never_block/db/fibered_postgres_connection.rb +0 -64
- data/lib/never_block/frameworks/activerecord.rb +0 -37
- data/lib/never_block/frameworks/rails.rb +0 -65
- data/lib/never_block/pool/fiber_pool.rb +0 -74
- data/lib/never_block/servers/mongrel.rb +0 -236
- data/lib/never_block/servers/thin.rb +0 -32
- data/lib/neverblock-mysql.rb +0 -5
- data/lib/neverblock-pg.rb +0 -5
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
require 'pg'
|
|
2
|
-
|
|
3
|
-
module NeverBlock
|
|
4
|
-
|
|
5
|
-
module DB
|
|
6
|
-
|
|
7
|
-
# A modified postgres connection driver
|
|
8
|
-
# builds on the original pg driver.
|
|
9
|
-
# This driver is able to register the socket
|
|
10
|
-
# at a certain backend (EM or Rev)
|
|
11
|
-
# and then whenever the query is executed
|
|
12
|
-
# within the scope of a friendly fiber
|
|
13
|
-
# it will be done in async mode and the fiber
|
|
14
|
-
# will yield
|
|
15
|
-
class FiberedPostgresConnection < PGconn
|
|
16
|
-
|
|
17
|
-
include FiberedDBConnection
|
|
18
|
-
|
|
19
|
-
# Assuming the use of NeverBlock fiber extensions and that the exec is run in
|
|
20
|
-
# the context of a fiber. One that have the value :neverblock set to true.
|
|
21
|
-
# All neverblock IO classes check this value, setting it to false will force
|
|
22
|
-
# the execution in a blocking way.
|
|
23
|
-
def exec(sql)
|
|
24
|
-
# TODO Still not "killing the query process"-proof
|
|
25
|
-
# In some cases, the query is simply sent but the fiber never yields
|
|
26
|
-
if NB.event_loop_available? && NB.neverblocking?
|
|
27
|
-
begin
|
|
28
|
-
send_query sql
|
|
29
|
-
@fiber = Fiber.current
|
|
30
|
-
Fiber.yield register_with_event_loop
|
|
31
|
-
while is_busy
|
|
32
|
-
consume_input
|
|
33
|
-
Fiber.yield if is_busy
|
|
34
|
-
end
|
|
35
|
-
res, data = 0, []
|
|
36
|
-
while res != nil
|
|
37
|
-
res = self.get_result
|
|
38
|
-
data << res unless res.nil?
|
|
39
|
-
end
|
|
40
|
-
data.last
|
|
41
|
-
rescue Exception => e
|
|
42
|
-
if error = ['not connected', 'gone away', 'Lost connection','no connection'].detect{|msg| e.message.include? msg}
|
|
43
|
-
#event_loop_connection_close
|
|
44
|
-
unregister_from_event_loop
|
|
45
|
-
reset
|
|
46
|
-
end
|
|
47
|
-
raise e
|
|
48
|
-
ensure
|
|
49
|
-
unregister_from_event_loop
|
|
50
|
-
end
|
|
51
|
-
else
|
|
52
|
-
super(sql)
|
|
53
|
-
end
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
alias_method :query, :exec
|
|
57
|
-
|
|
58
|
-
end #FiberedPostgresConnection
|
|
59
|
-
|
|
60
|
-
end #DB
|
|
61
|
-
|
|
62
|
-
end #NeverBlock
|
|
63
|
-
|
|
64
|
-
NeverBlock::DB::FPGconn = NeverBlock::DB::FiberedPostgresConnection
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
require 'activerecord'
|
|
2
|
-
|
|
3
|
-
# Patch ActiveRecord to store transaction depth information
|
|
4
|
-
# in fibers instead of threads. AR does not support nested
|
|
5
|
-
# transactions which makes the job easy.
|
|
6
|
-
# We also need to override the scoped methods to store
|
|
7
|
-
# the scope in the fiber context
|
|
8
|
-
class ActiveRecord::Base
|
|
9
|
-
|
|
10
|
-
def single_threaded_scoped_methods #:nodoc:
|
|
11
|
-
scoped_methods = (Fiber.current[:scoped_methods] ||= {})
|
|
12
|
-
scoped_methods[self] ||= []
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def self.transaction(&block)
|
|
16
|
-
increment_open_transactions
|
|
17
|
-
begin
|
|
18
|
-
connection.transaction(Fiber.current['start_db_transaction'], &block)
|
|
19
|
-
ensure
|
|
20
|
-
decrement_open_transactions
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
private
|
|
25
|
-
|
|
26
|
-
def self.increment_open_transactions #:nodoc:
|
|
27
|
-
open = Fiber.current['open_transactions'] ||= 0
|
|
28
|
-
Fiber.current['start_db_transaction'] = open.zero?
|
|
29
|
-
Fiber.current['open_transactions'] = open + 1
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def self.decrement_open_transactions #:nodoc:
|
|
33
|
-
Fiber.current['open_transactions'] -= 1
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
end
|
|
37
|
-
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
require 'neverblock' unless defined?(NeverBlock)
|
|
2
|
-
|
|
3
|
-
# Rails tries to protect dispatched actions
|
|
4
|
-
# by wrapping them in a synchronized code
|
|
5
|
-
# block, since fibers hate synchronized
|
|
6
|
-
# blocks we will trick the guard and
|
|
7
|
-
# transform it (without it knowing) to
|
|
8
|
-
# something more subtle
|
|
9
|
-
|
|
10
|
-
require 'thread'
|
|
11
|
-
# now you synchronize
|
|
12
|
-
class Mutex
|
|
13
|
-
def synchronize(&block)
|
|
14
|
-
# now you don't!
|
|
15
|
-
block.call
|
|
16
|
-
end
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
require 'action_controller'
|
|
20
|
-
class ActionController::Base
|
|
21
|
-
|
|
22
|
-
# Mark some actions to execute in a blocking manner overriding the default
|
|
23
|
-
# settings.
|
|
24
|
-
# Example:
|
|
25
|
-
# class UsersController < ApplicationController
|
|
26
|
-
# .
|
|
27
|
-
# allowblock :index
|
|
28
|
-
# .
|
|
29
|
-
# end
|
|
30
|
-
def self.allowblock(*actions)
|
|
31
|
-
actions.each do |action|
|
|
32
|
-
class_eval <<-"end_eval"
|
|
33
|
-
def allowblock_#{action}
|
|
34
|
-
status = Fiber.current[:neverblock]
|
|
35
|
-
Fiber.current[:neverblock] = false
|
|
36
|
-
yield
|
|
37
|
-
Fiber.current[:neverblock] = status
|
|
38
|
-
end
|
|
39
|
-
around_filter :allowblock_#{action}, :only => [:#{action}]
|
|
40
|
-
end_eval
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
# Mark some actions to execute in a non-blocking manner overriding the default
|
|
45
|
-
# settings.
|
|
46
|
-
# Example:
|
|
47
|
-
# class UsersController < ApplicationController
|
|
48
|
-
# .
|
|
49
|
-
# allowblock :index
|
|
50
|
-
# .
|
|
51
|
-
# end
|
|
52
|
-
def self.neverblock(*actions)
|
|
53
|
-
actions.each do |action|
|
|
54
|
-
class_eval <<-"end_eval"
|
|
55
|
-
def neverblock_#{action}
|
|
56
|
-
status = Fiber.current[:neverblock]
|
|
57
|
-
Fiber.current[:neverblock] = true
|
|
58
|
-
yield
|
|
59
|
-
Fiber.current[:neverblock] = status
|
|
60
|
-
end
|
|
61
|
-
around_filter :allowblock_#{action}, :only => [:#{action}]
|
|
62
|
-
end_eval
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
end
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
module NeverBlock
|
|
2
|
-
module Pool
|
|
3
|
-
|
|
4
|
-
# Author:: Mohammad A. Ali (mailto:oldmoe@gmail.com)
|
|
5
|
-
# Copyright:: Copyright (c) 2008 eSpace, Inc.
|
|
6
|
-
# License:: Distributes under the same terms as Ruby
|
|
7
|
-
#
|
|
8
|
-
# A pool of initialized fibers
|
|
9
|
-
# It does not grow in size or create transient fibers
|
|
10
|
-
# It will queue code blocks when needed (if all its fibers are busy)
|
|
11
|
-
#
|
|
12
|
-
# This class is particulary useful when you use the fibers
|
|
13
|
-
# to connect to evented back ends. It also does not generate
|
|
14
|
-
# transient objects and thus saves memory.
|
|
15
|
-
#
|
|
16
|
-
# Example:
|
|
17
|
-
# fiber_pool = NeverBlock::Pool::FiberPool.new(150)
|
|
18
|
-
#
|
|
19
|
-
# loop do
|
|
20
|
-
# fiber_pool.spawn do
|
|
21
|
-
# #fiber body goes here
|
|
22
|
-
# end
|
|
23
|
-
# end
|
|
24
|
-
#
|
|
25
|
-
class FiberPool
|
|
26
|
-
|
|
27
|
-
# gives access to the currently free fibers
|
|
28
|
-
attr_reader :fibers
|
|
29
|
-
|
|
30
|
-
# Prepare a list of fibers that are able to run different blocks of code
|
|
31
|
-
# every time. Once a fiber is done with its block, it attempts to fetch
|
|
32
|
-
# another one from the queue
|
|
33
|
-
def initialize(count = 50)
|
|
34
|
-
@fibers,@busy_fibers,@queue = [],{},[]
|
|
35
|
-
count.times do |i|
|
|
36
|
-
fiber = Fiber.new do |block|
|
|
37
|
-
loop do
|
|
38
|
-
block.call
|
|
39
|
-
# callbacks are called in a reverse order, much like c++ destructor
|
|
40
|
-
Fiber.current[:callbacks].pop.call while Fiber.current[:callbacks].length > 0
|
|
41
|
-
unless @queue.empty?
|
|
42
|
-
block = @queue.shift
|
|
43
|
-
else
|
|
44
|
-
@busy_fibers.delete(Fiber.current.object_id)
|
|
45
|
-
@fibers << Fiber.current
|
|
46
|
-
block = Fiber.yield
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
fiber[:callbacks] = []
|
|
51
|
-
fiber[:em_keys] = []
|
|
52
|
-
fiber[:neverblock] = true
|
|
53
|
-
@fibers << fiber
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
# If there is an available fiber use it, otherwise, leave it to linger
|
|
58
|
-
# in a queue
|
|
59
|
-
def spawn(evented = true, &block)
|
|
60
|
-
if fiber = @fibers.shift
|
|
61
|
-
fiber[:callbacks] = []
|
|
62
|
-
@busy_fibers[fiber.object_id] = fiber
|
|
63
|
-
fiber[:neverblock] = evented
|
|
64
|
-
fiber.resume(block)
|
|
65
|
-
else
|
|
66
|
-
@queue << block
|
|
67
|
-
end
|
|
68
|
-
self # we are keen on hiding our queue
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
end # FiberPool
|
|
72
|
-
end # Pool
|
|
73
|
-
end # NeverBlock
|
|
74
|
-
|
|
@@ -1,236 +0,0 @@
|
|
|
1
|
-
# This module rewrites pieces of the very good Mongrel web server in
|
|
2
|
-
# order to change it from a threaded application to an event based
|
|
3
|
-
# application running inside an EventMachine event loop. It should
|
|
4
|
-
# be compatible with the existing Mongrel handlers for Rails,
|
|
5
|
-
# Camping, Nitro, etc....
|
|
6
|
-
|
|
7
|
-
# NeverBlock support added
|
|
8
|
-
|
|
9
|
-
begin
|
|
10
|
-
load_attempted ||= false
|
|
11
|
-
require 'eventmachine'
|
|
12
|
-
rescue LoadError
|
|
13
|
-
unless load_attempted
|
|
14
|
-
load_attempted = true
|
|
15
|
-
require 'rubygems'
|
|
16
|
-
retry
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
require 'rubygems'
|
|
21
|
-
require 'neverblock'
|
|
22
|
-
require 'mongrel'
|
|
23
|
-
|
|
24
|
-
module Mongrel
|
|
25
|
-
class MongrelProtocol < EventMachine::Connection
|
|
26
|
-
def post_init
|
|
27
|
-
@parser = HttpParser.new
|
|
28
|
-
@params = HttpParams.new
|
|
29
|
-
@nparsed = 0
|
|
30
|
-
@request = nil
|
|
31
|
-
@request_len = nil
|
|
32
|
-
@linebuffer = ''
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def receive_data data
|
|
36
|
-
@linebuffer << data
|
|
37
|
-
@nparsed = @parser.execute(@params, @linebuffer, @nparsed) unless @parser.finished?
|
|
38
|
-
if @parser.finished?
|
|
39
|
-
if @request_len.nil?
|
|
40
|
-
@request_len = @params[::Mongrel::Const::CONTENT_LENGTH].to_i
|
|
41
|
-
script_name, path_info, handlers = ::Mongrel::HttpServer::Instance.classifier.resolve(@params[::Mongrel::Const::REQUEST_PATH])
|
|
42
|
-
if handlers
|
|
43
|
-
@params[::Mongrel::Const::PATH_INFO] = path_info
|
|
44
|
-
@params[::Mongrel::Const::SCRIPT_NAME] = script_name
|
|
45
|
-
@params[::Mongrel::Const::REMOTE_ADDR] = @params[::Mongrel::Const::HTTP_X_FORWARDED_FOR] || ::Socket.unpack_sockaddr_in(get_peername)[1]
|
|
46
|
-
@notifiers = handlers.select { |h| h.request_notify }
|
|
47
|
-
end
|
|
48
|
-
if @request_len > ::Mongrel::Const::MAX_BODY
|
|
49
|
-
new_buffer = Tempfile.new(::Mongrel::Const::MONGREL_TMP_BASE)
|
|
50
|
-
new_buffer.binmode
|
|
51
|
-
new_buffer << @linebuffer[@nparsed..-1]
|
|
52
|
-
@linebuffer = new_buffer
|
|
53
|
-
else
|
|
54
|
-
@linebuffer = StringIO.new(@linebuffer[@nparsed..-1])
|
|
55
|
-
@linebuffer.pos = @linebuffer.length
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
if @linebuffer.length >= @request_len
|
|
59
|
-
@linebuffer.rewind
|
|
60
|
-
::Mongrel::HttpServer::Instance.process_http_request(@params,@linebuffer,self)
|
|
61
|
-
@linebuffer.delete if Tempfile === @linebuffer
|
|
62
|
-
end
|
|
63
|
-
elsif @linebuffer.length > ::Mongrel::Const::MAX_HEADER
|
|
64
|
-
close_connection
|
|
65
|
-
raise ::Mongrel::HttpParserError.new("HEADER is longer than allowed, aborting client early.")
|
|
66
|
-
end
|
|
67
|
-
rescue ::Mongrel::HttpParserError
|
|
68
|
-
if $mongrel_debug_client
|
|
69
|
-
STDERR.puts "#{Time.now}: BAD CLIENT (#{params[Const::HTTP_X_FORWARDED_FOR] || client.peeraddr.last}): #$!"
|
|
70
|
-
STDERR.puts "#{Time.now}: REQUEST DATA: #{data.inspect}\n---\nPARAMS: #{params.inspect}\n---\n"
|
|
71
|
-
end
|
|
72
|
-
close_connection
|
|
73
|
-
rescue Exception => e
|
|
74
|
-
close_connection
|
|
75
|
-
raise e
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
def write data
|
|
79
|
-
send_data data
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
def closed?
|
|
83
|
-
false
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
class HttpServer
|
|
89
|
-
DEFAULT_FIBER_POOL_SIZE = 20
|
|
90
|
-
def initialize(host, port, num_processors=950, x=0, y=nil) # Deal with Mongrel 1.0.1 or earlier, as well as later.
|
|
91
|
-
@socket = nil
|
|
92
|
-
@classifier = URIClassifier.new
|
|
93
|
-
@host = host
|
|
94
|
-
@port = port
|
|
95
|
-
@workers = ThreadGroup.new
|
|
96
|
-
if y
|
|
97
|
-
@throttle = x
|
|
98
|
-
@timeout = y || 60
|
|
99
|
-
else
|
|
100
|
-
@timeout = x
|
|
101
|
-
end
|
|
102
|
-
@num_processors = num_processors #num_processors is pointless for evented....
|
|
103
|
-
@death_time = 60
|
|
104
|
-
self.class.const_set(:Instance,self)
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
def fiber_pool
|
|
108
|
-
@fiber_pool ||= NB::Pool::FiberPool.new(DEFAULT_FIBER_POOL_SIZE)
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
def run
|
|
112
|
-
trap('INT') { raise StopServer }
|
|
113
|
-
trap('TERM') { raise StopServer }
|
|
114
|
-
@acceptor = Thread.new do
|
|
115
|
-
EventMachine.epoll
|
|
116
|
-
EventMachine.set_descriptor_table_size(4096)
|
|
117
|
-
EventMachine.run do
|
|
118
|
-
begin
|
|
119
|
-
EventMachine.start_server(@host,@port,MongrelProtocol)
|
|
120
|
-
rescue StopServer
|
|
121
|
-
EventMachine.stop_event_loop
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
def process_http_request(params,linebuffer,client)
|
|
128
|
-
if not params[Const::REQUEST_PATH]
|
|
129
|
-
uri = URI.parse(params[Const::REQUEST_URI])
|
|
130
|
-
params[Const::REQUEST_PATH] = uri.request_uri
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
raise "No REQUEST PATH" if not params[Const::REQUEST_PATH]
|
|
134
|
-
|
|
135
|
-
script_name, path_info, handlers = @classifier.resolve(params[Const::REQUEST_PATH])
|
|
136
|
-
|
|
137
|
-
if handlers
|
|
138
|
-
notifiers = handlers.select { |h| h.request_notify }
|
|
139
|
-
request = HttpRequest.new(params, linebuffer, notifiers)
|
|
140
|
-
|
|
141
|
-
# request is good so far, continue processing the response
|
|
142
|
-
response = HttpResponse.new(client)
|
|
143
|
-
|
|
144
|
-
# Process each handler in registered order until we run out or one finalizes the response.
|
|
145
|
-
fiber_pool.spawn do
|
|
146
|
-
dispatch_to_handlers(handlers,request,response)
|
|
147
|
-
end
|
|
148
|
-
# And finally, if nobody closed the response off, we finalize it.
|
|
149
|
-
unless response.done
|
|
150
|
-
response.finished
|
|
151
|
-
else
|
|
152
|
-
response.close_connection_after_writing
|
|
153
|
-
end
|
|
154
|
-
else
|
|
155
|
-
# Didn't find it, return a stock 404 response.
|
|
156
|
-
client.send_data(Const::ERROR_404_RESPONSE)
|
|
157
|
-
client.close_connection_after_writing
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
|
|
161
|
-
def dispatch_to_handlers(handlers,request,response)
|
|
162
|
-
handlers.each do |handler|
|
|
163
|
-
handler.process(request, response)
|
|
164
|
-
break if response.done
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
class HttpRequest
|
|
170
|
-
def initialize(params, linebuffer, dispatchers)
|
|
171
|
-
@params = params
|
|
172
|
-
@dispatchers = dispatchers
|
|
173
|
-
@body = linebuffer
|
|
174
|
-
end
|
|
175
|
-
end
|
|
176
|
-
|
|
177
|
-
class HttpResponse
|
|
178
|
-
def send_file(path, small_file = false)
|
|
179
|
-
File.open(path, "rb") do |f|
|
|
180
|
-
while chunk = f.read(Const::CHUNK_SIZE) and chunk.length > 0
|
|
181
|
-
begin
|
|
182
|
-
write(chunk)
|
|
183
|
-
rescue Object => exc
|
|
184
|
-
break
|
|
185
|
-
end
|
|
186
|
-
end
|
|
187
|
-
end
|
|
188
|
-
@body_sent = true
|
|
189
|
-
end
|
|
190
|
-
|
|
191
|
-
def write(data)
|
|
192
|
-
@socket.send_data data
|
|
193
|
-
end
|
|
194
|
-
|
|
195
|
-
def close_connection_after_writing
|
|
196
|
-
@socket.close_connection_after_writing
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
def socket_error(details)
|
|
200
|
-
@socket.close_connection
|
|
201
|
-
done = true
|
|
202
|
-
raise details
|
|
203
|
-
end
|
|
204
|
-
|
|
205
|
-
def finished
|
|
206
|
-
send_status
|
|
207
|
-
send_header
|
|
208
|
-
send_body
|
|
209
|
-
@socket.close_connection_after_writing
|
|
210
|
-
end
|
|
211
|
-
end
|
|
212
|
-
|
|
213
|
-
class Configurator
|
|
214
|
-
# This version fixes a bug in the regular Mongrel version by adding
|
|
215
|
-
# initialization of groups.
|
|
216
|
-
def change_privilege(user, group)
|
|
217
|
-
if user and group
|
|
218
|
-
log "Initializing groups for {#user}:{#group}."
|
|
219
|
-
Process.initgroups(user,Etc.getgrnam(group).gid)
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
if group
|
|
223
|
-
log "Changing group to #{group}."
|
|
224
|
-
Process::GID.change_privilege(Etc.getgrnam(group).gid)
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
if user
|
|
228
|
-
log "Changing user to #{user}."
|
|
229
|
-
Process::UID.change_privilege(Etc.getpwnam(user).uid)
|
|
230
|
-
end
|
|
231
|
-
rescue Errno::EPERM
|
|
232
|
-
log "FAILED to change user:group #{user}:#{group}: #$!"
|
|
233
|
-
exit 1
|
|
234
|
-
end
|
|
235
|
-
end
|
|
236
|
-
end
|