shexecutor 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +25 -0
- data/lib/shexecutor/version.rb +1 -1
- data/lib/shexecutor.rb +32 -13
- data/spec/executor_spec.rb +13 -2
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c90615e32be8148e01050f014d0bf7e107b403ad
|
4
|
+
data.tar.gz: 55607d1521893564995bea9da74153b084bd92ec
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 54788b1980134c365b3b4c8cfb20c0d73ad74b3283e398f86e2b24662c57fcc382978dec80dfe10f463cf730ab7bab1244475dd1a32c609988a70ed888204b9d
|
7
|
+
data.tar.gz: becd1258cd4c5c1a526f180a419503430d5549c4064df9078300ba102d4100fb9229df812b6ca5b79787ec4d94894d00eea7ff993ed7bbd6073de8474f991af9
|
data/README.md
CHANGED
@@ -20,6 +20,31 @@ For a full description of status, please see Process::Status
|
|
20
20
|
|
21
21
|
This gem is sponsored by Hetzner (Pty) Ltd - http://hetzner.co.za
|
22
22
|
|
23
|
+
## Initialization options:
|
24
|
+
|
25
|
+
Required / optional:
|
26
|
+
|
27
|
+
```
|
28
|
+
{
|
29
|
+
:application_path # Path of the command to run
|
30
|
+
:params # Parameters to pass the command
|
31
|
+
}
|
32
|
+
```
|
33
|
+
|
34
|
+
```
|
35
|
+
@@default_options = {
|
36
|
+
:timeout => -1, # Seconds after which to raise Timeout::Error if not completed
|
37
|
+
:protect_against_injection => true, # look for spaces in and tainted application path
|
38
|
+
:stdout_path => nil, # file to append stdout to
|
39
|
+
:stderr_path => nil, # file to append stderr to
|
40
|
+
:append_stdout_path => true, # if true, will append, otherwise will overwrite
|
41
|
+
:append_stderr_path => true, # if true, will append, otherwise will overwrite
|
42
|
+
:replace => false, # replace the running process with the command
|
43
|
+
:wait_for_completion => false, # block until the command completes
|
44
|
+
:timeout_sig_kill_retry => 500 # if timeout occurs, send TERM, and send signal 9 if still present after X ms
|
45
|
+
}
|
46
|
+
```
|
47
|
+
|
23
48
|
## Installation
|
24
49
|
|
25
50
|
Add this line to your application's Gemfile:
|
data/lib/shexecutor/version.rb
CHANGED
data/lib/shexecutor.rb
CHANGED
@@ -3,14 +3,15 @@ require 'open3'
|
|
3
3
|
|
4
4
|
module SHExecutor
|
5
5
|
@@default_options = {
|
6
|
-
:timeout => -1,
|
7
|
-
:protect_against_injection => true,
|
8
|
-
:stdout_path => nil,
|
9
|
-
:stderr_path => nil,
|
10
|
-
:append_stdout_path => true,
|
11
|
-
:append_stderr_path => true,
|
12
|
-
:replace => false,
|
13
|
-
:wait_for_completion => false
|
6
|
+
:timeout => -1, # Seconds after which to raise Timeout::Error if not completed
|
7
|
+
:protect_against_injection => true, # look for spaces in and tainted application path
|
8
|
+
:stdout_path => nil, # file to append stdout to
|
9
|
+
:stderr_path => nil, # file to append stderr to
|
10
|
+
:append_stdout_path => true, # if true, will append, otherwise will overwrite
|
11
|
+
:append_stderr_path => true, # if true, will append, otherwise will overwrite
|
12
|
+
:replace => false, # replace the running process with the command
|
13
|
+
:wait_for_completion => false, # block until the command completes
|
14
|
+
:timeout_sig_kill_retry => 500 # if timeout occurs, send TERM, and send signal 9 if still present after X ms
|
14
15
|
}
|
15
16
|
|
16
17
|
def self.default_options
|
@@ -127,9 +128,9 @@ module SHExecutor
|
|
127
128
|
def run_process(application_path, options = "")
|
128
129
|
data_out = StringIO.new
|
129
130
|
data_err = StringIO.new
|
130
|
-
t0 = nil
|
131
|
+
@t0 = nil
|
131
132
|
Open3::popen3(application_path, options) do |stdin, stdout, stderr, thr|
|
132
|
-
t0 = thr
|
133
|
+
@t0 = thr
|
133
134
|
# read srderr and stdout into buffers to prevent blocking
|
134
135
|
t1 = Thread.new do
|
135
136
|
IO.copy_stream(stdout, data_out)
|
@@ -151,7 +152,7 @@ module SHExecutor
|
|
151
152
|
t1.join if not should_timeout?
|
152
153
|
t2.join if not should_timeout?
|
153
154
|
end
|
154
|
-
return data_out, data_err, t0
|
155
|
+
return data_out, data_err, @t0
|
155
156
|
end
|
156
157
|
|
157
158
|
def block_process
|
@@ -170,17 +171,35 @@ module SHExecutor
|
|
170
171
|
@result.join
|
171
172
|
@result.value
|
172
173
|
rescue Timeout::Error => ex
|
174
|
+
kill_process(@t0.pid)
|
173
175
|
raise ex
|
174
176
|
end
|
175
177
|
end
|
176
178
|
|
179
|
+
def process?(pid)
|
180
|
+
begin
|
181
|
+
Process.getpgid(pid)
|
182
|
+
true
|
183
|
+
rescue Errno::ESRCH
|
184
|
+
false
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def kill_process(pid)
|
189
|
+
return if pid.nil?
|
190
|
+
Process.kill("TERM", pid)
|
191
|
+
count = 0
|
192
|
+
while (count < (@options[:timeout_sig_kill_retry]/100) and process?(pid)) do
|
193
|
+
sleep 0.1
|
194
|
+
end
|
195
|
+
Process.kill(9, pid) if process?(pid)
|
196
|
+
end
|
197
|
+
|
177
198
|
def fork_process
|
178
199
|
validate
|
179
200
|
@stdin_stream, @stdout_stream, @stderr_stream, @result = Open3::popen3(@options[:application_path], *@options[:params])
|
180
201
|
end
|
181
202
|
|
182
|
-
private
|
183
|
-
|
184
203
|
def should_timeout?
|
185
204
|
@options[:timeout] > 0
|
186
205
|
end
|
data/spec/executor_spec.rb
CHANGED
@@ -27,7 +27,8 @@ describe 'Executor' do
|
|
27
27
|
:append_stdout_path => false,
|
28
28
|
:append_stderr_path => false,
|
29
29
|
:replace => false,
|
30
|
-
:wait_for_completion => true
|
30
|
+
:wait_for_completion => true,
|
31
|
+
:timeout_sig_kill_retry => 500
|
31
32
|
}
|
32
33
|
@iut = SHExecutor::Executor.new(iut_options)
|
33
34
|
expect(@iut.options).to eq(iut_options)
|
@@ -207,7 +208,7 @@ describe 'Executor' do
|
|
207
208
|
end
|
208
209
|
|
209
210
|
context 'when asked to execute and block' do
|
210
|
-
it 'should raise a
|
211
|
+
it 'should raise a Timeout::Error if a timeout is specified and the process does not exit before' do
|
211
212
|
test_command = "/bin/sleep"
|
212
213
|
test_params = ["5"]
|
213
214
|
iut = SHExecutor::Executor.new({:timeout => 1, :wait_for_completion => true, :application_path => test_command, :params => test_params})
|
@@ -219,6 +220,16 @@ describe 'Executor' do
|
|
219
220
|
expect(after - before).to be < 2.1
|
220
221
|
end
|
221
222
|
|
223
|
+
it 'should kill the subprocess when a TimeoutError is raised' do
|
224
|
+
test_command = "/bin/sleep"
|
225
|
+
test_params = ["2"]
|
226
|
+
iut = SHExecutor::Executor.new({:timeout => 1, :wait_for_completion => true, :application_path => test_command, :params => test_params})
|
227
|
+
expect(Process).to receive(:kill)
|
228
|
+
expect {
|
229
|
+
iut.execute
|
230
|
+
}.to raise_error(Timeout::Error, "execution expired")
|
231
|
+
end
|
232
|
+
|
222
233
|
it 'should call run_process with the command and parameters specified' do
|
223
234
|
test_command = "/bin/ls"
|
224
235
|
test_params = ["/tmp/"]
|