0
0
Fork 0
mirror of https://github.com/alerta/alerta.git synced 2025-01-24 17:29:39 +00:00
alerta_alerta/bin/alert-snmptrap.py
2012-11-23 15:32:30 +00:00

249 lines
8.4 KiB
Python
Executable file

#!/usr/bin/env python
########################################
#
# alert-snmptrap.py - Alert SNMP Trap Script
#
########################################
import os
import sys
try:
import json
except ImportError:
import simplejson as json
import yaml
import stomp
import time
import datetime
import logging
import uuid
import re
__program__ = 'alert-snmptrap'
__version__ = '1.2.5'
BROKER_LIST = [('localhost', 61613)] # list of brokers for failover
ALERT_QUEUE = '/queue/alerts'
DEFAULT_TIMEOUT = 86400
EXPIRATION_TIME = 600 # seconds = 10 minutes
LOGFILE = '/var/log/alerta/alert-snmptrap.log'
DISABLE = '/opt/alerta/conf/alert-snmptrap.disable'
TRAPCONF = '/opt/alerta/conf/alert-snmptrap.yaml'
PARSERDIR = '/opt/alerta/bin/parsers'
SEVERITY_CODE = {
# ITU RFC5674 -> Syslog RFC5424
'CRITICAL': 1, # Alert
'MAJOR': 2, # Crtical
'MINOR': 3, # Error
'WARNING': 4, # Warning
'NORMAL': 5, # Notice
'INFORM': 6, # Informational
'DEBUG': 7, # Debug
}
def main():
logging.basicConfig(level=logging.INFO, format="%(asctime)s alert-snmptrap[%(process)d] %(levelname)s - %(message)s", filename=LOGFILE)
logging.info('Starting up Alert SNMP Trap version %s', __version__)
if os.path.isfile(DISABLE):
logging.warning('Disable flag exists (%s). Exiting...', DISABLE)
sys.exit(0)
trapvars = dict()
trapvars['$$'] = '$'
recv = sys.stdin.read().splitlines()
logging.info('snmptrapd -> %s', json.dumps(recv))
agent = recv.pop(0)
transport = recv.pop(0)
# Get varbinds
varbinds = dict()
for idx, line in enumerate(recv, start=1):
oid,value = line.split(None, 1)
if value.startswith('"'):
value = value[1:-1]
varbinds[oid] = value
trapvars['$'+str(idx)] = value # $n
trapoid = trapvars['$O'] = trapvars['$2']
try:
enterprise,trapnumber = trapoid.rsplit('.',1)
except:
enterprise,trapnumber = trapoid.rsplit('::',1)
enterprise = enterprise.strip('.0')
# Get sysUpTime
if 'DISMAN-EVENT-MIB::sysUpTimeInstance' in varbinds:
trapvars['$T'] = varbinds['DISMAN-EVENT-MIB::sysUpTimeInstance']
else:
trapvars['$T'] = trapvars['$1'] # assume 1st varbind is sysUpTime
# Get agent address and IP
trapvars['$A'] = agent
m = re.match('UDP: \[(\d+\.\d+\.\d+\.\d+)]', transport)
if m:
trapvars['$a'] = m.group(1)
if 'SNMP-COMMUNITY-MIB::snmpTrapAddress.0' in varbinds:
trapvars['$R'] = varbinds['SNMP-COMMUNITY-MIB::snmpTrapAddress.0'] # snmpTrapAddress
# Get enterprise, specific and generic trap numbers
if trapvars['$2'].startswith('SNMPv2-MIB') or trapvars['$2'].startswith('IF-MIB'): # snmp generic traps
if 'SNMPv2-MIB::snmpTrapEnterprise.0' in varbinds: # snmpTrapEnterprise.0
trapvars['$E'] = varbinds['SNMPv2-MIB::snmpTrapEnterprise.0']
else:
trapvars['$E'] = '1.3.6.1.6.3.1.1.5'
trapvars['$G'] = str(int(trapnumber) - 1)
trapvars['$S'] = '0'
else:
trapvars['$E'] = enterprise
trapvars['$G'] = '6'
trapvars['$S'] = trapnumber
# Get community string
if 'SNMP-COMMUNITY-MIB::snmpTrapCommunity.0' in varbinds: # snmpTrapCommunity
trapvars['$C'] = varbinds['SNMP-COMMUNITY-MIB::snmpTrapCommunity.0']
else:
trapvars['$C'] = '<UNKNOWN>'
logging.info('agent=%s, ip=%s, uptime=%s, enterprise=%s, generic=%s, specific=%s', trapvars['$A'], trapvars['$a'], trapvars['$T'], trapvars['$E'], trapvars['$G'], trapvars['$S'])
logging.debug('trapvars = %s', trapvars)
# Defaults
event = trapoid
resource = agent.split('.')[0]
severity = 'NORMAL'
group = 'SNMP'
value = trapnumber
text = trapvars['$3'] # ie. whatever is in varbind 3
environment = ['INFRA']
service = ['Network']
tags = list()
correlate = list()
threshold = ''
suppress = False
# Match trap to specific config and load any parsers
# Note: any of these variables could have been modified by a parser
trapconf = dict()
try:
trapconf = yaml.load(open(TRAPCONF))
except Exception, e:
logging.error('Failed to load SNMP Trap configuration: %s', e)
sys.exit(1)
logging.info('Loaded %d SNMP Trap configurations OK', len(trapconf))
for t in trapconf:
logging.debug('trapconf: %s', t)
if re.match(t['trapoid'], trapoid):
if 'parser' in t:
print 'Loading parser %s' % t['parser']
try:
exec(open('%s/%s.py' % (PARSERDIR, t['parser'])))
logging.info('Parser %s/%s exec OK', PARSERDIR, t['parser'])
except Exception, e:
print 'Parser %s failed: %s' % (t['parser'], e)
logging.warning('Parser %s failed', t['parser'])
if 'event' in t:
event = t['event']
if 'resource' in t:
resource = t['resource']
if 'severity' in t:
severity = t['severity']
if 'group' in t:
group = t['group']
if 'value' in t:
value = t['value']
if 'text' in t:
text = t['text']
if 'environment' in t:
environment = [t['environment']]
if 'service' in t:
service = [t['service']]
if 'tags' in t:
tags = t['tags']
if 'correlatedEvents' in t:
correlate = t['correlatedEvents']
if 'thresholdInfo' in t:
threshold = t['thresholdInfo']
if 'suppress' in t:
suppress = t['suppress']
break
if suppress:
logging.info('Suppressing %s SNMP trap from %s', trapoid, resource)
return
# Trap variable substitution
logging.debug('trapvars: %s', trapvars)
for k,v in trapvars.iteritems():
logging.debug('replace: %s -> %s', k, v)
event = event.replace(k, v)
resource = resource.replace(k, v)
severity = severity.replace(k, v)
group = group.replace(k, v)
value = value.replace(k, v)
text = text.replace(k, v)
environment[:] = [s.replace(k, v) for s in environment]
service[:] = [s.replace(k, v) for s in service]
tags[:] = [s.replace(k, v) for s in tags]
threshold = threshold.replace(k, v)
alertid = str(uuid.uuid4()) # random UUID
createTime = datetime.datetime.utcnow()
headers = dict()
headers['type'] = "snmptrapAlert"
headers['correlation-id'] = alertid
alert = dict()
alert['id'] = alertid
alert['resource'] = resource
alert['event'] = event
alert['group'] = group
alert['value'] = value
alert['severity'] = severity.upper()
alert['severityCode'] = SEVERITY_CODE[alert['severity']]
alert['environment'] = environment
alert['service'] = service
alert['text'] = text
alert['type'] = 'snmptrapAlert'
alert['tags'] = tags
alert['summary'] = '%s - %s %s is %s on %s %s' % (','.join(environment), severity.upper(), event, value, ','.join(service), resource)
alert['createTime'] = createTime.replace(microsecond=0).isoformat() + ".%03dZ" % (createTime.microsecond//1000)
alert['origin'] = "%s/%s" % (__program__, os.uname()[1])
alert['thresholdInfo'] = threshold
alert['timeout'] = DEFAULT_TIMEOUT
alert['correlatedEvents'] = correlate
logging.info('%s : %s', alertid, json.dumps(alert))
try:
conn = stomp.Connection(BROKER_LIST)
conn.start()
conn.connect(wait=True)
except Exception, e:
print >>sys.stderr, "ERROR: Could not connect to broker - %s" % e
logging.error('Could not connect to broker %s', e)
sys.exit(1)
try:
conn.send(json.dumps(alert), headers, destination=ALERT_QUEUE)
broker = conn.get_host_and_port()
logging.info('%s : Alert sent to %s:%s', alertid, broker[0], str(broker[1]))
except Exception, e:
print >>sys.stderr, "ERROR: Failed to send alert to broker - %s " % e
logging.error('Failed to send alert to broker %s', e)
sys.exit(1)
conn.disconnect()
sys.exit(0)
if __name__ == '__main__':
main()