snipr 1.0.0 → 1.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/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
|