Skip to content

Commit

Permalink
Merge branch 'walks'
Browse files Browse the repository at this point in the history
  • Loading branch information
zenonas committed Oct 27, 2014
2 parents afe59ff + e474d84 commit 46ac000
Show file tree
Hide file tree
Showing 10 changed files with 256 additions and 32 deletions.
22 changes: 17 additions & 5 deletions lib/snmpjr.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
require "snmpjr/version"
require 'snmpjr/wrappers/smi'
require "snmpjr/getter"
require "snmpjr/walker"
require "snmpjr/target"

class Snmpjr
Expand All @@ -9,18 +11,20 @@ def initialize options = {}
@port = options.fetch(:port) { 161 }
@community = options.fetch(:community)
@timeout = options.fetch(:timeout) { 5000 }
@max_oids_per_request = options.fetch(:max_oids_per_request) { 30 }
@retries = options.fetch(:retries) { 0 }
end

def get oids
target = Snmpjr::Target.new.create(host: @host,
@target = Snmpjr::Target.new.create(host: @host,
port: @port,
community: @community,
timeout: @timeout,
retries: @retries
)
getter = Snmpjr::Getter.new(target: target, max_oids_per_request: @max_oids_per_request)

@max_oids_per_request = options.fetch(:max_oids_per_request) { 30 }
end

def get oids
getter = Snmpjr::Getter.new(target: @target, max_oids_per_request: @max_oids_per_request)

if oids.is_a?(String)
getter.get oids
Expand All @@ -31,4 +35,12 @@ def get oids
end
end

def walk oid
if oid.is_a?(String)
Snmpjr::Walker.new(target: @target).walk Snmpjr::Wrappers::SMI::OID.new(oid)
else
raise ArgumentError.new 'The oid needs to be passed in as a String'
end
end

end
4 changes: 4 additions & 0 deletions lib/snmpjr/pdu.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,9 @@ def create oids
pdu
end

def self.createPDU target
Snmpjr::Wrappers::PDU.new
end

end
end
1 change: 1 addition & 0 deletions lib/snmpjr/session.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

class Snmpjr
class Session
attr_reader :snmp

def initialize
@snmp = Snmpjr::Wrappers::Snmp.new(Snmpjr::Wrappers::Transport::DefaultUdpTransportMapping.new)
Expand Down
50 changes: 50 additions & 0 deletions lib/snmpjr/walker.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
require 'snmpjr/wrappers/util'
require 'snmpjr/wrappers/smi'
require 'snmpjr/session'

class Snmpjr
class Walker
def initialize opts = {}
@target = opts.fetch(:target)
end

def walk oid
session = Snmpjr::Session.new
session.start

tree_utils = Snmpjr::Wrappers::Util::TreeUtils.new(session.snmp, pdu_factory)
begin
response = tree_utils.getSubtree(@target, oid)
rescue Exception => e
raise RuntimeError.new e.to_s
ensure
session.close
end
results = response.flat_map {|response_event|
extract_variable_bindings(response_event)
}
results
end

private

def extract_variable_bindings event
if event.is_error?
if event.error_message == 'Request timed out.'
raise Snmpjr::TargetTimeoutError.new('Request timed out')
else
raise Snmpjr::RuntimeError.new(event.error_message)
end
end

event.variable_bindings.flat_map {|vb|
Snmpjr::Response.new(value: vb.variable.to_s)
}
end

def pdu_factory
Snmpjr::Wrappers::Util::DefaultPDUFactory.new
end

end
end
Binary file added lib/snmpjr/wrappers/snmp4j-agent-2.3.0.jar
Binary file not shown.
9 changes: 9 additions & 0 deletions lib/snmpjr/wrappers/util.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
require 'snmpjr/wrappers/snmp4j'

class Snmpjr
module Wrappers
module Util
include_package 'org.snmp4j.util'
end
end
end
File renamed without changes.
35 changes: 35 additions & 0 deletions spec/integration/snmpjr_walk_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
require 'snmpjr'
require 'snmpjr/response'
require 'snmpjr/target_timeout_error'

describe "snmpjr" do

describe 'WALK' do
context 'when the host is reachable' do
subject { Snmpjr.new(host: 'demo.snmplabs.com', port: 161, community: 'public') }

it 'can perform a simple synchronous walk request on an snmp agent' do
response = subject.walk '1.3.6.1.2.1.1'
expect(response.count).to eq 11
expect(response.first.to_s).to eq 'SunOS zeus.snmplabs.com 4.1.3_U1 1 sun4m'
expect(response.last.to_s).to match /^\d+\:\d+:\d+\.\d+$/
end

context "when a non existent subtree is walked" do
it 'returns an empty array' do
expect(subject.walk '1.3.6.1.5').to eq []
end
end
end

context 'when the host is unreachable' do
subject { Snmpjr.new(host: 'example.com', port: 161, community: 'public', timeout: 50) }

it 'the request times out after 5 seconds' do
expect{
subject.walk '1.3.6.1.2.1.1'
}.to raise_error(Snmpjr::TargetTimeoutError)
end
end
end
end
85 changes: 85 additions & 0 deletions spec/snmpjr/walker_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
require production_code

describe Snmpjr::Walker do
let(:target) { double :target }
let(:oid) { Snmpjr::Wrappers::SMI::OID.new '1.2.3.4.5.6' }
let(:session) { double(:session).as_null_object }

let(:pdu_factory) { double Snmpjr::Wrappers::Util::DefaultPDUFactory }
let(:tree_util) { double Snmpjr::Wrappers::Util::TreeUtils }

subject { described_class.new(target: target) }

let(:vb1) { Snmpjr::Wrappers::SMI::VariableBinding.new(
Snmpjr::Wrappers::SMI::OID.new('1.3.6'),
Snmpjr::Wrappers::SMI::OctetString.new('Sample Result 1'))
}

let(:vb2) { Snmpjr::Wrappers::SMI::VariableBinding.new(
Snmpjr::Wrappers::SMI::OID.new('1.3.6.1'),
Snmpjr::Wrappers::SMI::OctetString.new('Sample Result 2'))
}
let(:tree_event_1) { double :tree_event_1, {variable_bindings: [vb1], is_error?: false} }
let(:tree_event_2) { double :tree_event_2, {variable_bindings: [vb2], is_error?: false} }
let(:example_event_responses) { [tree_event_1, tree_event_2] }

before do
allow(Snmpjr::Wrappers::Util::DefaultPDUFactory).to receive(:new).and_return pdu_factory
allow(Snmpjr::Session).to receive(:new).and_return session

allow(Snmpjr::Wrappers::Util::TreeUtils).to receive(:new).with(session.snmp, pdu_factory).and_return tree_util
allow(tree_util).to receive(:getSubtree).with(target, oid).and_return example_event_responses
end

describe '#walk' do
it 'starts an snmp session' do
expect(session).to receive(:start)
subject.walk oid
end

context 'when an exception is raised' do
before do
allow(tree_util).to receive(:getSubtree).with(target, oid).and_raise Exception.new 'noAccess'
end
it 'raises a runtime error' do
expect{
subject.walk oid
}.to raise_error RuntimeError
end
end

context 'when a target times out' do
let(:tree_event_1) { double :tree_event_1 }
before do
allow(tree_event_1).to receive(:is_error?).and_return true
allow(tree_event_1).to receive(:error_message).and_return 'Request timed out.'
end

it 'raises a timeout error' do
expect{
subject.walk oid
}.to raise_error Snmpjr::TargetTimeoutError
end

end

context 'when a walk returns no variable bindings' do
let(:tree_event) { double :tree_event, {variable_bindings: [], is_error?: false } }
let(:example_event_responses) { [tree_event] }

it 'returns an empty array' do
expect(subject.walk oid).to eq []
end
end

it 'performs a synchronous walk' do
expect(subject.walk oid).to match_array [Snmpjr::Response.new(value: vb1.variable.to_s),
Snmpjr::Response.new(value: vb2.variable.to_s)]
end

it 'closes the snmp session' do
expect(session).to receive(:close)
subject.walk oid
end
end
end
82 changes: 55 additions & 27 deletions spec/snmpjr_spec.rb
Original file line number Diff line number Diff line change
@@ -1,44 +1,72 @@
require production_code

describe Snmpjr do
let(:target) { double Snmpjr::Target }
let(:community_target) { double :community_target }
let(:agent_details) { { host: '127.0.0.1', port: 161, community: 'some_community', timeout: 50, retries: 50 } }

subject { described_class.new(agent_details) }

before do
allow(Snmpjr::Target).to receive(:new).and_return target
allow(target).to receive(:create).with(agent_details).and_return community_target
end

describe "#get" do
context "when the call is synchronous" do
let(:getter) { double Snmpjr::Getter }

let(:target) { double Snmpjr::Target }
let(:community_target) { double :community_target }
let(:getter) { double Snmpjr::Getter }
before do
allow(Snmpjr::Getter).to receive(:new).with(target: community_target, max_oids_per_request: 20).and_return getter
end

before do
allow(Snmpjr::Target).to receive(:new).and_return target
allow(target).to receive(:create).with(agent_details).and_return community_target
allow(Snmpjr::Getter).to receive(:new).with(target: community_target, max_oids_per_request: 20).and_return getter
end

let(:agent_details) { { host: '127.0.0.1', port: 161, community: 'some_community', timeout: 50, retries: 50 } }
subject { described_class.new(agent_details.merge({max_oids_per_request: 20})) }

subject { described_class.new(agent_details.merge({max_oids_per_request: 20})) }
context 'when passed a single oid' do
it 'performs a synchronous get' do
expect(getter).to receive(:get).with('1.2.3.4.5.6')
subject.get '1.2.3.4.5.6'
end
end

context 'when passed a single oid' do
it 'performs a synchronous get' do
expect(getter).to receive(:get).with('1.2.3.4.5.6')
subject.get '1.2.3.4.5.6'
end
context 'when passed multiple oids' do
it 'performs a get multiple using the getter' do
expect(getter).to receive(:get_multiple).with(['1.2.3.4.5.6', '6.5.4.3.2.1'])
subject.get ['1.2.3.4.5.6', '6.5.4.3.2.1']
end
end

context 'when passed multiple oids' do
it 'performs a get multiple using the getter' do
expect(getter).to receive(:get_multiple).with(['1.2.3.4.5.6', '6.5.4.3.2.1'])
subject.get ['1.2.3.4.5.6', '6.5.4.3.2.1']
end
context 'when an invalid argument was passed in' do
it 'raises an ArgumentError' do
expect {
subject.get({'oid_value' => '1.3.4.5.6'})
}.to raise_error ArgumentError
end
end
end

describe '#walk' do
let(:walker) { double Snmpjr::Walker }
let(:oid) { double :oid }

before do
allow(Snmpjr::Walker).to receive(:new).with(target: community_target).and_return walker
allow(Snmpjr::Wrappers::SMI::OID).to receive(:new).with('1.3.6.1.1').and_return oid
end
context 'when a string is passed' do
it 'performs a synchronous walk' do
expect(walker).to receive(:walk).with(oid)
subject.walk '1.3.6.1.1'
end
end

context 'when an invalid argument was passed in' do
it 'raises an ArgumentError' do
expect {
subject.get({'oid_value' => '1.3.4.5.6'})
}.to raise_error ArgumentError
end
context 'when anything else is passed in' do
it 'raises an ArgumentError' do
expect {
subject.walk({'oid_value' => '1.3.4.5.6'})
}.to raise_error ArgumentError
end
end

end
end

0 comments on commit 46ac000

Please sign in to comment.