Class: Sensu::Extension::SNMPTrap

Inherits:
Check
  • Object
show all
Defined in:
lib/sensu/extensions/snmp-trap.rb

Constant Summary collapse

RESULT_MAP =
[
  [/checkname/i, :name],
  [/notification/i, :output],
  [/severity/i, :status]
]
RUBY_ASN1_MAP =
{
  "INTEGER" => :to_i,
  "OCTET STRING" => :to_s,
  "OBJECT IDENTIFIER" => :to_s,
  "IpAddress" => :to_s,
  "Counter32" => :to_i,
  "Gauge32" => :to_i,
  "Unsigned32" => :to_i,
  "TimeTicks" => :to_i,
  "Opaque" => :to_s,
  "Counter64" => :to_i
}

Instance Method Summary collapse

Instance Method Details

#definitionObject



36
37
38
39
40
41
# File 'lib/sensu/extensions/snmp-trap.rb', line 36

def definition
  {
    name: name,
    publish: false
  }
end

#descriptionObject



32
33
34
# File 'lib/sensu/extensions/snmp-trap.rb', line 32

def description
  "receives snmp traps and translates them to check results"
end

#determine_hostname(address) ⇒ Object



96
97
98
99
100
101
102
103
# File 'lib/sensu/extensions/snmp-trap.rb', line 96

def determine_hostname(address)
  begin
    Resolv.getname(address)
  rescue Resolv::ResolvError
    @logger.debug("snmp trap check extension unable to resolve hostname", :address => address)
    address
  end
end

#determine_trap_oid(trap) ⇒ Object



105
106
107
108
109
110
# File 'lib/sensu/extensions/snmp-trap.rb', line 105

def determine_trap_oid(trap)
  varbind = trap.varbind_list.detect do |varbind|
    varbind.name.to_oid == SNMP::SNMP_TRAP_OID_OID
  end
  varbind.value.to_s.gsub(/[^\w\.-]/i, "-") rescue "trap_oid_unknown"
end

#load_mibs!Object



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/sensu/extensions/snmp-trap.rb', line 68

def load_mibs!
  @logger.debug("snmp trap check extension importing mibs", :mibs_dir => options[:mibs_dir])
  Dir.glob(File.join(options[:mibs_dir], "*")) do |mib_file|
    @logger.debug("snmp trap check extension importing mib", :mib_file => mib_file)
    begin
      SNMP::MIB.import_module(mib_file)
    rescue StandardError, SyntaxError => error
      @logger.debug("snmp trap check extension failed to import mib", {
        :mib_file => mib_file,
        :error => error
      })
    end
  end
  @mibs = SNMP::MIB.new
  @logger.debug("snmp trap check extension loading mibs")
  SNMP::MIB.list_imported.each do |module_name|
    @logger.debug("snmp trap check extension loading mib", :module_name => module_name)
    @mibs.load_module(module_name)
  end
  @mibs
end

#nameObject



28
29
30
# File 'lib/sensu/extensions/snmp-trap.rb', line 28

def name
  "snmp_trap"
end

#optionsObject



43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/sensu/extensions/snmp-trap.rb', line 43

def options
  return @options if @options
  @options = {
    :bind => "0.0.0.0",
    :port => 1062,
    :community => "public",
    :handlers => ["default"],
    :mibs_dir => "/etc/sensu/mibs"
  }
  @options.merge!(@settings[:snmp_trap]) if @settings[:snmp_trap].is_a?(Hash)
  @options
end

#post_initObject



147
148
149
150
151
# File 'lib/sensu/extensions/snmp-trap.rb', line 147

def post_init
  @traps = Queue.new
  start_snmpv2_listener!
  start_trap_processor!
end

#process_trap(trap) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/sensu/extensions/snmp-trap.rb', line 112

def process_trap(trap)
  @logger.debug("snmp trap check extension processing a v2 trap")
  result = {
    :source => determine_hostname(trap.source_ip),
    :handlers => options[:handlers]
  }
  trap.varbind_list.each do |varbind|
    symbolic_name = @mibs.name(varbind.name.to_oid)
    mapping = RESULT_MAP.detect do |mapping|
      symbolic_name =~ mapping.first
    end
    if mapping && !result[mapping.last]
      type_conversion = RUBY_ASN1_MAP[varbind.value.asn1_type]
      if type_conversion
        result[mapping.last] = varbind.value.send(type_conversion)
      end
    end
  end
  result[:name] ||= determine_trap_oid(trap)
  result[:output] ||= trap.inspect
  result[:status] ||= 3
  send_result(result)
end

#run(event) {|"no-op", 0| ... } ⇒ Object

Yields:

  • ("no-op", 0)


158
159
160
# File 'lib/sensu/extensions/snmp-trap.rb', line 158

def run(event, &callback)
  yield "no-op", 0
end

#send_result(result) ⇒ Object



90
91
92
93
94
# File 'lib/sensu/extensions/snmp-trap.rb', line 90

def send_result(result)
  socket = UDPSocket.new
  socket.send(Sensu::JSON.dump(result), 0, "127.0.0.1", 3030)
  socket.close
end

#start_snmpv2_listener!Object



56
57
58
59
60
61
62
63
64
65
66
# File 'lib/sensu/extensions/snmp-trap.rb', line 56

def start_snmpv2_listener!
  @listener = SNMP::TrapListener.new(
    :host => options[:bind],
    :port => options[:port],
    :community => options[:community]) do |listener|
    listener.on_trap_v2c do |trap|
      @logger.debug("snmp trap check extension received a v2 trap")
      @traps << trap
    end
  end
end

#start_trap_processor!Object



136
137
138
139
140
141
142
143
144
145
# File 'lib/sensu/extensions/snmp-trap.rb', line 136

def start_trap_processor!
  @processor = Thread.new do
    load_mibs!
    loop do
      process_trap(@traps.pop)
    end
  end
  @processor.abort_on_exception = true
  @processor
end

#stopObject



153
154
155
156
# File 'lib/sensu/extensions/snmp-trap.rb', line 153

def stop
  @listener.kill if @listener
  @processor.kill if @processor
end