def create_lookup_table(filename, lookup_file, namespace, owner, key): ''' Create a new lookup file. @param filename: The full path to the replacement lookup table file. @param lookup_file: The lookup FILE name (NOT the stanza name) @param namespace: A Splunk namespace to limit the search to. @param owner: A Splunk user. @param key: A Splunk session key. @return: Boolean success status. WARNING: "owner" should be "nobody" to update a public lookup table file; otherwise the file will be replicated only for the admin user. ''' # Create the temporary location path lookup_tmp = make_splunkhome_path(['var', 'run', 'splunk', 'lookup_tmp']) destination_lookup_full_path = os.path.join(lookup_tmp, lookup_file) # Copy the file to the temporary location shutil.move(filename, destination_lookup_full_path) # CReate the URL for the REST call url = '/servicesNS/%s/%s/data/lookup-table-files' % (owner, namespace) postargs = { 'output_mode': 'json', 'eai:data': str(destination_lookup_full_path), 'name': lookup_file } # Perform the call rest.simpleRequest( url, postargs=postargs, sessionKey=key, raiseAllErrors=True)
def __init__(self, sessionKey, incident_id): self.sessionKey = sessionKey query = {} query['incident_id'] = incident_id uri = '/servicesNS/nobody/alert_manager/storage/collections/data/incidents?query=%s' % urllib.quote(json.dumps(query)) serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey) incident = json.loads(serverContent) incident = incident[0] query_incident_settings = {} query_incident_settings['alert'] = incident["alert"] uri = '/servicesNS/nobody/alert_manager/storage/collections/data/incident_settings?query=%s' % urllib.quote(json.dumps(query_incident_settings)) serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey) incident_settings = json.loads(serverContent) if len(incident_settings) > 0: incident_settings = incident_settings[0] uri = '/servicesNS/nobody/alert_manager/storage/collections/data/incident_results?query=%s' % urllib.quote(json.dumps(query)) serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey) results = json.loads(serverContent) if len(results) > 0: results = results[0] uri = '/services/server/info?output_mode=json' serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey) server_info = json.loads(serverContent) if len(server_info) > 0: server_info = server_info["entry"][0]["content"] self.setContext(incident, incident_settings, results, server_info)
def autoPreviousResolve(alert, job_id): # Auto Previous resolve log.info("auto_previous_resolve is active for alert %s, searching for incidents to resolve..." % alert) query = '{ "alert": "'+ alert +'", "$or": [ { "status": "auto_assigned" } , { "status": "new" } ], "job_id": { "$ne": "'+ job_id +'"} }' log.debug("Filter for auto_previous_resolve: %s" % query) uri = '/servicesNS/nobody/alert_manager/storage/collections/data/incidents?query=%s' % urllib.quote(query) serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey) incidents = json.loads(serverContent) if len(incidents): log.info("Got %s incidents to auto-resolve" % len(incidents)) for incident in incidents: log.info("Auto-resolving incident with key=%s" % incident['_key']) previous_status = incident["status"] previous_job_id = incident["job_id"] previous_incident_id = incident["incident_id"] incident['status'] = 'auto_previous_resolved' uri = '/servicesNS/nobody/alert_manager/storage/collections/data/incidents/%s' % incident['_key'] incident = json.dumps(incident) serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, jsonargs=incident) now = datetime.datetime.now().isoformat() event_id = hashlib.md5(job_id + now).hexdigest() log.debug("event_id=%s now=%s incident=%s" % (event_id, now, incident)) event = 'time=%s severity=INFO origin="alert_handler" event_id="%s" user="******" action="auto_previous_resolve" previous_status="%s" status="auto_previous_resolved" incident_id="%s" job_id="%s"' % (now, event_id, previous_status, previous_incident_id, previous_job_id) log.debug("Resolve event will be: %s" % event) input.submit(event, hostname = socket.gethostname(), sourcetype = 'incident_change', source = 'alert_handler.py', index = config['index']) else: log.info("No incidents with matching criteria for auto_previous_resolve found.")
def getRestData(uri, sessionKey, data = None, output_mode = 'json'): try: if data == None: if output_mode == 'default': serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey) else: serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, getargs={'output_mode': 'json'}) else: if output_mode == 'default': serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, jsonargs=data) else: serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, jsonargs=data, getargs={'output_mode': 'json'}) except: log.info("An error occurred or no data was returned from the server query.") serverContent = None #log.debug("serverResponse: %s" % serverResponse) #log.debug("serverContent: %s" % serverContent) try: returnData = json.loads(serverContent) except: log.info("An error occurred or no data was returned from the server query.") returnData = [] return returnData
def isRestartRequired(self): """Query the messages endpoint to determine whether a restart is currently required""" try: rest.simpleRequest('/messages/restart_required', sessionKey=cherrypy.session['sessionKey']) return True except splunk.ResourceNotFound: return False
def save_risks(self, contents, **kwargs): logger.info("Saving risks...") user = cherrypy.session['user']['name'] sessionKey = cherrypy.session.get('sessionKey') splunk.setDefault('sessionKey', sessionKey) config = {} config['index'] = 'risks' restconfig = entity.getEntities('configs/risk_manager', count=-1, sessionKey=sessionKey) if len(restconfig) > 0: if 'index' in restconfig['settings']: config['index'] = restconfig['settings']['index'] logger.debug("Global settings: %s" % config) # Parse the JSON parsed_contents = json.loads(contents) logger.debug("Contents: %s" % contents) for entry in parsed_contents: if '_key' in entry and entry['_key'] != None: uri = '/servicesNS/nobody/risk_manager/storage/collections/data/risks/' + entry['_key'] # Get current risk serverResponse, risk = rest.simpleRequest(uri, sessionKey=sessionKey) logger.debug("Current risk: %s" % risk) risk = json.loads(risk) # Update risk if score has changed if int(risk['risk_score']) != int(entry['risk_score']): logger.info("Updating risk_object_type=%s risk_object=%s to score=%s." % (entry['risk_object_type'], entry['risk_object'], entry['risk_score'])) del entry['_key'] if 'risk_id' in risk: entry['risk_id'] = risk['risk_id'] else: entry['risk_id'] = str(uuid.uuid4()) risk['risk_id'] = entry['risk_id'] entryStr = json.dumps(entry) serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, jsonargs=entryStr) logger.debug("Updated entry. serverResponse was ok") now = datetime.datetime.now().isoformat() event = 'time="%s" risk_id="%s" action="update_risk_score" alert="Risk Score Tuner" user="******" risk_object_type="%s" risk_object="%s" risk_score="%s" previous_risk_score="%s"' % (now, risk['risk_id'], user, entry['risk_object_type'], entry['risk_object'], entry['risk_score'], risk['risk_score']) logger.debug("Event will be: %s" % event) input.submit(event, hostname = socket.gethostname(), sourcetype = 'risk_scoring', source = 'helpers.py', index = config['index']) else: logger.info("Won't update risk_object_type=%s risk_object=%s, since score didn't change." % (entry['risk_object_type'], entry['risk_object'])) return 'Done'
def assignIncident(incident_key, incident_id, owner): uri = '/servicesNS/nobody/alert_manager/storage/collections/data/incidents/%s' % incident_key serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey) incident = json.loads(serverContent) incident["owner"] = owner incident["status"] = "auto_assigned" if "_user" in incident: del(incident["_user"]) if "_key" in incident: del(incident["_key"]) serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, jsonargs=json.dumps(incident)) log.info("Incident %s assigned to %s" % (incident_id, owner))
def call_peer(remote_host, remote_user, local_host, local_user, ts, nonce, signature): ''' make remote REST call to retreive foreign sessionKey ''' postargs = { 'name': '_create', 'userid': local_user, 'peername': local_host, 'username': remote_user, 'ts': ts, 'nonce': nonce, 'sig': signature } resp, cont = rest.simpleRequest(remote_host + REMOTE_ENDPOINT, postargs=postargs) if resp.status not in [200, 201]: logger.error('unable to get session key from remote peer %s' % remote_host) return None try: atomEntry = rest.format.parseFeedDocument(cont) ret = atomEntry.toPrimitive()[remote_user][remote_user] return ret except Exception, ex: logger.error('unable to parse response from remote peer %s' % remote_host) logger.exception(ex) return None
def parseSearchToXML(search, hostPath=None, sessionKey=None, parseOnly='t', namespace=None, owner=None): """ Given a valid search string, return the XML from the splunk parsing endpoint that represents the search. """ if search == None or len(search) == 0: return None if not owner: owner = auth.getCurrentUser()['name'] uri = entity.buildEndpoint('/search/parser', namespace=namespace, owner=owner) if hostPath: uri = splunk.mergeHostPath(hostPath) + uri args = { 'q' : search, 'parse_only' : parseOnly } serverResponse, serverContent = rest.simpleRequest(uri, getargs=args, sessionKey=sessionKey) #print "SERVERCONTENT:", serverContent # normal messages from splunkd are propogated via SplunkdException; if 400 <= serverResponse.status < 500: root = et.fromstring(serverContent) extractedMessages = rest.extractMessages(root) for msg in extractedMessages: raise splunk.SearchException, msg['text'] return serverContent
def toggle_search(self, search_name, action, **kwargs): user = cherrypy.session['user']['name'] sessionKey = cherrypy.session.get('sessionKey') if action == 'enable': uri = '/servicesNS/nobody/SA-alert_manager_demo/saved/searches/%s/enable' % search_name serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, method='POST') logger.info("Enabled search=%s", search_name) return 'Alert %s has been enabled' % search_name else: uri = '/servicesNS/nobody/SA-alert_manager_demo/saved/searches/%s/disable' % search_name serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, method='POST') logger.info("Disabled search=%s", search_name) return 'Alert %s has been disabled' % search_name
def _reload(self): path = '/'.join([self.id.rsplit('/', 1)[0], '_reload']) response, content = rest.simpleRequest(path, method='POST') if response.status == 200: return True return False
def install(self, appid, state, install=None, **kw): """ Start the app download and installation processs """ if not isinstance(state, StateDict): state = StateDict.unserialize(state) sbSessionKey = self.getSBSessionKey() if not sbSessionKey: logger.warn("Attempted install of app '%s' with sbSessionKey unset" % appid) return self.redirect_to_url(['/manager/appinstall/', appid], _qs={'error': _('SplunkApps login failed'), 'state': state.serialize()}) # don't hold the session lock through network I/O cherrypy.session.release_lock() # attempt to actually install the app url = 'apps/remote/entriesbyid/%s' % appid requestArgs = {'action': 'install', 'auth': urllib.quote(sbSessionKey)} try: logger.info("Installing app %s" % appid) response, content = rest.simpleRequest(url, postargs=requestArgs, sessionKey=cherrypy.session['sessionKey'], timeout=APP_INSTALL_TIMEOUT) except splunk.AuthenticationFailed: # login expired return self.redirect_to_url(['/manager/appinstall', appid], _qs={'error': _('SplunkApps login timed out'), 'state': state.serialize()}) except Exception, e: logger.exception(e) if e.statusCode == 403: return self.render_admin_template('/admin/appinstall/sb-login.html', { 'appid': appid, 'breadcrumbs': state['breadcrumbs'], 'error': _('SplunkApps login timed out'), 'state': state, 'next': install }) else: return self.redirect_to_url(['/manager/appinstall', appid], _qs={'error': _('An error occurred while downloading the app: %s') % str(e), 'state': state.serialize()})
def getRestData(uri, sessionKey, data = None, output_mode = 'json'): if data == None: if output_mode == 'default': serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey) else: serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, getargs={'output_mode': 'json'}) else: if output_mode == 'default': serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, jsonargs=data) else: serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, jsonargs=data, getargs={'output_mode': 'json'}) #log.debug("serverResponse: %s" % serverResponse) #log.debug("serverContent: %s" % serverContent) returnData = json.loads(serverContent) return returnData
def processAppUpload(self, f, force): """ Process a file uploaded from the upload page """ if not (isinstance(f, cgi.FieldStorage) and f.file): raise SBFileUploadException(_("No file was uploaded.")) # Copy uploaded data to a named temporary file fd, tmpPath = tempfile.mkstemp() tfile = os.fdopen(fd, "w+") shutil.copyfileobj(f.file, tfile) tfile.flush() # leave the file open, but flush so it's all committed to disk try: args = { 'name': tmpPath, 'filename' : 1 } if force: args['update'] = 1 response, content = rest.simpleRequest('apps/local', postargs=args, sessionKey=cherrypy.session['sessionKey']) if response.status in (200, 201): atomFeed = rest.format.parseFeedDocument(content) return atomFeed[0].toPrimitive()['name'] elif response.status == 409: raise SBFileUploadException(_("App with this name already exists.")) raise SBFileUploadException(_("There was an error processing the upload.")) except splunk.AuthorizationFailed: raise SBFileUploadException(_("Client is not authorized to upload apps.")) finally: shutil.rmtree(tmpPath, True)
def index(self, **params): ssId = params.get('s') #no ssId if not ssId: raise cherrypy.HTTPError(400, _('Must specify a savedsearch id.')) #fetch saved search responseHeaders, responseBody = simpleRequest(ssId, method='GET', getargs={'output_mode':'json'}, sessionKey=cherrypy.session['sessionKey']) savedSearchJSON = json.loads(responseBody) app = savedSearchJSON['entry'][0]['content'].get("request.ui_dispatch_app") or\ savedSearchJSON['entry'][0]['acl'].get("app") or 'search' #scheduled view if '_ScheduledView__' in ssId: #redirect to dashboard page name = savedSearchJSON['entry'][0]['name'] name = string.replace(name, '_ScheduledView__', '', 1) self.redirect_to_url(['app', app, name], _qs={'dialog': 'schedulePDF'}) if savedSearchJSONIsAlert(savedSearchJSON): #if alert route to :app/alert?s=ssId self.redirect_to_url(['app', app, 'alert'], _qs={'s': ssId, 'dialog': 'actions'}) #report - :app/report?s=ssId self.redirect_to_url(['app', app, 'report'], _qs={'s': ssId, 'dialog': 'schedule'}) return
def createContext(incident, incident_settings, results): context = { } try: uri = '/services/server/info?output_mode=json' serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey) server_info = json.loads(serverContent) if len(server_info) > 0: server_info = server_info["entry"][0]["content"] context.update({ "alert_time" : incident["alert_time"] }) context.update({ "owner" : incident["owner"] }) context.update({ "name" : incident["alert"] }) context.update({ "alert" : { "impact": incident["impact"], "urgency": incident["urgency"], "priority": incident["priority"], "expires": incident["ttl"] } }) context.update({ "app" : incident["app"] }) context.update({ "category" : incident_settings['category'] }) context.update({ "subcategory" : incident_settings['subcategory'] }) context.update({ "tags" : incident_settings['tags'] }) context.update({ "results_link" : "http://"+server_info["host_fqdn"] + ":8000/app/" + incident["app"] + "/@go?sid=" + incident["job_id"] }) context.update({ "view_link" : "http://"+server_info["host_fqdn"] + ":8000/app/" + incident["app"] + "/alert?s=" + urllib.quote("/servicesNS/nobody/"+incident["app"]+"/saved/searches/" + incident["alert"] ) }) context.update({ "server" : { "version": server_info["version"], "build": server_info["build"], "serverName": server_info["serverName"] } }) if "fields" in results: result_context = { "result" : results["fields"] } context.update(result_context) except Exception as e: log.error("Unexpected Error: %s" % (traceback.format_exc())) return context
def test_ping_handler(self): """ Make sure the handler is onlne. """ response, content = simpleRequest("/services/data/lookup_backup/ping", sessionKey=self.get_session_key()) self.assertEqual(response.status, 200)
def update(self, appid, state, update=None, **kw): """ Attempt to download and install an app update from Splunkbase """ if not isinstance(state, StateDict): state = StateDict.unserialize(state) sbSessionKey = self.getSBSessionKey() if not sbSessionKey: # login required return self.render_admin_template('/admin/appinstall/sb-login.html', { 'appid': appid, 'breadcrumbs': state['breadcrumbs'], 'state': state, 'next': 'update' }) url = 'apps/local/%s/update' % appid requestArgs = { 'auth': urllib.quote(sbSessionKey), 'implicit_id_required' : state.get('implicit_id_required') } try: logger.info("Updating app %s" % appid) response, content = rest.simpleRequest(url, postargs=requestArgs, sessionKey=cherrypy.session['sessionKey']) except splunk.AuthenticationFailed: # login expired return self.redirect_to_url(['/manager/appinstall', appid], _qs={'error': _('Splunkbase login timed out'), 'state': state.serialize()}) except Exception, e: return self.redirect_to_url(['/manager/appinstall', appid], _qs={'error': _('An error occurred while downloading the app: %s') % str(e), 'state': state.serialize()})
def reload( session_key=None ): path = SplunkLookupTableFile.resource + "/" + '_reload' response, content = rest.simpleRequest(path, method='GET', sessionKey=session_key) if response.status == 200: return True return False
def validate_time(self, time): try: serverResponse, serverContent = rest.simpleRequest('/services/search/timeparser', getargs={'time': time, 'output_mode':'json'}, rawResult=True) except Exception: return False if serverResponse and serverResponse.status == 200: return True return False
def quick_and_dirty_call(uri, type, getargs, postargs, namespace, owner, method='GET', sessionKey=''): """""" qad_uri = buildEndpoint(uri, entityName='', namespace=namespace, owner=owner) try: serverResponse, serverContent = simpleRequest(qad_uri, sessionKey=sessionKey, getargs=getargs, postargs=postargs, method=method) except Exception, e: logger.debug('Could not construct quick_and_dirty uri: %s, %s' % (str(qad_uri), str(e))) raise CliArgError, 'Could not get app context'
def get_results(self): try: job_uri = "/servicesNS/nobody/%s/search/jobs/%s?output_mode=json" % (self.app, self.sid) serverResponse, serverContent = rest.simpleRequest(job_uri, sessionKey=self.session_key) self.job = json.loads(serverContent)["entry"][0] results_uri = "/servicesNS/nobody/%s/search/jobs/%s/results?output_mode=json" % (self.app, self.sid) serverResponse, serverContent = rest.simpleRequest(results_uri, sessionKey=self.session_key) self.results = json.loads(serverContent) except Exception, e: exc_type, exc_obj, exc_tb = sys.exc_info() print >>sys.stderr, 'error="%s" object="%s" line=%s message="%s"' % ( exc_type, exc_obj, exc_tb.tb_lineno, "WARN: Unexpected exception seen getting search result data from REST API", )
def save(self, contents, **kwargs): logger.info("Saving user settings contents...") user = cherrypy.session['user']['name'] sessionKey = cherrypy.session.get('sessionKey') # Parse the JSON parsed_contents = json.loads(contents) logger.debug("Contents: %s" % contents) for entry in parsed_contents: if '_key' in entry and entry['_key'] != None and entry['_key'] != 'n/a': uri = '/servicesNS/nobody/alert_manager/storage/collections/data/alert_users/' + entry['_key'] logger.debug("uri is %s" % uri) del entry['_key'] if 'type' in entry: del entry['type'] entry = json.dumps(entry) serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, jsonargs=entry) logger.debug("Updated entry. serverResponse was %s" % serverResponse) else: if '_key' in entry: del entry['_key'] if 'type' in entry: del entry['type'] ['' if val is None else val for val in entry] uri = '/servicesNS/nobody/alert_manager/storage/collections/data/alert_users/' logger.debug("uri is %s" % uri) entry = json.dumps(entry) logger.debug("entry is %s" % entry) serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, jsonargs=entry) logger.debug("Added entry. serverResponse was %s" % serverResponse) return 'Data has been saved'
def disable(self): output = False if self.action_links: for item in self.action_links: if 'enable' in item: response, content = rest.simpleRequest(item[1], method='POST') if response.status == 200: output = True return output
def delete(self): if not self.action_links: return False for item in self.action_links: if 'remove' in item: response, content = rest.simpleRequest(item[1], method='DELETE') if response.status == 200: return True return False
def disable(self): if not self.action_links: return True for item in self.action_links: if 'disable' in item: response, content = rest.simpleRequest(item[1], method='POST') if response.status == 200: return True return False
def clear_data(self, **kwargs): user = cherrypy.session['user']['name'] sessionKey = cherrypy.session.get('sessionKey') logger.info("Clearing demo data...") uri = '/servicesNS/nobody/alert_manager/storage/collections/data/alert_settings' serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, method='DELETE') logger.info("alert_settings cleared.") uri = '/servicesNS/nobody/alert_manager/storage/collections/data/alert_users' serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, method='DELETE') logger.info("alert_users cleared.") uri = '/servicesNS/nobody/alert_manager/storage/collections/data/incidents' serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, method='DELETE') logger.info("incidents cleared.") return 'Demo data has been cleared'
def createTestUser(tz, sessionKey): uri = entity.buildEndpoint('authentication', 'users') userName = str(uuid.uuid1()) postargs = { "name": userName, "password": "******", "roles": "user", "tz": tz } (response, content) = rest.simpleRequest(uri, postargs=postargs, sessionKey=sessionKey) return userName
def getLookupFile(lookup_name): try: uri = '/servicesNS/nobody/alert_manager/data/transforms/lookups/%s?output_mode=json' % lookup_name serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey) lookup = json.loads(serverContent) log.debug("Got lookup content for lookup=%s. filename=%s app=%s" % (lookup_name, lookup["entry"][0]["content"]["filename"], lookup["entry"][0]["acl"]["app"])) return os.path.join(os.path.join(os.environ.get('SPLUNK_HOME')), 'etc', 'apps', lookup["entry"][0]["acl"]["app"], 'lookups', lookup["entry"][0]["content"]["filename"]) except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() log.warn("Unable to get lookup %s. Reason: %s. Line: %s" % (lookup_name, config['default_priority'], exc_type, exc_tb.tb_lineno)) return ""
def get_email_template(self, template_name): query = {} query["email_template_name"] = template_name uri = '/servicesNS/nobody/alert_manager/storage/collections/data/email_templates?output_mode=json&query=%s' % urllib.quote(json.dumps(query)) serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=self.sessionKey) self.log.debug("Response for template listing: %s" % serverContent) entries = json.loads(serverContent) if len(entries) > 0: return entries[0] else: return False
def __init__(self, file_path='', lookup_name='', sessionKey=''): # Reset on init to avoid strange caching effects self.csv_data = [] log.debug("file_path: '%s', lookup_name: '%s'" % (file_path, lookup_name)) if file_path == '': if lookup_name == '': raise Exception("No file_path or lookup_name specified.") else: if sessionKey == '': raise Exception( "No sessionKey provided, unable to query REST API.") else: # Get csv name from API uri = '/servicesNS/nobody/alert_manager/data/transforms/lookups/%s' % lookup_name serverResponse, serverContent = rest.simpleRequest( uri, sessionKey=sessionKey, method='GET', getargs={'output_mode': 'json'}) try: lookup = json.loads(serverContent) file_path = os.path.join( util.get_apps_dir(), lookup["entry"][0]["acl"]["app"], 'lookups', lookup["entry"][0]["content"]["filename"]) log.debug( "Got file_path=%s from REST API for lookup_name=%s" % (file_path, lookup_name)) except: log.error("Unable to retrieve lookup.") raise Exception("Unable to retrieve lookup.") else: log.debug("file_path=%s is set, don't have to query the API." % file_path) if not os.path.exists(file_path): log.error("Wasn't able to find file_path=%s, aborting." % file_path) raise Exception("File %s not found." % file_path) else: with open(file_path) as fh: reader = csv.DictReader(fh) for row in reader: self.csv_data.append(row)
def post_lookup_contents(self, request_info, contents=None, lookup_file=None, namespace="lookup_editor", owner=None, **kwargs): """ Save the JSON contents to the lookup file. """ self.logger.info("Saving lookup contents...") try: # Backup the lookup file data = { 'lookup_file': lookup_file, 'namespace': namespace, 'owner': owner, 'file_time': time.time() } try: _, _ = simpleRequest('/services/data/lookup_backup/backup', sessionKey=request_info.session_key, method='POST', postargs=data) except ResourceNotFound: self.logger.info( "Existing lookup could not be found for backup") file_name = self.lookup_editor.update(contents, lookup_file, namespace, owner, request_info.session_key, request_info.user) # Everything worked, return accordingly return { 'payload': str(file_name), # Payload of the request. 'status': 200 # HTTP status code } except LookupNameInvalidException: return self.render_error_json("Lookup name is invalid", 400) except: self.logger.exception("Unable to save the lookup") return self.render_error_json("Unable to save the lookup")
def get_paths(self): # Get file paths from conf file try: _, serverContent = rest.simpleRequest( "/servicesNS/nobody/{}/configs/conf-{}?output_mode=json".format(APP_NAME, CONF_FILE), sessionKey=self.sessionKey) data = json.loads(serverContent)['entry'] for i in data: if i['name'] == STANZA_NAME: self.savepath = i['content']['savepath'] self.pendingPath = i['content']['temppath'] logger.info("Got savepath and pending path from uploader.conf. savepath={} pendingpath={}".format(self.savepath, self.pendingPath)) break except Exception as e: logger.error("Unable to fetch file paths from uploader.conf file." + str(e)) raise
def getRestData(uri, sessionKey, data=None, output_mode='json'): try: if data == None: if output_mode == 'default': serverResponse, serverContent = rest.simpleRequest( uri, sessionKey=sessionKey) else: serverResponse, serverContent = rest.simpleRequest( uri, sessionKey=sessionKey, getargs={'output_mode': 'json'}) else: if output_mode == 'default': serverResponse, serverContent = rest.simpleRequest( uri, sessionKey=sessionKey, jsonargs=data) else: serverResponse, serverContent = rest.simpleRequest( uri, sessionKey=sessionKey, jsonargs=data, getargs={'output_mode': 'json'}) except: log.info( "An error occurred or no data was returned from the server query.") serverContent = None log.debug("serverResponse: {}".format(serverResponse)) log.debug("serverContent: {}".format(serverContent.decode('utf-8'))) try: returnData = json.loads(serverContent.decode('utf-8')) except: log.info( "An error occurred or no data was returned from the server query.") returnData = [] return returnData
def app_configured(self): sessionKey = self.getSessionKey() try: conf = bundle.getConf('app', sessionKey, namespace=mmdb_utils.APP_NAME, owner='nobody') stanza = conf.stanzas['install'].findKeys('is_configured') if stanza: if stanza["is_configured"] == "0" or stanza[ "is_configured"] == "false": conf["install"]["is_configured"] = 'true' rest.simpleRequest("/apps/local/{}/_reload".format( mmdb_utils.APP_NAME), sessionKey=sessionKey) else: conf["install"]["is_configured"] = 'true' rest.simpleRequest("/apps/local/{}/_reload".format( mmdb_utils.APP_NAME), sessionKey=sessionKey) except Exception as e: raise Exception( 'Unable to set is_configured parameter in local app.conf file. {}' .format(e))
def update_lookup_table(filename, lookup_file, namespace, owner, key): '''Update a Splunk lookup table file with a new file. @param filename: The full path to the replacement lookup table file. @param lookup_file: The lookup FILE name (NOT the stanza name) @param namespace: A Splunk namespace to limit the search to. @param owner: A Splunk user. @param key: A Splunk session key. @return: Boolean success status. WARNING: "owner" should be "nobody" to update a public lookup table file; otherwise the file will be replicated only for the admin user. ''' # Create the temporary location path lookup_tmp = make_splunkhome_path(['var', 'run', 'splunk', 'lookup_tmp']) destination_lookup_full_path = os.path.join(lookup_tmp, lookup_file) # Copy the file to the temporary location shutil.move(filename, destination_lookup_full_path) # CReate the URL for the REST call url = '/servicesNS/%s/%s/data/lookup-table-files/%s' % (owner, namespace, lookup_file) postargs = { 'output_mode': 'json', 'eai:data': str(destination_lookup_full_path) } # Perform the call rest.simpleRequest(url, postargs=postargs, sessionKey=key, raiseAllErrors=True)
def set_incident_comment(incident_id, external_key, session_key): uri = "/services/alert_manager/helpers" post_args = '{"action": "write_log_entry", "log_action": "comment", "origin": "externalworkflowaction", "incident_id": "%s", "comment": "Updated external_reference_id=%s"}' % ( incident_id, external_key) try: server_response, server_content = rest.simpleRequest(uri, sessionKey=session_key, postargs=json.loads(post_args), method='POST') except Exception, e: print >> sys.stderr, "ERROR Unexpected error: %s" % e error("Unexpected error: %s" % e) server_response = None server_content = None
def checkKvStore(self): try: query = { } uri = '/servicesNS/nobody/alert_manager/storage/collections/data/email_templates?query=%s' % urllib.quote(json.dumps(query)) serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=self.sessionKey) if serverResponse['status'] == '503': self.log.debug("KVStore unavailable. Response status: %s" % serverResponse['status']) return False else: self.log.debug("KVStore is available. Response status: %s" % serverResponse['status']) return True except Exception as e: self.log.debug("KVStore unavailable. Exception: %s" % str(e)) return False
def update_item_by_key(self, key, updated_item): """ Update an item of kvstore. :param key: key id in kvstore :param updated_item: a json-able object (such as a dict) containing new values of ALL attributes :return: response, content """ json_args = json.dumps(updated_item) key = self.uri_encode(key) post_url = '%s/%s' % (self.uri, key) return rest.simpleRequest(post_url, sessionKey=self.session_key, jsonargs=json_args, method='POST', raiseAllErrors=True)
def timeParser(ts='now', session_key=None): getargs = {} getargs['time'] = ts tsStatus, tsResp = rest.simpleRequest('/search/timeparser', sessionKey=session_key, getargs=getargs) root = et.fromstring(tsResp) ts = root.find('dict/key') if ts != None: return util.parseISO(ts.text, strict=True) else: logger.warn("Could not retrieve timestamp for specifier '%s' from /search/timeparser" % (getargs['time']) ) return False
def delete(self, key, **kwargs): logger.info("Removing incident settings contents for %s..." % key) user = cherrypy.session['user']['name'] sessionKey = cherrypy.session.get('sessionKey') query = {} query['_key'] = key logger.debug("Query for incident settings: %s" % urllib.quote(json.dumps(query))) uri = '/servicesNS/nobody/alert_manager/storage/collections/data/incident_settings?query=%s' % urllib.quote(json.dumps(query)) serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey, method='DELETE') logger.debug("Entry removed. serverResponse was %s" % serverResponse) return 'Incident settings have been removed for entry with _key=%s' % key
def get_server_apps(uri, session_key, app=None): apps = [] if app is not None: apps.append(app) else: # Enumerate all remote apps apps_uri = uri + '/services/apps/local?output_mode=json' content = rest.simpleRequest(apps_uri, sessionKey=session_key, method='GET')[1] content = json.loads(content) for entry in content["entry"]: if not entry["content"]["disabled"]: apps.append(entry["name"]) return apps
def _get_notification_schemes(self, sessionKey, query_params): logger.debug("START _get_notification_schemes()") uri = '/servicesNS/nobody/alert_manager/storage/collections/data/notification_schemes?q=output_mode=json' serverResponse, serverContent = rest.simpleRequest( uri, sessionKey=sessionKey, method='GET') logger.debug("notification_schemes: %s" % serverContent) entries = json.loads(serverContent) scheme_list = [] if len(entries) > 0: for entry in entries: scheme_list.append(entry['schemeName']) return self.response(scheme_list, httplib.OK)
def call_peer(remote_host, remote_user, local_host, local_user, ts, nonce, signature): #DBX-2442 if not utils.validateHostName(remote_host): logger.debug("invalid remote_host") return None if not utils.validateHostName(local_host): logger.debug("invalid local_host") return None if not utils.validateUserName(remote_user): logger.debug("invalid remote_user") return None if not utils.validateUserName(local_user): logger.debug("invalid local_user") return None ''' make remote REST call to retreive foreign sessionKey ''' postargs = { 'name': '_create', USERID: local_user, PEERNAME: local_host, USERNAME: remote_user, TS: ts, NONCE: nonce, SIGNATURE: signature } logger.debug('call peer: remote_host=%s postargs=%s' % (remote_host, postargs)) resp, cont = rest.simpleRequest(remote_host + AUTH_TOKENS_ENDPOINT, postargs=postargs) if resp.status not in [200, 201]: logger.error('unable to get session key from remote peer %s' % remote_host) return None try: atomEntry = rest.format.parseFeedDocument(cont) logger.debug('response from peer:\n%s' % atomEntry.toPrimitive()) ret = atomEntry.toPrimitive()[remote_user][remote_user] return ret except Exception, ex: logger.error('unable to parse response from remote peer %s' % remote_host) logger.exception(ex) return None
def _enableInputs(appName, sessionKey): os_altsep = '\\' if os.path.sep == '/' else '/' inputsConf = en.getEntities('data/inputs/script', sessionKey=sessionKey, search='eai:acl.app=' + appName) for stanza in inputsConf: if stanza.endswith('monitor.py'): uri = None if os_altsep in stanza: uri = inputsConf[stanza].getLink('disable') else: uri = inputsConf[stanza].getLink('enable') if uri: serverResponse, serverContent = rest.simpleRequest( uri, sessionKey=sessionKey, method='POST')
def _get_freezer_info(self, sessionKey, query_params): logger.debug("START _get_freezer_info()") splunk.setDefault('sessionKey', sessionKey) freezers_uri = '/servicesNS/nobody/FreezerInventoryAppForSplunk/storage/collections/data/freezers?output_mode=json' # Get item json serverResponse, serverContent = rest.simpleRequest(freezers_uri, sessionKey=sessionKey, method='GET') logger.debug("freezers: %s" % serverContent) freezers = json.loads(serverContent) for freezer in freezers: if freezer['id'] == query_params['id']: freezer_info = freezer return self.response(freezer_info, httplib.OK)
def get_app_list_request(authtoken, params=None): """ Returns a list of all splunk apps viewable using the permissions of the supplied authtoken :param authtoken: Authorization token :return: List of Splunk apps """ request_url = '{}services/apps/local'.format(rest.makeSplunkdUri()) params = params if params is not None else {} _, content = rest.simpleRequest(request_url, sessionKey=authtoken, method='GET', getargs=params, raiseAllErrors=True) return json.loads(content)
def __init__(self, sessionKey, schemeName, currentAssignee=None): self.sessionKey = sessionKey # Retrieve notification scheme from KV store schemeFilter = {} schemeFilter["schemeName"] = schemeName uri = '/servicesNS/nobody/alert_manager/storage/collections/data/notification_schemes/?query=%s' % urllib.quote(json.dumps(schemeFilter)) schemeFilter = json.dumps(schemeFilter) serverResponse, serverContent = rest.simpleRequest(uri, sessionKey=sessionKey) # TODO: Check response, fall back to default notification scheme entries = json.loads(serverContent) scheme = entries[0] self.schemeName = scheme["schemeName"] self.displayName = scheme["displayName"] self.notifications = self.parseNotifications(scheme["notifications"])
def get_deployment_info(session_key, default_value=""): base_uri = rest.makeSplunkdUri() uri = '{}services/ssg/kvstore/deployment_info'.format(base_uri) try: r, content = rest.simpleRequest(uri, sessionKey=session_key, method='GET', raiseAllErrors=False) parsed = json.loads(content) return parsed except Exception as e: LOGGER.exception("Exception fetching ssg meta info") return default_value
def __init__(self, sessionKey): self.sessionKey = sessionKey # Setup template paths local_dir = os.path.join(os.environ.get('SPLUNK_HOME'), "etc", "apps", "alert_manager", "default", "templates") default_dir = os.path.join(os.environ.get('SPLUNK_HOME'), "etc", "apps", "alert_manager", "local", "templates") # Get mailserver settings from splunk uri = '/servicesNS/nobody/system/configs/conf-alert_actions/email?output_mode=json' serverResponse, serverContent = rest.simpleRequest( uri, sessionKey=self.sessionKey) server_settings = json.loads(serverContent) server_settings = server_settings["entry"][0]["content"] #self.log.debug("server settings from splunk: %s" % json.dumps(server_settings)) # Parse mailserver if ":" in server_settings['mailserver']: match = re.search(r'([^\:]+)\:(\d+)', server_settings['mailserver']) mailserver = match.group(1) mailport = int(match.group(2)) else: mailserver = server_settings['mailserver'] mailport = 25 self.log.debug("Parsed mailserver settings. Host: %s, Port: %s" % (mailserver, mailport)) use_ssl = False if server_settings['use_ssl'] == "1": use_ssl = True use_tls = False if server_settings['use_tls'] == "1": use_tls = True # Configure django settings settings.configure( TEMPLATE_DIRS=(default_dir, local_dir), EMAIL_HOST=mailserver, EMAIL_PORT=mailport, EMAIL_HOST_USER=server_settings['auth_username'], EMAIL_HOST_PASSWORD=server_settings['auth_password'], EMAIL_USE_TLS=use_tls, EMAIL_USE_SSL=use_ssl)
def getRetentionFilter(self, ls, modelJson=None): retentionTemplate = '''| where strptime('%s', "%s")>=relative_time(now(), "%s")''' retentionDict = ls.get('retention', False) if retentionDict: earliestTime = retentionDict.get('earliestTime', False) timeField = retentionDict.get('timeField', False) timeFormat = retentionDict.get('timeFormat', False) if earliestTime and timeField and timeFormat: r, c = simpleRequest('/search/timeparser', sessionKey=self.sessionKey, getargs={ 'output_mode': 'json', 'time': earliestTime }) if r.status != 200: e = 'A valid retention period must specify a valid earliestTime' self.logger.error(e) raise InvalidRetentionFilter(e) if timeField not in self.getAvailableFields( ls, modelJson=modelJson): e = 'A valid retention period must specify a valid timeField' self.logger.error(e) raise InvalidRetentionFilter(e) ts = datetime.datetime.now() tf = ts.strftime(timeFormat) ## python returns this differently depending on the platform if tf == timeFormat or tf == timeFormat.replace('%', ''): e = 'A valid retention period must specify a valid timeFormat' self.logger.error(e) raise InvalidRetentionFilter(e) return retentionTemplate % (timeField, timeFormat, earliestTime) else: e = 'A valid retention period must specify an earliestTime, timeField, and timeFormat' self.logger.error(e) raise InvalidRetentionFilter(e) else: self.logger.warn('No retention period specified') return ''
def getUserList(self): # Get alert manager config config = {} config['user_directories'] = 'both' restconfig = entity.getEntities('configs/alert_manager', count=-1, sessionKey=self.sessionKey) if len(restconfig) > 0: for cfg in config.keys(): if cfg in restconfig['settings']: config[cfg] = restconfig['settings'][cfg] uri = '/servicesNS/nobody/alert_manager/storage/collections/data/alert_users?output_mode=json' serverResponse, serverContent = rest.simpleRequest( uri, sessionKey=self.sessionKey) entries = json.loads(serverContent.decode('utf-8')) user_list = [] if config['user_directories'] == "builtin" or config[ 'user_directories'] == "both": if len(entries) > 0: for entry in entries: if 'type' in entry and entry['type'] == "builtin": if 'user' in entry: del (entry['user']) if '_user' in entry: del (entry['_user']) if '_key' in entry: del (entry['_key']) user_list.append(entry) if config['user_directories'] == "alert_manager" or config[ 'user_directories'] == "both": if len(entries) > 0: for entry in entries: if 'type' not in entry or entry['type'] == "alert_manager": if 'user' in entry: del (entry['user']) if '_user' in entry: del (entry['_user']) if '_key' in entry: del (entry['_key']) user_list.append(entry) return user_list
def __init__(self, sessionKey): self.sessionKey = sessionKey # Setup template paths local_dir = os.path.join(os.environ.get('SPLUNK_HOME'), "etc", "apps", "alert_manager", "default", "templates") default_dir = os.path.join(os.environ.get('SPLUNK_HOME'), "etc", "apps", "alert_manager", "local", "templates") loader = FileSystemLoader([default_dir, local_dir]) self.env = Environment(loader=loader, variable_start_string='$', variable_end_string='$') # TODO: Add support for custom filters self.env.filters['get_type'] = get_type # Get mailserver settings from splunk uri = '/servicesNS/nobody/system/configs/conf-alert_actions/email?output_mode=json' serverResponse, serverContent = rest.simpleRequest( uri, sessionKey=self.sessionKey) server_settings = json.loads(serverContent) server_settings = server_settings["entry"][0]["content"] #self.log.debug("server settings from splunk: %s" % json.dumps(server_settings)) self.default_sender = server_settings['from'] use_ssl = False if server_settings['use_ssl']: use_ssl = True use_tls = False if server_settings['use_tls']: use_tls = True # Configure django settings clear_pass = '' if 'clear_password' in server_settings: clear_pass = server_settings['clear_password'] self.settings = { "MAIL_SERVER": server_settings['mailserver'], "EMAIL_HOST_USER": server_settings['auth_username'], "EMAIL_HOST_PASSWORD": clear_pass, "EMAIL_USE_TLS": use_tls, "EMAIL_USE_SSL": use_ssl }
def install(self, appid, state, install=None, **kw): """ Start the app download and installation processs """ if not isinstance(state, StateDict): state = StateDict.unserialize(state) sbSessionKey = self.getSBSessionKey() if not sbSessionKey: logger.warn( "Attempted install of app '%s' with sbSessionKey unset" % appid) return self.redirect_to_url(['/manager/appinstall/', appid], _qs={'state': state.serialize()}) # don't hold the session lock through network I/O cherrypy.session.release_lock() # attempt to actually install the app url = 'apps/remote/entriesbyid/%s' % appid requestArgs = {'action': 'install', 'auth': urllib.quote(sbSessionKey)} try: logger.info("Installing app %s" % appid) response, content = rest.simpleRequest( url, postargs=requestArgs, sessionKey=cherrypy.session['sessionKey'], timeout=APP_INSTALL_TIMEOUT) except splunk.AuthenticationFailed: # login expired return self.redirect_to_url( ['/manager/appinstall', appid], _qs={ 'error': _('Splunkbase login timed out'), 'state': state.serialize() }) except Exception, e: logger.exception(e) return self.redirect_to_url( ['/manager/appinstall', appid], _qs={ 'error': _('An error occurred while downloading the app: %s') % str(e), 'state': state.serialize() })
def add_to_collection(self): issues_entry = {} # JIRA fields issues_entry['project'] = issue.fields.project.key issues_entry['key'] = issue.key issues_entry['id'] = issue.id issues_entry['summary'] = issue.fields.summary issues_entry['issuetype'] = issue.fields.issuetype.name if issue.fields.assignee: issues_entry['assignee'] = issue.fields.assignee.key else: issues_entry['assignee'] = None issues_entry['reporter'] = issue.fields.reporter.key issues_entry['created'] = issue.fields.created issues_entry['updated'] = issue.fields.updated if issue.fields.resolution: issues_entry['resolution'] = issue.fields.resolution.name else: issues_entry['resolution'] = None issues_entry['labels'] = issue.fields.labels issues_entry['priority'] = issue.fields.priority.name # event data issues_entry['group_by_field'] = template_conf['group_by_field'] issues_entry['event_hash'] = entry['event_hash'] issues_entry['search_name'] = entry['savedsearch_name'] issues_entry['search_id'] = entry['sid'] issues_entry['trigger_time'] = entry['trigger_time'] now = datetime.datetime.now() expires = datetime.datetime.fromtimestamp(entry['trigger_time'] + entry['ttl']) ttl = (expires - now).total_seconds() issues_entry['keywords'] = ttl issues_entry['keywords'] = entry['keywords'] issues_entry['event_count'] = entry['event_count'] issues_entry['result_count'] = entry['result_count'] issues_entry['update_count'] = 0 # ... then add issues to collections ... issues_entry_uri = '/servicesNS/nobody/jira/storage/collections/data/issues/' serverResponse, serverContent = rest.simpleRequest(issues_entry_uri, sessionKey=sessionKey, jsonargs=json.dumps(issues_entry)) new_issue = json.loads(serverContent) new_alert = json.loads(serverContent) issues_entry['_key'] = new_alert['_key'] return issues_entry
def get_email_template(self, template_name): query = {} query["template_name"] = template_name uri = '/servicesNS/nobody/alert_manager/storage/collections/data/email_templates?output_mode=json&query=%s' % urllib.quote( json.dumps(query)) serverResponse, serverContent = rest.simpleRequest( uri, sessionKey=self.sessionKey) self.log.debug("Response for template listing: %s" % serverContent) entries = json.loads(serverContent) if len(entries) > 0: return entries[0] else: self.log.error( "Template %s not found in email_templates! Aborting..." % template_name) return False
def getNotificationSchemeName(self, alert): # Retrieve notification scheme from KV store query_filter = {} query_filter["alert"] = alert uri = '/servicesNS/nobody/alert_manager/storage/collections/data/incident_settings/?query=%s' % urllib.quote( json.dumps(query_filter)) serverResponse, serverContent = rest.simpleRequest( uri, sessionKey=self.sessionKey) entries = json.loads(serverContent) try: return entries[0]["notification_scheme"] except Exception as e: # TODO: Check response, fall back to default notification scheme return None
def test_kv_export(self): """ Test whether the exported CSV file matches. """ url = ('/services/data/lookup_edit/lookup_as_file?' 'namespace=lookup_test&owner=nobody' '&lookup_file=test_kv_store_hierarchy&lookup_type=kv') response, content = simpleRequest(url, sessionKey=self.get_session_key()) self.assertEqual(response.status, 200) first_line = content.split('\n')[0] self.assertEqual(first_line.count(","), 7)
def do_POST(self, path, postargs=None): _postargs = copy.deepcopy(self.postargs) if self.postargs else None if postargs: if _postargs: _postargs.update(postargs) else: _postargs = postargs resp, cont = rest.simpleRequest(self.make_uri(path), self.sessionKey, postargs=_postargs) if resp.status not in [200, 201]: raise BaseException(cont) try: atomEntry = rest.format.parseFeedDocument(cont) except Exception, e: return None
def handleList(self, confInfo): user, app = self.user_app() try: response, content = \ rest.simpleRequest(self.makeRequestURL(), sessionKey=self.getSessionKey(), method='GET', raiseAllErrors=True) res = json.loads(content) if 'entry' in res: for entry in res['entry']: name, ent = entry['name'], entry['content'] ent[admin.EAI_ENTRY_ACL] = entry['acl'] ent = self.decode(name, self.convert(ent)) util.makeConfItem(name, ent, confInfo, user=user, app=app) except Exception as exc: RH_Err.ctl(-1, msgx=exc, logLevel=logging.INFO) return