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

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