def save_stream(self, **kwargs): amp_api = ApiService(kwargs['api_host'], kwargs['api_id'], kwargs['api_key']) storage = AmpStorageWrapper(self.__metadata(kwargs.get('name'))) stream = storage.find_stream() if stream is None: logger.info('Controller - Creating the stream at API') response = amp_api.create(kwargs) logger.info('Controller - Created the stream at API: {}'.format( kwargs.get('name'))) storage.save_stream_with_data( StreamDictManager(response['data']).merged_with(kwargs)) else: dict_manager = StreamDictManager(stream) diff = dict_manager.diff_fields_from(kwargs) if len(diff) > 0: logger.info( 'Controller - Updating the stream at API {}'.format( stream.get('name'))) amp_api.update(stream['id'], diff) storage.save_stream_with_data(dict_manager.merged_with(kwargs)) logger.info('Controller - Updated the stream at API') output = jsonresponse.JsonResponse() output.success = True return self.render_json(output)
def save_api_key(self, **kwargs): session_key = cherrypy.session.get('sessionKey') service = client.connect(token=session_key) service.storage_passwords.create(kwargs['api_key'], kwargs['api_id']) output = jsonresponse.JsonResponse() output.success = True return self.render_json(output)
def delete_event_stream(self, **kwargs): amp_api = ApiService(kwargs['api_host'], kwargs['api_id'], kwargs['api_key']) self.__try_destroy_stream(amp_api, kwargs['id']) output = jsonresponse.JsonResponse() output.success = True return self.render_json(output)
def build_response(self, entities, selectionMode=None): output = jsonresponse.JsonResponse() output.count = entities.itemsPerPage output.offset = entities.offset output.total = entities.totalResults output.data = [] if entities: if len(entities) == 1 and not entities.values()[0].get('name'): # empty node return output blocks = [] for ent in entities.values(): hasChildren = util.normalizeBoolean(ent.get('hasSubNodes', True)) block = {'text': ent.get('name', ent.name), 'fileSize': ent.get('fileSize'), 'id': ent.name, 'hasChildren': hasChildren, 'classes': 'nonleaf' if hasChildren else 'leaf', 'selectable': self.is_selectable(ent, selectionMode) } blocks.append(block) output.data = sorted(blocks, key=lambda block: block['text'].lower()) return output
def getPanel(self, namespace, view_id, panel_type, panel_sequence, **unused): ''' Returns a dashboard panel config GET /<namespace>/<view_id>/panel/<panel_sequence> --> panel config for panel at <panel_sequence> ==> returns a JSON response ''' output = jsonresponse.JsonResponse() try: username = cherrypy.session['user'].get('name') dash_id = en.buildEndpoint(VIEW_ENTITY_CLASS, view_id, namespace=namespace, owner=username) dashObject = Dashboard.get(dash_id) output.data = dashObject.get_panel(panel_sequence) except IndexError, e: cherrypy.response.status = 404 output.success = False output.addError( _('Requested panel %s does not exist') % panel_sequence)
def insecurelogin(self, username=None, password=None, return_to=None): ''' Provide insecure login endpoint for HTTP GET-based credential passing ''' # Force a refresh of startup info so that we know to # redirect if license stuff has expired. startup.initVersionInfo(force=True) output = jsonresponse.JsonResponse() if not splunk.util.normalizeBoolean( cherrypy.config.get('enable_insecure_login')): cherrypy.response.status = 403 output.success = False output.addError( 'The insecure login endpoint is disabled. See web.conf for details.' ) return self.render_json(output) if not username or not password: cherrypy.response.status = 400 output.success = False output.addError('Missing credentials') return self.render_json(output) try: sessionKey = splunk.auth.getSessionKey( username, password, hostPath=self.splunkd_urlhost) except Exception, e: output.parseRESTException(e) output.success = False return self.render_json(output)
def render_error_json(self, msg): output = jsonresponse.JsonResponse() output.data = [] output.success = False output.addError(msg) cherrypy.response.status = 400 return self.render_json(output, set_mime='text/plain')
def render_error_json(self, msg): """ Render JSON that describes an error state. """ output = jsonresponse.JsonResponse() output.data = [] output.success = False output.addError(msg) return self.render_json(output, set_mime='text/plain')
def setPanel(self, namespace, view_id, panel_type, panel_sequence, panel_class=None, action='edit', **panel_definition): ''' Provides management for view panel objects The HTTP signature for this method expects standard form params to match the property names used in the panel objects. All form params are inserted into a dict and passed into the panel object for processing POST /<namespace>/<view_id>/panel/<panel_sequence> &action=edit --> updates the existing panel at <panel_sequence> &action=delete --> deletes the panel at <panel_sequence> ==> returns JSON response ''' output = jsonresponse.JsonResponse() self.collatePanelOptions(panel_definition) try: username = cherrypy.session['user'].get('name') dash_id = en.buildEndpoint(VIEW_ENTITY_CLASS, view_id, namespace=namespace, owner=username) dashObject = Dashboard.get(dash_id) if action == 'edit': dashObject.set_panel(panel_sequence, panel_class, **panel_definition) elif action == 'delete': dashObject.delete_panel(panel_sequence) else: raise ValueError, 'Unknown action requested: %s' % action dashObject.save() output.addInfo(_('Successfully updated %s' % view_id)) except Exception, e: logger.exception(e) output.success = False output.addError( _('Unable to update panel at sequence %s: %s') % (panel_sequence, e))
def delete_stream(self, **kwargs): amp_api = ApiService(kwargs['api_host'], kwargs['api_id'], kwargs['api_key']) storage = AmpStorageWrapper(self.__metadata(kwargs.get('name'))) stream = storage.find_stream() if stream is not None: logger.info('Controller - Deleting the stream at API: {}'.format(stream.get('name'))) self.__try_destroy_stream(amp_api, stream['id']) storage.delete_stream() output = jsonresponse.JsonResponse() output.success = True return self.render_json(output)
def render_error_json(self, msg): """ Render an error such that it can be returned to the client as JSON. Arguments: msg -- A message describing the problem (a string) """ output = jsonresponse.JsonResponse() output.data = [] output.success = False output.addError(msg) return self.render_json(output)
def fetch_api_key(self, **kwargs): session_key = cherrypy.session.get('sessionKey') service = client.connect(token=session_key) storage_passwords = service.storage_passwords api_key = None for storage_password in storage_passwords: if kwargs['api_id'] in storage_password.name: api_key = storage_password.clear_password break output = jsonresponse.JsonResponse() output.success = True output.api_key = api_key return self.render_json(output)
def add_error(self, output, error): status = None if not error: return output if not output: output = jsonresponse.JsonResponse() output.data = [] if isinstance(error, tuple): status = error[1] error = error[0] if status: cherrypy.response.status = status output.success = False output.addError(error) return output
def createPanel(self, namespace, view_id, panel_type, panel_class, **panel_definition): ''' Create a new panel to add to an existing dashboard POST /<namespace>/<view_id>/<panel_type=panel> &panel_class={table | chart | html | event | list} &<panel_property>=<property_value> --> creates a new panel the <panel_property> is a direct map to the panel XML data ==> returns a JSON response ''' output = jsonresponse.JsonResponse() try: if panel_type != 'panel': raise ValueError, 'Only panel type "panel" is currently supported' # support all options self.collatePanelOptions(panel_definition) # get dashboard and create panel username = cherrypy.session['user'].get('name') dash_id = en.buildEndpoint(VIEW_ENTITY_CLASS, view_id, namespace=namespace, owner=username) dashObject = Dashboard.get(dash_id) dashObject.create_panel(type=panel_class, **panel_definition) dashObject.save() except Exception, e: logger.exception(e) output.success = False output.addError(_('Unable to add panel: %s') % e)
def insecurelogin(self, username=None, password=None, return_to=None): ''' Provide insecure login endpoint for HTTP GET-based credential passing ''' # Force a refresh of startup info so that we know to # redirect if license stuff has expired. startup.initVersionInfo(force=True) output = jsonresponse.JsonResponse() if not splunk.util.normalizeBoolean( cherrypy.config.get('enable_insecure_login')): cherrypy.response.status = 403 output.success = False output.addError( 'The insecure login endpoint is disabled. See web.conf for details.' ) return self.render_json(output) if not username or not password: cherrypy.response.status = 400 output.success = False output.addError('Missing credentials') return self.render_json(output) ua = cherrypy.request.headers.get('user-agent', 'unknown') ip = cherrypy.request.remote.ip try: sessionKey = splunk.auth.getSessionKey( username, password, hostPath=self.splunkd_urlhost) except Exception, e: logger.error('user=%s action=insecurelogin status=failure session=%s ' \ 'reason=user-initiated useragent="%s" clientip=%s' % (username, sessionKey, ua, ip)) output.parseRESTException(e) output.success = False return self.render_json(output)
def setContainer(self, namespace, view_id, action, view_json=None): ''' Provides support to modify dashboard configs POST /<namespace>/<view_id> &action=delete --> deletes the current view &action=edit --> updates the current view config (view JSON object) ==> returns a JSON response ''' output = jsonresponse.JsonResponse() try: username = cherrypy.session['user'].get('name') dash_id = en.buildEndpoint(VIEW_ENTITY_CLASS, view_id, namespace=namespace, owner=username) dashObject = Dashboard.get(dash_id) if action == 'delete': dashObject.delete() output.addInfo(_('Successfully deleted %s') % view_id) elif action == 'edit': # convert incoming JSON to native struct; clean strings, view_json = json.loads(view_json) if view_json.get('label'): dashObject.label = view_json['label'].strip() if view_json.get('refresh'): dashObject.refresh = int(view_json['refresh'].strip()) # handle panel reordering; wrap number of columns to the max # column constraint newPanelDefinition = [] for row in view_json['new_panel_sequence']: newRow = [] for seq in row: newRow.append(dashObject._obj.getPanelBySequence(seq)) if len( newRow ) >= splunk.models.dashboard.MAX_DASHBOARD_ROW_SIZE: newPanelDefinition.append(newRow) newRow = [] if len(row) > 0: newPanelDefinition.append(newRow) dashObject._obj.rows = newPanelDefinition # ensure that the row grouping array is synced if len(dashObject._obj.rowGrouping) < len( dashObject._obj.rows): dashObject._obj.rowGrouping.extend( [None] * (len(dashObject._obj.rows) - len(dashObject._obj.rowGrouping))) # commit dashObject.save() output.addInfo(_('Successfully updated %s') % view_id) else: output.success = False output.addError( _('Unrecognized dashboard action: %s; cannot process') % action) logger.error( 'Unrecognized dashboard action: %s; cannot process' % action) except splunk.ResourceNotFound: cherrypy.response.status = 404 output.addWarn(_('"%s" was not found; no action taken') % view_id) except Exception, e: output.success = False output.addError(_('Unable to update view %s: %s') % (view_id, e)) logger.exception(e)
def getContainer(self, namespace, view_id, mode='', **unused): ''' Renders the dashboard edit page GET /<namespace>/<view_id> ==> HTML form page with dashboard edit form (labels, panels) and master panel edit form (hidden) GET /api/<namespace>/<view_id> ==> JSON structure of dashboard config (unused?) ''' # serve data feed output = jsonresponse.JsonResponse() try: username = cherrypy.session['user'].get('name') dash_id = en.buildEndpoint(VIEW_ENTITY_CLASS, view_id, namespace=namespace, owner=username) dashObject = Dashboard.get(dash_id) output.data = dashObject._obj.toJsonable() except splunk.ResourceNotFound: cherrypy.response.status = 404 output.success = False output.addError(_('View %s was not found') % view_id) return self.render_json(output) # serve template page if cherrypy.request.is_api: return self.render_json(output) else: cherrypy.response.headers['content-type'] = MIME_HTML # get supporting assets savedSearches = en.getEntities('saved/searches', namespace=namespace, count=-1, search="is_visible=1") for savedSearch in savedSearches: acl = savedSearches[savedSearch]['eai:acl'] if dashObject.metadata.sharing == 'user': continue if dashObject.metadata.sharing == 'app' and acl[ 'sharing'] == 'user': savedSearches[savedSearch]['dq'] = True continue if dashObject.metadata.sharing == 'global' and acl[ 'sharing'] != 'global': savedSearches[savedSearch]['dq'] = True continue if dashObject.metadata.perms['read'].count( '*') > 0 and acl['perms']['read'].count('*') == 0: savedSearches[savedSearch]['dq'] = True continue #dashboardObject = splunk.entity.getEntity('data/ui/views', view_id, namespace=APP['id'], owner=cherrypy.session['user'].get('name')) #dashOwner = dashboardObject['eai:acl'].get('owner', 'nobody') editLink = self.make_url( ['manager', namespace, 'data/ui/views', view_id], _qs=dict(action='edit', url=self.make_url(['app', namespace, view_id]), redirect_override="/app/%s/%s" % (namespace, view_id))) permissionsLink = self.make_url( [ 'manager', 'permissions', namespace, 'data/ui/views', view_id ], _qs=dict( uri=en.buildEndpoint('data/ui/views', view_id, namespace=namespace, owner=dashObject.metadata.owner))) return self.render_template( 'viewmaster/edit_dashboard.html', { 'namespace': namespace, 'view_id': view_id, 'view_object': dashObject._obj, 'APP': { 'id': namespace }, 'savedSearches': savedSearches, 'editLink': editLink, 'permissionsLink': permissionsLink, 'mode': mode, })
def createContainer(self, namespace, view_id='', view_label='', container_type='dashboard'): ''' Handles dashboard creation GET /<namespace> ==> HTML template form to input create data POST /<namespace> ==> Saves the HTML input values from GET == returns JSON response ''' # # serve template # if cherrypy.request.method == 'GET': return self.render_template('viewmaster/create_dashboard.html', {'namespace': namespace}) # # handle create view # output = jsonresponse.JsonResponse() # clean inputs view_id = re.sub(r'[^\w]', '', view_id) view_label = view_label.strip() or view_id if view_id == '': output.success = False output.addError(_('Dashboard ID cannot be empty')) return self.render_json(output) # check that view doesn't already exist try: username = cherrypy.session['user'].get('name') dash_id = en.buildEndpoint(VIEW_ENTITY_CLASS, view_id, namespace=namespace, owner=username) Dashboard.get(dash_id) output.success = False output.addError( _('Cannot create new %(container_type)s: %(view_id)s already exists') \ % {'container_type': container_type, 'view_id': view_id}) return self.render_json(output) except splunk.ResourceNotFound: pass # generate new try: view = Dashboard(namespace, username, view_id) view.label = view_label view.save() output.data = {'view_id': view_id, 'view_label': view_label} output.addInfo(_('Successfully created new %(container_type)s: %(view_id)s') \ % {'container_type': container_type, 'view_id': view_id}) logger.info('Created new %s: namespace=%s id=%s label=%s' % (container_type, namespace, view_id, view_label)) except Exception, e: logger.exception(e) output.success = False output.addError(_('Unable to create dashboard: %s') % e)
def __json_error(self, payload): output = jsonresponse.JsonResponse() output.error = payload output.success = False return self.render_json(output)
def dispatcher(self, service, action=None, **kwargs): ''' This is the main dispatcher that provides compatibility with the Twitter API. The URI structure of Twitter's API is not as clean as the routes system expects; we route everything through here first. ''' # parse the URI serviceParts = service.split('.', 2) handler = serviceParts[0] actionParts = action.split('.', 2) action = actionParts[0] outputMode = 'html' if len(serviceParts) > 1: outputMode = serviceParts[-1] elif len(actionParts) > 1: outputMode = actionParts[-1] data = None if handler == 'statuses': if action == 'public_timeline': searchString = 'search index=twink | head 100' data = self.executeSearch(searchString) elif action == 'user_timeline': searchString = 'search index=twink source="%s" | head 100' % kwargs.get( 'screen_name', cherrypy.session['user'].get('name')) data = self.executeSearch(searchString) elif action == 'mentions': pass elif action == 'show': pass elif action == 'update': self.addTweet(kwargs['status']) raise cherrypy.HTTPRedirect('public_timeline') else: raise cherrypy.HTTPError( 404, 'statuses does not recognize action: %s' % action) elif handler == 'search': searchString = 'search index=twink | head 100' elif handler == 'saved_searches': if action == 'show': pass else: pass else: raise cherrypy.HTTPError(404, 'handler not found: %s' % handler) if outputMode == 'html': cherrypy.response.headers['content-type'] = MIME_HTML return self.render_template( '/twink:/templates/public_timeline.html', {'stream': data}) elif outputMode == 'json': output = jsonresponse.JsonResponse() output.data = data return self.render_json(output) else: raise cherrypy.HTTPError(500, 'something is wrong')