def resolve_vars(cls, vars): """ Resolve FM key -> value dict according to MIBs :param cls: :param vars: :return: """ r = {} for k in vars: if not is_oid(k): # Nothing to resolve continue v = fm_unescape(vars[k]) rk, syntax = cls.get_name_and_syntax(k) rv = v if syntax: # Format value according to syntax if syntax["base_type"] == "Enumeration": # Expand enumerated type try: rv = syntax["enum_map"][str(v)] except KeyError: pass elif syntax["base_type"] == "Bits": # @todo: Fix ugly hack if v.startswith("="): xv = int(v[1:], 16) else: xv = 0 for c in v: xv = (xv << 8) + ord(c) # Decode b_map = syntax.get("enum_map", {}) b = [] n = 0 while xv: if xv & 1: x = str(n) if x in b_map: b = [b_map[x]] + b else: b = ["%X" % (1 << n)] n += 1 xv >>= 1 rv = "(%s)" % ",".join(b) else: # Render according to TC rv = render_tc(v, syntax["base_type"], syntax.get("display_hint", None)) try: unicode(rv, "utf8") except ValueError: # Escape invalid UTF8 rv = fm_escape(rv) else: try: unicode(rv, "utf8") except ValueError: # escape invalid UTF8 rv = fm_escape(rv) if is_oid(v): # Resolve OID in value rv = MIB.get_name(v) if rk != k or rv != v: r[rk] = rv return r
async def classify_event(self, event, data): """ Perform event classification. Classification steps are: 1. Format SNMP values accordind to MIB definitions (for SNMP events only) 2. Find matching classification rule 3. Calculate rule variables :param event: Event to classify :type event: NewEvent :returns: Classification status (CR_*) """ metrics[E_SRC_METRICS.get(event.source, E_SRC_OTHER)] += 1 is_unknown = False # pre_event = data.pop("$event", None) # Resolve MIB variables for SNMP Traps resolved_vars = {"profile": event.managed_object.profile.name} # Store event variables event.raw_vars = data if event.source == E_SRC_SNMP_TRAP: resolved_vars.update(MIB.resolve_vars(event.raw_vars)) event.resolved_vars = resolved_vars # Get matched event class if pre_event: # Event is preprocessed, get class and variables event_class_name = pre_event.get("class") event_class = EventClass.get_by_name(event_class_name) if not event_class: self.logger.error( "[%s|%s|%s] Failed to process event: Invalid event class '%s'", event.id, event.managed_object.name, event.managed_object, event_class_name, ) metrics[CR_FAILED] += 1 return # Drop malformed message event.event_class = event_class event.vars = pre_event.get("vars", {}) else: # Prevent unclassified events flood if self.check_unclassified_syslog_flood(event): return # Find matched event class c_vars = event.raw_vars.copy() c_vars.update({ k: smart_text(fm_unescape(resolved_vars[k])) for k in resolved_vars }) rule, vars = self.ruleset.find_rule(event, c_vars) if rule is None: # Something goes wrong. # No default rule found. Exit immediately self.logger.error("No default rule found. Exiting") os._exit(1) if rule.to_drop: # Silently drop event if declared by action self.logger.info( "[%s|%s|%s] Dropped by action", event.id, event.managed_object.name, event.managed_object.address, ) metrics[CR_DELETED] += 1 return if rule.is_unknown_syslog: # Append to codebook msg = event.raw_vars.get("message", "") cb = self.get_msg_codebook(msg) o_id = event.managed_object.id if o_id not in self.unclassified_codebook: self.unclassified_codebook[o_id] = [] cbs = [cb] + self.unclassified_codebook[o_id] cbs = cbs[:self.unclassified_codebook_depth] self.unclassified_codebook[o_id] = cbs self.logger.debug( "[%s|%s|%s] Matching rule: %s", event.id, event.managed_object.name, event.managed_object.address, rule.name, ) event.event_class = rule.event_class # Calculate rule variables event.vars = self.ruleset.eval_vars(event, event.event_class, vars) message = "Classified as '%s' by rule '%s'" % ( event.event_class.name, rule.name) event.log += [ EventLog( timestamp=datetime.datetime.now(), from_status="N", to_status="A", message=message, ) ] is_unknown = rule.is_unknown # Event class found, process according to rules self.logger.info( "[%s|%s|%s] Event class: %s (%s)", event.id, event.managed_object.name, event.managed_object.address, event.event_class.name, event.vars, ) # Deduplication if self.deduplicate_event(event): return # Suppress repeats if self.suppress_repeats(event): return # Activate event event.expires = event.timestamp + datetime.timedelta( seconds=event.event_class.ttl) event.save() # Fill deduplication filter self.dedup_filter.register(event) # Fill suppress filter self.suppress_filter.register(event) # Call handlers if self.call_event_handlers(event): return # Additionally check link events if await self.check_link_event(event): return # Call triggers if self.call_event_triggers(event): return # Finally dispose event to further processing by correlator if event.to_dispose: await self.dispose_event(event) if is_unknown: metrics[CR_UNKNOWN] += 1 elif pre_event: metrics[CR_PREPROCESSED] += 1 else: metrics[CR_CLASSIFIED] += 1
def test_fm_unescape(value, expected): assert fm_unescape(value) == expected