netsnmp 0.0.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.
@@ -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