netsnmp 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,3 @@
1
+ module NETSNMP
2
+ VERSION = '0.0.0'.freeze
3
+ end
@@ -0,0 +1,36 @@
1
+ require File.expand_path('../lib/netsnmp/version',__FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "netsnmp"
5
+ gem.summary = "SNMP Client library"
6
+ gem.description = <<DESC
7
+ Wraps the net-snmp core usage into idiomatic ruby.
8
+ It is designed to support as many environments and concurrency frameworks as possible.
9
+ DESC
10
+ gem.requirements = ['net-snmp']
11
+ gem.version = NETSNMP::VERSION
12
+ gem.license = "Apache-2.0"
13
+ gem.authors = ["Tiago Cardoso"]
14
+ gem.email = "cardoso_tiago@hotmail.com"
15
+ gem.homepage = ""
16
+ gem.platform = Gem::Platform::RUBY
17
+ gem.required_ruby_version = '>=2.0.0'
18
+
19
+ # Manifest
20
+ gem.files = `git ls-files`.split("\n") - Dir['tmp/**/*']
21
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
23
+ gem.require_paths = ["lib"]
24
+
25
+ gem.executables = Dir["bin/*"].map { |e| File.basename e }
26
+ gem.add_runtime_dependency "ffi", ["~> 1.9"]
27
+ unless RUBY_PLATFORM == "java"
28
+ gem.add_runtime_dependency "RubyInline", ["~> 3.12"]
29
+ end
30
+
31
+ gem.add_development_dependency "rake", ["~> 10.4.2"]
32
+ gem.add_development_dependency "rspec", ["~> 3.3.0"]
33
+
34
+ gem.add_development_dependency "em-synchrony", ["~> 1.0.4"]
35
+ gem.add_development_dependency "celluloid-io", ["~> 0.17.2"]
36
+ end
@@ -0,0 +1,90 @@
1
+ RSpec.describe NETSNMP::Client do
2
+ let(:host) { "localhost" }
3
+ let(:host_options) { {
4
+ peername: "localhost",
5
+ port: SNMPPORT,
6
+ username: "simulator",
7
+ auth_password: "auctoritas",
8
+ auth_protocol: :md5,
9
+ priv_password: "privatus",
10
+ priv_protocol: :des
11
+ } }
12
+
13
+ subject { described_class.new(host, options) }
14
+
15
+ describe "#get" do
16
+ let(:oid) { "1.3.6.1.2.1.1.5.0" } # sysName.0
17
+ let(:value) { subject.get(oid) }
18
+ let(:options) { host_options.merge(context: "a172334d7d97871b72241397f713fa12") }
19
+ it "fetches the varbinds for a given oid" do
20
+ expect(value).to eq("tt")
21
+ end
22
+ end
23
+
24
+ describe "#get_next" do
25
+ let(:oid) { "1.3.6.1.2.1.1.5.0" } # sysName.0
26
+ let(:value) { subject.get_next(oid) }
27
+ let(:options) { host_options.merge(context: "a172334d7d97871b72241397f713fa12") }
28
+ it "fetches the varbinds for the next oid" do
29
+ expect(value).to start_with("KK12")
30
+ end
31
+ end
32
+
33
+ describe "#walk" do
34
+ let(:oid) { "1.3.6.1.2.1.1.9.1.3" } # sysORDescr
35
+ let(:value) { subject.walk(oid) }
36
+ let(:options) { host_options.merge(context: "a172334d7d97871b72241397f713fa12") }
37
+ it "fetches the varbinds for the next oid" do
38
+ expect(value.next).to eq(["#{oid}.1","The SNMP Management Architecture MIB."])
39
+ expect(value.next).to eq(["#{oid}.2","The MIB for Message Processing and Dispatching."])
40
+ expect(value.next).to eq(["#{oid}.3","The management information definitions for the SNMP User-based Security Model."])
41
+ expect(value.next).to eq(["#{oid}.4","The MIB module for SNMPv2 entities"])
42
+ expect(value.next).to eq(["#{oid}.5","The MIB module for managing TCP implementations"])
43
+ expect(value.next).to eq(["#{oid}.6","The MIB module for managing IP and ICMP implementations"])
44
+ expect(value.next).to eq(["#{oid}.7","The MIB module for managing UDP implementations"])
45
+ expect(value.next).to eq(["#{oid}.8","View-based Access Control Model for SNMP."])
46
+ expect{ value.next }.to raise_error(StopIteration)
47
+ end
48
+ end
49
+
50
+ describe "#get_bulk" do
51
+ let(:oid) { "1.3.6.1.2.1.1.9.1.3" }
52
+ let(:value) { subject.get_bulk(oid) }
53
+ let(:options) { host_options.merge(context: "a172334d7d97871b72241397f713fa12") }
54
+ it "fetches the varbinds for the next oid" do
55
+ expect(value.next).to eq(["#{oid}.1","The SNMP Management Architecture MIB."])
56
+ expect(value.next).to eq(["#{oid}.2","The MIB for Message Processing and Dispatching."])
57
+ expect(value.next).to eq(["#{oid}.3","The management information definitions for the SNMP User-based Security Model."])
58
+ expect(value.next).to eq(["#{oid}.4","The MIB module for SNMPv2 entities"])
59
+ expect(value.next).to eq(["#{oid}.5","The MIB module for managing TCP implementations"])
60
+ expect(value.next).to eq(["#{oid}.6","The MIB module for managing IP and ICMP implementations"])
61
+ expect(value.next).to eq(["#{oid}.7","The MIB module for managing UDP implementations"])
62
+ expect(value.next).to eq(["#{oid}.8","View-based Access Control Model for SNMP."])
63
+ expect(value.next).to eq(["1.3.6.1.2.1.1.9.1.4.1",2])
64
+ expect(value.next).to eq(["1.3.6.1.2.1.1.9.1.4.2",2])
65
+ expect{ value.next }.to raise_error(StopIteration)
66
+ end
67
+ end
68
+
69
+
70
+ # TODO: use this oid to test error calls
71
+ # let(:oid) { "SNMPv2-MIB::sysORDescr.1" }
72
+
73
+ describe "#set" do
74
+ let(:options) { host_options.merge(context: "0886e1397d572377c17c15036a1e6c66") } # write cache
75
+ let(:oid) { "1.3.6.1.2.1.1.3.0" } # sysUpTimeInstance
76
+ let(:new_value) { 43 }
77
+ after { subject.set(oid, value: 42) }
78
+ it "updates the value of the oid" do
79
+ expect(subject.get(oid)).to be(42)
80
+
81
+ # without type
82
+ subject.set(oid, value: 43)
83
+ expect(subject.get(oid)).to be(43)
84
+
85
+ subject.set(oid, value: 44, type: :integer)
86
+ expect(subject.get(oid)).to be(44)
87
+
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,2 @@
1
+ RSpec.describe NETSNMP::Core::C do
2
+ end
@@ -0,0 +1,32 @@
1
+ RSpec.describe NETSNMP::Core::LibSNMP do
2
+ subject { described_class }
3
+ it "exposes initialization and shutdown methods" do
4
+ [:init_snmp, :snmp_perror].each do |meth|
5
+ is_expected.to respond_to(meth)
6
+ end
7
+ end
8
+
9
+ it "exposes netsnmp session handling methods" do
10
+ [:snmp_sess_init, :snmp_sess_open, :snmp_sess_close, :generate_Ku].each do |meth|
11
+ is_expected.to respond_to(meth)
12
+ end
13
+ end
14
+
15
+ it "exposes netsnmp read API" do
16
+ [:snmp_sess_synch_response, :snmp_sess_send].each do |meth|
17
+ is_expected.to respond_to(meth)
18
+ end
19
+ end
20
+
21
+ it "exposes netsnmp session async send/read" do
22
+ [:snmp_sess_async_send, :snmp_sess_select_info, :snmp_sess_read].each do |meth|
23
+ is_expected.to respond_to(meth)
24
+ end
25
+ end
26
+
27
+ it "exposes the pdu API" do
28
+ [:snmp_pdu_create, :snmp_free_pdu, :snmp_pdu_add_variable].each do |meth|
29
+ is_expected.to respond_to(meth)
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,54 @@
1
+ RSpec.describe NETSNMP::Core::Structures do
2
+ describe NETSNMP::Core::Structures::Session do
3
+ [:version, :retries, :timeout, :flags, :subsession, :next, :peername, :remote_port, :localname, :local_port, :authenticator,
4
+ :callback, :callback_magic, :community, :community_len, :rcvMsgMaxSize, :sndMsgMaxSize, :isAuthoritative, :contextEngineID,
5
+ :contextEngineIDLen, :engineBoots, :engineTime, :contextName, :contextNameLen, :securityEngineID, :securityEngineIDLen,
6
+ :securityName, :securityNameLen, :securityAuthProto, :securityAuthProtoLen, :securityAuthKey, :securityAuthKeyLen,
7
+ :securityAuthLocalKey, :securityAuthLocalKeyLen, :securityPrivProto, :securityPrivProtoLen, :securityPrivKey, :securityPrivKeyLen,
8
+ :securityPrivLocalKey, :securityPrivLocalKeyLen, :securityModel, :securityLevel, :paramName, :securityInfo, :myvoid].each do |attr|
9
+ it { expect(subject[attr]).not_to be_nil }
10
+ end
11
+ end
12
+
13
+ describe NETSNMP::Core::Structures::Vardata do
14
+ [:integer, :string, :objid, :bitstring, :counter64, :float, :double].each do |attr|
15
+ it { expect(subject[attr]).not_to be_nil }
16
+ end
17
+ end
18
+
19
+ describe NETSNMP::Core::Structures::VariableList do
20
+ [:next_variable, :name, :name_length, :type, :val, :val_len, :name_loc, :buf, :data, :dataFreeHook, :index].each do |attr|
21
+ it { expect(subject[attr]).not_to be_nil }
22
+ end
23
+ end
24
+
25
+ describe NETSNMP::Core::Structures::PDU do
26
+ [:version, :command, :reqid, :msgid, :transid, :sessid, :errstat, :errindex, :time, :flags, :securityModel,
27
+ :securityLevel, :msgParseModel, :transport_data, :transport_data_length, :tDomain, :tDomainLen, :variables,
28
+ :community, :community_len, :enterprise, :enterprise_length, :trap_type, :specific_type, :agent_addr,
29
+ :contextEngineID, :contextEngineIDLen, :contextName, :contextNameLen, :securityEngineID, :securityEngineIDLen,
30
+ :securityName, :securityNameLen, :priority, :range_subid, :securityStateRef].each do |attr|
31
+ it { expect(subject[attr]).not_to be_nil }
32
+ end
33
+ end
34
+
35
+ describe NETSNMP::Core::Structures::SessionList do
36
+ [:next, :session, :transport, :internal].each do |attr|
37
+ it { expect(subject[attr]).not_to be_nil }
38
+ end
39
+ end
40
+
41
+ describe NETSNMP::Core::Structures::Transport do
42
+ [:domain, :domain_length, :local, :local_length, :remote, :remote_length,
43
+ :sock, :flags, :data, :data_length, :msgMaxSize, :base_transport].each do |attr|
44
+ it { expect(subject[attr]).not_to be_nil }
45
+ end
46
+ end
47
+
48
+ describe NETSNMP::Core::Structures::Counter64 do
49
+ [:high, :low].each do |attr|
50
+ it { expect(subject[attr]).not_to be_nil }
51
+ end
52
+ end
53
+
54
+ end
@@ -0,0 +1,29 @@
1
+ require 'celluloid/io'
2
+ require 'netsnmp/handlers/celluloid'
3
+ require_relative '../support/celluloid'
4
+
5
+ RSpec.describe NETSNMP::Celluloid::Client, type: :celluloid do
6
+ include CelluloidHelpers
7
+ let(:host) { "localhost" }
8
+ let(:host_options) { {
9
+ peername: "localhost",
10
+ port: SNMPPORT,
11
+ username: "simulator",
12
+ auth_password: "auctoritas",
13
+ auth_protocol: :md5,
14
+ priv_password: "privatus",
15
+ priv_protocol: :des
16
+ } }
17
+
18
+ subject { described_class.new(host, options) }
19
+
20
+ describe "#get" do
21
+ let(:oid) { "1.3.6.1.2.1.1.5.0" } # sysName.0
22
+ let(:options) { host_options.merge(context: "a172334d7d97871b72241397f713fa12") }
23
+ it "fetches the varbinds for a given oid" do
24
+ value = within_io_actor { value = subject.get(oid) }
25
+ expect(value).to eq("tt")
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,34 @@
1
+ require 'em-synchrony'
2
+ require 'netsnmp/handlers/em'
3
+
4
+ RSpec.describe NETSNMP::EM::Client do
5
+ let(:host) { "localhost" }
6
+ let(:host_options) { {
7
+ peername: "localhost",
8
+ port: SNMPPORT,
9
+ username: "simulator",
10
+ auth_password: "auctoritas",
11
+ auth_protocol: :md5,
12
+ priv_password: "privatus",
13
+ priv_protocol: :des
14
+ } }
15
+
16
+ subject { described_class.new(host, options) }
17
+
18
+ describe "#get" do
19
+ let(:oid) { "1.3.6.1.2.1.1.5.0" } # sysName.0
20
+ let(:options) { host_options.merge(context: "a172334d7d97871b72241397f713fa12") }
21
+ it "fetches the varbinds for a given oid" do
22
+ value = nil
23
+ EM.synchrony do
24
+ begin
25
+ value = subject.get(oid)
26
+ ensure
27
+ EM.stop_event_loop
28
+ end
29
+ end
30
+ expect(value).to eq("tt")
31
+ end
32
+ end
33
+
34
+ end
@@ -0,0 +1,9 @@
1
+ RSpec.describe NETSNMP::OID do
2
+ let(:code) { "SNMPv2-MIB::sysDescr.0" }
3
+ let(:oid_code) { "1.3.6.1.2.1.1.1.0" }
4
+ subject { described_class.new(code) }
5
+
6
+ it "translates always to numerical oid code" do
7
+ expect(subject.to_s).to eq(oid_code)
8
+ end
9
+ end
@@ -0,0 +1,29 @@
1
+ RSpec.describe NETSNMP::PDU do
2
+ let(:struct) { double(:structure) }
3
+ let(:pointer) { double(:pointer) }
4
+ subject { NETSNMP::PDU.new(pointer) }
5
+ before do
6
+ allow(NETSNMP::Core::Structures::PDU).to receive(:new).with(pointer).and_return(struct)
7
+ end
8
+
9
+ it { is_expected.to respond_to(:struct) }
10
+ it { expect(subject.varbinds).to be_empty }
11
+
12
+ describe NETSNMP::RequestPDU do
13
+ before { allow(NETSNMP::Core::LibSNMP).to receive(:snmp_pdu_create).and_return(pointer) }
14
+ subject { NETSNMP::PDU.build(:get) }
15
+
16
+ describe "#add_varbind" do
17
+ let(:oid) { double(:oid) }
18
+ let(:value) { double(:value) }
19
+ let(:varbind) { double(:varbind) }
20
+ before { allow(NETSNMP::RequestVarbind).to receive(:new).with(subject, oid, value, instance_of(Hash)).and_return(varbind) }
21
+ it "creates a new varbind and adds it to the structure" do
22
+ subject.add_varbind(oid, { value: value })
23
+ expect(subject.varbinds).not_to be_empty
24
+ expect(subject.varbinds).to include(varbind)
25
+ end
26
+ end
27
+ end
28
+
29
+ end
@@ -0,0 +1,34 @@
1
+ RSpec.describe NETSNMP::Session do
2
+ let(:host) { "localhost" }
3
+ let(:options) { {
4
+ version: '2c',
5
+ context: "public",
6
+ port: SNMPPORT
7
+ } }
8
+ subject { described_class.new(host, options) }
9
+ after { subject.close }
10
+
11
+
12
+ describe "#send" do
13
+ let(:pointer) { double(:pointer) }
14
+ let(:pdu) { double(:pdu, pointer: pointer) }
15
+ let(:response) { double(:response) }
16
+ let(:reqid) { double(:requestid) }
17
+ let(:requests) { {} }
18
+
19
+ before do
20
+ allow(pdu).to receive(:[]).with(:reqid).and_return(reqid)
21
+ allow(requests).to receive(:[]).with(reqid).and_return([:success, response])
22
+ end
23
+
24
+ it "sends and receives a pdu" do
25
+ expect(IO).to receive(:select).twice.and_return([[], []])
26
+ expect(NETSNMP::Core::LibSNMP).to receive(:snmp_sess_async_send).with(subject.signature, pointer, instance_of(FFI::Function), nil)
27
+ expect(subject).to receive(:handle_response).and_return(response)
28
+ expect(subject.send(pdu)).to be(response)
29
+ end
30
+
31
+
32
+ end
33
+
34
+ end
@@ -0,0 +1,114 @@
1
+ require 'simplecov' if ENV["COVERAGE"]
2
+ require 'coveralls'
3
+ Coveralls.wear!
4
+
5
+ SimpleCov.start do
6
+ minimum_coverage 85
7
+ add_filter ".bundle"
8
+ add_filter "/spec/"
9
+ end if defined?(SimpleCov)
10
+
11
+ require 'bundler/setup'
12
+ Bundler.require(:default, :test)
13
+
14
+ require 'netsnmp'
15
+
16
+
17
+ SNMPPORT = `sudo docker port test-snmp-emulator 1161/udp`[/.*:(\d+)/, 1].to_i
18
+
19
+ # This file was generated by the `rspec --init` command. Conventionally, all
20
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
21
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
22
+ # this file to always be loaded, without a need to explicitly require it in any
23
+ # files.
24
+ #
25
+ # Given that it is always loaded, you are encouraged to keep this file as
26
+ # light-weight as possible. Requiring heavyweight dependencies from this file
27
+ # will add to the boot time of your test suite on EVERY test run, even for an
28
+ # individual file that may not need all of that loaded. Instead, consider making
29
+ # a separate helper file that requires the additional dependencies and performs
30
+ # the additional setup, and require it from the spec files that actually need
31
+ # it.
32
+ #
33
+ # The `.rspec` file also contains a few flags that are not defaults but that
34
+ # users commonly want.
35
+ #
36
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
37
+ RSpec.configure do |config|
38
+ # rspec-expectations config goes here. You can use an alternate
39
+ # assertion/expectation library such as wrong or the stdlib/minitest
40
+ # assertions if you prefer.
41
+ config.expect_with :rspec do |expectations|
42
+ # This option will default to `true` in RSpec 4. It makes the `description`
43
+ # and `failure_message` of custom matchers include text for helper methods
44
+ # defined using `chain`, e.g.:
45
+ # be_bigger_than(2).and_smaller_than(4).description
46
+ # # => "be bigger than 2 and smaller than 4"
47
+ # ...rather than:
48
+ # # => "be bigger than 2"
49
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
50
+ end
51
+
52
+ # rspec-mocks config goes here. You can use an alternate test double
53
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
54
+ config.mock_with :rspec do |mocks|
55
+ # Prevents you from mocking or stubbing a method that does not exist on
56
+ # a real object. This is generally recommended, and will default to
57
+ # `true` in RSpec 4.
58
+ mocks.verify_partial_doubles = true
59
+ end
60
+
61
+ # The settings below are suggested to provide a good initial experience
62
+ # with RSpec, but feel free to customize to your heart's content.
63
+ =begin
64
+ # These two settings work together to allow you to limit a spec run
65
+ # to individual examples or groups you care about by tagging them with
66
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
67
+ # get run.
68
+ config.filter_run :focus
69
+ config.run_all_when_everything_filtered = true
70
+
71
+ # Allows RSpec to persist some state between runs in order to support
72
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
73
+ # you configure your source control system to ignore this file.
74
+ config.example_status_persistence_file_path = "spec/examples.txt"
75
+
76
+ # Limits the available syntax to the non-monkey patched syntax that is
77
+ # recommended. For more details, see:
78
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
79
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
80
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
81
+ config.disable_monkey_patching!
82
+
83
+ # This setting enables warnings. It's recommended, but in some cases may
84
+ # be too noisy due to issues in dependencies.
85
+ config.warnings = true
86
+
87
+ # Many RSpec users commonly either run the entire suite or an individual
88
+ # file, and it's useful to allow more verbose output when running an
89
+ # individual spec file.
90
+ if config.files_to_run.one?
91
+ # Use the documentation formatter for detailed output,
92
+ # unless a formatter has already been configured
93
+ # (e.g. via a command-line flag).
94
+ config.default_formatter = 'doc'
95
+ end
96
+
97
+ # Print the 10 slowest examples and example groups at the
98
+ # end of the spec run, to help surface which specs are running
99
+ # particularly slow.
100
+ config.profile_examples = 10
101
+
102
+ # Run specs in random order to surface order dependencies. If you find an
103
+ # order dependency and want to debug it, you can fix the order by providing
104
+ # the seed, which is printed after each run.
105
+ # --seed 1234
106
+ config.order = :random
107
+
108
+ # Seed global randomization in this process using the `--seed` CLI option.
109
+ # Setting this allows you to use `--seed` to deterministically reproduce
110
+ # test failures related to randomization by passing the same `--seed` value
111
+ # as the one that triggered the failure.
112
+ Kernel.srand config.seed
113
+ =end
114
+ end