예제 #1
0
  def GET(self, deviceId, notificationId):
    """
      Get single notification

      ::

          GET /_notifications/{deviceId}/{notificationId}

      Returns:

      ::

          {
            "uid": "e78599c4-758b-4c6e-87b1-daabaccff798",
            "timestamp": "2014-02-07 16:26:44",
            "metric": "e5511f295a474037a75bc966d02b67d2",
            "acknowledged": 0,
            "seen": 0,
            "windowsize": 3600,
            "device": "9a90eaf2-6374-4230-aa96-0830c0a737fe"
          }

      :param uid: Notification ID
      :type uid: str
      :param timestamp: Notification timestamp
      :type timestamp: timestamp
      :param metric: Metric that triggered notification
      :type metric: str
      :param acknowledged: Acknowledged status
      :type acknowledged: int
      :param seen: Seen status
      :type seen: int
      :param windowsize: Notification window in seconds during which no other
        notifications for a given instance should be sent to a given device
      :type windowsize: int
      :param device: Device ID
      :type device: str
    """
    # Update the last_timestamp for the notification device.
    try:
      with web.ctx.connFactory() as conn:
        repository.updateNotificationDeviceTimestamp(conn, deviceId)
    except ObjectNotFoundError:
      return web.notfound("Notification device not found: %s" % deviceId)

    try:
      with web.ctx.connFactory() as conn:
        notificationRow = repository.getNotification(conn,
                                                     notificationId,
                                                     NotificationHandler.fields)
      notificationDict = dict([(col, notificationRow[col])
                              for col in NotificationHandler.fields])

      if notificationRow["device"] != deviceId:
        return web.notfound("Device not found: %s" % deviceId)

      self.addStandardHeaders()
      return utils.jsonEncode(notificationDict)
    except ObjectNotFoundError:
      return web.notfound("Notification not found: %s" % notificationId)
예제 #2
0
    def GET(self, deviceId, notificationId):
        """
      Get single notification

      ::

          GET /_notifications/{deviceId}/{notificationId}

      Returns:

      ::

          {
            "uid": "e78599c4-758b-4c6e-87b1-daabaccff798",
            "timestamp": "2014-02-07 16:26:44",
            "metric": "e5511f295a474037a75bc966d02b67d2",
            "acknowledged": 0,
            "seen": 0,
            "windowsize": 3600,
            "device": "9a90eaf2-6374-4230-aa96-0830c0a737fe"
          }

      :param uid: Notification ID
      :type uid: str
      :param timestamp: Notification timestamp
      :type timestamp: timestamp
      :param metric: Metric that triggered notification
      :type metric: str
      :param acknowledged: Acknowledged status
      :type acknowledged: int
      :param seen: Seen status
      :type seen: int
      :param windowsize: Notification window in seconds during which no other
        notifications for a given instance should be sent to a given device
      :type windowsize: int
      :param device: Device ID
      :type device: str
    """
        # Update the last_timestamp for the notification device.
        try:
            with web.ctx.connFactory() as conn:
                repository.updateNotificationDeviceTimestamp(conn, deviceId)
        except ObjectNotFoundError:
            return web.notfound("Notification device not found: %s" % deviceId)

        try:
            with web.ctx.connFactory() as conn:
                notificationRow = repository.getNotification(
                    conn, notificationId, NotificationHandler.fields)
            notificationDict = dict([(col, notificationRow[col])
                                     for col in NotificationHandler.fields])

            if notificationRow["device"] != deviceId:
                return web.notfound("Device not found: %s" % deviceId)

            self.addStandardHeaders()
            return utils.jsonEncode(notificationDict)
        except ObjectNotFoundError:
            return web.notfound("Notification not found: %s" % notificationId)
예제 #3
0
    def messageHandler(self, message):
        """ Inspect all inbound model results in a batch for anomaly thresholds and
        trigger notifications where applicable.

        :param amqp.messages.ConsumerMessage message: ``message.body`` is a
          serialized batch of model inference results generated in
          ``AnomalyService`` and must be deserialized using
          ``AnomalyService.deserializeModelResult()``. The message conforms to
          htmengine/runtime/json_schema/model_inference_results_msg_schema.json
    """
        if message.properties.headers and "dataType" in message.properties.headers:
            # Not a model inference result
            return

        YOMP.app.config.loadConfig()  # reload config on every batch
        engine = repository.engineFactory()
        # Cache minimum threshold to trigger any notification to avoid permuting
        # settings x metricDataRows
        try:
            try:
                batch = AnomalyService.deserializeModelResult(message.body)
            except Exception:
                self._log.exception("Error deserializing model result")
                raise

            # Load all settings for all users (once per incoming batch)
            with engine.connect() as conn:
                settings = repository.retryOnTransientErrors(repository.getAllNotificationSettings)(conn)

            self._log.debug("settings: %r" % settings)

            if settings:
                minThreshold = min(setting.sensitivity for setting in settings)
            else:
                minThreshold = 0.99999

            metricInfo = batch["metric"]
            metricId = metricInfo["uid"]
            resource = metricInfo["resource"]

            for row in batch["results"]:

                if row["anomaly"] >= minThreshold:
                    for settingObj in settings:
                        if row["rowid"] <= 1000:
                            continue  # Not enough data

                        rowDatetime = datetime.utcfromtimestamp(row["ts"])

                        if rowDatetime < datetime.utcnow() - timedelta(seconds=3600):
                            continue  # Skip old

                        if row["anomaly"] >= settingObj.sensitivity:
                            # First let's clear any old users out of the database.
                            with engine.connect() as conn:
                                repository.retryOnTransientErrors(repository.deleteStaleNotificationDevices)(
                                    conn, _NOTIFICATION_DEVICE_STALE_DAYS
                                )

                            # If anomaly_score meets or exceeds any of the device
                            # notification sensitivity settings, trigger notification.
                            # repository.addNotification() will handle throttling.
                            notificationId = str(uuid.uuid4())

                            with engine.connect() as conn:
                                result = repository.retryOnTransientErrors(repository.addNotification)(
                                    conn,
                                    uid=notificationId,
                                    server=resource,
                                    metric=metricId,
                                    rowid=row["rowid"],
                                    device=settingObj.uid,
                                    windowsize=(settingObj.windowsize),
                                    timestamp=rowDatetime,
                                    acknowledged=0,
                                    seen=0,
                                )

                            self._log.info(
                                "NOTIFICATION=%s SERVER=%s METRICID=%s DEVICE=%s "
                                "Notification generated. " % (notificationId, resource, metricId, settingObj.uid)
                            )

                            if result is not None and result.rowcount > 0 and settingObj.email_addr:
                                # Notification was generated.  Attempt to send email
                                with engine.connect() as conn:
                                    notificationObj = repository.getNotification(conn, notificationId)

                                self.sendNotificationEmail(engine, settingObj, notificationObj)

                    if not settings:
                        # There are no device notification settings stored on this server,
                        # no notifications will be generated.  However, log that a
                        # an anomaly was detected and notification would be sent if there
                        # were any configured devices
                        self._log.info(
                            "<%r>" % (metricInfo)
                            + ("{TAG:APP.NOTIFICATION} Anomaly " "detected at %s, but no devices are " "configured.")
                            % rowDatetime
                        )

        finally:
            message.ack()

        # Do cleanup
        with engine.connect() as conn:
            repository.clearOldNotifications(conn)  # Delete all notifications outside