0
0
Fork 0
mirror of https://github.com/alerta/alerta.git synced 2025-02-21 20:36:07 +00:00
alerta_alerta/alerta/api/v2/views.py

438 lines
15 KiB
Python
Raw Normal View History

2013-03-18 12:18:17 +00:00
import json
2013-03-21 13:43:13 +00:00
import time
2013-02-19 10:57:05 +00:00
from functools import wraps
2014-02-20 23:43:36 +00:00
from flask import request, current_app, render_template, abort
2013-04-09 18:19:47 +00:00
2013-04-13 21:44:15 +00:00
from alerta.api.v2 import app, db, mq
2013-04-07 21:45:23 +00:00
from alerta.api.v2.switch import Switch
2013-04-09 18:32:54 +00:00
from alerta.common import config
2013-03-15 17:18:39 +00:00
from alerta.common import log as logging
from alerta.common.alert import Alert
2013-04-09 18:32:54 +00:00
from alerta.common.heartbeat import Heartbeat
from alerta.common import status_code, severity_code
2013-03-15 17:18:39 +00:00
from alerta.common.utils import DateEncoder
2013-09-12 16:51:25 +00:00
from alerta.api.v2.utils import parse_fields, crossdomain
2013-03-15 17:18:39 +00:00
2013-04-09 18:19:47 +00:00
2014-02-20 23:43:36 +00:00
Version = '2.1.2'
2013-03-15 17:18:39 +00:00
LOG = logging.getLogger(__name__)
CONF = config.CONF
2013-03-17 22:53:08 +00:00
2013-03-15 17:18:39 +00:00
# Over-ride jsonify to support Date Encoding
def jsonify(*args, **kwargs):
return current_app.response_class(json.dumps(dict(*args, **kwargs), cls=DateEncoder,
indent=None if request.is_xhr else 2), mimetype='application/json')
2013-02-19 10:57:05 +00:00
2013-03-17 22:53:08 +00:00
2013-02-19 10:57:05 +00:00
def jsonp(func):
"""Wraps JSONified output for JSONP requests."""
@wraps(func)
def decorated_function(*args, **kwargs):
callback = request.args.get('callback', False)
if callback:
data = str(func(*args, **kwargs).data)
content = str(callback) + '(' + data + ')'
mimetype = 'application/javascript'
return current_app.response_class(content, mimetype=mimetype)
else:
return func(*args, **kwargs)
return decorated_function
2013-09-12 16:51:25 +00:00
@app.route('/test', methods=['OPTIONS', 'PUT', 'POST', 'DELETE', 'GET'])
@crossdomain(origin='*', headers=['Origin', 'X-Requested-With', 'Content-Type', 'Accept'])
2013-03-28 10:13:12 +00:00
@jsonp
2013-03-17 22:53:08 +00:00
def test():
2013-02-19 10:57:05 +00:00
2013-04-02 16:09:05 +00:00
return jsonify(response={
"status": "ok",
"method": request.method,
2013-04-02 16:09:05 +00:00
"json": request.json,
"data": request.data,
"args": request.args,
"app_root": app.root_path,
})
2013-02-19 10:57:05 +00:00
2014-01-08 11:45:58 +00:00
@app.route('/alerta/api/v2', methods=['GET'])
def routes():
rules = []
for rule in app.url_map.iter_rules():
rule.methods = ','.join([r for r in rule.methods if r not in ['OPTIONS', 'HEAD']])
if rule.endpoint not in ['test','static']:
rules.append(rule)
return render_template('index.html', rules=rules)
2013-03-17 23:32:54 +00:00
2013-03-17 22:53:08 +00:00
@app.route('/alerta/api/v2/alerts', methods=['GET'])
@jsonp
2013-04-04 08:07:09 +00:00
def get_alerts():
2013-02-19 10:57:05 +00:00
2013-07-13 12:34:51 +00:00
try:
query, sort, limit, query_time = parse_fields(request)
except Exception, e:
return jsonify(response={"status": "error", "message": str(e)})
2013-02-19 10:57:05 +00:00
fields = dict()
fields['history'] = {'$slice': CONF.history_limit}
alerts = db.get_alerts(query=query, fields=fields, sort=sort, limit=limit)
2013-03-18 21:02:53 +00:00
total = db.get_count(query=query) # TODO(nsatterl): possible race condition?
2013-03-18 22:33:00 +00:00
2013-03-18 21:02:53 +00:00
found = 0
severity_count = dict.fromkeys(severity_code.ALL, 0)
status_count = dict.fromkeys(status_code.ALL, 0)
2013-03-18 22:33:00 +00:00
alert_details = list()
2013-03-18 21:02:53 +00:00
if len(alerts) > 0:
2013-02-19 10:57:05 +00:00
2013-03-16 16:06:05 +00:00
last_time = None
2013-03-16 12:11:56 +00:00
for alert in alerts:
2013-03-16 16:06:05 +00:00
body = alert.get_body()
2013-03-18 21:02:53 +00:00
if body['severity'] in request.args.getlist('hide-alert-repeats') and body['repeat']:
continue
2013-06-25 23:31:14 +00:00
if not request.args.get('hide-alert-details', 'false') == 'true':
2013-03-18 21:02:53 +00:00
alert_details.append(body)
2013-06-25 23:31:14 +00:00
if request.args.get('hide-alert-history', 'false') == 'true':
2013-03-18 21:02:53 +00:00
body['history'] = []
2013-03-16 16:06:05 +00:00
2013-03-18 22:33:00 +00:00
found += 1
severity_count[body['severity']] += 1
2013-03-16 16:06:05 +00:00
status_count[body['status']] += 1
if not last_time:
last_time = body['lastReceiveTime']
elif body['lastReceiveTime'] > last_time:
last_time = body['lastReceiveTime']
2013-02-19 10:57:05 +00:00
2013-03-16 12:11:56 +00:00
return jsonify(response={
2013-03-16 16:06:05 +00:00
"alerts": {
"alertDetails": alert_details,
"severityCounts": severity_count,
"statusCounts": status_count,
2013-03-16 16:06:05 +00:00
"lastTime": last_time,
},
2013-03-16 12:11:56 +00:00
"status": "ok",
"total": found,
"more": total > limit,
2013-04-04 12:21:20 +00:00
"autoRefresh": Switch.get('auto-refresh-allow').is_on(),
2013-03-16 16:06:05 +00:00
})
2013-02-19 10:57:05 +00:00
else:
2013-03-16 16:06:05 +00:00
return jsonify(response={
"alerts": {
"alertDetails": [],
2013-05-25 19:11:53 +00:00
"severityCounts": severity_count,
"statusCounts": status_count,
2013-03-18 14:55:34 +00:00
"lastTime": query_time,
2013-03-16 16:06:05 +00:00
},
2013-07-13 12:34:51 +00:00
"status": "ok",
"message": "not found",
2013-03-16 16:06:05 +00:00
"total": 0,
"more": False,
2013-04-04 12:21:20 +00:00
"autoRefresh": Switch.get('auto-refresh-allow').is_on(),
2013-03-16 16:06:05 +00:00
})
2013-02-19 10:57:05 +00:00
2013-09-12 16:51:25 +00:00
@app.route('/alerta/api/v2/alerts/alert.json', methods=['OPTIONS', 'POST'])
@crossdomain(origin='*', headers=['Origin', 'X-Requested-With', 'Content-Type', 'Accept'])
2013-03-17 22:53:08 +00:00
@jsonp
def create_alert():
# Create a new alert
try:
newAlert = Alert.parse_alert(request.data)
2013-06-14 16:31:15 +00:00
except ValueError, e:
return jsonify(response={"status": "error", "message": str(e)})
2013-03-17 22:53:08 +00:00
LOG.debug('New alert %s', newAlert)
2013-04-13 21:44:15 +00:00
mq.send(newAlert)
2013-03-17 22:53:08 +00:00
2013-03-17 23:32:54 +00:00
if newAlert:
return jsonify(response={"status": "ok", "id": newAlert.get_id()})
2013-03-17 22:53:08 +00:00
else:
return jsonify(response={"status": "error", "message": "something went wrong"})
2013-02-19 10:57:05 +00:00
2014-02-23 23:49:03 +00:00
@app.route('/alerta/api/v2/alerts/alert/<alertid>', methods=['OPTIONS', 'GET'])
2013-09-12 16:51:25 +00:00
@crossdomain(origin='*', headers=['Origin', 'X-Requested-With', 'Content-Type', 'Accept'])
2013-03-17 22:53:08 +00:00
@jsonp
2014-02-23 23:49:03 +00:00
def get_alert(alertid):
2013-04-13 21:44:15 +00:00
2014-02-23 23:49:03 +00:00
alert = db.get_alert(alertid=alertid)
2013-03-17 22:53:08 +00:00
2014-02-23 23:49:03 +00:00
if alert:
return jsonify(response={"alert": alert.get_body(), "status": "ok", "total": 1})
2013-03-17 22:53:08 +00:00
else:
2014-02-23 23:49:03 +00:00
return jsonify(response={"alert": None, "status": "ok", "message": "not found", "total": 0})
2013-02-19 10:57:05 +00:00
2013-09-12 16:51:25 +00:00
@app.route('/alerta/api/v2/alerts/alert/<alertid>/tag', methods=['OPTIONS', 'PUT'])
@crossdomain(origin='*', headers=['Origin', 'X-Requested-With', 'Content-Type', 'Accept'])
2013-03-17 22:53:08 +00:00
@jsonp
def tag_alert(alertid):
2013-03-18 17:56:52 +00:00
tag = request.json
2013-03-17 22:53:08 +00:00
if tag:
2013-03-18 17:56:52 +00:00
response = db.tag_alert(alertid, tag['tag'])
2013-03-17 22:53:08 +00:00
else:
2013-03-18 17:56:52 +00:00
return jsonify(response={"status": "error", "message": "no data"})
2013-03-17 22:53:08 +00:00
if response:
return jsonify(response={"status": "ok"})
else:
2013-03-18 17:56:52 +00:00
return jsonify(response={"status": "error", "message": "error tagging alert"})
2013-02-19 10:57:05 +00:00
2014-02-23 23:49:03 +00:00
@app.route('/alerta/api/v2/alerts/alert/<alertid>/status', methods=['OPTIONS', 'PUT'])
@crossdomain(origin='*', headers=['Origin', 'X-Requested-With', 'Content-Type', 'Accept'])
@jsonp
def modify_status(alertid):
status = request.json['status']
text = request.json['text']
if status:
modifiedAlert = db.update_status(alertid=alertid, status=status, text=text)
# Forward alert to notify topic and logger queue
mq.send(modifiedAlert, CONF.outbound_queue)
mq.send(modifiedAlert, CONF.outbound_topic)
LOG.info('%s : Alert forwarded to %s and %s', modifiedAlert.get_id(), CONF.outbound_queue, CONF.outbound_topic)
else:
return jsonify(response={"status": "error", "message": "no data"})
if modifiedAlert:
return jsonify(response={"status": "ok"})
else:
return jsonify(response={"status": "error", "message": "error changing alert status"})
@app.route('/alerta/api/v2/alerts/alert/<alertid>', methods=['OPTIONS', 'DELETE', 'POST'])
@crossdomain(origin='*', headers=['Origin', 'X-Requested-With', 'Content-Type', 'Accept'])
@jsonp
def delete_alert(alertid):
error = None
if request.method == 'DELETE' or (request.method == 'POST' and request.json['_method'] == 'delete'):
response = db.delete_alert(alertid)
if response:
return jsonify(response={"status": "ok"})
else:
return jsonify(response={"status": "error", "message": error})
else:
return jsonify(response={"status": "error", "message": "POST request without '_method' override?"})
# Return severity and status counts
@app.route('/alerta/api/v2/alerts/counts', methods=['GET'])
2014-03-16 10:38:28 +00:00
@crossdomain(origin='*', headers=['Origin', 'X-Requested-With', 'Content-Type', 'Accept'])
@jsonp
def get_counts():
2013-07-13 12:34:51 +00:00
try:
query, _, _, query_time = parse_fields(request)
except Exception, e:
return jsonify(response={"status": "error", "message": str(e)})
found, severity_count, status_count = db.get_counts(query=query)
2014-03-16 10:38:28 +00:00
googleviz = {
"cols": [
{"id": "", "label": "severity", "pattern": "", "type": "string"},
{"id": "", "label": "count", "pattern": "", "type": "number"}
],
"rows": [
{"c": [{"v": "critical", "f": None}, {"v": severity_count['critical'], "f": None}]},
{"c": [{"v": "major", "f": None}, {"v": severity_count['major'], "f": None}]},
{"c": [{"v": "minor", "f": None}, {"v": severity_count['minor'], "f": None}]},
{"c": [{"v": "warning", "f": None}, {"v": severity_count['warning'], "f": None}]},
{"c": [{"v": "normal", "f": None}, {"v": severity_count['normal'], "f": None}]},
{"c": [{"v": "informational", "f": None}, {"v": severity_count['informational'], "f": None}]}
]
}
return jsonify(response={
"alerts": {
"alertDetails": [],
"severityCounts": severity_count,
"statusCounts": status_count,
"lastTime": query_time,
},
"status": "ok",
"total": found,
"more": False,
"autoRefresh": Switch.get('auto-refresh-allow').is_on(),
2014-03-16 10:38:28 +00:00
"googleviz": googleviz
})
2013-02-19 10:57:05 +00:00
2014-02-20 23:43:36 +00:00
@app.route('/pagerduty', methods=['POST'])
def pagerduty():
if not request.json or not 'messages' in request.json:
abort(400)
for message in request.json['messages']:
2014-02-23 23:49:03 +00:00
LOG.debug('%s', json.dumps(message))
2014-02-20 23:43:36 +00:00
alertid = message['data']['incident']['incident_key']
2014-02-23 23:49:03 +00:00
html_url = message['data']['incident']['html_url']
incident_number = message['data']['incident']['incident_number']
incident_url = '<a href="%s">#%s</a>' % (html_url, incident_number)
LOG.info('PagerDuty incident #%s webhook for alert %s', incident_number, alertid)
LOG.error('previous status %s', db.get_alert(alertid=alertid).status)
2014-02-20 23:43:36 +00:00
if message['type'] == 'incident.trigger':
2014-02-23 23:49:03 +00:00
status = status_code.OPEN
2014-02-20 23:43:36 +00:00
user = message['data']['incident']['assigned_to_user']['name']
2014-02-23 23:49:03 +00:00
text = 'Incident %s assigned to %s' % (incident_url, user)
2014-02-20 23:43:36 +00:00
elif message['type'] == 'incident.acknowledge':
2014-02-23 23:49:03 +00:00
status = status_code.ACK
2014-02-20 23:43:36 +00:00
user = message['data']['incident']['assigned_to_user']['name']
2014-02-23 23:49:03 +00:00
text = 'Incident %s acknowledged by %s' % (incident_url, user)
elif message['type'] == 'incident.unacknowledge':
status = status_code.OPEN
text = 'Incident %s unacknowledged due to timeout' % incident_url
2014-02-20 23:43:36 +00:00
elif message['type'] == 'incident.resolve':
2014-02-23 23:49:03 +00:00
status = status_code.CLOSED
if message['data']['incident']['resolved_by_user']:
user = message['data']['incident']['resolved_by_user']['name']
else:
user = 'n/a'
text = 'Incident %s resolved by %s' % (incident_url, user)
elif message['type'] == 'incident.assign':
status = status_code.ASSIGN
user = message['data']['incident']['assigned_to_user']['name']
text = 'Incident %s manually assigned to %s' % (incident_url, user)
elif message['type'] == 'incident.escalate':
status = status_code.OPEN
user = message['data']['incident']['assigned_to_user']['name']
text = 'Incident %s escalated to %s' % (incident_url, user)
elif message['type'] == 'incident.delegate':
status = status_code.OPEN
user = message['data']['incident']['assigned_to_user']['name']
text = 'Incident %s reassigned due to escalation to %s' % (incident_url, user)
2014-02-20 23:43:36 +00:00
else:
2014-02-23 23:49:03 +00:00
status = status_code.UNKNOWN
2014-02-20 23:43:36 +00:00
text = message['type']
LOG.warn('Unknown PagerDuty message type: %s', message)
2014-02-23 23:49:03 +00:00
LOG.info('PagerDuty webhook %s change status to %s', message['type'], status)
2014-02-20 23:43:36 +00:00
pdAlert = db.update_status(alertid=alertid, status=status, text=text)
2014-02-23 23:49:03 +00:00
db.tag_alert(alertid=alertid, tag='incident=#%s' % incident_number)
LOG.error('returned status %s', pdAlert.status)
LOG.error('current status %s', db.get_alert(alertid=alertid).status)
2014-02-20 23:43:36 +00:00
# Forward alert to notify topic and logger queue
2014-02-23 23:49:03 +00:00
if pdAlert:
pdAlert.origin = 'pagerduty/webhook'
mq.send(pdAlert, CONF.outbound_queue)
mq.send(pdAlert, CONF.outbound_topic)
LOG.info('%s : Alert forwarded to %s and %s', pdAlert.get_id(), CONF.outbound_queue, CONF.outbound_topic)
2014-02-20 23:43:36 +00:00
return jsonify(response={"status": "ok"})
2013-03-28 10:13:12 +00:00
# Return a list of resources
@app.route('/alerta/api/v2/resources', methods=['GET'])
@jsonp
def get_resources():
query, sort, limit, query_time = parse_fields(request)
2013-03-28 10:13:12 +00:00
resources = db.get_resources(query=query, sort=sort, limit=limit)
total = db.get_count(query=query) # TODO(nsatterl): possible race condition?
found = 0
resource_details = list()
if len(resources) > 0:
last_time = None
2013-03-28 10:13:12 +00:00
for resource in resources:
resource_details.append(resource)
found += 1
if not last_time:
last_time = resource['lastReceiveTime']
elif resource['lastReceiveTime'] > last_time:
last_time = resource['lastReceiveTime']
2013-03-28 10:13:12 +00:00
return jsonify(response={
"resources": {
"resourceDetails": resource_details,
"lastTime": last_time,
2013-03-28 10:13:12 +00:00
},
"status": "ok",
"total": found,
"more": total > limit
})
else:
return jsonify(response={
"resources": {
"resourceDetails": list(),
"lastTime": query_time,
2013-03-28 10:13:12 +00:00
},
2013-07-13 12:34:51 +00:00
"status": "ok",
"message": "not found",
2013-03-28 10:13:12 +00:00
"total": 0,
"more": False,
})
2013-09-12 16:51:25 +00:00
@app.route('/alerta/api/v2/resources/resource/<resource>', methods=['OPTIONS', 'POST', 'DELETE'])
@crossdomain(origin='*', headers=['Origin', 'X-Requested-With', 'Content-Type', 'Accept'])
@jsonp
def delete_resource(resource):
error = None
2013-05-26 10:34:51 +00:00
# Delete all alerts for a single resource
if request.method == 'DELETE' or (request.method == 'POST' and request.json['_method'] == 'delete'):
response = db.delete_resource(resource)
if response:
return jsonify(response={"status": "ok"})
else:
return jsonify(response={"status": "error", "message": error})
else:
return jsonify(response={"status": "error", "message": "POST request without '_method' override?"})
2013-03-28 10:13:12 +00:00
2013-03-27 15:37:53 +00:00
# Return a list of heartbeats
@app.route('/alerta/api/v2/heartbeats', methods=['GET'])
2013-03-21 13:43:13 +00:00
@jsonp
2013-03-27 15:37:53 +00:00
def get_heartbeats():
2013-03-21 13:43:13 +00:00
heartbeats = db.get_heartbeats()
return jsonify(application="alerta", time=int(time.time() * 1000), heartbeats=heartbeats)
2013-09-12 16:51:25 +00:00
@app.route('/alerta/api/v2/heartbeats/heartbeat.json', methods=['OPTIONS', 'POST'])
@crossdomain(origin='*', headers=['Origin', 'X-Requested-With', 'Content-Type', 'Accept'])
2013-03-27 15:37:53 +00:00
@jsonp
def create_heartbeat():
# Create a new heartbeat
try:
heartbeat = Heartbeat.parse_heartbeat(request.data)
2013-03-27 15:37:53 +00:00
except Exception, e:
2013-06-14 16:31:15 +00:00
return jsonify(response={"status": "error", "message": str(e)})
2013-03-27 15:37:53 +00:00
LOG.debug('New heartbeat %s', heartbeat)
2013-04-13 21:44:15 +00:00
mq.send(heartbeat)
2013-03-27 15:37:53 +00:00
if heartbeat:
return jsonify(response={"status": "ok", "id": heartbeat.get_id()})
else:
return jsonify(response={"status": "error", "message": "something went wrong"})