logstash-input-snmp 1.3.0 → 1.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 747dbf68d6a90a7ab937bf8c64edef786b7d0c4c0ac2f97088401d1e842c2616
4
- data.tar.gz: e53514a31810159796b3e80ee56f7aa6d66eba23ac781744fd9fbf0be83d4d9a
3
+ metadata.gz: 3fe1c5f85dcfcd638d7a15c9798f34d27cee90599d45b984e3a6a9d578233894
4
+ data.tar.gz: 4261ebb2f0e9d7ab9b7f73d11bc2e4b1af37c176131b14c97b4808c249176d45
5
5
  SHA512:
6
- metadata.gz: fa84badc45e056d01ca6a8668e3b5a2ddf89348339f49524b60b77843753cb7eb51fe2fcfe40d2d61dfc95523988f1fa6e11cc430692bbbe38d0014371c62278
7
- data.tar.gz: 9e8e9895750a23892e99b2c198eef3e66f75de885e700dcea020d00356e843a022bd5dae6894a390f9f64faea40ea0f15310dbc7b34ef1fa96947b15d9d1a45b
6
+ metadata.gz: 89ee144bd1e2a3d40dcdd355bac9b330a93b0b011739367721c82e33adca7762e716c53db4f95ae5816a87f004a1155f824603acf0c8f57025ac14502f5b4f11
7
+ data.tar.gz: d7879c1a5de45a5e8f50574223dc883723cdda586540409ced17442f79396fb42669ce6bec8302c3f62d97a2b49927e3e62e7157ac23bec6ebbf05831e753e32
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## 1.3.2
2
+ - Docs: add troubleshooting help for "failed to locate MIB module" error when using smidump to convert MIBs
3
+
4
+ ## 1.3.1
5
+ - Refactor: handle no response(s) wout error logging [#105](https://github.com/logstash-plugins/logstash-input-snmp/pull/105)
6
+
1
7
  ## 1.3.0
2
8
  - Feat: ECS compliance + optional target [#99](https://github.com/logstash-plugins/logstash-input-snmp/pull/99)
3
9
  - Internal: update to Gradle 7 [#102](https://github.com/logstash-plugins/logstash-input-snmp/pull/102)
data/docs/index.asciidoc CHANGED
@@ -63,6 +63,37 @@ $ smidump --level=1 -k -f python RFC1213-MIB > RFC1213-MIB.dic
63
63
 
64
64
  Note that the resulting file as output by `smidump` must have the `.dic` extension.
65
65
 
66
+ As `smidump` only looks for mib dependencies in its pre-configured path lists as defined in the documentaion in the https://www.ibr.cs.tu-bs.de/projects/libsmi/smi_config.html["MODULES LOCATIONS"] section, you may need to provide the paths to locations of MIBs in your particular environment to avoid a `failed to locate MIB module` error.
67
+
68
+ Two ways to achieve this are by using an environment variable or a config file to provide the additional path configuration.
69
+
70
+ Set the `SMIPATH` env var with the path to your mibs ensuring you include a prepended colon `:` for the path, for example:
71
+
72
+ [source,sh]
73
+ -----
74
+ $ SMIPATH=":/path/to/mibs/" smidump -k -f python CISCO-PROCESS-MIB.mib > CISCO-PROCESS-MIB_my.dic
75
+ -----
76
+
77
+ NOTE: SMI docs on the prepended colon:
78
+
79
+ The ‘path’ command argument and the environment variable either start with a path separator character (‘:’ on UNIX-like systems, ‘;’ on MS-Windows systems) to append to the path, or end with a path separator character to prepend to the path, or otherwise completely replace the path.
80
+
81
+
82
+ The other way is to create a configuration file eg `smi.conf` with the `path` option.
83
+
84
+ [source,sh]
85
+ -----
86
+ path :/path/to/mibs/
87
+ -----
88
+
89
+ and use that config with smidump:
90
+
91
+ [source,sh]
92
+ -----
93
+ $ smidump -c smi.conf -k -f python CISCO-PROCESS-MIB.mib > CISCO-PROCESS-MIB_my.dic
94
+ -----
95
+
96
+
66
97
  [id="plugins-{type}s-{plugin}-options"]
67
98
  ==== SNMP Input Configuration Options
68
99
 
@@ -52,13 +52,13 @@ module LogStash
52
52
  end
53
53
 
54
54
  def walk(oid, strip_root = 0, path_length = 0)
55
- result = {}
56
-
57
55
  pdufactory = get_pdu_factory
58
56
  treeUtils = TreeUtils.new(@snmp, pdufactory)
59
57
  events = treeUtils.getSubtree(@target, OID.new(oid))
60
58
  return nil if events.nil? || events.size == 0
61
59
 
60
+ result = {}
61
+
62
62
  events.each do |event|
63
63
  next if event.nil?
64
64
 
@@ -192,53 +192,73 @@ class LogStash::Inputs::Snmp < LogStash::Inputs::Base
192
192
 
193
193
  def run(queue)
194
194
  # for now a naive single threaded poller which sleeps off the remaining interval between
195
- # each run. each run polls all the defined hosts for the get and walk options.
195
+ # each run. each run polls all the defined hosts for the get, table and walk options.
196
196
  stoppable_interval_runner.every(@interval, "polling hosts") do
197
- @client_definitions.each do |definition|
198
- client = definition[:client]
199
- result = {}
200
- if !definition[:get].empty?
201
- oids = definition[:get]
202
- begin
203
- result = result.merge(client.get(oids, @oid_root_skip, @oid_path_length))
204
- rescue => e
205
- logger.error("error invoking get operation for OIDs: #{oids}, ignoring",
206
- host: definition[:host_address], exception: e, backtrace: e.backtrace)
197
+ poll_clients(queue)
198
+ end
199
+ end
200
+
201
+ def poll_clients(queue)
202
+ @client_definitions.each do |definition|
203
+ client = definition[:client]
204
+ host = definition[:host_address]
205
+ result = {}
206
+
207
+ if !definition[:get].empty?
208
+ oids = definition[:get]
209
+ begin
210
+ data = client.get(oids, @oid_root_skip, @oid_path_length)
211
+ if data
212
+ result.update(data)
213
+ else
214
+ logger.debug? && logger.debug("get operation returned no response", host: host, oids: oids)
207
215
  end
216
+ rescue => e
217
+ logger.error("error invoking get operation, ignoring", host: host, oids: oids, exception: e, backtrace: e.backtrace)
208
218
  end
209
- if !definition[:walk].empty?
210
- definition[:walk].each do |oid|
211
- begin
212
- result = result.merge(client.walk(oid, @oid_root_skip, @oid_path_length))
213
- rescue => e
214
- logger.error("error invoking walk operation on OID: #{oid}, ignoring",
215
- host: definition[:host_address], exception: e, backtrace: e.backtrace)
219
+ end
220
+
221
+ if !definition[:walk].empty?
222
+ definition[:walk].each do |oid|
223
+ begin
224
+ data = client.walk(oid, @oid_root_skip, @oid_path_length)
225
+ if data
226
+ result.update(data)
227
+ else
228
+ logger.debug? && logger.debug("walk operation returned no response", host: host, oid: oid)
216
229
  end
230
+ rescue => e
231
+ logger.error("error invoking walk operation, ignoring", host: host, oid: oid, exception: e, backtrace: e.backtrace)
217
232
  end
218
233
  end
234
+ end
219
235
 
220
- if !Array(@tables).empty?
221
- @tables.each do |table_entry|
222
- begin
223
- result = result.merge(client.table(table_entry, @oid_root_skip, @oid_path_length))
224
- rescue => e
225
- logger.error("error invoking table operation on OID: #{table_entry['name']}, ignoring",
226
- host: definition[:host_address], exception: e, backtrace: e.backtrace)
236
+ if !Array(@tables).empty?
237
+ @tables.each do |table_entry|
238
+ begin
239
+ data = client.table(table_entry, @oid_root_skip, @oid_path_length)
240
+ if data
241
+ result.update(data)
242
+ else
243
+ logger.debug? && logger.debug("table operation returned no response", host: host, table: table_entry)
227
244
  end
245
+ rescue => e
246
+ logger.error("error invoking table operation, ignoring",
247
+ host: host, table_name: table_entry['name'], exception: e, backtrace: e.backtrace)
228
248
  end
229
249
  end
250
+ end
230
251
 
231
- unless result.empty?
232
- event = targeted_event_factory.new_event(result)
233
- event.set(@host_protocol_field, definition[:host_protocol])
234
- event.set(@host_address_field, definition[:host_address])
235
- event.set(@host_port_field, definition[:host_port])
236
- event.set(@host_community_field, definition[:host_community])
237
- decorate(event)
238
- queue << event
239
- else
240
- logger.debug? && logger.debug("no snmp data retrieved", host: definition[:host_address])
241
- end
252
+ unless result.empty?
253
+ event = targeted_event_factory.new_event(result)
254
+ event.set(@host_protocol_field, definition[:host_protocol])
255
+ event.set(@host_address_field, definition[:host_address])
256
+ event.set(@host_port_field, definition[:host_port])
257
+ event.set(@host_community_field, definition[:host_community])
258
+ decorate(event)
259
+ queue << event
260
+ else
261
+ logger.debug? && logger.debug("no snmp data retrieved", host: definition[:host_address])
242
262
  end
243
263
  end
244
264
  end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'logstash-input-snmp'
3
- s.version = '1.3.0'
3
+ s.version = '1.3.2'
4
4
  s.licenses = ['Apache-2.0']
5
5
  s.summary = "SNMP input plugin"
6
6
  s.description = "This gem is a Logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/logstash-plugin install gemname. This gem is not a stand-alone program"
@@ -2,7 +2,7 @@ require "logstash/devutils/rspec/spec_helper"
2
2
  require "logstash/inputs/snmp"
3
3
 
4
4
  describe LogStash::Inputs::Snmp do
5
- let(:config) { {"get" => ["1.3.6.1.2.1.1.1.0", "1.3.6.1.2.1.1.3.0", "1.3.6.1.2.1.1.5.0"]} }
5
+ let(:config) { {"get" => %w[1.3.6.1.2.1.1.1.0 1.3.6.1.2.1.1.3.0 1.3.6.1.2.1.1.5.0], "ecs_compatibility" => "disabled" } }
6
6
  let(:plugin) { LogStash::Inputs::Snmp.new(config)}
7
7
 
8
8
  shared_examples "snmp plugin return single event" do
@@ -114,8 +114,8 @@ describe LogStash::Inputs::Snmp do
114
114
  end
115
115
 
116
116
  describe "multiple pipelines and mix of udp tcp hosts", :integration => true do
117
- let(:config) { {"get" => ["1.3.6.1.2.1.1.1.0"], "hosts" => [{"host" => "udp:snmp1/161", "community" => "public"}]} }
118
- let(:config2) { {"get" => ["1.3.6.1.2.1.1.1.0"], "hosts" => [{"host" => "tcp:snmp2/162", "community" => "public"}]} }
117
+ let(:config) { {"get" => ["1.3.6.1.2.1.1.1.0"], "hosts" => [{"host" => "udp:snmp1/161", "community" => "public"}], "ecs_compatibility" => "disabled" } }
118
+ let(:config2) { {"get" => ["1.3.6.1.2.1.1.1.0"], "hosts" => [{"host" => "tcp:snmp2/162", "community" => "public"}], "ecs_compatibility" => "disabled"} }
119
119
  let(:plugin) { LogStash::Inputs::Snmp.new(config)}
120
120
  let(:plugin2) { LogStash::Inputs::Snmp.new(config2)}
121
121
 
@@ -148,10 +148,12 @@ describe LogStash::Inputs::Snmp do
148
148
  snmp {
149
149
  get => ["1.3.6.1.2.1.1.1.0"]
150
150
  hosts => [{host => "udp:snmp1/161" community => "public"}]
151
+ ecs_compatibility => "disabled"
151
152
  }
152
153
  snmp {
153
154
  get => ["1.3.6.1.2.1.1.1.0"]
154
155
  hosts => [{host => "tcp:snmp2/162" community => "public"}]
156
+ ecs_compatibility => "disabled"
155
157
  }
156
158
  }
157
159
  CONFIG
@@ -171,6 +173,7 @@ describe LogStash::Inputs::Snmp do
171
173
  priv_protocol => "aes"
172
174
  priv_pass => "STr0ngP@SSWRD161"
173
175
  security_level => "authPriv"
176
+ ecs_compatibility => "disabled"
174
177
  }
175
178
  snmp {
176
179
  get => ["1.3.6.1.2.1.1.1.0"]
@@ -181,6 +184,7 @@ describe LogStash::Inputs::Snmp do
181
184
  priv_protocol => "aes"
182
185
  priv_pass => "STr0ngP@SSWRD162"
183
186
  security_level => "authPriv"
187
+ ecs_compatibility => "disabled"
184
188
  }
185
189
  }
186
190
  CONFIG
@@ -136,43 +136,46 @@ describe LogStash::Inputs::Snmp, :ecs_compatibility_support do
136
136
 
137
137
  before(:each) do
138
138
  allow_any_instance_of(described_class).to receive(:ecs_compatibility).and_return(ecs_compatibility)
139
- end
140
139
 
141
- before do
142
140
  expect(LogStash::SnmpClient).to receive(:new).and_return(mock_client)
143
- expect(mock_client).to receive(:get).and_return({"foo" => "bar"})
144
141
  # devutils in v6 calls close on the test pipelines while it does not in v7+
145
- expect(mock_client).to receive(:close).at_most(:once)
142
+ allow(mock_client).to receive(:close).at_most(:once)
146
143
  end
147
144
 
148
- it "shoud add @metadata fields and add default host field" do
149
- config = <<-CONFIG
145
+ context 'mocked get' do
146
+
147
+ before do
148
+ expect(mock_client).to receive(:get).and_return({"foo" => "bar"})
149
+ end
150
+
151
+ it "shoud add @metadata fields and add default host field" do
152
+ config = <<-CONFIG
150
153
  input {
151
154
  snmp {
152
155
  get => ["1.3.6.1.2.1.1.1.0"]
153
156
  hosts => [{ host => "udp:127.0.0.1/161" community => "public" }]
154
157
  }
155
158
  }
156
- CONFIG
157
- event = input(config) { |_, queue| queue.pop }
158
-
159
- if ecs_select.active_mode == :disabled
160
- expect(event.get("[@metadata][host_protocol]")).to eq("udp")
161
- expect(event.get("[@metadata][host_address]")).to eq("127.0.0.1")
162
- expect(event.get("[@metadata][host_port]")).to eq("161")
163
- expect(event.get("[@metadata][host_community]")).to eq("public")
164
- expect(event.get("host")).to eql("127.0.0.1")
165
- else
166
- expect(event.get("[@metadata][input][snmp][host][protocol]")).to eq("udp")
167
- expect(event.get("[@metadata][input][snmp][host][address]")).to eq("127.0.0.1")
168
- expect(event.get("[@metadata][input][snmp][host][port]")).to eq('161')
169
- expect(event.get("[@metadata][input][snmp][host][community]")).to eq("public")
170
- expect(event.get("host")).to eql('ip' => "127.0.0.1")
159
+ CONFIG
160
+ event = input(config) { |_, queue| queue.pop }
161
+
162
+ if ecs_select.active_mode == :disabled
163
+ expect(event.get("[@metadata][host_protocol]")).to eq("udp")
164
+ expect(event.get("[@metadata][host_address]")).to eq("127.0.0.1")
165
+ expect(event.get("[@metadata][host_port]")).to eq("161")
166
+ expect(event.get("[@metadata][host_community]")).to eq("public")
167
+ expect(event.get("host")).to eql("127.0.0.1")
168
+ else
169
+ expect(event.get("[@metadata][input][snmp][host][protocol]")).to eq("udp")
170
+ expect(event.get("[@metadata][input][snmp][host][address]")).to eq("127.0.0.1")
171
+ expect(event.get("[@metadata][input][snmp][host][port]")).to eq('161')
172
+ expect(event.get("[@metadata][input][snmp][host][community]")).to eq("public")
173
+ expect(event.get("host")).to eql('ip' => "127.0.0.1")
174
+ end
171
175
  end
172
- end
173
176
 
174
- it "should add custom host field (legacy metadata)" do
175
- config = <<-CONFIG
177
+ it "should add custom host field (legacy metadata)" do
178
+ config = <<-CONFIG
176
179
  input {
177
180
  snmp {
178
181
  get => ["1.3.6.1.2.1.1.1.0"]
@@ -180,14 +183,14 @@ describe LogStash::Inputs::Snmp, :ecs_compatibility_support do
180
183
  add_field => { host => "%{[@metadata][host_protocol]}:%{[@metadata][host_address]}/%{[@metadata][host_port]},%{[@metadata][host_community]}" }
181
184
  }
182
185
  }
183
- CONFIG
184
- event = input(config) { |_, queue| queue.pop }
186
+ CONFIG
187
+ event = input(config) { |_, queue| queue.pop }
185
188
 
186
- expect(event.get("host")).to eq("udp:127.0.0.1/161,public")
187
- end if ecs_select.active_mode == :disabled
189
+ expect(event.get("host")).to eq("udp:127.0.0.1/161,public")
190
+ end if ecs_select.active_mode == :disabled
188
191
 
189
- it "should add custom host field (ECS mode)" do
190
- config = <<-CONFIG
192
+ it "should add custom host field (ECS mode)" do
193
+ config = <<-CONFIG
191
194
  input {
192
195
  snmp {
193
196
  get => ["1.3.6.1.2.1.1.1.0"]
@@ -195,14 +198,14 @@ describe LogStash::Inputs::Snmp, :ecs_compatibility_support do
195
198
  add_field => { "[host][formatted]" => "%{[@metadata][input][snmp][host][protocol]}://%{[@metadata][input][snmp][host][address]}:%{[@metadata][input][snmp][host][port]}" }
196
199
  }
197
200
  }
198
- CONFIG
199
- event = input(config) { |_, queue| queue.pop }
201
+ CONFIG
202
+ event = input(config) { |_, queue| queue.pop }
200
203
 
201
- expect(event.get("host")).to eq('formatted' => "tcp://192.168.1.11:1161")
202
- end if ecs_select.active_mode != :disabled
204
+ expect(event.get("host")).to eq('formatted' => "tcp://192.168.1.11:1161")
205
+ end if ecs_select.active_mode != :disabled
203
206
 
204
- it "should target event data" do
205
- config = <<-CONFIG
207
+ it "should target event data" do
208
+ config = <<-CONFIG
206
209
  input {
207
210
  snmp {
208
211
  get => ["1.3.6.1.2.1.1.1.0"]
@@ -210,12 +213,92 @@ describe LogStash::Inputs::Snmp, :ecs_compatibility_support do
210
213
  target => "snmp_data"
211
214
  }
212
215
  }
213
- CONFIG
214
- event = input(config) { |_, queue| queue.pop }
216
+ CONFIG
217
+ event = input(config) { |_, queue| queue.pop }
218
+
219
+ expect( event.include?('foo') ).to be false
220
+ expect( event.get('[snmp_data]') ).to eql 'foo' => 'bar'
221
+ end
222
+
223
+ end
224
+
225
+ context 'mocked nil get response' do
226
+
227
+ let(:config) do
228
+ {
229
+ 'get' => ["1.3.6.1.2.1.1.1.0"],
230
+ "hosts" => [{"host" => "udp:127.0.0.1/161", "community" => "public"}]
231
+ }
232
+ end
233
+
234
+ let(:logger) { double("Logger").as_null_object }
235
+
236
+ before do
237
+ expect(mock_client).to receive(:get).once.and_return(nil)
238
+ allow_any_instance_of(described_class).to receive(:logger).and_return(logger)
239
+ expect(logger).not_to receive(:error)
240
+ end
241
+
242
+ it 'generates no events when client returns no response' do
243
+ input = described_class.new(config).tap { |input| input.register }
244
+ input.poll_clients queue = Queue.new
245
+
246
+ expect( queue.size ).to eql 0
247
+ end
248
+ end
249
+
250
+ context 'mocked nil table response' do
251
+
252
+ let(:config) do
253
+ {
254
+ 'tables' => [
255
+ { 'name' => "a1Table", 'columns' => ["1.3.6.1.4.1.3375.2.2.5.2.3.1.1"] }
256
+ ],
257
+ "hosts" => [{"host" => "udp:127.0.0.1/161", "community" => "public"}]
258
+ }
259
+ end
260
+
261
+ let(:logger) { double("Logger").as_null_object }
215
262
 
216
- expect( event.include?('foo') ).to be false
217
- expect( event.get('[snmp_data]') ).to eql 'foo' => 'bar'
263
+ before do
264
+ expect(mock_client).to receive(:table).once.and_return(nil)
265
+ allow_any_instance_of(described_class).to receive(:logger).and_return(logger)
266
+ expect(logger).not_to receive(:error)
267
+ end
268
+
269
+ it 'generates no events when client returns no response' do
270
+ input = described_class.new(config).tap { |input| input.register }
271
+ input.poll_clients queue = Queue.new
272
+
273
+ expect( queue.size ).to eql 0
274
+ end
275
+ end
276
+
277
+ context 'mocked nil walk response' do
278
+
279
+ let(:config) do
280
+ {
281
+ 'walk' => ["1.3.6.1.2.1.1"],
282
+ "hosts" => [{"host" => "udp:127.0.0.1/161", "community" => "public"}]
283
+ }
284
+ end
285
+
286
+ let(:logger) { double("Logger").as_null_object }
287
+
288
+ before do
289
+ expect(mock_client).to receive(:walk).once.and_return(nil)
290
+ allow_any_instance_of(described_class).to receive(:logger).and_return(logger)
291
+ expect(logger).not_to receive(:error)
292
+ end
293
+
294
+ it 'generates no events when client returns no response' do
295
+ input = described_class.new(config).tap { |input| input.register }
296
+ input.poll_clients queue = Queue.new
297
+
298
+ expect( queue.size ).to eql 0
299
+ end
218
300
  end
301
+
219
302
  end
220
303
 
221
304
  context "StoppableIntervalRunner" do
@@ -307,5 +390,28 @@ describe LogStash::Inputs::Snmp, :ecs_compatibility_support do
307
390
  end
308
391
  end
309
392
  end
393
+
394
+ context "close" do
395
+ let(:config) do
396
+ <<-CONFIG
397
+ input {
398
+ snmp {
399
+ get => ["1.3.6.1.2.1.1.1.0"]
400
+ hosts => [{host => "udp:127.0.0.1/161" community => "public"}]
401
+ }
402
+ }
403
+ CONFIG
404
+ end
405
+
406
+ before(:each) do
407
+ expect(LogStash::SnmpClient).to receive(:new).and_return(mock_client)
408
+ expect(mock_client).to receive(:get).and_return({"foo" => "bar"})
409
+ end
410
+
411
+ it "should call the close method upon termination" do
412
+ expect(mock_client).to receive(:close).once
413
+ input(config) { }
414
+ end
415
+ end
310
416
  end
311
417
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: logstash-input-snmp
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Elasticsearch
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-19 00:00:00.000000000 Z
11
+ date: 2023-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  requirement: !ruby/object:Gem::Requirement
@@ -483,7 +483,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
483
483
  - !ruby/object:Gem::Version
484
484
  version: '0'
485
485
  requirements: []
486
- rubygems_version: 3.1.6
486
+ rubygems_version: 3.2.33
487
487
  signing_key:
488
488
  specification_version: 4
489
489
  summary: SNMP input plugin