logstash-input-snmp 1.3.0 → 1.3.2

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.
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