snipr 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/snipe +7 -1
- data/lib/snipr/process_signaller.rb +39 -2
- data/lib/snipr/version.rb +1 -1
- data/spec/process_signaller_spec.rb +30 -1
- metadata +59 -22
- checksums.yaml +0 -7
data/bin/snipe
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#!/usr/bin/ruby
|
1
|
+
#!/usr/bin/env ruby
|
2
2
|
require 'ostruct'
|
3
3
|
require 'optparse'
|
4
4
|
|
@@ -59,6 +59,11 @@ parser = OptionParser.new do |config|
|
|
59
59
|
config.on("-d", "--dry-run", desc) do
|
60
60
|
options.no_signals = true
|
61
61
|
end
|
62
|
+
|
63
|
+
desc = "Use the pkill utility to send the signal (targetted process only)"
|
64
|
+
config.on("--pkill", desc) do
|
65
|
+
options.pkill = true
|
66
|
+
end
|
62
67
|
end.parse!
|
63
68
|
|
64
69
|
# TODO remove me
|
@@ -88,6 +93,7 @@ signaller = Snipr::ProcessSignaller.new do |signaller|
|
|
88
93
|
end
|
89
94
|
signaller.signal options.signal
|
90
95
|
signaller.target_parent options.target_parent
|
96
|
+
signaller.pkill if options.pkill
|
91
97
|
signaller.dry_run if options.no_signals
|
92
98
|
|
93
99
|
if options.bytes
|
@@ -132,14 +132,51 @@ module Snipr
|
|
132
132
|
@dry_run = true
|
133
133
|
end
|
134
134
|
|
135
|
+
##
|
136
|
+
# Use pkill to ensure that the process we are attempting to signal
|
137
|
+
# matches what we know about it. This only works for the
|
138
|
+
# targetted process, not the parent.
|
139
|
+
def pkill
|
140
|
+
@pkill = which("pkill")
|
141
|
+
raise "pkill not found in path or is not executable!" unless @pkill
|
142
|
+
end
|
143
|
+
|
144
|
+
# Determine if a command exists in our PATH
|
145
|
+
def which(cmd)
|
146
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
147
|
+
location = File.join(path, cmd)
|
148
|
+
return location if File.executable?(location)
|
149
|
+
end
|
150
|
+
return nil
|
151
|
+
end
|
152
|
+
|
153
|
+
##
|
154
|
+
# Ensure that the PID we are attempting to kill still matches what we expect
|
155
|
+
# This is not used when pkill option is set
|
156
|
+
def cmd_matches?(process)
|
157
|
+
process.command == Snipr.exec_cmd("ps -p #{process.pid} -o 'command='").first.strip
|
158
|
+
end
|
159
|
+
|
160
|
+
def ppid_matches?(process)
|
161
|
+
Integer(process.ppid) == Integer(Snipr.exec_cmd("ps -p #{process.pid} -o 'ppid='").first.strip)
|
162
|
+
end
|
163
|
+
|
164
|
+
def process_matches?(process)
|
165
|
+
cmd_matches?(process) && ppid_matches?(process)
|
166
|
+
end
|
167
|
+
|
135
168
|
private
|
136
169
|
def signal_process(process)
|
137
170
|
@before_signal.call(@signal, process)
|
138
171
|
unless @dry_run
|
139
172
|
if @target_parent
|
140
|
-
Process.kill(@signal, process.ppid)
|
173
|
+
Process.kill(@signal, process.ppid) if process_matches?(process)
|
141
174
|
else
|
142
|
-
|
175
|
+
if @pkill
|
176
|
+
system("#{@pkill} --signal #{@signal} -P #{process.ppid} -f \"^#{Regexp.escape(process.command)}\"")
|
177
|
+
else
|
178
|
+
Process.kill(@signal, process.pid) if process_matches?(process)
|
179
|
+
end
|
143
180
|
end
|
144
181
|
end
|
145
182
|
@after_signal.call(@signal, process)
|
data/lib/snipr/version.rb
CHANGED
@@ -6,6 +6,7 @@ module Snipr
|
|
6
6
|
let(:signal) {Signal.list["USR1"]}
|
7
7
|
let(:ps_output) {File.read("spec/ps_output.txt").split("\n")}
|
8
8
|
let(:checkins) {OpenStruct.new}
|
9
|
+
let(:pkill) { "/bin/pkill" }
|
9
10
|
subject do
|
10
11
|
ProcessSignaller.new do |signaller|
|
11
12
|
signaller.include /resque/i
|
@@ -64,13 +65,29 @@ module Snipr
|
|
64
65
|
|
65
66
|
context "when process is found" do
|
66
67
|
before do
|
67
|
-
|
68
|
+
allow(Snipr).to receive(:exec_cmd).and_return(:default)
|
69
|
+
expect(Snipr).to receive(:exec_cmd).with("ps h -eo pid,ppid,%mem,%cpu,etime,command").and_return(ps_output).at_least(:once)
|
68
70
|
subject.cpu_greater_than(90)
|
69
71
|
end
|
70
72
|
|
71
73
|
context "targetting the process itself" do
|
72
74
|
it "should send the appropriate signal to the process and call callbacks" do
|
73
75
|
expect(Process).to receive(:kill).with(signal, 6337)
|
76
|
+
expect(Snipr).to receive(:exec_cmd).with(/ps -p \d+ -o/).and_return(
|
77
|
+
"resque-1.24.1: Processing foo since 1410189132 [FooJob]",
|
78
|
+
"4347 "
|
79
|
+
).twice
|
80
|
+
subject.send_signals
|
81
|
+
expect(checkins.before_signal).to eq("#{signal} > 6337")
|
82
|
+
expect(checkins.after_signal).to eq("#{signal} > 6337")
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should shell out to pkill when --pkill option is set" do
|
86
|
+
expect(subject).to receive(:which).and_return(pkill)
|
87
|
+
subject.pkill
|
88
|
+
expect(subject).to receive(:system).with(
|
89
|
+
"#{pkill} --signal #{signal} -P 4347 -f \"^#{Regexp.escape('resque-1.24.1: Processing foo since 1410189132 [FooJob]')}\""
|
90
|
+
)
|
74
91
|
subject.send_signals
|
75
92
|
expect(checkins.before_signal).to eq("#{signal} > 6337")
|
76
93
|
expect(checkins.after_signal).to eq("#{signal} > 6337")
|
@@ -80,6 +97,10 @@ module Snipr
|
|
80
97
|
context "targetting the parent process" do
|
81
98
|
it "should send the appropriate signal to the parent process and call callbacks" do
|
82
99
|
subject.target_parent true
|
100
|
+
expect(Snipr).to receive(:exec_cmd).with(/ps -p \d+ -o/).and_return(
|
101
|
+
"resque-1.24.1: Processing foo since 1410189132 [FooJob]",
|
102
|
+
"4347 "
|
103
|
+
).twice
|
83
104
|
expect(Process).to receive(:kill).with(signal, 4347)
|
84
105
|
subject.send_signals
|
85
106
|
expect(checkins.before_signal).to eq("#{signal} > 6337")
|
@@ -89,6 +110,7 @@ module Snipr
|
|
89
110
|
|
90
111
|
context "when encountering an error signalling a process" do
|
91
112
|
it "should call the on_error callback" do
|
113
|
+
expect(subject).to receive(:process_matches?).and_return(true)
|
92
114
|
expect(Process).to receive(:kill).with(signal, 6337).and_raise('Ouch!')
|
93
115
|
subject.send_signals
|
94
116
|
expect(checkins.on_error).to eq("Ouch! #{signal} > 6337")
|
@@ -105,6 +127,13 @@ module Snipr
|
|
105
127
|
end
|
106
128
|
end
|
107
129
|
end
|
130
|
+
|
131
|
+
context "when --pkill is set but no pkill is found in the path" do
|
132
|
+
it "raise an exception" do
|
133
|
+
expect(subject).to receive(:which).and_return(nil)
|
134
|
+
expect{ subject.pkill }.to raise_error
|
135
|
+
end
|
136
|
+
end
|
108
137
|
end
|
109
138
|
end
|
110
139
|
end
|
metadata
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: snipr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 19
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 1.1.0
|
5
11
|
platform: ruby
|
6
12
|
authors:
|
7
13
|
- Lance Woodson
|
@@ -9,49 +15,69 @@ autorequire:
|
|
9
15
|
bindir: bin
|
10
16
|
cert_chain: []
|
11
17
|
|
12
|
-
date:
|
18
|
+
date: 2017-10-27 00:00:00 -05:00
|
19
|
+
default_executable:
|
13
20
|
dependencies:
|
14
21
|
- !ruby/object:Gem::Dependency
|
15
|
-
name: bundler
|
16
|
-
prerelease: false
|
17
22
|
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
none: false
|
18
24
|
requirements:
|
19
25
|
- - ~>
|
20
26
|
- !ruby/object:Gem::Version
|
27
|
+
hash: 3
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 6
|
21
31
|
version: "1.6"
|
22
|
-
type: :development
|
23
32
|
version_requirements: *id001
|
24
|
-
- !ruby/object:Gem::Dependency
|
25
|
-
name: rake
|
26
33
|
prerelease: false
|
34
|
+
type: :development
|
35
|
+
name: bundler
|
36
|
+
- !ruby/object:Gem::Dependency
|
27
37
|
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
28
39
|
requirements:
|
29
40
|
- - ~>
|
30
41
|
- !ruby/object:Gem::Version
|
42
|
+
hash: 35
|
43
|
+
segments:
|
44
|
+
- 10
|
45
|
+
- 0
|
31
46
|
version: "10.0"
|
32
|
-
type: :development
|
33
47
|
version_requirements: *id002
|
34
|
-
- !ruby/object:Gem::Dependency
|
35
|
-
name: rspec
|
36
48
|
prerelease: false
|
49
|
+
type: :development
|
50
|
+
name: rake
|
51
|
+
- !ruby/object:Gem::Dependency
|
37
52
|
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
38
54
|
requirements:
|
39
55
|
- - ~>
|
40
56
|
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 3
|
60
|
+
- 1
|
61
|
+
- 0
|
41
62
|
version: 3.1.0
|
42
|
-
type: :development
|
43
63
|
version_requirements: *id003
|
44
|
-
- !ruby/object:Gem::Dependency
|
45
|
-
name: pry
|
46
64
|
prerelease: false
|
65
|
+
type: :development
|
66
|
+
name: rspec
|
67
|
+
- !ruby/object:Gem::Dependency
|
47
68
|
requirement: &id004 !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
48
70
|
requirements:
|
49
|
-
-
|
50
|
-
- ">="
|
71
|
+
- - ">="
|
51
72
|
- !ruby/object:Gem::Version
|
73
|
+
hash: 3
|
74
|
+
segments:
|
75
|
+
- 0
|
52
76
|
version: "0"
|
53
|
-
type: :development
|
54
77
|
version_requirements: *id004
|
78
|
+
prerelease: false
|
79
|
+
type: :development
|
80
|
+
name: pry
|
55
81
|
description: |
|
56
82
|
Ruby classes and executables for targetting and sending signals to
|
57
83
|
*nix processes that match/don't match command name patterns, memory
|
@@ -84,28 +110,39 @@ files:
|
|
84
110
|
- spec/process_signaller_spec.rb
|
85
111
|
- spec/ps_output.txt
|
86
112
|
- spec/spec_helper.rb
|
113
|
+
has_rdoc: true
|
87
114
|
homepage: ""
|
88
115
|
licenses:
|
89
116
|
- MIT
|
90
|
-
metadata: {}
|
91
|
-
|
92
117
|
post_install_message:
|
93
118
|
rdoc_options: []
|
94
119
|
|
95
120
|
require_paths:
|
96
121
|
- lib
|
97
122
|
required_ruby_version: !ruby/object:Gem::Requirement
|
123
|
+
none: false
|
98
124
|
requirements:
|
99
|
-
-
|
125
|
+
- - ">="
|
126
|
+
- !ruby/object:Gem::Version
|
127
|
+
hash: 3
|
128
|
+
segments:
|
129
|
+
- 0
|
130
|
+
version: "0"
|
100
131
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
132
|
+
none: false
|
101
133
|
requirements:
|
102
|
-
-
|
134
|
+
- - ">="
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
hash: 3
|
137
|
+
segments:
|
138
|
+
- 0
|
139
|
+
version: "0"
|
103
140
|
requirements: []
|
104
141
|
|
105
142
|
rubyforge_project:
|
106
|
-
rubygems_version:
|
143
|
+
rubygems_version: 1.6.2
|
107
144
|
signing_key:
|
108
|
-
specification_version:
|
145
|
+
specification_version: 3
|
109
146
|
summary: Take aim and fire at runaway processes using ruby
|
110
147
|
test_files:
|
111
148
|
- spec/process_locator_spec.rb
|
checksums.yaml
DELETED
@@ -1,7 +0,0 @@
|
|
1
|
-
---
|
2
|
-
SHA1:
|
3
|
-
data.tar.gz: 0432d5218407fc9b0a154390e2ac486f87e6df94
|
4
|
-
metadata.gz: d415fed3259b55fbfaa03a951951f79ed5620fde
|
5
|
-
SHA512:
|
6
|
-
data.tar.gz: bc24aca5874832df60f75758f0958e96628af0bcedbb2ab7284dff51cadd46cc2af3c31e125f4808b7695cc25ad497e8be9291e71818fc6ddd3162ccda56f3e8
|
7
|
-
metadata.gz: cc023afbc9374259e1f1923b1c720e8ad6e1729fe9809c3adffb36855a849a76488f99f3e0b97812cfe25ef4a26057a1e03ce927089bd8c309dd2ca76b29bb4b
|