You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
250 lines
9.7 KiB
250 lines
9.7 KiB
try:
|
|
import defusedxml.cElementTree as et
|
|
except:
|
|
import defusedxml.ElementTree as et
|
|
|
|
import os
|
|
import re
|
|
import sys
|
|
import time
|
|
|
|
import cherrypy
|
|
|
|
import splunk
|
|
import splunk.rest
|
|
import uuid
|
|
|
|
from splunk.models.fired_alert import FiredAlert
|
|
from splunk.models.saved_search import SavedSearch
|
|
|
|
import splunk.appserver.mrsparkle.controllers as controllers
|
|
import splunk.appserver.mrsparkle.lib.util as util
|
|
|
|
from splunk.appserver.mrsparkle.lib.decorators import expose_page
|
|
from splunk.appserver.mrsparkle.lib.routes import route
|
|
|
|
dir = os.path.join(util.get_apps_dir(), __file__.split('.')[-2], 'bin')
|
|
if not dir in sys.path:
|
|
sys.path.append(dir)
|
|
|
|
from sc_rest import setup_logging
|
|
logger = setup_logging('unixheadlines')
|
|
|
|
from unix.util.timesince import *
|
|
from unix.models.headlines import Headlines
|
|
|
|
class unixHeadlines(controllers.BaseController):
|
|
'''unixHeadlines Controller'''
|
|
|
|
@route('/:app/:action=manage')
|
|
@expose_page(must_login=True, methods=['GET'])
|
|
def manage(self, app, action, **kwargs):
|
|
''' return the headlines as output'''
|
|
|
|
output = {'headlines': []}
|
|
user = cherrypy.session['user']['name']
|
|
host_app = cherrypy.request.path_info.split('/')[3]
|
|
|
|
headlines = Headlines.all()
|
|
headlines = headlines.filter_by_app(app)
|
|
output['headlines'] = [{"name": headline.name, "label": headline.label, "alert_name": headline.alert_name } for headline in headlines]
|
|
|
|
return self.render_json(output)
|
|
|
|
@route('/:app/:action=delete')
|
|
@expose_page(must_login=True, trim_spaces=True, methods=['POST'])
|
|
def delete(self, app, action, **params):
|
|
''' delete the provided headline '''
|
|
|
|
user = cherrypy.session['user']['name']
|
|
host_app = cherrypy.request.path_info.split('/')[3]
|
|
id = params.get('name')
|
|
|
|
if not id:
|
|
logger.error('on delete, no identifier was provided')
|
|
return self.render_json({'success':'false', 'error':'internal server error'})
|
|
try:
|
|
headline = Headlines.get(Headlines.build_id(id, app, user))
|
|
except:
|
|
logger.error('Failed to load headline %s' % id)
|
|
return self.render_json({'success':'false', 'error':'failed to load headline'})
|
|
|
|
if not headline.delete():
|
|
logger.error('failed to delete headline %s' % headline.label)
|
|
return self.render_json({'success':'false', 'error':'failed to delete headline'})
|
|
|
|
logger.info('successfully deleted headline %s' % headline.label)
|
|
|
|
return self.render_json({'success':'true', 'error':'headline %s deleted' % headline.label})
|
|
|
|
@route('/:app/:action=id/:id')
|
|
@expose_page(must_login=True, methods=['GET'])
|
|
def id(self, app, action, id, **kwargs):
|
|
''' return details for a specific headline'''
|
|
|
|
headline = None
|
|
output = {}
|
|
user = cherrypy.session['user']['name']
|
|
host_app = cherrypy.request.path_info.split('/')[3]
|
|
|
|
try:
|
|
headline = Headlines.get(Headlines.build_id(id, app, 'nobody'))
|
|
except Exception as ex:
|
|
logger.exception(ex)
|
|
logger.warn('problem retreiving headline %s' % id)
|
|
return self.render_json({'success':'false', 'error':'problem retreiving headline %s' % id})
|
|
|
|
alerts = SavedSearch.all()
|
|
alerts = alerts.filter_by_app(app)
|
|
alerts = alerts.search('is_scheduled=True')
|
|
output['headline'] = [{"name": headline.name, "label": headline.label, "alert_name": headline.alert_name, "message": headline.message, "description": headline.description, "errors": headline.errors}]
|
|
output['alerts'] = [{"name": alert.name, "is_disabled": alert.is_disabled} for alert in alerts]
|
|
|
|
return self.render_json(output)
|
|
|
|
@route('/:app/:action=new')
|
|
@expose_page(must_login=True, methods=['GET'])
|
|
def new(self, app, action, **kwargs):
|
|
''' return new headline and alerts '''
|
|
|
|
output = {'headlines': [], 'alerts':[]}
|
|
user = cherrypy.session['user']['name']
|
|
host_app = cherrypy.request.path_info.split('/')[3]
|
|
|
|
headline = Headlines(app, user, '_new')
|
|
alerts = SavedSearch.all()
|
|
alerts = alerts.filter_by_app(app)
|
|
alerts = alerts.search('is_scheduled=True')
|
|
|
|
output['headline'] = [{"name": headline.name, "errors": headline.errors}]
|
|
output['alerts'] = [{"name": alert.name, "is_disabled": alert.is_disabled} for alert in alerts]
|
|
|
|
return self.render_json(output)
|
|
|
|
|
|
@route('/:app/:action=list')
|
|
@expose_page(must_login=True, methods=['GET'])
|
|
def list(self, app, action, **kwargs):
|
|
''' return headlines'''
|
|
|
|
output = {'headlines': []}
|
|
user = cherrypy.session['user']['name']
|
|
host_app = cherrypy.request.path_info.split('/')[3]
|
|
|
|
count = int(kwargs.get('count', '10'))
|
|
earliest = kwargs.get('earliest', None)
|
|
severity = kwargs.get('severity', ['1','2','3','4','5'])
|
|
|
|
headlines = Headlines.all()
|
|
headlines = headlines.filter_by_app(app)
|
|
headlines = headlines.filter_by_user(user)
|
|
|
|
output['headlines'] = self.get_headlines_detail(headlines, app, user,
|
|
count, earliest, severity=severity, srtd=True)
|
|
|
|
return self.render_json(output)
|
|
|
|
@route('/:app/:action=save')
|
|
@expose_page(must_login=True, methods=['POST'])
|
|
def save(self, app, action, **params):
|
|
''' save the posted headline '''
|
|
|
|
user = cherrypy.session['user']['name']
|
|
host_app = cherrypy.request.path_info.split('/')[3]
|
|
|
|
key = params.get('name')
|
|
|
|
try:
|
|
if key == '_new':
|
|
headline = Headlines(app, user, str(uuid.uuid4()))
|
|
else:
|
|
headline = Headlines.get(Headlines.build_id(key, app, user))
|
|
except:
|
|
headline = Headlines(app, user, str(uuid.uuid4()))
|
|
|
|
headline.label = params.get('label')
|
|
if not headline.label:
|
|
headline.errors = ['label cannot be blank']
|
|
else:
|
|
headline.message = params.get('message')
|
|
headline.description = params.get('description')
|
|
headline.alert_name = params.get('alert_name')
|
|
headline.metadata.sharing = 'app'
|
|
|
|
if headline.errors or not headline.passive_save():
|
|
logger.error('Error saving headline %s: %s' % (headline.name, headline.errors[0]))
|
|
alerts = SavedSearch.all()
|
|
alerts = alerts.filter_by_app(app)
|
|
alerts = alerts.search('is_scheduled=True')
|
|
headline.name = key
|
|
output = {}
|
|
output['headline'] = [{"name": headline.name, "alert_name": headline.alert_name, "message": headline.message, "description":headline.description, "errors": headline.errors}]
|
|
output['alerts'] = [{"name": alert.name, "is_disabled": alert.is_disabled} for alert in alerts]
|
|
return self.render_json(output)
|
|
else:
|
|
return self.render_json({'success':'true', 'error':'headline %s saved' % headline.label})
|
|
|
|
def get_headlines_detail(self, headlines, app, user, count, earliest, severity=None, srtd=None):
|
|
search_string = ""
|
|
sorted_list = []
|
|
if earliest is not None:
|
|
search_string = search_string + ' trigger_time > ' + str(self.get_time(earliest))
|
|
|
|
for headline in headlines:
|
|
try:
|
|
s = SavedSearch.get(SavedSearch.build_id(headline.alert_name, app, user))
|
|
alerts = None
|
|
if s.alert.severity in severity:
|
|
alerts = s.get_alerts()
|
|
if alerts is not None:
|
|
if len(search_string) > 0:
|
|
alerts.search(search_string)
|
|
for alert in alerts:
|
|
h = {'message' : self.replace_tokens(headline.message, alert.sid),
|
|
'job_id' : alert.sid,
|
|
'severity' : s.alert.severity,
|
|
'count' : alert.triggered_alerts,
|
|
'time' : int(time.mktime(alert.trigger_time.timetuple())),
|
|
'timesince' : timesince(alert.trigger_time)}
|
|
sorted_list.append(h)
|
|
except Exception as ex:
|
|
logger.warn('problem retreiving alerts for saved search %s' % headline.alert_name)
|
|
logger.info(ex)
|
|
|
|
if len(sorted_list) > 0:
|
|
if srtd is not None:
|
|
tmp = sorted(sorted_list, key=lambda k: k['time'], reverse=True)[0:count]
|
|
sorted_list = tmp
|
|
|
|
return sorted_list
|
|
|
|
def get_time(self, time):
|
|
getargs = {'time': time, 'time_format': '%s'}
|
|
serverStatus, serverResp = splunk.rest.simpleRequest('/search/timeparser', getargs=getargs)
|
|
root = et.fromstring(serverResp)
|
|
if root.find('messages/msg'):
|
|
raise splunk.SplunkdException(root.findtext('messages/msg'))
|
|
for node in root.findall('dict/key'):
|
|
return node.text
|
|
|
|
def discover_tokens(self, search):
|
|
return re.findall('\$([^\$]+)\$', search)
|
|
|
|
def replace_tokens(self, search, sid):
|
|
output = search
|
|
tokens = self.discover_tokens(search)
|
|
|
|
if len(tokens) > 0:
|
|
try:
|
|
job = splunk.search.JobLite(sid)
|
|
rs = job.getResults('results', count=1)
|
|
for row in rs.results():
|
|
tmp = []
|
|
for token in tokens:
|
|
if row[token] is not None:
|
|
output = re.sub(r'\$' + token + '\$', str(row[token]), output)
|
|
except Exception as ex:
|
|
logger.warn('unable to parse tokens from search %s' % sid)
|
|
logger.debug(ex)
|
|
return output
|