alerta_alerta/alerta/webhooks/grafana.py

136 lines
4.8 KiB
Python

import copy
import json
from typing import Any, Dict
from flask import current_app
from werkzeug.datastructures import ImmutableMultiDict, MultiDict
from alerta.app import alarm_model, qb
from alerta.exceptions import ApiError, RejectException
from alerta.models.alert import Alert
from alerta.utils.api import process_alert
from . import WebhookBase
JSON = Dict[str, Any]
def parse_grafana(args: ImmutableMultiDict, alert: JSON, match: Dict[str, Any]) -> Alert:
# default to setting attributes from tags for backwards compat. with users using legacy behavior
grafana_tags_as_attributes = current_app.config.get('GRAFANA_TAGS_AS_ATTRIBUTES', True)
grafana_tags_as_tags = current_app.config.get('GRAFANA_TAGS_AS_TAGS', False)
# get values from request params
environment = args.get('environment', current_app.config['DEFAULT_ENVIRONMENT'])
alerting_severity = args.get('severity', 'major')
service = args.getlist('service') or ['Grafana']
group = args.get('group', 'Performance')
customer = args.get('customer', None)
origin = args.get('origin', 'Grafana')
timeout = args.get('timeout', type=int)
# get metric labels (evalMatches tags)
match_tags = match.get('tags') or {}
environment = match_tags.pop('environment', environment)
alerting_severity = match_tags.pop('severity', alerting_severity)
if 'service' in match_tags:
service.append(match_tags.pop('service'))
group = match_tags.pop('group', group)
customer = match_tags.pop('customer', customer)
origin = match_tags.pop('origin', origin)
attributes = {}
tags = []
# assign leftover match tags as attributes
if grafana_tags_as_attributes:
attributes = {k.replace('.', '_'): v for (k, v) in match_tags.items()}
if grafana_tags_as_tags:
for (k, v) in match_tags.items():
tags.append('{}={}'.format(k, v))
# get alert rule tags
rules_tags = copy.copy(alert.get('tags') or {})
environment = rules_tags.pop('environment', environment)
alerting_severity = rules_tags.pop('severity', alerting_severity)
if 'service' in rules_tags:
service.append(rules_tags.pop('service'))
group = rules_tags.pop('group', group)
customer = rules_tags.pop('customer', customer)
origin = rules_tags.pop('origin', origin)
# set severity
if alert['state'] == 'alerting':
severity = alerting_severity
elif alert['state'] == 'ok':
severity = alarm_model.DEFAULT_NORMAL_SEVERITY
else:
severity = 'indeterminate'
# assign leftover rule tags as attributes
if grafana_tags_as_attributes:
attributes.update({k.replace('.', '_'): v for (k, v) in rules_tags.items()})
if grafana_tags_as_tags:
for (k, v) in rules_tags.items():
tags.append('{}={}'.format(k, v))
attributes['ruleId'] = str(alert['ruleId'])
if 'ruleUrl' in alert:
attributes['ruleUrl'] = f"<a href=\"{alert['ruleUrl']}\" target=\"_blank\">Rule</a>"
if 'imageUrl' in alert:
attributes['imageUrl'] = f"<a href=\"{alert['imageUrl']}\" target=\"_blank\">Image</a>"
return Alert(
resource=match['metric'],
event=alert['ruleName'],
environment=environment,
severity=severity,
service=service,
group=group,
value=f"{match['value']}",
text=alert.get('message', None) or alert.get('title', alert['state']),
tags=tags,
attributes=attributes,
customer=customer,
origin=origin,
event_type='grafanaAlert',
timeout=timeout,
raw_data=json.dumps(alert)
)
class GrafanaWebhook(WebhookBase):
"""
Grafana Alert alert notification webhook
See http://docs.grafana.org/alerting/notifications/#webhook
"""
def incoming(self, path, query_string, payload):
if payload and payload['state'] == 'alerting':
return [parse_grafana(query_string, payload, match) for match in payload.get('evalMatches', [])]
elif payload and payload['state'] == 'ok' and payload.get('ruleId'):
try:
query = qb.alerts.from_params(MultiDict([('attributes.ruleId', str(payload['ruleId']))]))
existingAlerts = Alert.find_all(query)
except Exception as e:
raise ApiError(str(e), 500)
alerts = []
for updateAlert in existingAlerts:
updateAlert.severity = alarm_model.DEFAULT_NORMAL_SEVERITY
updateAlert.status = 'closed'
try:
alert = process_alert(updateAlert)
except RejectException as e:
raise ApiError(str(e), 403)
except Exception as e:
raise ApiError(str(e), 500)
alerts.append(alert)
return alerts
else:
raise ApiError('no alerts in Grafana notification payload', 400)