lib/logstash/inputs/snmp.rb in logstash-input-snmp-0.1.0.beta4 vs lib/logstash/inputs/snmp.rb in logstash-input-snmp-0.1.0.beta5
- old
+ new
@@ -2,10 +2,11 @@
require "logstash/inputs/base"
require "logstash/namespace"
require "stud/interval"
require "socket" # for Socket.gethostname
require_relative "snmp/client"
+require_relative "snmp/clientv3"
require_relative "snmp/mib"
# Generate a repeating message.
#
# This plugin is intented only as an example.
@@ -24,15 +25,19 @@
# Each host definition is a hash and must define the `host` key and value.
# `host` must use the format {tcp|udp}:{ip address}/{port}
# for example `host => "udp:127.0.0.1/161"`
# Each host definition can optionally include the following keys and values:
# `community` with a default value of `public`
- # `version` `1` or `2c` with a default value of `2c`
- # `retries` with a detault value of `2`
+ # `version` `1`, `2c` or `3` with a default value of `2c`
+ # `retries` with a default value of `2`
# `timeout` in milliseconds with a default value of `1000`
config :hosts, :validate => :array #[ {"host" => "udp:127.0.0.1/161", "community" => "public"} ]
+ # This plugin provides sets of MIBs publicly available. The full paths to these provided MIBs paths
+ # Will be displayed at plugin startup.
+ config :use_provided_mibs, :validate => :boolean, :default => true
+
# List of paths of MIB .dic files of dirs. If a dir path is specified, all files with .dic extension will be loaded.
#
# ATTENTION: a MIB .dic file must be generated using the libsmi library `smidump` command line utility
# like this for example. Here the `RFC1213-MIB.txt` file is an ASN.1 MIB file.
#
@@ -48,32 +53,69 @@
# as "1.3.6.1.2.mib-2.system.sysDescr.0" would become "mib-2.system.sysDescr.0"
config :oid_root_skip, :validate => :number, :default => 0
# Set polling interval in seconds
#
- # The default, `30`, means poll each host every 30second.
+ # The default, `30`, means poll each host every 30 seconds.
config :interval, :validate => :number, :default => 30
# Add the default "host" field to the event.
config :add_field, :validate => :hash, :default => { "host" => "%{[@metadata][host_address]}" }
+ # SNMPv3 Credentials
+ #
+ # A single user can be configured and will be used for all defined SNMPv3 hosts.
+ # Multiple snmp input declarations will be needed if multiple SNMPv3 users are required.
+ # If not using SNMPv3 simply leave options empty.
+
+ # The SNMPv3 security name or user name
+ config :security_name, :validate => :string
+
+ # The SNMPv3 authentication protocol or type
+ config :auth_protocol, :validate => ["md5", "sha", "sha2", "hmac128sha224", "hmac192sha256", "hmac256sha384", "hmac384sha512"]
+
+ # The SNMPv3 authentication passphrase or password
+ config :auth_pass, :validate => :password
+
+ # The SNMPv3 privacy/encryption protocol
+ config :priv_protocol, :validate => ["des", "3des", "aes", "aes128", "aes192", "aes256"]
+
+ # The SNMPv3 encryption password
+ config :priv_pass, :validate => :password
+
+ # The SNMPv3 security level can be Authentication, No Privacy; Authentication, Privacy; or no Authentication, no Privacy
+ config :security_level, :validate => ["noAuthNoPriv", "authNoPriv", "authPriv"]
+
+ BASE_MIB_PATH = ::File.join(__FILE__, "..", "..", "..", "mibs")
+ PROVIDED_MIB_PATHS = [::File.join(BASE_MIB_PATH, "logstash"), ::File.join(BASE_MIB_PATH, "ietf")].map { |path| ::File.expand_path(path) }
+
def register
validate_oids!
validate_hosts!
mib = LogStash::SnmpMib.new
+
+ if @use_provided_mibs
+ PROVIDED_MIB_PATHS.each do |path|
+ logger.info("using plugin provided MIB path #{path}")
+ mib.add_mib_path(path)
+ end
+ end
+
Array(@mib_paths).each do |path|
- # TODO handle errors
+ logger.info("using user provided MIB path #{path}")
mib.add_mib_path(path)
end
+ # setup client definitions per provided host
+
@client_definitions = []
@hosts.each do |host|
host_name = host["host"]
community = host["community"] || "public"
version = host["version"] || "2c"
- raise(LogStash::ConfigurationError, "only protocol version '1' and '2c' are supported for host option '#{host_name}'") unless version =~ VERSION_REGEX
+ raise(LogStash::ConfigurationError, "only protocol version '1', '2c' and '3' are supported for host option '#{host_name}'") unless version =~ VERSION_REGEX
retries = host["retries"] || 2
timeout = host["timeout"] || 1000
# TODO: move these validations in a custom validator so it happens before the register method is called.
@@ -84,19 +126,27 @@
protocol = host_details[:host_protocol]
address = host_details[:host_address]
port = host_details[:host_port]
definition = {
- :client => LogStash::SnmpClient.new(protocol, address, port, community, version, retries, timeout, mib),
:get => Array(get),
:walk => Array(walk),
:host_protocol => protocol,
:host_address => address,
:host_port => port,
:host_community => community,
}
+
+ if version == "3"
+ validate_v3_user! # don't really care if verified for every host
+ auth_pass = @auth_pass.nil? ? nil : @auth_pass.value
+ priv_pass = @priv_pass.nil? ? nil : @priv_pass.value
+ definition[:client] = LogStash::SnmpClientV3.new(protocol, address, port, retries, timeout, mib, @security_name, @auth_protocol, auth_pass, @priv_protocol, priv_pass, @security_level)
+ else
+ definition[:client] = LogStash::SnmpClient.new(protocol, address, port, community, version, retries, timeout, mib)
+ end
@client_definitions << definition
end
end
def run(queue)
@@ -107,11 +157,11 @@
result = {}
if !definition[:get].empty?
begin
result = result.merge(definition[:client].get(definition[:get], @oid_root_skip))
rescue => e
- logger.error("error invoking get operation on OIDs: #{definition[:get]}, ignoring", :exception => e, :backtrace => e.backtrace)
+ logger.error("error invoking get operation on #{definition[:host_address]} for OIDs: #{definition[:get]}, ignoring", :exception => e, :backtrace => e.backtrace)
end
end
if !definition[:walk].empty?
definition[:walk].each do |oid|
begin
@@ -122,14 +172,14 @@
end
end
unless result.empty?
metadata = {
- "host_protocol" => definition[:host_protocol],
- "host_address" => definition[:host_address],
- "host_port" => definition[:host_port],
- "host_community" => definition[:host_community],
+ "host_protocol" => definition[:host_protocol],
+ "host_address" => definition[:host_address],
+ "host_port" => definition[:host_port],
+ "host_community" => definition[:host_community],
}
result["@metadata"] = metadata
event = LogStash::Event.new(result)
decorate(event)
@@ -146,11 +196,11 @@
private
OID_REGEX = /^\.?([0-9\.]+)$/
HOST_REGEX = /^(?<host_protocol>udp|tcp):(?<host_address>.+)\/(?<host_port>\d+)$/i
- VERSION_REGEX =/^1|2c$/
+ VERSION_REGEX =/^1|2c|3$/
def validate_oids!
@get = Array(@get).map do |oid|
# verify oids for valid pattern and get rid or any leading dot if present
unless oid =~ OID_REGEX
@@ -167,9 +217,22 @@
$1
end
raise(LogStash::ConfigurationError, "at least one get OID or one walk OID is required") if @get.empty? && @walk.empty?
end
+
+ def validate_v3_user!
+ errors = []
+
+ errors << "v3 user must have a \"security_name\" option" if @security_name.nil?
+ errors << "you must specify an auth protocol if you specify an auth pass" if @auth_protocol.nil? && !@auth_pass.nil?
+ errors << "you must specify an auth pass if you specify an auth protocol" if !@auth_protocol.nil? && @auth_pass.nil?
+ errors << "you must specify a priv protocol if you specify a priv pass" if @priv_protocol.nil? && !@priv_pass.nil?
+ errors << "you must specify a priv pass if you specify a priv protocol" if !@priv_protocol.nil? && @priv_pass.nil?
+
+ raise(LogStash::ConfigurationError, errors.join(", ")) unless errors.empty?
+ end
+
def validate_hosts!
# TODO: for new we only validate the host part, not the other optional options
raise(LogStash::ConfigurationError, "at least one host definition is required") if Array(@hosts).empty?