Пример #1
0
 def correlate_merge_downlinks(ca: ActiveAlarm) -> bool:
     """
     Donwlink merge correlation
     :param ca:
     :return:
     """
     if not ca.uplinks or not ca.rca_neighbors:
         return False
     dlm_neighbors = {
         mo: w
         for mo, w in zip(ca.rca_neighbors, ca.dlm_windows) if w > 0
     }
     dlm_candidates = set(neighbor_alarms) & set(dlm_neighbors)
     if not dlm_candidates:
         return False
     # Get possible candidates
     t0 = ca.timestamp
     candidates = list(
         sorted(
             (neighbor_alarms[mo] for mo in dlm_candidates
              if (t0 - neighbor_alarms[mo].timestamp
                  ).total_seconds() <= dlm_neighbors[mo]),
             key=operator.attrgetter("timestamp"),
         ))
     if not candidates:
         return False
     ra = candidates[0]
     self.logger.info("[%s] Set root to %s (downlink merge)", ca.id,
                      ra.id)
     ca.set_root(ra, rca_type=RCA_DOWNLINK_MERGE)
     metrics["alarm_correlated_topology"] += 1
     return True
Пример #2
0
 def get_alarms(objects: List[int]) -> Set[int]:
     """
     Returns a set of objects with alarms
     """
     alarms: Set[int] = set()
     coll = ActiveAlarm._get_collection()
     while objects:
         chunk, objects = objects[:500], objects[500:]
         a = coll.aggregate([
             {
                 "$match": {
                     "managed_object": {
                         "$in": chunk
                     }
                 }
             },
             {
                 "$group": {
                     "_id": "$managed_object",
                     "count": {
                         "$sum": 1
                     }
                 }
             },
         ])
         alarms.update(d["_id"] for d in a)
     return alarms
Пример #3
0
 def api_notification(self, request):
     delta = request.GET.get("delta")
     n = 0
     sound = None
     volume = 0
     if delta:
         dt = datetime.timedelta(seconds=int(delta))
         t0 = datetime.datetime.now() - dt
         r = list(ActiveAlarm._get_collection().aggregate([{
             "$match": {
                 "timestamp": {
                     "$gt": t0
                 }
             }
         }, {
             "$group": {
                 "_id": "$item",
                 "severity": {
                     "$max": "$severity"
                 }
             }
         }]))
         if r:
             s = AlarmSeverity.get_severity(r[0]["severity"])
             if s and s.sound and s.volume:
                 sound = "/ui/pkg/nocsound/%s.mp3" % s.sound
                 volume = float(s.volume) / 100.0
     return {"new_alarms": n, "sound": sound, "volume": volume}
Пример #4
0
 def correlate_uplinks(ca: ActiveAlarm) -> bool:
     """
     Correlate with uplink alarms if all uplinks are faulty.
     :param a1:
     :return:
     """
     if not all_uplinks_failed(ca):
         return False
     self.logger.info("[%s] All uplinks are faulty. Correlating", ca.id)
     ra = get_root(ca)
     if not ra:
         return False
     self.logger.info("[%s] Set root to %s", ca.id, ra.id)
     ca.set_root(ra, rca_type=RCA_TOPOLOGY)
     metrics["alarm_correlated_topology"] += 1
     return True
Пример #5
0
def check_segment_redundancy(alarm):
    """
    Reset lost_redundancy from segment when all redundant objects
    are up
    :param alarm:
    :return:
    """
    mo = alarm.managed_object
    seg = mo.segment
    if not seg.is_redundant or not seg.lost_redundancy:
        return
    u = mo.data.uplinks
    if len(u) < 2:
        return
    seg_objects = list(seg.managed_objects.values_list("id", flat=True))
    alarms = [
        d["managed_object"] for d in ActiveAlarm._get_collection().find(
            {"managed_object": {
                "$in": seg_objects
            }}, {
                "_id": 0,
                "managed_object": 1
            }) if d["managed_object"] != mo.id
    ]
    uplinks = ObjectData.uplinks_for_objects(alarms)
    if not any(x for x in uplinks.values() if len(x) > 1):
        logger.info("[%s] Redundancy recovered for %s", alarm.id, seg.name)
        seg.set_lost_redundancy(False)
Пример #6
0
 def get_alarms(objects):
     """
     Returns a set of objects with alarms
     """
     r = set()
     c = ActiveAlarm._get_collection()
     while objects:
         chunk, objects = objects[:500], objects[500:]
         a = c.aggregate([
             {
                 "$match": {
                     "managed_object": {
                         "$in": chunk
                     }
                 }
             },
             {
                 "$group": {
                     "_id": "$managed_object",
                     "count": {
                         "$sum": 1
                     }
                 }
             },
         ])
         r.update([d["_id"] for d in a])
     return r
Пример #7
0
 def showalarm(self):
     alarms = ActiveAlarm.objects().order_by("-timestamp")
     res = []
     i = 0
     #        for a in alarms:
     #            res.append('{} - {}'.format(a.managed_object.name, a.subject))
     #            i = 1+1
     pprint(alarms[0].subject)
Пример #8
0
 def get_data(self):
     # Calculate contained objects
     summary = {
         "service": SummaryItem.items_to_dict(self.object.total_services),
         "subscriber": SummaryItem.items_to_dict(self.object.total_subscribers)
     }
     objects = []
     for mo in self.object.managed_objects.filter(is_managed=True):
         ss = ServiceSummary.get_object_summary(mo)
         objects += [{
             "id": mo.id,
             "name": mo.name,
             "object": mo,
             "summary": ss
         }]
     # Update object statuses
     mos = [o["id"] for o in objects]
     alarms = set(d["managed_object"] for d in ActiveAlarm._get_collection().find({
         "managed_object": {
             "$in": mos
         }
     }, {"_id": 0, "managed_object": 1}))
     o_status = ObjectStatus.get_statuses(mos)
     for o in objects:
         if o["id"] in o_status:
             if o["id"] in alarms:
                 o["status"] = "alarm"
             else:
                 o["status"] = "up"
         else:
             o["status"] = "down"
     # Calculate children
     children = []
     for ns in NetworkSegment.objects.filter(parent=self.object.id):
         children += [{
             "id": ns.id,
             "name": ns.name,
             "object": ns,
             "summary": {
                 "service": SummaryItem.items_to_dict(ns.total_services),
                 "subscriber": SummaryItem.items_to_dict(ns.total_subscribers),
             }
         }]
     # Calculate VLANs
     vlans = []
     if self.object.vlan_border:
         vlans = list(VLAN.objects.filter(segment=self.object.id).order_by("vlan"))
     #
     return {
         "object": self.object,
         "managed_objects": sorted(objects, key=operator.itemgetter("name")),
         "children": sorted(children, key=operator.itemgetter("name")),
         "parent": self.object.parent,
         "summary": summary,
         "vlans": vlans
     }
Пример #9
0
 def sync_alarms(self):
     """
     Raise/close related alarms
     """
     # Check errors are exists
     n_errors = sum(1 for e in self.iter_errors())
     alarm = ActiveAlarm.objects.filter(
         alarm_class=self.AC_POLICY_VIOLATION.id,
         managed_object=self.object.id).first()
     if n_errors:
         if not alarm:
             self.logger.info("Raise alarm")
             # Raise alarm
             alarm = ActiveAlarm(
                 timestamp=datetime.datetime.now(),
                 managed_object=self.object,
                 alarm_class=self.AC_POLICY_VIOLATION,
                 severity=2000,  # WARNING
             )
         # Alarm is already exists
         alarm.log_message("%d errors has been found" % n_errors)
     elif alarm:
         # Clear alarm
         self.logger.info("Clear alarm")
         alarm.clear_alarm("No errors has been registered")
Пример #10
0
 def get_alarms_info(mo_ids, alarms_all=False):
     q = {"severity": {"$exists": True}}
     if not alarms_all:
         q["managed_object"] = {"$in": mo_ids}
     coll = ActiveAlarm._get_collection().with_options(
         read_preference=ReadPreference.SECONDARY_PREFERRED)
     r = {}
     for o in coll.find(q, {"managed_object": 1, "severity": 1, "_id": 0}):
         if (o["managed_object"] in r and r[o["managed_object"]] >
                 o["severity"]):  # Save alarm with max severity
             continue
         r[o["managed_object"]] = o["severity"]
     return r
Пример #11
0
 def handle_clean(self, options, events):
     before = options.get("before")
     if before:
         datetime.datetime.strptime(before, "%Y-%m-%d")
     else:
         self.print("Before is not set, use default")
         before = datetime.datetime.now() - DEFAULT_CLEAN
     force = options.get("force")
     aa = ActiveAlarm._get_collection()
     ah = ArchivedAlarm._get_collection()
     ae = ActiveEvent._get_collection()
     event_ts = ae.find_one({"timestamp": {"$lte": before}}, limit=1, sort=[("timestamp", 1)])
     event_ts = event_ts["timestamp"]
     print("[%s] Cleaned before %s ... \n" % ("events", before), end="")
     bulk = []
     window = CLEAN_WINDOW
     while event_ts < before:
         refer_event_ids = []
         for e in [aa, ah]:
             for ee in e.find(
                 {"timestamp": {"$gte": event_ts, "$lte": event_ts + CLEAN_WINDOW}},
                 {"opening_event": 1, "closing_event": 1},
             ):
                 if "opening_event" in ee:
                     refer_event_ids += [ee["opening_event"]]
                 if "closing_event" in ee:
                     refer_event_ids += [ee["closing_event"]]
         try:
             clear_qs = {
                 "timestamp": {"$gte": event_ts, "$lte": event_ts + CLEAN_WINDOW},
                 "_id": {"$nin": refer_event_ids},
             }
             self.print(
                 "Interval: %s, %s; Count: %d"
                 % (event_ts, event_ts + CLEAN_WINDOW, ae.count(clear_qs))
             )
             bulk += [DeleteMany(clear_qs)]
             event_ts += window
             if window != CLEAN_WINDOW:
                 window = CLEAN_WINDOW
         except DocumentTooLarge:
             window = window // 2
             if window < datetime.timedelta(hours=1):
                 self.die("Too many events for delete in interval %s" % window)
             event_ts -= window
     if force:
         self.print("All data before %s from active events will be Remove..\n" % before)
         for i in reversed(range(1, 10)):
             self.print("%d\n" % i)
             time.sleep(1)
         ae.bulk_write(bulk)
Пример #12
0
    def handle_ttl_policy(self, ttl=10, dry_run=True, *args, **options):
        from noc.fm.models.activealarm import ActiveAlarm

        today = datetime.datetime.now()
        deadline = today - datetime.timedelta(days=ttl)

        alarm_mos = [
            d["managed_object"] for d in ActiveAlarm._get_collection().find(
                {"managed_object": {
                    "$exists": True
                }}, {"managed_object": 1})
        ]
        # Filter object with Active alarm, and manual links
        deadline_links = Link.objects.filter(last_seen__lt=deadline,
                                             linked_objects__nin=alarm_mos,
                                             discovery_method__ne="")
        self.print(
            "# Links: %d, Deadline links: %d, Manual links: %d, On alarmed objects: %d"
            % (
                Link.objects.count(),
                Link.objects.filter(last_seen__lt=deadline).count(),
                Link.objects.filter(discovery_method="").count(),
                Link.objects.filter(linked_objects__in=alarm_mos).count(),
            ))
        self.print("# %d/%d Links over on deadline: %s" %
                   (deadline_links.count(), Link.objects.count(), deadline))

        if not dry_run:
            self.print("Claimed data will be Loss..\n")
            for i in reversed(range(1, 10)):
                self.print("%d\n" % i)
                time.sleep(1)
            for link in list(deadline_links):
                self.print("Clean %s" % link)
                iface = link.interfaces[0]
                iface.unlink()
            self.print("# Done.")
Пример #13
0
    def get_ajax_data(self, **kwargs):
        def update_dict(d, s):
            for k in s:
                if k in d:
                    d[k] += s[k]
                else:
                    d[k] = s[k]

        zoom = int(self.handler.get_argument("z"))
        west = float(self.handler.get_argument("w"))
        east = float(self.handler.get_argument("e"))
        north = float(self.handler.get_argument("n"))
        south = float(self.handler.get_argument("s"))
        ms = int(self.handler.get_argument("maintenance"))
        active_layers = [
            l_r for l_r in self.get_pop_layers()
            if l_r.min_zoom <= zoom <= l_r.max_zoom
        ]
        alarms = []
        res = {}
        services = {}
        subscribers = {}
        t_data = defaultdict(list)
        mos = ManagedObject.objects.filter(is_managed=True).values(
            "id", "name", "x", "y")
        if not self.current_user.is_superuser:
            mos = mos.filter(administrative_domain__in=UserAccess.get_domains(
                self.current_user))
        for mo in mos:
            res[mo.pop("id")] = mo
        mos_id = list(res.keys())
        if ms == 0:
            mos_id = list(
                set(list(res.keys())) - set(Maintenance.currently_affected()))
        for a in ActiveAlarm._get_collection().find(
            {"managed_object": {
                "$in": mos_id,
                "$exists": True
            }},
            {
                "_id": 1,
                "managed_object": 1,
                "direct_subscribers": 1,
                "direct_services": 1
            },
        ):
            s_sub, s_service = {}, {}
            if a.get("direct_subscribers"):
                s_sub = {
                    dsub["profile"]: dsub["summary"]
                    for dsub in a["direct_subscribers"]
                }
            if a.get("direct_services"):
                s_service = {
                    dserv["profile"]: dserv["summary"]
                    for dserv in a["direct_services"]
                }
            mo = res.get(a["managed_object"])
            if not mo:
                continue
            if mo["x"] and mo["y"]:
                w = ServiceSummary.get_weight({
                    "subscriber": s_sub,
                    "service": s_service
                })
                # @todo: Should we add the object's weight to summary?
                # @todo: Check west/south hemisphere
                if active_layers and west <= mo["x"] <= east and south <= mo[
                        "y"] <= north:
                    t_data[mo["x"], mo["y"]] += [(mo, w)]
            else:
                w = 0
            alarms += [{
                "alarm_id": str(a.get("_id")),
                "managed_object": mo["name"],
                "x": mo["x"],
                "y": mo["y"],
                "w": max(w, 1),
            }]
            if s_service:
                update_dict(services, s_service)
            if s_sub:
                update_dict(subscribers, s_sub)
        links = None
        o_seen = set()
        points = None
        o_data = {}
        if t_data and active_layers:
            # Create lines
            bbox = get_bbox(west, east, north, south)
            lines = []
            for d in ObjectConnection._get_collection().find(
                {
                    "type": "pop_link",
                    "layer": {
                        "$in": [a_l.id for a_l in active_layers]
                    },
                    "line": {
                        "$geoIntersects": {
                            "$geometry": bbox
                        }
                    },
                },
                {
                    "_id": 0,
                    "connection": 1,
                    "line": 1
                },
            ):
                for c in d["line"]["coordinates"]:
                    if tuple(c) in t_data:
                        for c in d["line"]["coordinates"]:
                            tc = tuple(c)
                            o_data[tc] = t_data.get(tc, [])
                        o_seen.add(tuple(c))
                        lines += [d["line"]]
                        break
            if lines:
                links = geojson.FeatureCollection(features=lines)
            # Create points
            points = []
            for x, y in o_data:
                data = {}
                for mo, w in o_data[x, y]:
                    if mo not in data:
                        data[mo] = w
                data = sorted(data, key=lambda z: data[z],
                              reverse=True)[:self.TOOLTIP_LIMIT]
                points += [
                    geojson.Feature(
                        geometry=geojson.Point(coordinates=[x, y]),
                        properties={
                            "alarms":
                            len(t_data[x, y]),
                            "objects": [{
                                "id": mo.id,
                                "name": mo.name,
                                "address": mo.address
                            } for mo in mos],
                        },
                    )
                ]
            points = geojson.FeatureCollection(features=points)
        return {
            "alarms":
            alarms,
            "summary":
            self.f_glyph_summary({
                "service": services,
                "subscriber": subscribers
            }),
            "links":
            links,
            "pops":
            points,
        }
Пример #14
0
def escalate(alarm_id, escalation_id, escalation_delay, *args, **kwargs):
    def log(message, *args):
        msg = message % args
        logger.info("[%s] %s", alarm_id, msg)
        alarm.log_message(msg, to_save=True)

    def summary_to_list(summary, model):
        r = []
        for k in summary:
            p = model.get_by_id(k.profile)
            if not p or getattr(p, "show_in_summary", True) is False:
                continue
            r += [{
                "profile": p.name,
                "summary": k.summary,
                "order": (getattr(p, "display_order", 100), -k.summary),
            }]
        return sorted(r, key=operator.itemgetter("order"))

    logger.info("[%s] Performing escalations", alarm_id)
    alarm = get_alarm(alarm_id)
    if alarm is None:
        logger.info("[%s] Missing alarm, skipping", alarm_id)
        metrics["escalation_missed_alarm"] += 1
        return
    if alarm.status == "C":
        logger.info("[%s] Alarm is closed, skipping", alarm_id)
        metrics["escalation_already_closed"] += 1
        return
    if alarm.root:
        log("[%s] Alarm is not root cause, skipping", alarm_id)
        metrics["escalation_alarm_is_not_root"] += 1
        return
    #
    escalation = AlarmEscalation.get_by_id(escalation_id)
    if not escalation:
        log("Escalation %s is not found, skipping", escalation_id)
        metrics["escalation_not_found"] += 1
        return
    if alarm.managed_object.tt_system:
        sample = alarm.managed_object.tt_system.telemetry_sample
    else:
        sample = PARENT_SAMPLE
    with Span(client="escalator", sample=sample) as ctx:
        alarm.set_escalation_context()
        # Evaluate escalation chain
        mo = alarm.managed_object
        for a in escalation.escalations:
            if a.delay != escalation_delay:
                continue  # Try other type
            # Check administrative domain
            if a.administrative_domain and a.administrative_domain.id not in alarm.adm_path:
                continue
            # Check severity
            if a.min_severity and alarm.severity < a.min_severity:
                continue
            # Check selector
            if a.selector and not SelectorCache.is_in_selector(mo, a.selector):
                continue
            # Check time pattern
            if a.time_pattern and not a.time_pattern.match(alarm.timestamp):
                continue
            # Render escalation message
            if not a.template:
                log("No escalation template, skipping")
                continue
            # Check global limits
            # @todo: Move into escalator service
            # @todo: Process per-ttsystem limits
            ets = datetime.datetime.now() - datetime.timedelta(
                seconds=config.escalator.ets)
            ae = ActiveAlarm._get_collection().count_documents(
                {"escalation_ts": {
                    "$gte": ets
                }})
            ae += ArchivedAlarm._get_collection().count_documents(
                {"escalation_ts": {
                    "$gte": ets
                }})
            if ae >= config.escalator.tt_escalation_limit:
                logger.error(
                    "Escalation limit exceeded (%s/%s). Skipping",
                    ae,
                    config.escalator.tt_escalation_limit,
                )
                metrics["escalation_throttled"] += 1
                alarm.set_escalation_error(
                    "Escalation limit exceeded (%s/%s). Skipping" %
                    (ae, config.escalator.tt_escalation_limit))
                return
            # Check whether consequences has escalations
            cons_escalated = sorted(alarm.iter_escalated(),
                                    key=operator.attrgetter("timestamp"))
            affected_objects = sorted(alarm.iter_affected(),
                                      key=operator.attrgetter("name"))
            #
            segment = alarm.managed_object.segment
            if segment.is_redundant:
                uplinks = alarm.managed_object.data.uplinks
                lost_redundancy = len(uplinks) > 1
                affected_subscribers = summary_to_list(
                    segment.total_subscribers, SubscriberProfile)
                affected_services = summary_to_list(segment.total_services,
                                                    ServiceProfile)
            else:
                lost_redundancy = False
                affected_subscribers = []
                affected_services = []
            #
            ctx = {
                "alarm":
                alarm,
                "affected_objects":
                affected_objects,
                "cons_escalated":
                cons_escalated,
                "total_objects":
                summary_to_list(alarm.total_objects, ManagedObjectProfile),
                "total_subscribers":
                summary_to_list(alarm.total_subscribers, SubscriberProfile),
                "total_services":
                summary_to_list(alarm.total_services, ServiceProfile),
                "tt":
                None,
                "lost_redundancy":
                lost_redundancy,
                "affected_subscribers":
                affected_subscribers,
                "affected_services":
                affected_services,
            }
            # Escalate to TT
            if a.create_tt and mo.can_escalate():
                tt_id = None
                if alarm.escalation_tt:
                    log("Already escalated with TT #%s", alarm.escalation_tt)
                else:
                    pre_reason = escalation.get_pre_reason(mo.tt_system)
                    active_maintenance = Maintenance.get_object_maintenance(mo)
                    if active_maintenance:
                        for m in active_maintenance:
                            log(
                                "Object is under maintenance: %s (%s-%s)",
                                m.subject,
                                m.start,
                                m.stop,
                            )
                        metrics["escalation_stop_on_maintenance"] += 1
                    elif pre_reason is not None:
                        subject = a.template.render_subject(**ctx)
                        body = a.template.render_body(**ctx)
                        logger.debug(
                            "[%s] Escalation message:\nSubject: %s\n%s",
                            alarm_id, subject, body)
                        log("Creating TT in system %s", mo.tt_system.name)
                        tts = mo.tt_system.get_system()
                        try:
                            try:
                                tt_id = tts.create_tt(
                                    queue=mo.tt_queue,
                                    obj=mo.tt_system_id,
                                    reason=pre_reason,
                                    subject=subject,
                                    body=body,
                                    login="******",
                                    timestamp=alarm.timestamp,
                                )
                            except TemporaryTTError as e:
                                metrics["escalation_tt_retry"] += 1
                                log(
                                    "Temporary error detected. Retry after %ss",
                                    RETRY_TIMEOUT)
                                mo.tt_system.register_failure()
                                Job.retry_after(get_next_retry(), str(e))
                            ctx["tt"] = "%s:%s" % (mo.tt_system.name, tt_id)
                            alarm.escalate(
                                ctx["tt"],
                                close_tt=a.close_tt,
                                wait_tt=ctx["tt"] if a.wait_tt else None,
                            )
                            if tts.promote_group_tt and a.promote_group_tt:
                                # Create group TT
                                log("Promoting to group tt")
                                gtt = tts.create_group_tt(
                                    tt_id, alarm.timestamp)
                                # Append affected objects
                                for ao in alarm.iter_affected():
                                    if ao.can_escalate(True):
                                        if ao.tt_system == mo.tt_system:
                                            log(
                                                "Appending object %s to group tt %s",
                                                ao.name, gtt)
                                            try:
                                                tts.add_to_group_tt(
                                                    gtt, ao.tt_system_id)
                                            except TTError as e:
                                                alarm.set_escalation_error(
                                                    "[%s] %s" %
                                                    (mo.tt_system.name, e))
                                        else:
                                            log(
                                                "Cannot append object %s to group tt %s: Belongs to other TT system",
                                                ao.name,
                                                gtt,
                                            )
                                    else:
                                        log(
                                            "Cannot append object %s to group tt %s: Escalations are disabled",
                                            ao.name,
                                            gtt,
                                        )
                            metrics["escalation_tt_create"] += 1
                        except TTError as e:
                            log("Failed to create TT: %s", e)
                            metrics["escalation_tt_fail"] += 1
                            alarm.log_message("Failed to escalate: %s" % e,
                                              to_save=True)
                            alarm.set_escalation_error("[%s] %s" %
                                                       (mo.tt_system.name, e))
                    else:
                        log("Cannot find pre reason")
                        metrics["escalation_tt_fail"] += 1
                if tt_id and cons_escalated:
                    # Notify consequences
                    for ca in cons_escalated:
                        c_tt_name, c_tt_id = ca.escalation_tt.split(":")
                        cts = TTSystem.get_by_name(c_tt_name)
                        if cts:
                            tts = cts.get_system()
                            try:
                                log("Appending comment to TT %s", tt_id)
                                tts.add_comment(c_tt_id,
                                                body="Covered by TT %s" %
                                                tt_id,
                                                login="******")
                                metrics["escalation_tt_comment"] += 1
                            except NotImplementedError:
                                log(
                                    "Cannot add comment to %s: Feature not implemented",
                                    ca.escalation_tt,
                                )
                                metrics["escalation_tt_comment_fail"] += 1
                            except TTError as e:
                                log("Failed to add comment to %s: %s",
                                    ca.escalation_tt, e)
                                metrics["escalation_tt_comment_fail"] += 1
                        else:
                            log(
                                "Failed to add comment to %s: Invalid TT system",
                                ca.escalation_tt)
                            metrics["escalation_tt_comment_fail"] += 1
            # Send notification
            if a.notification_group and mo.can_notify():
                subject = a.template.render_subject(**ctx)
                body = a.template.render_body(**ctx)
                logger.debug("[%s] Notification message:\nSubject: %s\n%s",
                             alarm_id, subject, body)
                log("Sending notification to group %s",
                    a.notification_group.name)
                a.notification_group.notify(subject, body)
                alarm.set_clear_notification(a.notification_group,
                                             a.clear_template)
                metrics["escalation_notify"] += 1
            #
            if a.stop_processing:
                logger.debug("Stopping processing")
                break
        nalarm = get_alarm(alarm_id)
        if nalarm and nalarm.status == "C":
            nalarm.log_message(
                "Alarm has been closed during escalation. Try to deescalate")
            logger.info(
                "[%s] Alarm has been closed during escalation. Try to deescalate",
                alarm.id)
            metrics["escalation_closed_while_escalated"] += 1
            if tt_id and not nalarm.escalation_tt:
                nalarm.escalation_ts = datetime.datetime.now()
                nalarm.escalation_tt = "%s:%s" % (mo.tt_system.name, tt_id)
                nalarm.save()
            if not nalarm.escalation_close_ts and not nalarm.escalation_close_error:
                notify_close(
                    alarm_id=alarm_id,
                    tt_id=nalarm.escalation_tt,
                    subject="Closing",
                    body="Closing",
                    notification_group_id=alarm.clear_notification_group.id
                    if alarm.clear_notification_group else None,
                    close_tt=alarm.close_tt,
                )
        elif nalarm == "A" and not nalarm.escalation_tt and tt_id:
            logger.error("[%s] Alarm without escalation TT: %s", alarm.id,
                         tt_id)
        logger.info("[%s] Escalations loop end", alarm_id)
Пример #15
0
    def update_umbrella(self, umbrella_cls, details):
        """
        Update umbrella alarm status for managed object

        :param umbrella_cls: Umbrella alarm class (AlarmClass instance)
        :param details: List of dicts, containing
            * alarm_class - Detail alarm class
            * path - Additional path
            * severity - Alarm severity
            * vars - dict of alarm vars
        :return:
        """
        from noc.fm.models.activealarm import ActiveAlarm

        now = datetime.datetime.now()
        umbrella = ActiveAlarm.objects.filter(
            alarm_class=umbrella_cls.id,
            managed_object=self.object.id).first()
        u_sev = sum(d.get("severity", 0) for d in details)
        if not umbrella and not details:
            # No money, no honey
            return
        elif not umbrella and details:
            # Open new umbrella
            umbrella = ActiveAlarm(timestamp=now,
                                   managed_object=self.object.id,
                                   alarm_class=umbrella_cls.id,
                                   severity=u_sev)
            umbrella.save()
            self.logger.info("Opening umbrella alarm %s (%s)", umbrella.id,
                             umbrella_cls.name)
        elif umbrella and not details:
            # Close existing umbrella
            self.logger.info("Clearing umbrella alarm %s (%s)", umbrella.id,
                             umbrella_cls.name)
            umbrella.clear_alarm("Closing umbrella")
        elif umbrella and details and u_sev != umbrella.severity:
            self.logger.info("Change umbrella alarm %s severity %s -> %s (%s)",
                             umbrella.id, umbrella.severity, u_sev,
                             umbrella_cls.name)
            umbrella.change_severity(severity=u_sev)
        # Get existing details for umbrella
        active_details = {}  # (alarm class, path) -> alarm
        if umbrella:
            for da in ActiveAlarm.objects.filter(root=umbrella.id):
                d_path = da.vars.get("path", "")
                active_details[da.alarm_class, d_path] = da
        # Synchronize details
        self.logger.info("Active details: %s" % active_details)
        seen = set()
        for d in details:
            d_path = d.get("path", "")
            d_key = (d["alarm_class"], d_path)
            d_sev = d.get("severity", 0)
            # Key for seen details
            seen.add(d_key)
            if d_key in active_details and active_details[
                    d_key].severity != d_sev:
                # Change severity
                self.logger.info("Change detail alarm %s severity %s -> %s",
                                 active_details[d_key].id,
                                 active_details[d_key].severity, d_sev)
                active_details[d_key].change_severity(severity=d_sev)
            elif d_key not in active_details:
                # Create alarm
                self.logger.info("Create detail alarm to path %s", d_key)
                v = d.get("vars", {})
                v["path"] = d_path
                da = ActiveAlarm(timestamp=now,
                                 managed_object=self.object.id,
                                 alarm_class=d["alarm_class"],
                                 severity=d_sev,
                                 vars=v,
                                 root=umbrella.id)
                da.save()
                self.logger.info("Opening detail alarm %s %s (%s)", da.id,
                                 d_path, da.alarm_class.name)
        # Close details when necessary
        for d in set(active_details) - seen:
            self.logger.info("Clearing detail alarm %s", active_details[d].id)
            active_details[d].clear_alarm("Closing")
Пример #16
0
    def api_report(
        self,
        request,
        from_date,
        to_date,
        o_format,
        administrative_domain=None,
        columns=None,
        source="both",
        alarm_class=None,
        enable_autowidth=False,
    ):
        def row(row):
            def qe(v):
                if v is None:
                    return ""
                if isinstance(v, str):
                    return smart_text(v)
                elif isinstance(v, datetime.datetime):
                    return v.strftime("%Y-%m-%d %H:%M:%S")
                elif not isinstance(v, str):
                    return smart_text(v)
                else:
                    return v

            return [qe(x) for x in row]

        def translate_row(row, cmap):
            return [row[i] for i in cmap]

        cols = [
            "id",
            "alarm_class",
            "alarm_from_ts",
            "alarm_to_ts",
            "alarm_tt",
            "object_name",
            "object_address",
            "object_admdomain",
            "log_timestamp",
            "log_source",
            "log_message",
            # "tt",
            # "escalation_ts",
        ]

        header_row = [
            "ID",
            _("ALARM_CLASS"),
            _("ALARM_FROM_TS"),
            _("ALARM_TO_TS"),
            _("ALARM_TT"),
            _("OBJECT_NAME"),
            _("OBJECT_ADDRESS"),
            _("OBJECT_ADMDOMAIN"),
            _("LOG_TIMESTAMP"),
            _("LOG_SOURCE"),
            _("LOG_MESSAGE"),
        ]

        if columns:
            cmap = []
            for c in columns.split(","):
                try:
                    cmap += [cols.index(c)]
                except ValueError:
                    continue
        else:
            cmap = list(range(len(cols)))

        r = [translate_row(header_row, cmap)]
        fd = datetime.datetime.strptime(
            to_date, "%d.%m.%Y") + datetime.timedelta(days=1)
        match = {
            "timestamp": {
                "$gte": datetime.datetime.strptime(from_date, "%d.%m.%Y"),
                "$lte": fd
            }
        }
        mos = ManagedObject.objects.filter()

        ads = []
        if administrative_domain:
            if administrative_domain.isdigit():
                administrative_domain = [int(administrative_domain)]
                ads = AdministrativeDomain.get_nested_ids(
                    administrative_domain[0])

        if not request.user.is_superuser:
            user_ads = UserAccess.get_domains(request.user)
            if administrative_domain and ads:
                if administrative_domain[0] not in user_ads:
                    ads = list(set(ads) & set(user_ads))
                    if not ads:
                        return HttpResponse(
                            "<html><body>Permission denied: Invalid Administrative Domain</html></body>"
                        )
            else:
                ads = user_ads
        if ads:
            mos = mos.filter(administrative_domain__in=ads)

        # Working if Administrative domain set
        if ads:
            try:
                match["adm_path"] = {"$in": ads}
                # @todo More 2 level hierarhy
            except bson.errors.InvalidId:
                pass

        addr_map = {
            mo[0]: (mo[1], mo[2])
            for mo in mos.values_list("id", "name", "address")
        }

        # Active Alarms
        coll = ActiveAlarm._get_collection()
        for aa in coll.aggregate([
            {
                "$match": match
            },
            {
                "$unwind": "$log"
            },
            {
                "$match": {
                    "log.source": {
                        "$exists": True,
                        "$ne": None
                    }
                }
            },
            {
                "$project": {
                    "timestamp": 1,
                    "managed_object": 1,
                    "alarm_class": 1,
                    "escalation_tt": 1,
                    "adm_path": 1,
                    "log": 1,
                }
            },
            {
                "$sort": {
                    "_id": 1,
                    "log.timestamp": 1
                }
            },
        ]):
            r += [
                translate_row(
                    row([
                        smart_text(aa["_id"]),
                        AlarmClass.get_by_id(aa["alarm_class"]).name,
                        aa["timestamp"],
                        "",
                        aa.get("escalation_tt", ""),
                        addr_map[aa["managed_object"]][0],
                        addr_map[aa["managed_object"]][1],
                        AdministrativeDomain.get_by_id(
                            aa["adm_path"][-1]).name,
                        aa["log"]["timestamp"],
                        aa["log"]["source"],
                        aa["log"]["message"],
                    ]),
                    cmap,
                )
            ]
        # Active Alarms
        coll = ArchivedAlarm._get_collection()
        for aa in coll.aggregate([
            {
                "$match": match
            },
            {
                "$unwind": "$log"
            },
            {
                "$match": {
                    "log.source": {
                        "$exists": True
                    }
                }
            },
            {
                "$project": {
                    "timestamp": 1,
                    "clear_timestamp": 1,
                    "managed_object": 1,
                    "alarm_class": 1,
                    "escalation_tt": 1,
                    "adm_path": 1,
                    "log": 1,
                }
            },
            {
                "$sort": {
                    "_id": 1,
                    "log.timestamp": 1
                }
            },
        ]):
            r += [
                translate_row(
                    row([
                        smart_text(aa["_id"]),
                        AlarmClass.get_by_id(aa["alarm_class"]).name,
                        aa["timestamp"],
                        aa["clear_timestamp"],
                        aa.get("escalation_tt", ""),
                        addr_map[aa["managed_object"]][0],
                        addr_map[aa["managed_object"]][1],
                        AdministrativeDomain.get_by_id(
                            aa["adm_path"][-1]).name,
                        aa["log"]["timestamp"],
                        aa["log"]["source"],
                        aa["log"]["message"],
                    ]),
                    cmap,
                )
            ]
        filename = "alarm_comments.csv"
        if o_format == "csv":
            response = HttpResponse(content_type="text/csv")
            response[
                "Content-Disposition"] = 'attachment; filename="%s"' % filename
            writer = csv.writer(response)
            writer.writerows(r)
            return response
        elif o_format == "csv_zip":
            response = BytesIO()
            f = TextIOWrapper(TemporaryFile(mode="w+b"), encoding="utf-8")
            writer = csv.writer(f,
                                dialect="excel",
                                delimiter=";",
                                quotechar='"')
            writer.writerow(columns)
            writer.writerows(r)
            f.seek(0)
            with ZipFile(response, "w", compression=ZIP_DEFLATED) as zf:
                zf.writestr(filename, f.read())
                zf.filename = "%s.zip" % filename
            # response = HttpResponse(content_type="text/csv")
            response.seek(0)
            response = HttpResponse(response.getvalue(),
                                    content_type="application/zip")
            response[
                "Content-Disposition"] = 'attachment; filename="%s.zip"' % filename
            return response
        elif o_format == "xlsx":
            response = BytesIO()
            wb = xlsxwriter.Workbook(response)
            cf1 = wb.add_format({"bottom": 1, "left": 1, "right": 1, "top": 1})
            ws = wb.add_worksheet("Alarms")
            max_column_data_length = {}
            for rn, x in enumerate(r):
                for cn, c in enumerate(x):
                    if rn and (r[0][cn] not in max_column_data_length or
                               len(str(c)) > max_column_data_length[r[0][cn]]):
                        max_column_data_length[r[0][cn]] = len(str(c))
                    ws.write(rn, cn, c, cf1)
            ws.autofilter(0, 0, rn, cn)
            ws.freeze_panes(1, 0)
            for cn, c in enumerate(r[0]):
                # Set column width
                width = get_column_width(c)
                if enable_autowidth and width < max_column_data_length[c]:
                    width = max_column_data_length[c]
                ws.set_column(cn, cn, width=width)
            wb.close()
            response.seek(0)
            response = HttpResponse(response.getvalue(),
                                    content_type="application/vnd.ms-excel")
            response[
                "Content-Disposition"] = 'attachment; filename="alarm_comments.xlsx"'
            response.close()
            return response
Пример #17
0
    def api_report(
        self,
        request,
        from_date,
        to_date,
        o_format,
        min_duration=0,
        max_duration=0,
        min_objects=0,
        min_subscribers=0,
        segment=None,
        administrative_domain=None,
        selector=None,
        ex_selector=None,
        columns=None,
        source="both",
        alarm_class=None,
        subscribers=None,
        enable_autowidth=False,
    ):
        def row(row, container_path, segment_path):
            def qe(v):
                if v is None:
                    return ""
                if isinstance(v, unicode):
                    return v.encode("utf-8")
                elif isinstance(v, datetime.datetime):
                    return v.strftime("%Y-%m-%d %H:%M:%S")
                elif not isinstance(v, str):
                    return str(v)
                else:
                    return v

            r = [qe(x) for x in row]
            if len(container_path) < self.CONTAINER_PATH_DEPTH:
                container_path += [""] * (self.CONTAINER_PATH_DEPTH -
                                          len(container_path))
            else:
                container_path = container_path[:self.CONTAINER_PATH_DEPTH]
            if len(segment_path) < self.SEGMENT_PATH_DEPTH:
                segment_path += [""] * (self.SEGMENT_PATH_DEPTH -
                                        len(segment_path))
            else:
                segment_path = segment_path[:self.SEGMENT_PATH_DEPTH]
            return r + container_path + segment_path

        def translate_row(row, cmap):
            return [row[i] for i in cmap]

        cols = ([
            "id",
            "root_id",
            "from_ts",
            "to_ts",
            "duration_sec",
            "object_name",
            "object_address",
            "object_hostname",
            "object_profile",
            "object_admdomain",
            "object_platform",
            "object_version",
            "alarm_class",
            "alarm_subject",
            "maintenance",
            "objects",
            "subscribers",
            "tt",
            "escalation_ts",
            "location",
            "container_address",
        ] + ["container_%d" % i for i in range(self.CONTAINER_PATH_DEPTH)] +
                ["segment_%d" % i for i in range(self.SEGMENT_PATH_DEPTH)])

        header_row = (
            [
                "ID",
                _("ROOT_ID"),
                _("FROM_TS"),
                _("TO_TS"),
                _("DURATION_SEC"),
                _("OBJECT_NAME"),
                _("OBJECT_ADDRESS"),
                _("OBJECT_HOSTNAME"),
                _("OBJECT_PROFILE"),
                _("OBJECT_ADMDOMAIN"),
                _("OBJECT_PLATFORM"),
                _("OBJECT_VERSION"),
                _("ALARM_CLASS"),
                _("ALARM_SUBJECT"),
                _("MAINTENANCE"),
                _("OBJECTS"),
                _("SUBSCRIBERS"),
                _("TT"),
                _("ESCALATION_TS"),
                _("LOCATION"),
                _("CONTAINER_ADDRESS"),
            ] + ["CONTAINER_%d" % i
                 for i in range(self.CONTAINER_PATH_DEPTH)] +
            ["SEGMENT_%d" % i for i in range(self.SEGMENT_PATH_DEPTH)])

        if columns:
            cmap = []
            for c in columns.split(","):
                try:
                    cmap += [cols.index(c)]
                except ValueError:
                    continue
        else:
            cmap = list(range(len(cols)))
        subscribers_profile = self.default_subscribers_profile
        if subscribers:
            subscribers_profile = set(
                SubscriberProfile.objects.filter(
                    id__in=subscribers.split(",")).scalar("id"))
        r = [translate_row(header_row, cmap)]
        fd = datetime.datetime.strptime(
            to_date, "%d.%m.%Y") + datetime.timedelta(days=1)
        match = {
            "timestamp": {
                "$gte": datetime.datetime.strptime(from_date, "%d.%m.%Y"),
                "$lte": fd
            }
        }

        match_duration = {"duration": {"$gte": min_duration}}
        if max_duration:
            match_duration = {
                "duration": {
                    "$gte": min_duration,
                    "$lte": max_duration
                }
            }
        mos = ManagedObject.objects.filter(is_managed=True)

        if segment:
            try:
                match["segment_path"] = bson.ObjectId(segment)
            except bson.errors.InvalidId:
                pass

        ads = []
        if administrative_domain:
            if administrative_domain.isdigit():
                administrative_domain = [int(administrative_domain)]
                ads = AdministrativeDomain.get_nested_ids(
                    administrative_domain[0])

        if not request.user.is_superuser:
            user_ads = UserAccess.get_domains(request.user)
            if administrative_domain and ads:
                if administrative_domain[0] not in user_ads:
                    ads = list(set(ads) & set(user_ads))
                else:
                    ads = administrative_domain
            else:
                ads = user_ads
        if ads:
            mos = mos.filter(administrative_domain__in=ads)
        if selector:
            selector = ManagedObjectSelector.get_by_id(int(selector))
            mos = mos.filter(selector.Q)
        if ex_selector:
            ex_selector = ManagedObjectSelector.get_by_id(int(ex_selector))
            mos = mos.exclude(ex_selector.Q)

        # Working if Administrative domain set
        if ads:
            try:
                match["adm_path"] = {"$in": ads}
                # @todo More 2 level hierarhy
            except bson.errors.InvalidId:
                pass

        mos_id = list(mos.order_by("id").values_list("id", flat=True))
        mo_hostname = {}
        maintenance = []
        if mos_id and (selector or ex_selector):
            match["managed_object"] = {"$in": mos_id}
        if "maintenance" in columns.split(","):
            maintenance = Maintenance.currently_affected()
        if "object_hostname" in columns.split(","):
            mo_hostname = ReportObjectsHostname1(sync_ids=mos_id)
            mo_hostname = mo_hostname.get_dictionary()
        moss = ReportAlarmObjects(mos_id).get_all()
        # container_lookup = ReportContainer(mos_id)
        container_lookup = None
        subject = "alarm_subject" in columns
        loc = AlarmApplication([])
        if source in ["archive", "both"]:
            # Archived Alarms
            for a in (ArchivedAlarm._get_collection().with_options(
                    read_preference=ReadPreference.SECONDARY_PREFERRED
            ).aggregate([
                {
                    "$match": match
                },
                {
                    "$addFields": {
                        "duration": {
                            "$divide": [
                                {
                                    "$subtract":
                                    ["$clear_timestamp", "$timestamp"]
                                },
                                1000,
                            ]
                        }
                    }
                },
                {
                    "$match": match_duration
                },
                    # {"$sort": {"timestamp": 1}}
            ])):
                if int(a["managed_object"]) not in moss:
                    continue
                dt = a["clear_timestamp"] - a["timestamp"]
                duration = int(dt.total_seconds())
                total_objects = sum(ss["summary"] for ss in a["total_objects"])
                if min_objects and total_objects < min_objects:
                    continue
                total_subscribers = sum(
                    ss["summary"] for ss in a["total_subscribers"]
                    if subscribers_profile
                    and ss["profile"] in subscribers_profile)
                if min_subscribers and total_subscribers < min_subscribers:
                    continue
                if "segment_" in columns.split(
                        ",") or "container_" in columns.split(","):
                    path = ObjectPath.get_path(a["managed_object"])
                    if path:
                        segment_path = [
                            NetworkSegment.get_by_id(s).name
                            for s in path.segment_path
                            if NetworkSegment.get_by_id(s)
                        ]
                        container_path = [
                            Object.get_by_id(s).name
                            for s in path.container_path if Object.get_by_id(s)
                        ]
                    else:
                        segment_path = []
                        container_path = []
                else:
                    segment_path = []
                    container_path = []
                r += [
                    translate_row(
                        row(
                            [
                                str(a["_id"]),
                                str(a["root"]) if a.get("root") else "",
                                a["timestamp"],
                                a["clear_timestamp"],
                                str(duration),
                                moss[a["managed_object"]][0],
                                moss[a["managed_object"]][1],
                                mo_hostname.get(a["managed_object"], ""),
                                Profile.get_by_id(
                                    moss[a["managed_object"]][3]).name
                                if moss[a["managed_object"]][5] else "",
                                moss[a["managed_object"]][6],
                                Platform.get_by_id(
                                    moss[a["managed_object"]][9])
                                if moss[a["managed_object"]][9] else "",
                                Firmware.get_by_id(
                                    moss[a["managed_object"]][10])
                                if moss[a["managed_object"]][10] else "",
                                AlarmClass.get_by_id(a["alarm_class"]).name,
                                ArchivedAlarm.objects.get(
                                    id=a["_id"]).subject if subject else "",
                                "",
                                total_objects,
                                total_subscribers,
                                a.get("escalation_tt"),
                                a.get("escalation_ts"),
                                ", ".join(l for l in (
                                    loc.location(moss[a["managed_object"]][5]
                                                 ) if moss[a["managed_object"]]
                                    [5] is not None else "") if l),
                                container_lookup[a["managed_object"]].get(
                                    "text", "") if container_lookup else "",
                            ],
                            container_path,
                            segment_path,
                        ),
                        cmap,
                    )
                ]
        # Active Alarms
        if source in ["active", "both"]:
            for a in (ActiveAlarm._get_collection().with_options(
                    read_preference=ReadPreference.SECONDARY_PREFERRED).
                      aggregate([
                          {
                              "$match": match
                          },
                          {
                              "$addFields": {
                                  "duration": {
                                      "$divide": [{
                                          "$subtract": [fd, "$timestamp"]
                                      }, 1000]
                                  }
                              }
                          },
                          {
                              "$match": match_duration
                          },
                          # {"$sort": {"timestamp": 1}}
                      ])):
                dt = fd - a["timestamp"]
                duration = int(dt.total_seconds())
                total_objects = sum(ss["summary"] for ss in a["total_objects"])
                if min_objects and total_objects < min_objects:
                    continue
                total_subscribers = sum(
                    ss["summary"] for ss in a["total_subscribers"]
                    if subscribers_profile
                    and ss["profile"] in subscribers_profile)
                if min_subscribers and total_subscribers < min_subscribers:
                    continue
                if "segment_" in columns.split(
                        ",") or "container_" in columns.split(","):
                    path = ObjectPath.get_path(a["managed_object"])
                    if path:
                        segment_path = [
                            NetworkSegment.get_by_id(s).name
                            for s in path.segment_path
                            if NetworkSegment.get_by_id(s)
                        ]
                        container_path = [
                            Object.get_by_id(s).name
                            for s in path.container_path if Object.get_by_id(s)
                        ]
                    else:
                        segment_path = []
                        container_path = []
                else:
                    segment_path = []
                    container_path = []
                r += [
                    translate_row(
                        row(
                            [
                                str(a["_id"]),
                                str(a["root"]) if a.get("root") else "",
                                a["timestamp"],
                                # a["clear_timestamp"],
                                "",
                                str(duration),
                                moss[a["managed_object"]][0],
                                moss[a["managed_object"]][1],
                                mo_hostname.get(a["managed_object"], ""),
                                Profile.get_by_id(moss[a["managed_object"]][3])
                                if moss[a["managed_object"]][5] else "",
                                moss[a["managed_object"]][6],
                                Platform.get_by_id(
                                    moss[a["managed_object"]][9])
                                if moss[a["managed_object"]][9] else "",
                                Firmware.get_by_id(
                                    moss[a["managed_object"]][10])
                                if moss[a["managed_object"]][10] else "",
                                AlarmClass.get_by_id(a["alarm_class"]).name,
                                ActiveAlarm.objects.get(
                                    id=a["_id"]).subject if subject else None,
                                "Yes" if a["managed_object"] in maintenance
                                else "No",
                                total_objects,
                                total_subscribers,
                                a.get("escalation_tt"),
                                a.get("escalation_ts"),
                                ", ".join(l for l in (
                                    loc.location(moss[a["managed_object"]][5]
                                                 ) if moss[a["managed_object"]]
                                    [5] is not None else "") if l),
                                container_lookup[a["managed_object"]].get(
                                    "text", "") if container_lookup else "",
                            ],
                            container_path,
                            segment_path,
                        ),
                        cmap,
                    )
                ]

        if o_format == "csv":
            response = HttpResponse(content_type="text/csv")
            response[
                "Content-Disposition"] = 'attachment; filename="alarms.csv"'
            writer = csv.writer(response)
            writer.writerows(r)
            return response
        elif o_format == "xlsx":
            response = StringIO()
            wb = xlsxwriter.Workbook(response)
            cf1 = wb.add_format({"bottom": 1, "left": 1, "right": 1, "top": 1})
            ws = wb.add_worksheet("Alarms")
            max_column_data_length = {}
            for rn, x in enumerate(r):
                for cn, c in enumerate(x):
                    if rn and (r[0][cn] not in max_column_data_length or
                               len(str(c)) > max_column_data_length[r[0][cn]]):
                        max_column_data_length[r[0][cn]] = len(str(c))
                    ws.write(rn, cn, c, cf1)
            ws.autofilter(0, 0, rn, cn)
            ws.freeze_panes(1, 0)
            for cn, c in enumerate(r[0]):
                # Set column width
                width = get_column_width(c)
                if enable_autowidth and width < max_column_data_length[c]:
                    width = max_column_data_length[c]
                ws.set_column(cn, cn, width=width)
            wb.close()
            response.seek(0)
            response = HttpResponse(response.getvalue(),
                                    content_type="application/vnd.ms-excel")
            response[
                "Content-Disposition"] = 'attachment; filename="alarms.xlsx"'
            response.close()
            return response
Пример #18
0
 def raise_alarm(self, r, e):
     managed_object = self.eval_expression(r.managed_object, event=e)
     if not managed_object:
         self.logger.info("Empty managed object, ignoring")
         return
     # @todo: Make configurable
     if not managed_object.is_managed:
         self.logger.info(
             "Managed object is not managed. Do not raise alarm")
         return
     if e.managed_object.id != managed_object.id:
         metrics["alarm_change_mo"] += 1
         self.logger.info("Changing managed object to %s",
                          managed_object.name)
     discriminator, vars = r.get_vars(e)
     if r.unique:
         assert discriminator is not None
         a = ActiveAlarm.objects.filter(
             managed_object=managed_object.id,
             discriminator=discriminator).first()
         if not a:
             # Try to reopen alarm
             a = ArchivedAlarm.objects.filter(
                 managed_object=managed_object.id,
                 discriminator=discriminator,
                 control_time__gte=e.timestamp).first()
             if a:
                 # Reopen alarm
                 self.logger.info("[%s|%s|%s] %s reopens alarm %s(%s)",
                                  e.id, managed_object.name,
                                  managed_object.address,
                                  e.event_class.name, a.alarm_class.name,
                                  a.id)
                 a = a.reopen("Reopened by disposition rule '%s'" %
                              r.u_name)
                 metrics["alarm_reopen"] += 1
         if a:
             # Active alarm found, refresh
             self.logger.info(
                 "[%s|%s|%s] Contributing event %s to active alarm %s(%s)",
                 e.id, managed_object.name, managed_object.address,
                 e.event_class.name, a.alarm_class.name, a.id)
             # Contribute event to alarm
             e.contribute_to_alarm(a)
             if e.timestamp < a.timestamp:
                 # Set to earlier date
                 a.timestamp = e.timestamp
                 a.save()
             elif e.timestamp > a.last_update:
                 # Refresh last update
                 a.last_update = e.timestamp
                 a.save()
             metrics["alarm_contribute"] += 1
             return
     # Calculate alarm coverage
     summary = ServiceSummary.get_object_summary(managed_object)
     summary["object"] = {managed_object.object_profile.id: 1}
     #
     severity = max(ServiceSummary.get_severity(summary), 1)
     self.logger.info("[%s|%s|%s] %s: Calculated alarm severity is: %s",
                      e.id, managed_object.name, managed_object.address,
                      r.u_name, severity)
     # Create new alarm
     a = ActiveAlarm(
         timestamp=e.timestamp,
         last_update=e.timestamp,
         managed_object=managed_object.id,
         alarm_class=r.alarm_class,
         severity=severity,
         vars=vars,
         discriminator=discriminator,
         direct_services=SummaryItem.dict_to_items(summary["service"]),
         direct_subscribers=SummaryItem.dict_to_items(
             summary["subscriber"]),
         total_objects=ObjectSummaryItem.dict_to_items(summary["object"]),
         total_services=SummaryItem.dict_to_items(summary["service"]),
         total_subscribers=SummaryItem.dict_to_items(summary["subscriber"]),
         log=[
             AlarmLog(timestamp=datetime.datetime.now(),
                      from_status="A",
                      to_status="A",
                      message="Alarm risen from event %s(%s) by rule '%s'" %
                      (str(e.id), str(e.event_class.name), r.u_name))
         ],
         opening_event=e.id)
     a.save()
     e.contribute_to_alarm(a)
     self.logger.info("[%s|%s|%s] %s raises alarm %s(%s): %r", e.id,
                      managed_object.name, managed_object.address,
                      e.event_class.name, a.alarm_class.name, a.id, a.vars)
     metrics["alarm_raise"] += 1
     self.correlate(r, a)
     # Notify about new alarm
     if not a.root:
         a.managed_object.event(
             a.managed_object.EV_ALARM_RISEN, {
                 "alarm": a,
                 "subject": a.subject,
                 "body": a.body,
                 "symptoms": a.alarm_class.symptoms,
                 "recommended_actions": a.alarm_class.recommended_actions,
                 "probable_causes": a.alarm_class.probable_causes
             },
             delay=a.alarm_class.get_notification_delay())
     # Gather diagnostics when necessary
     AlarmDiagnosticConfig.on_raise(a)
     # Watch for escalations, when necessary
     if config.correlator.auto_escalation and not a.root:
         AlarmEscalation.watch_escalations(a)
Пример #19
0
from noc.fm.models.activealarm import ActiveAlarm
from noc.fm.models.activeevent import ActiveEvent
from noc.fm.models.archivedalarm import ArchivedAlarm
from datetime import *

alarms = ActiveAlarm.objects()
events = ActiveEvent.objects()
ar_alarms = ArchivedAlarm.objects()

for alarm in alarms:
    alarm.delete()

for alarm in ar_alarms:
    alarm.delete()

for event in events:
    event.delete()
Пример #20
0
    def api_report(
        self,
        request,
        from_date,
        to_date,
        o_format,
        min_duration=0,
        max_duration=0,
        min_objects=0,
        min_subscribers=0,
        segment=None,
        administrative_domain=None,
        selector=None,
        ex_selector=None,
        columns=None,
        source="both",
        alarm_class=None,
        subscribers=None,
        enable_autowidth=False,
    ):
        def row(row, container_path, segment_path):
            def qe(v):
                if v is None:
                    return ""
                if isinstance(v, str):
                    return smart_text(v)
                elif isinstance(v, datetime.datetime):
                    return v.strftime("%Y-%m-%d %H:%M:%S")
                elif not isinstance(v, str):
                    return smart_text(v)
                else:
                    return v

            r = [qe(x) for x in row]
            if len(container_path) < self.CONTAINER_PATH_DEPTH:
                container_path += [""] * (self.CONTAINER_PATH_DEPTH -
                                          len(container_path))
            else:
                container_path = container_path[:self.CONTAINER_PATH_DEPTH]
            if len(segment_path) < self.SEGMENT_PATH_DEPTH:
                segment_path += [""] * (self.SEGMENT_PATH_DEPTH -
                                        len(segment_path))
            else:
                segment_path = segment_path[:self.SEGMENT_PATH_DEPTH]
            return r + container_path + segment_path

        def translate_row(row, cmap):
            return [row[i] for i in cmap]

        cols = ([
            "id",
            "root_id",
            "from_ts",
            "to_ts",
            "duration_sec",
            "object_name",
            "object_address",
            "object_hostname",
            "object_profile",
            "object_admdomain",
            "object_platform",
            "object_version",
            "alarm_class",
            "alarm_subject",
            "maintenance",
            "objects",
            "subscribers",
            "tt",
            "escalation_ts",
            "location",
            "container_address",
        ] + ["container_%d" % i for i in range(self.CONTAINER_PATH_DEPTH)] +
                ["segment_%d" % i for i in range(self.SEGMENT_PATH_DEPTH)])

        header_row = (
            [
                "ID",
                _("ROOT_ID"),
                _("FROM_TS"),
                _("TO_TS"),
                _("DURATION_SEC"),
                _("OBJECT_NAME"),
                _("OBJECT_ADDRESS"),
                _("OBJECT_HOSTNAME"),
                _("OBJECT_PROFILE"),
                _("OBJECT_ADMDOMAIN"),
                _("OBJECT_PLATFORM"),
                _("OBJECT_VERSION"),
                _("ALARM_CLASS"),
                _("ALARM_SUBJECT"),
                _("MAINTENANCE"),
                _("OBJECTS"),
                _("SUBSCRIBERS"),
                _("TT"),
                _("ESCALATION_TS"),
                _("LOCATION"),
                _("CONTAINER_ADDRESS"),
            ] + ["CONTAINER_%d" % i
                 for i in range(self.CONTAINER_PATH_DEPTH)] +
            ["SEGMENT_%d" % i for i in range(self.SEGMENT_PATH_DEPTH)])

        if columns:
            cmap = []
            for c in columns.split(","):
                try:
                    cmap += [cols.index(c)]
                except ValueError:
                    continue
        else:
            cmap = list(range(len(cols)))
        subscribers_profile = self.default_subscribers_profile
        if subscribers:
            subscribers_profile = set(
                SubscriberProfile.objects.filter(
                    id__in=subscribers.split(",")).scalar("id"))
        r = [translate_row(header_row, cmap)]
        fd = datetime.datetime.strptime(
            to_date, "%d.%m.%Y") + datetime.timedelta(days=1)
        match = {
            "timestamp": {
                "$gte": datetime.datetime.strptime(from_date, "%d.%m.%Y"),
                "$lte": fd
            }
        }

        match_duration = {"duration": {"$gte": min_duration}}
        if max_duration:
            match_duration = {
                "duration": {
                    "$gte": min_duration,
                    "$lte": max_duration
                }
            }
        mos = ManagedObject.objects.filter(is_managed=True)

        if segment:
            try:
                match["segment_path"] = bson.ObjectId(segment)
            except bson.errors.InvalidId:
                pass

        ads = []
        if administrative_domain:
            if administrative_domain.isdigit():
                administrative_domain = [int(administrative_domain)]
                ads = AdministrativeDomain.get_nested_ids(
                    administrative_domain[0])

        if not request.user.is_superuser:
            user_ads = UserAccess.get_domains(request.user)
            if administrative_domain and ads:
                if administrative_domain[0] not in user_ads:
                    ads = list(set(ads) & set(user_ads))
                    if not ads:
                        return HttpResponse(
                            "<html><body>Permission denied: Invalid Administrative Domain</html></body>"
                        )
            else:
                ads = user_ads
        if ads:
            mos = mos.filter(administrative_domain__in=ads)
        if selector:
            selector = ManagedObjectSelector.get_by_id(int(selector))
            mos = mos.filter(selector.Q)
        if ex_selector:
            ex_selector = ManagedObjectSelector.get_by_id(int(ex_selector))
            mos = mos.exclude(ex_selector.Q)

        # Working if Administrative domain set
        if ads:
            try:
                match["adm_path"] = {"$in": ads}
                # @todo More 2 level hierarhy
            except bson.errors.InvalidId:
                pass

        mos_id = list(mos.order_by("id").values_list("id", flat=True))
        mo_hostname = {}
        maintenance = []
        if mos_id and (selector or ex_selector):
            match["managed_object"] = {"$in": mos_id}
        if "maintenance" in columns.split(","):
            maintenance = Maintenance.currently_affected()
        if "object_hostname" in columns.split(","):
            mo_hostname = ReportObjectsHostname1(sync_ids=mos_id)
            mo_hostname = mo_hostname.get_dictionary()
        moss = ReportAlarmObjects(mos_id).get_all()
        # container_lookup = ReportContainer(mos_id)
        container_lookup = None
        subject = "alarm_subject" in columns
        loc = AlarmApplication([])
        if source in ["archive", "both"]:
            # Archived Alarms
            for a in (ArchivedAlarm._get_collection().with_options(
                    read_preference=ReadPreference.SECONDARY_PREFERRED
            ).aggregate([
                {
                    "$match": match
                },
                {
                    "$addFields": {
                        "duration": {
                            "$divide": [
                                {
                                    "$subtract":
                                    ["$clear_timestamp", "$timestamp"]
                                },
                                1000,
                            ]
                        }
                    }
                },
                {
                    "$match": match_duration
                },
                    # {"$sort": {"timestamp": 1}}
            ])):
                if int(a["managed_object"]) not in moss:
                    continue
                dt = a["clear_timestamp"] - a["timestamp"]
                duration = int(dt.total_seconds())
                total_objects = sum(ss["summary"] for ss in a["total_objects"])
                if min_objects and total_objects < min_objects:
                    continue
                total_subscribers = sum(
                    ss["summary"] for ss in a["total_subscribers"]
                    if subscribers_profile
                    and ss["profile"] in subscribers_profile)
                if min_subscribers and total_subscribers < min_subscribers:
                    continue
                if "segment_" in columns.split(
                        ",") or "container_" in columns.split(","):
                    path = ObjectPath.get_path(a["managed_object"])
                    if path:
                        segment_path = [
                            NetworkSegment.get_by_id(s).name
                            for s in path.segment_path
                            if NetworkSegment.get_by_id(s)
                        ]
                        container_path = [
                            Object.get_by_id(s).name
                            for s in path.container_path if Object.get_by_id(s)
                        ]
                    else:
                        segment_path = []
                        container_path = []
                else:
                    segment_path = []
                    container_path = []
                r += [
                    translate_row(
                        row(
                            [
                                smart_text(a["_id"]),
                                smart_text(a["root"]) if a.get("root") else "",
                                a["timestamp"],
                                a["clear_timestamp"],
                                smart_text(duration),
                                moss[a["managed_object"]][0],
                                moss[a["managed_object"]][1],
                                smart_text(
                                    mo_hostname.get(a["managed_object"], "")),
                                Profile.get_by_id(
                                    moss[a["managed_object"]][3]).name
                                if moss[a["managed_object"]][5] else "",
                                moss[a["managed_object"]][6],
                                Platform.get_by_id(
                                    moss[a["managed_object"]][9])
                                if moss[a["managed_object"]][9] else "",
                                smart_text(
                                    Firmware.get_by_id(
                                        moss[a["managed_object"]][10]).version)
                                if moss[a["managed_object"]][10] else "",
                                AlarmClass.get_by_id(a["alarm_class"]).name,
                                ArchivedAlarm.objects.get(
                                    id=a["_id"]).subject if subject else "",
                                "",
                                total_objects,
                                total_subscribers,
                                a.get("escalation_tt"),
                                a.get("escalation_ts"),
                                ", ".join(ll for ll in (
                                    loc.location(moss[a["managed_object"]][5]
                                                 ) if moss[a["managed_object"]]
                                    [5] is not None else "") if ll),
                                container_lookup[a["managed_object"]].get(
                                    "text", "") if container_lookup else "",
                            ],
                            container_path,
                            segment_path,
                        ),
                        cmap,
                    )
                ]
        # Active Alarms
        if source in ["active", "both"]:
            datenow = datetime.datetime.now()
            for a in (ActiveAlarm._get_collection().with_options(
                    read_preference=ReadPreference.SECONDARY_PREFERRED).
                      aggregate([
                          {
                              "$match": match
                          },
                          {
                              "$addFields": {
                                  "duration": {
                                      "$divide": [{
                                          "$subtract": [fd, "$timestamp"]
                                      }, 1000]
                                  }
                              }
                          },
                          {
                              "$match": match_duration
                          },
                          # {"$sort": {"timestamp": 1}}
                      ])):
                dt = datenow - a["timestamp"]
                duration = int(dt.total_seconds())
                total_objects = sum(ss["summary"] for ss in a["total_objects"])
                if min_objects and total_objects < min_objects:
                    continue
                total_subscribers = sum(
                    ss["summary"] for ss in a["total_subscribers"]
                    if subscribers_profile
                    and ss["profile"] in subscribers_profile)
                if min_subscribers and total_subscribers < min_subscribers:
                    continue
                if "segment_" in columns.split(
                        ",") or "container_" in columns.split(","):
                    path = ObjectPath.get_path(a["managed_object"])
                    if path:
                        segment_path = [
                            NetworkSegment.get_by_id(s).name
                            for s in path.segment_path
                            if NetworkSegment.get_by_id(s)
                        ]
                        container_path = [
                            Object.get_by_id(s).name
                            for s in path.container_path if Object.get_by_id(s)
                        ]
                    else:
                        segment_path = []
                        container_path = []
                else:
                    segment_path = []
                    container_path = []
                r += [
                    translate_row(
                        row(
                            [
                                smart_text(a["_id"]),
                                smart_text(a["root"]) if a.get("root") else "",
                                a["timestamp"],
                                # a["clear_timestamp"],
                                "",
                                smart_text(duration),
                                moss[a["managed_object"]][0],
                                moss[a["managed_object"]][1],
                                smart_text(
                                    mo_hostname.get(a["managed_object"], "")),
                                Profile.get_by_id(moss[a["managed_object"]][3])
                                if moss[a["managed_object"]][5] else "",
                                moss[a["managed_object"]][6],
                                Platform.get_by_id(
                                    moss[a["managed_object"]][9])
                                if moss[a["managed_object"]][9] else "",
                                smart_text(
                                    Firmware.get_by_id(
                                        moss[a["managed_object"]][10]).version)
                                if moss[a["managed_object"]][10] else "",
                                AlarmClass.get_by_id(a["alarm_class"]).name,
                                ActiveAlarm.objects.get(
                                    id=a["_id"]).subject if subject else None,
                                "Yes" if a["managed_object"] in maintenance
                                else "No",
                                total_objects,
                                total_subscribers,
                                a.get("escalation_tt"),
                                a.get("escalation_ts"),
                                ", ".join(ll for ll in (
                                    loc.location(moss[a["managed_object"]][5]
                                                 ) if moss[a["managed_object"]]
                                    [5] is not None else "") if ll),
                                container_lookup[a["managed_object"]].get(
                                    "text", "") if container_lookup else "",
                            ],
                            container_path,
                            segment_path,
                        ),
                        cmap,
                    )
                ]
        if source in ["long_archive"]:
            o_format = "csv_zip"
            columns = [
                "ALARM_ID",
                "MO_ID",
                "OBJECT_PROFILE",
                "VENDOR",
                "PLATFORM",
                "VERSION",
                "OPEN_TIMESTAMP",
                "CLOSE_TIMESTAMP",
                "LOCATION",
                "",
                "POOL",
                "ADM_DOMAIN",
                "MO_NAME",
                "IP",
                "ESCALATION_TT",
                "DURATION",
                "SEVERITY",
                "REBOOTS",
            ]
            from noc.core.clickhouse.connect import connection

            ch = connection()
            fd = datetime.datetime.strptime(from_date, "%d.%m.%Y")
            td = datetime.datetime.strptime(
                to_date, "%d.%m.%Y") + datetime.timedelta(days=1)
            if td - fd > datetime.timedelta(days=390):
                return HttpResponseBadRequest(
                    _("Report more than 1 year not allowed. If nedeed - request it from Administrator"
                      ))
            ac = AlarmClass.objects.get(
                name="NOC | Managed Object | Ping Failed")
            subs = ", ".join(
                "subscribers.summary[indexOf(subscribers.profile, '%s')] as `%s`"
                % (sp.bi_id, sp.name)
                for sp in SubscriberProfile.objects.filter().order_by("name"))
            if subs:
                columns += [
                    sp.name for sp in
                    SubscriberProfile.objects.filter().order_by("name")
                ]
            r = ch.execute(LONG_ARCHIVE_QUERY % (
                ", %s" % subs if subs else "",
                fd.date().isoformat(),
                td.date().isoformat(),
                ac.bi_id,
            ))

        filename = "alarms.csv"
        if o_format == "csv":
            response = HttpResponse(content_type="text/csv")
            response[
                "Content-Disposition"] = 'attachment; filename="%s"' % filename
            writer = csv.writer(response)
            writer.writerows(r)
            return response
        elif o_format == "csv_zip":
            response = BytesIO()
            f = TextIOWrapper(TemporaryFile(mode="w+b"), encoding="utf-8")
            writer = csv.writer(f,
                                dialect="excel",
                                delimiter=";",
                                quotechar='"')
            writer.writerow(columns)
            writer.writerows(r)
            f.seek(0)
            with ZipFile(response, "w", compression=ZIP_DEFLATED) as zf:
                zf.writestr(filename, f.read())
                zf.filename = "%s.zip" % filename
            # response = HttpResponse(content_type="text/csv")
            response.seek(0)
            response = HttpResponse(response.getvalue(),
                                    content_type="application/zip")
            response[
                "Content-Disposition"] = 'attachment; filename="%s.zip"' % filename
            return response
        elif o_format == "xlsx":
            response = BytesIO()
            wb = xlsxwriter.Workbook(response)
            cf1 = wb.add_format({"bottom": 1, "left": 1, "right": 1, "top": 1})
            ws = wb.add_worksheet("Alarms")
            max_column_data_length = {}
            for rn, x in enumerate(r):
                for cn, c in enumerate(x):
                    if rn and (r[0][cn] not in max_column_data_length or
                               len(str(c)) > max_column_data_length[r[0][cn]]):
                        max_column_data_length[r[0][cn]] = len(str(c))
                    ws.write(rn, cn, c, cf1)
            ws.autofilter(0, 0, rn, cn)
            ws.freeze_panes(1, 0)
            for cn, c in enumerate(r[0]):
                # Set column width
                width = get_column_width(c)
                if enable_autowidth and width < max_column_data_length[c]:
                    width = max_column_data_length[c]
                ws.set_column(cn, cn, width=width)
            wb.close()
            response.seek(0)
            response = HttpResponse(response.getvalue(),
                                    content_type="application/vnd.ms-excel")
            response[
                "Content-Disposition"] = 'attachment; filename="alarms.xlsx"'
            response.close()
            return response